From a4a2210f3ed56cfb1f02ebb04e34f19a98413af4 Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Fri, 14 Nov 2025 10:30:56 -0500 Subject: [PATCH 1/2] fix: format tool responses for native protocol - Add toolResultFormatting utilities for protocol detection - ReadFileTool now builds both XML and native formats - Native format returns clean, readable text without XML tags - Legacy conversation history conversion is protocol-aware - All tests passing (55 total) --- src/core/task/Task.ts | 17 +-- src/core/tools/ReadFileTool.ts | 89 ++++++++++++--- .../__tests__/toolResultFormatting.spec.ts | 104 ++++++++++++++++++ .../tools/helpers/toolResultFormatting.ts | 38 +++++++ 4 files changed, 228 insertions(+), 20 deletions(-) create mode 100644 src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts create mode 100644 src/core/tools/helpers/toolResultFormatting.ts diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 18e7795245f..fb6c3a81b0b 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -10,6 +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, isNativeProtocol } from "../tools/helpers/toolResultFormatting" import { type TaskLike, @@ -1383,19 +1384,21 @@ export class Task extends EventEmitter implements TaskLike { let existingApiConversationHistory: ApiMessage[] = await this.getSavedApiConversationHistory() // 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 protocol = getCurrentToolProtocol() + const useNative = isNativeProtocol(protocol) + const conversationWithoutToolBlocks = existingApiConversationHistory.map((message) => { if (Array.isArray(message.content)) { const newContent = message.content.map((block) => { if (block.type === "tool_use") { - // It's important we convert to the new tool schema - // format so the model doesn't get confused about how to - // invoke tools. - const inputAsXml = Object.entries(block.input as Record) - .map(([key, value]) => `<${key}>\n${value}\n`) - .join("\n") + // Format tool invocation based on protocol + const params = block.input as Record + const formattedText = formatToolInvocation(block.name, params, protocol) + return { type: "text", - text: `<${block.name}>\n${inputAsXml}\n`, + text: formattedText, } as Anthropic.Messages.TextBlockParam } else if (block.type === "tool_result") { // Convert block.content to text block array, removing images diff --git a/src/core/tools/ReadFileTool.ts b/src/core/tools/ReadFileTool.ts index 11c1e077997..abc4b683bf8 100644 --- a/src/core/tools/ReadFileTool.ts +++ b/src/core/tools/ReadFileTool.ts @@ -14,6 +14,7 @@ import { readLines } from "../../integrations/misc/read-lines" import { extractTextFromFile, addLineNumbers, getSupportedBinaryFormats } from "../../integrations/misc/extract-text" import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter" import { parseXml } from "../../utils/xml" +import { getCurrentToolProtocol, isNativeProtocol } from "./helpers/toolResultFormatting" import { DEFAULT_MAX_IMAGE_FILE_SIZE_MB, DEFAULT_MAX_TOTAL_IMAGE_SIZE_MB, @@ -35,6 +36,7 @@ interface FileResult { notice?: string lineRanges?: LineRange[] xmlContent?: string + nativeContent?: string imageDataUrl?: string feedbackText?: string feedbackImages?: any[] @@ -105,12 +107,15 @@ export class ReadFileTool extends BaseTool<"read_file"> { async execute(params: { files: FileEntry[] }, task: Task, callbacks: ToolCallbacks): Promise { const { handleError, pushToolResult } = callbacks const fileEntries = params.files + const protocol = getCurrentToolProtocol() + const useNative = isNativeProtocol(protocol) if (!fileEntries || fileEntries.length === 0) { task.consecutiveMistakeCount++ task.recordToolError("read_file") const errorMsg = await task.sayAndCreateMissingParamError("read_file", "args (containing valid file paths)") - pushToolResult(`${errorMsg}`) + const errorResult = useNative ? `Error: ${errorMsg}` : `${errorMsg}` + pushToolResult(errorResult) return } @@ -146,6 +151,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { status: "blocked", error: errorMsg, xmlContent: `${relPath}Error reading file: ${errorMsg}`, + nativeContent: `File: ${relPath}\nError: Error reading file: ${errorMsg}`, }) await handleError(`reading file ${relPath}`, new Error(errorMsg)) hasRangeError = true @@ -157,6 +163,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { status: "blocked", error: errorMsg, xmlContent: `${relPath}Error reading file: ${errorMsg}`, + nativeContent: `File: ${relPath}\nError: Error reading file: ${errorMsg}`, }) await handleError(`reading file ${relPath}`, new Error(errorMsg)) hasRangeError = true @@ -175,6 +182,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { status: "blocked", error: errorMsg, xmlContent: `${relPath}${errorMsg}`, + nativeContent: `File: ${relPath}\nError: ${errorMsg}`, }) continue } @@ -228,6 +236,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { updateFileResult(fileResult.path, { status: "denied", xmlContent: `${fileResult.path}Denied by user`, + nativeContent: `File: ${fileResult.path}\nStatus: Denied by user`, feedbackText: text, feedbackImages: images, }) @@ -248,6 +257,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { updateFileResult(fileResult.path, { status: "denied", xmlContent: `${fileResult.path}Denied by user`, + nativeContent: `File: ${fileResult.path}\nStatus: Denied by user`, }) } }) @@ -260,6 +270,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { updateFileResult(fileResult.path, { status: "denied", xmlContent: `${fileResult.path}Denied by user`, + nativeContent: `File: ${fileResult.path}\nStatus: Denied by user`, }) }) } @@ -299,6 +310,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { updateFileResult(relPath, { status: "denied", xmlContent: `${relPath}Denied by user`, + nativeContent: `File: ${relPath}\nStatus: Denied by user`, feedbackText: text, feedbackImages: images, }) @@ -343,6 +355,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { await task.fileContextTracker.trackFileContext(relPath, "read_tool" as RecordSource) updateFileResult(relPath, { xmlContent: `${relPath}\n${validationResult.notice}\n`, + nativeContent: `File: ${relPath}\nNote: ${validationResult.notice}`, }) continue } @@ -353,6 +366,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { updateFileResult(relPath, { xmlContent: `${relPath}\n${imageResult.notice}\n`, + nativeContent: `File: ${relPath}\nNote: ${imageResult.notice}`, imageDataUrl: imageResult.dataUrl, }) continue @@ -362,6 +376,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { status: "error", error: `Error reading image file: ${errorMsg}`, xmlContent: `${relPath}Error reading image file: ${errorMsg}`, + nativeContent: `File: ${relPath}\nError: Error reading image file: ${errorMsg}`, }) await handleError( `reading image file ${relPath}`, @@ -378,6 +393,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { updateFileResult(relPath, { notice: `Binary file format: ${fileFormat}`, xmlContent: `${relPath}\nBinary file - content not displayed\n`, + nativeContent: `File: ${relPath}\nBinary file (${fileFormat}) - content not displayed`, }) continue } @@ -385,6 +401,8 @@ export class ReadFileTool extends BaseTool<"read_file"> { if (fileResult.lineRanges && fileResult.lineRanges.length > 0) { const rangeResults: string[] = [] + const nativeRangeResults: string[] = [] + for (const range of fileResult.lineRanges) { const content = addLineNumbers( await readLines(fullPath, range.end - 1, range.start - 1), @@ -392,9 +410,12 @@ export class ReadFileTool extends BaseTool<"read_file"> { ) const lineRangeAttr = ` lines="${range.start}-${range.end}"` rangeResults.push(`\n${content}`) + nativeRangeResults.push(`Lines ${range.start}-${range.end}:\n${content}`) } + updateFileResult(relPath, { xmlContent: `${relPath}\n${rangeResults.join("\n")}\n`, + nativeContent: `File: ${relPath}\n${nativeRangeResults.join("\n\n")}`, }) continue } @@ -406,9 +427,10 @@ export class ReadFileTool extends BaseTool<"read_file"> { task.rooIgnoreController, ) if (defResult) { - let xmlInfo = `Showing only ${maxReadFileLine} of ${totalLines} total lines. Use line_range if you need to read more lines\n` + const notice = `Showing only ${maxReadFileLine} of ${totalLines} total lines. Use line_range if you need to read more lines` updateFileResult(relPath, { - xmlContent: `${relPath}\n${defResult}\n${xmlInfo}`, + xmlContent: `${relPath}\n${defResult}\n${notice}\n`, + nativeContent: `File: ${relPath}\nCode Definitions:\n${defResult}\n\nNote: ${notice}`, }) } } catch (error) { @@ -427,6 +449,7 @@ export class ReadFileTool extends BaseTool<"read_file"> { const content = addLineNumbers(await readLines(fullPath, maxReadFileLine - 1, 0)) const lineRangeAttr = ` lines="1-${maxReadFileLine}"` let xmlInfo = `\n${content}\n` + let nativeInfo = `Lines 1-${maxReadFileLine}:\n${content}\n` try { const defResult = await parseSourceCodeDefinitionsForFile( @@ -436,10 +459,16 @@ export class ReadFileTool extends BaseTool<"read_file"> { if (defResult) { const truncatedDefs = truncateDefinitionsToLineLimit(defResult, maxReadFileLine) xmlInfo += `${truncatedDefs}\n` + nativeInfo += `\nCode Definitions:\n${truncatedDefs}\n` } - xmlInfo += `Showing only ${maxReadFileLine} of ${totalLines} total lines. Use line_range if you need to read more lines\n` + + const notice = `Showing only ${maxReadFileLine} of ${totalLines} total lines. Use line_range if you need to read more lines` + xmlInfo += `${notice}\n` + nativeInfo += `\nNote: ${notice}` + updateFileResult(relPath, { xmlContent: `${relPath}\n${xmlInfo}`, + nativeContent: `File: ${relPath}\n${nativeInfo}`, }) } catch (error) { if (error instanceof Error && error.message.startsWith("Unsupported language:")) { @@ -462,6 +491,8 @@ export class ReadFileTool extends BaseTool<"read_file"> { let content = await extractTextFromFile(fullPath) let xmlInfo = "" + let nativeInfo = "" + if (budgetResult.shouldTruncate && budgetResult.maxChars !== undefined) { const truncateResult = truncateFileContent( content, @@ -479,31 +510,52 @@ export class ReadFileTool extends BaseTool<"read_file"> { xmlInfo = content.length > 0 ? `\n${content}\n` : `` xmlInfo += `${truncateResult.notice}\n` + + nativeInfo = + content.length > 0 + ? `Lines 1-${displayedLines}:\n${content}\n\nNote: ${truncateResult.notice}` + : `Note: ${truncateResult.notice}` } else { const lineRangeAttr = ` lines="1-${totalLines}"` xmlInfo = totalLines > 0 ? `\n${content}\n` : `` if (totalLines === 0) { xmlInfo += `File is empty\n` + nativeInfo = "Note: File is empty" + } else { + nativeInfo = `Lines 1-${totalLines}:\n${content}` } } await task.fileContextTracker.trackFileContext(relPath, "read_tool" as RecordSource) - updateFileResult(relPath, { xmlContent: `${relPath}\n${xmlInfo}` }) + updateFileResult(relPath, { + xmlContent: `${relPath}\n${xmlInfo}`, + nativeContent: `File: ${relPath}\n${nativeInfo}`, + }) } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error) updateFileResult(relPath, { status: "error", error: `Error reading file: ${errorMsg}`, xmlContent: `${relPath}Error reading file: ${errorMsg}`, + nativeContent: `File: ${relPath}\nError: Error reading file: ${errorMsg}`, }) await handleError(`reading file ${relPath}`, error instanceof Error ? error : new Error(errorMsg)) } } - const xmlResults = fileResults.filter((result) => result.xmlContent).map((result) => result.xmlContent) - const filesXml = `\n${xmlResults.join("\n")}\n` + // Build final result based on protocol + let finalResult: string + if (useNative) { + const nativeResults = fileResults + .filter((result) => result.nativeContent) + .map((result) => result.nativeContent) + finalResult = nativeResults.join("\n\n---\n\n") + } else { + const xmlResults = fileResults.filter((result) => result.xmlContent).map((result) => result.xmlContent) + finalResult = `\n${xmlResults.join("\n")}\n` + } const fileImageUrls = fileResults .filter((result) => result.imageDataUrl) @@ -537,26 +589,26 @@ export class ReadFileTool extends BaseTool<"read_file"> { if (statusMessage || imagesToInclude.length > 0) { const result = formatResponse.toolResult( - statusMessage || filesXml, + statusMessage || finalResult, imagesToInclude.length > 0 ? imagesToInclude : undefined, ) if (typeof result === "string") { if (statusMessage) { - pushToolResult(`${result}\n${filesXml}`) + pushToolResult(`${result}\n${finalResult}`) } else { pushToolResult(result) } } else { if (statusMessage) { - const textBlock = { type: "text" as const, text: filesXml } + const textBlock = { type: "text" as const, text: finalResult } pushToolResult([...result, textBlock]) } else { pushToolResult(result) } } } else { - pushToolResult(filesXml) + pushToolResult(finalResult) } } catch (error) { const relPath = fileEntries[0]?.path || "unknown" @@ -567,14 +619,25 @@ export class ReadFileTool extends BaseTool<"read_file"> { status: "error", error: `Error reading file: ${errorMsg}`, xmlContent: `${relPath}Error reading file: ${errorMsg}`, + nativeContent: `File: ${relPath}\nError: Error reading file: ${errorMsg}`, }) } await handleError(`reading file ${relPath}`, error instanceof Error ? error : new Error(errorMsg)) - const xmlResults = fileResults.filter((result) => result.xmlContent).map((result) => result.xmlContent) + // Build final error result based on protocol + let errorResult: string + if (useNative) { + const nativeResults = fileResults + .filter((result) => result.nativeContent) + .map((result) => result.nativeContent) + errorResult = nativeResults.join("\n\n---\n\n") + } else { + const xmlResults = fileResults.filter((result) => result.xmlContent).map((result) => result.xmlContent) + errorResult = `\n${xmlResults.join("\n")}\n` + } - pushToolResult(`\n${xmlResults.join("\n")}\n`) + pushToolResult(errorResult) } } diff --git a/src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts b/src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts new file mode 100644 index 00000000000..52907c60037 --- /dev/null +++ b/src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts @@ -0,0 +1,104 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest" +import * as vscode from "vscode" +import { formatToolInvocation, isNativeProtocol, getCurrentToolProtocol } from "../toolResultFormatting" +import { TOOL_PROTOCOL } from "@roo-code/types" + +vi.mock("vscode", () => ({ + workspace: { + getConfiguration: vi.fn(), + }, +})) + +describe("toolResultFormatting", () => { + let mockGetConfiguration: ReturnType + + beforeEach(() => { + mockGetConfiguration = vi.fn() + ;(vscode.workspace.getConfiguration as any).mockReturnValue({ + get: mockGetConfiguration, + }) + }) + + afterEach(() => { + vi.clearAllMocks() + }) + + describe("getCurrentToolProtocol", () => { + it("should return configured protocol", () => { + mockGetConfiguration.mockReturnValue(TOOL_PROTOCOL.NATIVE) + expect(getCurrentToolProtocol()).toBe(TOOL_PROTOCOL.NATIVE) + }) + + it("should default to xml when config is not set", () => { + mockGetConfiguration.mockReturnValue("xml") + expect(getCurrentToolProtocol()).toBe("xml") + }) + }) + + describe("isNativeProtocol", () => { + it("should return true for native protocol from config", () => { + mockGetConfiguration.mockReturnValue(TOOL_PROTOCOL.NATIVE) + expect(isNativeProtocol()).toBe(true) + }) + + it("should return false for XML protocol from config", () => { + mockGetConfiguration.mockReturnValue("xml") + expect(isNativeProtocol()).toBe(false) + }) + + it("should accept protocol parameter", () => { + expect(isNativeProtocol(TOOL_PROTOCOL.NATIVE)).toBe(true) + expect(isNativeProtocol("xml")).toBe(false) + }) + }) + + describe("formatToolInvocation", () => { + it("should format for XML protocol", () => { + const result = formatToolInvocation("read_file", { path: "test.ts" }, "xml") + + expect(result).toContain("") + expect(result).toContain("") + expect(result).toContain("test.ts") + expect(result).toContain("") + expect(result).toContain("") + }) + + it("should format for native protocol", () => { + const result = formatToolInvocation("read_file", { path: "test.ts" }, TOOL_PROTOCOL.NATIVE) + + expect(result).toBe("Called read_file with path: test.ts") + expect(result).not.toContain("<") + }) + + it("should handle multiple parameters for XML", () => { + const result = formatToolInvocation( + "read_file", + { path: "test.ts", start_line: "1", end_line: "10" }, + "xml", + ) + + expect(result).toContain("\ntest.ts\n") + expect(result).toContain("\n1\n") + expect(result).toContain("\n10\n") + }) + + it("should handle multiple parameters for native", () => { + const result = formatToolInvocation("read_file", { path: "test.ts", start_line: "1" }, TOOL_PROTOCOL.NATIVE) + + expect(result).toContain("Called read_file with") + expect(result).toContain("path: test.ts") + expect(result).toContain("start_line: 1") + }) + + it("should handle empty parameters", () => { + const result = formatToolInvocation("list_files", {}, TOOL_PROTOCOL.NATIVE) + expect(result).toBe("Called list_files") + }) + + it("should use config when protocol not specified", () => { + mockGetConfiguration.mockReturnValue(TOOL_PROTOCOL.NATIVE) + const result = formatToolInvocation("read_file", { path: "test.ts" }) + expect(result).toBe("Called read_file with path: test.ts") + }) + }) +}) diff --git a/src/core/tools/helpers/toolResultFormatting.ts b/src/core/tools/helpers/toolResultFormatting.ts new file mode 100644 index 00000000000..d847fd93664 --- /dev/null +++ b/src/core/tools/helpers/toolResultFormatting.ts @@ -0,0 +1,38 @@ +import * as vscode from "vscode" +import { Package } from "../../../shared/package" +import { TOOL_PROTOCOL, ToolProtocol } from "@roo-code/types" + +/** + * Gets the current tool protocol from workspace configuration. + */ +export function getCurrentToolProtocol(): ToolProtocol { + return vscode.workspace.getConfiguration(Package.name).get("toolProtocol", "xml") +} + +/** + * Checks if the current protocol is native. + */ +export function isNativeProtocol(protocol?: ToolProtocol): boolean { + const effectiveProtocol = protocol ?? getCurrentToolProtocol() + return effectiveProtocol === TOOL_PROTOCOL.NATIVE +} + +/** + * Formats tool invocation parameters for display based on protocol. + * Used for legacy conversation history conversion. + */ +export function formatToolInvocation(toolName: string, params: Record, protocol?: ToolProtocol): string { + if (isNativeProtocol(protocol)) { + // Native protocol: readable format + const paramsList = Object.entries(params) + .map(([key, value]) => `${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`) + .join(", ") + return `Called ${toolName}${paramsList ? ` with ${paramsList}` : ""}` + } else { + // XML protocol: preserve XML format + const paramsXml = Object.entries(params) + .map(([key, value]) => `<${key}>\n${value}\n`) + .join("\n") + return `<${toolName}>\n${paramsXml}\n` + } +} From af90a8cea5135efa752f43cda13800257b244ed6 Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Fri, 14 Nov 2025 11:44:39 -0500 Subject: [PATCH 2/2] refactor: use isNativeProtocol from @roo-code/types Remove duplicate implementation and import from types package instead --- src/core/task/Task.ts | 3 ++- src/core/tools/ReadFileTool.ts | 3 ++- .../__tests__/toolResultFormatting.spec.ts | 17 +++++------------ src/core/tools/helpers/toolResultFormatting.ts | 13 +++---------- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index fb6c3a81b0b..4299d322259 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -10,7 +10,8 @@ import delay from "delay" import pWaitFor from "p-wait-for" import { serializeError } from "serialize-error" import { Package } from "../../shared/package" -import { getCurrentToolProtocol, formatToolInvocation, isNativeProtocol } from "../tools/helpers/toolResultFormatting" +import { isNativeProtocol } from "@roo-code/types" +import { getCurrentToolProtocol, formatToolInvocation } from "../tools/helpers/toolResultFormatting" import { type TaskLike, diff --git a/src/core/tools/ReadFileTool.ts b/src/core/tools/ReadFileTool.ts index abc4b683bf8..d3ed9ec8d3b 100644 --- a/src/core/tools/ReadFileTool.ts +++ b/src/core/tools/ReadFileTool.ts @@ -1,6 +1,7 @@ import path from "path" import { isBinaryFile } from "isbinaryfile" import type { FileEntry, LineRange } from "@roo-code/types" +import { isNativeProtocol } from "@roo-code/types" import { Task } from "../task/Task" import { ClineSayTool } from "../../shared/ExtensionMessage" @@ -14,7 +15,7 @@ import { readLines } from "../../integrations/misc/read-lines" import { extractTextFromFile, addLineNumbers, getSupportedBinaryFormats } from "../../integrations/misc/extract-text" import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter" import { parseXml } from "../../utils/xml" -import { getCurrentToolProtocol, isNativeProtocol } from "./helpers/toolResultFormatting" +import { getCurrentToolProtocol } from "./helpers/toolResultFormatting" import { DEFAULT_MAX_IMAGE_FILE_SIZE_MB, DEFAULT_MAX_TOTAL_IMAGE_SIZE_MB, diff --git a/src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts b/src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts index 52907c60037..8f83381f17e 100644 --- a/src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts +++ b/src/core/tools/helpers/__tests__/toolResultFormatting.spec.ts @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest" import * as vscode from "vscode" -import { formatToolInvocation, isNativeProtocol, getCurrentToolProtocol } from "../toolResultFormatting" -import { TOOL_PROTOCOL } from "@roo-code/types" +import { TOOL_PROTOCOL, isNativeProtocol } from "@roo-code/types" +import { formatToolInvocation, getCurrentToolProtocol } from "../toolResultFormatting" vi.mock("vscode", () => ({ workspace: { @@ -36,18 +36,11 @@ describe("toolResultFormatting", () => { }) describe("isNativeProtocol", () => { - it("should return true for native protocol from config", () => { - mockGetConfiguration.mockReturnValue(TOOL_PROTOCOL.NATIVE) - expect(isNativeProtocol()).toBe(true) - }) - - it("should return false for XML protocol from config", () => { - mockGetConfiguration.mockReturnValue("xml") - expect(isNativeProtocol()).toBe(false) + it("should return true for native protocol", () => { + expect(isNativeProtocol(TOOL_PROTOCOL.NATIVE)).toBe(true) }) - it("should accept protocol parameter", () => { - expect(isNativeProtocol(TOOL_PROTOCOL.NATIVE)).toBe(true) + it("should return false for XML protocol", () => { expect(isNativeProtocol("xml")).toBe(false) }) }) diff --git a/src/core/tools/helpers/toolResultFormatting.ts b/src/core/tools/helpers/toolResultFormatting.ts index d847fd93664..d4c77798c5d 100644 --- a/src/core/tools/helpers/toolResultFormatting.ts +++ b/src/core/tools/helpers/toolResultFormatting.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode" import { Package } from "../../../shared/package" -import { TOOL_PROTOCOL, ToolProtocol } from "@roo-code/types" +import { TOOL_PROTOCOL, ToolProtocol, isNativeProtocol } from "@roo-code/types" /** * Gets the current tool protocol from workspace configuration. @@ -9,20 +9,13 @@ export function getCurrentToolProtocol(): ToolProtocol { return vscode.workspace.getConfiguration(Package.name).get("toolProtocol", "xml") } -/** - * Checks if the current protocol is native. - */ -export function isNativeProtocol(protocol?: ToolProtocol): boolean { - const effectiveProtocol = protocol ?? getCurrentToolProtocol() - return effectiveProtocol === TOOL_PROTOCOL.NATIVE -} - /** * Formats tool invocation parameters for display based on protocol. * Used for legacy conversation history conversion. */ export function formatToolInvocation(toolName: string, params: Record, protocol?: ToolProtocol): string { - if (isNativeProtocol(protocol)) { + const effectiveProtocol = protocol ?? getCurrentToolProtocol() + if (isNativeProtocol(effectiveProtocol)) { // Native protocol: readable format const paramsList = Object.entries(params) .map(([key, value]) => `${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`)