@bitkyc08/opencodex 2.7.36 → 2.7.38-preview.20260724

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.
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Eager bounded single-reader SSE relay (#314 mitigation, WP2).
3
+ *
4
+ * Replaces the tee()+background-inspection passthrough shape on runtimes where
5
+ * the Bun#32111 async-pull cancel fix is present (src/lib/bun-stream-caps.ts):
6
+ * ONE eager producer loop reads upstream, feeds every chunk through the shared
7
+ * SSE inspector (terminal outcome, quota, request log, context cache), and
8
+ * enqueues it into a byte-bounded client queue. When the queue is full the
9
+ * producer pauses — no unbounded tee branch queue can build up behind a slow
10
+ * client.
11
+ *
12
+ * Honesty caveats (audit M5): full leak relief additionally assumes the
13
+ * runtime carries the Bun#29831 fetch receive-backpressure fix and that Bun's
14
+ * native Response sink pull-paces a JS ReadableStream. Neither is provable in
15
+ * bun:test (a JS reader always paces); both remain "awaiting Windows user
16
+ * verification".
17
+ *
18
+ * #44 cancel semantics: after client cancel the relay keeps reading upstream in
19
+ * DISCARD-DRAIN mode (inspection only) until a terminal is seen or the bounded
20
+ * drain window (ms/bytes) expires — a genuinely reached terminal records as
21
+ * completed/failed, never downgraded to cancel. Only when no terminal arrives
22
+ * within bounds does onClientCancel fire. This bounds today's unbounded tee
23
+ * drain; the tradeoff is that client-cancel log finalization may be delayed by
24
+ * up to the drain window.
25
+ */
26
+
27
+ export type EagerRelayHooks = {
28
+ /** Feed one upstream chunk through SSE inspection (createSseInspector.feed). */
29
+ inspectChunk: (chunk: Uint8Array) => void;
30
+ /** Flush inspection at upstream end (createSseInspector.finish). */
31
+ finishInspection: () => void;
32
+ /** True once inspection has reported a protocol terminal (inspector.reported). */
33
+ sawTerminal: () => boolean;
34
+ /** Record a synthetic terminal (caller decides incomplete vs failed-502). */
35
+ onSynthetic: (kind: "incomplete" | "failed") => void;
36
+ /** Client cancelled and NO terminal arrived within the drain bounds. */
37
+ onClientCancel: () => void;
38
+ /** Exactly once, after the producer fully stops (unregisterTurn parity). */
39
+ onDone: () => void;
40
+ };
41
+
42
+ export type EagerRelayOptions = {
43
+ /** Bounded client queue in bytes; producer pauses above it. Default 8 MiB. */
44
+ maxQueueBytes?: number;
45
+ /** Post-cancel discard-drain wall-clock bound. Default 15 000 ms. */
46
+ postCancelDrainMs?: number;
47
+ /** Post-cancel discard-drain byte bound. Default 32 MiB. */
48
+ postCancelDrainBytes?: number;
49
+ /** Injectable clock for tests. */
50
+ now?: () => number;
51
+ };
52
+
53
+ const DEFAULT_MAX_QUEUE_BYTES = 8 * 1024 * 1024;
54
+ const DEFAULT_DRAIN_MS = 15_000;
55
+ const DEFAULT_DRAIN_BYTES = 32 * 1024 * 1024;
56
+
57
+ /**
58
+ * Relay `body` to the returned stream with eager bounded reading and inline
59
+ * inspection. `upstream` is aborted on cancel-drain expiry and observed for
60
+ * shutdown teardown (its abort wakes a paused producer and suppresses
61
+ * synthetic terminals — audit M3).
62
+ */
63
+ export function relaySseEagerBounded(
64
+ body: ReadableStream<Uint8Array>,
65
+ upstream: AbortController,
66
+ hooks: EagerRelayHooks,
67
+ opts?: EagerRelayOptions,
68
+ ): ReadableStream<Uint8Array> {
69
+ const maxQueueBytes = opts?.maxQueueBytes ?? DEFAULT_MAX_QUEUE_BYTES;
70
+ const drainMs = opts?.postCancelDrainMs ?? DEFAULT_DRAIN_MS;
71
+ const drainBytes = opts?.postCancelDrainBytes ?? DEFAULT_DRAIN_BYTES;
72
+ const now = opts?.now ?? Date.now;
73
+
74
+ const reader = body.getReader();
75
+ let queuedBytes = 0;
76
+ let cancelled = false;
77
+ let done = false;
78
+ // Pause gate: resolved by client pull, client cancel, or upstream abort so a
79
+ // paused producer ALWAYS resumes (audit blocker 2 — no deadlock; onDone and
80
+ // turn unregistration stay reachable, drainAndShutdown never hangs).
81
+ let wake: (() => void) | null = null;
82
+ const wakeUp = () => { const w = wake; wake = null; w?.(); };
83
+ const paused = () => new Promise<void>(resolve => { wake = resolve; });
84
+ upstream.signal.addEventListener("abort", wakeUp, { once: true });
85
+
86
+ let controllerRef: ReadableStreamDefaultController<Uint8Array> | null = null;
87
+ let doneFired = false;
88
+ let drainTimer: ReturnType<typeof setTimeout> | null = null;
89
+ const fireDone = () => {
90
+ if (doneFired) return;
91
+ doneFired = true;
92
+ if (drainTimer) { clearTimeout(drainTimer); drainTimer = null; }
93
+ try { hooks.onDone(); } catch { /* lifecycle callbacks must not break teardown */ }
94
+ };
95
+ // A silent upstream after cancel would park the drain loop in reader.read();
96
+ // the wall-clock bound must fire regardless, so cancel arms a hard timer that
97
+ // aborts upstream at the deadline (the abort wakes the read).
98
+ const armDrainTimer = () => {
99
+ if (drainTimer) return;
100
+ drainTimer = setTimeout(() => {
101
+ drainTimer = null;
102
+ upstream.abort(new Error("post-cancel drain window expired"));
103
+ }, drainMs);
104
+ (drainTimer as { unref?: () => void }).unref?.();
105
+ };
106
+
107
+ const producer = async () => {
108
+ let syntheticKind: "incomplete" | "failed" | null = null;
109
+ // reader.read() is not intrinsically tied to the upstream AbortController
110
+ // (a fetch body usually rejects on abort, but that coupling is the fetch
111
+ // implementation's, not the stream's). Race every read against the abort
112
+ // signal so cancel-drain expiry and shutdown teardown ALWAYS break the
113
+ // loop even on a silent upstream.
114
+ const aborted: Promise<"aborted"> = new Promise(resolve => {
115
+ if (upstream.signal.aborted) resolve("aborted");
116
+ else upstream.signal.addEventListener("abort", () => resolve("aborted"), { once: true });
117
+ });
118
+ try {
119
+ for (;;) {
120
+ const result = await Promise.race([reader.read(), aborted]);
121
+ if (result === "aborted") break;
122
+ const { done: upstreamDone, value } = result;
123
+ if (upstreamDone) {
124
+ hooks.finishInspection();
125
+ if (!hooks.sawTerminal() && !cancelled && !upstream.signal.aborted) {
126
+ syntheticKind = "incomplete";
127
+ }
128
+ break;
129
+ }
130
+ hooks.inspectChunk(value);
131
+ if (cancelled) {
132
+ // Discard-drain: inspection only, nothing queued. Stop at terminal
133
+ // or when the bounded window expires.
134
+ drainedBytes += value.byteLength;
135
+ if (hooks.sawTerminal() || drainedBytes >= drainBytes || now() >= drainDeadline) {
136
+ break;
137
+ }
138
+ continue;
139
+ }
140
+ queuedBytes += value.byteLength;
141
+ try {
142
+ controllerRef?.enqueue(value);
143
+ } catch {
144
+ // Controller already torn down (client went away without cancel()).
145
+ cancelled = true;
146
+ drainDeadline = now() + drainMs;
147
+ armDrainTimer();
148
+ continue;
149
+ }
150
+ while (queuedBytes > maxQueueBytes && !cancelled && !upstream.signal.aborted) {
151
+ await paused();
152
+ }
153
+ }
154
+ } catch {
155
+ // Upstream read failure. Distinguish genuine mid-stream reset from
156
+ // abort-driven teardown (shutdown/cancel-expiry) — audit M3.
157
+ if (!hooks.sawTerminal() && !cancelled && !upstream.signal.aborted) {
158
+ syntheticKind = "failed";
159
+ try { controllerRef?.error(new Error("upstream stream failed")); } catch { /* torn down */ }
160
+ }
161
+ } finally {
162
+ if (syntheticKind) hooks.onSynthetic(syntheticKind);
163
+ if (cancelled && !hooks.sawTerminal()) {
164
+ hooks.onClientCancel();
165
+ }
166
+ if (cancelled || upstream.signal.aborted) {
167
+ upstream.abort();
168
+ reader.cancel().catch(() => {});
169
+ }
170
+ if (!cancelled) {
171
+ try { controllerRef?.close(); } catch { /* already closed/errored */ }
172
+ }
173
+ fireDone();
174
+ }
175
+ };
176
+
177
+ let drainedBytes = 0;
178
+ let drainDeadline = Number.POSITIVE_INFINITY;
179
+
180
+ return new ReadableStream<Uint8Array>({
181
+ start(controller) {
182
+ controllerRef = controller;
183
+ void producer();
184
+ },
185
+ pull() {
186
+ // The client consumed from the queue; approximate accounting: reset on
187
+ // pull below cap. desiredSize reflects internal queue in chunks, not
188
+ // bytes, so we track bytes ourselves and drain optimistically.
189
+ queuedBytes = 0;
190
+ wakeUp();
191
+ },
192
+ cancel() {
193
+ cancelled = true;
194
+ drainDeadline = now() + drainMs;
195
+ armDrainTimer();
196
+ wakeUp();
197
+ },
198
+ });
199
+ }
@@ -159,15 +159,22 @@ export function completedResponseFromSsePayload(payload: string): { id?: unknown
159
159
  if (payload === "[DONE]") return null;
160
160
  try {
161
161
  const json = JSON.parse(payload) as { type?: unknown; response?: unknown };
162
- if (json.type !== "response.completed") return null;
163
- const response = json.response;
164
- if (!response || typeof response !== "object" || Array.isArray(response)) return null;
165
- return response as { id?: unknown; output?: unknown; status?: unknown };
162
+ return completedResponseFromParsedEvent(json);
166
163
  } catch {
167
164
  return null;
168
165
  }
169
166
  }
170
167
 
168
+ /** Extract the response object from an already-parsed `response.completed` event, or null. */
169
+ function completedResponseFromParsedEvent(
170
+ json: { type?: unknown; response?: unknown } | null,
171
+ ): { id?: unknown; output?: unknown; status?: unknown } | null {
172
+ if (!json || json.type !== "response.completed") return null;
173
+ const response = json.response;
174
+ if (!response || typeof response !== "object" || Array.isArray(response)) return null;
175
+ return response as { id?: unknown; output?: unknown; status?: unknown };
176
+ }
177
+
171
178
  export function trackSseForRequestLog(
172
179
  body: ReadableStream<Uint8Array>,
173
180
  onTerminal: (status: ResponsesTerminalStatus) => void,
@@ -404,6 +411,116 @@ export function relaySseWithHeartbeat(
404
411
  * Background-consume an SSE stream purely for terminal-outcome inspection (quota tracking).
405
412
  * Does not produce output; safe to ignore errors (the client-facing stream is separate).
406
413
  */
414
+ export type SseInspector = {
415
+ /** Feed one upstream chunk through the SSE scanning state machine. */
416
+ feed(chunk: Uint8Array): void;
417
+ /** Flush the decoder + trailing unterminated buffer (upstream cleanly done). */
418
+ finish(): void;
419
+ /** True once a protocol terminal was detected and reported. */
420
+ reported(): boolean;
421
+ };
422
+
423
+ /**
424
+ * Per-chunk SSE inspection state machine shared by consumeForInspection,
425
+ * consumeForResponseLogMetadata, and the eager bounded relay (relay-eager.ts).
426
+ *
427
+ * Extraction-fidelity invariants (devlog/_plan/260723_win_mem_safestream/020):
428
+ * - logCtx SSE inspection is gated on !reported; in the metadata configuration
429
+ * (no onTerminal) `reported` stays permanently false, which reproduces the
430
+ * metadata consumer's unconditional inspection through the same gate.
431
+ * - finish() skips the trailing-buffer scan once reported, while per-block
432
+ * onCompletedResponse continues firing after reported — an intentional
433
+ * asymmetry inherited from consumeForInspection.
434
+ * - logCtx.transportPhase/terminalSource are mutated BEFORE onTerminal fires.
435
+ * - Synthetic terminals (incomplete / failed-502) are the CALLER's decision:
436
+ * the caller owns `cancelled` state and reads `reported()` to decide.
437
+ */
438
+ export function createSseInspector(handlers: {
439
+ onTerminal?: (status: ResponsesTerminalStatus, httpStatusOverride?: number) => void;
440
+ logCtx?: RequestLogContext;
441
+ onCompletedResponse?: (response: { id?: unknown; output?: unknown; status?: unknown }) => void;
442
+ onFirstOutput?: () => void;
443
+ }): SseInspector {
444
+ const decoder = new TextDecoder();
445
+ let buffer = "";
446
+ let reported = false;
447
+ const reportFirstOutput = createFirstOutputReporter(handlers.onFirstOutput);
448
+ // Allocate reconstruction state only for persistence-capable inspectors.
449
+ const completedItemsByOutputIndex = handlers.onCompletedResponse
450
+ ? new Map<number, unknown>()
451
+ : null;
452
+
453
+ const scanPayload = (payload: string | null): void => {
454
+ if (!reported && handlers.logCtx) inspectResponseLogSsePayload(handlers.logCtx, payload);
455
+ reportFirstOutput(payload);
456
+ if (!payload) return;
457
+ if (!reported && handlers.onTerminal) {
458
+ const status = terminalStatusFromSsePayload(payload);
459
+ if (status) {
460
+ reported = true;
461
+ if (handlers.logCtx) {
462
+ handlers.logCtx.transportPhase = "terminal_sse";
463
+ handlers.logCtx.terminalSource = "upstream";
464
+ }
465
+ handlers.onTerminal(status);
466
+ }
467
+ }
468
+ if (handlers.onCompletedResponse) {
469
+ type ParsedSseEvent = { type?: unknown; output_index?: unknown; item?: unknown; response?: unknown };
470
+ let parsedEvent: ParsedSseEvent | null = null;
471
+ try {
472
+ if (payload !== "[DONE]") parsedEvent = JSON.parse(payload) as ParsedSseEvent;
473
+ } catch {
474
+ /* malformed SSE payloads remain best-effort/no-throw */
475
+ }
476
+ const doneItem = parsedEvent?.type === "response.output_item.done" ? parsedEvent.item : undefined;
477
+ if (parsedEvent
478
+ && doneItem !== undefined
479
+ && Number.isInteger(parsedEvent.output_index)
480
+ && (parsedEvent.output_index as number) >= 0
481
+ && typeof doneItem === "object"
482
+ && doneItem !== null
483
+ && !Array.isArray(doneItem)
484
+ && typeof (doneItem as { type?: unknown }).type === "string") {
485
+ completedItemsByOutputIndex!.set(parsedEvent.output_index as number, doneItem);
486
+ }
487
+
488
+ let response = completedResponseFromParsedEvent(parsedEvent);
489
+ if (response
490
+ && (!Array.isArray(response.output) || response.output.length === 0)
491
+ && completedItemsByOutputIndex!.size > 0) {
492
+ response = {
493
+ ...response,
494
+ output: [...completedItemsByOutputIndex!.entries()]
495
+ .sort(([left], [right]) => left - right)
496
+ .map(([, item]) => item),
497
+ };
498
+ }
499
+ if (response) handlers.onCompletedResponse(response);
500
+ }
501
+ };
502
+
503
+ return {
504
+ feed(chunk) {
505
+ buffer += decoder.decode(chunk, { stream: true });
506
+ let next: { block: string; rest: string } | null;
507
+ while ((next = nextSseBlock(buffer))) {
508
+ buffer = next.rest;
509
+ if (reported && !handlers.onCompletedResponse) continue;
510
+ scanPayload(sseDataPayload(next.block));
511
+ }
512
+ },
513
+ finish() {
514
+ buffer += decoder.decode();
515
+ if (buffer.trim() && !reported) {
516
+ scanPayload(sseDataPayload(buffer));
517
+ }
518
+ buffer = "";
519
+ },
520
+ reported: () => reported,
521
+ };
522
+ }
523
+
407
524
  export function consumeForInspection(
408
525
  body: ReadableStream<Uint8Array>,
409
526
  onTerminal: (status: ResponsesTerminalStatus, httpStatusOverride?: number) => void,
@@ -415,11 +532,8 @@ export function consumeForInspection(
415
532
  onFirstOutput?: () => void,
416
533
  ): void {
417
534
  const reader = body.getReader();
418
- const decoder = new TextDecoder();
419
- let buffer = "";
420
- let reported = false;
535
+ const inspector = createSseInspector({ onTerminal, logCtx, onCompletedResponse, onFirstOutput });
421
536
  let cancelled = false;
422
- const reportFirstOutput = createFirstOutputReporter(onFirstOutput);
423
537
  if (signal) {
424
538
  if (signal.aborted) {
425
539
  // Aborted before we could read anything (Codex disconnects the instant it finishes reading).
@@ -444,64 +558,20 @@ export function consumeForInspection(
444
558
  for (;;) {
445
559
  const { done, value } = await reader.read();
446
560
  if (done) {
447
- buffer += decoder.decode();
448
- if (buffer.trim() && !reported) {
449
- const payload = sseDataPayload(buffer);
450
- if (logCtx) inspectResponseLogSsePayload(logCtx, payload);
451
- reportFirstOutput(payload);
452
- if (payload) {
453
- const status = terminalStatusFromSsePayload(payload);
454
- if (status) {
455
- reported = true;
456
- if (logCtx) {
457
- logCtx.transportPhase = "terminal_sse";
458
- logCtx.terminalSource = "upstream";
459
- }
460
- onTerminal(status);
461
- }
462
- if (onCompletedResponse) {
463
- const response = completedResponseFromSsePayload(payload);
464
- if (response) onCompletedResponse(response);
465
- }
466
- }
467
- }
468
- if (!reported && !cancelled) {
561
+ inspector.finish();
562
+ if (!inspector.reported() && !cancelled) {
469
563
  if (logCtx) logCtx.terminalSource = "synthetic";
470
564
  onTerminal("incomplete");
471
565
  }
472
566
  return;
473
567
  }
474
- buffer += decoder.decode(value, { stream: true });
475
- let next: { block: string; rest: string } | null;
476
- while ((next = nextSseBlock(buffer))) {
477
- buffer = next.rest;
478
- if (reported && !onCompletedResponse) continue;
479
- const payload = sseDataPayload(next.block);
480
- if (!reported && logCtx) inspectResponseLogSsePayload(logCtx, payload);
481
- reportFirstOutput(payload);
482
- if (!payload) continue;
483
- if (!reported) {
484
- const status = terminalStatusFromSsePayload(payload);
485
- if (status) {
486
- reported = true;
487
- if (logCtx) {
488
- logCtx.transportPhase = "terminal_sse";
489
- logCtx.terminalSource = "upstream";
490
- }
491
- onTerminal(status);
492
- }
493
- }
494
- if (onCompletedResponse) {
495
- const response = completedResponseFromSsePayload(payload);
496
- if (response) onCompletedResponse(response);
497
- }
498
- }
568
+ inspector.feed(value);
499
569
  }
500
570
  } catch {
501
571
  // Upstream read failure after HTTP 200 (mid-stream socket reset) is not a
502
572
  // protocol `response.incomplete` terminal. Report a synthetic 502 so account
503
573
  // health treats it as transient; abort-driven client cancellation still wins.
504
- if (!reported && !cancelled) {
574
+ if (!inspector.reported() && !cancelled) {
505
575
  if (logCtx) {
506
576
  logCtx.transportPhase = "mid_stream";
507
577
  logCtx.terminalSource = "synthetic";
@@ -524,9 +594,9 @@ export function consumeForResponseLogMetadata(
524
594
  onFirstOutput?: () => void,
525
595
  ): void {
526
596
  const reader = body.getReader();
527
- const decoder = new TextDecoder();
528
- let buffer = "";
529
- const reportFirstOutput = createFirstOutputReporter(onFirstOutput);
597
+ // No onTerminal the inspector's `reported` gate stays permanently false,
598
+ // reproducing this consumer's unconditional logCtx inspection.
599
+ const inspector = createSseInspector({ logCtx, onCompletedResponse, onFirstOutput });
530
600
  if (signal) {
531
601
  if (signal.aborted) {
532
602
  reader.cancel(signal.reason).catch(() => {});
@@ -542,30 +612,10 @@ export function consumeForResponseLogMetadata(
542
612
  for (;;) {
543
613
  const { done, value } = await reader.read();
544
614
  if (done) {
545
- buffer += decoder.decode();
546
- if (buffer.trim()) {
547
- const payload = sseDataPayload(buffer);
548
- inspectResponseLogSsePayload(logCtx, payload);
549
- reportFirstOutput(payload);
550
- if (payload && onCompletedResponse) {
551
- const response = completedResponseFromSsePayload(payload);
552
- if (response) onCompletedResponse(response);
553
- }
554
- }
615
+ inspector.finish();
555
616
  return;
556
617
  }
557
- buffer += decoder.decode(value, { stream: true });
558
- let next: { block: string; rest: string } | null;
559
- while ((next = nextSseBlock(buffer))) {
560
- buffer = next.rest;
561
- const payload = sseDataPayload(next.block);
562
- inspectResponseLogSsePayload(logCtx, payload);
563
- reportFirstOutput(payload);
564
- if (payload && onCompletedResponse) {
565
- const response = completedResponseFromSsePayload(payload);
566
- if (response) onCompletedResponse(response);
567
- }
568
- }
618
+ inspector.feed(value);
569
619
  }
570
620
  } catch {
571
621
  /* metadata inspection must not affect the client-facing stream */
@@ -281,11 +281,29 @@ export function subagentRosterText(models: Array<{ model: string; efforts: strin
281
281
 
282
282
 
283
283
 
284
+ function isRecord(value: unknown): value is Record<string, unknown> {
285
+ return !!value && typeof value === "object" && !Array.isArray(value);
286
+ }
287
+
288
+ function isGeneratedDeveloperItem(item: unknown, text: string): boolean {
289
+ if (!isRecord(item) || item.type !== "message" || item.role !== "developer") return false;
290
+ if (!Array.isArray(item.content) || item.content.length !== 1) return false;
291
+ const [part] = item.content;
292
+ return isRecord(part) && part.type === "input_text" && part.text === text;
293
+ }
294
+
284
295
  export function injectDeveloperMessage(parsed: OcxParsedRequest, text: string): void {
285
- parsed.context.messages.push({ role: "developer", content: text, timestamp: Date.now() });
286
296
  const raw = parsed._rawBody as { input?: unknown } | undefined;
297
+ const devItem = { type: "message", role: "developer", content: [{ type: "input_text", text }] };
298
+ if (raw && Array.isArray(raw.input)) {
299
+ const replayPrefixLen = Math.min(parsed._replayPrefixLen ?? 0, raw.input.length);
300
+ if (raw.input.slice(0, replayPrefixLen).some(item => isGeneratedDeveloperItem(item, text))) {
301
+ return;
302
+ }
303
+ }
304
+
305
+ parsed.context.messages.push({ role: "developer", content: text, timestamp: Date.now() });
287
306
  if (raw && Array.isArray(raw.input)) {
288
- const devItem = { type: "message", role: "developer", content: [{ type: "input_text", text }] };
289
307
  // compaction_trigger must remain the final input item (codex-rs + ChatGPT backend both
290
308
  // validate this). Insert the developer message BEFORE the trigger when present.
291
309
  const last = raw.input[raw.input.length - 1];
@@ -297,4 +315,3 @@ export function injectDeveloperMessage(parsed: OcxParsedRequest, text: string):
297
315
  }
298
316
  }
299
317
 
300
-
@@ -89,11 +89,14 @@ import type { AttemptRecoveryKind } from "../../usage/log";
89
89
  import {
90
90
  consumeForInspection,
91
91
  consumeForResponseLogMetadata,
92
+ createSseInspector,
92
93
  markNativePassthroughSseResponse,
93
94
  relaySseWithFailedTail,
94
95
  relayWithAbort,
95
96
  sanitizePassthroughHeaders,
96
97
  } from "../relay";
98
+ import { relaySseEagerBounded } from "../relay-eager";
99
+ import { decideEagerRelay } from "../../lib/bun-stream-caps";
97
100
  import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
98
101
  import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
99
102
 
@@ -1021,9 +1024,57 @@ export async function handleResponses(
1021
1024
  // async-pull segfault on Windows. Branch[0] goes directly to the Response (Bun
1022
1025
  // native relay, never enters JS Sink.write); branch[1] is consumed in the
1023
1026
  // background for terminal-outcome/quota inspection only.
1027
+ // #314 alternative shape: on win32 (no repair) with a runtime carrying the
1028
+ // Bun#32111 fix — or explicit `streamMode: "eager-relay"` opt-in — the tee
1029
+ // is skipped entirely and relaySseEagerBounded provides a single eager
1030
+ // bounded reader with inline inspection (see src/server/relay-eager.ts and
1031
+ // devlog/_plan/260723_win_mem_safestream/020). Default on the bundled
1032
+ // known-bad runtime remains the tee path below.
1024
1033
  if (upstreamResponse.ok && isEventStream && upstreamResponse.body) {
1025
- const [nativeBody, inspectBody] = upstreamResponse.body.tee();
1026
1034
  const repairConfig = route.provider.responsesItemIdRepair;
1035
+ const winNoRepair = process.platform === "win32" && !hasResponsesItemIdRepair(repairConfig);
1036
+ const eagerDecision = winNoRepair ? decideEagerRelay(config.streamMode ?? "auto") : null;
1037
+ if (eagerDecision?.useEagerRelay) {
1038
+ const turnAc = new AbortController();
1039
+ linkAbortSignal(upstream, turnAc.signal);
1040
+ registerTurn(turnAc);
1041
+ const reportNativeTerminal = recordTerminalOutcomes
1042
+ ? (status: ResponsesTerminalStatus, httpStatusOverride?: number) => {
1043
+ terminalRecorder?.(status, httpStatusOverride);
1044
+ options.onNativePassthroughTerminal?.(status);
1045
+ }
1046
+ : undefined;
1047
+ const inspector = createSseInspector({
1048
+ onTerminal: reportNativeTerminal,
1049
+ logCtx,
1050
+ onCompletedResponse: rememberPassthroughResponse,
1051
+ onFirstOutput: options.onFirstOutput,
1052
+ });
1053
+ const eagerBody = relaySseEagerBounded(upstreamResponse.body, turnAc, {
1054
+ inspectChunk: chunk => inspector.feed(chunk),
1055
+ finishInspection: () => inspector.finish(),
1056
+ sawTerminal: () => inspector.reported(),
1057
+ onSynthetic: kind => {
1058
+ if (!reportNativeTerminal) return;
1059
+ if (kind === "incomplete") {
1060
+ logCtx.terminalSource = "synthetic";
1061
+ reportNativeTerminal("incomplete");
1062
+ } else {
1063
+ logCtx.transportPhase = "mid_stream";
1064
+ logCtx.terminalSource = "synthetic";
1065
+ reportNativeTerminal("failed", 502);
1066
+ }
1067
+ },
1068
+ onClientCancel: () => options.onNativePassthroughCancel?.(),
1069
+ onDone: () => unregisterTurn(turnAc),
1070
+ });
1071
+ if (!headers.has("content-type")) headers.set("content-type", "text/event-stream");
1072
+ return markNativePassthroughSseResponse(new Response(eagerBody, {
1073
+ status: upstreamResponse.status,
1074
+ headers,
1075
+ }));
1076
+ }
1077
+ const [nativeBody, inspectBody] = upstreamResponse.body.tee();
1027
1078
  const turnAc = new AbortController();
1028
1079
  linkAbortSignal(upstream, turnAc.signal);
1029
1080
  registerTurn(turnAc);
package/src/types.ts CHANGED
@@ -5,6 +5,8 @@ export interface OcxParsedRequest {
5
5
  stream: boolean;
6
6
  options: OcxRequestOptions;
7
7
  _rawBody?: unknown;
8
+ /** Number of leading raw input items restored from local previous_response_id state. */
9
+ _replayPrefixLen?: number;
8
10
  /** True when the proxy expanded a previous_response_id request into a full input replay. */
9
11
  _previousResponseInputExpanded?: boolean;
10
12
  /** Provider-private stable Cursor conversation id resolved from the Responses previous_response_id chain. */
@@ -445,6 +447,15 @@ export interface OcxConfig {
445
447
  * Undefined = passthrough (don't modify what the client sends).
446
448
  */
447
449
  fastMode?: boolean;
450
+ /**
451
+ * Windows SSE passthrough stream shape (#314 mitigation).
452
+ * "auto" (default): eager bounded relay only on runtimes proven to carry the
453
+ * Bun#32111 fix (none today → legacy tee). "eager-relay": force the new relay
454
+ * (accepts #32111 crash risk on Bun 1.3.14). "legacy-tee": pin the tee path.
455
+ * Persisted in config.json because Windows services do not inherit shell env.
456
+ * See src/lib/bun-stream-caps.ts.
457
+ */
458
+ streamMode?: "auto" | "legacy-tee" | "eager-relay";
448
459
  /**
449
460
  * Custom override for the injected multi-agent guidance body (the text inside the
450
461
  * <multi_agent_mode> tags). When set, it replaces the built-in prompt on whichever
package/src/usage/cost.ts CHANGED
Binary file
@@ -130,3 +130,22 @@ export function findExpectedPriceOverlay(
130
130
  return exact.find(row => row.status === "verified")
131
131
  ?? exact.find(row => row.status === "verified-derived");
132
132
  }
133
+
134
+ /**
135
+ * OpenAI service_tier "priority" (Fast) price multipliers by model slug.
136
+ * Source: https://platform.openai.com/docs/models (2026-07-24).
137
+ * Priority pricing applies uniformly to all token types (input, output, cache).
138
+ * Models not listed here fall back to 1× (no multiplier).
139
+ */
140
+ export const PRIORITY_MULTIPLIERS: Readonly<Record<string, number>> = {
141
+ "gpt-5.6-sol": 2,
142
+ "gpt-5.6-terra": 2,
143
+ "gpt-5.6-luna": 2,
144
+ "gpt-5.5": 2.5,
145
+ "gpt-5.4": 2,
146
+ };
147
+
148
+ /** Returns the priority-tier price multiplier for a model (1 if not listed). */
149
+ export function resolvePriorityMultiplier(modelId: string): number {
150
+ return PRIORITY_MULTIPLIERS[modelId] ?? 1;
151
+ }