diff --git a/docs/core-data-structures/tasks.md b/docs/core-data-structures/tasks.md index 8ee766de78..80dd7fc52e 100644 --- a/docs/core-data-structures/tasks.md +++ b/docs/core-data-structures/tasks.md @@ -141,4 +141,4 @@ interface TaskRead { ## The service -`TaskService` (`ctx.tasks` — [`packages/tasks/tasks/src/index.ts`](../../packages/tasks/tasks/src/index.ts)): `start` (preflight → producer `run()` → atomic commit, fenced by `attachSurface`), non-consuming `get`/`list` (caller-scoped — owned-by-caller plus unowned only), `read` (consuming for stream kinds), `kill` (producer `cancel` first; a throw leaves the task untouched), `wait` (bounded, abort cancels the wait only), and `onTaskDone` (a `TaskDoneListener` per terminal record, given the exact lifecycle owner, effect-scoped, contained). Start retains the exact live Agent instance validated under its id; owner-scope cleanup selects by that identity, so a reused agent/session id cannot make an old scope cancel replacement work. Read/kill/wait/get authorization remains session-based and rejects a foreign session. A teardown cancel that throws force-fails only the registry record and reports that the underlying work may be orphaned, preventing disposal deadlock without claiming quiescence. The model-facing surface over all of this is [dsh-tool-tasks](../../packages/tasks/tool-tasks/README.md). +`TaskService` (`ctx.tasks` — [`packages/tasks/tasks/src/index.ts`](../../packages/tasks/tasks/src/index.ts)): `start` (preflight → producer `run()` → atomic commit, fenced by `attachSurface`), non-consuming `get`/`list` (caller-scoped — owned-by-caller plus unowned only), `read` (consuming for stream kinds), `kill` (producer `cancel` first; a throw leaves the task untouched), `wait` (bounded, abort cancels the wait only), and `onTaskDone` (a `TaskDoneListener` per terminal record, given the exact lifecycle owner and effect-scoped). Listener calls contain synchronous throws and returned promise rejections independently; returned promises are not awaited and therefore do not delay task settlement. Start retains the exact live Agent instance validated under its id; owner-scope cleanup selects by that identity, so a reused agent/session id cannot make an old scope cancel replacement work. Read/kill/wait/get authorization remains session-based and rejects a foreign session. A teardown cancel that throws force-fails only the registry record and reports that the underlying work may be orphaned, preventing disposal deadlock without claiming quiescence. The model-facing surface over all of this is [dsh-tool-tasks](../../packages/tasks/tool-tasks/README.md). diff --git a/docs/rfc/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/docs/rfc/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index b179ceaa49..6242aa97da 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/docs/rfc/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -75,7 +75,7 @@ class TaskService extends Service { // ctx.tasks read(id: TaskId, caller?: Agent): TaskRead // delta (stream kinds, consuming) or final output (final kinds, idempotent) + snapshot kill(id: TaskId, caller?: Agent, reason?: string): 'requested' | 'already-terminal' wait(id: TaskId, timeoutMs: number, caller?: Agent, signal?: AbortSignal): Promise - onTaskDone(listener: (snapshot: TaskSnapshot, owner: Agent | undefined) => void): () => void // exact lifecycle owner; effect-scoped, contained + onTaskDone(listener: (snapshot: TaskSnapshot, owner: Agent | undefined) => void | PromiseLike): () => void // exact owner; effect-scoped, contained attachSurface(name: string): () => void // the misconfiguration fence, below } ``` @@ -98,6 +98,8 @@ One system-prompt section (order 106, next to `tool:bash`) teaches the cross-cal Completion notices stay durable context, not a wake-up (`agent.inject()` appends a logged `context/message` the next model request sees; it does not run the model): on `onTaskDone`, `dsh-tool-tasks` injects `background task (: