fix(ai): use hyphenated Codex session header

closes #4967
This commit is contained in:
Armin Ronacher
2026-05-27 01:11:24 +02:00
parent 2531fc130d
commit 26f1e00f71
3 changed files with 16 additions and 6 deletions

View File

@@ -4,6 +4,7 @@
### Fixed
- Fixed OpenAI Codex Responses cache-affinity headers to send `session-id` instead of proxy-incompatible `session_id` ([#4967](https://github.com/earendil-works/pi/issues/4967)).
- Fixed `openai-codex/gpt-5.3-codex-spark` generated metadata to use its 128k context window ([#4969](https://github.com/earendil-works/pi/issues/4969)).
- Fixed OpenRouter/Poolside context overflow detection for `maximum allowed input length` errors ([#4943](https://github.com/earendil-works/pi/issues/4943)).

View File

@@ -1376,7 +1376,7 @@ function buildSSEHeaders(
headers.set("content-type", "application/json");
if (sessionId) {
headers.set("session_id", sessionId);
headers.set("session-id", sessionId);
headers.set("x-client-request-id", sessionId);
}
@@ -1397,6 +1397,6 @@ function buildWebSocketHeaders(
headers.delete("openai-beta");
headers.set("OpenAI-Beta", OPENAI_BETA_RESPONSES_WEBSOCKETS);
headers.set("x-client-request-id", requestId);
headers.set("session_id", requestId);
headers.set("session-id", requestId);
return headers;
}

View File

@@ -311,7 +311,7 @@ describe("openai-codex streaming", () => {
expect(result.stopReason).toBe("length");
});
it("sets session_id/x-client-request-id headers and prompt_cache_key when sessionId is provided", async () => {
it("sets session-id/x-client-request-id headers and prompt_cache_key when sessionId is provided", async () => {
const tempDir = mkdtempSync(join(tmpdir(), "pi-codex-stream-"));
process.env.PI_CODING_AGENT_DIR = tempDir;
@@ -372,7 +372,8 @@ describe("openai-codex streaming", () => {
if (url === "https://chatgpt.com/backend-api/codex/responses") {
const headers = init?.headers instanceof Headers ? init.headers : undefined;
// Verify sessionId is set in headers
expect(headers?.get("session_id")).toBe(sessionId);
expect(headers?.get("session-id")).toBe(sessionId);
expect(headers?.has("session_id")).toBe(false);
expect(headers?.get("x-client-request-id")).toBe(sessionId);
// Verify sessionId is set in request body as prompt_cache_key
@@ -721,7 +722,7 @@ describe("openai-codex streaming", () => {
},
);
it("does not set session_id/x-client-request-id headers when sessionId is not provided", async () => {
it("does not set session-id/x-client-request-id headers when sessionId is not provided", async () => {
const tempDir = mkdtempSync(join(tmpdir(), "pi-codex-stream-"));
process.env.PI_CODING_AGENT_DIR = tempDir;
@@ -781,6 +782,7 @@ describe("openai-codex streaming", () => {
if (url === "https://chatgpt.com/backend-api/codex/responses") {
const headers = init?.headers instanceof Headers ? init.headers : undefined;
// Verify headers are not set when sessionId is not provided
expect(headers?.has("session-id")).toBe(false);
expect(headers?.has("session_id")).toBe(false);
expect(headers?.has("x-client-request-id")).toBe(false);
@@ -819,6 +821,7 @@ describe("openai-codex streaming", () => {
it("forwards auto transport from streamSimple options and uses cached websocket context", async () => {
const token = mockToken();
const sentBodies: unknown[] = [];
let capturedWebSocketHeaders: Record<string, string> | undefined;
const fetchMock = vi.fn(async () => new Response("unexpected fetch", { status: 500 }));
vi.stubGlobal("fetch", fetchMock);
@@ -826,7 +829,10 @@ describe("openai-codex streaming", () => {
class MockWebSocket {
private listeners = new Map<string, Set<(event: unknown) => void>>();
constructor(_url: string, _protocols?: string | string[] | { headers?: Record<string, string> }) {
constructor(_url: string, protocols?: string | string[] | { headers?: Record<string, string> }) {
if (protocols && typeof protocols === "object" && !Array.isArray(protocols)) {
capturedWebSocketHeaders = protocols.headers;
}
queueMicrotask(() => this.dispatch("open", {}));
}
@@ -917,6 +923,9 @@ describe("openai-codex streaming", () => {
}).result();
expect(sentBodies).toHaveLength(1);
expect(capturedWebSocketHeaders?.["session-id"]).toBe("session-auto");
expect(capturedWebSocketHeaders?.session_id).toBeUndefined();
expect(capturedWebSocketHeaders?.["x-client-request-id"]).toBe("session-auto");
expect(global.fetch).not.toHaveBeenCalled();
expect(getOpenAICodexWebSocketDebugStats("session-auto")).toMatchObject({
cachedContextRequests: 1,