DSHarness Systems Dissection Pinned baseline 47f943859b · 36 verified / 0 in progress / 36 chapters
中文
Tool System·Chapter 18

Tool Parallelism and Result Ordering

Barriers, rolling windows, reclassification, and model-order settlement

VerifiedUpstream 47f943859bScope: Trace executionMode classification, concurrency pools, barriers, pre-start reclassification, settlement, and additional-context ordering.

Conclusion: Scheduler-Controlled Dispatch and Bodies May Overlap; Native Authoritative Commit Stays Ordered

Parallel tool calling in DeepSeek Harness does not hand the model's array directly to Promise.all. The visible definition first classifies each call through a fail-closed contract. The Agent Loop then builds a bounded rolling window in model order and turns every exclusive call into a barrier. Pre-policy, approval, and guards run in order; around-dispatch and bodies may overlap; Native top-level post/finalize, tool/result, and additional context commit in model order. Asynchronous tools/result observer continuations and Code Mode nested dispatch-log side work sit outside that commit guarantee. The default window is 10, and 1 restores serial scheduler-controlled dispatch.

The state machine in one line

classify → ordered prepare → concurrent dispatch → model-order finalize → durable result → next-step context. The complete Assistant message is persisted before the Loop extracts all tool-call blocks and enters this machine. PARALLEL-LOOP-ENTRYPARALLEL-GROUPING

The design protects replay, policy order, and parent Session state ahead of maximum throughput. Its costs are equally explicit: a fast result can wait behind a slow earlier sibling, the classifier cannot say that writes to two different paths are compatible, and a per-Agent, per-Step cap is not a process-wide resource budget.

1. Four Different Orders Must Be Kept Separate

OrderGuaranteeWhat may be out of order
Model orderThe order of tool-call blocks in Assistant content is the index and commit baselineNothing
Start orderCalls enter prepare and dispatch in model order; a later call does not start firstBody completion
Completion orderParallel bodies may complete in any orderThis is where concurrency actually exists
Commit orderPost-policy, tool/result, contexts, and concludes-turn follow model orderCompletion of asynchronous read-only observers is outside this guarantee

The implementation places completed dispatches into slots indexed by model order. The committed cursor can advance only across a contiguous ready prefix. A later call that returns first therefore cannot enter post, Session history, or next-step context first. PARALLEL-ROLLING-POOL

2. executionMode() Is Strict Opt-In and Evaluated Per Call

Input stateClassificationReason
The visible definition's isConcurrencySafe(args) returns exactly trueparallelThe only opt-in path
No classifier, false, or a truthy non-booleanexclusiveOverlap is denied by default
Unknown, hidden by scope, or collapsed as a direct code-only callexclusiveNo executable definition resolves
The classifier throwsexclusiveA classification failure cannot elevate authority
Arguments to a defineTool definition are invalidexclusiveThe helper soft-validates before calling the typed classifier
Outside the model contract

ToolExecutionMode has only the tagged parallel and exclusive arms. isConcurrencySafe is host metadata; schema projection sends only name, description, and parameters. PARALLEL-MODE-CONTRACTPARALLEL-CLASSIFIERPARALLEL-TYPED-CLASSIFIER

3. This Is a Unary Promise, Not a Resource-Conflict Graph

The classifier contract supplies only the current call's parsed arguments and expects a synchronous unary judgment; it receives neither siblings nor the current pool. JavaScript does not technically prevent a closure from touching other state or initiating I/O, but doing so violates the classification contract and introduces dependencies the scheduler cannot see. Returning true is a strong promise: this call may overlap with any sibling that also returns true. It can express “read mode is parallel, write mode is exclusive” for one tool, but not “these two writes are safe only when their targets differ.”

Author responsibility

A parallel body must not mutate parent-owned state. Races in a shared recorder, provider, or cache must commute, serialize internally, or fail closed. The scheduler does not verify that promise. An overly broad declaration turns a latent race into production behavior; an overly narrow one only costs latency. The upstream design note explicitly chooses this conservative tradeoff. PARALLEL-SAFETY-NOTE

4. Groups Are Discovered Incrementally, Not Pre-Sliced Once

model calls: P1  P2  X3  P4

classify P1 → open a candidate parallel suffix
start P1, reclassify/start P2
reclassify X3 → stop replenishing, drain P1/P2
run X3 alone through post/commit
classify/start P4

The outer loop classifies only the current first call. An exclusive first call becomes a singleton group that is fully awaited. A parallel first call passes the remaining suffix to runGroup, whose pool classifies each later call again immediately before it starts. When one becomes exclusive, the current group returns its actual consumed count and leaves the barrier for the next outer iteration. PARALLEL-GROUPING

The barrier covers full commit

