mixdog 0.9.87 → 0.9.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -7
- package/scripts/tool-failures.mjs +60 -24
- package/src/agents/heavy-worker/AGENT.md +3 -4
- package/src/agents/worker/AGENT.md +1 -2
- package/src/cli.mjs +8 -0
- package/src/defaults/cycle3-review-prompt.md +4 -4
- package/src/rules/agent/00-core.md +3 -0
- package/src/rules/agent/42-cycle3-agent.md +5 -6
- package/src/rules/lead/01-general.md +2 -0
- package/src/rules/shared/01-tool.md +29 -35
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +3 -51
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +59 -0
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +67 -0
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +57 -4
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +2 -3
- package/src/runtime/agent/orchestrator/config.mjs +29 -11
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +0 -24
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +25 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +321 -22
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +35 -22
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +28 -23
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +10 -2
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +2 -5
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +27 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +329 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +23 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +107 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +4 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +124 -12
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +19 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +110 -75
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +96 -113
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +160 -11
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +18 -1
- package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +147 -117
- package/src/runtime/agent/orchestrator/session/loop/stop-hooks.mjs +88 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +50 -8
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +25 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +47 -6
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +485 -24
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +100 -2
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +80 -14
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +142 -2
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +128 -32
- package/src/runtime/agent/orchestrator/session/manager.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +77 -4
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +70 -39
- package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +91 -0
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +141 -64
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +253 -0
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +211 -28
- package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +313 -0
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +622 -53
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +43 -10
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +53 -8
- package/src/runtime/agent/orchestrator/session/store/summary-rebuild-worker.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +113 -9
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +476 -52
- package/src/runtime/agent/orchestrator/session/store.mjs +721 -196
- package/src/runtime/agent/orchestrator/session/token-native.mjs +2 -4
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +4 -6
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +146 -90
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +93 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +85 -5
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +52 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +54 -51
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +14 -15
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +132 -8
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +86 -3
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +210 -38
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +87 -19
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -8
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +12 -2
- package/src/runtime/media/lanes.mjs +2 -2
- package/src/runtime/media/renditions.mjs +101 -17
- package/src/runtime/media/renditions.test.mjs +54 -0
- package/src/runtime/media/store.mjs +111 -43
- package/src/runtime/media/store.test.mjs +53 -11
- package/src/runtime/memory/index.mjs +26 -50
- package/src/runtime/memory/lib/core-memory-candidates.mjs +2 -7
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -9
- package/src/runtime/memory/lib/cycle-scheduler.mjs +10 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +3 -3
- package/src/runtime/memory/lib/embedding-worker.mjs +60 -15
- package/src/runtime/memory/lib/http-router.mjs +4 -0
- package/src/runtime/memory/lib/ko-morph.mjs +49 -6
- package/src/runtime/memory/lib/memory-action-handlers.mjs +21 -18
- package/src/runtime/memory/lib/memory-cycle2.mjs +3 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -3
- package/src/runtime/memory/lib/memory-recall-store.mjs +24 -0
- package/src/runtime/memory/lib/query-handlers.mjs +26 -28
- package/src/runtime/memory/tool-defs.mjs +3 -3
- package/src/runtime/shared/atomic-file.mjs +5 -1
- package/src/runtime/shared/child-guardian.mjs +73 -2
- package/src/runtime/shared/provider-api-key.mjs +22 -5
- package/src/runtime/shared/tool-execution-contract.mjs +53 -0
- package/src/session-runtime/config-helpers.mjs +6 -5
- package/src/session-runtime/lifecycle-api.mjs +16 -4
- package/src/session-runtime/media-api.mjs +31 -16
- package/src/session-runtime/prewarm.mjs +2 -24
- package/src/session-runtime/runtime-core.mjs +33 -15
- package/src/session-runtime/runtime-tunables.mjs +0 -3
- package/src/session-runtime/session-lifecycle.mjs +0 -6
- package/src/session-runtime/session-title.mjs +228 -0
- package/src/session-runtime/session-turn-api.mjs +11 -7
- package/src/session-runtime/workflow-agents-api.mjs +16 -0
- package/src/session-runtime/workflow.mjs +7 -5
- package/src/standalone/agent-tool/job-views.mjs +90 -36
- package/src/standalone/agent-tool/spawn-flow.mjs +25 -216
- package/src/standalone/agent-tool/worker-index.mjs +8 -0
- package/src/standalone/agent-tool/worker-rows.mjs +2 -1
- package/src/standalone/agent-tool.mjs +17 -17
- package/src/standalone/agent-watchdog-registry.mjs +19 -2
- package/src/standalone/channel-daemon.mjs +8 -0
- package/src/standalone/explore-tool.mjs +1 -1
- package/src/standalone/memory-runtime-proxy.mjs +4 -7
- package/src/standalone/projects.mjs +4 -1
- package/src/standalone/usage-dashboard.mjs +25 -3
- package/src/tui/App.jsx +5 -3
- package/src/tui/app/resume-picker.mjs +7 -2
- package/src/tui/app/route-pickers.mjs +11 -117
- package/src/tui/app/slash-dispatch.mjs +13 -3
- package/src/tui/app/transcript-row-estimate.mjs +1 -1
- package/src/tui/app/transcript-window.mjs +17 -93
- package/src/tui/app/use-transcript-scroll.mjs +32 -2
- package/src/tui/app/use-transcript-window.mjs +64 -114
- package/src/tui/components/Markdown.jsx +19 -2
- package/src/tui/components/Message.jsx +8 -3
- package/src/tui/components/ToolExecution.jsx +7 -3
- package/src/tui/dist/index.mjs +243 -223
- package/src/tui/engine/live-share.mjs +15 -5
- package/src/tui/engine/render-timing.mjs +2 -2
- package/src/tui/engine/session-api-ext.mjs +74 -4
- package/src/tui/engine/session-flow.mjs +3 -1
- package/src/tui/engine.mjs +2 -2
- package/src/tui/hooks/useSharedTick.mjs +0 -2
- package/src/tui/index.jsx +5 -5
- package/src/ui/statusline-agents.mjs +44 -11
- package/src/vendor/statusline/bin/statusline-route.mjs +26 -3
- package/src/workflows/default/WORKFLOW.md +3 -3
- package/src/workflows/solo/WORKFLOW.md +5 -3
- package/src/runtime/media/index.mjs +0 -18
- package/src/runtime/memory/lib/embedding-warmup.mjs +0 -68
- package/src/standalone/agent-shard/shard-child.mjs +0 -300
- package/src/standalone/agent-shard/shard-pool.mjs +0 -443
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
extractCachedTokens,
|
|
20
20
|
appendAgentTrace,
|
|
21
21
|
} from '../agent-trace.mjs';
|
|
22
|
-
import {
|
|
22
|
+
import { typedStatusFrom } from './retry-classifier.mjs';
|
|
23
|
+
import { stampStreamOutcome, STREAM_TRANSPORTS } from './lib/stream-outcome.mjs';
|
|
23
24
|
import { makeInvalidToolArgsMarker } from './openai-compat-stream.mjs';
|
|
24
25
|
import { createLeakGuard, createToolCallDedupe, dedupeToolCallList } from './anthropic-leaked-toolcall.mjs';
|
|
25
26
|
import {
|
|
@@ -51,7 +52,6 @@ import {
|
|
|
51
52
|
} from './openai-ws-events.mjs';
|
|
52
53
|
import {
|
|
53
54
|
createActiveToolItemTracker,
|
|
54
|
-
hasCompleteToolCall as sharedHasCompleteToolCall,
|
|
55
55
|
} from './tool-stream-state.mjs';
|
|
56
56
|
import {
|
|
57
57
|
enableSessionTransportTracking,
|
|
@@ -125,6 +125,21 @@ function _writeWsLifecycleTrace(lifecycle) {
|
|
|
125
125
|
process.stderr.write(`[ws-trace] t=${new Date().toISOString()} lifecycle=${lifecycle}\n`);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
// Wire-level `end_turn` on a terminal Responses frame (codex-rs
|
|
129
|
+
// codex-api/src/sse/responses.rs ResponseCompleted.end_turn: Option<bool>,
|
|
130
|
+
// consumed in core/src/session/turn.rs:2299 as "false ⇒ needs follow-up").
|
|
131
|
+
// The field is optional: only a real boolean is normalized; anything else —
|
|
132
|
+
// including a missing field — stays undefined so absence is preserved and no
|
|
133
|
+
// caller can mistake "server said nothing" for "server said true/false".
|
|
134
|
+
export function _endTurnFromEvent(event) {
|
|
135
|
+
if (!event || typeof event !== 'object') return undefined;
|
|
136
|
+
const fromResponse = event.response?.end_turn;
|
|
137
|
+
if (typeof fromResponse === 'boolean') return fromResponse;
|
|
138
|
+
const topLevel = event.end_turn;
|
|
139
|
+
if (typeof topLevel === 'boolean') return topLevel;
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
128
143
|
function _responseItemKey(item, fallbackIndex = 0) {
|
|
129
144
|
if (!item || typeof item !== 'object') return `primitive:${fallbackIndex}`;
|
|
130
145
|
if (item.id) return `${item.type || 'item'}:id:${item.id}`;
|
|
@@ -309,12 +324,6 @@ export async function _streamResponse({
|
|
|
309
324
|
// input starts streaming (before it lands in pendingCalls/toolCalls).
|
|
310
325
|
// Gates partial-final SUCCESS so a stall mid tool-input never looks text-only.
|
|
311
326
|
let _toolInFlight = false;
|
|
312
|
-
// Early tool-call settle latch. Set when a fully-formed tool call is
|
|
313
|
-
// available but the server never emits response.completed/response.done —
|
|
314
|
-
// we resolve successfully anyway and surface `closeSocket` so the pool
|
|
315
|
-
// discards (never reuses) the socket, which may still carry the missing
|
|
316
|
-
// terminal frames as orphans.
|
|
317
|
-
let _earlySettled = false;
|
|
318
327
|
// Fix 2: cross-path name+args dedupe. A text-leaked synthetic and an
|
|
319
328
|
// identical native function_call must fire onToolCall exactly once. Every
|
|
320
329
|
// dispatch site routes through emitToolCallDedupe.
|
|
@@ -494,6 +503,9 @@ export async function _streamResponse({
|
|
|
494
503
|
let usage;
|
|
495
504
|
let stopReason = null;
|
|
496
505
|
let incompleteReason = null;
|
|
506
|
+
// Normalized wire `end_turn` from the terminal frame; stays undefined
|
|
507
|
+
// unless the server actually supplied a boolean.
|
|
508
|
+
let endTurn;
|
|
497
509
|
let done = false;
|
|
498
510
|
let terminalError = null;
|
|
499
511
|
// Mid-stream retry classifier needs to distinguish "stream died before we
|
|
@@ -640,19 +652,41 @@ export async function _streamResponse({
|
|
|
640
652
|
firstMeaningfulTimer = null;
|
|
641
653
|
}
|
|
642
654
|
};
|
|
655
|
+
// Streamed partial state for a stream that ended WITHOUT the terminal
|
|
656
|
+
// response.completed/done frame. The transport never synthesizes a
|
|
657
|
+
// completion: it reports the continuation plus what it had, and the
|
|
658
|
+
// loop decides (partial text failure / explicit tool-call turn).
|
|
659
|
+
// `pendingToolUse` means "a tool input never finished streaming" — a
|
|
660
|
+
// fully assembled call is not pending.
|
|
661
|
+
const _attachWsPartialState = (err) => {
|
|
662
|
+
if (!err) return err;
|
|
663
|
+
// Fold the held leak-guard tail into `content` FIRST so the partial
|
|
664
|
+
// snapshot keeps legitimate trailing text; finish() then skips
|
|
665
|
+
// flushLeak (terminalError set) without losing it.
|
|
666
|
+
try { flushLeak(); } catch { /* best-effort */ }
|
|
667
|
+
try {
|
|
668
|
+
err.partialContent = content;
|
|
669
|
+
err.partialToolCalls = toolCalls.length ? toolCalls.slice() : undefined;
|
|
670
|
+
err.pendingToolUse = pendingCalls.size > 0
|
|
671
|
+
|| activeToolItems.size > 0
|
|
672
|
+
|| _toolInFlight === true;
|
|
673
|
+
err.partialModel = model || undefined;
|
|
674
|
+
} catch { /* best-effort enrichment */ }
|
|
675
|
+
return err;
|
|
676
|
+
};
|
|
643
677
|
const resetInterChunk = () => {
|
|
644
678
|
if (interChunkTimer) clearTimeout(interChunkTimer);
|
|
645
679
|
interChunkTimer = setTimeout(() => {
|
|
646
|
-
// Early settle: a complete tool call is already captured with no
|
|
647
|
-
// deferred salvage pending, so silence here is the missing
|
|
648
|
-
// response.completed/done — resolve with the tool call instead
|
|
649
|
-
// of a stall error the loop would retry.
|
|
650
|
-
if (settleEarlyOnToolCall('inter_chunk')) return;
|
|
651
680
|
if (process.env.MIXDOG_DEBUG_AGENT) {
|
|
652
681
|
process.stderr.write(`[agent-trace] ws-timeout kind=inter-chunk afterMs=${interChunkMs}\n`);
|
|
653
682
|
}
|
|
654
683
|
traceWsTimeout('inter_chunk_timeout', interChunkMs);
|
|
655
684
|
terminalError = new Error(`WS stream: inter-chunk inactivity for ${interChunkMs}ms`);
|
|
685
|
+
// No terminal frame arrived, so this is a CONTINUATION, never a
|
|
686
|
+
// synthesized completion. Attach the streamed partial state so
|
|
687
|
+
// the loop's partial/tool recovery can finalize it explicitly.
|
|
688
|
+
terminalError.streamStalled = true;
|
|
689
|
+
_attachWsPartialState(terminalError);
|
|
656
690
|
try { socket.close(4000, 'inter_chunk_timeout'); } catch {}
|
|
657
691
|
// Same half-open guard as the pre-stream watchdog: reject directly
|
|
658
692
|
// so a stuck socket.close() cannot leave the Promise pending.
|
|
@@ -666,29 +700,12 @@ export async function _streamResponse({
|
|
|
666
700
|
if (!semanticIdleEnabled) return;
|
|
667
701
|
if (semanticIdleTimer) clearTimeout(semanticIdleTimer);
|
|
668
702
|
semanticIdleTimer = setTimeout(() => {
|
|
669
|
-
// Early settle before treating tool-work silence as a stall: if
|
|
670
|
-
// a complete tool call is available and no deferred salvage
|
|
671
|
-
// remains, the turn result is already final even without
|
|
672
|
-
// response.completed/done.
|
|
673
|
-
if (settleEarlyOnToolCall('semantic_idle')) return;
|
|
674
703
|
traceWsTimeout('semantic_idle_timeout', semanticIdleMs);
|
|
675
704
|
terminalError = streamStalledError('Responses WS', semanticIdleMs, { emittedToolCall: !!midState?.emittedToolCall });
|
|
676
705
|
// Partial-final recovery: attach streamed partial state so
|
|
677
706
|
// a wedged FINAL no-tool summary can be accepted as partial-final
|
|
678
707
|
// success by the loop. pendingToolUse gates out mid-flight tools.
|
|
679
|
-
|
|
680
|
-
// partial snapshot below keeps legitimate trailing text; finish()
|
|
681
|
-
// then skips flushLeak (terminalError set) without losing it.
|
|
682
|
-
flushLeak();
|
|
683
|
-
try {
|
|
684
|
-
terminalError.partialContent = content;
|
|
685
|
-
terminalError.partialToolCalls = toolCalls.length ? toolCalls.slice() : undefined;
|
|
686
|
-
terminalError.pendingToolUse = pendingCalls.size > 0
|
|
687
|
-
|| !!midState?.emittedToolCall
|
|
688
|
-
|| toolCalls.length > 0
|
|
689
|
-
|| _toolInFlight === true;
|
|
690
|
-
terminalError.partialModel = model || undefined;
|
|
691
|
-
} catch { /* best-effort enrichment */ }
|
|
708
|
+
_attachWsPartialState(terminalError);
|
|
692
709
|
try { terminalError.wsCloseCode = 4000; } catch {}
|
|
693
710
|
try { socket.close(4000, 'semantic_idle_timeout'); } catch {}
|
|
694
711
|
finish();
|
|
@@ -737,7 +754,33 @@ export async function _streamResponse({
|
|
|
737
754
|
// Flush any partial-sentinel tail held back mid-stream so
|
|
738
755
|
// legitimate trailing text is never lost (streamed-text path).
|
|
739
756
|
cleanup();
|
|
740
|
-
if (terminalError) {
|
|
757
|
+
if (terminalError) {
|
|
758
|
+
// Canonical stream-outcome contract: ONE authoritative record
|
|
759
|
+
// of what this WS turn produced, stamped on every reject path
|
|
760
|
+
// (watchdog stall, abnormal close, server error, abort). Legacy
|
|
761
|
+
// aliases are preserved by stampStreamOutcome().
|
|
762
|
+
try {
|
|
763
|
+
stampStreamOutcome(terminalError, {
|
|
764
|
+
transport: STREAM_TRANSPORTS.WS,
|
|
765
|
+
provider: 'openai-responses',
|
|
766
|
+
terminalObserved: midState.sawCompleted === true,
|
|
767
|
+
continuation: midState.sawCompleted !== true,
|
|
768
|
+
textEmitted: midState.emittedText === true,
|
|
769
|
+
textObservedChars: content.length,
|
|
770
|
+
reasoningEmitted: midState.emittedReasoning === true,
|
|
771
|
+
toolCallsStarted: midState.startedToolCall === true || pendingCalls.size > 0,
|
|
772
|
+
toolCallsComplete: toolCalls.length,
|
|
773
|
+
toolCallsDispatched: midState.emittedToolCall === true ? Math.max(1, toolCalls.length) : 0,
|
|
774
|
+
pendingToolInput: pendingCalls.size > 0 || _toolInFlight === true,
|
|
775
|
+
userAbort: midState.userAbort === true,
|
|
776
|
+
// A terminal frame with end_turn=false keeps the same
|
|
777
|
+
// user turn open: terminal observed, still continuation.
|
|
778
|
+
...(endTurn === false ? { continuationDeclared: true } : {}),
|
|
779
|
+
});
|
|
780
|
+
} catch { /* stamping is best-effort; aliases already set */ }
|
|
781
|
+
reject(terminalError);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
741
784
|
resolve({
|
|
742
785
|
content,
|
|
743
786
|
model,
|
|
@@ -754,44 +797,13 @@ export async function _streamResponse({
|
|
|
754
797
|
// for the WS path (sendViaWebSocket spreads this result
|
|
755
798
|
// through to the provider caller unchanged).
|
|
756
799
|
...(stopReason === 'length' && content.length > 0 ? { truncated: true } : {}),
|
|
757
|
-
// Early tool-call settle: tell the caller to drop (not pool)
|
|
758
|
-
// this socket. The server may still emit the skipped
|
|
759
|
-
// response.completed/done as orphan frames; reusing the socket
|
|
760
|
-
// would read them as the next request's stream and wedge it.
|
|
761
|
-
...(_earlySettled ? { closeSocket: true } : {}),
|
|
762
800
|
incompleteReason: incompleteReason || undefined,
|
|
801
|
+
// Only present when the terminal frame carried the wire field.
|
|
802
|
+
...(typeof endTurn === 'boolean' ? { endTurn } : {}),
|
|
763
803
|
responseId: responseId || undefined,
|
|
764
804
|
serviceTier: responseServiceTier || undefined,
|
|
765
805
|
});
|
|
766
806
|
};
|
|
767
|
-
// Early tool-call settle guard. A fully-formed tool call (real call_id +
|
|
768
|
-
// name, not a deferred salvage placeholder) means the turn's actionable
|
|
769
|
-
// result is already complete. When the server then goes silent without
|
|
770
|
-
// response.completed/response.done, resolve successfully with that tool
|
|
771
|
-
// call rather than surfacing a stall error the loop gates out via
|
|
772
|
-
// pendingToolUse and retries. Returns true if it settled the stream.
|
|
773
|
-
const hasCompleteToolCall = () => sharedHasCompleteToolCall({
|
|
774
|
-
toolCalls,
|
|
775
|
-
pendingSize: pendingCalls.size,
|
|
776
|
-
activeSize: activeToolItems.size,
|
|
777
|
-
toolInFlight: _toolInFlight,
|
|
778
|
-
});
|
|
779
|
-
const settleEarlyOnToolCall = (reason) => {
|
|
780
|
-
if (done || terminalError) return false;
|
|
781
|
-
if (!hasCompleteToolCall()) return false;
|
|
782
|
-
_earlySettled = true;
|
|
783
|
-
// Treat as a normal completion for downstream state: we have the
|
|
784
|
-
// canonical tool call, only the terminal lifecycle frame is missing.
|
|
785
|
-
midState.sawCompleted = true;
|
|
786
|
-
midState.wsEarlySettle = reason;
|
|
787
|
-
done = true;
|
|
788
|
-
// Close and mark keep=false (via closeSocket in the resolve). The
|
|
789
|
-
// late/never response.completed cannot then leak onto a pooled reuse.
|
|
790
|
-
try { socket.close(4000, `early_settle_${reason}`); } catch {}
|
|
791
|
-
finish();
|
|
792
|
-
return true;
|
|
793
|
-
};
|
|
794
|
-
|
|
795
807
|
messageHandler = (data) => {
|
|
796
808
|
const frameBytes = _incomingFrameByteLength(data);
|
|
797
809
|
if (maxIncomingFrameBytes > 0 && frameBytes != null && frameBytes > maxIncomingFrameBytes) {
|
|
@@ -837,7 +849,10 @@ export async function _streamResponse({
|
|
|
837
849
|
const err = new Error(event.error.message || 'Responses WS error');
|
|
838
850
|
try {
|
|
839
851
|
err.payload = event.error;
|
|
840
|
-
|
|
852
|
+
// Typed evidence only: a server error event without a
|
|
853
|
+
// numeric status stays unclassified (surfaced, not retried).
|
|
854
|
+
const typed = typedStatusFrom(event.error, event);
|
|
855
|
+
if (typed) err.httpStatus = typed;
|
|
841
856
|
} catch {}
|
|
842
857
|
terminalError = err;
|
|
843
858
|
finish();
|
|
@@ -1187,6 +1202,13 @@ export async function _streamResponse({
|
|
|
1187
1202
|
finish();
|
|
1188
1203
|
break;
|
|
1189
1204
|
}
|
|
1205
|
+
// Wire-level completion signal (optional). Captured after
|
|
1206
|
+
// salvage validation so a failed stream never reports a
|
|
1207
|
+
// turn-completion hint; absence stays undefined.
|
|
1208
|
+
{
|
|
1209
|
+
const wireEndTurn = _endTurnFromEvent(event);
|
|
1210
|
+
if (typeof wireEndTurn === 'boolean') endTurn = wireEndTurn;
|
|
1211
|
+
}
|
|
1190
1212
|
midState.sawCompleted = true;
|
|
1191
1213
|
done = true;
|
|
1192
1214
|
finish();
|
|
@@ -1212,7 +1234,10 @@ export async function _streamResponse({
|
|
|
1212
1234
|
new Error(`${errLabel} response.done failed: ${msg}`),
|
|
1213
1235
|
{ responseFailed: event },
|
|
1214
1236
|
);
|
|
1215
|
-
|
|
1237
|
+
{
|
|
1238
|
+
const typed = typedStatusFrom(event.response?.error, event.error, event);
|
|
1239
|
+
if (typed) terminalError.httpStatus = typed;
|
|
1240
|
+
}
|
|
1216
1241
|
done = true;
|
|
1217
1242
|
finish();
|
|
1218
1243
|
break;
|
|
@@ -1244,6 +1269,13 @@ export async function _streamResponse({
|
|
|
1244
1269
|
finish();
|
|
1245
1270
|
break;
|
|
1246
1271
|
}
|
|
1272
|
+
// Success-shaped response.done (status '' or 'completed')
|
|
1273
|
+
// is the terminal frame for streams that never emit
|
|
1274
|
+
// response.completed — carry the same optional end_turn.
|
|
1275
|
+
{
|
|
1276
|
+
const wireEndTurn = _endTurnFromEvent(event);
|
|
1277
|
+
if (typeof wireEndTurn === 'boolean') endTurn = wireEndTurn;
|
|
1278
|
+
}
|
|
1247
1279
|
midState.sawCompleted = true;
|
|
1248
1280
|
done = true;
|
|
1249
1281
|
finish();
|
|
@@ -1280,20 +1312,23 @@ export async function _streamResponse({
|
|
|
1280
1312
|
terminalError = Object.assign(new Error(`${errLabel} response.failed: ${msg}`), {
|
|
1281
1313
|
responseFailed: event,
|
|
1282
1314
|
});
|
|
1283
|
-
//
|
|
1284
|
-
//
|
|
1285
|
-
//
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1315
|
+
// TYPED status only (event/error payload). A failure whose
|
|
1316
|
+
// only evidence is message text is 'unknown' to the retry
|
|
1317
|
+
// classifiers and is surfaced instead of replayed.
|
|
1318
|
+
{
|
|
1319
|
+
const typed = typedStatusFrom(event.response?.error, event.error, event);
|
|
1320
|
+
if (typed) terminalError.httpStatus = typed;
|
|
1321
|
+
}
|
|
1290
1322
|
finish();
|
|
1291
1323
|
break;
|
|
1292
1324
|
}
|
|
1293
1325
|
case 'error': {
|
|
1294
1326
|
const errMsg = String(event.message || event.error?.message || 'unknown');
|
|
1295
1327
|
terminalError = new Error(`${errLabel} error: ${errMsg}`);
|
|
1296
|
-
|
|
1328
|
+
{
|
|
1329
|
+
const typed = typedStatusFrom(event.error, event);
|
|
1330
|
+
if (typed) terminalError.httpStatus = typed;
|
|
1331
|
+
}
|
|
1297
1332
|
finish();
|
|
1298
1333
|
break;
|
|
1299
1334
|
}
|