1 // Meta parser for `edit_file` tool calls. Reads the file path and the
2 // array of edits from the streamed args (partial JSON for incremental
3 // rendering), plus the result blob for `result` / `edits_applied` /
6 import { parseToolArgs } from './_shared';
7 import { FILE_PATH_SEPARATOR_REGEX } from '$lib/constants';
8 import { BuiltInTool } from '$lib/enums';
9 import { type AgenticSection, tryParseToolResultObject } from '$lib/utils';
11 export type EditFileEdit = {
16 export type EditFileMeta = {
19 edits: EditFileEdit[];
20 resultMessage?: string;
21 editsApplied?: number;
22 errorMessage?: string;
25 export function parseEditFileMeta(section: AgenticSection): EditFileMeta | null {
26 const args = parseToolArgs(BuiltInTool.EDIT_FILE, section, { partial: true });
28 if (!args) return null;
30 const rawPath = args.path ?? args.file_path ?? args.filePath;
32 if (typeof rawPath !== 'string' || !rawPath) return null;
34 const fileName = rawPath.split(FILE_PATH_SEPARATOR_REGEX).pop() || rawPath;
35 // Filter the streamed edits array strictly: each entry must be an
36 // object with a non-empty `old_text`. Edits without an old_text
37 // would diff against empty and render as a full re-write.
38 const rawEdits = Array.isArray(args.edits) ? args.edits : [];
39 const edits: EditFileEdit[] = [];
41 for (const e of rawEdits) {
42 if (!e || typeof e !== 'object' || Array.isArray(e)) continue;
44 const obj = e as Record<string, unknown>;
45 const oldText = typeof obj.old_text === 'string' ? obj.old_text : '';
47 if (!oldText) continue;
49 const newText = typeof obj.new_text === 'string' ? obj.new_text : '';
51 edits.push({ newText, oldText });
54 const resultObj = tryParseToolResultObject(section.toolResult);
56 let resultMessage: string | undefined;
57 let editsApplied: number | undefined;
58 let errorMessage: string | undefined;
60 if (typeof resultObj?.error === 'string') {
61 errorMessage = resultObj.error;
62 } else if (resultObj) {
63 if (typeof resultObj.result === 'string') {
64 resultMessage = resultObj.result;
67 if (Number.isFinite(Number(resultObj.edits_applied))) {
68 editsApplied = Number(resultObj.edits_applied);