feat: plugins and public api (#71)

This commit is contained in:
banteg
2026-01-09 03:23:57 +04:00
committed by GitHub
parent 16c0069aa0
commit f856338b94
32 changed files with 3135 additions and 622 deletions
+63 -10
View File
@@ -9,10 +9,19 @@ flowchart TB
cli_desc["Entry point, config loading, lock file"]
end
subgraph Plugins["Plugin Layer"]
entrypoints[plugins.py<br/>entrypoint discovery]
engines[engines.py]
transports[transports.py]
commands[commands.py]
api[api.py<br/>public plugin API]
end
subgraph Orchestration["Orchestration Layer"]
router[AutoRouter<br/>router.py]
scheduler[ThreadScheduler<br/>scheduler.py]
projects[ProjectsConfig<br/>config.py]
runtime[TransportRuntime<br/>transport_runtime.py]
end
subgraph Bridge["Bridge Layer"]
@@ -42,8 +51,18 @@ flowchart TB
cli --> router
cli --> scheduler
cli --> projects
cli --> engines
cli --> transports
cli --> commands
engines --> entrypoints
transports --> entrypoints
commands --> entrypoints
router --> runtime
projects --> runtime
router --> tg_bridge
scheduler --> tg_bridge
runtime --> tg_bridge
tg_bridge --> commands
tg_bridge --> runner_bridge
runner_bridge --> runner_proto
runner_proto --> runners
@@ -59,6 +78,21 @@ flowchart TB
---
## Plugin Architecture
Takopi discovers plugins via Python entrypoints and keeps loading lazy:
- **Engine backends** (`takopi.engine_backends`)
- **Transport backends** (`takopi.transport_backends`)
- **Command backends** (`takopi.command_backends`)
Entrypoint names become plugin IDs, are validated up front (reserved names, regex),
and are only loaded when needed. The public surface for plugin authors lives in
`takopi.api`, while transports and commands interact with core routing via
`TransportRuntime`.
---
## Domain Model
```mermaid
@@ -120,19 +154,27 @@ sequenceDiagram
participant RunnerBridge as runner_bridge.py
participant Runner
participant AgentCLI as Agent CLI
participant Command as Command Plugin
User->>Telegram: Send message
Telegram->>Bridge: poll_incoming()
Bridge->>Bridge: Parse directives<br/>(/engine, /project, @branch)
Bridge->>Bridge: Extract resume token<br/>from reply
Bridge->>Bridge: Resolve worktree<br/>(if @branch)
Bridge->>Bridge: Parse slash command
alt Command plugin
Bridge->>Command: handle(ctx)
Command->>RunnerBridge: run_one/run_many (optional)
RunnerBridge->>Telegram: Send progress/final
else Default routing
Bridge->>Bridge: Parse directives<br/>(/engine, /project, @branch)
Bridge->>Bridge: Extract resume token<br/>from reply
Bridge->>Bridge: Resolve worktree<br/>(if @branch)
Bridge->>Scheduler: enqueue(ThreadJob)
Scheduler->>RunnerBridge: handle_message()
Bridge->>Scheduler: enqueue(ThreadJob)
Scheduler->>RunnerBridge: handle_message()
RunnerBridge->>Telegram: Send progress message
RunnerBridge->>Runner: run(prompt, resume)
RunnerBridge->>Telegram: Send progress message
RunnerBridge->>Runner: run(prompt, resume)
end
Runner->>AgentCLI: Spawn subprocess
@@ -217,8 +259,14 @@ sequenceDiagram
flowchart TD
cli[cli.py] --> config[config.py]
cli --> engines[engines.py]
cli --> transports[transports.py]
cli --> commands[commands.py]
cli --> lockfile[lockfile.py]
engines --> plugins[plugins.py]
transports --> plugins
commands --> plugins
engines --> backends[backends.py]
backends --> runners[runners/]
@@ -244,7 +292,10 @@ flowchart TD
pi --> pi_s
cli --> router[router.py]
router --> tg_bridge[telegram/bridge.py]
tg_bridge --> runtime[transport_runtime.py]
runtime --> router
runtime --> config
tg_bridge --> commands
runner --> runner_bridge[runner_bridge.py]
runner_bridge --> tg_bridge
@@ -274,12 +325,13 @@ flowchart LR
subgraph toml_contents["takopi.toml"]
direction TB
global["transport<br/>default_engine"]
global["transport<br/>default_engine<br/>default_project"]
telegram_cfg["[transports.telegram]<br/>bot_token = ...<br/>chat_id = ..."]
plugins_cfg["[plugins]<br/>enabled = [\"...\"]"]
plugins_extra["[plugins.mycommand]<br/>setting = ..."]
claude_cfg["[claude]<br/>model = ..."]
codex_cfg["[codex]<br/>model = ..."]
projects_cfg["[projects.alias]<br/>path = ...<br/>worktrees_dir = ...<br/>default_engine = ..."]
default_proj["[projects]<br/>default = ..."]
end
toml --> toml_contents
@@ -335,6 +387,7 @@ flowchart TD
| Layer | Components | Responsibility |
|-------|------------|----------------|
| **CLI** | `cli.py` | Entry point, config, lock |
| **Plugins** | `plugins.py`, `engines.py`, `transports.py`, `commands.py`, `api.py` | Entrypoint discovery, plugin loading, public API boundary |
| **Orchestration** | `router.py`, `scheduler.py`, `config.py` | Engine selection, job queuing, project config |
| **Bridge** | `telegram/bridge.py`, `runner_bridge.py` | Message handling, execution coordination |
| **Runner** | `runner.py`, `runners/*.py`, `schemas/*.py` | Agent CLI subprocess, JSONL parsing, event translation |