This commit is contained in:
roomote-v0[bot] 2026-04-07 00:29:07 +00:00 committed by GitHub
commit 08576ab626
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 79 additions and 0 deletions

View file

@ -397,6 +397,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

@ -1399,10 +1399,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"
}
@ -1410,6 +1416,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.