fix(tools): enforce cooperative cancellation
This commit is contained in:
@@ -741,7 +741,7 @@ Emitted when any prompt provider changes. This registry notification is unfilter
|
||||
|
||||
A tool was registered or unregistered, or a scoped restriction changed (the available tool set changed — possibly for one scope only). An UNFILTERED registry-subject notification, deliberately not scope-filtered dispatch: a global change concerns every agent's next assembly, so a scoped listener subscribing here sees every change, not just its own scope's.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L116)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L120)
|
||||
|
||||
### tools/execute
|
||||
|
||||
@@ -751,7 +751,9 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai
|
||||
/**
|
||||
* 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
|
||||
@@ -759,11 +761,11 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai
|
||||
'tools/execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, next: () => Promise<ToolExecutionResult>): Promise<ToolExecutionResult>
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
- `exec` — the allowed call about to dispatch (name, parsed arguments, caller agent, signal).
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L89)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L93)
|
||||
|
||||
### tools/post-execute
|
||||
|
||||
@@ -786,7 +788,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts
|
||||
- `exec` — the call that just ran (name, parsed arguments, caller agent).
|
||||
- `result` — the dispatch outcome a listener may accept, replace, or block.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L98)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L102)
|
||||
|
||||
### tools/pre-execute
|
||||
|
||||
@@ -795,7 +797,9 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts
|
||||
```ts website-api
|
||||
/**
|
||||
* 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
|
||||
@@ -803,11 +807,11 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts
|
||||
'tools/pre-execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, next: () => Promise<PreToolDecision>): Promise<PreToolDecision>
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
- `exec` — the pending call (name, parsed arguments, caller agent).
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L80)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L82)
|
||||
|
||||
### tools/result
|
||||
|
||||
@@ -829,7 +833,7 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained
|
||||
- `exec` — the execution object that traversed the pipeline.
|
||||
- `result` — a deep-frozen snapshot of the final returned result.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L106)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L110)
|
||||
|
||||
## workflow/*
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
Tool registry and execution pipeline. Scoped registrations shadow globals; one visibility resolver feeds presentation, lookup, and dispatch.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L438)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L465)
|
||||
|
||||
### ctx.tools.register(definition)
|
||||
|
||||
@@ -26,7 +26,7 @@ Register globally or in the calling agent scope. Scoped tools shadow globals; du
|
||||
|
||||
**Returns** the exact disposer that unregisters the tool.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L538)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L567)
|
||||
|
||||
### ctx.tools.restrict(filter)
|
||||
|
||||
@@ -47,7 +47,7 @@ Restrict global tools for the calling agent scope. Empty filters, unknown names,
|
||||
|
||||
**Returns** the exact disposer that lifts this restriction.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L578)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L607)
|
||||
|
||||
### ctx.tools.guard(guard)
|
||||
|
||||
@@ -71,7 +71,7 @@ Register a monotonic guard after the extensible `tools/pre-execute` waterfall. A
|
||||
|
||||
**Returns** the exact disposer that unregisters the guard.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L629)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L658)
|
||||
|
||||
### ctx.tools.get(name, scope?)
|
||||
|
||||
@@ -95,7 +95,7 @@ Look up a tool as one scope sees it (scoped shadows global; a restricted-away gl
|
||||
|
||||
**Returns** the definition the scope resolves, or undefined when none is visible.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L731)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L760)
|
||||
|
||||
### ctx.tools.schemas(scope?)
|
||||
|
||||
@@ -115,7 +115,7 @@ Project visible definitions onto the allowlisted model-facing schema fields, exc
|
||||
|
||||
**Returns** one deep-cloned schema per visible tool.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L741)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L770)
|
||||
|
||||
### ctx.tools.executionMode(exec)
|
||||
|
||||
@@ -136,7 +136,7 @@ Classify a pending call through the caller's visible tool definition. Only an ex
|
||||
|
||||
**Returns** the fail-closed scheduling mode.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L762)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L791)
|
||||
|
||||
### ctx.tools.execute(exec)
|
||||
|
||||
@@ -145,7 +145,10 @@ Classify a pending call through the caller's visible tool definition. Only an ex
|
||||
* 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.
|
||||
@@ -153,10 +156,10 @@ Classify a pending call through the caller's visible tool definition. Only an ex
|
||||
async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>
|
||||
```
|
||||
|
||||
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.
|
||||
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. 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.
|
||||
|
||||
- `exec` — the typed same-process call input. The registry assigns its correlation token before policy begins.
|
||||
|
||||
**Returns** the materialized final result.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L782)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/core/tools/src/index.ts#L814)
|
||||
|
||||
Reference in New Issue
Block a user