diff --git a/src/core/prompts/sections/__tests__/tool-use.spec.ts b/src/core/prompts/sections/__tests__/tool-use.spec.ts new file mode 100644 index 0000000000..d1b2f543bb --- /dev/null +++ b/src/core/prompts/sections/__tests__/tool-use.spec.ts @@ -0,0 +1,98 @@ +import { describe, it, expect } from "vitest" +import { getSharedToolUseSection } from "../tool-use" + +describe("getSharedToolUseSection", () => { + describe("base functionality", () => { + it("should return base tool use section when no apiProvider is provided", () => { + const result = getSharedToolUseSection() + + expect(result).toContain("TOOL USE") + expect(result).toContain("Tool uses are formatted using XML-style tags") + expect(result).toContain("") + expect(result).not.toContain("CRITICAL: Tool Use Requirements") + expect(result).not.toContain("MANDATORY") + }) + + it("should return base tool use section for non-local providers", () => { + const providers = ["anthropic", "openai", "openrouter", "bedrock"] + + providers.forEach((provider) => { + const result = getSharedToolUseSection(provider) + + expect(result).toContain("TOOL USE") + expect(result).toContain("Tool uses are formatted using XML-style tags") + expect(result).not.toContain("CRITICAL: Tool Use Requirements") + expect(result).not.toContain("MANDATORY") + }) + }) + }) + + describe("local model enhancements", () => { + it("should include enhanced instructions for ollama provider", () => { + const result = getSharedToolUseSection("ollama") + + // Check base content is still there + expect(result).toContain("TOOL USE") + expect(result).toContain("Tool uses are formatted using XML-style tags") + + // Check enhanced instructions + expect(result).toContain("CRITICAL: Tool Use Requirements for Your Response") + expect(result).toContain("MANDATORY") + expect(result).toContain("Every response MUST contain EXACTLY ONE tool use") + expect(result).toContain("DO NOT") + expect(result).toContain("Write explanations or text outside of the tool XML tags") + expect(result).toContain("Guess file locations or code content") + expect(result).toContain("ALWAYS") + expect(result).toContain("Start with codebase_search tool when exploring code") + + // Check examples + expect(result).toContain("Example of a CORRECT response") + expect(result).toContain("") + expect(result).toContain("main function entry point") + expect(result).toContain("") + + expect(result).toContain("Example of an INCORRECT response") + expect(result).toContain("I'll search for the main function") + + // Check final reminder + expect(result).toContain("Remember: Your ENTIRE response should be the tool XML, nothing else") + }) + + it("should include enhanced instructions for lmstudio provider", () => { + const result = getSharedToolUseSection("lmstudio") + + // Check base content is still there + expect(result).toContain("TOOL USE") + expect(result).toContain("Tool uses are formatted using XML-style tags") + + // Check enhanced instructions (same as ollama) + expect(result).toContain("CRITICAL: Tool Use Requirements for Your Response") + expect(result).toContain("MANDATORY") + expect(result).toContain("Every response MUST contain EXACTLY ONE tool use") + expect(result).toContain("DO NOT") + expect(result).toContain("ALWAYS") + expect(result).toContain("Example of a CORRECT response") + expect(result).toContain("Example of an INCORRECT response") + expect(result).toContain("Remember: Your ENTIRE response should be the tool XML, nothing else") + }) + }) + + describe("formatting and structure", () => { + it("should maintain proper formatting with line breaks", () => { + const result = getSharedToolUseSection("ollama") + + // Check that there are proper line breaks between sections + expect(result).toMatch(/TOOL USE\n\n/) + expect(result).toMatch(/# Tool Use Formatting\n\n/) + expect(result).toMatch(/# CRITICAL: Tool Use Requirements/) + }) + + it("should have consistent XML examples", () => { + const result = getSharedToolUseSection("ollama") + + // Check XML structure is properly formatted + expect(result).toMatch(/\nvalue1<\/parameter1_name>/) + expect(result).toMatch(/\n/) + }) + }) +}) diff --git a/src/core/prompts/sections/tool-use.ts b/src/core/prompts/sections/tool-use.ts index 28d47d0985..9a2af41f9c 100644 --- a/src/core/prompts/sections/tool-use.ts +++ b/src/core/prompts/sections/tool-use.ts @@ -1,5 +1,8 @@ -export function getSharedToolUseSection(): string { - return `==== +export function getSharedToolUseSection(apiProvider?: string): string { + // Enhanced instructions for local models that may struggle with tool formatting + const isLocalModel = apiProvider === "ollama" || apiProvider === "lmstudio" + + const baseSection = `==== TOOL USE @@ -16,4 +19,33 @@ Tool uses are formatted using XML-style tags. The tool name itself becomes the X Always use the actual tool name as the XML tag name for proper parsing and execution.` + + if (isLocalModel) { + return ( + baseSection + + ` + +# CRITICAL: Tool Use Requirements for Your Response + +**MANDATORY**: Every response MUST contain EXACTLY ONE tool use in the XML format shown above. +**DO NOT**: Write explanations or text outside of the tool XML tags. +**DO NOT**: Guess file locations or code content - use the appropriate search tools first. +**ALWAYS**: Start with codebase_search tool when exploring code for the first time. + +Example of a CORRECT response (using codebase_search): + +main function entry point + + +Example of an INCORRECT response (this will fail): +I'll search for the main function in your codebase. + +main function + + +Remember: Your ENTIRE response should be the tool XML, nothing else.` + ) + } + + return baseSection } diff --git a/src/core/prompts/system.ts b/src/core/prompts/system.ts index 3cc327c815..f2eafa978b 100644 --- a/src/core/prompts/system.ts +++ b/src/core/prompts/system.ts @@ -62,6 +62,7 @@ async function generatePrompt( settings?: SystemPromptSettings, todoList?: TodoItem[], modelId?: string, + apiProvider?: string, ): Promise { if (!context) { throw new Error("Extension context is required for generating system prompt") @@ -92,7 +93,7 @@ async function generatePrompt( ${markdownFormattingSection()} -${getSharedToolUseSection()} +${getSharedToolUseSection(apiProvider)} ${getToolDescriptionsForMode( mode, @@ -153,6 +154,7 @@ export const SYSTEM_PROMPT = async ( settings?: SystemPromptSettings, todoList?: TodoItem[], modelId?: string, + apiProvider?: string, ): Promise => { if (!context) { throw new Error("Extension context is required for generating system prompt") @@ -225,5 +227,6 @@ ${customInstructions}` settings, todoList, modelId, + apiProvider, ) } diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 851df91e6c..1b7989b3ab 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2445,6 +2445,7 @@ export class Task extends EventEmitter implements TaskLike { }, undefined, // todoList this.api.getModel().id, + this.apiConfiguration.apiProvider, ) })() } diff --git a/src/core/webview/generateSystemPrompt.ts b/src/core/webview/generateSystemPrompt.ts index a639d8a960..0e64de4958 100644 --- a/src/core/webview/generateSystemPrompt.ts +++ b/src/core/webview/generateSystemPrompt.ts @@ -89,6 +89,9 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web .getConfiguration("roo-cline") .get("newTaskRequireTodos", false), }, + undefined, // todoList + undefined, // modelId + apiConfiguration?.apiProvider, ) return systemPrompt