export interface ParsedToolCall { name: string; arguments: Record; raw: string; } export interface ToolCallParseResult { calls: ParsedToolCall[]; content: string; incomplete: boolean; errors: string[]; } const OPEN = ''; const CLOSE = ''; const FUNCTION_CLOSE = ''; const PARAMETER_CLOSE = ''; const MAX_TOOL_PAYLOAD = 64 * 1024; const NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_.:-]*$/; function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null && !Array.isArray(value); } function parseJsonEnvelope(raw: string): ParsedToolCall { const envelope: unknown = JSON.parse(raw); if (!isRecord(envelope) || typeof envelope.name !== 'string' || !envelope.name.trim()) { throw new Error('tool call must contain a non-empty name'); } let argumentsValue = envelope.arguments; if (typeof argumentsValue === 'string') argumentsValue = JSON.parse(argumentsValue); if (!isRecord(argumentsValue)) throw new Error('tool call arguments must be an object'); return { name: envelope.name.trim(), arguments: argumentsValue, raw }; } function parseFunctionEnvelope(raw: string): ParsedToolCall { const functionOpeningEnd = raw.indexOf('>'); if (!raw.startsWith(' = {}; let cursor = 0; while (cursor < body.length) { while (/\s/u.test(body[cursor] ?? '')) cursor += 1; if (cursor >= body.length) break; if (!body.startsWith('', cursor); if (parameterOpeningEnd < 0) throw new Error('function tool call has an incomplete parameter tag'); const parameterName = body.slice(cursor + ' MAX_TOOL_PAYLOAD) throw new Error('tool call exceeds 64 KiB'); return raw.startsWith('\n${serialized.slice(0, MAX_TOOL_PAYLOAD)}\n`; }