diff options
| author | Adam Malczewski <[email protected]> | 2026-06-30 01:30:06 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-30 01:30:06 +0900 |
| commit | bf74aeab143a49005c380706ae9847cf064fd2f2 (patch) | |
| tree | c9e93dc0ebe818e7c0d0aafeba8387afd161da3f /frontend-compaction-handoff.md | |
| parent | 6dd9ea9b935e5011c16faed6c869c976cf5ff172 (diff) | |
| download | dispatch-main.tar.gz dispatch-main.zip | |
Removed 40+ markdown files that were cluttering the repo root:
- frontend-*-handoff.md (28 files) — historical API contract handoffs, features all implemented
- backend-to-fe-handoff.md, backend-to-fe-handoff-2.md — old handoff docs
- broken-chat-repair-handoff.md — old repair handoff
- PLAN-mcp.md, PLAN-per-edit-diagnostics.md — old planning docs
- ai-review-report.md, crash-review-report.md — one-time review reports
- tasks.md, HANDOFF.md — outdated status docs (git log is the source of truth)
Kept: AGENTS.md, GLOSSARY.md, ORCHESTRATOR.md, README.md
Also: gitignored ai-review-report.md so future Gemini reviews don't commit it
Diffstat (limited to 'frontend-compaction-handoff.md')
| -rw-r--r-- | frontend-compaction-handoff.md | 167 |
1 files changed, 0 insertions, 167 deletions
diff --git a/frontend-compaction-handoff.md b/frontend-compaction-handoff.md deleted file mode 100644 index 195bc1e..0000000 --- a/frontend-compaction-handoff.md +++ /dev/null @@ -1,167 +0,0 @@ -# FE handoff — conversation compacting - -Courier this to `../frontend`. All changes are ADDITIVE. - -## What shipped (backend) - -Conversation compaction: summarize old history into a summary + recent N, -preserving the full pre-compaction history in a separate archive conversation. -Creates a linked chain of archives you can walk backward. - -Two modes: -- **Manual**: `POST /conversations/:id/compact` — triggers immediately. -- **Automatic**: after each turn settles, the backend checks if the last turn's - input tokens exceeded the per-conversation `compactThreshold` (default 85). - If so, compaction runs automatically (fire-and-forget, non-blocking). - -## How compaction works — non-destructive, chained - -The compacted conversation **keeps its original ID** (so messaging between -agents still works). The old full history is **forked** to a new archive -conversation (new UUID). The archive inherits the source's `compactedFrom`, -creating a chain: - -``` -Compaction 1: A (ID "abc") — full history forked to X (new ID). - A's history replaced with [summary + recent N]. - A.compactedFrom = X - -Compaction 2: A (ID "abc") — current history forked to Y (new ID). - A's history replaced with [new summary + recent N]. - A.compactedFrom = Y - Y.compactedFrom = X (inherited from A's pre-compaction state) - -Chain: A → Y → X (walk compactedFrom backward) -``` - -Each archive is an **immutable snapshot** — a complete copy of the conversation -at the time of that compaction. History is never destroyed. - -The FE **does not switch tabs** — the conversation ID doesn't change. Just -reload the history. - -## Bump pinned deps -- `@dispatch/wire` → `0.11.0` -- `@dispatch/transport-contract` → `0.15.0` - -## New types - -```ts -// @dispatch/wire — ConversationMeta now has compactedFrom -export interface ConversationMeta { - readonly id: string; - readonly createdAt: number; - readonly lastActivityAt: number; - readonly title: string; - readonly status: ConversationStatus; // "active" | "idle" | "closed" - /** Points to the archive conversation with full pre-compaction history. */ - readonly compactedFrom?: string; -} - -// @dispatch/wire -export interface CompactionResult { - readonly summary: string; - readonly newConversationId: string; // ID of the archive (old full history) - readonly messagesSummarized: number; - readonly messagesKept: number; -} - -// @dispatch/transport-contract — WS message (server → client) -export interface ConversationCompactedMessage { - readonly type: "conversation.compacted"; - readonly conversationId: string; // the conversation (ID unchanged) - readonly newConversationId: string; // the archive ID (old full history) - readonly messagesSummarized: number; - readonly messagesKept: number; -} -// Added to WsServerMessage union. - -// @dispatch/transport-contract — HTTP response types -export interface CompactResponse { - readonly conversationId: string; // the conversation (ID unchanged) - readonly newConversationId: string; // the archive ID (old full history) - readonly messagesSummarized: number; - readonly messagesKept: number; -} - -export interface CompactPercentResponse { - readonly conversationId: string; - readonly percent: number; // 0 = manual only; null = default 85 -} - -export interface SetCompactPercentRequest { - readonly percent: number; -} -``` - -## `POST /conversations/:id/compact` — manual compaction - -Triggers compaction on demand. Optional JSON body: -```json -{ "keepLastN": 10, "modelName": "umans/umans-glm-5.2" } -``` -- `keepLastN` (default 10): how many recent messages to retain. -- `modelName`: override the model used for summarization. - -200 response: `CompactResponse` — includes `newConversationId` (the archive ID). -The conversation ID in the response is the same as the request — the ID doesn't -change. The FE should reload the conversation history. - -409: `{ error: string }` — conversation is generating, too short, percent not exceeded, etc. -503: compaction service not available. - -## `GET /conversations/:id/compact-percent` — read percent - -200: `CompactPercentResponse { conversationId, percent }` -- `percent: 0` — auto-compact explicitly disabled (manual only). -- `percent: null` (not stored) — **default: 85** (85% tokens). The FE - should display 85 as the default value in the settings UI. -- Any positive number — auto-compact triggers when the last turn's input tokens - exceed this value. - -## `PUT /conversations/:id/compact-percent` — set percent - -Body: `SetCompactPercentRequest { percent: number }` -- `0` explicitly disables auto-compact. -- Any positive number sets the trigger percent. -- To "reset to default", set it to 85. - -## `conversation.compacted` WS message - -Broadcast to all connected WS clients when compaction completes. The FE should -**reload the conversation history** via `GET /conversations/:id` (the -conversation ID hasn't changed — just reload the same ID). The first message -will now be a system summary. - -No tab switching needed — the ID is the same. - -## What the FE needs to do - -1. **Compact button** in the conversation toolbar → `POST /conversations/:id/compact`. - Show a loading indicator while waiting. On success, reload the conversation - history (same ID — just re-fetch). - -2. **Settings UI** for compact percent: `PUT /conversations/:id/compact-percent` - with `{ percent: number }`. A number input (0 = manual only, default 85). - Read the current value via `GET /conversations/:id/compact-percent`. - -3. **Handle `conversation.compacted` WS messages**: reload the conversation - history via `GET /conversations/:id` (same ID, no tab switch). - -4. **"View predecessor" link**: when `ConversationMeta.compactedFrom` is present, - show a link that opens the archive conversation in a read-only view (or a new - tab). Load it via `GET /conversations/:compactedFrom`. The archive has - `status: "closed"` and title `"Archive: <original>"`. Each archive may also - have its own `compactedFrom` — walk the chain backward to see every snapshot. - -5. **Archives in conversation list**: archives appear in - `GET /conversations?status=closed`. They have `compactedFrom` chaining to - the previous archive (if any). The FE can show them in a history view. - -6. **Visual indicator**: show a badge on conversations that have a - `compactedFrom` (they've been compacted). E.g. "Compacted" badge or chain icon. - -## CLI - -`dispatch compact <conversationId>` — triggers manual compaction. Resolves -short IDs like other commands. The response includes the archive ID. |
