Skip to content

[BUG] DSH 0.2.1-rc.3 + dsh-ops 0.4.1:PTC 回合第二次组装抛 Cannot read properties of undefined (reading 'length'),整轮中断 #412

Closed as not planned

Description

@WeiLinCool

环境

  • DSH 0.2.1-rc.3(macOS arm64,profile dsh-ops-mac)
  • dsh-ops 0.4.1
  • 呈现:PTC(run_code 是唯一可直接调用的工具,tools:ptc-only 段非空)
  • 复现宿主:同一 checkout 的 master(dsh-v0.2.1-rc.3),Node 24.17.0

现象

任何 PTC 回合,第一步的 step/end 之后立刻 turn/end,整轮中断,客户端只显示一句:

Cannot read properties of undefined (reading 'length')

会话文件里的形状很固定 —— 有 step/start{turn:1,step:1}、tool/call、tool/ptc-dispatch、tool/result、step/end{turn:1,step:1},然后直接 turn/end{turn:1,reason:{kind:"error",code:"UNKNOWN",message:"Cannot read properties of undefined (reading 'length')"}};没有 step/start{turn:1,step:2},也没有第二次 request/header。也就是说:第一次模型调用成功、run_code 程序也跑完了,是准备第二步时炸的。

根因

DSH 0.2.1-rc.3 的 9d0c97b9d2 feat(tools): admit conditional tools per step(git describe = dsh-v0.2.1-rc.2-677-g9d0c97b9d2,提交说明里写明 “system-prompt/assemble now transforms PromptPresentation without a tool array”)改了瀑布契约:

  • 0.2.0-rc.2:system-prompt/assemble 收到的 assembly 是完整 PromptAssembly,含 tools
  • 0.2.1-rc.3:瀑布只变换 PromptPresentation(sections / contexts / variables),tools 由 SystemPrompt.assemble() 在瀑布之后追加(packages/core/system-prompt/src/index.ts:return { ...transformed, tools })

src/ptc/index.ts 的 isPtc() 读的是瀑布返回值:

const isPtc = (assembly: PromptAssembly): boolean => assembly.tools.length === 1 && assembly.tools[0]?.name === 'run_code'
  && assembly.sections.some(section => section.name === 'tools:ptc-only' && section.text.trim() !== '')

在 system-prompt/assemble 监听里 const result = await next(); ... isPtc(result),result.tools 在 0.2.1 上恒为 undefined → 抛 TypeError。

为什么只在“第二次组装”炸

同一监听有前置门控 heldPtc = Boolean(entry?.ptc && entry.owned.size)。第一步的组装发生在 agent/pre-step 把 PTC 工具面发出去之前(heldPtc === false,短路返回,不碰 isPtc),所以第一步永远正常;第二步起 heldPtc === true,必然踩空。这解释了“错误总是在第一次工具调用之后出现”的观感。

栈

TypeError: Cannot read properties of undefined (reading 'length')
    at isPtc (dsh-ops/lib/ptc/index.js:21:44)
    at Object.<anonymous> (dsh-ops/lib/ptc/index.js:259:39)      // system-prompt/assemble 监听
    at async Proxy.assemble (@deepseek-ai/dsh-system-prompt/lib/index.js:399:23)
    at async ReactLoopAgent.preStep (@deepseek-ai/dsh-agent-loop/lib/index.js:679:21)
    at async ReactLoopAgent.turn (@deepseek-ai/dsh-agent-loop/lib/index.js:732)

preStep 把异常直接抛给 turn 循环,所以整轮结束,且错误码落成 UNKNOWN。

同一契约变更还有第二处

src/official-tool-hiding.ts 的组装校验:

if (!Array.isArray(result?.tools)) throw block(context.scope, 'assembled tool schemas unavailable')

在 0.2.1 上同样恒真 → 只要 profile 启用了 dsh-ops-hide-official 且 replaceTools 非空,每个作用域的组装都会被 READINESS_BLOCKED ... assembled tool schemas unavailable 拦下。本次 profile 没启用这一行,所以先暴露的是 PTC 那条;两处是同一个假设。

(src/discovery/index.ts 的同名判断只看 tools:ptc-only 段,未受影响。)

最小复现

  1. DSH 0.2.1-rc.3 + dsh-ops 0.4.1,profile 里启用 dsh-ops-ptc(PTC 呈现)
  2. 任意新会话,发一句会触发工具调用的话,例如让它读一个文件
  3. 模型调用一次 run_code(程序内调 tools.ops_bash / tools.ops_inspect_local_file 均可)
  4. 工具返回后整轮报 Cannot read properties of undefined (reading 'length')

不依赖具体工具内容:只要这一步是 PTC 呈现下的第二次组装就会复现。用真实的 0.2.1-rc.3 AgentLoop + 0.4.1 的 lib/ 组一个脚本化 provider 可以稳定复现(第一步 run_code、第二步无工具调用),修复前固定报同一个 TypeError,修复后两步都正常。

期望行为

  • PTC 回合应能走到第二步;system-prompt/assemble 的监听不得假设载荷里有 tools
  • 0.2.0 的语义要保留:有 tools 时仍按 tools.length === 1 && tools[0].name === 'run_code' + 段落双重判定
  • hide-official 在载荷没有工具数组时,应改用注册表视图(visibleToolNames())完成同一项校验,而不是无条件 block

影响面

  • 0.2.1-rc.3 上只要走 PTC 呈现,dsh-ops 的 PTC 能力等于完全不可用(不是某条命令失败,是回合必断)
  • package.json 声明 peerDependencies["@deepseek-ai/dsh"] = "^0.2.0-rc.2",按 semver 0.2.1-rc.3 属于声明支持范围,所以这不是“不支持的组合”,而是兼容性缺陷

建议修复

把 PTC-only 判定抽成不依赖 tools 存在性的谓词(无数组时用提供方拥有的 tools:ptc-only 段判定,与 isNativePresentation、discovery 同一口径),hide-official 的校验回退到注册表视图。本地已有补丁 + 三条回归测试(真实 loop 双步、hiding 组装、谓词单测),需要的话我可以直接提 PR。

关联

Activity

  1. WeiLinCool commented on Oct 26, 2026

    @WeiLinCool
    ContributorAuthor

    和 #387 重复了。

    #387 已在 2026-10-25 由 211dc3e fix(session): defer Bash publication and accept text-only prompt hooks 在 main 上修好(hasPtcInstruction + text-only hooks:瀑布载荷没有 tools 时只按 tools:ptc-only 段判定)。我用真实 DSH 0.2.1-rc.3 的 AgentLoop + 本仓库 lib/ 复跑确认:main@dfafddc 上同一个会话两步都正常,0.4.1 的构建则在第二次组装上抛 Cannot read properties of undefined (reading 'length')。

    但 0.4.1 是当前发布版(npm 最新也是 0.4.1),还不含 211dc3e,所以 0.4.1 + DSH 0.2.1-rc.3 仍然必现,需要一次 0.4.2 才能让用户拿到修复。

    此外同一次契约变更还有一处没跟上:hide-official 的组装校验(src/official-tool-hiding.ts:176)在 main 上仍无条件要求载荷带 tools,一旦启用该行(replaceTools 非空)每个作用域都会被 READINESS_BLOCKED ... assembled tool schemas unavailable 拦下。已另开 #413,修复见 PR #414。

    本 issue 按重复关闭;PTC 侧请跟 #387 与 0.4.2 的发布进度。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions