// ToolShim — recovers structured tool calls from plain-text model output. // When the model emits tool calls as plain text instead of structured JSON, // this shim attempts to parse and recover them. export interface ParsedToolCall { id: string; name: string; arguments: string; } const TOOL_CALL_PATTERN = /\s*(.+?)<\/name>\s*(.+?)<\/arguments>\s*<\/tool_call>/gs; const JSON_TOOL_PATTERN = /\{\s*"name":\s*"([^"]+)",\s*"arguments":\s*({.+?})\s*\}/gs; export function extractToolCalls(text: string): ParsedToolCall[] { const calls: ParsedToolCall[] = []; let match: RegExpExecArray | null; // Try XML-style tool calls (common in Qwen output) const xmlRegex = new RegExp(TOOL_CALL_PATTERN); while ((match = xmlRegex.exec(text)) !== null) { calls.push({ id: `call_${calls.length}`, name: match[1]!.trim(), arguments: match[2]!.trim(), }); } if (calls.length > 0) return calls; // Try JSON-style tool calls const jsonRegex = new RegExp(JSON_TOOL_PATTERN); while ((match = jsonRegex.exec(text)) !== null) { calls.push({ id: `call_${calls.length}`, name: match[1]!.trim(), arguments: match[2]!.trim(), }); } return calls; } export function hasToolCallMarkup(text: string): boolean { return TOOL_CALL_PATTERN.test(text) || JSON_TOOL_PATTERN.test(text); }