mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-07 02:58:15 +00:00
feat: add Claude Code provider for local CLI integration (#4864)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com> Co-authored-by: Daniel Riccio <ricciodaniel98@gmail.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
This commit is contained in:
parent
9750d868c1
commit
ff9b6b3ef6
49 changed files with 714 additions and 52 deletions
|
|
@ -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,
|
||||
|
|
|
|||
13
packages/types/src/providers/claude-code.ts
Normal file
13
packages/types/src/providers/claude-code.ts
Normal file
|
|
@ -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<string, ModelInfo>
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
171
src/api/providers/claude-code.ts
Normal file
171
src/api/providers/claude-code.ts
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
import type { Anthropic } from "@anthropic-ai/sdk"
|
||||
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
|
||||
|
||||
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) {
|
||||
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()
|
||||
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 ||
|
||||
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")}`)
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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
|
||||
}
|
||||
|
||||
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],
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
export type ApiStream = AsyncGenerator<ApiStreamChunk>
|
||||
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -66,7 +66,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "No s'ha seleccionat contingut de terminal",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Kein Terminal-Inhalt ausgewählt",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "No terminal content selected",
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "No hay contenido de terminal seleccionado",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Aucun contenu de terminal sélectionné",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"processExitedWithError": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई। त्रुटि आउटपुट: {{output}}",
|
||||
"stoppedWithReason": "Claude Code इस कारण से रुका: {{reason}}",
|
||||
"apiKeyModelPlanMismatch": "API कुंजी और सब्सक्रिप्शन प्लान अलग-अलग मॉडल की अनुमति देते हैं। सुनिश्चित करें कि चयनित मॉडल आपकी योजना में शामिल है।"
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "कोई टर्मिनल सामग्री चयनित नहीं",
|
||||
|
|
@ -105,7 +112,12 @@
|
|||
"settings": {
|
||||
"providers": {
|
||||
"groqApiKey": "ग्रोक एपीआई कुंजी",
|
||||
"getGroqApiKey": "ग्रोक एपीआई कुंजी प्राप्त करें"
|
||||
"getGroqApiKey": "ग्रोक एपीआई कुंजी प्राप्त करें",
|
||||
"claudeCode": {
|
||||
"pathLabel": "क्लाउड कोड पाथ",
|
||||
"description": "आपके क्लाउड कोड CLI का वैकल्पिक पाथ। सेट न होने पर डिफ़ॉल्ट रूप से 'claude'。",
|
||||
"placeholder": "डिफ़ॉल्ट: claude"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdm": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Tidak ada konten terminal yang dipilih",
|
||||
|
|
@ -102,6 +109,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.",
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Nessun contenuto del terminale selezionato",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"processExitedWithError": "Claude Code プロセスがコード {{exitCode}} で終了しました。エラー出力:{{output}}",
|
||||
"stoppedWithReason": "Claude Code が理由により停止しました:{{reason}}",
|
||||
"apiKeyModelPlanMismatch": "API キーとサブスクリプションプランでは異なるモデルが利用可能です。選択したモデルがプランに含まれていることを確認してください。"
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "選択されたターミナルコンテンツがありません",
|
||||
|
|
@ -105,7 +112,12 @@
|
|||
"settings": {
|
||||
"providers": {
|
||||
"groqApiKey": "Groq APIキー",
|
||||
"getGroqApiKey": "Groq APIキーを取得"
|
||||
"getGroqApiKey": "Groq APIキーを取得",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude Code パス",
|
||||
"description": "Claude Code CLI へのオプションのパス。設定されていない場合は、デフォルトで「claude」になります。",
|
||||
"placeholder": "デフォルト: claude"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdm": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"processExitedWithError": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다. 오류 출력: {{output}}",
|
||||
"stoppedWithReason": "Claude Code가 다음 이유로 중지되었습니다: {{reason}}",
|
||||
"apiKeyModelPlanMismatch": "API 키와 구독 플랜에서 다른 모델을 허용합니다. 선택한 모델이 플랜에 포함되어 있는지 확인하세요."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "선택된 터미널 내용이 없습니다",
|
||||
|
|
@ -105,7 +112,12 @@
|
|||
"settings": {
|
||||
"providers": {
|
||||
"groqApiKey": "Groq API 키",
|
||||
"getGroqApiKey": "Groq API 키 받기"
|
||||
"getGroqApiKey": "Groq API 키 받기",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude Code 경로",
|
||||
"description": "Claude Code CLI의 선택적 경로입니다. 설정되지 않은 경우 기본값은 'claude'입니다.",
|
||||
"placeholder": "기본값: claude"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdm": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Geen terminalinhoud geselecteerd",
|
||||
|
|
@ -102,6 +109,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.",
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Nie wybrano zawartości terminala",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Nenhum conteúdo do terminal selecionado",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"processExitedWithError": "Процесс Claude Code завершился с кодом {{exitCode}}. Вывод ошибки: {{output}}",
|
||||
"stoppedWithReason": "Claude Code остановился по причине: {{reason}}",
|
||||
"apiKeyModelPlanMismatch": "API-ключи и планы подписки позволяют использовать разные модели. Убедитесь, что выбранная модель включена в ваш план."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Не выбрано содержимое терминала",
|
||||
|
|
@ -105,7 +112,12 @@
|
|||
"settings": {
|
||||
"providers": {
|
||||
"groqApiKey": "Ключ API Groq",
|
||||
"getGroqApiKey": "Получить ключ API Groq"
|
||||
"getGroqApiKey": "Получить ключ API Groq",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Путь к Claude Code",
|
||||
"description": "Необязательный путь к вашему CLI Claude Code. По умолчанию 'claude', если не установлено.",
|
||||
"placeholder": "По умолчанию: claude"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdm": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Seçili terminal içeriği yok",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"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."
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "Không có nội dung terminal được chọn",
|
||||
|
|
@ -105,7 +112,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": {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,14 @@
|
|||
"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}}",
|
||||
"processExitedWithError": "Claude Code 进程退出,退出码:{{exitCode}}。错误输出:{{output}}",
|
||||
"stoppedWithReason": "Claude Code 停止,原因:{{reason}}",
|
||||
"apiKeyModelPlanMismatch": "API 密钥和订阅计划支持不同的模型。请确保所选模型包含在您的计划中。"
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "没有选择终端内容",
|
||||
|
|
@ -110,7 +117,12 @@
|
|||
"settings": {
|
||||
"providers": {
|
||||
"groqApiKey": "Groq API 密钥",
|
||||
"getGroqApiKey": "获取 Groq API 密钥"
|
||||
"getGroqApiKey": "获取 Groq API 密钥",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude Code 路径",
|
||||
"description": "Claude Code CLI 的可选路径。如果未设置,默认为 'claude'。",
|
||||
"placeholder": "默认: claude"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdm": {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,14 @@
|
|||
"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}}",
|
||||
"processExitedWithError": "Claude Code 程序退出,退出碼:{{exitCode}}。錯誤輸出:{{output}}",
|
||||
"stoppedWithReason": "Claude Code 停止,原因:{{reason}}",
|
||||
"apiKeyModelPlanMismatch": "API 金鑰和訂閱方案允許不同的模型。請確保所選模型包含在您的方案中。"
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"no_terminal_content": "沒有選擇終端機內容",
|
||||
|
|
@ -105,7 +112,12 @@
|
|||
"settings": {
|
||||
"providers": {
|
||||
"groqApiKey": "Groq API 金鑰",
|
||||
"getGroqApiKey": "取得 Groq API 金鑰"
|
||||
"getGroqApiKey": "取得 Groq API 金鑰",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude Code 路徑",
|
||||
"description": "Claude Code CLI 的選用路徑。如果未設定,預設為 'claude'。",
|
||||
"placeholder": "預設: claude"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdm": {
|
||||
|
|
|
|||
44
src/integrations/claude-code/run.ts
Normal file
44
src/integrations/claude-code/run.ts
Normal file
|
|
@ -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 worth 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,
|
||||
})
|
||||
}
|
||||
52
src/integrations/claude-code/types.ts
Normal file
52
src/integrations/claude-code/types.ts
Normal file
|
|
@ -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: string | 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
|
||||
|
|
@ -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 = ({
|
|||
<Anthropic apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} />
|
||||
)}
|
||||
|
||||
{selectedProvider === "claude-code" && (
|
||||
<ClaudeCode apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} />
|
||||
)}
|
||||
|
||||
{selectedProvider === "openai-native" && (
|
||||
<OpenAI apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
type ModelInfo,
|
||||
anthropicModels,
|
||||
bedrockModels,
|
||||
claudeCodeModels,
|
||||
deepSeekModels,
|
||||
geminiModels,
|
||||
mistralModels,
|
||||
|
|
@ -15,6 +16,7 @@ import {
|
|||
|
||||
export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, ModelInfo>>> = {
|
||||
anthropic: anthropicModels,
|
||||
"claude-code": claudeCodeModels,
|
||||
bedrock: bedrockModels,
|
||||
deepseek: deepSeekModels,
|
||||
gemini: geminiModels,
|
||||
|
|
@ -29,6 +31,7 @@ export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, Mod
|
|||
export const PROVIDERS = [
|
||||
{ value: "openrouter", label: "OpenRouter" },
|
||||
{ value: "anthropic", label: "Anthropic" },
|
||||
{ value: "claude-code", label: "Claude Code" },
|
||||
{ value: "gemini", label: "Google Gemini" },
|
||||
{ value: "deepseek", label: "DeepSeek" },
|
||||
{ value: "openai-native", label: "OpenAI" },
|
||||
|
|
|
|||
40
webview-ui/src/components/settings/providers/ClaudeCode.tsx
Normal file
40
webview-ui/src/components/settings/providers/ClaudeCode.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import React from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import { type ProviderSettings } from "@roo-code/types"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
|
||||
interface ClaudeCodeProps {
|
||||
apiConfiguration: ProviderSettings
|
||||
setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
|
||||
}
|
||||
|
||||
export const ClaudeCode: React.FC<ClaudeCodeProps> = ({ apiConfiguration, setApiConfigurationField }) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const handleInputChange = (e: Event | React.FormEvent<HTMLElement>) => {
|
||||
const element = e.target as HTMLInputElement
|
||||
setApiConfigurationField("claudeCodePath", element.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.claudeCodePath || ""}
|
||||
style={{ width: "100%", marginTop: 3 }}
|
||||
type="text"
|
||||
onInput={handleInputChange}
|
||||
placeholder={t("settings:providers.claudeCode.placeholder")}>
|
||||
{t("settings:providers.claudeCode.pathLabel")}
|
||||
</VSCodeTextField>
|
||||
|
||||
<p
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
marginTop: 3,
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
}}>
|
||||
{t("settings:providers.claudeCode.description")}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Mitjà",
|
||||
"low": "Baix"
|
||||
},
|
||||
"setReasoningLevel": "Activa l'esforç de raonament"
|
||||
"setReasoningLevel": "Activa l'esforç de raonament",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Ruta del Codi Claude",
|
||||
"description": "Ruta opcional al teu CLI de Claude Code. Per defecte, 'claude' si no s'estableix.",
|
||||
"placeholder": "Per defecte: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Mittel",
|
||||
"low": "Niedrig"
|
||||
},
|
||||
"setReasoningLevel": "Denkaufwand aktivieren"
|
||||
"setReasoningLevel": "Denkaufwand aktivieren",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude-Code-Pfad",
|
||||
"description": "Optionaler Pfad zu Ihrer Claude Code CLI. Standard ist 'claude', wenn nicht festgelegt.",
|
||||
"placeholder": "Standard: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Medio",
|
||||
"low": "Bajo"
|
||||
},
|
||||
"setReasoningLevel": "Habilitar esfuerzo de razonamiento"
|
||||
"setReasoningLevel": "Habilitar esfuerzo de razonamiento",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Ruta de Claude Code",
|
||||
"description": "Ruta opcional a su CLI de Claude Code. Por defecto, es 'claude' si no se establece.",
|
||||
"placeholder": "Por defecto: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Moyen",
|
||||
"low": "Faible"
|
||||
},
|
||||
"setReasoningLevel": "Activer l'effort de raisonnement"
|
||||
"setReasoningLevel": "Activer l'effort de raisonnement",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Chemin du code Claude",
|
||||
"description": "Chemin facultatif vers votre CLI Claude Code. La valeur par défaut est 'claude' si non défini.",
|
||||
"placeholder": "Défaut : claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "मध्यम",
|
||||
"low": "निम्न"
|
||||
},
|
||||
"setReasoningLevel": "तर्क प्रयास सक्षम करें"
|
||||
"setReasoningLevel": "तर्क प्रयास सक्षम करें",
|
||||
"claudeCode": {
|
||||
"pathLabel": "क्लाउड कोड पथ",
|
||||
"description": "आपके क्लाउड कोड सीएलआई का वैकल्पिक पथ। यदि सेट नहीं है तो डिफ़ॉल्ट 'claude' है।",
|
||||
"placeholder": "डिफ़ॉल्ट: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -307,7 +307,12 @@
|
|||
"medium": "Sedang",
|
||||
"low": "Rendah"
|
||||
},
|
||||
"setReasoningLevel": "Aktifkan Upaya Reasoning"
|
||||
"setReasoningLevel": "Aktifkan Upaya Reasoning",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Jalur Kode Claude",
|
||||
"description": "Jalur opsional ke Claude Code CLI Anda. Defaultnya adalah 'claude' jika tidak diatur.",
|
||||
"placeholder": "Default: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Medio",
|
||||
"low": "Basso"
|
||||
},
|
||||
"setReasoningLevel": "Abilita sforzo di ragionamento"
|
||||
"setReasoningLevel": "Abilita sforzo di ragionamento",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Percorso Claude Code",
|
||||
"description": "Percorso facoltativo per la tua CLI Claude Code. Predefinito 'claude' se non impostato.",
|
||||
"placeholder": "Predefinito: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "中",
|
||||
"low": "低"
|
||||
},
|
||||
"setReasoningLevel": "推論労力を有効にする"
|
||||
"setReasoningLevel": "推論労力を有効にする",
|
||||
"claudeCode": {
|
||||
"pathLabel": "クロードコードパス",
|
||||
"description": "Claude Code CLIへのオプションパス。設定されていない場合、デフォルトは「claude」です。",
|
||||
"placeholder": "デフォルト:claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "중간",
|
||||
"low": "낮음"
|
||||
},
|
||||
"setReasoningLevel": "추론 노력 활성화"
|
||||
"setReasoningLevel": "추론 노력 활성화",
|
||||
"claudeCode": {
|
||||
"pathLabel": "클로드 코드 경로",
|
||||
"description": "Claude Code CLI의 선택적 경로입니다. 설정하지 않으면 'claude'가 기본값입니다.",
|
||||
"placeholder": "기본값: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Middel",
|
||||
"low": "Laag"
|
||||
},
|
||||
"setReasoningLevel": "Redeneervermogen inschakelen"
|
||||
"setReasoningLevel": "Redeneervermogen inschakelen",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude Code Pad",
|
||||
"description": "Optioneel pad naar uw Claude Code CLI. Standaard 'claude' als niet ingesteld.",
|
||||
"placeholder": "Standaard: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Średni",
|
||||
"low": "Niski"
|
||||
},
|
||||
"setReasoningLevel": "Włącz wysiłek rozumowania"
|
||||
"setReasoningLevel": "Włącz wysiłek rozumowania",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -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": "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": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "Средние",
|
||||
"low": "Низкие"
|
||||
},
|
||||
"setReasoningLevel": "Включить усилие рассуждения"
|
||||
"setReasoningLevel": "Включить усилие рассуждения",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Путь к Claude Code",
|
||||
"description": "Необязательный путь к вашему Claude Code CLI. По умолчанию используется 'claude', если не установлено.",
|
||||
"placeholder": "По умолчанию: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -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 Yolu",
|
||||
"description": "Claude Code CLI'nize isteğe bağlı yol. Ayarlanmazsa varsayılan olarak 'claude' kullanılır.",
|
||||
"placeholder": "Varsayılan: claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -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": "Đườ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": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "中",
|
||||
"low": "低"
|
||||
},
|
||||
"setReasoningLevel": "启用推理工作量"
|
||||
"setReasoningLevel": "启用推理工作量",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude Code 路径",
|
||||
"description": "您的 Claude Code CLI 的可选路径。如果未设置,则默认为 “claude”。",
|
||||
"placeholder": "默认:claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,12 @@
|
|||
"medium": "中",
|
||||
"low": "低"
|
||||
},
|
||||
"setReasoningLevel": "啟用推理工作量"
|
||||
"setReasoningLevel": "啟用推理工作量",
|
||||
"claudeCode": {
|
||||
"pathLabel": "Claude Code 路徑",
|
||||
"description": "可選的 Claude Code CLI 路徑。如果未設定,則預設為 'claude'。",
|
||||
"placeholder": "預設:claude"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"enable": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue