feat(tools): live dispatch lifecycle + native-contract parallel sub-calls in Code Mode

The bridge replaces its serialization queue with a pool that reuses the
native concurrency contract: submissions classify through
registry.executionMode (fail-closed isConcurrencySafe), start strictly in
submission order, overlap up to the validated maxParallelSubCalls config
(default 10; 1 restores serial), and exclusive calls drain the pool, run
alone, and bar later calls. Each started sub-call logs a
tool/code-dispatch-start event at pool entry; the existing
tool/code-dispatch settles the pair (started ⇔ settles exactly once;
abandoned queued calls log neither). SDK prompt guidance now states the
true Promise.all contract — re-recorded across every code/both-mode
snapshot (plus the stale cordis-dynamic-toolchain fixture gaining the
required description arg).

Client: CodeSubCall widens to RunningToolCall | ToolResultNode — starts
land the running shape (rows wear the native running ring), settles
replace in place preserving start order, callTime pairs to the start
time. Fixture emits start/settle pairs; jsdom pins the running sub-row;
runtime specs pin in-place settlement and out-of-order completion.
This commit is contained in:
Tianyi Cui
2026-07-26 06:02:36 +08:00
parent 526651cb88
commit 8a79679489
34 changed files with 1921 additions and 1673 deletions
@@ -20,7 +20,7 @@ import {
memo, useLayoutEffect, useMemo, useRef, useState, type ReactNode,
} from 'react'
import type {
ConversationNode, ConversationSnapshot, RunningToolCall, ToolResultNode,
CodeSubCall, ConversationNode, ConversationSnapshot, RunningToolCall, ToolResultNode,
} from '@deepseek-ai/dsh-client-runtime/client'
import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'
import { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
@@ -46,18 +46,22 @@ type RenderToolRow = ChatViewSlotProps['renderSlot']
type UseConversation = SnapshotSelectorHook<ConversationSnapshot>
/** One `run_code` sub-dispatch row: the identical keyed-slot dispatch as a
* top-level call (same registrations, same fallback), nested by the parent. */
* top-level call (same registrations, same fallback), nested by the parent.
* A started-but-unsettled sub-call arrives as the RunningToolCall shape and
* renders the running state exactly as a native in-flight row. */
const SubCallRow = memo(function SubCallRow({ renderSlot, node, onOpenDetails, selected }: {
renderSlot: RenderToolRow
node: ToolResultNode
node: CodeSubCall
onOpenDetails: OpenDetails
selected: boolean
}) {
const toolName = node.call?.name ?? ''
const settled = 'kind' in node
const toolName = settled ? node.call?.name ?? '' : node.name
const seq = settled ? node.seq : node.time
const owner = useMemo(() => ({
callId: node.callId, toolName, block: node,
openDetails: () => { onOpenDetails({ turnSeq: node.seq, callId: node.callId, toolName }) },
}), [node, toolName, onOpenDetails])
openDetails: () => { onOpenDetails({ turnSeq: seq, callId: node.callId, toolName }) },
}), [node, toolName, seq, onOpenDetails])
return (
<div className={css.callRow} data-selected={selected || undefined}>
{renderSlot('conversation.chat.toolview', owner, {
@@ -82,8 +86,8 @@ const CallRow = memo(function CallRow({ renderSlot, callId, toolName, block, seq
seq: number
onOpenDetails: OpenDetails
selected: boolean
/** `run_code` sub-dispatches in dispatch order (reference-stable per parent); undefined for ordinary calls. */
subCalls?: readonly ToolResultNode[] | undefined
/** `run_code` sub-dispatches in dispatch order (reference-stable per parent; running entries settle in place); undefined for ordinary calls. */
subCalls?: readonly CodeSubCall[] | undefined
/** The store's selected callId, matched against sub-rows (undefined when no sub-row here is selected). */
selectedCallId?: string | undefined
}) {
@@ -122,7 +126,7 @@ const ToolGroup = memo(function ToolGroup({ renderSlot, results, onOpenDetails,
/** Only set when the selected call lives in THIS group, top-level or nested (memo economy). */
selectedCallId: string | undefined
/** Sub-dispatch index off the snapshot (map reference is chunk-storm stable). */
codeDispatches: ReadonlyMap<string, readonly ToolResultNode[]>
codeDispatches: ReadonlyMap<string, readonly CodeSubCall[]>
}) {
return (
<div className={css.toolGroup}>
@@ -31,13 +31,16 @@ function materialFor(s: ConversationSnapshot, callId: string): CallMaterial | nu
if (open !== undefined) {
return { name: open.name, argsRaw: open.argsRaw, result: null, running: true }
}
// run_code sub-dispatches: already ToolResultNode-shaped, so a selected
// sub-row resolves through the same material as a native settled call.
// run_code sub-dispatches: the native call-block shapes, so a selected
// sub-row resolves through the same material as a native call — the
// settled ToolResultNode form, or the RunningToolCall form mid-flight.
for (const subs of s.codeDispatches.values()) {
for (const sub of subs) {
if (sub.callId === callId) {
if (sub.callId !== callId) continue
if ('kind' in sub) {
return { name: sub.call?.name ?? callId, argsRaw: sub.call?.argsRaw ?? null, result: sub, running: false }
}
return { name: sub.name, argsRaw: sub.argsRaw, result: null, running: true }
}
}
return null