56 lines
2.2 KiB
TypeScript
56 lines
2.2 KiB
TypeScript
import type { JSONObject, LanguageModelV3CallOptions, LanguageModelV3Middleware } from '@ai-sdk/provider';
|
|
|
|
const isNonEmptyString = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0;
|
|
|
|
const getSystemInstructions = (prompt: LanguageModelV3CallOptions['prompt']): string | undefined => {
|
|
const instructions = prompt
|
|
.filter((message) => message.role === 'system')
|
|
.map((message) => message.content)
|
|
.filter(isNonEmptyString);
|
|
|
|
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.
|
|
* The standard OpenAI provider otherwise serializes system prompts as input items.
|
|
*/
|
|
export function createOpenAiChatGptInstructionsMiddleware(): LanguageModelV3Middleware {
|
|
return {
|
|
specificationVersion: 'v3',
|
|
transformParams: async ({ params }) => {
|
|
const instructions = getSystemInstructions(params.prompt);
|
|
const providerOptions = params.providerOptions ?? {};
|
|
const openAiProviderOptions = providerOptions.openai ?? {};
|
|
const shouldApplyInstructions = !!instructions && !isNonEmptyString(openAiProviderOptions.instructions);
|
|
const shouldStripCacheRetention = hasUnsupportedChatGptCacheRetention(openAiProviderOptions);
|
|
|
|
if (!shouldApplyInstructions && !shouldStripCacheRetention) {
|
|
return params;
|
|
}
|
|
|
|
const nextOpenAiProviderOptions: JSONObject = { ...openAiProviderOptions };
|
|
delete nextOpenAiProviderOptions.promptCacheRetention;
|
|
delete nextOpenAiProviderOptions.prompt_cache_retention;
|
|
if (shouldApplyInstructions) {
|
|
nextOpenAiProviderOptions.instructions = instructions;
|
|
}
|
|
|
|
return {
|
|
...params,
|
|
prompt: shouldApplyInstructions
|
|
? params.prompt.filter((message) => message.role !== 'system')
|
|
: params.prompt,
|
|
providerOptions: {
|
|
...providerOptions,
|
|
openai: nextOpenAiProviderOptions,
|
|
},
|
|
} satisfies LanguageModelV3CallOptions;
|
|
},
|
|
};
|
|
}
|