@quilltap/plugin-utils 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,7 +30,7 @@ interface ParsedTextTool {
30
30
  /** End index in the original text */
31
31
  endIndex: number;
32
32
  /** Which format was detected */
33
- format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use';
33
+ format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use' | 'invoke';
34
34
  }
35
35
  /**
36
36
  * Normalize a tool name from hallucinated markup to the canonical name.
@@ -66,6 +66,14 @@ declare function parseFunctionCallFormat(response: string): ParsedTextTool[];
66
66
  * - Attributed: `<tool_use name="fn"><arguments>...</arguments></tool_use>`
67
67
  */
68
68
  declare function parseToolUseFormat(response: string): ParsedTextTool[];
69
+ /**
70
+ * Parse bare `<invoke name="...">` format (Kimi K2 and similar models)
71
+ *
72
+ * Matches `<invoke>` tags that appear WITHOUT a `<function_calls>` wrapper.
73
+ * IMPORTANT: In composite parsing, this must run AFTER parseFunctionCallsFormat
74
+ * so that wrapped invokes are claimed first and deduplicated by startIndex.
75
+ */
76
+ declare function parseInvokeFormat(response: string): ParsedTextTool[];
69
77
  /**
70
78
  * Parse all known XML tool call formats from response text.
71
79
  * Deduplicates by position and sorts by start index.
@@ -92,6 +100,8 @@ declare function hasToolCallMarkers(response: string): boolean;
92
100
  declare function hasFunctionCallMarkers(response: string): boolean;
93
101
  /** Check for `<tool_use>` markers (Gemini-style) */
94
102
  declare function hasToolUseMarkers(response: string): boolean;
103
+ /** Check for bare `<invoke name="...">` markers (Kimi K2-style) */
104
+ declare function hasInvokeMarkers(response: string): boolean;
95
105
  /**
96
106
  * Strip all known XML tool call markers from text.
97
107
  * Cleans up whitespace left behind.
@@ -105,5 +115,7 @@ declare function stripToolCallMarkers(response: string): string;
105
115
  declare function stripFunctionCallMarkers(response: string): string;
106
116
  /** Strip `<tool_use>` blocks */
107
117
  declare function stripToolUseMarkers(response: string): string;
118
+ /** Strip bare `<invoke>` blocks (Kimi K2-style) */
119
+ declare function stripInvokeMarkers(response: string): string;
108
120
 
109
- export { type ParsedTextTool, convertToToolCallRequest as convertTextToolToRequest, hasAnyXMLToolMarkers, hasFunctionCallMarkers, hasFunctionCallsMarkers, hasToolCallMarkers, hasToolUseMarkers, normalizeToolName, parseAllXMLAsToolCalls, parseAllXMLFormats, parseFunctionCallFormat, parseFunctionCallsFormat, parseToolCallFormat, parseToolUseFormat, stripAllXMLToolMarkers, stripFunctionCallMarkers, stripFunctionCallsMarkers, stripToolCallMarkers, stripToolUseMarkers };
121
+ export { type ParsedTextTool, convertToToolCallRequest as convertTextToolToRequest, hasAnyXMLToolMarkers, hasFunctionCallMarkers, hasFunctionCallsMarkers, hasInvokeMarkers, hasToolCallMarkers, hasToolUseMarkers, normalizeToolName, parseAllXMLAsToolCalls, parseAllXMLFormats, parseFunctionCallFormat, parseFunctionCallsFormat, parseInvokeFormat, parseToolCallFormat, parseToolUseFormat, stripAllXMLToolMarkers, stripFunctionCallMarkers, stripFunctionCallsMarkers, stripInvokeMarkers, stripToolCallMarkers, stripToolUseMarkers };
@@ -30,7 +30,7 @@ interface ParsedTextTool {
30
30
  /** End index in the original text */
31
31
  endIndex: number;
32
32
  /** Which format was detected */
33
- format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use';
33
+ format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use' | 'invoke';
34
34
  }
35
35
  /**
36
36
  * Normalize a tool name from hallucinated markup to the canonical name.
@@ -66,6 +66,14 @@ declare function parseFunctionCallFormat(response: string): ParsedTextTool[];
66
66
  * - Attributed: `<tool_use name="fn"><arguments>...</arguments></tool_use>`
67
67
  */
68
68
  declare function parseToolUseFormat(response: string): ParsedTextTool[];
69
+ /**
70
+ * Parse bare `<invoke name="...">` format (Kimi K2 and similar models)
71
+ *
72
+ * Matches `<invoke>` tags that appear WITHOUT a `<function_calls>` wrapper.
73
+ * IMPORTANT: In composite parsing, this must run AFTER parseFunctionCallsFormat
74
+ * so that wrapped invokes are claimed first and deduplicated by startIndex.
75
+ */
76
+ declare function parseInvokeFormat(response: string): ParsedTextTool[];
69
77
  /**
70
78
  * Parse all known XML tool call formats from response text.
71
79
  * Deduplicates by position and sorts by start index.
@@ -92,6 +100,8 @@ declare function hasToolCallMarkers(response: string): boolean;
92
100
  declare function hasFunctionCallMarkers(response: string): boolean;
93
101
  /** Check for `<tool_use>` markers (Gemini-style) */
94
102
  declare function hasToolUseMarkers(response: string): boolean;
103
+ /** Check for bare `<invoke name="...">` markers (Kimi K2-style) */
104
+ declare function hasInvokeMarkers(response: string): boolean;
95
105
  /**
96
106
  * Strip all known XML tool call markers from text.
97
107
  * Cleans up whitespace left behind.
@@ -105,5 +115,7 @@ declare function stripToolCallMarkers(response: string): string;
105
115
  declare function stripFunctionCallMarkers(response: string): string;
106
116
  /** Strip `<tool_use>` blocks */
107
117
  declare function stripToolUseMarkers(response: string): string;
118
+ /** Strip bare `<invoke>` blocks (Kimi K2-style) */
119
+ declare function stripInvokeMarkers(response: string): string;
108
120
 
