# 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 primitives，Platform 插件决定哪些事件触发哪些 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 负责产生 event；queue 负责处理“这个 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)` 内不一定需要直接调用这些 API；Host 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 Ledger（Foundation 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 Primitives（Control Primitives Partially Implemented; Product Queue Pending）

目标：Platform 插件管理业务 queue，Host 提供 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 Lease（Claim 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 Registry（Minimal Registry Implemented; Full Daemon Control Pending）

目标：当 Host 需要统一管理多个 daemon / worker 时，再引入 runtime registry。

范围：

- runtime register / heartbeat / deregister。
- capability report：provider、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 不是 queue；queue 是执行生命周期问题。
- 业务 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. 待定问题

- 已确认：Agent 与 Pipeline 都持久存在，并由 EBA 处理器 binding 指向其中之一；Pipeline 仅在 AI Stage 调用 runner 时投影一次性 `AgentBinding`，不会充当持久 Agent 的替代物。
- 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 lease，Platform 插件业务 queue 与 Host execution queue 如何避免双队列混乱。
