From 9e9bfbfb3dad46a6e75b6341f79e6e45984d0224 Mon Sep 17 00:00:00 2001 From: huanghuoguoguo <1051233107@qq.com> Date: Fri, 29 May 2026 22:41:10 +0800 Subject: [PATCH] docs(agent-runner): align runner protocol boundaries --- .../AGENT_CONTEXT_PROTOCOL.md | 12 +- .../HOST_SDK_INFRASTRUCTURE.md | 2 +- .../IMPLEMENTATION_PLAN.md | 20 +- .../OFFICIAL_RUNNER_PLUGINS.md | 25 +- .../PHASE1_QA_ACCEPTANCE_MATRIX.md | 367 ++++++++++-------- .../PHASE1_QA_REPORT_2026-05-18.md | 103 ----- .../PHASE1_QA_REPORT_2026-05-29.md | 103 ----- docs/agent-runner-pluginization/PROGRESS.md | 3 +- .../agent-runner-pluginization/PROTOCOL_V1.md | 16 +- docs/agent-runner-pluginization/README.md | 17 +- .../RUNTIME_CONTROL_PLANE_V2.md | 225 +++++++++++ src/langbot/pkg/agent/runner/host_models.py | 2 +- .../pkg/agent/runner/resource_builder.py | 4 +- tests/unit_tests/agent/conftest.py | 2 +- .../api/test_pipeline_service_defaults.py | 2 - 15 files changed, 504 insertions(+), 399 deletions(-) delete mode 100644 docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-18.md delete mode 100644 docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-29.md create mode 100644 docs/agent-runner-pluginization/RUNTIME_CONTROL_PLANE_V2.md diff --git a/docs/agent-runner-pluginization/AGENT_CONTEXT_PROTOCOL.md b/docs/agent-runner-pluginization/AGENT_CONTEXT_PROTOCOL.md index b406b5e2..da68b2bf 100644 --- a/docs/agent-runner-pluginization/AGENT_CONTEXT_PROTOCOL.md +++ b/docs/agent-runner-pluginization/AGENT_CONTEXT_PROTOCOL.md @@ -14,7 +14,7 @@ - ✅ `AgentRunAPIProxy.state` — get/set/delete API - ✅ EventLog / Transcript / ArtifactStore — host 事实源 - ✅ PersistentStateStore — 持久化状态存储 -- ✅ `max-round` 已从协议实体中移除,只在 Pipeline adapter 中处理 +- ✅ `max-round` 已从协议实体中移除;如某 runner 仍需要类似历史窗口参数,应作为 runner binding config 由插件 manifest 暴露,而不是 Host / Pipeline 协议字段 - ✅ 外部 harness context projection 已用 Claude Code runner 做 MVP 验证:context 文件、skill 投影、MCP 配置和 host-owned resume state ## 1. 设计原则 @@ -37,7 +37,11 @@ ### 1.2 不再把 `max-round` 作为目标设计 -Pipeline adapter 的 `max-round` 配置可以在运行时被读取并转换为某种默认 bootstrap policy,但不应继续作为 AgentRunner 协议的核心概念。 +`max-round` 这类历史窗口参数不应继续作为 AgentRunner 协议或 Pipeline adapter 的核心概念。 + +如果某个 runner 仍需要“最多读取多少轮历史”这样的策略参数,应由该 runner 在自己的 manifest/config schema 中声明,并作为 binding config 存到 `ctx.config` / `runner_config`。Host 只提供 history pull API、cursor、hard cap 和权限边界;runner 自己决定是否读取、读取多少、如何截断和压缩。 + +当前 official local-agent 方向是通过 Host history API 拉取 transcript,并由 runner 自己管理模型上下文。它不依赖 Pipeline adapter 下发的 `max-round` / bootstrap 窗口。 新协议不应该问“LangBot 每轮裁几轮历史给 agent”,而应该问: @@ -128,7 +132,7 @@ context: - 自管 runtime:`bootstrap: current_event` - 简单 HTTP runner:`bootstrap: recent_tail` -- Pipeline adapter 的 `max-round` 可映射为 `recent_tail` 配置,但不再作为协议字段扩展。 +- runner 如果需要 `recent_tail` 策略,应通过自己的 binding config 声明窗口大小;Host 不把 `max-round` 作为通用协议字段扩展。 ## 3. ContextAccess @@ -331,7 +335,7 @@ LangBot core 不应内置官方 agent 的业务流程: **已完成(当前分支)**: -- ✅ `max-round` 在 Pipeline adapter 中处理(不影响协议实体) +- ✅ `max-round` 不再是协议字段;类似历史窗口策略属于 runner binding config,而不是 Host / Pipeline 通用语义 - ✅ 新 runner 默认不收到历史窗口 - ✅ `AgentRunContext` 增加 `context` / cursor / access capabilities - ✅ `AgentRunAPIProxy` 增加 history / events / artifacts / state API diff --git a/docs/agent-runner-pluginization/HOST_SDK_INFRASTRUCTURE.md b/docs/agent-runner-pluginization/HOST_SDK_INFRASTRUCTURE.md index fdbf3366..dadeab5b 100644 --- a/docs/agent-runner-pluginization/HOST_SDK_INFRASTRUCTURE.md +++ b/docs/agent-runner-pluginization/HOST_SDK_INFRASTRUCTURE.md @@ -377,7 +377,7 @@ Proxy 是 runner 访问 host 能力的唯一入口: - ✅ `PipelineAdapter` — Query → Event + Binding - ✅ `AgentBinding` 抽象 - ✅ `AgentEventEnvelope` 抽象 -- ✅ `max-round` 从目标设计中移除,只在 Pipeline adapter 中处理 +- ✅ `max-round` 从目标协议中移除;类似历史窗口参数若仍需要,应由具体 runner 的 manifest/config schema 暴露为 binding config - ✅ `PersistentStateStore` — 持久化状态存储 - ✅ `EventLogStore` / `TranscriptStore` / `ArtifactStore` - ✅ history / artifact / event 的受限拉取 API diff --git a/docs/agent-runner-pluginization/IMPLEMENTATION_PLAN.md b/docs/agent-runner-pluginization/IMPLEMENTATION_PLAN.md index d6993104..2d605ef3 100644 --- a/docs/agent-runner-pluginization/IMPLEMENTATION_PLAN.md +++ b/docs/agent-runner-pluginization/IMPLEMENTATION_PLAN.md @@ -1,6 +1,6 @@ # Agent Runner 插件化当前实现与收尾计划 -> 2026-05-29 状态说明:本文档是实现推进计划和历史上下文,不是最新验收结论的唯一来源。当前设计入口见 [README.md](./README.md),协议边界见 [PROTOCOL_V1.md](./PROTOCOL_V1.md),进度见 [PROGRESS.md](./PROGRESS.md),最新本地 smoke 见 [PHASE1_QA_REPORT_2026-05-29.md](./PHASE1_QA_REPORT_2026-05-29.md)。 +> 2026-05-29 状态说明:本文档是实现推进计划和历史上下文,不是最新验收结论的唯一来源。当前设计入口见 [README.md](./README.md),协议边界见 [PROTOCOL_V1.md](./PROTOCOL_V1.md),进度见 [PROGRESS.md](./PROGRESS.md),下一轮测试入口见 [PHASE1_QA_ACCEPTANCE_MATRIX.md](./PHASE1_QA_ACCEPTANCE_MATRIX.md)。 本文档面向实现 agent,用来把当前 AgentRunner 插件化实现推进到可迁移状态。 @@ -188,10 +188,11 @@ Protocol v1 context 的稳定字段: Pipeline adapter 的 `prompt` 和公开业务变量不进入顶层协议字段: -- effective prompt -> `ctx.adapter.extra["prompt"]` - filtered params -> `ctx.adapter.extra["params"]` -- `max-round` working window -> `ctx.bootstrap.messages` -- 同一窗口也可出现在 `ctx.adapter.adapter_messages`,供 adapter 消费方读取 +- legacy/effective prompt 可以暂存到 `ctx.adapter.extra["prompt"]`,但 official + runner 不应把它当作行为契约 +- `max-round` working window 可以保留在 Pipeline adapter 兼容层,但 official + `local-agent` 不消费该 bootstrap/window - packaging 元数据 -> `ctx.runtime.metadata.context_packaging` 现阶段不要把新的压缩或 token-budget 裁剪塞回 Pipeline stage。Pipeline 只负责入口适配;完整历史和长期上下文由 EventLog / Transcript / pull APIs / future ContextCompressor 支撑。 @@ -301,6 +302,10 @@ api.create_temp_artifact(name: str, content_type: str, ttl_seconds: int) -> Arti 注意:旧的 unrestricted proxy action 必须二次校验,不能只靠 context 声明。AgentRunner 可用资源应来自 `ctx.resources`,不是插件 runtime 的全局能力。 +本阶段不接入 sandbox/skills,也不预留 runner 可见字段。后续相关分支合并后, +执行、文件、skill、MCP 等能力应先由 Host 侧封装成普通 tool,再通过 +`ctx.resources.tools` 进入 runner;runner 不应识别或硬编码执行环境 provider。 + 资源裁剪要尽量通用,不应只写死 local-agent: - `model-fallback-selector` 授权 primary/fallback LLM。 @@ -486,7 +491,7 @@ async def run_from_query(query: pipeline_query.Query) -> AsyncGenerator[Message - SDK `AgentRunContext` 保持 event-first:`event/input/delivery/resources/context/state/runtime/config/bootstrap/adapter`。 - LangBot context builder 只从 `AgentEventEnvelope + AgentBinding` 写入稳定协议字段。 -- Pipeline adapter 把 effective prompt 写入 `ctx.adapter.extra["prompt"]`,把公开业务变量写入 `ctx.adapter.extra["params"]`。 +- Pipeline adapter 可以把公开业务变量写入 `ctx.adapter.extra["params"]`;legacy/effective prompt 若保留在 `ctx.adapter.extra["prompt"]`,也只属于 adapter metadata。 - 保持 `ctx.config` 只表达静态绑定配置。 ### Step 2:增强宿主 AgentRun proxy action @@ -506,7 +511,8 @@ async def run_from_query(query: pipeline_query.Query) -> AsyncGenerator[Message ### Step 4:local-agent parity -- 使用 `ctx.adapter.extra["prompt"]` 而不是重新读取 `ctx.config["prompt"]`。 +- 使用静态绑定配置 `ctx.config["prompt"]`,不读取 `ctx.adapter.extra["prompt"]`。 +- 通过 Host history API 拉取 transcript,不读取 `ctx.bootstrap.messages` 或 `ctx.adapter.adapter_messages`。 - 当前 user message 从 `ctx.input.contents` 构造,保留多模态内容。 - RAG 只替换/插入文本部分,不丢图片/文件。 - streaming/non-streaming 默认跟随 `runtime.metadata.streaming_supported`。 @@ -519,7 +525,7 @@ async def run_from_query(query: pipeline_query.Query) -> AsyncGenerator[Message - 插件无输出时按 runner failed 处理。 - timeout/deadline 覆盖 plugin runtime、模型调用和外部 runner 调用。 - runner 协议错误转受控错误。 -- 覆盖旧 local-agent 行为 parity:普通回复、流式、工具、多步工具、KB、rerank、多模态、PromptPreProcessing。 +- 覆盖 local-agent 用户可见行为:普通回复、流式、工具、多步工具、KB、rerank、多模态、绑定 prompt、history API。 ### Step 6:官方 runner 迁移 diff --git a/docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md b/docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md index a02b2dce..9b04fde5 100644 --- a/docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md +++ b/docs/agent-runner-pluginization/OFFICIAL_RUNNER_PLUGINS.md @@ -183,7 +183,10 @@ LangBot core 不应为了 local-agent 保留业务编排逻辑。local-agent 的 - `ctx.runtime.metadata.streaming_supported`:当前 adapter 是否能消费流式输出。 - 宿主代理 action:模型、工具、知识库、rerank 调用必须通过 `run_id` 校验资源权限。 -`max-round` 可作为 Pipeline adapter 的历史配置输入。如需适配 Pipeline 行为,可以把 `max-round` 转成 local-agent 插件自己的 bootstrap/history policy;不要把它提升为 LangBot host 的目标协议字段。 +`local-agent` 不应消费 Pipeline adapter 生成的 `max-round` / `bootstrap` +窗口,也不应读取 `ctx.adapter.extra.prompt`。它应从绑定配置读取静态 +`prompt`,并通过 Host history API 拉取 transcript。Pipeline adapter 可以继续为旧入口 +保留 `max-round` 兼容逻辑,但这不是 official local-agent 的行为契约。 建议 local-agent manifest 使用 hybrid 或 self-managed context: @@ -203,6 +206,17 @@ context: 这表示:LangBot 只给当前事件和 context handles;local-agent 自己决定是否拉取历史、是否搜索、 何时摘要、如何构造最终 prompt。 +### 6.1 Native Execution / Skills 后续接入 + +本阶段不把 sandbox/skills 做成 AgentRunner 协议字段,也不预留 runner 可见字段。 +后续 sandbox/skills 分支合并后,命令执行、文件操作、skill、MCP managed process +等能力应先由 LangBot Host 封装成 scoped tools,再通过 `ctx.resources.tools` +暴露给 runner。 + +这让 local-agent 只消费授权后的 Host 基础设施,而不是直接持有宿主机执行能力。 +Claude Code / Codex 这类外部 harness runner 仍可先保留自己的执行模型,但要在文档和 +配置中明确它们是否使用 LangBot 提供的工具投影。 + ## 7. 外部 runner 插件要求 外部平台 runner 迁移时遵循: @@ -221,6 +235,9 @@ Claude Code、Codex、Kimi Code 这类 runner 不一定通过 LangBot 的模型/ - LangBot 授权后的资源应被投影为 harness 可读的 context 文件、MCP 配置、skill 目录、环境变量或 CLI 参数。 - 外部 session id、workspace、checkpoint 等跨轮次指针应写入 Host state 或 plugin storage;插件实例本身保持无状态。 - CLI / subprocess runner 必须处理 timeout、取消、空输出、非零退出和 stderr 映射。 +- 如果外部 harness 选择使用 LangBot 托管执行能力,它应通过 scoped MCP/tool + 投影消费 Host 授权资源;否则它属于 external harness mode,不能声称具备 + LangBot-managed 执行隔离。 - 外部 harness 的 permission mode、allowed/disallowed tools、MCP 配置只是一层执行约束;LangBot 仍负责调用前的资源授权、路径策略、secret 过滤和审计。发布级要求见 [SECURITY_HARDENING.md](./SECURITY_HARDENING.md)。 ## 8. Claude Code runner 当前形态 @@ -260,12 +277,12 @@ Claude Code runner 当前把 LangBot event-first context 投影给外部 harness - `codex-agent` 可通过 WebUI Debug Chat 调用本机 Codex CLI,读取 LangBot event context,并把 Codex `thread_id` 写入 host-owned state - 对需要代理的本地运行环境,`codex-agent` 可通过 binding config 的 `environment-json` 显式传递非 secret 环境变量 -详见 [PHASE1_QA_REPORT_2026-05-29.md](./PHASE1_QA_REPORT_2026-05-29.md)。 +下一轮测试入口见 [PHASE1_QA_ACCEPTANCE_MATRIX.md](./PHASE1_QA_ACCEPTANCE_MATRIX.md)。 ### 8.4 当前限制 - 不是发布级安全边界实现。 -- 默认只做本地 CLI 调用,不实现完整 sandbox/workspace 生命周期。 +- 默认只做本地 CLI 调用,不实现完整执行隔离或 workspace 生命周期。 - 不实现 issue-centric 队列、复杂 workflow engine 或长期任务调度。 - 不代表 Codex 发布级能力或 Kimi runner 已完成;当前只验证外部 harness runner 的协议形态。 @@ -290,6 +307,6 @@ Claude Code runner 当前把 LangBot event-first context 投影给外部 harness - 旧 runner 配置能无损复制到新 `runner_config[id]`。 - LangBot 主聊天路径不再通过 `RequestRunner` 执行业务 runner。 - 官方插件测试覆盖非流式、流式、错误、timeout、配置缺失。 -- `local-agent` 插件能完成模型 fallback、tool calling、知识库检索、多模态输入、prompt preprocessing 后的有效 prompt 消费、rerank。 +- `local-agent` 插件能完成模型 fallback、tool calling、知识库检索、多模态输入、静态绑定 prompt 消费、history API 拉取、rerank。 - `claude-code-agent` 或同类 code-agent harness runner 能消费 event-first context、投影 scoped resources、保存 external session state,并通过 WebUI Debug Chat smoke。 - 对外行为与旧内置 local-agent runner 保持一致;代码结构不需要相同。 diff --git a/docs/agent-runner-pluginization/PHASE1_QA_ACCEPTANCE_MATRIX.md b/docs/agent-runner-pluginization/PHASE1_QA_ACCEPTANCE_MATRIX.md index d644b11f..948b5542 100644 --- a/docs/agent-runner-pluginization/PHASE1_QA_ACCEPTANCE_MATRIX.md +++ b/docs/agent-runner-pluginization/PHASE1_QA_ACCEPTANCE_MATRIX.md @@ -1,194 +1,245 @@ -# Agent Runner 插件化 Phase 1 QA 验收矩阵 +# Agent Runner QA 指南 -本文档用于指导测试 agent 验收 Phase 1:Agent Runner 插件化是否已经达到旧内置 runner 的对外效果。 +本文档是 agent-runner 插件化下一轮测试的唯一 QA 入口。它合并并取代旧的 Phase 1 验收矩阵与 2026-05-18 / 2026-05-29 两份本地 QA 报告。 -Phase 1 的目标是让当前聊天 Pipeline 在选择插件化 AgentRunner 后,用户可感知行为与旧内置 runner 保持一致。Phase 2/EBA 不纳入本轮验收。 +目标不是保留完整历史流水账,而是指导测试 agent 用最小但高价值的路径判断当前分支是否仍然健康。 -本文档是当前分支兼容性验收矩阵,不代表目标架构边界。目标协议以 [PROTOCOL_V1.md](./PROTOCOL_V1.md) 为准:Pipeline 是兼容入口,`messages` 只是 optional bootstrap,LangBot 不默认 inline 全量历史。 +## 1. 测试边界 -## 1. 验收边界 +当前主线验证的是 AgentRunner Protocol v1: -本轮必须验收: +```text +event -> binding -> runner.run(ctx) -> result stream +``` -- Pipeline 仍按现有消息入口运行。 -- Runner 由插件提供,并通过 `AgentRunOrchestrator` 调用。 -- `local-agent` 插件达到旧内置 local-agent 的主要行为 parity。 -- 官方外部 runner 插件至少完成 smoke 验收。 -- 外部 harness runner(当前以 Claude Code MVP 为代表)至少完成一次 WebUI smoke,验证 event-first context、资源投影和 state handoff。 -- 旧 Pipeline 配置兼容,新配置可保存并生效。 -- 权限裁剪、错误隔离、运行状态更新不破坏主流程。 +本指南验证: -本轮不验收: +- Host 能通过当前 Pipeline adapter 进入 event-first `run(event, binding)` 主链路。 +- Runner 来自插件 registry,而不是旧内置 runner 分支。 +- `local-agent` 能消费 Host 模型、工具、知识库、history、state、artifact 等基础设施。 +- 外部 harness runner(Claude Code / Codex)能消费 event-first context,并把 session / working directory 等指针写回 host-owned state。 +- 错误、权限裁剪、无输出、timeout 等路径不会破坏主聊天流程。 -- EBA EventBus。 -- EBA EventRouter。 -- 消息撤回、群成员加入、好友申请等非消息事件的真实接入。 -- `action.requested` 平台动作执行。 -- 新平台 API 权限模型。 +本指南不验证: -上述非目标只允许检查协议预留是否存在,不允许作为 Phase 1 阻塞项。 +- Runtime Control Plane v2。 +- EventGateway / EventRouter 完整落地。 +- 发布级 path isolation、secret filtering、MCP allowlist、资源配额和 workspace cleanup。 +- 所有外部服务 runner 的真实凭据联调。 + +这些属于后续能力或发布门槛,分别见 [RUNTIME_CONTROL_PLANE_V2.md](./RUNTIME_CONTROL_PLANE_V2.md) 与 [SECURITY_HARDENING.md](./SECURITY_HARDENING.md)。 ## 2. 状态定义 -测试 agent 只能使用以下状态: +测试报告只使用以下状态: | 状态 | 含义 | | --- | --- | -| PASS | 按本矩阵步骤执行,所有通过条件满足,并记录证据。 | -| FAIL | 环境可用,但功能行为不满足通过条件。 | -| BLOCKED | 因缺少密钥、外部服务不可用、账号/OAuth 未完成、测试数据缺失等环境问题无法执行。必须写清阻塞原因。 | -| N/A | 当前插件或平台明确不支持该能力。必须引用 manifest capability、文档或配置说明。 | +| PASS | 按步骤执行,用户可见行为和日志证据都满足通过条件。 | +| FAIL | 环境可用,但行为不满足通过条件。 | +| BLOCKED | 凭据、CLI、外部服务、测试数据或本地配置缺失导致无法执行。必须写清阻塞原因。 | +| N/A | 当前 runner 或平台明确不支持该能力。必须引用 manifest、文档或配置说明。 | -不能使用“看起来正常”“大概通过”“未完全测试”等模糊状态。 +不能使用“看起来正常”“大概通过”“基本没问题”等模糊状态。 -## 3. 总体验收条件 +## 3. 执行顺序 -Phase 1 可以关闭的最低条件: +推荐按以下顺序执行,前一层失败时不要继续扩大测试面: -- 所有 P0 case 必须 PASS。 -- `local-agent` 的 P1 parity case 必须 PASS,除非该能力旧内置 runner 也不支持,此时可标 N/A。 -- 官方外部 runner smoke case 至少对已具备凭据和服务的插件 PASS;缺凭据的插件可标 BLOCKED,但必须保留配置页面截图或日志说明。 -- 没有会导致主聊天路径不可用、插件 runtime 崩溃、Pipeline 配置丢失、权限绕过的未解决 FAIL。 -- 所有 FAIL/BLOCKED 都必须记录复现步骤、日志位置、截图或请求/响应摘要。 +1. Host / SDK / runner 单测。 +2. WebUI 登录与 Pipeline Debug Chat 基础 smoke。 +3. `local-agent` 高价值场景。 +4. Claude Code / Codex 外部 harness smoke。 +5. 权限和错误路径补充检查。 +6. 汇总 PASS / FAIL / BLOCKED,并给出下一步建议。 -推荐测试前先运行: +用户可见流程必须通过 WebUI 或真实消息平台验证。API / curl 只能作为诊断证据,不能单独让 UI case PASS。 + +## 4. 必跑基线 + +### 4.1 单测基线 + +在 LangBot 仓库运行: ```bash uv run --frozen pytest tests/unit_tests/agent ``` -Host 侧 agent runner 单测不通过时,不应进入 UI parity QA。 +如果本次改动只触及默认配置或 API service,也至少补跑相关目标测试,例如: -## 4. 证据要求 +```bash +uv run pytest tests/unit_tests/api/test_pipeline_service_defaults.py +``` -每个 case 至少记录: +通过条件: + +- agent 单测全 PASS,或失败项已确认与本次 agent-runner 路径无关。 +- 若失败来自 `context_builder`、`orchestrator`、`session_registry`、`resource_builder`、`plugin/handler.py` 的 run action 权限路径,不应进入 UI smoke。 + +### 4.2 环境基线 + +用 `langbot-skills` 做环境检查: + +```bash +cd "$LANGBOT_SKILLS_REPO" +bin/lbs env doctor +bin/lbs case list +``` + +`LANGBOT_SKILLS_REPO` 指向当前工作区里的 `langbot-skills` 仓库。优先使用已有 case,而不是临时发明测试路径。 + +推荐首批 case: + +- `webui-login-state` +- `pipeline-debug-chat` +- `local-agent-basic-debug-chat` +- `local-agent-rag-debug-chat`(改动涉及 RAG / knowledge) +- `local-agent-plugin-tool-call-debug-chat`(改动涉及 tool / resource policy) + +## 5. WebUI 主链路 Smoke + +### 5.1 Runner registry + +步骤: + +1. 打开 WebUI Pipeline 配置页。 +2. 查看 AI runner 下拉列表。 +3. 选择 `plugin:langbot/local-agent/default`。 +4. 保存并刷新页面。 + +通过条件: + +- runner 选项来自插件 registry。 +- 保存后配置仍为 `ai.runner.id` + `ai.runner_config[id]`。 +- `runner_config` 表示 binding config,不表示插件实例状态。 +- 插件没有循环重启或 metadata 加载失败。 + +### 5.2 主聊天路径 + +步骤: + +1. 使用绑定 `plugin:langbot/local-agent/default` 的 Pipeline。 +2. 在 Debug Chat 发送确定性普通文本。 +3. 查看 WebUI 回复和后端日志。 + +通过条件: + +- 用户可见回复正常。 +- 后端日志显示走 `AgentRunOrchestrator` / `RUN_AGENT`。 +- 不走旧内置 local-agent 主执行分支。 +- conversation transcript 写入用户消息和助手消息。 + +## 6. `local-agent` 高价值测试 + +只保留最能覆盖架构边界的场景。 + +| ID | 场景 | 操作 | 通过条件 | +| --- | --- | --- | --- | +| LA-01 | 绑定 prompt | 配置 system prompt 后发送文本。 | runner 使用 `ctx.config.prompt`,不读取 `ctx.adapter.extra["prompt"]`;回复体现绑定 prompt。 | +| LA-02 | history API | 连续两轮对话,第二轮引用第一轮 marker。 | runner 通过 Host history API 或自管上下文读取历史,不依赖 bootstrap window。 | +| LA-03 | 流式 / 非流式 | 分别用支持流式和关闭流式的路径发送文本。 | 流式 UI 不重复、不空白;非流式只输出最终消息。 | +| LA-04 | 工具调用 | 绑定测试工具,发送会触发工具的 prompt。 | `ctx.resources.tools` 只包含授权工具;工具调用 started/completed;最终回复包含工具结果。 | +| LA-05 | RAG | 绑定测试知识库,发送命中文档的 prompt。 | `ctx.resources.knowledge_bases` 包含所选知识库;runner 通过授权 API 检索;回复使用检索内容。 | +| LA-06 | 多模态 | 发送图片输入。 | `ctx.input.contents` 保留图片;支持视觉模型时正常处理,不支持时受控失败。 | +| LA-07 | fallback / 错误 | 模拟 primary 模型失败或 runner 抛错。 | fallback 或 `run.failed` 行为受控;后续请求不受影响。 | +| LA-08 | 无输出保护 | 测试 runner 完成但不产出消息。 | 不产生空白成功回复;按受控失败或明确缺陷处理。 | + +Rerank、remove-think、文件输入等场景只在本次改动直接涉及时补测,不作为每轮必跑项。 + +## 7. 外部 Harness Runner Smoke + +这些测试用于验证 Claude Code / Codex 这类自管 runtime 能走同一条 Host 协议路径。若本机没有 CLI、登录态或代理配置,标记 BLOCKED,不要伪造 PASS。 + +### 7.1 Claude Code runner + +步骤: + +1. 确认 `claude` CLI 在 LangBot runtime host 上可执行。 +2. 绑定 `plugin:langbot/claude-code-agent/default`。 +3. 使用保守权限模式和确定性 prompt。 +4. 在 Debug Chat 执行一次真实 smoke。 +5. 检查 context / skill / MCP projection 和 host-owned state。 + +通过条件: + +- WebUI 可见回复包含预期 sentinel。 +- context JSON schema 为 `langbot.agent_runner.external_harness_context.v1` 或当前文档声明的等价 schema。 +- context 包含 event、input、delivery、resources、context、state。 +- 如启用 skills / MCP,投影路径和配置可被 Claude Code 读取。 +- `external.session_id` / `external.working_directory` 写入 host-owned state。 +- CLI missing、nonzero exit、timeout、empty output 都转成受控 `run.failed`。 + +### 7.2 Codex runner + +步骤: + +1. 确认 `codex` CLI 在 LangBot runtime host 上可执行。 +2. 绑定 `plugin:langbot/codex-agent/default`。 +3. 如需要代理,使用 binding config 的 `environment-json` 显式传入。 +4. 在 Debug Chat 执行一次真实 smoke。 +5. 检查 JSONL 事件、last message、host-owned state。 + +通过条件: + +- WebUI 可见回复包含预期 sentinel。 +- Codex JSONL 至少包含 thread/session 起始事件、agent message、turn completed。 +- `external.session_id` / `external.working_directory` 写入 host-owned state。 +- timeout/cancel 不遗留 orphan CLI 子进程。 +- CLI missing、nonzero exit、timeout、empty output 都转成受控 `run.failed`。 + +### 7.3 API 型外部 runner + +Dify、n8n、Coze、DashScope、Langflow、Tbox 等外部服务 runner 不作为每轮必跑项。只有在本次改动触及对应 runner 或凭据已经可用时执行 smoke。 + +通过条件: + +- runner 可选,配置可保存。 +- 请求成功,或外部服务错误被清晰返回。 +- 外部服务凭据缺失时标记 BLOCKED,并记录缺失项。 + +## 8. 权限与隔离补充 + +以下优先用单测 / targeted fixture 覆盖,不要求每次通过 UI 人工构造恶意 runner。 + +| 场景 | 推荐证据 | +| --- | --- | +| 未授权模型调用被拒绝 | `plugin/handler.py` run action 权限测试或目标单测。 | +| 未授权工具调用被拒绝 | `ctx.resources.tools` 与 host action 拒绝日志。 | +| 未授权知识库检索被拒绝 | `ctx.resources.knowledge_bases` 与 host action 拒绝日志。 | +| run_id 结束后复用被拒绝 | session registry 注销测试。 | +| 插件身份不匹配被拒绝 | `caller_plugin_identity` mismatch 测试。 | +| storage/state scope 越权被拒绝 | state/storage proxy 单测。 | + +如果这些单测失败,不能用 WebUI 正常回复替代。 + +## 9. 证据要求 + +每轮测试报告至少记录: - LangBot commit、SDK commit、相关 runner 插件 commit。 -- Pipeline UUID/name、runner id、runner config 摘要。 -- WebUI 截图或浏览器操作记录。 -- 后端日志中对应 query id/run id 的关键行。 -- 对外部 runner,记录外部服务响应摘要或错误码。 -- 对外部 harness runner,记录 context 文件、MCP/skill 投影、外部 session id / working directory state 和 CLI 错误摘要。 +- Pipeline UUID/name、runner id、关键 runner config 摘要。 +- WebUI 截图或 Playwright 操作记录。 +- 后端日志中对应 query id / run id 的关键行。 +- `langbot-skills` case/report 路径。 +- 外部 harness runner 的 context 文件、session id、working directory、CLI 错误摘要。 +- FAIL/BLOCKED 的复现步骤和归属仓库建议。 -用户可见流程必须通过 WebUI 或真实消息平台验证。API/curl 只能作为诊断证据,不能单独让 UI case PASS。 +报告结论必须回答: -## 5. P0 环境与主链路 +- 是否建议继续进入下一阶段测试。 +- 是否存在主聊天路径阻塞。 +- 是否只是凭据 / 外部服务 / 本机 CLI 缺失导致 BLOCKED。 +- 是否需要进入 [SECURITY_HARDENING.md](./SECURITY_HARDENING.md) 的发布级验收。 -| ID | 场景 | 步骤 | 通过条件 | -| --- | --- | --- | --- | -| P0-ENV-01 | LangBot 服务可用 | 启动后端和前端,打开 WebUI。 | WebUI 可登录/访问;后端无启动异常;插件系统按配置启用。 | -| P0-ENV-02 | 插件 runtime 可用 | 查看插件列表或后端日志。 | runtime 已启动;官方 runner 插件处于可用状态;无循环重启。 | -| P0-ENV-03 | Runner registry 可发现插件 runner | 打开 Pipeline AI runner 配置。 | runner 下拉列表来自插件 registry;至少能看到 `plugin:langbot/local-agent/default`;若安装了 Claude Code runner,还应看到 `plugin:langbot/claude-code-agent/default`。 | -| P0-ENV-04 | 默认 Pipeline 可创建 | 新建 Pipeline 或读取默认 Pipeline。 | 默认配置使用 `ai.runner.id` 与 `ai.runner_config`;默认 runner 可保存。 | -| P0-ENV-05 | 主聊天路径调用插件 runner | 使用默认 `local-agent` Pipeline 发送一条普通消息。 | 后端日志显示走 `AgentRunOrchestrator` / `RUN_AGENT`;用户收到正常回复;旧内置 runner 不应作为主路径执行。 | -| P0-ENV-06 | 单测基线 | 运行 `uv run --frozen pytest tests/unit_tests/agent`。 | 全部通过;若失败,必须先修复或记录为 P0 FAIL。 | +## 10. 历史高价值记录 -## 6. P1 local-agent parity +历史报告已合并为本指南,不再保留单独文档。后续若需要追溯,优先查看 `langbot-skills/reports/` 下的原始执行报告。 -`local-agent` 是 Phase 1 的主验收对象。以下 case 需要和旧内置 local-agent 的用户可见行为对齐。 +截至 2026-05-29,已有本地 smoke 证明: -| ID | 场景 | 步骤 | 通过条件 | -| --- | --- | --- | --- | -| P1-LA-01 | 普通文本对话 | 绑定 `plugin:langbot/local-agent/default`,发送普通文本。 | 回复正常生成;conversation history 写入用户消息和助手消息。 | -| P1-LA-02 | 有效 prompt | 配置 system prompt,并通过 PromptPreProcessing 插件或现有预处理改变 prompt。 | runner 使用 host 处理后的 `ctx.adapter.extra["prompt"]`,不是只读取静态 `ctx.config.prompt`;回复体现有效 prompt。 | -| P1-LA-03 | 历史消息 | 连续多轮对话,第二轮引用第一轮内容。 | 当前兼容路径下 runner 能读到 host 下发的 bootstrap/history;目标协议下应通过 history API 或插件自管上下文实现。第二轮能基于上下文回答。 | -| P1-LA-04 | 流式输出 | 使用支持流式的 adapter/WebUI,开启流式模型或流式 runner。 | UI 逐步更新;后端接收 `message.delta`;最终没有重复消息或空白卡片。 | -| P1-LA-05 | 非流式输出 | 使用不支持流式或关闭流式的路径。 | 只输出最终消息;不会创建异常流式卡片。 | -| P1-LA-06 | 工具调用 | 绑定一个可调用工具,提问触发工具。 | `ctx.resources.tools` 只包含授权工具;runner 能获取工具详情并调用;最终回复包含工具结果。 | -| P1-LA-07 | 工具权限裁剪 | 不绑定某工具,但让 runner 尝试调用。 | 调用被拒绝;错误不泄露未授权工具详情;Pipeline 不崩溃。 | -| P1-LA-08 | RAG 检索 | 绑定知识库并提问命中文档。 | `ctx.resources.knowledge_bases` 包含所选知识库;runner 可检索;回复引用或使用检索内容。 | -| P1-LA-09 | RAG 权限裁剪 | 不绑定知识库或绑定另一个知识库。 | 未授权知识库不可检索;错误可控。 | -| P1-LA-10 | rerank | 绑定 rerank 模型并启用知识库检索排序。 | runner 可通过授权 rerank 模型排序;无权限时不允许调用。 | -| P1-LA-11 | fallback model | 配置 primary 和 fallback,模拟 primary 失败。 | fallback 被调用;用户得到可用回复或明确失败提示;日志能区分 primary/fallback。 | -| P1-LA-12 | remove-think | 开启输出 `remove-think`,使用会产生 think 内容的模型。 | 用户最终回复不包含被移除的 think 内容;插件 runner 走 runtime metadata 或 API 参数保持旧行为。 | -| P1-LA-13 | 多模态图片 | 发送图片输入。 | `ctx.input.contents` / `ctx.input.attachments` 保留图片;支持视觉模型时可正常处理;不支持时错误提示可控。 | -| P1-LA-14 | 文件输入 | 发送文件或文件 URL。 | runner 可看到文件 attachment 摘要;支持文件处理时正常处理;不支持时不崩溃。 | -| P1-LA-15 | 会话状态 | runner 返回 `state.updated`,下一轮继续对话。 | state 被 host 接收并作用于下一轮;conversation id 等兼容旧行为。 | -| P1-LA-16 | 异常处理 | 让 runner 返回 `run.failed` 或抛异常。 | ChatMessageHandler 使用 Pipeline 的异常策略;用户提示符合配置;runtime 和后续请求不受影响。 | -| P1-LA-17 | 无输出保护 | runner 完成但不返回消息。 | 不产生空白成功回复;应按受控失败处理或明确记录缺陷。 | +- `local-agent` 可以通过 Pipeline Debug Chat 走插件化 `AgentRunOrchestrator` 主链路。 +- Claude Code runner 可以通过同一条 `run(event, binding)` 路径执行。 +- Claude Code runner 可以读取 LangBot event-first context / skill / MCP 投影,并写回 `external.session_id` / `external.working_directory`。 +- Codex runner 可以通过同一条路径执行,并把 Codex `thread_id` 写回 host-owned state。 -## 7. P1 配置兼容与迁移 - -| ID | 场景 | 步骤 | 通过条件 | -| --- | --- | --- | --- | -| P1-CFG-01 | 读取旧配置 | 使用只包含 `ai.runner.runner = local-agent` 和旧 `ai.local-agent` 配置的 Pipeline。 | 能解析为 `plugin:langbot/local-agent/default`;旧配置值生效。 | -| P1-CFG-02 | 保存新配置 | 在 WebUI 修改 runner 和 runner config 后保存。 | 数据库存储 `ai.runner.id` 和 `ai.runner_config[id]`;刷新页面后不丢失。 | -| P1-CFG-03 | runner 切换 | 同一 Pipeline 从 local-agent 切到另一个官方 runner,再切回。 | 每个 runner 的绑定配置独立保存;切换不污染其它 runner config。 | -| P1-CFG-04 | 插件缺失 | 配置引用一个未安装或未启动的 runner。 | WebUI/后端给出可理解错误;Pipeline 不因 metadata 加载失败整体不可用。 | -| P1-CFG-05 | bound plugin 授权 | Pipeline 只绑定部分插件。 | 未绑定插件的 runner 不能执行;已绑定插件正常执行。 | - -## 8. P1 权限与隔离 - -| ID | 场景 | 步骤 | 通过条件 | -| --- | --- | --- | --- | -| P1-AUTH-01 | 模型权限 | runner 尝试调用不在 `ctx.resources.models` 的模型。 | Host action 拒绝;错误包含 run/session 维度信息;不会调用实际模型。 | -| P1-AUTH-02 | 工具权限 | runner 尝试调用不在 `ctx.resources.tools` 的工具。 | Host action 拒绝;不会越权执行工具。 | -| P1-AUTH-03 | 知识库权限 | runner 尝试检索不在 `ctx.resources.knowledge_bases` 的知识库。 | Host action 拒绝;不会返回未授权知识库内容。 | -| P1-AUTH-04 | 存储权限 | manifest 未声明 storage 权限时访问 plugin/workspace storage。 | 访问被拒绝;普通插件非 AgentRunner 的兼容路径不受影响。 | -| P1-AUTH-05 | run_id 生命周期 | runner 结束后继续使用旧 run_id 调 host action。 | session 已注销;请求被拒绝。 | -| P1-AUTH-06 | 插件身份隔离 | A 插件 runner 的 run_id 被 B 插件使用。 | Host 拒绝 identity mismatch。 | - -## 9. P2 官方外部 runner smoke - -以下 case 是 smoke,不要求和 local-agent 一样覆盖全部能力。若缺少外部服务凭据,状态标 BLOCKED,并记录缺失项。 - -| ID | Runner | 步骤 | 通过条件 | -| --- | --- | --- | --- | -| P2-EXT-01 | `dify-agent` | 配置 chat/agent/workflow 中至少一种可用应用并发送消息。 | runner 可选、配置可保存、请求成功或外部服务错误被清晰返回。 | -| P2-EXT-02 | `n8n-agent` | 配置 webhook 和认证方式并发送消息。 | webhook 被调用;返回内容进入 LangBot 回复;认证失败时提示明确。 | -| P2-EXT-03 | `coze-agent` | 配置 Coze 应用并发送文本,若可用再测图片。 | 文本回复正常;多模态能力按 manifest/配置表现;思维链处理不污染最终回复。 | -| P2-EXT-04 | `dashscope-agent` | 配置 agent 或 workflow 并发送消息。 | 调用成功;失败时错误可控且不影响后续请求。 | -| P2-EXT-05 | `langflow-agent` | 配置 flow endpoint 并发送消息。 | 普通或 SSE 流式响应能归一为 LangBot 消息。 | -| P2-EXT-06 | `tbox-agent` | 配置 Tbox 应用并发送消息。 | 回复正常;多模态输入按插件能力处理。 | -| P2-EXT-07 | `claude-code-agent` | 配置本地 Claude Code CLI,使用保守权限模式发送确定性 Debug Chat prompt。 | runner 可选、配置可保存、CLI 成功返回;LangBot context 文件可被 Claude Code 读取;`external.session_id` / `external.working_directory` 可写入 host-owned state;CLI 错误、timeout、空输出能被转成受控 `run.failed`。 | -| P2-EXT-08 | `codex-agent` | 配置本地 Codex CLI,使用 Debug Chat 发送确定性 prompt。 | runner 可选、配置可保存、CLI 成功返回;LangBot context 文件可被 Codex 读取;`external.session_id` / `external.working_directory` 可写入 host-owned state;代理等 runtime-local 环境可通过 binding config 显式传入;CLI 错误、timeout、空输出能被转成受控 `run.failed`。 | - -### 9.1 外部 harness runner 追加检查 - -对 Claude Code / Codex / Kimi Code 这类 runner,P2 smoke 还需要检查: - -- 默认不要求 LangBot 调用自己的模型/工具 loop;runner 可以依赖自身 harness。 -- LangBot 仍要把当前 event、input、delivery、resources、context 和 state 作为 scoped context 传给 runner。 -- skill / MCP / workspace projection 必须来自 binding 或 Host 授权后的资源,不应让 runner 自行读取全局未授权配置。 -- session id、working directory、checkpoint 等跨轮次状态必须进入 Host state 或 plugin storage,不能保存在插件实例内存中。 -- 发布级 path isolation、secret filtering、MCP allowlist、资源配额和 workspace cleanup 只作为 [SECURITY_HARDENING.md](./SECURITY_HARDENING.md) 的后续 release gate,不阻塞当前 smoke。 - -## 10. P2 事件预留检查 - -这些只检查协议预留,不要求真实平台事件接入。 - -| ID | 场景 | 步骤 | 通过条件 | -| --- | --- | --- | --- | -| P2-EVT-01 | 消息事件名稳定 | 触发普通消息 runner。 | `ctx.trigger.type` 和 `ctx.event.event_type` 为 `message.received`;平台原始类型保存在 `ctx.event.event_data.source_event_type`。 | -| P2-EVT-02 | 非消息事件名预留 | 检查 host 侧保留事件名。 | `message.recalled`、`group.member_joined`、`friend.request_received` 作为稳定协议名存在。 | -| P2-EVT-03 | action.requested 预留 | 让测试 runner 返回 `action.requested`。 | Host 只记录日志,不执行平台动作,不影响主流程。 | - -## 11. 退出标准 - -QA agent 完成后应输出一份报告,至少包含: - -- 总状态:PASS / FAIL / BLOCKED。 -- 每个 case 的状态表。 -- 所有 FAIL 的复现步骤和建议归属仓库。 -- 所有 BLOCKED 的环境缺口。 -- 是否建议关闭 Phase 1,进入 Phase 2/EBA。 - -建议关闭 Phase 1 的条件: - -- P0 全 PASS。 -- P1 全 PASS,或只有旧内置 runner 同样不支持的 N/A。 -- P2 外部 runner smoke 对可用凭据全部 PASS;本地 Claude Code runner 若作为当前 external harness 代表,应至少 PASS 一次 WebUI smoke。 -- 剩余问题均为 EBA 预留、外部服务凭据、或非阻塞体验问题。 - -## 12. 当前已知验收记录 - -2026-05-29 本地记录: - -| 范围 | 状态 | 证据 | -| --- | --- | --- | -| `local-agent` WebUI Debug Chat | PASS | `langbot-skills/reports/2026-05-29-17-59-00-462-08-00-pipeline-debug-chat.md` | -| `claude-code-agent` WebUI Debug Chat | PASS | `langbot-skills/reports/2026-05-29-18-03-31-169-08-00-pipeline-debug-chat.md` | -| Claude Code context / skill / MCP projection | PASS | `langbot-skills/reports/claude-code-agent-resource-context-20260529.md` | -| Claude Code resume state | PASS | `langbot-skills/reports/claude-code-agent-real-workdir-20260529.md` | - -完整汇总见 [PHASE1_QA_REPORT_2026-05-29.md](./PHASE1_QA_REPORT_2026-05-29.md)。 +这些记录只证明本地协议闭环可用,不代表发布级 security hardening 已完成。 diff --git a/docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-18.md b/docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-18.md deleted file mode 100644 index dae8e838..00000000 --- a/docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-18.md +++ /dev/null @@ -1,103 +0,0 @@ -# Agent Runner Pluginization Phase 1 QA Report - -Date: 2026-05-18 - -## Environment - -- LangBot repo: `/home/glwuy/langbot-app/LangBot` -- LangBot branch/commit: `feat/agent-runner-plugin` / `036affe0` -- SDK repo commit: `/home/glwuy/langbot-app/sdk` / `feed530` -- langbot-skills commit: `/home/glwuy/langbot-app/langbot-skills` / `a82f006` -- Backend: `http://127.0.0.1:5300`, started from the `LangBot` worktree -- Frontend: `http://127.0.0.1:3000`, started from `LangBot/web` -- Pipeline: `565ec946-01a6-496d-8b8c-056a4eab7f4d` / `测试` -- Runner: `plugin:langbot/local-agent/default` -- Runner config summary: primary model configured, knowledge base `qa-local-agent-rag-20260516` bound, rerank disabled -- Installed runner plugins observed: `langbot/local-agent`, `langbot/dify-agent` -- Supporting plugins observed: `qa/plugin-smoke`, `langbot-team/LangRAG` - -Evidence files: - -- `/home/glwuy/langbot-app/phase1-runner-config.png` -- `/home/glwuy/langbot-app/phase1-local-agent-debug-chat.png` -- `/home/glwuy/langbot-app/phase1-console.log` -- Backend log: `/home/glwuy/langbot-app/LangBot/data/logs/langbot-2026-05-18.log` - -## Automated Checks - -| Check | Status | Evidence | -| --- | --- | --- | -| `uv run --frozen pytest tests/unit_tests/agent` | PASS | `241 passed, 16 warnings` | -| `uv run --frozen pytest tests/unit_tests/agent/test_handler_auth.py tests/unit_tests/agent/test_orchestrator_integration.py tests/unit_tests/agent/test_result_normalizer.py` | PASS | `96 passed, 11 warnings` | -| `langbot-skills` local env/tooling regression | PASS | `npm test`: `7 passed`; `bin/lbs validate`: `OK` | - -## UI Cases Executed - -| Matrix ID | Status | Evidence | -| --- | --- | --- | -| P0-ENV-01 | PASS | WebUI opened at `http://127.0.0.1:3000/home/pipelines`; backend responded on `5300`. | -| P0-ENV-02 | PASS | Logs show plugin runtime connected and plugins initialized without restart loop. | -| P0-ENV-03 | PASS | Pipeline AI runner UI and metadata show `plugin:langbot/local-agent/default` and `plugin:langbot/dify-agent/default`. | -| P0-ENV-04 | PASS | Existing default-style pipeline uses `ai.runner.id` and `ai.runner_config`; config page loaded and displayed runner config. | -| P0-ENV-05 | PASS | Debug Chat message returned `PHASE1_LOCAL_AGENT_PLAIN_OK`; logs show `[Action] run_agent`. | -| P0-ENV-06 | PASS | Agent unit baseline passed. | -| P1-LA-01 | PASS | Plain text Debug Chat returned `PHASE1_LOCAL_AGENT_PLAIN_OK`. | -| P1-LA-02 | PASS | Sending `qa-effective-prompt` returned `PROMPT_PREPROCESS_OK`. | -| P1-LA-03 | PASS | Second turn referenced the first marker and returned `PHASE1_LOCAL_AGENT_PLAIN_OK`. | -| P1-LA-04 | PASS | Stream mode enabled; UI showed bot response and logs reported streaming completion. | -| P1-LA-05 | PASS | Stream mode disabled; UI returned `PHASE1_LOCAL_AGENT_NONSTREAM_OK` without a blank/duplicate card. | -| P1-LA-06 | PASS | Prompt triggered tool call; logs show tool call started/completed for `qa_echo`; UI returned `qa-plugin-smoke:PHASE1_TOOL_CALL_OK`. | -| P1-LA-08 | PASS | Bound LangRAG KB retrieval returned sentinel `azalea-cobalt-7421`; logs show `retrieve_knowledge`. | -| P1-LA-13 | PASS | Uploaded 64x64 red-square fixture; UI returned `RED_IMAGE_OK`. | - -## Unit Or Protocol Covered Cases - -| Matrix ID | Status | Evidence | -| --- | --- | --- | -| P1-AUTH-01 | PASS | `test_handler_auth.py` covers unauthorized model rejection. | -| P1-AUTH-02 | PASS | `test_handler_auth.py` covers unauthorized tool rejection. | -| P1-AUTH-03 | PASS | `test_handler_auth.py` covers unauthorized knowledge-base rejection. | -| P1-AUTH-04 | PASS | `test_handler_auth.py` covers storage permission validation. | -| P1-AUTH-05 | PASS | `test_handler_auth.py` covers session expiry and unregister behavior. | -| P1-AUTH-06 | PASS | `test_handler_auth.py` covers caller plugin identity mismatch. | -| P1-LA-15 | PASS | `test_orchestrator_integration.py` covers `state.updated` handling. | -| P1-LA-16 | PASS | `test_orchestrator_integration.py` and `test_result_normalizer.py` cover `run.failed`. | -| P1-LA-17 | PASS | `test_result_normalizer.py` covers `run.completed` without message. | -| P1-CFG-01 | PASS | Config migration unit tests in the full agent suite passed. | -| P1-CFG-04 | PASS | Chat handler unit tests cover runner-not-found controlled errors. | -| P1-CFG-05 | PASS | Authorization unit tests cover bound resource restrictions. | -| P2-EVT-01 | PASS | `test_orchestrator_integration.py` asserts `message.received`. | -| P2-EVT-02 | PASS | `src/langbot/pkg/agent/runner/events.py` defines reserved event names. | -| P2-EVT-03 | PASS | `test_result_normalizer.py` covers `action.requested` as log-only/no execution. | - -## Blocked Or N/A - -| Matrix ID | Status | Reason | -| --- | --- | --- | -| P1-LA-07 | BLOCKED | Needs a dedicated restricted-pipeline or malicious-runner fixture to force an unauthorized tool call through the runner. Unit-level authorization passes. | -| P1-LA-09 | BLOCKED | Needs a dedicated restricted-pipeline or malicious-runner fixture to force unauthorized KB access. Unit-level authorization passes. | -| P1-LA-10 | BLOCKED | No rerank model configured for this environment. | -| P1-LA-11 | BLOCKED | Primary/fallback failure injection was not configured for this run. | -| P1-LA-12 | BLOCKED | No known think-output model/path configured for this run. | -| P1-LA-14 | N/A | Debug Chat UI exposes image upload but no generic file upload control in this run. | -| P1-CFG-03 | BLOCKED | Runner switching to an external runner requires a usable external runner config; only Dify is discoverable and no Dify credentials are configured. | -| P2-EXT-01 | BLOCKED | Dify runner is discoverable, but no Dify API key/app config is available. | -| P2-EXT-02 | N/A | `n8n-agent` runner is not discoverable in metadata. | -| P2-EXT-03 | N/A | `coze-agent` runner is not discoverable in metadata. | -| P2-EXT-04 | N/A | `dashscope-agent` runner is not discoverable in metadata. | -| P2-EXT-05 | N/A | `langflow-agent` runner is not discoverable in metadata. | -| P2-EXT-06 | N/A | `tbox-agent` runner is not discoverable in metadata. | - -## Notes - -- The current environment is strong enough to validate the main pluginized local-agent path: WebUI, runner registry, prompt preprocessing, history, streaming, non-streaming, tool calls, LangRAG retrieval, image input, and host-side authorization/unit protocol behavior all passed. -- External runner smoke cannot close without credentials or installed runner plugins beyond Dify. -- Console capture contains stale errors from earlier service restarts and diagnostic cross-origin fetch attempts. During the executed Debug Chat flows, the UI completed normally and the backend processed all tested queries. -- `langbot-skills` now supports machine-local `skills/.env.local` overrides, so local worktree/port changes do not need to modify shared `skills/.env`. - -## Recommendation - -Do not mark the whole Phase 1 matrix fully closed yet. It is reasonable to treat the local-agent Phase 1 core path as PASS, but Phase 1 closure still needs either: - -- explicit acceptance that authorization/error/state cases are covered by unit/protocol tests rather than UI malicious-runner fixtures, and -- external runner credentials or a decision to keep external runner smoke BLOCKED by environment. diff --git a/docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-29.md b/docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-29.md deleted file mode 100644 index abf80395..00000000 --- a/docs/agent-runner-pluginization/PHASE1_QA_REPORT_2026-05-29.md +++ /dev/null @@ -1,103 +0,0 @@ -# Agent Runner Phase 1 QA Report - 2026-05-29 - -本文档记录 2026-05-29 对 agent-runner plugin 协议闭环的本地验收。它不改写 -[PHASE1_QA_REPORT_2026-05-18.md](./PHASE1_QA_REPORT_2026-05-18.md) 的历史结论。 - -## 1. 验收结论 - -当前分支可以认为完成了本地协议闭环 smoke: - -- `local-agent` 插件可以通过 Pipeline Debug Chat 走插件化 `AgentRunOrchestrator` 主链路。 -- `claude-code-agent` 可以作为外部 harness runner 通过同一条 `run(event, binding)` 路径执行。 -- Claude Code runner 可以接收 LangBot event-first context,并把 context / skill / MCP 配置投影给本地 Claude Code CLI。 -- Claude Code runner 可以把外部 session id 和 working directory 写回 LangBot host-owned state,用于后续 resume。 -- `codex-agent` 可以作为外部 harness runner 通过同一条 `run(event, binding)` 路径执行,并把 Codex `thread_id` 写回 host-owned state。 - -这表示当前架构足以支撑 `local-agent`、最小 Claude Code runner 与最小 Codex runner 的联调;不表示安全发布级 hardening 已完成。 - -## 2. 环境 - -| 项 | 值 | -| --- | --- | -| LangBot commit | `58e4b357` | -| `langbot-agent-runner` commit | `d681dda` | -| `langbot-local-agent` commit | `573cc00` | -| Claude Code CLI | `2.1.137 (Claude Code)` | -| Frontend | `http://127.0.0.1:3000` | -| Backend | `http://127.0.0.1:5300` | - -## 3. Pipeline 与 Runner - -| Runner | Pipeline | Runner ID | 结果 | -| --- | --- | --- | --- | -| local-agent | `dc75c543-70f9-4d2a-9467-968628e6ca01` | `plugin:langbot/local-agent/default` | PASS | -| Claude Code | `f5c6d8e0-0c5a-4f3f-b7d4-0c1a0dec0de1` | `plugin:langbot/claude-code-agent/default` | PASS | -| Codex | `57eb0cc8-5a5a-4865-9f3e-8b3ad070fbc2` | `plugin:langbot/codex-agent/default` | PASS | - -## 4. 证据 - -### 4.1 local-agent UI E2E - -- 报告:`/home/glwuy/langbot-app/langbot-skills/reports/2026-05-29-17-59-00-462-08-00-pipeline-debug-chat.md` -- 后端日志成功信号: - - `Processing request from person_websocket` - - `Conversation(1) Streaming completed: 1 chunks, 2 chars` -- 验收点:Debug Chat 用户可见回复正常,后台 log guard 未发现失败信号。 - -### 4.2 Claude Code runner UI E2E - -- 报告:`/home/glwuy/langbot-app/langbot-skills/reports/2026-05-29-18-03-31-169-08-00-pipeline-debug-chat.md` -- 后端日志成功信号: - - `Processing request from person_websocket` - - `Conversation(3) Streaming completed: 1 chunks, 22 chars` -- 验收点:Debug Chat 用户可见回复 `LANGBOT_CLAUDE_E2E_OK2`。 - -### 4.3 Claude Code context / skill / MCP projection - -- 报告:`/home/glwuy/langbot-app/langbot-skills/reports/claude-code-agent-resource-context-20260529.md` -- 通过点: - - 生成的 context JSON schema 为 `langbot.agent_runner.external_harness_context.v1`。 - - context JSON 包含 `event`、`actor`、`delivery`、`input`、`resources`、`context` 和 `state`。 - - Claude Code 可读取 LangBot 注入的 context 文件并输出 `LANGBOT_CLAUDE_CONTEXT_RESOURCE_OK`。 - - skill 文件投影到 `.claude/skills/langbot-e2e-context/SKILL.md`。 - -### 4.4 Claude Code resume state - -- 报告:`/home/glwuy/langbot-app/langbot-skills/reports/claude-code-agent-real-workdir-20260529.md` -- 通过点: - - `agent_runner_state` 中记录了 `external.session_id`。 - - `agent_runner_state` 中记录了 `external.working_directory`。 - - 使用保存的 session id 在对应工作目录执行 Claude Code resume 成功。 - -### 4.5 Codex runner UI E2E - -- 报告:`/home/glwuy/langbot-app/langbot-skills/reports/codex-agent-real-20260529-fifth.md` -- 截图:`/home/glwuy/langbot-app/langbot-skills/reports/evidence/codex-agent-real-20260529-fifth/screenshot.png` -- 后端日志成功信号: - - `Processing request from person_websocket` - - `Conversation(0) Streaming completed: 1 chunks, 21 chars` -- Codex JSONL 事件: - - `thread.started` - - `item.completed` with `agent_message` - - `turn.completed` -- 通过点: - - Debug Chat 用户可见回复 `LANGBOT_CODEX_E2E_OK5`。 - - `agent_runner_state` 中记录了 `external.session_id` 和 `external.working_directory`。 - - `environment-json` 可以显式传入代理环境,避免插件 worker 环境缺失导致本地 Codex CLI 卡住。 - - timeout/cancel 路径会清理 Codex 子进程,避免 orphan `codex exec`。 - -## 5. 当前未关闭项 - -以下不应作为当前协议闭环的阻塞项: - -- 发布级安全 hardening:见 [SECURITY_HARDENING.md](./SECURITY_HARDENING.md)。 -- 完整 EBA 分支联调和 EventGateway 迁移。 -- 完整异步队列、issue-centric 产品模型和复杂 workflow engine。 -- Codex 发布级能力 / Kimi runner 全量接入。 - -## 6. 建议状态 - -- 本地 `local-agent` 协议闭环:PASS。 -- 本地 Claude Code external harness smoke:PASS。 -- 本地 Codex external harness smoke:PASS。 -- Phase 1 是否整体关闭:可以关闭本地协议闭环;若定义为所有官方外部服务 runner 都必须有真实凭据,则外部服务 runner 仍按凭据可用性分别 PASS / BLOCKED。 diff --git a/docs/agent-runner-pluginization/PROGRESS.md b/docs/agent-runner-pluginization/PROGRESS.md index 37b0e745..cf57441e 100644 --- a/docs/agent-runner-pluginization/PROGRESS.md +++ b/docs/agent-runner-pluginization/PROGRESS.md @@ -151,8 +151,7 @@ ## 相关文档 - [README.md](./README.md) — 总体设计 -- [PHASE1_QA_ACCEPTANCE_MATRIX.md](./PHASE1_QA_ACCEPTANCE_MATRIX.md) — Phase 1 agent QA 验收矩阵 -- [PHASE1_QA_REPORT_2026-05-29.md](./PHASE1_QA_REPORT_2026-05-29.md) — 2026-05-29 本地 smoke 验收记录 +- [PHASE1_QA_ACCEPTANCE_MATRIX.md](./PHASE1_QA_ACCEPTANCE_MATRIX.md) — Agent Runner QA 指南和下一轮测试入口 - [OFFICIAL_RUNNER_PLUGINS.md](./OFFICIAL_RUNNER_PLUGINS.md) — 官方插件仓库计划 - [SECURITY_HARDENING.md](./SECURITY_HARDENING.md) — 安全发布级 hardening 后续门槛 - [IMPLEMENTATION_PLAN.md](./IMPLEMENTATION_PLAN.md) — 具体实施细节 diff --git a/docs/agent-runner-pluginization/PROTOCOL_V1.md b/docs/agent-runner-pluginization/PROTOCOL_V1.md index 09dea23c..6608a088 100644 --- a/docs/agent-runner-pluginization/PROTOCOL_V1.md +++ b/docs/agent-runner-pluginization/PROTOCOL_V1.md @@ -11,7 +11,7 @@ - ✅ Host 支持 `run_id` session authorization - ✅ Host 能从当前 Pipeline 入口生成 event-first context - ✅ `messages` 降级为 optional bootstrap -- ✅ `max-round` 不出现在协议实体中(只在 Pipeline adapter 中处理) +- ✅ `max-round` 不出现在协议实体中;类似历史窗口参数若存在,应来自 runner manifest/config schema,并作为 binding config 进入 `ctx.config` - ✅ Proxy 覆盖 model、tool、knowledge、state/storage - ✅ History / Event / Artifact / State API 已落地 - ✅ EventLog / Transcript / ArtifactStore / PersistentStateStore 已落地 @@ -147,7 +147,7 @@ Host 使用该声明决定是否给 runner inline bootstrap history。默认原 - Host 默认只 inline 当前 event / input 和 context handles。 - Runner 拥有 working context assembly。 - Runner 可在授权后通过 Host history / event / artifact / state APIs 拉取更多上下文。 -- `max-round` 不属于 Protocol v1 字段。 +- `max-round` 不属于 Protocol v1 字段,也不属于 Pipeline / Host 通用语义。 ## 4. Run 协议 @@ -344,7 +344,7 @@ class BootstrapContext(BaseModel): - `bootstrap.messages` 是 host convenience,不是协议核心。 - 自管 context runner 默认应收到空 bootstrap 或只收到当前 event。 - Host 不应为了”帮 agent 更聪明”而自动拼接完整 transcript。 -- Pipeline adapter 的 `max-round` 配置只影响 adapter 如何生成 `bootstrap.messages`,不能成为 Protocol v1 字段。 +- 类似历史窗口策略应由具体 runner 的 binding config 表达;new/official runners 不应依赖 Pipeline adapter 下发的 bootstrap window。 ### 4.10 RuntimeContext @@ -638,7 +638,7 @@ Protocol v1 的安全边界在 Host: - Host 在调用前完成 binding/resource policy 裁剪、路径策略、secret 过滤和审计记录。 - Runner plugin 把授权后的 context/resource projection 适配为目标 harness 的 context 文件、MCP 配置、skill 目录、环境变量或 CLI 参数。 -- Claude Code / Codex / Kimi Code 等外部 harness 的 native permission mode、allowed/disallowed tools 和 sandbox 只是额外执行约束,不能替代 Host 侧授权。 +- Claude Code / Codex / Kimi Code 等外部 harness 的 native permission mode、allowed/disallowed tools 和执行隔离策略只是额外执行约束,不能替代 Host 侧授权。 - 外部 session id、working directory、checkpoint 等跨轮次指针应作为小型 JSON state 保存,例如 `external.session_id`、`external.working_directory`。 完整路径隔离、MCP allowlist、secret redaction、配额、workspace 清理和发布级安全测试不属于当前 Protocol v1 smoke 闭环,详见 [SECURITY_HARDENING.md](./SECURITY_HARDENING.md)。 @@ -662,15 +662,15 @@ Pipeline 是当前入口 adapter,不是协议中心。 - ✅ `PipelineAdapter.query_to_event(query)` — 从 `Query` 构造 `AgentEventEnvelope` - ✅ `PipelineAdapter.pipeline_config_to_binding(query, runner_id)` — 从 Pipeline config 构造临时 AgentBinding - ✅ `run_from_query()` 委托到 `run(event, binding)` -- ✅ `max-round` 在 Pipeline adapter 中处理,不进入协议实体 +- ✅ runner-specific config 从 Pipeline 当前绑定配置透传到 `AgentBinding.runner_config` / `ctx.config` - ✅ Query-only 字段放入 `adapter` context Pipeline adapter 负责: - 从 `Query` 构造 `AgentEventContext`。 - 从 Pipeline config 构造临时 AgentBinding。 -- 从旧 runner config 构造 `ctx.config`。 -- 将 `max-round` 转换为 `bootstrap` policy。 +- 从当前 runner binding config 构造 `ctx.config`。 +- 保留必要的 legacy adapter metadata,但不定义历史窗口、prompt 组装或 agentic context 策略。 - 将 Query-only 字段放入 `adapter`。 Runner 不应长期依赖 `adapter`。新 runner 应只依赖 event-first context 和 Host APIs。 @@ -684,7 +684,7 @@ Protocol v1 已在当前分支完成: - ✅ Host 支持 `run_id` session authorization - ✅ Host 能从当前 Pipeline 入口生成 event-first context - ✅ `messages` 降级为 optional bootstrap -- ✅ `max-round` 不出现在协议实体中 +- ✅ `max-round` 不出现在协议实体中;类似参数属于具体 runner binding config - ✅ Proxy 至少覆盖 model、tool、knowledge、state/storage - ✅ History / event / artifact API 已落地 - ✅ EventLog / Transcript / ArtifactStore / PersistentStateStore 已落地 diff --git a/docs/agent-runner-pluginization/README.md b/docs/agent-runner-pluginization/README.md index e8b3604c..2359ba9b 100644 --- a/docs/agent-runner-pluginization/README.md +++ b/docs/agent-runner-pluginization/README.md @@ -24,6 +24,7 @@ - **Event subscription / Event notification**:事件订阅、推送通知 - **BindingResolver persistence UI**:绑定配置的持久化 UI 和 event router 集成(如由其他模块负责) - **Scheduler / Background event source**:定时任务、后台事件源 +- **Runtime control plane v2**:runtime registry、heartbeat、task queue、daemon claim、progress/cancel 和 runtime audit EventGateway 在本文档中描述为 **future integration point**,由外部 event branch 提供。本分支只定义 host-side envelope/binding models 和 `run(event, binding)` orchestrator 入口。 @@ -51,11 +52,11 @@ Pipeline path 已获得 event-first host capabilities: | [HOST_SDK_INFRASTRUCTURE.md](./HOST_SDK_INFRASTRUCTURE.md) | LangBot 宿主能力、SDK 协议、runner 发现、绑定、权限、状态、存储、生命周期和调用链。 | | [AGENT_CONTEXT_PROTOCOL.md](./AGENT_CONTEXT_PROTOCOL.md) | Agent-owned context 方向:事件到来时 LangBot 传什么,agent 如何按需拉取更多历史 / artifact / state,以及如何支持 KV cache 友好的上下文管理。 | | [EVENT_BASED_AGENT.md](./EVENT_BASED_AGENT.md) | EBA 预留:事件模型、事件来源、触发绑定、非消息事件如何复用 AgentRunner 调度。**标注为 future design note**。 | +| [RUNTIME_CONTROL_PLANE_V2.md](./RUNTIME_CONTROL_PLANE_V2.md) | Agent Platform v2 / runtime 管控面预留:Host 新增 runtime registry、heartbeat、task queue、daemon 执行和 audit;管理插件构建在这些 Host 能力之上。**标注为 future design note**。 | | [OFFICIAL_RUNNER_PLUGINS.md](./OFFICIAL_RUNNER_PLUGINS.md) | 官方 runner 插件迁移,包括 local-agent 和外部 runner。它是下游落地计划,不是 LangBot 基础能力设计的前置约束。 | -| [PHASE1_QA_ACCEPTANCE_MATRIX.md](./PHASE1_QA_ACCEPTANCE_MATRIX.md) | 当前阶段的 QA 验收矩阵。它验证现有分支的兼容性,不代表最终架构边界。 | +| [PHASE1_QA_ACCEPTANCE_MATRIX.md](./PHASE1_QA_ACCEPTANCE_MATRIX.md) | Agent Runner QA 指南:保留最高价值测试路径,指导 agent 开展下一轮 WebUI / runner smoke 验证。 | | [SECURITY_HARDENING.md](./SECURITY_HARDENING.md) | 安全发布级 hardening 的后续发布门槛:路径隔离、权限边界、secret、资源配额、MCP / skill 投影和审计。 | | [PROGRESS.md](./PROGRESS.md) | 当前实现进度、已验收能力、未完成收尾和非本分支范围。 | -| [PHASE1_QA_REPORT_2026-05-29.md](./PHASE1_QA_REPORT_2026-05-29.md) | 2026-05-29 本地 local-agent 与 Claude Code runner 的 UI E2E / smoke 验收记录。 | ## 工作拆分 @@ -79,7 +80,7 @@ Pipeline path 已获得 event-first host capabilities: LangBot 不应成为最终 agentic context manager。它应提供事实源、默认上下文引用和按需读取 API;agent 或其背后的 runtime 负责历史剪裁、摘要、召回和 KV cache 策略。 -当前代码中的 `max-round` 是 Pipeline adapter 配置,不应作为目标协议继续扩展。 +`max-round` 这类历史窗口参数不应作为目标协议继续扩展;如果某个 runner 仍需要类似策略,应由该 runner 的 manifest/config schema 暴露为 binding config。 详见 [AGENT_CONTEXT_PROTOCOL.md](./AGENT_CONTEXT_PROTOCOL.md)。 @@ -103,6 +104,15 @@ LangBot 不应成为最终 agentic context manager。它应提供事实源、默 详见 [OFFICIAL_RUNNER_PLUGINS.md](./OFFICIAL_RUNNER_PLUGINS.md)。 +### 5. Runtime Control Plane v2(Future) + +当前 AgentRunner v1 主线只负责 `event -> binding -> runner.run(ctx) -> result stream`。 +后续 Agent Platform v2 可以在 Host 侧新增 runtime registry、heartbeat、task queue、daemon claim、progress/cancel 和 runtime audit。 + +在这些 Host 能力之上,可以构建独立 agent 管控面插件;插件负责 UI、策略和编排体验,runtime/task 的事实源仍由 Host 持有。 + +详见 [RUNTIME_CONTROL_PLANE_V2.md](./RUNTIME_CONTROL_PLANE_V2.md)。 + ## 已确认决策 - 一个插件可以声明多个 `AgentRunner` 组件,每个组件独立暴露 manifest、配置 schema、能力和权限。 @@ -112,3 +122,4 @@ LangBot 不应成为最终 agentic context manager。它应提供事实源、默 - 官方 runner 插件是协议消费者,不是协议设计的优先约束。 - Pipeline 是当前入口 adapter,不是未来架构中心。 - EventGateway 是 future integration point,由外部 event branch 提供。 +- Runtime control plane 是 v2 Host capability layer,不阻塞当前 AgentRunner v1 主线;agent 管控面插件应构建在该 Host 能力层之上。 diff --git a/docs/agent-runner-pluginization/RUNTIME_CONTROL_PLANE_V2.md b/docs/agent-runner-pluginization/RUNTIME_CONTROL_PLANE_V2.md new file mode 100644 index 00000000..c7e496fb --- /dev/null +++ b/docs/agent-runner-pluginization/RUNTIME_CONTROL_PLANE_V2.md @@ -0,0 +1,225 @@ +# Agent Runtime Control Plane V2 + +本文档记录后续 Agent Platform / runtime 管控面的设计方向。它是当前讨论中的 **v2 文档**,但这里的 v2 指 Host capability layer / runtime control plane,不是 `AgentRunner Protocol v2`,也不属于当前 AgentRunner Protocol v1 插件化主线的交付范围。 + +## 1. 结论 + +当前主线应继续收口 AgentRunner v1: + +```text +message/event -> binding -> runner.run(ctx) -> result stream +``` + +Runtime Control Plane v2 在 Host 侧新增 runtime control plane: + +```text +event -> task -> runtime selection -> daemon claim -> execute -> progress/audit/result +``` + +在 Runtime Control Plane v2 之上,可以构建独立的 agent 管控面插件。插件负责 UI、策略和编排体验;runtime、task、heartbeat、audit 的事实源必须属于 LangBot Host,而不是插件私有 storage。 + +## 2. 不影响 v1 主线 + +v2 不应改变 AgentRunner v1 的基本契约: + +- 现有 `local-agent`、Dify、n8n、Coze 等 runner 仍可按 v1 直接执行。 +- 当前 Claude Code / Codex MVP runner 可以继续作为本机 subprocess 开发路径。 +- Host v1 已有的 event-first context、resource authorization、history / event / artifact / state / storage pull APIs 继续保留。 +- Pipeline 仍只是当前入口 adapter,不参与 v2 runtime 管控面的设计中心。 + +v2 只是在 Host 上新增一层可选能力。需要管控面的 runner 或管理插件可以声明使用它;不需要的 runner 不受影响。 + +## 3. 当前 Host 能力与缺口 + +当前 Host 已经具备 v2 的基础设施底座: + +- `AgentEventEnvelope` / `AgentBinding` +- run-scoped resource authorization +- EventLog / Transcript / ArtifactStore / PersistentStateStore +- History / Event / Artifact / State / Storage pull APIs +- AgentRunner result stream 和受控错误回流 +- binding config 与 host-owned state + +这些能力足够支持一次 `runner.run(ctx)` 内的安全执行,但不足以承担完整 runtime 管控面。 + +v2 还需要 Host 新增: + +- runtime registry:runtime id、所属 workspace、所在机器、provider 能力、状态。 +- capability discovery:`claude` / `codex` / 其它 CLI 是否存在、版本、登录状态、执行隔离能力。 +- heartbeat / liveness:runtime 在线、忙闲、最后心跳、可用 slot。 +- task queue:enqueue、claim、start、progress、complete、fail、cancel。 +- workspace mapping:LangBot workspace / project 如何映射到 runtime 上的真实目录、仓库或挂载。 +- secret / env projection:按授权向 runtime 投影 token、代理、MCP 配置、技能和环境变量。 +- runtime audit:stdout、stderr、事件流、产物、失败原因、执行耗时、使用量。 +- control API / UI:选择 runtime、测试 runtime、查看状态、下线、取消任务、重试任务。 + +## 4. 角色边界 + +### 4.1 LangBot Host + +Host 是事实源和控制面内核: + +- 保存 runtime / task / heartbeat / audit 状态。 +- 做权限校验、资源裁剪、workspace 绑定和审计。 +- 决定任务是否可被某 runtime claim。 +- 将执行结果统一回写到 event / transcript / artifact / state。 + +Host 不应内置具体 agent CLI 的复杂业务逻辑,也不应把某个官方 runner 的特殊行为提升为通用协议。 + +### 4.2 Agent 管控面插件 + +管理插件是 v2 control plane 的产品化管理层: + +- 展示 runtime、agent、task、进度、失败、审计。 +- 提供策略配置,例如默认 runtime、provider 偏好、并发限制、重试策略。 +- 触发 runtime 测试、任务取消、任务重试、手动分配。 + +管理插件不应把 runtime/task 的事实源放进自己的 plugin storage。它应该调用 Host v2 API。 + +### 4.3 Runtime daemon / worker + +Runtime daemon 负责真实执行: + +- 在所在机器上检测 CLI 和版本。 +- 管理工作目录、仓库、挂载、临时文件和进程。 +- 从 Host claim 任务,执行后上报 progress / complete / fail。 +- 将 stdout / stderr / artifacts / session id 回流 Host。 + +Claude Code、Codex、OpenCode、Gemini CLI 等 provider 适配逻辑应主要落在 daemon / worker 或 provider adapter 中。 + +## 5. 部署形态 + +### 5.1 uv / local embedded + +用户用 `uv` 或源码直接启动 LangBot 时,LangBot 进程所在机器就是 runtime host。 + +这种模式下可以直接检测用户主机上的 `claude`、`codex` 等 CLI,也可以直接 subprocess 执行。它适合个人开发和本地 smoke,但不应作为团队级管控面的唯一形态。 + +### 5.2 Docker embedded + +用户用 Docker 启动 LangBot 时,runtime host 是容器,不是宿主机。 + +因此: + +- 只能检测容器内的 `claude`、`codex`。 +- 只能使用容器内的 HOME、PATH、凭据和挂载目录。 +- 如果镜像未安装 CLI,或未挂载认证文件 / workspace,CLI runner 会不可用。 + +Docker embedded 可以作为高级部署选项,但需要用户显式安装 CLI、挂载工作区和凭据。Host 不应假设 Docker 容器能自动访问宿主机 CLI。 + +### 5.3 Sidecar daemon + +推荐的 v2 形态是 sidecar daemon: + +```text +LangBot Host (Docker or server) + <-> Runtime daemon on user host / worker host + -> claude / codex / other CLI +``` + +这种模式下,LangBot 可以跑在 Docker 内,runtime daemon 跑在宿主机或独立 worker 机器上。daemon 负责检测本机 CLI、持有本机凭据和工作区访问能力。 + +### 5.4 Remote runtime + +团队场景可以使用远端 runtime: + +- 开发机、构建机、云主机或专用 worker。 +- 多个 workspace 可绑定不同 runtime。 +- Host 只通过 registry / task queue / heartbeat / audit 进行管理。 + +### 5.5 API-only agent + +Dify、n8n、Coze、DashScope 等 API 型 runner 不依赖本地 CLI。它们可以继续按 v1 直接执行,也可以在未来按需要接入 v2 task/audit。 + +## 6. 与 Claude Code / Codex MVP runner 的关系 + +当前 Claude Code / Codex runner 是 v1 runner: + +```text +runner.run(ctx) -> subprocess("claude" / "codex") +``` + +它们适合验证 Host context 投影、state resume、result stream 和基础 CLI 调用,但有明确限制: + +- 命令只在 LangBot runtime host 上执行。 +- Docker 环境只能看到容器内 CLI。 +- 没有 runtime registry、heartbeat、task queue、cancel、workspace lifecycle。 +- 不提供发布级执行隔离、secret projection、团队级 audit。 + +v2 不需要删除这些 runner。它们可以继续作为 dev / MVP 路径存在。未来若接入管控面,可以增加 runtime-managed 执行模式: + +```text +runner binding -> Host task -> runtime daemon -> provider CLI -> Host result +``` + +## 7. 最小 v2 API 草案 + +以下仅记录能力边界,不代表最终 API 命名。 + +Runtime: + +- `runtime.register` +- `runtime.heartbeat` +- `runtime.list` +- `runtime.get` +- `runtime.disable` +- `runtime.capabilities.report` +- `runtime.capabilities.probe` + +Task: + +- `task.enqueue` +- `task.claim` +- `task.start` +- `task.progress` +- `task.complete` +- `task.fail` +- `task.cancel` +- `task.retry` + +Workspace: + +- `runtime.workspace.bind` +- `runtime.workspace.unbind` +- `runtime.workspace.resolve` + +Audit / artifacts: + +- `task.log.append` +- `task.artifact.create` +- `task.events.page` + +这些 API 应由 Host 提供,并受 workspace、runtime、binding、actor 和 plugin identity 约束。 + +## 8. 管控面插件可以构建的能力 + +基于 v2 Host 能力,可以实现一个类似 Multica 的 agent 管控面插件: + +- runtime 列表、在线状态、CLI 能力、版本、认证状态。 +- agent profile 与 runtime/provider 绑定。 +- 任务看板、任务详情、进度流、失败原因、重试和取消。 +- workspace 到 runtime 目录 / 仓库的映射管理。 +- provider capability 测试,例如 Claude Code / Codex 是否可执行。 +- 审计视图:输入、输出、工具、artifact、stdout/stderr、session id。 +- 策略配置:并发、队列、默认 runtime、fallback runtime、权限模式。 + +该插件应该是 Host v2 的消费者,而不是 Host v2 的替代品。 + +## 9. 设计原则 + +- v1 先稳定,v2 可选叠加。 +- Host 保存事实源,插件提供管理体验。 +- Runtime daemon 执行具体 CLI 和本机资源访问。 +- Docker 不假设拥有宿主机 CLI;需要 sidecar 或显式挂载。 +- Pipeline 不进入 v2 控制面中心。 +- 直接 subprocess runner 可保留,但只作为 local/dev/MVP 路径。 +- 发布级能力必须经过 Host 权限、审计和资源边界。 + +## 10. 待定问题 + +- runtime daemon 与 Host 的认证模型:workspace token、device token、还是 scoped PAT。 +- task 与 AgentRunner binding 的映射关系:由 binding 直接 enqueue,还是由独立 task policy 决定。 +- runtime capability schema 的稳定字段:provider、version、login status、execution isolation、workspace access、slot。 +- secret projection 的边界:Host 存储、用户本机存储、或外部 secret manager。 +- Docker compose 是否提供官方 sidecar daemon 示例。 +- v2 UI 是核心前端的一部分,还是完全由管理插件提供。 diff --git a/src/langbot/pkg/agent/runner/host_models.py b/src/langbot/pkg/agent/runner/host_models.py index a29c52d5..12ebf796 100644 --- a/src/langbot/pkg/agent/runner/host_models.py +++ b/src/langbot/pkg/agent/runner/host_models.py @@ -155,7 +155,7 @@ class AgentBinding(pydantic.BaseModel): """Runner ID to invoke.""" runner_config: dict[str, typing.Any] = pydantic.Field(default_factory=dict) - """Runner instance configuration.""" + """Runner binding configuration.""" resource_policy: ResourcePolicy = pydantic.Field(default_factory=ResourcePolicy) """Resource policy.""" diff --git a/src/langbot/pkg/agent/runner/resource_builder.py b/src/langbot/pkg/agent/runner/resource_builder.py index 00039ffc..d930c44a 100644 --- a/src/langbot/pkg/agent/runner/resource_builder.py +++ b/src/langbot/pkg/agent/runner/resource_builder.py @@ -23,7 +23,7 @@ class AgentResourceBuilder: - Apply 3-layer permission filtering: 1. Runner manifest declared permissions 2. Pipeline extensions_preference (bound plugins/MCP servers) - 3. Runner instance config selected resources + 3. Runner binding config selected resources - Build models list from authorized models - Build tools list from bound plugins/MCP servers - Build knowledge_bases list from config @@ -68,7 +68,7 @@ class AgentResourceBuilder: # Layer 2: Binding resource policy resource_policy = binding.resource_policy - # Layer 3: Runner instance config + # Layer 3: Runner binding config runner_config = binding.runner_config # Build each resource category diff --git a/tests/unit_tests/agent/conftest.py b/tests/unit_tests/agent/conftest.py index 85c12478..dcdc5413 100644 --- a/tests/unit_tests/agent/conftest.py +++ b/tests/unit_tests/agent/conftest.py @@ -75,4 +75,4 @@ def make_session( 'last_activity_at': now, }, '_authorized_ids': authorized_ids, - } \ No newline at end of file + } diff --git a/tests/unit_tests/api/test_pipeline_service_defaults.py b/tests/unit_tests/api/test_pipeline_service_defaults.py index 08de46d6..1cdb7af8 100644 --- a/tests/unit_tests/api/test_pipeline_service_defaults.py +++ b/tests/unit_tests/api/test_pipeline_service_defaults.py @@ -42,7 +42,6 @@ async def test_default_pipeline_config_uses_installed_local_agent_schema(): 'plugin:langbot/local-agent/default', [ {'name': 'model', 'type': 'model-fallback-selector', 'default': {'primary': '', 'fallbacks': []}}, - {'name': 'max-round', 'type': 'integer', 'default': 10}, {'name': 'prompt', 'type': 'prompt-editor', 'default': [{'role': 'system', 'content': 'Hello'}]}, ], ) @@ -61,7 +60,6 @@ async def test_default_pipeline_config_uses_installed_local_agent_schema(): assert config['ai']['runner_config'] == { 'plugin:langbot/local-agent/default': { 'model': {'primary': '', 'fallbacks': []}, - 'max-round': 10, 'prompt': [{'role': 'system', 'content': 'Hello'}], }, }