DeepSeek Harness 文件系统路径解析:按会话 cwd 实现多工作区一致性

📅 发布时间:2026/9/20 12:24:25
DeepSeek Harness 文件系统路径解析:按会话 cwd 实现多工作区一致性
DeepSeek Harness 文件系统路径解析按会话 cwd 实现多工作区一致性【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness这篇技术指南解析 DeepSeek Harness 中的一项已落地架构决策把文件系统工具的路径解析基准从服务器启动目录迁移到调用方 Agent 的会话 cwdSession cwd使一个服务器进程内的多个 ACP 会话各自拥有独立且一致的工作区语义。读完本文你将理解该决策要解决的三类路径分歧问题、FileSystem.resolve接口扩展与sessionCwd辅助函数的实现机制、符号链接与父级目录..在物理与词法解析下的语义差异以及它对沙箱授权、FsTarget身份与向后兼容性的实际影响。背景一个服务器进程、N 个工作区DeepSeek Harness 通过 ACPAgent Client Protocol桥接层接入自动化客户端。ACP 桥接为每个会话分配独立工作区session/new将自动化客户端选择的项目目录记录在SessionHeader.cwd中dsh-tool-bash将每次 bash 调用的workdir默认指向调用方 Agent 的session.header.cwd见 ACP 包 与dsh-tool-bash中的resolveWorkdir。于是会话 A 中的 bash 命令在 A 的项目里执行会话 B 中的 bash 命令在 B 的项目里执行——一个服务器进程N 个工作区。这与传统单工作目录的 CLI 工具有本质区别也是本次文件系统改造的起点。在dsh-tool-bash中resolveWorkdir的实现体现了会话 cwd 的基准作用tool-bash/src/index.tsfunction resolveWorkdir( modelWorkdir: string | undefined, exec: { agent?: Agent }, policyWorkspaceRoot?: string, ): string | undefined { const headerCwd exec.agent?.session.header.cwd const sessionCwd policyWorkspaceRoot ?? (headerCwd undefined ? undefined : canonicalPath(headerCwd)) if (modelWorkdir undefined) return sessionCwd if (sessionCwd ! undefined !isAbsolute(modelWorkdir)) { return resolvePath(sessionCwd, modelWorkdir) } return modelWorkdir }关键点模型提供的workdir若是相对路径就相对会话 cwd 解析未提供时直接退回会话 cwd而解析后的沙箱策略根目录policyWorkspaceRoot拥有最高优先级保证工作目录与沙箱授权范围使用同一个调用级身份。问题文件系统工具与 bash 的路径基准不一致bash 已经做到了按会话解析但文件系统解析层当时使用的仍是插件加载时的 cwdone plugin-load cwd。由此产生了一类根本分歧只要自动化客户端的项目目录与服务器启动目录不同相对路径在两类工具之间就会产生不同的结果。快照测试恰好让两类路径相同从而掩盖了该缺陷。具体后果包括会话 A 中的 bash 操作的是 A 的项目目录而同一会话里文件系统工具的相对路径却落在服务器启动目录下模型或插件给出的同一相对路径read/write/edit与 bash 看到的是不同文件多会话共享一个服务器进程时文件系统工具无法体现每个会话各自的项目这一 ACP 契约。更深层的问题合法绝对 cwd 也可能有两个父亲文档进一步指出即便 cwd 是合法绝对路径只要包含symlink/..这类片段就会在物理解析与词法解析之间出现分歧文件系统查找进程视角会先跟随符号链接再应用..而path.resolve()会在词法上直接消去这两段。例如 cwd 写作/workspace/link/..其中link是指向/data/real的符号链接解析方式结果进程/文件系统先 follow 再../data/real的上一级即/datapath.resolve()词法消去/workspace旧的实现用path.resolve()词法解析沙箱策略却从原始 cwd 启动 bash结果把与真实工作区无关的词法父目录授予了沙箱拒绝了对真实工作区的写入让文件系统工具把相对路径解析进错误目录。即使 cwd 是普通符号链接不含..当请求的相对路径中含..时同样存在分歧进程从符号链接的物理目标出发向上遍历path.resolve(cwd, path)从符号链接的词法拼写出发向上遍历。结果同样的模型路径read选中的文件与 bash 或沙箱化变更操作的文件不是同一个。决策把调用方的会话 cwd 串进路径解析解决方案与dsh-tool-bash对workdir的做法完全对齐——把调用方的会话 cwd 串入路径解析当 cwd 或请求路径含父级段..时先在任何词法拼接之前把 cwd 解析为原生文件系统身份native realpath当没有发生穿越时普通 cwd 拼写保持不变仅用于展示display不暴露身份差异沙箱化变更与沙箱化 bash 调用复用解析后的沙箱策略根保证一次调用只有一个工作区身份cwd 由调用方工具层提供provider 不主动读取任何 session 或 agent。FileSystem.resolve接口扩展抽象基类FileSystem的resolve方法新增可选optsfs/src/index.tsabstract resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): PromiseFsTarget参数语义参数含义path模型/插件提供的路径相对路径以opts.cwd为基准解析opts.cwd相对路径的解析基准绝对路径忽略它省略时使用后端自身的默认 cwdopts.signal后端执行 I/O如远端/沙箱后端需要往返映射稳定身份时用于取消解析的AbortSignal设计要点选项对象把两个调用方所有的解析控制cwd 覆盖与取消放在一起避免接口位置参数无限膨胀。resolve保持异步因为远端/沙箱后端可能需要一次网络往返才能把路径映射为稳定身份本地后端则只做规范化与 realpath。dsh-fs-local的落地本地后端在解析时以opts.cwd ?? this.config.cwd作为基准dsh-fs-local.resolve 使用 resolveLocalTarget(opts?.cwd ?? this.config.cwd, path)config.cwd仍然是调用方未提供会话 cwd 时的默认基准。底层resolveLocalTargetfs-local/src/fsio.ts实现了两段式解析displayPath resolve(cwd, path)词法拼接作为面向调用方的展示路径优先realpath(displayPath)得到稳定身份targetKey目标不存在时对最近的已存在祖先做 realpath再重新拼接缺失后缀从而在目录创建前后保持身份稳定。LocalTarget正是这一展示与身份分离的载体displayPath用于展示targetKeyrealpath作为稳定身份与 I/O 路径。dsh-tool-fs的会话 cwd 推导dsh-tool-fs的read/write/edit通过共享的sessionCwd(exec, requestedPath)辅助函数推导会话 cwdtool-fs/src/session-cwd.tsexport function sessionCwd(exec: ToolExecution, requestedPath: string): string | undefined { const cwd exec.agent?.session.header.cwd if (cwd undefined || (!PARENT_PATH_SEGMENT.test(cwd) !PARENT_PATH_SEGMENT.test(requestedPath))) return cwd return canonicalPath(cwd) }行为要点cwd 取自exec.agent?.session.header.cwd与 bash 的resolveWorkdir完全镜像只有当 cwd 或请求路径中出现父级段/\.\./正则PARENT_PATH_SEGMENT同时覆盖/与\分隔符时才用canonicalPath把 cwd 归一到原生文件系统身份没有穿越时保留普通拼写对展示友好且身份不可观察时无需归一非 Agent / 无 header 的调用方返回undefined由后端应用自身默认而不是在工具边界擅自制造process.cwd()基准。配套的sessionResolveOptions把 cwd 与取消信号打包为resolve的opts并让带沙箱策略的变更操作复用策略的workspaceRoot作为 cwdtool-fs/src/session-cwd.tsexport function sessionResolveOptions( exec: ToolExecution, requestedPath: string, policyWorkspaceRoot?: string, ): { cwd?: string; signal?: AbortSignal } { const cwd policyWorkspaceRoot ?? sessionCwd(exec, requestedPath) return { ...cwd ! undefined ? { cwd } : {}, signal: exec.signal, } }三个工具入口都以ctx.fs.resolve(path, sessionResolveOptions(exec, path))的形式消费这一辅助函数readtool-fs/src/read-target.tswritetool-fs/src/write.ts额外传入sandboxPolicy?.workspaceRootedittool-fs/src/edit.ts同样复用策略根。其中write/edit传入策略根的做法与 bash 的policyWorkspaceRoot优先级一致一次调用只有一个工作区身份解析、变更与沙箱授权三者的基准完全相同。备选方案为什么由调用方提供 cwd而非 provider文档明确否定了provider 自行读取会话的方案理由构成一条重要的包边界约定explicit implicit at package boundariesprovider 契约不能依赖dsh-agent/dsh-session。FileSystem是文本存储后端沙箱化或远端实现同样要满足该契约而它们根本没有Agent 会话的概念工具层恰好持有ToolExecutionexec其中携带 agent。因此exec → cwd投影的正确位置是工具层provider 拿到的只是普通字符串与dsh-tool-bash一一对应。两个面向模型的文件面文件系统工具与 bash由此能以完全相同的规则解析路径默认值只存在一处provider 的config.cwd。sessionCwd在没有会话时返回undefined而非process.cwd()工具层绝不制造 provider 本来会自行选择的基准。影响与兼容性改造后的实际影响可以归纳为四点事实与一点边界说明ACP 演示中 fs 工具与 bash 对齐自动化客户端可以选择任意绝对项目目录两类工具族都作用在同一个工作区上符号链接语义统一含symlink/..的会话 cwd或普通符号链接 cwd 配合父级穿越相对路径时bash、文件系统工具与沙箱授权都从同一物理工作区解析词法父目录不再获得任何授权FsTarget身份不变targetKey仍是解析后绝对路径的 realpath因此观测状态键控observed-state keying与符号链接身份不受影响——正确的按会话 cwd 会产生与 bash 目标相同的键向后兼容所有既有resolve(path)调用主要在测试中继续可用新参数是可选参数单会话 stdio 演示不受影响它不提供会话 cwd其 agent 的 session 没有cwd解析回退到config.cwd process.cwd()即工作区本身。小结按会话 cwd 解析文件系统路径是 DeepSeek Harness 多工作区架构中的一块关键拼图。它以最小侵入一个可选opts.cwd参数 一个共享辅助函数弥合了文件系统工具与 bash 之间、词法解析与物理解析之间的路径分歧同时守住了三条边界调用方提供基准、provider 只管存储、默认值只存一处。对开发者而言若要为 Harness 编写新的文件系统后端或工具可沿 packages/fs/fs、packages/fs/fs-local、packages/fs/tool-fs 三条主线追踪本设计并以 tool-fs/tests/integration.spec.ts 与 tool-fs/tests/tools.spec.ts 为参考验证多工作区与符号链接场景。【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考