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 { BuiltInTool } from '$lib/enums';
7 import { FILE_PATH_SEPARATOR_REGEX } from '$lib/constants';
8 import { tryParseToolResultObject, type AgenticSection } from '$lib/utils';
9 import { parseToolArgs } from './_shared';
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 });
27 if (!args) return null;
29 const rawPath = args.path ?? args.file_path ?? args.filePath;
30 if (typeof rawPath !== 'string' || !rawPath) return null;
32 const fileName = rawPath.split(FILE_PATH_SEPARATOR_REGEX).pop() || rawPath;
34 // Filter the streamed edits array strictly: each entry must be an
35 // object with a non-empty `old_text`. Edits without an old_text
36 // would diff against empty and render as a full re-write.
37 const rawEdits = Array.isArray(args.edits) ? args.edits : [];
38 const edits: EditFileEdit[] = [];
39 for (const e of rawEdits) {
40 if (!e || typeof e !== 'object' || Array.isArray(e)) continue;
41 const obj = e as Record<string, unknown>;
42 const oldText = typeof obj.old_text === 'string' ? obj.old_text : '';
43 if (!oldText) continue;
44 const newText = typeof obj.new_text === 'string' ? obj.new_text : '';
45 edits.push({ oldText, newText });
48 const resultObj = tryParseToolResultObject(section.toolResult);
49 let resultMessage: string | undefined;
50 let editsApplied: number | undefined;
51 let errorMessage: string | undefined;
52 if (typeof resultObj?.error === 'string') {
53 errorMessage = resultObj.error;
54 } else if (resultObj) {
55 if (typeof resultObj.result === 'string') {
56 resultMessage = resultObj.result;
58 if (Number.isFinite(Number(resultObj.edits_applied))) {
59 editsApplied = Number(resultObj.edits_applied);