UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

77 lines (76 loc) • 2.35 kB
import { mintFallbackToolCallId } from "./tool-call-id.js"; const TAG_RE = /<(tool_call|function_call|tool_calls|function_calls)>\s*([\s\S]*?)\s*<\/\1>/gi; const FENCE_RE = /```(?:json|tool_call|tool|function)?\s*([\s\S]*?)```/gi; function asRecord(v) { return v && typeof v === "object" && !Array.isArray(v) ? v : undefined; } function extractCall(obj, toolNames, framed) { const rec = asRecord(obj); if (!rec) { return undefined; } const fn = asRecord(rec.function); const name = rec.name ?? rec.tool ?? rec.tool_name ?? fn?.name; if (typeof name !== "string" || !toolNames.has(name)) { return undefined; } const rawArgs = rec.arguments ?? rec.parameters ?? rec.input ?? rec.args ?? fn?.arguments; let args; if (rawArgs === undefined) { if (!framed) return undefined; args = {}; } else if (typeof rawArgs === "string") { let parsed; try { parsed = JSON.parse(rawArgs); } catch { return undefined; } const rec2 = asRecord(parsed); if (!rec2) return undefined; args = rec2; } else { const rec2 = asRecord(rawArgs); if (!rec2) return undefined; args = rec2; } return { type: "toolCall", id: mintFallbackToolCallId("repair_"), name, arguments: args, }; } function parseBlock(raw, toolNames, out, framed) { let parsed; try { parsed = JSON.parse(raw.trim()); } catch { return "none"; } const items = Array.isArray(parsed) ? parsed : [parsed]; let promoted = 0; for (const item of items) { const call = extractCall(item, toolNames, framed); if (call) { out.push(call); promoted++; } } if (promoted === 0) return "none"; return promoted === items.length ? "all" : "some"; } export function repairTextToolCalls(text, toolNames) { const toolCalls = []; let cleaned = text.replace(TAG_RE, (m, _tag, inner) => parseBlock(inner, toolNames, toolCalls, true) === "all" ? "" : m); cleaned = cleaned.replace(FENCE_RE, (m, inner) => parseBlock(inner, toolNames, toolCalls, false) === "all" ? "" : m); return { toolCalls, cleanedText: cleaned.trim() }; }