- Moved streaming state (isGenerating, content, tokens, errors) from StepGenerate to usePostEditor hook - Added new state management to allow continuous AI generation when navigating between editor steps - Updated EditorShell to pass streaming state and setters down to StepGenerate component - Added detailed documentation explaining streaming persistence architecture and user experience - Removed local state from StepGenerate in favor of props
		
			
				
	
	
	
		
			6.6 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	Streaming Persistence Across Navigation
Problem Solved
Before: When navigating away from the Generate step during AI generation, the streaming would stop and all progress would be lost.
After: Streaming continues in the background even when you navigate to other steps. Content is preserved and available when you return.
How It Works
State Management Architecture
usePostEditor Hook (Persistent)
    ↓
    ├─ isGenerating: boolean
    ├─ streamingContent: string
    ├─ tokenCount: number
    └─ generationError: string
    ↓
EditorShell (Parent)
    ↓
StepGenerate (Child)
Key Changes
1. Lifted State to Hook (usePostEditor.ts)
// Streaming state (persisted across navigation)
const [isGenerating, setIsGenerating] = useState(false);
const [streamingContent, setStreamingContent] = useState('');
const [tokenCount, setTokenCount] = useState(0);
const [generationError, setGenerationError] = useState<string>('');
2. Passed Through EditorShell (EditorShell.tsx)
<StepGenerate
  // ... other props
  isGenerating={isGenerating}
  streamingContent={streamingContent}
  tokenCount={tokenCount}
  generationError={generationError}
  onSetIsGenerating={setIsGenerating}
  onSetStreamingContent={setStreamingContent}
  onSetTokenCount={setTokenCount}
  onSetGenerationError={setGenerationError}
/>
3. Used in Component (StepGenerate.tsx)
// No longer local state - uses props from hook
const { 
  isGenerating, 
  streamingContent, 
  tokenCount, 
  generationError,
  onSetIsGenerating,
  onSetStreamingContent,
  onSetTokenCount,
  onSetGenerationError
} = props;
User Experience
Scenario 1: Navigate During Streaming
- Start generation on Generate step
- See content streaming in real-time
- Navigate to Assets step to check something
- Generation continues in background
- Return to Generate step
- See completed content or ongoing stream
Scenario 2: Check Other Steps While Generating
Step 0: Assets     ← Navigate here
Step 1: AI Prompt  ← Or here
Step 2: Generate   ← Streaming continues here
Step 3: Edit       ← Or here
Step 4: Metadata
Step 5: Publish
Result: Generation keeps running, content preserved
Scenario 3: Long Generation
- Start 2000-word article generation (~60 seconds)
- Navigate to Edit step to prepare
- Navigate to Metadata to plan tags
- Return to Generate step
- Content is complete and ready!
Technical Benefits
1. State Persistence
- State lives in usePostEditorhook
- Hook persists across step navigation
- Only unmounts when leaving entire editor
2. Background Processing
- Streaming API continues regardless of UI
- Server-Sent Events connection stays open
- Content accumulates in hook state
3. No Data Loss
- Partial content preserved if navigation occurs
- Token count maintained
- Error state preserved
- Can resume viewing at any time
4. Better UX
- Don't have to wait on Generate step
- Can multitask while AI generates
- No accidental cancellation
- Flexible workflow
Implementation Details
State Flow During Streaming
1. User clicks "Generate Draft"
   ↓
2. onSetIsGenerating(true) in hook
   ↓
3. Stream starts, chunks arrive
   ↓
4. onSetStreamingContent(content + delta)
   ↓
5. User navigates to another step
   ↓
6. StepGenerate unmounts (local state lost)
   BUT hook state persists!
   ↓
7. Stream continues, updating hook state
   ↓
8. User returns to Generate step
   ↓
9. StepGenerate remounts with current hook state
   ↓
10. Sees current streaming content or final result
Memory Management
- Hook state: ~few KB for content string
- Streaming connection: Maintained by browser
- Cleanup: Automatic when leaving editor
- No memory leaks: State cleared on unmount
Edge Cases Handled
1. Navigation During Stream
✅ Stream continues ✅ Content preserved ✅ Can return anytime
2. Error During Stream
✅ Error state preserved ✅ Visible when returning ✅ Can retry generation
3. Multiple Generations
✅ Previous content cleared on new generation ✅ State reset properly ✅ No conflicts
4. Browser Refresh
❌ Stream lost (expected - SSE connection closed) ✅ Last saved draft preserved in database ✅ Can regenerate if needed
Comparison
Before (Local State)
// In StepGenerate.tsx
const [isGenerating, setIsGenerating] = useState(false);
const [streamingContent, setStreamingContent] = useState('');
// ❌ Lost on navigation
// ❌ Stream stops
// ❌ Progress lost
After (Hook State)
// In usePostEditor.ts
const [isGenerating, setIsGenerating] = useState(false);
const [streamingContent, setStreamingContent] = useState('');
// ✅ Persists across navigation
// ✅ Stream continues
// ✅ Progress preserved
Testing
Test Case 1: Basic Persistence
- Start generation
- Wait 5 seconds (partial content)
- Navigate to Assets
- Navigate back to Generate
- Expected: See partial content, stream continuing
Test Case 2: Complete During Navigation
- Start generation
- Navigate away immediately
- Wait 60 seconds
- Navigate back to Generate
- Expected: See complete content
Test Case 3: Error Handling
- Disconnect network
- Start generation
- Navigate away
- Navigate back
- Expected: See error message
Future Enhancements
1. Visual Indicator
Show streaming status in step navigation:
Step 2: Generate ⚡ (Streaming...)
2. Notification on Complete
Toast notification when generation completes while on another step:
✅ Article generation complete! (2,456 tokens)
3. Progress in Sidebar
Show live progress in sidebar:
┌─────────────────────┐
│ AI Generation       │
│ ▓▓▓▓▓▓▓░░░░░░░░░    │
│ 1,234 tokens        │
└─────────────────────┘
4. Pause/Resume
Add ability to pause streaming:
const [isPaused, setIsPaused] = useState(false);
// Pause SSE consumption, resume later
Conclusion
The streaming persistence feature provides a seamless, flexible workflow where users can multitask during long AI generations without losing progress. The implementation is clean, using React's built-in state management patterns and requiring minimal changes to the existing codebase.
Status: ✅ Fully implemented and tested Impact: Significantly improved UX for long-running generations Complexity: Low (simple state lifting pattern)