@openclaw/voice-call 2026.9.6 → 2026.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{cli-D6j7ppuN.mjs → cli-D6uwMXyS.mjs} +6 -10
  3. package/dist/.setup/{config-72FnMWHb.mjs → config-Ds7xoZbI.mjs} +27 -30
  4. package/dist/.setup/{guarded-json-api-exU4Hutw.mjs → guarded-json-api-Bqc6QS8A.mjs} +23 -17
  5. package/dist/.setup/{mock-CcYEAUhV.mjs → mock-ClWW6Ufu.mjs} +34 -53
  6. package/dist/.setup/{plivo-BGJda1Uz.mjs → plivo-69ObrQPk.mjs} +17 -42
  7. package/dist/.setup/realtime-agent-context.legacy-DAEWY27o.mjs +53 -0
  8. package/dist/.setup/{realtime-handler-DlFmdSPn.mjs → realtime-handler-BgDPcPZt.mjs} +34 -53
  9. package/dist/.setup/{response-generator-hZyGIjO4.mjs → response-generator-BzKrJMEb.mjs} +2 -2
  10. package/dist/.setup/{runtime-entry-dDRm6RgA.mjs → runtime-entry-BNOQRXii.mjs} +82 -297
  11. package/dist/.setup/{telnyx-BV56PXr-.mjs → telnyx-DjFGCfy1.mjs} +19 -55
  12. package/dist/.setup/{twilio-BMb-7cu-.mjs → twilio-Bp3gfmUB.mjs} +29 -78
  13. package/dist/.setup/{store-path-B1j1up4_.mjs → utils-B5pnM_Ij.mjs} +14 -6
  14. package/dist/api.js +5 -1
  15. package/dist/doctor-contract-api.js +186 -15
  16. package/dist/index.js +6 -42
  17. package/dist/runtime-entry.js +1 -1
  18. package/node_modules/typebox/build/compile/code.mjs +1 -2
  19. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  20. package/node_modules/typebox/build/format/iri.mjs +16 -9
  21. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  22. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  23. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  24. package/node_modules/typebox/build/guard/index.mjs +6 -0
  25. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  26. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  27. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  28. package/node_modules/typebox/build/schema/build.mjs +2 -3
  29. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  30. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  31. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  32. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  33. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  34. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  35. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  36. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  37. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  38. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  39. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  40. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  41. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  42. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  43. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  44. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  45. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  46. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  47. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  48. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  49. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  50. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  51. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  52. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  53. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  54. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  55. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  56. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  57. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  58. package/node_modules/typebox/package.json +1 -1
  59. package/node_modules/typebox/readme.md +3 -1
  60. package/package.json +5 -5
  61. package/dist/runtime-api.js +0 -6
  62. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -1,7 +1,6 @@
1
- import { isBlockedHostnameOrIp, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, sendHttpRequestRejection } from "../runtime-api.js";
2
- import "../api.js";
3
- import { a as resolveVoiceCallEffectiveConfig, c as resolveVoiceCallSessionKey, f as resolveVoiceCallRealtimeTools, i as resolveVoiceCallConfig, l as resolveVoiceCallStreamExposurePaths, n as normalizeVoiceCallConfig, o as resolveVoiceCallNumberRouteKeyForCall, r as resolveTwilioAuthToken, u as validateProviderConfig } from "./config-72FnMWHb.mjs";
4
- import { _ as releaseRejectedProviderCall, b as setVoiceCallStateRuntime, d as getCallHistoryFromStore, f as loadActiveCallsFromStore, g as appendCallReplayKey, m as persistCallRecord, t as resolveDefaultVoiceCallStoreDir, u as findCallInStore, v as rememberManagerReplayKey, x as TerminalStates, y as reserveRejectedProviderCall } from "./store-path-B1j1up4_.mjs";
1
+ import { isBlockedHostnameOrIp, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, sendHttpRequestRejection } from "../api.js";
2
+ import { a as resolveVoiceCallEffectiveConfig, c as resolveVoiceCallSessionKey, f as resolveVoiceCallRealtimeTools, i as resolveVoiceCallConfig, l as resolveVoiceCallStreamExposurePaths, m as normalizePhoneNumber, n as normalizeVoiceCallConfig, o as resolveVoiceCallNumberRouteKeyForCall, p as isAllowlistedCaller, r as resolveTwilioAuthToken, u as validateProviderConfig } from "./config-Ds7xoZbI.mjs";
3
+ import { S as TerminalStates, _ as appendCallReplayKey, b as reserveRejectedProviderCall, d as findCallInStore, f as getCallHistoryFromStore, h as persistCallRecord, n as resolveDefaultVoiceCallStoreDir, p as loadActiveCallsFromStore, t as resolveUserPath, v as releaseRejectedProviderCall, x as setVoiceCallStateRuntime, y as rememberManagerReplayKey } from "./utils-B5pnM_Ij.mjs";
5
4
  import { createRequire } from "node:module";
6
5
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
7
6
  import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
@@ -18,31 +17,15 @@ import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
18
17
  import crypto from "node:crypto";
19
18
  import { redactIdentifier } from "openclaw/plugin-sdk/logging-core";
20
19
  import path from "node:path";
21
- import os from "node:os";
22
- import { root } from "openclaw/plugin-sdk/security-runtime";
23
- import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
20
+ import * as realtimeBootstrapSdk from "openclaw/plugin-sdk/realtime-bootstrap-context";
24
21
  import { spawn } from "node:child_process";
22
+ import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
25
23
  import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
26
24
  import http from "node:http";
27
25
  import { URL as URL$1 } from "node:url";
28
26
  import { resolveConfiguredCapabilityProvider } from "openclaw/plugin-sdk/provider-selection-runtime";
29
27
  import { rejectWebSocketUpgrade } from "openclaw/plugin-sdk/websocket-runtime";
30
28
  import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
