diff --git a/extensions/microsoft-foundry/index.test.ts b/extensions/microsoft-foundry/index.test.ts index 636cc7f71ac8..b7bef35a4822 100644 --- a/extensions/microsoft-foundry/index.test.ts +++ b/extensions/microsoft-foundry/index.test.ts @@ -803,6 +803,8 @@ describe("microsoft-foundry plugin", () => { const model = config.models?.providers?.["microsoft-foundry"]?.models[0]; expect(model?.id).toBe("gpt-5.4"); expect(model?.reasoning).toBe(true); + expect(model?.contextWindow).toBe(1_050_000); + expect(model?.maxTokens).toBe(128_000); expect(model?.compat?.supportsReasoningEffort).toBe(true); }); @@ -1420,6 +1422,41 @@ describe("microsoft-foundry plugin", () => { expect(provider?.headers).toBeUndefined(); }); + it.each([ + ["gpt-5.6", 1_050_000, 128_000], + ["gpt-5.6-sol", 1_050_000, 128_000], + ["gpt-5.6-terra", 1_050_000, 128_000], + ["gpt-5.6-luna", 1_050_000, 128_000], + ["gpt-5.5", 1_050_000, 128_000], + ["gpt-5.4", 1_050_000, 128_000], + ["gpt-5.4-pro", 1_050_000, 128_000], + ["gpt-5.4-mini", 400_000, 128_000], + ["gpt-5.4-nano", 400_000, 128_000], + ["gpt-5-chat", 128_000, 16_384], + ["gpt-4o-mini", 128_000, 16_384], + ] as const)( + "uses Foundry-native token limits for %s", + (modelNameHint, contextWindow, maxTokens) => { + const result = buildFoundryAuthResult({ + profileId: "microsoft-foundry:default", + apiKey: "test-api-key", + endpoint: "https://example.services.ai.azure.com", + modelId: `prod-${modelNameHint}`, + modelNameHint, + api: modelNameHint.startsWith("gpt-5") ? "openai-responses" : "openai-completions", + authMethod: "api-key", + }); + + expect(result.configPatch?.models?.providers?.["microsoft-foundry"]?.models[0]).toMatchObject( + { + name: modelNameHint, + contextWindow, + maxTokens, + }, + ); + }, + ); + it.each([ ["claude-mythos-preview", 128_000], ["claude-opus-5", 128_000], diff --git a/extensions/microsoft-foundry/shared.ts b/extensions/microsoft-foundry/shared.ts index 9dc2312762f4..dc427aac2938 100644 --- a/extensions/microsoft-foundry/shared.ts +++ b/extensions/microsoft-foundry/shared.ts @@ -225,12 +225,33 @@ function supportsFoundryManualClaudeThinking(value?: string | null): boolean { : false; } +function resolveFoundryOpenAIModelTokenLimits( + normalized: string | undefined, +): { contextWindow: number; maxTokens: number } | undefined { + if (!normalized) { + return undefined; + } + // Foundry publishes provider-native capacities. Keep exact families here so + // older GPT and continuously updated chat models retain their separate caps. + if (/^gpt-5\.(?:4(?:-pro)?|5|6(?:-(?:sol|terra|luna))?)$/u.test(normalized)) { + return { contextWindow: 1_050_000, maxTokens: 128_000 }; + } + if (/^gpt-5\.4-(?:mini|nano)$/u.test(normalized)) { + return { contextWindow: 400_000, maxTokens: 128_000 }; + } + return undefined; +} + function resolveFoundryModelTokenLimits(value?: string | null): { contextWindow: number; maxTokens: number; } { const normalized = normalizeFoundryModelName(value); const normalizedVersion = normalized?.replace(/\./g, "-"); + const foundryOpenAILimits = resolveFoundryOpenAIModelTokenLimits(normalized); + if (foundryOpenAILimits) { + return foundryOpenAILimits; + } if ( normalized && (supportsClaudeAdaptiveThinking({ id: normalized }) ||