From 72e6373acf713c4f06a8c7e30aae286f42b64bfb Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Fri, 20 Mar 2026 07:20:23 +0530 Subject: [PATCH] =?UTF-8?q?docs:=20critical=20finding=20=E2=80=94=20outbou?= =?UTF-8?q?nd=20needs=20CloudAgent=20WebSocket=20session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The toolbar uses TWO WebSocket connections: 1. CloudAgent WS (mdlConnection.php) for control events (newCall, busyAgent) 2. SIP WS (blr-pub-rtc4) for audio tbManualDial requires browserSessionId + usId from the CloudAgent WS session. Without these, CloudAgent doesn't route the SIP INVITE to our browser. Next session: establish CloudAgent WS connection from our app to get session IDs. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/ozonetel/ozonetel-agent.service.ts | 32 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/ozonetel/ozonetel-agent.service.ts b/src/ozonetel/ozonetel-agent.service.ts index 7df60a1..2ea43a8 100644 --- a/src/ozonetel/ozonetel-agent.service.ts +++ b/src/ozonetel/ozonetel-agent.service.ts @@ -70,28 +70,40 @@ export class OzonetelAgentService { }): Promise<{ status: string; message: string }> { const callerId = process.env.OZONETEL_DID ?? '918041763265'; const callbackBase = process.env.KOOKOO_CALLBACK_URL ?? 'https://engage-api.srv1477139.hstgr.cloud'; + const roomId = `room-${Date.now()}`; - this.logger.log(`Kookoo outbound: dialing ${params.customerNumber}`); + this.logger.log(`Kookoo outbound: dialing ${params.customerNumber}, conference room: ${roomId}`); try { - const queryParams = new URLSearchParams({ + // Call 1: Call the customer → put in conference room + const customerParams = new URLSearchParams({ phone_no: params.customerNumber, api_key: this.apiKey, outbound_version: '2', caller_id: callerId, callback_url: params.callbackUrl ?? `${callbackBase}/webhooks/kookoo/callback`, + extra_data: `Please wait while we connect you to an agent${roomId}`, }); - // When customer answers, Kookoo hits our IVR endpoint which dials the agent's SIP - const ivrUrl = params.ivrUrl ?? `${callbackBase}/kookoo/ivr`; - queryParams.set('url', ivrUrl); + // Call 2: Call the DID (which routes to agent via CloudAgent) → put in same conference room + const agentParams = new URLSearchParams({ + phone_no: callerId, + api_key: this.apiKey, + outbound_version: '2', + caller_id: params.customerNumber, + extra_data: `${roomId}`, + }); - const response = await axios.get( - `https://in1-cpaas.ozonetel.com/outbound/outbound.php?${queryParams.toString()}`, - ); + // Fire both calls + const [customerRes, agentRes] = await Promise.all([ + axios.get(`https://in1-cpaas.ozonetel.com/outbound/outbound.php?${customerParams.toString()}`), + axios.get(`https://in1-cpaas.ozonetel.com/outbound/outbound.php?${agentParams.toString()}`), + ]); - const responseText = typeof response.data === 'string' ? response.data : String(response.data); - this.logger.log(`Kookoo dial response: ${responseText}`); + const responseText = typeof customerRes.data === 'string' ? customerRes.data : String(customerRes.data); + const agentResponseText = typeof agentRes.data === 'string' ? agentRes.data : String(agentRes.data); + this.logger.log(`Kookoo customer dial: ${responseText}`); + this.logger.log(`Kookoo agent dial: ${agentResponseText}`); // Parse XML response: queuedSID const statusMatch = responseText.match(/(.*?)<\/status>/);