前言
在上一篇中,我们梳理了渠道抽象、ChannelManager、路由解析(resolveAgentRoute)与 Session Key、以及渠道插件开发。消息路由到 agentId 与 sessionKey 后,需要加载会话、调用 Agent 运行时(Pi Agent)执行一轮对话,并在此过程中使用 工具(Browser、Canvas、Nodes、sessions、gateway 等)。本文是《Clawdbot 源码解读》系列的第六篇,我们将深入 Agent 与工具:Agent 作用域与 Workspace、会话管理(Session Key、存储、隔离、持久化)、Pi Agent 的 RPC/嵌入式调用、工具注册与调用流程、以及工具权限与状态管理。
学习目标
- 理解 Agent 作用域(agent-scope)、Workspace 与 agentDir 的解析
- 掌握会话存储(SessionEntry、store、transcript)与 main-session 的职责
- 熟悉 Agent 执行入口(agentCommand、Gateway agent、runReplyAgent、runEmbeddedPiAgent)
- 了解工具注册(createClawdbotTools、pi-tools、插件工具)、调用流程与策略(allow/deny、subagent)
前置知识
- 已阅读系列前五篇(架构、CLI、配置、Gateway、渠道与路由)
- 对 LLM/Agent、会话上下文、工具调用有基本概念
一、核心概念
1.1 Agent 作用域与 Workspace
- Agent 列表:配置中 agents.list 定义多个 Agent(id、name、default、workspace、agentDir、model、sandbox、tools 等);resolveDefaultAgentId(cfg) 取默认 Agent(第一个 default 或第一个条目)。
- Workspace:每个 Agent 可有 workspace 目录(默认主 Agent 为 ~/.clawd 或 agents.defaults.workspace,其它为 ~/.clawd-<id>),用于 SOUL.md、TOOLS.md、AGENTS.md、技能等;resolveAgentWorkspaceDir(cfg, agentId) 得到路径。
- agentDir:Agent 专属「agent」目录(默认 $CLAWDBOT_STATE_DIR/agents/<id>/agent),用于身份、模型配置等;resolveAgentDir(cfg, agentId) 得到路径。
- Session Key 与 Agent:resolveSessionAgentId({ sessionKey, config }) 从 parseAgentSessionKey(sessionKey) 解析出 agentId,未解析到时用 resolveDefaultAgentId。
1.2 会话管理:存储、隔离与持久化
- Session Key:格式为 agent:<agentId>:…(见第五篇),用于唯一标识一条会话;同一 sessionKey 下共享 SessionEntry、transcript(会话历史文件)。
- SessionEntry:内存/存储中的会话元数据(sessionId、updatedAt、sessionFile、deliveryContext、modelOverride、queueMode、compactionCount、spawnedBy 等),由 loadSessionStore(storePath) 从 JSON 文件加载,updateSessionStore 写回。
- storePath:会话存储根路径(由配置与 resolveDefaultSessionStorePath 等决定),其下按 sessionKey 或约定结构存 store(SessionEntry 字典)与 transcript(会话历史 JSONL)。
- 隔离:不同 sessionKey 对应不同 SessionEntry 与 transcript;session.scope(per-sender / global)、dmScope(main / per-peer / per-channel-peer)影响 Session Key 的生成与复用(见路由篇)。
- 持久化:appendAssistantMessageToSessionTranscript、SessionManager(Pi 库)等向 transcript 追加消息;updateSessionStore 将 SessionEntry 变更写回 store 文件。
1.3 Agent 运行时:Pi Agent 与调用入口
- Pi Agent:Clawdbot 使用 Pi(@mariozechner/pi-agent-core / pi-coding-agent)作为对话与工具执行引擎;支持 嵌入式(同一进程内 runEmbeddedPiAgent)与 RPC/CLI(runCliAgent)等模式。
- 嵌入式调用:runEmbeddedPiAgent(params) 在 pi-embedded-runner 中实现:按 sessionKey 解析 lane(并发控制)、加载 workspace、解析模型与 auth、构建 system prompt 与工具列表、调用 Pi 的 SessionManager 执行一轮;支持 queueEmbeddedPiMessage(排队)、abortEmbeddedPiRun、compactEmbeddedPiSession 等。
- 调用入口:
- CLI:agentCommand(opts)(commands/agent.ts)解析 --message、--to、--sessionKey 等,解析 session、加载 store、调用 runEmbeddedPiAgent 或 runCliAgent,再根据 deliver 决定是否投递到渠道。
- Gateway:agent handler(server-methods/agent.ts)校验 params、解析 sessionKey、loadSessionEntry、agentCommand 或 waitForAgentJob,并通过 respond 返回结果。
- 自动回复:runReplyAgent(auto-reply/reply/agent-runner.ts)在渠道消息触发时调用,加载 session、runAgentTurnWithFallback(内部 queueEmbeddedPiMessage / runEmbeddedPiAgent),再组 reply payload、followup、typing 等。
1.4 工具系统:注册、调用与策略
- 工具注册:createClawdbotTools(options) 返回一组 AnyAgentTool(Browser、Canvas、Nodes、Cron、Message、TTS、Gateway、SessionsList/History/Send/Spawn、SessionStatus、AgentsList、WebSearch、WebFetch、Image 等);pi-tools.ts 中再合并 createExecTool、createReadTool、createWriteTool、createEditTool、createApplyPatchTool、技能等,并按 config.tools、agent.tools、sandbox、pluginToolAllowlist 做 filterToolsByPolicy。
- 调用流程:Pi 在执行 turn 时按模型返回的 tool_use 调用对应 tool 的 execute;参数校验、权限(resolveEffectiveToolPolicy、resolveSubagentToolPolicy)在调用前由 isToolAllowedByPolicies、filterToolsByPolicy 等保证。
- 核心工具:Browser(browser-tool.ts,可接沙箱 bridge)、Canvas(canvas-tool.ts)、Nodes(nodes-tool.ts,与 Gateway node 交互)、SessionsSend/SessionsSpawn(发消息/拉起子会话)、Gateway(gateway-tool.ts,重启/配置等)、Cron、Message(渠道发送)、TTS、WebSearch/WebFetch、Memory(插件)等。
- 工具权限:tools.allow、tools.deny、tools.alsoAllow、agents.defaults.tools、agent.tools、沙箱 sandbox.tools;子 Agent(subagent)有 resolveSubagentToolPolicy,默认拒绝 sessions_spawn、gateway、agents_list 等,可由配置 tools.subagents.tools 覆盖。
二、代码解析
2.1 Agent 作用域:agent-scope 与 workspace
src/agents/agent-scope.ts:
- listAgents(cfg):返回 cfg.agents?.list 过滤后的 AgentEntry[]。
- resolveDefaultAgentId(cfg):取第一个 default: true 或第一个条目,归一化为 DEFAULT_AGENT_ID("main")或配置 id。
- resolveAgentConfig(cfg, agentId):从 listAgents 中按 id 取条目,返回 ResolvedAgentConfig(name、workspace、agentDir、model、memorySearch、humanDelay、heartbeat、identity、groupChat、subagents、sandbox、tools)。
- resolveAgentWorkspaceDir(cfg, agentId):优先 resolveAgentConfig(...).workspace,否则默认 Agent 用 agents.defaults.workspace 或 DEFAULT_AGENT_WORKSPACE_DIR(~/.clawd),其它用 ~/.clawd-<id>。
- resolveAgentDir(cfg, agentId):优先 resolveAgentConfig(...).agentDir,否则 $STATE_DIR/agents/<id>/agent。
- resolveSessionAgentId({ sessionKey, config }):parseAgentSessionKey(sessionKey) 得到 agentId,缺省时用 resolveDefaultAgentId。
src/agents/workspace.ts:
- resolveDefaultAgentWorkspaceDir、DEFAULT_AGENT_WORKSPACE_DIR(~/.clawd 或 profile 下 ~/.clawd-<profile>)。
- ensureAgentWorkspace({ dir, ensureBootstrapFiles }):确保目录存在,可选写入 BOOTSTRAP.md、AGENTS.md 等模板;Workspace 下可放 SOUL.md、TOOLS.md、技能目录等。
2.2 会话存储与 transcript
src/config/sessions/store.ts:
- loadSessionStore(storePath, options):从 storePath 对应 JSON 文件读取 Record<string, SessionEntry>;支持 SESSION_STORE_CACHE 与 TTL,避免频繁读盘。
- updateSessionStore(storePath, store):将 store 写回文件;updateSessionStoreEntry(storePath, sessionKey, patch) 对单条 SessionEntry 做 merge 后写回。
- normalizeSessionStore:对 store 内每条 entry 做 normalizeSessionEntryDelivery(deliveryContext、lastChannel 等)。
src/config/sessions/types.ts:
- SessionEntry:sessionId、updatedAt、sessionFile、deliveryContext、modelOverride、queueMode、compactionCount、spawnedBy、thinkingLevel、responseUsage、sendPolicy、groupActivation 等大量可选字段,用于持久化会话级设置与状态。
src/config/sessions/main-session.ts:
- resolveMainSessionKey(cfg):根据 session.scope(global 时返回 "global")、session.mainKey、默认 agentId 得到 agent:<agentId>:<mainKey>。
- resolveExplicitAgentSessionKey({ cfg, agentId }):仅由 agentId 与 mainKey 得到 agent:<agentId>:<mainKey>。
src/config/sessions/transcript.ts:
- appendAssistantMessageToSessionTranscript:向 sessionKey 对应的 transcript 文件追加 assistant 消息(含 text、mediaUrls);resolveSessionTranscriptPath 等决定文件路径。
- 与 Pi 的 SessionManager、CURRENT_SESSION_VERSION 配合,保证历史格式兼容。
2.3 Agent 执行入口
src/commands/agent.ts 中 agentCommand(opts, runtime, deps):
- 校验 opts.message、opts.to | sessionId | sessionKey | agentId;若提供 agentId 则校验在 listAgentIds(cfg) 中,且与 sessionKey 解析出的 agentId 一致。
- resolveAgentWorkspaceDir、resolveAgentDir;ensureAgentWorkspace;解析 session(resolveSession)、loadSessionStore、loadSessionEntry。
- 根据是否 CLI provider 等选择 runEmbeddedPiAgent 或 runCliAgent;registerAgentRunContext、emitAgentEvent;结束后 updateSessionStoreAfterAgentRun、可选 deliverAgentCommandResult。
src/gateway/server-methods/agent.ts 中 agent handler:
- validateAgentParams 校验 message、sessionKey、idempotencyKey 等;dedupe 幂等;loadSessionEntry 加载会话;agentCommand 或 waitForAgentJob(异步 job 时)执行;respond 返回 result 或 error。
src/auto-reply/reply/agent-runner.ts 中 runReplyAgent:
- 接收 followupRun、sessionEntry、sessionKey、storePath、defaultModel、sessionCtx 等;createTypingSignaler、runAgentTurnWithFallback(内部 queueEmbeddedPiMessage / runEmbeddedPiAgent);buildReplyPayloads、createBlockReplyPipeline、finalizeWithFollowup;runMemoryFlushIfNeeded、persistSessionUsageUpdate、incrementCompactionCount 等。
src/agents/pi-embedded-runner/run.ts 中 runEmbeddedPiAgent(params):
- resolveSessionLane、resolveGlobalLane;enqueueSession、enqueueGlobal 做并发与排队;解析 workspaceDir、agentDir、provider、model;ensureClawdbotModelsJson;buildEmbeddedRunPayloads(system prompt、tools、history);runEmbeddedAttempt 执行单次尝试;支持 fallback、compaction、auth profile 轮换等。
2.4 工具注册与策略
src/agents/clawdbot-tools.ts 中 createClawdbotTools(options):
- 按 options 创建 createBrowserTool、createCanvasTool、createNodesTool、createCronTool、createMessageTool、createTtsTool、createGatewayTool、createAgentsListTool、createSessionsListTool、createSessionsHistoryTool、createSessionsSendTool、createSessionsSpawnTool、createSessionStatusTool、createWebSearchTool、createWebFetchTool、createImageTool(若 agentDir 存在)等。
- resolvePluginTools({ context, existingToolNames, toolAllowlist }) 合并插件提供的工具,返回 [...tools, ...pluginTools]。
src/agents/pi-tools.ts:
- 合并 createClawdbotTools、createExecTool、createReadTool、createWriteTool、createEditTool、createApplyPatchTool、listChannelAgentTools(渠道的 agentTools)、技能相关工具等。
- filterToolsByPolicy、resolveEffectiveToolPolicy、resolveGroupToolPolicy、resolveSubagentToolPolicy、expandPolicyWithPluginGroups 等按 config.tools、agent.tools、沙箱、子 Agent、插件组做 allow/deny,得到最终传给 Pi 的工具列表。
src/agents/pi-tools.policy.ts:
- resolveSubagentToolPolicy(cfg):子 Agent 默认 deny 列表(sessions_list、sessions_send、sessions_spawn、gateway、agents_list、whatsapp_login、cron、memory_search 等),可配置 tools.subagents.tools.deny/allow 覆盖。
- resolveEffectiveToolPolicy、resolveGroupToolPolicy:按渠道群组、tools.allow、tools.deny、tools.alsoAllow 等合并。
2.5 核心工具示例:Browser、Canvas、Nodes
- Browser(tools/browser-tool.ts):提供浏览器自动化(导航、截图等),可选 sandboxBridgeUrl、allowHostControl,与 Browser Control 服务或沙箱内浏览器桥接。
- Canvas(tools/canvas-tool.ts):与 Canvas Host(A2UI)交互,用于富内容编辑与展示。
- Nodes(tools/nodes-tool.ts):与 Gateway 的 node.invoke、node.event 等配合,向已连接的 iOS/Android 节点发送指令(如拍照、技能 bin);依赖 agentSessionKey、config 解析节点与策略。
三、架构图解
3.1 Agent 与会话数据流
graph TB
A[消息/CLI/Gateway] --> B[sessionKey + agentId]
B --> C[resolveSessionAgentId / loadSessionEntry]
C --> D[SessionEntry + transcript]
D --> E[runEmbeddedPiAgent / runReplyAgent / agentCommand]
E --> F[Pi SessionManager + tools]
F --> G[reply / deliver]
E --> H[updateSessionStore / appendTranscript]
3.2 工具注册与策略
graph LR
A[createClawdbotTools] --> B[Browser/Canvas/Nodes/...]
C[pi-tools] --> B
C --> D[Exec/Read/Write/Edit/ApplyPatch]
C --> E[listChannelAgentTools]
C --> F[resolvePluginTools]
B --> G[filterToolsByPolicy]
D --> G
E --> G
F --> G
G --> H[resolveEffectiveToolPolicy / resolveSubagentToolPolicy]
H --> I[最终工具列表]
3.3 Agent 执行入口关系
graph TB
CLI[agentCommand] --> Emb[runEmbeddedPiAgent]
GW[Gateway agent handler] --> Emb
AR[runReplyAgent] --> Q[queueEmbeddedPiMessage]
Q --> Emb
Emb --> Lane[resolveSessionLane / resolveGlobalLane]
Lane --> Attempt[runEmbeddedAttempt]
Attempt --> Pi[Pi SessionManager + tools]
四、实践建议
4.1 如何调试 Agent 执行
- sessionKey 与 agentId:确认 resolveSessionAgentId、resolveAgentRoute 与配置 bindings 一致;sessionKey 错误会导致加载错误会话或默认 Agent。
- 会话未持久化:检查 storePath、updateSessionStore 是否被调用;loadSessionStore 的 cache TTL 可能导致短时间未看到最新写入。
- 模型与 auth:runEmbeddedPiAgent 依赖 resolveModel、getApiKeyForModel、resolveAuthProfileOrder;auth 失败或模型不可用会报错或 fallback。
- verbose:agentCommand、Gateway 请求可带 thinking、verbose 等,便于查看 prompt、工具调用与回复。
4.2 如何开发自定义工具
- 实现 AgentTool<TSchema, TResult>(name、description、parameters schema、execute(params)),与 pi-agent-core 或 pi-coding-agent 的接口一致。
- 在 createClawdbotTools 或 pi-tools 的合并处加入新工具;若仅某 Agent 需要,可在 agent.tools.allow 中显式加入 name,并在构建工具列表时根据 options.agentSessionKey / options.config 条件创建。
- 若需权限控制,在 resolveEffectiveToolPolicy、resolveSubagentToolPolicy 或渠道 groups.resolveToolPolicy 中加入对新工具名的 allow/deny。
- 工具参数建议用 TypeBox/JSON Schema 定义,并避免 Union/anyOf(见仓库 guardrails);execute 内做参数校验与安全边界检查。
4.3 会话与工具测试
- SessionEntry:可用 loadSessionStore、updateSessionStoreEntry 在测试中注入或断言;storePath 可指向临时目录。
- runEmbeddedPiAgent:参数较多,测试时可只传 sessionKey、message、workspaceDir、agentDir、config 等必要项;通过 enqueue 注入同步执行避免并发干扰。
- 工具:单独对 createXxxTool() 返回的 tool 的 execute 做单元测试;filterToolsByPolicy、isToolAllowedByPolicies 可单独测策略结果。
4.4 常见问题
Q: 回复发到错误会话或未发送?
A: 检查 deliveryContext、resolveAgentOutboundTarget、resolveSendPolicy;sessionKey 与渠道路由的 sessionKey 一致时,lastChannel、lastTo 等会用于投递目标。
Q: 子 Agent 调用了被禁止的工具?
A: 确认 resolveSubagentToolPolicy 的 deny 列表包含该工具名;若配置了 tools.subagents.tools.allow,仅 allow 中的工具可用;isSubagentSessionKey(sessionKey) 为 true 时才会应用 subagent 策略。
Q: 工具列表为空或缺少某工具?
A: 检查 config.tools.allow/deny、agent.tools、sandbox.tools、pluginToolAllowlist;filterToolsByPolicy 会过滤,expandPolicyWithPluginGroups 会展开插件工具组;渠道 groups.resolveToolPolicy 也可能限制群组内可用工具。
五、总结
5.1 本文要点
- Agent 作用域:resolveDefaultAgentId、resolveAgentWorkspaceDir、resolveAgentDir、resolveSessionAgentId 决定 Agent 与目录;Workspace 用于 SOUL/TOOLS/技能,agentDir 用于身份与模型配置。
- 会话管理:SessionEntry 存于 store(JSON),loadSessionStore、updateSessionStore 读写;transcript 持久化历史;resolveMainSessionKey、resolveExplicitAgentSessionKey 用于 main 会话别名。
- Agent 执行:agentCommand(CLI)、Gateway agent handler、runReplyAgent(自动回复)最终调用 runEmbeddedPiAgent;queueEmbeddedPiMessage、resolveSessionLane、resolveGlobalLane 控制排队与并发。
- 工具:createClawdbotTools + resolvePluginTools + pi-tools(Exec/Read/Write/Edit/ApplyPatch、渠道 agentTools、技能)经 filterToolsByPolicy、resolveEffectiveToolPolicy、resolveSubagentToolPolicy 得到最终列表;Browser、Canvas、Nodes、Sessions、Gateway、Cron、Message、TTS 等为核心工具。
参考资源
- 项目仓库:github.com/clawdbot/cl…
- 官方文档:docs.clawd.bot
- Agent 作用域:
src/agents/agent-scope.ts、src/agents/workspace.ts - 会话存储与类型:
src/config/sessions/store.ts、src/config/sessions/types.ts、src/config/sessions/main-session.ts、src/config/sessions/transcript.ts、src/config/sessions/paths.ts - Agent 执行入口:
src/commands/agent.ts、src/gateway/server-methods/agent.ts、src/auto-reply/reply/agent-runner.ts、src/agents/pi-embedded-runner/run.ts、src/agents/pi-embedded.ts - 工具注册与策略:
src/agents/clawdbot-tools.ts、src/agents/pi-tools.ts、src/agents/pi-tools.policy.ts、src/agents/tool-policy.ts - 核心工具:
src/agents/tools/browser-tool.ts、src/agents/tools/canvas-tool.ts、src/agents/tools/nodes-tool.ts、src/agents/tools/sessions-send-tool.ts、src/agents/tools/gateway-tool.ts