docs: tighten parallel tool-call prose
This commit is contained in:
@@ -34,14 +34,14 @@ sequenceDiagram
|
||||
Session-->>SDK: <code>session/event</code> <code>assistant/chunk</code>*
|
||||
Driver->>Hooks: <code>agent/step-result</code> waterfall
|
||||
Driver->>Session: <code>assistant/message</code>
|
||||
Driver->>Tools: classify next call by executionMode
|
||||
loop bounded rolling pool with reclassification before replenishing
|
||||
opt capacity available for an unstarted call
|
||||
Driver->>Session: <code>tool/call</code> pending audit
|
||||
Driver->>Tools: ordered pre / pooled dispatch
|
||||
Driver->>Tools: classify pending call by executionMode
|
||||
loop barriers and bounded rolling pool, reclassify before start
|
||||
opt call starts
|
||||
Driver->>Session: <code>tool/call</code>
|
||||
Driver->>Tools: ordered pre, concurrent execute
|
||||
Tools-->>Session: tool-owned events when applicable
|
||||
end
|
||||
opt next model-order result is ready
|
||||
opt next model-order result ready
|
||||
Driver->>Tools: ordered post
|
||||
Driver->>Session: <code>tool/result</code>
|
||||
end
|
||||
|
||||
@@ -82,11 +82,11 @@ forever:
|
||||
'assistant/chunk'
|
||||
agent/step-result
|
||||
'assistant/message'
|
||||
schedule tool calls by ctx.tools.executionMode (reclassify before pool replenishment;
|
||||
exclusive = barrier; parallel-safe = rolling pool, <= maxParallelToolCalls in flight):
|
||||
while the bounded pool has work:
|
||||
capacity available -> 'tool/call' -> tools/pre-execute -> monotonic guards -> tools/execute
|
||||
next model-order slot ready -> tools/post-execute -> 'tool/result'
|
||||
schedule tool calls by ctx.tools.executionMode:
|
||||
exclusive -> one-call barrier
|
||||
parallel -> rolling pool, <= maxParallelToolCalls in flight; reclassify before start
|
||||
each start -> 'tool/call' -> ordered tools/pre-execute -> concurrent tools/execute
|
||||
each model-order result -> ordered tools/post-execute -> 'tool/result'
|
||||
append post-tool context (model order) and steering
|
||||
'step/end'
|
||||
agent/turn-continuation
|
||||
|
||||
@@ -39,18 +39,14 @@ Source: [`packages/ui/acp/src/index.ts:208`](../packages/ui/acp/src/index.ts)
|
||||
* deployment persona (forwarded to the system-prompt plugin); `toolOrder` is
|
||||
* the explicit model-facing tool order (forwarded to the system-prompt plugin);
|
||||
* `tools` is the tool registry's config (its presentation `mode`, forwarded
|
||||
* through agent-spine-demo); `maxParallelToolCalls` configures the bundled
|
||||
* agent loop; `persistenceRoot` is the JSONL backend's directory.
|
||||
* through agent-spine-demo); `persistenceRoot` is the JSONL backend's directory.
|
||||
*/
|
||||
export interface Config {
|
||||
/** Provider route for ACP-created agents. */
|
||||
provider: string
|
||||
/** Model name for ACP-created agents (must have a registered adapter). */
|
||||
model: string
|
||||
/**
|
||||
* Concurrent parallel-safe tool-call cap for the bundled agent loop. A
|
||||
* positive integer; the loop defaults it when omitted and `1` is serial.
|
||||
*/
|
||||
/** Bundled agent-loop concurrency cap; `1` is serial and omission uses its default. */
|
||||
maxParallelToolCalls?: number
|
||||
/** Deployment persona (the system-prompt plugin's `persona` config). */
|
||||
persona?: string
|
||||
@@ -75,7 +71,7 @@ export interface Config {
|
||||
|
||||
Depends on: [`agentCore`](../packages/examples/agent-spine-demo/src/index.ts) · [`ToolsConfig`](#deepseek-aidsh-tools)
|
||||
|
||||
Source: [`packages/examples/acp-demo/src/index.ts:33`](../packages/examples/acp-demo/src/index.ts)
|
||||
Source: [`packages/examples/acp-demo/src/index.ts:32`](../packages/examples/acp-demo/src/index.ts)
|
||||
|
||||
## `@deepseek-ai/dsh-agent-loop`
|
||||
|
||||
@@ -85,9 +81,8 @@ Requires: `agents` · `sessions` · `llm` · `tools` · `systemPrompt`
|
||||
/** Agent-loop plugin configuration. */
|
||||
export interface Config {
|
||||
/**
|
||||
* Concurrent parallel-safe tool-call cap shared by every agent this factory
|
||||
* creates. A positive integer; `1` preserves fully serial execution and an
|
||||
* omitted value defaults to {@link DEFAULT_MAX_PARALLEL_TOOL_CALLS}.
|
||||
* Maximum parallel-safe calls in flight per agent step. `1` is serial;
|
||||
* omission defaults to {@link DEFAULT_MAX_PARALLEL_TOOL_CALLS}.
|
||||
*/
|
||||
maxParallelToolCalls?: number
|
||||
/** Agents created or resumed at plugin startup. */
|
||||
@@ -127,7 +122,7 @@ Source: [`packages/core/agent-loop/src/index.ts:334`](../packages/core/agent-loo
|
||||
export interface Config {
|
||||
/** The agent-loop `agents` list (see dsh-agent-loop's `Config`). */
|
||||
agents?: AgentLoopConfig['agents']
|
||||
/** Shared concurrent tool-call cap (see dsh-agent-loop's `Config`). */
|
||||
/** Agent-loop concurrency cap; `1` is serial. */
|
||||
maxParallelToolCalls?: AgentLoopConfig['maxParallelToolCalls']
|
||||
/** The deployment persona (see dsh-system-prompt's `Config`). */
|
||||
persona?: SystemPromptConfig['persona']
|
||||
@@ -814,10 +809,7 @@ export interface Config {
|
||||
provider: string
|
||||
/** Model name for the `main` agent (must have a registered adapter). */
|
||||
model: string
|
||||
/**
|
||||
* Concurrent parallel-safe tool-call cap for the bundled agent loop. A
|
||||
* positive integer; the loop defaults it when omitted and `1` is serial.
|
||||
*/
|
||||
/** Bundled agent-loop concurrency cap; `1` is serial and omission uses its default. */
|
||||
maxParallelToolCalls?: number
|
||||
/** Deployment persona (the system-prompt plugin's `persona` config). */
|
||||
persona?: string
|
||||
@@ -1215,7 +1207,7 @@ export interface Config {
|
||||
export type ToolPresentationMode = 'native' | 'code' | 'both'
|
||||
```
|
||||
|
||||
Source: [`packages/core/tools/src/index.ts:391`](../packages/core/tools/src/index.ts)
|
||||
Source: [`packages/core/tools/src/index.ts:382`](../packages/core/tools/src/index.ts)
|
||||
|
||||
## `@deepseek-ai/dsh-user-approval`
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<Agent
|
||||
async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>
|
||||
```
|
||||
|
||||
Source: [`packages/core/agent-loop/src/index.ts:353`](../../packages/core/agent-loop/src/index.ts)
|
||||
Source: [`packages/core/agent-loop/src/index.ts:352`](../../packages/core/agent-loop/src/index.ts)
|
||||
|
||||
## `ctx.agents` — `AgentRegistry`
|
||||
|
||||
@@ -312,7 +312,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>
|
||||
|
||||
Types: [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md)
|
||||
|
||||
Source: [`packages/core/tools/src/index.ts:447`](../../packages/core/tools/src/index.ts)
|
||||
Source: [`packages/core/tools/src/index.ts:438`](../../packages/core/tools/src/index.ts)
|
||||
|
||||
## `ctx.userInteraction` — `UserInteractionService`
|
||||
|
||||
|
||||
@@ -20,28 +20,15 @@ interface ToolDefinition extends ToolSchema {
|
||||
*/
|
||||
timeoutMs?: number
|
||||
/**
|
||||
* Optional synchronous, pure classification: may this call run concurrently
|
||||
* with other tool calls in the same assistant step? The agent-loop scheduler
|
||||
* calls it (via {@link ToolRegistry.executionMode}) to decide whether the call
|
||||
* joins a parallel group or forms an exclusive barrier; a missing declaration,
|
||||
* a thrown check, or any non-`true` return is treated as exclusive. Like
|
||||
* `timeoutMs` it is host-only scheduler metadata — NEVER sent to the model,
|
||||
* since `schemas()` whitelists only name/description/parameters.
|
||||
* Pure synchronous classifier for overlap with sibling tool calls. Only
|
||||
* `true` opts in; omission, exceptions, non-`true` returns, and invalid
|
||||
* `defineTool` arguments are exclusive. This metadata is never model-visible.
|
||||
*
|
||||
* It may inspect the parsed `args` (`unknown` — a hand-rolled definition
|
||||
* receives the raw parsed value; `defineTool` schema-validates first and
|
||||
* returns `false` on invalid args). The check performs no I/O and receives no
|
||||
* live `Agent` or mutable `ToolExecution`.
|
||||
*
|
||||
* Declaring `true` is a contract: during `execute` the tool body must NOT
|
||||
* mutate the parent agent's session or other parent-owned async state (no
|
||||
* `exec.agent.session.append(...)`, no `agent.inject(...)`); its only parent-
|
||||
* step outputs are the returned content, `meta`, structured error, and
|
||||
* `additionalContext` on the loop's ordered post-execute path. A synchronous,
|
||||
* side-effect-only recorder whose updates are commutative or fail closed for
|
||||
* concurrent same-session calls is the one exception (`fs/observed` is the
|
||||
* worked example). Full contract and rationale: the parallel-tool-call RFC
|
||||
* (docs/rfc/implemented/feature/2026-07-10-parallel-tool-call-execution.md).
|
||||
* Opted-in executions must not mutate parent-owned state. Shared state must
|
||||
* tolerate concurrent dispatch; recorder races are permitted only when they
|
||||
* commute or fail closed. See the parallel-tool-call RFC for the full contract.
|
||||
* @param args - parsed arguments; `defineTool` validates before calling.
|
||||
* @returns Whether this call may join a parallel group.
|
||||
*/
|
||||
isConcurrencySafe?(args: unknown): boolean
|
||||
/**
|
||||
|
||||
@@ -16,11 +16,11 @@ Each tool may provide an optional `isConcurrencySafe(args)` classifier. It is sy
|
||||
|
||||
The classifier is deliberately unary. Returning `true` is the tool's promise that this call may overlap with any sibling call that also returns `true`; the scheduler does not compare calls or prove that their resource accesses are compatible.
|
||||
|
||||
Arguments still support input-sensitive classification. A tool may classify a read-only operation as parallel and a mutating operation as exclusive. The interface cannot express relational rules such as "these writes are safe only when their paths differ," so a call whose safety depends on a sibling remains exclusive.
|
||||
The unary classifier remains input-sensitive. A tool may classify a read-only operation as parallel and a mutating operation as exclusive. The interface cannot express relational rules such as "these writes are safe only when their paths differ," so a call whose safety depends on a sibling remains exclusive.
|
||||
|
||||
`defineTool()` validates arguments before invoking a typed classifier. Invalid arguments classify as exclusive and produce the ordinary argument error only if the call executes. `ctx.tools.executionMode(exec)` resolves the live tool definition and returns the tagged `parallel` or `exclusive` mode; unknown tools fail closed to exclusive.
|
||||
|
||||
A tagged mode, rather than a public boolean scheduler API, leaves room for a future resource-aware mode without changing the classifier contract.
|
||||
A tagged mode, rather than a public boolean scheduler API, keeps resource-aware variants representable without changing the classifier contract.
|
||||
|
||||
## Scheduling and ordering
|
||||
|
||||
@@ -58,7 +58,7 @@ Any shared state touched during execution must be concurrency-safe. This include
|
||||
|
||||
`maxParallelToolCalls` is a positive AgentLoop deployment cap shared by every agent the factory creates. It defaults to `10`; `1` preserves serial execution. Exact fields and defaults live in the generated [configuration catalog](../../../config-catalog.md).
|
||||
|
||||
The shipped declarations are conservative. Web search, web fetch, and filesystem read opt in. Filesystem writes and edits, bash tools, subagent delegation, workflow, user interaction, todo mutation, Code Mode, and Cordis mutation tools remain exclusive. A subagent may share its parent's workspace or external resources, and the unary classifier cannot prove that sibling delegations have disjoint effects. Bash stays exclusive until its owning package supplies a proven input-sensitive classifier.
|
||||
The shipped declarations are conservative. Web search, web fetch, and filesystem read opt in. Filesystem writes and edits, bash tools, subagent delegation, workflow, user interaction, todo mutation, Code Mode, and Cordis mutation tools remain exclusive. A subagent may share its parent's workspace or external resources, and the unary classifier cannot prove that sibling delegations have disjoint effects. Bash has no proven input-sensitive classifier and remains exclusive.
|
||||
|
||||
Filesystem read relies on a narrow recorder exception: its synchronous observation updates may settle out of order, but write and edit re-check the observed version before mutation, so stale state only produces `FS_STALE_VERSION`.
|
||||
|
||||
@@ -80,7 +80,7 @@ Snapshot coverage pins the visible multi-call transcript: pending calls may over
|
||||
|
||||
**Parallelize the complete tool pipeline.** This keeps the loop on the public one-call API but runs pre- and post-execute middleware concurrently. Existing guards and hook bridges may carry ordered state, so only dispatch overlaps.
|
||||
|
||||
**Expose staged methods or a scheduling waterfall.** Public `prepare` / `dispatch` / `finalize` methods or a `tools/execution-mode` event add extension surface before another consumer needs it. The loop uses an internal scheduler view, while `executionMode(exec)` remains the insertion point for a future policy seam.
|
||||
**Expose staged methods or a scheduling waterfall.** Public `prepare` / `dispatch` / `finalize` methods or a `tools/execution-mode` event add extension surface before another consumer needs it. The loop uses an internal scheduler view, while `executionMode(exec)` leaves an insertion point for a policy seam.
|
||||
|
||||
**Start calls while the model streams.** This may reduce latency further but changes assistant-message authority, replay, and call/result pairing. The scheduler starts only after the assistant message is complete.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user