cmdr-agent 2.4.0 → 2.5.0

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.
Files changed (65) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/cli/progress.d.ts +58 -0
  3. package/dist/src/cli/progress.d.ts.map +1 -0
  4. package/dist/src/cli/progress.js +179 -0
  5. package/dist/src/cli/progress.js.map +1 -0
  6. package/dist/src/cli/spinner.d.ts +2 -0
  7. package/dist/src/cli/spinner.d.ts.map +1 -1
  8. package/dist/src/cli/spinner.js +18 -0
  9. package/dist/src/cli/spinner.js.map +1 -1
  10. package/dist/src/core/agent-runner.d.ts +12 -0
  11. package/dist/src/core/agent-runner.d.ts.map +1 -1
  12. package/dist/src/core/agent-runner.js +176 -5
  13. package/dist/src/core/agent-runner.js.map +1 -1
  14. package/dist/src/core/event-bus.d.ts +12 -0
  15. package/dist/src/core/event-bus.d.ts.map +1 -1
  16. package/dist/src/core/event-bus.js.map +1 -1
  17. package/dist/src/core/types.d.ts +17 -0
  18. package/dist/src/core/types.d.ts.map +1 -1
  19. package/dist/src/core/types.js +8 -1
  20. package/dist/src/core/types.js.map +1 -1
  21. package/dist/src/llm/anthropic.d.ts +1 -0
  22. package/dist/src/llm/anthropic.d.ts.map +1 -1
  23. package/dist/src/llm/anthropic.js +20 -1
  24. package/dist/src/llm/anthropic.js.map +1 -1
  25. package/dist/src/llm/ollama.d.ts +2 -12
  26. package/dist/src/llm/ollama.d.ts.map +1 -1
  27. package/dist/src/llm/ollama.js +46 -250
  28. package/dist/src/llm/ollama.js.map +1 -1
  29. package/dist/src/llm/openai.d.ts +1 -0
  30. package/dist/src/llm/openai.d.ts.map +1 -1
  31. package/dist/src/llm/openai.js +21 -7
  32. package/dist/src/llm/openai.js.map +1 -1
  33. package/dist/src/llm/repair/retry-policy.d.ts +48 -0
  34. package/dist/src/llm/repair/retry-policy.d.ts.map +1 -0
  35. package/dist/src/llm/repair/retry-policy.js +85 -0
  36. package/dist/src/llm/repair/retry-policy.js.map +1 -0
  37. package/dist/src/llm/repair/tool-repair.d.ts +39 -0
  38. package/dist/src/llm/repair/tool-repair.d.ts.map +1 -0
  39. package/dist/src/llm/repair/tool-repair.js +313 -0
  40. package/dist/src/llm/repair/tool-repair.js.map +1 -0
  41. package/dist/src/llm/shared/text-cleanup.d.ts +16 -0
  42. package/dist/src/llm/shared/text-cleanup.d.ts.map +1 -0
  43. package/dist/src/llm/shared/text-cleanup.js +120 -0
  44. package/dist/src/llm/shared/text-cleanup.js.map +1 -0
  45. package/dist/src/llm/shared/tool-parsing.d.ts +70 -0
  46. package/dist/src/llm/shared/tool-parsing.d.ts.map +1 -0
  47. package/dist/src/llm/shared/tool-parsing.js +355 -0
  48. package/dist/src/llm/shared/tool-parsing.js.map +1 -0
  49. package/dist/src/llm/validation/tool-call-schema.d.ts +83 -0
  50. package/dist/src/llm/validation/tool-call-schema.d.ts.map +1 -0
  51. package/dist/src/llm/validation/tool-call-schema.js +145 -0
  52. package/dist/src/llm/validation/tool-call-schema.js.map +1 -0
  53. package/dist/src/tools/built-in/bash.d.ts +5 -1
  54. package/dist/src/tools/built-in/bash.d.ts.map +1 -1
  55. package/dist/src/tools/built-in/bash.js +34 -46
  56. package/dist/src/tools/built-in/bash.js.map +1 -1
  57. package/dist/src/tools/executor.d.ts +7 -1
  58. package/dist/src/tools/executor.d.ts.map +1 -1
  59. package/dist/src/tools/executor.js +20 -5
  60. package/dist/src/tools/executor.js.map +1 -1
  61. package/dist/src/tools/shell/shell-executor.d.ts +71 -0
  62. package/dist/src/tools/shell/shell-executor.d.ts.map +1 -0
  63. package/dist/src/tools/shell/shell-executor.js +238 -0
  64. package/dist/src/tools/shell/shell-executor.js.map +1 -0
  65. package/package.json +1 -1
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Retry policy — configures when and how to retry failed tool calls.
3
+ *
4
+ * Produces correction messages that tell the model exactly what went wrong
5
+ * and how to fix it, enabling the repair-retry loop in agent-runner.
6
+ */
7
+ import { buildLeakageCorrectionPrompt } from '../validation/tool-call-schema.js';
8
+ /** Default retry policy for unknown/reliable models. */
9
+ export const DEFAULT_RETRY_POLICY = {
10
+ maxRetries: 0,
11
+ attemptRepair: false,
12
+ correctionStyle: 'gentle',
13
+ };
14
+ /** Retry policy for models known to produce messy tool calls (Kimi, MiniMax, etc.). */
15
+ export const STRICT_RETRY_POLICY = {
16
+ maxRetries: 2,
17
+ attemptRepair: true,
18
+ correctionStyle: 'strict',
19
+ };
20
+ /** Retry policy for moderately reliable models. */
21
+ export const MODERATE_RETRY_POLICY = {
22
+ maxRetries: 1,
23
+ attemptRepair: true,
24
+ correctionStyle: 'gentle',
25
+ };
26
+ /**
27
+ * Determine whether to retry after a tool call failure.
28
+ */
29
+ export function shouldRetry(attempt, policy, errorType) {
30
+ if (attempt >= policy.maxRetries) {
31
+ return { shouldRetry: false, reason: `Max retries (${policy.maxRetries}) exhausted` };
32
+ }
33
+ // Always retry leakage — model is trying to use tools but in the wrong format
34
+ if (errorType === 'leakage') {
35
+ return { shouldRetry: true, reason: 'Tool call leaked into text output' };
36
+ }
37
+ // Retry validation errors if policy allows
38
+ if (errorType === 'validation' && policy.maxRetries > 0) {
39
+ return { shouldRetry: true, reason: 'Tool call failed validation' };
40
+ }
41
+ // Retry unknown tools if policy allows (model may have misspelled)
42
+ if (errorType === 'unknown_tool' && policy.maxRetries > 0) {
43
+ return { shouldRetry: true, reason: 'Unknown tool name — may be misspelled' };
44
+ }
45
+ return { shouldRetry: false, reason: 'No retry policy for this error type' };
46
+ }
47
+ /**
48
+ * Build correction messages to inject into the conversation before retrying.
49
+ * These tell the model exactly what went wrong and how to fix it.
50
+ */
51
+ export function buildCorrectionMessages(ctx, policy) {
52
+ const messages = [];
53
+ if (ctx.isLeakage) {
54
+ // Leakage: model outputted tool format in text instead of proper API
55
+ messages.push({
56
+ role: 'user',
57
+ content: [{ type: 'text', text: buildLeakageCorrectionPrompt() }],
58
+ isMeta: true,
59
+ });
60
+ return messages;
61
+ }
62
+ // Build error summary
63
+ const errorLines = ctx.errors.map(e => `- Tool "${e.name}": ${e.error}`).join('\n');
64
+ const toolList = ctx.availableTools.join(', ');
65
+ const gentle = [
66
+ `Your previous tool call(s) had issues:\n${errorLines}`,
67
+ `Available tools: ${toolList}`,
68
+ 'Please retry with corrected tool calls.',
69
+ ].join('\n\n');
70
+ const strict = [
71
+ `ERROR: Your tool call(s) failed validation. This is attempt ${ctx.attempt + 1}.`,
72
+ `Issues:\n${errorLines}`,
73
+ `You MUST use one of these exact tool names: ${toolList}`,
74
+ 'Respond with ONLY a valid tool call. Do not include explanatory text.',
75
+ 'Use the exact argument types specified in the tool schema.',
76
+ ].join('\n\n');
77
+ const text = policy.correctionStyle === 'strict' ? strict : gentle;
78
+ messages.push({
79
+ role: 'user',
80
+ content: [{ type: 'text', text }],
81
+ isMeta: true,
82
+ });
83
+ return messages;
84
+ }
85
+ //# sourceMappingURL=retry-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-policy.js","sourceRoot":"","sources":["../../../../src/llm/repair/retry-policy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAA;AAehF,wDAAwD;AACxD,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAC/C,UAAU,EAAE,CAAC;IACb,aAAa,EAAE,KAAK;IACpB,eAAe,EAAE,QAAQ;CAC1B,CAAA;AAED,uFAAuF;AACvF,MAAM,CAAC,MAAM,mBAAmB,GAAgB;IAC9C,UAAU,EAAE,CAAC;IACb,aAAa,EAAE,IAAI;IACnB,eAAe,EAAE,QAAQ;CAC1B,CAAA;AAED,mDAAmD;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAgB;IAChD,UAAU,EAAE,CAAC;IACb,aAAa,EAAE,IAAI;IACnB,eAAe,EAAE,QAAQ;CAC1B,CAAA;AAWD;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,OAAe,EACf,MAAmB,EACnB,SAAoD;IAEpD,IAAI,OAAO,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACjC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,MAAM,CAAC,UAAU,aAAa,EAAE,CAAA;IACvF,CAAC;IAED,8EAA8E;IAC9E,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,mCAAmC,EAAE,CAAA;IAC3E,CAAC;IAED,2CAA2C;IAC3C,IAAI,SAAS,KAAK,YAAY,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QACxD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAA;IACrE,CAAC;IAED,mEAAmE;IACnE,IAAI,SAAS,KAAK,cAAc,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,uCAAuC,EAAE,CAAA;IAC/E,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,qCAAqC,EAAE,CAAA;AAC9E,CAAC;AAiBD;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAAsB,EACtB,MAAmB;IAEnB,MAAM,QAAQ,GAAiB,EAAE,CAAA;IAEjC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAClB,qEAAqE;QACrE,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,EAAE,EAAe,CAAC;YAC9E,MAAM,EAAE,IAAI;SACb,CAAC,CAAA;QACF,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,sBAAsB;IACtB,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnF,MAAM,QAAQ,GAAG,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAE9C,MAAM,MAAM,GAAG;QACb,2CAA2C,UAAU,EAAE;QACvD,oBAAoB,QAAQ,EAAE;QAC9B,yCAAyC;KAC1C,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAEd,MAAM,MAAM,GAAG;QACb,+DAA+D,GAAG,CAAC,OAAO,GAAG,CAAC,GAAG;QACjF,YAAY,UAAU,EAAE;QACxB,+CAA+C,QAAQ,EAAE;QACzD,uEAAuE;QACvE,4DAA4D;KAC7D,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAEd,MAAM,IAAI,GAAG,MAAM,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;IAElE,QAAQ,CAAC,IAAI,CAAC;QACZ,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAe,CAAC;QAC9C,MAAM,EAAE,IAAI;KACb,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Tool repair module — attempts to fix malformed tool calls before giving up.
3
+ *
4
+ * Strategies (applied in order):
5
+ * A. Strip surrounding text, re-extract JSON
6
+ * B. Fix common JSON issues (trailing commas, unquoted keys, partial brackets)
7
+ * C. Fuzzy-match partial tool names to closest registered tool
8
+ * D. Coerce argument types ("true" → true, "42" → 42) per Zod schema
9
+ *
10
+ * If any strategy produces a valid tool call, it's returned immediately.
11
+ * If none succeed, null is returned → caller should retry or give up.
12
+ */
13
+ import type { ZodSchema } from 'zod';
14
+ import { type ParsedToolCall } from '../validation/tool-call-schema.js';
15
+ export interface RepairContext {
16
+ /** Names of all registered tools. */
17
+ readonly availableTools: readonly string[];
18
+ /** Registered Zod input schemas, keyed by tool name. */
19
+ readonly toolSchemas: ReadonlyMap<string, ZodSchema>;
20
+ }
21
+ export interface RepairResult {
22
+ readonly repaired: ParsedToolCall[];
23
+ /** Human-readable description of what was fixed. */
24
+ readonly fixes: string[];
25
+ }
26
+ /**
27
+ * Attempt to repair a set of rejected tool calls.
28
+ *
29
+ * @param rawText The full LLM output text that contained the failed tool calls.
30
+ * @param rejected The tool calls that failed validation, with error details.
31
+ * @param context Available tool names and schemas for fuzzy matching + type coercion.
32
+ * @returns Repaired tool calls, or null if repair failed entirely.
33
+ */
34
+ export declare function attemptRepair(rawText: string, rejected: Array<{
35
+ name: string;
36
+ arguments: Record<string, unknown>;
37
+ error: string;
38
+ }>, context: RepairContext): RepairResult | null;
39
+ //# sourceMappingURL=tool-repair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-repair.d.ts","sourceRoot":"","sources":["../../../../src/llm/repair/tool-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAyB,MAAM,KAAK,CAAA;AAC3D,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAM9F,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,wDAAwD;IACxD,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CACrD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAA;IACnC,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EACpF,OAAO,EAAE,aAAa,GACrB,YAAY,GAAG,IAAI,CAuDrB"}
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Tool repair module — attempts to fix malformed tool calls before giving up.
3
+ *
4
+ * Strategies (applied in order):
5
+ * A. Strip surrounding text, re-extract JSON
6
+ * B. Fix common JSON issues (trailing commas, unquoted keys, partial brackets)
7
+ * C. Fuzzy-match partial tool names to closest registered tool
8
+ * D. Coerce argument types ("true" → true, "42" → 42) per Zod schema
9
+ *
10
+ * If any strategy produces a valid tool call, it's returned immediately.
11
+ * If none succeed, null is returned → caller should retry or give up.
12
+ */
13
+ import { validateToolCallShape } from '../validation/tool-call-schema.js';
14
+ /**
15
+ * Attempt to repair a set of rejected tool calls.
16
+ *
17
+ * @param rawText The full LLM output text that contained the failed tool calls.
18
+ * @param rejected The tool calls that failed validation, with error details.
19
+ * @param context Available tool names and schemas for fuzzy matching + type coercion.
20
+ * @returns Repaired tool calls, or null if repair failed entirely.
21
+ */
22
+ export function attemptRepair(rawText, rejected, context) {
23
+ const repaired = [];
24
+ const fixes = [];
25
+ for (const call of rejected) {
26
+ // Strategy C: Fuzzy-match tool name
27
+ let toolName = call.name;
28
+ const nameFixed = fuzzyMatchToolName(toolName, context.availableTools);
29
+ if (nameFixed && nameFixed !== toolName) {
30
+ fixes.push(`Fixed tool name: "${toolName}" → "${nameFixed}"`);
31
+ toolName = nameFixed;
32
+ }
33
+ // Strategy D: Type coercion per Zod schema
34
+ let args = { ...call.arguments };
35
+ const schema = context.toolSchemas.get(toolName);
36
+ if (schema) {
37
+ const coerced = coerceArgumentTypes(args, schema);
38
+ if (coerced.fixed) {
39
+ args = coerced.args;
40
+ fixes.push(...coerced.fixes);
41
+ }
42
+ }
43
+ // Validate after fixes
44
+ const validation = validateToolCallShape({ name: toolName, arguments: args });
45
+ if (validation.ok) {
46
+ // Double-check input schema if available
47
+ if (schema) {
48
+ const result = schema.safeParse(args);
49
+ if (result.success) {
50
+ repaired.push({ name: toolName, arguments: result.data });
51
+ continue;
52
+ }
53
+ }
54
+ else {
55
+ repaired.push(validation.toolCall);
56
+ continue;
57
+ }
58
+ }
59
+ }
60
+ // Strategy A+B: Re-extract from raw text if per-call repair failed
61
+ if (repaired.length < rejected.length && rawText) {
62
+ const extracted = extractFromRawText(rawText, context);
63
+ if (extracted.length > 0) {
64
+ fixes.push(`Re-extracted ${extracted.length} tool call(s) from raw output`);
65
+ for (const tc of extracted) {
66
+ if (!repaired.some(r => r.name === tc.name)) {
67
+ repaired.push(tc);
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return repaired.length > 0 ? { repaired, fixes } : null;
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Strategy A: Re-extract JSON from raw text
76
+ // ---------------------------------------------------------------------------
77
+ function extractFromRawText(text, context) {
78
+ const results = [];
79
+ // Strip markdown code fences and try to find JSON objects
80
+ const stripped = text
81
+ .replace(/```(?:json|tool_call)?\s*\n?/g, '')
82
+ .replace(/```/g, '');
83
+ // Find all JSON-like objects in the text
84
+ const jsonRegex = /\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/g;
85
+ let match;
86
+ while ((match = jsonRegex.exec(stripped)) !== null) {
87
+ const candidate = match[0];
88
+ const parsed = tryParseAndRepairJson(candidate);
89
+ if (parsed && parsed.name && typeof parsed.name === 'string') {
90
+ const args = (parsed.arguments ?? parsed.args ?? parsed.params ?? parsed.input ?? {});
91
+ const toolName = fuzzyMatchToolName(parsed.name, context.availableTools) ?? parsed.name;
92
+ const validation = validateToolCallShape({ name: toolName, arguments: args });
93
+ if (validation.ok) {
94
+ results.push(validation.toolCall);
95
+ }
96
+ }
97
+ }
98
+ return results;
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // Strategy B: Fix common JSON issues
102
+ // ---------------------------------------------------------------------------
103
+ function tryParseAndRepairJson(text) {
104
+ // Try direct parse first
105
+ try {
106
+ const parsed = JSON.parse(text);
107
+ if (typeof parsed === 'object' && parsed !== null)
108
+ return parsed;
109
+ }
110
+ catch {
111
+ // Fall through to repairs
112
+ }
113
+ let repaired = text;
114
+ // Fix trailing commas: { "a": 1, }
115
+ repaired = repaired.replace(/,\s*([}\]])/g, '$1');
116
+ // Fix unquoted keys: { name: "value" } → { "name": "value" }
117
+ repaired = repaired.replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":');
118
+ // Fix single-quoted strings: { 'name': 'value' } → { "name": "value" }
119
+ repaired = repaired.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
120
+ // Fix missing closing bracket
121
+ const openBraces = (repaired.match(/\{/g) || []).length;
122
+ const closeBraces = (repaired.match(/\}/g) || []).length;
123
+ if (openBraces > closeBraces) {
124
+ repaired += '}'.repeat(openBraces - closeBraces);
125
+ }
126
+ // Fix missing closing square bracket in arrays
127
+ const openBrackets = (repaired.match(/\[/g) || []).length;
128
+ const closeBrackets = (repaired.match(/\]/g) || []).length;
129
+ if (openBrackets > closeBrackets) {
130
+ // Insert before last }
131
+ const lastBrace = repaired.lastIndexOf('}');
132
+ if (lastBrace > 0) {
133
+ repaired = repaired.slice(0, lastBrace) + ']'.repeat(openBrackets - closeBrackets) + repaired.slice(lastBrace);
134
+ }
135
+ }
136
+ try {
137
+ const parsed = JSON.parse(repaired);
138
+ if (typeof parsed === 'object' && parsed !== null)
139
+ return parsed;
140
+ }
141
+ catch {
142
+ // Could not repair
143
+ }
144
+ return null;
145
+ }
146
+ // ---------------------------------------------------------------------------
147
+ // Strategy C: Fuzzy tool name matching
148
+ // ---------------------------------------------------------------------------
149
+ /**
150
+ * Find the closest registered tool name for a possibly misspelled/partial name.
151
+ * Uses: exact match → case-insensitive → prefix match → Levenshtein distance.
152
+ */
153
+ function fuzzyMatchToolName(name, available) {
154
+ if (!name || available.length === 0)
155
+ return null;
156
+ // Exact match
157
+ if (available.includes(name))
158
+ return name;
159
+ // Case-insensitive match
160
+ const lower = name.toLowerCase();
161
+ const ciMatch = available.find(t => t.toLowerCase() === lower);
162
+ if (ciMatch)
163
+ return ciMatch;
164
+ // Prefix match (e.g., "file_wr" → "file_write")
165
+ const prefixMatches = available.filter(t => t.toLowerCase().startsWith(lower));
166
+ if (prefixMatches.length === 1)
167
+ return prefixMatches[0];
168
+ // Contains match (e.g., "write" → "file_write")
169
+ const containsMatches = available.filter(t => t.toLowerCase().includes(lower));
170
+ if (containsMatches.length === 1)
171
+ return containsMatches[0];
172
+ // Levenshtein distance (max distance 3 to avoid wild matches)
173
+ let bestMatch = null;
174
+ let bestDist = 4;
175
+ for (const tool of available) {
176
+ const dist = levenshtein(lower, tool.toLowerCase());
177
+ if (dist < bestDist) {
178
+ bestDist = dist;
179
+ bestMatch = tool;
180
+ }
181
+ }
182
+ return bestMatch;
183
+ }
184
+ function levenshtein(a, b) {
185
+ const m = a.length;
186
+ const n = b.length;
187
+ // Use single-row optimization for memory efficiency
188
+ const row = Array.from({ length: n + 1 }, (_, i) => i);
189
+ for (let i = 1; i <= m; i++) {
190
+ let prev = i - 1;
191
+ row[0] = i;
192
+ for (let j = 1; j <= n; j++) {
193
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
194
+ const val = Math.min(row[j] + 1, // deletion
195
+ row[j - 1] + 1, // insertion
196
+ prev + cost);
197
+ prev = row[j];
198
+ row[j] = val;
199
+ }
200
+ }
201
+ return row[n];
202
+ }
203
+ /**
204
+ * Coerce argument types to match the tool's Zod schema.
205
+ * Handles: string "true" → boolean, "42" → number, "null" → null.
206
+ */
207
+ function coerceArgumentTypes(args, schema) {
208
+ const result = { ...args };
209
+ const fixes = [];
210
+ let fixed = false;
211
+ // Extract shape from ZodObject if possible
212
+ const shape = getZodObjectShape(schema);
213
+ if (!shape)
214
+ return { args, fixed: false, fixes };
215
+ for (const [key, value] of Object.entries(args)) {
216
+ const fieldSchema = shape[key];
217
+ if (!fieldSchema)
218
+ continue;
219
+ const expectedType = getZodBaseType(fieldSchema);
220
+ if (!expectedType)
221
+ continue;
222
+ // String → boolean coercion
223
+ if (expectedType === 'boolean' && typeof value === 'string') {
224
+ const lower = value.toLowerCase();
225
+ if (lower === 'true' || lower === 'yes' || lower === '1') {
226
+ result[key] = true;
227
+ fixes.push(`Coerced "${key}": "${value}" → true`);
228
+ fixed = true;
229
+ }
230
+ else if (lower === 'false' || lower === 'no' || lower === '0') {
231
+ result[key] = false;
232
+ fixes.push(`Coerced "${key}": "${value}" → false`);
233
+ fixed = true;
234
+ }
235
+ }
236
+ // String → number coercion
237
+ if (expectedType === 'number' && typeof value === 'string') {
238
+ const num = Number(value);
239
+ if (!isNaN(num) && value.trim() !== '') {
240
+ result[key] = num;
241
+ fixes.push(`Coerced "${key}": "${value}" → ${num}`);
242
+ fixed = true;
243
+ }
244
+ }
245
+ // String → null coercion
246
+ if (expectedType === 'null' && typeof value === 'string') {
247
+ if (value.toLowerCase() === 'null' || value === '') {
248
+ result[key] = null;
249
+ fixes.push(`Coerced "${key}": "${value}" → null`);
250
+ fixed = true;
251
+ }
252
+ }
253
+ // Array string → array coercion (e.g. "[1,2,3]" → [1,2,3])
254
+ if (expectedType === 'array' && typeof value === 'string') {
255
+ try {
256
+ const parsed = JSON.parse(value);
257
+ if (Array.isArray(parsed)) {
258
+ result[key] = parsed;
259
+ fixes.push(`Coerced "${key}": string → array`);
260
+ fixed = true;
261
+ }
262
+ }
263
+ catch {
264
+ // Not valid JSON array
265
+ }
266
+ }
267
+ }
268
+ return { args: result, fixed, fixes };
269
+ }
270
+ // ---------------------------------------------------------------------------
271
+ // Zod introspection helpers
272
+ // ---------------------------------------------------------------------------
273
+ function getZodObjectShape(schema) {
274
+ try {
275
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
276
+ const def = schema?._def;
277
+ if (def?.typeName === 'ZodObject') {
278
+ return def.shape();
279
+ }
280
+ // Handle ZodEffects wrapping (e.g., .transform(), .refine())
281
+ if (def?.typeName === 'ZodEffects' && def?.schema) {
282
+ return getZodObjectShape(def.schema);
283
+ }
284
+ }
285
+ catch {
286
+ // Schema introspection failed
287
+ }
288
+ return null;
289
+ }
290
+ function getZodBaseType(schema) {
291
+ try {
292
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
293
+ const def = schema?._def;
294
+ const typeName = def?.typeName;
295
+ if (!typeName)
296
+ return null;
297
+ switch (typeName) {
298
+ case 'ZodString': return 'string';
299
+ case 'ZodNumber': return 'number';
300
+ case 'ZodBoolean': return 'boolean';
301
+ case 'ZodNull': return 'null';
302
+ case 'ZodArray': return 'array';
303
+ case 'ZodOptional': return getZodBaseType(def.innerType);
304
+ case 'ZodDefault': return getZodBaseType(def.innerType);
305
+ case 'ZodNullable': return getZodBaseType(def.innerType);
306
+ default: return null;
307
+ }
308
+ }
309
+ catch {
310
+ return null;
311
+ }
312
+ }
313
+ //# sourceMappingURL=tool-repair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-repair.js","sourceRoot":"","sources":["../../../../src/llm/repair/tool-repair.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Pre-parse text cleanup — sanitizes raw LLM output before tool call parsing.
3
+ *
4
+ * Fixes common model artifacts that break JSON/XML parsing:
5
+ * - Markdown code fence wrappers around JSON
6
+ * - Thinking/reasoning tags (<think>, <thought>, etc.)
7
+ * - Control characters
8
+ * - Repeated newlines in JSON
9
+ * - Incomplete/truncated brackets
10
+ */
11
+ /**
12
+ * Clean raw LLM output text before passing it to tool call parsers.
13
+ * This is a pure function that returns sanitized text — idempotent and safe.
14
+ */
15
+ export declare function cleanLLMOutput(text: string): string;
16
+ //# sourceMappingURL=text-cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-cleanup.d.ts","sourceRoot":"","sources":["../../../../src/llm/shared/text-cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmBnD"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Pre-parse text cleanup — sanitizes raw LLM output before tool call parsing.
3
+ *
4
+ * Fixes common model artifacts that break JSON/XML parsing:
5
+ * - Markdown code fence wrappers around JSON
6
+ * - Thinking/reasoning tags (<think>, <thought>, etc.)
7
+ * - Control characters
8
+ * - Repeated newlines in JSON
9
+ * - Incomplete/truncated brackets
10
+ */
11
+ // ---------------------------------------------------------------------------
12
+ // Main cleanup function
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Clean raw LLM output text before passing it to tool call parsers.
16
+ * This is a pure function that returns sanitized text — idempotent and safe.
17
+ */
18
+ export function cleanLLMOutput(text) {
19
+ if (!text)
20
+ return text;
21
+ let cleaned = text;
22
+ // 1. Strip thinking/reasoning tags and their content
23
+ cleaned = stripThinkingTags(cleaned);
24
+ // 2. Strip control characters (except newline, tab, carriage return)
25
+ cleaned = stripControlChars(cleaned);
26
+ // 3. Unwrap bare markdown JSON fences that wrap the entire response
27
+ // (but NOT tool_call fences — those are handled by the parser)
28
+ cleaned = unwrapBareJsonFences(cleaned);
29
+ // 4. Collapse excessive whitespace inside JSON-like structures
30
+ cleaned = collapseJsonWhitespace(cleaned);
31
+ return cleaned;
32
+ }
33
+ // ---------------------------------------------------------------------------
34
+ // Individual cleanup strategies
35
+ // ---------------------------------------------------------------------------
36
+ /**
37
+ * Strip thinking/reasoning tags and their content.
38
+ * Models like Qwen3, DeepSeek emit <think>...</think> blocks.
39
+ */
40
+ function stripThinkingTags(text) {
41
+ // <think>...</think>
42
+ let cleaned = text.replace(/<think>[\s\S]*?<\/think>/gi, '');
43
+ // <thought>...</thought>
44
+ cleaned = cleaned.replace(/<thought>[\s\S]*?<\/thought>/gi, '');
45
+ // <reasoning>...</reasoning>
46
+ cleaned = cleaned.replace(/<reasoning>[\s\S]*?<\/reasoning>/gi, '');
47
+ // <reflection>...</reflection>
48
+ cleaned = cleaned.replace(/<reflection>[\s\S]*?<\/reflection>/gi, '');
49
+ // Ollama-specific thinking channel markers
50
+ cleaned = cleaned.replace(/<\|channel>thought[\s\S]*?<channel\|>/g, '');
51
+ cleaned = cleaned.replace(/<channel\|>/g, '');
52
+ return cleaned.trim();
53
+ }
54
+ /**
55
+ * Strip control characters that break JSON parsing.
56
+ * Preserves: \n (0x0A), \r (0x0D), \t (0x09)
57
+ */
58
+ function stripControlChars(text) {
59
+ // eslint-disable-next-line no-control-regex
60
+ return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
61
+ }
62
+ /**
63
+ * Unwrap bare JSON code fences that wrap the entire response.
64
+ *
65
+ * Some models wrap their entire tool call in ```json ... ``` instead of
66
+ * using the proper ```tool_call format. We unwrap these to expose the
67
+ * raw JSON for the parser.
68
+ *
69
+ * Does NOT unwrap ```tool_call fences — those are handled by the parser.
70
+ */
71
+ function unwrapBareJsonFences(text) {
72
+ const trimmed = text.trim();
73
+ // Check if the entire response is a single ```json fence
74
+ const jsonFenceMatch = trimmed.match(/^```(?:json)?\s*\n([\s\S]*?)\n```\s*$/);
75
+ if (jsonFenceMatch) {
76
+ const inner = jsonFenceMatch[1].trim();
77
+ // Only unwrap if the inner content looks like a tool call JSON
78
+ if (isToolCallLike(inner)) {
79
+ // Re-wrap as ```tool_call so the parser picks it up
80
+ return '```tool_call\n' + inner + '\n```';
81
+ }
82
+ }
83
+ return text;
84
+ }
85
+ /**
86
+ * Collapse excessive whitespace inside JSON structures.
87
+ * Some models emit JSON with many blank lines between keys.
88
+ */
89
+ function collapseJsonWhitespace(text) {
90
+ // Only apply inside ```tool_call blocks to avoid mangling prose
91
+ return text.replace(/```tool_call\s*\n([\s\S]*?)\n```/g, (_match, inner) => {
92
+ const collapsed = inner
93
+ .split('\n')
94
+ .map((line) => line.trimEnd())
95
+ .filter((line, i, arr) => {
96
+ // Remove blank lines between JSON lines, but keep at least one
97
+ if (line === '' && i > 0 && arr[i - 1] === '')
98
+ return false;
99
+ return true;
100
+ })
101
+ .join('\n');
102
+ return '```tool_call\n' + collapsed + '\n```';
103
+ });
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Helpers
107
+ // ---------------------------------------------------------------------------
108
+ /**
109
+ * Heuristic: does this text look like a tool call JSON object?
110
+ */
111
+ function isToolCallLike(text) {
112
+ const trimmed = text.trim();
113
+ if (!trimmed.startsWith('{'))
114
+ return false;
115
+ // Check for tool call shape indicators
116
+ return ((trimmed.includes('"name"') && trimmed.includes('"arguments"')) ||
117
+ (trimmed.includes('"name"') && trimmed.includes('"args"')) ||
118
+ (trimmed.includes('"function"') && trimmed.includes('"arguments"')));
119
+ }
120
+ //# sourceMappingURL=text-cleanup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-cleanup.js","sourceRoot":"","sources":["../../../../src/llm/shared/text-cleanup.ts"],"names":[],"mappings":"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"}