@ai0x0/codex-ts 0.5.5 → 0.6.1

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.
Files changed (34) hide show
  1. package/dist/core/src/codex_thread.d.ts +11 -0
  2. package/dist/core/src/codex_thread.d.ts.map +1 -1
  3. package/dist/core/src/codex_thread.js +10 -0
  4. package/dist/core/src/codex_thread.js.map +1 -1
  5. package/dist/core/src/compact.d.ts.map +1 -1
  6. package/dist/core/src/compact.js +79 -28
  7. package/dist/core/src/compact.js.map +1 -1
  8. package/dist/core/src/index.d.ts +3 -0
  9. package/dist/core/src/index.d.ts.map +1 -1
  10. package/dist/core/src/index.js +3 -0
  11. package/dist/core/src/index.js.map +1 -1
  12. package/dist/core/src/normalize.d.ts +40 -0
  13. package/dist/core/src/normalize.d.ts.map +1 -0
  14. package/dist/core/src/normalize.js +88 -0
  15. package/dist/core/src/normalize.js.map +1 -0
  16. package/dist/core/src/session/retry.d.ts +13 -0
  17. package/dist/core/src/session/retry.d.ts.map +1 -1
  18. package/dist/core/src/session/retry.js +27 -0
  19. package/dist/core/src/session/retry.js.map +1 -1
  20. package/dist/core/src/session/turn.d.ts +17 -0
  21. package/dist/core/src/session/turn.d.ts.map +1 -1
  22. package/dist/core/src/session/turn.js +122 -21
  23. package/dist/core/src/session/turn.js.map +1 -1
  24. package/dist/core/src/state/token_state.d.ts +52 -0
  25. package/dist/core/src/state/token_state.d.ts.map +1 -0
  26. package/dist/core/src/state/token_state.js +66 -0
  27. package/dist/core/src/state/token_state.js.map +1 -0
  28. package/dist/core/tests/suite/compact.test.js +231 -1
  29. package/dist/core/tests/suite/compact.test.js.map +1 -1
  30. package/dist/core/tests/suite/normalize.test.d.ts +13 -0
  31. package/dist/core/tests/suite/normalize.test.d.ts.map +1 -0
  32. package/dist/core/tests/suite/normalize.test.js +147 -0
  33. package/dist/core/tests/suite/normalize.test.js.map +1 -0
  34. package/package.json +1 -1
@@ -12,9 +12,54 @@
12
12
  import { toolSpecToRequestJson } from "../../../tools/src/tool_spec.js";
13
13
  import { extractSkillMentions, renderSkillInjection } from "../skills.js";
14
14
  import { parseSseStream } from "./sse.js";
15
- import { computeRetryDelay, DEFAULT_MAX_RETRIES, isRetryableError, parseRetryAfter, ResponsesApiError, sleep, } from "./retry.js";
15
+ import { computeRetryDelay, DEFAULT_MAX_RETRIES, isContextWindowExceededError, isRetryableError, parseRetryAfter, ResponsesApiError, sleep, } from "./retry.js";
16
16
  import { runInlineAutoCompactTask } from "../compact.js";
17
+ import { normalizeHistory } from "../normalize.js";
17
18
  import { AutoCompactWindow } from "../state/auto_compact_window.js";
