This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/FORKING_IMPL.md
2026-02-21 16:53:07 +00:00

97 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Message Editing & Forking — Implementation
**Version:** 0.7.x (Phase 2 per ARCHITECTURE.md §8)
**Depends on:** parent_id (006), channel_cursors (008) — both deployed
---
## Status: Complete (backend + frontend)
### Backend (already existed)
- [x] Migration 013 (`deleted_at`, `sibling_index`)
- [x] `tree.go``getActivePath`, `getActiveLeaf`, `getPathToLeaf`, `getSiblings`,
`findLeafFromMessage`, `nextSiblingIndex`, `updateCursor`
- [x] `completion.go``loadConversation` walks active path via recursive CTE,
`persistMessage` is cursor-aware with sibling_index, returns new message ID
- [x] `messages.go``GetActivePath`, `EditMessage`, `Regenerate` (streaming + sibling),
`UpdateCursor`, `ListSiblings`
- [x] Routes wired in `main.go`
### Frontend (new work)
- [x] `api.js``getActivePath`, `editMessage`, `streamRegenerate`, `updateCursor`, `listSiblings`
- [x] `app.js` — tree-aware message flow:
- `selectChat` uses `/path` endpoint
- `sendMessage` reloads path after streaming for server-authoritative IDs
- `regenerateMessage(id)` creates sibling via message-specific endpoint
- `editMessage(id)` → inline edit → `submitEdit` → sibling + completion
- `switchSibling(id, direction)` navigates branches via cursor update
- `reloadActivePath()` refreshes from server after every mutation
- Legacy `regenerate()` button delegates to `regenerateMessage(lastAssistantId)`
- [x] `ui.js`:
- `_messageHTML` renders 1/3 branch indicators at fork points
- Edit button on user messages, Regen button on assistant messages
- `showEditInline` — textarea with Ctrl+Enter submit, Escape cancel
- [x] `styles.css``.branch-nav`, `.branch-arrow`, `.branch-pos`,
`.msg-edit-input`, `.msg-edit-actions`, `.msg-edit-cancel`, `.msg-edit-submit`
---
## API Endpoints
| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/channels/:id/path` | Active path with sibling metadata |
| `POST` | `/channels/:id/messages/:msgId/edit` | Create sibling user message |
| `POST` | `/channels/:id/messages/:msgId/regenerate` | Create sibling assistant response (SSE) |
| `PUT` | `/channels/:id/cursor` | Switch active branch |
| `GET` | `/channels/:id/messages/:msgId/siblings` | List siblings at a fork point |
---
## Design Decisions
1. **`sibling_index` column** — explicit integer, not derived from `created_at`. Tree is self-describing.
2. **New `/path` endpoint**`ListMessages` retained for admin/debug. Frontend uses `/path` exclusively.
3. **Two-step edit** — API: edit creates sibling, completion is separate. Frontend chains them.
4. **Uniform arrows** — same UI regardless of how fork was created (edit, regen, explicit).
5. **Message-specific regenerate** — replaces old channel-level stub. Bottom-bar button delegates.
6. **Branch switch → leaf** — clicking mid-tree sibling walks to deepest descendant via `findLeafFromMessage`.
7. **Path reload after every mutation**`reloadActivePath()` called post-send, edit, regen, abort.
---
## User Flows
### Edit a message
1. Hover user message → click **Edit**
2. Textarea replaces message text (Ctrl+Enter to submit, Escape to cancel)
3. Submit → `POST /messages/:id/edit` (creates sibling) → `POST /chat/completions` (new response)
4. Branch indicator appears: 1/2
5. Old branch preserved, navigable via arrows
### Regenerate a response
1. Hover assistant message → click **Regen** (or bottom-bar ↻ button)
2. `POST /messages/:id/regenerate` streams new response as sibling
3. Branch indicator appears: 1/2
4. Original response preserved, navigable via arrows
### Navigate branches
1. Click or on any fork point
2. `GET /messages/:id/siblings` → pick adjacent → `PUT /cursor` with sibling ID
3. Backend walks to leaf, returns new path
4. Entire conversation below fork point updates to show selected branch
---
## Testing Checklist
- [ ] Existing linear conversations load and render correctly (backward compat)
- [ ] New messages in linear conversation work as before
- [ ] Regen creates sibling, shows 1/2 , original preserved
- [ ] Multiple regens show 1/3 , all navigable
- [ ] Edit creates sibling user message + triggers new completion
- [ ] Branch arrows navigate correctly (← older, → newer)
- [ ] Context sent to LLM is active path only (no cross-branch pollution)
- [ ] Cursor persists across page reload (reopening chat shows last-viewed branch)
- [ ] Mobile: edit textarea usable, branch arrows tappable