docs: add Conversational Branching design spec
Full design for branching troubleshooting workspace — extends existing infrastructure without replacing it. Additive tables, nullable columns, dual-write backward compat. Removable if feature is pulled. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,498 @@
|
||||
# Conversational Branching — Design Spec
|
||||
|
||||
> **Date:** 2026-03-24
|
||||
> **Status:** Draft
|
||||
> **Branch:** `feat/conversational-branching` (to be created)
|
||||
> **Source:** `docs/ConversationalBranching_DataModel_Spec.docx` (original spec)
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Conversational Branching transforms FlowPilot from a linear AI chat into a branching troubleshooting workspace. Engineers explore multiple diagnostic hypotheses as first-class branches, with full AI context awareness across all paths.
|
||||
|
||||
The design is **additive and removable** — all branching state lives in new tables and nullable columns. If the feature is pulled, drop the tables, remove the columns, and the app works exactly as it does today.
|
||||
|
||||
---
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Extend, don't replace.** Reuse existing tables, services, and infrastructure. No parallel code paths.
|
||||
2. **Removable.** Every branching artifact (tables, columns, services, components) can be deleted without breaking existing functionality.
|
||||
3. **Dual-write for backward compat.** New handoff system writes to both `session_handoffs` table AND existing `escalation_package`/`escalated_to_id` fields until the old queue UI is fully migrated.
|
||||
4. **Branching services never touch the Anthropic SDK.** They assemble context and call `_call_ai` from `assistant_chat_service.py` — the same function `unified_chat_service` already uses.
|
||||
|
||||
---
|
||||
|
||||
## What This Enables
|
||||
|
||||
1. **Branch Map sidebar** — live tree visualization of all diagnostic paths, with status badges (active, dead end, solved, untried) and click-to-switch.
|
||||
2. **Fork Cards** — in-chat decision points where FlowPilot suggests multiple hypotheses, each becoming a branch.
|
||||
3. **Cross-branch AI context** — when exploring Branch 3, FlowPilot knows what was tried on Branches 1 and 2.
|
||||
4. **Branch revival** — new evidence from one branch can reopen a previously dead-end branch.
|
||||
5. **Unified handoff (park / escalate)** — single snapshot mechanism with intent toggle.
|
||||
6. **Three-output resolution package** — PSA ticket notes, KB article draft, and client-facing summary.
|
||||
|
||||
---
|
||||
|
||||
## Reuse Map
|
||||
|
||||
### What branching reuses (NOT duplicated):
|
||||
|
||||
| Capability | Existing Source | How Branching Uses It |
|
||||
|---|---|---|
|
||||
| LLM calls | `_call_ai` in `assistant_chat_service.py` | All branching LLM calls go through this |
|
||||
| Image content blocks | `_call_ai` multimodal support | Current branch images included in messages via existing format |
|
||||
| Token counting | `AISessionStep.input_tokens/output_tokens` | Unchanged — tokens tracked per step per branch |
|
||||
| RAG search | `rag_service.py` | Branch messages use same RAG pipeline |
|
||||
| Image upload + S3 storage | `file_uploads` table + `storage_service.py` | Extended with 5 new columns, no new table |
|
||||
| PSA push | `psa_documentation_service.py` | Resolution outputs and handoff notes push through existing service |
|
||||
| Escalation package | `_build_escalation_package_enhanced()` | HandoffManager reuses this for snapshot generation |
|
||||
| Escalation queue | Existing `ai_sessions` query + frontend | Dual-write keeps old queue working |
|
||||
| Session lifecycle | `flowpilot_engine.py` resolve/escalate/pause | Extended, not replaced |
|
||||
|
||||
### What's new:
|
||||
|
||||
| Capability | Notes |
|
||||
|---|---|
|
||||
| `session_branches` table | Core branching entity |
|
||||
| `fork_points` table | Decision point metadata (kept separate for expandability) |
|
||||
| `session_handoffs` table | Unified park/escalate with history |
|
||||
| `session_resolution_outputs` table | Three independent output deliverables |
|
||||
| `BranchManager` service | Branch lifecycle CRUD + context summary generation |
|
||||
| `BranchAwarePromptBuilder` service | Cross-branch context assembly |
|
||||
| `HandoffManager` service | Snapshot, assessment, claim, PSA push |
|
||||
| `ResolutionOutputGenerator` service | PSA notes, KB article, client summary generation |
|
||||
| AI description pipeline | Async `ai_description` generation on every file upload |
|
||||
|
||||
---
|
||||
|
||||
## Data Model
|
||||
|
||||
### Modified existing tables
|
||||
|
||||
**`ai_sessions` — add columns:**
|
||||
|
||||
| Column | Type | Default | Notes |
|
||||
|---|---|---|---|
|
||||
| `is_branching` | BOOLEAN | FALSE | Whether branching is active |
|
||||
| `active_branch_id` | UUID FK NULLABLE | NULL | Currently viewed branch |
|
||||
| `handoff_count` | INTEGER | 0 | Times handed off |
|
||||
| `total_active_seconds` | INTEGER | 0 | Cumulative active time |
|
||||
| `total_parked_seconds` | INTEGER | 0 | Cumulative parked time |
|
||||
|
||||
**`ai_session_steps` — add columns:**
|
||||
|
||||
| Column | Type | Default | Notes |
|
||||
|---|---|---|---|
|
||||
| `branch_id` | UUID FK NULLABLE | NULL | NULL = pre-branching/root |
|
||||
| `is_fork_point` | BOOLEAN | FALSE | Whether this step triggered a fork |
|
||||
| `fork_point_id` | UUID FK NULLABLE | NULL | References `fork_points.id` |
|
||||
|
||||
**`file_uploads` — add columns:**
|
||||
|
||||
| Column | Type | Default | Notes |
|
||||
|---|---|---|---|
|
||||
| `ai_description` | TEXT NULLABLE | NULL | AI-generated one-sentence description |
|
||||
| `extracted_content` | TEXT NULLABLE | NULL | Extracted text from logs/configs |
|
||||
| `content_summary` | TEXT NULLABLE | NULL | AI summary for long files |
|
||||
| `uploaded_on_branch_id` | UUID FK NULLABLE | NULL | Which branch the file was uploaded from |
|
||||
| `uploaded_at_step_id` | UUID FK NULLABLE | NULL | Which step triggered the upload |
|
||||
|
||||
All columns nullable. Existing rows unaffected. `ai_description` is always generated on upload (not just branching sessions) — useful for search, exports, PSA notes, Knowledge Flywheel.
|
||||
|
||||
Also add `'fork'` to `ai_session_steps.step_type` check constraint.
|
||||
|
||||
### New tables
|
||||
|
||||
**`session_branches`**
|
||||
|
||||
| Column | Type | Notes |
|
||||
|---|---|---|
|
||||
| `id` | UUID PK | |
|
||||
| `session_id` | UUID FK → `ai_sessions.id` CASCADE | |
|
||||
| `parent_branch_id` | UUID FK → self, NULLABLE | NULL = root branch |
|
||||
| `fork_point_step_id` | UUID FK → `ai_session_steps.id`, NULLABLE | Step where this branch forked |
|
||||
| `branch_order` | INTEGER | Display order among siblings (1-based) |
|
||||
| `label` | VARCHAR(200) | "Network connectivity", "Print spooler service" |
|
||||
| `status` | VARCHAR(20) | `active`, `dead_end`, `solved`, `untried`, `revived` |
|
||||
| `status_reason` | TEXT NULLABLE | AI-generated reason for status |
|
||||
| `status_changed_at` | TIMESTAMP NULLABLE | |
|
||||
| `status_changed_by` | UUID FK NULLABLE | |
|
||||
| `conversation_messages` | JSONB | LLM message history scoped to this branch |
|
||||
| `context_summary` | JSONB | `{tried: [], concluded: str, artifacts: []}` |
|
||||
| `evidence_from_branch_id` | UUID FK NULLABLE | If revived, evidence source |
|
||||
| `evidence_description` | TEXT NULLABLE | What triggered revival |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
| `updated_at` | TIMESTAMP | |
|
||||
|
||||
Indexes: `session_id`, `parent_branch_id`, `(session_id, status)`, `(session_id, branch_order)`.
|
||||
Check constraints: `status IN (...)`, `branch_order > 0`.
|
||||
|
||||
**`fork_points`**
|
||||
|
||||
| Column | Type | Notes |
|
||||
|---|---|---|
|
||||
| `id` | UUID PK | |
|
||||
| `session_id` | UUID FK → `ai_sessions.id` | |
|
||||
| `parent_branch_id` | UUID FK → `session_branches.id` | Branch this fork occurs in |
|
||||
| `trigger_step_id` | UUID FK → `ai_session_steps.id`, NULLABLE | Step that triggered fork |
|
||||
| `fork_reason` | TEXT | AI explanation |
|
||||
| `options` | JSONB | `[{label, description, branch_id, status}]` |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
|
||||
**`session_handoffs`**
|
||||
|
||||
| Column | Type | Notes |
|
||||
|---|---|---|
|
||||
| `id` | UUID PK | |
|
||||
| `session_id` | UUID FK → `ai_sessions.id` | |
|
||||
| `handed_off_by` | UUID FK → `users.id` | |
|
||||
| `intent` | VARCHAR(20) | `park` or `escalate` |
|
||||
| `source_branch_id` | UUID FK NULLABLE | Active branch at handoff |
|
||||
| `snapshot` | JSONB | Branch map, status, next step, waiting on, watch out |
|
||||
| `ai_assessment` | TEXT NULLABLE | Diagnostic assessment (escalate only) |
|
||||
| `ai_assessment_data` | JSONB NULLABLE | `{likely_cause, suggested_steps, confidence}` |
|
||||
| `artifacts` | JSONB NULLABLE | `[{name, type, reference}]` |
|
||||
| `engineer_notes` | TEXT NULLABLE | |
|
||||
| `priority` | VARCHAR(20) | `normal` or `elevated` |
|
||||
| `claimed_by` | UUID FK NULLABLE | |
|
||||
| `claimed_at` | TIMESTAMP NULLABLE | |
|
||||
| `psa_note_pushed` | BOOLEAN DEFAULT FALSE | |
|
||||
| `psa_note_id` | VARCHAR(100) NULLABLE | |
|
||||
| `notification_sent` | BOOLEAN DEFAULT FALSE | |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
|
||||
Check constraints: `intent IN ('park', 'escalate')`, `priority IN ('normal', 'elevated')`.
|
||||
Dual-write: on create, also populates `ai_sessions.escalation_package` and `escalated_to_id`.
|
||||
|
||||
**`session_resolution_outputs`**
|
||||
|
||||
| Column | Type | Notes |
|
||||
|---|---|---|
|
||||
| `id` | UUID PK | |
|
||||
| `session_id` | UUID FK → `ai_sessions.id` | |
|
||||
| `output_type` | VARCHAR(30) | `psa_ticket_notes`, `knowledge_base`, `client_summary` |
|
||||
| `generated_content` | TEXT | AI-generated output |
|
||||
| `structured_data` | JSONB NULLABLE | For KB: `{symptoms, root_cause, steps, tags}` |
|
||||
| `edited_content` | TEXT NULLABLE | Engineer's edited version |
|
||||
| `status` | VARCHAR(20) | `draft`, `approved`, `pushed`, `rejected` |
|
||||
| `pushed_to` | VARCHAR(50) NULLABLE | `psa`, `kb_library`, `clipboard`, `email` |
|
||||
| `pushed_at` | TIMESTAMP NULLABLE | |
|
||||
| `pushed_reference` | VARCHAR(200) NULLABLE | External ID after push |
|
||||
| `generated_by_model` | VARCHAR(50) | |
|
||||
| `created_at` | TIMESTAMP | |
|
||||
| `updated_at` | TIMESTAMP | |
|
||||
|
||||
Constraints: `UNIQUE(session_id, output_type)`, check constraints on `output_type` and `status`.
|
||||
|
||||
### Entity Relationships
|
||||
|
||||
```
|
||||
AISession 1──* SessionBranch (session has many branches)
|
||||
AISession 1──* AISessionStep (unchanged)
|
||||
AISession 1──* SessionHandoff (can be handed off multiple times)
|
||||
AISession 1──3 SessionResolutionOutput (one per output type)
|
||||
SessionBranch 1──* AISessionStep (branch owns steps via branch_id)
|
||||
SessionBranch 1──* SessionBranch (parent → children, self-referential)
|
||||
SessionBranch 1──* ForkPoint (branch contains fork points)
|
||||
ForkPoint 1──* SessionBranch (each option becomes a branch)
|
||||
SessionHandoff *──1 User (handed_off_by, claimed_by)
|
||||
FileUpload *──1 SessionBranch (optional, via uploaded_on_branch_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service Layer
|
||||
|
||||
### Integration Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ LAYER 3: BRANCHING SERVICES (NEW) │
|
||||
│ │
|
||||
│ BranchManager — Fork, switch, mark status, revive, │
|
||||
│ tree query, context summary gen │
|
||||
│ │
|
||||
│ BranchAwarePromptBuilder — Assembles system prompt + │
|
||||
│ messages + images with cross- │
|
||||
│ branch context, returns dict │
|
||||
│ for _call_ai │
|
||||
│ │
|
||||
│ HandoffManager — Snapshot, AI assessment, claim, │
|
||||
│ briefing, PSA push, queue query │
|
||||
│ │
|
||||
│ ResolutionOutputGen — PSA notes, KB article, client │
|
||||
│ summary, push to destination │
|
||||
└────────────────────────────┬────────────────────────────────┘
|
||||
│ calls _call_ai directly
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ LAYER 2: EXISTING CHAT INFRASTRUCTURE │
|
||||
│ │
|
||||
│ _call_ai / _call_anthropic_cached │
|
||||
│ — Anthropic API, prompt caching, image blocks, MCP │
|
||||
│ │
|
||||
│ unified_chat_service — Session-level chat (linear) │
|
||||
│ flowpilot_engine — Step lifecycle, resolve, escalate │
|
||||
│ rag_service — Flow library search │
|
||||
│ psa_documentation_service — ConnectWise note push │
|
||||
└────────────────────────────┬────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ LAYER 1: INFRASTRUCTURE (EXISTS) │
|
||||
│ │
|
||||
│ Railway Object Storage — S3 bucket, presigned URLs │
|
||||
│ PostgreSQL — All data │
|
||||
│ Anthropic API — Claude with Vision │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### `services/branch_manager.py`
|
||||
|
||||
Branch lifecycle management. Pure data operations + one LLM call pattern (context summary).
|
||||
|
||||
| Method | What it does | LLM call? |
|
||||
|---|---|---|
|
||||
| `create_root_branch(session_id)` | Creates root branch, sets `is_branching=True`, copies `session.conversation_messages` into root branch. Session-level field kept as pre-branching snapshot. | No |
|
||||
| `create_fork(session_id, parent_branch_id, trigger_step_id, fork_reason, options[])` | Creates `ForkPoint` + N `SessionBranch` rows. Sets `is_fork_point=True` on trigger step. Unexplored options get status `untried`. | No |
|
||||
| `switch_branch(session_id, target_branch_id)` | Updates `session.active_branch_id`. Returns branch with context. | No |
|
||||
| `mark_branch_status(branch_id, status, reason)` | Updates status. Generates `context_summary` via `_call_ai`. | Yes — summary |
|
||||
| `revive_branch(branch_id, evidence_from_branch_id, evidence_description)` | Sets status `revived`, records evidence source, prepends revival context to branch messages. | No |
|
||||
| `get_branch_tree(session_id)` | Full tree with status, labels, step counts, summaries. | No |
|
||||
| `build_cross_branch_context(branch_id)` | Reads `context_summary` from all sibling branches, returns formatted text. | No |
|
||||
|
||||
### `services/branch_aware_prompt_builder.py`
|
||||
|
||||
Pure function — takes data, returns assembled prompt components. No DB access, no LLM calls.
|
||||
|
||||
**Single method:** `build(branch, sibling_summaries, session_context, attachments, token_budget)`
|
||||
|
||||
Returns: `{system_prompt: str, history: list[dict], new_message: str, images: list[dict]}`
|
||||
|
||||
Preserves `_call_ai`'s cache breakpoint behavior by separating history from new message.
|
||||
|
||||
**Assembly order:**
|
||||
1. Session context (~2,000 tokens) — problem summary, domain, client info, PSA data
|
||||
2. Cross-branch summaries (~3,000 token cap) — prioritized: active > untried > revived > dead_end
|
||||
3. Revival context — if branch was revived, prepend evidence
|
||||
4. Attachment descriptions (~1,000 tokens) — `ai_description` from other branches' uploads
|
||||
5. Branch messages (remaining budget) — last 10-15 turns verbatim, older summarized
|
||||
6. Token budget enforcement — compress: old messages → dead-end summaries → file content → never drop system prompt, last 5 messages, branch status map
|
||||
|
||||
### `services/handoff_manager.py`
|
||||
|
||||
Unified park/escalate with dual-write backward compatibility.
|
||||
|
||||
| Method | What it does | LLM call? |
|
||||
|---|---|---|
|
||||
| `create_handoff(session_id, intent, engineer_notes, user_id)` | Creates `SessionHandoff`. Calls `generate_snapshot()`. If escalate, calls `generate_ai_assessment()`. Dual-writes to `session.escalation_package` + `escalated_to_id`. | Escalate only |
|
||||
| `generate_snapshot(session_id)` | Serializes branch tree into snapshot JSONB. Reuses `_build_escalation_package_enhanced()` for steps-tried data. | No |
|
||||
| `generate_ai_assessment(session_id)` | Full session + branch context → diagnostic assessment. | Yes |
|
||||
| `generate_briefing(handoff_id, claiming_user_id)` | Natural-language handoff summary for claiming engineer. | Yes |
|
||||
| `claim_session(handoff_id, claiming_user_id)` | Updates `claimed_by/at`, sets session `active`. Dual-writes `escalation_package`. | No |
|
||||
| `push_to_psa(handoff_id)` | Calls existing `psa_documentation_service`. | No |
|
||||
| `get_queue(team_id, filters)` | DB query for parked + escalated sessions. | No |
|
||||
|
||||
### `services/resolution_output_generator.py`
|
||||
|
||||
Three LLM calls on resolve, each through `_call_ai`.
|
||||
|
||||
| Method | What it does | LLM call? |
|
||||
|---|---|---|
|
||||
| `generate_all(session_id)` | Creates 3 `SessionResolutionOutput` rows. | 3 calls |
|
||||
| `generate_psa_notes(session_id)` | Structured ticket notes with full branch history. | Yes |
|
||||
| `generate_kb_article(session_id)` | KB draft — dead-end branches become "rule out first" guidance. `structured_data` has `{symptoms, root_cause, steps, tags}`. | Yes |
|
||||
| `generate_client_summary(session_id)` | Non-technical summary for end user. | Yes |
|
||||
| `push_output(output_id, destination)` | Routes: `psa` → `psa_documentation_service`, `kb_library` → flow/step library, `clipboard` → returns content. | No |
|
||||
|
||||
### AI Description Pipeline (upload extension)
|
||||
|
||||
Not a new service — extends the existing upload endpoint in `uploads.py`:
|
||||
|
||||
1. Upload completes, response returned immediately.
|
||||
2. Background task (via `asyncio.create_task`) calls `_call_ai` with image + prompt: "Describe this in one sentence for a troubleshooting context log."
|
||||
3. Result written to `file_uploads.ai_description`.
|
||||
4. For text files: extract content directly, call `_call_ai` for summary if >2,000 tokens.
|
||||
5. Always runs (not just branching sessions) — useful for search, exports, PSA notes.
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
All under existing `/api` prefix, JWT auth, team-scoped.
|
||||
|
||||
### Branch Management
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|---|---|---|
|
||||
| GET | `/ai-sessions/{id}/branches` | List all branches (tree structure) |
|
||||
| POST | `/ai-sessions/{id}/branches/fork` | Create fork point with N branches |
|
||||
| PATCH | `/ai-sessions/{id}/branches/{bid}` | Update branch status |
|
||||
| POST | `/ai-sessions/{id}/branches/{bid}/switch` | Switch active branch |
|
||||
| POST | `/ai-sessions/{id}/branches/{bid}/revive` | Revive dead-end with evidence |
|
||||
| POST | `/ai-sessions/{id}/branches/{bid}/message` | Send message on a specific branch |
|
||||
|
||||
### Handoff (Park / Escalate)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|---|---|---|
|
||||
| POST | `/ai-sessions/{id}/handoff` | Create handoff (park or escalate) |
|
||||
| GET | `/ai-sessions/{id}/handoffs` | Handoff history for session |
|
||||
| POST | `/ai-sessions/{id}/handoffs/{hid}/claim` | Claim a handed-off session |
|
||||
| GET | `/ai-sessions/queue` | Team queue (parked + escalated) |
|
||||
|
||||
### Resolution Outputs
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|---|---|---|
|
||||
| POST | `/ai-sessions/{id}/resolve` | Resolve + auto-generate 3 outputs |
|
||||
| GET | `/ai-sessions/{id}/outputs` | Get all resolution outputs |
|
||||
| PATCH | `/ai-sessions/{id}/outputs/{oid}` | Edit output before pushing |
|
||||
| POST | `/ai-sessions/{id}/outputs/{oid}/push` | Push to destination |
|
||||
|
||||
Note: endpoints nest under `/ai-sessions` (not `/api/v1/sessions` as the original spec proposed) to match existing routing conventions.
|
||||
|
||||
---
|
||||
|
||||
## Token Budget Strategy
|
||||
|
||||
### Budget Allocation
|
||||
|
||||
| Context Layer | Budget | Strategy |
|
||||
|---|---|---|
|
||||
| System prompt + session context | ~2,000 tokens | Fixed |
|
||||
| Cross-branch summaries | ~3,000 tokens | Scales with branch count. Each summary ~200-500 tokens. Cap at 3,000. |
|
||||
| Current branch messages | Remaining budget | Last 10-15 turns verbatim. Older summarized. |
|
||||
| Attachment descriptions | ~1,000 tokens | Included in cross-branch summaries |
|
||||
|
||||
### Graceful Degradation (in order)
|
||||
|
||||
1. Summarize old current-branch messages (keep last 8-10 verbatim)
|
||||
2. Trim cross-branch summaries (dead-end → one sentence)
|
||||
3. Drop file content, keep descriptions
|
||||
4. **Never drop:** system prompt, problem summary, last 5 messages, branch status map
|
||||
|
||||
### Branch Limits by Plan
|
||||
|
||||
| Plan | Max Branches | Rationale |
|
||||
|---|---|---|
|
||||
| Free | 2 | Experience branching, limit cost |
|
||||
| Pro | 5 | Covers most scenarios |
|
||||
| Team | 10 | Complex multi-path issues |
|
||||
| Enterprise | Unlimited | |
|
||||
|
||||
---
|
||||
|
||||
## Frontend Components
|
||||
|
||||
| Component | Location | Description |
|
||||
|---|---|---|
|
||||
| `BranchMap` | `components/session/BranchMap.tsx` | Sidebar tree visualization with status badges |
|
||||
| `BranchNode` | `components/session/BranchNode.tsx` | Individual node in branch map |
|
||||
| `ForkCard` | `components/session/ForkCard.tsx` | In-chat fork decision point |
|
||||
| `BranchTransitionBar` | `components/session/BranchTransitionBar.tsx` | Context bar on branch switch |
|
||||
| `BranchRevivalCard` | `components/session/BranchRevivalCard.tsx` | Evidence card for revival |
|
||||
| `HandoffModal` | `components/session/HandoffModal.tsx` | Unified park/escalate modal |
|
||||
| `ResolutionOutputPanel` | `components/session/ResolutionOutputPanel.tsx` | Three-tab resolution view |
|
||||
| `SessionQueuePage` | `pages/SessionQueuePage.tsx` | Team queue for parked/escalated |
|
||||
|
||||
| Hook | Location | Description |
|
||||
|---|---|---|
|
||||
| `useBranching` | `hooks/useBranching.ts` | Branch state management |
|
||||
| `useHandoff` | `hooks/useHandoff.ts` | Handoff flow state |
|
||||
| `useResolutionOutputs` | `hooks/useResolutionOutputs.ts` | Resolution output state |
|
||||
|
||||
| API Client | Location | Description |
|
||||
|---|---|---|
|
||||
| `branches.ts` | `api/branches.ts` | Branch API client |
|
||||
| `handoffs.ts` | `api/handoffs.ts` | Handoff API client |
|
||||
| `resolutions.ts` | `api/resolutions.ts` | Resolution output API client |
|
||||
|
||||
---
|
||||
|
||||
## Backend File Locations
|
||||
|
||||
```
|
||||
backend/app/
|
||||
├── models/
|
||||
│ ├── session_branch.py # SessionBranch model
|
||||
│ ├── fork_point.py # ForkPoint model
|
||||
│ ├── session_handoff.py # SessionHandoff model
|
||||
│ └── session_resolution_output.py # SessionResolutionOutput model
|
||||
├── schemas/
|
||||
│ ├── session_branch.py # Pydantic schemas
|
||||
│ ├── session_handoff.py # Pydantic schemas
|
||||
│ └── session_resolution.py # Pydantic schemas
|
||||
├── services/
|
||||
│ ├── branch_manager.py # Branch lifecycle
|
||||
│ ├── branch_aware_prompt_builder.py # Cross-branch context assembly
|
||||
│ ├── handoff_manager.py # Park/escalate
|
||||
│ └── resolution_output_generator.py # 3-output generator
|
||||
├── api/endpoints/
|
||||
│ ├── session_branches.py # Branch API router
|
||||
│ ├── session_handoffs.py # Handoff API router
|
||||
│ └── session_resolutions.py # Resolution output API router
|
||||
└── alembic/versions/
|
||||
└── xxx_add_branching_tables.py # Single migration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Data Foundation (est. 2 days)
|
||||
- Create 4 new models + Pydantic schemas
|
||||
- Add columns to `ai_sessions`, `ai_session_steps`, `file_uploads`
|
||||
- Single Alembic migration (all additive)
|
||||
- Unit tests for model creation and relationships
|
||||
|
||||
### Phase 2: Branch Engine (est. 2-3 days)
|
||||
- `BranchManager` service
|
||||
- `BranchAwarePromptBuilder` service
|
||||
- Branch API endpoints
|
||||
- Integration with FlowPilot engine (branch_id on step creation)
|
||||
- Integration tests: create → fork → explore → dead-end → switch → verify cross-branch context
|
||||
|
||||
### Phase 3: Handoff System (est. 1.5-2 days)
|
||||
- `HandoffManager` service with dual-write
|
||||
- Handoff API endpoints + queue endpoint
|
||||
- PSA push integration (reuses existing service)
|
||||
- Tests: park → verify snapshot. Escalate → verify assessment. Claim from queue.
|
||||
|
||||
### Phase 4: Resolution Outputs (est. 1.5-2 days)
|
||||
- `ResolutionOutputGenerator` service
|
||||
- Resolution API endpoints + push logic
|
||||
- KB article generation with dead-end branch "rule out" guidance
|
||||
- Tests: resolve multi-branch session → verify 3 outputs → edit → push
|
||||
|
||||
### Phase 5: AI Description Pipeline (est. 0.5 day)
|
||||
- Extend upload endpoint with async `ai_description` generation
|
||||
- Add `extracted_content` + `content_summary` for text files
|
||||
- Tests: upload image → verify `ai_description` populated
|
||||
|
||||
### Phase 6: Frontend (est. 3-4 days)
|
||||
- Branch Map sidebar (tree vis, status badges, click-to-switch)
|
||||
- Fork Card component (in-chat decision point)
|
||||
- Branch transition animation
|
||||
- Handoff modal (unified park/escalate)
|
||||
- Session queue page
|
||||
- Resolution output panel (three-tab view + edit + push)
|
||||
- Branch revival UI
|
||||
|
||||
---
|
||||
|
||||
## Removability Checklist
|
||||
|
||||
If this feature is pulled:
|
||||
|
||||
1. Drop tables: `session_branches`, `fork_points`, `session_handoffs`, `session_resolution_outputs`
|
||||
2. Remove columns from `ai_sessions`: `is_branching`, `active_branch_id`, `handoff_count`, `total_active_seconds`, `total_parked_seconds`
|
||||
3. Remove columns from `ai_session_steps`: `branch_id`, `is_fork_point`, `fork_point_id`
|
||||
4. Remove columns from `file_uploads`: `uploaded_on_branch_id`, `uploaded_at_step_id` (keep `ai_description`, `extracted_content`, `content_summary` — useful independently)
|
||||
5. Remove `'fork'` from step_type check constraint
|
||||
6. Delete service files: `branch_manager.py`, `branch_aware_prompt_builder.py`, `handoff_manager.py`, `resolution_output_generator.py`
|
||||
7. Delete endpoint files: `session_branches.py`, `session_handoffs.py`, `session_resolutions.py`
|
||||
8. Delete frontend components/hooks/API clients listed above
|
||||
9. Existing escalation flow, upload pipeline, chat service, PSA integration — **all untouched**
|
||||
Reference in New Issue
Block a user