19
+ import { approxTokenCount, estimateItemsTokenCount, SessionTokenState, } from "../state/token_state.js";
20
+ // ─── Auto-compaction status + orchestration ──────────────────────────────────
21
+ /**
22
+ * mirrors auto_compact_token_status (turn.rs:719-769), BodyAfterPrefix scope:
23
+ * the limit is reached when EITHER the growth since the window baseline hits
24
+ * `autoCompactTokenLimit`, OR the total active context reaches the model's
25
+ * full `contextWindow`. The second condition is what keeps a session with a
26
+ * large baseline (or a force-filled one after a context-window-exceeded
27
+ * rejection) from sailing past the model's window.
28
+ */
29
+ function autoCompactTokenStatus(config, compactWindow, tokenState) {
30
+ const activeContextTokens = tokenState.totalTokens ?? 0;
31
+ const scopeTokens = compactWindow.bodyAfterPrefix(activeContextTokens);
32
+ const scopeLimit = config.autoCompactTokenLimit ?? Number.POSITIVE_INFINITY;
33
+ const fullContextWindowLimitReached = config.contextWindow !== undefined &&
34
+ activeContextTokens >= config.contextWindow;
35
+ return {
36
+ activeContextTokens,
37
+ tokenLimitReached: scopeTokens >= scopeLimit || fullContextWindowLimitReached,
38
+ };
39
+ }
40
+ /**
41
+ * Run one inline compaction and reseed the token bookkeeping.
42
+ * mirrors run_auto_compact + recompute_token_usage (session/mod.rs:3059-3095):
43
+ * after history is rewritten, the session total and the NEW window's baseline
44
+ * both restart from a byte-based estimate of the compacted context (replaced
45
+ * by real server usage on the next sampled response).
46
+ */
47
+ async function runCompactAndRecompute(history, config, compactWindow, tokenState, emitEvent) {
48
+ emitEvent({ type: "ContextCompacted", event: {} });
49
+ await runInlineAutoCompactTask(history, config);
50
+ compactWindow.startNext();
51
+ const estimated = estimateItemsTokenCount([...(config.contextItems ?? []), ...history]) +
52
+ approxTokenCount(config.instructions ?? "");
53
+ tokenState.setEstimated(estimated);
54
+ compactWindow.setEstimatedPrefill(estimated);
55
+ emitEvent({
56
+ type: "Warning",
57
+ event: {
58
+ message: "Heads up: Long threads and multiple compactions can cause the model to be less accurate. " +
59
+ "Start a new thread when possible to keep threads small and targeted.",
60
+ },
61
+ });
62
+ }
18
63
  export async function runTurn(turnId, userItems, history, config, router, pendingInputs, emitEvent, liveThread,
19
64
  /** mirrors: codex-rs propagates a tokio CancellationToken into the turn loop;
20
65
  * AbortSignal is the browser-native equivalent. */
@@ -87,11 +132,43 @@ extraUserMessages) {
87
132
  // silently grows past the model's context window → "prompt is too long". Fall
88
133
  // back to a private window only when no shared one is supplied (one-shot/tests).
89
134
  const compactWindow = config.compactWindow ?? new AutoCompactWindow();
135
+ // Session token accounting — same thread-owned pattern (mirrors session state).
136
+ const tokenState = config.tokenState ?? new SessionTokenState();
137
+ // ── Estimated baseline seed (mirrors set_estimated_prefill, mod.rs:1290) ────
138
+ // Until the first server usage arrives (fresh thread, resumed thread, or a
139
+ // freshly compacted window) the window baseline and session total start from
140
+ // a byte-based estimate of what this turn is about to send. Server usage
141
+ // overrides both on the next sampled response.
142
+ if (compactWindow.snapshot().prefillInputTokens === null) {
143
+ const estimated = estimateItemsTokenCount([...(config.contextItems ?? []), ...history]) +
144
+ approxTokenCount(config.instructions ?? "");
145
+ compactWindow.setEstimatedPrefill(estimated);
146
+ if (tokenState.totalTokens === null) {
147
+ tokenState.setEstimated(estimated);
148
+ }
149
+ }
150
+ // ── Pre-sampling compaction (mirrors run_pre_sampling_compact, turn.rs:149) ─
151
+ // Compact BEFORE the first request of the turn when the context is already
152
+ // at/over budget — e.g. the previous turn ended with a context-window-exceeded
153
+ // rejection (which force-filled the session total), or a resumed thread's
154
+ // history estimate already exceeds the window. This is the self-heal path:
155
+ // without it, every subsequent request would keep failing with 400.
156
+ {
157
+ const preStatus = autoCompactTokenStatus(config, compactWindow, tokenState);
158
+ if (preStatus.tokenLimitReached) {
159
+ await runCompactAndRecompute(history, config, compactWindow, tokenState, emitEvent);
160
+ }
161
+ }
90
162
  for (;;) {
91
163
  // Bail out before sampling again if the turn was interrupted.
92
164
  if (abortSignal?.aborted) {
93
165
  throw new DOMException("Turn interrupted", "AbortError");
94
166
  }
167
+ // ── Pairing invariants before every request (mirrors for_prompt →
168
+ // normalize_history): synthesize "aborted" outputs for calls that never
169
+ // got one (interrupted turn, resumed corrupted thread) and drop orphaned
170
+ // outputs. Anthropic 400s on unpaired tool_use/tool_result otherwise.
171
+ normalizeHistory(history);
95
172
  // ── Sample from the model ───────────────────────────────────────────────
96
173
  const body = {
97
174
  model: config.model,
@@ -207,15 +284,35 @@ extraUserMessages) {
207
284
  // the same "response.completed" (codex-api/src/sse/responses.rs) to read
208
285
  // usage. (An earlier port used "response.done", which no Responses
209
286
  // backend emits, so usage never arrived and auto-compaction never armed.)
210
- // Mirrors ensure_server_observed_prefill_from_usage in auto_compact_window.rs
287
+ // Mirrors record_token_usage_info (turn.rs:2072): session total ←
288
+ // usage, window prefill ← first server-observed input_tokens.
211
289
  const resp = raw["response"];
212
290
  const usage = resp?.["usage"];
213
291
  if (typeof usage?.["input_tokens"] === "number") {
214
292
  inputTokensThisRound = usage["input_tokens"];
293
+ tokenState.updateFromUsage({
294
+ inputTokens: inputTokensThisRound,
295
+ outputTokens: typeof usage["output_tokens"] === "number"
296
+ ? usage["output_tokens"]
297
+ : undefined,
298
+ totalTokens: typeof usage["total_tokens"] === "number"
299
+ ? usage["total_tokens"]
300
+ : undefined,
301
+ });
215
302
  compactWindow.ensureServerObservedPrefill(inputTokensThisRound);
216
303
  }
217
304
  break;
218
305
  }
306
+ case "response.failed": {
307
+ // mirrors codex-api sse/responses.rs "response.failed": the stream's
308
+ // terminal error event. Surface it as a ResponsesApiError so the
309
+ // catch below classifies it — context-window-exceeded is terminal
310
+ // (and marks tokens full); anything else is treated as a transient
311
+ // stream failure (rs defaults response.failed to Retryable; the
312
+ // 503 status keeps it in the retryable set here).
313
+ const resp = raw["response"];
314
+ throw new ResponsesApiError(503, JSON.stringify(resp?.["error"] ?? raw));
315
+ }
219
316
  }
220
317
  }