Exclusive does not merely mean “one body at a time.” The whole singleton group completes prepare, body, post, finalization, result append, and context acceptance before the next group starts. Tests cover parallel → exclusive → parallel grouping and reclassification after registry replacement. PARALLEL-GROUP-TESTS

5. The Rolling Pool Keeps Its Cap Without Fixed-Window Idling

inFlight holds dispatch Promises that have launched but have not yet been reaped by the driver; a settled Promise may remain briefly between settlement and deletion. The pool fills in order up to maxParallelToolCalls. Any settlement wakes the driver through Promise.race; the driver removes that slot, commits the contiguous ready prefix if possible, and then admits another call. It does not wait for an entire fixed window, so capacity beside one slow call remains useful.

cap = 2
start C1, C2
C2 settles first  → slot[1] ready, cannot commit, one capacity opens
start C3
C1 settles        → commit C1, C2; continue rolling
C3 settles        → commit C3
Cap semantics

The cap limits concurrently unsettled parallel dispatches in one Agent Step. It does not count settled slots waiting for an earlier commit and does not constrain another Agent. Tests prove cap-2 replenishment and fully serial behavior at cap 1. PARALLEL-ROLLING-POOLPARALLEL-CAP-TESTS

6. Why Only the Middle of the Pipeline Is Concurrent

StageConcurrencyReason
Append tool/callOrderedEstablish durable identity and the original argument fact first
Create execution, pre-execute, approval, guardsOrderedPolicy may carry order-sensitive state
tools/execute wrappers and bodyMay overlapThis is where external I/O and compute latency live; wrappers must be reentrant
Post-execute, rendering/finalization, result notificationInvoked in orderPromises returned by observers are not awaited, so their continuations may overlap
Append tool/result, accept contextOrderedAuthoritative model-history and next-Step order

ToolRuntime's symbol-keyed private scheduler view splits the same execution pipeline into prepare, dispatch, and finalize/finish. Ordinary callers still use the complete execute(). PARALLEL-PIPELINE-SPLITPARALLEL-PREPAREPARALLEL-DISPATCHPARALLEL-FINALIZE

7. What “Ordered Results” Means in the Session Log

Every started call first appends tool/call with the provider's raw argument string and retains its seq. At commit, the Loop creates tool/result from final content, isError, error information, and metadata, then points sourceEventSeqs:[callSeq] back to the exact call. Only then does it accept each additionalContexts item from that result. PARALLEL-DURABLE-PAIRING

The production test settles C2 first and confirms that no result exists before C1 is released. The final deriveMessages() output still contains C1 then C2. PARALLEL-ORDER-TESTS

8. Head-of-Line Blocking Deliberately Buys Consistency

Benefit

The next provider request, Session replay, post hooks, and next-step contexts all agree with the model's original call order. A later network response cannot reorder policy state merely because it was faster.

Cost

One slow early call blocks post/finalization and model visibility for every completed later result, whose slots remain in memory. The rolling pool may continue starting safe later work, but the model cannot consume it early. This is an explicit latency-versus-determinism tradeoff, not a missed scheduler wakeup.

9. Live Reclassification Closes Most Queue Drift but Does Not Snapshot a Definition

The scheduler reclassifies the first call after every barrier and rereads the current visible definition before each parallel-pool replenishment. If a synchronous result observer replaces a tool, an unstarted call sees the new classifier. A test proves the current pool drains before the replacement's new exclusive definition starts. PARALLEL-RECLASS-TESTS

Static finding: classify-to-body-resolution window

Classification does not pin ToolDefinition into the execution. After classification, startCall awaits ordered prepare; dispatch then awaits the tools/execute waterfall; only the body finally resolves the live definition again by name. A replacement from parallel to mutating exclusive anywhere in that interval can occupy the old parallel slot. The execution has also captured the old definition's finalizer, potentially producing “old finalizer + new body.” A complete repair must snapshot/bind one definition across classification and execution, or atomically validate a registry generation and schedule at actual body resolution. Reclassifying after prepare closes only one example window. PARALLEL-GROUPINGPARALLEL-PREPAREPARALLEL-DISPATCH

10. Result Observers Are Invoked in Order but Are Not Awaitable Scheduler Gates

finishScheduledExecution synchronously publishes the frozen result. notifyResult invokes callbacks in sequence but sends each returned Promise to an independent rejection handler instead of awaiting it. A registry change made before an observer's first await can therefore affect the next classification; a change made afterward may lose that race.

Extension boundary

Policy that must block later calls belongs in an awaited pre/post waterfall or must finish synchronously. Asynchronous tools/result work is appropriate for telemetry, not barriers. The current “result observer makes next call exclusive” test uses a synchronous callback and proves only synchronous mutation. PARALLEL-RESULT-OBSERVERPARALLEL-RECLASS-TESTS

