fix(openai): strip unsupported ChatGPT prompt cache retention options while preserving prompt cache keys
This commit is contained in:
@@ -4,6 +4,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- strip unsupported ChatGPT prompt cache retention options while preserving prompt cache keys (openai)
|
||||||
|
- Removes promptCacheRetention values before sending requests to the ChatGPT Codex backend.
|
||||||
|
- Keeps prompt_cache_key forwarding intact for OpenAI provider options.
|
||||||
|
- Only rewrites system prompts into top-level instructions when needed, avoiding unnecessary prompt changes.
|
||||||
|
|
||||||
## 2026-05-14 - 4.0.1
|
## 2026-05-14 - 4.0.1
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|||||||
@@ -203,6 +203,12 @@ tap.test('getModel uses ChatGPT Codex backend for OpenAI ChatGPT auth', async ()
|
|||||||
model,
|
model,
|
||||||
system: 'system prompt',
|
system: 'system prompt',
|
||||||
prompt: 'hello',
|
prompt: 'hello',
|
||||||
|
providerOptions: {
|
||||||
|
openai: {
|
||||||
|
promptCacheKey: 'session-1',
|
||||||
|
promptCacheRetention: 'in_memory',
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(capturedRequest?.url).toEqual('https://chatgpt.com/backend-api/codex/responses');
|
expect(capturedRequest?.url).toEqual('https://chatgpt.com/backend-api/codex/responses');
|
||||||
@@ -214,6 +220,8 @@ tap.test('getModel uses ChatGPT Codex backend for OpenAI ChatGPT auth', async ()
|
|||||||
expect(capturedBody.input).toEqual([
|
expect(capturedBody.input).toEqual([
|
||||||
{ role: 'user', content: [{ type: 'input_text', text: 'hello' }] },
|
{ role: 'user', content: [{ type: 'input_text', text: 'hello' }] },
|
||||||
]);
|
]);
|
||||||
|
expect(capturedBody.prompt_cache_key).toEqual('session-1');
|
||||||
|
expect(capturedBody.prompt_cache_retention).toEqual(undefined);
|
||||||
} finally {
|
} finally {
|
||||||
globalThis.fetch = originalFetch;
|
globalThis.fetch = originalFetch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ const getSystemInstructions = (prompt: LanguageModelV3CallOptions['prompt']): st
|
|||||||
return instructions.length > 0 ? instructions.join('\n') : undefined;
|
return instructions.length > 0 ? instructions.join('\n') : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasUnsupportedChatGptCacheRetention = (options: JSONObject): boolean => {
|
||||||
|
return options.promptCacheRetention !== undefined || options.prompt_cache_retention !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChatGPT's Codex backend requires top-level Responses API instructions.
|
* ChatGPT's Codex backend requires top-level Responses API instructions.
|
||||||
* The standard OpenAI provider otherwise serializes system prompts as input items.
|
* The standard OpenAI provider otherwise serializes system prompts as input items.
|
||||||
@@ -20,25 +24,30 @@ export function createOpenAiChatGptInstructionsMiddleware(): LanguageModelV3Midd
|
|||||||
specificationVersion: 'v3',
|
specificationVersion: 'v3',
|
||||||
transformParams: async ({ params }) => {
|
transformParams: async ({ params }) => {
|
||||||
const instructions = getSystemInstructions(params.prompt);
|
const instructions = getSystemInstructions(params.prompt);
|
||||||
if (!instructions) {
|
const providerOptions = params.providerOptions ?? {};
|
||||||
|
const openAiProviderOptions = providerOptions.openai ?? {};
|
||||||
|
const shouldApplyInstructions = !!instructions && !isNonEmptyString(openAiProviderOptions.instructions);
|
||||||
|
const shouldStripCacheRetention = hasUnsupportedChatGptCacheRetention(openAiProviderOptions);
|
||||||
|
|
||||||
|
if (!shouldApplyInstructions && !shouldStripCacheRetention) {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
const providerOptions = params.providerOptions ?? {};
|
const nextOpenAiProviderOptions: JSONObject = { ...openAiProviderOptions };
|
||||||
const openAiProviderOptions = providerOptions.openai ?? {};
|
delete nextOpenAiProviderOptions.promptCacheRetention;
|
||||||
if (isNonEmptyString(openAiProviderOptions.instructions)) {
|
delete nextOpenAiProviderOptions.prompt_cache_retention;
|
||||||
return params;
|
if (shouldApplyInstructions) {
|
||||||
|
nextOpenAiProviderOptions.instructions = instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...params,
|
...params,
|
||||||
prompt: params.prompt.filter((message) => message.role !== 'system'),
|
prompt: shouldApplyInstructions
|
||||||
|
? params.prompt.filter((message) => message.role !== 'system')
|
||||||
|
: params.prompt,
|
||||||
providerOptions: {
|
providerOptions: {
|
||||||
...providerOptions,
|
...providerOptions,
|
||||||
openai: {
|
openai: nextOpenAiProviderOptions,
|
||||||
...openAiProviderOptions,
|
|
||||||
instructions,
|
|
||||||
} as JSONObject,
|
|
||||||
},
|
},
|
||||||
} satisfies LanguageModelV3CallOptions;
|
} satisfies LanguageModelV3CallOptions;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user