@caupulican/pi-agent-core 0.93.16 → 0.93.18

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.
@@ -39,6 +39,18 @@ export function createSilenceWatchdog(opts) {
39
39
  // --- Stream-idle watchdog (wraps a StreamFn) -------------------------------
40
40
  import { createAssistantMessageEventStream } from "@caupulican/pi-ai/event-stream";
41
41
  import { createEmptyUsage } from "@caupulican/pi-ai/usage";
42
+ /** Structured abort reason shared with profilers; the user-facing message remains stable. */
43
+ export class StreamStallError extends Error {
44
+ constructor(phase, elapsedMs) {
45
+ super(`stream stalled: no events for ${elapsedMs}ms (${phase} phase)`);
46
+ this.name = "StreamStallError";
47
+ this.phase = phase;
48
+ this.elapsedMs = elapsedMs;
49
+ }
50
+ }
51
+ export function isStreamStallError(value) {
52
+ return value instanceof StreamStallError;
53
+ }
42
54
  /** Defaults: connect 120s / first progress 120s / active 180s / quiet 600s. The quiet bound must stay
43
55
  * below the HTTP dispatcher idle timeout (see coding-agent http-dispatcher.ts, 660s) or the
44
56
  * HTTP layer would kill quiet-but-healthy streams before this watchdog ever sees the gap. */
@@ -163,8 +175,9 @@ export function withStreamIdleWatchdog(streamFn, options) {
163
175
  return;
164
176
  stalled = true;
165
177
  opts.onStall?.({ phase, elapsedMs });
166
- const description = `stream stalled: no events for ${elapsedMs}ms (${phase} phase)`;
167
- controller.abort(new Error(description));
178
+ const stallError = new StreamStallError(phase, elapsedMs);
179
+ const description = stallError.message;
180
+ controller.abort(stallError);
168
181
  const message = {
169
182
  ...latest,
170
183
  stopReason: "error",
@@ -1 +1 @@
1
- {"version":3,"file":"watchdogs.js","sourceRoot":"","sources":["../../src/reliability/watchdogs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Silence/idle watchdogs for the reliability kernel.\n *\n * A silence watchdog bounds \"running but mute\" — it never bounds total runtime,\n * so long tasks that produce output are never killed (autonomy constraint).\n */\n\nexport interface SilenceWatchdog {\n\t/** Report activity (output chunk / stream event); resets the countdown.\n\t * Pass silenceMs to also change the bound for this and subsequent countdowns. */\n\ttouch(silenceMs?: number): void;\n\t/** Stop permanently (normal completion). Idempotent. */\n\tdisarm(): void;\n}\n\nexport interface SilenceWatchdogOptions {\n\tsilenceMs: number;\n\t/** Fired at most once, after silenceMs with no touch(). The watchdog self-disarms. */\n\tonSilence: () => void;\n}\n\nexport function createSilenceWatchdog(opts: SilenceWatchdogOptions): SilenceWatchdog {\n\tlet timer: NodeJS.Timeout | undefined;\n\tlet disarmed = false;\n\tlet currentSilenceMs = opts.silenceMs;\n\n\tconst arm = () => {\n\t\ttimer = setTimeout(() => {\n\t\t\tdisarmed = true;\n\t\t\ttimer = undefined;\n\t\t\topts.onSilence();\n\t\t}, currentSilenceMs);\n\t\t// Never keep the host process alive just for a watchdog.\n\t\ttimer.unref?.();\n\t};\n\n\tarm();\n\n\treturn {\n\t\ttouch(silenceMs?: number): void {\n\t\t\tif (disarmed) return;\n\t\t\tif (silenceMs !== undefined) currentSilenceMs = silenceMs;\n\t\t\tif (timer) clearTimeout(timer);\n\t\t\tarm();\n\t\t},\n\t\tdisarm(): void {\n\t\t\tdisarmed = true;\n\t\t\tif (timer) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t},\n\t};\n}\n\n// --- Stream-idle watchdog (wraps a StreamFn) -------------------------------\n\nimport { createAssistantMessageEventStream } from \"@caupulican/pi-ai/event-stream\";\nimport type { Api, AssistantMessage, AssistantMessageEvent, Model, ProviderResponse } from \"@caupulican/pi-ai/types\";\nimport { createEmptyUsage } from \"@caupulican/pi-ai/usage\";\nimport type { StreamFn } from \"../types.ts\";\n\nexport type StallPhase = \"connect\" | \"first-progress\" | \"quiet\" | \"active\";\n\nexport interface StreamIdleOptions {\n\t/** Max ms to wait for the FIRST event (connection/first-token allowance). */\n\tconnectMs: number;\n\t/** Max ms between events while content is flowing — the latest content block is\n\t * text or toolCall. A flowing stream that goes silent this long is presumed dead. */\n\tactiveIdleMs: number;\n\t/** Max ms after transport confirmation until the first non-empty model delta.\n\t * Headers and structural start frames prove connectivity, not generation progress. */\n\tfirstProgressMs: number;\n\t/** Max ms between events while the model is quietly working — no content blocks\n\t * after it has emitted non-empty thinking. Deep-thinking models legitimately sit\n\t * here for minutes, so this bound is deliberately generous. */\n\tquietIdleMs: number;\n\t/** Fired once when a stall is detected, before the inner request is aborted. */\n\tonStall?: (info: { phase: StallPhase; elapsedMs: number }) => void;\n}\n\n/** Defaults: connect 120s / first progress 120s / active 180s / quiet 600s. The quiet bound must stay\n * below the HTTP dispatcher idle timeout (see coding-agent http-dispatcher.ts, 660s) or the\n * HTTP layer would kill quiet-but-healthy streams before this watchdog ever sees the gap. */\nexport const DEFAULT_STREAM_IDLE: StreamIdleOptions = {\n\tconnectMs: 120_000,\n\tfirstProgressMs: 120_000,\n\tactiveIdleMs: 180_000,\n\tquietIdleMs: 600_000,\n};\n\n/** Re-resolved at the start of every request, so hosts can wire live-tunable settings. */\nexport type StreamIdleOptionsResolver = (...args: Parameters<StreamFn>) => Partial<StreamIdleOptions>;\n\n/** Extracts the current AssistantMessage snapshot carried by any stream event variant. */\nfunction partialFromEvent(event: AssistantMessageEvent): AssistantMessage {\n\tif (event.type === \"done\") return event.message;\n\tif (event.type === \"error\") return event.error;\n\treturn event.partial;\n}\n\n/**\n * Wrap a StreamFn so a silently dead connection cannot wedge a turn forever.\n *\n * Phase-aware: `connectMs` bounds the wait for transport confirmation,\n * `firstProgressMs` bounds headers and structural frames that contain no model output,\n * `quietIdleMs` covers silence after non-empty thinking, and `activeIdleMs` covers\n * silence after text or tool-call output. This keeps detection fast where silence is\n * anomalous without killing healthy deep-thinking or compaction-sized requests.\n * No bound ever limits total runtime (autonomy constraint).\n *\n * On stall, the inner request is aborted and the returned stream resolves immediately\n * with a synthetic `AssistantMessage` (`stopReason: \"error\"`, `errorMessage: \"stream\n * stalled: no events for <n>ms (<phase> phase)\"`) — the `stream stalled` phrasing is\n * what `classifyFailure` maps to a retryable `stream_stall`, so the host's\n * retry/failover path takes it from there.\n *\n * Options may be a resolver function; it is re-invoked at the start of every request,\n * so settings changes apply without rewrapping.\n *\n * A caller-initiated abort (via the options `signal`) is never treated as a stall: it\n * is chained into the wrapper's own controller. The inner stream's abort result is\n * forwarded untouched when it provides one; if it just ends, the wrapper synthesizes\n * an aborted terminal event so the returned stream always settles.\n */\nexport function withStreamIdleWatchdog(\n\tstreamFn: StreamFn,\n\toptions?: Partial<StreamIdleOptions> | StreamIdleOptionsResolver,\n): StreamFn {\n\treturn (model, context, streamOptions) => {\n\t\tconst resolved = typeof options === \"function\" ? options(model, context, streamOptions) : options;\n\t\tconst cleaned: Partial<StreamIdleOptions> = {};\n\t\tif (resolved) {\n\t\t\tfor (const [key, val] of Object.entries(resolved)) {\n\t\t\t\tif (val !== undefined) {\n\t\t\t\t\t(cleaned as any)[key] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst opts = { ...DEFAULT_STREAM_IDLE, ...cleaned };\n\n\t\tconst controller = new AbortController();\n\t\tconst callerSignal = streamOptions?.signal;\n\t\tlet callerAborted = callerSignal?.aborted ?? false;\n\t\tconst outer = createAssistantMessageEventStream();\n\t\tlet readySettled = false;\n\t\tlet resolveReady: (stream: typeof outer) => void = () => {};\n\t\tconst ready = new Promise<typeof outer>((resolve) => {\n\t\t\tresolveReady = resolve;\n\t\t});\n\t\tconst settleReady = () => {\n\t\t\tif (readySettled) return;\n\t\t\treadySettled = true;\n\t\t\tresolveReady(outer);\n\t\t};\n\n\t\t// Seeded so a connect-phase stall (no event ever arrived) still has a base message\n\t\t// to report on; overwritten with the latest real snapshot once events start flowing.\n\t\tlet latest: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: createEmptyUsage(),\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tlet stalled = false;\n\t\tlet meaningfulProgressSeen = false;\n\t\tlet transportConfirmed = false;\n\t\tlet streamSetupSettled = false;\n\t\tlet terminalPushed = false;\n\t\tconst pushFailure = (error?: unknown) => {\n\t\t\tif (terminalPushed || stalled) return;\n\t\t\tconst stopReason = callerAborted ? \"aborted\" : \"error\";\n\t\t\tconst detail = error instanceof Error ? `: ${error.message}` : error === undefined ? \"\" : `: ${String(error)}`;\n\t\t\tterminalPushed = true;\n\t\t\touter.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: stopReason,\n\t\t\t\terror: {\n\t\t\t\t\t...latest,\n\t\t\t\t\tstopReason,\n\t\t\t\t\terrorMessage: callerAborted\n\t\t\t\t\t\t? `stream aborted before terminal event${detail}`\n\t\t\t\t\t\t: `stream ended without terminal event${detail}`,\n\t\t\t\t},\n\t\t\t});\n\t\t\tsettleReady();\n\t\t};\n\n\t\t// The idle bound adapts per event: quiet while nothing/thinking, active while\n\t\t// text/toolCall content is flowing. Mutable so the onSilence closure always\n\t\t// reports the phase/bound that actually elapsed.\n\t\tlet currentPhase: StallPhase = \"connect\";\n\t\tlet currentBoundMs = opts.connectMs;\n\t\tconst idleBoundFor = (message: AssistantMessage): { phase: StallPhase; ms: number } => {\n\t\t\tconst lastBlock = message.content[message.content.length - 1];\n\t\t\treturn !lastBlock || lastBlock.type === \"thinking\"\n\t\t\t\t? { phase: \"quiet\", ms: opts.quietIdleMs }\n\t\t\t\t: { phase: \"active\", ms: opts.activeIdleMs };\n\t\t};\n\n\t\t// Emits the stall result directly (rather than after the inner loop finishes) so a\n\t\t// connection that never resolves at all still yields a result promptly — providers\n\t\t// are contractually expected to end their stream after abort, but the watchdog does\n\t\t// not depend on that to report the stall itself.\n\t\tconst stall = (phase: StallPhase, elapsedMs: number) => {\n\t\t\tif (callerAborted || stalled || terminalPushed) return;\n\t\t\tstalled = true;\n\t\t\topts.onStall?.({ phase, elapsedMs });\n\t\t\tconst description = `stream stalled: no events for ${elapsedMs}ms (${phase} phase)`;\n\t\t\tcontroller.abort(new Error(description));\n\t\t\tconst message: AssistantMessage = {\n\t\t\t\t...latest,\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terrorMessage: description,\n\t\t\t};\n\t\t\tterminalPushed = true;\n\t\t\touter.push({ type: \"error\", reason: \"error\", error: message });\n\t\t\tsettleReady();\n\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t};\n\n\t\tconst watchdog = createSilenceWatchdog({\n\t\t\tsilenceMs: opts.connectMs,\n\t\t\tonSilence: () => stall(currentPhase, currentBoundMs),\n\t\t});\n\t\tconst markTransportConfirmed = () => {\n\t\t\tif (callerAborted || stalled || meaningfulProgressSeen || transportConfirmed) return;\n\t\t\ttransportConfirmed = true;\n\t\t\tcurrentPhase = \"first-progress\";\n\t\t\tcurrentBoundMs = opts.firstProgressMs;\n\t\t\twatchdog.touch(opts.firstProgressMs);\n\t\t};\n\t\tconst originalOnResponse = streamOptions?.onResponse;\n\t\tconst pushSetupAbort = () => {\n\t\t\tif (streamSetupSettled || terminalPushed || stalled) return;\n\t\t\tterminalPushed = true;\n\t\t\twatchdog.disarm();\n\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\touter.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: \"aborted\",\n\t\t\t\terror: {\n\t\t\t\t\t...latest,\n\t\t\t\t\tstopReason: \"aborted\",\n\t\t\t\t\terrorMessage: \"stream aborted before terminal event during stream setup\",\n\t\t\t\t},\n\t\t\t});\n\t\t\tsettleReady();\n\t\t};\n\t\tconst onCallerAbort = () => {\n\t\t\tcallerAborted = true;\n\t\t\tcontroller.abort(callerSignal?.reason);\n\t\t\tpushSetupAbort();\n\t\t};\n\t\tif (callerAborted) {\n\t\t\tonCallerAbort();\n\t\t\treturn ready;\n\t\t}\n\t\tcallerSignal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tlet inner: Awaited<ReturnType<StreamFn>>;\n\t\t\t\ttry {\n\t\t\t\t\tinner = await streamFn(model, context, {\n\t\t\t\t\t\t...streamOptions,\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t\tonResponse: async (response: ProviderResponse, responseModel: Model<Api>) => {\n\t\t\t\t\t\t\tmarkTransportConfirmed();\n\t\t\t\t\t\t\tawait originalOnResponse?.(response, responseModel);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tstreamSetupSettled = true;\n\t\t\t\t\tsettleReady();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstreamSetupSettled = true;\n\t\t\t\t\tif (terminalPushed || stalled) return;\n\t\t\t\t\twatchdog.disarm();\n\t\t\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\t\t\tpushFailure(error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// A setup promise may resolve after a connect stall or caller abort. The outer\n\t\t\t\t// stream is already terminal in that case, so never attach a late event pump.\n\t\t\t\tif (terminalPushed || stalled || callerAborted) return;\n\t\t\t\tfor await (const event of inner) {\n\t\t\t\t\tif (stalled) break;\n\t\t\t\t\tlatest = partialFromEvent(event);\n\t\t\t\t\tconst meaningfulProgress = eventHasMeaningfulProgress(event);\n\t\t\t\t\tif (meaningfulProgress) meaningfulProgressSeen = true;\n\t\t\t\t\tif (!transportConfirmed && !meaningfulProgress) {\n\t\t\t\t\t\tmarkTransportConfirmed();\n\t\t\t\t\t} else if (meaningfulProgressSeen) {\n\t\t\t\t\t\tconst bound = idleBoundFor(latest);\n\t\t\t\t\t\tcurrentPhase = bound.phase;\n\t\t\t\t\t\tcurrentBoundMs = bound.ms;\n\t\t\t\t\t\twatchdog.touch(bound.ms);\n\t\t\t\t\t}\n\t\t\t\t\t// A terminal event ends the turn: disarm synchronously, in the same tick as\n\t\t\t\t\t// the push below, so no watchdog can fire after the consumer's `result()`\n\t\t\t\t\t// promise resolves — a disarm that only happened once the loop later notices\n\t\t\t\t\t// `inner` is done would race with that resolution (it runs a tick or more\n\t\t\t\t\t// later) and could fire a spurious stall on an already-finished stream.\n\t\t\t\t\tconst terminal = event.type === \"done\" || event.type === \"error\";\n\t\t\t\t\tif (terminal) {\n\t\t\t\t\t\tterminalPushed = true;\n\t\t\t\t\t\twatchdog.disarm();\n\t\t\t\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\t\t\t}\n\t\t\t\t\touter.push(event);\n\t\t\t\t\tif (terminal) return;\n\t\t\t\t}\n\t\t\t\tif (!terminalPushed && !stalled) {\n\t\t\t\t\tconst stopReason = callerAborted ? \"aborted\" : \"error\";\n\t\t\t\t\tconst description = callerAborted\n\t\t\t\t\t\t? \"stream aborted before terminal event\"\n\t\t\t\t\t\t: \"stream ended without terminal event\";\n\t\t\t\t\tterminalPushed = true;\n\t\t\t\t\touter.push({\n\t\t\t\t\t\ttype: \"error\",\n\t\t\t\t\t\treason: stopReason,\n\t\t\t\t\t\terror: { ...latest, stopReason, errorMessage: description },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tpushFailure(error);\n\t\t\t} finally {\n\t\t\t\twatchdog.disarm();\n\t\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\t}\n\t\t})();\n\n\t\treturn ready;\n\t};\n}\n\nfunction eventHasMeaningfulProgress(event: AssistantMessageEvent): boolean {\n\tswitch (event.type) {\n\t\tcase \"text_delta\":\n\t\tcase \"thinking_delta\":\n\t\tcase \"toolcall_delta\":\n\t\t\treturn event.delta.length > 0;\n\t\tcase \"text_end\":\n\t\tcase \"thinking_end\":\n\t\t\treturn event.content.length > 0;\n\t\tcase \"toolcall_end\":\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n"]}
1
+ {"version":3,"file":"watchdogs.js","sourceRoot":"","sources":["../../src/reliability/watchdogs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Silence/idle watchdogs for the reliability kernel.\n *\n * A silence watchdog bounds \"running but mute\" — it never bounds total runtime,\n * so long tasks that produce output are never killed (autonomy constraint).\n */\n\nexport interface SilenceWatchdog {\n\t/** Report activity (output chunk / stream event); resets the countdown.\n\t * Pass silenceMs to also change the bound for this and subsequent countdowns. */\n\ttouch(silenceMs?: number): void;\n\t/** Stop permanently (normal completion). Idempotent. */\n\tdisarm(): void;\n}\n\nexport interface SilenceWatchdogOptions {\n\tsilenceMs: number;\n\t/** Fired at most once, after silenceMs with no touch(). The watchdog self-disarms. */\n\tonSilence: () => void;\n}\n\nexport function createSilenceWatchdog(opts: SilenceWatchdogOptions): SilenceWatchdog {\n\tlet timer: NodeJS.Timeout | undefined;\n\tlet disarmed = false;\n\tlet currentSilenceMs = opts.silenceMs;\n\n\tconst arm = () => {\n\t\ttimer = setTimeout(() => {\n\t\t\tdisarmed = true;\n\t\t\ttimer = undefined;\n\t\t\topts.onSilence();\n\t\t}, currentSilenceMs);\n\t\t// Never keep the host process alive just for a watchdog.\n\t\ttimer.unref?.();\n\t};\n\n\tarm();\n\n\treturn {\n\t\ttouch(silenceMs?: number): void {\n\t\t\tif (disarmed) return;\n\t\t\tif (silenceMs !== undefined) currentSilenceMs = silenceMs;\n\t\t\tif (timer) clearTimeout(timer);\n\t\t\tarm();\n\t\t},\n\t\tdisarm(): void {\n\t\t\tdisarmed = true;\n\t\t\tif (timer) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t},\n\t};\n}\n\n// --- Stream-idle watchdog (wraps a StreamFn) -------------------------------\n\nimport { createAssistantMessageEventStream } from \"@caupulican/pi-ai/event-stream\";\nimport type { Api, AssistantMessage, AssistantMessageEvent, Model, ProviderResponse } from \"@caupulican/pi-ai/types\";\nimport { createEmptyUsage } from \"@caupulican/pi-ai/usage\";\nimport type { StreamFn } from \"../types.ts\";\n\nexport type StallPhase = \"connect\" | \"first-progress\" | \"quiet\" | \"active\";\n\n/** Structured abort reason shared with profilers; the user-facing message remains stable. */\nexport class StreamStallError extends Error {\n\treadonly phase: StallPhase;\n\treadonly elapsedMs: number;\n\n\tconstructor(phase: StallPhase, elapsedMs: number) {\n\t\tsuper(`stream stalled: no events for ${elapsedMs}ms (${phase} phase)`);\n\t\tthis.name = \"StreamStallError\";\n\t\tthis.phase = phase;\n\t\tthis.elapsedMs = elapsedMs;\n\t}\n}\n\nexport function isStreamStallError(value: unknown): value is StreamStallError {\n\treturn value instanceof StreamStallError;\n}\n\nexport interface StreamIdleOptions {\n\t/** Max ms to wait for the FIRST event (connection/first-token allowance). */\n\tconnectMs: number;\n\t/** Max ms between events while content is flowing — the latest content block is\n\t * text or toolCall. A flowing stream that goes silent this long is presumed dead. */\n\tactiveIdleMs: number;\n\t/** Max ms after transport confirmation until the first non-empty model delta.\n\t * Headers and structural start frames prove connectivity, not generation progress. */\n\tfirstProgressMs: number;\n\t/** Max ms between events while the model is quietly working — no content blocks\n\t * after it has emitted non-empty thinking. Deep-thinking models legitimately sit\n\t * here for minutes, so this bound is deliberately generous. */\n\tquietIdleMs: number;\n\t/** Fired once when a stall is detected, before the inner request is aborted. */\n\tonStall?: (info: { phase: StallPhase; elapsedMs: number }) => void;\n}\n\n/** Defaults: connect 120s / first progress 120s / active 180s / quiet 600s. The quiet bound must stay\n * below the HTTP dispatcher idle timeout (see coding-agent http-dispatcher.ts, 660s) or the\n * HTTP layer would kill quiet-but-healthy streams before this watchdog ever sees the gap. */\nexport const DEFAULT_STREAM_IDLE: StreamIdleOptions = {\n\tconnectMs: 120_000,\n\tfirstProgressMs: 120_000,\n\tactiveIdleMs: 180_000,\n\tquietIdleMs: 600_000,\n};\n\n/** Re-resolved at the start of every request, so hosts can wire live-tunable settings. */\nexport type StreamIdleOptionsResolver = (...args: Parameters<StreamFn>) => Partial<StreamIdleOptions>;\n\n/** Extracts the current AssistantMessage snapshot carried by any stream event variant. */\nfunction partialFromEvent(event: AssistantMessageEvent): AssistantMessage {\n\tif (event.type === \"done\") return event.message;\n\tif (event.type === \"error\") return event.error;\n\treturn event.partial;\n}\n\n/**\n * Wrap a StreamFn so a silently dead connection cannot wedge a turn forever.\n *\n * Phase-aware: `connectMs` bounds the wait for transport confirmation,\n * `firstProgressMs` bounds headers and structural frames that contain no model output,\n * `quietIdleMs` covers silence after non-empty thinking, and `activeIdleMs` covers\n * silence after text or tool-call output. This keeps detection fast where silence is\n * anomalous without killing healthy deep-thinking or compaction-sized requests.\n * No bound ever limits total runtime (autonomy constraint).\n *\n * On stall, the inner request is aborted and the returned stream resolves immediately\n * with a synthetic `AssistantMessage` (`stopReason: \"error\"`, `errorMessage: \"stream\n * stalled: no events for <n>ms (<phase> phase)\"`) — the `stream stalled` phrasing is\n * what `classifyFailure` maps to a retryable `stream_stall`, so the host's\n * retry/failover path takes it from there.\n *\n * Options may be a resolver function; it is re-invoked at the start of every request,\n * so settings changes apply without rewrapping.\n *\n * A caller-initiated abort (via the options `signal`) is never treated as a stall: it\n * is chained into the wrapper's own controller. The inner stream's abort result is\n * forwarded untouched when it provides one; if it just ends, the wrapper synthesizes\n * an aborted terminal event so the returned stream always settles.\n */\nexport function withStreamIdleWatchdog(\n\tstreamFn: StreamFn,\n\toptions?: Partial<StreamIdleOptions> | StreamIdleOptionsResolver,\n): StreamFn {\n\treturn (model, context, streamOptions) => {\n\t\tconst resolved = typeof options === \"function\" ? options(model, context, streamOptions) : options;\n\t\tconst cleaned: Partial<StreamIdleOptions> = {};\n\t\tif (resolved) {\n\t\t\tfor (const [key, val] of Object.entries(resolved)) {\n\t\t\t\tif (val !== undefined) {\n\t\t\t\t\t(cleaned as any)[key] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst opts = { ...DEFAULT_STREAM_IDLE, ...cleaned };\n\n\t\tconst controller = new AbortController();\n\t\tconst callerSignal = streamOptions?.signal;\n\t\tlet callerAborted = callerSignal?.aborted ?? false;\n\t\tconst outer = createAssistantMessageEventStream();\n\t\tlet readySettled = false;\n\t\tlet resolveReady: (stream: typeof outer) => void = () => {};\n\t\tconst ready = new Promise<typeof outer>((resolve) => {\n\t\t\tresolveReady = resolve;\n\t\t});\n\t\tconst settleReady = () => {\n\t\t\tif (readySettled) return;\n\t\t\treadySettled = true;\n\t\t\tresolveReady(outer);\n\t\t};\n\n\t\t// Seeded so a connect-phase stall (no event ever arrived) still has a base message\n\t\t// to report on; overwritten with the latest real snapshot once events start flowing.\n\t\tlet latest: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: createEmptyUsage(),\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tlet stalled = false;\n\t\tlet meaningfulProgressSeen = false;\n\t\tlet transportConfirmed = false;\n\t\tlet streamSetupSettled = false;\n\t\tlet terminalPushed = false;\n\t\tconst pushFailure = (error?: unknown) => {\n\t\t\tif (terminalPushed || stalled) return;\n\t\t\tconst stopReason = callerAborted ? \"aborted\" : \"error\";\n\t\t\tconst detail = error instanceof Error ? `: ${error.message}` : error === undefined ? \"\" : `: ${String(error)}`;\n\t\t\tterminalPushed = true;\n\t\t\touter.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: stopReason,\n\t\t\t\terror: {\n\t\t\t\t\t...latest,\n\t\t\t\t\tstopReason,\n\t\t\t\t\terrorMessage: callerAborted\n\t\t\t\t\t\t? `stream aborted before terminal event${detail}`\n\t\t\t\t\t\t: `stream ended without terminal event${detail}`,\n\t\t\t\t},\n\t\t\t});\n\t\t\tsettleReady();\n\t\t};\n\n\t\t// The idle bound adapts per event: quiet while nothing/thinking, active while\n\t\t// text/toolCall content is flowing. Mutable so the onSilence closure always\n\t\t// reports the phase/bound that actually elapsed.\n\t\tlet currentPhase: StallPhase = \"connect\";\n\t\tlet currentBoundMs = opts.connectMs;\n\t\tconst idleBoundFor = (message: AssistantMessage): { phase: StallPhase; ms: number } => {\n\t\t\tconst lastBlock = message.content[message.content.length - 1];\n\t\t\treturn !lastBlock || lastBlock.type === \"thinking\"\n\t\t\t\t? { phase: \"quiet\", ms: opts.quietIdleMs }\n\t\t\t\t: { phase: \"active\", ms: opts.activeIdleMs };\n\t\t};\n\n\t\t// Emits the stall result directly (rather than after the inner loop finishes) so a\n\t\t// connection that never resolves at all still yields a result promptly — providers\n\t\t// are contractually expected to end their stream after abort, but the watchdog does\n\t\t// not depend on that to report the stall itself.\n\t\tconst stall = (phase: StallPhase, elapsedMs: number) => {\n\t\t\tif (callerAborted || stalled || terminalPushed) return;\n\t\t\tstalled = true;\n\t\t\topts.onStall?.({ phase, elapsedMs });\n\t\t\tconst stallError = new StreamStallError(phase, elapsedMs);\n\t\t\tconst description = stallError.message;\n\t\t\tcontroller.abort(stallError);\n\t\t\tconst message: AssistantMessage = {\n\t\t\t\t...latest,\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terrorMessage: description,\n\t\t\t};\n\t\t\tterminalPushed = true;\n\t\t\touter.push({ type: \"error\", reason: \"error\", error: message });\n\t\t\tsettleReady();\n\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t};\n\n\t\tconst watchdog = createSilenceWatchdog({\n\t\t\tsilenceMs: opts.connectMs,\n\t\t\tonSilence: () => stall(currentPhase, currentBoundMs),\n\t\t});\n\t\tconst markTransportConfirmed = () => {\n\t\t\tif (callerAborted || stalled || meaningfulProgressSeen || transportConfirmed) return;\n\t\t\ttransportConfirmed = true;\n\t\t\tcurrentPhase = \"first-progress\";\n\t\t\tcurrentBoundMs = opts.firstProgressMs;\n\t\t\twatchdog.touch(opts.firstProgressMs);\n\t\t};\n\t\tconst originalOnResponse = streamOptions?.onResponse;\n\t\tconst pushSetupAbort = () => {\n\t\t\tif (streamSetupSettled || terminalPushed || stalled) return;\n\t\t\tterminalPushed = true;\n\t\t\twatchdog.disarm();\n\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\touter.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: \"aborted\",\n\t\t\t\terror: {\n\t\t\t\t\t...latest,\n\t\t\t\t\tstopReason: \"aborted\",\n\t\t\t\t\terrorMessage: \"stream aborted before terminal event during stream setup\",\n\t\t\t\t},\n\t\t\t});\n\t\t\tsettleReady();\n\t\t};\n\t\tconst onCallerAbort = () => {\n\t\t\tcallerAborted = true;\n\t\t\tcontroller.abort(callerSignal?.reason);\n\t\t\tpushSetupAbort();\n\t\t};\n\t\tif (callerAborted) {\n\t\t\tonCallerAbort();\n\t\t\treturn ready;\n\t\t}\n\t\tcallerSignal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tlet inner: Awaited<ReturnType<StreamFn>>;\n\t\t\t\ttry {\n\t\t\t\t\tinner = await streamFn(model, context, {\n\t\t\t\t\t\t...streamOptions,\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t\tonResponse: async (response: ProviderResponse, responseModel: Model<Api>) => {\n\t\t\t\t\t\t\tmarkTransportConfirmed();\n\t\t\t\t\t\t\tawait originalOnResponse?.(response, responseModel);\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tstreamSetupSettled = true;\n\t\t\t\t\tsettleReady();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstreamSetupSettled = true;\n\t\t\t\t\tif (terminalPushed || stalled) return;\n\t\t\t\t\twatchdog.disarm();\n\t\t\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\t\t\tpushFailure(error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// A setup promise may resolve after a connect stall or caller abort. The outer\n\t\t\t\t// stream is already terminal in that case, so never attach a late event pump.\n\t\t\t\tif (terminalPushed || stalled || callerAborted) return;\n\t\t\t\tfor await (const event of inner) {\n\t\t\t\t\tif (stalled) break;\n\t\t\t\t\tlatest = partialFromEvent(event);\n\t\t\t\t\tconst meaningfulProgress = eventHasMeaningfulProgress(event);\n\t\t\t\t\tif (meaningfulProgress) meaningfulProgressSeen = true;\n\t\t\t\t\tif (!transportConfirmed && !meaningfulProgress) {\n\t\t\t\t\t\tmarkTransportConfirmed();\n\t\t\t\t\t} else if (meaningfulProgressSeen) {\n\t\t\t\t\t\tconst bound = idleBoundFor(latest);\n\t\t\t\t\t\tcurrentPhase = bound.phase;\n\t\t\t\t\t\tcurrentBoundMs = bound.ms;\n\t\t\t\t\t\twatchdog.touch(bound.ms);\n\t\t\t\t\t}\n\t\t\t\t\t// A terminal event ends the turn: disarm synchronously, in the same tick as\n\t\t\t\t\t// the push below, so no watchdog can fire after the consumer's `result()`\n\t\t\t\t\t// promise resolves — a disarm that only happened once the loop later notices\n\t\t\t\t\t// `inner` is done would race with that resolution (it runs a tick or more\n\t\t\t\t\t// later) and could fire a spurious stall on an already-finished stream.\n\t\t\t\t\tconst terminal = event.type === \"done\" || event.type === \"error\";\n\t\t\t\t\tif (terminal) {\n\t\t\t\t\t\tterminalPushed = true;\n\t\t\t\t\t\twatchdog.disarm();\n\t\t\t\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\t\t\t}\n\t\t\t\t\touter.push(event);\n\t\t\t\t\tif (terminal) return;\n\t\t\t\t}\n\t\t\t\tif (!terminalPushed && !stalled) {\n\t\t\t\t\tconst stopReason = callerAborted ? \"aborted\" : \"error\";\n\t\t\t\t\tconst description = callerAborted\n\t\t\t\t\t\t? \"stream aborted before terminal event\"\n\t\t\t\t\t\t: \"stream ended without terminal event\";\n\t\t\t\t\tterminalPushed = true;\n\t\t\t\t\touter.push({\n\t\t\t\t\t\ttype: \"error\",\n\t\t\t\t\t\treason: stopReason,\n\t\t\t\t\t\terror: { ...latest, stopReason, errorMessage: description },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tpushFailure(error);\n\t\t\t} finally {\n\t\t\t\twatchdog.disarm();\n\t\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t\t}\n\t\t})();\n\n\t\treturn ready;\n\t};\n}\n\nfunction eventHasMeaningfulProgress(event: AssistantMessageEvent): boolean {\n\tswitch (event.type) {\n\t\tcase \"text_delta\":\n\t\tcase \"thinking_delta\":\n\t\tcase \"toolcall_delta\":\n\t\t\treturn event.delta.length > 0;\n\t\tcase \"text_end\":\n\t\tcase \"thinking_end\":\n\t\t\treturn event.content.length > 0;\n\t\tcase \"toolcall_end\":\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n"]}
@@ -35,11 +35,19 @@ export interface ModelChangeEntry extends SessionEntryBase {
35
35
  provider: string;
36
36
  modelId: string;
37
37
  }
38
+ /** Sparse history retained after a full session-replacement compaction. */
39
+ export interface CompactionRetention {
40
+ mode: "original-user";
41
+ /** User-message entry that anchors the owner's original request on the active branch. */
42
+ userEntryId: string;
43
+ }
38
44
  export interface CompactionEntry<T = unknown> extends SessionEntryBase {
39
45
  type: "compaction";
40
46
  summary: string;
41
47
  firstKeptEntryId: string;
42
48
  tokensBefore: number;
49
+ /** Optional non-contiguous retention policy for provider-native session replacement. */
50
+ retention?: CompactionRetention;
43
51
  /** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
44
52
  details?: T;
45
53
  /** Usage from every LLM call that produced or verified this summary. */
@@ -238,7 +246,7 @@ export declare class SessionManager {
238
246
  /** Append a model change as child of current leaf, then advance leaf. Returns entry id. */
239
247
  appendModelChange(provider: string, modelId: string): string;
240
248
  /** Append a compaction summary as child of current leaf, then advance leaf. Returns entry id. */
241
- appendCompaction<T = unknown>(summary: string, firstKeptEntryId: string, tokensBefore: number, details?: T, fromHook?: boolean, usage?: Usage): string;
249
+ appendCompaction<T = unknown>(summary: string, firstKeptEntryId: string, tokensBefore: number, details?: T, fromHook?: boolean, usage?: Usage, retention?: CompactionRetention): string;
242
250
  /** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */
243
251
  appendCustomEntry(customType: string, data?: unknown): string;
244
252
  /** Append a session info entry (e.g., display name). Returns entry id. */
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
@@ -201,11 +201,9 @@ export function buildSessionContext(entries, leafId, byId) {
201
201
  compaction = entry;
202
202
  }
203
203
  }
204
- // Build messages and collect corresponding entries
205
- // When there's a compaction, we need to:
206
- // 1. Emit summary first (entry = compaction)
207
- // 2. Emit kept messages (from firstKeptEntryId up to compaction)
208
- // 3. Emit messages after compaction
204
+ // Build messages and collect corresponding entries. Standard compaction emits the summary followed
205
+ // by a contiguous recent tail. Session replacement instead retains one sparse original-user anchor
206
+ // before the summary, matching providers whose compactor atomically replaces the live transcript.
209
207
  const messages = [];
210
208
  const appendMessage = (entry) => {
211
209
  if (entry.type === "message") {
@@ -219,19 +217,28 @@ export function buildSessionContext(entries, leafId, byId) {
219
217
  }
220
218
  };
221
219
  if (compaction) {
222
- // Emit summary first
223
- messages.push(retainSynthesizedSessionContextMessage(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp)));
224
220
  // Find compaction index in path
225
221
  const compactionIdx = path.findIndex((e) => e.type === "compaction" && e.id === compaction.id);
226
- // Emit kept messages (before compaction, starting from firstKeptEntryId)
227
- let foundFirstKept = false;
228
- for (let i = 0; i < compactionIdx; i++) {
229
- const entry = path[i];
230
- if (entry.id === compaction.firstKeptEntryId) {
231
- foundFirstKept = true;
232
- }
233
- if (foundFirstKept) {
234
- appendMessage(entry);
222
+ const originalUserEntry = compaction.retention?.mode === "original-user"
223
+ ? path
224
+ .slice(0, compactionIdx)
225
+ .find((entry) => entry.id === compaction.retention?.userEntryId &&
226
+ entry.type === "message" &&
227
+ entry.message.role === "user")
228
+ : undefined;
229
+ if (originalUserEntry)
230
+ appendMessage(originalUserEntry);
231
+ messages.push(retainSynthesizedSessionContextMessage(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp)));
232
+ if (!compaction.retention) {
233
+ // Emit the standard contiguous tail before compaction, starting from firstKeptEntryId.
234
+ let foundFirstKept = false;
235
+ for (let i = 0; i < compactionIdx; i++) {
236
+ const entry = path[i];
237
+ if (entry.id === compaction.firstKeptEntryId) {
238
+ foundFirstKept = true;
239
+ }
240
+ if (foundFirstKept)
241
+ appendMessage(entry);
235
242
  }
236
243
  }
237
244
  // Emit messages after compaction
@@ -1120,24 +1127,42 @@ export class SessionManager {
1120
1127
  const leaf = this.leafId ? this.byId.get(this.leafId) : undefined;
1121
1128
  visitSessionAncestry(leaf, this.byId, (current) => {
1122
1129
  if (current.type === "compaction") {
1123
- this._releaseCompactedMessagePayloads(current.firstKeptEntryId, current.parentId);
1130
+ this._releaseCompactedMessagePayloads(current.firstKeptEntryId, current.parentId, current.retention, current.id);
1124
1131
  return false;
1125
1132
  }
1126
1133
  });
1127
1134
  }
1128
- _releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId) {
1135
+ _releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId, retention, compactionEntryId) {
1129
1136
  if (!this.persist || !this.flushed || !this.sessionFile)
1130
1137
  return;
1131
1138
  const keptEntryIds = new Set();
1132
1139
  let foundFirstKept = false;
1133
1140
  const compactionParent = compactionParentId ? this.byId.get(compactionParentId) : undefined;
1134
- visitSessionAncestry(compactionParent, this.byId, (current) => {
1135
- keptEntryIds.add(current.id);
1136
- if (current.id === firstKeptEntryId) {
1137
- foundFirstKept = true;
1138
- return false;
1139
- }
1140
- });
1141
+ if (retention?.mode === "original-user") {
1142
+ visitSessionAncestry(compactionParent, this.byId, (current) => {
1143
+ if (current.id === retention.userEntryId && current.type === "message" && current.message.role === "user") {
1144
+ keptEntryIds.add(current.id);
1145
+ foundFirstKept = true;
1146
+ return false;
1147
+ }
1148
+ });
1149
+ const leaf = this.leafId ? this.byId.get(this.leafId) : undefined;
1150
+ visitSessionAncestry(leaf, this.byId, (current) => {
1151
+ if (current.id === compactionEntryId)
1152
+ return false;
1153
+ if (current.type === "message")
1154
+ keptEntryIds.add(current.id);
1155
+ });
1156
+ }
1157
+ else {
1158
+ visitSessionAncestry(compactionParent, this.byId, (current) => {
1159
+ keptEntryIds.add(current.id);
1160
+ if (current.id === firstKeptEntryId) {
1161
+ foundFirstKept = true;
1162
+ return false;
1163
+ }
1164
+ });
1165
+ }
1141
1166
  if (!foundFirstKept)
1142
1167
  return;
1143
1168
  const retainedIds = new Set();
@@ -1288,7 +1313,7 @@ export class SessionManager {
1288
1313
  return entry.id;
1289
1314
  }
1290
1315
  /** Append a compaction summary as child of current leaf, then advance leaf. Returns entry id. */
1291
- appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromHook, usage) {
1316
+ appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromHook, usage, retention) {
1292
1317
  const compactionParentId = this.leafId;
1293
1318
  const entry = {
1294
1319
  type: "compaction",
@@ -1298,12 +1323,13 @@ export class SessionManager {
1298
1323
  summary,
1299
1324
  firstKeptEntryId,
1300
1325
  tokensBefore,
1326
+ retention,
1301
1327
  details,
1302
1328
  usage,
1303
1329
  fromHook,
1304
1330
  };
1305
1331
  this._appendEntry(entry);
1306
- this._releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId);
1332
+ this._releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId, retention, entry.id);
1307
1333
  return entry.id;
1308
1334
  }
1309
1335
  /** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */