fix(tools): enforce cooperative cancellation

This commit is contained in:
Tianyi Cui
2026-07-19 18:05:54 +08:00
parent b6858a5ce1
commit 2bc4e05a08
16 changed files with 583 additions and 85 deletions

View File

@@ -654,17 +654,19 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai
'tools/change'(): void
```
Source: [`packages/core/tools/src/index.ts:116`](../../packages/core/tools/src/index.ts)
Source: [`packages/core/tools/src/index.ts:120`](../../packages/core/tools/src/index.ts)
### `tools/execute` — waterfall
Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a normalized result; wrappers may change only `exec.signal`, while call identity remains immutable. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a normalized result; wrappers may change only `exec.signal`, while call identity remains immutable. The registry re-fuses the original caller signal before the body, so replacement cannot detach caller cancellation; wrappers must still restore their signal and reach quiescence. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
```ts cordis-catalog
/**
* Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns
* a normalized result; wrappers may change only `exec.signal`, while call
* identity remains immutable.
* identity remains immutable. The registry re-fuses the original caller
* signal before the body, so replacement cannot detach caller cancellation;
* wrappers must still restore their signal and reach quiescence.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
* @param exec - the allowed call about to dispatch (name, parsed arguments, caller agent, signal).
* @mode waterfall
@@ -674,7 +676,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor
Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
Source: [`packages/core/tools/src/index.ts:89`](../../packages/core/tools/src/index.ts)
Source: [`packages/core/tools/src/index.ts:93`](../../packages/core/tools/src/index.ts)
### `tools/post-execute` — waterfall
@@ -694,16 +696,18 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts
Types: [PostToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
Source: [`packages/core/tools/src/index.ts:98`](../../packages/core/tools/src/index.ts)
Source: [`packages/core/tools/src/index.ts:102`](../../packages/core/tools/src/index.ts)
### `tools/pre-execute` — waterfall
Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approval support turns `ask` into denial. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approval support turns `ask` into denial. Async gates must observe `exec.signal`; the registry rechecks cancellation after they settle but never abandons their promise. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
```ts cordis-catalog
/**
* Allow, deny, or ask before dispatch. `next()` delegates to allow; missing
* approval support turns `ask` into denial.
* approval support turns `ask` into denial. Async gates must observe
* `exec.signal`; the registry rechecks cancellation after they settle but
* never abandons their promise.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.
* @param exec - the pending call (name, parsed arguments, caller agent).
* @mode waterfall
@@ -713,7 +717,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv
Types: [PreToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
Source: [`packages/core/tools/src/index.ts:80`](../../packages/core/tools/src/index.ts)
Source: [`packages/core/tools/src/index.ts:82`](../../packages/core/tools/src/index.ts)
### `tools/result` — emit
@@ -732,7 +736,7 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained
Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md)
Source: [`packages/core/tools/src/index.ts:106`](../../packages/core/tools/src/index.ts)
Source: [`packages/core/tools/src/index.ts:110`](../../packages/core/tools/src/index.ts)
## `workflow/*`

View File

@@ -1174,7 +1174,10 @@ executionMode(exec: ToolExecutionInput): ToolExecutionMode
* Execute through pre-policy, guards, around-dispatch, post-policy, and final
* notification. Tool and listener failures resolve as materialized error
* results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is
* the same lossless, frozen snapshot final observers receive.
* the same lossless, frozen snapshot final observers receive. Cancellation
* arriving after entry skips a not-yet-started body or replaces a successful
* dispatch outcome with `ABORTED`; already-started work is still drained and
* may retain a tool-owned structured error.
* @param exec - the typed same-process call input. The registry assigns its
* correlation token before policy begins.
* @returns the materialized final result.
@@ -1184,7 +1187,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>
Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md)
Source: [`packages/core/tools/src/index.ts:438`](../../packages/core/tools/src/index.ts)
Source: [`packages/core/tools/src/index.ts:465`](../../packages/core/tools/src/index.ts)
## `ctx.userInteraction` — `UserInteractionService`