diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index b5db12bb70..41d00c7a04 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -930,10 +930,11 @@ export const openAiNativeModels = { }, } as const satisfies Record +// `maxTokens` is intentionally omitted so that no max output token limit is sent to the +// provider by default. export const openAiModelInfoSaneDefaults: ModelInfo = { - maxTokens: -1, contextWindow: 128_000, - supportsImages: true, + supportsImages: false, supportsPromptCache: false, inputPrice: 0, outputPrice: 0, diff --git a/src/api/providers/__tests__/base-openai-compatible-provider.spec.ts b/src/api/providers/__tests__/base-openai-compatible-provider.spec.ts index e761a380ea..b251168461 100644 --- a/src/api/providers/__tests__/base-openai-compatible-provider.spec.ts +++ b/src/api/providers/__tests__/base-openai-compatible-provider.spec.ts @@ -325,6 +325,7 @@ describe("BaseOpenAiCompatibleProvider", () => { expect(model.id).not.toBe("test-model") // Falls back to sane default metadata so the rest of the pipeline works. expect(model.info).toEqual(openAiModelInfoSaneDefaults) + expect(model.info).not.toHaveProperty("maxTokens") }) it("sends the custom model id verbatim to the API", async () => { @@ -343,6 +344,18 @@ describe("BaseOpenAiCompatibleProvider", () => { ) }) + it("omits max_tokens for a custom model", async () => { + mockCreate.mockImplementationOnce(() => asyncStreamFrom([])) + + const customHandler = new TestOpenAiCompatibleProvider("test-api-key", { + apiModelId: "some/custom-model-not-in-list", + }) + + await collectStream(customHandler.createMessage("system prompt", [])) + + expect(mockCreate.mock.calls[0][0].max_tokens).toBeUndefined() + }) + it("completePrompt sends the custom model id verbatim to the API", async () => { mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: "ok" } }] }) diff --git a/src/api/providers/__tests__/fireworks.spec.ts b/src/api/providers/__tests__/fireworks.spec.ts index de56c5a803..480f965894 100644 --- a/src/api/providers/__tests__/fireworks.spec.ts +++ b/src/api/providers/__tests__/fireworks.spec.ts @@ -98,6 +98,29 @@ describe("FireworksHandler", () => { expect(model.info).toEqual(expect.objectContaining(fireworksModels[testModelId])) }) + it("should omit max_tokens for a custom model", async () => { + const handlerWithCustomModel = new FireworksHandler({ + apiModelId: "accounts/fireworks/models/deepseek-v4p1-flash", + fireworksApiKey: "test-fireworks-api-key", + }) + + await collectStream(handlerWithCustomModel.createMessage("system prompt", [])) + + expect(mockCreate.mock.calls[0][0].model).toBe("accounts/fireworks/models/deepseek-v4p1-flash") + expect(mockCreate.mock.calls[0][0].max_tokens).toBeUndefined() + }) + + it("should still send a positive max_tokens for a known model", async () => { + const handlerWithModel = new FireworksHandler({ + apiModelId: "accounts/fireworks/models/kimi-k2-instruct", + fireworksApiKey: "test-fireworks-api-key", + }) + + await collectStream(handlerWithModel.createMessage("system prompt", [])) + + expect(mockCreate.mock.calls[0][0].max_tokens).toBe(16384) + }) + it.each([ { modelId: "accounts/fireworks/models/glm-5p1" as const, diff --git a/src/api/providers/__tests__/lmstudio.spec.ts b/src/api/providers/__tests__/lmstudio.spec.ts index 566d6c4d95..f3b87df7a9 100644 --- a/src/api/providers/__tests__/lmstudio.spec.ts +++ b/src/api/providers/__tests__/lmstudio.spec.ts @@ -254,7 +254,7 @@ describe("LmStudioHandler", () => { const modelInfo = handler.getModel() expect(modelInfo.id).toBe(mockOptions.lmStudioModelId) expect(modelInfo.info).toBeDefined() - expect(modelInfo.info.maxTokens).toBe(-1) + expect(modelInfo.info.maxTokens).toBeUndefined() expect(modelInfo.info.contextWindow).toBe(128_000) }) }) diff --git a/src/api/providers/__tests__/openai.spec.ts b/src/api/providers/__tests__/openai.spec.ts index e32111c273..4dc6521153 100644 --- a/src/api/providers/__tests__/openai.spec.ts +++ b/src/api/providers/__tests__/openai.spec.ts @@ -1106,7 +1106,7 @@ describe("OpenAiHandler", () => { expect(model.id).toBe(mockOptions.openAiModelId) expect(model.info).toBeDefined() expect(model.info.contextWindow).toBe(128_000) - expect(model.info.supportsImages).toBe(true) + expect(model.info.supportsImages).toBe(false) }) it("should handle undefined model ID", () => { diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-azure-guidance-dark.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-azure-guidance-dark.png index 8f5e90e872..75caad8a48 100644 Binary files a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-azure-guidance-dark.png and b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-azure-guidance-dark.png differ diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-dark.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-dark.png index 1f8796c4b0..2e82ab0811 100644 Binary files a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-dark.png and b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-dark.png differ diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast-light.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast-light.png index 33a01f2d77..0469607672 100644 Binary files a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast-light.png and b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast-light.png differ diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast.png index c9718915c5..7c51ab1f57 100644 Binary files a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast.png and b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-high-contrast.png differ diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-light.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-light.png index eeea3e5ac8..e48013ba4c 100644 Binary files a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-light.png and b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-extra-body-light.png differ