221
318
  break; // stream consumed successfully → leave the retry loop
@@ -224,6 +321,14 @@ extraUserMessages) {
224
321
  // An interrupt is terminal — never retry past a cancellation.
225
322
  if (abortSignal?.aborted)
226
323
  throw err;
324
+ // Context-window-exceeded is terminal AND self-healing: mark the
325
+ // session tokens FULL so the NEXT turn's pre-sampling check compacts
326
+ // before sampling (mirrors turn.rs:1045-1047 set_total_tokens_full).
327
+ // Retrying the identical request would only fail again.
328
+ if (isContextWindowExceededError(err)) {
329
+ tokenState.setFull(config.contextWindow);
330
+ throw err;
331
+ }
227
332
  // Stop retrying once visible output streamed (would duplicate), the
228
333
  // budget is spent, or the error is not transient.
229
334
  if (emittedOutput ||
@@ -266,25 +371,6 @@ extraUserMessages) {
266
371
  // ── Done when no tool calls ─────────────────────────────────────────────
267
372
  if (functionCalls.length === 0)
268
373
  break;
269
- // ── Auto-compaction check (mirrors post-sampling compact in turn.rs) ─────
270
- // Only triggered mid-turn (when there are more tool calls to dispatch),
271
- // matching InitialContextInjection::BeforeLastUserMessage behaviour.
272
- if (config.autoCompactTokenLimit !== undefined && inputTokensThisRound > 0) {
273
- const scopeTokens = compactWindow.bodyAfterPrefix(inputTokensThisRound);
274
- const limitReached = scopeTokens >= config.autoCompactTokenLimit;
275
- if (limitReached) {
276
- emitEvent({ type: "ContextCompacted", event: {} });
277
- await runInlineAutoCompactTask(history, config);
278
- compactWindow.startNext();
279
- emitEvent({
280
- type: "Warning",
281
- event: {
282
- message: "Heads up: Long threads and multiple compactions can cause the model to be less accurate. " +
283
- "Start a new thread when possible to keep threads small and targeted.",
284
- },
285
- });
286
- }
287
- }
288
374
  // ── Dispatch tool calls ─────────────────────────────────────────────────
289
375
  for (const call of functionCalls) {
290
376
  let args;
@@ -307,6 +393,21 @@ extraUserMessages) {
307
393
  history.push(outputItem);
308
394
  await liveThread?.appendConversationItems([outputItem]);
309
395
  }
396
+ // ── Auto-compaction check (mirrors post-sampling compact, turn.rs:266-292) ─
397
+ // Only triggered mid-turn (more sampling rounds follow), matching
398
+ // `token_limit_reached && needs_follow_up` in codex-rs. Runs AFTER the tool
399
+ // outputs are recorded — codex-rs compacts only between COMPLETE rounds; an
400
+ // earlier port compacted between call-recording and dispatch, so the
401
+ // rewrite dropped the pending function_calls and the outputs pushed right
402
+ // after became orphans → Anthropic 400 "tool_use ids … without tool_result".
403
+ // Fires on EITHER growth-since-baseline ≥ autoCompactTokenLimit OR total
404
+ // active context ≥ contextWindow (see autoCompactTokenStatus).
405
+ {
406
+ const status = autoCompactTokenStatus(config, compactWindow, tokenState);
407
+ if (status.tokenLimitReached) {
408
+ await runCompactAndRecompute(history, config, compactWindow, tokenState, emitEvent);
409
+ }
410
+ }
310
411
  }
311
412
  return { lastAgentMessage };
312
413
  }
