feat(claude-code): add configurable max output tokens setting (#5610)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com>
Co-authored-by: Daniel Riccio <ricciodaniel98@gmail.com>
This commit is contained in:
Hannes Rudolph 2025-07-11 20:31:50 -06:00 committed by GitHub
parent 9aa2e6ea54
commit f5dfbf1fc2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 305 additions and 232 deletions

View file

@ -80,6 +80,7 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({
const claudeCodeSchema = apiModelIdProviderModelSchema.extend({
claudeCodePath: z.string().optional(),
claudeCodeMaxOutputTokens: z.number().int().min(1).max(200000).optional(),
})
const glamaSchema = baseProviderSettingsSchema.extend({

View file

@ -4,6 +4,7 @@ import { anthropicModels } from "./anthropic.js"
// Claude Code
export type ClaudeCodeModelId = keyof typeof claudeCodeModels
export const claudeCodeDefaultModelId: ClaudeCodeModelId = "claude-sonnet-4-20250514"
export const CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS = 8000
export const claudeCodeModels = {
"claude-sonnet-4-20250514": {
...anthropicModels["claude-sonnet-4-20250514"],

View file

@ -48,6 +48,32 @@ describe("ClaudeCodeHandler", () => {
expect(model.id).toBe("claude-sonnet-4-20250514") // default model
})
test("should override maxTokens when claudeCodeMaxOutputTokens is provided", () => {
const options: ApiHandlerOptions = {
claudeCodePath: "claude",
apiModelId: "claude-sonnet-4-20250514",
claudeCodeMaxOutputTokens: 8000,
}
const handlerWithMaxTokens = new ClaudeCodeHandler(options)
const model = handlerWithMaxTokens.getModel()
expect(model.id).toBe("claude-sonnet-4-20250514")
expect(model.info.maxTokens).toBe(8000) // Should use the configured value, not the default 64000
})
test("should override maxTokens for default model when claudeCodeMaxOutputTokens is provided", () => {
const options: ApiHandlerOptions = {
claudeCodePath: "claude",
apiModelId: "invalid-model", // Will fall back to default
claudeCodeMaxOutputTokens: 16384,
}
const handlerWithMaxTokens = new ClaudeCodeHandler(options)
const model = handlerWithMaxTokens.getModel()
expect(model.id).toBe("claude-sonnet-4-20250514") // default model
expect(model.info.maxTokens).toBe(16384) // Should use the configured value
})
test("should filter messages and call runClaudeCode", async () => {
const systemPrompt = "You are a helpful assistant"
const messages = [{ role: "user" as const, content: "Hello" }]
@ -76,6 +102,43 @@ describe("ClaudeCodeHandler", () => {
messages: filteredMessages,
path: "claude",
modelId: "claude-3-5-sonnet-20241022",
maxOutputTokens: undefined, // No maxOutputTokens configured in this test
})
})
test("should pass maxOutputTokens to runClaudeCode when configured", async () => {
const options: ApiHandlerOptions = {
claudeCodePath: "claude",
apiModelId: "claude-3-5-sonnet-20241022",
claudeCodeMaxOutputTokens: 16384,
}
const handlerWithMaxTokens = new ClaudeCodeHandler(options)
const systemPrompt = "You are a helpful assistant"
const messages = [{ role: "user" as const, content: "Hello" }]
const filteredMessages = [{ role: "user" as const, content: "Hello (filtered)" }]
mockFilterMessages.mockReturnValue(filteredMessages)
// Mock empty async generator
const mockGenerator = async function* (): AsyncGenerator<ClaudeCodeMessage | string> {
// Empty generator for basic test
}
mockRunClaudeCode.mockReturnValue(mockGenerator())
const stream = handlerWithMaxTokens.createMessage(systemPrompt, messages)
// Need to start iterating to trigger the call
const iterator = stream[Symbol.asyncIterator]()
await iterator.next()
// Verify runClaudeCode was called with maxOutputTokens
expect(mockRunClaudeCode).toHaveBeenCalledWith({
systemPrompt,
messages: filteredMessages,
path: "claude",
modelId: "claude-3-5-sonnet-20241022",
maxOutputTokens: 16384,
})
})

View file

@ -1,5 +1,5 @@
import type { Anthropic } from "@anthropic-ai/sdk"
import { claudeCodeDefaultModelId, type ClaudeCodeModelId, claudeCodeModels } from "@roo-code/types"
import { claudeCodeDefaultModelId, type ClaudeCodeModelId, claudeCodeModels, type ModelInfo } from "@roo-code/types"
import { type ApiHandler } from ".."
import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream"
import { runClaudeCode } from "../../integrations/claude-code/run"
@ -25,6 +25,7 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler {
messages: filteredMessages,
path: this.options.claudeCodePath,
modelId: this.getModel().id,
maxOutputTokens: this.options.claudeCodeMaxOutputTokens,
})
// Usage is included with assistant messages,
@ -129,12 +130,26 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler {
const modelId = this.options.apiModelId
if (modelId && modelId in claudeCodeModels) {
const id = modelId as ClaudeCodeModelId
return { id, info: claudeCodeModels[id] }
const modelInfo: ModelInfo = { ...claudeCodeModels[id] }
// Override maxTokens with the configured value if provided
if (this.options.claudeCodeMaxOutputTokens !== undefined) {
modelInfo.maxTokens = this.options.claudeCodeMaxOutputTokens
}
return { id, info: modelInfo }
}
const defaultModelInfo: ModelInfo = { ...claudeCodeModels[claudeCodeDefaultModelId] }
// Override maxTokens with the configured value if provided
if (this.options.claudeCodeMaxOutputTokens !== undefined) {
defaultModelInfo.maxTokens = this.options.claudeCodeMaxOutputTokens
}
return {
id: claudeCodeDefaultModelId,
info: claudeCodeModels[claudeCodeDefaultModelId],
info: defaultModelInfo,
}
}

View file

@ -3,6 +3,7 @@ import type Anthropic from "@anthropic-ai/sdk"
import { execa } from "execa"
import { ClaudeCodeMessage } from "./types"
import readline from "readline"
import { CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS } from "@roo-code/types"
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0)
@ -20,7 +21,9 @@ type ProcessState = {
exitCode: number | null
}
export async function* runClaudeCode(options: ClaudeCodeOptions): AsyncGenerator<ClaudeCodeMessage | string> {
export async function* runClaudeCode(
options: ClaudeCodeOptions & { maxOutputTokens?: number },
): AsyncGenerator<ClaudeCodeMessage | string> {
const process = runProcess(options)
const rl = readline.createInterface({
@ -107,7 +110,13 @@ const claudeCodeTools = [
const CLAUDE_CODE_TIMEOUT = 600000 // 10 minutes
function runProcess({ systemPrompt, messages, path, modelId }: ClaudeCodeOptions) {
function runProcess({
systemPrompt,
messages,
path,
modelId,
maxOutputTokens,
}: ClaudeCodeOptions & { maxOutputTokens?: number }) {
const claudePath = path || "claude"
const args = [
@ -134,8 +143,11 @@ function runProcess({ systemPrompt, messages, path, modelId }: ClaudeCodeOptions
stderr: "pipe",
env: {
...process.env,
// The default is 32000. However, I've gotten larger responses, so we increase it unless the user specified it.
CLAUDE_CODE_MAX_OUTPUT_TOKENS: process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS || "64000",
// Use the configured value, or the environment variable, or default to CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS
CLAUDE_CODE_MAX_OUTPUT_TOKENS:
maxOutputTokens?.toString() ||
process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS ||
CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS.toString(),
},
cwd,
maxBuffer: 1024 * 1024 * 1000,

View file

@ -1,164 +1,97 @@
// npx vitest run src/shared/__tests__/api.spec.ts
import { type ModelInfo, type ProviderSettings, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types"
import { describe, test, expect } from "vitest"
import { getModelMaxOutputTokens, shouldUseReasoningBudget, shouldUseReasoningEffort } from "../api"
import type { ModelInfo, ProviderSettings } from "@roo-code/types"
import { CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types"
describe("getMaxTokensForModel", () => {
const modelId = "test"
/**
* Testing the specific fix in commit cc79178f:
* For thinking models, use apiConfig.modelMaxTokens if available,
* otherwise fall back to 8192 (not modelInfo.maxTokens)
*/
it("should return apiConfig.modelMaxTokens for thinking models when provided", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
requiredReasoningBudget: true,
maxTokens: 8000,
}
describe("getModelMaxOutputTokens", () => {
const mockModel: ModelInfo = {
maxTokens: 8192,
contextWindow: 200000,
supportsPromptCache: true,
}
test("should return claudeCodeMaxOutputTokens when using claude-code provider", () => {
const settings: ProviderSettings = {
modelMaxTokens: 4000,
apiProvider: "claude-code",
claudeCodeMaxOutputTokens: 16384,
}
expect(getModelMaxOutputTokens({ modelId, model, settings })).toBe(4000)
const result = getModelMaxOutputTokens({
modelId: "claude-3-5-sonnet-20241022",
model: mockModel,
settings,
})
expect(result).toBe(16384)
})
it("should return 16_384 for thinking models when modelMaxTokens not provided", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
requiredReasoningBudget: true,
maxTokens: 8000,
}
const settings = {}
expect(getModelMaxOutputTokens({ modelId, model, settings })).toBe(16_384)
})
it("should return 16_384 for thinking models when apiConfig is undefined", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
requiredReasoningBudget: true,
maxTokens: 8000,
}
expect(getModelMaxOutputTokens({ modelId, model, settings: undefined })).toBe(16_384)
})
it("should return modelInfo.maxTokens for non-thinking models", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
maxTokens: 8000,
}
test("should return model maxTokens when not using claude-code provider", () => {
const settings: ProviderSettings = {
modelMaxTokens: 4000,
apiProvider: "anthropic",
}
expect(getModelMaxOutputTokens({ modelId, model, settings })).toBe(8000)
const result = getModelMaxOutputTokens({
modelId: "claude-3-5-sonnet-20241022",
model: mockModel,
settings,
})
expect(result).toBe(8192)
})
it("should return 20% of context window for non-thinking models with undefined maxTokens", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
}
test("should return default CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS when claude-code provider has no custom max tokens", () => {
const settings: ProviderSettings = {
modelMaxTokens: 4000,
apiProvider: "claude-code",
// No claudeCodeMaxOutputTokens set
}
// Should return 20% of context window when maxTokens is undefined
expect(getModelMaxOutputTokens({ modelId, model, settings })).toBe(40000)
const result = getModelMaxOutputTokens({
modelId: "claude-3-5-sonnet-20241022",
model: mockModel,
settings,
})
expect(result).toBe(CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS)
})
test("should return maxTokens from modelInfo when thinking is false", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
maxTokens: 2048,
}
const settings: ProviderSettings = {
modelMaxTokens: 4096,
}
const result = getModelMaxOutputTokens({ modelId, model, settings })
expect(result).toBe(2048)
})
test("should return modelMaxTokens from apiConfig when thinking is true", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
maxTokens: 2048,
test("should handle reasoning budget models correctly", () => {
const reasoningModel: ModelInfo = {
...mockModel,
supportsReasoningBudget: true,
requiredReasoningBudget: true,
}
const settings: ProviderSettings = {
modelMaxTokens: 4096,
apiProvider: "anthropic",
enableReasoningEffort: true,
modelMaxTokens: 32000,
}
const result = getModelMaxOutputTokens({ modelId, model, settings })
expect(result).toBe(4096)
const result = getModelMaxOutputTokens({
modelId: "claude-3-7-sonnet-20250219",
model: reasoningModel,
settings,
})
expect(result).toBe(32000)
})
test("should fallback to DEFAULT_THINKING_MODEL_MAX_TOKENS when thinking is true but apiConfig.modelMaxTokens is not defined", () => {
const model: ModelInfo = {
contextWindow: 200_000,
test("should return 20% of context window when maxTokens is undefined", () => {
const modelWithoutMaxTokens: ModelInfo = {
contextWindow: 100000,
supportsPromptCache: true,
maxTokens: 2048,
requiredReasoningBudget: true,
}
const settings: ProviderSettings = {}
const result = getModelMaxOutputTokens({
modelId: "some-model",
model: modelWithoutMaxTokens,
settings: {},
})
const result = getModelMaxOutputTokens({ modelId, model, settings: undefined })
expect(result).toBe(16_384)
})
test("should handle undefined inputs gracefully", () => {
const modelInfoOnly: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
maxTokens: 2048,
}
expect(getModelMaxOutputTokens({ modelId, model: modelInfoOnly, settings: undefined })).toBe(2048)
})
test("should handle missing properties gracefully", () => {
const modelInfoWithoutMaxTokens: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
requiredReasoningBudget: true,
}
const settings: ProviderSettings = {
modelMaxTokens: 4096,
}
expect(getModelMaxOutputTokens({ modelId, model: modelInfoWithoutMaxTokens, settings })).toBe(4096)
const modelInfoWithoutThinking: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
maxTokens: 2048,
}
expect(getModelMaxOutputTokens({ modelId, model: modelInfoWithoutThinking, settings: undefined })).toBe(2048)
expect(result).toBe(20000) // 20% of 100000
})
test("should return ANTHROPIC_DEFAULT_MAX_TOKENS for Anthropic models that support reasoning budget but aren't using it", () => {
// Test case for models that support reasoning budget but enableReasoningEffort is false
const anthropicModelId = "claude-sonnet-4-20250514"
const model: ModelInfo = {
contextWindow: 200_000,
@ -168,6 +101,7 @@ describe("getMaxTokensForModel", () => {
}
const settings: ProviderSettings = {
apiProvider: "anthropic",
enableReasoningEffort: false, // Not using reasoning
}
@ -176,7 +110,6 @@ describe("getMaxTokensForModel", () => {
})
test("should return model.maxTokens for non-Anthropic models that support reasoning budget but aren't using it", () => {
// Test case for non-Anthropic models - should still use model.maxTokens
const geminiModelId = "gemini-2.5-flash-preview-04-17"
const model: ModelInfo = {
contextWindow: 1_048_576,
@ -186,16 +119,45 @@ describe("getMaxTokensForModel", () => {
}
const settings: ProviderSettings = {
apiProvider: "gemini",
enableReasoningEffort: false, // Not using reasoning
}
const result = getModelMaxOutputTokens({ modelId: geminiModelId, model, settings })
expect(result).toBe(65_535) // Should use model.maxTokens, not ANTHROPIC_DEFAULT_MAX_TOKENS
})
test("should return modelMaxTokens from settings when reasoning budget is required", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
requiredReasoningBudget: true,
maxTokens: 8000,
}
const settings: ProviderSettings = {
modelMaxTokens: 4000,
}
expect(getModelMaxOutputTokens({ modelId: "test", model, settings })).toBe(4000)
})
test("should return default 16_384 for reasoning budget models when modelMaxTokens not provided", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
requiredReasoningBudget: true,
maxTokens: 8000,
}
const settings = {}
expect(getModelMaxOutputTokens({ modelId: "test", model, settings })).toBe(16_384)
})
})
describe("shouldUseReasoningBudget", () => {
it("should return true when model has requiredReasoningBudget", () => {
test("should return true when model has requiredReasoningBudget", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -208,7 +170,7 @@ describe("shouldUseReasoningBudget", () => {
expect(shouldUseReasoningBudget({ model, settings: { enableReasoningEffort: false } })).toBe(true)
})
it("should return true when model supports reasoning budget and settings enable reasoning effort", () => {
test("should return true when model supports reasoning budget and settings enable reasoning effort", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -222,7 +184,7 @@ describe("shouldUseReasoningBudget", () => {
expect(shouldUseReasoningBudget({ model, settings })).toBe(true)
})
it("should return false when model supports reasoning budget but settings don't enable reasoning effort", () => {
test("should return false when model supports reasoning budget but settings don't enable reasoning effort", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -238,7 +200,7 @@ describe("shouldUseReasoningBudget", () => {
expect(shouldUseReasoningBudget({ model })).toBe(false)
})
it("should return false when model doesn't support reasoning budget", () => {
test("should return false when model doesn't support reasoning budget", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -251,27 +213,10 @@ describe("shouldUseReasoningBudget", () => {
expect(shouldUseReasoningBudget({ model, settings })).toBe(false)
expect(shouldUseReasoningBudget({ model })).toBe(false)
})
it("should handle undefined settings gracefully", () => {
const modelWithRequired: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
requiredReasoningBudget: true,
}
const modelWithSupported: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
supportsReasoningBudget: true,
}
expect(shouldUseReasoningBudget({ model: modelWithRequired, settings: undefined })).toBe(true)
expect(shouldUseReasoningBudget({ model: modelWithSupported, settings: undefined })).toBe(false)
})
})
describe("shouldUseReasoningEffort", () => {
it("should return true when model has reasoningEffort property", () => {
test("should return true when model has reasoningEffort property", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -284,7 +229,7 @@ describe("shouldUseReasoningEffort", () => {
expect(shouldUseReasoningEffort({ model, settings: { reasoningEffort: undefined } })).toBe(true)
})
it("should return true when model supports reasoning effort and settings provide reasoning effort", () => {
test("should return true when model supports reasoning effort and settings provide reasoning effort", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -298,7 +243,7 @@ describe("shouldUseReasoningEffort", () => {
expect(shouldUseReasoningEffort({ model, settings })).toBe(true)
})
it("should return false when model supports reasoning effort but settings don't provide reasoning effort", () => {
test("should return false when model supports reasoning effort but settings don't provide reasoning effort", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -314,7 +259,7 @@ describe("shouldUseReasoningEffort", () => {
expect(shouldUseReasoningEffort({ model })).toBe(false)
})
it("should return false when model doesn't support reasoning effort", () => {
test("should return false when model doesn't support reasoning effort", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -328,7 +273,7 @@ describe("shouldUseReasoningEffort", () => {
expect(shouldUseReasoningEffort({ model })).toBe(false)
})
it("should handle different reasoning effort values", () => {
test("should handle different reasoning effort values", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
@ -343,37 +288,4 @@ describe("shouldUseReasoningEffort", () => {
expect(shouldUseReasoningEffort({ model, settings: settingsMedium })).toBe(true)
expect(shouldUseReasoningEffort({ model, settings: settingsHigh })).toBe(true)
})
it("should handle undefined settings gracefully", () => {
const modelWithReasoning: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
reasoningEffort: "medium",
}
const modelWithSupported: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
supportsReasoningEffort: true,
}
expect(shouldUseReasoningEffort({ model: modelWithReasoning, settings: undefined })).toBe(true)
expect(shouldUseReasoningEffort({ model: modelWithSupported, settings: undefined })).toBe(false)
})
it("should prioritize model reasoningEffort over settings", () => {
const model: ModelInfo = {
contextWindow: 200_000,
supportsPromptCache: true,
supportsReasoningEffort: true,
reasoningEffort: "low",
}
const settings: ProviderSettings = {
reasoningEffort: "high",
}
// Should return true because model.reasoningEffort exists, regardless of settings
expect(shouldUseReasoningEffort({ model, settings })).toBe(true)
})
})

View file

@ -1,4 +1,9 @@
import { type ModelInfo, type ProviderSettings, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types"
import {
type ModelInfo,
type ProviderSettings,
ANTHROPIC_DEFAULT_MAX_TOKENS,
CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS,
} from "@roo-code/types"
// ApiHandlerOptions
@ -58,6 +63,12 @@ export const getModelMaxOutputTokens = ({
model: ModelInfo
settings?: ProviderSettings
}): number | undefined => {
// Check for Claude Code specific max output tokens setting
if (settings?.apiProvider === "claude-code") {
// Return the configured value or default to CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS
return settings.claudeCodeMaxOutputTokens || CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS
}
if (shouldUseReasoningBudget({ model, settings })) {
return settings?.modelMaxTokens || DEFAULT_HYBRID_REASONING_MODEL_MAX_TOKENS
}

View file

@ -2,6 +2,7 @@ import React from "react"
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
import { type ProviderSettings } from "@roo-code/types"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { Slider } from "@src/components/ui"
interface ClaudeCodeProps {
apiConfiguration: ProviderSettings
@ -16,25 +17,46 @@ export const ClaudeCode: React.FC<ClaudeCodeProps> = ({ apiConfiguration, setApi
setApiConfigurationField("claudeCodePath", element.value)
}
return (
<div>
<VSCodeTextField
value={apiConfiguration?.claudeCodePath || ""}
style={{ width: "100%", marginTop: 3 }}
type="text"
onInput={handleInputChange}
placeholder={t("settings:providers.claudeCode.placeholder")}>
{t("settings:providers.claudeCode.pathLabel")}
</VSCodeTextField>
const maxOutputTokens = apiConfiguration?.claudeCodeMaxOutputTokens || 8000
<p
style={{
fontSize: "12px",
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
{t("settings:providers.claudeCode.description")}
</p>
return (
<div className="flex flex-col gap-4">
<div>
<VSCodeTextField
value={apiConfiguration?.claudeCodePath || ""}
style={{ width: "100%", marginTop: 3 }}
type="text"
onInput={handleInputChange}
placeholder={t("settings:providers.claudeCode.placeholder")}>
{t("settings:providers.claudeCode.pathLabel")}
</VSCodeTextField>
<p
style={{
fontSize: "12px",
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
{t("settings:providers.claudeCode.description")}
</p>
</div>
<div className="flex flex-col gap-1">
<div className="font-medium">{t("settings:providers.claudeCode.maxTokensLabel")}</div>
<div className="flex items-center gap-1">
<Slider
min={8000}
max={64000}
step={1024}
value={[maxOutputTokens]}
onValueChange={([value]) => setApiConfigurationField("claudeCodeMaxOutputTokens", value)}
/>
<div className="w-16 text-sm text-center">{maxOutputTokens}</div>
</div>
<p className="text-sm text-vscode-descriptionForeground mt-1">
{t("settings:providers.claudeCode.maxTokensDescription")}
</p>
</div>
</div>
)
}

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Ruta del Codi Claude",
"description": "Ruta opcional al teu CLI de Claude Code. Per defecte, 'claude' si no s'estableix.",
"placeholder": "Per defecte: claude"
"placeholder": "Per defecte: claude",
"maxTokensLabel": "Tokens màxims de sortida",
"maxTokensDescription": "Nombre màxim de tokens de sortida per a les respostes de Claude Code. El valor per defecte és 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Claude-Code-Pfad",
"description": "Optionaler Pfad zu Ihrer Claude Code CLI. Standard ist 'claude', wenn nicht festgelegt.",
"placeholder": "Standard: claude"
"placeholder": "Standard: claude",
"maxTokensLabel": "Maximale Ausgabe-Tokens",
"maxTokensDescription": "Maximale Anzahl an Ausgabe-Tokens für Claude Code-Antworten. Standard ist 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Claude Code Path",
"description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.",
"placeholder": "Default: claude"
"placeholder": "Default: claude",
"maxTokensLabel": "Max Output Tokens",
"maxTokensDescription": "Maximum number of output tokens for Claude Code responses. Default is 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Ruta de Claude Code",
"description": "Ruta opcional a su CLI de Claude Code. Por defecto, es 'claude' si no se establece.",
"placeholder": "Por defecto: claude"
"placeholder": "Por defecto: claude",
"maxTokensLabel": "Tokens máximos de salida",
"maxTokensDescription": "Número máximo de tokens de salida para las respuestas de Claude Code. El valor predeterminado es 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Chemin du code Claude",
"description": "Chemin facultatif vers votre CLI Claude Code. La valeur par défaut est 'claude' si non défini.",
"placeholder": "Défaut : claude"
"placeholder": "Défaut : claude",
"maxTokensLabel": "Jetons de sortie max",
"maxTokensDescription": "Nombre maximum de jetons de sortie pour les réponses de Claude Code. La valeur par défaut est 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "क्लाउड कोड पथ",
"description": "आपके क्लाउड कोड सीएलआई का वैकल्पिक पथ। यदि सेट नहीं है तो डिफ़ॉल्ट 'claude' है।",
"placeholder": "डिफ़ॉल्ट: claude"
"placeholder": "डिफ़ॉल्ट: claude",
"maxTokensLabel": "अधिकतम आउटपुट टोकन",
"maxTokensDescription": "Claude Code प्रतिक्रियाओं के लिए आउटपुट टोकन की अधिकतम संख्या। डिफ़ॉल्ट 8000 है।"
}
},
"browser": {

View file

@ -377,7 +377,9 @@
"claudeCode": {
"pathLabel": "Jalur Kode Claude",
"description": "Jalur opsional ke Claude Code CLI Anda. Defaultnya adalah 'claude' jika tidak diatur.",
"placeholder": "Default: claude"
"placeholder": "Default: claude",
"maxTokensLabel": "Token Output Maks",
"maxTokensDescription": "Jumlah maksimum token output untuk respons Claude Code. Default adalah 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Percorso Claude Code",
"description": "Percorso facoltativo per la tua CLI Claude Code. Predefinito 'claude' se non impostato.",
"placeholder": "Predefinito: claude"
"placeholder": "Predefinito: claude",
"maxTokensLabel": "Token di output massimi",
"maxTokensDescription": "Numero massimo di token di output per le risposte di Claude Code. Il valore predefinito è 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "クロードコードパス",
"description": "Claude Code CLIへのオプションパス。設定されていない場合、デフォルトは「claude」です。",
"placeholder": "デフォルトclaude"
"placeholder": "デフォルトclaude",
"maxTokensLabel": "最大出力トークン",
"maxTokensDescription": "Claude Codeレスポンスの最大出力トークン数。デフォルトは8000です。"
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "클로드 코드 경로",
"description": "Claude Code CLI의 선택적 경로입니다. 설정하지 않으면 'claude'가 기본값입니다.",
"placeholder": "기본값: claude"
"placeholder": "기본값: claude",
"maxTokensLabel": "최대 출력 토큰",
"maxTokensDescription": "Claude Code 응답의 최대 출력 토큰 수. 기본값은 8000입니다."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Claude Code Pad",
"description": "Optioneel pad naar uw Claude Code CLI. Standaard 'claude' als niet ingesteld.",
"placeholder": "Standaard: claude"
"placeholder": "Standaard: claude",
"maxTokensLabel": "Max Output Tokens",
"maxTokensDescription": "Maximaal aantal output-tokens voor Claude Code-reacties. Standaard is 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Ścieżka Claude Code",
"description": "Opcjonalna ścieżka do Twojego CLI Claude Code. Domyślnie 'claude', jeśli nie ustawiono.",
"placeholder": "Domyślnie: claude"
"placeholder": "Domyślnie: claude",
"maxTokensLabel": "Maksymalna liczba tokenów wyjściowych",
"maxTokensDescription": "Maksymalna liczba tokenów wyjściowych dla odpowiedzi Claude Code. Domyślnie 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Caminho do Claude Code",
"description": "Caminho opcional para o seu Claude Code CLI. O padrão é 'claude' se não for definido.",
"placeholder": "Padrão: claude"
"placeholder": "Padrão: claude",
"maxTokensLabel": "Tokens de saída máximos",
"maxTokensDescription": "Número máximo de tokens de saída para respostas do Claude Code. O padrão é 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Путь к Claude Code",
"description": "Необязательный путь к вашему Claude Code CLI. По умолчанию используется 'claude', если не установлено.",
"placeholder": "По умолчанию: claude"
"placeholder": "По умолчанию: claude",
"maxTokensLabel": "Макс. выходных токенов",
"maxTokensDescription": "Максимальное количество выходных токенов для ответов Claude Code. По умолчанию 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Claude Code Yolu",
"description": "Claude Code CLI'nize isteğe bağlı yol. Ayarlanmazsa varsayılan olarak 'claude' kullanılır.",
"placeholder": "Varsayılan: claude"
"placeholder": "Varsayılan: claude",
"maxTokensLabel": "Maksimum Çıktı Token sayısı",
"maxTokensDescription": "Claude Code yanıtları için maksimum çıktı token sayısı. Varsayılan 8000'dir."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Đường dẫn Claude Code",
"description": "Đường dẫn tùy chọn đến Claude Code CLI của bạn. Mặc định là 'claude' nếu không được đặt.",
"placeholder": "Mặc định: claude"
"placeholder": "Mặc định: claude",
"maxTokensLabel": "Số token đầu ra tối đa",
"maxTokensDescription": "Số lượng token đầu ra tối đa cho các phản hồi của Claude Code. Mặc định là 8000."
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Claude Code 路径",
"description": "您的 Claude Code CLI 的可选路径。如果未设置,则默认为 “claude”。",
"placeholder": "默认claude"
"placeholder": "默认claude",
"maxTokensLabel": "最大输出 Token",
"maxTokensDescription": "Claude Code 响应的最大输出 Token 数量。默认为 8000。"
}
},
"browser": {

View file

@ -373,7 +373,9 @@
"claudeCode": {
"pathLabel": "Claude Code 路徑",
"description": "可選的 Claude Code CLI 路徑。如果未設定,則預設為 'claude'。",
"placeholder": "預設claude"
"placeholder": "預設claude",
"maxTokensLabel": "最大輸出 Token",
"maxTokensDescription": "Claude Code 回應的最大輸出 Token 數量。預設為 8000。"
}
},
"browser": {