Clawdbot 源码解读 6: Agent 运行时、会话管理与工具扩展

4 阅读6分钟

前言

在上一篇中,我们梳理了渠道抽象、ChannelManager、路由解析(resolveAgentRoute)与 Session Key、以及渠道插件开发。消息路由到 agentIdsessionKey 后,需要加载会话、调用 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 为 ~/.clawdagents.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 下共享 SessionEntrytranscript(会话历史文件)。
  • 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 的生成与复用(见路由篇)。
  • 持久化appendAssistantMessageToSessionTranscriptSessionManager(Pi 库)等向 transcript 追加消息;updateSessionStore 将 SessionEntry 变更写回 store 文件。

1.3 Agent 运行时:Pi Agent 与调用入口

  • Pi Agent:Clawdbot 使用 Pi(@mariozechner/pi-agent-core / pi-coding-agent)作为对话与工具执行引擎;支持 嵌入式(同一进程内 runEmbeddedPiAgent)与 RPC/CLIrunCliAgent)等模式。
  • 嵌入式调用runEmbeddedPiAgent(params)pi-embedded-runner 中实现:按 sessionKey 解析 lane(并发控制)、加载 workspace、解析模型与 auth、构建 system prompt 与工具列表、调用 Pi 的 SessionManager 执行一轮;支持 queueEmbeddedPiMessage(排队)、abortEmbeddedPiRuncompactEmbeddedPiSession 等。
  • 调用入口
    • CLIagentCommand(opts)(commands/agent.ts)解析 --message、--to、--sessionKey 等,解析 session、加载 store、调用 runEmbeddedPiAgentrunCliAgent,再根据 deliver 决定是否投递到渠道。
    • Gatewayagent handler(server-methods/agent.ts)校验 params、解析 sessionKey、loadSessionEntryagentCommandwaitForAgentJob,并通过 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 中再合并 createExecToolcreateReadToolcreateWriteToolcreateEditToolcreateApplyPatchTool、技能等,并按 config.toolsagent.toolssandboxpluginToolAllowlistfilterToolsByPolicy
  • 调用流程:Pi 在执行 turn 时按模型返回的 tool_use 调用对应 tool 的 execute;参数校验、权限(resolveEffectiveToolPolicyresolveSubagentToolPolicy)在调用前由 isToolAllowedByPoliciesfilterToolsByPolicy 等保证。
  • 核心工具Browser(browser-tool.ts,可接沙箱 bridge)、Canvas(canvas-tool.ts)、Nodes(nodes-tool.ts,与 Gateway node 交互)、SessionsSend/SessionsSpawn(发消息/拉起子会话)、Gateway(gateway-tool.ts,重启/配置等)、CronMessage(渠道发送)、TTSWebSearch/WebFetchMemory(插件)等。
  • 工具权限tools.allowtools.denytools.alsoAllowagents.defaults.toolsagent.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.workspaceDEFAULT_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

  • resolveDefaultAgentWorkspaceDirDEFAULT_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

  • SessionEntrysessionIdupdatedAtsessionFiledeliveryContextmodelOverridequeueModecompactionCountspawnedBythinkingLevelresponseUsagesendPolicygroupActivation 等大量可选字段,用于持久化会话级设置与状态。

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 的 SessionManagerCURRENT_SESSION_VERSION 配合,保证历史格式兼容。

2.3 Agent 执行入口

src/commands/agent.tsagentCommand(opts, runtime, deps)

  • 校验 opts.messageopts.to | sessionId | sessionKey | agentId;若提供 agentId 则校验在 listAgentIds(cfg) 中,且与 sessionKey 解析出的 agentId 一致。
  • resolveAgentWorkspaceDirresolveAgentDirensureAgentWorkspace;解析 sessionresolveSession)、loadSessionStoreloadSessionEntry
  • 根据是否 CLI provider 等选择 runEmbeddedPiAgentrunCliAgentregisterAgentRunContextemitAgentEvent;结束后 updateSessionStoreAfterAgentRun、可选 deliverAgentCommandResult

