第四部分:基础设施与客户端模块群
以下为 dsh 基础设施与客户端模块群的深度分析,涵盖 session/session-query/storage/settings/credentials/identity/interaction/guard/hooks/todo/plan/goal/feedback/schedule/jobs/spill/runtime-diagnostics/boot/bundle/preset/api/sdk/typert/client/host/extensions/acp/attachment/context/workspace/util 三十一个模块。
目录
- [session --- 持久化会话数据](#session — 持久化会话数据)
- [session-query --- 会话查询](#session-query — 会话查询)
- [storage --- 存储能力](#storage — 存储能力)
- [settings --- 用户设置](#settings — 用户设置)
- [credentials --- 凭证管理](#credentials — 凭证管理)
- [identity --- 身份标识](#identity — 身份标识)
- [interaction --- 交互/审批](#interaction — 交互/审批)
- [guard --- 安全防护](#guard — 安全防护)
- [hooks --- 钩子桥接](#hooks — 钩子桥接)
- [todo --- 待办工具](#todo — 待办工具)
- [plan --- 计划模式](#plan — 计划模式)
- [goal --- 目标管理](#goal — 目标管理)
- [feedback --- 反馈](#feedback — 反馈)
- [schedule --- 调度](#schedule — 调度)
- [jobs --- 后台任务](#jobs — 后台任务)
- [spill --- 溢出管理](#spill — 溢出管理)
- [runtime-diagnostics --- 运行时诊断](#runtime-diagnostics — 运行时诊断)
- [boot --- 启动引导](#boot — 启动引导)
- [bundle --- 打包分发](#bundle — 打包分发)
- [preset --- 预设组合](#preset — 预设组合)
- [api --- 远程 API 网关](#api — 远程 API 网关)
- [sdk --- JSON-RPC 协议](#sdk — JSON-RPC 协议)
- [typert --- 类型图](#typert — 类型图)
- [client --- 客户端](#client — 客户端)
- [host --- 宿主](#host — 宿主)
- [extensions --- 扩展](#extensions — 扩展)
- [acp --- Agent Client Protocol](#acp — Agent Client Protocol)
- [attachment --- 附件](#attachment — 附件)
- [context --- 上下文插件](#context — 上下文插件)
- [workspace --- 工作区](#workspace — 工作区)
- [util --- 工具库](#util — 工具库)
- 基础设施协作总览
session
路径 : packages/session/
核心作用: 事件溯源的会话持久化层,管理 Agent 会话的生命周期事件(turn/start, turn/end, user/message, assistant/message, tool/* 等),提供会话格式版本化、写后序列化链和检查点策略。
架构图
#mermaid-svg-PcJODCIbME1nVXcJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PcJODCIbME1nVXcJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PcJODCIbME1nVXcJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PcJODCIbME1nVXcJ .error-icon{fill:#552222;}#mermaid-svg-PcJODCIbME1nVXcJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PcJODCIbME1nVXcJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PcJODCIbME1nVXcJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PcJODCIbME1nVXcJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PcJODCIbME1nVXcJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PcJODCIbME1nVXcJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PcJODCIbME1nVXcJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PcJODCIbME1nVXcJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PcJODCIbME1nVXcJ .marker.cross{stroke:#333333;}#mermaid-svg-PcJODCIbME1nVXcJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PcJODCIbME1nVXcJ p{margin:0;}#mermaid-svg-PcJODCIbME1nVXcJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PcJODCIbME1nVXcJ .cluster-label text{fill:#333;}#mermaid-svg-PcJODCIbME1nVXcJ .cluster-label span{color:#333;}#mermaid-svg-PcJODCIbME1nVXcJ .cluster-label span p{background-color:transparent;}#mermaid-svg-PcJODCIbME1nVXcJ .label text,#mermaid-svg-PcJODCIbME1nVXcJ span{fill:#333;color:#333;}#mermaid-svg-PcJODCIbME1nVXcJ .node rect,#mermaid-svg-PcJODCIbME1nVXcJ .node circle,#mermaid-svg-PcJODCIbME1nVXcJ .node ellipse,#mermaid-svg-PcJODCIbME1nVXcJ .node polygon,#mermaid-svg-PcJODCIbME1nVXcJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PcJODCIbME1nVXcJ .rough-node .label text,#mermaid-svg-PcJODCIbME1nVXcJ .node .label text,#mermaid-svg-PcJODCIbME1nVXcJ .image-shape .label,#mermaid-svg-PcJODCIbME1nVXcJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-PcJODCIbME1nVXcJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PcJODCIbME1nVXcJ .rough-node .label,#mermaid-svg-PcJODCIbME1nVXcJ .node .label,#mermaid-svg-PcJODCIbME1nVXcJ .image-shape .label,#mermaid-svg-PcJODCIbME1nVXcJ .icon-shape .label{text-align:center;}#mermaid-svg-PcJODCIbME1nVXcJ .node.clickable{cursor:pointer;}#mermaid-svg-PcJODCIbME1nVXcJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PcJODCIbME1nVXcJ .arrowheadPath{fill:#333333;}#mermaid-svg-PcJODCIbME1nVXcJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PcJODCIbME1nVXcJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PcJODCIbME1nVXcJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PcJODCIbME1nVXcJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PcJODCIbME1nVXcJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PcJODCIbME1nVXcJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PcJODCIbME1nVXcJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PcJODCIbME1nVXcJ .cluster text{fill:#333;}#mermaid-svg-PcJODCIbME1nVXcJ .cluster span{color:#333;}#mermaid-svg-PcJODCIbME1nVXcJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PcJODCIbME1nVXcJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PcJODCIbME1nVXcJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-PcJODCIbME1nVXcJ .icon-shape,#mermaid-svg-PcJODCIbME1nVXcJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PcJODCIbME1nVXcJ .icon-shape p,#mermaid-svg-PcJODCIbME1nVXcJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PcJODCIbME1nVXcJ .icon-shape .label rect,#mermaid-svg-PcJODCIbME1nVXcJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PcJODCIbME1nVXcJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PcJODCIbME1nVXcJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PcJODCIbME1nVXcJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-PcJODCIbME1nVXcJ .core>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .core span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .core tspan{fill:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .persist>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .persist span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .persist tspan{fill:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .policy>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .policy span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .policy tspan{fill:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .proj>*{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .proj span{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .proj tspan{fill:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .title>*{fill:#f8e71c!important;stroke:#c5b416!important;color:#333!important;}#mermaid-svg-PcJODCIbME1nVXcJ .title span{fill:#f8e71c!important;stroke:#c5b416!important;color:#333!important;}#mermaid-svg-PcJODCIbME1nVXcJ .title tspan{fill:#333!important;}#mermaid-svg-PcJODCIbME1nVXcJ .tele>*{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .tele span{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-PcJODCIbME1nVXcJ .tele tspan{fill:#fff!important;} session-projection
session-checkpoint-policy
session-persistence
session 核心包
session-telemetry
SessionTelemetry
遥测协调器
OTel Backend
OpenTelemetry后端
session-title-llm
SessionTitle
标题服务
TitleLlmProvider
LLM标题生成器
Session
会话实体
SessionHeader
会话头元数据
SessionEvent
会话事件
SessionId
品牌类型ID
SessionPersistence
持久化服务
JSONL 后端
追加写入
CheckpointPolicy
检查点策略
FlushGate
刷新门控
SessionProjection
会话投影
Surface
表面节点
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Session |
类 | 会话实体,持有事件日志、表面节点(Surface)、头部元数据,提供 append() 追加事件 |
SessionHeader |
接口 | 会话元数据:id、cwd、createdAt、parentSession |
SessionEvent |
类型联合 | 事件溯源事件类型(user/message, assistant/message, turn/start, turn/end, tool/* 等) |
SessionId |
品牌类型 | Branded<'SessionId'>,跨包边界的编译时类型安全 |
SessionPersistence |
服务 | 持久化服务,提供 list() 枚举和会话加载 |
SessionProjection |
投影 | 会话事件折叠投影,通过 SessionProjectionMap 声明合并扩展 |
SessionTitle |
服务 | 会话标题生成服务,支持 LLM 提供商注册 |
CheckpointPolicy |
插件 | 语义检查点策略:模型请求前、工具分派前、步骤边界刷新持久化 |
SessionTelemetryCoordinator |
服务 | 遥测协调器,管理记录发射和共享策略 |
foldPlanMode() |
函数 | 从会话事件折叠计划模式状态(last-write-wins) |
registerSessionTitleLlmProvider() |
函数 | 注册 LLM 标题生成提供商 |
架构要点
- 事件溯源模式:所有状态变化以不可变事件追加到会话日志,投影通过折叠事件派生当前状态
- 格式版本化 :
SessionFormatVersion标记日志格式版本,跨版本兼容通过格式迁移处理 - 写后序列化链 :
Session.append()先在内存中追加事件,通过检查点策略在语义边界刷新到持久化后端 - 检查点策略 :
session-checkpoint-policy在模型请求前(llm/stream)、工具分派前(tools/execute)、步骤边界(agent/pre-step)设置刷新门控,确保持久化完成后才执行副作用 - 遥测共享策略 :
FULL/FEEDBACK_ONLY/DISABLED三级共享策略,feedback/record事件可触发反馈门控的会话前缀共享
session-query
路径 : packages/session-query/
核心作用: 会话查询能力,提供跨会话搜索、事件搜索、会话谱系追踪和事件读取工具,支持工作区访问控制。
架构图
#mermaid-svg-G7lgTTQmjrTF17qn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-G7lgTTQmjrTF17qn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-G7lgTTQmjrTF17qn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-G7lgTTQmjrTF17qn .error-icon{fill:#552222;}#mermaid-svg-G7lgTTQmjrTF17qn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-G7lgTTQmjrTF17qn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-G7lgTTQmjrTF17qn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-G7lgTTQmjrTF17qn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-G7lgTTQmjrTF17qn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-G7lgTTQmjrTF17qn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-G7lgTTQmjrTF17qn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-G7lgTTQmjrTF17qn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-G7lgTTQmjrTF17qn .marker.cross{stroke:#333333;}#mermaid-svg-G7lgTTQmjrTF17qn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-G7lgTTQmjrTF17qn p{margin:0;}#mermaid-svg-G7lgTTQmjrTF17qn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-G7lgTTQmjrTF17qn .cluster-label text{fill:#333;}#mermaid-svg-G7lgTTQmjrTF17qn .cluster-label span{color:#333;}#mermaid-svg-G7lgTTQmjrTF17qn .cluster-label span p{background-color:transparent;}#mermaid-svg-G7lgTTQmjrTF17qn .label text,#mermaid-svg-G7lgTTQmjrTF17qn span{fill:#333;color:#333;}#mermaid-svg-G7lgTTQmjrTF17qn .node rect,#mermaid-svg-G7lgTTQmjrTF17qn .node circle,#mermaid-svg-G7lgTTQmjrTF17qn .node ellipse,#mermaid-svg-G7lgTTQmjrTF17qn .node polygon,#mermaid-svg-G7lgTTQmjrTF17qn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-G7lgTTQmjrTF17qn .rough-node .label text,#mermaid-svg-G7lgTTQmjrTF17qn .node .label text,#mermaid-svg-G7lgTTQmjrTF17qn .image-shape .label,#mermaid-svg-G7lgTTQmjrTF17qn .icon-shape .label{text-anchor:middle;}#mermaid-svg-G7lgTTQmjrTF17qn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-G7lgTTQmjrTF17qn .rough-node .label,#mermaid-svg-G7lgTTQmjrTF17qn .node .label,#mermaid-svg-G7lgTTQmjrTF17qn .image-shape .label,#mermaid-svg-G7lgTTQmjrTF17qn .icon-shape .label{text-align:center;}#mermaid-svg-G7lgTTQmjrTF17qn .node.clickable{cursor:pointer;}#mermaid-svg-G7lgTTQmjrTF17qn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-G7lgTTQmjrTF17qn .arrowheadPath{fill:#333333;}#mermaid-svg-G7lgTTQmjrTF17qn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-G7lgTTQmjrTF17qn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-G7lgTTQmjrTF17qn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G7lgTTQmjrTF17qn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-G7lgTTQmjrTF17qn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G7lgTTQmjrTF17qn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-G7lgTTQmjrTF17qn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-G7lgTTQmjrTF17qn .cluster text{fill:#333;}#mermaid-svg-G7lgTTQmjrTF17qn .cluster span{color:#333;}#mermaid-svg-G7lgTTQmjrTF17qn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-G7lgTTQmjrTF17qn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-G7lgTTQmjrTF17qn rect.text{fill:none;stroke-width:0;}#mermaid-svg-G7lgTTQmjrTF17qn .icon-shape,#mermaid-svg-G7lgTTQmjrTF17qn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G7lgTTQmjrTF17qn .icon-shape p,#mermaid-svg-G7lgTTQmjrTF17qn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-G7lgTTQmjrTF17qn .icon-shape .label rect,#mermaid-svg-G7lgTTQmjrTF17qn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G7lgTTQmjrTF17qn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-G7lgTTQmjrTF17qn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-G7lgTTQmjrTF17qn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-G7lgTTQmjrTF17qn .core>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .core span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .core tspan{fill:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .tool>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .tool span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .tool tspan{fill:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .access>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .access span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-G7lgTTQmjrTF17qn .access tspan{fill:#fff!important;} tool-session-query
session-query 核心
SessionQuery
查询服务
SearchEngine
搜索引擎
LineageTracer
谱系追踪
Presentation
模型文本渲染
WorkspaceAccess
工作区访问控制
Tool Definitions
工具定义
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
SessionSearchHit |
接口 | 会话搜索结果项,包含头部、最佳匹配事件、可用性状态 |
SessionEventSearchHit |
接口 | 事件搜索结果项,包含 seq、类型、片段 |
SessionLineageTrace |
接口 | 会话谱系追踪,祖先和后代关系 |
SessionEventTraceObservation |
接口 | 事件追踪观察,替换链、派生事件 |
SessionEventWindow |
接口 | 事件窗口,目标事件及前后邻居 |
formatSessionSearch() |
函数 | 渲染会话搜索结果为模型可读文本 |
formatEventSearch() |
函数 | 渲染事件搜索结果 |
formatSessionTrace() |
函数 | 渲染会话谱系追踪 |
workspaceAccess |
对象 | 工作区访问控制:读取标题、授权后代访问 |
架构要点
- 工作区访问控制 :通过
workspaceAccess模块实现工作区边界检查,祖先/后代访问需要工作区授权 - 模型文本渲染 :
Presentation模块将查询结果格式化为模型可读的结构化文本,包含序号、时间戳、片段 - 三层查询:会话搜索(跨会话)、事件搜索(单会话内)、事件读取(单事件+上下文窗口)
storage
路径 : packages/storage/
核心作用: 存储能力枢纽,提供命名后端注册表和挂载的数据形式(KV 等),自身不执行 IO------后端拥有介质,数据形式拥有语义。
架构图
#mermaid-svg-CcE0jKc3nxuenpY5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CcE0jKc3nxuenpY5 .error-icon{fill:#552222;}#mermaid-svg-CcE0jKc3nxuenpY5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CcE0jKc3nxuenpY5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CcE0jKc3nxuenpY5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CcE0jKc3nxuenpY5 .marker.cross{stroke:#333333;}#mermaid-svg-CcE0jKc3nxuenpY5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CcE0jKc3nxuenpY5 p{margin:0;}#mermaid-svg-CcE0jKc3nxuenpY5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CcE0jKc3nxuenpY5 .cluster-label text{fill:#333;}#mermaid-svg-CcE0jKc3nxuenpY5 .cluster-label span{color:#333;}#mermaid-svg-CcE0jKc3nxuenpY5 .cluster-label span p{background-color:transparent;}#mermaid-svg-CcE0jKc3nxuenpY5 .label text,#mermaid-svg-CcE0jKc3nxuenpY5 span{fill:#333;color:#333;}#mermaid-svg-CcE0jKc3nxuenpY5 .node rect,#mermaid-svg-CcE0jKc3nxuenpY5 .node circle,#mermaid-svg-CcE0jKc3nxuenpY5 .node ellipse,#mermaid-svg-CcE0jKc3nxuenpY5 .node polygon,#mermaid-svg-CcE0jKc3nxuenpY5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CcE0jKc3nxuenpY5 .rough-node .label text,#mermaid-svg-CcE0jKc3nxuenpY5 .node .label text,#mermaid-svg-CcE0jKc3nxuenpY5 .image-shape .label,#mermaid-svg-CcE0jKc3nxuenpY5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CcE0jKc3nxuenpY5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CcE0jKc3nxuenpY5 .rough-node .label,#mermaid-svg-CcE0jKc3nxuenpY5 .node .label,#mermaid-svg-CcE0jKc3nxuenpY5 .image-shape .label,#mermaid-svg-CcE0jKc3nxuenpY5 .icon-shape .label{text-align:center;}#mermaid-svg-CcE0jKc3nxuenpY5 .node.clickable{cursor:pointer;}#mermaid-svg-CcE0jKc3nxuenpY5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CcE0jKc3nxuenpY5 .arrowheadPath{fill:#333333;}#mermaid-svg-CcE0jKc3nxuenpY5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CcE0jKc3nxuenpY5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CcE0jKc3nxuenpY5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CcE0jKc3nxuenpY5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CcE0jKc3nxuenpY5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CcE0jKc3nxuenpY5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CcE0jKc3nxuenpY5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CcE0jKc3nxuenpY5 .cluster text{fill:#333;}#mermaid-svg-CcE0jKc3nxuenpY5 .cluster span{color:#333;}#mermaid-svg-CcE0jKc3nxuenpY5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CcE0jKc3nxuenpY5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CcE0jKc3nxuenpY5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CcE0jKc3nxuenpY5 .icon-shape,#mermaid-svg-CcE0jKc3nxuenpY5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CcE0jKc3nxuenpY5 .icon-shape p,#mermaid-svg-CcE0jKc3nxuenpY5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CcE0jKc3nxuenpY5 .icon-shape .label rect,#mermaid-svg-CcE0jKc3nxuenpY5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CcE0jKc3nxuenpY5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CcE0jKc3nxuenpY5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CcE0jKc3nxuenpY5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-CcE0jKc3nxuenpY5 .hub>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .hub span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .hub tspan{fill:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .backend>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .backend span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .backend tspan{fill:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .domain>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .domain span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-CcE0jKc3nxuenpY5 .domain tspan{fill:#fff!important;} storage-domain
后端层
storage 枢纽
Storage
存储枢纽服务
BackendRegistry
后端注册表
StorageForms
数据形式表
JSON Backend
文件树后端
SQLite Backend
数据库后端
KvFacet
KV操作面
Domain Layer
领域层
DomainGlobal
领域全局单例
KvTable
KV表
defineDomain
领域定义
chmentError | 类 | 附件错误,携带稳定错误码(INVALID_IMAGE/IMAGE_TOO_LARGE/ATTACHMENT_CORRUPT等) | |ImageAttachmentRef| 接口 | 持久化图像引用:attachmentId、mediaType、bytes、width、height | |ImageAttachmentLimits| 接口 | 部署解析的限制:maxImageBytes、maxImagesPerMessage 等 | |SaveImageAttachment| 接口 | 保存请求:data、mediaType、name | |StoredImageAttachment| 接口 | 存储结果:ref + data | |LocalAttachmentStore| 类 | 本地后端,基于DSH_HOME/attachments/v1| |detectImage()| 函数 | 完全解码光栅图像,返回格式和尺寸 | |probeImage()| 函数 | 仅解析头部,不完整解码像素 | |saveImageFile()| 函数 | 保存图像:哈希→暂存→link→目录同步 | |readImageFile()| 函数 | 读取图像:读取→哈希验证→头部验证 | |validateImageFile()| 函数 | 验证图像不持久化 | |ensureDurableHome()| 函数 | 确保 DSH_HOME 目录持久性 | |ensureDurableDirectory()| 函数 | 确保目录及其祖先持久性 | |syncDirectory()` | 函数 | 同步目录条目(fsync) |
架构要点
- 内容寻址 :对象按
sha256:<hash>存储,相同内容自动去重(link EEXIST 时验证) - 不可变存储:写入后不可修改,读取时验证哈希完整性
- 持久性保证:写入后 fsync 文件和目录,确保崩溃后条目持久
- 两阶段写入:暂存文件→link 到目标→同步目录→清理暂存
- 双重验证 :写入时完全解码(
detectImage),读取时仅探头部(probeImage) - 进程级持久性证明 :
ensureDurableHome每进程独立执行一次 DSH_HOME 持久性证明 - 显示名清洗 :剥离路径分隔符(
/和\),防止本地路径泄露到引用和会话日志
context
路径 : packages/context/
核心作用 : 上下文插件群,包含 agent-instructions(工作区指令加载器)、session-reference(会话引用)、time-context(时间上下文)和 tmux-context(tmux 上下文)。
架构图
#mermaid-svg-7tdqBqhfYgu8Yyfe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7tdqBqhfYgu8Yyfe .error-icon{fill:#552222;}#mermaid-svg-7tdqBqhfYgu8Yyfe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7tdqBqhfYgu8Yyfe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .marker.cross{stroke:#333333;}#mermaid-svg-7tdqBqhfYgu8Yyfe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7tdqBqhfYgu8Yyfe p{margin:0;}#mermaid-svg-7tdqBqhfYgu8Yyfe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .cluster-label text{fill:#333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .cluster-label span{color:#333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .cluster-label span p{background-color:transparent;}#mermaid-svg-7tdqBqhfYgu8Yyfe .label text,#mermaid-svg-7tdqBqhfYgu8Yyfe span{fill:#333;color:#333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .node rect,#mermaid-svg-7tdqBqhfYgu8Yyfe .node circle,#mermaid-svg-7tdqBqhfYgu8Yyfe .node ellipse,#mermaid-svg-7tdqBqhfYgu8Yyfe .node polygon,#mermaid-svg-7tdqBqhfYgu8Yyfe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7tdqBqhfYgu8Yyfe .rough-node .label text,#mermaid-svg-7tdqBqhfYgu8Yyfe .node .label text,#mermaid-svg-7tdqBqhfYgu8Yyfe .image-shape .label,#mermaid-svg-7tdqBqhfYgu8Yyfe .icon-shape .label{text-anchor:middle;}#mermaid-svg-7tdqBqhfYgu8Yyfe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7tdqBqhfYgu8Yyfe .rough-node .label,#mermaid-svg-7tdqBqhfYgu8Yyfe .node .label,#mermaid-svg-7tdqBqhfYgu8Yyfe .image-shape .label,#mermaid-svg-7tdqBqhfYgu8Yyfe .icon-shape .label{text-align:center;}#mermaid-svg-7tdqBqhfYgu8Yyfe .node.clickable{cursor:pointer;}#mermaid-svg-7tdqBqhfYgu8Yyfe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .arrowheadPath{fill:#333333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7tdqBqhfYgu8Yyfe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7tdqBqhfYgu8Yyfe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7tdqBqhfYgu8Yyfe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7tdqBqhfYgu8Yyfe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7tdqBqhfYgu8Yyfe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7tdqBqhfYgu8Yyfe .cluster text{fill:#333;}#mermaid-svg-7tdqBqhfYgu8Yyfe .cluster span{color:#333;}#mermaid-svg-7tdqBqhfYgu8Yyfe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7tdqBqhfYgu8Yyfe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7tdqBqhfYgu8Yyfe rect.text{fill:none;stroke-width:0;}#mermaid-svg-7tdqBqhfYgu8Yyfe .icon-shape,#mermaid-svg-7tdqBqhfYgu8Yyfe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7tdqBqhfYgu8Yyfe .icon-shape p,#mermaid-svg-7tdqBqhfYgu8Yyfe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7tdqBqhfYgu8Yyfe .icon-shape .label rect,#mermaid-svg-7tdqBqhfYgu8Yyfe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7tdqBqhfYgu8Yyfe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7tdqBqhfYgu8Yyfe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7tdqBqhfYgu8Yyfe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-7tdqBqhfYgu8Yyfe .instruct>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .instruct span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .instruct tspan{fill:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .ref>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .ref span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .ref tspan{fill:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .time>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .time span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .time tspan{fill:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .tmux>*{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .tmux span{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-7tdqBqhfYgu8Yyfe .tmux tspan{fill:#fff!important;} tmux-context
Tmux Context
tmux上下文
time-context
Time Context
时间上下文
Timestamp
时间戳
Request Zone
请求时区
session-reference
Session Reference
会话引用
Projection
投影
URI
统一资源标识
Serialization
序列化
agent-instructions
Agent Instructions
工作区指令加载器
Files Loader
文件发现与读取
Render Engine
渲染引擎
State Manager
状态管理器
Config
配置
Digest
内容摘要
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
apply() |
函数 | 挂载工作区指令加载器 |
loadBaselineInstructions() |
函数 | 发现、读取、渲染基线指令链 |
loadBaselineInstructionSet() |
函数 | 加载基线+保留的文件 |
discoverBaselineInstructionFiles() |
函数 | 发现主机可见的指令候选 |
findProjectRoot() |
函数 | 向上查找项目根(标记文件) |
ancestorChain() |
函数 | 构建根到 cwd 的目录链 |
dedupInstructionFilesByDirectory() |
函数 | 按目录去重(trimmed 内容摘要) |
renderWorkspaceContext() |
函数 | 渲染基线指令链 |
renderWorkspaceInstructionSet() |
函数 | 渲染基线+保留文件 |
renderInstructionChanges() |
函数 | 渲染对账批次 |
reconcileInstructionContext() |
函数 | 对账指令上下文 |
baselineInstructionState() |
函数 | 将基线文件转为比较和元数据状态 |
probeScopeInstruction() |
函数 | 探测指令作用域 |
readScopeInstruction() |
函数 | 读取已探测的指令 |
instructionContentSha1() |
函数 | 计算内容 SHA-1 |
trimmedInstructionDigest() |
函数 | 计算修剪内容摘要(去空白) |
workspaceBaselineIdentity() |
函数 | 基线身份标识 |
candidateScopeKey() |
函数 | 每候选作用域键 |
instructionScopeKey() |
函数 | 指令作用域键 |
Config |
配置 | dshHome、projectRootMarkers、maxBytes、instructionFileCandidates 等 |
InstructionVersionCache |
类型 | WeakMap<Session, Map> 每会话元数据缓存 |
AgentInstructionChange |
接口 | 指令变更:set/replace/remove |
AgentInstructionSource |
接口 | 指令来源声明(合并到 MessageSourceMap) |
架构要点
- 三层指令发现 :用户全局(
$DSH_HOME/AGENTS.md)→ 项目根到 cwd 的目录链 → 每目录候选文件(AGENTS.md、CLAUDE.md+.local覆盖) - 字节预算 :
maxBytes限制渲染后文本长度,超出时从最不特定开始省略,最特定文件二分截断 - 内容去重:按目录修剪内容摘要去重,同目录相同内容的不同候选只保留首个
- 动态对账:文件工具触碰(read/write/edit)后异步重新加载和对账指令上下文
- 步骤边界 :步骤内触碰延迟到
step/end后投影,步骤外立即投影 - 投影排队 :通过
projectionTailsWeakMap 确保同 Agent 投影串行执行 - system-reminder 框架 :渲染文本包裹在
<system-reminder>标签中,框架在消息内容中烘焙 - 版本缓存 :
InstructionVersionCache通过 WeakMap 隔离每会话的元数据缓存 - 基线替换 :配置变更时通过
replacePreviousBaseline标记完整替换前序基线
session-reference 架构要点
- 会话引用投影:将会话引用结构投影到模型上下文
- URI 标识:通过 URI 标识会话引用目标
- 序列化:支持会话引用的序列化和反序列化
time-context 架构要点
- 时间戳:为模型提供当前时间戳上下文
- 请求时区 :
request-zone处理请求的时区信息
workspace
路径 : packages/workspace/
核心作用 : 工作区实体注册表(ctx.workspaceRegistry),管理工作区记录、稳定的注册表顺序和经头部验证的会话成员关系。基于存储域数据形式,通过 fs.realpath 规范化路径作为唯一标识。
架构图
#mermaid-svg-VNDxmRnvDcBoTdXF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VNDxmRnvDcBoTdXF .error-icon{fill:#552222;}#mermaid-svg-VNDxmRnvDcBoTdXF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VNDxmRnvDcBoTdXF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VNDxmRnvDcBoTdXF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VNDxmRnvDcBoTdXF .marker.cross{stroke:#333333;}#mermaid-svg-VNDxmRnvDcBoTdXF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VNDxmRnvDcBoTdXF p{margin:0;}#mermaid-svg-VNDxmRnvDcBoTdXF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VNDxmRnvDcBoTdXF .cluster-label text{fill:#333;}#mermaid-svg-VNDxmRnvDcBoTdXF .cluster-label span{color:#333;}#mermaid-svg-VNDxmRnvDcBoTdXF .cluster-label span p{background-color:transparent;}#mermaid-svg-VNDxmRnvDcBoTdXF .label text,#mermaid-svg-VNDxmRnvDcBoTdXF span{fill:#333;color:#333;}#mermaid-svg-VNDxmRnvDcBoTdXF .node rect,#mermaid-svg-VNDxmRnvDcBoTdXF .node circle,#mermaid-svg-VNDxmRnvDcBoTdXF .node ellipse,#mermaid-svg-VNDxmRnvDcBoTdXF .node polygon,#mermaid-svg-VNDxmRnvDcBoTdXF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VNDxmRnvDcBoTdXF .rough-node .label text,#mermaid-svg-VNDxmRnvDcBoTdXF .node .label text,#mermaid-svg-VNDxmRnvDcBoTdXF .image-shape .label,#mermaid-svg-VNDxmRnvDcBoTdXF .icon-shape .label{text-anchor:middle;}#mermaid-svg-VNDxmRnvDcBoTdXF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VNDxmRnvDcBoTdXF .rough-node .label,#mermaid-svg-VNDxmRnvDcBoTdXF .node .label,#mermaid-svg-VNDxmRnvDcBoTdXF .image-shape .label,#mermaid-svg-VNDxmRnvDcBoTdXF .icon-shape .label{text-align:center;}#mermaid-svg-VNDxmRnvDcBoTdXF .node.clickable{cursor:pointer;}#mermaid-svg-VNDxmRnvDcBoTdXF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VNDxmRnvDcBoTdXF .arrowheadPath{fill:#333333;}#mermaid-svg-VNDxmRnvDcBoTdXF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VNDxmRnvDcBoTdXF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VNDxmRnvDcBoTdXF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VNDxmRnvDcBoTdXF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VNDxmRnvDcBoTdXF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VNDxmRnvDcBoTdXF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VNDxmRnvDcBoTdXF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VNDxmRnvDcBoTdXF .cluster text{fill:#333;}#mermaid-svg-VNDxmRnvDcBoTdXF .cluster span{color:#333;}#mermaid-svg-VNDxmRnvDcBoTdXF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VNDxmRnvDcBoTdXF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VNDxmRnvDcBoTdXF rect.text{fill:none;stroke-width:0;}#mermaid-svg-VNDxmRnvDcBoTdXF .icon-shape,#mermaid-svg-VNDxmRnvDcBoTdXF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VNDxmRnvDcBoTdXF .icon-shape p,#mermaid-svg-VNDxmRnvDcBoTdXF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VNDxmRnvDcBoTdXF .icon-shape .label rect,#mermaid-svg-VNDxmRnvDcBoTdXF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VNDxmRnvDcBoTdXF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VNDxmRnvDcBoTdXF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VNDxmRnvDcBoTdXF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-VNDxmRnvDcBoTdXF .core>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .core span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .core tspan{fill:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .data>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .data span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .data tspan{fill:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .path>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .path span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .path tspan{fill:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .inv>*{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .inv span{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-VNDxmRnvDcBoTdXF .inv tspan{fill:#fff!important;} 不变量
路径
数据层
workspace 核心
WorkspaceRegistry
工作区注册表
WorkspaceEntity
工作区实体
WorkspaceEntityHost
实体宿主接口
workspaceDomainSpec
域规格
WorkspaceRecord
工作区记录
WorkspaceDomainState
域状态
Types
公共类型
realpathNormalize
路径规范化
Workspace Invariant
工作区不变量
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
WorkspaceRegistry |
服务 | 工作区注册表 ctx.workspaceRegistry,依赖 storageDomain 和 sessionPersistence |
WorkspaceEntity |
类 | 单个 Workspace 实现,持有记录快照,所有写入通过私有 mutate() |
WorkspaceEntityHost |
接口 | 实体宿主:table()/sessionPath()/readSessionHeader()/rememberSessionPath() |
Workspace |
接口 | 消费者接口:id、path、title、sessionIds、setTitle/attachSession/insertSessionBefore/detachSession/status |
WorkspaceId |
品牌类型 | Branded<'WorkspaceId'>,生成的 UUID |
WorkspaceRecord |
Zod 推断 | 持久化记录:path、title、sessionIds、createdAt、updatedAt |
WorkspaceDomainState |
Zod 推断 | 域状态:initialized、workspaceIds、archivedSessionIds、pendingMutation |
workspaceDomainSpec |
域规格 | defineDomain({ name: 'workspace', version: 2, ... }) |
realpathNormalize() |
函数 | 通过 fs.realpath 规范化目录路径 |
WorkspaceMoveInvalidError |
类 | 移动会话时引用了不在账户中的会话 |
WorkspaceUnknownSessionError |
类 | 归档时引用了未知的会话 |
WorkspaceOrderInvalidError |
类 | 重排序时引用了未知的工作区 |
架构要点
- realpath 唯一标识 :工作区路径通过
fs.realpath规范化作为唯一标识------尾斜杠、..和符号链接都被解析 - 头部验证成员关系:会话成员关系需要同时满足:id 在账户中 AND 会话头部的规范化 cwd 等于工作区路径
- 待定变更恢复 :
pendingMutation标记在域状态中,启动时恢复未完成的创建/删除操作 - 操作序列化 :
enqueueOperation()确保所有注册表写操作串行执行 - Bootstrap:首次启动时从会话头部按 cwd 分组创建工作区记录
- 过滤候选修剪:每次接受的变更都执行持久化的过滤候选修剪(移除无效 sessionIds)
- 不变量检查:域变更事件验证注册表缓存与域表的一致性------删除时缓存必须已移除,写入时缓存必须已存在
- 归档集:归档会话保留 sessionIds 槽位,取消归档恢复位置
util
路径 : packages/util/
核心作用: 共享工具库集合,提供品牌类型、原生命令执行、启动环境快照、DSH 路径解析、超时算术、输出保留和原子写入等基础能力。
架构图
#mermaid-svg-Ude4EIP9d3qWqkc8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ude4EIP9d3qWqkc8 .error-icon{fill:#552222;}#mermaid-svg-Ude4EIP9d3qWqkc8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ude4EIP9d3qWqkc8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .marker.cross{stroke:#333333;}#mermaid-svg-Ude4EIP9d3qWqkc8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ude4EIP9d3qWqkc8 p{margin:0;}#mermaid-svg-Ude4EIP9d3qWqkc8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cluster-label text{fill:#333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cluster-label span{color:#333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cluster-label span p{background-color:transparent;}#mermaid-svg-Ude4EIP9d3qWqkc8 .label text,#mermaid-svg-Ude4EIP9d3qWqkc8 span{fill:#333;color:#333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .node rect,#mermaid-svg-Ude4EIP9d3qWqkc8 .node circle,#mermaid-svg-Ude4EIP9d3qWqkc8 .node ellipse,#mermaid-svg-Ude4EIP9d3qWqkc8 .node polygon,#mermaid-svg-Ude4EIP9d3qWqkc8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ude4EIP9d3qWqkc8 .rough-node .label text,#mermaid-svg-Ude4EIP9d3qWqkc8 .node .label text,#mermaid-svg-Ude4EIP9d3qWqkc8 .image-shape .label,#mermaid-svg-Ude4EIP9d3qWqkc8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Ude4EIP9d3qWqkc8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Ude4EIP9d3qWqkc8 .rough-node .label,#mermaid-svg-Ude4EIP9d3qWqkc8 .node .label,#mermaid-svg-Ude4EIP9d3qWqkc8 .image-shape .label,#mermaid-svg-Ude4EIP9d3qWqkc8 .icon-shape .label{text-align:center;}#mermaid-svg-Ude4EIP9d3qWqkc8 .node.clickable{cursor:pointer;}#mermaid-svg-Ude4EIP9d3qWqkc8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .arrowheadPath{fill:#333333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ude4EIP9d3qWqkc8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ude4EIP9d3qWqkc8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Ude4EIP9d3qWqkc8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ude4EIP9d3qWqkc8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Ude4EIP9d3qWqkc8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cluster text{fill:#333;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cluster span{color:#333;}#mermaid-svg-Ude4EIP9d3qWqkc8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Ude4EIP9d3qWqkc8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ude4EIP9d3qWqkc8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Ude4EIP9d3qWqkc8 .icon-shape,#mermaid-svg-Ude4EIP9d3qWqkc8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ude4EIP9d3qWqkc8 .icon-shape p,#mermaid-svg-Ude4EIP9d3qWqkc8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Ude4EIP9d3qWqkc8 .icon-shape .label rect,#mermaid-svg-Ude4EIP9d3qWqkc8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ude4EIP9d3qWqkc8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ude4EIP9d3qWqkc8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ude4EIP9d3qWqkc8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-Ude4EIP9d3qWqkc8 .type>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .type span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .type tspan{fill:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cmd>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cmd span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .cmd tspan{fill:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .env>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .env span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .env tspan{fill:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .path>*{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .path span{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .path tspan{fill:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .timeout>*{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .timeout span{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .timeout tspan{fill:#fff!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .retain>*{fill:#f8e71c!important;stroke:#c5b416!important;color:#333!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .retain span{fill:#f8e71c!important;stroke:#c5b416!important;color:#333!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .retain tspan{fill:#333!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .atomic>*{fill:#50e3c2!important;stroke:#2bb89a!important;color:#333!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .atomic span{fill:#50e3c2!important;stroke:#2bb89a!important;color:#333!important;}#mermaid-svg-Ude4EIP9d3qWqkc8 .atomic tspan{fill:#333!important;} atomic-write
writeFileAtomic
原子文件写入
withFileLock
文件锁
output-retention
ItemRetainer
项保留器
formatRetentionNotice
保留通知格式化
TextRetainer
文本保留器
timeout
deadline
截止时间
TimeoutReason
超时原因
idleWatchdog
空闲看门狗
clampTimeout
钳制超时
timeoutOf
超时判定
home-paths
resolveDshHome
解析DSH主目录
expandHomePath
展开主目录前缀
canonicalizeWatchPath
规范化监视路径
launch-environment
LaunchEnvironmentSnapshot
启动环境快照
Layers
层级: process/project-env/user-env
native-command
runNativeCommand
原生命令执行器
brand
Branded<B>
品牌类型原语
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Branded<B> |
类型 | 编译时品牌类型原语,零运行时成本 |
runNativeCommand() |
函数 | 无 shell 的 execFile 执行器,utf8 stdio + abort 传播 + Windows 隐藏 |
LaunchEnvironmentSnapshot |
接口 | 不可变启动环境快照,按层级信任顺序解析变量 |
createLaunchEnvironmentSnapshot() |
函数 | 从各层内容构建快照 |
launchEnvironmentOf() |
函数 | 从上下文获取启动环境快照 |
resolveDshHome() |
函数 | 解析 DSH 主目录:配置 > $DSH_HOME > ~/.dsh |
defaultDshHome() |
函数 | 默认 DSH 主目录:~/.dsh |
expandHomePath() |
函数 | 展开 ~/~//~\ 前缀 |
canonicalizeWatchPath() |
函数 | 为文件监视器规范化路径(最深存在祖先 realpath + 缺失后缀) |
dshHomeDisplay() |
函数 | 用户友好显示形式(~/.dsh 或 $DSH_HOME) |
dshHomePath() |
函数 | 在 DSH 主目录下拼接路径段 |
deadline() |
函数 | 融合上游取消和可识别超时,返回 Deadline(信号 + 清理) |
idleWatchdog() |
函数 | 可重武装的空闲看门狗,计时器仅在 next() 待出时存在 |
clampTimeout() |
函数 | 验证、默认、钳制超时值 |
TimeoutReason |
类 | 超时原因:携带能力拥有的 code 和 timeoutMs |
timeoutOf() |
函数 | 从信号或原因载体恢复超时原因 |
MAX_TIMER_DELAY_MS |
常量 | Node 计时器不钳制为 1ms 的最大延迟 |
ItemRetainer<T> |
类 | 有序逻辑单元保留器,head 策略 |
TextRetainer |
类 | 字节导向文本流保留器,head/tail/headTail 策略 |
RetainedItems<T> |
接口 | 项保留结果 |
RetainedText |
接口 | 文本保留结果 |
formatRetentionNotice() |
函数 | 格式化保留通知(标准化省略子句 + 工具恢复指导) |
describeOmitted() |
函数 | 标准化省略措辞 |
writeFileAtomic() |
函数 | 原子文件替换:随机后缀兄弟文件 + rename |
withFileLock() |
函数 | 跨进程写入锁:wx 创建 .lock 兄弟文件 |
WriteFileAtomicOptions |
接口 | 写入选项:mode(必需)+ dirMode(可选) |
架构要点
- 品牌类型原语 :
Branded<B>是纯类型工具,零运行时代码,各包品牌自己拥有的 ID - 层级信任顺序 :启动环境按
process>project-env>user-env信任顺序解析,Windows 大小写折叠 - 冻结快照:启动环境快照在构建后不可变,后续 chdir/工作区切换/会话恢复观察相同值
- 超时融合 :
AbortSignal.any融合上游取消和超时,竞速解析为单个原因 - UTF-8 边界安全 :
TextRetainer.finish()在切割处修剪部分 UTF-8 序列,永不发出替换字符 - 原子写入 :
wx标志独占创建防止符号链接植入,同目录兄弟 rename 确保原子性 - 跨进程锁:指数退避重试(20ms→200ms),2 秒超时,从不移除现有锁(文件年龄不能证明所有者已停止)
基础设施协作总览
DeepSeek Harness 的基础设施模块群通过分层协作支撑整个 AI Agent 运行时。以下总览图展示了核心基础设施模块之间的协作关系:
#mermaid-svg-2XmrbMHk7r3YlixI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2XmrbMHk7r3YlixI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2XmrbMHk7r3YlixI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2XmrbMHk7r3YlixI .error-icon{fill:#552222;}#mermaid-svg-2XmrbMHk7r3YlixI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2XmrbMHk7r3YlixI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2XmrbMHk7r3YlixI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2XmrbMHk7r3YlixI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2XmrbMHk7r3YlixI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2XmrbMHk7r3YlixI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2XmrbMHk7r3YlixI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2XmrbMHk7r3YlixI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2XmrbMHk7r3YlixI .marker.cross{stroke:#333333;}#mermaid-svg-2XmrbMHk7r3YlixI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2XmrbMHk7r3YlixI p{margin:0;}#mermaid-svg-2XmrbMHk7r3YlixI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2XmrbMHk7r3YlixI .cluster-label text{fill:#333;}#mermaid-svg-2XmrbMHk7r3YlixI .cluster-label span{color:#333;}#mermaid-svg-2XmrbMHk7r3YlixI .cluster-label span p{background-color:transparent;}#mermaid-svg-2XmrbMHk7r3YlixI .label text,#mermaid-svg-2XmrbMHk7r3YlixI span{fill:#333;color:#333;}#mermaid-svg-2XmrbMHk7r3YlixI .node rect,#mermaid-svg-2XmrbMHk7r3YlixI .node circle,#mermaid-svg-2XmrbMHk7r3YlixI .node ellipse,#mermaid-svg-2XmrbMHk7r3YlixI .node polygon,#mermaid-svg-2XmrbMHk7r3YlixI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2XmrbMHk7r3YlixI .rough-node .label text,#mermaid-svg-2XmrbMHk7r3YlixI .node .label text,#mermaid-svg-2XmrbMHk7r3YlixI .image-shape .label,#mermaid-svg-2XmrbMHk7r3YlixI .icon-shape .label{text-anchor:middle;}#mermaid-svg-2XmrbMHk7r3YlixI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2XmrbMHk7r3YlixI .rough-node .label,#mermaid-svg-2XmrbMHk7r3YlixI .node .label,#mermaid-svg-2XmrbMHk7r3YlixI .image-shape .label,#mermaid-svg-2XmrbMHk7r3YlixI .icon-shape .label{text-align:center;}#mermaid-svg-2XmrbMHk7r3YlixI .node.clickable{cursor:pointer;}#mermaid-svg-2XmrbMHk7r3YlixI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2XmrbMHk7r3YlixI .arrowheadPath{fill:#333333;}#mermaid-svg-2XmrbMHk7r3YlixI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2XmrbMHk7r3YlixI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2XmrbMHk7r3YlixI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2XmrbMHk7r3YlixI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2XmrbMHk7r3YlixI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2XmrbMHk7r3YlixI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2XmrbMHk7r3YlixI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2XmrbMHk7r3YlixI .cluster text{fill:#333;}#mermaid-svg-2XmrbMHk7r3YlixI .cluster span{color:#333;}#mermaid-svg-2XmrbMHk7r3YlixI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2XmrbMHk7r3YlixI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2XmrbMHk7r3YlixI rect.text{fill:none;stroke-width:0;}#mermaid-svg-2XmrbMHk7r3YlixI .icon-shape,#mermaid-svg-2XmrbMHk7r3YlixI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2XmrbMHk7r3YlixI .icon-shape p,#mermaid-svg-2XmrbMHk7r3YlixI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2XmrbMHk7r3YlixI .icon-shape .label rect,#mermaid-svg-2XmrbMHk7r3YlixI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2XmrbMHk7r3YlixI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2XmrbMHk7r3YlixI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2XmrbMHk7r3YlixI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-2XmrbMHk7r3YlixI .boot>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .boot span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .boot tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .storage>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .storage span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .storage tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .session>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .session span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .session tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .config>*{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .config span{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .config tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .security>*{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .security span{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .security tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .workspace>*{fill:#50e3c2!important;stroke:#2bb89a!important;color:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .workspace span{fill:#50e3c2!important;stroke:#2bb89a!important;color:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .workspace tspan{fill:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .tool>*{fill:#f8e71c!important;stroke:#c5b416!important;color:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .tool span{fill:#f8e71c!important;stroke:#c5b416!important;color:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .tool tspan{fill:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .comm>*{fill:#ff6b6b!important;stroke:#e55353!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .comm span{fill:#ff6b6b!important;stroke:#e55353!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .comm tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .client>*{fill:#4ecdc4!important;stroke:#3bb5ac!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .client span{fill:#4ecdc4!important;stroke:#3bb5ac!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .client tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .diag>*{fill:#a55eea!important;stroke:#8e44ad!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .diag span{fill:#a55eea!important;stroke:#8e44ad!important;color:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .diag tspan{fill:#fff!important;}#mermaid-svg-2XmrbMHk7r3YlixI .util>*{fill:#dfe6e9!important;stroke:#b2bec3!important;color:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .util span{fill:#dfe6e9!important;stroke:#b2bec3!important;color:#333!important;}#mermaid-svg-2XmrbMHk7r3YlixI .util tspan{fill:#333!important;} 工具库
诊断层
客户端层
通信层
工具层
工作区层
安全层
配置层
会话层
存储层
启动层
Boot
启动引导
LaunchEnvironment
启动环境快照
HomePaths
DSH主目录解析
Storage Hub
存储枢纽
StorageDomain
领域层
Backend
后端: JSON/SQLite
Session
会话实体
SessionPersistence
会话持久化
CheckpointPolicy
检查点策略
SessionQuery
会话查询
Settings
用户设置
Credentials
凭证管理
Preset
预设组合
Guard
安全防护
Interaction
交互/审批
Attachment
附件存储
WorkspaceRegistry
工作区注册表
Context
上下文插件
Spill
溢出管理
Hooks
钩子桥接
Todo
待办工具
Plan
计划模式
Goal
目标管理
Jobs
后台任务
Schedule
调度
Feedback
反馈
API Gateway
API网关
SDK Protocol
JSON-RPC协议
ACP Bridge
Agent客户端协议
Typert
类型图
Client
客户端运行时
Host
宿主能力
Extensions
扩展系统
RuntimeDiagnostics
运行时诊断
SessionTelemetry
会话遥测
Brand
品牌类型
Timeout
超时算术
OutputRetention
输出保留
AtomicWrite
原子写入
NativeCommand
原生命令
协作说明
-
启动与存储初始化 :
Boot阶段首先通过LaunchEnvironment捕获启动环境快照,通过HomePaths解析 DSH 主目录,然后初始化Storage枢纽。Storage挂载后端(JSON/SQLite),StorageDomain在后端之上构建领域抽象(DomainGlobal、KvTable)。 -
会话持久化链 :
Session实体通过SessionPersistence持久化到存储后端。CheckpointPolicy在语义边界(模型请求前、工具分派前、步骤边界)调用sessions.flush()确保持久化完成。SessionQuery在持久化会话之上提供跨会话搜索和谱系追踪。 -
配置与预设 :
Settings和Credentials通过Storage持久化。Preset从Session事件折叠旋钮状态(沙箱模式、审批策略),通过derive()匹配预设规格。 -
安全与交互 :
Guard提供沙箱模式控制,Interaction提供审批瀑布和用户问题。Attachment提供内容寻址的不可变附件存储,通过Storage的本地后端持久化。 -
工作区管理 :
WorkspaceRegistry依赖StorageDomain(域表)和SessionPersistence(会话头部索引),通过fs.realpath规范化路径作为工作区唯一标识。Context(agent-instructions)发现和渲染工作区指令,依赖Workspace的路径信息。Spill在DSH_HOME下管理溢出文件。 -
工具生态 :
Hooks、Todo、Plan、Goal、Jobs、Schedule、Feedback等工具模块都通过Session追加事件,通过SessionProjection派生投影状态。Timeout为Jobs、Schedule、Hooks提供超时算术。OutputRetention为Spill提供有界输出保留。 -
通信与客户端 :
API Gateway通过Typert生成的 Remote 命名空间暴露主机能力,SDK提供 JSON-RPC 传输层,ACP通过 stdio 暴露自动化接口。Client通过API连接主机,Host提供目录选择等宿主能力,Extensions管理动态插件。 -
诊断与遥测 :
RuntimeDiagnostics聚合各子系统运行时状态,SessionTelemetry通过 OpenTelemetry 导出遥测数据,Feedback事件可触发反馈门控的会话共享。 -
工具库横切 :
Brand为所有跨边界 ID 提供编译时类型安全;AtomicWrite为Settings、Credentials等提供原子文件替换和跨进程锁;NativeCommand为Host的原生集成提供无 shell 命令执行。 -
不变量伴生 :每个包都有一个不变量伴生插件,通过
ctx.invariants.register()注册包级不变量检查,确保运行时状态一致性。大多数工具模块的不变量验证会话事件(如todo/write的列表完整性、plan/mode的布尔状态)。Workspace的不变量验证注册表缓存与域表的一致性。
本文档基于 DeepSeek Harness 项目源码分析生成,覆盖 31 个模块(
create包不存在,已跳过)。所有 Mermaid 图使用graph TB方向和classDef着色。分析日期:2026-08-18。
class Storage,BackendRegistry,Forms hub
class JsonBackend,SqliteBackend,KvFacet backend
class DomainLayer,DomainGlobal,KvTable,DefineDomain domain
### 关键类/函数表
| 名称 | 类型 | 职责 |
|------|------|------|
| `Storage` | 服务 | 存储枢纽,`ctx.storage`,管理后端注册和数据形式挂载 |
| `BackendRegistry` | 类 | 命名后端注册表,支持注册/解析/列表,防止重复注册 |
| `StorageBackend` | 接口 | 后端契约:拥有一种介质,暴露 KV 操作面和 `close()` |
| `KvFacet` | 接口 | KV 操作面:`open()` 打开单元,返回 `KvUnit` |
| `KvUnit` | 接口 | 已打开单元:`loadAll()`、`putRecord()`、`deleteRecord()`、`setGlobal()`、`close()` |
| `KvUnitDescriptor` | 接口 | 单元描述符:名称、版本、表名列表、是否有全局单例 |
| `StorageError` | 类 | 存储错误类,携带稳定错误码 |
| `StorageErrorCode` | 类型 | 错误码联合:`backend-not-found`、`duplicate-backend`、`version-mismatch` 等 |
| `UNIT_NAME_RE` | 常量 | 单元/表名正则:`/^[a-z][a-z0-9_]*$/` |
| `storageBackendServiceKey()` | 函数 | 派生后端生命周期服务键 |
| `defineDomain()` | 函数 | 领域定义:名称、版本、全局模式、表规格 |
| `DomainGlobal<T>` | 接口 | 领域全局单例:`get()`/`set()` |
| `KvTable<K, V>` | 接口 | KV 表:`get()`/`put()`/`delete()`/`update()`/`entries()`/`size` |
### 架构要点
- **后端不可知**:存储枢纽自身不执行任何 IO,后端拥有介质(文件树、数据库文件),数据形式拥有语义
- **多后端共存**:多个后端可同时挂载,由消费者配置决定路由
- **单元版本化**:`KvUnitDescriptor.version` 在首次物化时标记介质,版本不匹配拒绝 `version-mismatch`
- **领域层**:`storage-domain` 在 KV 之上构建领域抽象------`DomainGlobal` 单例和 `KvTable` 表接口,通过 `defineDomain()` 声明领域规格
- **写链序列化**:领域层运行每单元一个写链,确保写操作顺序一致
---
## settings
**路径**: `packages/settings/`
**核心作用**: 用户设置管理,提供命名空间设置存储和配置读写能力。
### 架构图
```mermaid
graph TB
subgraph "settings 核心"
SettingsService[Settings<br/>设置服务]
Namespace[Namespace<br/>命名空间]
SettingsPath[SettingsPath<br/>设置路径]
end
subgraph "settings-local"
LocalBackend[LocalSettings<br/>本地设置后端]
JsonStore[JSON Store<br/>文件存储]
end
SettingsService --> Namespace
Namespace --> SettingsPath
SettingsService --> LocalBackend
LocalBackend --> JsonStore
classDef core fill:#4a90d9,stroke:#357abd,color:#fff
classDef local fill:#f5a623,stroke:#d48b0a,color:#fff
class SettingsService,Namespace,SettingsPath core
class LocalBackend,JsonStore local
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Settings |
服务 | 设置服务 ctx.settings,提供命名空间读写 |
SettingsNamespaceView |
接口 | 命名空间视图,暴露路径操作和值读取 |
SettingsPathOpView |
接口 | 设置路径操作视图 |
LocalSettings |
类 | 本地设置后端,基于 JSON 文件存储 |
Config |
配置 | 设置插件配置 |
架构要点
- 命名空间隔离:设置按命名空间组织,每个命名空间独立管理其配置路径
- 原子写入 :本地设置后端使用
writeFileAtomic实现原子替换,通过withFileLock序列化跨进程写入 - 客户端投影 :通过
./client和./types双出口投影,零重复
credentials
路径 : packages/credentials/
核心作用: 凭证管理,提供 API 密钥、令牌等敏感凭证的安全存储和读取能力。
架构图
#mermaid-svg-OhU2HT7BiWTlULLK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OhU2HT7BiWTlULLK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OhU2HT7BiWTlULLK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OhU2HT7BiWTlULLK .error-icon{fill:#552222;}#mermaid-svg-OhU2HT7BiWTlULLK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OhU2HT7BiWTlULLK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OhU2HT7BiWTlULLK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OhU2HT7BiWTlULLK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OhU2HT7BiWTlULLK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OhU2HT7BiWTlULLK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OhU2HT7BiWTlULLK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OhU2HT7BiWTlULLK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OhU2HT7BiWTlULLK .marker.cross{stroke:#333333;}#mermaid-svg-OhU2HT7BiWTlULLK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OhU2HT7BiWTlULLK p{margin:0;}#mermaid-svg-OhU2HT7BiWTlULLK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OhU2HT7BiWTlULLK .cluster-label text{fill:#333;}#mermaid-svg-OhU2HT7BiWTlULLK .cluster-label span{color:#333;}#mermaid-svg-OhU2HT7BiWTlULLK .cluster-label span p{background-color:transparent;}#mermaid-svg-OhU2HT7BiWTlULLK .label text,#mermaid-svg-OhU2HT7BiWTlULLK span{fill:#333;color:#333;}#mermaid-svg-OhU2HT7BiWTlULLK .node rect,#mermaid-svg-OhU2HT7BiWTlULLK .node circle,#mermaid-svg-OhU2HT7BiWTlULLK .node ellipse,#mermaid-svg-OhU2HT7BiWTlULLK .node polygon,#mermaid-svg-OhU2HT7BiWTlULLK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OhU2HT7BiWTlULLK .rough-node .label text,#mermaid-svg-OhU2HT7BiWTlULLK .node .label text,#mermaid-svg-OhU2HT7BiWTlULLK .image-shape .label,#mermaid-svg-OhU2HT7BiWTlULLK .icon-shape .label{text-anchor:middle;}#mermaid-svg-OhU2HT7BiWTlULLK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OhU2HT7BiWTlULLK .rough-node .label,#mermaid-svg-OhU2HT7BiWTlULLK .node .label,#mermaid-svg-OhU2HT7BiWTlULLK .image-shape .label,#mermaid-svg-OhU2HT7BiWTlULLK .icon-shape .label{text-align:center;}#mermaid-svg-OhU2HT7BiWTlULLK .node.clickable{cursor:pointer;}#mermaid-svg-OhU2HT7BiWTlULLK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OhU2HT7BiWTlULLK .arrowheadPath{fill:#333333;}#mermaid-svg-OhU2HT7BiWTlULLK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OhU2HT7BiWTlULLK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OhU2HT7BiWTlULLK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OhU2HT7BiWTlULLK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OhU2HT7BiWTlULLK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OhU2HT7BiWTlULLK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OhU2HT7BiWTlULLK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OhU2HT7BiWTlULLK .cluster text{fill:#333;}#mermaid-svg-OhU2HT7BiWTlULLK .cluster span{color:#333;}#mermaid-svg-OhU2HT7BiWTlULLK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OhU2HT7BiWTlULLK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OhU2HT7BiWTlULLK rect.text{fill:none;stroke-width:0;}#mermaid-svg-OhU2HT7BiWTlULLK .icon-shape,#mermaid-svg-OhU2HT7BiWTlULLK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OhU2HT7BiWTlULLK .icon-shape p,#mermaid-svg-OhU2HT7BiWTlULLK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OhU2HT7BiWTlULLK .icon-shape .label rect,#mermaid-svg-OhU2HT7BiWTlULLK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OhU2HT7BiWTlULLK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OhU2HT7BiWTlULLK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OhU2HT7BiWTlULLK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-OhU2HT7BiWTlULLK .core>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .core span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .core tspan{fill:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .local>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .local span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .local tspan{fill:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .err>*{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .err span{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-OhU2HT7BiWTlULLK .err tspan{fill:#fff!important;} credentials-local
credentials 核心
CredentialStore
凭证存储服务
CredentialView
凭证视图
CredentialError
凭证错误
LocalCredentialStore
本地凭证后端
Encrypted Store
加密存储
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
CredentialStore |
服务 | 凭证存储服务 ctx.credentials |
CredentialView |
接口 | 凭证客户端视图,包含提供商和模型信息 |
CredentialError |
类 | 凭证错误类 |
LocalCredentialStore |
类 | 本地凭证后端实现 |
架构要点
- 安全隔离:凭证通过独立服务管理,不混入通用设置
- 客户端安全投影 :
CredentialView只暴露必要的非敏感信息给客户端 - 与设置分离:凭证独立于设置命名空间,避免意外泄露
identity
路径 : packages/identity/
核心作用: 身份标识管理,提供匿名用户 ID 和会话身份追踪能力。
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
getOrCreateAnonymousUserId() |
函数 | 获取或创建匿名用户 ID,用于遥测和反馈 |
AnonymousUserId |
类型 | 匿名用户标识符 |
架构要点
- 匿名身份:为遥测和反馈提供匿名用户标识,不泄露个人信息
- 持久化:匿名 ID 持久化存储在 DSH_HOME 下
interaction
路径 : packages/interaction/
核心作用: 交互与审批能力,提供用户问题、审批请求和交互式决策的框架。
架构图
#mermaid-svg-vjjg3fhfH117dNgp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vjjg3fhfH117dNgp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vjjg3fhfH117dNgp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vjjg3fhfH117dNgp .error-icon{fill:#552222;}#mermaid-svg-vjjg3fhfH117dNgp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vjjg3fhfH117dNgp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vjjg3fhfH117dNgp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vjjg3fhfH117dNgp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vjjg3fhfH117dNgp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vjjg3fhfH117dNgp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vjjg3fhfH117dNgp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vjjg3fhfH117dNgp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vjjg3fhfH117dNgp .marker.cross{stroke:#333333;}#mermaid-svg-vjjg3fhfH117dNgp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vjjg3fhfH117dNgp p{margin:0;}#mermaid-svg-vjjg3fhfH117dNgp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vjjg3fhfH117dNgp .cluster-label text{fill:#333;}#mermaid-svg-vjjg3fhfH117dNgp .cluster-label span{color:#333;}#mermaid-svg-vjjg3fhfH117dNgp .cluster-label span p{background-color:transparent;}#mermaid-svg-vjjg3fhfH117dNgp .label text,#mermaid-svg-vjjg3fhfH117dNgp span{fill:#333;color:#333;}#mermaid-svg-vjjg3fhfH117dNgp .node rect,#mermaid-svg-vjjg3fhfH117dNgp .node circle,#mermaid-svg-vjjg3fhfH117dNgp .node ellipse,#mermaid-svg-vjjg3fhfH117dNgp .node polygon,#mermaid-svg-vjjg3fhfH117dNgp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vjjg3fhfH117dNgp .rough-node .label text,#mermaid-svg-vjjg3fhfH117dNgp .node .label text,#mermaid-svg-vjjg3fhfH117dNgp .image-shape .label,#mermaid-svg-vjjg3fhfH117dNgp .icon-shape .label{text-anchor:middle;}#mermaid-svg-vjjg3fhfH117dNgp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vjjg3fhfH117dNgp .rough-node .label,#mermaid-svg-vjjg3fhfH117dNgp .node .label,#mermaid-svg-vjjg3fhfH117dNgp .image-shape .label,#mermaid-svg-vjjg3fhfH117dNgp .icon-shape .label{text-align:center;}#mermaid-svg-vjjg3fhfH117dNgp .node.clickable{cursor:pointer;}#mermaid-svg-vjjg3fhfH117dNgp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vjjg3fhfH117dNgp .arrowheadPath{fill:#333333;}#mermaid-svg-vjjg3fhfH117dNgp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vjjg3fhfH117dNgp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vjjg3fhfH117dNgp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vjjg3fhfH117dNgp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vjjg3fhfH117dNgp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vjjg3fhfH117dNgp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vjjg3fhfH117dNgp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vjjg3fhfH117dNgp .cluster text{fill:#333;}#mermaid-svg-vjjg3fhfH117dNgp .cluster span{color:#333;}#mermaid-svg-vjjg3fhfH117dNgp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vjjg3fhfH117dNgp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vjjg3fhfH117dNgp rect.text{fill:none;stroke-width:0;}#mermaid-svg-vjjg3fhfH117dNgp .icon-shape,#mermaid-svg-vjjg3fhfH117dNgp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vjjg3fhfH117dNgp .icon-shape p,#mermaid-svg-vjjg3fhfH117dNgp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vjjg3fhfH117dNgp .icon-shape .label rect,#mermaid-svg-vjjg3fhfH117dNgp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vjjg3fhfH117dNgp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vjjg3fhfH117dNgp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vjjg3fhfH117dNgp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-vjjg3fhfH117dNgp .core>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .core span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .core tspan{fill:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .approval>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .approval span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .approval tspan{fill:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .question>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .question span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-vjjg3fhfH117dNgp .question tspan{fill:#fff!important;} user-questions
user-approval
interaction 核心
Interaction
交互服务
ApprovalRequest
审批请求
UserQuestion
用户问题
ApprovalWaterfall
审批瀑布
ApprovalPolicy
审批策略
QuestionService
问题服务
UserQuestionError
问题错误
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
ApprovalRequest |
接口 | 审批请求:代理、工具调用 ID、选项列表 |
ApprovalWaterfall |
机制 | 审批瀑布:多个监听器依次处理审批请求 |
ApprovalPolicy |
类型 | 审批策略:never/always/on-failure 等 |
UserQuestion |
服务 | 用户问题服务,支持多选/单选问题 |
UserQuestionError |
类 | 用户问题错误 |
架构要点
- 审批瀑布 :多个审批提供者通过
ctx.on('approval/request', ...)串联,依次评估审批请求 - 一次性审批 :ACP 桥接器提供
allow-once/reject-once选项,从不推断持久授权 - 问题服务:支持向用户提出结构化问题并等待回答
guard
路径 : packages/guard/
核心作用: 安全防护层,提供沙箱模式控制和工具执行防护。
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Guard |
服务 | 安全防护服务 |
SandboxMode |
类型 | 沙箱模式:off/workspace/full |
GuardPolicy |
接口 | 防护策略配置 |
架构要点
- 沙箱模式:控制 Agent 工具执行的范围限制
- 与预设联动:沙箱模式是预设匹配的关键维度之一
hooks
路径 : packages/hooks/
核心作用 : 钩子桥接系统,将 Claude Code 和 Codex 的命令钩子适配到 dsh 的扩展点。hook-protocol 提供共享执行和解析层,hooks-claude-code 和 hooks-codex 是提供者特定的桥接器。
架构图
#mermaid-svg-HEjUR2kAGYB7gBrU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HEjUR2kAGYB7gBrU .error-icon{fill:#552222;}#mermaid-svg-HEjUR2kAGYB7gBrU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HEjUR2kAGYB7gBrU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HEjUR2kAGYB7gBrU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HEjUR2kAGYB7gBrU .marker.cross{stroke:#333333;}#mermaid-svg-HEjUR2kAGYB7gBrU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HEjUR2kAGYB7gBrU p{margin:0;}#mermaid-svg-HEjUR2kAGYB7gBrU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HEjUR2kAGYB7gBrU .cluster-label text{fill:#333;}#mermaid-svg-HEjUR2kAGYB7gBrU .cluster-label span{color:#333;}#mermaid-svg-HEjUR2kAGYB7gBrU .cluster-label span p{background-color:transparent;}#mermaid-svg-HEjUR2kAGYB7gBrU .label text,#mermaid-svg-HEjUR2kAGYB7gBrU span{fill:#333;color:#333;}#mermaid-svg-HEjUR2kAGYB7gBrU .node rect,#mermaid-svg-HEjUR2kAGYB7gBrU .node circle,#mermaid-svg-HEjUR2kAGYB7gBrU .node ellipse,#mermaid-svg-HEjUR2kAGYB7gBrU .node polygon,#mermaid-svg-HEjUR2kAGYB7gBrU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HEjUR2kAGYB7gBrU .rough-node .label text,#mermaid-svg-HEjUR2kAGYB7gBrU .node .label text,#mermaid-svg-HEjUR2kAGYB7gBrU .image-shape .label,#mermaid-svg-HEjUR2kAGYB7gBrU .icon-shape .label{text-anchor:middle;}#mermaid-svg-HEjUR2kAGYB7gBrU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HEjUR2kAGYB7gBrU .rough-node .label,#mermaid-svg-HEjUR2kAGYB7gBrU .node .label,#mermaid-svg-HEjUR2kAGYB7gBrU .image-shape .label,#mermaid-svg-HEjUR2kAGYB7gBrU .icon-shape .label{text-align:center;}#mermaid-svg-HEjUR2kAGYB7gBrU .node.clickable{cursor:pointer;}#mermaid-svg-HEjUR2kAGYB7gBrU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HEjUR2kAGYB7gBrU .arrowheadPath{fill:#333333;}#mermaid-svg-HEjUR2kAGYB7gBrU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HEjUR2kAGYB7gBrU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HEjUR2kAGYB7gBrU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HEjUR2kAGYB7gBrU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HEjUR2kAGYB7gBrU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HEjUR2kAGYB7gBrU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HEjUR2kAGYB7gBrU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HEjUR2kAGYB7gBrU .cluster text{fill:#333;}#mermaid-svg-HEjUR2kAGYB7gBrU .cluster span{color:#333;}#mermaid-svg-HEjUR2kAGYB7gBrU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HEjUR2kAGYB7gBrU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HEjUR2kAGYB7gBrU rect.text{fill:none;stroke-width:0;}#mermaid-svg-HEjUR2kAGYB7gBrU .icon-shape,#mermaid-svg-HEjUR2kAGYB7gBrU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HEjUR2kAGYB7gBrU .icon-shape p,#mermaid-svg-HEjUR2kAGYB7gBrU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HEjUR2kAGYB7gBrU .icon-shape .label rect,#mermaid-svg-HEjUR2kAGYB7gBrU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HEjUR2kAGYB7gBrU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HEjUR2kAGYB7gBrU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HEjUR2kAGYB7gBrU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-HEjUR2kAGYB7gBrU .shared>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .shared span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .shared tspan{fill:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .cc>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .cc span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .cc tspan{fill:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .codex>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .codex span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-HEjUR2kAGYB7gBrU .codex tspan{fill:#fff!important;} hooks-codex
hooks-claude-code
hook-protocol 共享层
runHook
钩子执行器
matchesMatcher
匹配器
Codec
编解码
mergeHookOutputs
输出合并
createDetachedRuns
分离运行
HookEvent
钩子事件
parseClaudeCodeConfig
CC配置解析
ClaudeCode Bridge
CC桥接器
substituteCommand
变量替换
Codex Bridge
Codex桥接器
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
runHook() |
函数 | 执行单个命令钩子,带超时和 abort 传播 |
matchesMatcher() |
函数 | 匹配器评估:正则匹配工具名/参数 |
mergeHookOutputs() |
函数 | 合并多个钩子输出为单个决策 |
createDetachedRuns() |
函数 | 创建分离运行的钩子(不阻塞主流程) |
appendHookInvoked() |
函数 | 追加钩子调用事件到会话日志 |
appendHookResult() |
函数 | 追加钩子结果事件 |
MatcherGroup |
接口 | 匹配器组:matcher + hooks 列表 |
HookOutput |
接口 | 钩子输出:stdout、stderr、退出码 |
MergedHookOutcome |
接口 | 合并后的钩子决策 |
parseClaudeCodeConfig() |
函数 | 解析 CC 钩子配置为匹配器组 |
substituteCommand() |
函数 | 替换 ${CLAUDE_PLUGIN_ROOT} 和 ${CLAUDE_PROJECT_DIR} |
架构要点
- 共享执行层 :
hook-protocol提供编解码、匹配、执行、合并的通用实现,桥接器只需处理提供者特定格式 - CC 事件映射:支持 SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、Stop、SubagentStart、SubagentStop 七种事件
- 变量替换:在解析时对命令字符串进行变量替换,而非运行时
- 分离运行 :
createDetachedRuns支持不阻塞主流程的钩子执行 - 匹配器诊断 :无效正则表达式在配置解析时即抛出
SyntaxError
todo
路径 : packages/todo/
核心作用 : 模型可见的整列表替换待办工具。每次调用追加 todo/write 快照到会话日志,重放为 last-write-wins。
架构图
#mermaid-svg-ggUKGuvl28U3gCrl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ggUKGuvl28U3gCrl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ggUKGuvl28U3gCrl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ggUKGuvl28U3gCrl .error-icon{fill:#552222;}#mermaid-svg-ggUKGuvl28U3gCrl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ggUKGuvl28U3gCrl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ggUKGuvl28U3gCrl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ggUKGuvl28U3gCrl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ggUKGuvl28U3gCrl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ggUKGuvl28U3gCrl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ggUKGuvl28U3gCrl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ggUKGuvl28U3gCrl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ggUKGuvl28U3gCrl .marker.cross{stroke:#333333;}#mermaid-svg-ggUKGuvl28U3gCrl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ggUKGuvl28U3gCrl p{margin:0;}#mermaid-svg-ggUKGuvl28U3gCrl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ggUKGuvl28U3gCrl .cluster-label text{fill:#333;}#mermaid-svg-ggUKGuvl28U3gCrl .cluster-label span{color:#333;}#mermaid-svg-ggUKGuvl28U3gCrl .cluster-label span p{background-color:transparent;}#mermaid-svg-ggUKGuvl28U3gCrl .label text,#mermaid-svg-ggUKGuvl28U3gCrl span{fill:#333;color:#333;}#mermaid-svg-ggUKGuvl28U3gCrl .node rect,#mermaid-svg-ggUKGuvl28U3gCrl .node circle,#mermaid-svg-ggUKGuvl28U3gCrl .node ellipse,#mermaid-svg-ggUKGuvl28U3gCrl .node polygon,#mermaid-svg-ggUKGuvl28U3gCrl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ggUKGuvl28U3gCrl .rough-node .label text,#mermaid-svg-ggUKGuvl28U3gCrl .node .label text,#mermaid-svg-ggUKGuvl28U3gCrl .image-shape .label,#mermaid-svg-ggUKGuvl28U3gCrl .icon-shape .label{text-anchor:middle;}#mermaid-svg-ggUKGuvl28U3gCrl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ggUKGuvl28U3gCrl .rough-node .label,#mermaid-svg-ggUKGuvl28U3gCrl .node .label,#mermaid-svg-ggUKGuvl28U3gCrl .image-shape .label,#mermaid-svg-ggUKGuvl28U3gCrl .icon-shape .label{text-align:center;}#mermaid-svg-ggUKGuvl28U3gCrl .node.clickable{cursor:pointer;}#mermaid-svg-ggUKGuvl28U3gCrl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ggUKGuvl28U3gCrl .arrowheadPath{fill:#333333;}#mermaid-svg-ggUKGuvl28U3gCrl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ggUKGuvl28U3gCrl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ggUKGuvl28U3gCrl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ggUKGuvl28U3gCrl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ggUKGuvl28U3gCrl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ggUKGuvl28U3gCrl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ggUKGuvl28U3gCrl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ggUKGuvl28U3gCrl .cluster text{fill:#333;}#mermaid-svg-ggUKGuvl28U3gCrl .cluster span{color:#333;}#mermaid-svg-ggUKGuvl28U3gCrl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ggUKGuvl28U3gCrl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ggUKGuvl28U3gCrl rect.text{fill:none;stroke-width:0;}#mermaid-svg-ggUKGuvl28U3gCrl .icon-shape,#mermaid-svg-ggUKGuvl28U3gCrl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ggUKGuvl28U3gCrl .icon-shape p,#mermaid-svg-ggUKGuvl28U3gCrl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ggUKGuvl28U3gCrl .icon-shape .label rect,#mermaid-svg-ggUKGuvl28U3gCrl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ggUKGuvl28U3gCrl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ggUKGuvl28U3gCrl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ggUKGuvl28U3gCrl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-ggUKGuvl28U3gCrl .tool>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .tool span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .tool tspan{fill:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .inv>*{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .inv span{fill:#e74c3c!important;stroke:#c0392b!important;color:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .inv tspan{fill:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .proj>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .proj span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-ggUKGuvl28U3gCrl .proj tspan{fill:#fff!important;} 会话投影
不变量
tool-todo
defineTool
todo工具定义
toTodoList
规范化列表
Types
类型声明
Client
客户端投影
validateTodos
不变量验证
todos 投影
TodoItem\[\] | null
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
defineTool('todo_write') |
工具 | 模型面向的待办写入工具 |
toTodoList() |
函数 | 规范化模型输入为 TodoItem[]:去空白、去重、并行策略检查 |
TodoItem |
接口 | 待办项:content + status(pending/in_progress/completed) |
validateTodos() |
函数 | 不变量验证:数组、非空内容、去重、合法状态 |
Config |
配置 | allowParallelInProgress:是否允许多个 in_progress |
SessionProjectionMap.todos |
声明合并 | todos 投影键声明 |
架构要点
- 整列表替换:每次调用携带完整替换列表,无增量更新
- 并行策略 :
allowParallelInProgress配置控制是否允许多个in_progress项 - 投影声明合并 :通过
SessionProjectionMap声明合并扩展todos投影键 - 双出口投影 :
./types供主机消费者,./client供客户端聚合,零内容重复
plan
路径 : packages/plan/
核心作用 : 计划模式是按 Agent 记录的协作状态。激活时,部署拥有的指导段落包含在每个模型请求中,exit_plan_mode 工具呈现完成计划供用户审查。
架构图
#mermaid-svg-MzkIylE49Si4D3oX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MzkIylE49Si4D3oX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MzkIylE49Si4D3oX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MzkIylE49Si4D3oX .error-icon{fill:#552222;}#mermaid-svg-MzkIylE49Si4D3oX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MzkIylE49Si4D3oX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MzkIylE49Si4D3oX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MzkIylE49Si4D3oX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MzkIylE49Si4D3oX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MzkIylE49Si4D3oX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MzkIylE49Si4D3oX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MzkIylE49Si4D3oX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MzkIylE49Si4D3oX .marker.cross{stroke:#333333;}#mermaid-svg-MzkIylE49Si4D3oX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MzkIylE49Si4D3oX p{margin:0;}#mermaid-svg-MzkIylE49Si4D3oX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MzkIylE49Si4D3oX .cluster-label text{fill:#333;}#mermaid-svg-MzkIylE49Si4D3oX .cluster-label span{color:#333;}#mermaid-svg-MzkIylE49Si4D3oX .cluster-label span p{background-color:transparent;}#mermaid-svg-MzkIylE49Si4D3oX .label text,#mermaid-svg-MzkIylE49Si4D3oX span{fill:#333;color:#333;}#mermaid-svg-MzkIylE49Si4D3oX .node rect,#mermaid-svg-MzkIylE49Si4D3oX .node circle,#mermaid-svg-MzkIylE49Si4D3oX .node ellipse,#mermaid-svg-MzkIylE49Si4D3oX .node polygon,#mermaid-svg-MzkIylE49Si4D3oX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MzkIylE49Si4D3oX .rough-node .label text,#mermaid-svg-MzkIylE49Si4D3oX .node .label text,#mermaid-svg-MzkIylE49Si4D3oX .image-shape .label,#mermaid-svg-MzkIylE49Si4D3oX .icon-shape .label{text-anchor:middle;}#mermaid-svg-MzkIylE49Si4D3oX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MzkIylE49Si4D3oX .rough-node .label,#mermaid-svg-MzkIylE49Si4D3oX .node .label,#mermaid-svg-MzkIylE49Si4D3oX .image-shape .label,#mermaid-svg-MzkIylE49Si4D3oX .icon-shape .label{text-align:center;}#mermaid-svg-MzkIylE49Si4D3oX .node.clickable{cursor:pointer;}#mermaid-svg-MzkIylE49Si4D3oX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MzkIylE49Si4D3oX .arrowheadPath{fill:#333333;}#mermaid-svg-MzkIylE49Si4D3oX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MzkIylE49Si4D3oX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MzkIylE49Si4D3oX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MzkIylE49Si4D3oX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MzkIylE49Si4D3oX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MzkIylE49Si4D3oX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MzkIylE49Si4D3oX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MzkIylE49Si4D3oX .cluster text{fill:#333;}#mermaid-svg-MzkIylE49Si4D3oX .cluster span{color:#333;}#mermaid-svg-MzkIylE49Si4D3oX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MzkIylE49Si4D3oX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MzkIylE49Si4D3oX rect.text{fill:none;stroke-width:0;}#mermaid-svg-MzkIylE49Si4D3oX .icon-shape,#mermaid-svg-MzkIylE49Si4D3oX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MzkIylE49Si4D3oX .icon-shape p,#mermaid-svg-MzkIylE49Si4D3oX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MzkIylE49Si4D3oX .icon-shape .label rect,#mermaid-svg-MzkIylE49Si4D3oX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MzkIylE49Si4D3oX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MzkIylE49Si4D3oX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MzkIylE49Si4D3oX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-MzkIylE49Si4D3oX .core>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .core span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .core tspan{fill:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .event>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .event span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .event tspan{fill:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .interact>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .interact span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-MzkIylE49Si4D3oX .interact tspan{fill:#fff!important;} 交互
会话事件
plan-mode 核心
PlanModeController
计划模式控制器
PlanModeConfig
配置
exit_plan_mode
退出工具
PlanProjection
计划投影
plan/mode
计划模式事件
command/run
命令运行事件
ReviewQuestion
审查问题
User Feedback
用户反馈
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
PlanModeController |
服务 | 计划模式控制器 ctx.planMode |
PlanModeConfig |
接口 | 配置:section 指导段落 |
PlanProjection |
接口 | 投影:active + pending |
EXIT_PLAN_MODE |
常量 | 退出工具名称 'exit_plan_mode' |
SessionEventMap['plan/mode'] |
声明合并 | 计划模式事件:{ active: boolean } |
SessionProjectionMap.plan |
声明合并 | 计划投影键声明 |
resolveConfig() |
函数 | 验证部署指导配置 |
foldPlanMode() |
函数 | 从事件折叠计划模式状态 |
架构要点
- 日志状态 :计划模式状态记录在会话日志中(
plan/mode事件),恢复和分叉无需活动镜像 - 待定状态:用户选择在下一个接受的回合前步骤前保持待定
- 工具目录稳定 :
exit_plan_mode工具在计划模式未激活时也保持注册,模式切换只改变提示段落 - 审查交互:退出工具通过用户问题服务呈现审查选择(批准/继续计划)
goal
路径 : packages/goal/
核心作用 : 目标管理工具,提供 get_goal、create_goal、update_goal 模型面向工具,支持目标创建、完成和阻塞的状态管理。
架构图
#mermaid-svg-kMkbDlIJTtnfT6s3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kMkbDlIJTtnfT6s3 .error-icon{fill:#552222;}#mermaid-svg-kMkbDlIJTtnfT6s3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kMkbDlIJTtnfT6s3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .marker.cross{stroke:#333333;}#mermaid-svg-kMkbDlIJTtnfT6s3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kMkbDlIJTtnfT6s3 p{margin:0;}#mermaid-svg-kMkbDlIJTtnfT6s3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .cluster-label text{fill:#333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .cluster-label span{color:#333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .cluster-label span p{background-color:transparent;}#mermaid-svg-kMkbDlIJTtnfT6s3 .label text,#mermaid-svg-kMkbDlIJTtnfT6s3 span{fill:#333;color:#333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .node rect,#mermaid-svg-kMkbDlIJTtnfT6s3 .node circle,#mermaid-svg-kMkbDlIJTtnfT6s3 .node ellipse,#mermaid-svg-kMkbDlIJTtnfT6s3 .node polygon,#mermaid-svg-kMkbDlIJTtnfT6s3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kMkbDlIJTtnfT6s3 .rough-node .label text,#mermaid-svg-kMkbDlIJTtnfT6s3 .node .label text,#mermaid-svg-kMkbDlIJTtnfT6s3 .image-shape .label,#mermaid-svg-kMkbDlIJTtnfT6s3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-kMkbDlIJTtnfT6s3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kMkbDlIJTtnfT6s3 .rough-node .label,#mermaid-svg-kMkbDlIJTtnfT6s3 .node .label,#mermaid-svg-kMkbDlIJTtnfT6s3 .image-shape .label,#mermaid-svg-kMkbDlIJTtnfT6s3 .icon-shape .label{text-align:center;}#mermaid-svg-kMkbDlIJTtnfT6s3 .node.clickable{cursor:pointer;}#mermaid-svg-kMkbDlIJTtnfT6s3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .arrowheadPath{fill:#333333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kMkbDlIJTtnfT6s3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kMkbDlIJTtnfT6s3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kMkbDlIJTtnfT6s3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kMkbDlIJTtnfT6s3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kMkbDlIJTtnfT6s3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kMkbDlIJTtnfT6s3 .cluster text{fill:#333;}#mermaid-svg-kMkbDlIJTtnfT6s3 .cluster span{color:#333;}#mermaid-svg-kMkbDlIJTtnfT6s3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kMkbDlIJTtnfT6s3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kMkbDlIJTtnfT6s3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-kMkbDlIJTtnfT6s3 .icon-shape,#mermaid-svg-kMkbDlIJTtnfT6s3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kMkbDlIJTtnfT6s3 .icon-shape p,#mermaid-svg-kMkbDlIJTtnfT6s3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kMkbDlIJTtnfT6s3 .icon-shape .label rect,#mermaid-svg-kMkbDlIJTtnfT6s3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kMkbDlIJTtnfT6s3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kMkbDlIJTtnfT6s3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kMkbDlIJTtnfT6s3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-kMkbDlIJTtnfT6s3 .tool>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .tool span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .tool tspan{fill:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .domain>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .domain span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .domain tspan{fill:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .auth>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .auth span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-kMkbDlIJTtnfT6s3 .auth tspan{fill:#fff!important;} 权限模型
goal 领域
tool-goal
Goal Tools
目标工具集
Authority
权限检查
Wrapup
收尾指令
GoalView
目标视图
GoalId
目标ID
GoalRef
目标引用
Goals Service
目标服务
direct-human
直接人类输入
goal-round
目标回合
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
goalToolExecution() |
函数 | 认证调用代理和驱动边界 |
requireDirectHuman() |
函数 | 要求直接人类输入权限 |
completionAuthority() |
函数 | 解析完成权限:直接人类或目标回合 |
GoalToolAuthority |
类型 | 权限联合:direct-human |
renderWrapupContext() |
函数 | 渲染终端自主目标更新的收尾指令 |
GoalView |
接口 | 目标视图:id、revision、roundsStarted |
GoalId |
品牌类型 | Branded<'GoalId'> |
架构要点
- 权限模型:目标操作需要权限------直接人类输入或当前目标回合
- 驱动边界检查 :
goalToolExecution()验证调用代理是当前活动驱动发起者 - 收尾指令:自主目标回合结束后注入收尾上下文,让模型向用户致辞
- 回合匹配 :通过
isMatchingGoalRound()验证当前回合是否为目标许可回合
feedback
路径 : packages/feedback/
核心作用 : 会话反馈机制,包括 /feedback 命令(追加 feedback/record 事件)和消息级反馈(持久化到存储域)。
架构图
#mermaid-svg-R45az4kWlrHStOnd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-R45az4kWlrHStOnd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-R45az4kWlrHStOnd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-R45az4kWlrHStOnd .error-icon{fill:#552222;}#mermaid-svg-R45az4kWlrHStOnd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-R45az4kWlrHStOnd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-R45az4kWlrHStOnd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-R45az4kWlrHStOnd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-R45az4kWlrHStOnd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-R45az4kWlrHStOnd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-R45az4kWlrHStOnd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-R45az4kWlrHStOnd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-R45az4kWlrHStOnd .marker.cross{stroke:#333333;}#mermaid-svg-R45az4kWlrHStOnd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-R45az4kWlrHStOnd p{margin:0;}#mermaid-svg-R45az4kWlrHStOnd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-R45az4kWlrHStOnd .cluster-label text{fill:#333;}#mermaid-svg-R45az4kWlrHStOnd .cluster-label span{color:#333;}#mermaid-svg-R45az4kWlrHStOnd .cluster-label span p{background-color:transparent;}#mermaid-svg-R45az4kWlrHStOnd .label text,#mermaid-svg-R45az4kWlrHStOnd span{fill:#333;color:#333;}#mermaid-svg-R45az4kWlrHStOnd .node rect,#mermaid-svg-R45az4kWlrHStOnd .node circle,#mermaid-svg-R45az4kWlrHStOnd .node ellipse,#mermaid-svg-R45az4kWlrHStOnd .node polygon,#mermaid-svg-R45az4kWlrHStOnd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-R45az4kWlrHStOnd .rough-node .label text,#mermaid-svg-R45az4kWlrHStOnd .node .label text,#mermaid-svg-R45az4kWlrHStOnd .image-shape .label,#mermaid-svg-R45az4kWlrHStOnd .icon-shape .label{text-anchor:middle;}#mermaid-svg-R45az4kWlrHStOnd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-R45az4kWlrHStOnd .rough-node .label,#mermaid-svg-R45az4kWlrHStOnd .node .label,#mermaid-svg-R45az4kWlrHStOnd .image-shape .label,#mermaid-svg-R45az4kWlrHStOnd .icon-shape .label{text-align:center;}#mermaid-svg-R45az4kWlrHStOnd .node.clickable{cursor:pointer;}#mermaid-svg-R45az4kWlrHStOnd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-R45az4kWlrHStOnd .arrowheadPath{fill:#333333;}#mermaid-svg-R45az4kWlrHStOnd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-R45az4kWlrHStOnd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-R45az4kWlrHStOnd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R45az4kWlrHStOnd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-R45az4kWlrHStOnd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R45az4kWlrHStOnd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-R45az4kWlrHStOnd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-R45az4kWlrHStOnd .cluster text{fill:#333;}#mermaid-svg-R45az4kWlrHStOnd .cluster span{color:#333;}#mermaid-svg-R45az4kWlrHStOnd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-R45az4kWlrHStOnd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-R45az4kWlrHStOnd rect.text{fill:none;stroke-width:0;}#mermaid-svg-R45az4kWlrHStOnd .icon-shape,#mermaid-svg-R45az4kWlrHStOnd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R45az4kWlrHStOnd .icon-shape p,#mermaid-svg-R45az4kWlrHStOnd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-R45az4kWlrHStOnd .icon-shape .label rect,#mermaid-svg-R45az4kWlrHStOnd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R45az4kWlrHStOnd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-R45az4kWlrHStOnd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-R45az4kWlrHStOnd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-R45az4kWlrHStOnd .cmd>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .cmd span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .cmd tspan{fill:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .msg>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .msg span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .msg tspan{fill:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .tele>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .tele span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-R45az4kWlrHStOnd .tele tspan{fill:#fff!important;} 遥测集成
command-feedback
message-feedback
MessageFeedback
消息反馈
Spec
存储规格
MessageFeedbackItem
反馈项
Storage Domain
存储域
feedback 命令
反馈命令
recordFeedback
记录反馈
feedback/record
反馈事件
SessionTelemetry
遥测
SharingDisclosure
共享披露
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
recordFeedback() |
函数 | 记录反馈到会话日志(feedback/record 事件) |
executeFeedbackCommand() |
函数 | 执行 /feedback 命令:验证、记录、确认 |
sharingDisclosure() |
函数 | 生成共享策略披露文本 |
MessageFeedbackItem |
接口 | 消息反馈项:messageId、rating、note、version |
MessageFeedbackRating |
类型 | 评分:positive |
messageFeedbackRowSchema |
Zod 模式 | 消息反馈行持久化模式 |
messageFeedbackItemSchema |
Zod 模式 | 反馈项模式,含时间戳一致性验证 |
架构要点
- 双层反馈 :会话级反馈(
feedback/record事件,追加到会话日志)和消息级反馈(独立存储域 sidecar) - 共享披露 :
/feedback确认包含会话共享策略状态(full/feedback-only/disabled) - 匿名用户:反馈确认包含匿名用户 ID
- 消息反馈存储域:消息级反馈使用独立存储域,按会话生命周期隔离
schedule
路径 : packages/schedule/
核心作用: 调度系统,为根 Agent 提供一次性提醒和重复提醒能力。使用实时计时器投影和事务序列化确保调度一致性。
架构图
#mermaid-svg-MlO7UUvqx9X8hPg1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MlO7UUvqx9X8hPg1 .error-icon{fill:#552222;}#mermaid-svg-MlO7UUvqx9X8hPg1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MlO7UUvqx9X8hPg1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .marker.cross{stroke:#333333;}#mermaid-svg-MlO7UUvqx9X8hPg1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MlO7UUvqx9X8hPg1 p{margin:0;}#mermaid-svg-MlO7UUvqx9X8hPg1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .cluster-label text{fill:#333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .cluster-label span{color:#333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .cluster-label span p{background-color:transparent;}#mermaid-svg-MlO7UUvqx9X8hPg1 .label text,#mermaid-svg-MlO7UUvqx9X8hPg1 span{fill:#333;color:#333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .node rect,#mermaid-svg-MlO7UUvqx9X8hPg1 .node circle,#mermaid-svg-MlO7UUvqx9X8hPg1 .node ellipse,#mermaid-svg-MlO7UUvqx9X8hPg1 .node polygon,#mermaid-svg-MlO7UUvqx9X8hPg1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MlO7UUvqx9X8hPg1 .rough-node .label text,#mermaid-svg-MlO7UUvqx9X8hPg1 .node .label text,#mermaid-svg-MlO7UUvqx9X8hPg1 .image-shape .label,#mermaid-svg-MlO7UUvqx9X8hPg1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-MlO7UUvqx9X8hPg1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MlO7UUvqx9X8hPg1 .rough-node .label,#mermaid-svg-MlO7UUvqx9X8hPg1 .node .label,#mermaid-svg-MlO7UUvqx9X8hPg1 .image-shape .label,#mermaid-svg-MlO7UUvqx9X8hPg1 .icon-shape .label{text-align:center;}#mermaid-svg-MlO7UUvqx9X8hPg1 .node.clickable{cursor:pointer;}#mermaid-svg-MlO7UUvqx9X8hPg1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .arrowheadPath{fill:#333333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MlO7UUvqx9X8hPg1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MlO7UUvqx9X8hPg1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MlO7UUvqx9X8hPg1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MlO7UUvqx9X8hPg1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MlO7UUvqx9X8hPg1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MlO7UUvqx9X8hPg1 .cluster text{fill:#333;}#mermaid-svg-MlO7UUvqx9X8hPg1 .cluster span{color:#333;}#mermaid-svg-MlO7UUvqx9X8hPg1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MlO7UUvqx9X8hPg1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MlO7UUvqx9X8hPg1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-MlO7UUvqx9X8hPg1 .icon-shape,#mermaid-svg-MlO7UUvqx9X8hPg1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MlO7UUvqx9X8hPg1 .icon-shape p,#mermaid-svg-MlO7UUvqx9X8hPg1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MlO7UUvqx9X8hPg1 .icon-shape .label rect,#mermaid-svg-MlO7UUvqx9X8hPg1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MlO7UUvqx9X8hPg1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MlO7UUvqx9X8hPg1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MlO7UUvqx9X8hPg1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-MlO7UUvqx9X8hPg1 .core>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .core span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .core tspan{fill:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .type>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .type span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .type tspan{fill:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .runtime>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .runtime span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .runtime tspan{fill:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .persist>*{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .persist span{fill:#bd10e0!important;stroke:#9c0bb3!important;color:#fff!important;}#mermaid-svg-MlO7UUvqx9X8hPg1 .persist tspan{fill:#fff!important;} 持久化
运行时
调度类型
schedule 核心
ScheduleRuntime
调度运行时
runScheduleTransaction
事务序列化
Domain Logic
领域逻辑
OneShotSchedule
一次性调度
EverySchedule
重复调度
TimerProjection
计时器投影
DueDecision
到期决策
Drive Loop
驱动循环
flushSchedulePersistence
刷新持久化
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
ScheduleRuntime |
类 | 一次性实时计时器投影,驱动到期决策 |
runScheduleTransaction() |
函数 | Agent 级事务序列化 |
foldScheduleEvents() |
函数 | 折叠调度事件为当前状态 |
resolveEveryOccurrence() |
函数 | 解析重复调度的下一次发生 |
renderReminderFraming() |
函数 | 渲染提醒框架文本 |
renderEveryReminderBatchFraming() |
函数 | 渲染批量提醒框架 |
flushSchedulePersistence() |
函数 | 刷新调度持久化 |
ScheduleLogError |
类 | 调度日志错误 |
FoldedSchedules |
接口 | 折叠后的调度状态:active 列表 |
DueDecision |
类型 | 到期决策:one-shot/every/wait |
MAX_TIMER_DELAY_MS |
常量 | Node 计时器最大延迟 |
架构要点
- Agent 级序列化 :通过
WeakMap<Agent, Promise>实现每 Agent 事务串行化 - 到期决策 :
dueDecision()按优先级选择到期的一次性调度、批量到期重复调度、或等待下一次唤醒 - 合并触发:多个触发合并到一次驱动循环,避免重复计算
- 计时器管理:实时计时器投影,到期前清除并重设
- 提醒框架:提醒消息使用 framing 文本包装,注入到 Agent inbox
jobs
路径 : packages/jobs/
核心作用: 后台任务能力,提供进程内作业注册表,支持任务启动、取消、等待和输出读取。
架构图
#mermaid-svg-rYzx0nWTs3CFoFKv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rYzx0nWTs3CFoFKv .error-icon{fill:#552222;}#mermaid-svg-rYzx0nWTs3CFoFKv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rYzx0nWTs3CFoFKv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rYzx0nWTs3CFoFKv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rYzx0nWTs3CFoFKv .marker.cross{stroke:#333333;}#mermaid-svg-rYzx0nWTs3CFoFKv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rYzx0nWTs3CFoFKv p{margin:0;}#mermaid-svg-rYzx0nWTs3CFoFKv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rYzx0nWTs3CFoFKv .cluster-label text{fill:#333;}#mermaid-svg-rYzx0nWTs3CFoFKv .cluster-label span{color:#333;}#mermaid-svg-rYzx0nWTs3CFoFKv .cluster-label span p{background-color:transparent;}#mermaid-svg-rYzx0nWTs3CFoFKv .label text,#mermaid-svg-rYzx0nWTs3CFoFKv span{fill:#333;color:#333;}#mermaid-svg-rYzx0nWTs3CFoFKv .node rect,#mermaid-svg-rYzx0nWTs3CFoFKv .node circle,#mermaid-svg-rYzx0nWTs3CFoFKv .node ellipse,#mermaid-svg-rYzx0nWTs3CFoFKv .node polygon,#mermaid-svg-rYzx0nWTs3CFoFKv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rYzx0nWTs3CFoFKv .rough-node .label text,#mermaid-svg-rYzx0nWTs3CFoFKv .node .label text,#mermaid-svg-rYzx0nWTs3CFoFKv .image-shape .label,#mermaid-svg-rYzx0nWTs3CFoFKv .icon-shape .label{text-anchor:middle;}#mermaid-svg-rYzx0nWTs3CFoFKv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rYzx0nWTs3CFoFKv .rough-node .label,#mermaid-svg-rYzx0nWTs3CFoFKv .node .label,#mermaid-svg-rYzx0nWTs3CFoFKv .image-shape .label,#mermaid-svg-rYzx0nWTs3CFoFKv .icon-shape .label{text-align:center;}#mermaid-svg-rYzx0nWTs3CFoFKv .node.clickable{cursor:pointer;}#mermaid-svg-rYzx0nWTs3CFoFKv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rYzx0nWTs3CFoFKv .arrowheadPath{fill:#333333;}#mermaid-svg-rYzx0nWTs3CFoFKv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rYzx0nWTs3CFoFKv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rYzx0nWTs3CFoFKv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rYzx0nWTs3CFoFKv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rYzx0nWTs3CFoFKv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rYzx0nWTs3CFoFKv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rYzx0nWTs3CFoFKv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rYzx0nWTs3CFoFKv .cluster text{fill:#333;}#mermaid-svg-rYzx0nWTs3CFoFKv .cluster span{color:#333;}#mermaid-svg-rYzx0nWTs3CFoFKv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rYzx0nWTs3CFoFKv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rYzx0nWTs3CFoFKv rect.text{fill:none;stroke-width:0;}#mermaid-svg-rYzx0nWTs3CFoFKv .icon-shape,#mermaid-svg-rYzx0nWTs3CFoFKv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rYzx0nWTs3CFoFKv .icon-shape p,#mermaid-svg-rYzx0nWTs3CFoFKv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rYzx0nWTs3CFoFKv .icon-shape .label rect,#mermaid-svg-rYzx0nWTs3CFoFKv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rYzx0nWTs3CFoFKv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rYzx0nWTs3CFoFKv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rYzx0nWTs3CFoFKv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-rYzx0nWTs3CFoFKv .abs>*{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .abs span{fill:#4a90d9!important;stroke:#357abd!important;color:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .abs tspan{fill:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .impl>*{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .impl span{fill:#f5a623!important;stroke:#d48b0a!important;color:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .impl tspan{fill:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .scope>*{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .scope span{fill:#7ed321!important;stroke:#5da018!important;color:#fff!important;}#mermaid-svg-rYzx0nWTs3CFoFKv .scope tspan{fill:#fff!important;} 作用域
jobs-local 实现
jobs 抽象层
JobRegistry
作业注册表抽象
JobId
品牌类型
JobSnapshot
作业快照
JobStart
启动规格
LocalJobRegistry
本地注册表
TrackedTask
追踪任务
ScopedLayers
作用域分层
JobLayer
作业层
Controllers
控制器
JobDoneListeners
完成监听器
JobsChangedListeners
变更监听器
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
JobRegistry |
抽象服务 | 作业注册表 ctx.jobs |
LocalJobRegistry |
类 | 进程内实现,内存存储所有记录 |
JobId |
品牌类型 | Branded<'JobId'> |
JobSnapshot |
接口 | 不可变快照:id、kind、label、status、output |
JobStart |
接口 | 启动规格:kind、label、owner、run()、outputLimitBytes |
JobStatus |
类型 | running/stopping/completed/killed/failed |
JobKind |
类型 | 作业类型字符串 |
JobOutcome |
类型 | 作业结果 |
JobDoneListener |
类型 | 完成监听器 |
JobsChangedListener |
类型 | 变更监听器 |
TrackedTask |
接口 | 内部追踪记录(不对外暴露) |
JobLayer |
类 | 作用域层:控制器、监听器、变更通知 |
ScopedLayers |
类 | 作用域分层管理 |
TASK_WAIT_TIMEOUT |
常量 | 等待超时码 |
DEFAULT_MAX_CONCURRENT_TASKS_PER_OWNER |
常量 | 默认每 owner 最大并发:10 |
架构要点
- 作用域分层:作业控制器和监听器按注册上下文的作用域分层,读取是 owner 相对的
- 快照隔离 :
snapshot()只返回不可变快照,永不返回活动状态 - 并发限制:每 owner 最大并发作业数限制,超出拒绝
- 生命周期独立:注册表记录比生产者和控制器光纤寿命更长
- 清理钩子:Agent 或服务销毁时取消活动工作并等待合规生产者