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:
@@ -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 () => {
|
||||
|
||||
Reference in New Issue
Block a user