src/gateway/server-methods/agent.tsagent handler:

  • validateAgentParams 校验 messagesessionKeyidempotencyKey 等;dedupe 幂等;loadSessionEntry 加载会话;agentCommandwaitForAgentJob(异步 job 时)执行;respond 返回 result 或 error。

src/auto-reply/reply/agent-runner.tsrunReplyAgent

  • 接收 followupRunsessionEntrysessionKeystorePathdefaultModelsessionCtx 等;createTypingSignalerrunAgentTurnWithFallback(内部 queueEmbeddedPiMessage / runEmbeddedPiAgent);buildReplyPayloadscreateBlockReplyPipelinefinalizeWithFollowuprunMemoryFlushIfNeededpersistSessionUsageUpdateincrementCompactionCount 等。

src/agents/pi-embedded-runner/run.tsrunEmbeddedPiAgent(params)

  • resolveSessionLaneresolveGlobalLaneenqueueSessionenqueueGlobal 做并发与排队;解析 workspaceDiragentDirprovidermodelensureClawdbotModelsJsonbuildEmbeddedRunPayloads(system prompt、tools、history);runEmbeddedAttempt 执行单次尝试;支持 fallback、compaction、auth profile 轮换等。

2.4 工具注册与策略

src/agents/clawdbot-tools.tscreateClawdbotTools(options)

  • options 创建 createBrowserToolcreateCanvasToolcreateNodesToolcreateCronToolcreateMessageToolcreateTtsToolcreateGatewayToolcreateAgentsListToolcreateSessionsListToolcreateSessionsHistoryToolcreateSessionsSendToolcreateSessionsSpawnToolcreateSessionStatusToolcreateWebSearchToolcreateWebFetchToolcreateImageTool(若 agentDir 存在)等。
  • resolvePluginTools({ context, existingToolNames, toolAllowlist }) 合并插件提供的工具,返回 [...tools, ...pluginTools]

src/agents/pi-tools.ts

  • 合并 createClawdbotToolscreateExecToolcreateReadToolcreateWriteToolcreateEditToolcreateApplyPatchToollistChannelAgentTools(渠道的 agentTools)、技能相关工具等。
  • filterToolsByPolicyresolveEffectiveToolPolicyresolveGroupToolPolicyresolveSubagentToolPolicyexpandPolicyWithPluginGroups 等按 config.toolsagent.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 覆盖。
  • resolveEffectiveToolPolicyresolveGroupToolPolicy:按渠道群组、tools.allowtools.denytools.alsoAllow 等合并。

2.5 核心工具示例:Browser、Canvas、Nodes

  • Browsertools/browser-tool.ts):提供浏览器自动化(导航、截图等),可选 sandboxBridgeUrlallowHostControl,与 Browser Control 服务或沙箱内浏览器桥接。
  • Canvastools/canvas-tool.ts):与 Canvas Host(A2UI)交互,用于富内容编辑与展示。
  • Nodestools/nodes-tool.ts):与 Gateway 的 node.invokenode.event 等配合,向已连接的 iOS/Android 节点发送指令(如拍照、技能 bin);依赖 agentSessionKeyconfig 解析节点与策略。

三、架构图解

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:确认 resolveSessionAgentIdresolveAgentRoute 与配置 bindings 一致;sessionKey 错误会导致加载错误会话或默认 Agent。
  • 会话未持久化:检查 storePathupdateSessionStore 是否被调用;loadSessionStore 的 cache TTL 可能导致短时间未看到最新写入。
  • 模型与 authrunEmbeddedPiAgent 依赖 resolveModelgetApiKeyForModelresolveAuthProfileOrder;auth 失败或模型不可用会报错或 fallback。
  • verboseagentCommand、Gateway 请求可带 thinkingverbose 等,便于查看 prompt、工具调用与回复。

