2026-05-20 21:39:12 +08:00

149 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 会话级子 Agent 委派
created: 2026-04-19
updated: 2026-04-23
type: entity
tags: [agent, runtime, websocket, backend]
sources: [packages/backend/src/modules/netaclaw/service/subagent.ts, packages/backend/src/modules/netaclaw/subagent/process_runner.ts, packages/backend/src/modules/netaclaw/subagent/process_protocol.ts, packages/backend/src/modules/netaclaw/subagent/worker.ts, packages/backend/src/modules/netaclaw/subagent/worker_tools.ts, packages/backend/src/modules/netaclaw/session-tree/types.ts, packages/frontend/src/modules/agent/store/chat.ts]
---
# 会话级子 Agent 委派
会话级子 Agent 委派是普通对话内部的临时任务分解能力。它不同于长期运行的 [[crew-orchestration]]:主 Agent 在一次对话中把局部目标交给一个或多个预设 Agent子 Agent 执行后把摘要和结果回填到当前会话树。
当前实现已经从“服务内复用 runAgent 的元数据聚合”升级为“SubagentService + 独立 worker 进程 + JSONL 协议 + Session Tree 节点”的运行模型。
## 核心职责
- 接收主 Agent 的 `delegate_task` / `delegate_parallel` 工具调用。
- 为每个任务创建受限的 Agent 配置和工具集合。
- 根据 [[tool-runtime-policy]] 推导子进程工具策略。
- 通过 `process_runner.ts` 启动 worker消费 JSONL 事件。
- 将子任务批次写入 `subagent_batch``subagent_result` 树节点。
- 向前端推送批次状态、工具路由、运行结果。
## 关键文件
| 文件 | 职责 |
| --- | --- |
| `service/subagent.ts` | 子 Agent 批次编排、任务状态聚合、结果归档 |
| `subagent/process_protocol.ts` | 父子进程之间的 envelope、policy、manifest、事件协议 |
| `subagent/process_runner.ts` | 启动/取消/超时控制 worker处理 proxy tool call |
| `subagent/worker.ts` | 子进程入口,执行受限 Agent |
| `subagent/worker_tools.ts` | 子进程本地工具适配 |
| `tools/manifest.ts` | 为子 Agent 生成工具 manifest |
| `tools/runtime_policy.ts` | 推导 worker policy 和工具运行路由 |
| `session-tree/types.ts` | `subagent_batch` / `subagent_result` 节点类型 |
## 进程协议
父进程向 worker 发送 `SubagentTaskEnvelope`,其中包含:
- `protocolVersion`
- `runId`
- `sessionId`
- `parentEntryId`
- `task`
- `agentConfig`
- `toolNames`
- `toolManifest`
- `policy`
- `timeoutMs`
worker 以 JSONL 形式回传事件:
- `run_start`
- `token`
- `thinking`
- `log`
- `tool_call`
- `tool_result`
- `proxy_tool_call`
- `run_end`
- `run_error`
`runId` 是父进程校验事件归属的边界,避免不同子任务输出串流。
## 工具路由
子 Agent 不再简单复制主 Agent 工具集,而是按 manifest 和 policy 分三类:
| 路由 | 含义 |
| --- | --- |
| `worker-local` | 可在 worker 内直接执行,例如只读文件搜索类工具 |
| `main-process-proxy` | worker 发起 `proxy_tool_call`,父进程代执行,例如写文件、技能、记忆类工具 |
| `disabled` | 当前策略下不可用,例如缺少 workspace root、shell 被禁、只读策略阻止写入 |
这个设计把“工具是否被 Agent 选择”和“工具能否在子进程执行”拆开,避免子 Agent 越权。详见 [[tool-runtime-policy]]。
## Session Tree 表达
子 Agent 结果现在是会话树的一部分:
- `subagent_batch` 表示一个批次开始或运行中状态。
- `subagent_result` 表示批次结果和每个子任务的最终输出。
- 节点通过 `parentEntryId` 关联到触发它的主 Agent 消息或工具调用。
- 前端可在刷新后从 snapshot 恢复批次卡片,不依赖仅存在内存里的 streaming state。
这使子 Agent、压缩、分支摘要、普通消息都能进入统一的 [[session-tree-runtime]]。
## 与 Agent 配置的关系
Agent 编辑页需要配置的不只是“是否允许子 Agent”
- `subagentConfig.enabled`
- `subagentConfig.maxConcurrent`
- `subagentConfig.allowedPresetAgentIds`
- `subagentConfig.allowedToolNames`
- 每个工具的有效运行画像和子 Agent 可用性诊断
- 本地存储、workspace、shell、readonly 等会影响工具路由的策略输入
这些配置最终应通过后端 projection 返回给前端避免工具列表、工具管理页、Agent 配置页三处口径不一致。
## 与 Crew 的边界
| 维度 | 会话级子 Agent | Crew 编排 |
| --- | --- | --- |
| 生命周期 | 一次普通 chat 内部的临时批次 | 独立编排运行 |
| 状态载体 | Session Tree 节点 | Crew run/task 记录 |
| 展示位置 | Agent 对话页内联卡片 | Crew 页面、画布、监控视图 |
| 工具入口 | `delegate_task` / `delegate_parallel` | Crew orchestration 入口 |
| 权限模型 | 主 Agent 控制的受限 worker | Crew 配置控制 |
## 相关页面
- [[agent-runtime]]
- [[session-tree-runtime]]
- [[tool-runtime-policy]]
- [[tool-governance]]
- [[tool-system]]
- [[frontend-architecture]]
- [[websocket-gateway]]
- [[crew-orchestration]]
## 2026-04-22 Replay Contract
`subagent_result` is now the durable replay/evidence node for session-level subagents.
- `subagent_result.metadata.processEvents` stores projected worker JSONL events such as `run_start`, `tool_call`, `tool_result`, `proxy_tool_call`, `run_end`, and `run_error`.
- `subagent_result.metadata.evidenceSummaries` stores structured summaries derived from tool results, for example file counts or tool-result previews.
- `subagent_batch.metadata.events` and `subagent_batch.metadata.latestEvent` remain runtime/status projection data. They are useful while a batch is running, but they are not the primary refresh/replay source.
- `processEvents` and `evidenceSummaries` must not be injected into `runtimeContext.messages`; they are UI replay/evidence metadata, not LLM conversation context.
- Frontend projection lives in `packages/frontend/src/modules/agent/store/chat.ts` via `subagentEvidenceSummariesByEntryId` and `subagentProcessEventsByEntryId`.
## 2026-04-23 Projection And Evidence Model
本轮实现把“子 Agent 执行结果”拆成三层,避免运行态、持久态和展示态混在一起:
- `service/subagent.ts` 负责产出原始结果载荷:`finalOutput``rawFinalContent``toolResults``evidenceSummary``processEvents``toolRuntimeRoutes`
- `service/subagent_evidence.ts` 负责把工具结果规范化,并按任务目标推导证据摘要;当前支持文件计数类摘要和工具预览类摘要。
- `service/chat_orchestrator.ts` 在批次完成后把结果聚合进 `subagent_result.metadata.finalResults/processEvents/evidenceSummaries`,使刷新后的 replay 不依赖内存态。
- `session-tree/subagent_projection.ts` 再把这些持久化数据投影成 `metadata.subagentProjection`,其中包含 `taskPanels`、每个 task 的 `toolExecutions`、剩余 `processEvents` 以及诊断信息。
这里要特别区分两个节点职责:
- `subagent_batch` 更偏运行中状态:批次任务列表、最近事件、运行态工具路由。
- `subagent_result` 更偏最终回放状态:最终结果、过程时间线、证据摘要、任务面板。
因此“刷新后还能看到什么”应首先看 `subagent_result`,而不是假设 `subagent_batch` 会长期保存完整过程。