11. Cancellation Stops Replenishment, Drains Started Calls, and Synthesizes Results for Skipped Calls

Cancellation pointBodyDurable resultLater behavior
Before a groupNo body startsEvery model call gets a synthetic call/result with ABORTED_BEFORE_DISPATCHNo next LLM request
During pre/approvalThe current body does not start; siblings are no longer preparedThe current and unstarted siblings receive before-dispatch errorsThe Step ends
During parallel bodiesThe signal propagates; the scheduler waits for all started Promises to quiesceA success normally becomes ABORTED; a tool-owned error may survive; all commit in model orderNo replenishment and no later exclusive barrier runs
During result/post commitStarted work is still drainedA final cancellation check may replace an outcome that remains successfulContexts remain in the inbox

The Loop's synthetic pairs ensure every tool-call in this Assistant message is closed for replay. This is an important change from the earlier design note. PARALLEL-ABORTPARALLEL-ABORT-RESULTPARALLEL-ABORT-TESTS

12. Cancellation Does Not Discard Accepted Additional Context

Post-policy still runs in order for started calls, and their additionalContexts enter the Agent's next-step inbox after the corresponding results commit. If cancellation ends the Turn, those items are not yet appended as user/message; they enter a new Step on the next wake. Tests pin C1, C2 context order and their parked inbox state after cancellation. PARALLEL-CONTEXT-TEST

concludesTurn is likewise aggregated only when a successful result commits in order. It does not cancel siblings already submitted in the same Assistant message. The Agent treats the Step as completed only after the scheduler finishes the batch. PARALLEL-AGENT-STEP

13. Ordinary Tool Failures and Scheduler-Invariant Failures Use Different Channels

Failure classCarrierDoes the group continue?
Arguments, policy denial, approval, guard, body, output, post, or finalizer failureToolRuntime normalizes a ToolExecutionResult.isErrorYes; it commits in model order and the model may self-correct next Step
An internal staged scheduler Promise unexpectedly rejectsThrown to the Agent Turn error boundaryNew dispatch stops and allSettled drains started work

The second class is not an ordinary extension result. The Native scheduler keeps already appended tool/call events and does not fabricate outcomes it cannot attribute, so the failed Step may contain calls without results. The Turn ultimately closes with an error reason. PARALLEL-SCHEDULER-FAILUREPARALLEL-FAILURE-TEST

14. Two Independent Tens: Native Steps and Code Runs Have Separate Pools

ConfigurationDefaultScopeDynamism
agent-loop.maxParallelToolCalls10Each top-level Step of each AgentSettings may update it; each group reads once, without disturbing an in-flight group
tools.maxParallelSubCalls10The nested binding pool of each run_codeFixed when ToolRuntime is constructed

Both require a positive integer, and 1 means serial. They are not one shared semaphore. Multiple Agents, concurrent runs, and provider concurrency may multiply, so API quota, process pools, and connection pools still require provider-level admission control. PARALLEL-CAP-CONFIGPARALLEL-CODE-DRIVER

15. Code Mode Repeats the Principle Without Reusing the Same Loop

run_code is one top-level exclusive tool from the model's perspective. Inside the program, every tools.name(args) call enters a separate per-run driver. That driver owns a pending queue, in-flight set, commit queue, and exclusiveActive. One ordered lane performs start/prepare and commit/finalize, while only nested dispatch bodies overlap.

program submissions
→ normalize lossless JSON + assign <outer>:code:N
→ pendingQueue (submission order)
→ classify at start
→ bounded inFlight bodies / exclusive barrier
→ commitQueue head cursor
→ program promise value or ToolCallError
→ defer contexts onto outer run_code result
Two history layers

A nested call does not create top-level tool/call/result. It writes tool/code-dispatch-start and tool/code-dispatch for UI and trajectory reconstruction. Only the outer run_code call's curated logs and result enter model history. PARALLEL-CODE-DRIVERPARALLEL-CODE-BINDING

16. Code Mode Barriers, Context, and Settlement

The driver always tries to commit a ready commitQueue[0] before starting the pending head. Exclusive waits for inFlight.size===0 and holds exclusiveActive until its own post/commit completes. A started binding resolves or rejects from its tool outcome only in ordered-commit settle(), so the program observes the policy-final canonical value or one ToolCallError message rather than raw body completion. A queued binding cancelled before start is the exception: abandon() rejects it.

Nested contexts are passed to exec.deferContext in commit order on the outer execution. They can survive even if the program later fails. Once the outer run settles, its run-scoped controller cancels in-flight calls, rejects queued-unstarted calls, and drains both the driver and durable log work before the outer tool returns. PARALLEL-CODE-BINDINGPARALLEL-CODE-DRAINPARALLEL-CODE-TESTS

