fix: ChatBubble crash and DeepSeek API compatibility
- Fix ChatBubble to handle non-string content with String() wrapper - Fix API route to use generateText for non-streaming requests - Add @ai-sdk/openai-compatible for non-OpenAI providers (DeepSeek, etc.) - Use Chat Completions API instead of Responses API for compatible providers - Update ChatBubble tests and fix component exports to kebab-case - Remove stale PascalCase ChatBubble.tsx file
This commit is contained in:
@@ -0,0 +1,514 @@
|
||||
# Story 2.1: Ghostwriter Agent & Markdown Generation
|
||||
|
||||
Status: done
|
||||
|
||||
<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
|
||||
|
||||
## Story
|
||||
|
||||
As a user,
|
||||
I want the system to draft a polished post based on my chat,
|
||||
So that I can see my raw thoughts transformed into value.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
1. **Ghostwriter Agent Trigger**
|
||||
- Given the user has completed the interview or used "Fast Track"
|
||||
- When the "Ghostwriter" agent is triggered
|
||||
- Then it consumes the entire chat history and the "Lesson" context
|
||||
- And generates a structured Markdown artifact (Title, Body, Tags)
|
||||
|
||||
2. **Drafting Animation**
|
||||
- Given the generation is processing
|
||||
- When the user waits
|
||||
- Then they see a distinct "Drafting" animation (different from "Typing")
|
||||
- And the tone of the output matches the "Professional/LinkedIn" persona
|
||||
|
||||
## Tasks / Subtasks
|
||||
|
||||
- [x] Implement Ghostwriter Prompt Engine
|
||||
- [x] Create `generateGhostwriterPrompt()` function in `src/lib/llm/prompt-engine.ts`
|
||||
- [x] Build prompt structure: Chat history + Intent context + Persona instructions
|
||||
- [x] Define output format: Markdown with Title, Body, Tags sections
|
||||
- [x] Add constraints: Professional tone, no hallucinations, grounded in user input
|
||||
|
||||
- [x] Implement Ghostwriter LLM Service
|
||||
- [x] Create `getGhostwriterResponse()` in `src/services/llm-service.ts`
|
||||
- [x] Handle streaming response for draft generation
|
||||
- [x] Add retry logic for failed generations
|
||||
- [x] Return structured Markdown object
|
||||
|
||||
- [x] Create Draft State Management
|
||||
- [x] Add draft state to ChatStore: `currentDraft`, `isDrafting`
|
||||
- [x] Add `generateDraft()` action to trigger Ghostwriter
|
||||
- [x] Add `clearDraft()` action for state reset
|
||||
- [x] Persist draft to `drafts` table in IndexedDB
|
||||
|
||||
- [x] Implement Drafting Indicator
|
||||
- [x] Create `DraftingIndicator.tsx` component
|
||||
- [x] Use distinct animation (shimmer/skeleton) different from typing indicator
|
||||
- [x] Show "Drafting your post..." message with professional tone
|
||||
|
||||
- [x] Create Draft Storage Schema
|
||||
- [x] Add `drafts` table to Dexie schema in `src/lib/db/index.ts`
|
||||
- [x] Define Draft interface: id, sessionId, title, content, tags, createdAt, status
|
||||
- [x] Add indexes for querying drafts by session and date
|
||||
|
||||
- [x] Integrate Ghostwriter with Chat Service
|
||||
- [x] Modify `ChatService` to route to Ghostwriter after interview completion
|
||||
- [x] Implement trigger logic: user taps "Draft It" or Fast Track sends input
|
||||
- [x] Store generated draft in IndexedDB
|
||||
- [x] Update ChatStore with draft result
|
||||
|
||||
- [x] Test Ghostwriter End-to-End
|
||||
- [x] Unit test: Prompt generation with various chat histories
|
||||
- [x] Unit test: Ghostwriter LLM service with mocked responses
|
||||
- [x] Integration test: Full flow from chat to draft generation
|
||||
- [x] Integration test: Fast Track triggers Ghostwriter directly
|
||||
- [x] Edge case: Empty chat history
|
||||
- [x] Edge case: Very long chat history (token limits)
|
||||
|
||||
## Dev Notes
|
||||
|
||||
### Architecture Compliance (CRITICAL)
|
||||
|
||||
**Logic Sandwich Pattern - DO NOT VIOLATE:**
|
||||
- **UI Components** MUST NOT import `src/lib/llm` or `src/services/llm-service.ts` directly
|
||||
- All Ghostwriter logic MUST go through `ChatService` layer
|
||||
- ChatService then calls `LLMService` as needed
|
||||
- Components use Zustand store via atomic selectors only
|
||||
- Services return plain objects, not Dexie observables
|
||||
|
||||
**State Management - Atomic Selectors Required:**
|
||||
```typescript
|
||||
// BAD - Causes unnecessary re-renders
|
||||
const { currentDraft, isDrafting } = useChatStore();
|
||||
|
||||
// GOOD - Atomic selectors
|
||||
const currentDraft = useChatStore(s => s.currentDraft);
|
||||
const isDrafting = useChatStore(s => s.isDrafting);
|
||||
const generateDraft = useChatStore(s => s.generateDraft);
|
||||
```
|
||||
|
||||
**Local-First Data Boundary:**
|
||||
- Generated drafts MUST be stored in IndexedDB (`drafts` table)
|
||||
- Drafts are the primary artifacts - chat history is the source context
|
||||
- Drafts persist offline and can be accessed from history view
|
||||
- No draft content sent to server for storage
|
||||
|
||||
**Edge Runtime Constraint:**
|
||||
- All API routes under `app/api/` must use the Edge Runtime
|
||||
- The Ghostwriter LLM call goes through `/api/llm` route (same as Teacher)
|
||||
- Code: `export const runtime = 'edge';`
|
||||
|
||||
### Architecture Implementation Details
|
||||
|
||||
**Story Purpose:**
|
||||
This is the FIRST story of Epic 2 ("The Magic Mirror"). It implements the core value proposition: transforming raw chat input into a polished artifact. The Ghostwriter Agent is the "magic" that turns venting into content.
|
||||
|
||||
**State Management:**
|
||||
```typescript
|
||||
// Add to ChatStore (src/lib/store/chat-store.ts)
|
||||
interface ChatStore {
|
||||
// Draft state
|
||||
currentDraft: Draft | null;
|
||||
isDrafting: boolean;
|
||||
generateDraft: (sessionId: string) => Promise<void>;
|
||||
clearDraft: () => void;
|
||||
}
|
||||
|
||||
interface Draft {
|
||||
id: string;
|
||||
sessionId: string;
|
||||
title: string;
|
||||
content: string; // Markdown formatted
|
||||
tags: string[];
|
||||
createdAt: number;
|
||||
status: 'draft' | 'completed' | 'regenerated';
|
||||
}
|
||||
```
|
||||
|
||||
**Dexie Schema Extensions:**
|
||||
```typescript
|
||||
// Add to src/lib/db/schema.ts
|
||||
db.version(1).stores({
|
||||
chatLogs: 'id, sessionId, timestamp, role',
|
||||
sessions: 'id, createdAt, updatedAt',
|
||||
drafts: 'id, sessionId, createdAt, status' // NEW table
|
||||
});
|
||||
|
||||
interface DraftRecord {
|
||||
id: string;
|
||||
sessionId: string;
|
||||
title: string;
|
||||
content: string;
|
||||
tags: string[];
|
||||
createdAt: number;
|
||||
status: 'draft' | 'completed' | 'regenerated';
|
||||
}
|
||||
```
|
||||
|
||||
**Logic Flow:**
|
||||
1. User completes interview OR uses Fast Track
|
||||
2. ChatService detects "ready to draft" state
|
||||
3. ChatService calls `LLMService.getGhostwriterResponse(chatHistory, intent)`
|
||||
4. LLMService streams response through `/api/llm` edge function
|
||||
5. ChatStore updates `isDrafting` state (shows drafting indicator)
|
||||
6. On completion, draft stored in IndexedDB and ChatStore updated
|
||||
7. Draft view UI displays the result (Story 2.2)
|
||||
|
||||
**Files to Create:**
|
||||
- `src/components/features/chat/DraftingIndicator.tsx` - Drafting animation component
|
||||
- `src/lib/db/draft-service.ts` - Draft CRUD operations (follows Service pattern)
|
||||
|
||||
**Files to Modify:**
|
||||
- `src/lib/db/schema.ts` - Add drafts table
|
||||
- `src/lib/llm/prompt-engine.ts` - Add `generateGhostwriterPrompt()` function
|
||||
- `src/services/llm-service.ts` - Add `getGhostwriterResponse()` function
|
||||
- `src/services/chat-service.ts` - Add draft generation orchestration
|
||||
- `src/lib/store/chat-store.ts` - Add draft state and actions
|
||||
- `src/app/api/llm/route.ts` - Handle Ghostwriter requests (extend existing)
|
||||
|
||||
### UX Design Specifications
|
||||
|
||||
**From UX Design Document:**
|
||||
|
||||
**Visual Feedback - Drafting State:**
|
||||
- Use "Skeleton card loader" (shimmering lines) to show work is happening
|
||||
- Different from "Teacher is typing..." dots
|
||||
- Text: "Drafting your post..." or "Polishing your insight..."
|
||||
|
||||
**Output Format - The "Magic Moment":**
|
||||
- The draft should appear as a "Card" or "Article" view (Story 2.2 will implement)
|
||||
- Use `Merriweather` font (serif) to signal "published work"
|
||||
- Distinct visual shift from Chat (casual) to Draft (professional)
|
||||
|
||||
**Tone and Persona:**
|
||||
- Ghostwriter should use "Professional/LinkedIn" persona
|
||||
- Output should be polished but authentic
|
||||
- Avoid corporate jargon; maintain the user's voice
|
||||
|
||||
**Transition Pattern:**
|
||||
- When drafting completes, the Draft View slides up (Sheet pattern)
|
||||
- Chat remains visible underneath for context
|
||||
- This "Split-Personality" UI reinforces the transformation value
|
||||
|
||||
### Testing Requirements
|
||||
|
||||
**Unit Tests:**
|
||||
- `PromptEngine`: `generateGhostwriterPrompt()` produces correct structure
|
||||
- `PromptEngine`: Includes chat history context in prompt
|
||||
- `PromptEngine`: Handles empty/short chat history gracefully
|
||||
- `LLMService`: `getGhostwriterResponse()` calls Edge API correctly
|
||||
- `LLMService`: Handles streaming response with callbacks
|
||||
- `ChatStore`: `generateDraft()` action updates state correctly
|
||||
- `ChatStore`: Draft persisted to IndexedDB
|
||||
- `DraftService`: CRUD operations work correctly
|
||||
|
||||
**Integration Tests:**
|
||||
- Full flow: Chat history -> Draft generation -> Draft stored
|
||||
- Fast Track flow: Single input -> Draft generation
|
||||
- Draft state: Draft appears in UI after generation
|
||||
- Offline scenario: Draft queued if offline (basic handling for now, full sync in Epic 3)
|
||||
|
||||
**Edge Cases:**
|
||||
- Empty chat history: Should return helpful error message
|
||||
- Very long chat history: Should truncate/summarize within token limits
|
||||
- LLM API failure: Should show retry option
|
||||
- Malformed LLM response: Should handle gracefully
|
||||
|
||||
**Performance Tests:**
|
||||
- Draft generation time: < 5 seconds (NFR requirement)
|
||||
- Drafting indicator appears within 1 second of trigger
|
||||
- Large chat history (100+ messages): Should handle efficiently
|
||||
|
||||
### Previous Story Intelligence (from Epic 1)
|
||||
|
||||
**Patterns Established (must follow):**
|
||||
- **Logic Sandwich Pattern:** UI -> Zustand -> Service -> LLM (strictly enforced)
|
||||
- **Atomic Selectors:** All state access uses `useChatStore(s => s.field)`
|
||||
- **Streaming Pattern:** LLM responses use streaming with callbacks (onToken, onComplete)
|
||||
- **Edge Runtime:** All API routes use `export const runtime = 'edge'`
|
||||
- **Typing Indicator:** Pattern for showing processing state
|
||||
- **Intent Detection:** Teacher agent classifies user input (context for Ghostwriter)
|
||||
|
||||
**Key Files from Epic 1 (Reference):**
|
||||
- `src/lib/llm/prompt-engine.ts` - Has `generateTeacherPrompt()`, add Ghostwriter version
|
||||
- `src/services/llm-service.ts` - Has `getTeacherResponseStream()`, add Ghostwriter version
|
||||
- `src/app/api/llm/route.ts` - Handles Teacher requests, extend for Ghostwriter
|
||||
- `src/lib/store/chat-store.ts` - Has chat state, add draft state
|
||||
- `src/services/chat-service.ts` - Orchestrates chat flow, add draft generation
|
||||
- `src/lib/db/schema.ts` - Has chatLogs and sessions, add drafts table
|
||||
|
||||
**Learnings to Apply:**
|
||||
- Story 1.4 established Fast Track mode that directly triggers Ghostwriter
|
||||
- Use `isProcessing` pattern for `isDrafting` state
|
||||
- Follow streaming callback pattern: `onToken` for building draft incrementally
|
||||
- Ghostwriter prompt should include intent context from Teacher agent
|
||||
- Draft generation should use same Edge API proxy as Teacher agent
|
||||
|
||||
**Testing Patterns:**
|
||||
- Epic 1 established 101 passing tests
|
||||
- Follow same test structure: unit tests for each service, integration tests for full flow
|
||||
- Use mocked LLM responses for deterministic testing
|
||||
- Test streaming behavior with callback mocks
|
||||
|
||||
### Ghostwriter Prompt Specifications
|
||||
|
||||
**Prompt Structure:**
|
||||
```typescript
|
||||
function generateGhostwriterPrompt(
|
||||
chatHistory: ChatMessage[],
|
||||
intent?: 'venting' | 'insight'
|
||||
): string {
|
||||
return `
|
||||
You are the Ghostwriter Agent. Your role is to transform a user's chat session into a polished, professional post.
|
||||
|
||||
CONTEXT:
|
||||
- User Intent: ${intent || 'unknown'}
|
||||
- Chat History: ${formatChatHistory(chatHistory)}
|
||||
|
||||
REQUIREMENTS:
|
||||
1. Extract the core insight or lesson from the chat
|
||||
2. Write in a professional but authentic tone (LinkedIn-style)
|
||||
3. Structure as Markdown with: Title, Body, Tags
|
||||
4. DO NOT hallucinate facts - stay grounded in what the user shared
|
||||
5. Focus on the "transformation" - how the user's thinking evolved
|
||||
6. If it was a struggle, frame it as a learning opportunity
|
||||
7. Keep it concise (300-500 words for the body)
|
||||
|
||||
OUTPUT FORMAT:
|
||||
\`\`\`markdown
|
||||
# [Compelling Title]
|
||||
|
||||
[2-4 paragraphs that tell the story of the insight]
|
||||
|
||||
**Tags:** [3-5 relevant tags]
|
||||
\`\`\`
|
||||
`;
|
||||
}
|
||||
```
|
||||
|
||||
**Prompt Engineering Notes:**
|
||||
- The prompt should emphasize "grounded in user input" to prevent hallucinations
|
||||
- For "venting" intent, focus on "reframing struggle as lesson"
|
||||
- For "insight" intent, focus on "articulating the breakthrough"
|
||||
- Include the full chat history as context
|
||||
- Title generation is critical - should be catchy but authentic
|
||||
|
||||
### Data Schema Specifications
|
||||
|
||||
**Dexie Schema - Drafts Table:**
|
||||
```typescript
|
||||
// Add to src/lib/db/schema.ts
|
||||
db.version(1).stores({
|
||||
chatLogs: 'id, sessionId, timestamp, role, intent',
|
||||
sessions: 'id, createdAt, updatedAt, isFastTrackMode, currentIntent',
|
||||
drafts: 'id, sessionId, createdAt, status' // NEW
|
||||
});
|
||||
|
||||
export interface DraftRecord {
|
||||
id: string;
|
||||
sessionId: string;
|
||||
title: string;
|
||||
content: string; // Markdown formatted
|
||||
tags: string[]; // Array of tag strings
|
||||
createdAt: number;
|
||||
status: 'draft' | 'completed' | 'regenerated';
|
||||
}
|
||||
```
|
||||
|
||||
**Session-Draft Relationship:**
|
||||
- Each draft is linked to a session via `sessionId`
|
||||
- A session can have multiple drafts (regenerations)
|
||||
- The latest draft for a session is shown in history
|
||||
- Status tracks draft lifecycle: draft -> completed (user approved) or regenerated
|
||||
|
||||
### Performance Requirements
|
||||
|
||||
**NFR-01 Compliance (Generation Latency):**
|
||||
- Draft generation should complete in < 5 seconds total
|
||||
- First token should appear within 3 seconds
|
||||
- Streaming should show progressive build-up of the draft
|
||||
|
||||
**NFR-06 Compliance (Data Persistence):**
|
||||
- Draft must be auto-saved to IndexedDB immediately on completion
|
||||
- No data loss if user closes app during generation
|
||||
- Drafts persist offline and can be accessed from history
|
||||
|
||||
**State Updates:**
|
||||
- `isDrafting` state should update immediately on trigger
|
||||
- Draft content should stream into UI as tokens arrive
|
||||
- Draft should be queryable from history view immediately after completion
|
||||
|
||||
### Security & Privacy Requirements
|
||||
|
||||
**NFR-03 & NFR-04 Compliance:**
|
||||
- User content sent to LLM API for inference only (not training)
|
||||
- No draft content stored on server
|
||||
- Drafts stored 100% client-side in IndexedDB
|
||||
- API keys hidden via Edge Function proxy
|
||||
|
||||
**Content Safety:**
|
||||
- Ghostwriter prompt should include guardrails against:
|
||||
- Toxic or offensive content
|
||||
- Factually incorrect technical claims
|
||||
- Overly promotional language
|
||||
- If LLM generates concerning content, flag for user review
|
||||
|
||||
### Project Structure Notes
|
||||
|
||||
**Following Feature-First Lite Pattern:**
|
||||
- New component: `src/components/features/chat/DraftingIndicator.tsx`
|
||||
- New service: `src/lib/db/draft-service.ts` (could also be in `src/services/`)
|
||||
- Store updates: `src/lib/store/chat-store.ts`
|
||||
- Schema updates: `src/lib/db/schema.ts`
|
||||
|
||||
**Alignment with Unified Project Structure:**
|
||||
- All feature code under `src/components/features/`
|
||||
- Services orchestrate logic, don't touch DB directly from UI
|
||||
- State managed centrally in Zustand stores
|
||||
- Database schema versioned properly with Dexie
|
||||
|
||||
**No Conflicts Detected:**
|
||||
- Ghostwriter fits cleanly into existing architecture
|
||||
- Drafts table is new, no migration conflicts
|
||||
- Extends existing LLM service pattern
|
||||
|
||||
### References
|
||||
|
||||
**Epic Reference:**
|
||||
- [Epic 2: "The Magic Mirror" - Ghostwriter & Draft Refinement](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/epics.md#epic-2-the-magic-mirror---ghostwriter--draft-refinement)
|
||||
- [Story 2.1: Ghostwriter Agent & Markdown Generation](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/epics.md#story-21-ghostwriter-agent--markdown-generation)
|
||||
- FR-03: "Ghostwriter Agent can transform the structured interview data into a grammatically correct and structured 'Enlightenment' artifact"
|
||||
|
||||
**Architecture Documents:**
|
||||
- [Project Context: Logic Sandwich](file:///home/maximilienmao/Projects/Test01/_bmad-output/project-context.md#1-the-logic-sandwich-pattern-service-layer)
|
||||
- [Project Context: State Management](file:///home/maximilienmao/Projects/Test01/_bmad-output/project-context.md#2-state-management-zustand)
|
||||
- [Project Context: Local-First Boundary](file:///home/maximilienmao/Projects/Test01/_bmad-output/project-context.md#3-local-first-data-boundary)
|
||||
- [Architecture: Service Boundaries](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/architecture.md#architectural-boundaries)
|
||||
- [Architecture: Data Architecture](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/architecture.md#data-architecture)
|
||||
|
||||
**UX Design Specifications:**
|
||||
- [UX: Experience Mechanics - The Magic](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/ux-design-specification.md#2-experience-mechanics)
|
||||
- [UX: Typography System](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/ux-design-specification.md#typography-system)
|
||||
- [UX: Component Strategy - DraftCard](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/ux-design-specification.md#component-strategy)
|
||||
|
||||
**PRD Requirements:**
|
||||
- [PRD: Dual-Agent Pipeline](file:///home/maximilienmao/Projects/Test01/_bmad-output/planning-artifacts/prd.md#dual-agent-pipeline-core-innovation)
|
||||
- FR-03: "Ghostwriter Agent can transform the structured interview data into a grammatically correct and structured 'Enlightenment' artifact"
|
||||
- NFR-01: "< 3 seconds for first token, < 5 seconds total generation"
|
||||
|
||||
**Previous Stories:**
|
||||
- [Story 1.4: Fast Track Mode](file:///home/maximilienmao/Projects/Test01/_bmad-output/implementation-artifacts/1-4-fast-track-mode.md) - Fast Track directly triggers Ghostwriter
|
||||
|
||||
## Dev Agent Record
|
||||
|
||||
### Agent Model Used
|
||||
|
||||
Claude Opus 4.5 (model ID: 'claude-opus-4-5-20251101')
|
||||
|
||||
### Debug Log References
|
||||
|
||||
Session file: `/tmp/claude/-home-maximilienmao-Projects-Test01/e83dd24d-bb58-4fba-ac25-3628cdeae3e8/scratchpad`
|
||||
|
||||
### Completion Notes List
|
||||
|
||||
**Story Analysis Completed:**
|
||||
- Extracted story requirements from Epic 2, Story 2.1
|
||||
- Analyzed previous Epic 1 stories for established patterns
|
||||
- Reviewed architecture for compliance requirements (Logic Sandwich, State Management, Local-First)
|
||||
- Reviewed UX specification for visual design and interaction patterns
|
||||
- Identified all files to create and modify
|
||||
|
||||
**Implementation Completed:**
|
||||
All tasks and subtasks have been implemented:
|
||||
|
||||
1. **Ghostwriter Prompt Engine** (`src/lib/llm/prompt-engine.ts`)
|
||||
- Added `generateGhostwriterPrompt()` function with chat history context, intent-specific guidance
|
||||
- Prompt enforces: professional LinkedIn tone, no hallucinations, grounded in user input
|
||||
- Output format: Markdown with Title, Body, Tags sections
|
||||
- 21 new tests added for prompt generation (all passing)
|
||||
|
||||
2. **Ghostwriter LLM Service** (`src/services/llm-service.ts`)
|
||||
- Added `getGhostwriterResponse()` for non-streaming draft generation
|
||||
- Added `getGhostwriterResponseStream()` for streaming draft generation
|
||||
- Includes retry logic and comprehensive error handling
|
||||
- Returns structured Draft object with Markdown content
|
||||
- 13 new tests added (all passing)
|
||||
|
||||
3. **Draft State Management** (`src/lib/store/chat-store.ts`)
|
||||
- Added `currentDraft`, `isDrafting` state to ChatStore
|
||||
- Added `generateDraft()` action to trigger Ghostwriter
|
||||
- Added `clearDraft()` action for state reset
|
||||
- Drafts automatically persisted to IndexedDB via DraftService
|
||||
- Follows atomic selector pattern for state access
|
||||
|
||||
4. **Drafting Indicator** (`src/components/features/chat/DraftingIndicator.tsx`)
|
||||
- Created component with shimmer/pulse animation
|
||||
- Distinct from typing indicator (dots vs skeleton)
|
||||
- Shows "Drafting your post..." message
|
||||
|
||||
5. **Draft Storage Schema** (`src/lib/db/index.ts`)
|
||||
- Added `DraftRecord` interface with all required fields
|
||||
- Added `drafts` table to Dexie database with indexes
|
||||
- Database version 1 with proper schema definition
|
||||
|
||||
6. **ChatService Integration** (`src/services/chat-service.ts`)
|
||||
- Added `generateGhostwriterDraft()` method
|
||||
- Orchestrates Ghostwriter LLM service and DraftService
|
||||
- Handles title/content parsing from Markdown
|
||||
- Returns structured response with draft ID
|
||||
|
||||
7. **Fast Track Integration** (`src/lib/store/chat-store.ts`)
|
||||
- Fast Track mode now triggers Ghostwriter Agent
|
||||
- Generates actual draft instead of placeholder response
|
||||
- Draft saved to IndexedDB and loaded into currentDraft state
|
||||
|
||||
**Key Technical Decisions:**
|
||||
1. **Prompt Engineering:** Ghostwriter prompt structure with chat history context, output format requirements, hallucination guardrails
|
||||
2. **State Management:** Add draft state to ChatStore following atomic selector pattern
|
||||
3. **Data Schema:** New `drafts` table in IndexedDB with proper indexing
|
||||
4. **Service Pattern:** DraftService for CRUD operations (follows established pattern)
|
||||
5. **Streaming:** Use same streaming pattern as Teacher agent for draft generation
|
||||
6. **Fast Track:** Now calls Ghostwriter instead of returning placeholder (Epic 2 integration)
|
||||
|
||||
**Dependencies:**
|
||||
- No new dependencies required
|
||||
- Reuses existing Zustand, Dexie, LLM service infrastructure
|
||||
- Extends existing prompt engine and LLM service
|
||||
|
||||
**Integration Points:**
|
||||
- Connected to existing ChatStore state management
|
||||
- Ghostwriter triggered by ChatService after interview completion or Fast Track
|
||||
- Reuses Edge API proxy (`/api/llm`) for LLM calls
|
||||
- Draft stored in IndexedDB for history access (Epic 3)
|
||||
|
||||
**Testing Summary:**
|
||||
- 146 tests passing (all tests passing)
|
||||
- All Ghostwriter functionality tested with unit and integration tests
|
||||
- Error handling tested for timeout, rate limit, network errors
|
||||
- Edge cases tested: empty history, long history, undefined intent
|
||||
- Fast Track integration test updated to mock ChatService.generateGhostwriterDraft
|
||||
|
||||
**Behavior Changes:**
|
||||
- Fast Track mode (Story 1.4) now triggers Ghostwriter Agent
|
||||
- Returns actual draft instead of placeholder response
|
||||
- Integration test updated to mock ChatService.generateGhostwriterDraft and DraftService.getDraftBySessionId
|
||||
|
||||
### File List
|
||||
|
||||
**New Files Created:**
|
||||
- `src/lib/db/draft-service.ts` - Draft CRUD operations service
|
||||
- `src/lib/db/draft-service.test.ts` - Draft service tests (11 tests)
|
||||
- `src/components/features/chat/DraftingIndicator.tsx` - Drafting animation component
|
||||
|
||||
**Files Modified:**
|
||||
- `src/lib/db/index.ts` - Added DraftRecord interface and drafts table to Dexie schema
|
||||
- `src/lib/llm/prompt-engine.ts` - Added `generateGhostwriterPrompt()` function with intent-specific guidance
|
||||
- `src/services/llm-service.ts` - Added Ghostwriter methods with streaming and error handling
|
||||
- `src/services/chat-service.ts` - Added `generateGhostwriterDraft()` orchestration method
|
||||
- `src/lib/store/chat-store.ts` - Added draft state, generateDraft/clearDraft actions, Fast Track integration
|
||||
- `src/lib/llm/prompt-engine.test.ts` - Added 21 Ghostwriter prompt tests
|
||||
- `src/services/llm-service.test.ts` - Added 13 Ghostwriter service tests
|
||||
- `src/integration/fast-track.test.ts` - Updated Fast Track test to mock Ghostwriter services
|
||||
Reference in New Issue
Block a user