From d98352b433784c02249beeccb10b7987d2a59371 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 20:20:13 -0600 Subject: [PATCH 01/16] feat: add Claude Code provider for local CLI integration - Add new provider that executes local claude CLI tool - Support streaming responses from CLI JSON output - Add configuration UI for setting CLI path - Include all necessary type definitions and models - Add English translations for new provider This allows users to use Claude models through a locally installed command-line tool instead of API endpoints. --- packages/types/src/api.ts | 4 + packages/types/src/provider-settings.ts | 7 + packages/types/src/providers/claude-code.ts | 13 ++ packages/types/src/providers/index.ts | 1 + src/api/index.ts | 3 + src/api/providers/claude-code.ts | 168 ++++++++++++++++++ src/api/providers/index.ts | 1 + src/api/retry.ts | 64 +++++++ src/api/transform/stream.ts | 8 +- src/i18n/locales/en/common.json | 9 + src/integrations/claude-code/run.ts | 44 +++++ src/integrations/claude-code/types.ts | 52 ++++++ src/shared/api.ts | 14 +- .../src/components/settings/ApiOptions.tsx | 7 + .../src/components/settings/constants.ts | 3 + .../settings/providers/ClaudeCode.tsx | 40 +++++ .../components/settings/providers/index.ts | 1 + 17 files changed, 433 insertions(+), 6 deletions(-) create mode 100644 packages/types/src/providers/claude-code.ts create mode 100644 src/api/providers/claude-code.ts create mode 100644 src/api/retry.ts create mode 100644 src/integrations/claude-code/run.ts create mode 100644 src/integrations/claude-code/types.ts create mode 100644 webview-ui/src/components/settings/providers/ClaudeCode.tsx diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index 6fb181b573..9d86bcd333 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -3,6 +3,10 @@ import type { Socket } from "net" import type { RooCodeSettings } from "./global-settings.js" import type { ProviderSettingsEntry, ProviderSettings } from "./provider-settings.js" + +// ApiHandlerOptions + +export type ApiHandlerOptions = Omit import type { ClineMessage, TokenUsage } from "./message.js" import type { ToolUsage, ToolName } from "./tool.js" import type { IpcMessage, IpcServerEvents, IsSubtask } from "./ipc.js" diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 65e3f9b5b6..609d0fefbf 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -9,6 +9,7 @@ import { codebaseIndexProviderSchema } from "./codebase-index.js" export const providerNames = [ "anthropic", + "claude-code", "glama", "openrouter", "bedrock", @@ -76,6 +77,10 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({ anthropicUseAuthToken: z.boolean().optional(), }) +const claudeCodeSchema = apiModelIdProviderModelSchema.extend({ + claudeCodePath: z.string().optional(), +}) + const glamaSchema = baseProviderSettingsSchema.extend({ glamaModelId: z.string().optional(), glamaApiKey: z.string().optional(), @@ -208,6 +213,7 @@ const defaultSchema = z.object({ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProvider", [ anthropicSchema.merge(z.object({ apiProvider: z.literal("anthropic") })), + claudeCodeSchema.merge(z.object({ apiProvider: z.literal("claude-code") })), glamaSchema.merge(z.object({ apiProvider: z.literal("glama") })), openRouterSchema.merge(z.object({ apiProvider: z.literal("openrouter") })), bedrockSchema.merge(z.object({ apiProvider: z.literal("bedrock") })), @@ -234,6 +240,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv export const providerSettingsSchema = z.object({ apiProvider: providerNamesSchema.optional(), ...anthropicSchema.shape, + ...claudeCodeSchema.shape, ...glamaSchema.shape, ...openRouterSchema.shape, ...bedrockSchema.shape, diff --git a/packages/types/src/providers/claude-code.ts b/packages/types/src/providers/claude-code.ts new file mode 100644 index 0000000000..ebf053a532 --- /dev/null +++ b/packages/types/src/providers/claude-code.ts @@ -0,0 +1,13 @@ +import type { ModelInfo } from "../model.js" +import { anthropicModels } from "./anthropic.js" + +// Claude Code +export type ClaudeCodeModelId = keyof typeof claudeCodeModels +export const claudeCodeDefaultModelId: ClaudeCodeModelId = "claude-sonnet-4-20250514" +export const claudeCodeModels = { + "claude-sonnet-4-20250514": anthropicModels["claude-sonnet-4-20250514"], + "claude-opus-4-20250514": anthropicModels["claude-opus-4-20250514"], + "claude-3-7-sonnet-20250219": anthropicModels["claude-3-7-sonnet-20250219"], + "claude-3-5-sonnet-20241022": anthropicModels["claude-3-5-sonnet-20241022"], + "claude-3-5-haiku-20241022": anthropicModels["claude-3-5-haiku-20241022"], +} as const satisfies Record diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 5f1c08041f..4a2b7f1885 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -1,6 +1,7 @@ export * from "./anthropic.js" export * from "./bedrock.js" export * from "./chutes.js" +export * from "./claude-code.js" export * from "./deepseek.js" export * from "./gemini.js" export * from "./glama.js" diff --git a/src/api/index.ts b/src/api/index.ts index 8b09bf4cf9..960209f714 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -27,6 +27,7 @@ import { GroqHandler, ChutesHandler, LiteLLMHandler, + ClaudeCodeHandler, } from "./providers" export interface SingleCompletionHandler { @@ -64,6 +65,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { switch (apiProvider) { case "anthropic": return new AnthropicHandler(options) + case "claude-code": + return new ClaudeCodeHandler(options) case "glama": return new GlamaHandler(options) case "openrouter": diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts new file mode 100644 index 0000000000..6aef469d43 --- /dev/null +++ b/src/api/providers/claude-code.ts @@ -0,0 +1,168 @@ +import type { Anthropic } from "@anthropic-ai/sdk" +import { + type ApiHandlerOptions, + claudeCodeDefaultModelId, + type ClaudeCodeModelId, + claudeCodeModels, +} from "@roo-code/types" +import { type ApiHandler } from ".." +import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream" +import { runClaudeCode } from "../../integrations/claude-code/run" +import { ClaudeCodeMessage } from "../../integrations/claude-code/types" +import { BaseProvider } from "./base-provider" + +export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { + private options: ApiHandlerOptions + + constructor(options: ApiHandlerOptions) { + super() + this.options = options + } + + override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream { + const claudeProcess = runClaudeCode({ + systemPrompt, + messages, + path: this.options.claudeCodePath, + modelId: this.getModel().id, + }) + + const dataQueue: string[] = [] + let processError = null + let errorOutput = "" + let exitCode: number | null = null + + claudeProcess.stdout.on("data", (data) => { + const output = data.toString() + const lines = output.split("\n").filter((line: string) => line.trim() !== "") + + for (const line of lines) { + dataQueue.push(line) + } + }) + + claudeProcess.stderr.on("data", (data) => { + errorOutput += data.toString() + }) + + claudeProcess.on("close", (code) => { + exitCode = code + }) + + claudeProcess.on("error", (error) => { + processError = error + }) + + // Usage is included with assistant messages, + // but cost is included in the result chunk + let usage: ApiStreamUsageChunk = { + type: "usage", + inputTokens: 0, + outputTokens: 0, + cacheReadTokens: 0, + cacheWriteTokens: 0, + } + + while (exitCode !== 0 || dataQueue.length > 0) { + if (dataQueue.length === 0) { + await new Promise((resolve) => setImmediate(resolve)) + } + + if (exitCode !== null && exitCode !== 0) { + throw new Error( + `Claude Code process exited with code ${exitCode}.${errorOutput ? ` Error output: ${errorOutput.trim()}` : ""}`, + ) + } + + const data = dataQueue.shift() + if (!data) { + continue + } + + const chunk = this.attemptParseChunk(data) + + if (!chunk) { + yield { + type: "text", + text: data || "", + } + + continue + } + + if (chunk.type === "system" && chunk.subtype === "init") { + continue + } + + if (chunk.type === "assistant" && "message" in chunk) { + const message = chunk.message + + if (message.stop_reason !== null && message.stop_reason !== "tool_use") { + const errorMessage = + message.content[0]?.text || `Claude Code stopped with reason: ${message.stop_reason}` + + if (errorMessage.includes("Invalid model name")) { + throw new Error( + errorMessage + + `\n\nAPI keys and subscription plans allow different models. Make sure the selected model is included in your plan.`, + ) + } + + throw new Error(errorMessage) + } + + for (const content of message.content) { + if (content.type === "text") { + yield { + type: "text", + text: content.text, + } + } else { + console.warn("Unsupported content type:", content.type) + } + } + + usage.inputTokens += message.usage.input_tokens + usage.outputTokens += message.usage.output_tokens + usage.cacheReadTokens = (usage.cacheReadTokens || 0) + (message.usage.cache_read_input_tokens || 0) + usage.cacheWriteTokens = + (usage.cacheWriteTokens || 0) + (message.usage.cache_creation_input_tokens || 0) + + continue + } + + if (chunk.type === "result" && "result" in chunk) { + usage.totalCost = chunk.cost_usd || 0 + + yield usage + } + + if (processError) { + throw processError + } + } + } + + getModel() { + const modelId = this.options.apiModelId + if (modelId && modelId in claudeCodeModels) { + const id = modelId as ClaudeCodeModelId + return { id, info: claudeCodeModels[id] } + } + + return { + id: claudeCodeDefaultModelId, + info: claudeCodeModels[claudeCodeDefaultModelId], + } + } + + // TOOD: Validate instead of parsing + private attemptParseChunk(data: string): ClaudeCodeMessage | null { + try { + return JSON.parse(data) + } catch (error) { + console.error("Error parsing chunk:", error) + return null + } + } +} diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index b305118188..93df5c58ff 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -2,6 +2,7 @@ export { AnthropicVertexHandler } from "./anthropic-vertex" export { AnthropicHandler } from "./anthropic" export { AwsBedrockHandler } from "./bedrock" export { ChutesHandler } from "./chutes" +export { ClaudeCodeHandler } from "./claude-code" export { DeepSeekHandler } from "./deepseek" export { FakeAIHandler } from "./fake-ai" export { GeminiHandler } from "./gemini" diff --git a/src/api/retry.ts b/src/api/retry.ts new file mode 100644 index 0000000000..3a8849e4af --- /dev/null +++ b/src/api/retry.ts @@ -0,0 +1,64 @@ +import { Anthropic } from "@anthropic-ai/sdk" +import { ApiStream, ApiStreamError } from "./transform/stream" +import delay from "delay" + +const RETRIABLE_STATUS_CODES = [408, 429, 500, 502, 503, 504] +const MAX_RETRIES = 5 +const INITIAL_DELAY_MS = 2000 + +// `withRetry` is a decorator that adds retry logic to a method that returns an async generator. +// It will retry the method if it fails with a retriable error. +// It uses exponential backoff with jitter to delay between retries. +export function withRetry ApiStream>( + options: { + maxRetries?: number + baseDelay?: number + maxDelay?: number + } = {}, +) { + const { maxRetries = MAX_RETRIES, baseDelay = INITIAL_DELAY_MS } = options + + return function ( + _target: T, + _context: ClassMethodDecoratorContext, + ): (this: unknown, ...args: Parameters) => ApiStream { + const originalMethod = _target + + return async function* (this: unknown, ...args: Parameters): ApiStream { + let lastError: Error | undefined + for (let i = 0; i < maxRetries; i++) { + try { + yield* originalMethod.apply(this, args) + return + } catch (error: any) { + lastError = error + const isRetriable = + error instanceof Anthropic.APIError && + error.status && + RETRIABLE_STATUS_CODES.includes(error.status) + + if (!isRetriable) { + throw error + } + + const exponentialBackoff = Math.pow(2, i) + const jitter = Math.random() + const delayMs = Math.min( + options.maxDelay || Infinity, + baseDelay * exponentialBackoff * (1 + jitter), + ) + + await delay(delayMs) + } + } + + const error: ApiStreamError = { + type: "error", + error: "Retries exhausted", + message: lastError!.message, + } + + yield error + } + } +} diff --git a/src/api/transform/stream.ts b/src/api/transform/stream.ts index caa69a09fe..89655a3f56 100644 --- a/src/api/transform/stream.ts +++ b/src/api/transform/stream.ts @@ -1,6 +1,12 @@ export type ApiStream = AsyncGenerator -export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk | ApiStreamReasoningChunk +export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk | ApiStreamReasoningChunk | ApiStreamError + +export interface ApiStreamError { + type: "error" + error: string + message: string +} export interface ApiStreamTextChunk { type: "text" diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 7d534d8bc3..c9c2a01a01 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -108,5 +108,14 @@ "organization_mismatch": "You must be authenticated with your organization's Roo Code Cloud account.", "verification_failed": "Unable to verify organization authentication." } + }, + "settings": { + "providers": { + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } + } } } diff --git a/src/integrations/claude-code/run.ts b/src/integrations/claude-code/run.ts new file mode 100644 index 0000000000..7cae66a2eb --- /dev/null +++ b/src/integrations/claude-code/run.ts @@ -0,0 +1,44 @@ +import * as vscode from "vscode" +import Anthropic from "@anthropic-ai/sdk" +import { execa } from "execa" + +export function runClaudeCode({ + systemPrompt, + messages, + path, + modelId, +}: { + systemPrompt: string + messages: Anthropic.Messages.MessageParam[] + path?: string + modelId?: string +}) { + const claudePath = path || "claude" + + // TODO: Is it worh using sessions? Where do we store the session ID? + const args = [ + "-p", + JSON.stringify(messages), + "--system-prompt", + systemPrompt, + "--verbose", + "--output-format", + "stream-json", + // Cline will handle recursive calls + "--max-turns", + "1", + ] + + if (modelId) { + args.push("--model", modelId) + } + + const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) + return execa(claudePath, args, { + stdin: "ignore", + stdout: "pipe", + stderr: "pipe", + env: process.env, + cwd, + }) +} diff --git a/src/integrations/claude-code/types.ts b/src/integrations/claude-code/types.ts new file mode 100644 index 0000000000..8b0c977808 --- /dev/null +++ b/src/integrations/claude-code/types.ts @@ -0,0 +1,52 @@ +type InitMessage = { + type: "system" + subtype: "init" + session_id: string + tools: string[] + mcp_servers: string[] +} + +type ClaudeCodeContent = { + type: "text" + text: string +} + +type AssistantMessage = { + type: "assistant" + message: { + id: string + type: "message" + role: "assistant" + model: string + content: ClaudeCodeContent[] + stop_reason: null + stop_sequence: null + usage: { + input_tokens: number + cache_creation_input_tokens?: number + cache_read_input_tokens?: number + output_tokens: number + service_tier: "standard" + } + } + session_id: string +} + +type ErrorMessage = { + type: "error" +} + +type ResultMessage = { + type: "result" + subtype: "success" + cost_usd: number + is_error: boolean + duration_ms: number + duration_api_ms: number + num_turns: number + result: string + total_cost: number + session_id: string +} + +export type ClaudeCodeMessage = InitMessage | AssistantMessage | ErrorMessage | ResultMessage diff --git a/src/shared/api.ts b/src/shared/api.ts index 8ad8828658..aa96d11cc5 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -1,8 +1,12 @@ -import { type ModelInfo, type ProviderSettings, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types" - -// ApiHandlerOptions - -export type ApiHandlerOptions = Omit +import { + type ModelInfo, + type ProviderSettings, + ANTHROPIC_DEFAULT_MAX_TOKENS, + type ApiHandlerOptions, +} from "@roo-code/types" + +// Re-export ApiHandlerOptions for backward compatibility +export type { ApiHandlerOptions } // RouterName diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index c55999efbd..aff2be9b26 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -13,6 +13,7 @@ import { litellmDefaultModelId, openAiNativeDefaultModelId, anthropicDefaultModelId, + claudeCodeDefaultModelId, geminiDefaultModelId, deepSeekDefaultModelId, mistralDefaultModelId, @@ -36,6 +37,7 @@ import { Anthropic, Bedrock, Chutes, + ClaudeCode, DeepSeek, Gemini, Glama, @@ -254,6 +256,7 @@ const ApiOptions = ({ requesty: { field: "requestyModelId", default: requestyDefaultModelId }, litellm: { field: "litellmModelId", default: litellmDefaultModelId }, anthropic: { field: "apiModelId", default: anthropicDefaultModelId }, + "claude-code": { field: "apiModelId", default: claudeCodeDefaultModelId }, "openai-native": { field: "apiModelId", default: openAiNativeDefaultModelId }, gemini: { field: "apiModelId", default: geminiDefaultModelId }, deepseek: { field: "apiModelId", default: deepSeekDefaultModelId }, @@ -383,6 +386,10 @@ const ApiOptions = ({ )} + {selectedProvider === "claude-code" && ( + + )} + {selectedProvider === "openai-native" && ( )} diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index 5b808643e5..bbee8f990d 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -3,6 +3,7 @@ import { type ModelInfo, anthropicModels, bedrockModels, + claudeCodeModels, deepSeekModels, geminiModels, mistralModels, @@ -15,6 +16,7 @@ import { export const MODELS_BY_PROVIDER: Partial>> = { anthropic: anthropicModels, + "claude-code": claudeCodeModels, bedrock: bedrockModels, deepseek: deepSeekModels, gemini: geminiModels, @@ -29,6 +31,7 @@ export const MODELS_BY_PROVIDER: Partial void +} + +export const ClaudeCode: React.FC = ({ apiConfiguration, setApiConfigurationField }) => { + const { t } = useAppTranslation() + + const handleInputChange = (e: Event | React.FormEvent) => { + const element = e.target as HTMLInputElement + setApiConfigurationField("claudeCodePath", element.value) + } + + return ( +
+ + {t("settings:providers.claudeCode.pathLabel")} + + +

