Deepseek-harness增加桌面版端序列:第 6 讲 · core 六包主线:一次回合的骨架

📅 2026/8/22 2:22:47
Deepseek-harness增加桌面版端序列:第 6 讲 · core 六包主线:一次回合的骨架
第 6 讲 · core 六包主线一次回合的骨架系列我在Deepseek harness中增加了桌面版将逐行代码解析我是怎么增加的希望你也能创建属于自己的桌面版Agent本讲目标走读packages/core/六个核心包的关键导出与依赖关系——session事件日志、system-prompt组装、tools管道、agent接口、agent-loop驱动、scope隔离。目标掌握一次回合的骨架与六包的依赖方向。方式关键类型/函数精讲非全行——本讲是支线精讲。代码仓库https://github.com/tslcarmack/deepseek-harness-desktopDesktop App 运行效果图 本讲地图scope依赖最底层纯库 ▲ ├── sessionctx.sessions事件日志 ├── system-promptctx.systemPrompt提示词组装 ├── toolsctx.tools工具管道 └── agentctx.agentsAgent 接口 ▲ └── agent-loopctx.agentLoop唯一实现最上层依赖法则扩展插件依赖agent接口永不直接依赖agent-loop实现——所以主循环可被替换。这就是脊梁可换、接口稳定的架构。 1. scope作用域原语packages/core/scope/src/index.ts定位非服务纯库被 session/system-prompt 无环引用。exportfunctioncreateScope(ctx:Context,key:ScopeKey,options?:CreateScopeOptions):ScopeexportfunctionscopeOf(ctx:Context):ScopeKey|undefinedexportfunctionscopeTarget(base:T,key:ScopeKey|undefined):ScopedexportfunctionbindScopeParent(key:ScopeKey,parent:ScopeKey):ScopeParentBindingexportfunctionscopeParentOf(key:ScopeKey):ScopeKey|undefinedexportfunctionscopeChainOf(key:ScopeKey|undefined):ScopeKey[]精讲函数作用createScope为某个 key默认是 Agent 对象铸一个注册作用域返回{ ctx, rawDispose, dispose }scopeOf从 ctx 取当前作用域 keyscopeTarget生成带品牌的路由接收器——作用域过滤事件用它做thisbindScopeParent/scopeParentOf/scopeChainOf作用域继承链子 agent 可见父级注册为什么重要一个进程跑多个 agent 时ctx.tools.register()到底注册给全局还是某个 agent由作用域决定。ScopedLayersstore.ts管理全局层 精确作用域层层空即回收。 2. session事件日志packages/core/session/src/index.ts定位Session第 425 行是追加式事件日志SessionStore第 792 行管理多个 session。exportclassSession{// 核心方法示意append(event:SessionEvent):voidderiveMessages():Message[]// 从日志派生模型历史fork(source,boundary?,childSessionId?):Session}exportclassSessionStoreextendsService{// ctx.sessions 的实现}精讲成员作用append追加一条 SessionEventturn/step/user/assistant/tool…seq 连续deriveMessages从日志派生模型看到的 Message[]——从不单独存历史fork从边界复制历史生成子会话adoptSessionEvent/snapshotSessionEvent第 167/192 行事件采纳与快照lossless JSON 保证核心不变量前几讲反复出现模型可见即已入日志。第 3 讲 desktop 的每次对话都在这份日志上追加。 3. system-prompt提示词组装packages/core/system-prompt/src/index.ts定位ctx.systemPrompt收集各插件的提示词段 工具 schema。exportinterfacePromptSection{name:stringorder:numbertext:string// ...}exportinterfaceToolProviderResult{...}exportinterfacePromptAssembly{...}exportconstPERSONA_SECTIONdeployment:personaexportconstPERSONA_ORDER0精讲PromptSection一段提示词name order text。插件用systemPrompt.section(...)注册自己的段如第 4 讲addHarnessSourceSection注册harness:sourceorder -99。system-prompt/assemble瀑布每步请求前把所有段按 order 排序组装成最终提示词 工具 schema 列表。PERSONA_ORDER 0persona人设段的默认位置——agent 级deployment:persona可遮蔽全局默认。 4. tools工具管道packages/core/tools/src/index.ts定位ctx.tools工具注册表 守卫执行管道。exportinterfaceToolDefinitionextendsToolSchema{output:ToolOutputDefinitionexecute(args:unknown,exec:ToolRunContext):PromisefinalizeContent?(...):ContentBlock[]|undefinedtimeoutMs?:numberisConcurrencySafe?(args):booleanpresentCall?/presentResult?(...)}exportinterfaceToolExecutionInput{callId,name,arguments,signal,...}exporttypeToolExecutionMode{kind:parallel}|{kind:exclusive}精讲管道五段 守卫tools/pre-executeallow/deny/ask 策略瀑布 → ctx.tools.guard()单调守卫只能拒绝无法被后续撤销 → tools/executearound 包装超时/重试/指标只可换 signal → tools/post-executeaccept/replace/block 结果变换 → finalizeContent工具定义级末次内容 → tools/result只读观察冻结结果第 469-472 行TOOL_ABORTED/TOOL_ABORTED_BEFORE_DISPATCH两个取消码——取消语义的标准化。第 494 行ToolNotFoundError未知工具映射UNKNOWN_TOOL调用失败但不结束回合。 5. agentAgent 接口packages/core/agent/src/index.ts定位ctx.agents活 Agent 句柄 注册表 创建工厂缝。exportinterfaceAgentHandle{agent:Agentdispose():Promise}exportinterfaceAgentFactory{create(options:CreateAgentOptions):Promiseresume(options:ResumeAgentOptions):Promise}exportclassAgentRegistryextendsService{...}精讲类型作用AgentHandle拥有者句柄dispose()是能力只有持有者能拆 agentAgentFactory创建缝——agent-loop 通过ctx.agents.setFactory()注册实现消费者只依赖ctx.agentsCreateAgentOptions新 agent 的完整上下文session 元数据、seed、per-agent options、setup 回调关键设计Agent接口packages/core/agent/src/types.ts定义send/followup/steer/inject/cancel/whenIdle等——第 3 讲桌面端一次对话最终都汇聚到这些方法。 6. agent-loop主循环packages/core/agent-loop/src/index.ts定位ctx.agentLoopAgent 接口的唯一具体实现。exportclassAgentLoopextendsServiceimplementsAgentFactory{...}exportinterfaceAgentLoopSettings{...}精讲一次回合的主循环骨架claim inbox 批next-step 一条 next-turn → turn/start入日志 → agent/pre-step 瀑布改写/拒绝认领的消息 → step/start user/message入日志 → system-prompt/assemble 派生历史 → agent/request 瀑布 → llm/stream → assistant/chunk*入日志 → tool/call → tools 管道 → tool/result入日志 → step/end → 若工具还亏欠 → 下一 step → agent/turn-stoppingserial 终检 → turn/end入日志AgentLoop implements AgentFactory通过ctx.agents.setFactory()把自己注册为创建者。可替换性UI/hooks/协议插件都依赖ctx.agents接口从不 importagent-loop——想换主循环注册一个新 factory 即可。️ 第 6 讲依赖图图 6-1 · core 六包依赖方向与一次回合数据流⚙️ 机制小结依赖方向单向scope → {session, system-prompt, tools} → agent → agent-loop。底层是库上层是驱动。接口/实现分离agent定义契约agent-loop提供实现——换主循环不动消费者。六包各司其职日志session→ 组装system-prompt→ 执行tools→ 句柄agent→ 驱动agent-loop→ 隔离scope。一次回合 六包协奏认领 → 组装 → 请求 → 工具 → 落日志每步都有 durable 事件。作用域贯穿tools 注册、事件派发都受 scope 控制——多 agent 隔离的根基。 动手验证# 1) 数核心包规模感受接口轻、实现重cdD:\code\deepseek-harnesswc-lpackages/core/agent/src/index.ts packages/core/agent-loop/src/index.ts# 2) 验证 agent-loop 是唯一实现搜谁 implements AgentFactorygrep-rnimplements AgentFactorypackages/--include*.ts|grep-vnode_modules# 3) 在 desktop 树里定位六包行nodeapps/cli/lib/bin.js--profiledesktop --dump-config|grep-Esession|agent-loop|system-prompt|tools|head 深入指引包关键文件scopesrc/index.ts/src/store.tssessionsrc/index.tsSession425/src/types.tsSessionEventMapsystem-promptsrc/index.tstoolssrc/index.ts/src/schema.ts/src/presentation.tsagentsrc/index.ts/src/types.tsAgent 接口agent-loopsrc/index.tsAgentLoop296下一讲预告把六包串成一条线——从桌面窗口发一句话到模型回复的完整旅程每一步对应哪个事件、哪个源码文件。