From 5859139f92834dca6b705e4d458410db66dfd07a Mon Sep 17 00:00:00 2001 From: Sabiha Khan Date: Wed, 6 May 2026 17:17:12 +0530 Subject: [PATCH] feat: add onCallConnected & onCallDisconnected callback --- ui/public/embed/dograh-widget.js | 49 ++++++++++++++------------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/ui/public/embed/dograh-widget.js b/ui/public/embed/dograh-widget.js index f7c8753..91017ed 100644 --- a/ui/public/embed/dograh-widget.js +++ b/ui/public/embed/dograh-widget.js @@ -33,6 +33,8 @@ callbacks: { onReady: null, onCallStart: null, + onCallConnected: null, + onCallDisconnected: null, onCallEnd: null, onError: null, onStatusChange: null @@ -627,6 +629,10 @@ async function startCall() { updateStatus('connecting', 'Connecting...', 'Please wait while we establish the connection'); + if (state.callbacks.onCallStart) { + state.callbacks.onCallStart(); + } + try { // Initialize session if using embed token if (state.config.token) { @@ -784,9 +790,8 @@ updateStatus('connected', 'Connected', 'Your voice call is now active'); if (!wasAlreadyConnected) { state.callStartedAt = Date.now(); - emitMessage('dograh:call_started', {}); - if (state.callbacks.onCallStart) { - state.callbacks.onCallStart({ + if (state.callbacks.onCallConnected) { + state.callbacks.onCallConnected({ agentId: state.config.workflowId || null, token: state.config.token || null, workflowRunId: state.workflowRunId || null @@ -925,15 +930,11 @@ * Stop voice call */ function stopCall() { - // Emit end message before clearing state so identifiers are still available - const durationSeconds = state.callStartedAt - ? Math.round((Date.now() - state.callStartedAt) / 1000) - : 0; - emitMessage('dograh:call_ended', { durationSeconds }); - - // Trigger call end callback with the same identifiers before we clear them - if (state.callbacks.onCallEnd) { - state.callbacks.onCallEnd({ + // Fire onCallDisconnected only if the call had actually connected, with + // identifiers and duration. Must run before we clear callStartedAt. + if (state.callStartedAt && state.callbacks.onCallDisconnected) { + const durationSeconds = Math.round((Date.now() - state.callStartedAt) / 1000); + state.callbacks.onCallDisconnected({ agentId: state.config.workflowId || null, token: state.config.token || null, workflowRunId: state.workflowRunId || null, @@ -944,6 +945,10 @@ updateStatus('idle', 'Call ended', 'Click below to start a new call'); + if (state.callbacks.onCallEnd) { + state.callbacks.onCallEnd(); + } + // Close WebSocket if (state.ws) { state.ws.close(); @@ -976,22 +981,6 @@ setTimeout(() => startCall(), 500); } - /** - * Emit a postMessage event to the host window - * Allows the embedding website to listen for agent lifecycle events via: - * window.addEventListener('message', (event) => { ... }) - */ - function emitMessage(eventType, detail) { - const message = { - type: eventType, - agentId: state.config.workflowId || null, - token: state.config.token || null, - workflowRunId: state.workflowRunId || null, - ...detail - }; - window.postMessage(message, '*'); - } - /** * Generate unique peer ID */ @@ -1020,6 +1009,8 @@ getState: () => state, onReady: (callback) => { state.callbacks.onReady = callback; }, onCallStart: (callback) => { state.callbacks.onCallStart = callback; }, + onCallConnected: (callback) => { state.callbacks.onCallConnected = callback; }, + onCallDisconnected: (callback) => { state.callbacks.onCallDisconnected = callback; }, onCallEnd: (callback) => { state.callbacks.onCallEnd = callback; }, onError: (callback) => { state.callbacks.onError = callback; }, onStatusChange: (callback) => { state.callbacks.onStatusChange = callback; }, @@ -1045,6 +1036,8 @@ // Set callbacks if provided if (options.onReady) state.callbacks.onReady = options.onReady; if (options.onCallStart) state.callbacks.onCallStart = options.onCallStart; + if (options.onCallConnected) state.callbacks.onCallConnected = options.onCallConnected; + if (options.onCallDisconnected) state.callbacks.onCallDisconnected = options.onCallDisconnected; if (options.onCallEnd) state.callbacks.onCallEnd = options.onCallEnd; if (options.onError) state.callbacks.onError = options.onError; if (options.onStatusChange) state.callbacks.onStatusChange = options.onStatusChange;