refactor(tools): let the terminal marker ride the nested result

The staged-promotion machinery (concludingParents keyed by parent token
plus a pendingParentConclusions staging map) spread one fact — this call
concluded the turn — across three registry-side collections with manual
cleanup. Align it with how additionalContexts already crosses the same
boundary: concludeTurn() marks only its own execution, the marker rides
that execution's successful result (ToolExecutionFailure types
concludesTurn as never, so a policy-converted failure sheds it with the
type), and the composite that owns the nested dispatch forwards it —
Code Mode's binding does so beside its existing context forwarding.

The registry loses both parent-keyed collections and the promotion
block; the propagation decision moves to the owning boundary; the
structured-output consumer's own two-phase commit is untouched.
This commit is contained in:
_Kerman
2026-07-26 21:24:16 +08:00
parent 39c09c9a49
commit 04f0435cc9
4 changed files with 68 additions and 34 deletions

View File

@@ -268,6 +268,12 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () =>
for (const context of result.additionalContexts ?? []) {
exec.deferContext(context)
}
// Like the context forwarding above, cross-boundary facts travel on
// the nested result and the composite forwards them: only a
// successful nested result can carry the terminal marker
// (ToolExecutionFailure types it never), so a policy-converted
// failure cannot stop the turn through a recovering program.
if (result.concludesTurn) exec.concludeTurn()
exec.agent?.session.append('tool/code-dispatch', {
parentCallId: exec.callId,
subCallId,