fix(chat): keep a long turn's Edited N files card whole across the page cut (#86)
The reported turn (/vp-auto, ~120 messages) showed "Edited 1 file": the chat loads the newest 50 messages, and the turn's other Write (rbac_routes_test.go, +176) was in the part before the page. - turnCarry (agent-edits.js): every message the route's sliding window drops goes through it; it keeps the file changes since the last prompt it dropped (a dropped call whose result is on the page, and dropped subagents, included). - A Claude page that starts mid-turn answers them as `turn_edits`; the chat keeps the one from the page that holds its oldest message and adds it to that turn's card. Files a turn changed through Bash (python/sed writing a file) are still not listed: nothing in the transcript says which files a command wrote.
This commit is contained in:
@@ -172,6 +172,9 @@ interface MessageListProps {
|
||||
/** A subagent's conversation inside its step: tight spacing, and the task
|
||||
* the orchestrator gave it reads as the prompt it is. */
|
||||
compact?: boolean;
|
||||
/** The files the first, cut-off turn changed before `messages` begins (the
|
||||
* transcript page's `turn_edits`): counted in that turn's card. */
|
||||
leadEdits?: TranscriptContent["edits"];
|
||||
}
|
||||
|
||||
/** Build a map from tool_use id → tool_result for matching */
|
||||
@@ -493,6 +496,8 @@ type Item =
|
||||
const EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
||||
// A subagent's result carries the files IT changed (`edits`): they count too.
|
||||
const AGENT_TOOLS = new Set(["Agent", "Task"]);
|
||||
// The stand-in for the part of a turn the page cut off: its `edits` count.
|
||||
const LEAD = "__lead_edits";
|
||||
|
||||
/** A line that is only Claude Code's local-command plumbing — the caveat it
|
||||
* writes first, the command, what the command printed — or null for
|
||||
@@ -517,11 +522,18 @@ export function localCommand(
|
||||
return { name, output, error };
|
||||
}
|
||||
|
||||
export function chatItems(messages: TranscriptMessage[], keys: string[]): Item[] {
|
||||
export function chatItems(
|
||||
messages: TranscriptMessage[],
|
||||
keys: string[],
|
||||
leadEdits?: TranscriptContent["edits"]
|
||||
): Item[] {
|
||||
const items: Item[] = [];
|
||||
// The file-changing calls of the turn so far, closed into one card when the
|
||||
// human speaks again (or the list ends).
|
||||
let edits: TranscriptContent[] = [];
|
||||
// human speaks again (or the list ends) — starting with what the page's
|
||||
// cut-off first turn changed before it.
|
||||
let edits: TranscriptContent[] = leadEdits?.length
|
||||
? [{ type: "tool_use", name: LEAD, edits: leadEdits }]
|
||||
: [];
|
||||
// The turn's prompt time, its newest assistant line and its output so far,
|
||||
// for the "Done in …" line under a turn that ended.
|
||||
let start: string | null = null;
|
||||
@@ -684,8 +696,8 @@ function EditedFilesCard({
|
||||
const byAgent = new Set<string>();
|
||||
for (const b of blocks) {
|
||||
const r0 = b.id ? toolResultMap.get(b.id) : undefined;
|
||||
if (AGENT_TOOLS.has(b.name ?? "")) {
|
||||
for (const e of r0?.edits ?? []) {
|
||||
if (AGENT_TOOLS.has(b.name ?? "") || b.name === LEAD) {
|
||||
for (const e of (b.name === LEAD ? b.edits : r0?.edits) ?? []) {
|
||||
if (!files.has(e.path)) byAgent.add(e.path);
|
||||
const f = files.get(e.path) ?? { added: 0, removed: 0, counted: false };
|
||||
f.added += e.added;
|
||||
@@ -798,6 +810,7 @@ function MessageListView({
|
||||
sessionId,
|
||||
agentLinks,
|
||||
compact = false,
|
||||
leadEdits,
|
||||
}: MessageListProps) {
|
||||
const { t } = useTranslation("sessions");
|
||||
const toolResultMap = useMemo(() => buildToolResultMap(messages), [messages]);
|
||||
@@ -823,9 +836,10 @@ function MessageListView({
|
||||
m.sender === "orchestrator" ? { ...m, sender: "user" as const } : m
|
||||
)
|
||||
: messages,
|
||||
keys
|
||||
keys,
|
||||
leadEdits
|
||||
),
|
||||
[messages, keys, compact]
|
||||
[messages, keys, compact, leadEdits]
|
||||
);
|
||||
const agents = useMemo(
|
||||
() => (live ? backgroundAgents(messages, toolResultMap) : []),
|
||||
|
||||
Reference in New Issue
Block a user