You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PTC mode's 10-minute run_code wall-clock (maxWallMs) makes workflow() unusable
#5822
In PTC (Programmatic Tool Call) mode, a workflow() that needs more than 10 minutes cannot finish. The workflow call happens inside a run_code program (await tools.workflow(...)), and run_code's code runs in a worker that has a wall-clock ceiling — maxWallMs, default 600000 ms (10 min). When the ceiling is hit the run is terminated:
Because workflow is foreground and neither run_code nor workflow has a background mode, in PTC mode there is no way to run a workflow longer than the cap without changing the runtime config.
A full scan of all 5,711 discussions on this repo found no prior report of this workflow-specific framing; the only discussion that hits the cap itself is #2394 (general PTC execution, not workflow-specific). This post documents the workflow-specific consequence.
How the cap is wired (research)
PTC mode exposes run_code as the only directly-callable tool; every other tool is reached through the generated tools binding inside a run_code program.
run_code executes the program through ctx.codeRuntime; the shipped PTC backend is @deepseek-ai/dsh-code-runtime-worker-thread, which runs each program in one fresh Node worker thread.
That worker enforces two budgets:
computeMs — busy-time, default 60000 ms (60 s).
maxWallMs — wall-clock ceiling, default 600000 ms (10 min), "the backstop for waits that busy time cannot see."
A workflow invoked as await tools.workflow(...) is foreground: the run_code program blocks on it until the workflow's script settles, and all of that waiting time counts against maxWallMs. At the ceiling the worker is terminated and run_code surfaces CodeRunFailedError.
In the ptc agent preset the direct workflow tool is disabled: true, so the workflow is reachable only through run_code's tools binding — i.e. always under maxWallMs.
Neither run_code (params are just code + description) nor workflow (background collection is a deferred non-goal) has a background mode, so the call cannot be detached past the ceiling.
maxWallMsis raisable (up to MAX_TIMER_DELAY_MS ≈ 24.8 days), but that only lets one foreground run_code block for the whole run — it does not remove the blocking + wall-capped shape.
Code / config references:
packages/code-runtime/code-runtime-worker-thread/src/index.ts — maxWallMs: z.number().default(600_000); the wall-clock ceiling reached (…)ms failure.
packages/core/tools/src/ptc.ts — the run_code (PTC) transport; CodeRunFailedError / CODE_RUN_FAILED; no run_in_background.
packages/preset/agent-presets/presets/ptc/agent.cordis.yml — tool-workflow: disabled: true in PTC mode.
Minimal reproduction (illustrative)
A run_code program that fans out per-item work whose agents take many minutes dies at the 10-minute mark, before the workflow resolves:
// run_code program — PTC mode. Foreground, bounded by maxWallMs (10 min).constwf=awaittools.workflow({meta: {name: "long-fanout",description: "per-item research + verify + remediate",phases: [{title: "Research"},{title: "Verify"},{title: "Remediate"}],},args: {issues: chunk},script: ` // e.g. pipeline(issues, research, verify, remediate), // where each stage's agent() takes 10+ minutes `,});// if the subagents' total wall time exceeds 10 min, run_code is killed here:// "wall-clock ceiling reached (600000ms)"
Workarounds
1. Background subagents — build your own pipeline (recommended)
run_code can't run in the background, but the work can. The subagent tool supports run_in_background (the ptc preset's subagent rows are backgroundMode: one-shot), and a background launch returns an id immediately, so run_code stays well under the cap. The long per-item work runs in background sessions and settles via in-session completion notices.
Instead of letting the workflow tool's pipeline / agent do everything in one foreground call, you drive the stages yourself: launch a background subagent per item, collect on completion, then launch the next stage (verify → remediate) for the items that finished.
// run_code — kick off one background subagent per issue (returns immediately)consthandles=awaitPromise.all(issues.map(issue=>tools.subagent({description: `research ${issue}`,prompt: `Research + verify ${issue}; return a structured result.`,run_in_background: true,// returns an id/handle now — not bounded by maxWallMs})));// As each completion notice arrives (or via job_output), collect the result// and launch the next stage's background subagent for that item. You build// Research → Verify → Remediate yourself, one background agent at a time, so// no single run_code call ever outlives 10 minutes.
Trade-off: you give up the workflow tool's built-in pipeline / parallel / agent structure and phase progress, and re-implement the orchestration + hand-off. In exchange there is no wall-clock ceiling.
2. Leave PTC mode and call workflow() at the top level
The 10-minute ceiling belongs to the run_code program, not to the workflow tool. In a non-PTC agent preset, workflow is a first-class top-level tool (not wrapped in run_code), so it is not subject to maxWallMs. It runs in the agent loop, foreground, bounded only by cancellation or an explicit requestTimeoutMs (default: indefinite). A >10-minute workflow then completes — still blocking the turn for its full duration, but nothing force-kills it at 10 minutes.
// non-PTC preset: workflow is a direct tool — no run_code envelope, no maxWallMsworkflow({meta: {name: "long-fanout",description: "...",phases: [/* … */]},args: {issues: chunk},script: `/* same body as above */`,});
Trade-off: the workflow is still foreground — the turn blocks until the whole script settles. You escape the cap, not the blocking.
Raising maxWallMs is a third, less-ideal lever (it lets one run_code block past 10 min), but it's a global runtime config, not a per-call knob, and it stays a single long foreground block:
- name: '@deepseek-ai/dsh-code-runtime-worker-thread'config:
maxWallMs: 10800000# 3 hours — foreground-blocks the turn for the whole run
Related discussions
#2394 — "在选项中取消 Timeout 的设置" — a user hitting and quoting the exact wall-clock ceiling reached (600000ms) error and asking for the timeout to be removable. The same ceiling that bounds a foreground await tools.workflow(...) in PTC mode.
#3769 — Node TimeoutOverflowWarning; cites the maxWallMs knob on @deepseek-ai/dsh-code-runtime-worker-thread. Corroborates the named ceiling.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Problem
In PTC (Programmatic Tool Call) mode, a
workflow()that needs more than 10 minutes cannot finish. Theworkflowcall happens inside arun_codeprogram (await tools.workflow(...)), andrun_code's code runs in a worker that has a wall-clock ceiling —maxWallMs, default600000ms (10 min). When the ceiling is hit the run is terminated:Because
workflowis foreground and neitherrun_codenorworkflowhas a background mode, in PTC mode there is no way to run a workflow longer than the cap without changing the runtime config.A full scan of all 5,711 discussions on this repo found no prior report of this workflow-specific framing; the only discussion that hits the cap itself is #2394 (general PTC execution, not workflow-specific). This post documents the workflow-specific consequence.
How the cap is wired (research)
run_codeas the only directly-callable tool; every other tool is reached through the generatedtoolsbinding inside arun_codeprogram.run_codeexecutes the program throughctx.codeRuntime; the shipped PTC backend is@deepseek-ai/dsh-code-runtime-worker-thread, which runs each program in one fresh Node worker thread.computeMs— busy-time, default60000ms (60 s).maxWallMs— wall-clock ceiling, default600000ms (10 min), "the backstop for waits that busy time cannot see."workflowinvoked asawait tools.workflow(...)is foreground: therun_codeprogram blocks on it until the workflow's script settles, and all of that waiting time counts againstmaxWallMs. At the ceiling the worker is terminated andrun_codesurfacesCodeRunFailedError.ptcagent preset the directworkflowtool isdisabled: true, so the workflow is reachable only throughrun_code'stoolsbinding — i.e. always undermaxWallMs.run_code(params are justcode+description) norworkflow(background collection is a deferred non-goal) has a background mode, so the call cannot be detached past the ceiling.maxWallMsis raisable (up toMAX_TIMER_DELAY_MS≈ 24.8 days), but that only lets one foregroundrun_codeblock for the whole run — it does not remove the blocking + wall-capped shape.Code / config references:
packages/code-runtime/code-runtime-worker-thread/src/index.ts—maxWallMs: z.number().default(600_000); thewall-clock ceiling reached (…)msfailure.packages/core/tools/src/ptc.ts— therun_code(PTC) transport;CodeRunFailedError/CODE_RUN_FAILED; norun_in_background.packages/preset/agent-presets/presets/ptc/agent.cordis.yml—tool-workflow: disabled: truein PTC mode.Minimal reproduction (illustrative)
A
run_codeprogram that fans out per-item work whose agents take many minutes dies at the 10-minute mark, before theworkflowresolves:Workarounds
1. Background subagents — build your own pipeline (recommended)
run_codecan't run in the background, but the work can. Thesubagenttool supportsrun_in_background(the ptc preset's subagent rows arebackgroundMode: one-shot), and a background launch returns an id immediately, sorun_codestays well under the cap. The long per-item work runs in background sessions and settles via in-session completion notices.Instead of letting the
workflowtool'spipeline/agentdo everything in one foreground call, you drive the stages yourself: launch a background subagent per item, collect on completion, then launch the next stage (verify → remediate) for the items that finished.Trade-off: you give up the
workflowtool's built-inpipeline/parallel/agentstructure and phase progress, and re-implement the orchestration + hand-off. In exchange there is no wall-clock ceiling.2. Leave PTC mode and call
workflow()at the top levelThe 10-minute ceiling belongs to the
run_codeprogram, not to theworkflowtool. In a non-PTC agent preset,workflowis a first-class top-level tool (not wrapped inrun_code), so it is not subject tomaxWallMs. It runs in the agent loop, foreground, bounded only by cancellation or an explicitrequestTimeoutMs(default: indefinite). A >10-minute workflow then completes — still blocking the turn for its full duration, but nothing force-kills it at 10 minutes.Trade-off: the workflow is still foreground — the turn blocks until the whole script settles. You escape the cap, not the blocking.
Related discussions
wall-clock ceiling reached (600000ms)error and asking for the timeout to be removable. The same ceiling that bounds a foregroundawait tools.workflow(...)in PTC mode.TimeoutOverflowWarning; cites themaxWallMsknob on@deepseek-ai/dsh-code-runtime-worker-thread. Corroborates the named ceiling.run_coderejections lack recovery hints.简要(中文)
在 PTC 模式(只能用
run_code的模式)里,workflow()一跑超过 10 分钟就会被强制停掉,报wall-clock ceiling reached (600000ms)。原因是:
run_code的代码在一个 worker 里跑,有一个 10 分钟的墙钟上限(maxWallMs,默认 600000 毫秒)。workflow是前台运行,等它跑完的时间也算在这个上限里,到点 worker 就被杀掉。run_code和workflow都没有后台模式,所以在 PTC 模式下没法跑超过 10 分钟的workflow。绕开办法有两个:
subagent加run_in_background)自己搭流水线:一条任务发一个后台子代理,立刻拿到 id(不受 10 分钟限制),完成后再发下一阶段。代价是要自己写编排,没有workflow自带的 pipeline。workflow():这样不受maxWallMs限制(但仍以前台运行,会卡住直到跑完)。(也可以调大
maxWallMs,但那是全局配置,而且还是一个长时间前台阻塞,不推荐。)相关讨论:#2394 有人报了同样的报错,但没提到
workflow。All reactions