109
- export { type ParsedTextTool, convertToToolCallRequest as convertTextToolToRequest, hasAnyXMLToolMarkers, hasFunctionCallMarkers, hasFunctionCallsMarkers, hasToolCallMarkers, hasToolUseMarkers, normalizeToolName, parseAllXMLAsToolCalls, parseAllXMLFormats, parseFunctionCallFormat, parseFunctionCallsFormat, parseToolCallFormat, parseToolUseFormat, stripAllXMLToolMarkers, stripFunctionCallMarkers, stripFunctionCallsMarkers, stripToolCallMarkers, stripToolUseMarkers };
121
+ export { type ParsedTextTool, convertToToolCallRequest as convertTextToolToRequest, hasAnyXMLToolMarkers, hasFunctionCallMarkers, hasFunctionCallsMarkers, hasInvokeMarkers, hasToolCallMarkers, hasToolUseMarkers, normalizeToolName, parseAllXMLAsToolCalls, parseAllXMLFormats, parseFunctionCallFormat, parseFunctionCallsFormat, parseInvokeFormat, parseToolCallFormat, parseToolUseFormat, stripAllXMLToolMarkers, stripFunctionCallMarkers, stripFunctionCallsMarkers, stripInvokeMarkers, stripToolCallMarkers, stripToolUseMarkers };
@@ -34,6 +34,7 @@ __export(tools_exports, {
34
34
  hasAnyXMLToolMarkers: () => hasAnyXMLToolMarkers,
35
35
  hasFunctionCallMarkers: () => hasFunctionCallMarkers,
36
36
  hasFunctionCallsMarkers: () => hasFunctionCallsMarkers,
37
+ hasInvokeMarkers: () => hasInvokeMarkers,
37
38
  hasToolCallMarkers: () => hasToolCallMarkers,
38
39
  hasToolCalls: () => hasToolCalls,
39
40
  hasToolUseMarkers: () => hasToolUseMarkers,
@@ -44,6 +45,7 @@ __export(tools_exports, {
44
45
  parseFunctionCallFormat: () => parseFunctionCallFormat,
45
46
  parseFunctionCallsFormat: () => parseFunctionCallsFormat,
46
47
  parseGoogleToolCalls: () => parseGoogleToolCalls,
48
+ parseInvokeFormat: () => parseInvokeFormat,
47
49
  parseOpenAIToolCalls: () => parseOpenAIToolCalls,
48
50
  parseToolCallFormat: () => parseToolCallFormat,
49
51
  parseToolCalls: () => parseToolCalls,
@@ -51,6 +53,7 @@ __export(tools_exports, {
51
53
  stripAllXMLToolMarkers: () => stripAllXMLToolMarkers,
52
54
  stripFunctionCallMarkers: () => stripFunctionCallMarkers,
53
55
  stripFunctionCallsMarkers: () => stripFunctionCallsMarkers,
56
+ stripInvokeMarkers: () => stripInvokeMarkers,
54
57
  stripToolCallMarkers: () => stripToolCallMarkers,
55
58
  stripToolUseMarkers: () => stripToolUseMarkers
56
59
  });
@@ -314,7 +317,13 @@ var TOOL_NAME_ALIASES = {
314
317
  "search": "search_web",
315
318
  "web_search": "search_web",
316
319
  "websearch": "search_web",
317
- "web": "search_web"
320
+ "web": "search_web",
321
+ // Help tool aliases
322
+ "help_search": "help_search",
323
+ "helpsearch": "help_search",
324
+ "search_help": "help_search",
325
+ "help_navigate": "help_navigate",
326
+ "helpnavigate": "help_navigate"
318
327
  };
319
328
  function normalizeToolName(name) {
320
329
  const normalized = name.toLowerCase().trim();
@@ -344,6 +353,21 @@ function convertToToolCallRequest(parsed) {
344
353
  query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || ""
345
354
  }
346
355
  };
356
+ case "help_search":
357
+ return {
358
+ name: "help_search",
359
+ arguments: {
360
+ query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || "",
361
+ limit: parsed.arguments.limit
362
+ }
363
+ };
364
+ case "help_navigate":
365
+ return {
366
+ name: "help_navigate",
367
+ arguments: {
368
+ url: parsed.arguments.url || parsed.arguments.path || Object.values(parsed.arguments)[0] || ""
369
+ }
370
+ };
347
371
  default:
348
372
  return {
349
373
  name: parsed.toolName,
@@ -537,12 +561,38 @@ function parseToolUseFormat(response) {
537
561
  }
538
562
  return results;
539
563
  }
564
+ function parseInvokeFormat(response) {
565
+ const results = [];
566
+ const invokePattern = /<invoke\s+name=["']([^"']+)["']>([\s\S]*?)<\/invoke>/gi;
567
+ let match;
568
+ while ((match = invokePattern.exec(response)) !== null) {
569
+ const toolName = match[1];
570
+ const paramContent = match[2];
571
+ const startIndex = match.index;
572
+ const args = {};
573
+ const paramPattern = /<parameter\s+name=["']([^"']+)["']>([^<]*)<\/parameter>/gi;
574
+ let paramMatch;
575
+ while ((paramMatch = paramPattern.exec(paramContent)) !== null) {
576
+ args[paramMatch[1]] = paramMatch[2].trim();
577
+ }
578
+ results.push({
579
+ toolName: normalizeToolName(toolName),
580
+ arguments: args,
581
+ fullMatch: match[0],
582
+ startIndex,
583
+ endIndex: startIndex + match[0].length,
584
+ format: "invoke"
585
+ });
586
+ }
587
+ return results;
588
+ }
540
589
  function parseAllXMLFormats(response) {
541
590
  const allResults = [];
542
591
  allResults.push(...parseFunctionCallsFormat(response));
543
592
  allResults.push(...parseToolCallFormat(response));
544
593
  allResults.push(...parseFunctionCallFormat(response));
545
594
  allResults.push(...parseToolUseFormat(response));
595
+ allResults.push(...parseInvokeFormat(response));
546
596
  const seen = /* @__PURE__ */ new Set();
547
597
  const deduped = allResults.filter((result) => {
548
598
  if (seen.has(result.startIndex)) {
@@ -558,7 +608,7 @@ function parseAllXMLAsToolCalls(response) {
558
608
  return parseAllXMLFormats(response).map(convertToToolCallRequest);
559
609
  }
560
610
  function hasAnyXMLToolMarkers(response) {
561
- return /<function_calls>/i.test(response) || /<tool_call>/i.test(response) || /<function_call\s+/i.test(response) || /<tool_use[\s>]/i.test(response);
611
+ return /<function_calls>/i.test(response) || /<tool_call>/i.test(response) || /<function_call\s+/i.test(response) || /<tool_use[\s>]/i.test(response) || /<invoke\s+name=/i.test(response);
562
612
  }
563
613
  function hasFunctionCallsMarkers(response) {
564
614
  return /<function_calls>/i.test(response);
@@ -572,12 +622,16 @@ function hasFunctionCallMarkers(response) {
572
622
  function hasToolUseMarkers(response) {
573
623
  return /<tool_use[\s>]/i.test(response);
574
624
  }
625
+ function hasInvokeMarkers(response) {
626
+ return /<invoke\s+name=/i.test(response);
627
+ }
575
628
  function stripAllXMLToolMarkers(response) {
576
629
  let stripped = response;
577
630
  stripped = stripped.replace(/<function_calls>[\s\S]*?<\/function_calls>/gi, "");
578
631
  stripped = stripped.replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, "");
579
632
  stripped = stripped.replace(/<function_call\s+[^>]*>[\s\S]*?<\/function_call>/gi, "");
580
633
  stripped = stripped.replace(/<tool_use[\s>][\s\S]*?<\/tool_use>/gi, "");
634
+ stripped = stripped.replace(/<invoke\s+name=["'][^"']*["']>[\s\S]*?<\/invoke>/gi, "");
581
635
  stripped = stripped.replace(/\n{3,}/g, "\n\n").replace(/ +/g, " ").trim();
582
636
  return stripped;
583
637
  }
@@ -593,6 +647,9 @@ function stripFunctionCallMarkers(response) {
593
647
  function stripToolUseMarkers(response) {
594
648
  return response.replace(/<tool_use[\s>][\s\S]*?<\/tool_use>/gi, "");
595
649
  }
650
+ function stripInvokeMarkers(response) {
651
+ return response.replace(/<invoke\s+name=["'][^"']*["']>[\s\S]*?<\/invoke>/gi, "");
652
+ }
596
653
  // Annotate the CommonJS export names for ESM import in node:
597
654
  0 && (module.exports = {
598
655
  applyDescriptionLimit,
@@ -609,6 +666,7 @@ function stripToolUseMarkers(response) {
609
666
  hasAnyXMLToolMarkers,
610
667
  hasFunctionCallMarkers,
611
668
  hasFunctionCallsMarkers,
669
+ hasInvokeMarkers,
612
670
  hasToolCallMarkers,
613
671
  hasToolCalls,
614
672
  hasToolUseMarkers,
@@ -619,6 +677,7 @@ function stripToolUseMarkers(response) {
619
677
  parseFunctionCallFormat,
620
678
  parseFunctionCallsFormat,
621
679
  parseGoogleToolCalls,
680
+ parseInvokeFormat,
622
681
  parseOpenAIToolCalls,
623
682
  parseToolCallFormat,
624
683
  parseToolCalls,
@@ -626,6 +685,7 @@ function stripToolUseMarkers(response) {
626
685
  stripAllXMLToolMarkers,
627
686
  stripFunctionCallMarkers,
628
687
  stripFunctionCallsMarkers,
688
+ stripInvokeMarkers,
629
689
  stripToolCallMarkers,
630
690
  stripToolUseMarkers
631
691
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tools/index.ts","../../src/tools/parsers.ts","../../src/tools/converters.ts","../../src/tools/text-parsers.ts"],"sourcesContent":["/**\n * Tool Utilities\n *\n * Exports all tool-related utilities for parsing and converting\n * tool calls between different LLM provider formats.\n *\n * @module @quilltap/plugin-utils/tools\n */\n\n// Re-export types\nexport type {\n OpenAIToolDefinition,\n UniversalTool,\n AnthropicToolDefinition,\n GoogleToolDefinition,\n ToolCall,\n ToolCallRequest,\n ToolResult,\n ToolFormatOptions,\n} from './types';\n\n// Export parsers\nexport {\n parseToolCalls,\n parseOpenAIToolCalls,\n parseAnthropicToolCalls,\n parseGoogleToolCalls,\n detectToolCallFormat,\n hasToolCalls,\n} from './parsers';\n\nexport type { ToolCallFormat } from './parsers';\n\n// Export converters\nexport {\n convertToAnthropicFormat,\n convertToGoogleFormat,\n convertFromAnthropicFormat,\n convertFromGoogleFormat,\n convertToolTo,\n convertToolsTo,\n applyDescriptionLimit,\n // Backward-compatible aliases\n convertOpenAIToAnthropicFormat,\n convertOpenAIToGoogleFormat,\n} from './converters';\n\nexport type { ToolConvertTarget } from './converters';\n\n// Export text-based tool call parsers (for spontaneous XML emissions)\nexport {\n // Composite utilities\n parseAllXMLFormats,\n parseAllXMLAsToolCalls,\n hasAnyXMLToolMarkers,\n stripAllXMLToolMarkers,\n // Individual format parsers\n parseFunctionCallsFormat,\n parseToolCallFormat,\n parseFunctionCallFormat,\n parseToolUseFormat,\n // Individual marker checks\n hasFunctionCallsMarkers,\n hasToolCallMarkers,\n hasFunctionCallMarkers,\n hasToolUseMarkers,\n // Individual strippers\n stripFunctionCallsMarkers,\n stripToolCallMarkers,\n stripFunctionCallMarkers,\n stripToolUseMarkers,\n // Utilities\n normalizeToolName,\n convertToToolCallRequest as convertTextToolToRequest,\n} from './text-parsers';\n\nexport type { ParsedTextTool } from './text-parsers';\n","/**\n * Tool Call Parsers\n *\n * Provider-specific parsers for extracting tool calls from LLM responses.\n * Each parser converts from a provider's native format to the standardized\n * ToolCallRequest format.\n *\n * @module @quilltap/plugin-utils/tools/parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Supported tool call response formats\n */\nexport type ToolCallFormat = 'openai' | 'anthropic' | 'google' | 'auto';\n\n/**\n * Parse OpenAI format tool calls from LLM response\n *\n * Extracts tool calls from OpenAI/Grok API responses which return\n * tool_calls in the message object.\n *\n * Expected response structures:\n * - `response.tool_calls` (direct)\n * - `response.choices[0].message.tool_calls` (nested)\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await openai.chat.completions.create({...});\n * const toolCalls = parseOpenAIToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseOpenAIToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n // Handle direct tool_calls array (snake_case)\n let toolCallsArray = resp?.tool_calls as unknown[] | undefined;\n\n // Handle direct toolCalls array (camelCase - some SDKs use this)\n if (!toolCallsArray) {\n toolCallsArray = (resp as Record<string, unknown>)?.toolCalls as unknown[] | undefined;\n }\n\n // Check nested structure from non-streaming responses: choices[0].message.tool_calls\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ message?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls;\n }\n\n // Check nested structure from streaming responses: choices[0].delta.toolCalls\n // OpenRouter SDK uses camelCase and puts tool calls in delta for streaming\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls;\n }\n\n if (toolCallsArray && Array.isArray(toolCallsArray) && toolCallsArray.length > 0) {\n for (const toolCall of toolCallsArray) {\n const tc = toolCall as {\n id?: string;\n type?: string;\n function?: { name: string; arguments: string };\n };\n\n if (tc.type === 'function' && tc.function) {\n const argsStr = tc.function.arguments || '{}';\n\n // During streaming, arguments may be incomplete JSON.\n // Check if the string looks like complete JSON before parsing.\n // Skip incomplete tool calls - they'll be complete in the final response.\n const trimmed = argsStr.trim();\n if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {\n // Incomplete JSON - skip this tool call for now\n continue;\n }\n\n try {\n toolCalls.push({\n name: tc.function.name,\n arguments: JSON.parse(argsStr),\n callId: tc.id || undefined,\n });\n } catch {\n // JSON parse failed (e.g., incomplete JSON during streaming)\n // This is expected during streaming - skip silently\n continue;\n }\n }\n }\n }\n } catch (error) {\n // Log error for unexpected parsing failures (not JSON parse errors)\n console.error('[plugin-utils] Error parsing OpenAI tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Anthropic format tool calls from LLM response\n *\n * Extracts tool calls from Anthropic API responses which return\n * tool_use blocks in the content array.\n *\n * Expected response structure:\n * - `response.content` array with `{ type: 'tool_use', name, input }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await anthropic.messages.create({...});\n * const toolCalls = parseAnthropicToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseAnthropicToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n if (!resp?.content || !Array.isArray(resp.content)) {\n return toolCalls;\n }\n\n for (const block of resp.content) {\n const b = block as { type?: string; id?: string; name?: string; input?: Record<string, unknown> };\n\n if (b.type === 'tool_use' && b.name) {\n toolCalls.push({\n name: b.name,\n arguments: b.input || {},\n callId: b.id || undefined,\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Anthropic tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Google Gemini format tool calls from LLM response\n *\n * Extracts tool calls from Google Gemini API responses which return\n * functionCall objects in the parts array.\n *\n * Expected response structure:\n * - `response.candidates[0].content.parts` array with `{ functionCall: { name, args } }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await gemini.generateContent({...});\n * const toolCalls = parseGoogleToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseGoogleToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n const candidates = resp?.candidates as\n | Array<{ content?: { parts?: unknown[] } }>\n | undefined;\n const parts = candidates?.[0]?.content?.parts;\n\n if (!parts || !Array.isArray(parts)) {\n return toolCalls;\n }\n\n for (const part of parts) {\n const p = part as {\n functionCall?: { name: string; args?: Record<string, unknown> };\n };\n\n if (p.functionCall) {\n toolCalls.push({\n name: p.functionCall.name,\n arguments: p.functionCall.args || {},\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Google tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Detect the format of a tool call response\n *\n * Analyzes the response structure to determine which provider format it uses.\n *\n * @param response - The raw response from a provider API\n * @returns The detected format, or null if unrecognized\n */\nexport function detectToolCallFormat(response: unknown): ToolCallFormat | null {\n if (!response || typeof response !== 'object') {\n return null;\n }\n\n const resp = response as Record<string, unknown>;\n\n // OpenAI format: has tool_calls/toolCalls directly or in choices[0].message or choices[0].delta\n if (resp.tool_calls && Array.isArray(resp.tool_calls)) {\n return 'openai';\n }\n if (resp.toolCalls && Array.isArray(resp.toolCalls)) {\n return 'openai';\n }\n\n const choices = resp.choices as Array<{\n message?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n }> | undefined;\n if (choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls) {\n return 'openai';\n }\n // Check delta for streaming responses (OpenRouter SDK uses this)\n if (choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls) {\n return 'openai';\n }\n\n // Anthropic format: has content array with tool_use type\n if (resp.content && Array.isArray(resp.content)) {\n const hasToolUse = (resp.content as Array<{ type?: string }>).some(\n (block) => block.type === 'tool_use'\n );\n if (hasToolUse) {\n return 'anthropic';\n }\n }\n\n // Google format: has candidates[0].content.parts with functionCall\n const candidates = resp.candidates as\n | Array<{ content?: { parts?: Array<{ functionCall?: unknown }> } }>\n | undefined;\n if (candidates?.[0]?.content?.parts) {\n const hasFunctionCall = candidates[0].content.parts.some((part) => part.functionCall);\n if (hasFunctionCall) {\n return 'google';\n }\n }\n\n return null;\n}\n\n/**\n * Parse tool calls with auto-detection or explicit format\n *\n * A unified parser that can either auto-detect the response format\n * or use a specified format. This is useful when you're not sure\n * which provider's response you're handling.\n *\n * @param response - The raw response from a provider API\n * @param format - The format to use: 'openai', 'anthropic', 'google', or 'auto'\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * // Auto-detect format\n * const toolCalls = parseToolCalls(response, 'auto');\n *\n * // Or specify format explicitly\n * const toolCalls = parseToolCalls(response, 'openai');\n * ```\n */\nexport function parseToolCalls(\n response: unknown,\n format: ToolCallFormat = 'auto'\n): ToolCallRequest[] {\n let actualFormat: ToolCallFormat | null = format;\n\n if (format === 'auto') {\n actualFormat = detectToolCallFormat(response);\n if (!actualFormat) {\n return [];\n }\n }\n\n switch (actualFormat) {\n case 'openai':\n return parseOpenAIToolCalls(response);\n case 'anthropic':\n return parseAnthropicToolCalls(response);\n case 'google':\n return parseGoogleToolCalls(response);\n default:\n return [];\n }\n}\n\n/**\n * Check if a response contains tool calls\n *\n * Quick check to determine if a response has any tool calls\n * without fully parsing them.\n *\n * @param response - The raw response from a provider API\n * @returns True if the response contains tool calls\n */\nexport function hasToolCalls(response: unknown): boolean {\n const format = detectToolCallFormat(response);\n return format !== null;\n}\n","/**\n * Tool Format Converters\n *\n * Utilities for converting between different provider tool formats.\n * The universal format (OpenAI-style) serves as the baseline for all conversions.\n *\n * @module @quilltap/plugin-utils/tools/converters\n */\n\nimport type {\n UniversalTool,\n AnthropicToolDefinition,\n GoogleToolDefinition,\n OpenAIToolDefinition,\n} from '@quilltap/plugin-types';\n\n/**\n * Convert OpenAI/Universal format tool to Anthropic format\n *\n * Anthropic uses a tool_use format with:\n * - name: string\n * - description: string\n * - input_schema: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Anthropic's tool_use\n *\n * @example\n * ```typescript\n * const anthropicTool = convertToAnthropicFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // input_schema: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToAnthropicFormat(tool: UniversalTool | OpenAIToolDefinition): AnthropicToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n input_schema: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert OpenAI/Universal format tool to Google Gemini format\n *\n * Google uses a function calling format with:\n * - name: string\n * - description: string\n * - parameters: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Google's functionCall\n *\n * @example\n * ```typescript\n * const googleTool = convertToGoogleFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // parameters: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToGoogleFormat(tool: UniversalTool | OpenAIToolDefinition): GoogleToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert Anthropic format tool to Universal/OpenAI format\n *\n * @param tool - Anthropic format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromAnthropicFormat(tool: AnthropicToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.input_schema.properties,\n required: tool.input_schema.required ?? [],\n },\n },\n };\n}\n\n/**\n * Convert Google format tool to Universal/OpenAI format\n *\n * @param tool - Google format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromGoogleFormat(tool: GoogleToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n },\n };\n}\n\n/**\n * Apply prompt/description length limit to a tool\n *\n * Modifies a tool's description if it exceeds maxBytes, appending a warning\n * that the description was truncated. This is useful for providers with\n * strict token limits.\n *\n * @param tool - Tool object (any format) with a description property\n * @param maxBytes - Maximum bytes allowed for description (including warning)\n * @returns Modified tool with truncated description if needed\n *\n * @example\n * ```typescript\n * const limitedTool = applyDescriptionLimit(tool, 500);\n * // If description > 500 bytes, truncates and adds warning\n * ```\n */\nexport function applyDescriptionLimit<T extends { description: string }>(\n tool: T,\n maxBytes: number\n): T {\n if (!tool || !tool.description) {\n return tool;\n }\n\n const warningText = ' [Note: description truncated due to length limit]';\n const maxDescBytes = maxBytes - Buffer.byteLength(warningText);\n\n if (maxDescBytes <= 0) {\n console.warn('[plugin-utils] Length limit too small for warning text:', maxBytes);\n return tool;\n }\n\n const descBytes = Buffer.byteLength(tool.description);\n\n if (descBytes > maxBytes) {\n // Truncate description to fit within the byte limit\n let truncated = tool.description;\n while (Buffer.byteLength(truncated) > maxDescBytes && truncated.length > 0) {\n truncated = truncated.slice(0, -1);\n }\n\n return {\n ...tool,\n description: truncated + warningText,\n };\n }\n\n return tool;\n}\n\n/**\n * Target format for tool conversion\n */\nexport type ToolConvertTarget = 'openai' | 'anthropic' | 'google';\n\n/**\n * Convert a universal tool to a specific provider format\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @param target - Target provider format\n * @returns Tool in the target format\n */\nexport function convertToolTo(\n tool: UniversalTool | OpenAIToolDefinition,\n target: ToolConvertTarget\n): UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition {\n switch (target) {\n case 'anthropic':\n return convertToAnthropicFormat(tool);\n case 'google':\n return convertToGoogleFormat(tool);\n case 'openai':\n default:\n return tool;\n }\n}\n\n/**\n * Convert multiple tools to a specific provider format\n *\n * @param tools - Array of universal tools or OpenAI tool definitions\n * @param target - Target provider format\n * @returns Array of tools in the target format\n */\nexport function convertToolsTo(\n tools: Array<UniversalTool | OpenAIToolDefinition>,\n target: ToolConvertTarget\n): Array<UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition> {\n return tools.map((tool) => convertToolTo(tool, target));\n}\n\n// ============================================================================\n// Backward-compatible aliases\n// ============================================================================\n\n/**\n * Alias for convertToAnthropicFormat\n * @deprecated Use convertToAnthropicFormat instead\n */\nexport const convertOpenAIToAnthropicFormat = convertToAnthropicFormat;\n\n/**\n * Alias for convertToGoogleFormat\n * @deprecated Use convertToGoogleFormat instead\n */\nexport const convertOpenAIToGoogleFormat = convertToGoogleFormat;\n","/**\n * Text-Based Tool Call Parsers\n *\n * Utility functions for parsing spontaneous XML-style tool calls from LLM\n * text responses. These are for models that emit tool-call-like markup in\n * their output instead of using native function calling APIs.\n *\n * Provider plugins import and compose these utilities to implement their\n * `hasTextToolMarkers`, `parseTextToolCalls`, and `stripTextToolMarkers` methods.\n *\n * @module @quilltap/plugin-utils/tools/text-parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Parsed text-based tool call from LLM output\n */\nexport interface ParsedTextTool {\n /** The tool name */\n toolName: string;\n /** Arguments extracted from the markup */\n arguments: Record<string, unknown>;\n /** The full matched markup text (for stripping) */\n fullMatch: string;\n /** Start index in the original text */\n startIndex: number;\n /** End index in the original text */\n endIndex: number;\n /** Which format was detected */\n format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use';\n}\n\n/**\n * Common tool name aliases that models use when hallucinating tool calls.\n * Maps common variations to canonical Quilltap tool names.\n */\nconst TOOL_NAME_ALIASES: Record<string, string> = {\n // Direct mappings\n 'search_memories': 'search_memories',\n 'generate_image': 'generate_image',\n 'search_web': 'search_web',\n\n // Memory tool aliases\n 'memory': 'search_memories',\n 'memory_search': 'search_memories',\n 'search_memory': 'search_memories',\n 'memories': 'search_memories',\n\n // Image tool aliases\n 'image': 'generate_image',\n 'create_image': 'generate_image',\n 'image_generation': 'generate_image',\n 'gen_image': 'generate_image',\n\n // Web search aliases\n 'search': 'search_web',\n 'web_search': 'search_web',\n 'websearch': 'search_web',\n 'web': 'search_web',\n};\n\n/**\n * Normalize a tool name from hallucinated markup to the canonical name.\n * Returns the original name if no alias is found (passes through unknown tools).\n */\nexport function normalizeToolName(name: string): string {\n const normalized = name.toLowerCase().trim();\n return TOOL_NAME_ALIASES[normalized] || name;\n}\n\n/**\n * Convert a ParsedTextTool to the standard ToolCallRequest format.\n *\n * For well-known tools, normalizes argument names (e.g., \"search\" → \"query\").\n * For unknown tools, passes arguments through as-is.\n */\nexport function convertToToolCallRequest(parsed: ParsedTextTool): ToolCallRequest {\n switch (parsed.toolName) {\n case 'search_memories':\n return {\n name: 'search_memories',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n limit: parsed.arguments.limit,\n },\n };\n\n case 'generate_image':\n return {\n name: 'generate_image',\n arguments: {\n prompt: parsed.arguments.prompt || parsed.arguments.description || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n case 'search_web':\n return {\n name: 'search_web',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n default:\n // Pass through unknown tools with their original arguments\n return {\n name: parsed.toolName,\n arguments: parsed.arguments,\n };\n }\n}\n\n// ============================================================================\n// Individual format parsers\n// ============================================================================\n\n/**\n * Parse `<function_calls><invoke name=\"...\">` format (DeepSeek and Claude-style)\n */\nexport function parseFunctionCallsFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallsPattern = /<function_calls>([\\s\\S]*?)<\\/function_calls>/gi;\n\n let wrapperMatch;\n while ((wrapperMatch = functionCallsPattern.exec(response)) !== null) {\n const wrapperContent = wrapperMatch[1];\n const wrapperStartIndex = wrapperMatch.index;\n const contentOffset = wrapperStartIndex + '<function_calls>'.length;\n\n const invokePattern = /<invoke\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/invoke>/gi;\n\n let invokeMatch;\n while ((invokeMatch = invokePattern.exec(wrapperContent)) !== null) {\n const toolName = invokeMatch[1];\n const paramContent = invokeMatch[2];\n const invokeStartIndex = contentOffset + invokeMatch.index;\n const invokeEndIndex = invokeStartIndex + invokeMatch[0].length;\n\n const args: Record<string, unknown> = {};\n let format: 'deepseek' | 'claude' = 'claude';\n\n // DeepSeek format: <parameter name=\"...\" string=\"...\">value</parameter>\n const deepseekParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']\\s+string=[\"']([^\"']*)[\"'][^>]*>([^<]*)<\\/parameter>/gi;\n let paramMatch;\n while ((paramMatch = deepseekParamPattern.exec(paramContent)) !== null) {\n const paramName = paramMatch[1];\n const stringAttr = paramMatch[2];\n const value = paramMatch[3].trim();\n\n if (stringAttr === 'false') {\n const numVal = Number(value);\n if (!isNaN(numVal)) {\n args[paramName] = numVal;\n } else if (value === 'true') {\n args[paramName] = true;\n } else if (value === 'false') {\n args[paramName] = false;\n } else {\n args[paramName] = value;\n }\n } else {\n args[paramName] = value;\n }\n format = 'deepseek';\n }\n\n // Claude format: <parameter name=\"...\">value</parameter>\n if (Object.keys(args).length === 0) {\n const claudeParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = claudeParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n }\n\n // antml:parameter format (Claude Code style)\n const antmlParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/antml:parameter>/gi;\n while ((paramMatch = antmlParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: invokeMatch[0],\n startIndex: invokeStartIndex,\n endIndex: invokeEndIndex,\n format,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_call>` format (generic XML)\n */\nexport function parseToolCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolCallPattern = /<tool_call>([\\s\\S]*?)<\\/tool_call>/gi;\n\n let match;\n while ((match = toolCallPattern.exec(response)) !== null) {\n const content = match[1];\n const startIndex = match.index;\n\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n\n const toolName = nameMatch[1].trim();\n const args: Record<string, unknown> = {};\n\n const argsMatch = /<arguments>([\\s\\S]*?)<\\/arguments>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1];\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'generic',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<function_call name=\"...\">` format\n */\nexport function parseFunctionCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallPattern = /<function_call\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/function_call>/gi;\n\n let match;\n while ((match = functionCallPattern.exec(response)) !== null) {\n const toolName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n const args: Record<string, unknown> = {};\n\n const paramPattern = /<param\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/param>/gi;\n let paramMatch;\n while ((paramMatch = paramPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n const parameterPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = parameterPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'function_call',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_use>` format (Gemini and others)\n *\n * Handles multiple sub-formats:\n * - Bare JSON: `<tool_use>{\"name\":\"fn\",\"input\":{...}}</tool_use>`\n * - XML children: `<tool_use><name>fn</name><arguments>...</arguments></tool_use>`\n * - JSON in arguments: `<tool_use><name>fn</name><arguments>{\"q\":\"v\"}</arguments></tool_use>`\n * - Attributed: `<tool_use name=\"fn\"><arguments>...</arguments></tool_use>`\n */\nexport function parseToolUseFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolUsePattern = /<tool_use(?:\\s+name=[\"']([^\"']+)[\"'])?\\s*>([\\s\\S]*?)<\\/tool_use>/gi;\n\n let match;\n while ((match = toolUsePattern.exec(response)) !== null) {\n const attrName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n // Try bare JSON first (Gemini's primary format)\n const trimmedContent = content.trim();\n if (trimmedContent.startsWith('{')) {\n try {\n const jsonBlob = JSON.parse(trimmedContent);\n if (typeof jsonBlob === 'object' && jsonBlob !== null && jsonBlob.name) {\n const args = jsonBlob.input || jsonBlob.arguments || jsonBlob.parameters || {};\n results.push({\n toolName: normalizeToolName(jsonBlob.name),\n arguments: typeof args === 'object' && args !== null ? args : {},\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n continue;\n }\n } catch {\n // Not valid JSON, fall through\n }\n }\n\n // Extract name from attribute or child element\n let toolName = attrName;\n if (!toolName) {\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n toolName = nameMatch[1].trim();\n }\n\n const args: Record<string, unknown> = {};\n\n // Try <arguments>, <input>, or <parameters>\n const argsMatch = /<(?:arguments|input|parameters)>([\\s\\S]*?)<\\/(?:arguments|input|parameters)>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1].trim();\n\n if (argsContent.startsWith('{')) {\n try {\n const parsed = JSON.parse(argsContent);\n if (typeof parsed === 'object' && parsed !== null) {\n Object.assign(args, parsed);\n }\n } catch {\n // Not valid JSON\n }\n }\n\n if (Object.keys(args).length === 0) {\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n }\n\n return results;\n}\n\n// ============================================================================\n// Composite utilities for plugins\n// ============================================================================\n\n/**\n * Parse all known XML tool call formats from response text.\n * Deduplicates by position and sorts by start index.\n *\n * Plugins can call this directly or compose individual format parsers\n * for provider-specific behavior.\n */\nexport function parseAllXMLFormats(response: string): ParsedTextTool[] {\n const allResults: ParsedTextTool[] = [];\n\n allResults.push(...parseFunctionCallsFormat(response));\n allResults.push(...parseToolCallFormat(response));\n allResults.push(...parseFunctionCallFormat(response));\n allResults.push(...parseToolUseFormat(response));\n\n // Deduplicate by startIndex\n const seen = new Set<number>();\n const deduped = allResults.filter(result => {\n if (seen.has(result.startIndex)) {\n return false;\n }\n seen.add(result.startIndex);\n return true;\n });\n\n deduped.sort((a, b) => a.startIndex - b.startIndex);\n return deduped;\n}\n\n/**\n * Convert parsed text tools to standard ToolCallRequest array.\n * Convenience wrapper for plugins implementing parseTextToolCalls.\n */\nexport function parseAllXMLAsToolCalls(response: string): ToolCallRequest[] {\n return parseAllXMLFormats(response).map(convertToToolCallRequest);\n}\n\n/**\n * Check if text contains any of the known XML tool call patterns.\n * Quick regex check before full parsing.\n */\nexport function hasAnyXMLToolMarkers(response: string): boolean {\n return (\n /<function_calls>/i.test(response) ||\n /<tool_call>/i.test(response) ||\n /<function_call\\s+/i.test(response) ||\n /<tool_use[\\s>]/i.test(response)\n );\n}\n\n// Individual marker checks for plugins that only care about specific formats\n\n/** Check for `<function_calls>` markers (DeepSeek/Claude-style) */\nexport function hasFunctionCallsMarkers(response: string): boolean {\n return /<function_calls>/i.test(response);\n}\n\n/** Check for `<tool_call>` markers (generic) */\nexport function hasToolCallMarkers(response: string): boolean {\n return /<tool_call>/i.test(response);\n}\n\n/** Check for `<function_call>` markers */\nexport function hasFunctionCallMarkers(response: string): boolean {\n return /<function_call\\s+/i.test(response);\n}\n\n/** Check for `<tool_use>` markers (Gemini-style) */\nexport function hasToolUseMarkers(response: string): boolean {\n return /<tool_use[\\s>]/i.test(response);\n}\n\n/**\n * Strip all known XML tool call markers from text.\n * Cleans up whitespace left behind.\n */\nexport function stripAllXMLToolMarkers(response: string): string {\n let stripped = response;\n\n stripped = stripped.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n stripped = stripped.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n stripped = stripped.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n stripped = stripped.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n\n stripped = stripped\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/ +/g, ' ')\n .trim();\n\n return stripped;\n}\n\n// Individual strippers for plugins that only handle specific formats\n\n/** Strip `<function_calls>` blocks */\nexport function stripFunctionCallsMarkers(response: string): string {\n return response.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n}\n\n/** Strip `<tool_call>` blocks */\nexport function stripToolCallMarkers(response: string): string {\n return response.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n}\n\n/** Strip `<function_call>` blocks */\nexport function stripFunctionCallMarkers(response: string): string {\n return response.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n}\n\n/** Strip `<tool_use>` blocks */\nexport function stripToolUseMarkers(response: string): string {\n return response.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqCO,SAAS,qBAAqB,UAAsC;AACzE,QAAM,YAA+B,CAAC;AAEtC,MAAI;AACF,UAAM,OAAO;AAGb,QAAI,iBAAiB,MAAM;AAG3B,QAAI,CAAC,gBAAgB;AACnB,uBAAkB,MAAkC;AAAA,IACtD;AAGA,QAAI,CAAC,gBAAgB;AACnB,YAAM,UAAU,MAAM;AAGtB,uBAAiB,UAAU,CAAC,GAAG,SAAS,cAAc,UAAU,CAAC,GAAG,SAAS;AAAA,IAC/E;AAIA,QAAI,CAAC,gBAAgB;AACnB,YAAM,UAAU,MAAM;AAGtB,uBAAiB,UAAU,CAAC,GAAG,OAAO,cAAc,UAAU,CAAC,GAAG,OAAO;AAAA,IAC3E;AAEA,QAAI,kBAAkB,MAAM,QAAQ,cAAc,KAAK,eAAe,SAAS,GAAG;AAChF,iBAAW,YAAY,gBAAgB;AACrC,cAAM,KAAK;AAMX,YAAI,GAAG,SAAS,cAAc,GAAG,UAAU;AACzC,gBAAM,UAAU,GAAG,SAAS,aAAa;AAKzC,gBAAM,UAAU,QAAQ,KAAK;AAC7B,cAAI,CAAC,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,SAAS,GAAG,GAAG;AAEtD;AAAA,UACF;AAEA,cAAI;AACF,sBAAU,KAAK;AAAA,cACb,MAAM,GAAG,SAAS;AAAA,cAClB,WAAW,KAAK,MAAM,OAAO;AAAA,cAC7B,QAAQ,GAAG,MAAM;AAAA,YACnB,CAAC;AAAA,UACH,QAAQ;AAGN;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAEd,YAAQ,MAAM,mDAAmD,KAAK;AAAA,EACxE;AAEA,SAAO;AACT;AAqBO,SAAS,wBAAwB,UAAsC;AAC5E,QAAM,YAA+B,CAAC;AAEtC,MAAI;AACF,UAAM,OAAO;AAEb,QAAI,CAAC,MAAM,WAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,GAAG;AAClD,aAAO;AAAA,IACT;AAEA,eAAW,SAAS,KAAK,SAAS;AAChC,YAAM,IAAI;AAEV,UAAI,EAAE,SAAS,cAAc,EAAE,MAAM;AACnC,kBAAU,KAAK;AAAA,UACb,MAAM,EAAE;AAAA,UACR,WAAW,EAAE,SAAS,CAAC;AAAA,UACvB,QAAQ,EAAE,MAAM;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,sDAAsD,KAAK;AAAA,EAC3E;AAEA,SAAO;AACT;AAqBO,SAAS,qBAAqB,UAAsC;AACzE,QAAM,YAA+B,CAAC;AAEtC,MAAI;AACF,UAAM,OAAO;AACb,UAAM,aAAa,MAAM;AAGzB,UAAM,QAAQ,aAAa,CAAC,GAAG,SAAS;AAExC,QAAI,CAAC,SAAS,CAAC,MAAM,QAAQ,KAAK,GAAG;AACnC,aAAO;AAAA,IACT;AAEA,eAAW,QAAQ,OAAO;AACxB,YAAM,IAAI;AAIV,UAAI,EAAE,cAAc;AAClB,kBAAU,KAAK;AAAA,UACb,MAAM,EAAE,aAAa;AAAA,UACrB,WAAW,EAAE,aAAa,QAAQ,CAAC;AAAA,QACrC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,mDAAmD,KAAK;AAAA,EACxE;AAEA,SAAO;AACT;AAUO,SAAS,qBAAqB,UAA0C;AAC7E,MAAI,CAAC,YAAY,OAAO,aAAa,UAAU;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,OAAO;AAGb,MAAI,KAAK,cAAc,MAAM,QAAQ,KAAK,UAAU,GAAG;AACrD,WAAO;AAAA,EACT;AACA,MAAI,KAAK,aAAa,MAAM,QAAQ,KAAK,SAAS,GAAG;AACnD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,KAAK;AAIrB,MAAI,UAAU,CAAC,GAAG,SAAS,cAAc,UAAU,CAAC,GAAG,SAAS,WAAW;AACzE,WAAO;AAAA,EACT;AAEA,MAAI,UAAU,CAAC,GAAG,OAAO,cAAc,UAAU,CAAC,GAAG,OAAO,WAAW;AACrE,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,WAAW,MAAM,QAAQ,KAAK,OAAO,GAAG;AAC/C,UAAM,aAAc,KAAK,QAAqC;AAAA,MAC5D,CAAC,UAAU,MAAM,SAAS;AAAA,IAC5B;AACA,QAAI,YAAY;AACd,aAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,aAAa,KAAK;AAGxB,MAAI,aAAa,CAAC,GAAG,SAAS,OAAO;AACnC,UAAM,kBAAkB,WAAW,CAAC,EAAE,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,YAAY;AACpF,QAAI,iBAAiB;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAsBO,SAAS,eACd,UACA,SAAyB,QACN;AACnB,MAAI,eAAsC;AAE1C,MAAI,WAAW,QAAQ;AACrB,mBAAe,qBAAqB,QAAQ;AAC5C,QAAI,CAAC,cAAc;AACjB,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAEA,UAAQ,cAAc;AAAA,IACpB,KAAK;AACH,aAAO,qBAAqB,QAAQ;AAAA,IACtC,KAAK;AACH,aAAO,wBAAwB,QAAQ;AAAA,IACzC,KAAK;AACH,aAAO,qBAAqB,QAAQ;AAAA,IACtC;AACE,aAAO,CAAC;AAAA,EACZ;AACF;AAWO,SAAS,aAAa,UAA4B;AACvD,QAAM,SAAS,qBAAqB,QAAQ;AAC5C,SAAO,WAAW;AACpB;;;AC5RO,SAAS,yBAAyB,MAAqE;AAC5G,SAAO;AAAA,IACL,MAAM,KAAK,SAAS;AAAA,IACpB,aAAa,KAAK,SAAS,eAAe;AAAA,IAC1C,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,YAAY,KAAK,SAAS,YAAY,cAAc,CAAC;AAAA,MACrD,UAAU,KAAK,SAAS,YAAY,YAAY,CAAC;AAAA,IACnD;AAAA,EACF;AACF;AA2BO,SAAS,sBAAsB,MAAkE;AACtG,SAAO;AAAA,IACL,MAAM,KAAK,SAAS;AAAA,IACpB,aAAa,KAAK,SAAS,eAAe;AAAA,IAC1C,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY,KAAK,SAAS,YAAY,cAAc,CAAC;AAAA,MACrD,UAAU,KAAK,SAAS,YAAY,YAAY,CAAC;AAAA,IACnD;AAAA,EACF;AACF;AAQO,SAAS,2BAA2B,MAA8C;AACvF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,MACR,MAAM,KAAK;AAAA,MACX,aAAa,KAAK,eAAe;AAAA,MACjC,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY,KAAK,aAAa;AAAA,QAC9B,UAAU,KAAK,aAAa,YAAY,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;AAQO,SAAS,wBAAwB,MAA2C;AACjF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,MACR,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY,KAAK,WAAW;AAAA,QAC5B,UAAU,KAAK,WAAW;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACF;AAmBO,SAAS,sBACd,MACA,UACG;AACH,MAAI,CAAC,QAAQ,CAAC,KAAK,aAAa;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,cAAc;AACpB,QAAM,eAAe,WAAW,OAAO,WAAW,WAAW;AAE7D,MAAI,gBAAgB,GAAG;AACrB,YAAQ,KAAK,2DAA2D,QAAQ;AAChF,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,OAAO,WAAW,KAAK,WAAW;AAEpD,MAAI,YAAY,UAAU;AAExB,QAAI,YAAY,KAAK;AACrB,WAAO,OAAO,WAAW,SAAS,IAAI,gBAAgB,UAAU,SAAS,GAAG;AAC1E,kBAAY,UAAU,MAAM,GAAG,EAAE;AAAA,IACnC;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,aAAa,YAAY;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AACT;AAcO,SAAS,cACd,MACA,QACuF;AACvF,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,yBAAyB,IAAI;AAAA,IACtC,KAAK;AACH,aAAO,sBAAsB,IAAI;AAAA,IACnC,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;AASO,SAAS,eACd,OACA,QAC8F;AAC9F,SAAO,MAAM,IAAI,CAAC,SAAS,cAAc,MAAM,MAAM,CAAC;AACxD;AAUO,IAAM,iCAAiC;AAMvC,IAAM,8BAA8B;;;ACzM3C,IAAM,oBAA4C;AAAA;AAAA,EAEhD,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,cAAc;AAAA;AAAA,EAGd,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,YAAY;AAAA;AAAA,EAGZ,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,aAAa;AAAA;AAAA,EAGb,UAAU;AAAA,EACV,cAAc;AAAA,EACd,aAAa;AAAA,EACb,OAAO;AACT;AAMO,SAAS,kBAAkB,MAAsB;AACtD,QAAM,aAAa,KAAK,YAAY,EAAE,KAAK;AAC3C,SAAO,kBAAkB,UAAU,KAAK;AAC1C;AAQO,SAAS,yBAAyB,QAAyC;AAChF,UAAQ,OAAO,UAAU;AAAA,IACvB,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,WAAW;AAAA,UACT,OAAO,OAAO,UAAU,SAAS,OAAO,UAAU,UAAU,OAAO,OAAO,OAAO,SAAS,EAAE,CAAC,KAAK;AAAA,UAClG,OAAO,OAAO,UAAU;AAAA,QAC1B;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,WAAW;AAAA,UACT,QAAQ,OAAO,UAAU,UAAU,OAAO,UAAU,eAAe,OAAO,OAAO,OAAO,SAAS,EAAE,CAAC,KAAK;AAAA,QAC3G;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,WAAW;AAAA,UACT,OAAO,OAAO,UAAU,SAAS,OAAO,UAAU,UAAU,OAAO,OAAO,OAAO,SAAS,EAAE,CAAC,KAAK;AAAA,QACpG;AAAA,MACF;AAAA,IAEF;AAEE,aAAO;AAAA,QACL,MAAM,OAAO;AAAA,QACb,WAAW,OAAO;AAAA,MACpB;AAAA,EACJ;AACF;AASO,SAAS,yBAAyB,UAAoC;AAC3E,QAAM,UAA4B,CAAC;AAEnC,QAAM,uBAAuB;AAE7B,MAAI;AACJ,UAAQ,eAAe,qBAAqB,KAAK,QAAQ,OAAO,MAAM;AACpE,UAAM,iBAAiB,aAAa,CAAC;AACrC,UAAM,oBAAoB,aAAa;AACvC,UAAM,gBAAgB,oBAAoB,mBAAmB;AAE7D,UAAM,gBAAgB;AAEtB,QAAI;AACJ,YAAQ,cAAc,cAAc,KAAK,cAAc,OAAO,MAAM;AAClE,YAAM,WAAW,YAAY,CAAC;AAC9B,YAAM,eAAe,YAAY,CAAC;AAClC,YAAM,mBAAmB,gBAAgB,YAAY;AACrD,YAAM,iBAAiB,mBAAmB,YAAY,CAAC,EAAE;AAEzD,YAAM,OAAgC,CAAC;AACvC,UAAI,SAAgC;AAGpC,YAAM,uBAAuB;AAC7B,UAAI;AACJ,cAAQ,aAAa,qBAAqB,KAAK,YAAY,OAAO,MAAM;AACtE,cAAM,YAAY,WAAW,CAAC;AAC9B,cAAM,aAAa,WAAW,CAAC;AAC/B,cAAM,QAAQ,WAAW,CAAC,EAAE,KAAK;AAEjC,YAAI,eAAe,SAAS;AAC1B,gBAAM,SAAS,OAAO,KAAK;AAC3B,cAAI,CAAC,MAAM,MAAM,GAAG;AAClB,iBAAK,SAAS,IAAI;AAAA,UACpB,WAAW,UAAU,QAAQ;AAC3B,iBAAK,SAAS,IAAI;AAAA,UACpB,WAAW,UAAU,SAAS;AAC5B,iBAAK,SAAS,IAAI;AAAA,UACpB,OAAO;AACL,iBAAK,SAAS,IAAI;AAAA,UACpB;AAAA,QACF,OAAO;AACL,eAAK,SAAS,IAAI;AAAA,QACpB;AACA,iBAAS;AAAA,MACX;AAGA,UAAI,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG;AAClC,cAAM,qBAAqB;AAC3B,gBAAQ,aAAa,mBAAmB,KAAK,YAAY,OAAO,MAAM;AACpE,eAAK,WAAW,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,KAAK;AAAA,QAC3C;AAAA,MACF;AAGA,YAAM,oBAAoB;AAC1B,cAAQ,aAAa,kBAAkB,KAAK,YAAY,OAAO,MAAM;AACnE,aAAK,WAAW,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,KAAK;AAAA,MAC3C;AAEA,cAAQ,KAAK;AAAA,QACX,UAAU,kBAAkB,QAAQ;AAAA,QACpC,WAAW;AAAA,QACX,WAAW,YAAY,CAAC;AAAA,QACxB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,oBAAoB,UAAoC;AACtE,QAAM,UAA4B,CAAC;AAEnC,QAAM,kBAAkB;AAExB,MAAI;AACJ,UAAQ,QAAQ,gBAAgB,KAAK,QAAQ,OAAO,MAAM;AACxD,UAAM,UAAU,MAAM,CAAC;AACvB,UAAM,aAAa,MAAM;AAEzB,UAAM,YAAY,yBAAyB,KAAK,OAAO;AACvD,QAAI,CAAC,UAAW;AAEhB,UAAM,WAAW,UAAU,CAAC,EAAE,KAAK;AACnC,UAAM,OAAgC,CAAC;AAEvC,UAAM,YAAY,sCAAsC,KAAK,OAAO;AACpE,QAAI,WAAW;AACb,YAAM,cAAc,UAAU,CAAC;AAC/B,YAAM,aAAa;AACnB,UAAI;AACJ,cAAQ,WAAW,WAAW,KAAK,WAAW,OAAO,MAAM;AACzD,aAAK,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,EAAE,KAAK;AAAA,MACvC;AAAA,IACF;AAEA,YAAQ,KAAK;AAAA,MACX,UAAU,kBAAkB,QAAQ;AAAA,MACpC,WAAW;AAAA,MACX,WAAW,MAAM,CAAC;AAAA,MAClB;AAAA,MACA,UAAU,aAAa,MAAM,CAAC,EAAE;AAAA,MAChC,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAKO,SAAS,wBAAwB,UAAoC;AAC1E,QAAM,UAA4B,CAAC;AAEnC,QAAM,sBAAsB;AAE5B,MAAI;AACJ,UAAQ,QAAQ,oBAAoB,KAAK,QAAQ,OAAO,MAAM;AAC5D,UAAM,WAAW,MAAM,CAAC;AACxB,UAAM,UAAU,MAAM,CAAC;AACvB,UAAM,aAAa,MAAM;AAEzB,UAAM,OAAgC,CAAC;AAEvC,UAAM,eAAe;AACrB,QAAI;AACJ,YAAQ,aAAa,aAAa,KAAK,OAAO,OAAO,MAAM;AACzD,WAAK,WAAW,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,KAAK;AAAA,IAC3C;AAEA,UAAM,mBAAmB;AACzB,YAAQ,aAAa,iBAAiB,KAAK,OAAO,OAAO,MAAM;AAC7D,WAAK,WAAW,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,KAAK;AAAA,IAC3C;AAEA,YAAQ,KAAK;AAAA,MACX,UAAU,kBAAkB,QAAQ;AAAA,MACpC,WAAW;AAAA,MACX,WAAW,MAAM,CAAC;AAAA,MAClB;AAAA,MACA,UAAU,aAAa,MAAM,CAAC,EAAE;AAAA,MAChC,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAWO,SAAS,mBAAmB,UAAoC;AACrE,QAAM,UAA4B,CAAC;AAEnC,QAAM,iBAAiB;AAEvB,MAAI;AACJ,UAAQ,QAAQ,eAAe,KAAK,QAAQ,OAAO,MAAM;AACvD,UAAM,WAAW,MAAM,CAAC;AACxB,UAAM,UAAU,MAAM,CAAC;AACvB,UAAM,aAAa,MAAM;AAGzB,UAAM,iBAAiB,QAAQ,KAAK;AACpC,QAAI,eAAe,WAAW,GAAG,GAAG;AAClC,UAAI;AACF,cAAM,WAAW,KAAK,MAAM,cAAc;AAC1C,YAAI,OAAO,aAAa,YAAY,aAAa,QAAQ,SAAS,MAAM;AACtE,gBAAMA,QAAO,SAAS,SAAS,SAAS,aAAa,SAAS,cAAc,CAAC;AAC7E,kBAAQ,KAAK;AAAA,YACX,UAAU,kBAAkB,SAAS,IAAI;AAAA,YACzC,WAAW,OAAOA,UAAS,YAAYA,UAAS,OAAOA,QAAO,CAAC;AAAA,YAC/D,WAAW,MAAM,CAAC;AAAA,YAClB;AAAA,YACA,UAAU,aAAa,MAAM,CAAC,EAAE;AAAA,YAChC,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,QAAI,WAAW;AACf,QAAI,CAAC,UAAU;AACb,YAAM,YAAY,yBAAyB,KAAK,OAAO;AACvD,UAAI,CAAC,UAAW;AAChB,iBAAW,UAAU,CAAC,EAAE,KAAK;AAAA,IAC/B;AAEA,UAAM,OAAgC,CAAC;AAGvC,UAAM,YAAY,gFAAgF,KAAK,OAAO;AAC9G,QAAI,WAAW;AACb,YAAM,cAAc,UAAU,CAAC,EAAE,KAAK;AAEtC,UAAI,YAAY,WAAW,GAAG,GAAG;AAC/B,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,WAAW;AACrC,cAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,mBAAO,OAAO,MAAM,MAAM;AAAA,UAC5B;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,UAAI,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG;AAClC,cAAM,aAAa;AACnB,YAAI;AACJ,gBAAQ,WAAW,WAAW,KAAK,WAAW,OAAO,MAAM;AACzD,eAAK,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,EAAE,KAAK;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,KAAK;AAAA,MACX,UAAU,kBAAkB,QAAQ;AAAA,MACpC,WAAW;AAAA,MACX,WAAW,MAAM,CAAC;AAAA,MAClB;AAAA,MACA,UAAU,aAAa,MAAM,CAAC,EAAE;AAAA,MAChC,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAaO,SAAS,mBAAmB,UAAoC;AACrE,QAAM,aAA+B,CAAC;AAEtC,aAAW,KAAK,GAAG,yBAAyB,QAAQ,CAAC;AACrD,aAAW,KAAK,GAAG,oBAAoB,QAAQ,CAAC;AAChD,aAAW,KAAK,GAAG,wBAAwB,QAAQ,CAAC;AACpD,aAAW,KAAK,GAAG,mBAAmB,QAAQ,CAAC;AAG/C,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,UAAU,WAAW,OAAO,YAAU;AAC1C,QAAI,KAAK,IAAI,OAAO,UAAU,GAAG;AAC/B,aAAO;AAAA,IACT;AACA,SAAK,IAAI,OAAO,UAAU;AAC1B,WAAO;AAAA,EACT,CAAC;AAED,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAClD,SAAO;AACT;AAMO,SAAS,uBAAuB,UAAqC;AAC1E,SAAO,mBAAmB,QAAQ,EAAE,IAAI,wBAAwB;AAClE;AAMO,SAAS,qBAAqB,UAA2B;AAC9D,SACE,oBAAoB,KAAK,QAAQ,KACjC,eAAe,KAAK,QAAQ,KAC5B,qBAAqB,KAAK,QAAQ,KAClC,kBAAkB,KAAK,QAAQ;AAEnC;AAKO,SAAS,wBAAwB,UAA2B;AACjE,SAAO,oBAAoB,KAAK,QAAQ;AAC1C;AAGO,SAAS,mBAAmB,UAA2B;AAC5D,SAAO,eAAe,KAAK,QAAQ;AACrC;AAGO,SAAS,uBAAuB,UAA2B;AAChE,SAAO,qBAAqB,KAAK,QAAQ;AAC3C;AAGO,SAAS,kBAAkB,UAA2B;AAC3D,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAMO,SAAS,uBAAuB,UAA0B;AAC/D,MAAI,WAAW;AAEf,aAAW,SAAS,QAAQ,gDAAgD,EAAE;AAC9E,aAAW,SAAS,QAAQ,sCAAsC,EAAE;AACpE,aAAW,SAAS,QAAQ,sDAAsD,EAAE;AACpF,aAAW,SAAS,QAAQ,wCAAwC,EAAE;AAEtE,aAAW,SACR,QAAQ,WAAW,MAAM,EACzB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AAER,SAAO;AACT;AAKO,SAAS,0BAA0B,UAA0B;AAClE,SAAO,SAAS,QAAQ,gDAAgD,EAAE;AAC5E;AAGO,SAAS,qBAAqB,UAA0B;AAC7D,SAAO,SAAS,QAAQ,sCAAsC,EAAE;AAClE;AAGO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,SAAS,QAAQ,sDAAsD,EAAE;AAClF;AAGO,SAAS,oBAAoB,UAA0B;AAC5D,SAAO,SAAS,QAAQ,wCAAwC,EAAE;AACpE;","names":["args"]}
1
+ {"version":3,"sources":["../../src/tools/index.ts","../../src/tools/parsers.ts","../../src/tools/converters.ts","../../src/tools/text-parsers.ts"],"sourcesContent":["/**\n * Tool Utilities\n *\n * Exports all tool-related utilities for parsing and converting\n * tool calls between different LLM provider formats.\n *\n * @module @quilltap/plugin-utils/tools\n */\n\n// Re-export types\nexport type {\n OpenAIToolDefinition,\n UniversalTool,\n AnthropicToolDefinition,\n GoogleToolDefinition,\n ToolCall,\n ToolCallRequest,\n ToolResult,\n ToolFormatOptions,\n} from './types';\n\n// Export parsers\nexport {\n parseToolCalls,\n parseOpenAIToolCalls,\n parseAnthropicToolCalls,\n parseGoogleToolCalls,\n detectToolCallFormat,\n hasToolCalls,\n} from './parsers';\n\nexport type { ToolCallFormat } from './parsers';\n\n// Export converters\nexport {\n convertToAnthropicFormat,\n convertToGoogleFormat,\n convertFromAnthropicFormat,\n convertFromGoogleFormat,\n convertToolTo,\n convertToolsTo,\n applyDescriptionLimit,\n // Backward-compatible aliases\n convertOpenAIToAnthropicFormat,\n convertOpenAIToGoogleFormat,\n} from './converters';\n\nexport type { ToolConvertTarget } from './converters';\n\n// Export text-based tool call parsers (for spontaneous XML emissions)\nexport {\n // Composite utilities\n parseAllXMLFormats,\n parseAllXMLAsToolCalls,\n hasAnyXMLToolMarkers,\n stripAllXMLToolMarkers,\n // Individual format parsers\n parseFunctionCallsFormat,\n parseToolCallFormat,\n parseFunctionCallFormat,\n parseToolUseFormat,\n parseInvokeFormat,\n // Individual marker checks\n hasFunctionCallsMarkers,\n hasToolCallMarkers,\n hasFunctionCallMarkers,\n hasToolUseMarkers,\n hasInvokeMarkers,\n // Individual strippers\n stripFunctionCallsMarkers,\n stripToolCallMarkers,\n stripFunctionCallMarkers,\n stripToolUseMarkers,\n stripInvokeMarkers,\n // Utilities\n normalizeToolName,\n convertToToolCallRequest as convertTextToolToRequest,\n} from './text-parsers';\n\nexport type { ParsedTextTool } from './text-parsers';\n","/**\n * Tool Call Parsers\n *\n * Provider-specific parsers for extracting tool calls from LLM responses.\n * Each parser converts from a provider's native format to the standardized\n * ToolCallRequest format.\n *\n * @module @quilltap/plugin-utils/tools/parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Supported tool call response formats\n */\nexport type ToolCallFormat = 'openai' | 'anthropic' | 'google' | 'auto';\n\n/**\n * Parse OpenAI format tool calls from LLM response\n *\n * Extracts tool calls from OpenAI/Grok API responses which return\n * tool_calls in the message object.\n *\n * Expected response structures:\n * - `response.tool_calls` (direct)\n * - `response.choices[0].message.tool_calls` (nested)\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await openai.chat.completions.create({...});\n * const toolCalls = parseOpenAIToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseOpenAIToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n // Handle direct tool_calls array (snake_case)\n let toolCallsArray = resp?.tool_calls as unknown[] | undefined;\n\n // Handle direct toolCalls array (camelCase - some SDKs use this)\n if (!toolCallsArray) {\n toolCallsArray = (resp as Record<string, unknown>)?.toolCalls as unknown[] | undefined;\n }\n\n // Check nested structure from non-streaming responses: choices[0].message.tool_calls\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ message?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls;\n }\n\n // Check nested structure from streaming responses: choices[0].delta.toolCalls\n // OpenRouter SDK uses camelCase and puts tool calls in delta for streaming\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls;\n }\n\n if (toolCallsArray && Array.isArray(toolCallsArray) && toolCallsArray.length > 0) {\n for (const toolCall of toolCallsArray) {\n const tc = toolCall as {\n id?: string;\n type?: string;\n function?: { name: string; arguments: string };\n };\n\n if (tc.type === 'function' && tc.function) {\n const argsStr = tc.function.arguments || '{}';\n\n // During streaming, arguments may be incomplete JSON.\n // Check if the string looks like complete JSON before parsing.\n // Skip incomplete tool calls - they'll be complete in the final response.\n const trimmed = argsStr.trim();\n if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {\n // Incomplete JSON - skip this tool call for now\n continue;\n }\n\n try {\n toolCalls.push({\n name: tc.function.name,\n arguments: JSON.parse(argsStr),\n callId: tc.id || undefined,\n });\n } catch {\n // JSON parse failed (e.g., incomplete JSON during streaming)\n // This is expected during streaming - skip silently\n continue;\n }\n }\n }\n }\n } catch (error) {\n // Log error for unexpected parsing failures (not JSON parse errors)\n console.error('[plugin-utils] Error parsing OpenAI tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Anthropic format tool calls from LLM response\n *\n * Extracts tool calls from Anthropic API responses which return\n * tool_use blocks in the content array.\n *\n * Expected response structure:\n * - `response.content` array with `{ type: 'tool_use', name, input }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await anthropic.messages.create({...});\n * const toolCalls = parseAnthropicToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseAnthropicToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n if (!resp?.content || !Array.isArray(resp.content)) {\n return toolCalls;\n }\n\n for (const block of resp.content) {\n const b = block as { type?: string; id?: string; name?: string; input?: Record<string, unknown> };\n\n if (b.type === 'tool_use' && b.name) {\n toolCalls.push({\n name: b.name,\n arguments: b.input || {},\n callId: b.id || undefined,\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Anthropic tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Google Gemini format tool calls from LLM response\n *\n * Extracts tool calls from Google Gemini API responses which return\n * functionCall objects in the parts array.\n *\n * Expected response structure:\n * - `response.candidates[0].content.parts` array with `{ functionCall: { name, args } }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await gemini.generateContent({...});\n * const toolCalls = parseGoogleToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseGoogleToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n const candidates = resp?.candidates as\n | Array<{ content?: { parts?: unknown[] } }>\n | undefined;\n const parts = candidates?.[0]?.content?.parts;\n\n if (!parts || !Array.isArray(parts)) {\n return toolCalls;\n }\n\n for (const part of parts) {\n const p = part as {\n functionCall?: { name: string; args?: Record<string, unknown> };\n };\n\n if (p.functionCall) {\n toolCalls.push({\n name: p.functionCall.name,\n arguments: p.functionCall.args || {},\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Google tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Detect the format of a tool call response\n *\n * Analyzes the response structure to determine which provider format it uses.\n *\n * @param response - The raw response from a provider API\n * @returns The detected format, or null if unrecognized\n */\nexport function detectToolCallFormat(response: unknown): ToolCallFormat | null {\n if (!response || typeof response !== 'object') {\n return null;\n }\n\n const resp = response as Record<string, unknown>;\n\n // OpenAI format: has tool_calls/toolCalls directly or in choices[0].message or choices[0].delta\n if (resp.tool_calls && Array.isArray(resp.tool_calls)) {\n return 'openai';\n }\n if (resp.toolCalls && Array.isArray(resp.toolCalls)) {\n return 'openai';\n }\n\n const choices = resp.choices as Array<{\n message?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n }> | undefined;\n if (choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls) {\n return 'openai';\n }\n // Check delta for streaming responses (OpenRouter SDK uses this)\n if (choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls) {\n return 'openai';\n }\n\n // Anthropic format: has content array with tool_use type\n if (resp.content && Array.isArray(resp.content)) {\n const hasToolUse = (resp.content as Array<{ type?: string }>).some(\n (block) => block.type === 'tool_use'\n );\n if (hasToolUse) {\n return 'anthropic';\n }\n }\n\n // Google format: has candidates[0].content.parts with functionCall\n const candidates = resp.candidates as\n | Array<{ content?: { parts?: Array<{ functionCall?: unknown }> } }>\n | undefined;\n if (candidates?.[0]?.content?.parts) {\n const hasFunctionCall = candidates[0].content.parts.some((part) => part.functionCall);\n if (hasFunctionCall) {\n return 'google';\n }\n }\n\n return null;\n}\n\n/**\n * Parse tool calls with auto-detection or explicit format\n *\n * A unified parser that can either auto-detect the response format\n * or use a specified format. This is useful when you're not sure\n * which provider's response you're handling.\n *\n * @param response - The raw response from a provider API\n * @param format - The format to use: 'openai', 'anthropic', 'google', or 'auto'\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * // Auto-detect format\n * const toolCalls = parseToolCalls(response, 'auto');\n *\n * // Or specify format explicitly\n * const toolCalls = parseToolCalls(response, 'openai');\n * ```\n */\nexport function parseToolCalls(\n response: unknown,\n format: ToolCallFormat = 'auto'\n): ToolCallRequest[] {\n let actualFormat: ToolCallFormat | null = format;\n\n if (format === 'auto') {\n actualFormat = detectToolCallFormat(response);\n if (!actualFormat) {\n return [];\n }\n }\n\n switch (actualFormat) {\n case 'openai':\n return parseOpenAIToolCalls(response);\n case 'anthropic':\n return parseAnthropicToolCalls(response);\n case 'google':\n return parseGoogleToolCalls(response);\n default:\n return [];\n }\n}\n\n/**\n * Check if a response contains tool calls\n *\n * Quick check to determine if a response has any tool calls\n * without fully parsing them.\n *\n * @param response - The raw response from a provider API\n * @returns True if the response contains tool calls\n */\nexport function hasToolCalls(response: unknown): boolean {\n const format = detectToolCallFormat(response);\n return format !== null;\n}\n","/**\n * Tool Format Converters\n *\n * Utilities for converting between different provider tool formats.\n * The universal format (OpenAI-style) serves as the baseline for all conversions.\n *\n * @module @quilltap/plugin-utils/tools/converters\n */\n\nimport type {\n UniversalTool,\n AnthropicToolDefinition,\n GoogleToolDefinition,\n OpenAIToolDefinition,\n} from '@quilltap/plugin-types';\n\n/**\n * Convert OpenAI/Universal format tool to Anthropic format\n *\n * Anthropic uses a tool_use format with:\n * - name: string\n * - description: string\n * - input_schema: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Anthropic's tool_use\n *\n * @example\n * ```typescript\n * const anthropicTool = convertToAnthropicFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // input_schema: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToAnthropicFormat(tool: UniversalTool | OpenAIToolDefinition): AnthropicToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n input_schema: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert OpenAI/Universal format tool to Google Gemini format\n *\n * Google uses a function calling format with:\n * - name: string\n * - description: string\n * - parameters: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Google's functionCall\n *\n * @example\n * ```typescript\n * const googleTool = convertToGoogleFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // parameters: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToGoogleFormat(tool: UniversalTool | OpenAIToolDefinition): GoogleToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert Anthropic format tool to Universal/OpenAI format\n *\n * @param tool - Anthropic format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromAnthropicFormat(tool: AnthropicToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.input_schema.properties,\n required: tool.input_schema.required ?? [],\n },\n },\n };\n}\n\n/**\n * Convert Google format tool to Universal/OpenAI format\n *\n * @param tool - Google format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromGoogleFormat(tool: GoogleToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n },\n };\n}\n\n/**\n * Apply prompt/description length limit to a tool\n *\n * Modifies a tool's description if it exceeds maxBytes, appending a warning\n * that the description was truncated. This is useful for providers with\n * strict token limits.\n *\n * @param tool - Tool object (any format) with a description property\n * @param maxBytes - Maximum bytes allowed for description (including warning)\n * @returns Modified tool with truncated description if needed\n *\n * @example\n * ```typescript\n * const limitedTool = applyDescriptionLimit(tool, 500);\n * // If description > 500 bytes, truncates and adds warning\n * ```\n */\nexport function applyDescriptionLimit<T extends { description: string }>(\n tool: T,\n maxBytes: number\n): T {\n if (!tool || !tool.description) {\n return tool;\n }\n\n const warningText = ' [Note: description truncated due to length limit]';\n const maxDescBytes = maxBytes - Buffer.byteLength(warningText);\n\n if (maxDescBytes <= 0) {\n console.warn('[plugin-utils] Length limit too small for warning text:', maxBytes);\n return tool;\n }\n\n const descBytes = Buffer.byteLength(tool.description);\n\n if (descBytes > maxBytes) {\n // Truncate description to fit within the byte limit\n let truncated = tool.description;\n while (Buffer.byteLength(truncated) > maxDescBytes && truncated.length > 0) {\n truncated = truncated.slice(0, -1);\n }\n\n return {\n ...tool,\n description: truncated + warningText,\n };\n }\n\n return tool;\n}\n\n/**\n * Target format for tool conversion\n */\nexport type ToolConvertTarget = 'openai' | 'anthropic' | 'google';\n\n/**\n * Convert a universal tool to a specific provider format\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @param target - Target provider format\n * @returns Tool in the target format\n */\nexport function convertToolTo(\n tool: UniversalTool | OpenAIToolDefinition,\n target: ToolConvertTarget\n): UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition {\n switch (target) {\n case 'anthropic':\n return convertToAnthropicFormat(tool);\n case 'google':\n return convertToGoogleFormat(tool);\n case 'openai':\n default:\n return tool;\n }\n}\n\n/**\n * Convert multiple tools to a specific provider format\n *\n * @param tools - Array of universal tools or OpenAI tool definitions\n * @param target - Target provider format\n * @returns Array of tools in the target format\n */\nexport function convertToolsTo(\n tools: Array<UniversalTool | OpenAIToolDefinition>,\n target: ToolConvertTarget\n): Array<UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition> {\n return tools.map((tool) => convertToolTo(tool, target));\n}\n\n// ============================================================================\n// Backward-compatible aliases\n// ============================================================================\n\n/**\n * Alias for convertToAnthropicFormat\n * @deprecated Use convertToAnthropicFormat instead\n */\nexport const convertOpenAIToAnthropicFormat = convertToAnthropicFormat;\n\n/**\n * Alias for convertToGoogleFormat\n * @deprecated Use convertToGoogleFormat instead\n */\nexport const convertOpenAIToGoogleFormat = convertToGoogleFormat;\n","/**\n * Text-Based Tool Call Parsers\n *\n * Utility functions for parsing spontaneous XML-style tool calls from LLM\n * text responses. These are for models that emit tool-call-like markup in\n * their output instead of using native function calling APIs.\n *\n * Provider plugins import and compose these utilities to implement their\n * `hasTextToolMarkers`, `parseTextToolCalls`, and `stripTextToolMarkers` methods.\n *\n * @module @quilltap/plugin-utils/tools/text-parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Parsed text-based tool call from LLM output\n */\nexport interface ParsedTextTool {\n /** The tool name */\n toolName: string;\n /** Arguments extracted from the markup */\n arguments: Record<string, unknown>;\n /** The full matched markup text (for stripping) */\n fullMatch: string;\n /** Start index in the original text */\n startIndex: number;\n /** End index in the original text */\n endIndex: number;\n /** Which format was detected */\n format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use' | 'invoke';\n}\n\n/**\n * Common tool name aliases that models use when hallucinating tool calls.\n * Maps common variations to canonical Quilltap tool names.\n */\nconst TOOL_NAME_ALIASES: Record<string, string> = {\n // Direct mappings\n 'search_memories': 'search_memories',\n 'generate_image': 'generate_image',\n 'search_web': 'search_web',\n\n // Memory tool aliases\n 'memory': 'search_memories',\n 'memory_search': 'search_memories',\n 'search_memory': 'search_memories',\n 'memories': 'search_memories',\n\n // Image tool aliases\n 'image': 'generate_image',\n 'create_image': 'generate_image',\n 'image_generation': 'generate_image',\n 'gen_image': 'generate_image',\n\n // Web search aliases\n 'search': 'search_web',\n 'web_search': 'search_web',\n 'websearch': 'search_web',\n 'web': 'search_web',\n\n // Help tool aliases\n 'help_search': 'help_search',\n 'helpsearch': 'help_search',\n 'search_help': 'help_search',\n 'help_navigate': 'help_navigate',\n 'helpnavigate': 'help_navigate',\n};\n\n/**\n * Normalize a tool name from hallucinated markup to the canonical name.\n * Returns the original name if no alias is found (passes through unknown tools).\n */\nexport function normalizeToolName(name: string): string {\n const normalized = name.toLowerCase().trim();\n return TOOL_NAME_ALIASES[normalized] || name;\n}\n\n/**\n * Convert a ParsedTextTool to the standard ToolCallRequest format.\n *\n * For well-known tools, normalizes argument names (e.g., \"search\" → \"query\").\n * For unknown tools, passes arguments through as-is.\n */\nexport function convertToToolCallRequest(parsed: ParsedTextTool): ToolCallRequest {\n switch (parsed.toolName) {\n case 'search_memories':\n return {\n name: 'search_memories',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n limit: parsed.arguments.limit,\n },\n };\n\n case 'generate_image':\n return {\n name: 'generate_image',\n arguments: {\n prompt: parsed.arguments.prompt || parsed.arguments.description || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n case 'search_web':\n return {\n name: 'search_web',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n case 'help_search':\n return {\n name: 'help_search',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n limit: parsed.arguments.limit,\n },\n };\n\n case 'help_navigate':\n return {\n name: 'help_navigate',\n arguments: {\n url: parsed.arguments.url || parsed.arguments.path || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n default:\n // Pass through unknown tools with their original arguments\n return {\n name: parsed.toolName,\n arguments: parsed.arguments,\n };\n }\n}\n\n// ============================================================================\n// Individual format parsers\n// ============================================================================\n\n/**\n * Parse `<function_calls><invoke name=\"...\">` format (DeepSeek and Claude-style)\n */\nexport function parseFunctionCallsFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallsPattern = /<function_calls>([\\s\\S]*?)<\\/function_calls>/gi;\n\n let wrapperMatch;\n while ((wrapperMatch = functionCallsPattern.exec(response)) !== null) {\n const wrapperContent = wrapperMatch[1];\n const wrapperStartIndex = wrapperMatch.index;\n const contentOffset = wrapperStartIndex + '<function_calls>'.length;\n\n const invokePattern = /<invoke\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/invoke>/gi;\n\n let invokeMatch;\n while ((invokeMatch = invokePattern.exec(wrapperContent)) !== null) {\n const toolName = invokeMatch[1];\n const paramContent = invokeMatch[2];\n const invokeStartIndex = contentOffset + invokeMatch.index;\n const invokeEndIndex = invokeStartIndex + invokeMatch[0].length;\n\n const args: Record<string, unknown> = {};\n let format: 'deepseek' | 'claude' = 'claude';\n\n // DeepSeek format: <parameter name=\"...\" string=\"...\">value</parameter>\n const deepseekParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']\\s+string=[\"']([^\"']*)[\"'][^>]*>([^<]*)<\\/parameter>/gi;\n let paramMatch;\n while ((paramMatch = deepseekParamPattern.exec(paramContent)) !== null) {\n const paramName = paramMatch[1];\n const stringAttr = paramMatch[2];\n const value = paramMatch[3].trim();\n\n if (stringAttr === 'false') {\n const numVal = Number(value);\n if (!isNaN(numVal)) {\n args[paramName] = numVal;\n } else if (value === 'true') {\n args[paramName] = true;\n } else if (value === 'false') {\n args[paramName] = false;\n } else {\n args[paramName] = value;\n }\n } else {\n args[paramName] = value;\n }\n format = 'deepseek';\n }\n\n // Claude format: <parameter name=\"...\">value</parameter>\n if (Object.keys(args).length === 0) {\n const claudeParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = claudeParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n }\n\n // antml:parameter format (Claude Code style)\n const antmlParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/antml:parameter>/gi;\n while ((paramMatch = antmlParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: invokeMatch[0],\n startIndex: invokeStartIndex,\n endIndex: invokeEndIndex,\n format,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_call>` format (generic XML)\n */\nexport function parseToolCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolCallPattern = /<tool_call>([\\s\\S]*?)<\\/tool_call>/gi;\n\n let match;\n while ((match = toolCallPattern.exec(response)) !== null) {\n const content = match[1];\n const startIndex = match.index;\n\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n\n const toolName = nameMatch[1].trim();\n const args: Record<string, unknown> = {};\n\n const argsMatch = /<arguments>([\\s\\S]*?)<\\/arguments>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1];\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'generic',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<function_call name=\"...\">` format\n */\nexport function parseFunctionCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallPattern = /<function_call\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/function_call>/gi;\n\n let match;\n while ((match = functionCallPattern.exec(response)) !== null) {\n const toolName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n const args: Record<string, unknown> = {};\n\n const paramPattern = /<param\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/param>/gi;\n let paramMatch;\n while ((paramMatch = paramPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n const parameterPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = parameterPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'function_call',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_use>` format (Gemini and others)\n *\n * Handles multiple sub-formats:\n * - Bare JSON: `<tool_use>{\"name\":\"fn\",\"input\":{...}}</tool_use>`\n * - XML children: `<tool_use><name>fn</name><arguments>...</arguments></tool_use>`\n * - JSON in arguments: `<tool_use><name>fn</name><arguments>{\"q\":\"v\"}</arguments></tool_use>`\n * - Attributed: `<tool_use name=\"fn\"><arguments>...</arguments></tool_use>`\n */\nexport function parseToolUseFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolUsePattern = /<tool_use(?:\\s+name=[\"']([^\"']+)[\"'])?\\s*>([\\s\\S]*?)<\\/tool_use>/gi;\n\n let match;\n while ((match = toolUsePattern.exec(response)) !== null) {\n const attrName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n // Try bare JSON first (Gemini's primary format)\n const trimmedContent = content.trim();\n if (trimmedContent.startsWith('{')) {\n try {\n const jsonBlob = JSON.parse(trimmedContent);\n if (typeof jsonBlob === 'object' && jsonBlob !== null && jsonBlob.name) {\n const args = jsonBlob.input || jsonBlob.arguments || jsonBlob.parameters || {};\n results.push({\n toolName: normalizeToolName(jsonBlob.name),\n arguments: typeof args === 'object' && args !== null ? args : {},\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n continue;\n }\n } catch {\n // Not valid JSON, fall through\n }\n }\n\n // Extract name from attribute or child element\n let toolName = attrName;\n if (!toolName) {\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n toolName = nameMatch[1].trim();\n }\n\n const args: Record<string, unknown> = {};\n\n // Try <arguments>, <input>, or <parameters>\n const argsMatch = /<(?:arguments|input|parameters)>([\\s\\S]*?)<\\/(?:arguments|input|parameters)>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1].trim();\n\n if (argsContent.startsWith('{')) {\n try {\n const parsed = JSON.parse(argsContent);\n if (typeof parsed === 'object' && parsed !== null) {\n Object.assign(args, parsed);\n }\n } catch {\n // Not valid JSON\n }\n }\n\n if (Object.keys(args).length === 0) {\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n }\n\n return results;\n}\n\n/**\n * Parse bare `<invoke name=\"...\">` format (Kimi K2 and similar models)\n *\n * Matches `<invoke>` tags that appear WITHOUT a `<function_calls>` wrapper.\n * IMPORTANT: In composite parsing, this must run AFTER parseFunctionCallsFormat\n * so that wrapped invokes are claimed first and deduplicated by startIndex.\n */\nexport function parseInvokeFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const invokePattern = /<invoke\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/invoke>/gi;\n\n let match;\n while ((match = invokePattern.exec(response)) !== null) {\n const toolName = match[1];\n const paramContent = match[2];\n const startIndex = match.index;\n\n const args: Record<string, unknown> = {};\n\n // Parse <parameter name=\"...\">value</parameter> children\n const paramPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n let paramMatch;\n while ((paramMatch = paramPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'invoke',\n });\n }\n\n return results;\n}\n\n// ============================================================================\n// Composite utilities for plugins\n// ============================================================================\n\n/**\n * Parse all known XML tool call formats from response text.\n * Deduplicates by position and sorts by start index.\n *\n * Plugins can call this directly or compose individual format parsers\n * for provider-specific behavior.\n */\nexport function parseAllXMLFormats(response: string): ParsedTextTool[] {\n const allResults: ParsedTextTool[] = [];\n\n allResults.push(...parseFunctionCallsFormat(response));\n allResults.push(...parseToolCallFormat(response));\n allResults.push(...parseFunctionCallFormat(response));\n allResults.push(...parseToolUseFormat(response));\n // Bare <invoke> MUST be last — wrapped invokes inside <function_calls> are\n // already claimed above and will be deduplicated by startIndex.\n allResults.push(...parseInvokeFormat(response));\n\n // Deduplicate by startIndex\n const seen = new Set<number>();\n const deduped = allResults.filter(result => {\n if (seen.has(result.startIndex)) {\n return false;\n }\n seen.add(result.startIndex);\n return true;\n });\n\n deduped.sort((a, b) => a.startIndex - b.startIndex);\n return deduped;\n}\n\n/**\n * Convert parsed text tools to standard ToolCallRequest array.\n * Convenience wrapper for plugins implementing parseTextToolCalls.\n */\nexport function parseAllXMLAsToolCalls(response: string): ToolCallRequest[] {\n return parseAllXMLFormats(response).map(convertToToolCallRequest);\n}\n\n/**\n * Check if text contains any of the known XML tool call patterns.\n * Quick regex check before full parsing.\n */\nexport function hasAnyXMLToolMarkers(response: string): boolean {\n return (\n /<function_calls>/i.test(response) ||\n /<tool_call>/i.test(response) ||\n /<function_call\\s+/i.test(response) ||\n /<tool_use[\\s>]/i.test(response) ||\n /<invoke\\s+name=/i.test(response)\n );\n}\n\n// Individual marker checks for plugins that only care about specific formats\n\n/** Check for `<function_calls>` markers (DeepSeek/Claude-style) */\nexport function hasFunctionCallsMarkers(response: string): boolean {\n return /<function_calls>/i.test(response);\n}\n\n/** Check for `<tool_call>` markers (generic) */\nexport function hasToolCallMarkers(response: string): boolean {\n return /<tool_call>/i.test(response);\n}\n\n/** Check for `<function_call>` markers */\nexport function hasFunctionCallMarkers(response: string): boolean {\n return /<function_call\\s+/i.test(response);\n}\n\n/** Check for `<tool_use>` markers (Gemini-style) */\nexport function hasToolUseMarkers(response: string): boolean {\n return /<tool_use[\\s>]/i.test(response);\n}\n\n/** Check for bare `<invoke name=\"...\">` markers (Kimi K2-style) */\nexport function hasInvokeMarkers(response: string): boolean {\n return /<invoke\\s+name=/i.test(response);\n}\n\n/**\n * Strip all known XML tool call markers from text.\n * Cleans up whitespace left behind.\n */\nexport function stripAllXMLToolMarkers(response: string): string {\n let stripped = response;\n\n // <function_calls> MUST be stripped first — it contains <invoke> tags that\n // would otherwise be matched by the bare <invoke> stripper below, leaving\n // empty <function_calls></function_calls> wrappers behind.\n stripped = stripped.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n stripped = stripped.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n stripped = stripped.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n stripped = stripped.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n // Bare <invoke> last — only catches unwrapped invoke tags (Kimi K2-style)\n stripped = stripped.replace(/<invoke\\s+name=[\"'][^\"']*[\"']>[\\s\\S]*?<\\/invoke>/gi, '');\n\n stripped = stripped\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/ +/g, ' ')\n .trim();\n\n return stripped;\n}\n\n// Individual strippers for plugins that only handle specific formats\n\n/** Strip `<function_calls>` blocks */\nexport function stripFunctionCallsMarkers(response: string): string {\n return response.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n}\n\n/** Strip `<tool_call>` blocks */\nexport function stripToolCallMarkers(response: string): string {\n return response.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n}\n\n/** Strip `<function_call>` blocks */\nexport function stripFunctionCallMarkers(response: string): string {\n return response.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n}\n\n/** Strip `<tool_use>` blocks */\nexport function stripToolUseMarkers(response: string): string {\n return response.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n}\n\n/** Strip bare `<invoke>` blocks (Kimi K2-style) */\nexport function stripInvokeMarkers(response: string): string {\n return response.replace(/<invoke\\s+name=[\"'][^\"']*[\"']>[\\s\\S]*?<\\/invoke>/gi, '');\n}\n"],"mappings":"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","names":["args"]}
@@ -256,7 +256,13 @@ var TOOL_NAME_ALIASES = {
256
256
  "search": "search_web",
257
257
  "web_search": "search_web",
258
258
  "websearch": "search_web",
259
- "web": "search_web"
259
+ "web": "search_web",
260
+ // Help tool aliases
261
+ "help_search": "help_search",
262
+ "helpsearch": "help_search",
263
+ "search_help": "help_search",
264
+ "help_navigate": "help_navigate",
265
+ "helpnavigate": "help_navigate"
260
266
  };
261
267
  function normalizeToolName(name) {
262
268
  const normalized = name.toLowerCase().trim();
@@ -286,6 +292,21 @@ function convertToToolCallRequest(parsed) {
286
292
  query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || ""
287
293
  }
288
294
  };
295
+ case "help_search":
296
+ return {
297
+ name: "help_search",
298
+ arguments: {
299
+ query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || "",
300
+ limit: parsed.arguments.limit
301
+ }
302
+ };
303
+ case "help_navigate":
304
+ return {
305
+ name: "help_navigate",
306
+ arguments: {
307
+ url: parsed.arguments.url || parsed.arguments.path || Object.values(parsed.arguments)[0] || ""
308
+ }
309
+ };
289
310
  default:
290
311
  return {
291
312
  name: parsed.toolName,
@@ -479,12 +500,38 @@ function parseToolUseFormat(response) {
479
500
  }
480
501
  return results;
481
502
  }
503
+ function parseInvokeFormat(response) {
504
+ const results = [];
505
+ const invokePattern = /<invoke\s+name=["']([^"']+)["']>([\s\S]*?)<\/invoke>/gi;
506
+ let match;
507
+ while ((match = invokePattern.exec(response)) !== null) {
508
+ const toolName = match[1];
509
+ const paramContent = match[2];
510
+ const startIndex = match.index;
511
+ const args = {};
512
+ const paramPattern = /<parameter\s+name=["']([^"']+)["']>([^<]*)<\/parameter>/gi;
513
+ let paramMatch;
514
+ while ((paramMatch = paramPattern.exec(paramContent)) !== null) {
515
+ args[paramMatch[1]] = paramMatch[2].trim();
516
+ }
517
+ results.push({
518
+ toolName: normalizeToolName(toolName),
519
+ arguments: args,
520
+ fullMatch: match[0],
521
+ startIndex,
522
+ endIndex: startIndex + match[0].length,
523
+ format: "invoke"
524
+ });
525
+ }
526
+ return results;
527
+ }
482
528
  function parseAllXMLFormats(response) {
483
529
  const allResults = [];
484
530
  allResults.push(...parseFunctionCallsFormat(response));
485
531
  allResults.push(...parseToolCallFormat(response));
486
532
  allResults.push(...parseFunctionCallFormat(response));
487
533
  allResults.push(...parseToolUseFormat(response));
534
+ allResults.push(...parseInvokeFormat(response));
488
535
  const seen = /* @__PURE__ */ new Set();
489
536
  const deduped = allResults.filter((result) => {
490
537
  if (seen.has(result.startIndex)) {
@@ -500,7 +547,7 @@ function parseAllXMLAsToolCalls(response) {
500
547
  return parseAllXMLFormats(response).map(convertToToolCallRequest);
501
548
  }
502
549
  function hasAnyXMLToolMarkers(response) {
503
- return /<function_calls>/i.test(response) || /<tool_call>/i.test(response) || /<function_call\s+/i.test(response) || /<tool_use[\s>]/i.test(response);
550
+ return /<function_calls>/i.test(response) || /<tool_call>/i.test(response) || /<function_call\s+/i.test(response) || /<tool_use[\s>]/i.test(response) || /<invoke\s+name=/i.test(response);
504
551
  }
505
552
  function hasFunctionCallsMarkers(response) {
506
553
  return /<function_calls>/i.test(response);
@@ -514,12 +561,16 @@ function hasFunctionCallMarkers(response) {
514
561
  function hasToolUseMarkers(response) {
515
562
  return /<tool_use[\s>]/i.test(response);
516
563
  }
564
+ function hasInvokeMarkers(response) {
565
+ return /<invoke\s+name=/i.test(response);
566
+ }
517
567
  function stripAllXMLToolMarkers(response) {
518
568
  let stripped = response;
519
569
  stripped = stripped.replace(/<function_calls>[\s\S]*?<\/function_calls>/gi, "");
520
570
  stripped = stripped.replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, "");
521
571
  stripped = stripped.replace(/<function_call\s+[^>]*>[\s\S]*?<\/function_call>/gi, "");
522
572
  stripped = stripped.replace(/<tool_use[\s>][\s\S]*?<\/tool_use>/gi, "");
573
+ stripped = stripped.replace(/<invoke\s+name=["'][^"']*["']>[\s\S]*?<\/invoke>/gi, "");
523
574
  stripped = stripped.replace(/\n{3,}/g, "\n\n").replace(/ +/g, " ").trim();
524
575
  return stripped;
525
576
  }
@@ -535,6 +586,9 @@ function stripFunctionCallMarkers(response) {
535
586
  function stripToolUseMarkers(response) {
536
587
  return response.replace(/<tool_use[\s>][\s\S]*?<\/tool_use>/gi, "");
537
588
  }
589
+ function stripInvokeMarkers(response) {
590
+ return response.replace(/<invoke\s+name=["'][^"']*["']>[\s\S]*?<\/invoke>/gi, "");
591
+ }
538
592
  export {
539
593
  applyDescriptionLimit,
540
594
  convertFromAnthropicFormat,
@@ -550,6 +604,7 @@ export {
550
604
  hasAnyXMLToolMarkers,
551
605
  hasFunctionCallMarkers,
552
606
  hasFunctionCallsMarkers,
607
+ hasInvokeMarkers,
553
608
  hasToolCallMarkers,
554
609
  hasToolCalls,
555
610
  hasToolUseMarkers,
@@ -560,6 +615,7 @@ export {
560
615
  parseFunctionCallFormat,
561
616
  parseFunctionCallsFormat,
562
617
  parseGoogleToolCalls,
618
+ parseInvokeFormat,
563
619
  parseOpenAIToolCalls,
564
620
  parseToolCallFormat,
565
621
  parseToolCalls,
@@ -567,6 +623,7 @@ export {
567
623
  stripAllXMLToolMarkers,
568
624
  stripFunctionCallMarkers,
569
625
  stripFunctionCallsMarkers,
626
+ stripInvokeMarkers,
570
627
  stripToolCallMarkers,
571
628
  stripToolUseMarkers
572
629
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tools/parsers.ts","../../src/tools/converters.ts","../../src/tools/text-parsers.ts"],"sourcesContent":["/**\n * Tool Call Parsers\n *\n * Provider-specific parsers for extracting tool calls from LLM responses.\n * Each parser converts from a provider's native format to the standardized\n * ToolCallRequest format.\n *\n * @module @quilltap/plugin-utils/tools/parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Supported tool call response formats\n */\nexport type ToolCallFormat = 'openai' | 'anthropic' | 'google' | 'auto';\n\n/**\n * Parse OpenAI format tool calls from LLM response\n *\n * Extracts tool calls from OpenAI/Grok API responses which return\n * tool_calls in the message object.\n *\n * Expected response structures:\n * - `response.tool_calls` (direct)\n * - `response.choices[0].message.tool_calls` (nested)\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await openai.chat.completions.create({...});\n * const toolCalls = parseOpenAIToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseOpenAIToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n // Handle direct tool_calls array (snake_case)\n let toolCallsArray = resp?.tool_calls as unknown[] | undefined;\n\n // Handle direct toolCalls array (camelCase - some SDKs use this)\n if (!toolCallsArray) {\n toolCallsArray = (resp as Record<string, unknown>)?.toolCalls as unknown[] | undefined;\n }\n\n // Check nested structure from non-streaming responses: choices[0].message.tool_calls\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ message?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls;\n }\n\n // Check nested structure from streaming responses: choices[0].delta.toolCalls\n // OpenRouter SDK uses camelCase and puts tool calls in delta for streaming\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls;\n }\n\n if (toolCallsArray && Array.isArray(toolCallsArray) && toolCallsArray.length > 0) {\n for (const toolCall of toolCallsArray) {\n const tc = toolCall as {\n id?: string;\n type?: string;\n function?: { name: string; arguments: string };\n };\n\n if (tc.type === 'function' && tc.function) {\n const argsStr = tc.function.arguments || '{}';\n\n // During streaming, arguments may be incomplete JSON.\n // Check if the string looks like complete JSON before parsing.\n // Skip incomplete tool calls - they'll be complete in the final response.\n const trimmed = argsStr.trim();\n if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {\n // Incomplete JSON - skip this tool call for now\n continue;\n }\n\n try {\n toolCalls.push({\n name: tc.function.name,\n arguments: JSON.parse(argsStr),\n callId: tc.id || undefined,\n });\n } catch {\n // JSON parse failed (e.g., incomplete JSON during streaming)\n // This is expected during streaming - skip silently\n continue;\n }\n }\n }\n }\n } catch (error) {\n // Log error for unexpected parsing failures (not JSON parse errors)\n console.error('[plugin-utils] Error parsing OpenAI tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Anthropic format tool calls from LLM response\n *\n * Extracts tool calls from Anthropic API responses which return\n * tool_use blocks in the content array.\n *\n * Expected response structure:\n * - `response.content` array with `{ type: 'tool_use', name, input }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await anthropic.messages.create({...});\n * const toolCalls = parseAnthropicToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseAnthropicToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n if (!resp?.content || !Array.isArray(resp.content)) {\n return toolCalls;\n }\n\n for (const block of resp.content) {\n const b = block as { type?: string; id?: string; name?: string; input?: Record<string, unknown> };\n\n if (b.type === 'tool_use' && b.name) {\n toolCalls.push({\n name: b.name,\n arguments: b.input || {},\n callId: b.id || undefined,\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Anthropic tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Google Gemini format tool calls from LLM response\n *\n * Extracts tool calls from Google Gemini API responses which return\n * functionCall objects in the parts array.\n *\n * Expected response structure:\n * - `response.candidates[0].content.parts` array with `{ functionCall: { name, args } }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await gemini.generateContent({...});\n * const toolCalls = parseGoogleToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseGoogleToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n const candidates = resp?.candidates as\n | Array<{ content?: { parts?: unknown[] } }>\n | undefined;\n const parts = candidates?.[0]?.content?.parts;\n\n if (!parts || !Array.isArray(parts)) {\n return toolCalls;\n }\n\n for (const part of parts) {\n const p = part as {\n functionCall?: { name: string; args?: Record<string, unknown> };\n };\n\n if (p.functionCall) {\n toolCalls.push({\n name: p.functionCall.name,\n arguments: p.functionCall.args || {},\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Google tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Detect the format of a tool call response\n *\n * Analyzes the response structure to determine which provider format it uses.\n *\n * @param response - The raw response from a provider API\n * @returns The detected format, or null if unrecognized\n */\nexport function detectToolCallFormat(response: unknown): ToolCallFormat | null {\n if (!response || typeof response !== 'object') {\n return null;\n }\n\n const resp = response as Record<string, unknown>;\n\n // OpenAI format: has tool_calls/toolCalls directly or in choices[0].message or choices[0].delta\n if (resp.tool_calls && Array.isArray(resp.tool_calls)) {\n return 'openai';\n }\n if (resp.toolCalls && Array.isArray(resp.toolCalls)) {\n return 'openai';\n }\n\n const choices = resp.choices as Array<{\n message?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n }> | undefined;\n if (choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls) {\n return 'openai';\n }\n // Check delta for streaming responses (OpenRouter SDK uses this)\n if (choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls) {\n return 'openai';\n }\n\n // Anthropic format: has content array with tool_use type\n if (resp.content && Array.isArray(resp.content)) {\n const hasToolUse = (resp.content as Array<{ type?: string }>).some(\n (block) => block.type === 'tool_use'\n );\n if (hasToolUse) {\n return 'anthropic';\n }\n }\n\n // Google format: has candidates[0].content.parts with functionCall\n const candidates = resp.candidates as\n | Array<{ content?: { parts?: Array<{ functionCall?: unknown }> } }>\n | undefined;\n if (candidates?.[0]?.content?.parts) {\n const hasFunctionCall = candidates[0].content.parts.some((part) => part.functionCall);\n if (hasFunctionCall) {\n return 'google';\n }\n }\n\n return null;\n}\n\n/**\n * Parse tool calls with auto-detection or explicit format\n *\n * A unified parser that can either auto-detect the response format\n * or use a specified format. This is useful when you're not sure\n * which provider's response you're handling.\n *\n * @param response - The raw response from a provider API\n * @param format - The format to use: 'openai', 'anthropic', 'google', or 'auto'\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * // Auto-detect format\n * const toolCalls = parseToolCalls(response, 'auto');\n *\n * // Or specify format explicitly\n * const toolCalls = parseToolCalls(response, 'openai');\n * ```\n */\nexport function parseToolCalls(\n response: unknown,\n format: ToolCallFormat = 'auto'\n): ToolCallRequest[] {\n let actualFormat: ToolCallFormat | null = format;\n\n if (format === 'auto') {\n actualFormat = detectToolCallFormat(response);\n if (!actualFormat) {\n return [];\n }\n }\n\n switch (actualFormat) {\n case 'openai':\n return parseOpenAIToolCalls(response);\n case 'anthropic':\n return parseAnthropicToolCalls(response);\n case 'google':\n return parseGoogleToolCalls(response);\n default:\n return [];\n }\n}\n\n/**\n * Check if a response contains tool calls\n *\n * Quick check to determine if a response has any tool calls\n * without fully parsing them.\n *\n * @param response - The raw response from a provider API\n * @returns True if the response contains tool calls\n */\nexport function hasToolCalls(response: unknown): boolean {\n const format = detectToolCallFormat(response);\n return format !== null;\n}\n","/**\n * Tool Format Converters\n *\n * Utilities for converting between different provider tool formats.\n * The universal format (OpenAI-style) serves as the baseline for all conversions.\n *\n * @module @quilltap/plugin-utils/tools/converters\n */\n\nimport type {\n UniversalTool,\n AnthropicToolDefinition,\n GoogleToolDefinition,\n OpenAIToolDefinition,\n} from '@quilltap/plugin-types';\n\n/**\n * Convert OpenAI/Universal format tool to Anthropic format\n *\n * Anthropic uses a tool_use format with:\n * - name: string\n * - description: string\n * - input_schema: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Anthropic's tool_use\n *\n * @example\n * ```typescript\n * const anthropicTool = convertToAnthropicFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // input_schema: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToAnthropicFormat(tool: UniversalTool | OpenAIToolDefinition): AnthropicToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n input_schema: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert OpenAI/Universal format tool to Google Gemini format\n *\n * Google uses a function calling format with:\n * - name: string\n * - description: string\n * - parameters: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Google's functionCall\n *\n * @example\n * ```typescript\n * const googleTool = convertToGoogleFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // parameters: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToGoogleFormat(tool: UniversalTool | OpenAIToolDefinition): GoogleToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert Anthropic format tool to Universal/OpenAI format\n *\n * @param tool - Anthropic format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromAnthropicFormat(tool: AnthropicToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.input_schema.properties,\n required: tool.input_schema.required ?? [],\n },\n },\n };\n}\n\n/**\n * Convert Google format tool to Universal/OpenAI format\n *\n * @param tool - Google format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromGoogleFormat(tool: GoogleToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n },\n };\n}\n\n/**\n * Apply prompt/description length limit to a tool\n *\n * Modifies a tool's description if it exceeds maxBytes, appending a warning\n * that the description was truncated. This is useful for providers with\n * strict token limits.\n *\n * @param tool - Tool object (any format) with a description property\n * @param maxBytes - Maximum bytes allowed for description (including warning)\n * @returns Modified tool with truncated description if needed\n *\n * @example\n * ```typescript\n * const limitedTool = applyDescriptionLimit(tool, 500);\n * // If description > 500 bytes, truncates and adds warning\n * ```\n */\nexport function applyDescriptionLimit<T extends { description: string }>(\n tool: T,\n maxBytes: number\n): T {\n if (!tool || !tool.description) {\n return tool;\n }\n\n const warningText = ' [Note: description truncated due to length limit]';\n const maxDescBytes = maxBytes - Buffer.byteLength(warningText);\n\n if (maxDescBytes <= 0) {\n console.warn('[plugin-utils] Length limit too small for warning text:', maxBytes);\n return tool;\n }\n\n const descBytes = Buffer.byteLength(tool.description);\n\n if (descBytes > maxBytes) {\n // Truncate description to fit within the byte limit\n let truncated = tool.description;\n while (Buffer.byteLength(truncated) > maxDescBytes && truncated.length > 0) {\n truncated = truncated.slice(0, -1);\n }\n\n return {\n ...tool,\n description: truncated + warningText,\n };\n }\n\n return tool;\n}\n\n/**\n * Target format for tool conversion\n */\nexport type ToolConvertTarget = 'openai' | 'anthropic' | 'google';\n\n/**\n * Convert a universal tool to a specific provider format\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @param target - Target provider format\n * @returns Tool in the target format\n */\nexport function convertToolTo(\n tool: UniversalTool | OpenAIToolDefinition,\n target: ToolConvertTarget\n): UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition {\n switch (target) {\n case 'anthropic':\n return convertToAnthropicFormat(tool);\n case 'google':\n return convertToGoogleFormat(tool);\n case 'openai':\n default:\n return tool;\n }\n}\n\n/**\n * Convert multiple tools to a specific provider format\n *\n * @param tools - Array of universal tools or OpenAI tool definitions\n * @param target - Target provider format\n * @returns Array of tools in the target format\n */\nexport function convertToolsTo(\n tools: Array<UniversalTool | OpenAIToolDefinition>,\n target: ToolConvertTarget\n): Array<UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition> {\n return tools.map((tool) => convertToolTo(tool, target));\n}\n\n// ============================================================================\n// Backward-compatible aliases\n// ============================================================================\n\n/**\n * Alias for convertToAnthropicFormat\n * @deprecated Use convertToAnthropicFormat instead\n */\nexport const convertOpenAIToAnthropicFormat = convertToAnthropicFormat;\n\n/**\n * Alias for convertToGoogleFormat\n * @deprecated Use convertToGoogleFormat instead\n */\nexport const convertOpenAIToGoogleFormat = convertToGoogleFormat;\n","/**\n * Text-Based Tool Call Parsers\n *\n * Utility functions for parsing spontaneous XML-style tool calls from LLM\n * text responses. These are for models that emit tool-call-like markup in\n * their output instead of using native function calling APIs.\n *\n * Provider plugins import and compose these utilities to implement their\n * `hasTextToolMarkers`, `parseTextToolCalls`, and `stripTextToolMarkers` methods.\n *\n * @module @quilltap/plugin-utils/tools/text-parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Parsed text-based tool call from LLM output\n */\nexport interface ParsedTextTool {\n /** The tool name */\n toolName: string;\n /** Arguments extracted from the markup */\n arguments: Record<string, unknown>;\n /** The full matched markup text (for stripping) */\n fullMatch: string;\n /** Start index in the original text */\n startIndex: number;\n /** End index in the original text */\n endIndex: number;\n /** Which format was detected */\n format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use';\n}\n\n/**\n * Common tool name aliases that models use when hallucinating tool calls.\n * Maps common variations to canonical Quilltap tool names.\n */\nconst TOOL_NAME_ALIASES: Record<string, string> = {\n // Direct mappings\n 'search_memories': 'search_memories',\n 'generate_image': 'generate_image',\n 'search_web': 'search_web',\n\n // Memory tool aliases\n 'memory': 'search_memories',\n 'memory_search': 'search_memories',\n 'search_memory': 'search_memories',\n 'memories': 'search_memories',\n\n // Image tool aliases\n 'image': 'generate_image',\n 'create_image': 'generate_image',\n 'image_generation': 'generate_image',\n 'gen_image': 'generate_image',\n\n // Web search aliases\n 'search': 'search_web',\n 'web_search': 'search_web',\n 'websearch': 'search_web',\n 'web': 'search_web',\n};\n\n/**\n * Normalize a tool name from hallucinated markup to the canonical name.\n * Returns the original name if no alias is found (passes through unknown tools).\n */\nexport function normalizeToolName(name: string): string {\n const normalized = name.toLowerCase().trim();\n return TOOL_NAME_ALIASES[normalized] || name;\n}\n\n/**\n * Convert a ParsedTextTool to the standard ToolCallRequest format.\n *\n * For well-known tools, normalizes argument names (e.g., \"search\" → \"query\").\n * For unknown tools, passes arguments through as-is.\n */\nexport function convertToToolCallRequest(parsed: ParsedTextTool): ToolCallRequest {\n switch (parsed.toolName) {\n case 'search_memories':\n return {\n name: 'search_memories',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n limit: parsed.arguments.limit,\n },\n };\n\n case 'generate_image':\n return {\n name: 'generate_image',\n arguments: {\n prompt: parsed.arguments.prompt || parsed.arguments.description || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n case 'search_web':\n return {\n name: 'search_web',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n default:\n // Pass through unknown tools with their original arguments\n return {\n name: parsed.toolName,\n arguments: parsed.arguments,\n };\n }\n}\n\n// ============================================================================\n// Individual format parsers\n// ============================================================================\n\n/**\n * Parse `<function_calls><invoke name=\"...\">` format (DeepSeek and Claude-style)\n */\nexport function parseFunctionCallsFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallsPattern = /<function_calls>([\\s\\S]*?)<\\/function_calls>/gi;\n\n let wrapperMatch;\n while ((wrapperMatch = functionCallsPattern.exec(response)) !== null) {\n const wrapperContent = wrapperMatch[1];\n const wrapperStartIndex = wrapperMatch.index;\n const contentOffset = wrapperStartIndex + '<function_calls>'.length;\n\n const invokePattern = /<invoke\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/invoke>/gi;\n\n let invokeMatch;\n while ((invokeMatch = invokePattern.exec(wrapperContent)) !== null) {\n const toolName = invokeMatch[1];\n const paramContent = invokeMatch[2];\n const invokeStartIndex = contentOffset + invokeMatch.index;\n const invokeEndIndex = invokeStartIndex + invokeMatch[0].length;\n\n const args: Record<string, unknown> = {};\n let format: 'deepseek' | 'claude' = 'claude';\n\n // DeepSeek format: <parameter name=\"...\" string=\"...\">value</parameter>\n const deepseekParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']\\s+string=[\"']([^\"']*)[\"'][^>]*>([^<]*)<\\/parameter>/gi;\n let paramMatch;\n while ((paramMatch = deepseekParamPattern.exec(paramContent)) !== null) {\n const paramName = paramMatch[1];\n const stringAttr = paramMatch[2];\n const value = paramMatch[3].trim();\n\n if (stringAttr === 'false') {\n const numVal = Number(value);\n if (!isNaN(numVal)) {\n args[paramName] = numVal;\n } else if (value === 'true') {\n args[paramName] = true;\n } else if (value === 'false') {\n args[paramName] = false;\n } else {\n args[paramName] = value;\n }\n } else {\n args[paramName] = value;\n }\n format = 'deepseek';\n }\n\n // Claude format: <parameter name=\"...\">value</parameter>\n if (Object.keys(args).length === 0) {\n const claudeParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = claudeParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n }\n\n // antml:parameter format (Claude Code style)\n const antmlParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/antml:parameter>/gi;\n while ((paramMatch = antmlParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: invokeMatch[0],\n startIndex: invokeStartIndex,\n endIndex: invokeEndIndex,\n format,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_call>` format (generic XML)\n */\nexport function parseToolCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolCallPattern = /<tool_call>([\\s\\S]*?)<\\/tool_call>/gi;\n\n let match;\n while ((match = toolCallPattern.exec(response)) !== null) {\n const content = match[1];\n const startIndex = match.index;\n\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n\n const toolName = nameMatch[1].trim();\n const args: Record<string, unknown> = {};\n\n const argsMatch = /<arguments>([\\s\\S]*?)<\\/arguments>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1];\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'generic',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<function_call name=\"...\">` format\n */\nexport function parseFunctionCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallPattern = /<function_call\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/function_call>/gi;\n\n let match;\n while ((match = functionCallPattern.exec(response)) !== null) {\n const toolName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n const args: Record<string, unknown> = {};\n\n const paramPattern = /<param\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/param>/gi;\n let paramMatch;\n while ((paramMatch = paramPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n const parameterPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = parameterPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'function_call',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_use>` format (Gemini and others)\n *\n * Handles multiple sub-formats:\n * - Bare JSON: `<tool_use>{\"name\":\"fn\",\"input\":{...}}</tool_use>`\n * - XML children: `<tool_use><name>fn</name><arguments>...</arguments></tool_use>`\n * - JSON in arguments: `<tool_use><name>fn</name><arguments>{\"q\":\"v\"}</arguments></tool_use>`\n * - Attributed: `<tool_use name=\"fn\"><arguments>...</arguments></tool_use>`\n */\nexport function parseToolUseFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolUsePattern = /<tool_use(?:\\s+name=[\"']([^\"']+)[\"'])?\\s*>([\\s\\S]*?)<\\/tool_use>/gi;\n\n let match;\n while ((match = toolUsePattern.exec(response)) !== null) {\n const attrName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n // Try bare JSON first (Gemini's primary format)\n const trimmedContent = content.trim();\n if (trimmedContent.startsWith('{')) {\n try {\n const jsonBlob = JSON.parse(trimmedContent);\n if (typeof jsonBlob === 'object' && jsonBlob !== null && jsonBlob.name) {\n const args = jsonBlob.input || jsonBlob.arguments || jsonBlob.parameters || {};\n results.push({\n toolName: normalizeToolName(jsonBlob.name),\n arguments: typeof args === 'object' && args !== null ? args : {},\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n continue;\n }\n } catch {\n // Not valid JSON, fall through\n }\n }\n\n // Extract name from attribute or child element\n let toolName = attrName;\n if (!toolName) {\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n toolName = nameMatch[1].trim();\n }\n\n const args: Record<string, unknown> = {};\n\n // Try <arguments>, <input>, or <parameters>\n const argsMatch = /<(?:arguments|input|parameters)>([\\s\\S]*?)<\\/(?:arguments|input|parameters)>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1].trim();\n\n if (argsContent.startsWith('{')) {\n try {\n const parsed = JSON.parse(argsContent);\n if (typeof parsed === 'object' && parsed !== null) {\n Object.assign(args, parsed);\n }\n } catch {\n // Not valid JSON\n }\n }\n\n if (Object.keys(args).length === 0) {\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n }\n\n return results;\n}\n\n// ============================================================================\n// Composite utilities for plugins\n// ============================================================================\n\n/**\n * Parse all known XML tool call formats from response text.\n * Deduplicates by position and sorts by start index.\n *\n * Plugins can call this directly or compose individual format parsers\n * for provider-specific behavior.\n */\nexport function parseAllXMLFormats(response: string): ParsedTextTool[] {\n const allResults: ParsedTextTool[] = [];\n\n allResults.push(...parseFunctionCallsFormat(response));\n allResults.push(...parseToolCallFormat(response));\n allResults.push(...parseFunctionCallFormat(response));\n allResults.push(...parseToolUseFormat(response));\n\n // Deduplicate by startIndex\n const seen = new Set<number>();\n const deduped = allResults.filter(result => {\n if (seen.has(result.startIndex)) {\n return false;\n }\n seen.add(result.startIndex);\n return true;\n });\n\n deduped.sort((a, b) => a.startIndex - b.startIndex);\n return deduped;\n}\n\n/**\n * Convert parsed text tools to standard ToolCallRequest array.\n * Convenience wrapper for plugins implementing parseTextToolCalls.\n */\nexport function parseAllXMLAsToolCalls(response: string): ToolCallRequest[] {\n return parseAllXMLFormats(response).map(convertToToolCallRequest);\n}\n\n/**\n * Check if text contains any of the known XML tool call patterns.\n * Quick regex check before full parsing.\n */\nexport function hasAnyXMLToolMarkers(response: string): boolean {\n return (\n /<function_calls>/i.test(response) ||\n /<tool_call>/i.test(response) ||\n /<function_call\\s+/i.test(response) ||\n /<tool_use[\\s>]/i.test(response)\n );\n}\n\n// Individual marker checks for plugins that only care about specific formats\n\n/** Check for `<function_calls>` markers (DeepSeek/Claude-style) */\nexport function hasFunctionCallsMarkers(response: string): boolean {\n return /<function_calls>/i.test(response);\n}\n\n/** Check for `<tool_call>` markers (generic) */\nexport function hasToolCallMarkers(response: string): boolean {\n return /<tool_call>/i.test(response);\n}\n\n/** Check for `<function_call>` markers */\nexport function hasFunctionCallMarkers(response: string): boolean {\n return /<function_call\\s+/i.test(response);\n}\n\n/** Check for `<tool_use>` markers (Gemini-style) */\nexport function hasToolUseMarkers(response: string): boolean {\n return /<tool_use[\\s>]/i.test(response);\n}\n\n/**\n * Strip all known XML tool call markers from text.\n * Cleans up whitespace left behind.\n */\nexport function stripAllXMLToolMarkers(response: string): string {\n let stripped = response;\n\n stripped = stripped.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n stripped = stripped.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n stripped = stripped.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n stripped = stripped.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n\n stripped = stripped\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/ +/g, ' ')\n .trim();\n\n return stripped;\n}\n\n// Individual strippers for plugins that only handle specific formats\n\n/** Strip `<function_calls>` blocks */\nexport function stripFunctionCallsMarkers(response: string): string {\n return response.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n}\n\n/** Strip `<tool_call>` blocks */\nexport function stripToolCallMarkers(response: string): string {\n return response.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n}\n\n/** Strip `<function_call>` blocks */\nexport function stripFunctionCallMarkers(response: string): string {\n return response.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n}\n\n/** Strip `<tool_use>` blocks */\nexport function stripToolUseMarkers(response: string): string {\n return response.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n}\n"],"mappings":"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","names":["args"]}
1
+ {"version":3,"sources":["../../src/tools/parsers.ts","../../src/tools/converters.ts","../../src/tools/text-parsers.ts"],"sourcesContent":["/**\n * Tool Call Parsers\n *\n * Provider-specific parsers for extracting tool calls from LLM responses.\n * Each parser converts from a provider's native format to the standardized\n * ToolCallRequest format.\n *\n * @module @quilltap/plugin-utils/tools/parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Supported tool call response formats\n */\nexport type ToolCallFormat = 'openai' | 'anthropic' | 'google' | 'auto';\n\n/**\n * Parse OpenAI format tool calls from LLM response\n *\n * Extracts tool calls from OpenAI/Grok API responses which return\n * tool_calls in the message object.\n *\n * Expected response structures:\n * - `response.tool_calls` (direct)\n * - `response.choices[0].message.tool_calls` (nested)\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await openai.chat.completions.create({...});\n * const toolCalls = parseOpenAIToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseOpenAIToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n // Handle direct tool_calls array (snake_case)\n let toolCallsArray = resp?.tool_calls as unknown[] | undefined;\n\n // Handle direct toolCalls array (camelCase - some SDKs use this)\n if (!toolCallsArray) {\n toolCallsArray = (resp as Record<string, unknown>)?.toolCalls as unknown[] | undefined;\n }\n\n // Check nested structure from non-streaming responses: choices[0].message.tool_calls\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ message?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls;\n }\n\n // Check nested structure from streaming responses: choices[0].delta.toolCalls\n // OpenRouter SDK uses camelCase and puts tool calls in delta for streaming\n if (!toolCallsArray) {\n const choices = resp?.choices as\n | Array<{ delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] } }>\n | undefined;\n toolCallsArray = choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls;\n }\n\n if (toolCallsArray && Array.isArray(toolCallsArray) && toolCallsArray.length > 0) {\n for (const toolCall of toolCallsArray) {\n const tc = toolCall as {\n id?: string;\n type?: string;\n function?: { name: string; arguments: string };\n };\n\n if (tc.type === 'function' && tc.function) {\n const argsStr = tc.function.arguments || '{}';\n\n // During streaming, arguments may be incomplete JSON.\n // Check if the string looks like complete JSON before parsing.\n // Skip incomplete tool calls - they'll be complete in the final response.\n const trimmed = argsStr.trim();\n if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {\n // Incomplete JSON - skip this tool call for now\n continue;\n }\n\n try {\n toolCalls.push({\n name: tc.function.name,\n arguments: JSON.parse(argsStr),\n callId: tc.id || undefined,\n });\n } catch {\n // JSON parse failed (e.g., incomplete JSON during streaming)\n // This is expected during streaming - skip silently\n continue;\n }\n }\n }\n }\n } catch (error) {\n // Log error for unexpected parsing failures (not JSON parse errors)\n console.error('[plugin-utils] Error parsing OpenAI tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Anthropic format tool calls from LLM response\n *\n * Extracts tool calls from Anthropic API responses which return\n * tool_use blocks in the content array.\n *\n * Expected response structure:\n * - `response.content` array with `{ type: 'tool_use', name, input }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await anthropic.messages.create({...});\n * const toolCalls = parseAnthropicToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseAnthropicToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n\n if (!resp?.content || !Array.isArray(resp.content)) {\n return toolCalls;\n }\n\n for (const block of resp.content) {\n const b = block as { type?: string; id?: string; name?: string; input?: Record<string, unknown> };\n\n if (b.type === 'tool_use' && b.name) {\n toolCalls.push({\n name: b.name,\n arguments: b.input || {},\n callId: b.id || undefined,\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Anthropic tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Parse Google Gemini format tool calls from LLM response\n *\n * Extracts tool calls from Google Gemini API responses which return\n * functionCall objects in the parts array.\n *\n * Expected response structure:\n * - `response.candidates[0].content.parts` array with `{ functionCall: { name, args } }`\n *\n * @param response - The raw response from provider API\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * const response = await gemini.generateContent({...});\n * const toolCalls = parseGoogleToolCalls(response);\n * // Returns: [{ name: 'search_web', arguments: { query: 'hello' } }]\n * ```\n */\nexport function parseGoogleToolCalls(response: unknown): ToolCallRequest[] {\n const toolCalls: ToolCallRequest[] = [];\n\n try {\n const resp = response as Record<string, unknown>;\n const candidates = resp?.candidates as\n | Array<{ content?: { parts?: unknown[] } }>\n | undefined;\n const parts = candidates?.[0]?.content?.parts;\n\n if (!parts || !Array.isArray(parts)) {\n return toolCalls;\n }\n\n for (const part of parts) {\n const p = part as {\n functionCall?: { name: string; args?: Record<string, unknown> };\n };\n\n if (p.functionCall) {\n toolCalls.push({\n name: p.functionCall.name,\n arguments: p.functionCall.args || {},\n });\n }\n }\n } catch (error) {\n console.error('[plugin-utils] Error parsing Google tool calls:', error);\n }\n\n return toolCalls;\n}\n\n/**\n * Detect the format of a tool call response\n *\n * Analyzes the response structure to determine which provider format it uses.\n *\n * @param response - The raw response from a provider API\n * @returns The detected format, or null if unrecognized\n */\nexport function detectToolCallFormat(response: unknown): ToolCallFormat | null {\n if (!response || typeof response !== 'object') {\n return null;\n }\n\n const resp = response as Record<string, unknown>;\n\n // OpenAI format: has tool_calls/toolCalls directly or in choices[0].message or choices[0].delta\n if (resp.tool_calls && Array.isArray(resp.tool_calls)) {\n return 'openai';\n }\n if (resp.toolCalls && Array.isArray(resp.toolCalls)) {\n return 'openai';\n }\n\n const choices = resp.choices as Array<{\n message?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n delta?: { tool_calls?: unknown[]; toolCalls?: unknown[] };\n }> | undefined;\n if (choices?.[0]?.message?.tool_calls || choices?.[0]?.message?.toolCalls) {\n return 'openai';\n }\n // Check delta for streaming responses (OpenRouter SDK uses this)\n if (choices?.[0]?.delta?.tool_calls || choices?.[0]?.delta?.toolCalls) {\n return 'openai';\n }\n\n // Anthropic format: has content array with tool_use type\n if (resp.content && Array.isArray(resp.content)) {\n const hasToolUse = (resp.content as Array<{ type?: string }>).some(\n (block) => block.type === 'tool_use'\n );\n if (hasToolUse) {\n return 'anthropic';\n }\n }\n\n // Google format: has candidates[0].content.parts with functionCall\n const candidates = resp.candidates as\n | Array<{ content?: { parts?: Array<{ functionCall?: unknown }> } }>\n | undefined;\n if (candidates?.[0]?.content?.parts) {\n const hasFunctionCall = candidates[0].content.parts.some((part) => part.functionCall);\n if (hasFunctionCall) {\n return 'google';\n }\n }\n\n return null;\n}\n\n/**\n * Parse tool calls with auto-detection or explicit format\n *\n * A unified parser that can either auto-detect the response format\n * or use a specified format. This is useful when you're not sure\n * which provider's response you're handling.\n *\n * @param response - The raw response from a provider API\n * @param format - The format to use: 'openai', 'anthropic', 'google', or 'auto'\n * @returns Array of parsed tool call requests\n *\n * @example\n * ```typescript\n * // Auto-detect format\n * const toolCalls = parseToolCalls(response, 'auto');\n *\n * // Or specify format explicitly\n * const toolCalls = parseToolCalls(response, 'openai');\n * ```\n */\nexport function parseToolCalls(\n response: unknown,\n format: ToolCallFormat = 'auto'\n): ToolCallRequest[] {\n let actualFormat: ToolCallFormat | null = format;\n\n if (format === 'auto') {\n actualFormat = detectToolCallFormat(response);\n if (!actualFormat) {\n return [];\n }\n }\n\n switch (actualFormat) {\n case 'openai':\n return parseOpenAIToolCalls(response);\n case 'anthropic':\n return parseAnthropicToolCalls(response);\n case 'google':\n return parseGoogleToolCalls(response);\n default:\n return [];\n }\n}\n\n/**\n * Check if a response contains tool calls\n *\n * Quick check to determine if a response has any tool calls\n * without fully parsing them.\n *\n * @param response - The raw response from a provider API\n * @returns True if the response contains tool calls\n */\nexport function hasToolCalls(response: unknown): boolean {\n const format = detectToolCallFormat(response);\n return format !== null;\n}\n","/**\n * Tool Format Converters\n *\n * Utilities for converting between different provider tool formats.\n * The universal format (OpenAI-style) serves as the baseline for all conversions.\n *\n * @module @quilltap/plugin-utils/tools/converters\n */\n\nimport type {\n UniversalTool,\n AnthropicToolDefinition,\n GoogleToolDefinition,\n OpenAIToolDefinition,\n} from '@quilltap/plugin-types';\n\n/**\n * Convert OpenAI/Universal format tool to Anthropic format\n *\n * Anthropic uses a tool_use format with:\n * - name: string\n * - description: string\n * - input_schema: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Anthropic's tool_use\n *\n * @example\n * ```typescript\n * const anthropicTool = convertToAnthropicFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // input_schema: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToAnthropicFormat(tool: UniversalTool | OpenAIToolDefinition): AnthropicToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n input_schema: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert OpenAI/Universal format tool to Google Gemini format\n *\n * Google uses a function calling format with:\n * - name: string\n * - description: string\n * - parameters: JSON schema object\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @returns Tool formatted for Google's functionCall\n *\n * @example\n * ```typescript\n * const googleTool = convertToGoogleFormat(universalTool);\n * // Returns: {\n * // name: 'search_web',\n * // description: 'Search the web',\n * // parameters: {\n * // type: 'object',\n * // properties: { query: { type: 'string' } },\n * // required: ['query']\n * // }\n * // }\n * ```\n */\nexport function convertToGoogleFormat(tool: UniversalTool | OpenAIToolDefinition): GoogleToolDefinition {\n return {\n name: tool.function.name,\n description: tool.function.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.function.parameters?.properties ?? {},\n required: tool.function.parameters?.required ?? [],\n },\n };\n}\n\n/**\n * Convert Anthropic format tool to Universal/OpenAI format\n *\n * @param tool - Anthropic format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromAnthropicFormat(tool: AnthropicToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description ?? '',\n parameters: {\n type: 'object',\n properties: tool.input_schema.properties,\n required: tool.input_schema.required ?? [],\n },\n },\n };\n}\n\n/**\n * Convert Google format tool to Universal/OpenAI format\n *\n * @param tool - Google format tool\n * @returns Tool in universal OpenAI format\n */\nexport function convertFromGoogleFormat(tool: GoogleToolDefinition): UniversalTool {\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n },\n };\n}\n\n/**\n * Apply prompt/description length limit to a tool\n *\n * Modifies a tool's description if it exceeds maxBytes, appending a warning\n * that the description was truncated. This is useful for providers with\n * strict token limits.\n *\n * @param tool - Tool object (any format) with a description property\n * @param maxBytes - Maximum bytes allowed for description (including warning)\n * @returns Modified tool with truncated description if needed\n *\n * @example\n * ```typescript\n * const limitedTool = applyDescriptionLimit(tool, 500);\n * // If description > 500 bytes, truncates and adds warning\n * ```\n */\nexport function applyDescriptionLimit<T extends { description: string }>(\n tool: T,\n maxBytes: number\n): T {\n if (!tool || !tool.description) {\n return tool;\n }\n\n const warningText = ' [Note: description truncated due to length limit]';\n const maxDescBytes = maxBytes - Buffer.byteLength(warningText);\n\n if (maxDescBytes <= 0) {\n console.warn('[plugin-utils] Length limit too small for warning text:', maxBytes);\n return tool;\n }\n\n const descBytes = Buffer.byteLength(tool.description);\n\n if (descBytes > maxBytes) {\n // Truncate description to fit within the byte limit\n let truncated = tool.description;\n while (Buffer.byteLength(truncated) > maxDescBytes && truncated.length > 0) {\n truncated = truncated.slice(0, -1);\n }\n\n return {\n ...tool,\n description: truncated + warningText,\n };\n }\n\n return tool;\n}\n\n/**\n * Target format for tool conversion\n */\nexport type ToolConvertTarget = 'openai' | 'anthropic' | 'google';\n\n/**\n * Convert a universal tool to a specific provider format\n *\n * @param tool - Universal tool or OpenAI tool definition\n * @param target - Target provider format\n * @returns Tool in the target format\n */\nexport function convertToolTo(\n tool: UniversalTool | OpenAIToolDefinition,\n target: ToolConvertTarget\n): UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition {\n switch (target) {\n case 'anthropic':\n return convertToAnthropicFormat(tool);\n case 'google':\n return convertToGoogleFormat(tool);\n case 'openai':\n default:\n return tool;\n }\n}\n\n/**\n * Convert multiple tools to a specific provider format\n *\n * @param tools - Array of universal tools or OpenAI tool definitions\n * @param target - Target provider format\n * @returns Array of tools in the target format\n */\nexport function convertToolsTo(\n tools: Array<UniversalTool | OpenAIToolDefinition>,\n target: ToolConvertTarget\n): Array<UniversalTool | OpenAIToolDefinition | AnthropicToolDefinition | GoogleToolDefinition> {\n return tools.map((tool) => convertToolTo(tool, target));\n}\n\n// ============================================================================\n// Backward-compatible aliases\n// ============================================================================\n\n/**\n * Alias for convertToAnthropicFormat\n * @deprecated Use convertToAnthropicFormat instead\n */\nexport const convertOpenAIToAnthropicFormat = convertToAnthropicFormat;\n\n/**\n * Alias for convertToGoogleFormat\n * @deprecated Use convertToGoogleFormat instead\n */\nexport const convertOpenAIToGoogleFormat = convertToGoogleFormat;\n","/**\n * Text-Based Tool Call Parsers\n *\n * Utility functions for parsing spontaneous XML-style tool calls from LLM\n * text responses. These are for models that emit tool-call-like markup in\n * their output instead of using native function calling APIs.\n *\n * Provider plugins import and compose these utilities to implement their\n * `hasTextToolMarkers`, `parseTextToolCalls`, and `stripTextToolMarkers` methods.\n *\n * @module @quilltap/plugin-utils/tools/text-parsers\n */\n\nimport type { ToolCallRequest } from '@quilltap/plugin-types';\n\n/**\n * Parsed text-based tool call from LLM output\n */\nexport interface ParsedTextTool {\n /** The tool name */\n toolName: string;\n /** Arguments extracted from the markup */\n arguments: Record<string, unknown>;\n /** The full matched markup text (for stripping) */\n fullMatch: string;\n /** Start index in the original text */\n startIndex: number;\n /** End index in the original text */\n endIndex: number;\n /** Which format was detected */\n format: 'deepseek' | 'claude' | 'generic' | 'function_call' | 'tool_use' | 'invoke';\n}\n\n/**\n * Common tool name aliases that models use when hallucinating tool calls.\n * Maps common variations to canonical Quilltap tool names.\n */\nconst TOOL_NAME_ALIASES: Record<string, string> = {\n // Direct mappings\n 'search_memories': 'search_memories',\n 'generate_image': 'generate_image',\n 'search_web': 'search_web',\n\n // Memory tool aliases\n 'memory': 'search_memories',\n 'memory_search': 'search_memories',\n 'search_memory': 'search_memories',\n 'memories': 'search_memories',\n\n // Image tool aliases\n 'image': 'generate_image',\n 'create_image': 'generate_image',\n 'image_generation': 'generate_image',\n 'gen_image': 'generate_image',\n\n // Web search aliases\n 'search': 'search_web',\n 'web_search': 'search_web',\n 'websearch': 'search_web',\n 'web': 'search_web',\n\n // Help tool aliases\n 'help_search': 'help_search',\n 'helpsearch': 'help_search',\n 'search_help': 'help_search',\n 'help_navigate': 'help_navigate',\n 'helpnavigate': 'help_navigate',\n};\n\n/**\n * Normalize a tool name from hallucinated markup to the canonical name.\n * Returns the original name if no alias is found (passes through unknown tools).\n */\nexport function normalizeToolName(name: string): string {\n const normalized = name.toLowerCase().trim();\n return TOOL_NAME_ALIASES[normalized] || name;\n}\n\n/**\n * Convert a ParsedTextTool to the standard ToolCallRequest format.\n *\n * For well-known tools, normalizes argument names (e.g., \"search\" → \"query\").\n * For unknown tools, passes arguments through as-is.\n */\nexport function convertToToolCallRequest(parsed: ParsedTextTool): ToolCallRequest {\n switch (parsed.toolName) {\n case 'search_memories':\n return {\n name: 'search_memories',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n limit: parsed.arguments.limit,\n },\n };\n\n case 'generate_image':\n return {\n name: 'generate_image',\n arguments: {\n prompt: parsed.arguments.prompt || parsed.arguments.description || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n case 'search_web':\n return {\n name: 'search_web',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n case 'help_search':\n return {\n name: 'help_search',\n arguments: {\n query: parsed.arguments.query || parsed.arguments.search || Object.values(parsed.arguments)[0] || '',\n limit: parsed.arguments.limit,\n },\n };\n\n case 'help_navigate':\n return {\n name: 'help_navigate',\n arguments: {\n url: parsed.arguments.url || parsed.arguments.path || Object.values(parsed.arguments)[0] || '',\n },\n };\n\n default:\n // Pass through unknown tools with their original arguments\n return {\n name: parsed.toolName,\n arguments: parsed.arguments,\n };\n }\n}\n\n// ============================================================================\n// Individual format parsers\n// ============================================================================\n\n/**\n * Parse `<function_calls><invoke name=\"...\">` format (DeepSeek and Claude-style)\n */\nexport function parseFunctionCallsFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallsPattern = /<function_calls>([\\s\\S]*?)<\\/function_calls>/gi;\n\n let wrapperMatch;\n while ((wrapperMatch = functionCallsPattern.exec(response)) !== null) {\n const wrapperContent = wrapperMatch[1];\n const wrapperStartIndex = wrapperMatch.index;\n const contentOffset = wrapperStartIndex + '<function_calls>'.length;\n\n const invokePattern = /<invoke\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/invoke>/gi;\n\n let invokeMatch;\n while ((invokeMatch = invokePattern.exec(wrapperContent)) !== null) {\n const toolName = invokeMatch[1];\n const paramContent = invokeMatch[2];\n const invokeStartIndex = contentOffset + invokeMatch.index;\n const invokeEndIndex = invokeStartIndex + invokeMatch[0].length;\n\n const args: Record<string, unknown> = {};\n let format: 'deepseek' | 'claude' = 'claude';\n\n // DeepSeek format: <parameter name=\"...\" string=\"...\">value</parameter>\n const deepseekParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']\\s+string=[\"']([^\"']*)[\"'][^>]*>([^<]*)<\\/parameter>/gi;\n let paramMatch;\n while ((paramMatch = deepseekParamPattern.exec(paramContent)) !== null) {\n const paramName = paramMatch[1];\n const stringAttr = paramMatch[2];\n const value = paramMatch[3].trim();\n\n if (stringAttr === 'false') {\n const numVal = Number(value);\n if (!isNaN(numVal)) {\n args[paramName] = numVal;\n } else if (value === 'true') {\n args[paramName] = true;\n } else if (value === 'false') {\n args[paramName] = false;\n } else {\n args[paramName] = value;\n }\n } else {\n args[paramName] = value;\n }\n format = 'deepseek';\n }\n\n // Claude format: <parameter name=\"...\">value</parameter>\n if (Object.keys(args).length === 0) {\n const claudeParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = claudeParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n }\n\n // antml:parameter format (Claude Code style)\n const antmlParamPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/antml:parameter>/gi;\n while ((paramMatch = antmlParamPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: invokeMatch[0],\n startIndex: invokeStartIndex,\n endIndex: invokeEndIndex,\n format,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_call>` format (generic XML)\n */\nexport function parseToolCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolCallPattern = /<tool_call>([\\s\\S]*?)<\\/tool_call>/gi;\n\n let match;\n while ((match = toolCallPattern.exec(response)) !== null) {\n const content = match[1];\n const startIndex = match.index;\n\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n\n const toolName = nameMatch[1].trim();\n const args: Record<string, unknown> = {};\n\n const argsMatch = /<arguments>([\\s\\S]*?)<\\/arguments>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1];\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'generic',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<function_call name=\"...\">` format\n */\nexport function parseFunctionCallFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const functionCallPattern = /<function_call\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/function_call>/gi;\n\n let match;\n while ((match = functionCallPattern.exec(response)) !== null) {\n const toolName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n const args: Record<string, unknown> = {};\n\n const paramPattern = /<param\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/param>/gi;\n let paramMatch;\n while ((paramMatch = paramPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n const parameterPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n while ((paramMatch = parameterPattern.exec(content)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'function_call',\n });\n }\n\n return results;\n}\n\n/**\n * Parse `<tool_use>` format (Gemini and others)\n *\n * Handles multiple sub-formats:\n * - Bare JSON: `<tool_use>{\"name\":\"fn\",\"input\":{...}}</tool_use>`\n * - XML children: `<tool_use><name>fn</name><arguments>...</arguments></tool_use>`\n * - JSON in arguments: `<tool_use><name>fn</name><arguments>{\"q\":\"v\"}</arguments></tool_use>`\n * - Attributed: `<tool_use name=\"fn\"><arguments>...</arguments></tool_use>`\n */\nexport function parseToolUseFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const toolUsePattern = /<tool_use(?:\\s+name=[\"']([^\"']+)[\"'])?\\s*>([\\s\\S]*?)<\\/tool_use>/gi;\n\n let match;\n while ((match = toolUsePattern.exec(response)) !== null) {\n const attrName = match[1];\n const content = match[2];\n const startIndex = match.index;\n\n // Try bare JSON first (Gemini's primary format)\n const trimmedContent = content.trim();\n if (trimmedContent.startsWith('{')) {\n try {\n const jsonBlob = JSON.parse(trimmedContent);\n if (typeof jsonBlob === 'object' && jsonBlob !== null && jsonBlob.name) {\n const args = jsonBlob.input || jsonBlob.arguments || jsonBlob.parameters || {};\n results.push({\n toolName: normalizeToolName(jsonBlob.name),\n arguments: typeof args === 'object' && args !== null ? args : {},\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n continue;\n }\n } catch {\n // Not valid JSON, fall through\n }\n }\n\n // Extract name from attribute or child element\n let toolName = attrName;\n if (!toolName) {\n const nameMatch = /<name>([^<]+)<\\/name>/i.exec(content);\n if (!nameMatch) continue;\n toolName = nameMatch[1].trim();\n }\n\n const args: Record<string, unknown> = {};\n\n // Try <arguments>, <input>, or <parameters>\n const argsMatch = /<(?:arguments|input|parameters)>([\\s\\S]*?)<\\/(?:arguments|input|parameters)>/i.exec(content);\n if (argsMatch) {\n const argsContent = argsMatch[1].trim();\n\n if (argsContent.startsWith('{')) {\n try {\n const parsed = JSON.parse(argsContent);\n if (typeof parsed === 'object' && parsed !== null) {\n Object.assign(args, parsed);\n }\n } catch {\n // Not valid JSON\n }\n }\n\n if (Object.keys(args).length === 0) {\n const argPattern = /<(\\w+)>([^<]*)<\\/\\1>/gi;\n let argMatch;\n while ((argMatch = argPattern.exec(argsContent)) !== null) {\n args[argMatch[1]] = argMatch[2].trim();\n }\n }\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'tool_use',\n });\n }\n\n return results;\n}\n\n/**\n * Parse bare `<invoke name=\"...\">` format (Kimi K2 and similar models)\n *\n * Matches `<invoke>` tags that appear WITHOUT a `<function_calls>` wrapper.\n * IMPORTANT: In composite parsing, this must run AFTER parseFunctionCallsFormat\n * so that wrapped invokes are claimed first and deduplicated by startIndex.\n */\nexport function parseInvokeFormat(response: string): ParsedTextTool[] {\n const results: ParsedTextTool[] = [];\n\n const invokePattern = /<invoke\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/invoke>/gi;\n\n let match;\n while ((match = invokePattern.exec(response)) !== null) {\n const toolName = match[1];\n const paramContent = match[2];\n const startIndex = match.index;\n\n const args: Record<string, unknown> = {};\n\n // Parse <parameter name=\"...\">value</parameter> children\n const paramPattern = /<parameter\\s+name=[\"']([^\"']+)[\"']>([^<]*)<\\/parameter>/gi;\n let paramMatch;\n while ((paramMatch = paramPattern.exec(paramContent)) !== null) {\n args[paramMatch[1]] = paramMatch[2].trim();\n }\n\n results.push({\n toolName: normalizeToolName(toolName),\n arguments: args,\n fullMatch: match[0],\n startIndex,\n endIndex: startIndex + match[0].length,\n format: 'invoke',\n });\n }\n\n return results;\n}\n\n// ============================================================================\n// Composite utilities for plugins\n// ============================================================================\n\n/**\n * Parse all known XML tool call formats from response text.\n * Deduplicates by position and sorts by start index.\n *\n * Plugins can call this directly or compose individual format parsers\n * for provider-specific behavior.\n */\nexport function parseAllXMLFormats(response: string): ParsedTextTool[] {\n const allResults: ParsedTextTool[] = [];\n\n allResults.push(...parseFunctionCallsFormat(response));\n allResults.push(...parseToolCallFormat(response));\n allResults.push(...parseFunctionCallFormat(response));\n allResults.push(...parseToolUseFormat(response));\n // Bare <invoke> MUST be last — wrapped invokes inside <function_calls> are\n // already claimed above and will be deduplicated by startIndex.\n allResults.push(...parseInvokeFormat(response));\n\n // Deduplicate by startIndex\n const seen = new Set<number>();\n const deduped = allResults.filter(result => {\n if (seen.has(result.startIndex)) {\n return false;\n }\n seen.add(result.startIndex);\n return true;\n });\n\n deduped.sort((a, b) => a.startIndex - b.startIndex);\n return deduped;\n}\n\n/**\n * Convert parsed text tools to standard ToolCallRequest array.\n * Convenience wrapper for plugins implementing parseTextToolCalls.\n */\nexport function parseAllXMLAsToolCalls(response: string): ToolCallRequest[] {\n return parseAllXMLFormats(response).map(convertToToolCallRequest);\n}\n\n/**\n * Check if text contains any of the known XML tool call patterns.\n * Quick regex check before full parsing.\n */\nexport function hasAnyXMLToolMarkers(response: string): boolean {\n return (\n /<function_calls>/i.test(response) ||\n /<tool_call>/i.test(response) ||\n /<function_call\\s+/i.test(response) ||\n /<tool_use[\\s>]/i.test(response) ||\n /<invoke\\s+name=/i.test(response)\n );\n}\n\n// Individual marker checks for plugins that only care about specific formats\n\n/** Check for `<function_calls>` markers (DeepSeek/Claude-style) */\nexport function hasFunctionCallsMarkers(response: string): boolean {\n return /<function_calls>/i.test(response);\n}\n\n/** Check for `<tool_call>` markers (generic) */\nexport function hasToolCallMarkers(response: string): boolean {\n return /<tool_call>/i.test(response);\n}\n\n/** Check for `<function_call>` markers */\nexport function hasFunctionCallMarkers(response: string): boolean {\n return /<function_call\\s+/i.test(response);\n}\n\n/** Check for `<tool_use>` markers (Gemini-style) */\nexport function hasToolUseMarkers(response: string): boolean {\n return /<tool_use[\\s>]/i.test(response);\n}\n\n/** Check for bare `<invoke name=\"...\">` markers (Kimi K2-style) */\nexport function hasInvokeMarkers(response: string): boolean {\n return /<invoke\\s+name=/i.test(response);\n}\n\n/**\n * Strip all known XML tool call markers from text.\n * Cleans up whitespace left behind.\n */\nexport function stripAllXMLToolMarkers(response: string): string {\n let stripped = response;\n\n // <function_calls> MUST be stripped first — it contains <invoke> tags that\n // would otherwise be matched by the bare <invoke> stripper below, leaving\n // empty <function_calls></function_calls> wrappers behind.\n stripped = stripped.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n stripped = stripped.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n stripped = stripped.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n stripped = stripped.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n // Bare <invoke> last — only catches unwrapped invoke tags (Kimi K2-style)\n stripped = stripped.replace(/<invoke\\s+name=[\"'][^\"']*[\"']>[\\s\\S]*?<\\/invoke>/gi, '');\n\n stripped = stripped\n .replace(/\\n{3,}/g, '\\n\\n')\n .replace(/ +/g, ' ')\n .trim();\n\n return stripped;\n}\n\n// Individual strippers for plugins that only handle specific formats\n\n/** Strip `<function_calls>` blocks */\nexport function stripFunctionCallsMarkers(response: string): string {\n return response.replace(/<function_calls>[\\s\\S]*?<\\/function_calls>/gi, '');\n}\n\n/** Strip `<tool_call>` blocks */\nexport function stripToolCallMarkers(response: string): string {\n return response.replace(/<tool_call>[\\s\\S]*?<\\/tool_call>/gi, '');\n}\n\n/** Strip `<function_call>` blocks */\nexport function stripFunctionCallMarkers(response: string): string {\n return response.replace(/<function_call\\s+[^>]*>[\\s\\S]*?<\\/function_call>/gi, '');\n}\n\n/** Strip `<tool_use>` blocks */\nexport function stripToolUseMarkers(response: string): string {\n return response.replace(/<tool_use[\\s>][\\s\\S]*?<\\/tool_use>/gi, '');\n}\n\n/** Strip bare `<invoke>` blocks (Kimi K2-style) */\nexport function stripInvokeMarkers(response: string): string {\n return response.replace(/<invoke\\s+name=[\"'][^\"']*[\"']>[\\s\\S]*?<\\/invoke>/gi, '');\n}\n"],"mappings":"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","names":["args"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quilltap/plugin-utils",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Utility functions for Quilltap plugin development",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -63,9 +63,9 @@
63
63
  }
64
64
  },
65
65
  "devDependencies": {
66
- "openai": "^6.22.0",
67
- "tsup": "^8.0.0",
68
- "typescript": "^5.3.0"
66
+ "openai": "^6.32.0",
67
+ "tsup": "^8.5.1",
68
+ "typescript": "^5.9.3"
69
69
  },
70
70
  "keywords": [
71
71
  "quilltap",