代理开发与调试
项目结构
OpenClaw是一个多平台、多通道的个人AI助手系统,核心由“网关控制平面 + 代理运行时 + 工具与技能体系 + 会话与工作空间”构成。下图给出高层结构示意(概念映射):
graph TB
subgraph "客户端"
UI["Web 控制台/桌面应用"]
节点["移动/桌面节点"]
end
subgraph "网关控制平面"
WS["WebSocket 控制面"]
配置["配置与路由"]
会话["会话存储与维护"]
日志["日志与审计"]
end
subgraph "代理运行时"
运行时["嵌入式代理运行时<br/>pi-mono 衍生"]
提示["系统提示工程"]
工具["内置工具集"]
技能["技能加载与过滤"]
end
客户端 --> WS
WS --> 运行时
运行时 --> 工具
运行时 --> 技能
运行时 --> 会话
运行时 --> 日志
配置 --> WS
会话 --> WS
日志 --> WS
核心组件
- 代理运行时与会话循环:负责消息输入、上下文组装、模型推理、工具执行、流式输出与持久化。
- 工作空间与引导文件:作为代理唯一工作目录,注入AGENTS/SOUL/TOOLS等引导文件,支持Git备份与迁移。
- 系统提示工程:构建紧凑、可配置的系统提示,按模式注入工具列表、安全提醒、技能清单、时间信息等。
- 子代理与会话工具:支持后台并行任务、线程绑定、深度限制、并发控制与结果回传。
- 调试与开发工具:Watch模式、原始流日志、运行时调试覆盖、开发配置隔离。
- 技能体系:多级加载优先级、环境/二进制/配置门禁、安装器与热更新、令牌开销估算。
架构总览
下图展示一次典型代理循环的端到端流程,包括入口、队列与并发、提示装配、事件流与收尾:
sequenceDiagram
participant 客户端 as "客户端/CLI"
participant 网关 as "网关 RPC/CLI"
participant 会话 as "会话管理器"
participant 运行时 as "嵌入式代理运行时"
participant 模型 as "模型提供方"
participant 工具 as "工具执行器"
客户端->>网关 : 发送消息/命令
网关->>会话 : 解析会话键/准备工作空间
会话-->>网关 : 返回会话状态
网关->>运行时 : 启动代理循环序列化/排队
运行时->>运行时 : 组装系统提示含引导文件/技能
运行时->>模型 : 推理请求流式/分块
模型-->>运行时 : 流式响应思考/文本/工具调用
运行时->>工具 : 执行工具调用
工具-->>运行时 : 工具结果
运行时-->>网关 : 事件流生命周期/助手/工具
网关-->>客户端 : 实时流式回复
运行时->>会话 : 写入转录/统计
运行时-->>网关 : 生命周期结束/错误
详细组件分析
代理测试辅助工具
- Watch模式与开发配置隔离:通过全局--dev与网关--dev组合,实现状态隔离与默认引导,便于快速迭代与复现问题。
- 原始流日志:开启原始助手流与pi-mono原始块日志,用于观察推理泄漏与分块细节。
- 运行时调试覆盖:/debug命令在内存中临时覆盖配置,无需修改磁盘配置即可切换参数。
flowchart TD
Start(["开始"]) --> DevProfile["设置 OPENCLAW_PROFILE=dev"]
DevProfile --> DevGateway["启动网关 --dev自动写入最小配置/种子工作空间"]
DevGateway --> Watch["pnpm gateway:watch热重载"]
Watch --> EnableRaw["启用原始流日志CLI 或环境变量"]
EnableRaw --> Inspect["观察原始流/分块"]
Inspect --> DebugOverride["/debug 切换运行时覆盖"]
DebugOverride --> End(["结束"])
工作空间管理与压缩机制
- 默认位置与布局:工作空间为代理唯一工作目录,推荐使用openclaw setup初始化,包含AGENTS/SOUL/TOOLS/BOOTSTRAP/IDENTITY/USER等引导文件。
- Git备份策略:建议将工作空间放入私有Git仓库,仅提交引导文件与每日记忆文件,避免提交凭据与会话历史。
- 压缩与修剪:系统提示注入的引导文件会进行截断与标记,防止上下文膨胀;会话修剪在LLM调用前清理旧工具结果,减少上下文占用。
- 大文件与令牌成本:MEMORY.md等大文件需谨慎,建议定期归档或使用memory_search/memory_get按需读取。
flowchart TD
Init["初始化工作空间openclaw setup"] --> Seed["种子引导文件AGENTS/SOUL/TOOLS/IDENTITY/USER/BOOTSTRAP"]
Seed --> Inject["每轮注入系统提示引导文件截断/标记"]
Inject --> Trim["会话修剪调用前清理旧工具结果"]
Trim --> Backup["Git备份私有仓库,仅提交必要文件"]
Backup --> Compress["长期记忆归档按需检索"]
系统提示工程
- 结构化组成:工具列表、安全提醒、可用技能清单、自更新指引、工作空间路径、文档位置、注入的引导文件、沙箱信息、当前日期时间、回复标签、心跳、运行时信息、推理可见性。
- 模式控制:full/minimal/none三种模式,子代理使用minimal以缩小上下文。
- 引导文件注入:AGENTS/SOUL/TOOLS/IDENTITY/USER/HEARTBEAT/MEMORY等,支持截断与警告标记,总量与单文件上限可配置。
- 时间处理:仅包含时区信息以稳定提示缓存;需要实时时间时使用会话状态。
flowchart TD
Build["构建系统提示"] --> Base["基础结构工具/安全/技能/工作空间/文档"]
Base --> Inject["注入引导文件截断/标记"]
Inject --> Sandbox["沙箱信息启用时"]
Sandbox --> Time["当前日期时间时区"]
Time --> Mode["提示模式full/minimal/none"]
Mode --> Output["输出到模型"]
子代理注册与生命周期管理
- 角色与目标:并行研究/长任务/慢速工具,保持隔离(会话分离+可选沙箱),硬限制工具面,支持可配置嵌套深度。
- 启动方式:/subagents spawn(一次性)与sessions_spawn(可线程绑定/持久会话),支持模型/思考级别覆盖、超时、清理策略。
- 线程绑定:Discord等适配器支持线程绑定,配合/focus、/unfocus、/agents、/session idle/max-age等命令。
- 并发与深度:默认最大深度1,可提升至2形成编排者-工作者模式;全局并发与每会话子代上限可配置;停止主会话会级联停止子代。
- 结果回传:子代理完成时在请求者会话中发布摘要/统计,支持ANNOUNCE_SKIP静默。
sequenceDiagram
participant 主会话 as "主会话"
participant 子代理 as "子代理"
participant 请求者 as "请求者聊天"
主会话->>子代理 : sessions_spawn可线程绑定/模式
子代理-->>主会话 : 返回 runId/childSessionKey
子代理->>子代理 : 执行任务受限工具集
子代理-->>主会话 : 完成结果/统计
主会话->>请求者 : 发布摘要/统计可线程保留
代理开发环境搭建与调试工具
- 开发配置隔离:OPENCLAW_PROFILE=dev隔离状态,网关--dev自动写入最小配置与工作空间种子文件。
- Watch模式:监听源码变更并重启,支持传递额外参数;适合快速迭代。
- 原始流日志:记录未过滤的助手流与pi-mono原始块,便于定位推理泄漏与分块行为。
- 运行时调试覆盖:/debug set/unset/reset在内存中临时覆盖配置项,无需重启。
代理配置验证、错误处理与日志记录
- 配置验证:通过openclaw doctor检查DM策略、通道配置、工作空间状态等;会话维护策略(清理/旋转/磁盘预算)可通过openclaw sessions cleanup预览与强制执行。
- 错误处理:代理循环在生命周期事件缺失时回退;工具结果大小与图像负载会被清洗;重复确认与NO_REPLY抑制逻辑避免冗余输出。
- 日志记录:原始流日志可写入指定路径;注意敏感信息脱敏与本地留存时限。
代理开发最佳实践与质量保证
- 工作空间治理:仅在工作空间内存放引导文件与每日记忆;凭据与会话历史放在~/.openclaw;使用私有Git备份。
- 提示工程:保持AGENTS/SOUL/TOOLS简洁;MEMORY.md避免过度增长;合理设置bootstrapMaxChars与bootstrapTotalMaxChars。
- 子代理使用:为重型任务选择更便宜模型;限制嵌套深度;控制并发与每会话子代数量;明确ANNOUNCE_SKIP语义。
- 技能管理:遵循门禁要求(二进制/环境/配置);在沙箱中运行不受信任技能;利用skills watcher热更新;关注技能列表令牌开销。
- 调试与回归:使用--dev与watch模式;开启原始流日志;/debug覆盖关键开关;定期清理会话存储。
依赖关系分析
- 组件耦合
- 网关控制平面与代理运行时:通过RPC与事件流交互,会话管理器与日志模块贯穿始终。
- 代理运行时与系统提示工程:提示装配依赖工作空间引导文件与技能快照。
- 子代理与会话工具:依赖sessions_*系列工具与线程绑定适配器。
- 外部依赖
- 模型提供方:OpenAI兼容流式接口;原始块日志仅在使用pi-mono的openai-completions提供方时产生。
- 渠道适配器:Discord等支持线程绑定与特定配置键。
graph LR
网关["网关控制平面"] --> 运行时["代理运行时"]
运行时 --> 提示["系统提示工程"]
运行时 --> 工具["工具集"]
运行时 --> 会话["会话存储"]
运行时 --> 日志["日志"]
运行时 --> 技能["技能加载"]
子代理["子代理"] --> 会话
子代理 --> 工具
会话 --> 日志
性能考量
- 上下文与令牌
- 引导文件截断与总量上限控制;技能列表注入字符开销可估算;MEMORY.md按需检索降低上下文占用。
- 会话修剪与维护
- 调用前修剪旧工具结果;维护策略包括时间窗口、条目上限、轮换与磁盘预算;生产环境建议强制模式并设定合理阈值。
- 子代理与并发
- 限制最大嵌套深度与全局并发;为重型任务选择低价格模型;及时归档子代理会话。
- 原始流日志
- 仅在调试阶段启用,注意文件体积与敏感信息脱敏。
代理引擎架构
代理引擎架构
OpenClaw 的代理引擎围绕“网关(Gateway)—路由(Routing)—会话(Sessions)—配置(Config)—代理(Agents)”五大维度组织,形成可插拔、可扩展、可治理的代理执行环境。核心模块职责如下:
- 网关:接收节点事件与外部请求,解析会话与交付目标,触发代理命令与回执。
- 路由:将消息映射到具体代理、账号与会话键,支持别名与回退策略。
- 会话:维护会话状态、最近通道与收件人,支撑按会话复用投递目标。
- 配置:集中式配置合并、默认值与运行时替换,提供代理与工具策略。
- 代理:代理生命周期事件、绑定与配置变更、ACPI/Acp 策略与运行边界。
graph TB
GW["网关<br/>server-node-events.ts"] --> RT["路由<br/>resolve-route.ts"]
GW --> SESS["会话<br/>sessions.ts"]
GW --> CFG["配置<br/>merge-config.ts / defaults.ts"]
RT --> BIND["绑定<br/>bindings.ts"]
RT --> SK["会话键<br/>session-key.ts"]
RT --> ACCT["账号标识<br/>account-id.ts"]
GW --> EVT["事件钩子<br/>internal-hooks.test.ts"]
GW --> BOOT["引导脚本钩子<br/>boot-md/HOOK.md"]
AG["代理<br/>agents.*"] --> GW
ACP["ACPI/Acp 策略<br/>policy.ts"] --> GW
EXT["扩展运行时<br/>acpx/runtime.ts"] --> AG
核心组件
- 代理路径管理与绑定
- 绑定列表与路由绑定解析,支持移除绑定、冲突检测与缺失项识别。
- 代理配置应用与裁剪,支持按代理 ID 更新名称、工作区、代理目录与模型等字段。
- 作用域隔离与引导文件系统
- 通过会话键与账号标识进行作用域隔离;在网关启动时按代理作用域执行引导脚本(如 BOOT.md)。
- 生命周期管理与状态转换
- 子代理生命周期结束结果枚举与结局解析,支持重置、删除、超时、被杀等状态。
- 事件处理与消息路由
- 节点事件驱动代理请求,自动复用会话最近通道与收件人,必要时发出回执;当路由不可达时禁用投递而非全局降级。
- 配置系统与默认参数
- 合并配置、默认值注入、环境变量替换、路径规范化与会话缓存策略。
- 扩展与运行时边界
- ACP 策略控制代理允许列表;ACPX 运行时根据 MCP 服务器构建代理命令,支持代理命令覆盖与缓存。
架构总览
下图展示从节点事件到代理执行的关键流程:事件进入网关后,解析会话与路由,决定是否投递与回执;路由解析失败时仅禁用本次投递,避免全局降级;配置与策略参与运行边界控制;扩展运行时可对代理命令进行覆盖与代理。
sequenceDiagram
participant Node as "节点"
participant GW as "网关(server-node-events)"
participant RT as "路由(resolve-route)"
participant SESS as "会话(sessions)"
participant AG as "代理(agents)"
participant ACP as "策略(policy)"
participant EXT as "扩展(acpx)"
Node->>GW : "agent.request 事件"
GW->>SESS : "读取会话最近通道/收件人"
GW->>RT : "解析代理路由(通道/账号/会话键)"
RT-->>GW : "返回路由(可能为空)"
alt 路由可用
GW->>AG : "执行代理命令(可带投递参数)"
AG-->>GW : "返回结果"
opt 需要回执
GW->>Node : "发送回执"
end
else 路由不可用
GW->>GW : "记录告警并禁用本次投递"
end
GW->>ACP : "检查代理策略/允许列表"
ACP-->>GW : "允许/拒绝"
GW->>EXT : "构建/覆盖代理命令(含MCP)"
EXT-->>GW : "返回最终命令"
详细组件分析
组件一:代理路径管理与绑定
- 绑定管理
- 支持列出现有路由绑定、区分非路由绑定、批量移除绑定,并检测缺失与冲突。
- 代理配置应用
- 按代理 ID 应用名称、工作区、代理目录与模型等字段,若不存在则追加默认代理条目。
- 代理配置裁剪
- 移除指定代理条目,并统计移除的绑定与允许项数量,保证配置整洁。
flowchart TD
Start(["开始"]) --> List["列出现有绑定"]
List --> Diff["区分路由/非路由绑定"]
Diff --> Remove["计算待移除索引"]
Remove --> Detect["检测缺失与冲突"]
Detect --> ApplyCfg["应用代理配置(名称/工作区/目录/模型)"]
ApplyCfg --> Prune["裁剪代理配置(移除条目)"]
Prune --> End(["结束"])
组件二:作用域隔离与引导文件系统
- 作用域隔离
- 使用会话键与账号标识进行作用域隔离,确保不同账号与会话不会互相干扰。
- 引导文件系统
- 在网关启动时,按代理作用域执行引导脚本(例如 BOOT.md),确保每个作用域具备一致的初始化行为。
flowchart TD
Boot(["网关启动"]) --> Scope["解析代理作用域(会话键/账号)"]
Scope --> Exists{"引导文件存在?"}
Exists -- 是 --> Run["执行引导脚本(如 BOOT.md)"]
Exists -- 否 --> Skip["跳过引导"]
Run --> Done(["完成"])
Skip --> Done
组件三:生命周期管理与状态转换
- 结果枚举
- 定义子代理生命周期结束的多种结局(正常、错误、超时、被杀、重置、删除)。
- 结局解析
- 将会话重置原因映射为重置或删除结局,便于上层统一处理。
flowchart TD
S(["会话结束"]) --> Check{"是否会话重置?"}
Check -- 是 --> Reset["映射为重置结局"]
Check -- 否 --> Delete["映射为删除结局"]
Reset --> E(["结束"])
Delete --> E
组件四:事件处理与消息路由
- 节点事件驱动
- 网关接收节点事件,解析会话与投递目标;当请求投递但缺少通道/收件人时,尝试复用会话最近通道与收件人。
- 回执机制
- 当需要回执且具备投递目标时,发送回执;否则记录告警并跳过。
- 路由不可达策略
- 路由不可达时仅禁用本次投递,不进行全局降级,避免影响其他会话。
sequenceDiagram
participant C as "客户端/节点"
participant G as "网关"
participant R as "路由"
participant S as "会话"
participant A as "代理"
C->>G : "agent.request(可选 deliver/channel/to)"
G->>S : "读取最近通道/收件人"
G->>R : "解析路由"
alt 路由可用
G->>A : "执行代理(携带投递参数)"
opt 需要回执
G-->>C : "发送回执"
end
else 路由不可用
G-->>G : "记录告警并禁用本次投递"
end
组件五:配置系统与默认参数
- 配置合并
- 将用户配置与内置默认配置合并,确保关键字段不缺失。
- 默认值注入
- 提供默认代理、模型、端口等默认值,保证最小可用配置。
- 环境变量替换
- 在运行时对配置中的占位符进行环境变量替换,支持动态注入。
- 路径与会话
- 规范化路径、缓存会话数据,减少重复 IO。
flowchart TD
Load(["加载用户配置"]) --> Merge["合并内置默认配置"]
Merge --> Env["环境变量替换"]
Env --> Normalize["路径规范化"]
Normalize --> Cache["会话缓存"]
Cache --> Apply(["应用到运行时"])
组件六:扩展与运行时边界(ACPX/Acp)
- ACP 策略
- 基于允许列表控制代理是否允许执行,未配置允许列表时默认放行。
- ACPX 运行时
- 解析代理命令覆盖,构建包含 MCP 服务器信息的代理命令,支持缓存以提升性能。
- 命令构建
- 将目标命令与 MCP 服务器序列化为 base64url 负载,拼接为可执行命令行。
flowchart TD
Policy["策略检查(允许列表)"] --> Allowed{"允许?"}
Allowed -- 否 --> Deny["返回策略错误"]
Allowed -- 是 --> Resolve["解析代理命令覆盖"]
Resolve --> Build["构建MCP代理命令(负载)"]
Build --> Cache["写入命令缓存"]
Cache --> Exec["执行代理命令"]
依赖关系分析
- 组件耦合
- 网关高度依赖路由与会话模块;路由依赖绑定、会话键与账号标识;配置模块贯穿所有组件。
- 外部集成
- ACP 策略与扩展运行时(ACPX)提供安全边界与代理命令覆盖能力。
- 潜在循环依赖
- 路由与会话之间为单向依赖(路由使用会话键/账号),未见循环依赖迹象。
graph LR
GW["网关"] --> RT["路由"]
GW --> SESS["会话"]
RT --> BIND["绑定"]
RT --> SK["会话键"]
RT --> ACCT["账号"]
GW --> CFG["配置"]
GW --> ACP["策略"]
GW --> EXT["扩展运行时"]
性能考虑
- 命令缓存
- ACPX 运行时对代理命令进行缓存,避免重复构建与 IO 开销。
- 会话复用
- 投递目标缺失时优先复用会话最近通道与收件人,减少路由解析成本。
- 路由不可达短路
- 路由不可达时立即禁用本次投递并记录告警,避免无效尝试。
- 配置合并与环境变量替换
- 在启动阶段完成合并与替换,运行时直接使用已解析配置,降低运行时开销。
工具系统与执行
工具系统与执行
工具系统主要由以下层次构成:
- 工具注册与导出:统一入口导出 exec 与 process 工具,并暴露类型与默认值。
- 执行引擎:负责命令解析、环境注入、主机选择、安全策略、批准流程、输出聚合与超时控制。
- 进程管理:对后台会话进行生命周期管理、日志切片、轮询、输入写入、键序列发送、粘贴、终止与清理。
- 变异与显示:识别工具变异行为、构建指纹以去重与防环、生成用户可读的工具显示摘要。
- 循环检测:基于历史记录与模式匹配的环路检测与全局断路器,保障稳定性。
- 缓存与 TTL:文件统计快照、缓存 TTL 计算与持久化时间戳,提升性能与一致性。
- 权限与安全:安全二进制白名单、主机与安全级别、批准策略与节点主机隔离。
- 显示层:移动端工具显示配置与渲染,结合模板系统展示可用工具列表。
graph TB
subgraph "工具注册与导出"
BT["bash-tools.ts"]
end
subgraph "执行引擎"
BE["bash-tools.exec.ts"]
NSR["node-host/invoke-system-run.ts"]
end
subgraph "进程管理"
BP["bash-tools.process.ts"]
end
subgraph "变异与显示"
TM["tool-mutation.ts"]
TD["ToolDisplay.kt"]
HTML["export-html/template.js"]
end
subgraph "循环检测"
TLD["tool-loop-detection.ts"]
DIAG["logging/diagnostic.ts"]
end
subgraph "缓存与TTL"
CU["config/cache-utils.ts"]
CTTLS["pi-embedded-runner/cache-ttl.ts"]
end
subgraph "权限与安全"
DOCTOR["commands/doctor-config-flow.ts"]
SAFE_BIN_TESTS["doctor-config-flow.safe-bins.test.ts"]
end
BT --> BE
BT --> BP
BE --> NSR
BE --> DIAG
BE --> TLD
BP --> DIAG
TM --> TD
TM --> HTML
TLD --> DIAG
CU --> CTTLS
DOCTOR --> BE
SAFE_BIN_TESTS --> DOCTOR
核心组件
- 工具注册与导出
- 统一导出 exec 与 process 工具工厂函数与类型,便于上层按需装配。
- 提供默认参数与环境变量注入能力,支持沙箱与主机模式切换。
- 执行引擎
- 解析命令、工作目录、环境变量、PTY、超时、背景执行窗口等参数。
- 基于主机(沙箱/网关/节点)与安全级别(deny/allowlist/full)执行策略。
- 安全二进制白名单与预检,防止脚本中误用 shell 变量语法。
- 支持批准策略与通知,以及失败/完成后的结果封装。
- 进程管理
- 列表、轮询、日志切片、写入标准输入、发送键序列、粘贴文本、终止与清理。
- 轮询等待时间限制、重试建议记录与诊断状态联动。
- 变异与显示
- 识别写入、编辑、应用补丁、消息发送、定时任务等变异动作。
- 构建稳定指纹用于重复检测与去重;移动端与 HTML 模板渲染工具摘要。
- 循环检测
- 基于工具调用历史与模式匹配,检测通用重复、已知轮询无进展、Ping-Pong 交替与全局断路器。
- 发生阻断时发出诊断事件并记录关键信息。
- 缓存与 TTL
- 文件统计快照与缓存 TTL 解析;会话管理器中追加/读取缓存 TTL 时间戳。
- 权限与安全
- 安全二进制可信目录与配置收集,提示不在可信目录的警告。
- 节点主机运行策略评估,结合批准与白名单判定。
架构总览
下图展示了工具从注册到执行、再到进程管理与循环检测的整体交互:
sequenceDiagram
participant Caller as "调用方"
participant Reg as "工具注册(bash-tools.ts)"
participant Exec as "执行引擎(bash-tools.exec.ts)"
participant Gate as "网关/节点(node-host)"
participant Proc as "进程管理(bash-tools.process.ts)"
participant Loop as "循环检测(tool-loop-detection.ts)"
participant Diag as "诊断(logging/diagnostic.ts)"
Caller->>Reg : 创建 exec/process 工具实例
Caller->>Exec : 调用 exec(toolCallId, args, signal, onUpdate)
Exec->>Gate : 依据主机/安全策略执行命令
Gate-->>Exec : 返回会话ID/状态或挂起
Exec-->>Caller : 返回运行中/完成结果
Caller->>Proc : 调用 process(action, sessionId,...)
Proc->>Diag : 记录轮询/日志/状态
Exec->>Loop : 上报调用历史与结果
Loop-->>Exec : 若检测到环路则阻断或告警
详细组件分析
工具注册与导出(bash-tools.ts)
- 导出 exec 与 process 工具工厂函数与类型,统一入口便于上层按需装配。
- 提供默认参数(如背景执行窗口、超时、PATH 前缀、通知开关等),并支持按会话键解析代理 ID。
执行引擎(bash-tools.exec.ts)
- 参数归一化与校验:命令必填、工作目录解析、环境变量合并与验证、PTY、超时、主机与安全级别、批准策略。
- 主机与安全策略:
- 主机选择:sandbox/gateway/node,默认 sandbox;仅在允许时接受请求主机。
- 安全级别:deny/allowlist/full,结合请求与配置取最小安全级别。
- 批准策略:ask/on-miss/off,结合批准系统与 gate 控制。
- 安全二进制与预检:
- 解析安全二进制白名单与可信目录,未配置的条目会记录警告。
- 预检脚本文件,避免 shell 变量语法泄漏到 Python/Node。
- 输出与超时:
- 最大输出限制、挂起最大输出、聚合输出、超时控制、PTY 支持。
- 结果封装:
- 运行中返回会话 ID 与 PID;完成后返回退出码、耗时、聚合输出等。
flowchart TD
Start(["进入 exec.execute"]) --> Validate["校验命令/参数"]
Validate --> HostSel["主机选择与安全级别归一化"]
HostSel --> EnvMerge["合并并验证环境变量"]
EnvMerge --> Precheck["安全二进制与脚本预检"]
Precheck --> Run["启动进程/网关/节点执行"]
Run --> Yield{"是否需要挂起?"}
Yield --> |是| YieldRes["返回运行中结果"]
Yield --> |否| Done["返回完成结果"]
Run --> |异常| Fail["抛出错误"]
进程管理(bash-tools.process.ts)
- 动作集合:list、poll、log、write、send-keys、submit、paste、kill、clear、remove。
- 会话生命周期:运行中与已完成两类列表,支持按作用域过滤。
- 日志切片:默认尾部展示固定行数,支持 offset/limit 分页。
- 轮询与重试:设置最大轮询等待时间,记录重试建议并在退出时重置。
- 终止策略:优先通过进程监管器取消,否则回退到进程树终止。
flowchart TD
PStart(["进入 process.execute"]) --> Action{"action 类型"}
Action --> |list| List["列出运行中/已完成会话"]
Action --> |poll| Poll["轮询指定会话,聚合输出"]
Action --> |log| Log["按窗口切片输出日志"]
Action --> |write/send-keys/submit/paste| Stdin["写入标准输入"]
Action --> |kill/clear/remove| Terminate["终止或移除会话"]
Poll --> Retry["记录/重置重试建议"]
Log --> Slice["切片与统计"]
Stdin --> Running["返回运行中结果"]
Terminate --> Done["返回完成/失败结果"]
变异处理与显示(tool-mutation.ts 与 ToolDisplay.kt)
- 变异识别:
- 工具名集合与只读动作集合,结合 action 判断是否为变异操作。
- 特定工具(如 process、message、session_status)有专门规则。
- 构建稳定指纹:优先使用稳定参数键(如 path、to、jobId、model 等),否则回退到 meta 文本。
- 显示摘要:
- 移动端根据工具名与 action 生成标题、标签、细节行与表情符号。
- HTML 模板渲染工具列表,区分必填/可选参数。
flowchart TD
MStart(["构建变异状态"]) --> IsMutating{"是否为变异动作?"}
IsMutating --> |否| NoFP["返回 undefined 指纹"]
IsMutating --> |是| FP["提取稳定参数键/回退 meta"]
FP --> State["返回 mutatingAction 与 actionFingerprint"]
循环检测与状态管理(tool-loop-detection.ts 与 diagnostic.ts)
- 检测器:
- 通用重复、已知轮询无进展、Ping-Pong 交替、全局断路器。
- 使用稳定哈希(工具名 + 参数 JSON 规范化)进行模式匹配。
- 阈值与级别:
- 警告阈值、严重阈值、全局断路器阈值,自动保证顺序关系。
- 诊断事件:
- 记录工具环路事件,包含级别、动作(warn/block)、探测器、计数、消息与配对工具名。
flowchart TD
LStart(["上报一次工具调用"]) --> History["更新历史与配对状态"]
History --> Detect["检测重复/无进展/Ping-Pong/全局断路器"]
Detect --> |未触发| OK["继续执行"]
Detect --> |警告| Warn["记录警告事件"]
Detect --> |严重| Block["阻断并记录关键事件"]
结果缓存与性能优化(cache-utils.ts 与 cache-ttl.ts)
- 缓存 TTL:
- 从环境变量解析 TTL,支持非负整数与默认回退。
- 判断缓存是否启用(TTL > 0)。
- 文件统计快照:
- 获取文件 mtime 与 size,用于缓存命中判断。
- 会话缓存 TTL:
- 在会话管理器中追加/读取缓存 TTL 时间戳,忽略持久化失败。
执行策略、权限控制与安全隔离
- 执行默认值解析:
- 从会话、代理与全局配置解析 host、security、ask、node 等默认值。
- 安全二进制与可信目录:
- 收集 tools.exec 与代理级配置,提示不在可信目录的条目。
- 单元测试覆盖安全二进制不在可信目录的提示场景。
- 节点主机运行策略:
- 评估系统运行策略阶段,结合批准、安全级别、白名单与可信目录,决定允许/拒绝与提示。
工具开发指南与自定义工具创建
- 工具命名与权限:
- 工具名规范化与长度/格式校验,用于权限分类。
- 工具目录与显示:
- 工具目录分组模型与工具条目模型,支持插件来源与可选字段。
- HTML 模板渲染工具列表,展示名称、描述与参数要求。
- 自定义工具集成测试:
- 测试用例覆盖工具别名、不暴露特定提供程序工具、按子代理会话过滤等场景。
依赖关系分析
graph LR
BT["bash-tools.ts"] --> BE["bash-tools.exec.ts"]
BT --> BP["bash-tools.process.ts"]
BE --> DIAG["logging/diagnostic.ts"]
BE --> TLD["tool-loop-detection.ts"]
BP --> DIAG
TM["tool-mutation.ts"] --> TD["ToolDisplay.kt"]
TM --> HTML["export-html/template.js"]
DOCTOR["doctor-config-flow.ts"] --> BE
DOCTOR --> SAFE_BIN_TESTS["safe-bins.test.ts"]
NSR["node-host/invoke-system-run.ts"] --> BE
CU["config/cache-utils.ts"] --> CTTLS["pi-embedded-runner/cache-ttl.ts"]
性能考量
- 输出与日志
- 设置最大输出与挂起最大输出,避免内存膨胀;日志切片默认尾部展示固定行数,支持分页。
- 轮询与重试
- 限制最大轮询等待时间;根据新输出动态调整重试建议,减少无效轮询。
- 缓存
- 使用文件统计快照与缓存 TTL,降低重复读取成本;在会话管理器中记录缓存 TTL 时间戳。
- 背景执行
- 合理设置背景执行窗口与超时,避免长时间占用资源;对挂起会话采用独立生命周期管理。
- 安全预检
- 在执行前进行脚本文件预检,避免在环路中浪费令牌与资源。
会话管理系统
会话管理系统
会话管理相关代码主要位于以下模块:
- 会话存储与缓存:store.ts、store-cache.ts、store-maintenance.ts、store-migrations.ts、disk-budget.ts
- 会话路径与命名:paths.ts
- 转录修复与完整性:session-transcript-repair.ts
- 文件系统工具:session-utils.fs.ts
- 并发写锁:session-write-lock.ts
- 配置与类型:types.base.ts、cache-utils.ts
graph TB
subgraph "会话存储层"
A["store.ts<br/>加载/保存/更新会话"]
B["store-cache.ts<br/>对象与序列化缓存"]
C["store-maintenance.ts<br/>修剪/封顶/轮转"]
D["store-migrations.ts<br/>迁移适配"]
E["disk-budget.ts<br/>磁盘预算清理"]
end
subgraph "路径与命名"
F["paths.ts<br/>会话目录/文件解析"]
end
subgraph "转录与修复"
G["session-transcript-repair.ts<br/>工具调用/结果配对修复"]
end
subgraph "文件系统工具"
H["session-utils.fs.ts<br/>预览/归档/清理"]
end
subgraph "并发与锁"
I["session-write-lock.ts<br/>进程级写锁"]
end
subgraph "配置与类型"
J["types.base.ts<br/>维护配置/重置策略"]
K["cache-utils.ts<br/>缓存TTL/统计快照"]
end
A --> B
A --> C
A --> D
A --> E
A --> F
A --> H
A --> I
A --> J
A --> K
G --> A
核心组件
- 会话存储与持久化:负责从磁盘加载、合并更新、规范化字段、应用维护策略(修剪、封顶、轮转)、原子写入与缓存同步。
- 会话缓存:支持对象缓存与序列化缓存,带TTL与文件元信息校验,避免脏读。
- 维护策略:按时间阈值修剪过期条目、按数量封顶、按大小轮转sessions.json,并支持磁盘预算清理。
- 路径与命名:统一解析会话目录、默认存储路径、转录文件名规则(含话题主题)。
- 转录修复:严格修复工具调用与结果配对、去重、合成缺失结果、输入清洗与敏感信息脱敏。
- 并发控制:基于锁文件的进程级写锁,支持超时、过期回收、看门狗释放。
- 工具结果守卫:确保严格配对与完整性,避免API拒绝请求。
- 历史记录维护:支持归档与清理,保留最近N份备份,按原因与时间戳归档。
架构总览
会话管理采用“存储+缓存+维护+并发”的分层设计:
- 存储层:以JSON对象记录会话条目,条目内含运行时模型、通道上下文、派生元数据等。
- 缓存层:在内存中缓存对象与序列化字符串,结合文件mtime与size进行一致性校验。
- 维护层:在保存前执行修剪、封顶、轮转与磁盘预算清理,保证空间可控。
- 并发层:通过写锁保障同一会话文件的串行写入,避免竞态与损坏。
- 工具修复层:在读取或修复阶段对转录进行严格校验与修复,确保对外接口兼容性。
sequenceDiagram
participant Caller as "调用方"
participant Store as "会话存储(store.ts)"
participant Cache as "缓存(store-cache.ts)"
participant Maint as "维护(store-maintenance.ts)"
participant Disk as "磁盘(fs)"
participant Lock as "写锁(session-write-lock.ts)"
Caller->>Store : 更新/保存会话
Store->>Cache : 读取缓存(TTL/元信息)
alt 命中缓存
Cache-->>Store : 返回缓存对象
else 未命中
Store->>Disk : 读取sessions.json
Store->>Store : 应用迁移/规范化
Store->>Cache : 写入缓存
end
Store->>Maint : 执行修剪/封顶/轮转/磁盘预算
Maint-->>Store : 返回维护报告
Store->>Lock : 获取写锁
Lock-->>Store : 可写入
Store->>Disk : 原子写入sessions.json
Store->>Cache : 更新缓存
Store-->>Caller : 完成
详细组件分析
会话存储与缓存
- 加载流程:优先读取缓存(带TTL与mtime/size校验),否则从磁盘读取并应用迁移与规范化,再写入缓存。
- 保存流程:规范化后执行维护策略(修剪、封顶、轮转、磁盘预算),随后原子写入,最后更新缓存。
- 锁队列:内部维护Promise链式队列,确保并发写入串行化,避免竞态。
flowchart TD
Start(["开始"]) --> LoadCache["读取缓存(TTL/元信息)"]
LoadCache --> Hit{"命中?"}
Hit --> |是| ReturnCache["返回缓存对象"]
Hit --> |否| ReadDisk["读取磁盘sessions.json"]
ReadDisk --> ApplyMig["应用迁移/规范化"]
ApplyMig --> WriteCache["写入缓存"]
WriteCache --> Maintain["执行维护(修剪/封顶/轮转/磁盘预算)"]
Maintain --> AtomicWrite["原子写入sessions.json"]
AtomicWrite --> UpdateCache["更新缓存"]
UpdateCache --> End(["结束"])
ReturnCache --> End
会话维护策略(修剪/封顶/轮转/磁盘预算)
- 修剪:按updatedAt超过阈值删除条目。
- 封顶:按最近活跃排序,保留最多N条。
- 轮转:当sessions.json超过阈值大小时重命名为.bak.,并清理旧备份。
- 磁盘预算:按高水位清理最老条目,支持警告模式与强制模式。
flowchart TD
MStart(["维护入口"]) --> Mode{"模式(enforce/warn)"}
Mode --> |warn| WarnCheck["计算警告(活动会话是否会被移除)"]
WarnCheck --> ReportWarn["生成维护报告(仅统计)"]
Mode --> |enforce| Prune["修剪过期条目"]
Prune --> Cap["封顶到最大数量"]
Cap --> Archive["归档被删除会话转录"]
Archive --> Rotate["检查并轮转sessions.json"]
Rotate --> Budget["执行磁盘预算清理"]
Budget --> ReportEnforce["生成维护报告(统计+清理结果)"]
ReportWarn --> MEnd(["结束"])
ReportEnforce --> MEnd
会话路径与文件命名
- 默认存储路径:agents//sessions/sessions.json
- 转录文件命名:sessionId.jsonl 或 sessionId-topic-.jsonl
- 路径解析:支持相对/绝对路径、跨代理根兼容、安全限制与回退策略
flowchart TD
PStart(["解析会话文件路径"]) --> Opt{"传入storePath/agentId/sessionFile?"}
Opt --> |有storePath| FromStore["从storePath推导sessionsDir"]
Opt --> |无storePath| FromAgent["从agentId推导agents/<id>/sessions"]
FromStore --> Join["拼接默认sessions.json"]
FromAgent --> Join
Join --> Validate["路径合法性/安全性校验"]
Validate --> NameTranscript["根据sessionId/话题生成转录文件名"]
NameTranscript --> PEnd(["输出最终路径"])
会话转录修复与工具结果保护
- 工具调用输入修复:过滤无效/不匹配块,标准化名称,对敏感工具参数进行脱敏。
- 工具结果配对修复:严格要求assistant工具调用后紧随对应toolResult,移动/插入/去重/丢弃孤儿结果。
- 合成缺失结果:为每个工具调用ID生成合成错误结果,避免API拒绝。
- 结果细节剥离:可选剥离toolResult中的details字段,降低冗余。
flowchart TD
RStart(["读取转录"]) --> Sanitize["清洗工具调用输入"]
Sanitize --> Pair["严格配对工具调用与结果"]
Pair --> Move["移动结果到正确位置"]
Move --> Insert["为缺失ID插入合成错误结果"]
Insert --> Dedup["去重重复结果"]
Dedup --> Strip["可选剥离toolResult详情"]
Strip --> REnd(["输出修复后的转录"])
并发访问控制与写锁
- 进程级写锁:基于锁文件与PID/starttime检测,支持超时、过期回收、看门狗自动释放。
- 可重入:同进程多次获取计数累加,释放时递减至零才真正释放。
- 清理策略:注册信号处理器与退出钩子,异常终止时清理残留锁。
sequenceDiagram
participant W as "写入者"
participant L as "写锁(session-write-lock.ts)"
participant FS as "文件系统"
W->>L : 请求acquire(timeout,stale,maxHold)
L->>FS : 创建/读取锁文件(.lock)
alt 锁可用
FS-->>L : 成功
L-->>W : 返回release函数
W->>L : 执行写入
W->>L : 调用release()
L->>FS : 关闭句柄并删除锁文件
else 锁被占用
L->>L : 检查是否过期/自锁孤儿
alt 可回收
L->>FS : 删除旧锁
L->>FS : 重试获取
else 不可回收
L->>L : 等待/重试
end
end
会话工具结果守卫与状态持久化
- 守卫策略:严格配对与合成缺失结果,确保对外接口(如Anthropic)不会因历史错配而拒绝。
- 持久化:原子写入,失败重试,Windows平台增强容错;写后更新缓存与序列化缓存。
- 兼容性:迁移适配旧字段(provider→channel、room→groupChannel),保持向前兼容。
依赖关系分析
- store.ts依赖:
- 写锁:确保并发安全
- 维护模块:修剪、封顶、轮转、磁盘预算
- 缓存模块:对象与序列化缓存
- 路径模块:解析存储与转录路径
- 归档工具:删除/重命名转录文件
- 维护模块依赖:
- 配置解析:从openclaw.json读取维护策略
- 字节解析:解析大小与持续时间
- 转录修复依赖:
- 工具调用ID提取与结果ID提取
- 文件系统工具依赖:
- 路径解析与转录候选集
- 时间戳格式化/解析
graph LR
Store["store.ts"] --> Lock["session-write-lock.ts"]
Store --> Maint["store-maintenance.ts"]
Store --> Cache["store-cache.ts"]
Store --> Paths["paths.ts"]
Store --> Utils["session-utils.fs.ts"]
Maint --> Types["types.base.ts"]
Maint --> Parse["parse-bytes/parse-duration"]
Repair["session-transcript-repair.ts"] --> Store
Utils --> Paths
性能考量
- 缓存策略:启用对象与序列化缓存,结合TTL与文件元信息校验,显著降低重复解析成本。
- IO优化:Windows平台读写退避与重试,避免短暂空文件导致失败;维护阶段批量处理,减少频繁IO。
- 内存控制:缓存容量上限与LRU淘汰,避免无限增长;序列化缓存减少深拷贝。
- 并发吞吐:Promise链式队列串行化写入,避免锁竞争;看门狗定时释放长时间占用的锁。