1 // Helpers shared by the per-tool meta parsers under
2 // `src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/parsers/`.
3 // Each tool needs the same first three steps (tool-name check,
4 // args-present check, JSON parse) - keeping them here lets each parser
5 // stay focused on its own format quirks.
7 import { BuiltInTool } from '$lib/enums';
8 import type { AgenticSection } from '$lib/utils/agentic';
9 import { parsePartialJsonArgs } from '$lib/utils/parse-partial-json-args';
12 * Strict (final-state) JSON parser for a tool-args blob. Mirrors the
13 * behaviour the per-tool components used before extraction: an
14 * invalid JSON blob, a JSON array, or a JSON primitive all map to
15 * `null` so callers don't have to guard against surprise shapes.
17 function parseFinalToolArgs(blob: string): Record<string, unknown> | null {
19 const parsed: unknown = JSON.parse(blob);
21 if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
22 return parsed as Record<string, unknown>;
32 * Parse a section's toolArgs against an expected tool name. Returns
34 * - the section's toolName doesn't match (component isn't for this
36 * - the section has no args yet (call hasn't started streaming);
37 * - or the args blob can't be parsed.
39 * Pass `{ partial: true }` for tools that need to render incrementally
40 * as each token lands (read_file, edit_file, write_file).
42 export function parseToolArgs(
43 expected: BuiltInTool,
44 section: AgenticSection,
45 options: { partial?: boolean } = {}
46 ): Record<string, unknown> | null {
47 if (section.toolName !== expected || !section.toolArgs) return null;
49 return options.partial
50 ? parsePartialJsonArgs(section.toolArgs)
51 : parseFinalToolArgs(section.toolArgs);