fix(ai): honored disabled Codex cache retention

Routed Codex prompt cache identity through the shared retention-aware resolver while preserving transport session identity.

Covered explicit and environment-derived opt-outs, option precedence, direct body construction, and transport headers.

Fixes #7219
This commit is contained in:
roboomp
2026-08-01 03:45:49 +00:00
parent 80627462b4
commit eb5bfbfb11
3 changed files with 50 additions and 2 deletions
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed OpenAI Codex Responses ignoring disabled cache retention when deriving `prompt_cache_key`, while preserving transport session identity ([#7219](https://github.com/can1357/oh-my-pi/issues/7219)).
## [17.2.2] - 2026-07-31
### Added
@@ -111,6 +111,7 @@ import {
finalizePendingResponsesToolCalls,
finalizeReasoningThinking,
finalizeToolCallArgumentsDone,
getOpenAIPromptCacheKey,
hasExecutableIncompleteResponsesToolCalls,
isOpenAIResponsesProgressEvent,
mapOpenAIResponsesStopReason,
@@ -1373,7 +1374,7 @@ async function buildCodexRequestContext(
const accountId = getCodexAccountId(apiKey);
const baseUrl = model.baseUrl || CODEX_BASE_URL;
const url = resolveCodexResponsesUrl(baseUrl);
const promptCacheKey = normalizeOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId);
const promptCacheKey = getOpenAIPromptCacheKey(options);
const transportSessionId = normalizeOpenAIPromptCacheKey(options?.sessionId);
const codexClientVersion = CODEX_CLIENT_VERSION;
const transformedBody = await buildTransformedCodexRequestBody(model, context, options, promptCacheKey);
@@ -1463,7 +1464,7 @@ export async function buildTransformedCodexRequestBody(
model: Model<"openai-codex-responses">,
context: Context,
options: OpenAICodexResponsesOptions | undefined,
promptCacheKey = normalizeOpenAIPromptCacheKey(options?.promptCacheKey ?? options?.sessionId),
promptCacheKey = getOpenAIPromptCacheKey(options),
): Promise<RequestBody> {
const params: RequestBody = {
model: model.requestModelId ?? model.id,
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
import { scheduler } from "node:timers/promises";
import { streamSimple } from "@oh-my-pi/pi-ai";
import {
buildTransformedCodexRequestBody,
getOpenAICodexTransportDetails,
getOpenAICodexWebSocketDebugStats,
prewarmOpenAICodexResponses,
@@ -19,6 +20,7 @@ import type {
import { __resetProxyCache } from "@oh-my-pi/pi-ai/utils/proxy";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import * as piUtils from "@oh-my-pi/pi-utils";
import { withEnv } from "./helpers";
const { getAgentDir, setAgentDir, TempDir } = piUtils;
@@ -2369,6 +2371,47 @@ describe("openai-codex streaming", () => {
expect(capturedHeaders?.get("session_id")).toBe(sessionId);
expect(capturedHeaders?.get("x-client-request-id")).toBe(sessionId);
expect(capturedBody?.prompt_cache_key).toBe(promptCacheKey);
await streamOpenAICodexResponses(model, createCodexTestContext(), {
fetch: fetchMock as FetchImpl,
apiKey: token,
sessionId,
promptCacheKey,
cacheRetention: "none",
}).result();
expect(capturedHeaders?.get("conversation_id")).toBe(sessionId);
expect(capturedHeaders?.get("session_id")).toBe(sessionId);
expect(capturedHeaders?.get("x-client-request-id")).toBe(sessionId);
expect(capturedBody?.prompt_cache_key).toBeUndefined();
});
it("applies cache retention resolution to direct Codex request body construction", async () => {
const model = createCodexTestModel();
const context = createCodexTestContext();
const disabledPromptKey = await buildTransformedCodexRequestBody(model, context, {
promptCacheKey: "disabled-cache",
cacheRetention: "none",
});
const disabledSession = await buildTransformedCodexRequestBody(model, context, {
sessionId: "disabled-session",
cacheRetention: "none",
});
expect(disabledPromptKey.prompt_cache_key).toBeUndefined();
expect(disabledSession.prompt_cache_key).toBeUndefined();
await withEnv({ PI_CACHE_RETENTION: "none" }, async () => {
const disabledEnvironment = await buildTransformedCodexRequestBody(model, context, {
sessionId: "environment-session",
});
const explicitShort = await buildTransformedCodexRequestBody(model, context, {
promptCacheKey: "explicit-cache",
cacheRetention: "short",
});
expect(disabledEnvironment.prompt_cache_key).toBeUndefined();
expect(explicitShort.prompt_cache_key).toBe("explicit-cache");
});
});
it("omits unsupported sampling keys (temperature/top_p/top_k/min_p/penalties) from the Codex Responses body", async () => {