mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: enhance tool use instructions for Ollama models
- Add enhanced XML formatting instructions for local models (Ollama/LMStudio) - Include explicit examples of correct and incorrect tool usage - Add mandatory requirements to prevent models from adding explanatory text - Pass apiProvider through system prompt generation chain - Add comprehensive tests for the new functionality This addresses the issue where local Ollama models were not properly following the XML tool format, causing them to hallucinate code or enter infinite loops instead of using the codebase_search tool. Fixes #8430
This commit is contained in:
parent
f8ed7a7931
commit
7c29ffbe73
5 changed files with 140 additions and 3 deletions
98
src/core/prompts/sections/__tests__/tool-use.spec.ts
Normal file
98
src/core/prompts/sections/__tests__/tool-use.spec.ts
Normal file
|
|
@ -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("<actual_tool_name>")
|
||||
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("<codebase_search>")
|
||||
expect(result).toContain("<query>main function entry point</query>")
|
||||
expect(result).toContain("</codebase_search>")
|
||||
|
||||
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(/<actual_tool_name>\n<parameter1_name>value1<\/parameter1_name>/)
|
||||
expect(result).toMatch(/<codebase_search>\n<query>/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -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
|
|||
</actual_tool_name>
|
||||
|
||||
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):
|
||||
<codebase_search>
|
||||
<query>main function entry point</query>
|
||||
</codebase_search>
|
||||
|
||||
Example of an INCORRECT response (this will fail):
|
||||
I'll search for the main function in your codebase.
|
||||
<codebase_search>
|
||||
<query>main function</query>
|
||||
</codebase_search>
|
||||
|
||||
Remember: Your ENTIRE response should be the tool XML, nothing else.`
|
||||
)
|
||||
}
|
||||
|
||||
return baseSection
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ async function generatePrompt(
|
|||
settings?: SystemPromptSettings,
|
||||
todoList?: TodoItem[],
|
||||
modelId?: string,
|
||||
apiProvider?: string,
|
||||
): Promise<string> {
|
||||
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<string> => {
|
||||
if (!context) {
|
||||
throw new Error("Extension context is required for generating system prompt")
|
||||
|
|
@ -225,5 +227,6 @@ ${customInstructions}`
|
|||
settings,
|
||||
todoList,
|
||||
modelId,
|
||||
apiProvider,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2445,6 +2445,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
},
|
||||
undefined, // todoList
|
||||
this.api.getModel().id,
|
||||
this.apiConfiguration.apiProvider,
|
||||
)
|
||||
})()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
|
|||
.getConfiguration("roo-cline")
|
||||
.get<boolean>("newTaskRequireTodos", false),
|
||||
},
|
||||
undefined, // todoList
|
||||
undefined, // modelId
|
||||
apiConfiguration?.apiProvider,
|
||||
)
|
||||
|
||||
return systemPrompt
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue