Files
deepseek-harness/packages/tasks/tool-tasks
Yichen Jiang f858c647a6 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).
2026-07-09 21:36:56 +08:00
..

@deepseek-ai/dsh-tool-tasks

The model-facing background task control surface over ctx.tasks: three kind-agnostic tools, the completion-notice injection, and the prompt section that teaches the background habit. Loading this plugin calls ctx.tasks.attachSurface('tool-tasks'), which is what arms producers' register().

Tools

  • task_output(task_id, wait?, timeout_ms?) — non-blocking read by default (stream kinds: the consuming delta since the previous read; final kinds: the final answer once terminal); every response ends with a [status: …] line (generic status + producer detail, e.g. [status: completed, exit code: 0]). wait: true blocks until settlement, bounded by waitTimeoutMs/maxWaitTimeoutMs config; a timed-out wait returns [status: running] and leaves the task alive.
  • task_list() — the caller's tasks, <id> [<kind>] <status> — <label> per line.
  • task_kill(task_id, reason?) — requests cancellation and returns immediately; the logged reason is forwarded to the producer. An already-terminal task is described via a non-consuming snapshot (never eats a pending delta).

ACP render intent: all three are generic cards (read/read/execute) — a task read is not a terminal.

Completion notices

On onTaskDone, injects background task <id> (<kind>: <label>) finished [status: …]. Read its output with task_output. into the owning agent's session (agent.inject() — durable context for the next request, not a wake-up). Suppressed when the snapshot is reported (the model already killed it, or a read/wait returned the end) — never a redundant "finished". The disposed-owner race is contained; a missing agent registry drops the notice.

Config

key default meaning
waitTimeoutMs 30000 wait duration when task_output sets wait without timeout_ms
maxWaitTimeoutMs 600000 hard cap; larger model-supplied timeout_ms values are clamped

A config whose default exceeds the cap fails loud at load.