From bb9a7460b49e0dca9bc44e3d175f974a8340e132 Mon Sep 17 00:00:00 2001 From: slytechnical Date: Thu, 29 May 2025 19:42:42 -0500 Subject: [PATCH] add litellm reasoning effort control --- packages/types/src/model.ts | 3 + src/api/providers/__tests__/litellm.test.ts | 186 ++++++++++++++++++ .../fetchers/__tests__/litellm.test.ts | 57 ++++++ src/api/providers/fetchers/litellm.ts | 2 + src/api/providers/litellm.ts | 49 ++++- .../components/settings/ThinkingBudget.tsx | 29 ++- webview-ui/src/i18n/locales/ca/settings.json | 1 + webview-ui/src/i18n/locales/de/settings.json | 1 + webview-ui/src/i18n/locales/en/settings.json | 1 + webview-ui/src/i18n/locales/es/settings.json | 1 + webview-ui/src/i18n/locales/fr/settings.json | 1 + webview-ui/src/i18n/locales/hi/settings.json | 1 + webview-ui/src/i18n/locales/it/settings.json | 1 + webview-ui/src/i18n/locales/ja/settings.json | 1 + webview-ui/src/i18n/locales/ko/settings.json | 1 + webview-ui/src/i18n/locales/nl/settings.json | 1 + webview-ui/src/i18n/locales/pl/settings.json | 1 + .../src/i18n/locales/pt-BR/settings.json | 1 + webview-ui/src/i18n/locales/ru/settings.json | 1 + webview-ui/src/i18n/locales/tr/settings.json | 1 + webview-ui/src/i18n/locales/vi/settings.json | 1 + .../src/i18n/locales/zh-CN/settings.json | 1 + .../src/i18n/locales/zh-TW/settings.json | 1 + 23 files changed, 325 insertions(+), 18 deletions(-) create mode 100644 src/api/providers/__tests__/litellm.test.ts diff --git a/packages/types/src/model.ts b/packages/types/src/model.ts index 3bd66782cf..df6e93235b 100644 --- a/packages/types/src/model.ts +++ b/packages/types/src/model.ts @@ -6,6 +6,8 @@ import { z } from "zod" export const reasoningEfforts = ["low", "medium", "high"] as const +export const reasoningEffortsWithDefault = ["default", "low", "medium", "high"] as const + export const reasoningEffortsSchema = z.enum(reasoningEfforts) export type ReasoningEffort = z.infer @@ -37,6 +39,7 @@ export const modelInfoSchema = z.object({ supportsReasoningBudget: z.boolean().optional(), requiredReasoningBudget: z.boolean().optional(), supportsReasoningEffort: z.boolean().optional(), + shouldExposeDefaultReasoningEffort: z.boolean().optional(), supportedParameters: z.array(modelParametersSchema).optional(), inputPrice: z.number().optional(), outputPrice: z.number().optional(), diff --git a/src/api/providers/__tests__/litellm.test.ts b/src/api/providers/__tests__/litellm.test.ts new file mode 100644 index 0000000000..0911e77daf --- /dev/null +++ b/src/api/providers/__tests__/litellm.test.ts @@ -0,0 +1,186 @@ +import { LiteLLMHandler } from "../litellm" +import { ApiHandlerOptions } from "../../../shared/api" + +// Mock the getModelParams function +jest.mock("../../transform/model-params", () => ({ + getModelParams: jest.fn(), +})) + +// Mock the RouterProvider's fetchModel method +jest.mock("../router-provider", () => { + return { + RouterProvider: class MockRouterProvider { + protected options: any + protected models: any = {} + protected client: any = { + chat: { + completions: { + create: jest.fn(), + }, + }, + } + + constructor(config: any) { + this.options = config.options + } + + async fetchModel() { + return { id: "test-model", info: { maxTokens: 4096 } } + } + + getModel() { + return { id: "test-model", info: { maxTokens: 4096 } } + } + + supportsTemperature() { + return true + } + }, + } +}) + +describe("LiteLLMHandler", () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + it("should include reasoning_effort in request when configured", async () => { + const { getModelParams } = require("../../transform/model-params") + getModelParams.mockReturnValue({ + maxTokens: 4096, + temperature: 0, + reasoningEffort: "high", + }) + + const mockCreate = jest.fn().mockReturnValue({ + withResponse: () => + Promise.resolve({ + data: (async function* () { + yield { + choices: [{ delta: { content: "test response" } }], + usage: { prompt_tokens: 10, completion_tokens: 5 }, + } + })(), + }), + }) + + const options: ApiHandlerOptions = { + reasoningEffort: "high", + } + + const handler = new LiteLLMHandler(options) + // Override the client mock + ;(handler as any).client.chat.completions.create = mockCreate + + // Call createMessage to trigger the request + const generator = handler.createMessage("test system", [{ role: "user", content: "test message" }]) + + // Consume the generator + const results = [] + for await (const chunk of generator) { + results.push(chunk) + } + + // Verify that reasoning_effort was included in the request + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + reasoning_effort: "high", + }), + ) + }) + + it("should not include reasoning_effort when not configured", async () => { + const { getModelParams } = require("../../transform/model-params") + getModelParams.mockReturnValue({ + maxTokens: 4096, + temperature: 0, + reasoningEffort: undefined, + }) + + const mockCreate = jest.fn().mockReturnValue({ + withResponse: () => + Promise.resolve({ + data: (async function* () { + yield { + choices: [{ delta: { content: "test response" } }], + usage: { prompt_tokens: 10, completion_tokens: 5 }, + } + })(), + }), + }) + + const options: ApiHandlerOptions = {} + + const handler = new LiteLLMHandler(options) + // Override the client mock + ;(handler as any).client.chat.completions.create = mockCreate + + // Call createMessage to trigger the request + const generator = handler.createMessage("test system", [{ role: "user", content: "test message" }]) + + // Consume the generator + const results = [] + for await (const chunk of generator) { + results.push(chunk) + } + + // Verify that reasoning_effort was not included in the request + const callArgs = mockCreate.mock.calls[0][0] + expect(callArgs).not.toHaveProperty("reasoning_effort") + }) + + it("should handle reasoning content in response stream", async () => { + const { getModelParams } = require("../../transform/model-params") + getModelParams.mockReturnValue({ + maxTokens: 4096, + temperature: 0, + reasoningEffort: "medium", + }) + + const mockCreate = jest.fn().mockReturnValue({ + withResponse: () => + Promise.resolve({ + data: (async function* () { + yield { + choices: [{ delta: { content: "regular content" } }], + } + yield { + choices: [{ delta: { reasoning_content: "reasoning content" } }], + } + yield { + choices: [{ delta: {} }], + usage: { prompt_tokens: 10, completion_tokens: 5 }, + } + })(), + }), + }) + + const options: ApiHandlerOptions = { + reasoningEffort: "medium", + } + + const handler = new LiteLLMHandler(options) + // Override the client mock + ;(handler as any).client.chat.completions.create = mockCreate + + // Call createMessage to trigger the request + const generator = handler.createMessage("test system", [{ role: "user", content: "test message" }]) + + // Consume the generator and collect results + const results = [] + for await (const chunk of generator) { + results.push(chunk) + } + + // Verify we got both text and reasoning content + expect(results).toEqual([ + { type: "text", text: "regular content" }, + { type: "reasoning", text: "reasoning content" }, + { + type: "usage", + inputTokens: 10, + outputTokens: 5, + }, + ]) + }) +}) diff --git a/src/api/providers/fetchers/__tests__/litellm.test.ts b/src/api/providers/fetchers/__tests__/litellm.test.ts index 49e928548f..0e10910d50 100644 --- a/src/api/providers/fetchers/__tests__/litellm.test.ts +++ b/src/api/providers/fetchers/__tests__/litellm.test.ts @@ -69,6 +69,8 @@ describe("getLiteLLMModels", () => { supportsImages: true, supportsComputerUse: true, supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: 3, outputPrice: 15, description: "claude-3-5-sonnet via LiteLLM proxy", @@ -79,6 +81,8 @@ describe("getLiteLLMModels", () => { supportsImages: false, supportsComputerUse: false, supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: 10, outputPrice: 30, description: "gpt-4-turbo via LiteLLM proxy", @@ -147,6 +151,8 @@ describe("getLiteLLMModels", () => { supportsImages: true, supportsComputerUse: true, supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: undefined, outputPrice: undefined, description: "test-computer-model via LiteLLM proxy", @@ -158,6 +164,8 @@ describe("getLiteLLMModels", () => { supportsImages: false, supportsComputerUse: false, supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: undefined, outputPrice: undefined, description: "test-non-computer-model via LiteLLM proxy", @@ -293,6 +301,8 @@ describe("getLiteLLMModels", () => { supportsImages: true, supportsComputerUse: true, // Should be true due to fallback supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: undefined, outputPrice: undefined, description: "claude-3-5-sonnet-latest via LiteLLM proxy", @@ -304,6 +314,8 @@ describe("getLiteLLMModels", () => { supportsImages: false, supportsComputerUse: false, // Should be false as it's not in fallback list supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: undefined, outputPrice: undefined, description: "gpt-4-turbo via LiteLLM proxy", @@ -367,6 +379,8 @@ describe("getLiteLLMModels", () => { supportsImages: true, supportsComputerUse: false, // False because explicitly set to false (fallback ignored) supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: undefined, outputPrice: undefined, description: "claude-3-5-sonnet-latest via LiteLLM proxy", @@ -378,6 +392,8 @@ describe("getLiteLLMModels", () => { supportsImages: false, supportsComputerUse: true, // True because explicitly set to true supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: undefined, outputPrice: undefined, description: "custom-model via LiteLLM proxy", @@ -389,12 +405,53 @@ describe("getLiteLLMModels", () => { supportsImages: false, supportsComputerUse: false, // False because explicitly set to false supportsPromptCache: false, + supportsReasoningEffort: false, + shouldExposeDefaultReasoningEffort: false, inputPrice: undefined, outputPrice: undefined, description: "another-custom-model via LiteLLM proxy", }) }) + it("sets shouldExposeDefaultReasoningEffort when supports_reasoning is true", async () => { + const mockResponse = { + data: { + data: [ + { + model_name: "reasoning-model", + model_info: { + max_tokens: 4096, + max_input_tokens: 200000, + supports_vision: true, + supports_prompt_caching: false, + supports_reasoning: true, // This should set shouldExposeDefaultReasoningEffort to true + }, + litellm_params: { + model: "openai/o1-preview", + }, + }, + ], + }, + } + + mockedAxios.get.mockResolvedValue(mockResponse) + + const result = await getLiteLLMModels("test-api-key", "http://localhost:4000") + + expect(result["reasoning-model"]).toEqual({ + maxTokens: 4096, + contextWindow: 200000, + supportsImages: true, + supportsComputerUse: false, + supportsPromptCache: false, + supportsReasoningEffort: true, + shouldExposeDefaultReasoningEffort: true, + inputPrice: undefined, + outputPrice: undefined, + description: "reasoning-model via LiteLLM proxy", + }) + }) + it("handles fallback detection with various model name formats", async () => { const mockResponse = { data: { diff --git a/src/api/providers/fetchers/litellm.ts b/src/api/providers/fetchers/litellm.ts index 093fd85888..faf7572883 100644 --- a/src/api/providers/fetchers/litellm.ts +++ b/src/api/providers/fetchers/litellm.ts @@ -52,6 +52,8 @@ export async function getLiteLLMModels(apiKey: string, baseUrl: string): Promise // litellm_params.model may have a prefix like openrouter/ supportsComputerUse, supportsPromptCache: Boolean(modelInfo.supports_prompt_caching), + supportsReasoningEffort: Boolean(modelInfo.supports_reasoning), + shouldExposeDefaultReasoningEffort: Boolean(modelInfo.supports_reasoning), 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/litellm.ts b/src/api/providers/litellm.ts index fc29f2c5f8..2124512bc7 100644 --- a/src/api/providers/litellm.ts +++ b/src/api/providers/litellm.ts @@ -4,6 +4,7 @@ import { Anthropic } from "@anthropic-ai/sdk" // Keep for type usage only import { ApiHandlerOptions, litellmDefaultModelId, litellmDefaultModelInfo } from "../../shared/api" import { ApiStream, ApiStreamUsageChunk } from "../transform/stream" import { convertToOpenAiMessages } from "../transform/openai-format" +import { getModelParams } from "../transform/model-params" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" import { RouterProvider } from "./router-provider" @@ -26,21 +27,32 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa }) } + override getModel() { + const { id, info } = super.getModel() + + const params = getModelParams({ + format: "openai", + modelId: id, + model: info, + settings: this.options, + }) + + return { id, info, ...params } + } + override async *createMessage( systemPrompt: string, messages: Anthropic.Messages.MessageParam[], metadata?: ApiHandlerCreateMessageMetadata, ): ApiStream { - const { id: modelId, info } = await this.fetchModel() + await this.fetchModel() // Ensure models are loaded + const { id: modelId, maxTokens, temperature, reasoningEffort: reasoning_effort } = this.getModel() const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [ { role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages), ] - // Required by some providers; others default to max tokens allowed - let maxTokens: number | undefined = info.maxTokens ?? undefined - const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = { model: modelId, max_tokens: maxTokens, @@ -49,10 +61,11 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa stream_options: { include_usage: true, }, + ...(reasoning_effort && { reasoning_effort }), } if (this.supportsTemperature(modelId)) { - requestOptions.temperature = this.options.modelTemperature ?? 0 + requestOptions.temperature = temperature } try { @@ -62,12 +75,27 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa for await (const chunk of completion) { const delta = chunk.choices[0]?.delta - const usage = chunk.usage as OpenAI.CompletionUsage + + // Log all available fields in delta + console.log("[LiteLLM] Delta fields:", Object.keys(delta || {})) + console.log("[LiteLLM] Full delta:", JSON.stringify(delta, null, 2)) + + // Check for any field that might contain reasoning + if (delta) { + for (const [key, value] of Object.entries(delta)) { + if (typeof value === "string" && value.length > 0 && key.includes("reason")) { + console.log(`[LiteLLM] Found potential reasoning field '${key}':`, value) + yield { type: "reasoning", text: value } + } + } + } if (delta?.content) { yield { type: "text", text: delta.content } } + const usage = chunk.usage as OpenAI.CompletionUsage + if (usage) { lastUsage = usage } @@ -91,20 +119,21 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa } async completePrompt(prompt: string): Promise { - const { id: modelId, info } = await this.fetchModel() + await this.fetchModel() // Ensure models are loaded + const { id: modelId, maxTokens, temperature, reasoningEffort: reasoning_effort } = this.getModel() try { const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = { model: modelId, messages: [{ role: "user", content: prompt }], + max_tokens: maxTokens, + ...(reasoning_effort && { reasoning_effort }), } if (this.supportsTemperature(modelId)) { - requestOptions.temperature = this.options.modelTemperature ?? 0 + requestOptions.temperature = temperature } - requestOptions.max_tokens = info.maxTokens - const response = await this.client.chat.completions.create(requestOptions) return response.choices[0]?.message.content || "" } catch (error) { diff --git a/webview-ui/src/components/settings/ThinkingBudget.tsx b/webview-ui/src/components/settings/ThinkingBudget.tsx index 456e0be17a..e52d505d13 100644 --- a/webview-ui/src/components/settings/ThinkingBudget.tsx +++ b/webview-ui/src/components/settings/ThinkingBudget.tsx @@ -1,7 +1,13 @@ import { useEffect } from "react" import { Checkbox } from "vscrui" -import { type ProviderSettings, type ModelInfo, type ReasoningEffort, reasoningEfforts } from "@roo-code/types" +import { + type ProviderSettings, + type ModelInfo, + type ReasoningEffort, + reasoningEfforts, + reasoningEffortsWithDefault, +} from "@roo-code/types" import { DEFAULT_HYBRID_REASONING_MODEL_MAX_TOKENS, DEFAULT_HYBRID_REASONING_MODEL_THINKING_TOKENS } from "@roo/api" @@ -20,6 +26,7 @@ export const ThinkingBudget = ({ apiConfiguration, setApiConfigurationField, mod const isReasoningBudgetSupported = !!modelInfo && modelInfo.supportsReasoningBudget const isReasoningBudgetRequired = !!modelInfo && modelInfo.requiredReasoningBudget const isReasoningEffortSupported = !!modelInfo && modelInfo.supportsReasoningEffort + const shouldExposeDefaultReasoningEffort = !!modelInfo && modelInfo.shouldExposeDefaultReasoningEffort const enableReasoningEffort = apiConfiguration.enableReasoningEffort const customMaxOutputTokens = apiConfiguration.modelMaxTokens || DEFAULT_HYBRID_REASONING_MODEL_MAX_TOKENS @@ -95,17 +102,23 @@ export const ThinkingBudget = ({ apiConfiguration, setApiConfigurationField, mod diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 7986c27883..2e873a4279 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Esforç de raonament del model", + "default": "Per defecte", "high": "Alt", "medium": "Mitjà", "low": "Baix" diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 3bb81837f6..b53c798979 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Modell-Denkaufwand", + "default": "Standard", "high": "Hoch", "medium": "Mittel", "low": "Niedrig" diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 752b034228..10ec7d2603 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Model Reasoning Effort", + "default": "Default", "high": "High", "medium": "Medium", "low": "Low" diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 983d2df266..49d1dd23b6 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Esfuerzo de razonamiento del modelo", + "default": "Por defecto", "high": "Alto", "medium": "Medio", "low": "Bajo" diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 24f1aa4e9d..e24a84a4b2 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Effort de raisonnement du modèle", + "default": "Par défaut", "high": "Élevé", "medium": "Moyen", "low": "Faible" diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 04476ece10..e6a2f7ae5d 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "मॉडल तर्क प्रयास", + "default": "डिफ़ॉल्ट", "high": "उच्च", "medium": "मध्यम", "low": "निम्न" diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index cbfc9cdfac..02fe26603f 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Sforzo di ragionamento del modello", + "default": "Predefinito", "high": "Alto", "medium": "Medio", "low": "Basso" diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index c8ac18fd01..03ad63eb27 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "モデル推論の労力", + "default": "デフォルト", "high": "高", "medium": "中", "low": "低" diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index ac8069a184..979d9a977b 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "모델 추론 노력", + "default": "기본값", "high": "높음", "medium": "중간", "low": "낮음" diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index c4ee8e58e3..fbdd99e3d2 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Model redeneervermogen", + "default": "Standaard", "high": "Hoog", "medium": "Middel", "low": "Laag" diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index c499976cc3..a7b004c0b6 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Wysiłek rozumowania modelu", + "default": "Domyślny", "high": "Wysoki", "medium": "Średni", "low": "Niski" diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 893e52d402..8c7d036b1d 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Esforço de raciocínio do modelo", + "default": "Padrão", "high": "Alto", "medium": "Médio", "low": "Baixo" diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 5c611d8a45..c39055549b 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Усилия по рассуждению модели", + "default": "По умолчанию", "high": "Высокие", "medium": "Средние", "low": "Низкие" diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 25ec36780f..518131c8eb 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Model Akıl Yürütme Çabası", + "default": "Varsayılan", "high": "Yüksek", "medium": "Orta", "low": "Düşük" diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 2871f73f3e..91da1dabea 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "Nỗ lực suy luận của mô hình", + "default": "Mặc định", "high": "Cao", "medium": "Trung bình", "low": "Thấp" diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 51f247fd0d..b7ebd64852 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "模型推理强度", + "default": "默认", "high": "高", "medium": "中", "low": "低" diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 595194f97c..5da3eb3ff1 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -283,6 +283,7 @@ }, "reasoningEffort": { "label": "模型推理強度", + "default": "預設", "high": "高", "medium": "中", "low": "低"