diff --git a/ui/litellm-dashboard/src/app/(dashboard)/agents/components/three-pane/files-changed-accordion.tsx b/ui/litellm-dashboard/src/app/(dashboard)/agents/components/three-pane/files-changed-accordion.tsx new file mode 100644 index 00000000000..2ce7bdff813 --- /dev/null +++ b/ui/litellm-dashboard/src/app/(dashboard)/agents/components/three-pane/files-changed-accordion.tsx @@ -0,0 +1,85 @@ +"use client"; + +/** + * FilesChangedAccordion — collapsible "N Files Changed" block in the + * conversation pane. Aggregates file_diff events by path: the latest patch + * wins, additions/deletions are summed per file. + * + * Cumulative across the entire run (per spec). + */ +import { Collapse, Tag, Typography } from "antd"; +import type { FileDiffPayload } from "@/types/cloud-agents"; + +const { Paragraph, Text } = Typography; + +interface FilesChangedAccordionProps { + diffs: FileDiffPayload[]; +} + +interface AggregatedDiff { + path: string; + additions: number; + deletions: number; + patch: string; +} + +function aggregate(diffs: FileDiffPayload[]): AggregatedDiff[] { + const byPath = new Map(); + for (const d of diffs) { + const existing = byPath.get(d.path); + if (existing) { + existing.additions += d.additions; + existing.deletions += d.deletions; + existing.patch = d.patch; // latest wins + } else { + byPath.set(d.path, { path: d.path, additions: d.additions, deletions: d.deletions, patch: d.patch }); + } + } + return Array.from(byPath.values()); +} + +export default function FilesChangedAccordion({ diffs }: FilesChangedAccordionProps) { + const aggregated = aggregate(diffs); + if (aggregated.length === 0) return null; + + return ( + + {aggregated.length} {aggregated.length === 1 ? "File" : "Files"} Changed + + ), + children: ( +
+ {aggregated.map((d) => ( +
+ + +{d.additions} + + + -{d.deletions} + + {d.path} +
+ ))} + {aggregated.map((d) => ( + + {d.patch} + + ))} +
+ ), + }, + ]} + /> + ); +}