fix(web): quiet structured transcript metadata

This commit is contained in:
Miguel Palhas
2026-09-06 21:51:17 +01:00
parent e30084ea24
commit 0b1c9e15cf
3 changed files with 54 additions and 9 deletions
+36
View File
@@ -115,6 +115,42 @@ describe("structured connection: data flow", () => {
conn.dispose();
});
it("shows turn details only while that footer is the conversation's final item", () => {
const ws = new FakeSocket();
const conn = mount({ sockets: [ws] });
const turnMeta = (id: string, elapsedMs: number) =>
row(id, "notice", {
maestroTurnMeta: { elapsedMs, contextTokens: 12_000, outcome: "completed", model: "codex" },
});
ws.open();
ws.emit({
type: "transcript_snapshot",
snapshot: {
cursor: 4,
rows: [
row("user:1", "user", { content: { type: "text", text: "first" } }),
turnMeta("turn:1", 1_000),
row("user:2", "user", { content: { type: "text", text: "second" } }),
turnMeta("turn:2", 2_000),
],
},
});
expect(conn.el.querySelectorAll(".st-turn-meta")).toHaveLength(1);
expect(conn.el.querySelector(".st-turn-meta")?.textContent).toContain("2s");
ws.emit({
type: "projection_update",
transcript: {
type: "append",
row: row("user:3", "user", { content: { type: "text", text: "third" } }),
},
state: idleState,
});
expect(conn.el.querySelector(".st-turn-meta")).toBeNull();
conn.dispose();
});
it("keeps state-only plan rows out of the transcript", () => {
const ws = new FakeSocket();
const conn = mount({ sockets: [ws] });
+8 -1
View File
@@ -340,7 +340,14 @@ export function createStructuredConnection(
rowEls.set(row.id, rowEl);
children.push(rowEl);
}
rowsEl.replaceChildren(...children);
// A completed turn's footer is useful as the conversation's current
// tail, but repeating duration/model/token summaries throughout history
// makes them read like transcript content. Keep only a footer that is the
// final visible item; appending the next turn naturally retires it.
const visibleChildren = children.filter(
(child, index) => !child.classList.contains("st-turn-meta") || index === children.length - 1,
);
rowsEl.replaceChildren(...visibleChildren);
if (restoreToolFocus && focusedRowId) {
rowEls.get(focusedRowId)?.querySelector<HTMLButtonElement>(".st-tool-head")?.focus();
} else if (restoreGroupFocus && focusedGroupId) {
+10 -8
View File
@@ -2549,19 +2549,27 @@ input.leaf-rename:focus {
transition: opacity var(--dur-fast) var(--ease-out);
}
.st-copyable:hover,
.st-copyable:focus-visible {
background: var(--surface-2);
outline: none;
}
.st-copyable:hover::after,
.st-copyable:focus-visible::after,
.st-copyable[data-copy-state="copied"]::after,
.st-copyable[data-copy-state="error"]::after {
opacity: 1;
}
@media (hover: hover) {
.st-copyable:hover {
background: var(--surface-2);
}
.st-copyable:hover::after {
opacity: 1;
}
}
.st-copyable[data-copy-state="copied"]::after {
content: "copied";
color: var(--live);
@@ -3126,12 +3134,6 @@ input.leaf-rename:focus {
}
}
@media (hover: none) {
.st-copyable::after {
opacity: 0.7;
}
}
/* ---------- modal ---------- */
.modal-backdrop {