import { useState } from "react"; import { get } from "../api"; import { useT } from "../i18n"; import type { Message } from "../types"; import { Diff } from "./Diff"; import { Icon } from "./Icon"; import { basename } from "./FileFigure"; interface Change { path: string; created: boolean; deleted?: boolean; diff?: string; truncated?: boolean; } const count = (diff: string | undefined, sign: "+" | "-") => (diff ?? "").split("\n").filter((l) => l.startsWith(sign) && !l.startsWith(sign.repeat(3))).length; /** * What one turn changed: files with their diffs (from the checkpoints the agent leaves before * every write/edit) and a button to roll the chat and the files back to before the turn. */ export function TurnChanges({ sessionId, fromId, untilId, fileCount, userMessage, onRewind, }: { sessionId: string; fromId: string; untilId?: string; fileCount: number; userMessage?: Message; onRewind?: (m: Message) => void; }) { const t = useT(); const [open, setOpen] = useState(false); const [changes, setChanges] = useState(); const [error, setError] = useState(); const toggle = () => { const next = !open; setOpen(next); if (next && !changes) { const q = `since_message=${encodeURIComponent(fromId)}&diff=true${untilId ? `&until_message=${encodeURIComponent(untilId)}` : ""}`; get(`/sessions/${sessionId}/changes?${q}`).then(setChanges, (e) => setError(e.message)); } }; return (
{open && (
{error &&
{error}
} {!changes && !error &&
…
} {changes?.length === 0 &&
{t("turn.noChanges")}
} {changes?.map((c) => (
{basename(c.path)} {c.created && {t("turn.new")}} {c.deleted && {t("turn.deleted")}} +{count(c.diff, "+")} −{count(c.diff, "-")} {c.diff ? :
{t("turn.noDiff")}
} {c.truncated &&
{t("turn.truncated")}
}
))} {userMessage && onRewind && changes && changes.length > 0 && ( )}
)}
); }