diff --git a/src/agents/model-compat.test.ts b/src/agents/model-compat.test.ts index c742ae643b7..0ef5bacbe73 100644 --- a/src/agents/model-compat.test.ts +++ b/src/agents/model-compat.test.ts @@ -157,6 +157,19 @@ describe("normalizeModelCompat", () => { }); }); + it("keeps supportsUsageInStreaming on for native ModelStudio endpoints", () => { + const model = { + ...baseModel(), + provider: "modelstudio", + baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", + }; + delete (model as { compat?: unknown }).compat; + const normalized = normalizeModelCompat(model); + expect(supportsDeveloperRole(normalized)).toBe(false); + expect(supportsUsageInStreaming(normalized)).toBe(true); + expect(supportsStrictMode(normalized)).toBe(false); + }); + it("leaves native api.openai.com model untouched", () => { const model = { ...baseModel(), diff --git a/src/agents/openai-completions-compat.ts b/src/agents/openai-completions-compat.ts index 99879c08210..1f3b136ce2d 100644 --- a/src/agents/openai-completions-compat.ts +++ b/src/agents/openai-completions-compat.ts @@ -13,6 +13,8 @@ export type OpenAICompletionsCompatDefaults = { supportsDeveloperRole: boolean; supportsReasoningEffort: boolean; supportsUsageInStreaming: boolean; + maxTokensField: "max_completion_tokens" | "max_tokens"; + thinkingFormat: "openai" | "openrouter" | "zai"; supportsStrictMode: boolean; }; @@ -50,6 +52,12 @@ export function resolveOpenAICompletionsCompatDefaults( isZai || (isDefaultRoute && isDefaultRouteProvider(input.provider, "cerebras", "chutes", "deepseek", "opencode", "xai")); + const isOpenRouterLike = input.provider === "openrouter" || endpointClass === "openrouter"; + const usesMaxTokens = + endpointClass === "chutes-native" || + endpointClass === "mistral-public" || + knownProviderFamily === "mistral" || + (isDefaultRoute && isDefaultRouteProvider(input.provider, "chutes")); return { supportsStore: @@ -62,6 +70,8 @@ export function resolveOpenAICompletionsCompatDefaults( !usesExplicitProxyLikeEndpoint, supportsUsageInStreaming: !isNonStandard && (!usesConfiguredNonOpenAIEndpoint || supportsNativeStreamingUsageCompat), + maxTokensField: usesMaxTokens ? "max_tokens" : "max_completion_tokens", + thinkingFormat: isZai ? "zai" : isOpenRouterLike ? "openrouter" : "openai", supportsStrictMode: !isZai && !usesConfiguredNonOpenAIEndpoint, }; } diff --git a/src/agents/openai-transport-stream.ts b/src/agents/openai-transport-stream.ts index 666bbf8f827..3440f2ec5a4 100644 --- a/src/agents/openai-transport-stream.ts +++ b/src/agents/openai-transport-stream.ts @@ -1346,11 +1346,6 @@ function detectCompat(model: OpenAIModeModel) { provider, ...capabilities, }); - const isMistral = - capabilities.knownProviderFamily === "mistral" || endpointClass === "mistral-public"; - const isZai = endpointClass === "zai-native" || (isDefaultRoute && provider === "zai"); - const useMaxTokens = - endpointClass === "chutes-native" || (isDefaultRoute && provider === "chutes") || isMistral; const isGroq = endpointClass === "groq-native" || (isDefaultRoute && provider === "groq"); const reasoningEffortMap: Record = isGroq && model.id === "qwen/qwen3-32b" @@ -1368,17 +1363,11 @@ function detectCompat(model: OpenAIModeModel) { supportsReasoningEffort: compatDefaults.supportsReasoningEffort, reasoningEffortMap, supportsUsageInStreaming: compatDefaults.supportsUsageInStreaming, - maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens", + maxTokensField: compatDefaults.maxTokensField, requiresToolResultName: false, requiresAssistantAfterToolResult: false, requiresThinkingAsText: false, - thinkingFormat: isZai - ? "zai" - : provider === "openrouter" || - capabilities.endpointClass === "openrouter" || - capabilities.attributionProvider === "openrouter" - ? "openrouter" - : "openai", + thinkingFormat: compatDefaults.thinkingFormat, openRouterRouting: {}, vercelGatewayRouting: {}, supportsStrictMode: compatDefaults.supportsStrictMode,