refactor(tasks): drive wait() timing through dsh-timeout

ctx.tasks.wait arms a deadline() fusing the caller's abort with the
wait timeout and classifies the outcome with timeoutOf scoped to the
new TASK_WAIT_TIMEOUT code: a wait timeout resolves to the live
snapshot (the task keeps running), a caller abort rejects the wait —
same contract, no hand-rolled timer/listener plumbing, and a nested
foreign deadline can no longer misread as a wait timeout. task_output
deliberately declares NO ToolDefinition.timeoutMs: timeout-policy
turns a timed-out call into a structured TOOL_TIMEOUT failure, but a
timed-out wait is a SUCCESS that must still report [status: running]
(decision recorded in the runtime RFC alternatives).
This commit is contained in:
Yichen Jiang
2026-07-09 21:36:56 +08:00
parent beaace5eb3
commit f858c647a6
8 changed files with 43 additions and 10 deletions
+5
View File
@@ -125,6 +125,11 @@ export function apply(ctx: Context, config: Config): void {
+ 'final-output tasks (subagent) return the final answer once the task finishes. '
+ 'Every response ends with a [status: ...] line. Non-blocking by default; '
+ 'set `wait: true` to block until the task finishes (bounded by a capped timeout) when you are genuinely blocked on its result.',
// Deliberately NO ToolDefinition.timeoutMs: the timeout-policy plugin
// replaces a timed-out call with a structured TOOL_TIMEOUT failure, but a
// timed-out wait here is a SUCCESS that reports [status: running] — the
// task's state must reach the model either way, so the wait bounds its
// own deadline (waitTimeoutMs/maxWaitTimeoutMs) via ctx.tasks.wait.
parameters: {
task_id: { type: 'string', required: true, description: 'Task id returned by the tool that started the background work.' },
wait: { type: 'boolean', description: 'Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive.' },