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 { parsePartialJsonArgs } from '$lib/utils/parse-partial-json-args';
9 import type { AgenticSection } from '$lib/utils/agentic';
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);
20 if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
21 return parsed as Record<string, unknown>;
30 * Parse a section's toolArgs against an expected tool name. Returns
32 * - the section's toolName doesn't match (component isn't for this
34 * - the section has no args yet (call hasn't started streaming);
35 * - or the args blob can't be parsed.
37 * Pass `{ partial: true }` for tools that need to render incrementally
38 * as each token lands (read_file, edit_file, write_file).
40 export function parseToolArgs(
41 expected: BuiltInTool,
42 section: AgenticSection,
43 options: { partial?: boolean } = {}
44 ): Record<string, unknown> | null {
45 if (section.toolName !== expected || !section.toolArgs) return null;
46 return options.partial
47 ? parsePartialJsonArgs(section.toolArgs)
48 : parseFinalToolArgs(section.toolArgs);