docs: correct fs/observed concurrency-safety wording
The read tool's isConcurrencySafe rationale called the fs/observed recorder "commutative" and said concurrent reads "converge to one observed version", overstating the guarantee: the WeakMap record is last-writer-wins. Safety comes from write/edit re-checking the version in their in-lock CAS (a stale observation only forces a later edit to fail closed with FS_STALE_VERSION), as the RFC already states. Align the read comment, the ToolDefinition JSDoc, both READMEs, and the regenerated catalogs.
This commit is contained in:
@@ -85,7 +85,7 @@ See `defineTool`, `validateArgs`, `ToolArgsError`, `SchemaSpec`, `InferArgs`, an
|
||||
|
||||
`defineTool` also validates an optional `timeoutMs` at definition time when present: it must be a positive finite number, or the helper throws — the budget is attached to the produced `ToolDefinition` (for `@deepseek-ai/dsh-timeout-policy`) and never reaches the model.
|
||||
|
||||
`defineTool` also accepts an optional `isConcurrencySafe(args): boolean` — the per-call concurrency classifier the agent-loop scheduler reads via `executionMode`. `args` is the typed `InferArgs<S>` shape. It is soft-validated exactly like the presenters: an arg mismatch yields `false` (the conservative exclusive default), never the hard `ToolArgsError`. Declaring `true` is a contract — the tool body must not mutate parent-owned async state (`exec.agent.session.append`, `agent.inject`) during `execute`; its only ordered outputs are the returned content, `meta`, error, and `additionalContext`. The one exception is a synchronous, side-effect-only commutative recorder (the `fs/observed` version recorder is the worked example); anything richer stays exclusive. Host-only, never model-visible.
|
||||
`defineTool` also accepts an optional `isConcurrencySafe(args): boolean` — the per-call concurrency classifier the agent-loop scheduler reads via `executionMode`. `args` is the typed `InferArgs<S>` shape. It is soft-validated exactly like the presenters: an arg mismatch yields `false` (the conservative exclusive default), never the hard `ToolArgsError`. Declaring `true` is a contract — the tool body must not mutate parent-owned async state (`exec.agent.session.append`, `agent.inject`) during `execute`; its only ordered outputs are the returned content, `meta`, error, and `additionalContext`. The one exception is a synchronous, side-effect-only recorder whose updates are commutative or fail closed (the `fs/observed` version recorder is the worked example: its record is last-writer-wins, and a stale observation only makes a later write/edit fail closed at its in-lock version CAS); anything richer stays exclusive. Host-only, never model-visible.
|
||||
|
||||
### Structured-output schema subset
|
||||
|
||||
|
||||
@@ -217,8 +217,10 @@ export interface ToolDefinition extends ToolSchema {
|
||||
* step outputs are the returned content, `meta`, structured error, and
|
||||
* `additionalContext` carried through the loop's ordered post-execute path.
|
||||
* The narrow exception is a synchronous, side-effect-only recorder whose
|
||||
* updates are commutative for concurrent calls by the same session (the
|
||||
* `fs/observed` version recorder is the worked example).
|
||||
* updates are commutative OR fail closed for concurrent calls by the same
|
||||
* session (the `fs/observed` version recorder is the worked example: its
|
||||
* WeakMap record is last-writer-wins, and a stale observation only makes a
|
||||
* later write/edit fail closed at its in-lock version CAS).
|
||||
*/
|
||||
isConcurrencySafe?(args: unknown): boolean
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user