CC Agent: - Call transfer (CONFERENCE + KICK_CALL) with inline transfer dialog - Recording pause/resume during active calls - Missed calls API (Ozonetel abandonCalls) - Call history API (Ozonetel fetchCDRDetails) Live Call Assist: - Deepgram Nova STT via raw WebSocket - OpenAI suggestions every 10s with lead context - LiveTranscript component in sidebar during calls - Browser audio capture from remote WebRTC stream Worklist: - Redesigned table: clickable phones, context menu (Call/SMS/WhatsApp) - Last interaction sub-line, source column, improved SLA - Filtered out rows without phone numbers - New missed call notifications Brand: - Logo on login page - Blue scale rebuilt from logo blue rgb(32, 96, 160) - FontAwesome duotone CSS variables set globally - Profile menu icons switched to duotone Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.3 KiB
Next Session — Outbound Call UI + Remaining Work
Priority 0: Outbound Call — CloudAgent WebSocket Integration
CRITICAL FINDING: The Ozonetel toolbar's outbound dial works via TWO connections:
- CloudAgent WebSocket (mdlConnection.php) — sends
tbManualDialwithbrowserSessionId+usId - SIP WebSocket (blr-pub-rtc4.ozonetel.com:444) — receives the SIP INVITE and auto-answers
The browserSessionId and usId come from the CloudAgent WebSocket session handshake. Without them, CloudAgent doesn't know which browser to route the SIP INVITE to.
The toolbar's tbManualDial payload:
{
"type": "tbManualDial",
"ns": "ozonetel.cloudagent",
"customer": "global_healthx",
"agentId": "global",
"agentUniqId": 374804,
"browserSessionId": "e15cd447-...", // FROM WEBSOCKET SESSION
"usId": "af7hkcT3BcwCG-g=", // FROM WEBSOCKET SESSION
"isSip": "true",
"mode": "manual",
"params": "312792,9949879837,523591,SIP:true", // campaignId,phone,sipExt,SIP:true
"utid": 57
}
What we need to do:
- Connect to CloudAgent WebSocket from our browser (same mdlConnection.php endpoint)
- Establish session → get
usIdandbrowserSessionId - Include these in
tbManualDialrequests - CloudAgent will then send SIP INVITE to our JsSIP
The toolbar's SIP service code is at: user pasted it in conversation. Key function: handleSipAutoAnswer() which auto-answers based on agent's autoAnswer setting (0=none, 1=all, 2=inbound, 3=outbound).
SIP config from toolbar: password = extension number (523590), registrar = sip:blr-pub-rtc4.ozonetel.com, session_timers = false. Same as what we have.
Kookoo approach is abandoned — <dial> only works with PSTN numbers, not SIP extensions.
Priority 0 (OLD): Kookoo Dial to SIP Extension
Status: Kookoo IVR endpoint works. When customer answers, Kookoo hits /kookoo/ivr, we respond with <dial>523590</dial>. But Kookoo tries to call 523590 as a PSTN number — status=not_answered.
The Voice URL in Kookoo dashboard has been changed to: https://engage-api.srv1477139.hstgr.cloud/kookoo/ivr
Formats to try in the <dial> tag:
523590— current, fails (treated as PSTN)0523590— with STD prefixsip:523590@blr-pub-rtc4.ozonetel.com— full SIP URI523590@blr-pub-rtc4.ozonetel.com— SIP without scheme- Use
<conference>tag instead — put customer in room, have browser SIP join same room
Alternative approach: Instead of <dial>, use <conference> tag:
- Customer answers → put in conference room "call-{sid}"
- Meanwhile, browser SIP joins the same conference room
- Both connected
Files: helix-engage-server/src/ozonetel/kookoo-ivr.controller.ts line where we return <dial>523590</dial>
Priority 1: Outbound Call UI
Problem: When agent clicks Call, a toast appears and the call happens in the background. No call screen shows.
Fix: When agent clicks Call on a lead:
- Immediately set
callState = 'ringing-out'andcallerNumbervia Jotai atoms - Show ActiveCallCard with "Calling {name}..." and End button
- Show CallPrepCard with AI summary (same as inbound)
- Context panel auto-loads Lead 360
- Sidecar calls Kookoo outbound in parallel
- When SIP bridge arrives (newRTCSession), auto-answer it — don't show Answer/Decline
- UI transitions to active call with Mute/Hold/End
- Call ends → Disposition form
Files to change:
src/components/call-desk/click-to-call-button.tsx— set Jotai atoms on click, not just call APIsrc/components/call-desk/active-call-card.tsx— handle 'ringing-out' statesrc/state/sip-manager.ts— auto-answer SIP when outbound call is pendingsrc/pages/call-desk.tsx— include 'ringing-out' in isInCall, set selected lead on dial
Key insight: The call card is driven by app state, not SIP events. Set state immediately on click.
Priority 2: Remaining Polish
- Kookoo callback creates call records (already deployed)
- Toast for dial should be replaced with the call card (covered by Priority 1)
- Test full outbound flow end-to-end on staging
Priority 3: Caching
- DataProvider fires 14 queries on mount (7 × StrictMode)
- Add deduplication or sidecar-level cache
Deploy Commands
See memory/helix-engage-session-progress.md for full deploy instructions.