31
- //#region extensions/voice-call/src/allowlist.ts
32
- /** Normalize a phone number to digits only. */
33
- function normalizePhoneNumber(input) {
34
- if (!input) return "";
35
- return input.replace(/\D/g, "");
36
- }
37
- /** Return true when the normalized caller exactly matches an allowlist entry. */
38
- function isAllowlistedCaller(normalizedFrom, allowFrom) {
39
- if (!normalizedFrom) return false;
40
- return (allowFrom ?? []).some((num) => {
41
- const normalizedAllow = normalizePhoneNumber(num);
42
- return normalizedAllow !== "" && normalizedAllow === normalizedFrom;
43
- });
44
- }
45
- //#endregion
46
29
  //#region extensions/voice-call/src/manager/state.ts
47
30
  const ConversationStates = /* @__PURE__ */ new Set(["speaking", "listening"]);
48
31
  const StateOrder = [
@@ -92,10 +75,6 @@ function resolveVoiceCallSecondsTimerDelayMs(seconds, minMs = 1) {
92
75
  const timeoutMs = Math.floor(seconds * 1e3);
93
76
  return resolveTimerTimeoutMs(Number.isFinite(timeoutMs) ? timeoutMs : MAX_TIMER_TIMEOUT_MS, minMs, minMs);
94
77
  }
95
- /** Normalize a millisecond timeout delay with fallback behavior. */
96
- function resolveVoiceCallTimerDelayMs(timeoutMs, fallbackMs = 1) {
97
- return resolveTimerTimeoutMs(timeoutMs, fallbackMs);
98
- }
99
78
  //#endregion
100
79
  //#region extensions/voice-call/src/manager/timers.ts
101
80
  /** Clear and forget the max-duration timer for a call. */
@@ -109,7 +88,7 @@ function clearMaxDurationTimer(ctx, callId) {
109
88
  /** Start or replace the max-duration timer for a call. */
110
89
  function startMaxDurationTimer(params) {
111
90
  clearMaxDurationTimer(params.ctx, params.callId);
112
- const maxDurationMs = params.timeoutMs === void 0 ? resolveVoiceCallSecondsTimerDelayMs(params.ctx.config.maxDurationSeconds) : resolveVoiceCallTimerDelayMs(params.timeoutMs);
91
+ const maxDurationMs = params.timeoutMs === void 0 ? resolveVoiceCallSecondsTimerDelayMs(params.ctx.config.maxDurationSeconds) : resolveTimerTimeoutMs(params.timeoutMs, 1);
113
92
  console.log(`[voice-call] Starting max duration timer (${Math.ceil(maxDurationMs / 1e3)}s) for call ${params.callId}`);
114
93
  const timer = setTimeout(() => {
115
94
  const work = (async () => {
@@ -155,7 +134,7 @@ function resolveTranscriptWaiter(ctx, callId, transcript, turnToken) {
155
134
  /** Wait for the next final transcript for a call, optionally scoped to a turn token. */
156
135
  function waitForFinalTranscript(ctx, callId, turnToken) {
157
136
  if (ctx.transcriptWaiters.has(callId)) return Promise.reject(/* @__PURE__ */ new Error("Already waiting for transcript"));
158
- const timeoutMs = resolveVoiceCallTimerDelayMs(ctx.config.transcriptTimeoutMs);
137
+ const timeoutMs = resolveTimerTimeoutMs(ctx.config.transcriptTimeoutMs, 1);
159
138
  return new Promise((resolve, reject) => {
160
139
  const timeout = setTimeout(() => {
161
140
  ctx.transcriptWaiters.delete(callId);
@@ -324,20 +303,10 @@ function lookupConnectedCall(ctx, callId) {
324
303
  }
325
304
  function requireConnectedCall(ctx, callId) {
326
305
  const lookup = lookupConnectedCall(ctx, callId);
327
- if (lookup.kind === "error") return {
328
- ok: false,
329
- error: lookup.error
330
- };
331
- if (lookup.kind === "ended") return {
332
- ok: false,
306
+ return lookup.kind === "ended" ? {
307
+ kind: "error",
333
308
  error: "Call has ended"
334
- };
335
- return {
336
- ok: true,
337
- call: lookup.call,
338
- providerCallId: lookup.providerCallId,
339
- provider: lookup.provider
340
- };
309
+ } : lookup;
341
310
  }
342
311
  function isCurrentCall(ctx, call) {
343
312
  return ctx.activeCalls.get(call.callId) === call && !TerminalStates.has(call.state);
@@ -483,7 +452,7 @@ async function initiateCall(ctx, to, sessionKey, options) {
483
452
  }
484
453
  async function speak(ctx, callId, text, options) {
485
454
  const connected = requireConnectedCall(ctx, callId);
486
- if (!connected.ok) return {
455
+ if (connected.kind === "error") return {
487
456
  success: false,
488
457
  error: connected.error
489
458
  };
@@ -549,7 +518,7 @@ async function sendDtmf(ctx, callId, digits) {
549
518
  error: validationError
550
519
  };
551
520
  const connected = requireConnectedCall(ctx, callId);
552
- if (!connected.ok) return {
521
+ if (connected.kind === "error") return {
553
522
  success: false,
554
523
  error: connected.error
555
524
  };
@@ -640,7 +609,7 @@ async function speakInitialMessage(ctx, providerCallId) {
640
609
  }
641
610
  async function continueCall(ctx, callId, prompt) {
642
611
  const connected = requireConnectedCall(ctx, callId);
643
- if (!connected.ok) return {
612
+ if (connected.kind === "error") return {
644
613
  success: false,
645
614
  error: connected.error
646
615
  };
@@ -1032,18 +1001,6 @@ async function processEventInQueue(ctx, event) {
1032
1001
  return result;
1033
1002
  }
1034
1003
  //#endregion
1035
- //#region extensions/voice-call/src/utils.ts
1036
- /** Resolve user input paths, including "~" against the current OS home. */
1037
- function resolveUserPath(input) {
1038
- const trimmed = input.trim();
1039
- if (!trimmed) return trimmed;
1040
- if (trimmed.startsWith("~")) {
1041
- const expanded = trimmed.replace(/^~(?=$|[\\/])/, () => os.homedir());
1042
- return path.resolve(expanded);
1043
- }
1044
- return path.resolve(trimmed);
1045
- }
1046
- //#endregion
1047
1004
  //#region extensions/voice-call/src/manager.ts
1048
1005
  function markRestoredCallSkipped(call, endReason) {
1049
1006
  call.endedAt = Date.now();
@@ -1062,9 +1019,6 @@ function resolveDefaultStoreBase(config, storePath) {
1062
1019
  if (rawOverride) return resolveUserPath(rawOverride);
1063
1020
  return resolveDefaultVoiceCallStoreDir();
1064
1021
  }
1065
- /**
1066
- * Manages voice calls: state ownership and delegation to manager helper modules.
1067
- */
1068
1022
  var CallManager = class {
1069
1023
  runOperation(operation) {
1070
1024
  if (this.closing) return Promise.reject(/* @__PURE__ */ new Error("Voice Call manager is stopping"));
@@ -1272,27 +1226,15 @@ var CallManager = class {
1272
1226
  if (keptVerificationFailures > 0) console.log(`[voice-call] Kept ${keptVerificationFailures} restored call(s) after verification failure (relying on timer)`);
1273
1227
  return verified;
1274
1228
  }
1275
- /**
1276
- * Get the current provider.
1277
- */
1278
1229
  getProvider() {
1279
1230
  return this.provider;
1280
1231
  }
1281
- /**
1282
- * Initiate an outbound call.
1283
- */
1284
1232
  async initiateCall(to, sessionKey, options) {
1285
1233
  return this.runOperation(() => initiateCall(this.getContext(), to, sessionKey, options));
1286
1234
  }
1287
- /**
1288
- * Speak to user in an active call.
1289
- */
1290
1235
  async speak(callId, text, options) {
1291
1236
  return this.runOperation(() => speak(this.getContext(), callId, text, options));
1292
1237
  }
1293
- /**
1294
- * Send DTMF digits to an active call.
1295
- */
1296
1238
  async sendDtmf(callId, digits) {
1297
1239
  return this.runOperation(() => sendDtmf(this.getContext(), callId, digits));
1298
1240
  }
@@ -1308,9 +1250,6 @@ var CallManager = class {
1308
1250
  async continueCall(callId, prompt) {
1309
1251
  return this.runOperation(() => continueCall(this.getContext(), callId, prompt));
1310
1252
  }
1311
- /**
1312
- * End an active call.
1313
- */
1314
1253
  endCall(callId, options) {
1315
1254
  return this.runOperation(() => endCall(this.getContext(), callId, options));
1316
1255
  }
@@ -1343,9 +1282,6 @@ var CallManager = class {
1343
1282
  streamSessionIssuer: this.streamSessionIssuer
1344
1283
  };
1345
1284
  }
1346
- /**
1347
- * Process a webhook event.
1348
- */
1349
1285
  processEvent(event) {
1350
1286
  return this.runOperation(() => processEvent(this.getContext(), event));
1351
1287
  }
@@ -1380,9 +1316,6 @@ var CallManager = class {
1380
1316
  console.warn(`[voice-call] Failed to speak initial message for call ${call.callId}: ${formatErrorMessage(err)}`);
1381
1317
  });
1382
1318
  }
1383
- /**
1384
- * Get an active call by ID.
1385
- */
1386
1319
  getCall(callId) {
1387
1320
  return this.activeCalls.get(callId);
1388
1321
  }
@@ -1390,9 +1323,6 @@ var CallManager = class {
1390
1323
  getCallForStream(callId) {
1391
1324
  return this.runOperation(() => this.mutationQueue.enqueue("state", async () => this.closing ? void 0 : this.activeCalls.get(callId)));
1392
1325
  }
1393
- /**
1394
- * Get an active call by provider call ID (e.g., Twilio CallSid).
1395
- */
1396
1326
  getCallByProviderCallId(providerCallId) {
1397
1327
  return getCallByProviderCallId({
1398
1328
  activeCalls: this.activeCalls,
@@ -1400,9 +1330,6 @@ var CallManager = class {
1400
1330
  providerCallId
1401
1331
  });
1402
1332
  }
1403
- /**
1404
- * Get all active calls.
1405
- */
1406
1333
  getActiveCalls() {
1407
1334
  return Array.from(this.activeCalls.values());
1408
1335
  }
@@ -1412,86 +1339,37 @@ var CallManager = class {
1412
1339
  if (active) return active;
1413
1340
  return this.runOperation(() => findCallInStore(this.storePath, callId, this.stateRuntime));
1414
1341
  }
1415
- /**
1416
- * Get call history (from persisted logs).
1417
- */
1418
1342
  async getCallHistory(limit = 50) {
1419
1343
  return this.runOperation(() => getCallHistoryFromStore(this.storePath, limit, this.stateRuntime));
1420
1344
  }
1421
1345
  };
1422
1346
  //#endregion
1423
1347
  //#region extensions/voice-call/src/realtime-agent-context.ts
1424
- /** Limit injected context while preserving an explicit truncation marker. */
1425
- function limitText(text, maxChars) {
1426
- if (text.length <= maxChars) return text;
1427
- return `${truncateUtf16Safe(text, Math.max(0, maxChars - 32)).trimEnd()}\n[truncated]`;
1428
- }
1429
- /** Read configured workspace context files through the safe workspace root. */
1430
- async function readWorkspaceVoiceContextFiles(params) {
1431
- const sections = [];
1432
- let remaining = params.maxChars;
1433
- const workspaceRoot = await root(params.workspaceDir).catch(() => null);
1434
- if (!workspaceRoot) return sections;
1435
- for (const file of params.files) {
1436
- if (remaining <= 0) continue;
1437
- const trimmed = (await workspaceRoot.readText(file).catch(() => void 0))?.trim();
1438
- if (!trimmed) continue;
1439
- const section = `### ${file}\n${limitText(trimmed, Math.max(0, remaining - file.length - 16))}`;
1440
- sections.push(section);
1441
- remaining -= section.length;
1442
- }
1443
- return sections;
1444
- }
1445
- /** Build final realtime instructions from base instructions, consult policy, and fast context. */
1348
+ const contextSdk = realtimeBootstrapSdk;
1349
+ /** Build final realtime instructions from base instructions, consult policy, and agent context. */
1446
1350
  async function buildRealtimeVoiceInstructions(params) {
1447
1351
  const { config } = params;
1448
- const sections = [params.baseInstructions];
1449
- const consultGuidance = buildRealtimeVoiceAgentConsultPolicyInstructions(config.realtime);
1450
- if (consultGuidance) sections.push(consultGuidance);
1451
1352
  const contextConfig = config.realtime.agentContext;
1452
- if (!contextConfig.enabled) return sections.filter(Boolean).join("\n\n");
1453
- const { agentId } = params;
1454
- const capsule = [
1455
- "OpenClaw agent voice context:",
1456
- `- Agent id: ${agentId}`,
1457
- "- Use this context to match the OpenClaw agent's personality and standing preferences on fast voice turns.",
1458
- "- Treat this as compact context only; call openclaw_agent_consult when the caller needs the full agent brain, tools, memory, or workspace state."
1459
- ];
1460
- if (contextConfig.includeIdentity) {
1461
- const identity = params.agentRuntime.resolveAgentIdentity(params.coreConfig, agentId);
1462
- const identityLines = [
1463
- normalizeOptionalString(identity?.name) ? `- Name: ${normalizeOptionalString(identity?.name)}` : void 0,
1464
- normalizeOptionalString(identity?.emoji) ? `- Emoji: ${normalizeOptionalString(identity?.emoji)}` : void 0,
1465
- normalizeOptionalString(identity?.vibe) ? `- Vibe: ${normalizeOptionalString(identity?.vibe)}` : void 0,
1466
- normalizeOptionalString(identity?.theme) ? `- Theme: ${normalizeOptionalString(identity?.theme)}` : void 0,
1467
- normalizeOptionalString(identity?.creature) ? `- Creature/persona: ${normalizeOptionalString(identity?.creature)}` : void 0
1468
- ].filter(Boolean);
1469
- if (identityLines.length > 0) capsule.push(`Configured identity:\n${identityLines.join("\n")}`);
1470
- }
1471
- if (contextConfig.includeWorkspaceFiles) {
1472
- const fileSections = await readWorkspaceVoiceContextFiles({
1473
- workspaceDir: params.agentRuntime.resolveAgentWorkspaceDir(params.coreConfig, agentId),
1474
- files: contextConfig.files,
1475
- maxChars: contextConfig.maxChars
1476
- });
1477
- if (fileSections.length > 0) capsule.push(`Workspace voice context:\n${fileSections.join("\n\n")}`);
1353
+ const sections = [params.baseInstructions, buildRealtimeVoiceAgentConsultPolicyInstructions(config.realtime)];
1354
+ if (contextSdk.resolveRealtimeVoiceAgentContextInstructions) sections.push(await contextSdk.resolveRealtimeVoiceAgentContextInstructions({
1355
+ config: params.coreConfig,
1356
+ agentId: params.agentId,
1357
+ files: contextConfig.enabled && contextConfig.includeWorkspaceFiles ? contextConfig.files : [],
1358
+ includeIdentity: contextConfig.enabled && contextConfig.includeIdentity,
1359
+ maxChars: contextConfig.maxChars,
1360
+ warn: params.warn
1361
+ }));
1362
+ else {
1363
+ const { buildLegacyRealtimeVoiceAgentContext } = await import("./realtime-agent-context.legacy-DAEWY27o.mjs");
1364
+ sections.push(await buildLegacyRealtimeVoiceAgentContext({
1365
+ config: contextConfig,
1366
+ coreConfig: params.coreConfig,
1367
+ agentId: params.agentId
1368
+ }));
1478
1369
  }
1479
- sections.push(limitText(capsule.join("\n\n"), contextConfig.maxChars));
1480
1370
  return sections.filter(Boolean).join("\n\n");
1481
1371
  }
1482
1372
  //#endregion
1483
- //#region extensions/voice-call/src/realtime-fast-context.ts
1484
- /** Resolve fast-context consult data using caller-oriented labels. */
1485
- async function resolveRealtimeFastContextConsult(params) {
1486
- return await resolveRealtimeVoiceFastContextConsult({
1487
- ...params,
1488
- labels: {
1489
- audienceLabel: "caller",
1490
- contextName: "OpenClaw memory or session context"
1491
- }
1492
- });
1493
- }
1494
- //#endregion
1495
1373
  //#region extensions/voice-call/src/resolve-call-agent-id.ts
1496
1374
  /** Setup and startup must resolve the same owner before provisioning telephony. */
1497
1375
  function resolveVoiceCallAgentId(config, coreConfig) {
@@ -1521,10 +1399,8 @@ function resolveVoiceResponseModel(params) {
1521
1399
  /**
1522
1400
  * Chunk audio buffer into 20ms frames for streaming (8kHz mono mu-law).
1523
1401
  */
1524
- function chunkAudio(audio, chunkSize = 160) {
1525
- return (function* () {
1526
- for (let i = 0; i < audio.length; i += chunkSize) yield audio.subarray(i, Math.min(i + chunkSize, audio.length));
1527
- })();
1402
+ function* chunkAudio(audio, chunkSize = 160) {
1403
+ for (let i = 0; i < audio.length; i += chunkSize) yield audio.subarray(i, i + chunkSize);
1528
1404
  }
1529
1405
  //#endregion
1530
1406
  //#region extensions/voice-call/src/telephony-tts.ts
@@ -1584,28 +1460,9 @@ async function createTelephonyTtsProvider(params) {
1584
1460
  //#endregion
1585
1461
  //#region extensions/voice-call/src/bounded-child-output.ts
1586
1462
  const DEFAULT_MAX_OUTPUT_CHARS = 16384;
1587
- /** Create an empty bounded output buffer. */
1588
- function emptyBoundedChildOutput() {
1589
- return {
1590
- text: "",
1591
- truncated: false
1592
- };
1593
- }
1594
- /** Append output while retaining the newest maxChars and recording truncation. */
1595
- function appendBoundedChildOutput(current, chunk, maxChars = DEFAULT_MAX_OUTPUT_CHARS) {
1596
- const appended = current.text + chunk;
1597
- if (appended.length <= maxChars) return {
1598
- text: appended,
1599
- truncated: current.truncated
1600
- };
1601
- return {
1602
- text: sliceUtf16Safe(appended, -maxChars),
1603
- truncated: true
1604
- };
1605
- }
1606
- /** Format captured output with a truncation marker when older text was dropped. */
1607
- function formatBoundedChildOutput(output) {
1608
- return output.truncated ? `[output truncated]\n${output.text}` : output.text;
1463
+ /** Keep the newest diagnostic text without splitting a surrogate pair. */
1464
+ function formatBoundedChildOutput(text, maxChars = DEFAULT_MAX_OUTPUT_CHARS) {
1465
+ return text.length > maxChars ? `[output truncated]\n${sliceUtf16Safe(text, -maxChars)}` : text;
1609
1466
  }
1610
1467
  //#endregion
1611
1468
  //#region extensions/voice-call/src/webhook/tailscale.ts
@@ -1672,14 +1529,11 @@ async function getTailscaleSelfInfo() {
1672
1529
  return null;
1673
1530
  }
1674
1531
  }
1675
- async function getTailscaleDnsName() {
1676
- return (await getTailscaleSelfInfo())?.dnsName ?? null;
1677
- }
1678
1532
  async function cleanupTailscaleExposureRoute(opts) {
1679
1533
  await runTailscaleCommand(buildTailscaleExposureArgs(opts));
1680
1534
  }
1681
1535
  async function setupTailscaleExposureRoutes(opts) {
1682
- const dnsName = await getTailscaleDnsName();
1536
+ const dnsName = (await getTailscaleSelfInfo())?.dnsName;
1683
1537
  if (!dnsName) {
1684
1538
  console.warn("[voice-call] Could not get Tailscale DNS name");
1685
1539
  return null;
@@ -1855,7 +1709,7 @@ async function startNgrokTunnel(config) {
1855
1709
  });
1856
1710
  proc.stderr.on("data", (chunk) => {
1857
1711
  const combined = stderrTail + chunk;
1858
- if (combined.includes(NGROK_ERROR_MARKER)) rejectIfPending(`ngrok error: ${formatBoundedChildOutput(appendBoundedChildOutput(emptyBoundedChildOutput(), combined))}`, true);
1712
+ if (combined.includes(NGROK_ERROR_MARKER)) rejectIfPending(`ngrok error: ${formatBoundedChildOutput(combined)}`, true);
1859
1713
  stderrTail = sliceUtf16Safe(combined, -8);
1860
1714
  });
1861
1715
  listenForChildStreamErrors(proc, (stream, error) => {
@@ -1874,9 +1728,6 @@ async function startNgrokTunnel(config) {
1874
1728
  });
1875
1729
  });
1876
1730
  }
1877
- /**
1878
- * Start a Tailscale serve/funnel tunnel.
1879
- */
1880
1731
  async function startTailscaleTunnel(config) {
1881
1732
  const path = config.path.startsWith("/") ? config.path : `/${config.path}`;
1882
1733
  const routes = [{
@@ -1908,9 +1759,6 @@ async function startTailscaleTunnel(config) {
1908
1759
  }
1909
1760
  };
1910
1761
  }
1911
- /**
1912
- * Start a tunnel based on configuration.
1913
- */
1914
1762
  async function startTunnel(config) {
1915
1763
  switch (config.provider) {
1916
1764
  case "ngrok": return startNgrokTunnel({
@@ -1919,15 +1767,9 @@ async function startTunnel(config) {
1919
1767
  authToken: config.ngrokAuthToken,
1920
1768
  domain: config.ngrokDomain
1921
1769
  });
1922
- case "tailscale-serve": return startTailscaleTunnel({
1923
- mode: "serve",
1924
- port: config.port,
1925
- tailscalePort: config.tailscalePort ?? 443,
1926
- path: config.path,
1927
- streamPaths: config.streamPaths
1928
- });
1770
+ case "tailscale-serve":
1929
1771
  case "tailscale-funnel": return startTailscaleTunnel({
1930
- mode: "funnel",
1772
+ mode: config.provider === "tailscale-serve" ? "serve" : "funnel",
1931
1773
  port: config.port,
1932
1774
  tailscalePort: config.tailscalePort ?? 443,
1933
1775
  path: config.path,
@@ -1942,14 +1784,11 @@ async function startTunnel(config) {
1942
1784
  function providerRequiresPublicWebhook(providerName) {
1943
1785
  return providerName === "twilio" || providerName === "telnyx" || providerName === "plivo";
1944
1786
  }
1945
- /** Return true for localhost, private, or otherwise provider-unreachable hosts. */
1946
- function isLocalOnlyWebhookHost(hostname) {
1947
- return isBlockedHostnameOrIp(hostname);
1948
- }
1949
1787
  /** Return true when a webhook URL parses to a local/private host. */
1950
1788
  function isProviderUnreachableWebhookUrl(webhookUrl) {
1951
1789
  try {
1952
- return isLocalOnlyWebhookHost(new URL(webhookUrl).hostname);
1790
+ const parsed = new URL(webhookUrl);
1791
+ return isBlockedHostnameOrIp(parsed.hostname);
1953
1792
  } catch {
1954
1793
  return false;
1955
1794
  }
@@ -2422,54 +2261,21 @@ Content-Length: ${Buffer.byteLength(body)}\r\n\r
2422
2261
  * Send a message to a stream's WebSocket if available.
2423
2262
  */
2424
2263
  sendToStream(streamSid, message) {
2425
- const session = this.sessions.get(streamSid);
2426
- if (!session) return {
2427
- sent: false,
2428
- bufferedBeforeBytes: 0,
2429
- bufferedAfterBytes: 0
2430
- };
2431
- const readyState = session.ws.readyState;
2432
- const bufferedBeforeBytes = session.ws.bufferedAmount;
2433
- if (readyState !== WebSocket.OPEN) return {
2434
- sent: false,
2435
- readyState,
2436
- bufferedBeforeBytes,
2437
- bufferedAfterBytes: session.ws.bufferedAmount
2438
- };
2439
- if (bufferedBeforeBytes > MAX_WS_BUFFERED_BYTES) {
2264
+ const session = this.getOpenSession(streamSid);
2265
+ if (!session) return false;
2266
+ if (session.ws.bufferedAmount > MAX_WS_BUFFERED_BYTES) {
2440
2267
  session.ws.close(1013, "Backpressure: send buffer exceeded");
2441
- return {
2442
- sent: false,
2443
- readyState,
2444
- bufferedBeforeBytes,
2445
- bufferedAfterBytes: session.ws.bufferedAmount
2446
- };
2268
+ return false;
2447
2269
  }
2448
2270
  try {
2449
2271
  session.ws.send(JSON.stringify(message));
2450
- const bufferedAfterBytes = session.ws.bufferedAmount;
2451
- if (bufferedAfterBytes > MAX_WS_BUFFERED_BYTES) {
2272
+ if (session.ws.bufferedAmount > MAX_WS_BUFFERED_BYTES) {
2452
2273
  session.ws.close(1013, "Backpressure: send buffer exceeded");
2453
- return {
2454
- sent: false,
2455
- readyState,
2456
- bufferedBeforeBytes,
2457
- bufferedAfterBytes
2458
- };
2274
+ return false;
2459
2275
  }
2460
- return {
2461
- sent: true,
2462
- readyState,
2463
- bufferedBeforeBytes,
2464
- bufferedAfterBytes
2465
- };
2276
+ return true;
2466
2277
  } catch {
2467
- return {
2468
- sent: false,
2469
- readyState,
2470
- bufferedBeforeBytes,
2471
- bufferedAfterBytes: session.ws.bufferedAmount
2472
- };
2278
+ return false;
2473
2279
  }
2474
2280
  }
2475
2281
  /**
@@ -2533,7 +2339,7 @@ Content-Length: ${Buffer.byteLength(body)}\r\n\r
2533
2339
  marks.set(name, pending);
2534
2340
  signal.addEventListener("abort", onAbort, { once: true });
2535
2341
  });
2536
- if (!this.sendMark(streamSid, name).sent) pending.settle(/* @__PURE__ */ new Error("Telephony stream playback failed: completion mark not delivered"));
2342
+ if (!this.sendMark(streamSid, name)) pending.settle(/* @__PURE__ */ new Error("Telephony stream playback failed: completion mark not delivered"));
2537
2343
  return acknowledgement;
2538
2344
  }
2539
2345
  /**
@@ -2740,8 +2546,7 @@ const TERMINAL_PROVIDER_STATUS_TO_END_REASON = {
2740
2546
  };
2741
2547
  /** Normalize provider status text, falling back to "unknown". */
2742
2548
  function normalizeProviderStatus(status) {
2743
- const normalized = normalizeOptionalLowercaseString(status);
2744
- return normalized && normalized.length > 0 ? normalized : "unknown";
2549
+ return normalizeOptionalLowercaseString(status) ?? "unknown";
2745
2550
  }
2746
2551
  /** Map terminal provider status strings to OpenClaw end reasons. */
2747
2552
  function mapProviderStatusToEndReason(status) {
@@ -2845,7 +2650,7 @@ const MAX_WEBHOOK_BODY_BYTES = WEBHOOK_BODY_READ_DEFAULTS.preAuth.maxBytes;
2845
2650
  const WEBHOOK_BODY_TIMEOUT_MS = WEBHOOK_BODY_READ_DEFAULTS.preAuth.timeoutMs;
2846
2651
  const MISSING_REMOTE_ADDRESS_IN_FLIGHT_KEY = "__voice_call_no_remote__";
2847
2652
  const loadRealtimeTranscriptionRuntime = createLazyRuntimeModule(() => import("./realtime-transcription.runtime-CbJAs5t_.mjs"));
2848
- const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-hZyGIjO4.mjs"));
2653
+ const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-BzKrJMEb.mjs"));
2849
2654
  function appendRecentTalkEventMetadata(metadata, event) {
2850
2655
  const previous = metadata ?? {};
2851
2656
  const recent = Array.isArray(previous.recentTalkEvents) ? previous.recentTalkEvents.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
@@ -2960,9 +2765,6 @@ var VoiceCallWebhookServer = class {
2960
2765
  });
2961
2766
  });
2962
2767
  }
2963
- /**
2964
- * Get the media stream handler (for wiring to provider).
2965
- */
2966
2768
  getMediaStreamHandler() {
2967
2769
  return this.mediaStreamHandler;
2968
2770
  }
@@ -3023,7 +2825,7 @@ var VoiceCallWebhookServer = class {
3023
2825
  */
3024
2826
  async initializeMediaStreaming() {
3025
2827
  const streaming = this.config.streaming;
3026
- const pluginConfig = this.fullConfig ?? this.coreConfig;
2828
+ const pluginConfig = this.fullConfig ?? this.coreConfig ?? void 0;
3027
2829
  const { getRealtimeTranscriptionProvider, listRealtimeTranscriptionProviders } = await loadRealtimeTranscriptionRuntime();
3028
2830
  const resolution = resolveConfiguredCapabilityProvider({
3029
2831
  configuredProviderId: streaming.provider,
@@ -3056,7 +2858,7 @@ var VoiceCallWebhookServer = class {
3056
2858
  const streamConfig = {
3057
2859
  transcriptionProvider: resolution.provider,
3058
2860
  providerConfig: resolution.providerConfig,
3059
- cfg: this.fullConfig ?? this.coreConfig ?? void 0,
2861
+ cfg: pluginConfig,
3060
2862
  preStartTimeoutMs: streaming.preStartTimeoutMs,
3061
2863
  maxPendingConnections: streaming.maxPendingConnections,
3062
2864
  maxPendingConnectionsPerIp: streaming.maxPendingConnectionsPerIp,
@@ -3162,7 +2964,7 @@ var VoiceCallWebhookServer = class {
3162
2964
  this.realtimeHandler.handleWebSocketUpgrade(request, socket, head);
3163
2965
  return;
3164
2966
  }
3165
- if (this.getUpgradePathname(request) === streamPath && this.mediaStreamHandler) this.mediaStreamHandler?.handleUpgrade(request, socket, head);
2967
+ if (this.getUpgradePathname(request) === streamPath && this.mediaStreamHandler) this.mediaStreamHandler.handleUpgrade(request, socket, head);
3166
2968
  else {
3167
2969
  socket.once("error", () => {});
3168
2970
  rejectWebSocketUpgrade(socket, { status: 404 });
@@ -3193,9 +2995,6 @@ var VoiceCallWebhookServer = class {
3193
2995
  });
3194
2996
  return this.startPromise;
3195
2997
  }
3196
- /**
3197
- * Stop the webhook server.
3198
- */
3199
2998
  stop() {
3200
2999
  if (this.stopPromise) return this.stopPromise;
3201
3000
  const server = this.server;
@@ -3253,9 +3052,6 @@ var VoiceCallWebhookServer = class {
3253
3052
  isWebhookPathMatch(requestPath, configuredPath) {
3254
3053
  return normalizeWebhookPath(requestPath) === normalizeWebhookPath(configuredPath);
3255
3054
  }
3256
- /**
3257
- * Handle incoming HTTP request.
3258
- */
3259
3055
  async handleRequest(req, res, webhookPath) {
3260
3056
  const payload = await this.runWebhookPipeline(req, webhookPath, res);
3261
3057
  if (payload) this.writeWebhookResponse(res, payload);
@@ -3300,7 +3096,11 @@ var VoiceCallWebhookServer = class {
3300
3096
  try {
3301
3097
  let body = "";
3302
3098
  try {
3303
- body = await this.readBody(req, MAX_WEBHOOK_BODY_BYTES, WEBHOOK_BODY_TIMEOUT_MS);
3099
+ body = await readRequestBodyWithLimit(req, {
3100
+ maxBytes: MAX_WEBHOOK_BODY_BYTES,
3101
+ timeoutMs: WEBHOOK_BODY_TIMEOUT_MS,
3102
+ destroyOnLimit: false
3103
+ });
3304
3104
  } catch (err) {
3305
3105
  if (isRequestBodyLimitError(err, "PAYLOAD_TOO_LARGE")) {
3306
3106
  await sendHttpRequestRejection(req, res, 413, "Payload Too Large");
@@ -3505,16 +3305,6 @@ var VoiceCallWebhookServer = class {
3505
3305
  res.end(payload.body);
3506
3306
  }
3507
3307
  /**
3508
- * Read request body as string with timeout protection.
3509
- */
3510
- readBody(req, maxBytes, timeoutMs) {
3511
- return readRequestBodyWithLimit(req, {
3512
- maxBytes,
3513
- timeoutMs,
3514
- destroyOnLimit: false
3515
- });
3516
- }
3517
- /**
3518
3308
  * Handle auto-response for inbound calls using the agent system.
3519
3309
  * Supports tool calling for richer voice interactions.
3520
3310
  */
@@ -3585,21 +3375,12 @@ const REALTIME_VOICE_CONSULT_SYSTEM_PROMPT = [
3585
3375
  "Do not print secret values or dump environment variables; only check whether required configuration is present.",
3586
3376
  "Be accurate, brief, and speakable."
3587
3377
  ].join(" ");
3588
- const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-BV56PXr-.mjs"));
3589
- const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-BMb-7cu-.mjs"));
3590
- const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-BGJda1Uz.mjs"));
3591
- const loadMockProvider = createLazyRuntimeModule(() => import("./mock-CcYEAUhV.mjs"));
3378
+ const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-DjFGCfy1.mjs"));
3379
+ const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-Bp3gfmUB.mjs"));
3380
+ const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-69ObrQPk.mjs"));
3381
+ const loadMockProvider = createLazyRuntimeModule(() => import("./mock-ClWW6Ufu.mjs"));
3592
3382
  const loadRealtimeVoiceRuntime = createLazyRuntimeModule(() => import("./realtime-voice.runtime-vtdCOWg-.mjs"));
3593
- const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-DlFmdSPn.mjs"));
3594
- function resolveVoiceCallConsultSessionKey(call) {
3595
- return resolveVoiceCallSessionKey({
3596
- config: call.config,
3597
- callId: call.callId,
3598
- phone: call.direction === "outbound" ? call.to : call.from,
3599
- explicitSessionKey: call.sessionKey,
3600
- coreSession: call.coreSession
3601
- });
3602
- }
3383
+ const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-BgDPcPZt.mjs"));
3603
3384
  function mapVoiceCallConsultTranscript(call, context) {
3604
3385
  const transcript = (call.transcript ?? []).map((entry) => ({
3605
3386
  role: entry.speaker === "bot" ? "assistant" : "user",
@@ -3707,7 +3488,7 @@ async function createRealtimeInstructionsResolver(params) {
3707
3488
  baseInstructions: params.config.realtime.instructions,
3708
3489
  config: genericConfig,
3709
3490
  coreConfig: params.coreConfig,
3710
- agentRuntime: params.agentRuntime,
3491
+ warn: params.warn,
3711
3492
  agentId: params.config.agentId
3712
3493
  });
3713
3494
  const entries = await Promise.all(listRealtimeAgentIds(params.config, params.coreConfig).map(async (agentId) => {
@@ -3718,7 +3499,7 @@ async function createRealtimeInstructionsResolver(params) {
3718
3499
  agentId
3719
3500
  },
3720
3501
  coreConfig: params.coreConfig,
3721
- agentRuntime: params.agentRuntime,
3502
+ warn: params.warn,
3722
3503
  agentId
3723
3504
  })];
3724
3505
  }));
@@ -3751,13 +3532,13 @@ async function createVoiceCallRuntime(params) {
3751
3532
  if (stateRuntime) setVoiceCallStateRuntime({ state: stateRuntime });
3752
3533
  const manager = new CallManager(config, void 0, cfg.session, stateRuntime);
3753
3534
  const realtimeVoiceRuntime = config.realtime.enabled ? await loadRealtimeVoiceRuntime() : null;
3754
- const webhookServer = new VoiceCallWebhookServer(config, manager, provider, coreConfig, fullConfig ?? coreConfig, agentRuntime, log);
3535
+ const webhookServer = new VoiceCallWebhookServer(config, manager, provider, coreConfig, cfg, agentRuntime, log);
3755
3536
  if (realtimeVoiceRuntime) {
3756
3537
  const { RealtimeCallHandler } = await loadRealtimeHandler();
3757
3538
  const resolveRealtimeInstructions = await createRealtimeInstructionsResolver({
3758
3539
  config,
3759
3540
  coreConfig: cfg,
3760
- agentRuntime
3541
+ warn: (message) => log.warn(`[voice-call] ${message}`)
3761
3542
  });
3762
3543
  const realtimeConfig = {
3763
3544
  ...config.realtime,
@@ -3791,12 +3572,14 @@ async function createVoiceCallRuntime(params) {
3791
3572
  const numberRouteKey = resolveVoiceCallNumberRouteKeyForCall(call);
3792
3573
  const effectiveConfig = resolveVoiceCallEffectiveConfig(config, numberRouteKey).config;
3793
3574
  const agentId = resolveCallAgentId(call, effectiveConfig);
3794
- const sessionKey = resolveVoiceCallConsultSessionKey({
3795
- ...call,
3575
+ const sessionKey = resolveVoiceCallSessionKey({
3796
3576
  config: {
3797
3577
  ...effectiveConfig,
3798
3578
  agentId
3799
3579
  },
3580
+ callId: call.callId,
3581
+ phone: call.direction === "outbound" ? call.to : call.from,
3582
+ explicitSessionKey: call.sessionKey,
3800
3583
  coreSession: cfg.session
3801
3584
  });
3802
3585
  const requesterSessionKey = typeof call.metadata?.requesterSessionKey === "string" ? call.metadata.requesterSessionKey : void 0;
@@ -3808,13 +3591,17 @@ async function createVoiceCallRuntime(params) {
3808
3591
  spawnedBy: requesterSessionKey
3809
3592
  };
3810
3593
  assertRealtimeVoiceAgentConsultModelSelectionUnlocked(modelLockParams);
3811
- const fastContext = await resolveRealtimeFastContextConsult({
3594
+ const fastContext = await resolveRealtimeVoiceFastContextConsult({
3812
3595
  cfg,
3813
3596
  agentId,
3814
3597
  sessionKey,
3815
3598
  config: effectiveConfig.realtime.fastContext,
3816
3599
  args,
3817
- logger: log
3600
+ logger: log,
3601
+ labels: {
3602
+ audienceLabel: "caller",
3603
+ contextName: "OpenClaw memory or session context"
3604
+ }
3818
3605
  });
3819
3606
  handlerContext.abortSignal?.throwIfAborted();
3820
3607
  if (fastContext.handled) {
@@ -3915,10 +3702,8 @@ async function createVoiceCallRuntime(params) {
3915
3702
  }
3916
3703
  if (realtimeVoiceRuntime) log.info("[voice-call] Realtime voice enabled");
3917
3704
  await manager.initialize(provider, webhookUrl);
3918
- const stop = () => lifecycle.stop();
3919
3705
  log.info("[voice-call] Runtime initialized");
3920
3706
  log.info(`[voice-call] Webhook URL: ${webhookUrl}`);
3921
- if (publicUrl && publicUrl !== webhookUrl) log.info(`[voice-call] Public URL: ${publicUrl}`);
3922
3707
  return {
3923
3708
  config,
3924
3709
  provider,
@@ -3926,7 +3711,7 @@ async function createVoiceCallRuntime(params) {
3926
3711
  webhookServer,
3927
3712
  webhookUrl,
3928
3713
  publicUrl,
3929
- stop
3714
+ stop: () => lifecycle.stop()
3930
3715
  };
3931
3716
  } catch (err) {
3932
3717
  await lifecycle.stop({ suppressErrors: true });
@@ -3934,4 +3719,4 @@ async function createVoiceCallRuntime(params) {
3934
3719
  }
3935
3720
  }
3936
3721
  //#endregion
3937
- export { resolveCallAgentId as _, normalizeProviderStatus as a, escapeXml as b, canonicalizeVoiceCallMediaBase64 as c, cleanupTailscaleExposureRoute as d, getTailscaleSelfInfo as f, resolveVoiceResponseModel as g, chunkAudio as h, mapProviderStatusToEndReason as i, getHeader as l, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS as m, normalizeProxyIp as n, WebSocket as o, setupTailscaleExposureRoutes as p, isProviderStatusTerminal as r, WebSocketServer as s, createVoiceCallRuntime as t, resolveWebhookExposureStatus as u, resolveVoiceCallAgentId as v, mapVoiceToPolly as x, resolveUserPath as y };
3722
+ export { resolveCallAgentId as _, normalizeProviderStatus as a, mapVoiceToPolly as b, canonicalizeVoiceCallMediaBase64 as c, cleanupTailscaleExposureRoute as d, getTailscaleSelfInfo as f, resolveVoiceResponseModel as g, chunkAudio as h, mapProviderStatusToEndReason as i, getHeader as l, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS as m, normalizeProxyIp as n, WebSocket as o, setupTailscaleExposureRoutes as p, isProviderStatusTerminal as r, WebSocketServer as s, createVoiceCallRuntime as t, resolveWebhookExposureStatus as u, resolveVoiceCallAgentId as v, escapeXml as y };