+ {t("settings:providers.claudeCode.description")} +

+
+ ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index b244fb515c..b195607430 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -1,6 +1,7 @@ export { Anthropic } from "./Anthropic" export { Bedrock } from "./Bedrock" export { Chutes } from "./Chutes" +export { ClaudeCode } from "./ClaudeCode" export { DeepSeek } from "./DeepSeek" export { Gemini } from "./Gemini" export { Glama } from "./Glama" From b02cd43602fcb136d58b1cd1120b090d1b7c038f Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Wed, 18 Jun 2025 20:21:52 -0600 Subject: [PATCH 02/16] Update src/api/providers/claude-code.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/api/providers/claude-code.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts index 6aef469d43..f88ed56b61 100644 --- a/src/api/providers/claude-code.ts +++ b/src/api/providers/claude-code.ts @@ -156,7 +156,7 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { } } - // TOOD: Validate instead of parsing + // TODO: Validate instead of parsing private attemptParseChunk(data: string): ClaudeCodeMessage | null { try { return JSON.parse(data) From 52fca05a58b29b21a70b2b6bac468dfa6ee55600 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 20:30:12 -0600 Subject: [PATCH 03/16] feat: add Claude Code translations for all supported languages - Added translations for Claude Code provider in all locale files - Includes provider name and path configuration label - Maintains consistency across all supported languages --- src/i18n/locales/ca/common.json | 7 ++++++- src/i18n/locales/de/common.json | 7 ++++++- src/i18n/locales/es/common.json | 7 ++++++- src/i18n/locales/fr/common.json | 7 ++++++- src/i18n/locales/hi/common.json | 7 ++++++- src/i18n/locales/id/common.json | 11 +++++++++++ src/i18n/locales/it/common.json | 7 ++++++- src/i18n/locales/ja/common.json | 7 ++++++- src/i18n/locales/ko/common.json | 7 ++++++- src/i18n/locales/nl/common.json | 11 +++++++++++ src/i18n/locales/pl/common.json | 7 ++++++- src/i18n/locales/pt-BR/common.json | 7 ++++++- src/i18n/locales/ru/common.json | 7 ++++++- src/i18n/locales/tr/common.json | 7 ++++++- src/i18n/locales/vi/common.json | 7 ++++++- src/i18n/locales/zh-CN/common.json | 7 ++++++- src/i18n/locales/zh-TW/common.json | 7 ++++++- 17 files changed, 112 insertions(+), 15 deletions(-) diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 8fdc1276cf..372776277c 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Clau API de Groq", - "getGroqApiKey": "Obté la clau API de Groq" + "getGroqApiKey": "Obté la clau API de Groq", + "claudeCode": { + "pathLabel": "Ruta de Claude Code", + "description": "Ruta opcional a la teva CLI de Claude Code. Per defecte 'claude' si no s'estableix.", + "placeholder": "Per defecte: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index e52de53868..5db0b98d5e 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Groq API-Schlüssel", - "getGroqApiKey": "Groq API-Schlüssel erhalten" + "getGroqApiKey": "Groq API-Schlüssel erhalten", + "claudeCode": { + "pathLabel": "Claude Code Pfad", + "description": "Optionaler Pfad zu deiner Claude Code CLI. Standardmäßig 'claude', falls nicht festgelegt.", + "placeholder": "Standard: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 62634f065b..cef69d0722 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Clave API de Groq", - "getGroqApiKey": "Obtener clave API de Groq" + "getGroqApiKey": "Obtener clave API de Groq", + "claudeCode": { + "pathLabel": "Ruta de Claude Code", + "description": "Ruta opcional a tu CLI de Claude Code. Por defecto 'claude' si no se establece.", + "placeholder": "Por defecto: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 811be35894..7be1a71b4b 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Clé API Groq", - "getGroqApiKey": "Obtenir la clé API Groq" + "getGroqApiKey": "Obtenir la clé API Groq", + "claudeCode": { + "pathLabel": "Chemin de Claude Code", + "description": "Chemin optionnel vers votre CLI Claude Code. Par défaut 'claude' si non défini.", + "placeholder": "Par défaut : claude" + } } }, "mdm": { diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index bbc5558afe..844ea493b6 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "ग्रोक एपीआई कुंजी", - "getGroqApiKey": "ग्रोक एपीआई कुंजी प्राप्त करें" + "getGroqApiKey": "ग्रोक एपीआई कुंजी प्राप्त करें", + "claudeCode": { + "pathLabel": "क्लाउड कोड पाथ", + "description": "आपके क्लाउड कोड CLI का वैकल्पिक पाथ। सेट न होने पर डिफ़ॉल्ट रूप से 'claude'。", + "placeholder": "डिफ़ॉल्ट: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index 4c459324b1..2f109d6913 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -102,6 +102,17 @@ "task_prompt": "Apa yang harus Roo lakukan?", "task_placeholder": "Ketik tugas kamu di sini" }, + "settings": { + "providers": { + "groqApiKey": "Kunci API Groq", + "getGroqApiKey": "Dapatkan Kunci API Groq", + "claudeCode": { + "pathLabel": "Jalur Claude Code", + "description": "Jalur opsional ke CLI Claude Code Anda. Defaultnya 'claude' jika tidak diatur.", + "placeholder": "Default: claude" + } + } + }, "mdm": { "errors": { "cloud_auth_required": "Organisasi kamu memerlukan autentikasi Roo Code Cloud. Silakan masuk untuk melanjutkan.", diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index 55eb562dfe..2e7837d98e 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Chiave API Groq", - "getGroqApiKey": "Ottieni chiave API Groq" + "getGroqApiKey": "Ottieni chiave API Groq", + "claudeCode": { + "pathLabel": "Percorso Claude Code", + "description": "Percorso opzionale alla tua CLI Claude Code. Predefinito 'claude' se non impostato.", + "placeholder": "Predefinito: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 965ba73bca..c2daae02fe 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Groq APIキー", - "getGroqApiKey": "Groq APIキーを取得" + "getGroqApiKey": "Groq APIキーを取得", + "claudeCode": { + "pathLabel": "Claude Code パス", + "description": "Claude Code CLI へのオプションのパス。設定されていない場合は、デフォルトで「claude」になります。", + "placeholder": "デフォルト: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 670326b851..308be2c9f2 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Groq API 키", - "getGroqApiKey": "Groq API 키 받기" + "getGroqApiKey": "Groq API 키 받기", + "claudeCode": { + "pathLabel": "Claude Code 경로", + "description": "Claude Code CLI의 선택적 경로입니다. 설정되지 않은 경우 기본값은 'claude'입니다.", + "placeholder": "기본값: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index 7a97a6b1bc..ad304387df 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -102,6 +102,17 @@ "task_prompt": "Wat moet Roo doen?", "task_placeholder": "Typ hier je taak" }, + "settings": { + "providers": { + "groqApiKey": "Groq API-sleutel", + "getGroqApiKey": "Groq API-sleutel ophalen", + "claudeCode": { + "pathLabel": "Claude Code Pad", + "description": "Optioneel pad naar je Claude Code CLI. Standaard 'claude' indien niet ingesteld.", + "placeholder": "Standaard: claude" + } + } + }, "mdm": { "errors": { "cloud_auth_required": "Je organisatie vereist Roo Code Cloud-authenticatie. Log in om door te gaan.", diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 87293db303..f75ce21796 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Klucz API Groq", - "getGroqApiKey": "Uzyskaj klucz API Groq" + "getGroqApiKey": "Uzyskaj klucz API Groq", + "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" + } } }, "mdm": { diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index e2847d590d..0eb7d3ff41 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Chave de API Groq", - "getGroqApiKey": "Obter chave de API Groq" + "getGroqApiKey": "Obter chave de API Groq", + "claudeCode": { + "pathLabel": "Caminho do Claude Code", + "description": "Caminho opcional para sua CLI do Claude Code. Padrão 'claude' se não for definido.", + "placeholder": "Padrão: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 9d5f29a44a..9a5fea397a 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Ключ API Groq", - "getGroqApiKey": "Получить ключ API Groq" + "getGroqApiKey": "Получить ключ API Groq", + "claudeCode": { + "pathLabel": "Путь к Claude Code", + "description": "Необязательный путь к вашему CLI Claude Code. По умолчанию 'claude', если не установлено.", + "placeholder": "По умолчанию: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 893117222a..aa0ab6cf86 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Groq API Anahtarı", - "getGroqApiKey": "Groq API Anahtarı Al" + "getGroqApiKey": "Groq API Anahtarı Al", + "claudeCode": { + "pathLabel": "Claude Code Yolu", + "description": "Claude Code CLI'nizin isteğe bağlı yolu. Ayarlanmazsa varsayılan olarak 'claude' olur.", + "placeholder": "Varsayılan: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index cc8a22f8a2..4879df0095 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Khóa API Groq", - "getGroqApiKey": "Lấy khóa API Groq" + "getGroqApiKey": "Lấy khóa API Groq", + "claudeCode": { + "pathLabel": "Đường dẫn Claude Code", + "description": "Đường dẫn tùy chọn đến CLI Claude Code của bạn. Mặc định là 'claude' nếu không được đặt.", + "placeholder": "Mặc định: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index b8e2307b85..2e34561936 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -110,7 +110,12 @@ "settings": { "providers": { "groqApiKey": "Groq API 密钥", - "getGroqApiKey": "获取 Groq API 密钥" + "getGroqApiKey": "获取 Groq API 密钥", + "claudeCode": { + "pathLabel": "Claude Code 路径", + "description": "Claude Code CLI 的可选路径。如果未设置,默认为 'claude'。", + "placeholder": "默认: claude" + } } }, "mdm": { diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 57e065a7f7..168d24e5c5 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -105,7 +105,12 @@ "settings": { "providers": { "groqApiKey": "Groq API 金鑰", - "getGroqApiKey": "取得 Groq API 金鑰" + "getGroqApiKey": "取得 Groq API 金鑰", + "claudeCode": { + "pathLabel": "Claude Code 路徑", + "description": "Claude Code CLI 的選用路徑。如果未設定,預設為 'claude'。", + "placeholder": "預設: claude" + } } }, "mdm": { From ff85ebcd56e3a2f59a6d2abf566ca6b89dca7b66 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 20:34:28 -0600 Subject: [PATCH 04/16] fix: remove unused retry.ts file to resolve knip CI failure --- src/api/retry.ts | 64 ------------------------------------------------ 1 file changed, 64 deletions(-) delete mode 100644 src/api/retry.ts diff --git a/src/api/retry.ts b/src/api/retry.ts deleted file mode 100644 index 3a8849e4af..0000000000 --- a/src/api/retry.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Anthropic } from "@anthropic-ai/sdk" -import { ApiStream, ApiStreamError } from "./transform/stream" -import delay from "delay" - -const RETRIABLE_STATUS_CODES = [408, 429, 500, 502, 503, 504] -const MAX_RETRIES = 5 -const INITIAL_DELAY_MS = 2000 - -// `withRetry` is a decorator that adds retry logic to a method that returns an async generator. -// It will retry the method if it fails with a retriable error. -// It uses exponential backoff with jitter to delay between retries. -export function withRetry ApiStream>( - options: { - maxRetries?: number - baseDelay?: number - maxDelay?: number - } = {}, -) { - const { maxRetries = MAX_RETRIES, baseDelay = INITIAL_DELAY_MS } = options - - return function ( - _target: T, - _context: ClassMethodDecoratorContext, - ): (this: unknown, ...args: Parameters) => ApiStream { - const originalMethod = _target - - return async function* (this: unknown, ...args: Parameters): ApiStream { - let lastError: Error | undefined - for (let i = 0; i < maxRetries; i++) { - try { - yield* originalMethod.apply(this, args) - return - } catch (error: any) { - lastError = error - const isRetriable = - error instanceof Anthropic.APIError && - error.status && - RETRIABLE_STATUS_CODES.includes(error.status) - - if (!isRetriable) { - throw error - } - - const exponentialBackoff = Math.pow(2, i) - const jitter = Math.random() - const delayMs = Math.min( - options.maxDelay || Infinity, - baseDelay * exponentialBackoff * (1 + jitter), - ) - - await delay(delayMs) - } - } - - const error: ApiStreamError = { - type: "error", - error: "Retries exhausted", - message: lastError!.message, - } - - yield error - } - } -} From 0e2306bfaa1d4cba4a0715c08632a866c219d797 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 20:43:05 -0600 Subject: [PATCH 05/16] fix: calculate cost for Claude Code provider when CLI doesn't provide it - Use cost_usd from CLI response when available - Fall back to calculating cost based on token usage and model pricing - Ensures consistent cost reporting across all providers --- src/api/providers/claude-code.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts index f88ed56b61..6bf857b1fa 100644 --- a/src/api/providers/claude-code.ts +++ b/src/api/providers/claude-code.ts @@ -10,6 +10,7 @@ import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream" import { runClaudeCode } from "../../integrations/claude-code/run" import { ClaudeCodeMessage } from "../../integrations/claude-code/types" import { BaseProvider } from "./base-provider" +import { calculateApiCostAnthropic } from "../../shared/cost" export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { private options: ApiHandlerOptions @@ -132,7 +133,20 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { } if (chunk.type === "result" && "result" in chunk) { - usage.totalCost = chunk.cost_usd || 0 + // Use the cost from the CLI if available, otherwise calculate it + if (chunk.cost_usd !== undefined && chunk.cost_usd !== null) { + usage.totalCost = chunk.cost_usd + } else { + // Calculate cost based on token usage and model pricing + const modelInfo = this.getModel().info + usage.totalCost = calculateApiCostAnthropic( + modelInfo, + usage.inputTokens, + usage.outputTokens, + usage.cacheWriteTokens, + usage.cacheReadTokens, + ) + } yield usage } From 1020c629ae445473965c1c95b6285f6a287fe17e Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 20:44:44 -0600 Subject: [PATCH 06/16] fix: revert cost calculation for Claude Code provider - Only use cost_usd from CLI response when provided - Default to 0 when CLI doesn't provide cost (e.g., subscription users) - Don't calculate cost based on token usage as it may not apply to all users --- src/api/providers/claude-code.ts | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts index 6bf857b1fa..c770cd6bdd 100644 --- a/src/api/providers/claude-code.ts +++ b/src/api/providers/claude-code.ts @@ -10,7 +10,6 @@ import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream" import { runClaudeCode } from "../../integrations/claude-code/run" import { ClaudeCodeMessage } from "../../integrations/claude-code/types" import { BaseProvider } from "./base-provider" -import { calculateApiCostAnthropic } from "../../shared/cost" export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { private options: ApiHandlerOptions @@ -133,20 +132,9 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { } if (chunk.type === "result" && "result" in chunk) { - // Use the cost from the CLI if available, otherwise calculate it - if (chunk.cost_usd !== undefined && chunk.cost_usd !== null) { - usage.totalCost = chunk.cost_usd - } else { - // Calculate cost based on token usage and model pricing - const modelInfo = this.getModel().info - usage.totalCost = calculateApiCostAnthropic( - modelInfo, - usage.inputTokens, - usage.outputTokens, - usage.cacheWriteTokens, - usage.cacheReadTokens, - ) - } + // Only use the cost from the CLI if provided + // Don't calculate cost as it may be $0 for subscription users + usage.totalCost = chunk.cost_usd ?? 0 yield usage } From a8711a4b0c5f09bef4c40161814253d3b9c75396 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 22:12:54 -0600 Subject: [PATCH 07/16] fix(i18n): correct claude code provider translations --- src/i18n/locales/en/common.json | 9 --------- webview-ui/src/i18n/locales/ca/settings.json | 7 ++++++- webview-ui/src/i18n/locales/de/settings.json | 7 ++++++- webview-ui/src/i18n/locales/en/settings.json | 7 ++++++- webview-ui/src/i18n/locales/es/settings.json | 7 ++++++- webview-ui/src/i18n/locales/fr/settings.json | 7 ++++++- webview-ui/src/i18n/locales/hi/settings.json | 7 ++++++- webview-ui/src/i18n/locales/id/settings.json | 7 ++++++- webview-ui/src/i18n/locales/it/settings.json | 7 ++++++- webview-ui/src/i18n/locales/ja/settings.json | 7 ++++++- webview-ui/src/i18n/locales/ko/settings.json | 7 ++++++- webview-ui/src/i18n/locales/nl/settings.json | 7 ++++++- webview-ui/src/i18n/locales/pl/settings.json | 7 ++++++- webview-ui/src/i18n/locales/pt-BR/settings.json | 7 ++++++- webview-ui/src/i18n/locales/ru/settings.json | 7 ++++++- webview-ui/src/i18n/locales/tr/settings.json | 7 ++++++- webview-ui/src/i18n/locales/vi/settings.json | 7 ++++++- webview-ui/src/i18n/locales/zh-CN/settings.json | 7 ++++++- webview-ui/src/i18n/locales/zh-TW/settings.json | 7 ++++++- 19 files changed, 108 insertions(+), 27 deletions(-) diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index c9c2a01a01..7d534d8bc3 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -108,14 +108,5 @@ "organization_mismatch": "You must be authenticated with your organization's Roo Code Cloud account.", "verification_failed": "Unable to verify organization authentication." } - }, - "settings": { - "providers": { - "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" - } - } } } diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index d72c7455fe..b2a143109e 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -303,7 +303,12 @@ "medium": "Mitjà", "low": "Baix" }, - "setReasoningLevel": "Activa l'esforç de raonament" + "setReasoningLevel": "Activa l'esforç de raonament", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 7aacb054e2..549ccbb0d7 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -303,7 +303,12 @@ "medium": "Mittel", "low": "Niedrig" }, - "setReasoningLevel": "Denkaufwand aktivieren" + "setReasoningLevel": "Denkaufwand aktivieren", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 690fea5026..85e7487c0c 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -303,7 +303,12 @@ "medium": "Medium", "low": "Low" }, - "setReasoningLevel": "Enable Reasoning Effort" + "setReasoningLevel": "Enable Reasoning Effort", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 9b2e239cf3..91b0473b92 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -303,7 +303,12 @@ "medium": "Medio", "low": "Bajo" }, - "setReasoningLevel": "Habilitar esfuerzo de razonamiento" + "setReasoningLevel": "Habilitar esfuerzo de razonamiento", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 2ac2efcc00..fa14906cc8 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -303,7 +303,12 @@ "medium": "Moyen", "low": "Faible" }, - "setReasoningLevel": "Activer l'effort de raisonnement" + "setReasoningLevel": "Activer l'effort de raisonnement", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 87628e5550..d298cfb736 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -303,7 +303,12 @@ "medium": "मध्यम", "low": "निम्न" }, - "setReasoningLevel": "तर्क प्रयास सक्षम करें" + "setReasoningLevel": "तर्क प्रयास सक्षम करें", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 1a4005446c..d04043f681 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -307,7 +307,12 @@ "medium": "Sedang", "low": "Rendah" }, - "setReasoningLevel": "Aktifkan Upaya Reasoning" + "setReasoningLevel": "Aktifkan Upaya Reasoning", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 515cbe8ec7..0d43514841 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -303,7 +303,12 @@ "medium": "Medio", "low": "Basso" }, - "setReasoningLevel": "Abilita sforzo di ragionamento" + "setReasoningLevel": "Abilita sforzo di ragionamento", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 3d3e53d6cd..04f8326daa 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -303,7 +303,12 @@ "medium": "中", "low": "低" }, - "setReasoningLevel": "推論労力を有効にする" + "setReasoningLevel": "推論労力を有効にする", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index eb0417ba76..6d5c50d0c4 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -303,7 +303,12 @@ "medium": "중간", "low": "낮음" }, - "setReasoningLevel": "추론 노력 활성화" + "setReasoningLevel": "추론 노력 활성화", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index d94ad5480e..6640a27ff3 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -303,7 +303,12 @@ "medium": "Middel", "low": "Laag" }, - "setReasoningLevel": "Redeneervermogen inschakelen" + "setReasoningLevel": "Redeneervermogen inschakelen", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 8b900ae0d4..f15181ba83 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -303,7 +303,12 @@ "medium": "Średni", "low": "Niski" }, - "setReasoningLevel": "Włącz wysiłek rozumowania" + "setReasoningLevel": "Włącz wysiłek rozumowania", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 9d1884efa9..e3039452e5 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -303,7 +303,12 @@ "medium": "Médio", "low": "Baixo" }, - "setReasoningLevel": "Habilitar esforço de raciocínio" + "setReasoningLevel": "Habilitar esforço de raciocínio", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index c6a9bca2d6..fd7df437d6 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -303,7 +303,12 @@ "medium": "Средние", "low": "Низкие" }, - "setReasoningLevel": "Включить усилие рассуждения" + "setReasoningLevel": "Включить усилие рассуждения", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 6f42914336..8005f20a83 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -303,7 +303,12 @@ "medium": "Orta", "low": "Düşük" }, - "setReasoningLevel": "Akıl Yürütme Çabasını Etkinleştir" + "setReasoningLevel": "Akıl Yürütme Çabasını Etkinleştir", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index b728ac1766..05a27e7605 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -303,7 +303,12 @@ "medium": "Trung bình", "low": "Thấp" }, - "setReasoningLevel": "Kích hoạt nỗ lực suy luận" + "setReasoningLevel": "Kích hoạt nỗ lực suy luận", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index f02923e14f..276d973ceb 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -303,7 +303,12 @@ "medium": "中", "low": "低" }, - "setReasoningLevel": "启用推理工作量" + "setReasoningLevel": "启用推理工作量", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index e8b0d2d3cf..14baf85415 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -303,7 +303,12 @@ "medium": "中", "low": "低" }, - "setReasoningLevel": "啟用推理工作量" + "setReasoningLevel": "啟用推理工作量", + "claudeCode": { + "pathLabel": "Claude Code Path", + "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "placeholder": "Default: claude" + } }, "browser": { "enable": { From c6b226c41dd9142d2091046a65e3e73a365fac92 Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 22:20:46 -0600 Subject: [PATCH 08/16] fix(i18n): add simplified chinese translations for claude code --- webview-ui/src/i18n/locales/zh-CN/settings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 276d973ceb..8978ff3e9c 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "启用推理工作量", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "Claude Code 路径", + "description": "您的 Claude Code CLI 的可选路径。如果未设置,则默认为 “claude”。", + "placeholder": "默认:claude" } }, "browser": { From b0ab355431cc3f024824c36f359c0b9dd298273a Mon Sep 17 00:00:00 2001 From: hannesrudolph Date: Wed, 18 Jun 2025 22:23:08 -0600 Subject: [PATCH 09/16] fix(i18n): translate claude code provider settings --- webview-ui/src/i18n/locales/ca/settings.json | 6 +++--- webview-ui/src/i18n/locales/de/settings.json | 6 +++--- webview-ui/src/i18n/locales/es/settings.json | 6 +++--- webview-ui/src/i18n/locales/fr/settings.json | 6 +++--- webview-ui/src/i18n/locales/hi/settings.json | 6 +++--- webview-ui/src/i18n/locales/id/settings.json | 4 ++-- webview-ui/src/i18n/locales/it/settings.json | 6 +++--- webview-ui/src/i18n/locales/ja/settings.json | 6 +++--- webview-ui/src/i18n/locales/ko/settings.json | 6 +++--- webview-ui/src/i18n/locales/nl/settings.json | 6 +++--- webview-ui/src/i18n/locales/pl/settings.json | 6 +++--- webview-ui/src/i18n/locales/pt-BR/settings.json | 6 +++--- webview-ui/src/i18n/locales/ru/settings.json | 6 +++--- webview-ui/src/i18n/locales/tr/settings.json | 6 +++--- webview-ui/src/i18n/locales/vi/settings.json | 6 +++--- webview-ui/src/i18n/locales/zh-TW/settings.json | 6 +++--- 16 files changed, 47 insertions(+), 47 deletions(-) diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index b2a143109e..a7cf42633f 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Activa l'esforç de raonament", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "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" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 549ccbb0d7..d5ccff3084 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Denkaufwand aktivieren", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "Claude-Code-Pfad", + "description": "Optionaler Pfad zu Ihrer Claude Code CLI. Standard ist 'claude', wenn nicht festgelegt.", + "placeholder": "Standard: claude" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 91b0473b92..035ccf5628 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Habilitar esfuerzo de razonamiento", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "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" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index fa14906cc8..fb0b47e0b3 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Activer l'effort de raisonnement", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "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" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index d298cfb736..883a84e982 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "तर्क प्रयास सक्षम करें", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "क्लाउड कोड पथ", + "description": "आपके क्लाउड कोड सीएलआई का वैकल्पिक पथ। यदि सेट नहीं है तो डिफ़ॉल्ट 'claude' है।", + "placeholder": "डिफ़ॉल्ट: claude" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index d04043f681..e95a415c6f 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -309,8 +309,8 @@ }, "setReasoningLevel": "Aktifkan Upaya Reasoning", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", + "pathLabel": "Jalur Kode Claude", + "description": "Jalur opsional ke Claude Code CLI Anda. Defaultnya adalah 'claude' jika tidak diatur.", "placeholder": "Default: claude" } }, diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 0d43514841..927bca66ee 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Abilita sforzo di ragionamento", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "Percorso Claude Code", + "description": "Percorso facoltativo per la tua CLI Claude Code. Predefinito 'claude' se non impostato.", + "placeholder": "Predefinito: claude" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 04f8326daa..2ca40dd91d 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "推論労力を有効にする", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "クロードコードパス", + "description": "Claude Code CLIへのオプションパス。設定されていない場合、デフォルトは「claude」です。", + "placeholder": "デフォルト:claude" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 6d5c50d0c4..4cce3ad754 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "추론 노력 활성화", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "클로드 코드 경로", + "description": "Claude Code CLI의 선택적 경로입니다. 설정하지 않으면 'claude'가 기본값입니다.", + "placeholder": "기본값: claude" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 6640a27ff3..95bd3ac762 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Redeneervermogen inschakelen", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "Claude Code Pad", + "description": "Optioneel pad naar uw Claude Code CLI. Standaard 'claude' als niet ingesteld.", + "placeholder": "Standaard: claude" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index f15181ba83..bb245d80ba 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Włącz wysiłek rozumowania", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "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" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index e3039452e5..96e7dac362 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Habilitar esforço de raciocínio", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "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" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index fd7df437d6..8508fea509 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Включить усилие рассуждения", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "Путь к Claude Code", + "description": "Необязательный путь к вашему Claude Code CLI. По умолчанию используется 'claude', если не установлено.", + "placeholder": "По умолчанию: claude" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 8005f20a83..5e3db268fc 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Akıl Yürütme Çabasını Etkinleştir", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "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" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 05a27e7605..0960c30a38 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "Kích hoạt nỗ lực suy luận", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "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" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 14baf85415..5e3ec47007 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -305,9 +305,9 @@ }, "setReasoningLevel": "啟用推理工作量", "claudeCode": { - "pathLabel": "Claude Code Path", - "description": "Optional path to your Claude Code CLI. Defaults to 'claude' if not set.", - "placeholder": "Default: claude" + "pathLabel": "Claude Code 路徑", + "description": "可選的 Claude Code CLI 路徑。如果未設定,則預設為 'claude'。", + "placeholder": "預設:claude" } }, "browser": { From c4370533416b68eeaf2c6d8194fc12a25e7e6b68 Mon Sep 17 00:00:00 2001 From: Daniel <57051444+daniel-lxs@users.noreply.github.com> Date: Fri, 20 Jun 2025 12:43:53 -0500 Subject: [PATCH 10/16] Update src/integrations/claude-code/types.ts --- src/integrations/claude-code/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integrations/claude-code/types.ts b/src/integrations/claude-code/types.ts index 8b0c977808..abac758182 100644 --- a/src/integrations/claude-code/types.ts +++ b/src/integrations/claude-code/types.ts @@ -19,7 +19,7 @@ type AssistantMessage = { role: "assistant" model: string content: ClaudeCodeContent[] - stop_reason: null + stop_reason: string | null stop_sequence: null usage: { input_tokens: number From 7dd9357aaf7458d73ffd70f2a1cc614251f399e1 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Fri, 20 Jun 2025 14:16:44 -0500 Subject: [PATCH 11/16] fix(i18n): add error messages for Claude Code process handling in multiple languages --- src/api/providers/claude-code.ts | 14 +++++++------- src/i18n/locales/ca/common.json | 8 +++++++- src/i18n/locales/de/common.json | 8 +++++++- src/i18n/locales/en/common.json | 8 +++++++- src/i18n/locales/es/common.json | 8 +++++++- src/i18n/locales/fr/common.json | 8 +++++++- src/i18n/locales/hi/common.json | 8 +++++++- src/i18n/locales/id/common.json | 8 +++++++- src/i18n/locales/it/common.json | 8 +++++++- src/i18n/locales/ja/common.json | 8 +++++++- src/i18n/locales/ko/common.json | 8 +++++++- src/i18n/locales/nl/common.json | 8 +++++++- src/i18n/locales/pl/common.json | 8 +++++++- src/i18n/locales/pt-BR/common.json | 8 +++++++- src/i18n/locales/ru/common.json | 8 +++++++- src/i18n/locales/tr/common.json | 8 +++++++- src/i18n/locales/vi/common.json | 8 +++++++- src/i18n/locales/zh-CN/common.json | 8 +++++++- src/i18n/locales/zh-TW/common.json | 8 +++++++- 19 files changed, 133 insertions(+), 25 deletions(-) diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts index c770cd6bdd..e32dd9752f 100644 --- a/src/api/providers/claude-code.ts +++ b/src/api/providers/claude-code.ts @@ -10,6 +10,7 @@ import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream" import { runClaudeCode } from "../../integrations/claude-code/run" import { ClaudeCodeMessage } from "../../integrations/claude-code/types" import { BaseProvider } from "./base-provider" +import { t } from "../../i18n" export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { private options: ApiHandlerOptions @@ -70,7 +71,8 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { if (exitCode !== null && exitCode !== 0) { throw new Error( - `Claude Code process exited with code ${exitCode}.${errorOutput ? ` Error output: ${errorOutput.trim()}` : ""}`, + t("common:errors.claudeCode.processExited", { exitCode }) + + (errorOutput ? ` ${t("common:errors.claudeCode.errorOutput", { output: errorOutput.trim() })}` : ""), ) } @@ -99,13 +101,11 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { if (message.stop_reason !== null && message.stop_reason !== "tool_use") { const errorMessage = - message.content[0]?.text || `Claude Code stopped with reason: ${message.stop_reason}` - + message.content[0]?.text || + t("common:errors.claudeCode.stoppedWithReason", { reason: message.stop_reason }) + if (errorMessage.includes("Invalid model name")) { - throw new Error( - errorMessage + - `\n\nAPI keys and subscription plans allow different models. Make sure the selected model is included in your plan.`, - ) + throw new Error(errorMessage + `\n\n${t("common:errors.claudeCode.apiKeyModelPlanMismatch")}`) } throw new Error(errorMessage) diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 372776277c..94ab9e94a5 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -66,7 +66,13 @@ "share_no_active_task": "No hi ha cap tasca activa per compartir", "share_auth_required": "Es requereix autenticació. Si us plau, inicia sessió per compartir tasques.", "share_not_enabled": "La compartició de tasques no està habilitada per a aquesta organització.", - "share_task_not_found": "Tasca no trobada o accés denegat." + "share_task_not_found": "Tasca no trobada o accés denegat.", + "claudeCode": { + "processExited": "El procés Claude Code ha sortit amb codi {{exitCode}}.", + "errorOutput": "Sortida d'error: {{output}}", + "stoppedWithReason": "Claude Code s'ha aturat per la raó: {{reason}}", + "apiKeyModelPlanMismatch": "Les claus API i els plans de subscripció permeten models diferents. Assegura't que el model seleccionat estigui inclòs al teu pla." + } }, "warnings": { "no_terminal_content": "No s'ha seleccionat contingut de terminal", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 5db0b98d5e..9eabb962a4 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Keine aktive Aufgabe zum Teilen", "share_auth_required": "Authentifizierung erforderlich. Bitte melde dich an, um Aufgaben zu teilen.", "share_not_enabled": "Aufgabenfreigabe ist für diese Organisation nicht aktiviert.", - "share_task_not_found": "Aufgabe nicht gefunden oder Zugriff verweigert." + "share_task_not_found": "Aufgabe nicht gefunden oder Zugriff verweigert.", + "claudeCode": { + "processExited": "Claude Code Prozess wurde mit Code {{exitCode}} beendet.", + "errorOutput": "Fehlerausgabe: {{output}}", + "stoppedWithReason": "Claude Code wurde mit Grund gestoppt: {{reason}}", + "apiKeyModelPlanMismatch": "API-Schlüssel und Abonnement-Pläne erlauben verschiedene Modelle. Stelle sicher, dass das ausgewählte Modell in deinem Plan enthalten ist." + } }, "warnings": { "no_terminal_content": "Kein Terminal-Inhalt ausgewählt", diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 7d534d8bc3..98e9c8969e 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "No active task to share", "share_auth_required": "Authentication required. Please sign in to share tasks.", "share_not_enabled": "Task sharing is not enabled for this organization.", - "share_task_not_found": "Task not found or access denied." + "share_task_not_found": "Task not found or access denied.", + "claudeCode": { + "processExited": "Claude Code process exited with code {{exitCode}}.", + "errorOutput": "Error output: {{output}}", + "stoppedWithReason": "Claude Code stopped with reason: {{reason}}", + "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan." + } }, "warnings": { "no_terminal_content": "No terminal content selected", diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index cef69d0722..8f8c10eea6 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "No hay tarea activa para compartir", "share_auth_required": "Se requiere autenticación. Por favor, inicia sesión para compartir tareas.", "share_not_enabled": "La compartición de tareas no está habilitada para esta organización.", - "share_task_not_found": "Tarea no encontrada o acceso denegado." + "share_task_not_found": "Tarea no encontrada o acceso denegado.", + "claudeCode": { + "processExited": "El proceso de Claude Code terminó con código {{exitCode}}.", + "errorOutput": "Salida de error: {{output}}", + "stoppedWithReason": "Claude Code se detuvo por la razón: {{reason}}", + "apiKeyModelPlanMismatch": "Las claves API y los planes de suscripción permiten diferentes modelos. Asegúrate de que el modelo seleccionado esté incluido en tu plan." + } }, "warnings": { "no_terminal_content": "No hay contenido de terminal seleccionado", diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 7be1a71b4b..11e8f7118c 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Aucune tâche active à partager", "share_auth_required": "Authentification requise. Veuillez vous connecter pour partager des tâches.", "share_not_enabled": "Le partage de tâches n'est pas activé pour cette organisation.", - "share_task_not_found": "Tâche non trouvée ou accès refusé." + "share_task_not_found": "Tâche non trouvée ou accès refusé.", + "claudeCode": { + "processExited": "Le processus Claude Code s'est terminé avec le code {{exitCode}}.", + "errorOutput": "Sortie d'erreur : {{output}}", + "stoppedWithReason": "Claude Code s'est arrêté pour la raison : {{reason}}", + "apiKeyModelPlanMismatch": "Les clés API et les plans d'abonnement permettent différents modèles. Assurez-vous que le modèle sélectionné est inclus dans votre plan." + } }, "warnings": { "no_terminal_content": "Aucun contenu de terminal sélectionné", diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index 844ea493b6..4dc08e47cc 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "साझा करने के लिए कोई सक्रिय कार्य नहीं", "share_auth_required": "प्रमाणीकरण आवश्यक है। कार्य साझा करने के लिए कृपया साइन इन करें।", "share_not_enabled": "इस संगठन के लिए कार्य साझाकरण सक्षम नहीं है।", - "share_task_not_found": "कार्य नहीं मिला या पहुंच अस्वीकृत।" + "share_task_not_found": "कार्य नहीं मिला या पहुंच अस्वीकृत।", + "claudeCode": { + "processExited": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई।", + "errorOutput": "त्रुटि आउटपुट: {{output}}", + "stoppedWithReason": "Claude Code इस कारण से रुका: {{reason}}", + "apiKeyModelPlanMismatch": "API कुंजी और सब्सक्रिप्शन प्लान अलग-अलग मॉडल की अनुमति देते हैं। सुनिश्चित करें कि चयनित मॉडल आपकी योजना में शामिल है।" + } }, "warnings": { "no_terminal_content": "कोई टर्मिनल सामग्री चयनित नहीं", diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index 2f109d6913..1366733757 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Tidak ada tugas aktif untuk dibagikan", "share_auth_required": "Autentikasi diperlukan. Silakan masuk untuk berbagi tugas.", "share_not_enabled": "Berbagi tugas tidak diaktifkan untuk organisasi ini.", - "share_task_not_found": "Tugas tidak ditemukan atau akses ditolak." + "share_task_not_found": "Tugas tidak ditemukan atau akses ditolak.", + "claudeCode": { + "processExited": "Proses Claude Code keluar dengan kode {{exitCode}}.", + "errorOutput": "Output error: {{output}}", + "stoppedWithReason": "Claude Code berhenti karena alasan: {{reason}}", + "apiKeyModelPlanMismatch": "Kunci API dan paket berlangganan memungkinkan model yang berbeda. Pastikan model yang dipilih termasuk dalam paket Anda." + } }, "warnings": { "no_terminal_content": "Tidak ada konten terminal yang dipilih", diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index 2e7837d98e..c80aed6f00 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Nessuna attività attiva da condividere", "share_auth_required": "Autenticazione richiesta. Accedi per condividere le attività.", "share_not_enabled": "La condivisione delle attività non è abilitata per questa organizzazione.", - "share_task_not_found": "Attività non trovata o accesso negato." + "share_task_not_found": "Attività non trovata o accesso negato.", + "claudeCode": { + "processExited": "Il processo Claude Code è terminato con codice {{exitCode}}.", + "errorOutput": "Output di errore: {{output}}", + "stoppedWithReason": "Claude Code si è fermato per il motivo: {{reason}}", + "apiKeyModelPlanMismatch": "Le chiavi API e i piani di abbonamento consentono modelli diversi. Assicurati che il modello selezionato sia incluso nel tuo piano." + } }, "warnings": { "no_terminal_content": "Nessun contenuto del terminale selezionato", diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index c2daae02fe..c8ca338ad1 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "共有するアクティブなタスクがありません", "share_auth_required": "認証が必要です。タスクを共有するにはサインインしてください。", "share_not_enabled": "この組織ではタスク共有が有効になっていません。", - "share_task_not_found": "タスクが見つからないか、アクセスが拒否されました。" + "share_task_not_found": "タスクが見つからないか、アクセスが拒否されました。", + "claudeCode": { + "processExited": "Claude Code プロセスがコード {{exitCode}} で終了しました。", + "errorOutput": "エラー出力:{{output}}", + "stoppedWithReason": "Claude Code が理由により停止しました:{{reason}}", + "apiKeyModelPlanMismatch": "API キーとサブスクリプションプランでは異なるモデルが利用可能です。選択したモデルがプランに含まれていることを確認してください。" + } }, "warnings": { "no_terminal_content": "選択されたターミナルコンテンツがありません", diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 308be2c9f2..55434be668 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "공유할 활성 작업이 없습니다", "share_auth_required": "인증이 필요합니다. 작업을 공유하려면 로그인하세요.", "share_not_enabled": "이 조직에서는 작업 공유가 활성화되지 않았습니다.", - "share_task_not_found": "작업을 찾을 수 없거나 액세스가 거부되었습니다." + "share_task_not_found": "작업을 찾을 수 없거나 액세스가 거부되었습니다.", + "claudeCode": { + "processExited": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다.", + "errorOutput": "오류 출력: {{output}}", + "stoppedWithReason": "Claude Code가 다음 이유로 중지되었습니다: {{reason}}", + "apiKeyModelPlanMismatch": "API 키와 구독 플랜에서 다른 모델을 허용합니다. 선택한 모델이 플랜에 포함되어 있는지 확인하세요." + } }, "warnings": { "no_terminal_content": "선택된 터미널 내용이 없습니다", diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index ad304387df..e696c246fb 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Geen actieve taak om te delen", "share_auth_required": "Authenticatie vereist. Log in om taken te delen.", "share_not_enabled": "Taken delen is niet ingeschakeld voor deze organisatie.", - "share_task_not_found": "Taak niet gevonden of toegang geweigerd." + "share_task_not_found": "Taak niet gevonden of toegang geweigerd.", + "claudeCode": { + "processExited": "Claude Code proces beëindigd met code {{exitCode}}.", + "errorOutput": "Foutuitvoer: {{output}}", + "stoppedWithReason": "Claude Code gestopt om reden: {{reason}}", + "apiKeyModelPlanMismatch": "API-sleutels en abonnementsplannen staan verschillende modellen toe. Zorg ervoor dat het geselecteerde model is opgenomen in je plan." + } }, "warnings": { "no_terminal_content": "Geen terminalinhoud geselecteerd", diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index f75ce21796..5d3a64a16f 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Brak aktywnego zadania do udostępnienia", "share_auth_required": "Wymagana autoryzacja. Zaloguj się, aby udostępniać zadania.", "share_not_enabled": "Udostępnianie zadań nie jest włączone dla tej organizacji.", - "share_task_not_found": "Zadanie nie znalezione lub dostęp odmówiony." + "share_task_not_found": "Zadanie nie znalezione lub dostęp odmówiony.", + "claudeCode": { + "processExited": "Proces Claude Code zakończył się kodem {{exitCode}}.", + "errorOutput": "Wyjście błędu: {{output}}", + "stoppedWithReason": "Claude Code zatrzymał się z powodu: {{reason}}", + "apiKeyModelPlanMismatch": "Klucze API i plany subskrypcji pozwalają na różne modele. Upewnij się, że wybrany model jest zawarty w twoim planie." + } }, "warnings": { "no_terminal_content": "Nie wybrano zawartości terminala", diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index 0eb7d3ff41..dbd8f0d1a0 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -66,7 +66,13 @@ "share_no_active_task": "Nenhuma tarefa ativa para compartilhar", "share_auth_required": "Autenticação necessária. Faça login para compartilhar tarefas.", "share_not_enabled": "O compartilhamento de tarefas não está habilitado para esta organização.", - "share_task_not_found": "Tarefa não encontrada ou acesso negado." + "share_task_not_found": "Tarefa não encontrada ou acesso negado.", + "claudeCode": { + "processExited": "O processo Claude Code saiu com código {{exitCode}}.", + "errorOutput": "Saída de erro: {{output}}", + "stoppedWithReason": "Claude Code parou pela razão: {{reason}}", + "apiKeyModelPlanMismatch": "Chaves de API e planos de assinatura permitem modelos diferentes. Certifique-se de que o modelo selecionado esteja incluído no seu plano." + } }, "warnings": { "no_terminal_content": "Nenhum conteúdo do terminal selecionado", diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 9a5fea397a..b087b1296b 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Нет активной задачи для совместного использования", "share_auth_required": "Требуется аутентификация. Войдите в систему для совместного доступа к задачам.", "share_not_enabled": "Совместный доступ к задачам не включен для этой организации.", - "share_task_not_found": "Задача не найдена или доступ запрещен." + "share_task_not_found": "Задача не найдена или доступ запрещен.", + "claudeCode": { + "processExited": "Процесс Claude Code завершился с кодом {{exitCode}}.", + "errorOutput": "Вывод ошибки: {{output}}", + "stoppedWithReason": "Claude Code остановился по причине: {{reason}}", + "apiKeyModelPlanMismatch": "API-ключи и планы подписки позволяют использовать разные модели. Убедитесь, что выбранная модель включена в ваш план." + } }, "warnings": { "no_terminal_content": "Не выбрано содержимое терминала", diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index aa0ab6cf86..2fc51087aa 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Paylaşılacak aktif görev yok", "share_auth_required": "Kimlik doğrulama gerekli. Görevleri paylaşmak için lütfen giriş yapın.", "share_not_enabled": "Bu kuruluş için görev paylaşımı etkinleştirilmemiş.", - "share_task_not_found": "Görev bulunamadı veya erişim reddedildi." + "share_task_not_found": "Görev bulunamadı veya erişim reddedildi.", + "claudeCode": { + "processExited": "Claude Code işlemi {{exitCode}} koduyla çıktı.", + "errorOutput": "Hata çıktısı: {{output}}", + "stoppedWithReason": "Claude Code şu nedenle durdu: {{reason}}", + "apiKeyModelPlanMismatch": "API anahtarları ve abonelik planları farklı modellere izin verir. Seçilen modelin planınıza dahil olduğundan emin olun." + } }, "warnings": { "no_terminal_content": "Seçili terminal içeriği yok", diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 4879df0095..42fe683b50 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "Không có nhiệm vụ hoạt động để chia sẻ", "share_auth_required": "Cần xác thực. Vui lòng đăng nhập để chia sẻ nhiệm vụ.", "share_not_enabled": "Chia sẻ nhiệm vụ không được bật cho tổ chức này.", - "share_task_not_found": "Không tìm thấy nhiệm vụ hoặc truy cập bị từ chối." + "share_task_not_found": "Không tìm thấy nhiệm vụ hoặc truy cập bị từ chối.", + "claudeCode": { + "processExited": "Tiến trình Claude Code thoát với mã {{exitCode}}.", + "errorOutput": "Đầu ra lỗi: {{output}}", + "stoppedWithReason": "Claude Code dừng lại vì lý do: {{reason}}", + "apiKeyModelPlanMismatch": "Khóa API và gói đăng ký cho phép các mô hình khác nhau. Đảm bảo rằng mô hình đã chọn được bao gồm trong gói của bạn." + } }, "warnings": { "no_terminal_content": "Không có nội dung terminal được chọn", diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 2e34561936..b1410b346a 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -67,7 +67,13 @@ "share_no_active_task": "没有活跃任务可分享", "share_auth_required": "需要身份验证。请登录以分享任务。", "share_not_enabled": "此组织未启用任务分享功能。", - "share_task_not_found": "未找到任务或访问被拒绝。" + "share_task_not_found": "未找到任务或访问被拒绝。", + "claudeCode": { + "processExited": "Claude Code 进程退出,退出码:{{exitCode}}。", + "errorOutput": "错误输出:{{output}}", + "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", + "apiKeyModelPlanMismatch": "API 密钥和订阅计划支持不同的模型。请确保所选模型包含在您的计划中。" + } }, "warnings": { "no_terminal_content": "没有选择终端内容", diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 168d24e5c5..9d0dbc77d9 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -62,7 +62,13 @@ "share_no_active_task": "沒有活躍的工作可分享", "share_auth_required": "需要身份驗證。請登入以分享工作。", "share_not_enabled": "此組織未啟用工作分享功能。", - "share_task_not_found": "未找到工作或存取被拒絕。" + "share_task_not_found": "未找到工作或存取被拒絕。", + "claudeCode": { + "processExited": "Claude Code 程序退出,退出碼:{{exitCode}}。", + "errorOutput": "錯誤輸出:{{output}}", + "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", + "apiKeyModelPlanMismatch": "API 金鑰和訂閱方案允許不同的模型。請確保所選模型包含在您的方案中。" + } }, "warnings": { "no_terminal_content": "沒有選擇終端機內容", From 8b50b3a698c98ccb95788d5867a0eaeb5fa99e79 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Sun, 22 Jun 2025 10:22:53 -0500 Subject: [PATCH 12/16] feat: add translations for processExitedWithError key - Added processExitedWithError translation key to all supported languages - This replaces concatenated translation calls with a single unified key - Allows for more natural word order in non-English languages - Addresses review feedback from PR #4864 --- src/api/providers/claude-code.ts | 15 ++++++++++----- src/i18n/locales/ca/common.json | 1 + src/i18n/locales/de/common.json | 1 + src/i18n/locales/en/common.json | 1 + src/i18n/locales/es/common.json | 1 + src/i18n/locales/fr/common.json | 1 + src/i18n/locales/hi/common.json | 1 + src/i18n/locales/id/common.json | 1 + src/i18n/locales/it/common.json | 1 + src/i18n/locales/ja/common.json | 1 + src/i18n/locales/ko/common.json | 1 + src/i18n/locales/nl/common.json | 1 + src/i18n/locales/pl/common.json | 1 + src/i18n/locales/pt-BR/common.json | 1 + src/i18n/locales/ru/common.json | 1 + src/i18n/locales/tr/common.json | 1 + src/i18n/locales/vi/common.json | 1 + src/i18n/locales/zh-CN/common.json | 1 + src/i18n/locales/zh-TW/common.json | 1 + 19 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts index e32dd9752f..64137b32f0 100644 --- a/src/api/providers/claude-code.ts +++ b/src/api/providers/claude-code.ts @@ -70,10 +70,15 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { } if (exitCode !== null && exitCode !== 0) { - throw new Error( - t("common:errors.claudeCode.processExited", { exitCode }) + - (errorOutput ? ` ${t("common:errors.claudeCode.errorOutput", { output: errorOutput.trim() })}` : ""), - ) + if (errorOutput) { + throw new Error( + t("common:errors.claudeCode.processExitedWithError", { + exitCode, + output: errorOutput.trim(), + }), + ) + } + throw new Error(t("common:errors.claudeCode.processExited", { exitCode })) } const data = dataQueue.shift() @@ -103,7 +108,7 @@ export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { const errorMessage = message.content[0]?.text || t("common:errors.claudeCode.stoppedWithReason", { reason: message.stop_reason }) - + if (errorMessage.includes("Invalid model name")) { throw new Error(errorMessage + `\n\n${t("common:errors.claudeCode.apiKeyModelPlanMismatch")}`) } diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 94ab9e94a5..d372a57ce6 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -70,6 +70,7 @@ "claudeCode": { "processExited": "El procés Claude Code ha sortit amb codi {{exitCode}}.", "errorOutput": "Sortida d'error: {{output}}", + "processExitedWithError": "El procés Claude Code ha sortit amb codi {{exitCode}}. Sortida d'error: {{output}}", "stoppedWithReason": "Claude Code s'ha aturat per la raó: {{reason}}", "apiKeyModelPlanMismatch": "Les claus API i els plans de subscripció permeten models diferents. Assegura't que el model seleccionat estigui inclòs al teu pla." } diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 9eabb962a4..d34d266e44 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code Prozess wurde mit Code {{exitCode}} beendet.", "errorOutput": "Fehlerausgabe: {{output}}", + "processExitedWithError": "Claude Code Prozess wurde mit Code {{exitCode}} beendet. Fehlerausgabe: {{output}}", "stoppedWithReason": "Claude Code wurde mit Grund gestoppt: {{reason}}", "apiKeyModelPlanMismatch": "API-Schlüssel und Abonnement-Pläne erlauben verschiedene Modelle. Stelle sicher, dass das ausgewählte Modell in deinem Plan enthalten ist." } diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 98e9c8969e..0de1a25354 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code process exited with code {{exitCode}}.", "errorOutput": "Error output: {{output}}", + "processExitedWithError": "Claude Code process exited with code {{exitCode}}. Error output: {{output}}", "stoppedWithReason": "Claude Code stopped with reason: {{reason}}", "apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan." } diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 8f8c10eea6..6da86eb225 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "El proceso de Claude Code terminó con código {{exitCode}}.", "errorOutput": "Salida de error: {{output}}", + "processExitedWithError": "El proceso de Claude Code terminó con código {{exitCode}}. Salida de error: {{output}}", "stoppedWithReason": "Claude Code se detuvo por la razón: {{reason}}", "apiKeyModelPlanMismatch": "Las claves API y los planes de suscripción permiten diferentes modelos. Asegúrate de que el modelo seleccionado esté incluido en tu plan." } diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 11e8f7118c..1875bb94a7 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Le processus Claude Code s'est terminé avec le code {{exitCode}}.", "errorOutput": "Sortie d'erreur : {{output}}", + "processExitedWithError": "Le processus Claude Code s'est terminé avec le code {{exitCode}}. Sortie d'erreur : {{output}}", "stoppedWithReason": "Claude Code s'est arrêté pour la raison : {{reason}}", "apiKeyModelPlanMismatch": "Les clés API et les plans d'abonnement permettent différents modèles. Assurez-vous que le modèle sélectionné est inclus dans votre plan." } diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index 4dc08e47cc..b991b167fe 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई।", "errorOutput": "त्रुटि आउटपुट: {{output}}", + "processExitedWithError": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई। त्रुटि आउटपुट: {{output}}", "stoppedWithReason": "Claude Code इस कारण से रुका: {{reason}}", "apiKeyModelPlanMismatch": "API कुंजी और सब्सक्रिप्शन प्लान अलग-अलग मॉडल की अनुमति देते हैं। सुनिश्चित करें कि चयनित मॉडल आपकी योजना में शामिल है।" } diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index 1366733757..f961b88bed 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Proses Claude Code keluar dengan kode {{exitCode}}.", "errorOutput": "Output error: {{output}}", + "processExitedWithError": "Proses Claude Code keluar dengan kode {{exitCode}}. Output error: {{output}}", "stoppedWithReason": "Claude Code berhenti karena alasan: {{reason}}", "apiKeyModelPlanMismatch": "Kunci API dan paket berlangganan memungkinkan model yang berbeda. Pastikan model yang dipilih termasuk dalam paket Anda." } diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index c80aed6f00..0cf42e2cbd 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Il processo Claude Code è terminato con codice {{exitCode}}.", "errorOutput": "Output di errore: {{output}}", + "processExitedWithError": "Il processo Claude Code è terminato con codice {{exitCode}}. Output di errore: {{output}}", "stoppedWithReason": "Claude Code si è fermato per il motivo: {{reason}}", "apiKeyModelPlanMismatch": "Le chiavi API e i piani di abbonamento consentono modelli diversi. Assicurati che il modello selezionato sia incluso nel tuo piano." } diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index c8ca338ad1..9e1107332b 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code プロセスがコード {{exitCode}} で終了しました。", "errorOutput": "エラー出力:{{output}}", + "processExitedWithError": "Claude Code プロセスがコード {{exitCode}} で終了しました。エラー出力:{{output}}", "stoppedWithReason": "Claude Code が理由により停止しました:{{reason}}", "apiKeyModelPlanMismatch": "API キーとサブスクリプションプランでは異なるモデルが利用可能です。選択したモデルがプランに含まれていることを確認してください。" } diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 55434be668..51614261c1 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다.", "errorOutput": "오류 출력: {{output}}", + "processExitedWithError": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다. 오류 출력: {{output}}", "stoppedWithReason": "Claude Code가 다음 이유로 중지되었습니다: {{reason}}", "apiKeyModelPlanMismatch": "API 키와 구독 플랜에서 다른 모델을 허용합니다. 선택한 모델이 플랜에 포함되어 있는지 확인하세요." } diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index e696c246fb..973f7331a8 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code proces beëindigd met code {{exitCode}}.", "errorOutput": "Foutuitvoer: {{output}}", + "processExitedWithError": "Claude Code proces beëindigd met code {{exitCode}}. Foutuitvoer: {{output}}", "stoppedWithReason": "Claude Code gestopt om reden: {{reason}}", "apiKeyModelPlanMismatch": "API-sleutels en abonnementsplannen staan verschillende modellen toe. Zorg ervoor dat het geselecteerde model is opgenomen in je plan." } diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 5d3a64a16f..71a044ba40 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Proces Claude Code zakończył się kodem {{exitCode}}.", "errorOutput": "Wyjście błędu: {{output}}", + "processExitedWithError": "Proces Claude Code zakończył się kodem {{exitCode}}. Wyjście błędu: {{output}}", "stoppedWithReason": "Claude Code zatrzymał się z powodu: {{reason}}", "apiKeyModelPlanMismatch": "Klucze API i plany subskrypcji pozwalają na różne modele. Upewnij się, że wybrany model jest zawarty w twoim planie." } diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index dbd8f0d1a0..f67383024a 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -70,6 +70,7 @@ "claudeCode": { "processExited": "O processo Claude Code saiu com código {{exitCode}}.", "errorOutput": "Saída de erro: {{output}}", + "processExitedWithError": "O processo Claude Code saiu com código {{exitCode}}. Saída de erro: {{output}}", "stoppedWithReason": "Claude Code parou pela razão: {{reason}}", "apiKeyModelPlanMismatch": "Chaves de API e planos de assinatura permitem modelos diferentes. Certifique-se de que o modelo selecionado esteja incluído no seu plano." } diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index b087b1296b..8a3798307c 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Процесс Claude Code завершился с кодом {{exitCode}}.", "errorOutput": "Вывод ошибки: {{output}}", + "processExitedWithError": "Процесс Claude Code завершился с кодом {{exitCode}}. Вывод ошибки: {{output}}", "stoppedWithReason": "Claude Code остановился по причине: {{reason}}", "apiKeyModelPlanMismatch": "API-ключи и планы подписки позволяют использовать разные модели. Убедитесь, что выбранная модель включена в ваш план." } diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 2fc51087aa..9902896503 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code işlemi {{exitCode}} koduyla çıktı.", "errorOutput": "Hata çıktısı: {{output}}", + "processExitedWithError": "Claude Code işlemi {{exitCode}} koduyla çıktı. Hata çıktısı: {{output}}", "stoppedWithReason": "Claude Code şu nedenle durdu: {{reason}}", "apiKeyModelPlanMismatch": "API anahtarları ve abonelik planları farklı modellere izin verir. Seçilen modelin planınıza dahil olduğundan emin olun." } diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 42fe683b50..93fa9b689b 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Tiến trình Claude Code thoát với mã {{exitCode}}.", "errorOutput": "Đầu ra lỗi: {{output}}", + "processExitedWithError": "Tiến trình Claude Code thoát với mã {{exitCode}}. Đầu ra lỗi: {{output}}", "stoppedWithReason": "Claude Code dừng lại vì lý do: {{reason}}", "apiKeyModelPlanMismatch": "Khóa API và gói đăng ký cho phép các mô hình khác nhau. Đảm bảo rằng mô hình đã chọn được bao gồm trong gói của bạn." } diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index b1410b346a..f2fedd3c1b 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -71,6 +71,7 @@ "claudeCode": { "processExited": "Claude Code 进程退出,退出码:{{exitCode}}。", "errorOutput": "错误输出:{{output}}", + "processExitedWithError": "Claude Code 进程退出,退出码:{{exitCode}}。错误输出:{{output}}", "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", "apiKeyModelPlanMismatch": "API 密钥和订阅计划支持不同的模型。请确保所选模型包含在您的计划中。" } diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 9d0dbc77d9..43f44a47b3 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -66,6 +66,7 @@ "claudeCode": { "processExited": "Claude Code 程序退出,退出碼:{{exitCode}}。", "errorOutput": "錯誤輸出:{{output}}", + "processExitedWithError": "Claude Code 程序退出,退出碼:{{exitCode}}。錯誤輸出:{{output}}", "stoppedWithReason": "Claude Code 停止,原因:{{reason}}", "apiKeyModelPlanMismatch": "API 金鑰和訂閱方案允許不同的模型。請確保所選模型包含在您的方案中。" } From 4ae2982630dfc19769bc4f38d96354683d71b9a4 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Sun, 22 Jun 2025 10:28:36 -0500 Subject: [PATCH 13/16] fix(api): remove redundant ApiHandlerOptions import in ClaudeCodeHandler --- packages/types/src/api.ts | 3 --- src/api/providers/claude-code.ts | 8 ++------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index 9d86bcd333..de8ae1f5b4 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -4,9 +4,6 @@ import type { Socket } from "net" import type { RooCodeSettings } from "./global-settings.js" import type { ProviderSettingsEntry, ProviderSettings } from "./provider-settings.js" -// ApiHandlerOptions - -export type ApiHandlerOptions = Omit import type { ClineMessage, TokenUsage } from "./message.js" import type { ToolUsage, ToolName } from "./tool.js" import type { IpcMessage, IpcServerEvents, IsSubtask } from "./ipc.js" diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts index 64137b32f0..f3e66604e4 100644 --- a/src/api/providers/claude-code.ts +++ b/src/api/providers/claude-code.ts @@ -1,16 +1,12 @@ import type { Anthropic } from "@anthropic-ai/sdk" -import { - type ApiHandlerOptions, - claudeCodeDefaultModelId, - type ClaudeCodeModelId, - claudeCodeModels, -} from "@roo-code/types" +import { claudeCodeDefaultModelId, type ClaudeCodeModelId, claudeCodeModels } from "@roo-code/types" import { type ApiHandler } from ".." import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream" import { runClaudeCode } from "../../integrations/claude-code/run" import { ClaudeCodeMessage } from "../../integrations/claude-code/types" import { BaseProvider } from "./base-provider" import { t } from "../../i18n" +import { ApiHandlerOptions } from "../../shared/api" export class ClaudeCodeHandler extends BaseProvider implements ApiHandler { private options: ApiHandlerOptions From a5d2f957c3a2dd4266983052d625e72cc958fce2 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Sun, 22 Jun 2025 10:41:46 -0500 Subject: [PATCH 14/16] revert this --- src/shared/api.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/shared/api.ts b/src/shared/api.ts index aa96d11cc5..8ad8828658 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -1,12 +1,8 @@ -import { - type ModelInfo, - type ProviderSettings, - ANTHROPIC_DEFAULT_MAX_TOKENS, - type ApiHandlerOptions, -} from "@roo-code/types" - -// Re-export ApiHandlerOptions for backward compatibility -export type { ApiHandlerOptions } +import { type ModelInfo, type ProviderSettings, ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types" + +// ApiHandlerOptions + +export type ApiHandlerOptions = Omit // RouterName From c32f71c632749f8841d80495787c8f109653fa44 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Sun, 22 Jun 2025 10:43:20 -0500 Subject: [PATCH 15/16] revert this --- packages/types/src/api.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index de8ae1f5b4..6fb181b573 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -3,7 +3,6 @@ import type { Socket } from "net" import type { RooCodeSettings } from "./global-settings.js" import type { ProviderSettingsEntry, ProviderSettings } from "./provider-settings.js" - import type { ClineMessage, TokenUsage } from "./message.js" import type { ToolUsage, ToolName } from "./tool.js" import type { IpcMessage, IpcServerEvents, IsSubtask } from "./ipc.js" From 94b553b851ff1cf55b9c7b2457c9ac4e607f99c4 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 22 Jun 2025 23:17:46 -0400 Subject: [PATCH 16/16] Update src/integrations/claude-code/run.ts --- src/integrations/claude-code/run.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integrations/claude-code/run.ts b/src/integrations/claude-code/run.ts index 7cae66a2eb..8bc12c8740 100644 --- a/src/integrations/claude-code/run.ts +++ b/src/integrations/claude-code/run.ts @@ -15,7 +15,7 @@ export function runClaudeCode({ }) { const claudePath = path || "claude" - // TODO: Is it worh using sessions? Where do we store the session ID? + // TODO: Is it worth using sessions? Where do we store the session ID? const args = [ "-p", JSON.stringify(messages),