feat(agent-runner): add plugin runner host integration

This commit is contained in:
huanghuoguoguo
2026-06-20 10:18:52 +08:00
parent acfac42107
commit 2e5244fe93
129 changed files with 26980 additions and 6209 deletions
@@ -0,0 +1,541 @@
# Agent Platform / Runtime Control Plane Decision Note
本文档记录 AgentRunner 插件化之后,LangBot 如何继续演进成 Agent Platform 基础设施层。这里讨论的是 Host capability layer,不是 `AgentRunner Protocol v2`,也不是把某个具体 Agent Platform 产品写进 LangBot core。
> 本文是当前决策版。协议数据结构仍以 [PROTOCOL_V1.md](./PROTOCOL_V1.md) 为准;测试执行入口见 [AGENT_RUNNER_QA_GUIDE.md](./AGENT_RUNNER_QA_GUIDE.md);扩展边界见 [EXTENSION_SCOPE_MATRIX.md](./EXTENSION_SCOPE_MATRIX.md)。
>
> 实现状态说明:本文描述的是 Runtime Control Plane v2 的目标能力和分阶段落地建议。当前 AgentRunner 插件化主线已经具备 event-first context、run-scoped authorization、EventLog / Transcript / State / sandbox 文件等 Host capability,并已落地持久 `AgentRun` / `AgentRunEvent` ledger、run control actions、最小 runtime heartbeat/claim lease 和 admin reconcile 原语。完整 Agent Platform 产品形态、daemon supervisor、runtime wakeup channel 和分布式 runtime 管控仍未完成。当前实现状态以 [STATUS.md](./STATUS.md) 为准。
## 1. 当前决策
LangBot 后续定位应更像 **Agent Host / infrastructure provider / transfer layer**,而不是把某个完整 Agent Platform 产品固化进 core。
结论:
- **Agent Platform 产品形态做成插件**。插件负责 agent 管理、策略、业务队列、UI、编排、多 agent 协作和产品体验。
- **Agent Platform 所需的基础事实源做进 Host**。当前 Host 已保存 event、state、transcript、sandbox 文件边界、active run 权限快照、持久 run/result ledger、审计关联和通用控制状态。
- **最小 runtime registry / heartbeat / claim lease 已作为 Host 原语落地,但不等于完整 daemon worker 管控**。远程 harness / daemon 的进程托管、wakeup channel、provider 登录态诊断和分布式调度仍可以先由 AgentRunner 插件和 SDK remote layer 自己维护。
- **不把业务调度写进 Host**。Host 提供通用 run/result/control primitivesPlatform 插件决定哪些事件触发哪些 agent、如何排队、如何分配、是否 fan-out。
推荐分层:
```text
LangBot Host
Current base: EventLog / runtime AgentBinding / State / Transcript / sandbox files / active run authorization
Current v2 foundation: Run / RunEvent / audit / result persistence / control primitives / minimal runtime heartbeat and claim lease
Planned: Agent / Binding persistence / daemon supervisor / wakeup channel / distributed runtime operations
Agent Platform plugin
Agent management UI / project-task model / event routing policy
Business queue / multi-agent orchestration / runtime selection policy
AgentRunner plugin / external harness runtime
Connects ACP / remote daemon / local subprocess / HTTP API
Executes and converts provider-native events to AgentRunResult
```
## 2. Platform 与非 Platform 的区别
当前 LangBot 已经具备 Agent Host 的核心特征:
- 抹平不同 AgentRunner。
- 从 IM / Pipeline 入口触发 runner。
- 有 event-first context 方向。
- 有 Host-owned EventLog / Transcript / State 和 sandbox/workspace 文件边界。
- 有 runner config 下发和 active run-scoped authorization。
-`run_id` 串联 event、transcript、state、sandbox 文件和内存授权上下文。
这还不是完整 Agent Platform。完整 Platform 至少还需要:
- 可管理的 agent 资产:agent profile、binding、resource policy、runner config、可用状态。
- 可观察的执行生命周期:run status、result stream、失败原因、文件引用、审计、回放。
- 可运营的控制面:取消、重试、排队、并发、超时、恢复、诊断。
- 可产品化的调度体验:事件订阅、路由策略、任务板、多 agent 协作、项目/工作区视图。
因此,区别不只是“有没有调度”,而是是否具备:
```text
managed agent assets + observable run lifecycle + operational run control
```
Host 负责这些能力的通用事实源和安全边界;Platform 插件负责把它们组装成具体产品。
### 2.1 当前实现边界
当前代码中的 `run_id` 已经连接 active run 授权、持久 run ledger 和多个 Host 事实源:
- `EventLog` 保存输入事件和审计入口,并记录 `run_id` / `runner_id`
- `Transcript` 保存对话历史投影,并用 `run_id` 关联 assistant 输出。
- Sandbox/workspace 保存当前运行输入文件和 runner 产物,并用 `run_id` 做访问边界的一部分。
- `PersistentStateStore` 保存 runner state,但不等同于 run lifecycle。
- `AgentRunSessionRegistry` 保存 active run 的内存态授权快照,用于 proxy action 校验;进程结束或 run 结束后不作为可回放事实源。
- `AgentRun` 保存 run lifecycle、scope、authorization snapshot、queue/claim 状态、cancel intent、usage/cost 和 metadata。
- `AgentRunEvent` 保存 runner/result/admin event stream,按 `run_id + sequence` 做可回放分页。
- `AgentRuntime` 保存最小 runtime registry / heartbeat 事实,用于 runtime list、stale mark 和 claim lease reconcile。
因此本文后续提到的 `AgentRun` / `AgentRunEvent``run_append_result``run_finalize``run_cancel``runtime_register``runtime_heartbeat``run_claim` 等基础原语已经存在。仍未完成的是独立 platform `run_create` action、Host-owned Agent / Binding 持久模型、业务队列产品形态、daemon supervisor、runtime wakeup channel、跨 Host 分布式锁和 provider/runtime 诊断面。
## 3. 基础概念
### 3.1 Event
Event 表示“发生了什么”:
```text
message.received
github.issue.opened
scheduler.tick
user.approved
system.webhook.received
```
EBA 负责把外部输入标准化成 event。Event 本身不是 queue,也不等同于一次 agent 执行。当前 `EventLog` 记录的是输入事件和审计事实;未来 `AgentRunEvent` 记录的是某次 run 的输出事件流,二者不能混用。
### 3.2 Run
Run 表示“某个 agent / binding / runner 针对某个 event 的一次执行”。
Run 应由 Host 持久化,成为执行状态、结果、权限和审计的事实源:
```text
run_id
event_id
agent_id / binding_id
runner_id
status
created_at / started_at / finished_at
error / failure_reason
delivery target
metadata
```
当前 `AgentRunSessionRegistry` 只保存 active run 的内存态授权信息,不足以支撑 Platform 的回放、审计、取消、重试和异步执行。
### 3.3 RunEvent / RunResult
RunEvent 是一次 run 过程中产生的结果事件流,对应 runner 返回的 `AgentRunResult`。它不同于 EBA/EventLog 的输入事件:
```text
message.delta
message.completed
tool.call.started
tool.call.completed
state.updated
action.requested
run.completed
run.failed
```
Host 应保存这些输出事件,按 `run_id + sequence` 可回放。Transcript、State 可以由这些 result event 触发写入现有 store,并保留能回溯到 `AgentRunEvent` 的关联。文件和工具大结果留在当前 run 的 sandbox/workspace 中,不作为 result event blob 回传。
### 3.4 Queue
Queue 不是 EBA 的替代品。
EBA 负责产生 eventqueue 负责处理“这个 event 对应的执行 work item 何时执行、谁来执行、如何取消/重试/恢复”。
队列可以分两层:
- **业务队列**:由 Platform 插件管理,例如项目任务、优先级、agent team、workflow、人工审批。
- **执行队列 / run queue**:可选 Host 原语,例如 queued / running / completed / failed / cancelled、claim lease、dispatch timeout、orphan recovery。
第一阶段不要求 Host 内置完整执行队列。Platform 插件可以先管理业务队列;在 Phase 1 / Phase 2 能力落地前,插件仍只能通过现有 `AgentRunOrchestrator.run(...)` 同步执行路径和现有 Host stores 获得有限的 run 关联能力。
### 3.5 Runtime / Daemon
Runtime / daemon 表示执行位置或执行能力,例如某台机器上的 Claude Code / Codex CLI。
当前决策:
- Host 不在第一阶段维护完整 runtime registry。
- AgentRunner 插件可以通过 SDK remote layer 与 daemon 保持连接、心跳和执行通道。
- 外部 harness / agent 不应直接访问 LangBot Host 或数据库。访问 LangBot 资源必须通过 daemon / AgentRunner plugin / SDK runtime / `AgentRunAPIProxy` / scoped MCP bridge,并接受 run-scoped authorization 校验。
- 如果后续多个插件都需要共享 runtime 状态,再把薄的 `RuntimeLease` / registry 下沉为 Host 通用能力。
## 4. Host 应新增的最小能力
第一阶段最重要的不是 daemon registry,而是让 Host 成为 run/result 的事实源。
### 4.1 AgentRun Store
新增持久 `AgentRun`
```text
id / run_id
event_id
agent_id
binding_id
runner_id
conversation_id / thread_id
workspace_id / bot_id
status
status_reason
created_at / started_at / finished_at / updated_at
deadline_at
cancel_requested_at
usage_json
cost_json
metadata_json
```
建议 status 至少包含:
```text
created
running
completed
failed
cancelled
timeout
```
如果后续加执行队列,再引入:
```text
queued
claimed
dispatching
```
### 4.2 AgentRunEvent Store
新增持久 `AgentRunEvent`
```text
id
run_id
sequence
type
data_json
usage_json
created_at
source
metadata_json
```
约束:
- 同一 `run_id``sequence` 单调递增。
- append 必须幂等,支持远程 daemon / plugin 重试。
- 未知 result type 可保存但 Host 只对已知类型执行副作用。
- 大 payload 仍应进入 sandbox/workspace,不直接塞入 result event。
- `usage_json` 保存 `AgentRunResult.usage` 原样结构;缺失表示 unknown,不等于 0。
### 4.3 Run Control API
Host 提供通用控制原语:
```text
run.create
run.get
run.list
run.events.page
run.cancel
run.append_result
run.finalize
```
语义:
- `run.create` 创建 Host-owned run 和授权快照。
- `run.append_result` 只允许受信 SDK/runtime 路径调用,必须绑定 run 创建时固化的授权快照,写入 `AgentRunEvent` 并触发 transcript/state/delivery 副作用。
- `run.finalize` 关闭 run,更新 terminal status。
- `run.cancel` 设置取消意图;同步 runner 通过 context/deadline 感知,远程 runner 通过插件/daemon 通道感知。
第一阶段可以只暴露给插件 runtime action,不一定先做公开 HTTP API。
### 4.4 Result Persistence In Orchestrator
当前 `AgentRunOrchestrator.run()` 已经处理:
```text
event -> binding -> context -> runner invocation -> result normalization
```
需要补齐:
- run 开始时创建 `AgentRun`
- 每个 `AgentRunResult` 进入 `AgentRunEvent`
- `run.completed` / 正常 generator 结束时标记 completed。
- `run.failed` / exception / timeout 标记 failed 或 timeout。
- terminal result 携带 usage 时,写入 `AgentRunEvent.usage_json` 并汇总到 `AgentRun.usage_json`
- `state.updated`、transcript 写入继续走现有 journal,但应与 `AgentRunEvent` 有可追踪关系。
### 4.5 Usage / Cost Accounting
SDK 侧 `AgentRunResult` 已提供可选 `usage` 字段,用于把不同 runner / external harness / provider-native event 的 token usage 归一到同一个 run result envelope。
语义:
- `run.completed.usage` SHOULD 表示本次 run 的最终聚合 token usage。
- `run.failed.usage` MAY 表示失败前已知的部分 token usage。
- 没有 usage 表示 upstream runtime 没有报告或 adapter 暂未接入;Host 不得按 0 计费或按 0 判断上下文消耗。
- Host 应把 event-level usage 原样写入 `AgentRunEvent.usage_json`,并在 terminal event 或 finalize 阶段汇总到 `AgentRun.usage_json`
- cost 应由 Host 根据 usage、runner/model identity、发生时间和价格表计算,写入 `AgentRun.cost_json`runner/provider 上报的 cost 只能作为非权威 telemetry 保留在 metadata 或 usage extra 中。
这层约束先解决协议位置和持久化位置;具体 ACP、remote daemon、local subprocess runner 如何从 native event 中抽取 usage,可在各插件后续适配。
### 4.6 Authorization Snapshot
异步或远程执行时,run 创建时必须固化授权快照:
- runner identity
- binding identity
- caller plugin identity
- resource policy
- allowed tools/models/files/knowledge bases/storage scopes
- state scopes
- conversation/thread/workspace scope
后续 append result、state API、history API 和 sandbox/workspace 文件访问都以这个 snapshot 校验,不重新扩大权限。
## 5. SDK 侧应新增的最小能力
SDK 不需要马上定义完整 daemon registry,但需要让插件和 runner 使用 Host run/result 能力。
### 5.1 Entities
新增或补齐:
```text
AgentRun
AgentRunStatus
AgentRunEvent
RunEventPage
RunCreateRequest / RunCreateResult
RunAppendResultRequest
```
这些是 Host control primitives,不替代 `AgentRunContext` / `AgentRunResult`
### 5.2 Proxy Methods
在 SDK proxy 中提供:
```python
create_run(...)
get_run(run_id)
list_runs(...)
page_run_events(run_id, cursor=None, limit=...)
cancel_run(run_id)
append_run_result(run_id, result, sequence=None)
finalize_run(run_id, status, error=None)
```
访问边界:
- 普通 AgentRunner 在同步 `run(ctx)` 内不一定需要直接调用这些 APIHost orchestrator 可自动记录。
- Platform 插件可以创建/查询/取消 run。
- AgentRunner 插件或 daemon bridge 可以 append/finalize 自己负责的 run。
- 外部 harness 仍不能直接调用 Host;必须经 SDK runtime / proxy / bridge。
### 5.3 Plugin-Daemon Heartbeat
远程 daemon 的初始心跳可以是 SDK / AgentRunner plugin 私有能力:
```text
daemon <-> AgentRunner plugin / SDK remote layer <-> LangBot plugin runtime <-> Host
```
Host 第一阶段只需要知道:
- 相关插件是否在线。
- run 是否有 progress/result。
- run 是否超时或取消。
如果后续需要跨插件共享 daemon 可用性,再把 heartbeat/registry 下沉为 Host 能力。
## 6. Platform 插件应负责什么
Agent Platform 插件可以负责:
- 管理哪些 agent 可用。
- 维护产品层 agent profile、项目、任务板、workflow、team。
- 订阅 EBA event,决定哪些 event 触发哪些 agent。
- 维护业务 queue:优先级、重试策略、人工审批、分配规则。
- 选择 runner / runtime / daemon。
- 在 Run Control API 落地后,调用 Host run API 创建、取消、查询执行。
- 展示 run status、result stream、文件引用、失败原因和审计。
Platform 插件不应负责:
- 在 Host Run Ledger 落地后,私有保存通用 run/result 事实源。
- 绕过 Host 直接写 transcript/state 或越权访问 sandbox/workspace 文件。
- 让外部 harness 直接访问 LangBot DB 或 Host 内部资源。
- 把某个业务队列语义强塞进 AgentRunner Protocol v1。
## 7. 与 EBA 的关系
EBA 做好后,事件流可以进入两种路径。
直接执行路径:
```text
EventGateway
-> EventRouter resolves AgentBinding
-> AgentRunOrchestrator.run(event, binding)
-> Host records AgentRun / AgentRunEvent (after Run Ledger lands)
-> delivery
```
Platform 插件编排路径:
```text
EventGateway
-> Platform plugin receives/subscribes event
-> plugin applies policy / business queue
-> plugin creates Host run (after Run Control API lands)
-> runner/plugin/daemon executes
-> Host records result and state
-> plugin displays / Host delivers
```
这两条路径最终应共享 Host run/result/state 事实源和 sandbox/workspace 文件边界。当前阶段可共享的是 event/transcript/state、sandbox 文件和同步执行链路;持久 run/result ledger 需要 Runtime Control Plane v2 Phase 1 补齐。区别在于是否有 Platform 插件参与产品化调度和业务队列。
## 8. 与 AgentRunner Protocol v1 的关系
本设计不改变 v1 的 runner 可见合同:
```text
AgentRunContext -> AgentRunner.run(ctx) -> AgentRunResult stream
```
必须保持:
- `AgentRunContext` 不塞入 daemon/worker/pod 细节。
- `AgentRunResult` 仍是 runner 输出的统一事件流。
- 普通 runner 不需要知道 task queue / runtime registry。
- 远程 harness 可以自管 session、tool loop、MCP、上下文压缩,但访问 LangBot 资源必须通过 SDK proxy / bridge。
- Runtime-managed execution 是 placement / transport 选择,不是普通 runner 协议的强制概念。
## 9. 分阶段实施建议
### Phase 1: Run LedgerFoundation Implemented
目标:Host 成为执行状态和结果事实源。
范围:
- `AgentRun` 表。
- `AgentRunEvent` 表。
- Orchestrator 自动创建/更新 run。
- Journal 持久化每个 `AgentRunResult`
- Run 查询和事件分页 API。
- SDK entities + proxy 方法。
复杂度:中等。
预计改动:
```text
Host: 12-20 个文件
SDK: 4-8 个文件
Tests: 8-15 个文件
```
### Phase 2: Platform Plugin Queue On Host Run PrimitivesControl Primitives Partially Implemented; Product Queue Pending
目标:Platform 插件管理业务 queueHost 提供 run/result/cancel 原语。
范围:
- `run.create`
- `run.cancel`
- `run.append_result`
- `run.finalize`
- result append 的 sequence/idempotency。
- 受权限保护的远程 append/finalize。
- Platform 插件可基于 Host run 构建任务板和调度体验。
复杂度:中等偏高。
预计改动:
```text
Host: 20-35 个文件
SDK: 8-14 个文件
Tests: 15-25 个文件
```
### Phase 3: Optional Host Execution Queue / Claim LeaseClaim Lease Primitive Implemented; Full Queue Pending
目标:当多个插件重复实现 claim/cancel/retry/recovery 时,再下沉执行队列到 Host。
范围:
- `queued/running/completed/failed/cancelled` 状态机扩展。
- `claim_run` / `lease_until`
- dispatch timeout。
- retry / orphan recovery。
- cancel propagation。
- 并发 claim 防重。
复杂度:高。
预计改动:
```text
Host: 35-55 个文件
SDK: 12-20 个文件
Tests: 25-40 个文件
```
### Phase 4: Optional Runtime RegistryMinimal Registry Implemented; Full Daemon Control Pending
目标:当 Host 需要统一管理多个 daemon / worker 时,再引入 runtime registry。
范围:
- runtime register / heartbeat / deregister。
- capability reportprovider、version、login status、workspace access、slot。
- runtime online/offline。
- runtime scoped auth。
- runtime audit。
- runtime gone recovery。
- task wakeup / long polling / websocket。
- 多 Host 实例下的 relay / distributed lock。
复杂度:很高。
预计改动:
```text
Host: 55-80+ 个文件
SDK: 18-30 个文件
Tests: 40+ 个文件
```
不建议现在直接进入此阶段。
## 10. 设计原则
- 先把 run/result 事实源做进 Host,再谈完整 runtime control plane。
- Agent Platform 产品做插件;Host 做基础设施。
- Host 不写业务调度策略,但要保存通用状态、结果、权限和审计。
- EBA event 不是 queuequeue 是执行生命周期问题。
- 业务 queue 可以先在 Platform 插件里;执行 queue 只有在复用需求明确后再下沉 Host。
- Daemon registry 不应污染 AgentRunner Protocol v1。
- 外部 harness 不直接访问 LangBot Host 或 DB。
- 所有 LangBot 资源访问必须走 SDK runtime / `AgentRunAPIProxy` / scoped MCP bridge。
- Docker / remote / local subprocess 只是 runtime placement,不是 runner 协议差异。
## 11. 非目标
当前阶段不做:
- 完整 Multica 式 runtime registry。
- Host 内置项目管理、任务板、agent team、workflow 产品逻辑。
- 把 daemon heartbeat / worker liveness 放进 `AgentRunContext`
- 把业务 queue 定义为 AgentRunner Protocol 字段。
- 让 Platform 插件私有保存 run/result 事实源。
- 让外部 agent/harness 直连 Host 内部资源。
## 12. 待定问题
- Host 是否需要最小持久 `Agent` / `Binding` 模型,还是继续由 Pipeline / Platform 插件投影运行期 `AgentBinding`
- Platform 插件创建 run 时,是否传完整 `AgentBinding` snapshot,还是引用 Host-owned binding id。
- `AgentRunEvent` 与现有 `EventLog` / `Transcript` 的查询关系:直接 join,还是通过专门 view 聚合。
- `run.append_result` 的认证粒度:runner plugin identity、run token、scoped capability token,或 SDK runtime 内部 channel。
- 取消语义:同步 runner、external harness runtime/session 如何统一感知 cancel。
- 何时把插件私有 daemon heartbeat 提升为 Host `RuntimeLease`
- 若未来 Host 做 claim leasePlatform 插件业务 queue 与 Host execution queue 如何避免双队列混乱。