import { describe, expect, it } from "vitest"; import { isCodexTransientUpstreamError, isCodexUnknownSessionError, parseCodexJsonl, } from "./parse.js"; describe("parseCodexJsonl", () => { it("captures session id, assistant summary, usage, and error message", () => { const stdout = [ JSON.stringify({ type: "thread.started", thread_id: "thread_123" }), JSON.stringify({ type: "item.completed", item: { type: "agent_message", text: "Recovered response" }, }), JSON.stringify({ type: "turn.completed", usage: { input_tokens: 10, cached_input_tokens: 2, output_tokens: 4 }, }), JSON.stringify({ type: "turn.failed", error: { message: "resume failed" } }), ].join("\n"); expect(parseCodexJsonl(stdout)).toEqual({ sessionId: "thread_123", summary: "Recovered response", usage: { inputTokens: 10, cachedInputTokens: 2, outputTokens: 4, }, errorMessage: "resume failed", }); }); it("uses the last agent message as the summary when commentary updates precede the final answer", () => { const stdout = [ JSON.stringify({ type: "thread.started", thread_id: "thread_123" }), JSON.stringify({ type: "item.completed", item: { type: "reasoning", text: "Checking the heartbeat procedure" }, }), JSON.stringify({ type: "item.completed", item: { type: "agent_message", text: "I’m checking out the issue and reading the docs now." }, }), JSON.stringify({ type: "item.completed", item: { type: "agent_message", text: "Fixed the issue and verified the targeted tests pass." }, }), JSON.stringify({ type: "turn.completed", usage: { input_tokens: 10, cached_input_tokens: 2, output_tokens: 4 }, }), ].join("\n"); expect(parseCodexJsonl(stdout)).toEqual({ sessionId: "thread_123", summary: "Fixed the issue and verified the targeted tests pass.", usage: { inputTokens: 10, cachedInputTokens: 2, outputTokens: 4, }, errorMessage: null, }); }); }); describe("isCodexUnknownSessionError", () => { it("detects the current missing-rollout thread error", () => { expect( isCodexUnknownSessionError( "", "Error: thread/resume: thread/resume failed: no rollout found for thread id d448e715-7607-4bcc-91fc-7a3c0c5a9632", ), ).toBe(true); }); it("still detects existing stale-session wordings", () => { expect(isCodexUnknownSessionError("unknown thread id", "")).toBe(true); expect(isCodexUnknownSessionError("", "state db missing rollout path for thread abc")).toBe(true); }); it("does not classify unrelated Codex failures as stale sessions", () => { expect(isCodexUnknownSessionError("", "model overloaded")).toBe(false); }); }); describe("isCodexTransientUpstreamError", () => { it("classifies the remote-compaction high-demand failure as transient upstream", () => { expect( isCodexTransientUpstreamError({ errorMessage: "Error running remote compact task: We're currently experiencing high demand, which may cause temporary errors.", }), ).toBe(true); expect( isCodexTransientUpstreamError({ stderr: "We're currently experiencing high demand, which may cause temporary errors.", }), ).toBe(true); }); it("does not classify deterministic compaction errors as transient", () => { expect( isCodexTransientUpstreamError({ errorMessage: [ "Error running remote compact task: {", ' "error": {', ' "message": "Unknown parameter: \'prompt_cache_retention\'.",', ' "type": "invalid_request_error",', ' "param": "prompt_cache_retention",', ' "code": "unknown_parameter"', " }", "}", ].join("\n"), }), ).toBe(false); }); });