diff --git a/packages/types/src/experiment.ts b/packages/types/src/experiment.ts index cc0aabd6f6b..f6f701a25d3 100644 --- a/packages/types/src/experiment.ts +++ b/packages/types/src/experiment.ts @@ -13,6 +13,7 @@ export const experimentIds = [ "imageGeneration", "runSlashCommand", "multipleNativeToolCalls", + "customTools", ] as const export const experimentIdsSchema = z.enum(experimentIds) @@ -30,6 +31,7 @@ export const experimentsSchema = z.object({ imageGeneration: z.boolean().optional(), runSlashCommand: z.boolean().optional(), multipleNativeToolCalls: z.boolean().optional(), + customTools: z.boolean().optional(), }) export type Experiments = z.infer diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts index 15f298726a4..c1876b8cd08 100644 --- a/src/core/assistant-message/presentAssistantMessage.ts +++ b/src/core/assistant-message/presentAssistantMessage.ts @@ -1081,17 +1081,15 @@ export async function presentAssistantMessage(cline: Task) { break } - const customTool = customToolRegistry.get(block.name) + const customTool = stateExperiments?.customTools ? customToolRegistry.get(block.name) : undefined if (customTool) { try { - console.log(`executing customTool -> ${JSON.stringify(customTool, null, 2)}`) let customToolArgs if (customTool.parameters) { try { customToolArgs = customTool.parameters.parse(block.nativeArgs || block.params || {}) - console.log(`customToolArgs -> ${JSON.stringify(customToolArgs, null, 2)}`) } catch (parseParamsError) { const message = `Custom tool "${block.name}" argument validation failed: ${parseParamsError.message}` console.error(message) @@ -1102,13 +1100,15 @@ export async function presentAssistantMessage(cline: Task) { } } - console.log(`${customTool.name}.execute() -> ${JSON.stringify(customToolArgs, null, 2)}`) - const result = await customTool.execute(customToolArgs, { mode: mode ?? defaultModeSlug, task: cline, }) + console.log( + `${customTool.name}.execute(): ${JSON.stringify(customToolArgs)} -> ${JSON.stringify(result)}`, + ) + pushToolResult(result) cline.consecutiveMistakeCount = 0 } catch (executionError: any) { diff --git a/src/core/prompts/system.ts b/src/core/prompts/system.ts index fe2d98504ce..b6543950378 100644 --- a/src/core/prompts/system.ts +++ b/src/core/prompts/system.ts @@ -124,7 +124,7 @@ async function generatePrompt( let customToolsSection = "" - if (!isNativeProtocol(effectiveProtocol)) { + if (experiments?.customTools && !isNativeProtocol(effectiveProtocol)) { const customTools = customToolRegistry.getAllSerialized() if (customTools.length > 0) { diff --git a/src/core/task/build-tools.ts b/src/core/task/build-tools.ts index b7861be3270..b636052341f 100644 --- a/src/core/task/build-tools.ts +++ b/src/core/task/build-tools.ts @@ -79,13 +79,16 @@ export async function buildNativeToolsArray(options: BuildToolsOptions): Promise const mcpTools = getMcpServerTools(mcpHub) const filteredMcpTools = filterMcpToolsForMode(mcpTools, mode, customModes, experiments) - // Add custom tools if they are available. - await customToolRegistry.loadFromDirectoryIfStale(path.join(cwd, ".roo", "tools")) - const customTools = customToolRegistry.getAllSerialized() + // Add custom tools if they are available and the experiment is enabled. let nativeCustomTools: OpenAI.Chat.ChatCompletionFunctionTool[] = [] - if (customTools.length > 0) { - nativeCustomTools = customTools.map(formatNative) + if (experiments?.customTools) { + await customToolRegistry.loadFromDirectoryIfStale(path.join(cwd, ".roo", "tools")) + const customTools = customToolRegistry.getAllSerialized() + + if (customTools.length > 0) { + nativeCustomTools = customTools.map(formatNative) + } } return [...filteredNativeTools, ...filteredMcpTools, ...nativeCustomTools] diff --git a/src/core/tools/validateToolUse.ts b/src/core/tools/validateToolUse.ts index de814f0b3c9..751d164fd26 100644 --- a/src/core/tools/validateToolUse.ts +++ b/src/core/tools/validateToolUse.ts @@ -11,13 +11,13 @@ import { TOOL_GROUPS, ALWAYS_AVAILABLE_TOOLS } from "../../shared/tools" * Note: This does NOT check if the tool is allowed for a specific mode, * only that the tool actually exists. */ -export function isValidToolName(toolName: string): toolName is ToolName { +export function isValidToolName(toolName: string, experiments?: Record): toolName is ToolName { // Check if it's a valid static tool if ((validToolNames as readonly string[]).includes(toolName)) { return true } - if (customToolRegistry.has(toolName)) { + if (experiments?.customTools && customToolRegistry.has(toolName)) { return true } @@ -40,7 +40,7 @@ export function validateToolUse( ): void { // First, check if the tool name is actually a valid/known tool // This catches completely invalid tool names like "edit_file" that don't exist - if (!isValidToolName(toolName)) { + if (!isValidToolName(toolName, experiments)) { throw new Error( `Unknown tool "${toolName}". This tool does not exist. Please use one of the available tools: ${validToolNames.join(", ")}.`, ) @@ -94,7 +94,7 @@ export function isToolAllowedForMode( // For now, allow all custom tools in any mode. // As a follow-up we should expand the custom tool definition to include mode restrictions. - if (customToolRegistry.has(tool)) { + if (experiments?.customTools && customToolRegistry.has(tool)) { return true } diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index aa72ee253f5..e042c5c1c67 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -16,6 +16,7 @@ import { Experiments, ExperimentId, } from "@roo-code/types" +import { customToolRegistry } from "@roo-code/core" import { CloudService } from "@roo-code/cloud" import { TelemetryService } from "@roo-code/telemetry" @@ -1725,6 +1726,24 @@ export const webviewMessageHandler = async ( } break } + case "refreshCustomTools": { + try { + await customToolRegistry.loadFromDirectory(path.join(getCurrentCwd(), ".roo", "tools")) + + await provider.postMessageToWebview({ + type: "customToolsResult", + tools: customToolRegistry.getAllSerialized(), + }) + } catch (error) { + await provider.postMessageToWebview({ + type: "customToolsResult", + tools: [], + error: error instanceof Error ? error.message : String(error), + }) + } + + break + } case "saveApiConfiguration": if (message.text && message.apiConfiguration) { try { diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 20bb5759645..093485fa3ee 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -14,6 +14,7 @@ import type { OrganizationAllowList, ShareVisibility, QueuedMessage, + SerializedCustomToolDefinition, } from "@roo-code/types" import { GitCommit } from "../utils/git" @@ -133,6 +134,7 @@ export interface ExtensionMessage { | "browserSessionUpdate" | "browserSessionNavigate" | "claudeCodeRateLimits" + | "customToolsResult" text?: string payload?: any // Add a generic payload for now, can refine later // Checkpoint warning message @@ -218,6 +220,7 @@ export interface ExtensionMessage { browserSessionMessages?: ClineMessage[] // For browser session panel updates isBrowserSessionActive?: boolean // For browser session panel updates stepIndex?: number // For browserSessionNavigate: the target step index to display + tools?: SerializedCustomToolDefinition[] // For customToolsResult } export type ExtensionState = Pick< diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 970208a2a3e..6c878159940 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -180,6 +180,7 @@ export interface WebviewMessage { | "openDebugUiHistory" | "downloadErrorDiagnostics" | "requestClaudeCodeRateLimits" + | "refreshCustomTools" text?: string editedMessageContent?: string tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud" diff --git a/src/shared/__tests__/experiments.spec.ts b/src/shared/__tests__/experiments.spec.ts index 23116b19b20..0b43302611b 100644 --- a/src/shared/__tests__/experiments.spec.ts +++ b/src/shared/__tests__/experiments.spec.ts @@ -32,6 +32,7 @@ describe("experiments", () => { imageGeneration: false, runSlashCommand: false, multipleNativeToolCalls: false, + customTools: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) @@ -44,6 +45,7 @@ describe("experiments", () => { imageGeneration: false, runSlashCommand: false, multipleNativeToolCalls: false, + customTools: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true) }) @@ -56,6 +58,7 @@ describe("experiments", () => { imageGeneration: false, runSlashCommand: false, multipleNativeToolCalls: false, + customTools: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) diff --git a/src/shared/experiments.ts b/src/shared/experiments.ts index 0b11edfcdf0..ad3aeca8634 100644 --- a/src/shared/experiments.ts +++ b/src/shared/experiments.ts @@ -7,6 +7,7 @@ export const EXPERIMENT_IDS = { IMAGE_GENERATION: "imageGeneration", RUN_SLASH_COMMAND: "runSlashCommand", MULTIPLE_NATIVE_TOOL_CALLS: "multipleNativeToolCalls", + CUSTOM_TOOLS: "customTools", } as const satisfies Record type _AssertExperimentIds = AssertEqual>> @@ -24,6 +25,7 @@ export const experimentConfigsMap: Record = { IMAGE_GENERATION: { enabled: false }, RUN_SLASH_COMMAND: { enabled: false }, MULTIPLE_NATIVE_TOOL_CALLS: { enabled: false }, + CUSTOM_TOOLS: { enabled: false }, } export const experimentDefault = Object.fromEntries( diff --git a/webview-ui/src/components/settings/CustomToolsSettings.tsx b/webview-ui/src/components/settings/CustomToolsSettings.tsx new file mode 100644 index 00000000000..176272734cd --- /dev/null +++ b/webview-ui/src/components/settings/CustomToolsSettings.tsx @@ -0,0 +1,173 @@ +import { useState, useEffect, useCallback, useMemo } from "react" +import { useEvent } from "react-use" +import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react" +import { RefreshCw, Loader2 } from "lucide-react" + +import type { SerializedCustomToolDefinition } from "@roo-code/types" + +import { useAppTranslation } from "@/i18n/TranslationContext" + +import { vscode } from "@/utils/vscode" + +import { Button } from "@/components/ui" + +interface ToolParameter { + name: string + type: string + description?: string + required: boolean +} + +interface ProcessedTool { + name: string + description: string + parameters: ToolParameter[] +} + +interface CustomToolsSettingsProps { + enabled: boolean + onChange: (enabled: boolean) => void +} + +export const CustomToolsSettings = ({ enabled, onChange }: CustomToolsSettingsProps) => { + const { t } = useAppTranslation() + const [tools, setTools] = useState([]) + const [isRefreshing, setIsRefreshing] = useState(false) + const [refreshError, setRefreshError] = useState(null) + + useEffect(() => { + if (enabled) { + vscode.postMessage({ type: "refreshCustomTools" }) + } else { + setTools([]) + } + }, [enabled]) + + useEvent("message", (event: MessageEvent) => { + const message = event.data + + if (message.type === "customToolsResult") { + setTools(message.tools || []) + setIsRefreshing(false) + setRefreshError(message.error ?? null) + } + }) + + const onRefresh = useCallback(() => { + setIsRefreshing(true) + setRefreshError(null) + vscode.postMessage({ type: "refreshCustomTools" }) + }, []) + + const processedTools = useMemo( + () => + tools.map((tool) => { + const params = tool.parameters + const properties = (params?.properties ?? {}) as Record + const required = (params?.required as string[] | undefined) ?? [] + + return { + name: tool.name, + description: tool.description, + parameters: Object.entries(properties).map(([name, def]) => ({ + name, + type: def.type ?? "any", + description: def.description, + required: required.includes(name), + })), + } + }), + [tools], + ) + + return ( +
+
+
+ onChange(e.target.checked)}> + {t("settings:experimental.CUSTOM_TOOLS.name")} + +
+

+ {t("settings:experimental.CUSTOM_TOOLS.description")} +

+
+ + {enabled && ( +
+
+ + +
+ + {refreshError && ( +
+ {t("settings:experimental.CUSTOM_TOOLS.refreshError")}: {refreshError} +
+ )} + + {processedTools.length === 0 ? ( +

+ {t("settings:experimental.CUSTOM_TOOLS.noTools")} +

+ ) : ( +
+ {processedTools.map((tool) => ( +
+
{tool.name}
+

{tool.description}

+ {tool.parameters.length > 0 && ( +
+
+ {t("settings:experimental.CUSTOM_TOOLS.toolParameters")}: +
+
+ {tool.parameters.map((param) => ( +
+ + {param.name} + + + ({param.type}) + + {param.required && ( + + required + + )} + {param.description && ( + + — {param.description} + + )} +
+ ))} +
+
+ )} +
+ ))} +
+ )} +
+ )} +
+ ) +} diff --git a/webview-ui/src/components/settings/ExperimentalSettings.tsx b/webview-ui/src/components/settings/ExperimentalSettings.tsx index a1719a954c4..982de949098 100644 --- a/webview-ui/src/components/settings/ExperimentalSettings.tsx +++ b/webview-ui/src/components/settings/ExperimentalSettings.tsx @@ -13,6 +13,7 @@ import { SectionHeader } from "./SectionHeader" import { Section } from "./Section" import { ExperimentalFeature } from "./ExperimentalFeature" import { ImageGenerationSettings } from "./ImageGenerationSettings" +import { CustomToolsSettings } from "./CustomToolsSettings" type ExperimentalSettingsProps = HTMLAttributes & { experiments: Experiments @@ -92,6 +93,15 @@ export const ExperimentalSettings = ({ /> ) } + if (config[0] === "CUSTOM_TOOLS") { + return ( + setExperimentEnabled(EXPERIMENT_IDS.CUSTOM_TOOLS, enabled)} + /> + ) + } return ( { runSlashCommand: false, nativeToolCalling: false, multipleNativeToolCalls: false, + customTools: false, } as Record, checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS + 5, } @@ -263,6 +264,7 @@ describe("mergeExtensionState", () => { runSlashCommand: false, nativeToolCalling: false, multipleNativeToolCalls: false, + customTools: false, }) }) }) diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 20b1e0d510f..abcfb3d4c4a 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -824,6 +824,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Crides paral·leles a eines", "description": "Quan està activat, el protocol natiu pot executar múltiples eines en un sol torn de missatge de l'assistent." + }, + "CUSTOM_TOOLS": { + "name": "Habilitar eines personalitzades", + "description": "Quan està habilitat, Roo pot carregar i utilitzar eines TypeScript/JavaScript personalitzades des del directori .roo/tools del vostre projecte.", + "toolsHeader": "Eines personalitzades disponibles", + "noTools": "No s'han carregat eines personalitzades. Afegiu fitxers .ts o .js al directori .roo/tools del vostre projecte.", + "refreshButton": "Actualitzar", + "refreshing": "Actualitzant...", + "refreshSuccess": "Eines actualitzades correctament", + "refreshError": "Error en actualitzar les eines", + "toolParameters": "Paràmetres" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index d68f7e7d32a..7d9e211b1c6 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -824,6 +824,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Parallele Tool-Aufrufe", "description": "Wenn aktiviert, kann das native Protokoll mehrere Tools in einer einzigen Assistenten-Nachrichtenrunde ausführen." + }, + "CUSTOM_TOOLS": { + "name": "Benutzerdefinierte Tools aktivieren", + "description": "Wenn aktiviert, kann Roo benutzerdefinierte TypeScript/JavaScript-Tools aus dem .roo/tools-Verzeichnis deines Projekts laden und verwenden.", + "toolsHeader": "Verfügbare benutzerdefinierte Tools", + "noTools": "Keine benutzerdefinierten Tools geladen. Füge .ts- oder .js-Dateien zum .roo/tools-Verzeichnis deines Projekts hinzu.", + "refreshButton": "Aktualisieren", + "refreshing": "Aktualisieren...", + "refreshSuccess": "Tools erfolgreich aktualisiert", + "refreshError": "Fehler beim Aktualisieren der Tools", + "toolParameters": "Parameter" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 2396bded682..32a401cd0d6 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -833,6 +833,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Parallel tool calls", "description": "When enabled, the native protocol can execute multiple tools in a single assistant message turn." + }, + "CUSTOM_TOOLS": { + "name": "Enable custom tools", + "description": "When enabled, Roo can load and use custom TypeScript/JavaScript tools from your project's .roo/tools directory. Note: these tools will automatically be auto-approved.", + "toolsHeader": "Available Custom Tools", + "noTools": "No custom tools loaded. Add .ts or .js files to your project's .roo/tools directory.", + "refreshButton": "Refresh", + "refreshing": "Refreshing...", + "refreshSuccess": "Tools refreshed successfully", + "refreshError": "Failed to refresh tools", + "toolParameters": "Parameters" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 6c03855056f..3a83c21a23e 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -824,6 +824,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Llamadas paralelas a herramientas", "description": "Cuando está habilitado, el protocolo nativo puede ejecutar múltiples herramientas en un solo turno de mensaje del asistente." + }, + "CUSTOM_TOOLS": { + "name": "Habilitar herramientas personalizadas", + "description": "Cuando está habilitado, Roo puede cargar y usar herramientas TypeScript/JavaScript personalizadas desde el directorio .roo/tools de tu proyecto.", + "toolsHeader": "Herramientas personalizadas disponibles", + "noTools": "No hay herramientas personalizadas cargadas. Añade archivos .ts o .js al directorio .roo/tools de tu proyecto.", + "refreshButton": "Actualizar", + "refreshing": "Actualizando...", + "refreshSuccess": "Herramientas actualizadas correctamente", + "refreshError": "Error al actualizar las herramientas", + "toolParameters": "Parámetros" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 9fb20036865..99f0406f66b 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -824,6 +824,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Appels d'outils parallèles", "description": "Lorsqu'activé, le protocole natif peut exécuter plusieurs outils en un seul tour de message d'assistant." + }, + "CUSTOM_TOOLS": { + "name": "Activer les outils personnalisés", + "description": "Lorsqu'activé, Roo peut charger et utiliser des outils TypeScript/JavaScript personnalisés à partir du répertoire .roo/tools de votre projet.", + "toolsHeader": "Outils personnalisés disponibles", + "noTools": "Aucun outil personnalisé chargé. Ajoutez des fichiers .ts ou .js au répertoire .roo/tools de votre projet.", + "refreshButton": "Actualiser", + "refreshing": "Actualisation...", + "refreshSuccess": "Outils actualisés avec succès", + "refreshError": "Échec de l'actualisation des outils", + "toolParameters": "Paramètres" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index ee4f55d243a..65cbee91caf 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "समानांतर टूल कॉल", "description": "सक्षम होने पर, नेटिव प्रोटोकॉल एकल सहायक संदेश टर्न में एकाधिक टूल निष्पादित कर सकता है।" + }, + "CUSTOM_TOOLS": { + "name": "कस्टम टूल्स सक्षम करें", + "description": "सक्षम होने पर, Roo आपके प्रोजेक्ट की .roo/tools निर्देशिका से कस्टम TypeScript/JavaScript टूल्स लोड और उपयोग कर सकता है।", + "toolsHeader": "उपलब्ध कस्टम टूल्स", + "noTools": "कोई कस्टम टूल लोड नहीं हुआ। अपने प्रोजेक्ट की .roo/tools निर्देशिका में .ts या .js फ़ाइलें जोड़ें।", + "refreshButton": "रिफ्रेश करें", + "refreshing": "रिफ्रेश हो रहा है...", + "refreshSuccess": "टूल्स सफलतापूर्वक रिफ्रेश हुए", + "refreshError": "टूल्स रिफ्रेश करने में विफल", + "toolParameters": "पैरामीटर्स" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 79bf7ba7bff..8cfcbb8f1c7 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -854,6 +854,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Panggilan tool paralel", "description": "Ketika diaktifkan, protokol native dapat mengeksekusi beberapa tool dalam satu giliran pesan asisten." + }, + "CUSTOM_TOOLS": { + "name": "Aktifkan tool kustom", + "description": "Ketika diaktifkan, Roo dapat memuat dan menggunakan tool TypeScript/JavaScript kustom dari direktori .roo/tools proyek Anda.", + "toolsHeader": "Tool Kustom yang Tersedia", + "noTools": "Tidak ada tool kustom yang dimuat. Tambahkan file .ts atau .js ke direktori .roo/tools proyek Anda.", + "refreshButton": "Refresh", + "refreshing": "Merefresh...", + "refreshSuccess": "Tool berhasil direfresh", + "refreshError": "Gagal merefresh tool", + "toolParameters": "Parameter" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index a7db28f7513..6967ba6d0c9 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Chiamate parallele agli strumenti", "description": "Quando abilitato, il protocollo nativo può eseguire più strumenti in un singolo turno di messaggio dell'assistente." + }, + "CUSTOM_TOOLS": { + "name": "Abilita strumenti personalizzati", + "description": "Quando abilitato, Roo può caricare e utilizzare strumenti TypeScript/JavaScript personalizzati dalla directory .roo/tools del tuo progetto.", + "toolsHeader": "Strumenti personalizzati disponibili", + "noTools": "Nessuno strumento personalizzato caricato. Aggiungi file .ts o .js alla directory .roo/tools del tuo progetto.", + "refreshButton": "Aggiorna", + "refreshing": "Aggiornamento...", + "refreshSuccess": "Strumenti aggiornati con successo", + "refreshError": "Impossibile aggiornare gli strumenti", + "toolParameters": "Parametri" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index b80892cd111..36fc3e3bf72 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "並列ツール呼び出し", "description": "有効にすると、ネイティブプロトコルは単一のアシスタントメッセージターンで複数のツールを実行できます。" + }, + "CUSTOM_TOOLS": { + "name": "カスタムツールを有効化", + "description": "有効にすると、Rooはプロジェクトの.roo/toolsディレクトリからカスタムTypeScript/JavaScriptツールを読み込んで使用できます。", + "toolsHeader": "利用可能なカスタムツール", + "noTools": "カスタムツールが読み込まれていません。プロジェクトの.roo/toolsディレクトリに.tsまたは.jsファイルを追加してください。", + "refreshButton": "更新", + "refreshing": "更新中...", + "refreshSuccess": "ツールが正常に更新されました", + "refreshError": "ツールの更新に失敗しました", + "toolParameters": "パラメーター" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 85ab220dfea..32c5a4df84f 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "병렬 도구 호출", "description": "활성화되면 네이티브 프로토콜이 단일 어시스턴트 메시지 턴에서 여러 도구를 실행할 수 있습니다." + }, + "CUSTOM_TOOLS": { + "name": "사용자 정의 도구 활성화", + "description": "활성화하면 Roo가 프로젝트의 .roo/tools 디렉터리에서 사용자 정의 TypeScript/JavaScript 도구를 로드하고 사용할 수 있습니다.", + "toolsHeader": "사용 가능한 사용자 정의 도구", + "noTools": "로드된 사용자 정의 도구가 없습니다. 프로젝트의 .roo/tools 디렉터리에 .ts 또는 .js 파일을 추가하세요.", + "refreshButton": "새로고침", + "refreshing": "새로고침 중...", + "refreshSuccess": "도구가 성공적으로 새로고침되었습니다", + "refreshError": "도구 새로고침에 실패했습니다", + "toolParameters": "매개변수" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index be2f2233628..fe93eea35c1 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Parallelle tool-aanroepen", "description": "Wanneer ingeschakeld, kan het native protocol meerdere tools uitvoeren in één enkele assistent-berichtbeurt." + }, + "CUSTOM_TOOLS": { + "name": "Aangepaste tools inschakelen", + "description": "Indien ingeschakeld kan Roo aangepaste TypeScript/JavaScript-tools laden en gebruiken uit de map .roo/tools van je project.", + "toolsHeader": "Beschikbare aangepaste tools", + "noTools": "Geen aangepaste tools geladen. Voeg .ts- of .js-bestanden toe aan de map .roo/tools van je project.", + "refreshButton": "Vernieuwen", + "refreshing": "Vernieuwen...", + "refreshSuccess": "Tools succesvol vernieuwd", + "refreshError": "Fout bij vernieuwen van tools", + "toolParameters": "Parameters" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 137bdabf3aa..c1563f2e23f 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Równoległe wywołania narzędzi", "description": "Po włączeniu protokół natywny może wykonywać wiele narzędzi w jednej turze wiadomości asystenta." + }, + "CUSTOM_TOOLS": { + "name": "Włącz niestandardowe narzędzia", + "description": "Gdy włączone, Roo może ładować i używać niestandardowych narzędzi TypeScript/JavaScript z katalogu .roo/tools Twojego projektu.", + "toolsHeader": "Dostępne niestandardowe narzędzia", + "noTools": "Nie załadowano niestandardowych narzędzi. Dodaj pliki .ts lub .js do katalogu .roo/tools swojego projektu.", + "refreshButton": "Odśwież", + "refreshing": "Odświeżanie...", + "refreshSuccess": "Narzędzia odświeżone pomyślnie", + "refreshError": "Nie udało się odświeżyć narzędzi", + "toolParameters": "Parametry" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index ea459ffdeb0..4df36d14dff 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Chamadas paralelas de ferramentas", "description": "Quando habilitado, o protocolo nativo pode executar múltiplas ferramentas em um único turno de mensagem do assistente." + }, + "CUSTOM_TOOLS": { + "name": "Ativar ferramentas personalizadas", + "description": "Quando habilitado, o Roo pode carregar e usar ferramentas TypeScript/JavaScript personalizadas do diretório .roo/tools do seu projeto.", + "toolsHeader": "Ferramentas personalizadas disponíveis", + "noTools": "Nenhuma ferramenta personalizada carregada. Adicione arquivos .ts ou .js ao diretório .roo/tools do seu projeto.", + "refreshButton": "Atualizar", + "refreshing": "Atualizando...", + "refreshSuccess": "Ferramentas atualizadas com sucesso", + "refreshError": "Falha ao atualizar ferramentas", + "toolParameters": "Parâmetros" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 57560a9d33b..1057c86115d 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Параллельные вызовы инструментов", "description": "При включении нативный протокол может выполнять несколько инструментов в одном ходе сообщения ассистента." + }, + "CUSTOM_TOOLS": { + "name": "Включить пользовательские инструменты", + "description": "Если включено, Roo сможет загружать и использовать пользовательские инструменты TypeScript/JavaScript из каталога .roo/tools вашего проекта.", + "toolsHeader": "Доступные пользовательские инструменты", + "noTools": "Пользовательские инструменты не загружены. Добавьте файлы .ts или .js в каталог .roo/tools вашего проекта.", + "refreshButton": "Обновить", + "refreshing": "Обновление...", + "refreshSuccess": "Инструменты успешно обновлены", + "refreshError": "Не удалось обновить инструменты", + "toolParameters": "Параметры" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index bb2b1d38432..c8bd9888ffe 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Paralel araç çağrıları", "description": "Etkinleştirildiğinde, yerel protokol tek bir asistan mesaj turunda birden fazla araç yürütebilir." + }, + "CUSTOM_TOOLS": { + "name": "Özel araçları etkinleştir", + "description": "Etkinleştirildiğinde, Roo projenizin .roo/tools dizininden özel TypeScript/JavaScript araçlarını yükleyebilir ve kullanabilir.", + "toolsHeader": "Kullanılabilir Özel Araçlar", + "noTools": "Özel araç yüklenmedi. Projenizin .roo/tools dizinine .ts veya .js dosyaları ekleyin.", + "refreshButton": "Yenile", + "refreshing": "Yenileniyor...", + "refreshSuccess": "Araçlar başarıyla yenilendi", + "refreshError": "Araçlar yenilenemedi", + "toolParameters": "Parametreler" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 8425d8d6ef5..4f1a38157d5 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "Lệnh gọi công cụ song song", "description": "Khi được bật, giao thức native có thể thực thi nhiều công cụ trong một lượt tin nhắn của trợ lý." + }, + "CUSTOM_TOOLS": { + "name": "Bật công cụ tùy chỉnh", + "description": "Khi được bật, Roo có thể tải và sử dụng các công cụ TypeScript/JavaScript tùy chỉnh từ thư mục .roo/tools của dự án của bạn.", + "toolsHeader": "Công cụ tùy chỉnh có sẵn", + "noTools": "Không có công cụ tùy chỉnh nào được tải. Thêm tệp .ts hoặc .js vào thư mục .roo/tools của dự án của bạn.", + "refreshButton": "Làm mới", + "refreshing": "Đang làm mới...", + "refreshSuccess": "Làm mới công cụ thành công", + "refreshError": "Không thể làm mới công cụ", + "toolParameters": "Thông số" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 327eb9f8c76..dd88c8fd20b 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "并行工具调用", "description": "启用后,原生协议可在单个助手消息轮次中执行多个工具。" + }, + "CUSTOM_TOOLS": { + "name": "启用自定义工具", + "description": "启用后,Roo 可以从项目中的 .roo/tools 目录加载并使用自定义 TypeScript/JavaScript 工具。", + "toolsHeader": "可用自定义工具", + "noTools": "未加载自定义工具。请向项目的 .roo/tools 目录添加 .ts 或 .js 文件。", + "refreshButton": "刷新", + "refreshing": "正在刷新...", + "refreshSuccess": "工具刷新成功", + "refreshError": "工具刷新失败", + "toolParameters": "参数" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 4967a7d6791..221ad881a5b 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -825,6 +825,17 @@ "MULTIPLE_NATIVE_TOOL_CALLS": { "name": "並行工具呼叫", "description": "啟用後,原生協定可在單個助理訊息輪次中執行多個工具。" + }, + "CUSTOM_TOOLS": { + "name": "啟用自訂工具", + "description": "啟用後,Roo 可以從專案中的 .roo/tools 目錄載入並使用自訂 TypeScript/JavaScript 工具。", + "toolsHeader": "可用自訂工具", + "noTools": "未載入自訂工具。請向專案的 .roo/tools 目錄新增 .ts 或 .js 檔案。", + "refreshButton": "重新整理", + "refreshing": "正在重新整理...", + "refreshSuccess": "工具重新整理成功", + "refreshError": "工具重新整理失敗", + "toolParameters": "參數" } }, "promptCaching": {