132 lines
7.2 KiB
Markdown
132 lines
7.2 KiB
Markdown
---
|
||
title: Agent 运行时
|
||
created: 2026-04-13
|
||
updated: 2026-04-23
|
||
type: entity
|
||
tags: [runtime, agent, llm, backend]
|
||
sources: [packages/backend/src/modules/netaclaw/service/chat_orchestrator.ts, packages/backend/src/modules/netaclaw/session-tree/, packages/backend/src/modules/netaclaw/runtime/, packages/backend/src/modules/netaclaw/service/tool_resolver.ts, packages/backend/src/modules/netaclaw/subagent/]
|
||
---
|
||
|
||
# Agent 运行时
|
||
|
||
Agent 运行时是 NetaClaw 对话执行链路的核心。当前实现已经从“线性消息 + 单次 runAgent 调用”升级为“Session Tree 快照 + ChatOrchestrator 编排 + ToolResolver/Manifest 治理 + Subagent Worker”的组合架构。
|
||
|
||
它同时负责:
|
||
|
||
- 维护会话树、活动路径和运行时上下文,详见 [[session-tree-runtime]]。
|
||
- 按 Agent 配置、模型能力、治理策略解析最终可用工具,详见 [[tool-governance]] 和 [[tool-runtime-policy]]。
|
||
- 构建 Prompt、执行 ReAct 循环、流式返回 token/thinking/tool 事件。
|
||
- 在主 Agent 与子 Agent 之间聚合委派结果,详见 [[subagent-session]]。
|
||
- 将快照和增量事件推送给前端,详见 [[websocket-gateway]] 和 [[frontend-architecture]]。
|
||
|
||
## 关键文件
|
||
|
||
| 文件 | 职责 |
|
||
| --- | --- |
|
||
| `service/chat_orchestrator.ts` | 对话主编排:创建会话、追加用户/助手节点、驱动运行、写回结果 |
|
||
| `session-tree/provider.ts` | Session Tree provider 抽象 |
|
||
| `session-tree/mysql_provider.ts` | MySQL 持久化 provider |
|
||
| `session-tree/file_provider.ts` | 文件持久化 provider |
|
||
| `session-tree/context_builder.ts` | 从 active path 构造模型上下文 |
|
||
| `runtime/agent.ts` | ReAct 循环执行入口 |
|
||
| `runtime/prompt_builder.ts` | Prompt Builder 分层注入 |
|
||
| `service/tool_resolver.ts` | 工具治理、Agent 覆盖、运行时诊断投影 |
|
||
| `tools/manifest.ts` | 工具 manifest 和 worker routing 基础画像 |
|
||
| `tools/runtime_policy.ts` | Subprocess worker policy 与工具路由状态推导 |
|
||
| `subagent/process_runner.ts` | 子 Agent 独立进程 runner |
|
||
| `subagent/process_protocol.ts` | 子进程 JSONL 事件协议 |
|
||
|
||
## 当前运行链路
|
||
|
||
```text
|
||
用户输入
|
||
-> ChatOrchestrator 接收
|
||
-> SessionTreeProvider 创建或恢复 session
|
||
-> appendMessage(user) 写入会话树
|
||
-> SessionTreeContextBuilder 读取 active path
|
||
-> ToolResolver 生成 toolNames / disabledReasons / runtimeDiagnostic
|
||
-> Prompt Builder 注入工具、记忆、技能、压缩摘要
|
||
-> runAgent 执行 ReAct 循环
|
||
-> 工具调用经 ToolResolver 提供的工具实例执行
|
||
-> 如触发 delegate_task/delegate_parallel,进入 SubagentService
|
||
-> appendEntry 写入 message、compaction、subagent_batch、subagent_result 等节点
|
||
-> WebSocket 推送 snapshot/patch/event
|
||
-> 前端 chat store 按 active path 渲染
|
||
```
|
||
|
||
## 与旧实现的关键区别
|
||
|
||
旧实现偏向按 `netaclaw_message` 的线性历史恢复对话。现在的运行时以会话树为主轴:
|
||
|
||
- `activePath` 决定当前模型上下文,而不是简单取全量消息列表。
|
||
- `leafEntryId` 表示当前分支叶子,支持分支、重置 leaf、派生 session。
|
||
- `compaction`、`branch_summary`、`label`、`session_info`、`subagent_batch`、`subagent_result` 都是树节点,而不是散落在消息 metadata 里的附属状态。
|
||
- 前端刷新后通过 session tree snapshot 恢复历史,不依赖浏览器 localStorage 存完整消息。
|
||
|
||
## 工具运行时
|
||
|
||
Agent 运行时不直接相信静态工具列表。最终工具集由 [[tool-governance]] 统一裁决:
|
||
|
||
- 全局工具状态来自 `netaclaw_tool` 和 catalog 同步。
|
||
- Agent 编辑页可以保存 `tools.enabled`、`tools.disabled`、`toolOverrides`、`subagentConfig.allowedToolNames` 等局部配置。
|
||
- 后端输出 `runtimeDiagnostic`,前端工具管理页、Agent 编辑页、对话页应使用同一份投影。
|
||
- 子 Agent 的工具还会经过 [[tool-runtime-policy]] 推导,区分 `worker-local`、`main-process-proxy`、`disabled`。
|
||
|
||
## 子 Agent 运行时
|
||
|
||
主 Agent 通过 `delegate_task` 或 `delegate_parallel` 发起委派后,`SubagentService` 会根据配置构造受限 Agent,并优先走独立 worker 进程执行。子进程通过 JSONL 协议向父进程上报:
|
||
|
||
- `run_start`
|
||
- `token`
|
||
- `thinking`
|
||
- `tool_call`
|
||
- `tool_result`
|
||
- `proxy_tool_call`
|
||
- `run_end`
|
||
- `run_error`
|
||
|
||
需要主进程能力的工具会通过 `proxy_tool_call` 回到父进程执行,避免子进程直接持有所有写入、记忆、技能管理权限。详见 [[subagent-session]] 和 [[tool-runtime-policy]]。
|
||
|
||
## 前端消费方式
|
||
|
||
前端 `agent/store/chat.ts` 现在围绕 session tree snapshot 工作:
|
||
|
||
- 保存最近 session/agent 的轻量指针到 localStorage。
|
||
- 通过 snapshot 恢复 `sessionMeta`、`entries`、`childrenByParentId`、`activePathIds`。
|
||
- `visibleEntries` 渲染 message、branch summary、compaction、custom message、subagent batch/result。
|
||
- 工具渲染统一通过 `projectToolRender` 和工具 renderer registry。
|
||
|
||
这意味着“刷新后历史看不到”一类问题应优先检查后端 session tree provider、session id 恢复、snapshot 加载,而不是把完整对话塞进浏览器 localStorage。
|
||
|
||
## 相关页面
|
||
|
||
- [[session-tree-runtime]]
|
||
- [[tool-runtime-policy]]
|
||
- [[tool-governance]]
|
||
- [[tool-system]]
|
||
- [[subagent-session]]
|
||
- [[context-compaction]]
|
||
- [[prompt-builder]]
|
||
- [[frontend-architecture]]
|
||
- [[websocket-gateway]]
|
||
- [[netaclaw-module]]
|
||
|
||
## 2026-04-22 Subagent Replay
|
||
|
||
The Agent runtime persists subagent evidence and process replay through session tree entries instead of transient chat state.
|
||
|
||
- `SubagentService` collects worker process events and writes projected events into `resultPayload.processEvents`.
|
||
- `ChatOrchestrator` aggregates completed task data into `subagent_result.metadata.processEvents` and `subagent_result.metadata.evidenceSummaries`.
|
||
- `SessionTreeProvider.getSnapshot()` is the refresh boundary: after page reload, the frontend should recover subagent evidence cards and replay timeline from `subagent_result` entries in the snapshot.
|
||
- These metadata fields are intentionally excluded from `runtimeContext.messages` so refresh/replay UI data does not contaminate the next LLM prompt.
|
||
|
||
## 2026-04-23 Canonical Projection Boundary
|
||
|
||
这一轮更新后,Agent runtime 对子 Agent 回放数据的口径进一步收敛:
|
||
|
||
- `gateway/session.ts` 在返回 `getSnapshot()`、`switchLeaf()`、`appendSubagentResultEntry()` 等结果前,会统一调用 `projectSubagentSnapshot()` / `projectSubagentEntry()`。
|
||
- `session-tree/subagent_projection.ts` 负责把 `subagent_result`、历史 tool message 或旧 metadata 中的委派结果整理为 `metadata.subagentProjection`,这才是前端首选的 canonical UI projection。
|
||
- projection 会生成 `taskPanels`、`toolExecutions`、`evidenceSummaries`、`processEvents` 和 `diagnostics`,并做数量裁剪,避免把整份原始 payload 直接暴露给 UI。
|
||
- 前端保留对旧 payload / metadata 的解析能力只是为了兼容历史会话;当前代码路径应优先依赖后端生成的 `subagentProjection`,而不是在页面里重复拼装结果。
|
||
- 这意味着“子 Agent 结果怎么展示”已经不再是纯前端约定,而是 Agent runtime 在 session 边界稳定输出的一部分契约。
|