@@ -1 +1 @@
1
- {"version":3,"file":"turn.js","sourceRoot":"","sources":["../../../../core/src/session/turn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"turn.js","sourceRoot":"","sources":["../../../../core/src/session/turn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * mirrors codex-rs/core/src/context_manager/history.rs (the token_info face)
3
+ * codex-rs/protocol/src/protocol.rs TokenUsageInfo::fill_to_context_window
4
+ *
5
+ * Session-scoped token accounting: the last known size of the active context,
6
+ * fed from server usage after each sampled response, from a byte-based estimate
7
+ * when no usage has arrived yet (fresh/resumed threads, post-compaction), or
8
+ * force-filled to the context window when the provider rejects a request with
9
+ * context-window-exceeded. `autoCompactTokenStatus` in turn.ts reads this to
10
+ * decide when to compact — mirrors sess.get_total_token_usage() in codex-rs.
11
+ */
12
+ import type { ConversationItem } from "../../../thread-store/src/types.js";
13
+ /** ~4 chars per token — coarse lower bound, same heuristic as codex-rs
14
+ * approx_token_count (utils/output-truncation). Good enough for budgeting. */
15
+ export declare function approxTokenCount(text: string): number;
16
+ /**
17
+ * Estimate the token size of serialized conversation items.
18
+ * mirrors history.estimate_token_count_with_base_instructions (history.rs:149):
19
+ * per-item byte-based estimates, summed. JSON form approximates wire size.
20
+ */
21
+ export declare function estimateItemsTokenCount(items: ConversationItem[]): number;
22
+ export declare class SessionTokenState {
23
+ /** Last known active-context size in tokens (server usage, estimate, or
24
+ * forced-full). null until the first sample/estimate. */
25
+ private total;
26
+ get totalTokens(): number | null;
27
+ /**
28
+ * Record the terminal usage of a sampled response.
29
+ * mirrors record_token_usage_info → history.update_token_info: the session
30
+ * total becomes the response's total_tokens (the active context as the
31
+ * server measured it). Falls back to input+output when total is absent.
32
+ */
33
+ updateFromUsage(input: {
34
+ inputTokens: number;
35
+ outputTokens?: number | undefined;
36
+ totalTokens?: number | undefined;
37
+ }): void;
38
+ /**
39
+ * Seed/replace the total with a byte-based estimate — used before the first
40
+ * server usage arrives and after compaction rewrites history.
41
+ * mirrors recompute_token_usage (session/mod.rs:3059).
42
+ */
43
+ setEstimated(tokens: number): void;
44
+ /**
45
+ * Mark the context as FULL after a context-window-exceeded rejection, so the
46
+ * next pre-sampling check is guaranteed to compact first.
47
+ * mirrors set_total_tokens_full (session/mod.rs:3140) — a no-op when the
48
+ * host didn't configure a context window, exactly like the rs guard.
49
+ */
50
+ setFull(contextWindow: number | undefined): void;
51
+ }
52
+ //# sourceMappingURL=token_state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token_state.d.ts","sourceRoot":"","sources":["../../../../core/src/state/token_state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAE3E;+EAC+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAMzE;AAED,qBAAa,iBAAiB;IAC5B;8DAC0D;IAC1D,OAAO,CAAC,KAAK,CAAuB;IAEpC,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED;;;;;OAKG;IACH,eAAe,CAAC,KAAK,EAAE;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAClC,GAAG,IAAI;IAMR;;;;OAIG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIlC;;;;;OAKG;IACH,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CAKjD"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * mirrors codex-rs/core/src/context_manager/history.rs (the token_info face)
3
+ * codex-rs/protocol/src/protocol.rs TokenUsageInfo::fill_to_context_window
4
+ *
5
+ * Session-scoped token accounting: the last known size of the active context,
6
+ * fed from server usage after each sampled response, from a byte-based estimate
7
+ * when no usage has arrived yet (fresh/resumed threads, post-compaction), or
8
+ * force-filled to the context window when the provider rejects a request with
9
+ * context-window-exceeded. `autoCompactTokenStatus` in turn.ts reads this to
10
+ * decide when to compact — mirrors sess.get_total_token_usage() in codex-rs.
11
+ */
12
+ /** ~4 chars per token — coarse lower bound, same heuristic as codex-rs
13
+ * approx_token_count (utils/output-truncation). Good enough for budgeting. */
14
+ export function approxTokenCount(text) {
15
+ return Math.ceil(text.length / 4);
16
+ }
17
+ /**
18
+ * Estimate the token size of serialized conversation items.
19
+ * mirrors history.estimate_token_count_with_base_instructions (history.rs:149):
20
+ * per-item byte-based estimates, summed. JSON form approximates wire size.
21
+ */
22
+ export function estimateItemsTokenCount(items) {
23
+ let total = 0;
24
+ for (const item of items) {
25
+ total += approxTokenCount(JSON.stringify(item));
26
+ }
27
+ return total;
28
+ }
29
+ export class SessionTokenState {
30
+ /** Last known active-context size in tokens (server usage, estimate, or
31
+ * forced-full). null until the first sample/estimate. */
32
+ total = null;
33
+ get totalTokens() {
34
+ return this.total;
35
+ }
36
+ /**
37
+ * Record the terminal usage of a sampled response.
38
+ * mirrors record_token_usage_info → history.update_token_info: the session
39
+ * total becomes the response's total_tokens (the active context as the
40
+ * server measured it). Falls back to input+output when total is absent.
41
+ */
42
+ updateFromUsage(input) {
43
+ const total = input.totalTokens ?? input.inputTokens + (input.outputTokens ?? 0);
44
+ this.total = Math.max(0, total);
45
+ }
46
+ /**
47
+ * Seed/replace the total with a byte-based estimate — used before the first
48
+ * server usage arrives and after compaction rewrites history.
49
+ * mirrors recompute_token_usage (session/mod.rs:3059).
50
+ */
51
+ setEstimated(tokens) {
52
+ this.total = Math.max(0, tokens);
53
+ }
54
+ /**
55
+ * Mark the context as FULL after a context-window-exceeded rejection, so the
56
+ * next pre-sampling check is guaranteed to compact first.
57
+ * mirrors set_total_tokens_full (session/mod.rs:3140) — a no-op when the
58
+ * host didn't configure a context window, exactly like the rs guard.
59
+ */
60
+ setFull(contextWindow) {
61
+ if (contextWindow !== undefined) {
62
+ this.total = contextWindow;
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=token_state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token_state.js","sourceRoot":"","sources":["../../../../core/src/state/token_state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;+EAC+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAyB;IAC/D,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,IAAI,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,OAAO,iBAAiB;IAC5B;8DAC0D;IAClD,KAAK,GAAkB,IAAI,CAAC;IAEpC,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;;;OAKG;IACH,eAAe,CAAC,KAIf;QACC,MAAM,KAAK,GACT,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,MAAc;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,aAAiC;QACvC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,GAAG,aAAa,CAAC;QAC7B,CAAC;IACH,CAAC;CACF"}
@@ -8,8 +8,10 @@
8
8
  */
9
9
  import { describe, expect, it, vi, beforeEach } from "vitest";
10
10
  import { AutoCompactWindow } from "../../src/state/auto_compact_window.js";
11
- import { collectUserMessages, buildCompactedHistory, SUMMARIZATION_PROMPT, SUMMARY_PREFIX, } from "../../src/compact.js";
11
+ import { collectUserMessages, buildCompactedHistory, runInlineAutoCompactTask, SUMMARIZATION_PROMPT, SUMMARY_PREFIX, } from "../../src/compact.js";
12
12
  import { CodexThread } from "../../src/codex_thread.js";
13
+ import { SessionTokenState } from "../../src/state/token_state.js";
14
+ import { isContextWindowExceededText } from "../../src/session/retry.js";
13
15
  import { evAssistantMessage, evCompleted, evFunctionCall, evResponseCreated, makeSseResponse, sseFlat, waitForEvent, } from "../common/lib.js";
14
16
  // ─── AutoCompactWindow unit tests ─────────────────────────────────────────────
15
17
  describe("AutoCompactWindow — BodyAfterPrefix tracking", () => {
@@ -241,4 +243,232 @@ describe("cross-turn auto-compaction (thread-owned window)", () => {
241
243
  expect(fetchMock).toHaveBeenCalledTimes(4);
242
244
  });
243
245
  });
246
+ // ─── Shared helpers for the context-window suites ──────────────────────────────
247
+ function makeErrorResponse(status, bodyText) {
248
+ return {
249
+ ok: false,
250
+ status,
251
+ headers: new Headers(),
252
+ body: new ReadableStream({
253
+ start(controller) {
254
+ controller.enqueue(new TextEncoder().encode(bodyText));
255
+ controller.close();
256
+ },
257
+ }),
258
+ text: async () => bodyText,
259
+ };
260
+ }
261
+ function sseWithFullUsage(inputTokens, totalTokens, items) {
262
+ return sseFlat([
263
+ ...items,
264
+ {
265
+ type: "response.completed",
266
+ response: {
267
+ id: "resp",
268
+ status: "completed",
269
+ usage: {
270
+ input_tokens: inputTokens,
271
+ output_tokens: totalTokens - inputTokens,
272
+ total_tokens: totalTokens,
273
+ },
274
+ },
275
+ },
276
+ ]);
277
+ }
278
+ // The EXACT body OpenRouter returned in the production incident (Anthropic raw
279
+ // error wrapped in metadata.raw — no OpenAI-canonical code anywhere).
280
+ const OPENROUTER_PROMPT_TOO_LONG_BODY = JSON.stringify({
281
+ error: {
282
+ message: "Provider returned error",
283
+ code: 400,
284
+ metadata: {
285
+ raw: '{"type":"error","error":{"type":"invalid_request_error","message":"prompt is too long: 1102084 tokens > 1000000 maximum"},"request_id":"req_x"}',
286
+ provider_name: "Azure",
287
+ },
288
+ },
289
+ });
290
+ // ─── Unit: context-window-exceeded classification ──────────────────────────────
291
+ // mirrors is_context_window_error (codex-api/src/sse/responses.rs:513) — rs only
292
+ // matches the OpenAI-canonical code; the ts port also matches each provider's
293
+ // wording because OpenRouter/codeproxy pass the ORIGINAL provider error through.
294
+ describe("isContextWindowExceededText", () => {
295
+ it("matches the OpenRouter/Anthropic incident payload", () => {
296
+ expect(isContextWindowExceededText(OPENROUTER_PROMPT_TOO_LONG_BODY)).toBe(true);
297
+ });
298
+ it("matches the OpenAI canonical code and message", () => {
299
+ expect(isContextWindowExceededText('{"code":"context_length_exceeded"}')).toBe(true);
300
+ expect(isContextWindowExceededText("Your input exceeds the context window of this model.")).toBe(true);
301
+ });
302
+ it("does NOT match unrelated 4xx bodies", () => {
303
+ expect(isContextWindowExceededText('{"error":{"message":"insufficient credits"}}')).toBe(false);
304
+ expect(isContextWindowExceededText("Bad Request")).toBe(false);
305
+ });
306
+ });
307
+ // ─── Integration: absolute context-window trigger ──────────────────────────────
308
+ // mirrors full_context_window_limit_reached (turn.rs:752-757): compaction must
309
+ // fire when TOTAL active context reaches the model window even though the
310
+ // growth-since-baseline budget (autoCompactTokenLimit) was never configured.
311
+ describe("full-context-window auto-compaction", () => {
312
+ beforeEach(() => {
313
+ vi.unstubAllGlobals();
314
+ });
315
+ it("compacts when total usage reaches contextWindow (no growth budget set)", async () => {
316
+ const fetchMock = vi.fn();
317
+ // Round 1 — tool call; usage total 810 < window 1000 → no compaction.
318
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseWithFullUsage(800, 810, [
319
+ evResponseCreated("r1"),
320
+ evFunctionCall("call-1", "get_goal", {}),
321
+ ])));
322
+ // Round 2 — tool call; usage total 1020 ≥ window 1000 → compact.
323
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseWithFullUsage(1010, 1020, [
324
+ evResponseCreated("r2"),
325
+ evFunctionCall("call-2", "get_goal", {}),
326
+ ])));
327
+ // Compaction request → summary.
328
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
329
+ evResponseCreated("compact"),
330
+ evAssistantMessage("summary text"),
331
+ evCompleted("compact"),
332
+ ])));
333
+ // Round 3 — final reply.
334
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
335
+ evResponseCreated("r3"),
336
+ evAssistantMessage("done"),
337
+ evCompleted("r3"),
338
+ ])));
339
+ vi.stubGlobal("fetch", fetchMock);
340
+ const codex = new CodexThread({
341
+ apiKey: "test",
342
+ model: "gpt-4o",
343
+ contextWindow: 1000, // NOTE: no autoCompactTokenLimit at all
344
+ });
345
+ await codex.submit({
346
+ type: "UserInput",
347
+ items: [{ type: "text", text: "hi" }],
348
+ });
349
+ const compacted = await waitForEvent(codex, (msg) => msg.type === "ContextCompacted");
350
+ expect(compacted.type).toBe("ContextCompacted");
351
+ await waitForEvent(codex, (msg) => msg.type === "TurnComplete");
352
+ expect(fetchMock).toHaveBeenCalledTimes(4);
353
+ // The compaction request (index 2) carries the summarization prompt.
354
+ const compactBody = JSON.parse(fetchMock.mock.calls[2][1].body);
355
+ expect(JSON.stringify(compactBody.input[compactBody.input.length - 1])).toContain(SUMMARIZATION_PROMPT.slice(0, 30));
356
+ });
357
+ });
358
+ // ─── Integration: context-window-exceeded self-heal across turns ───────────────
359
+ // mirrors turn.rs:1045-1047 (set_total_tokens_full on ContextWindowExceeded) +
360
+ // run_pre_sampling_compact (turn.rs:149): a rejected request marks the session
361
+ // tokens FULL; the NEXT turn compacts BEFORE sampling instead of failing with
362
+ // the same 400 forever — this is exactly the production incident shape.
363
+ describe("context-window-exceeded self-heal", () => {
364
+ beforeEach(() => {
365
+ vi.unstubAllGlobals();
366
+ });
367
+ it("marks tokens full on the 400 and compacts before sampling on the next turn", async () => {
368
+ const fetchMock = vi.fn();
369
+ // Turn 1 — provider rejects the sampling request outright (the incident).
370
+ fetchMock.mockResolvedValueOnce(makeErrorResponse(400, OPENROUTER_PROMPT_TOO_LONG_BODY));
371
+ // Turn 2 — FIRST request must be the pre-sampling compaction…
372
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
373
+ evResponseCreated("compact"),
374
+ evAssistantMessage("summary text"),
375
+ evCompleted("compact"),
376
+ ])));
377
+ // …then the actual sampling request succeeds on the compacted history.
378
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
379
+ evResponseCreated("t2"),
380
+ evAssistantMessage("recovered"),
381
+ evCompleted("t2"),
382
+ ])));
383
+ vi.stubGlobal("fetch", fetchMock);
384
+ const codex = new CodexThread({
385
+ apiKey: "test",
386
+ model: "gpt-4o",
387
+ contextWindow: 1000,
388
+ });
389
+ // Turn 1 fails with the 400 (no retry — the same request would fail again).
390
+ await codex.submit({
391
+ type: "UserInput",
392
+ items: [{ type: "text", text: "hi" }],
393
+ });
394
+ const errorEvent = await waitForEvent(codex, (msg) => msg.type === "Error");
395
+ expect(JSON.stringify(errorEvent)).toContain("prompt is too long");
396
+ expect(fetchMock).toHaveBeenCalledTimes(1);
397
+ // Turn 2 self-heals: compaction first, then sampling.
398
+ await codex.submit({
399
+ type: "UserInput",
400
+ items: [{ type: "text", text: "continue" }],
401
+ });
402
+ const compacted = await waitForEvent(codex, (msg) => msg.type === "ContextCompacted");
403
+ expect(compacted.type).toBe("ContextCompacted");
404
+ await waitForEvent(codex, (msg) => msg.type === "TurnComplete");
405
+ expect(fetchMock).toHaveBeenCalledTimes(3);
406
+ // Call 2 (index 1) is the compaction request (summarization prompt last)…
407
+ const compactBody = JSON.parse(fetchMock.mock.calls[1][1].body);
408
+ expect(JSON.stringify(compactBody.input[compactBody.input.length - 1])).toContain(SUMMARIZATION_PROMPT.slice(0, 30));
409
+ // …and call 3 (index 2) samples on the compacted history.
410
+ const finalBody = JSON.parse(fetchMock.mock.calls[2][1].body);
411
+ expect(JSON.stringify(finalBody.input)).toContain(SUMMARY_PREFIX.slice(0, 30));
412
+ });
413
+ });
414
+ // ─── Unit: compaction request trims itself out of the window ───────────────────
415
+ // mirrors compact.rs:232-241: when the compaction request ITSELF exceeds the
416
+ // window, drop the OLDEST history item and retry (prefix-preserving), instead
417
+ // of dying in the exact deadlock the production incident hit.
418
+ describe("runInlineAutoCompactTask — trim on context-window-exceeded", () => {
419
+ function turnConfig(fetchMock, tokenState) {
420
+ return {
421
+ apiKey: "test",
422
+ baseUrl: "http://mock",
423
+ model: "gpt-4o",
424
+ fetch: fetchMock,
425
+ contextWindow: 1000,
426
+ tokenState,
427
+ maxRetries: 0,
428
+ };
429
+ }
430
+ it("drops the oldest item and retries until the summarizer fits", async () => {
431
+ const history = [
432
+ { type: "message", role: "user", content: "oldest" },
433
+ { type: "message", role: "assistant", content: "middle" },
434
+ { type: "message", role: "user", content: "newest" },
435
+ ];
436
+ const tokenState = new SessionTokenState();
437
+ const fetchMock = vi
438
+ .fn()
439
+ // First attempt (full history) → the compaction request is too big.
440
+ .mockResolvedValueOnce(makeErrorResponse(400, OPENROUTER_PROMPT_TOO_LONG_BODY))
441
+ // Second attempt (oldest item dropped) → summary streams back.
442
+ .mockResolvedValueOnce(makeSseResponse(sseFlat([
443
+ evResponseCreated("compact"),
444
+ evAssistantMessage("trimmed summary"),
445
+ evCompleted("compact"),
446
+ ])));
447
+ const summary = await runInlineAutoCompactTask(history, turnConfig(fetchMock, tokenState));
448
+ expect(summary).toBe("trimmed summary");
449
+ expect(fetchMock).toHaveBeenCalledTimes(2);
450
+ // Attempt 1 sent 3 history items + prompt; attempt 2 sent 2 + prompt.
451
+ const firstInput = JSON.parse(fetchMock.mock.calls[0][1].body).input;
452
+ const secondInput = JSON.parse(fetchMock.mock.calls[1][1].body).input;
453
+ expect(firstInput).toHaveLength(4);
454
+ expect(secondInput).toHaveLength(3);
455
+ expect(JSON.stringify(secondInput)).not.toContain("oldest");
456
+ // Replacement history was still built from the ORIGINAL user messages.
457
+ expect(JSON.stringify(history)).toContain(SUMMARY_PREFIX.slice(0, 30));
458
+ expect(JSON.stringify(history)).toContain("oldest");
459
+ });
460
+ it("marks tokens full and surfaces the error when nothing is left to trim", async () => {
461
+ const history = [
462
+ { type: "message", role: "user", content: "only" },
463
+ ];
464
+ const tokenState = new SessionTokenState();
465
+ const fetchMock = vi
466
+ .fn()
467
+ .mockResolvedValue(makeErrorResponse(400, OPENROUTER_PROMPT_TOO_LONG_BODY));
468
+ await expect(runInlineAutoCompactTask(history, turnConfig(fetchMock, tokenState))).rejects.toThrow(/prompt is too long/u);
469
+ // mirrors compact.rs:242: set_total_tokens_full before surfacing.
470
+ expect(tokenState.totalTokens).toBe(1000);
471
+ expect(fetchMock).toHaveBeenCalledTimes(1);
472
+ });
473
+ });
244
474
  //# sourceMappingURL=compact.test.js.map