diff --git a/packages/build/src/__tests__/index.test.ts b/packages/build/src/__tests__/index.test.ts index 96b8f3d8bba..8f5f6c711e5 100644 --- a/packages/build/src/__tests__/index.test.ts +++ b/packages/build/src/__tests__/index.test.ts @@ -100,12 +100,6 @@ describe("generatePackageJson", () => { default: "", description: "%settings.customStoragePath.description%", }, - "roo-cline.toolProtocol": { - type: "string", - enum: ["xml", "native"], - default: "xml", - description: "%settings.toolProtocol.description%", - }, }, }, }, @@ -219,12 +213,6 @@ describe("generatePackageJson", () => { default: "", description: "%settings.customStoragePath.description%", }, - "roo-code-nightly.toolProtocol": { - type: "string", - enum: ["xml", "native"], - default: "xml", - description: "%settings.toolProtocol.description%", - }, }, }, }, diff --git a/packages/types/src/experiment.ts b/packages/types/src/experiment.ts index 37c6eecee75..05bff5706a3 100644 --- a/packages/types/src/experiment.ts +++ b/packages/types/src/experiment.ts @@ -12,6 +12,7 @@ export const experimentIds = [ "preventFocusDisruption", "imageGeneration", "runSlashCommand", + "nativeToolCalling", ] as const export const experimentIdsSchema = z.enum(experimentIds) @@ -28,6 +29,7 @@ export const experimentsSchema = z.object({ preventFocusDisruption: z.boolean().optional(), imageGeneration: z.boolean().optional(), runSlashCommand: z.boolean().optional(), + nativeToolCalling: 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 3ab7fddcb37..55d91ae6257 100644 --- a/src/core/assistant-message/presentAssistantMessage.ts +++ b/src/core/assistant-message/presentAssistantMessage.ts @@ -280,18 +280,18 @@ export async function presentAssistantMessage(cline: Task) { // Track if we've already pushed a tool result for this tool call (native protocol only) let hasToolResult = false - const pushToolResult = (content: ToolResponse) => { - // Check if we're using native tool protocol - const toolProtocol = resolveToolProtocol( - cline.apiConfiguration, - cline.api.getModel().info, - cline.apiConfiguration.apiProvider, - ) - const isNative = isNativeProtocol(toolProtocol) - - // Get the tool call ID if this is a native tool call - const toolCallId = (block as any).id + // Check if we're using native tool protocol (do this once before defining pushToolResult) + const state = await cline.providerRef.deref()?.getState() + const toolProtocol = resolveToolProtocol( + cline.apiConfiguration, + cline.api.getModel().info, + cline.apiConfiguration.apiProvider, + state?.experiments, + ) + const isNative = isNativeProtocol(toolProtocol) + const toolCallId = (block as any).id + const pushToolResult = (content: ToolResponse) => { if (isNative && toolCallId) { // For native protocol, only allow ONE tool_result per tool call if (hasToolResult) { @@ -518,10 +518,12 @@ export async function presentAssistantMessage(cline: Task) { await checkpointSaveAndMark(cline) // Check if native protocol is enabled - if so, always use single-file class-based tool + const state = await cline.providerRef.deref()?.getState() const applyDiffToolProtocol = resolveToolProtocol( cline.apiConfiguration, cline.api.getModel().info, cline.apiConfiguration.apiProvider, + state?.experiments, ) if (isNativeProtocol(applyDiffToolProtocol)) { await applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, { diff --git a/src/core/prompts/responses.ts b/src/core/prompts/responses.ts index 6f6ad465f04..ace37b7c68f 100644 --- a/src/core/prompts/responses.ts +++ b/src/core/prompts/responses.ts @@ -3,8 +3,7 @@ import * as path from "path" import * as diff from "diff" import { RooIgnoreController, LOCK_TEXT_SYMBOL } from "../ignore/RooIgnoreController" import { RooProtectedController } from "../protect/RooProtectedController" -import { ToolProtocol, isNativeProtocol } from "@roo-code/types" -import { getToolProtocolFromSettings } from "../../utils/toolProtocol" +import { ToolProtocol, isNativeProtocol, TOOL_PROTOCOL } from "@roo-code/types" export const formatResponse = { toolDenied: () => `The user denied this operation.`, @@ -245,10 +244,10 @@ Always ensure you provide all required parameters for the tool you wish to use.` /** * Gets the appropriate tool use instructions reminder based on the protocol. * - * @param protocol - Optional tool protocol, falls back to default if not provided + * @param protocol - Optional tool protocol, defaults to XML if not provided * @returns The tool use instructions reminder text */ function getToolInstructionsReminder(protocol?: ToolProtocol): string { - const effectiveProtocol = protocol ?? getToolProtocolFromSettings() + const effectiveProtocol = protocol ?? TOOL_PROTOCOL.XML return isNativeProtocol(effectiveProtocol) ? toolUseInstructionsReminderNative : toolUseInstructionsReminder } diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index cc4558a74b4..dbb9529c2e0 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -10,7 +10,7 @@ import delay from "delay" import pWaitFor from "p-wait-for" import { serializeError } from "serialize-error" import { Package } from "../../shared/package" -import { getCurrentToolProtocol, formatToolInvocation } from "../tools/helpers/toolResultFormatting" +import { formatToolInvocation } from "../tools/helpers/toolResultFormatting" import { type TaskLike, @@ -46,7 +46,6 @@ import { } from "@roo-code/types" import { TelemetryService } from "@roo-code/telemetry" import { CloudService, BridgeOrchestrator } from "@roo-code/cloud" -import { getToolProtocolFromSettings } from "../../utils/toolProtocol" import { resolveToolProtocol } from "../../utils/resolveToolProtocol" // api @@ -321,6 +320,7 @@ export class Task extends EventEmitter implements TaskLike { task, images, historyItem, + experiments: experimentsConfig, startTask = true, rootTask, parentTask, @@ -410,10 +410,12 @@ export class Task extends EventEmitter implements TaskLike { // Initialize the assistant message parser only for XML protocol. // For native protocol, tool calls come as tool_call chunks, not XML. + // experiments is always provided via TaskOptions (defaults to experimentDefault in provider) const toolProtocol = resolveToolProtocol( this.apiConfiguration, this.api.getModel().info, this.apiConfiguration.apiProvider, + experimentsConfig, ) this.assistantMessageParser = toolProtocol === "xml" ? new AssistantMessageParser() : undefined @@ -1268,7 +1270,13 @@ export class Task extends EventEmitter implements TaskLike { } without value for required parameter '${paramName}'. Retrying...`, ) const modelInfo = this.api.getModel().info - const toolProtocol = resolveToolProtocol(this.apiConfiguration, modelInfo, this.apiConfiguration.apiProvider) + const state = await this.providerRef.deref()?.getState() + const toolProtocol = resolveToolProtocol( + this.apiConfiguration, + modelInfo, + this.apiConfiguration.apiProvider, + state?.experiments, + ) return formatResponse.toolError(formatResponse.missingToolParameterError(paramName, toolProtocol)) } @@ -1409,10 +1417,12 @@ export class Task extends EventEmitter implements TaskLike { // v2.0 xml tags refactor caveat: since we don't use tools anymore, we need to replace all tool use blocks with a text block since the API disallows conversations with tool uses and no tool schema // Now also protocol-aware: format according to current protocol setting + const state = await this.providerRef.deref()?.getState() const protocol = resolveToolProtocol( this.apiConfiguration, this.api.getModel().info, this.apiConfiguration.apiProvider, + state?.experiments, ) const useNative = isNativeProtocol(protocol) @@ -1786,10 +1796,12 @@ export class Task extends EventEmitter implements TaskLike { break } else { const modelInfo = this.api.getModel().info + const state = await this.providerRef.deref()?.getState() const toolProtocol = resolveToolProtocol( this.apiConfiguration, modelInfo, this.apiConfiguration.apiProvider, + state?.experiments, ) nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed(toolProtocol) }] this.consecutiveMistakeCount++ @@ -2436,11 +2448,13 @@ export class Task extends EventEmitter implements TaskLike { const parsedBlocks = this.assistantMessageParser.getContentBlocks() // Check if we're using native protocol + const state = await this.providerRef.deref()?.getState() const isNative = isNativeProtocol( resolveToolProtocol( this.apiConfiguration, this.api.getModel().info, this.apiConfiguration.apiProvider, + state?.experiments, ), ) @@ -2581,10 +2595,12 @@ export class Task extends EventEmitter implements TaskLike { if (!didToolUse) { const modelInfo = this.api.getModel().info + const state = await this.providerRef.deref()?.getState() const toolProtocol = resolveToolProtocol( this.apiConfiguration, modelInfo, this.apiConfiguration.apiProvider, + state?.experiments, ) this.userMessageContent.push({ type: "text", text: formatResponse.noToolsUsed(toolProtocol) }) this.consecutiveMistakeCount++ @@ -2610,12 +2626,14 @@ export class Task extends EventEmitter implements TaskLike { // apiConversationHistory at line 1876. Since the assistant failed to respond, // we need to remove that message before retrying to avoid having two consecutive // user messages (which would cause tool_result validation errors). + let state = await this.providerRef.deref()?.getState() if ( isNativeProtocol( resolveToolProtocol( this.apiConfiguration, this.api.getModel().info, this.apiConfiguration.apiProvider, + state?.experiments, ), ) && this.apiConversationHistory.length > 0 @@ -2628,7 +2646,7 @@ export class Task extends EventEmitter implements TaskLike { } // Check if we should auto-retry or prompt the user - const state = await this.providerRef.deref()?.getState() + // Reuse the state variable from above if (state?.autoApprovalEnabled && state?.alwaysApproveResubmit) { // Auto-retry with backoff - don't persist failure message when retrying const errorMsg = @@ -2681,12 +2699,14 @@ export class Task extends EventEmitter implements TaskLike { } else { // User declined to retry // For native protocol, re-add the user message we removed + // Reuse the state variable from above if ( isNativeProtocol( resolveToolProtocol( this.apiConfiguration, this.api.getModel().info, this.apiConfiguration.apiProvider, + state?.experiments, ), ) ) { @@ -2791,6 +2811,7 @@ export class Task extends EventEmitter implements TaskLike { apiConfiguration ?? this.apiConfiguration, modelInfo, (apiConfiguration ?? this.apiConfiguration)?.apiProvider, + experiments, ) return SYSTEM_PROMPT( @@ -3030,7 +3051,12 @@ export class Task extends EventEmitter implements TaskLike { // 1. Tool protocol is set to NATIVE // 2. Model supports native tools const modelInfo = this.api.getModel().info - const toolProtocol = resolveToolProtocol(this.apiConfiguration, modelInfo, this.apiConfiguration.apiProvider) + const toolProtocol = resolveToolProtocol( + this.apiConfiguration, + modelInfo, + this.apiConfiguration.apiProvider, + state?.experiments, + ) const shouldIncludeTools = toolProtocol === TOOL_PROTOCOL.NATIVE && (modelInfo.supportsNativeTools ?? false) // Build complete tools array: native tools + dynamic MCP tools, filtered by mode restrictions diff --git a/src/core/tools/MultiApplyDiffTool.ts b/src/core/tools/MultiApplyDiffTool.ts index 9f154591546..8fd893469ca 100644 --- a/src/core/tools/MultiApplyDiffTool.ts +++ b/src/core/tools/MultiApplyDiffTool.ts @@ -62,10 +62,13 @@ export async function applyDiffTool( removeClosingTag: RemoveClosingTag, ) { // Check if native protocol is enabled - if so, always use single-file class-based tool + const provider = cline.providerRef.deref() + const state = await provider?.getState() const toolProtocol = resolveToolProtocol( cline.apiConfiguration, cline.api.getModel().info, cline.apiConfiguration.apiProvider, + state?.experiments, ) if (isNativeProtocol(toolProtocol)) { return applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, { @@ -77,9 +80,7 @@ export async function applyDiffTool( } // Check if MULTI_FILE_APPLY_DIFF experiment is enabled - const provider = cline.providerRef.deref() - if (provider) { - const state = await provider.getState() + if (provider && state) { const isMultiFileApplyDiffEnabled = experiments.isEnabled( state.experiments ?? {}, EXPERIMENT_IDS.MULTI_FILE_APPLY_DIFF, diff --git a/src/core/tools/ReadFileTool.ts b/src/core/tools/ReadFileTool.ts index a87399b763d..24deb195b11 100644 --- a/src/core/tools/ReadFileTool.ts +++ b/src/core/tools/ReadFileTool.ts @@ -109,7 +109,13 @@ export class ReadFileTool extends BaseTool<"read_file"> { const { handleError, pushToolResult } = callbacks const fileEntries = params.files const modelInfo = task.api.getModel().info - const protocol = resolveToolProtocol(task.apiConfiguration, modelInfo, task.apiConfiguration.apiProvider) + const state = await task.providerRef.deref()?.getState() + const protocol = resolveToolProtocol( + task.apiConfiguration, + modelInfo, + task.apiConfiguration.apiProvider, + state?.experiments, + ) const useNative = isNativeProtocol(protocol) if (!fileEntries || fileEntries.length === 0) { diff --git a/src/core/tools/__tests__/applyDiffTool.experiment.spec.ts b/src/core/tools/__tests__/applyDiffTool.experiment.spec.ts index 1d0f4cc01d7..3e3fc0e3dcd 100644 --- a/src/core/tools/__tests__/applyDiffTool.experiment.spec.ts +++ b/src/core/tools/__tests__/applyDiffTool.experiment.spec.ts @@ -156,12 +156,6 @@ describe("applyDiffTool experiment routing", () => { }) it("should use class-based tool when native protocol is enabled regardless of experiment", async () => { - // Enable native protocol - const vscode = await import("vscode") - vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ - get: vi.fn().mockReturnValue(TOOL_PROTOCOL.NATIVE), - } as any) - // Update model to support native tools mockCline.api.getModel = vi.fn().mockReturnValue({ id: "test-model", @@ -176,6 +170,7 @@ describe("applyDiffTool experiment routing", () => { mockProvider.getState.mockResolvedValue({ experiments: { [EXPERIMENT_IDS.MULTI_FILE_APPLY_DIFF]: true, + [EXPERIMENT_IDS.NATIVE_TOOL_CALLING]: true, // Enable native tool calling experiment }, }) ;(applyDiffToolClass.handle as any).mockResolvedValue(undefined) diff --git a/src/core/webview/generateSystemPrompt.ts b/src/core/webview/generateSystemPrompt.ts index f8ac6d250cf..e9f026f834a 100644 --- a/src/core/webview/generateSystemPrompt.ts +++ b/src/core/webview/generateSystemPrompt.ts @@ -70,7 +70,7 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web const canUseBrowserTool = modelSupportsBrowser && modeSupportsBrowser && (browserToolEnabled ?? true) // Resolve tool protocol for system prompt generation - const toolProtocol = resolveToolProtocol(apiConfiguration, modelInfo, apiConfiguration.apiProvider) + const toolProtocol = resolveToolProtocol(apiConfiguration, modelInfo, apiConfiguration.apiProvider, experiments) const systemPrompt = await SYSTEM_PROMPT( provider.context, diff --git a/src/package.json b/src/package.json index 57a2d313ea4..ba5370f84ae 100644 --- a/src/package.json +++ b/src/package.json @@ -436,15 +436,6 @@ "minimum": 1, "maximum": 200, "description": "%settings.codeIndex.embeddingBatchSize.description%" - }, - "roo-cline.toolProtocol": { - "type": "string", - "enum": [ - "xml", - "native" - ], - "default": "xml", - "description": "%settings.toolProtocol.description%" } } } diff --git a/src/package.nls.ca.json b/src/package.nls.ca.json index d26fcf218bc..22d3f633a64 100644 --- a/src/package.nls.ca.json +++ b/src/package.nls.ca.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Activa la càrrega de fitxers AGENTS.md per a regles específiques de l'agent (vegeu https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Temps màxim en segons per esperar les respostes de l'API (0 = sense temps d'espera, 1-3600s, per defecte: 600s). Es recomanen valors més alts per a proveïdors locals com LM Studio i Ollama que poden necessitar més temps de processament.", "settings.newTaskRequireTodos.description": "Requerir el paràmetre de tasques pendents quan es creïn noves tasques amb l'eina new_task", - "settings.codeIndex.embeddingBatchSize.description": "La mida del lot per a operacions d'incrustació durant la indexació de codi. Ajusta això segons els límits del teu proveïdor d'API. Per defecte és 60.", - "settings.toolProtocol.description": "Protocol d'eines a utilitzar per a les interaccions d'IA. XML és el protocol per defecte i recomanat. Natiu és experimental i pot ser que no funcioni amb tots els proveïdors." + "settings.codeIndex.embeddingBatchSize.description": "La mida del lot per a operacions d'incrustació durant la indexació de codi. Ajusta això segons els límits del teu proveïdor d'API. Per defecte és 60." } diff --git a/src/package.nls.de.json b/src/package.nls.de.json index f3c77fd0f55..3931ba000ef 100644 --- a/src/package.nls.de.json +++ b/src/package.nls.de.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Aktiviert das Laden von AGENTS.md-Dateien für agentenspezifische Regeln (siehe https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Maximale Wartezeit in Sekunden auf API-Antworten (0 = kein Timeout, 1-3600s, Standard: 600s). Höhere Werte werden für lokale Anbieter wie LM Studio und Ollama empfohlen, die möglicherweise mehr Verarbeitungszeit benötigen.", "settings.newTaskRequireTodos.description": "Todos-Parameter beim Erstellen neuer Aufgaben mit dem new_task-Tool erfordern", - "settings.codeIndex.embeddingBatchSize.description": "Die Batch-Größe für Embedding-Operationen während der Code-Indexierung. Passe dies an die Limits deines API-Anbieters an. Standard ist 60.", - "settings.toolProtocol.description": "Tool-Protokoll, das für KI-Interaktionen verwendet werden soll. XML ist das Standard- und empfohlene Protokoll. Nativ ist experimentell und funktioniert möglicherweise nicht mit allen Anbietern." + "settings.codeIndex.embeddingBatchSize.description": "Die Batch-Größe für Embedding-Operationen während der Code-Indexierung. Passe dies an die Limits deines API-Anbieters an. Standard ist 60." } diff --git a/src/package.nls.es.json b/src/package.nls.es.json index 7bb988c2f82..0c22cdf9045 100644 --- a/src/package.nls.es.json +++ b/src/package.nls.es.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Habilita la carga de archivos AGENTS.md para reglas específicas del agente (ver https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Tiempo máximo en segundos de espera para las respuestas de la API (0 = sin tiempo de espera, 1-3600s, por defecto: 600s). Se recomiendan valores más altos para proveedores locales como LM Studio y Ollama que puedan necesitar más tiempo de procesamiento.", "settings.newTaskRequireTodos.description": "Requerir el parámetro todos al crear nuevas tareas con la herramienta new_task", - "settings.codeIndex.embeddingBatchSize.description": "El tamaño del lote para operaciones de embedding durante la indexación de código. Ajusta esto según los límites de tu proveedor de API. Por defecto es 60.", - "settings.toolProtocol.description": "Protocolo de herramienta a utilizar para las interacciones de IA. XML es el protocolo predeterminado y recomendado. Nativo es experimental y puede que no funcione con todos los proveedores." + "settings.codeIndex.embeddingBatchSize.description": "El tamaño del lote para operaciones de embedding durante la indexación de código. Ajusta esto según los límites de tu proveedor de API. Por defecto es 60." } diff --git a/src/package.nls.fr.json b/src/package.nls.fr.json index c3de92aecc6..422db278202 100644 --- a/src/package.nls.fr.json +++ b/src/package.nls.fr.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Activer le chargement des fichiers AGENTS.md pour les règles spécifiques à l'agent (voir https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Temps maximum en secondes d'attente pour les réponses de l'API (0 = pas de timeout, 1-3600s, par défaut : 600s). Des valeurs plus élevées sont recommandées pour les fournisseurs locaux comme LM Studio et Ollama qui peuvent nécessiter plus de temps de traitement.", "settings.newTaskRequireTodos.description": "Exiger le paramètre todos lors de la création de nouvelles tâches avec l'outil new_task", - "settings.codeIndex.embeddingBatchSize.description": "La taille du lot pour les opérations d'embedding lors de l'indexation du code. Ajustez ceci selon les limites de votre fournisseur d'API. Par défaut, c'est 60.", - "settings.toolProtocol.description": "Protocole d'outil à utiliser pour les interactions AI. XML est le protocole par défaut et recommandé. Natif est expérimental et peut ne pas fonctionner avec tous les fournisseurs." + "settings.codeIndex.embeddingBatchSize.description": "La taille du lot pour les opérations d'embedding lors de l'indexation du code. Ajustez ceci selon les limites de votre fournisseur d'API. Par défaut, c'est 60." } diff --git a/src/package.nls.hi.json b/src/package.nls.hi.json index 102e1861dbd..6337e9e1a33 100644 --- a/src/package.nls.hi.json +++ b/src/package.nls.hi.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "एजेंट-विशिष्ट नियमों के लिए AGENTS.md फ़ाइलों को लोड करना सक्षम करें (देखें https://agent-rules.org/)", "settings.apiRequestTimeout.description": "एपीआई प्रतिक्रियाओं की प्रतीक्षा करने के लिए सेकंड में अधिकतम समय (0 = कोई टाइमआउट नहीं, 1-3600s, डिफ़ॉल्ट: 600s)। एलएम स्टूडियो और ओलामा जैसे स्थानीय प्रदाताओं के लिए उच्च मानों की सिफारिश की जाती है जिन्हें अधिक प्रसंस्करण समय की आवश्यकता हो सकती है।", "settings.newTaskRequireTodos.description": "new_task टूल के साथ नए कार्य बनाते समय टूडू पैरामीटर की आवश्यकता होती है", - "settings.codeIndex.embeddingBatchSize.description": "कोड इंडेक्सिंग के दौरान एम्बेडिंग ऑपरेशन के लिए बैच साइज़। इसे अपने API प्रदाता की सीमाओं के अनुसार समायोजित करें। डिफ़ॉल्ट 60 है।", - "settings.toolProtocol.description": "एआई इंटरैक्शन के लिए उपयोग करने वाला टूल प्रोटोकॉल। एक्सएमएल डिफ़ॉल्ट और अनुशंसित प्रोटोकॉल है। नेटिव प्रायोगिक है और सभी प्रदाताओं के साथ काम नहीं कर सकता है।" + "settings.codeIndex.embeddingBatchSize.description": "कोड इंडेक्सिंग के दौरान एम्बेडिंग ऑपरेशन के लिए बैच साइज़। इसे अपने API प्रदाता की सीमाओं के अनुसार समायोजित करें। डिफ़ॉल्ट 60 है।" } diff --git a/src/package.nls.id.json b/src/package.nls.id.json index 2b31f368954..1c3025a09d0 100644 --- a/src/package.nls.id.json +++ b/src/package.nls.id.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Aktifkan pemuatan file AGENTS.md untuk aturan khusus agen (lihat https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Waktu maksimum dalam detik untuk menunggu respons API (0 = tidak ada batas waktu, 1-3600s, default: 600s). Nilai yang lebih tinggi disarankan untuk penyedia lokal seperti LM Studio dan Ollama yang mungkin memerlukan lebih banyak waktu pemrosesan.", "settings.newTaskRequireTodos.description": "Memerlukan parameter todos saat membuat tugas baru dengan alat new_task", - "settings.codeIndex.embeddingBatchSize.description": "Ukuran batch untuk operasi embedding selama pengindeksan kode. Sesuaikan ini berdasarkan batas penyedia API kamu. Default adalah 60.", - "settings.toolProtocol.description": "Protokol alat untuk digunakan untuk interaksi AI. XML adalah protokol default dan yang direkomendasikan. Native bersifat eksperimental dan mungkin tidak berfungsi dengan semua penyedia." + "settings.codeIndex.embeddingBatchSize.description": "Ukuran batch untuk operasi embedding selama pengindeksan kode. Sesuaikan ini berdasarkan batas penyedia API kamu. Default adalah 60." } diff --git a/src/package.nls.it.json b/src/package.nls.it.json index d3cedcec141..d0c130e00b1 100644 --- a/src/package.nls.it.json +++ b/src/package.nls.it.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Abilita il caricamento dei file AGENTS.md per regole specifiche dell'agente (vedi https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Tempo massimo in secondi di attesa per le risposte API (0 = nessun timeout, 1-3600s, predefinito: 600s). Valori più alti sono consigliati per provider locali come LM Studio e Ollama che potrebbero richiedere più tempo di elaborazione.", "settings.newTaskRequireTodos.description": "Richiedere il parametro todos quando si creano nuove attività con lo strumento new_task", - "settings.codeIndex.embeddingBatchSize.description": "La dimensione del batch per le operazioni di embedding durante l'indicizzazione del codice. Regola questo in base ai limiti del tuo provider API. Il valore predefinito è 60.", - "settings.toolProtocol.description": "Protocollo dello strumento da utilizzare per le interazioni AI. XML è il protocollo predefinito e consigliato. Nativo è sperimentale e potrebbe non funzionare con tutti i provider." + "settings.codeIndex.embeddingBatchSize.description": "La dimensione del batch per le operazioni di embedding durante l'indicizzazione del codice. Regola questo in base ai limiti del tuo provider API. Il valore predefinito è 60." } diff --git a/src/package.nls.ja.json b/src/package.nls.ja.json index 70acffe0fed..05251f4aed1 100644 --- a/src/package.nls.ja.json +++ b/src/package.nls.ja.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "エージェント固有のルールのためにAGENTS.mdファイルの読み込みを有効にします(参照:https://agent-rules.org/)", "settings.apiRequestTimeout.description": "API応答を待機する最大時間(秒)(0 = タイムアウトなし、1-3600秒、デフォルト: 600秒)。LM StudioやOllamaのような、より多くの処理時間を必要とする可能性のあるローカルプロバイダーには、より高い値が推奨されます。", "settings.newTaskRequireTodos.description": "new_taskツールで新しいタスクを作成する際にtodosパラメータを必須にする", - "settings.codeIndex.embeddingBatchSize.description": "コードインデックス作成中のエンベディング操作のバッチサイズ。APIプロバイダーの制限に基づいてこれを調整してください。デフォルトは60です。", - "settings.toolProtocol.description": "AIインタラクションに使用するツールプロトコル。XMLがデフォルトで推奨されるプロトコルです。ネイティブは実験的なものであり、すべてのプロバイダーで動作するとは限りません。" + "settings.codeIndex.embeddingBatchSize.description": "コードインデックス作成中のエンベディング操作のバッチサイズ。APIプロバイダーの制限に基づいてこれを調整してください。デフォルトは60です。" } diff --git a/src/package.nls.json b/src/package.nls.json index 268ad0fe882..42443e1716d 100644 --- a/src/package.nls.json +++ b/src/package.nls.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Enable loading of AGENTS.md files for agent-specific rules (see https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Maximum time in seconds to wait for API responses (0 = no timeout, 1-3600s, default: 600s). Higher values are recommended for local providers like LM Studio and Ollama that may need more processing time.", "settings.newTaskRequireTodos.description": "Require todos parameter when creating new tasks with the new_task tool", - "settings.codeIndex.embeddingBatchSize.description": "The batch size for embedding operations during code indexing. Adjust this based on your API provider's limits. Default is 60.", - "settings.toolProtocol.description": "Tool protocol to use for AI interactions. XML is the default and recommended protocol. Native is experimental and may not work with all providers." + "settings.codeIndex.embeddingBatchSize.description": "The batch size for embedding operations during code indexing. Adjust this based on your API provider's limits. Default is 60." } diff --git a/src/package.nls.ko.json b/src/package.nls.ko.json index 20d913d1339..dd933733f78 100644 --- a/src/package.nls.ko.json +++ b/src/package.nls.ko.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "에이전트별 규칙에 대한 AGENTS.md 파일 로드를 활성화합니다 (참조: https://agent-rules.org/)", "settings.apiRequestTimeout.description": "API 응답을 기다리는 최대 시간(초) (0 = 시간 초과 없음, 1-3600초, 기본값: 600초). 더 많은 처리 시간이 필요할 수 있는 LM Studio 및 Ollama와 같은 로컬 공급자에게는 더 높은 값을 사용하는 것이 좋습니다.", "settings.newTaskRequireTodos.description": "new_task 도구로 새 작업을 생성할 때 todos 매개변수 필요", - "settings.codeIndex.embeddingBatchSize.description": "코드 인덱싱 중 임베딩 작업의 배치 크기입니다. API 공급자의 제한에 따라 이를 조정하세요. 기본값은 60입니다.", - "settings.toolProtocol.description": "AI 상호 작용에 사용할 도구 프로토콜입니다. XML이 기본 권장 프로토콜입니다. 네이티브는 실험적이며 모든 공급자와 작동하지 않을 수 있습니다." + "settings.codeIndex.embeddingBatchSize.description": "코드 인덱싱 중 임베딩 작업의 배치 크기입니다. API 공급자의 제한에 따라 이를 조정하세요. 기본값은 60입니다." } diff --git a/src/package.nls.nl.json b/src/package.nls.nl.json index d8165f65203..c5f52e55712 100644 --- a/src/package.nls.nl.json +++ b/src/package.nls.nl.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Laden van AGENTS.md-bestanden voor agentspecifieke regels inschakelen (zie https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Maximale tijd in seconden om te wachten op API-reacties (0 = geen time-out, 1-3600s, standaard: 600s). Hogere waarden worden aanbevolen voor lokale providers zoals LM Studio en Ollama die mogelijk meer verwerkingstijd nodig hebben.", "settings.newTaskRequireTodos.description": "Todos-parameter vereisen bij het maken van nieuwe taken met de new_task tool", - "settings.codeIndex.embeddingBatchSize.description": "De batchgrootte voor embedding-operaties tijdens code-indexering. Pas dit aan op basis van de limieten van je API-provider. Standaard is 60.", - "settings.toolProtocol.description": "Toolprotocol te gebruiken voor AI-interacties. XML is het standaard en aanbevolen protocol. Native is experimenteel en werkt mogelijk niet met alle providers." + "settings.codeIndex.embeddingBatchSize.description": "De batchgrootte voor embedding-operaties tijdens code-indexering. Pas dit aan op basis van de limieten van je API-provider. Standaard is 60." } diff --git a/src/package.nls.pl.json b/src/package.nls.pl.json index 2e515337287..1178336d684 100644 --- a/src/package.nls.pl.json +++ b/src/package.nls.pl.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Włącz wczytywanie plików AGENTS.md dla reguł specyficznych dla agenta (zobacz https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Maksymalny czas w sekundach oczekiwania na odpowiedzi API (0 = brak limitu czasu, 1-3600s, domyślnie: 600s). Wyższe wartości są zalecane dla lokalnych dostawców, takich jak LM Studio i Ollama, którzy mogą potrzebować więcej czasu na przetwarzanie.", "settings.newTaskRequireTodos.description": "Wymagaj parametru todos podczas tworzenia nowych zadań za pomocą narzędzia new_task", - "settings.codeIndex.embeddingBatchSize.description": "Rozmiar partii dla operacji osadzania podczas indeksowania kodu. Dostosuj to w oparciu o limity twojego dostawcy API. Domyślnie to 60.", - "settings.toolProtocol.description": "Protokół narzędzi do użycia w interakcjach z AI. XML jest domyślnym i zalecanym protokołem. Natywny jest eksperymentalny i może nie działać ze wszystkimi dostawcami." + "settings.codeIndex.embeddingBatchSize.description": "Rozmiar partii dla operacji osadzania podczas indeksowania kodu. Dostosuj to w oparciu o limity twojego dostawcy API. Domyślnie to 60." } diff --git a/src/package.nls.pt-BR.json b/src/package.nls.pt-BR.json index 49ad1375066..dfed1c8fb13 100644 --- a/src/package.nls.pt-BR.json +++ b/src/package.nls.pt-BR.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Habilita o carregamento de arquivos AGENTS.md para regras específicas do agente (consulte https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Tempo máximo em segundos de espera pelas respostas da API (0 = sem tempo limite, 1-3600s, padrão: 600s). Valores mais altos são recomendados para provedores locais como LM Studio e Ollama que podem precisar de mais tempo de processamento.", "settings.newTaskRequireTodos.description": "Exigir parâmetro todos ao criar novas tarefas com a ferramenta new_task", - "settings.codeIndex.embeddingBatchSize.description": "O tamanho do lote para operações de embedding durante a indexação de código. Ajuste isso com base nos limites do seu provedor de API. O padrão é 60.", - "settings.toolProtocol.description": "Protocolo de ferramenta a ser usado para interações de IA. XML é o protocolo padrão e recomendado. Nativo é experimental e pode não funcionar com todos os provedores." + "settings.codeIndex.embeddingBatchSize.description": "O tamanho do lote para operações de embedding durante a indexação de código. Ajuste isso com base nos limites do seu provedor de API. O padrão é 60." } diff --git a/src/package.nls.ru.json b/src/package.nls.ru.json index 269bb6f1d23..c2284af3695 100644 --- a/src/package.nls.ru.json +++ b/src/package.nls.ru.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Включить загрузку файлов AGENTS.md для специфичных для агента правил (см. https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Максимальное время в секундах для ожидания ответов API (0 = нет тайм-аута, 1-3600 с, по умолчанию: 600 с). Рекомендуются более высокие значения для локальных провайдеров, таких как LM Studio и Ollama, которым может потребоваться больше времени на обработку.", "settings.newTaskRequireTodos.description": "Требовать параметр todos при создании новых задач с помощью инструмента new_task", - "settings.codeIndex.embeddingBatchSize.description": "Размер пакета для операций встраивания во время индексации кода. Настройте это в соответствии с ограничениями вашего API-провайдера. По умолчанию 60.", - "settings.toolProtocol.description": "Протокол инструментов для использования в взаимодействиях с ИИ. XML является протоколом по умолчанию и рекомендуемым. Нативный является экспериментальным и может не работать со всеми провайдерами." + "settings.codeIndex.embeddingBatchSize.description": "Размер пакета для операций встраивания во время индексации кода. Настройте это в соответствии с ограничениями вашего API-провайдера. По умолчанию 60." } diff --git a/src/package.nls.tr.json b/src/package.nls.tr.json index baef09d27ff..21d9a1db93b 100644 --- a/src/package.nls.tr.json +++ b/src/package.nls.tr.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Aracıya özgü kurallar için AGENTS.md dosyalarının yüklenmesini etkinleştirin (bkz. https://agent-rules.org/)", "settings.apiRequestTimeout.description": "API yanıtları için beklenecek maksimum süre (saniye cinsinden) (0 = zaman aşımı yok, 1-3600s, varsayılan: 600s). LM Studio ve Ollama gibi daha fazla işlem süresi gerektirebilecek yerel sağlayıcılar için daha yüksek değerler önerilir.", "settings.newTaskRequireTodos.description": "new_task aracıyla yeni görevler oluştururken todos parametresini gerekli kıl", - "settings.codeIndex.embeddingBatchSize.description": "Kod indeksleme sırasında gömme işlemleri için toplu iş boyutu. Bunu API sağlayıcınızın sınırlarına göre ayarlayın. Varsayılan 60'tır.", - "settings.toolProtocol.description": "Yapay zeka etkileşimleri için kullanılacak araç protokolü. XML, varsayılan ve önerilen protokoldür. Yerel deneyseldir ve tüm sağlayıcılarla çalışmayabilir." + "settings.codeIndex.embeddingBatchSize.description": "Kod indeksleme sırasında gömme işlemleri için toplu iş boyutu. Bunu API sağlayıcınızın sınırlarına göre ayarlayın. Varsayılan 60'tır." } diff --git a/src/package.nls.vi.json b/src/package.nls.vi.json index a53591a53e8..795f8549cf4 100644 --- a/src/package.nls.vi.json +++ b/src/package.nls.vi.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "Bật tải tệp AGENTS.md cho các quy tắc dành riêng cho tác nhân (xem https://agent-rules.org/)", "settings.apiRequestTimeout.description": "Thời gian tối đa tính bằng giây để đợi phản hồi API (0 = không có thời gian chờ, 1-3600 giây, mặc định: 600 giây). Nên sử dụng các giá trị cao hơn cho các nhà cung cấp cục bộ như LM Studio và Ollama có thể cần thêm thời gian xử lý.", "settings.newTaskRequireTodos.description": "Yêu cầu tham số todos khi tạo nhiệm vụ mới với công cụ new_task", - "settings.codeIndex.embeddingBatchSize.description": "Kích thước lô cho các hoạt động nhúng trong quá trình lập chỉ mục mã. Điều chỉnh điều này dựa trên giới hạn của nhà cung cấp API của bạn. Mặc định là 60.", - "settings.toolProtocol.description": "Giao thức công cụ để sử dụng cho các tương tác AI. XML là giao thức mặc định và được khuyến nghị. Bản gốc là thử nghiệm và có thể không hoạt động với tất cả các nhà cung cấp." + "settings.codeIndex.embeddingBatchSize.description": "Kích thước lô cho các hoạt động nhúng trong quá trình lập chỉ mục mã. Điều chỉnh điều này dựa trên giới hạn của nhà cung cấp API của bạn. Mặc định là 60." } diff --git a/src/package.nls.zh-CN.json b/src/package.nls.zh-CN.json index 49bee7e5089..1112abab7d6 100644 --- a/src/package.nls.zh-CN.json +++ b/src/package.nls.zh-CN.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "为特定于代理的规则启用 AGENTS.md 文件的加载(请参阅 https://agent-rules.org/)", "settings.apiRequestTimeout.description": "等待 API 响应的最长时间(秒)(0 = 无超时,1-3600秒,默认值:600秒)。对于像 LM Studio 和 Ollama 这样可能需要更多处理时间的本地提供商,建议使用更高的值。", "settings.newTaskRequireTodos.description": "使用 new_task 工具创建新任务时需要 todos 参数", - "settings.codeIndex.embeddingBatchSize.description": "代码索引期间嵌入操作的批处理大小。根据 API 提供商的限制调整此设置。默认值为 60。", - "settings.toolProtocol.description": "用于 AI 交互的工具协议。XML 是默认且推荐的协议。本机是实验性的,可能不适用于所有提供商。" + "settings.codeIndex.embeddingBatchSize.description": "代码索引期间嵌入操作的批处理大小。根据 API 提供商的限制调整此设置。默认值为 60。" } diff --git a/src/package.nls.zh-TW.json b/src/package.nls.zh-TW.json index f970b215908..a212a7a3538 100644 --- a/src/package.nls.zh-TW.json +++ b/src/package.nls.zh-TW.json @@ -43,6 +43,5 @@ "settings.useAgentRules.description": "為特定於代理的規則啟用 AGENTS.md 檔案的載入(請參閱 https://agent-rules.org/)", "settings.apiRequestTimeout.description": "等待 API 回應的最長時間(秒)(0 = 無超時,1-3600秒,預設值:600秒)。對於像 LM Studio 和 Ollama 這樣可能需要更多處理時間的本地提供商,建議使用更高的值。", "settings.newTaskRequireTodos.description": "使用 new_task 工具建立新工作時需要 todos 參數", - "settings.codeIndex.embeddingBatchSize.description": "程式碼索引期間嵌入操作的批次大小。根據 API 提供商的限制調整此設定。預設值為 60。", - "settings.toolProtocol.description": "用於 AI 互動的工具協議。XML 是預設且推薦的協議。本機是實驗性的,可能不適用於所有提供商。" + "settings.codeIndex.embeddingBatchSize.description": "程式碼索引期間嵌入操作的批次大小。根據 API 提供商的限制調整此設定。預設值為 60。" } diff --git a/src/shared/__tests__/experiments.spec.ts b/src/shared/__tests__/experiments.spec.ts index 8a3c3004416..1731c0dbd87 100644 --- a/src/shared/__tests__/experiments.spec.ts +++ b/src/shared/__tests__/experiments.spec.ts @@ -23,6 +23,15 @@ describe("experiments", () => { }) }) + describe("NATIVE_TOOL_CALLING", () => { + it("is configured correctly", () => { + expect(EXPERIMENT_IDS.NATIVE_TOOL_CALLING).toBe("nativeToolCalling") + expect(experimentConfigsMap.NATIVE_TOOL_CALLING).toMatchObject({ + enabled: false, + }) + }) + }) + describe("isEnabled", () => { it("returns false when POWER_STEERING experiment is not enabled", () => { const experiments: Record = { @@ -31,6 +40,7 @@ describe("experiments", () => { preventFocusDisruption: false, imageGeneration: false, runSlashCommand: false, + nativeToolCalling: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) @@ -42,6 +52,7 @@ describe("experiments", () => { preventFocusDisruption: false, imageGeneration: false, runSlashCommand: false, + nativeToolCalling: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true) }) @@ -53,6 +64,7 @@ describe("experiments", () => { preventFocusDisruption: false, imageGeneration: false, runSlashCommand: false, + nativeToolCalling: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) diff --git a/src/shared/experiments.ts b/src/shared/experiments.ts index 90495c56b70..7d6eb0b6e59 100644 --- a/src/shared/experiments.ts +++ b/src/shared/experiments.ts @@ -6,6 +6,7 @@ export const EXPERIMENT_IDS = { PREVENT_FOCUS_DISRUPTION: "preventFocusDisruption", IMAGE_GENERATION: "imageGeneration", RUN_SLASH_COMMAND: "runSlashCommand", + NATIVE_TOOL_CALLING: "nativeToolCalling", } as const satisfies Record type _AssertExperimentIds = AssertEqual>> @@ -22,6 +23,7 @@ export const experimentConfigsMap: Record = { PREVENT_FOCUS_DISRUPTION: { enabled: false }, IMAGE_GENERATION: { enabled: false }, RUN_SLASH_COMMAND: { enabled: false }, + NATIVE_TOOL_CALLING: { enabled: false }, } export const experimentDefault = Object.fromEntries( diff --git a/src/utils/__tests__/resolveToolProtocol.spec.ts b/src/utils/__tests__/resolveToolProtocol.spec.ts index 93b27315876..58841c431d1 100644 --- a/src/utils/__tests__/resolveToolProtocol.spec.ts +++ b/src/utils/__tests__/resolveToolProtocol.spec.ts @@ -1,20 +1,9 @@ -import { describe, it, expect, vi, beforeEach } from "vitest" +import { describe, it, expect } from "vitest" import { resolveToolProtocol } from "../resolveToolProtocol" import { TOOL_PROTOCOL } from "@roo-code/types" -import type { ProviderSettings, ModelInfo, ProviderName } from "@roo-code/types" -import * as toolProtocolModule from "../toolProtocol" - -// Mock the getToolProtocolFromSettings function -vi.mock("../toolProtocol", () => ({ - getToolProtocolFromSettings: vi.fn(() => "xml"), -})) +import type { ProviderSettings, ModelInfo, Experiments } from "@roo-code/types" describe("resolveToolProtocol", () => { - beforeEach(() => { - // Reset mock before each test - vi.mocked(toolProtocolModule.getToolProtocolFromSettings).mockReturnValue("xml") - }) - describe("Precedence Level 1: User Profile Setting", () => { it("should use profile toolProtocol when explicitly set to xml", () => { const settings: ProviderSettings = { @@ -71,9 +60,8 @@ describe("resolveToolProtocol", () => { }) }) - describe("Precedence Level 2: Global User Preference (VSCode Setting)", () => { - it("should use global setting when no profile setting", () => { - vi.mocked(toolProtocolModule.getToolProtocolFromSettings).mockReturnValue("native") + describe("Precedence Level 2: Experimental Setting (Native Tool Calling)", () => { + it("should use experimental setting when enabled and no profile setting", () => { const settings: ProviderSettings = { apiProvider: "roo", } @@ -83,12 +71,14 @@ describe("resolveToolProtocol", () => { supportsPromptCache: false, supportsNativeTools: true, // Model supports native tools } - const result = resolveToolProtocol(settings, modelInfo, "roo") - expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Global setting wins over provider default + const experiments: Experiments = { + nativeToolCalling: true, // Experimental setting enabled + } + const result = resolveToolProtocol(settings, modelInfo, "roo", experiments) + expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Experimental setting wins over provider default }) - it("should use global setting over model default", () => { - vi.mocked(toolProtocolModule.getToolProtocolFromSettings).mockReturnValue("native") + it("should use experimental setting over model default", () => { const settings: ProviderSettings = { apiProvider: "roo", } @@ -99,14 +89,48 @@ describe("resolveToolProtocol", () => { defaultToolProtocol: "xml", // Model prefers XML supportsNativeTools: true, // But model supports native tools } - const result = resolveToolProtocol(settings, modelInfo, "roo") - expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Global setting wins + const experiments: Experiments = { + nativeToolCalling: true, // Experimental setting enabled + } + const result = resolveToolProtocol(settings, modelInfo, "roo", experiments) + expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Experimental setting wins + }) + + it("should not use experimental setting when disabled", () => { + const settings: ProviderSettings = { + apiProvider: "roo", + } + const modelInfo: ModelInfo = { + maxTokens: 4096, + contextWindow: 128000, + supportsPromptCache: false, + supportsNativeTools: true, + } + const experiments: Experiments = { + nativeToolCalling: false, // Experimental setting disabled + } + const result = resolveToolProtocol(settings, modelInfo, "roo", experiments) + expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to provider default + }) + + it("should not use experimental setting when undefined", () => { + const settings: ProviderSettings = { + apiProvider: "roo", + } + const modelInfo: ModelInfo = { + maxTokens: 4096, + contextWindow: 128000, + supportsPromptCache: false, + supportsNativeTools: true, + } + const experiments: Experiments = {} // nativeToolCalling not defined + const result = resolveToolProtocol(settings, modelInfo, "roo", experiments) + expect(result).toBe(TOOL_PROTOCOL.XML) // Falls back to provider default }) }) describe("Precedence Level 3: Model Default", () => { - it("should use model defaultToolProtocol when no profile or global setting", () => { - vi.mocked(toolProtocolModule.getToolProtocolFromSettings).mockReturnValue("xml") + it("should use model defaultToolProtocol when no profile or experimental setting", () => { const settings: ProviderSettings = { apiProvider: "roo", } @@ -118,7 +142,7 @@ describe("resolveToolProtocol", () => { supportsNativeTools: true, // Model must support native tools } const result = resolveToolProtocol(settings, modelInfo, "roo") - expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Model default wins when global is XML (default) + expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Model default wins when experiment is disabled }) it("should override model capability when model default is present", () => { @@ -271,7 +295,6 @@ describe("resolveToolProtocol", () => { describe("Precedence Level 5: XML Fallback", () => { it("should use XML fallback when no provider is specified and no preferences", () => { - vi.mocked(toolProtocolModule.getToolProtocolFromSettings).mockReturnValue("xml") const settings: ProviderSettings = {} const result = resolveToolProtocol(settings, undefined, undefined) expect(result).toBe(TOOL_PROTOCOL.XML) // XML fallback @@ -279,10 +302,8 @@ describe("resolveToolProtocol", () => { }) describe("Complete Precedence Chain", () => { - it("should respect full precedence: Profile > Model Default > Model Capability > Provider > Global", () => { + it("should respect full precedence: Profile > Experimental > Model Default > Provider", () => { // Set up a scenario with all levels defined - vi.mocked(toolProtocolModule.getToolProtocolFromSettings).mockReturnValue("xml") - const settings: ProviderSettings = { toolProtocol: "native", // Level 1: User profile setting apiProvider: "roo", @@ -292,14 +313,18 @@ describe("resolveToolProtocol", () => { maxTokens: 4096, contextWindow: 128000, supportsPromptCache: false, - defaultToolProtocol: "xml", // Level 2: Model default - supportsNativeTools: true, // Level 3: Model capability + defaultToolProtocol: "xml", // Level 3: Model default + supportsNativeTools: true, // Support check } - // Level 4: Provider default would be "native" for roo - // Level 5: Global setting is "xml" + const experiments: Experiments = { + nativeToolCalling: false, // Level 2: Experimental setting (disabled) + } - const result = resolveToolProtocol(settings, modelInfo, "roo") + // Level 4: Provider default would be XML + // Level 5: XML fallback + + const result = resolveToolProtocol(settings, modelInfo, "roo", experiments) expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Profile setting wins }) @@ -345,10 +370,9 @@ describe("resolveToolProtocol", () => { expect(result).toBe(TOOL_PROTOCOL.XML) // Provider default wins }) - it("should use global setting over provider default", () => { - vi.mocked(toolProtocolModule.getToolProtocolFromSettings).mockReturnValue("native") + it("should use experimental setting over provider default", () => { const settings: ProviderSettings = { - apiProvider: "ollama", // Provider not in native list, defaults to XML + apiProvider: "ollama", // Provider defaults to XML } const modelInfo: ModelInfo = { maxTokens: 4096, @@ -356,9 +380,12 @@ describe("resolveToolProtocol", () => { supportsPromptCache: false, supportsNativeTools: true, // Model supports native tools } + const experiments: Experiments = { + nativeToolCalling: true, // Experimental setting enabled + } - const result = resolveToolProtocol(settings, modelInfo, "ollama") - expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Global setting wins over provider default + const result = resolveToolProtocol(settings, modelInfo, "ollama", experiments) + expect(result).toBe(TOOL_PROTOCOL.NATIVE) // Experimental setting wins over provider default }) }) diff --git a/src/utils/resolveToolProtocol.ts b/src/utils/resolveToolProtocol.ts index 81d85d79882..bc39cb274d7 100644 --- a/src/utils/resolveToolProtocol.ts +++ b/src/utils/resolveToolProtocol.ts @@ -1,13 +1,13 @@ -import { ToolProtocol, TOOL_PROTOCOL } from "@roo-code/types" +import { ToolProtocol, TOOL_PROTOCOL, type Experiments } from "@roo-code/types" import type { ProviderSettings, ProviderName, ModelInfo } from "@roo-code/types" -import { getToolProtocolFromSettings } from "./toolProtocol" +import { EXPERIMENT_IDS, experiments } from "../shared/experiments" /** * Resolve the effective tool protocol based on the precedence hierarchy: * Support > Preference > Defaults * * 1. User Preference - Per-Profile (explicit profile setting) - * 2. User Preference - Global (VSCode setting) + * 2. User Preference - Experimental Setting (nativeToolCalling experiment) * 3. Model Default (defaultToolProtocol in ModelInfo) * 4. Provider Default (XML by default, native for specific providers) * 5. XML Fallback (final fallback) @@ -17,12 +17,14 @@ import { getToolProtocolFromSettings } from "./toolProtocol" * @param providerSettings - The provider settings for the current profile * @param modelInfo - Optional model information containing capabilities * @param provider - Optional provider name for provider-specific defaults + * @param experimentsConfig - Optional experiments configuration * @returns The resolved tool protocol (either "xml" or "native") */ export function resolveToolProtocol( providerSettings: ProviderSettings, modelInfo?: ModelInfo, provider?: ProviderName, + experimentsConfig?: Experiments, ): ToolProtocol { let protocol: ToolProtocol @@ -30,9 +32,9 @@ export function resolveToolProtocol( if (providerSettings.toolProtocol) { protocol = providerSettings.toolProtocol } - // 2. User Preference - Global (VSCode global setting) - // Only treat as user preference if explicitly set to native (non-default value) - else if (getToolProtocolFromSettings() === TOOL_PROTOCOL.NATIVE) { + // 2. User Preference - Experimental Setting (nativeToolCalling experiment) + // Only treat as user preference if explicitly enabled + else if (experiments.isEnabled(experimentsConfig ?? {}, EXPERIMENT_IDS.NATIVE_TOOL_CALLING)) { protocol = TOOL_PROTOCOL.NATIVE } // 3. Model Default - model's preferred protocol diff --git a/src/utils/toolProtocol.ts b/src/utils/toolProtocol.ts deleted file mode 100644 index d96b97689cd..00000000000 --- a/src/utils/toolProtocol.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as vscode from "vscode" -import { ToolProtocol } from "@roo-code/types" -import { Package } from "../shared/package" - -/** - * Get the tool protocol setting from VSCode configuration. - * This centralizes the logic for retrieving the toolProtocol setting, - * ensuring consistent behavior across the codebase. - * - * @returns The configured tool protocol, defaults to "xml" if not set - */ -export function getToolProtocolFromSettings(): ToolProtocol { - return vscode.workspace.getConfiguration(Package.name).get("toolProtocol", "xml") -} diff --git a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx index 92652733ddf..a0bdc51e75e 100644 --- a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx +++ b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx @@ -237,6 +237,7 @@ describe("mergeExtensionState", () => { newTaskRequireTodos: false, imageGeneration: false, runSlashCommand: false, + nativeToolCalling: false, } as Record, checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS + 5, } @@ -258,6 +259,7 @@ describe("mergeExtensionState", () => { newTaskRequireTodos: false, imageGeneration: false, runSlashCommand: false, + nativeToolCalling: false, }) }) }) diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 8e47cf53793..fb2adc0023b 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -771,6 +771,10 @@ "RUN_SLASH_COMMAND": { "name": "Habilitar comandes de barra diagonal iniciades pel model", "description": "Quan està habilitat, Roo pot executar les vostres comandes de barra diagonal per executar fluxos de treball." + }, + "NATIVE_TOOL_CALLING": { + "name": "Habilitar crida d'eines nativa", + "description": "Quan està activat, Roo utilitzarà l'API de crida de funció nativa del proveïdor en lloc de definicions d'eines basades en XML. Això és experimental i encara no funciona amb tots els proveïdors." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 66f806bd05d..42043e3a72b 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -771,6 +771,10 @@ "RUN_SLASH_COMMAND": { "name": "Modellinitierte Slash-Befehle aktivieren", "description": "Wenn aktiviert, kann Roo deine Slash-Befehle ausführen, um Workflows zu starten." + }, + "NATIVE_TOOL_CALLING": { + "name": "Native Tool Calling aktivieren", + "description": "Wenn aktiviert, verwendet Roo die native Function-Calling-API des Providers anstelle von XML-basierten Tool-Definitionen. Dies ist experimentell und funktioniert noch nicht mit allen Providern." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index efcd4ffa331..2a1a8ef19fc 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -776,6 +776,10 @@ "RUN_SLASH_COMMAND": { "name": "Enable model-initiated slash commands", "description": "When enabled, Roo can run your slash commands to execute workflows." + }, + "NATIVE_TOOL_CALLING": { + "name": "Enable native tool calling", + "description": "When enabled, Roo will use the provider's native function calling API instead of XML-based tool definitions. This is experimental and does not yet work with all providers." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 27a2121005f..a37389017f4 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -771,6 +771,10 @@ "RUN_SLASH_COMMAND": { "name": "Habilitar comandos slash iniciados por el modelo", "description": "Cuando está habilitado, Roo puede ejecutar tus comandos slash para ejecutar flujos de trabajo." + }, + "NATIVE_TOOL_CALLING": { + "name": "Habilitar llamada de herramientas nativas", + "description": "Cuando está habilitado, Roo utilizará la API de llamada de funciones nativa del proveedor en lugar de definiciones de herramientas basadas en XML. Esto es experimental y aún no funciona con todos los proveedores." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 1357ae95657..08b4d721f9f 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -771,6 +771,10 @@ "RUN_SLASH_COMMAND": { "name": "Activer les commandes slash initiées par le modèle", "description": "Lorsque activé, Roo peut exécuter tes commandes slash pour lancer des workflows." + }, + "NATIVE_TOOL_CALLING": { + "name": "Activer l'appel natif d'outils", + "description": "Lorsqu'activé, Roo utilisera l'API native d'appel de fonction du fournisseur au lieu des définitions d'outils basées sur XML. Ceci est expérimental et ne fonctionne pas encore avec tous les fournisseurs." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 94a859ba02e..dc6d4900134 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "मॉडल द्वारा शुरू किए गए स्लैश कमांड सक्षम करें", "description": "जब सक्षम होता है, Roo वर्कफ़्लो चलाने के लिए आपके स्लैश कमांड चला सकता है।" + }, + "NATIVE_TOOL_CALLING": { + "name": "नेटिव टूल कॉलिंग सक्षम करें", + "description": "सक्षम होने पर, Roo XML-आधारित टूल परिभाषाओं के बजाय प्रदाता के नेटिव फ़ंक्शन कॉलिंग API का उपयोग करेगा। यह प्रयोगात्मक है और अभी सभी प्रदाताओं के साथ काम नहीं करता है।" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 13084d5ff5a..c687ca6093d 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -801,6 +801,10 @@ "RUN_SLASH_COMMAND": { "name": "Aktifkan perintah slash yang dimulai model", "description": "Ketika diaktifkan, Roo dapat menjalankan perintah slash Anda untuk mengeksekusi alur kerja." + }, + "NATIVE_TOOL_CALLING": { + "name": "Aktifkan pemanggilan alat asli", + "description": "Ketika diaktifkan, Roo akan menggunakan API pemanggilan fungsi asli dari penyedia alih-alih definisi alat berbasis XML. Ini bersifat eksperimental dan belum berfungsi dengan semua penyedia." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 635438545c1..0641fe3e8d9 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "Abilita comandi slash avviati dal modello", "description": "Quando abilitato, Roo può eseguire i tuoi comandi slash per eseguire flussi di lavoro." + }, + "NATIVE_TOOL_CALLING": { + "name": "Abilita chiamata nativa degli strumenti", + "description": "Quando abilitato, Roo utilizzerà l'API di chiamata di funzioni nativa del provider invece delle definizioni di strumenti basate su XML. Questo è sperimentale e non funziona ancora con tutti i provider." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index deaaff23eff..5d0be4f59d5 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "モデル開始スラッシュコマンドを有効にする", "description": "有効にすると、Rooがワークフローを実行するためにあなたのスラッシュコマンドを実行できます。" + }, + "NATIVE_TOOL_CALLING": { + "name": "ネイティブツール呼び出しを有効にする", + "description": "有効にすると、RooはXMLベースのツール定義の代わりにプロバイダーのネイティブ関数呼び出しAPIを使用します。これは実験的なもので、まだすべてのプロバイダーで機能するわけではありません。" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index b1f3ccdcce5..8c54ac2be23 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "모델 시작 슬래시 명령 활성화", "description": "활성화되면 Roo가 워크플로를 실행하기 위해 슬래시 명령을 실행할 수 있습니다." + }, + "NATIVE_TOOL_CALLING": { + "name": "네이티브 도구 호출 활성화", + "description": "활성화하면 Roo는 XML 기반 도구 정의 대신 제공자의 네이티브 함수 호출 API를 사용합니다. 이는 실험적이며 아직 모든 제공자에서 작동하지 않습니다." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 021d3c23686..e0f558b4b7a 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "Model-geïnitieerde slash-commando's inschakelen", "description": "Wanneer ingeschakeld, kan Roo je slash-commando's uitvoeren om workflows uit te voeren." + }, + "NATIVE_TOOL_CALLING": { + "name": "Schakel native tool calling in", + "description": "Wanneer ingeschakeld, gebruikt Roo de native function calling API van de provider in plaats van XML-gebaseerde tooldefinities. Dit is experimenteel en werkt nog niet met alle providers." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index a71525b5d88..854403a51b2 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "Włącz polecenia slash inicjowane przez model", "description": "Gdy włączone, Roo może uruchamiać twoje polecenia slash w celu wykonywania przepływów pracy." + }, + "NATIVE_TOOL_CALLING": { + "name": "Włącz natywne wywoływanie narzędzi", + "description": "Gdy włączone, Roo będzie używać natywnego API wywoływania funkcji dostawcy zamiast definicji narzędzi opartych na XML. Jest to funkcja eksperymentalna i nie działa jeszcze ze wszystkimi dostawcami." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 14220029335..3aa124af4ea 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "Ativar comandos slash iniciados pelo modelo", "description": "Quando ativado, Roo pode executar seus comandos slash para executar fluxos de trabalho." + }, + "NATIVE_TOOL_CALLING": { + "name": "Ativar chamada nativa de ferramentas", + "description": "Quando ativado, Roo usará a API de chamada de função nativa do provedor em vez de definições de ferramentas baseadas em XML. Isso é experimental e ainda não funciona com todos os provedores." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 29189a96040..0874bf9f005 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "Включить слэш-команды, инициированные моделью", "description": "Когда включено, Roo может выполнять ваши слэш-команды для выполнения рабочих процессов." + }, + "NATIVE_TOOL_CALLING": { + "name": "Включить нативный вызов инструментов", + "description": "Когда включено, Roo будет использовать нативный API вызова функций провайдера вместо XML-определений инструментов. Это экспериментальная функция и пока не работает со всеми провайдерами." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 6b53f6275ec..bae8bdd8947 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "Model tarafından başlatılan slash komutlarını etkinleştir", "description": "Etkinleştirildiğinde, Roo iş akışlarını yürütmek için slash komutlarınızı çalıştırabilir." + }, + "NATIVE_TOOL_CALLING": { + "name": "Native tool calling'i etkinleştir", + "description": "Etkinleştirildiğinde, Roo XML tabanlı araç tanımları yerine sağlayıcının yerel fonksiyon çağırma API'sını kullanacaktır. Bu deneyseldir ve henüz tüm sağlayıcılarla çalışmamaktadır." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index c63383c54e5..0d000a3c294 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "Bật lệnh slash do mô hình khởi tạo", "description": "Khi được bật, Roo có thể chạy các lệnh slash của bạn để thực hiện các quy trình làm việc." + }, + "NATIVE_TOOL_CALLING": { + "name": "Bật gọi công cụ gốc", + "description": "Khi được bật, Roo sẽ sử dụng API gọi hàm gốc của nhà cung cấp thay vì định nghĩa công cụ dựa trên XML. Đây là tính năng thử nghiệm và chưa hoạt động với tất cả các nhà cung cấp." } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 0e35914c762..744ea697467 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "启用模型发起的斜杠命令", "description": "启用后 Roo 可运行斜杠命令执行工作流程。" + }, + "NATIVE_TOOL_CALLING": { + "name": "启用原生工具调用", + "description": "启用后,Roo 将使用提供商的原生函数调用 API,而不是基于 XML 的工具定义。这是实验性功能,目前尚未支持所有提供商。" } }, "promptCaching": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 71ddbfbcffa..44a5716be34 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -772,6 +772,10 @@ "RUN_SLASH_COMMAND": { "name": "啟用模型啟動的斜線命令", "description": "啟用時,Roo 可以執行您的斜線命令來執行工作流程。" + }, + "NATIVE_TOOL_CALLING": { + "name": "啟用原生工具呼叫", + "description": "啟用後,Roo 將使用提供商的原生函式呼叫 API,而非基於 XML 的工具定義。這是實驗性功能,目前尚未支援所有提供商。" } }, "promptCaching": {