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

93 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:**
```json
{
"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.