feat: implement PI core chat timeline

This commit is contained in:
2026-08-24 00:34:03 +08:00
parent 54d8bb2e4a
commit 612135f911
40 changed files with 3881 additions and 119 deletions

View File

@@ -0,0 +1,176 @@
# Task: Implement PI-120 core chat and first-conversation UX
## Identity
- Task ID: 20260823-pi-chat-timeline-c8f31a62
- Mode: Feature
- Branch: codex/20260823-pi-chat-timeline-c8f31a62-pi-chat-timeline
- Worktree: D:\Datas\OthersProjects\makelore-pi-chat-timeline-c8f31a62
- Base commit: 54d8bb2e4a6f1a7dd857827659e60d1b4a1fb6f5
- Owner: codex-root
- Status: In Progress
## Scope
- Implement `PI-120 — Core Chat and first-Conversation UX` on cumulative
PI-110 delivery HEAD `54d8bb2`.
- Add a vendor-neutral `CodingChatPanel` composition, first-Conversation
metadata selection/creation, core Composer, and memoized timeline renderers
for message/thinking/tool/compaction/boundary nodes.
- Bind the page exclusively to `/api/coding/*` Renderer facades and the
PI-110 Conversation store, including optimistic prompt acceptance,
preparing/queued/running/error/recovery states, draft continuity, and
hidden-Conversation render isolation.
- Add focused component/performance coverage and the first-prompt Electron E2E.
Do not implement PI-130 feature-complete controls or PI-140 legacy removal.
## Intent And Constraints
- The exact Ready Frontier is `{PI-120}`. PI-110 is Done at audit HEAD
`934ba02` and cumulative delivery HEAD `54d8bb2`; PI-130 remains locked until
this ticket is accepted.
- Textarea editability depends only on an active project, an enabled Agent,
and the absence of a project destruction/migration transition. It never
depends on worker/runtime/metadata loading, provider latency, diagnostics,
another Conversation, or the current Conversation run state.
- Conversation creation is local metadata only. Snapshot/prewarm is lazy and
Conversation-scoped; preparation beyond ten seconds becomes a recoverable
error while the draft stays editable.
- A send immediately creates one stable optimistic user node. HTTP 202 is only
acceptance; later provider/tool failure never removes the accepted user
message, and uncertain delivery is never silently resent.
- Renderer components must use granular PI-110 selectors and memoized blocks.
Hidden Conversation streaming cannot rerender the selected timeline;
cumulative tool output replaces rather than appends duplicate content.
- Do not read `src/stores/opencode.ts`, call `/api/opencode`, import Pi/OpenCode
wire types, or mechanically rename the legacy 4k-line panel. The old panel
remains only as PI-140 removal residue after the new page composition takes
ownership.
- PI-130 still owns model/thinking controls, steer/follow-up queue controls,
compaction/retry/context actions, interactions, subagent graph, changes/files/
browser/skills/commands, and Conversation archive/fork/title/unread UI.
- The planner amended the attachment contract: `POST /api/coding/attachments`
accepts one bounded image binary and returns only `{attachmentId,mime,byteLength}`;
authenticated `GET /api/coding/attachments/:id/content` returns raw bytes.
Upload happens only on Send, each local variant has one in-flight/result, and
Renderer state/protocol keep references rather than base64.
- The planner selected public `patch-batch` delivery only. Main retains private
single-patch envelopes and original seq, batches per Conversation/generation
for 16–33 ms with bounded early flush, and cancels an old generation's pending
batch. Renderer validates the full batch and folds it in one Zustand
transaction; malformed/gapped batches recover only their target.
- Real Provider remains Explicitly Waived / Accepted Risk with
`realTurnVerified=false`. macOS x64/arm64 remains deferred to mandatory
PI-150. Neither is Pass evidence. No subagents are authorized.
## Project Context Loaded
- Task identity: `20260823-pi-chat-timeline-c8f31a62`, feature mode, isolated
branch/worktree above, exact base
`54d8bb2e4a6f1a7dd857827659e60d1b4a1fb6f5`.
- Concurrent Task Gate passed. The only semantically adjacent planning task,
`20260820-partner-create-model-parity-c83d`, still has undefined scope and no
claimed files. The canonical main integration task is Blocked and is not a
write target; all other planning owners are unrelated Canvas/Robot/Learning
or read-only scopes.
- Planning Gate inputs read: memory index, active task record, project
positioning/current state/decision/system/architecture/domain documents,
PI-100/105/110 completion records, exact PI-120 ticket and PI-130 boundary,
and relevant `UX-*`, `REN-*`, API, performance and recovery Spec sections.
- Canonical positioning and project-level success fields are placeholders and
the integrated memory still describes the legacy OpenCode UI. Repository
guidance plus the planner-owned Pi Spec/tickets and reviewed cumulative code
are authoritative for this feature branch.
- Confirmed seams: schema-v2 project/config/Conversation routes already provide
local-only metadata; PI-110 provides the typed Snapshot/prompt/SSE facade,
shared reducer, per-Conversation store, optimistic identity, target-only
recovery, and granular selectors. The current Chat page still imports the
legacy `OpencodeChatPanel` and is the cutover seam.
- No accepted ADR conflicts with this ticket. The attachment transport gap is
recorded above and has been escalated to the planner instead of silently
inventing a route.
- Gate result: Passed.
## Plan
1. Add the minimal vendor-neutral project/config/Conversation Renderer facade
and metadata store needed to load the active project, enabled Agents and
Conversations without touching the legacy OpenCode store.
2. Build a small `CodingChatPanel` composition and switch the Chat page to it;
make first-Conversation selection/creation local-only and keep Textarea
readiness independent of snapshot/runtime preparation.
3. Implement focused Composer submission/recovery UI over the PI-110 draft and
optimistic request lifecycle, including preparing/queued/running/error
status without a page-wide loading gate.
4. Implement memoized/windowed message, thinking, tool, compaction and boundary
blocks that update only the selected target and keep large/cumulative output
bounded; apply the planner's attachment ruling without expanding PI-130.
5. Add red-capable first-Conversation, core Chat, optimistic failure,
hidden-Conversation/render-count and 100 KB performance fixtures, plus the
first-prompt Electron E2E; then run focused/full validation, build,
documentation gates and planner review.
## Outcome
- Replaced the Chat page composition with a vendor-neutral `CodingChatPanel`
backed only by `/api/coding/*` facades. It loads active project/config/local
Conversation metadata, auto-creates the first local Conversation, and keeps
the Composer editable while runtime Snapshot preparation is held.
- Added text/image Composer behavior, stable optimistic user nodes, distinct
preparing/accepted/running/uncertain/error/recovery feedback, Enter/Shift+Enter
and IME handling, Send-time single-flight image upload, and authenticated
object-URL previews without base64 state or protocol payloads.
- Added a memoized/windowed timeline for message, Markdown, thinking, tool,
compaction, boundary and notice nodes. Hidden Conversation batches leave the
selected timeline selector stable; cumulative tool output is replaced rather
than duplicated.
- Added Main-owned attachment binary routes/IPC transport and public Snapshot +
`patch-batch` SSE delivery. Main batches at 24 ms by default with item/byte
early-flush bounds; Renderer atomically rejects malformed/gapped batches,
buffers during target recovery, trims Snapshot-covered items and replays only
a strict continuous tail.
- Fixed a supported concurrency defect exposed by the full suite: the Pi
Session Registry now reuses one Conversation store per project, serializing
simultaneous first bindings instead of racing writes to the same metadata
file.
- Synchronized `README.md` with the current Pi core Chat, first-Conversation,
batch and attachment behavior. PI-130 feature controls and PI-140 legacy
removal remain outside this task.
## Verification
- `pnpm exec vitest run tests/unit/coding-workspace-store.test.ts tests/unit/coding-projects-facade.test.ts tests/unit/coding-attachments-facade.test.ts tests/unit/coding-attachments-routes.test.ts tests/unit/coding-chat-panel.test.tsx tests/unit/coding-conversation-timeline.test.tsx tests/unit/coding-conversations-store.test.tsx tests/unit/coding-core-routes.test.ts tests/unit/host-api.test.ts tests/unit/host-api-proxy.test.ts`: passed, 10 files / 68 tests before the final malformed-batch and Session Registry regression additions.
- `pnpm exec vitest run tests/unit/pi-session-registry.test.ts tests/unit/pi-conversation-runtime.test.ts tests/unit/coding-conversations-store.test.tsx tests/unit/coding-chat-panel.test.tsx`: passed, 4 files / 25 tests.
- `pnpm test`: passed, 217 files / 2303 passed / 2 skipped. The final run is green after fixing the same-project parallel Session Registry write race and stabilizing the AI Hardware async query at its actual loading boundary.
- `pnpm run typecheck`: passed.
- `pnpm run lint:check`: passed with 0 errors and six unchanged warnings in `ExecutionGraphCard`, `Home`, and `Makelore`.
- `pnpm run build:vite`: passed; existing Vite dynamic-import and chunk-size warnings remain.
- `pnpm exec playwright test tests/e2e/pi-coding-first-chat.spec.ts`: passed, 1/1.
- `pnpm exec playwright test tests/e2e/pi-coding-first-chat.spec.ts --repeat-each=20 --workers=1`: passed, 20/20 fresh-userData runs. Every sample asserted Composer editability below 500 ms while runtime Snapshot was held, so the measured sample p95 is below the locked 500 ms budget; the same fixture verifies optimistic prompt visibility and HTTP 202 acceptance without a real Provider.
- `git diff --check`: passed; only repository line-ending conversion notices were printed.
- Real Provider remains **Explicitly Waived / Accepted Risk** with
`realTurnVerified=false`; no Provider Account, credential isolation,
protocol-specific endpoint, rate-limit or real concurrency behavior is
claimed as Pass.
- macOS x64/arm64 execution remains user-deferred to mandatory `PI-150`; no
macOS Pass is claimed.
## Follow-ups
- PI-130 owns Conversation model/thinking controls, steer/follow-up queue,
compaction/retry/context controls, interactions, subagents, changes/files,
browser, skills/commands, and archive/fork/title/unread UI.
- PI-140 owns removal of legacy OpenCode runtime/routes/dependencies/UI/tests
and migration notice.
- PI-150 must run final packaged cross-platform proof, including the deferred
macOS x64/arm64 matrix. Real Provider qualification remains explicitly waived
unless the user changes that decision.
## Promotion Candidates
- Preserve the public Snapshot + `patch-batch` hard-cut contract and the
target-only recovery semantics in the planner-owned Pi Spec/tickets after
implementation review.
- Preserve the explicit attachment upload/read Host contract, Send-time
single-flight rule, and reference-only Renderer state in the planner-owned
Pi Spec/tickets after implementation review.