4.2 如何开发自定义工具

  1. 实现 AgentTool<TSchema, TResult>(name、description、parameters schema、execute(params)),与 pi-agent-corepi-coding-agent 的接口一致。
  2. createClawdbotToolspi-tools 的合并处加入新工具;若仅某 Agent 需要,可在 agent.tools.allow 中显式加入 name,并在构建工具列表时根据 options.agentSessionKey / options.config 条件创建。
  3. 若需权限控制,在 resolveEffectiveToolPolicyresolveSubagentToolPolicy 或渠道 groups.resolveToolPolicy 中加入对新工具名的 allow/deny。
  4. 工具参数建议用 TypeBox/JSON Schema 定义,并避免 Union/anyOf(见仓库 guardrails);execute 内做参数校验与安全边界检查。

4.3 会话与工具测试

  • SessionEntry:可用 loadSessionStoreupdateSessionStoreEntry 在测试中注入或断言;storePath 可指向临时目录。
  • runEmbeddedPiAgent:参数较多,测试时可只传 sessionKeymessageworkspaceDiragentDirconfig 等必要项;通过 enqueue 注入同步执行避免并发干扰。
  • 工具:单独对 createXxxTool() 返回的 tool 的 execute 做单元测试;filterToolsByPolicyisToolAllowedByPolicies 可单独测策略结果。

4.4 常见问题

Q: 回复发到错误会话或未发送?
A: 检查 deliveryContextresolveAgentOutboundTargetresolveSendPolicysessionKey 与渠道路由的 sessionKey 一致时,lastChannellastTo 等会用于投递目标。

Q: 子 Agent 调用了被禁止的工具?
A: 确认 resolveSubagentToolPolicy 的 deny 列表包含该工具名;若配置了 tools.subagents.tools.allow,仅 allow 中的工具可用;isSubagentSessionKey(sessionKey) 为 true 时才会应用 subagent 策略。

Q: 工具列表为空或缺少某工具?
A: 检查 config.tools.allow/denyagent.toolssandbox.toolspluginToolAllowlistfilterToolsByPolicy 会过滤,expandPolicyWithPluginGroups 会展开插件工具组;渠道 groups.resolveToolPolicy 也可能限制群组内可用工具。


五、总结

5.1 本文要点

  • Agent 作用域resolveDefaultAgentIdresolveAgentWorkspaceDirresolveAgentDirresolveSessionAgentId 决定 Agent 与目录;Workspace 用于 SOUL/TOOLS/技能,agentDir 用于身份与模型配置。
  • 会话管理SessionEntry 存于 store(JSON),loadSessionStoreupdateSessionStore 读写;transcript 持久化历史;resolveMainSessionKeyresolveExplicitAgentSessionKey 用于 main 会话别名。
  • Agent 执行agentCommand(CLI)、Gateway agent handler、runReplyAgent(自动回复)最终调用 runEmbeddedPiAgentqueueEmbeddedPiMessageresolveSessionLaneresolveGlobalLane 控制排队与并发。
  • 工具createClawdbotTools + resolvePluginTools + pi-tools(Exec/Read/Write/Edit/ApplyPatch、渠道 agentTools、技能)经 filterToolsByPolicyresolveEffectiveToolPolicyresolveSubagentToolPolicy 得到最终列表;Browser、Canvas、Nodes、Sessions、Gateway、Cron、Message、TTS 等为核心工具。

参考资源

  • 项目仓库:github.com/clawdbot/cl…
  • 官方文档:docs.clawd.bot
  • Agent 作用域:src/agents/agent-scope.tssrc/agents/workspace.ts
  • 会话存储与类型:src/config/sessions/store.tssrc/config/sessions/types.tssrc/config/sessions/main-session.tssrc/config/sessions/transcript.tssrc/config/sessions/paths.ts
  • Agent 执行入口:src/commands/agent.tssrc/gateway/server-methods/agent.tssrc/auto-reply/reply/agent-runner.tssrc/agents/pi-embedded-runner/run.tssrc/agents/pi-embedded.ts
  • 工具注册与策略:src/agents/clawdbot-tools.tssrc/agents/pi-tools.tssrc/agents/pi-tools.policy.tssrc/agents/tool-policy.ts
  • 核心工具:src/agents/tools/browser-tool.tssrc/agents/tools/canvas-tool.tssrc/agents/tools/nodes-tool.tssrc/agents/tools/sessions-send-tool.tssrc/agents/tools/gateway-tool.ts