refactor(ipuaro): simplify LLM integration with pure XML tool format

Refactor OllamaClient to use pure XML format for tool calls as
designed in CONCEPT.md. Removes dual system (Ollama native tools +
XML parser) in favor of single source of truth (ResponseParser).

Changes:
- Remove tools parameter from ILLMClient.chat() interface
- Remove convertTools(), convertParameters(), extractToolCalls()
- Add XML format instructions to system prompt with examples
- Add CDATA support in ResponseParser for multiline content
- Add tool name validation with helpful error messages
- Move ToolDef/ToolParameter to shared/types/tool-definitions.ts

Benefits:
- Simplified architecture (single source of truth)
- CONCEPT.md compliance (pure XML as designed)
- Better validation (early detection of invalid tools)
- Reduced complexity (fewer format conversions)

Tests: 1444 passed (+4 new tests)
Coverage: 97.83% lines, 91.98% branches, 99.16% functions
This commit is contained in:
imfozilbek
2025-12-01 21:03:55 +05:00
parent 902d1db831
commit 0433ef102c
13 changed files with 290 additions and 212 deletions

View File

@@ -27,9 +27,41 @@ const TOOL_CALL_REGEX = /<tool_call\s+name\s*=\s*"([^"]+)">([\s\S]*?)<\/tool_cal
const PARAM_REGEX_NAMED = /<param\s+name\s*=\s*"([^"]+)">([\s\S]*?)<\/param>/gi
const PARAM_REGEX_ELEMENT = /<([a-z_][a-z0-9_]*)>([\s\S]*?)<\/\1>/gi
/**
* CDATA section pattern.
* Matches: <![CDATA[...]]>
*/
const CDATA_REGEX = /<!\[CDATA\[([\s\S]*?)\]\]>/g
/**
* Valid tool names.
* Used for validation to catch typos or hallucinations.
*/
const VALID_TOOL_NAMES = new Set([
"get_lines",
"get_function",
"get_class",
"get_structure",
"edit_lines",
"create_file",
"delete_file",
"find_references",
"find_definition",
"get_dependencies",
"get_dependents",
"get_complexity",
"get_todos",
"git_status",
"git_diff",
"git_commit",
"run_command",
"run_tests",
])
/**
* Parse tool calls from LLM response text.
* Supports XML format: <tool_call name="get_lines"><path>src/index.ts</path></tool_call>
* Validates tool names and provides helpful error messages.
*/
export function parseToolCalls(response: string): ParsedResponse {
const toolCalls: ToolCall[] = []
@@ -41,6 +73,13 @@ export function parseToolCalls(response: string): ParsedResponse {
for (const match of matches) {
const [fullMatch, toolName, paramsXml] = match
if (!VALID_TOOL_NAMES.has(toolName)) {
parseErrors.push(
`Unknown tool "${toolName}". Valid tools: ${[...VALID_TOOL_NAMES].join(", ")}`,
)
continue
}
try {
const params = parseParameters(paramsXml)
const toolCall = createToolCall(
@@ -91,10 +130,16 @@ function parseParameters(xml: string): Record<string, unknown> {
/**
* Parse a value string to appropriate type.
* Supports CDATA sections for multiline content.
*/
function parseValue(value: string): unknown {
const trimmed = value.trim()
const cdataMatches = [...trimmed.matchAll(CDATA_REGEX)]
if (cdataMatches.length > 0 && cdataMatches[0][1] !== undefined) {
return cdataMatches[0][1]
}
if (trimmed === "true") {
return true
}