fix: replay annotated history in Web Console

This commit is contained in:
2026-08-29 23:10:32 +09:00
parent acb3c6d68b
commit 402ae0d466
2 changed files with 166 additions and 8 deletions
@@ -165,6 +165,108 @@ Deno.test("segment rotation retains a live error beside the real SegmentStart hi
);
});
Deno.test("reload snapshot projects provenance-annotated history entries", () => {
const metadata = {
entry_id: "history-entry-1",
origin: {
kind: "model_output",
worker: {
workspace_id: "workspace-secret",
runtime_id: "runtime-secret",
worker_id: "worker-secret",
},
},
};
const annotated = (item: unknown) => ({ item, metadata });
const projection = projectConsole([{
eventId: "annotated-reload",
event: snapshotEvent("/repo", [
{
kind: "annotated_segment_start",
ts: 1,
session_id: "session-1",
system_prompt: null,
config: {},
history: [annotated({
kind: "message",
role: "assistant",
content: [{ kind: "text", text: "older committed reply" }],
})],
},
{
kind: "annotated_user_input",
ts: 2,
segments: [{ kind: "text", content: "latest user message" }],
history: [annotated({
kind: "message",
role: "user",
content: [{ kind: "text", text: "latest user message" }],
})],
},
{
kind: "annotated_assistant_item",
ts: 3,
entry: annotated({
kind: "message",
role: "assistant",
content: [{ kind: "text", text: "latest committed reply" }],
}),
},
{
kind: "annotated_assistant_item",
ts: 4,
entry: annotated({
kind: "tool_call",
call_id: "annotated-call",
name: "Read",
arguments: '{"file_path":"/repo/a.md"}',
}),
},
{
kind: "annotated_tool_result",
ts: 5,
entry: annotated({
kind: "tool_result",
call_id: "annotated-call",
summary: "Read 1 line from /repo/a.md",
content: "1→content",
is_error: false,
}),
},
{
kind: "annotated_system_item",
ts: 6,
entry: annotated({
kind: "notification",
message: "Worker completed",
}),
},
]),
}]);
assertEquals(
projection.lines.map((line) =>
`${line.kind}:${line.toolCallLabel ?? line.body}`
),
[
"assistant:older committed reply",
"user:latest user message",
"assistant:latest committed reply",
"tool:Read(1 file)",
"system:Worker completed",
],
);
const visible = JSON.stringify(projection.lines);
assert(
!visible.includes("workspace-secret"),
"history metadata must not enter Console rows",
);
assert(
!visible.includes("runtime-secret"),
"history origin must remain non-visible metadata",
);
});
Deno.test("workerConsoleHref encodes runtime and worker target authority", () => {
assert(
workerConsoleHref({
@@ -1960,24 +1960,34 @@ function applyLogEntry(
applyLoggedItem(projection, `${eventId}-history-${index}`, item)
);
break;
case "user_input":
projection.lines.push(
line(
eventId,
"user",
"User",
segmentsToText(arrayField(entry, "segments") as Segment[]),
),
case "annotated_segment_start":
arrayField(entry, "history").forEach((historyEntry, index) =>
applyLoggedHistoryEntry(
projection,
`${eventId}-history-${index}`,
historyEntry,
)
);
break;
case "user_input":
case "annotated_user_input":
applyLoggedUserInput(projection, eventId, entry);
break;
case "system_item":
projection.lines.push(systemItemLine(eventId, entry["item"]));
applyTaskSystemItem(projection, entry["item"]);
break;
case "annotated_system_item":
applyLoggedSystemEntry(projection, eventId, entry["entry"]);
break;
case "assistant_item":
case "tool_result":
applyLoggedItem(projection, eventId, entry["item"]);
break;
case "annotated_assistant_item":
case "annotated_tool_result":
applyLoggedHistoryEntry(projection, eventId, entry["entry"]);
break;
case "run_errored":
projection.lines.push(
line(
@@ -2056,6 +2066,52 @@ function compactMessageForState(
}
}
function applyLoggedUserInput(
projection: ConsoleProjection,
eventId: string,
entry: Record<string, unknown>,
): void {
let body = segmentsToText(arrayField(entry, "segments") as Segment[]);
if (!body && stringField(entry, "kind") === "annotated_user_input") {
body = loggedUserText(arrayField(entry, "history"));
}
projection.lines.push(line(eventId, "user", "User", body));
}
function loggedUserText(history: unknown[]): string {
for (const historyEntry of history) {
if (!isRecord(historyEntry) || !isRecord(historyEntry["item"])) continue;
const item = historyEntry["item"];
if (
stringField(item, "kind") !== "message" ||
stringField(item, "role") !== "user"
) {
continue;
}
return loggedContentText(arrayField(item, "content"));
}
return "";
}
function applyLoggedHistoryEntry(
projection: ConsoleProjection,
eventId: string,
historyEntry: unknown,
): void {
if (!isRecord(historyEntry)) return;
applyLoggedItem(projection, eventId, historyEntry["item"]);
}
function applyLoggedSystemEntry(
projection: ConsoleProjection,
eventId: string,
historyEntry: unknown,
): void {
if (!isRecord(historyEntry)) return;
projection.lines.push(systemItemLine(eventId, historyEntry["item"]));
applyTaskSystemItem(projection, historyEntry["item"]);
}
function applyLoggedItem(
projection: ConsoleProjection,
eventId: string,