feat(escalations): subscribe EscalationQueue to live SSE arrivals
Adds the frontend live-arrival slice on top of the test-stabilized SSE backend. Senior techs now see a junior's escalation slide into the queue without refresh. - streamEscalations(handlers, signal) in aiSessions.ts: fetch-based ReadableStream parser (native EventSource cannot send auth headers). Handles SSE frames, partial frames across chunks, : keepalive heartbeats. Dispatches ready and handoff_created. - HandoffCreatedEvent + EscalationStreamHandlers types mirror the bus payload published by HandoffManager.dispatch_escalation_notifications. - EscalationQueue.tsx: AbortController-managed subscription with exponential-backoff reconnect (1s → 30s cap, attempt counter resets on ready). On handoff_created, refetch and diff against previous IDs via sessionsRef; new arrivals prepended (newest-first) above established cards (oldest-first preserved). Slide-in tag held for 800ms so the locked 200ms animation completes. Tab-title flash prefixes (N) while document.hidden, restores on focus / unmount. prefers-reduced-motion swaps slide-in for fade-in. ARIA region + aria-live=polite + aria-label on heading. Pick Up bumped to py-2.5 to clear the 44px touch floor. Verified end-to-end against the running dev stack: subscriber received the ready frame on connect; after posting a handoff via the API, the subscriber received the handoff_created frame with the expected payload — wire format matches the parser. Backend regression: focused subset still 32 passed in 18.91s. Frontend tsc -b clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -258,3 +258,23 @@ export interface SimilarSession {
|
||||
created_at: string | null
|
||||
similarity: number
|
||||
}
|
||||
|
||||
// ── Escalation SSE bus ──
|
||||
//
|
||||
// Mirrors the `event_generator` payload in
|
||||
// backend/app/api/endpoints/session_handoffs.py — keep this in sync with the
|
||||
// dict published by `HandoffManager.dispatch_escalation_notifications`.
|
||||
|
||||
export interface HandoffCreatedEvent {
|
||||
type: 'handoff_created'
|
||||
handoff_id: string
|
||||
session_id: string
|
||||
priority: string
|
||||
engineer_notes: string
|
||||
created_at: string | null
|
||||
}
|
||||
|
||||
export interface EscalationStreamHandlers {
|
||||
onReady?: () => void
|
||||
onHandoffCreated?: (event: HandoffCreatedEvent) => void
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user