fix: skip prompt_cache_retention parameter for Azure endpoints

Azure Foundry/AI does not support the prompt_cache_retention parameter
that OpenAI API accepts. This causes API errors when users try to use
models like gpt-5.2-codex through Azure Foundry endpoints.

This fix adds Azure endpoint detection and skips the prompt_cache_retention
parameter when the configured base URL points to an Azure endpoint
(*.azure.com or *.azure-api.net).

Fixes #10782
This commit is contained in:
Roo Code 2026-01-18 09:54:10 +00:00
parent 802b40a790
commit 287e843737
2 changed files with 79 additions and 0 deletions

View file

@ -387,6 +387,60 @@ describe("OpenAiNativeHandler - normalizeUsage", () => {
const body = buildRequestBodyForModel(modelId)
expect(body.prompt_cache_retention).toBeUndefined()
})
it("should not set prompt_cache_retention when using Azure .azure.com endpoints", () => {
const azureHandler = new OpenAiNativeHandler({
openAiNativeApiKey: "test-key",
openAiNativeBaseUrl: "https://myinstance.openai.azure.com",
apiModelId: "gpt-5.1",
} as any)
const model = azureHandler.getModel()
const body = (azureHandler as any).buildRequestBody(model, [], "", model.verbosity, undefined, undefined)
expect(body.prompt_cache_retention).toBeUndefined()
})
it("should not set prompt_cache_retention when using Azure AI Foundry endpoints", () => {
const azureHandler = new OpenAiNativeHandler({
openAiNativeApiKey: "test-key",
openAiNativeBaseUrl: "https://myinstance.services.ai.azure.com",
apiModelId: "gpt-5.1",
} as any)
const model = azureHandler.getModel()
const body = (azureHandler as any).buildRequestBody(model, [], "", model.verbosity, undefined, undefined)
expect(body.prompt_cache_retention).toBeUndefined()
})
it("should not set prompt_cache_retention when using Azure API Management endpoints", () => {
const azureHandler = new OpenAiNativeHandler({
openAiNativeApiKey: "test-key",
openAiNativeBaseUrl: "https://myapi.azure-api.net/openai",
apiModelId: "gpt-5.1",
} as any)
const model = azureHandler.getModel()
const body = (azureHandler as any).buildRequestBody(model, [], "", model.verbosity, undefined, undefined)
expect(body.prompt_cache_retention).toBeUndefined()
})
it("should set prompt_cache_retention for non-Azure endpoints with eligible models", () => {
const normalHandler = new OpenAiNativeHandler({
openAiNativeApiKey: "test-key",
openAiNativeBaseUrl: "https://api.openai.com/v1",
apiModelId: "gpt-5.1",
} as any)
const model = normalHandler.getModel()
const body = (normalHandler as any).buildRequestBody(model, [], "", model.verbosity, undefined, undefined)
expect(body.prompt_cache_retention).toBe("24h")
})
it("should set prompt_cache_retention when no base URL is configured (default OpenAI)", () => {
const defaultHandler = new OpenAiNativeHandler({
openAiNativeApiKey: "test-key",
apiModelId: "gpt-5.1",
} as any)
const model = defaultHandler.getModel()
const body = (defaultHandler as any).buildRequestBody(model, [], "", model.verbosity, undefined, undefined)
expect(body.prompt_cache_retention).toBe("24h")
})
})
describe("cost calculation", () => {

View file

@ -1300,10 +1300,16 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
* The policy is driven by ModelInfo.promptCacheRetention so that model-specific details
* live in the shared types layer rather than this provider. When set to "24h" and the
* model supports prompt caching, extended prompt cache retention is requested.
*
* Note: Azure Foundry/AI does not support the prompt_cache_retention parameter,
* so we skip it when using an Azure base URL.
*/
private getPromptCacheRetention(model: OpenAiNativeModel): "24h" | undefined {
if (!model.info.supportsPromptCache) return undefined
// Azure Foundry/AI does not support prompt_cache_retention
if (this.isAzureEndpoint()) return undefined
if (model.info.promptCacheRetention === "24h") {
return "24h"
}
@ -1311,6 +1317,25 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
return undefined
}
/**
* Checks if the configured base URL is an Azure endpoint.
* Azure Foundry/AI endpoints use different URL patterns than OpenAI's API
* and may not support all OpenAI-specific parameters like prompt_cache_retention.
*/
private isAzureEndpoint(): boolean {
const baseUrl = this.options.openAiNativeBaseUrl
if (!baseUrl) return false
try {
const url = new URL(baseUrl)
const host = url.host.toLowerCase()
// Match Azure OpenAI Service and Azure AI Foundry endpoints
return host.endsWith(".azure.com") || host.endsWith(".azure-api.net")
} catch {
return false
}
}
/**
* Returns a shallow-cloned ModelInfo with pricing overridden for the given tier, if available.
* If no tier or no overrides exist, the original ModelInfo is returned.