From 57cdd8ed0f46f33d83f4fbf103080de7b4e1da84 Mon Sep 17 00:00:00 2001 From: rhonda hollis Date: Fri, 15 May 2026 13:00:29 -0700 Subject: [PATCH] ensure session end at Ultravox --- lib/tasks/llm/llms/ultravox_s2s.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/tasks/llm/llms/ultravox_s2s.js b/lib/tasks/llm/llms/ultravox_s2s.js index 4c8ec939..688e0dae 100644 --- a/lib/tasks/llm/llms/ultravox_s2s.js +++ b/lib/tasks/llm/llms/ultravox_s2s.js @@ -146,6 +146,25 @@ class TaskLlmUltravox_S2S extends Task { return data; } + async hangupCall() { + if (!this.callId || this._hangupSent) return; + this._hangupSent = true; + const url = `https://api.ultravox.ai/api/calls/${this.callId}/send_data_message`; + try { + const {statusCode} = await request(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': this.apiKey + }, + body: JSON.stringify({type: 'hang_up'}) + }); + this.logger.debug({statusCode, callId: this.callId}, 'TaskLlmUltravox_S2S:hangupCall - sent hang_up'); + } catch (err) { + this.logger.info({err, callId: this.callId}, 'TaskLlmUltravox_S2S:hangupCall - error'); + } + } + _unregisterHandlers(ep) { this.removeCustomEventListeners(); ep.removeAllListeners('dtmf'); @@ -164,6 +183,7 @@ class TaskLlmUltravox_S2S extends Task { try { const data = await this.createCall(); + this.callId = data.callId; const {joinUrl} = data; // split the joinUrl into host and path const {host, pathname, search} = new URL(joinUrl); @@ -188,6 +208,8 @@ class TaskLlmUltravox_S2S extends Task { await this.awaitTaskDone(); + await this.hangupCall(); + /* note: the parent llm verb started the span, which is why this is necessary */ await this.parent.performAction(this.results); @@ -200,6 +222,8 @@ class TaskLlmUltravox_S2S extends Task { this._api(cs.ep, [cs.ep.uuid, SessionDelete]) .catch((err) => this.logger.info({err}, 'TaskLlmUltravox_S2S:kill - error deleting session')); + this.hangupCall(); + this.notifyTaskDone(); }