From 356be9710ad03fef76b2952108f0bb7df0d9f32f Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Thu, 23 Jul 2026 15:56:28 +0800 Subject: [PATCH] docs(gui): record the window-scoped todos gap and the web consumer runtime README documents ConversationSnapshot.todos and its window-scoped limitation; the todo tool README and Agent Note name the web client among the event consumers; the web display note records the cold-load gap and fix directions (bilingual pair re-recorded). --- .../notes/implemented/feature/2026-06-29-todo-write-tool.md | 4 ++-- .../implemented/feature/2026-07-23-web-todo-display.i18n.yaml | 4 ++-- .../notes/implemented/feature/2026-07-23-web-todo-display.md | 2 +- .../implemented/feature/2026-07-23-web-todo-display.zh.md | 2 +- packages/client/runtime/README.md | 3 ++- packages/todo/tool-todo/README.md | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.md b/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.md index bf5fceaafd..aa281a22a2 100644 --- a/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.md +++ b/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.md @@ -10,7 +10,7 @@ The harness gives the model bash and subagent tools but no way to record a struc ## Decision -Add a model-facing `todo_write(todos: [{ content, status }])` tool whose whole-list state lives on the event-sourced session log as a new `todo/write` `SessionEventMap` variant. Both the stdio UI and the ACP bridge render off the existing `session/event` — the ACP bridge maps the list to a `plan` sessionUpdate. +Add a model-facing `todo_write(todos: [{ content, status }])` tool whose whole-list state lives on the event-sourced session log as a new `todo/write` `SessionEventMap` variant. Every UI renders off the existing `session/event`: the stdio/TUI front doors show a persistent plan, the ACP bridge maps the list to a `plan` sessionUpdate, and the web client projects it into `ConversationSnapshot.todos` ([web todo display](2026-07-23-web-todo-display.md)). ### Whole-list replace, three-state status @@ -18,7 +18,7 @@ The model sends the ENTIRE list every call; the new list replaces the old (last- ### State on the session log, not a service -The list is appended as a `todo/write` event carrying the full `{ todos }` snapshot. The harness is event-sourced — the LLM history, tool calls, and turn structure all live on the log — so the todo list lives there too. This buys durability, replay, and `session/load` reconstruction for free: a reopened session re-derives the current list (the last `todo/write`) and the ACP bridge re-emits the `plan` on load, with no separate persistence backend, no in-memory service to rehydrate, and no extra wiring. An in-memory `ctx.todos` service would have had to reinvent all of that. +The list is appended as a `todo/write` event carrying the full `{ todos }` snapshot. The harness is event-sourced — the LLM history, tool calls, and turn structure all live on the log — so the todo list lives there too. This buys durability, replay, and `session/load` reconstruction for free: a reopened session re-derives the current list (the last `todo/write`) and the ACP bridge re-emits the `plan` on load, with no separate persistence backend, no in-memory service to rehydrate, and no extra wiring. An in-memory `ctx.todos` service would have had to reinvent all of that. (Full-log consumers get this reconstruction outright; the web client's paged window currently sees only the tail page — the gap and its fix directions are recorded in the [web todo display note](2026-07-23-web-todo-display.md).) ### NOT a surface event diff --git a/.agents/notes/implemented/feature/2026-07-23-web-todo-display.i18n.yaml b/.agents/notes/implemented/feature/2026-07-23-web-todo-display.i18n.yaml index d8a6a517bf..1bfe2b59f3 100644 --- a/.agents/notes/implemented/feature/2026-07-23-web-todo-display.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-23-web-todo-display.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-23-web-todo-display.md: 6b6af215016b2f73baa088653fcf133dbbfd3449 -2026-07-23-web-todo-display.zh.md: a06083190ba7b9b030a48aa7dc2c3177853f3cee +2026-07-23-web-todo-display.md: 003ab29546e8098331496641a28d095a1dd95fed +2026-07-23-web-todo-display.zh.md: 200fd1d44dca7c5bcaa4f47ac31e26cb1f0f8d3d diff --git a/.agents/notes/implemented/feature/2026-07-23-web-todo-display.md b/.agents/notes/implemented/feature/2026-07-23-web-todo-display.md index 6b6af21501..003ab29546 100644 --- a/.agents/notes/implemented/feature/2026-07-23-web-todo-display.md +++ b/.agents/notes/implemented/feature/2026-07-23-web-todo-display.md @@ -32,4 +32,4 @@ The dedicated `todo_write` chat row registers through the named `ctx.toolviews` ## Consequences -Replay correctness is owned by one code path: any future change to window rebuild keeps todos consistent for free, and the fixture (fx-alpha turn 63) plus `scripts/verify-todo-display.mjs` pin the full chain (panel visibility, row summary, details linkage, collapse, dark theme) in a real chromium. `todos` is a required `ConversationSnapshot` field, so scripted fakes in specs must carry it. The ACP bridge's todo → `plan` mapping and the TUI panel are untouched; the web surfaces render the same event with no new wire vocabulary. +Replay correctness is owned by one code path: any future change to window rebuild keeps todos consistent for free, and the fixture (fx-alpha turn 63) plus `scripts/verify-todo-display.mjs` pin the full chain (panel visibility, row summary, details linkage, collapse, dark theme) in a real chromium. `todos` is a required `ConversationSnapshot` field, so scripted fakes in specs must carry it. The ACP bridge's todo → `plan` mapping and the TUI panel are untouched; the web surfaces render the same event with no new wire vocabulary. Known gap: the projection is window-scoped — reopening a session whose last `todo/write` precedes the tail history page shows an empty plan until the user pages back to it; restoring the tool note's cold-load reconstruction promise needs the current projection independent of the display window (host-attached on the history response, or a dedicated read). diff --git a/.agents/notes/implemented/feature/2026-07-23-web-todo-display.zh.md b/.agents/notes/implemented/feature/2026-07-23-web-todo-display.zh.md index a06083190b..200fd1d44d 100644 --- a/.agents/notes/implemented/feature/2026-07-23-web-todo-display.zh.md +++ b/.agents/notes/implemented/feature/2026-07-23-web-todo-display.zh.md @@ -32,4 +32,4 @@ Status: implemented ## Consequences -回放正确性由一条代码路径掌管:未来对窗口重建的任何改动都免费保持 todos 一致;fx-alpha 第 63 轮的 fixture(测试前置数据)加 `scripts/verify-todo-display.mjs` 在真实 chromium 里钉住整条链(面板可见性、行摘要、详情联动、折叠、深色主题)。`todos` 是 `ConversationSnapshot` 的必填字段,所以 spec 里脚本化的 fake 必须带上它。ACP 桥接的 todo → `plan` 映射与 TUI 面板均未受改动;Web 各面渲染同一个事件,不引入任何新的协议词汇。 +回放正确性由一条代码路径掌管:未来对窗口重建的任何改动都免费保持 todos 一致;fx-alpha 第 63 轮的 fixture(测试前置数据)加 `scripts/verify-todo-display.mjs` 在真实 chromium 里钉住整条链(面板可见性、行摘要、详情联动、折叠、深色主题)。`todos` 是 `ConversationSnapshot` 的必填字段,所以 spec 里脚本化的 fake 必须带上它。ACP 桥接的 todo → `plan` 映射与 TUI 面板均未受改动;Web 各面渲染同一个事件,不引入任何新的协议词汇。已知缺口:该投影以窗口为界——重新打开一个最后一次 `todo/write` 落在尾页之前的会话时,计划面板为空,直到用户翻页翻到它;要兑现工具 Note 里冷加载重建的承诺,需要一份独立于显示窗口的当前投影(history 响应由 host 附带,或提供专门的读取口)。 diff --git a/packages/client/runtime/README.md b/packages/client/runtime/README.md index 4fd5d15905..a9d03279f1 100644 --- a/packages/client/runtime/README.md +++ b/packages/client/runtime/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-client-runtime -Client cordis boot + core services: SlotsService (Service wrapper over SlotCore + 'slots/changed' bridge), SessionsService (list store projection, scope tree, bindings, ancestry), the Session object layer (exported as a type; instances are owned and handed out by SessionsService — the manager/paging internals stay package-internal, tests reach them via src), ClientLoader (`./loader` subpath, statically held by the shell). Contract: api-contracts v3 §4. +Client cordis boot + core services: SlotsService (Service wrapper over SlotCore + 'slots/changed' bridge), SessionsService (list store projection, scope tree, bindings, ancestry), the Session object layer (exported as a type; instances are owned and handed out by SessionsService — the manager/paging internals stay package-internal, tests reach them via src), ClientLoader (`./loader` subpath, statically held by the shell). Contract: api-contracts v3 §4. `ConversationSnapshot` carries `todos` — the latest `todo/write` whole-list snapshot in the window, consumed as a per-event side effect (last write wins) and reset on every window rebuild. ## Session title projection @@ -19,3 +19,4 @@ None; this package neither assembles nor sends a provider request. - **`loader.unload` is a stub (throws not-implemented)** — the full chain (fiber dispose → registration cascade → style removal) lands with the HMR project. - **Scope teardown is stage-driven, single-occupant today** — the staged session follows `list.current` exactly (staging is the open signal: the event window opens ⟺ the session is on stage); a removed-while-staged session's scope survives frozen until the stage moves on, not until true observer count reaches zero. Resolution (`cell()`/`binding()`/`scope()`) is pure addressing, render-safe. The staged state can widen to a multi-pane list when concurrent panes land. - **Value imports of this package from plugin bundles must use the `/client` subpath** — the bare package name is not in the loader externals table and inlines a second module instance, whose private scope-tag Symbol never matches (the empty-state P0 postmortem). +- **`todos` is window-scoped** — the projection scans only the paged display window, so reopening a session whose last `todo/write` precedes the tail page shows an empty plan until the user pages back to it. Restoring the tool's cold-load reconstruction promise needs the current projection independent of the window (host-attached on history, or a dedicated read). diff --git a/packages/todo/tool-todo/README.md b/packages/todo/tool-todo/README.md index 2e06c7dde5..d7479a3bb2 100644 --- a/packages/todo/tool-todo/README.md +++ b/packages/todo/tool-todo/README.md @@ -18,7 +18,7 @@ Beyond the schema's type/required/enum checks, `execute` rejects an empty or dup ## Rendering -The canonical result is `{ todos, counts: { pending, inProgress, completed } }`; its Native renderer returns the compact update acknowledgement. The tool also writes the full `todo/write` session event. UIs subscribe to `session/event` and render that durable list themselves: the [TUI app](../../examples/tui-demo) shows a persistent plan, and the [ACP bridge](../../ui/acp) maps the list to a `plan` sessionUpdate (synthesizing the `priority` ACP requires). +The canonical result is `{ todos, counts: { pending, inProgress, completed } }`; its Native renderer returns the compact update acknowledgement. The tool also writes the full `todo/write` session event. UIs subscribe to `session/event` and render that durable list themselves: the [TUI app](../../examples/tui-demo) shows a persistent plan, the [ACP bridge](../../ui/acp) maps the list to a `plan` sessionUpdate (synthesizing the `priority` ACP requires), and the [web client](../../client/ui-conversation) renders a plan strip plus a dedicated tool row off `ConversationSnapshot.todos` ([Agent Note](../../../.agents/notes/implemented/feature/2026-07-23-web-todo-display.md)). ## Export shape