diff --git a/packages/types/src/providers/roo.ts b/packages/types/src/providers/roo.ts index 0b7ed89bd92..f1dec45f3bf 100644 --- a/packages/types/src/providers/roo.ts +++ b/packages/types/src/providers/roo.ts @@ -38,6 +38,7 @@ export const RooModelSchema = z.object({ tags: z.array(z.string()).optional(), pricing: RooPricingSchema, deprecated: z.boolean().optional(), + default_temperature: z.number().optional(), }) export const RooModelsResponseSchema = z.object({ diff --git a/src/api/providers/fetchers/__tests__/litellm.spec.ts b/src/api/providers/fetchers/__tests__/litellm.spec.ts index bf36f3e456e..fe6424e673c 100644 --- a/src/api/providers/fetchers/__tests__/litellm.spec.ts +++ b/src/api/providers/fetchers/__tests__/litellm.spec.ts @@ -222,7 +222,7 @@ describe("getLiteLLMModels", () => { contextWindow: 200000, supportsImages: true, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: 3, outputPrice: 15, cacheWritesPrice: undefined, @@ -234,7 +234,7 @@ describe("getLiteLLMModels", () => { contextWindow: 128000, supportsImages: false, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: 10, outputPrice: 30, cacheWritesPrice: undefined, @@ -305,7 +305,7 @@ describe("getLiteLLMModels", () => { contextWindow: 200000, supportsImages: true, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -318,7 +318,7 @@ describe("getLiteLLMModels", () => { contextWindow: 200000, supportsImages: false, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -455,7 +455,7 @@ describe("getLiteLLMModels", () => { contextWindow: 200000, supportsImages: true, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -468,7 +468,7 @@ describe("getLiteLLMModels", () => { contextWindow: 128000, supportsImages: false, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -533,7 +533,7 @@ describe("getLiteLLMModels", () => { contextWindow: 200000, supportsImages: true, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -546,7 +546,7 @@ describe("getLiteLLMModels", () => { contextWindow: 128000, supportsImages: false, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -559,7 +559,7 @@ describe("getLiteLLMModels", () => { contextWindow: 128000, supportsImages: false, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -673,7 +673,7 @@ describe("getLiteLLMModels", () => { contextWindow: 200000, supportsImages: true, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -687,7 +687,7 @@ describe("getLiteLLMModels", () => { contextWindow: 128000, supportsImages: false, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, @@ -701,7 +701,7 @@ describe("getLiteLLMModels", () => { contextWindow: 100000, supportsImages: false, supportsPromptCache: false, - supportsNativeTools: false, + supportsNativeTools: true, inputPrice: undefined, outputPrice: undefined, cacheWritesPrice: undefined, diff --git a/src/api/providers/fetchers/__tests__/roo.spec.ts b/src/api/providers/fetchers/__tests__/roo.spec.ts index 07502d95e32..c557dedd484 100644 --- a/src/api/providers/fetchers/__tests__/roo.spec.ts +++ b/src/api/providers/fetchers/__tests__/roo.spec.ts @@ -478,4 +478,171 @@ describe("getRooModels", () => { "Failed to fetch Roo Code Cloud models: No response from server", ) }) + + it("should parse default_temperature from API response", async () => { + const mockResponse = { + object: "list", + data: [ + { + id: "test/model-with-temp", + object: "model", + created: 1234567890, + owned_by: "test", + name: "Model with Default Temperature", + description: "Model with custom default temperature", + context_window: 128000, + max_tokens: 8192, + type: "language", + pricing: { + input: "0.0001", + output: "0.0002", + }, + default_temperature: 0.6, + }, + ], + } + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: async () => mockResponse, + }) + + const models = await getRooModels(baseUrl, apiKey) + + expect(models["test/model-with-temp"].defaultTemperature).toBe(0.6) + }) + + it("should handle models without default_temperature", async () => { + const mockResponse = { + object: "list", + data: [ + { + id: "test/model-no-temp", + object: "model", + created: 1234567890, + owned_by: "test", + name: "Model without Default Temperature", + description: "Model without custom default temperature", + context_window: 128000, + max_tokens: 8192, + type: "language", + pricing: { + input: "0.0001", + output: "0.0002", + }, + }, + ], + } + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: async () => mockResponse, + }) + + const models = await getRooModels(baseUrl, apiKey) + + expect(models["test/model-no-temp"].defaultTemperature).toBeUndefined() + }) + + it("should set defaultToolProtocol to native when default-native-tools tag is present", async () => { + const mockResponse = { + object: "list", + data: [ + { + id: "test/native-tools-model", + object: "model", + created: 1234567890, + owned_by: "test", + name: "Native Tools Model", + description: "Model with native tool calling default", + context_window: 128000, + max_tokens: 8192, + type: "language", + tags: ["tool-use", "default-native-tools"], + pricing: { + input: "0.0001", + output: "0.0002", + }, + }, + ], + } + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: async () => mockResponse, + }) + + const models = await getRooModels(baseUrl, apiKey) + + expect(models["test/native-tools-model"].supportsNativeTools).toBe(true) + expect(models["test/native-tools-model"].defaultToolProtocol).toBe("native") + }) + + it("should imply supportsNativeTools when default-native-tools tag is present without tool-use tag", async () => { + const mockResponse = { + object: "list", + data: [ + { + id: "test/implicit-native-tools", + object: "model", + created: 1234567890, + owned_by: "test", + name: "Implicit Native Tools Model", + description: "Model with default-native-tools but no tool-use tag", + context_window: 128000, + max_tokens: 8192, + type: "language", + tags: ["default-native-tools"], // Only default-native-tools, no tool-use + pricing: { + input: "0.0001", + output: "0.0002", + }, + }, + ], + } + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: async () => mockResponse, + }) + + const models = await getRooModels(baseUrl, apiKey) + + expect(models["test/implicit-native-tools"].supportsNativeTools).toBe(true) + expect(models["test/implicit-native-tools"].defaultToolProtocol).toBe("native") + }) + + it("should not set defaultToolProtocol when default-native-tools tag is not present", async () => { + const mockResponse = { + object: "list", + data: [ + { + id: "test/non-native-model", + object: "model", + created: 1234567890, + owned_by: "test", + name: "Non-Native Tools Model", + description: "Model without native tool calling default", + context_window: 128000, + max_tokens: 8192, + type: "language", + tags: ["tool-use"], + pricing: { + input: "0.0001", + output: "0.0002", + }, + }, + ], + } + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: async () => mockResponse, + }) + + const models = await getRooModels(baseUrl, apiKey) + + expect(models["test/non-native-model"].supportsNativeTools).toBe(true) + expect(models["test/non-native-model"].defaultToolProtocol).toBeUndefined() + }) }) diff --git a/src/api/providers/fetchers/litellm.ts b/src/api/providers/fetchers/litellm.ts index 625bc5c0b5e..2cfbb189ab6 100644 --- a/src/api/providers/fetchers/litellm.ts +++ b/src/api/providers/fetchers/litellm.ts @@ -45,11 +45,7 @@ export async function getLiteLLMModels(apiKey: string, baseUrl: string): Promise contextWindow: modelInfo.max_input_tokens || 200000, supportsImages: Boolean(modelInfo.supports_vision), supportsPromptCache: Boolean(modelInfo.supports_prompt_caching), - supportsNativeTools: Boolean( - modelInfo.supports_function_calling || - modelInfo.supports_tool_choice || - modelInfo.supports_tool_use, - ), + supportsNativeTools: true, inputPrice: modelInfo.input_cost_per_token ? modelInfo.input_cost_per_token * 1000000 : undefined, outputPrice: modelInfo.output_cost_per_token ? modelInfo.output_cost_per_token * 1000000 diff --git a/src/api/providers/fetchers/roo.ts b/src/api/providers/fetchers/roo.ts index 124628c9245..42b30139f66 100644 --- a/src/api/providers/fetchers/roo.ts +++ b/src/api/providers/fetchers/roo.ts @@ -107,8 +107,13 @@ export async function getRooModels(baseUrl: string, apiKey?: string): Promise { expect(result.temperature).toBe(0.5) }) + it("should use model defaultTemperature over provider defaultTemperature", () => { + const modelWithDefaultTemp: ModelInfo = { + ...baseModel, + defaultTemperature: 0.8, + } + + const result = getModelParams({ + ...anthropicParams, + settings: {}, + model: modelWithDefaultTemp, + defaultTemperature: 0.5, + }) + + expect(result.temperature).toBe(0.8) + }) + + it("should prefer settings temperature over model defaultTemperature", () => { + const modelWithDefaultTemp: ModelInfo = { + ...baseModel, + defaultTemperature: 0.8, + } + + const result = getModelParams({ + ...anthropicParams, + settings: { modelTemperature: 0.3 }, + model: modelWithDefaultTemp, + defaultTemperature: 0.5, + }) + + expect(result.temperature).toBe(0.3) + }) + it("should use model maxTokens when available", () => { const model: ModelInfo = { ...baseModel, diff --git a/src/api/transform/model-params.ts b/src/api/transform/model-params.ts index 962ddf1a9c6..a75b397d68f 100644 --- a/src/api/transform/model-params.ts +++ b/src/api/transform/model-params.ts @@ -117,7 +117,7 @@ export function getModelParams({ format, }) - let temperature = customTemperature ?? defaultTemperature + let temperature = customTemperature ?? model.defaultTemperature ?? defaultTemperature let reasoningBudget: ModelParams["reasoningBudget"] = undefined let reasoningEffort: ModelParams["reasoningEffort"] = undefined let verbosity: VerbosityLevel | undefined = customVerbosity diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index e43569c98c2..d034d9e0165 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -2,7 +2,6 @@ import { useMemo, useState, useCallback, useEffect, useRef, useLayoutEffect } fr import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" import { Trans } from "react-i18next" import { Check, X, Brain } from "lucide-react" -// import { ChevronsUpDown, Check, X, Info } from "lucide-react" import type { ProviderSettings, ModelInfo, OrganizationAllowList } from "@roo-code/types"