diff --git a/.yoi/tickets/00001KY1ZKCPC/item.md b/.yoi/tickets/00001KY1ZKCPC/item.md index af474a6f..033e4792 100644 --- a/.yoi/tickets/00001KY1ZKCPC/item.md +++ b/.yoi/tickets/00001KY1ZKCPC/item.md @@ -2,7 +2,7 @@ title: 'Backend runtime経由の操作をprotocol transportへ統一しTUI同等にする' state: 'planning' created_at: '2026-07-21T09:20:07Z' -updated_at: '2026-07-22T05:03:17Z' +updated_at: '2026-07-22T06:36:51Z' assignee: null readiness: 'draft' --- diff --git a/.yoi/tickets/00001KY1ZKCPC/thread.md b/.yoi/tickets/00001KY1ZKCPC/thread.md index 1c160d9a..2f5881ff 100644 --- a/.yoi/tickets/00001KY1ZKCPC/thread.md +++ b/.yoi/tickets/00001KY1ZKCPC/thread.md @@ -341,3 +341,38 @@ Verification: - `git diff --check` --- + + + +## Comment + +Reported issue before implementation: + +- TUI shows the `Compacting...` progress/status indication. +- Web Console does not show the same indication. + +Investigation plan: +- Compare TUI protocol/event handling with Web Console protocol/event handling. +- Confirm whether the relevant protocol event reaches the browser and is dropped by frontend state/rendering, or whether the event is not forwarded through the Backend/runtime protocol WS path. +- Fix the narrow missing mapping/rendering path without adding a synthetic event outside the normal Worker protocol/session flow. + +--- + + + +## Implementation report + +Implementation report for Web Console compact/rotation display gap: + +- Web Console already handled live `compact_start` by projecting a `Compacting…` status row. +- The projection was still ignoring `segment_rotated`, while TUI reseeds the visible transcript from the new segment start entry. This made Web diverge around compaction/segment-rotation boundaries. +- Updated `web/workspace/src/lib/workspace/console/model.ts` so `segment_rotated` reprojects `event.data.entry` through the same log-entry projection path used by `snapshot`. +- Added a Web projection regression test asserting `segment_rotated` replaces stale visible rows with the new segment seed. +- While running Web check, fixed a narrow `list_completions` TypeScript narrowing issue in `+page.svelte`: command completions return early, then the file completion kind/prefix are captured before the Promise closure. + +Verification: +- `cd web/workspace && deno test --allow-read=src --allow-env=VSCODE_TEXTMATE_DEBUG src/lib/workspace/console/model.test.ts` +- `cd web/workspace && deno task check` passes with 0 errors; it still reports 2 existing a11y warnings in `+page.svelte`. +- `git diff --check` + +--- diff --git a/web/workspace/src/lib/workspace/console/model.test.ts b/web/workspace/src/lib/workspace/console/model.test.ts index c15d48f8..c0192e81 100644 --- a/web/workspace/src/lib/workspace/console/model.test.ts +++ b/web/workspace/src/lib/workspace/console/model.test.ts @@ -818,3 +818,42 @@ Deno.test("projectConsole renders snapshot entries and in-flight output", () => ], ); }); + +Deno.test("projectConsole reseeds visible rows from segment rotation", () => { + const projection = projectConsole([ + { + eventId: "rotation-before", + event: { + event: "user_message", + data: { segments: [{ kind: "text", content: "before rotation" }] }, + } satisfies Event, + }, + { + eventId: "rotation-event", + event: { + event: "segment_rotated", + data: { + entry: { + kind: "segment_start", + ts: 10, + session_id: "00000000-0000-0000-0000-000000000001", + system_prompt: null, + config: {}, + history: [ + { + kind: "message", + role: "user", + content: [{ kind: "text", text: "after rotation seed" }], + }, + ], + }, + }, + } satisfies Event, + }, + ]); + + assertEquals( + projection.lines.map((line) => `${line.kind}:${line.body}`), + ["user:after rotation seed"], + ); +}); diff --git a/web/workspace/src/lib/workspace/console/model.ts b/web/workspace/src/lib/workspace/console/model.ts index 8e685550..9cd5b629 100644 --- a/web/workspace/src/lib/workspace/console/model.ts +++ b/web/workspace/src/lib/workspace/console/model.ts @@ -259,6 +259,9 @@ export function applyProtocolEvent( case "status": next.status = event.data.status; break; + case "segment_rotated": + next.lines = snapshotLinesFromEntries(envelope.eventId, [event.data.entry]); + break; case "invoke_start": case "turn_start": case "turn_end": @@ -272,7 +275,6 @@ export function applyProtocolEvent( appendAlertLine(next, envelope.eventId, event.data); break; case "memory_worker": - case "segment_rotated": case "completions": case "rewind_targets": case "rewind_applied": diff --git a/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte b/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte index 660d66f6..d69254ae 100644 --- a/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte +++ b/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte @@ -324,6 +324,8 @@ if (token.kind === "command") { return localCommandCompletions(token.prefix); } + const completionKind = token.kind; + const completionPrefix = token.prefix; return new Promise((resolve, reject) => { if (pendingCompletionRequest) { rejectPendingCompletion( @@ -339,7 +341,7 @@ try { sendProtocolMethod({ method: "list_completions", - params: { kind: token.kind, prefix: token.prefix }, + params: { kind: completionKind, prefix: completionPrefix }, }); } catch (error) { rejectPendingCompletion(