Files
helix-engage/docs/next-session.md
saridsa2 3064eeb444 feat: CC agent features, live call assist, worklist redesign, brand tokens
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>
2026-03-21 10:36:10 +05:30

4.3 KiB
Raw Blame History

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:

  1. CloudAgent WebSocket (mdlConnection.php) — sends tbManualDial with browserSessionId + usId
  2. 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:

  1. Connect to CloudAgent WebSocket from our browser (same mdlConnection.php endpoint)
  2. Establish session → get usId and browserSessionId
  3. Include these in tbManualDial requests
  4. 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:

  1. 523590 — current, fails (treated as PSTN)
  2. 0523590 — with STD prefix
  3. sip:523590@blr-pub-rtc4.ozonetel.com — full SIP URI
  4. 523590@blr-pub-rtc4.ozonetel.com — SIP without scheme
  5. 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:

  1. Immediately set callState = 'ringing-out' and callerNumber via Jotai atoms
  2. Show ActiveCallCard with "Calling {name}..." and End button
  3. Show CallPrepCard with AI summary (same as inbound)
  4. Context panel auto-loads Lead 360
  5. Sidecar calls Kookoo outbound in parallel
  6. When SIP bridge arrives (newRTCSession), auto-answer it — don't show Answer/Decline
  7. UI transitions to active call with Mute/Hold/End
  8. Call ends → Disposition form

Files to change:

  • src/components/call-desk/click-to-call-button.tsx — set Jotai atoms on click, not just call API
  • src/components/call-desk/active-call-card.tsx — handle 'ringing-out' state
  • src/state/sip-manager.ts — auto-answer SIP when outbound call is pending
  • src/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.