feat: mid-session status updates — ticket notes, client updates, email drafts
Engineers can now generate AI-powered status updates during active FlowPilot
sessions and after resolve/escalate. Three audiences (Ticket Notes, Client
Update, Email Draft) with Quick/Detailed length options. Copy to clipboard
with one click. Client names auto-inserted from intake/PSA context.
Backend: new endpoint POST /ai-sessions/{id}/status-update with audience-aware
system prompts. Frontend: StatusUpdateModal with 2-step selection flow,
Share Update button in action bar, Share Resolution/Escalation on completed
sessions. Also updates Solutions Library spec with Community tier design.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Network, Clock, Hash, Play, Ticket, ChevronDown, ChevronUp } from 'lucide-react'
|
||||
import { Network, Clock, Hash, Play, Ticket, ChevronDown, ChevronUp, FileText } from 'lucide-react'
|
||||
import type {
|
||||
AISessionDetail,
|
||||
AISessionStepResponse,
|
||||
@@ -7,12 +7,17 @@ import type {
|
||||
ResolveSessionRequest,
|
||||
EscalateSessionRequest,
|
||||
SessionDocumentation,
|
||||
StatusUpdateAudience,
|
||||
StatusUpdateLength,
|
||||
StatusUpdateContext,
|
||||
StatusUpdateResponse,
|
||||
} from '@/types/ai-session'
|
||||
import { ConfidenceIndicator } from './ConfidenceIndicator'
|
||||
import { FlowPilotStepCard } from './FlowPilotStepCard'
|
||||
import { FlowPilotActionBar } from './FlowPilotActionBar'
|
||||
import { FlowPilotMessageBar } from './FlowPilotMessageBar'
|
||||
import { SessionDocView } from './SessionDocView'
|
||||
import { StatusUpdateModal } from './StatusUpdateModal'
|
||||
import { SessionTicketCard } from './SessionTicketCard'
|
||||
import { SimilarSessions } from './SimilarSessions'
|
||||
import { TicketPickerModal } from '@/components/session/TicketPickerModal'
|
||||
@@ -39,6 +44,7 @@ interface FlowPilotSessionProps {
|
||||
onAbandon?: () => Promise<void>
|
||||
onRate: (rating: number) => void
|
||||
onReloadSession?: () => Promise<void>
|
||||
onGenerateStatusUpdate?: (audience: StatusUpdateAudience, length: StatusUpdateLength, context: StatusUpdateContext) => Promise<StatusUpdateResponse>
|
||||
}
|
||||
|
||||
export function FlowPilotSession({
|
||||
@@ -60,10 +66,12 @@ export function FlowPilotSession({
|
||||
onAbandon,
|
||||
onRate,
|
||||
onReloadSession,
|
||||
onGenerateStatusUpdate,
|
||||
}: FlowPilotSessionProps) {
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const [showTicketPicker, setShowTicketPicker] = useState(false)
|
||||
const [linkingTicket, setLinkingTicket] = useState(false)
|
||||
const [showShareCommunication, setShowShareCommunication] = useState(false)
|
||||
const [showMobileSidebar, setShowMobileSidebar] = useState(false)
|
||||
|
||||
const handleLinkTicket = async (ticketId: string, _ticket: PSATicketInfo) => {
|
||||
@@ -115,9 +123,24 @@ export function FlowPilotSession({
|
||||
|
||||
// Show documentation view for completed sessions
|
||||
if (isCompleted && documentation) {
|
||||
const shareContext = session.status === 'resolved' ? 'resolution' as const : 'escalation' as const
|
||||
const shareLabel = session.status === 'resolved' ? 'Share Resolution' : 'Share Escalation'
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<div className="flex-1 overflow-y-auto p-3 sm:p-4 lg:p-6">
|
||||
{/* Share Resolution/Escalation button */}
|
||||
{onGenerateStatusUpdate && (
|
||||
<div className="mb-4">
|
||||
<button
|
||||
onClick={() => setShowShareCommunication(true)}
|
||||
className="flex items-center gap-2 rounded-lg bg-cyan-500/10 border border-cyan-500/20 px-4 py-2.5 text-sm font-medium text-cyan-400 hover:bg-cyan-500/20 transition-colors"
|
||||
>
|
||||
<FileText size={16} />
|
||||
{shareLabel}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<SessionDocView
|
||||
documentation={documentation}
|
||||
onRate={onRate}
|
||||
@@ -129,6 +152,17 @@ export function FlowPilotSession({
|
||||
ticketId={session.psa_ticket_id}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Share communication modal for resolved/escalated sessions */}
|
||||
{onGenerateStatusUpdate && (
|
||||
<StatusUpdateModal
|
||||
open={showShareCommunication}
|
||||
onClose={() => setShowShareCommunication(false)}
|
||||
onGenerate={onGenerateStatusUpdate}
|
||||
context={shareContext}
|
||||
hasPsaTicket={!!session.psa_ticket_id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -320,10 +354,12 @@ export function FlowPilotSession({
|
||||
isProcessing={isProcessing}
|
||||
hasPsaTicket={!!session.psa_ticket_id}
|
||||
sessionId={session.id}
|
||||
canShareUpdate={allSteps.length >= 2}
|
||||
onResolve={onResolve}
|
||||
onEscalate={onEscalate}
|
||||
onPause={onPause}
|
||||
onAbandon={onAbandon}
|
||||
onGenerateStatusUpdate={onGenerateStatusUpdate}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user