17. Durable Nested-Event Order Is Weaker Than Binding Order in Code Mode

Static finding: log side work may reorder

Within the ordered commit lane, settle() first returns the result to the program and then launches asynchronous shapeDispatchLog → session.append(tool/code-dispatch) work. That work does not block the binding and is only drained collectively when the run ends. If an earlier log-content listener is slower than a later one, settlement events may append out of submission order. Start events remain ordered and the UI correlates by subCallId, so pairing is intact, but event seq/time must not be treated as canonical body-completion order. PARALLEL-CODE-BINDINGPARALLEL-CODE-DRAIN

The current concurrency test compares the set of settlement ids rather than their order. There is no assertion for settlement-event order under asynchronous log shaping. This must remain distinct from strict append order for Native top-level tool/result. PARALLEL-CODE-TESTS

18. Test Coverage Is Strong but Several Precise Timing Cases Remain

Proven behaviorEvidence style
Native parallel overlap, three-group barriers, dynamic replacement, rolling cap, and cap 1Deterministic gated tools
Native out-of-order body completion with ordered result, history, and contextRelease C2, assert no result, then release C1
Synthetic pairing and quiescence when cancelled before, during pre, during bodies, or before a barrierSession-event and inbox assertions
Native internal scheduler failure drains and closes the Turn as errorInjected private-scheduler rejection
Code Mode overlap, cap, exclusive barrier through post, and run-settlement drainPer-run gated tools
Coverage gap 1

The Code Mode test named “out-of-order completion” actually uses FIFO release(); its own comment acknowledges that reverse release is impossible, after which it calls releaseAll(). It does not make B complete before A. The commit cursor is clear in source, but the interleave claimed by the test name is not proven by that fixture. PARALLEL-CODE-ORDER-TEST

Other coverage gaps

Neither Native nor Code Mode directly tests replacement of a same-name definition after a parallel classification but before actual body resolution. There is also no characterization test for asynchronous result-observer continuations or asynchronous dispatch-log reordering. These are independent cases, not one fixed test count.

19. Documentation Audit: Both READMEs Are Current; Their Linked Implemented Note Is Not

packages/core/agent-loop/README and packages/core/tools/README accurately describe the rolling pool, exclusive barriers, ordered policy/results/context, default cap 10, and Code Mode's separate parallel bridge. PARALLEL-AGENT-READMEPARALLEL-README

Confirmed drift

The linked 2026-07-10 implemented Agent Note still says that unstarted calls have “no audit event” on cancellation, that Code Mode's internal queue remains serial and outside this scheduler, and that verification covers only a serial Code Mode boundary. Current source and tests use synthetic call/result pairs and a parallel per-run pool. The note should no longer be treated as the current “full safety contract”; it needs an update or an explicit supersession marker. PARALLEL-NOTE-DRIFT

20. Static Findings and Final Assessment

FindingClassificationImpact / recommendation
A live definition can change after classification but before actual body resolutionConditional concurrency-safety riskAdd tests; bind the definition or validate a registry generation at body resolution
Async result observers are not awaited by the schedulerExtension timing boundaryPut gating work in an awaited waterfall
Code nested settlement appends may reorder under asynchronous log shapingObservability boundaryPair by subCallId; do not infer body completion order from event seq
The Code “out-of-order” test never reverses completionRegression-coverage gapUse per-id gates and release the second call first
The implemented design note conflicts with current cancellation and Code schedulingDocumentation driftUpdate its decisions and verification claims
Both caps are local windows, not global admission controlOperational capacity boundaryKeep global quota in providers and hosts
The unary classifier cannot see resource relationshipsDeliberately conservativeKeep relationally safe operations exclusive
Overall judgment

The core algorithm is compact and disciplined: scheduler-controlled concurrency is concentrated in dispatch/bodies, intermediate results live in slots, and Native top-level post/result/context returns to one lane; cancellation and ordinary tool errors have explicit convergence paths. Async observers and Code nested logs are explicit exceptions. The highest-value next work is not a scheduler rewrite; it is closing the live-definition classify/body-resolution TOCTOU, separately covering definition replacement, observer continuations, nested-log reordering, and genuine reverse completion, and bringing the design note back in line with source.

Verification status

This chapter traced the ToolRuntime classifier and staged pipeline, Agent Loop scheduler and Session appends, Code Mode bridge, configuration, READMEs, implemented note, and corresponding unit tests line by line at the pinned commit. Targeted Vitest then passed all 120 tests across three files. That run proves the existing suite is green; the uncovered timing cases listed above remain static findings, not claimed regression proof.

My Learning Notes

Autosaved only in this browser. Nothing is uploaded or committed. Export Markdown whenever you want to keep a copy.