From 2c8aca395138d0cee9a7b0df2deb3507c15c0c11 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Sun, 29 Mar 2026 06:03:34 +0000 Subject: [PATCH] feat: add status update generation to assistant chat Wire StatusUpdateModal into AssistantChatPage with "Update" button in the chat toolbar. Enhance ConcludeSessionModal pause/escalate outcomes to offer ticket notes, client update, or email draft generation instead of static messages. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../assistant/ConcludeSessionModal.tsx | 176 ++++++++++++++---- frontend/src/pages/AssistantChatPage.tsx | 30 ++- 2 files changed, 165 insertions(+), 41 deletions(-) diff --git a/frontend/src/components/assistant/ConcludeSessionModal.tsx b/frontend/src/components/assistant/ConcludeSessionModal.tsx index c32e71cd..3f7609a0 100644 --- a/frontend/src/components/assistant/ConcludeSessionModal.tsx +++ b/frontend/src/components/assistant/ConcludeSessionModal.tsx @@ -11,6 +11,9 @@ import { ClipboardList, Sparkles, AlertTriangle, + FileText, + User, + Mail, } from 'lucide-react' import { cn } from '@/lib/utils' import { MarkdownContent } from '@/components/ui/MarkdownContent' @@ -76,6 +79,7 @@ export function ConcludeSessionModal({ const [error, setError] = useState(null) const [streaming, setStreaming] = useState(false) const [streamError, setStreamError] = useState(null) + const [generatingUpdate, setGeneratingUpdate] = useState(false) const summaryRef = useRef('') // Reset state when modal opens @@ -90,6 +94,7 @@ export function ConcludeSessionModal({ setError(null) setStreaming(false) setStreamError(null) + setGeneratingUpdate(false) summaryRef.current = '' } }, [isOpen]) @@ -142,10 +147,9 @@ export function ConcludeSessionModal({ }) }, ) - } else if (outcome === 'escalated') { - setSummary('Session escalated. Ticket notes will be generated when the session is resolved.') } else { - setSummary('Session paused. Progress saved — you can resume anytime.') + // For paused/escalated: don't set summary yet — show status update options + setSummary('') } } catch { setError('Failed to conclude session. Please try again.') @@ -176,6 +180,25 @@ export function ConcludeSessionModal({ onClose() } + const handleGenerateStatusUpdate = async (audience: 'ticket_notes' | 'client_update' | 'email_draft') => { + if (!sessionId) return + setGeneratingUpdate(true) + try { + const context = outcome === 'escalated' ? 'escalation' : 'status' + const result = await aiSessionsApi.generateStatusUpdate(sessionId, { + audience, + length: 'detailed', + context, + }) + setSummary(result.content) + setCopied(false) + } catch { + setSummary('Failed to generate status update. You can copy the conversation from the chat.') + } finally { + setGeneratingUpdate(false) + } + } + if (!isOpen) return null const selectedOutcome = OUTCOMES.find(o => o.value === outcome) @@ -354,42 +377,115 @@ export function ConcludeSessionModal({ )} - {/* Generated ticket notes */} -
-
- - - Ticket Notes - - {streaming && ( - - )} -
+ {/* Resolved: streamed ticket notes */} + {outcome === 'resolved' && ( +
+
+ + + Ticket Notes + + {streaming && ( + + )} +
- {/* Streaming content or skeleton */} - {summary ? ( + {summary ? ( +
+ +
+ ) : streaming ? ( +
+
+
+
+
+
+
+
+ ) : streamError ? ( +
+ + {streamError} +
+ ) : null} +
+ )} + + {/* Paused/Escalated: status update options */} + {(outcome === 'paused' || outcome === 'escalated') && !summary && !generatingUpdate && ( +
+

+ {outcome === 'paused' + ? 'Session paused. Generate a status update to share progress.' + : 'Session escalated. Generate an update to document the handoff.'} +

+
+ + + +
+
+ )} + + {/* Paused/Escalated: generating spinner */} + {(outcome === 'paused' || outcome === 'escalated') && generatingUpdate && ( +
+ +

Generating status update...

+
+ )} + + {/* Paused/Escalated: generated result */} + {(outcome === 'paused' || outcome === 'escalated') && summary && !generatingUpdate && ( +
+
+ + + Status Update + +
- ) : streaming ? ( -
-
-
-
-
-
-
-
- ) : streamError ? ( -
- - {streamError} -
- ) : null} -
+
+ )}
)}
@@ -451,9 +547,17 @@ export function ConcludeSessionModal({ Resume in New Chat )} + {(outcome === 'paused' || outcome === 'escalated') && summary && !generatingUpdate && ( + + )}
- {summary && !streaming && ( + {summary && !streaming && !generatingUpdate && ( + <> + + + )} {!showTaskLane && (activeQuestions.length > 0 || activeActions.length > 0) && (
)