@openclaw/voice-call 2026.9.2 → 2026.9.3

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.
@@ -1,8 +1,8 @@
1
1
  import { sleep } from "./runtime-api.js";
2
2
  import "./api.js";
3
3
  import { l as resolveVoiceCallStreamExposurePaths, u as validateProviderConfig } from "./config-DQwvsxeV.js";
4
- import { _ as resolveUserPath, c as resolveWebhookExposureStatus, d as setupTailscaleExposureRoutes, g as resolveVoiceCallAgentId, l as cleanupTailscaleExposureRoute, u as getTailscaleSelfInfo } from "./runtime-entry-DNmi-vZR.js";
5
- import { b as setVoiceCallStateRuntime, d as loadActiveCallsFromStore, l as findCallInStore, o as MAX_CALL_RECORD_EVENTS, t as resolveDefaultVoiceCallStoreDir, u as getCallHistoryFromStore } from "./store-path-C_z9zKnA.js";
4
+ import { d as cleanupTailscaleExposureRoute, f as getTailscaleSelfInfo, p as setupTailscaleExposureRoutes, u as resolveWebhookExposureStatus, v as resolveVoiceCallAgentId, y as resolveUserPath } from "./runtime-entry-B8SNb2qD.js";
5
+ import { b as setVoiceCallStateRuntime, d as loadActiveCallsFromStore, l as findCallInStore, o as MAX_CALL_RECORD_EVENTS, t as resolveDefaultVoiceCallStoreDir, u as getCallHistoryFromStore } from "./store-path-M0GXxUfv.js";
6
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
7
7
  import { callGatewayFromCli, isGatewayClientRequestError, isGatewayTransportError, redactSensitiveUrlLikeString } from "openclaw/plugin-sdk/gateway-runtime";
8
8
  import { isRecord, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -1,4 +1,4 @@
1
- import { a as CALL_RECORD_EVENT_META_MAX_ENTRIES, c as buildVoiceCallLegacyJsonlEventKey, f as parseVoiceCallRecordLine, h as resolveVoiceCallLegacyCallLogPath, i as CALL_RECORD_EVENT_CHUNKS_NAMESPACE, m as prepareVoiceCallRecordForStorage, n as CALL_RECORD_CHUNK_MAX_ENTRIES, o as MAX_CALL_RECORD_EVENTS, r as CALL_RECORD_EVENTS_NAMESPACE, s as RAW_CALL_RECORD_CHUNK_BYTES, t as resolveDefaultVoiceCallStoreDir } from "./store-path-C_z9zKnA.js";
1
+ import { a as CALL_RECORD_EVENT_META_MAX_ENTRIES, c as buildVoiceCallLegacyJsonlEventKey, f as parseVoiceCallRecordLine, h as resolveVoiceCallLegacyCallLogPath, i as CALL_RECORD_EVENT_CHUNKS_NAMESPACE, m as prepareVoiceCallRecordForStorage, n as CALL_RECORD_CHUNK_MAX_ENTRIES, o as MAX_CALL_RECORD_EVENTS, r as CALL_RECORD_EVENTS_NAMESPACE, s as RAW_CALL_RECORD_CHUNK_BYTES, t as resolveDefaultVoiceCallStoreDir } from "./store-path-M0GXxUfv.js";
2
2
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
3
3
  import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import path from "node:path";
@@ -68,6 +68,7 @@ function describeVoiceCallSchemaMigration(migration) {
68
68
  case "state-consolidation-v13": return "cron jobs and subagent runs -> canonical JSON storage";
69
69
  case "creator-namespace-v14": return "cron creators -> explicit principal namespaces";
70
70
  case "conversation-binding-targets-v15": return "conversation bindings -> exact target keys without agent/session projections";
71
+ case "skill-workshop-directory-ownership-v16": return "Skill Workshop proposals -> per-agent Workshop directory ownership";
71
72
  case "worker-placement-execution-mode-v8": return "cloud worker placements -> execution-mode claims";
72
73
  case "operator-approvals-system-agent": return "operator approvals -> OpenClaw system changes";
73
74
  case "session-watch-cursor-provenance-v4": return "session watch cursors -> provenance column";
@@ -1,6 +1,6 @@
1
1
  import { fetchWithSsrFGuard } from "./runtime-api.js";
2
2
  import "./api.js";
3
- import { n as normalizeProxyIp, s as getHeader } from "./runtime-entry-DNmi-vZR.js";
3
+ import { l as getHeader, n as normalizeProxyIp } from "./runtime-entry-B8SNb2qD.js";
4
4
  import { n as reserveWebhookReplay, t as createWebhookReplayCache } from "./webhook-replay-CCQSoBNF.js";
5
5
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6
6
  import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { definePluginEntry } from "./runtime-api.js";
2
2
  import "./api.js";
3
3
  import { VOICE_CALL_CLI_DESCRIPTOR } from "./cli-output-mode.js";
4
4
  import { i as resolveVoiceCallConfig, t as VoiceCallConfigSchema, u as validateProviderConfig } from "./config-DQwvsxeV.js";
5
- import { t as createVoiceCallRuntime } from "./runtime-entry-DNmi-vZR.js";
5
+ import { t as createVoiceCallRuntime } from "./runtime-entry-B8SNb2qD.js";
6
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
7
7
  import { ErrorCodes, errorShape } from "openclaw/plugin-sdk/gateway-runtime";
8
8
  import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
@@ -514,7 +514,7 @@ var voice_call_default = definePluginEntry({
514
514
  }
515
515
  }));
516
516
  api.registerCli(async ({ program }) => {
517
- const { registerVoiceCallCli } = await import("./cli-D3DeAqfd.js");
517
+ const { registerVoiceCallCli } = await import("./cli-D7qQRwUE.js");
518
518
  registerVoiceCallCli({
519
519
  program,
520
520
  config,
@@ -1,5 +1,5 @@
1
- import { s as getHeader, v as escapeXml } from "./runtime-entry-DNmi-vZR.js";
2
- import { a as reconstructWebhookUrl, o as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-BhLtja0F.js";
1
+ import { b as escapeXml, l as getHeader } from "./runtime-entry-B8SNb2qD.js";
2
+ import { a as reconstructWebhookUrl, o as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Z9SuGiD_.js";
3
3
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import crypto from "node:crypto";
5
5
  //#region extensions/voice-call/src/providers/plivo.ts
@@ -1,5 +1,5 @@
1
1
  import { d as REALTIME_VOICE_END_CALL_TOOL_NAME, s as resolveVoiceCallPublicPathPrefix } from "./config-DQwvsxeV.js";
2
- import { o as canonicalizeVoiceCallMediaBase64 } from "./runtime-entry-DNmi-vZR.js";
2
+ import { c as canonicalizeVoiceCallMediaBase64, o as WebSocket, s as WebSocketServer } from "./runtime-entry-B8SNb2qD.js";
3
3
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
4
4
  import { asNullableRecord, asOptionalObjectRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
@@ -9,7 +9,6 @@ import { isFutureDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openc
9
9
  import { randomUUID } from "node:crypto";
10
10
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
11
11
  import "node:http";
12
- import WebSocket$1, { WebSocketServer } from "ws";
13
12
  //#region extensions/voice-call/src/webhook/realtime-audio-pacer.ts
14
13
  const TELEPHONY_SAMPLE_RATE = 8e3;
15
14
  const TELEPHONY_CHUNK_BYTES = 160;
@@ -443,6 +442,15 @@ function appendRecentTalkEventMetadata(call, event) {
443
442
  }].slice(-12);
444
443
  call.metadata = metadata;
445
444
  }
445
+ function rejectRealtimeUpgrade(socket, status) {
446
+ const reason = status === 401 ? "Unauthorized" : "Service Unavailable";
447
+ try {
448
+ socket.end(`HTTP/1.1 ${status} ${reason}\r\nConnection: close\r\n\r\n`, () => socket.destroy());
449
+ } catch (error) {
450
+ socket.destroy();
451
+ throw error;
452
+ }
453
+ }
446
454
  var RealtimeCallHandler = class {
447
455
  constructor(config, manager, resolveCallRegistration, servePath, streamDisconnectLifecycle, coreConfig) {
448
456
  this.config = config;
@@ -506,16 +514,15 @@ var RealtimeCallHandler = class {
506
514
  }
507
515
  }
508
516
  handleWebSocketUpgrade(request, socket, head) {
517
+ socket.once("error", () => socket.destroy());
509
518
  if (this.closing) {
510
- socket.write("HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n");
511
- socket.destroy();
519
+ rejectRealtimeUpgrade(socket, 503);
512
520
  return;
513
521
  }
514
522
  const token = new URL(request.url ?? "/", "wss://localhost").pathname.split("/").pop() ?? null;
515
523
  const callerMeta = token ? this.consumeStreamToken(token) : null;
516
524
  if (!callerMeta) {
517
- socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
518
- socket.destroy();
525
+ rejectRealtimeUpgrade(socket, 401);
519
526
  return;
520
527
  }
521
528
  const adapter = (callerMeta.providerName ?? "twilio") === "telnyx" ? new TelnyxStreamFrameAdapter() : new TwilioStreamFrameAdapter();
@@ -598,7 +605,7 @@ var RealtimeCallHandler = class {
598
605
  this.pendingStreamTokens.clear();
599
606
  const sockets = [...this.activeSockets];
600
607
  this.closePromise = Promise.all([shutdownBarrier, ...sockets.map((ws) => new Promise((resolve) => {
601
- if (ws.readyState === WebSocket$1.CLOSED) {
608
+ if (ws.readyState === WebSocket.CLOSED) {
602
609
  resolve();
603
610
  return;
604
611
  }
@@ -790,7 +797,7 @@ var RealtimeCallHandler = class {
790
797
  });
791
798
  console.log(`[voice-call] Realtime bridge starting for call ${callId} (providerCallId=${callSid}, initialGreeting=${initialGreetingInstructions ? "queued" : "absent"})`);
792
799
  const sendString = (message) => {
793
- if (ws.readyState !== WebSocket$1.OPEN) return false;
800
+ if (ws.readyState !== WebSocket.OPEN) return false;
794
801
  if (ws.bufferedAmount > MAX_REALTIME_WS_BUFFERED_BYTES) {
795
802
  console.warn(`[voice-call] realtime outbound websocket backpressure before send callId=${callId} providerCallId=${callSid} bufferedBytes=${ws.bufferedAmount}`);
796
803
  ws.close(1013, "Backpressure: send buffer exceeded");
@@ -813,7 +820,7 @@ var RealtimeCallHandler = class {
813
820
  },
814
821
  onBackpressure: () => {
815
822
  console.warn(`[voice-call] realtime paced audio backpressure callId=${callId} providerCallId=${callSid}`);
816
- if (ws.readyState === WebSocket$1.OPEN) ws.close(1013, "Backpressure: paced audio queue exceeded");
823
+ if (ws.readyState === WebSocket.OPEN) ws.close(1013, "Backpressure: paced audio queue exceeded");
817
824
  }
818
825
  });
819
826
  const speechDetector = createSpeechThresholdGate({
@@ -839,7 +846,7 @@ var RealtimeCallHandler = class {
839
846
  initialGreetingInstructions,
840
847
  triggerGreetingOnReady: Boolean(initialGreetingInstructions),
841
848
  audioSink: {
842
- isOpen: () => ws.readyState === WebSocket$1.OPEN,
849
+ isOpen: () => ws.readyState === WebSocket.OPEN,
843
850
  sendAudio: (muLaw) => {
844
851
  harness.recordOutputAudio(muLaw);
845
852
  audioPacer.sendAudio(muLaw);
@@ -1035,7 +1042,7 @@ var RealtimeCallHandler = class {
1035
1042
  if (ownsCallState) this.clearUserTranscriptState(callId, userTranscriptOwner);
1036
1043
  if (reason === "completed" && (!ownsCallState || sessionClosed)) return;
1037
1044
  this.streamDisconnectLifecycle.retire(callSid, streamSid);
1038
- if (ws.readyState === WebSocket$1.OPEN) ws.close(reason === "error" ? 1011 : 1e3, "Bridge disconnected");
1045
+ if (ws.readyState === WebSocket.OPEN) ws.close(reason === "error" ? 1011 : 1e3, "Bridge disconnected");
1039
1046
  if (ownsCallState) emitCallEnd(reason);
1040
1047
  }
1041
1048
  };
@@ -1056,7 +1063,7 @@ var RealtimeCallHandler = class {
1056
1063
  audioPacer.close();
1057
1064
  const reason = provisionalCloseReason ?? "error";
1058
1065
  if (!hadPredecessorOnAdmission || !this.activeBridgesByCallId.has(callId)) emitCallEnd(reason);
1059
- if (ws.readyState === WebSocket$1.OPEN) ws.close(reason === "error" ? 1011 : 1e3, "Failed to create realtime bridge");
1066
+ if (ws.readyState === WebSocket.OPEN) ws.close(reason === "error" ? 1011 : 1e3, "Failed to create realtime bridge");
1060
1067
  return null;
1061
1068
  }
1062
1069
  const session = candidate;
@@ -1128,7 +1135,7 @@ var RealtimeCallHandler = class {
1128
1135
  close: (cause) => closeBinding(telephonyBinding, cause),
1129
1136
  endCall: () => {
1130
1137
  closeBinding(telephonyBinding);
1131
- if (ws.readyState === WebSocket$1.OPEN) ws.close(1e3, "Call ended");
1138
+ if (ws.readyState === WebSocket.OPEN) ws.close(1e3, "Call ended");
1132
1139
  },
1133
1140
  noteMediaActivity: () => {
1134
1141
  if (bindingClosed || this.activeTelephonyBindingsByCallId.get(callId) !== telephonyBinding) return;
@@ -1137,7 +1144,7 @@ var RealtimeCallHandler = class {
1137
1144
  console.warn(`[voice-call] Realtime media inactive callId=${callId} providerCallId=${callSid} timeoutMs=${REALTIME_MEDIA_INACTIVITY_TIMEOUT_MS} graceMs=${REALTIME_DISCONNECT_HANGUP_GRACE_MS}`);
1138
1145
  livenessTimer = setTimeout(() => {
1139
1146
  telephonyBinding.close("inactivity");
1140
- if (ws.readyState === WebSocket$1.OPEN) ws.close(1e3, "Media inactivity");
1147
+ if (ws.readyState === WebSocket.OPEN) ws.close(1e3, "Media inactivity");
1141
1148
  }, REALTIME_DISCONNECT_HANGUP_GRACE_MS);
1142
1149
  livenessTimer.unref?.();
1143
1150
  }, REALTIME_MEDIA_INACTIVITY_TIMEOUT_MS);
@@ -1,5 +1,5 @@
1
1
  import { c as resolveVoiceCallSessionKey } from "./config-DQwvsxeV.js";
2
- import { h as resolveCallAgentId, m as resolveVoiceResponseModel } from "./runtime-entry-DNmi-vZR.js";
2
+ import { _ as resolveCallAgentId, g as resolveVoiceResponseModel } from "./runtime-entry-B8SNb2qD.js";
3
3
  import { filterStringEntries, isRecord, normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { resolveAgentConfig } from "openclaw/plugin-sdk/agent-scope-runtime";
5
5
  import { isValidAgentHarnessSessionStoreEntry } from "openclaw/plugin-sdk/session-store-runtime";
@@ -1,7 +1,8 @@
1
1
  import { isBlockedHostnameOrIp, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, sendHttpRequestRejection } from "./runtime-api.js";
2
2
  import "./api.js";
3
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-DQwvsxeV.js";
4
- import { _ as releaseRejectedProviderCall, b as setVoiceCallStateRuntime, d as loadActiveCallsFromStore, g as appendCallReplayKey, l as findCallInStore, p as persistCallRecord, t as resolveDefaultVoiceCallStoreDir, u as getCallHistoryFromStore, v as rememberManagerReplayKey, x as TerminalStates, y as reserveRejectedProviderCall } from "./store-path-C_z9zKnA.js";
4
+ import { _ as releaseRejectedProviderCall, b as setVoiceCallStateRuntime, d as loadActiveCallsFromStore, g as appendCallReplayKey, l as findCallInStore, p as persistCallRecord, t as resolveDefaultVoiceCallStoreDir, u as getCallHistoryFromStore, v as rememberManagerReplayKey, x as TerminalStates, y as reserveRejectedProviderCall } from "./store-path-M0GXxUfv.js";
5
+ import { createRequire } from "node:module";
5
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6
7
  import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
7
8
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
@@ -24,7 +25,6 @@ import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
24
25
  import http from "node:http";
25
26
  import { URL as URL$1 } from "node:url";
26
27
  import { resolveConfiguredCapabilityProvider } from "openclaw/plugin-sdk/provider-selection-runtime";
27
- import { WebSocket, WebSocketServer } from "ws";
28
28
  import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
29
29
  //#region extensions/voice-call/src/allowlist.ts
30
30
  /** Normalize a phone number to digits only. */
@@ -1850,6 +1850,10 @@ function canonicalizeVoiceCallMediaBase64(payloadBase64) {
1850
1850
  return canonicalizeBase64(payloadBase64.replaceAll("-", "+").replaceAll("_", "/"));
1851
1851
  }
1852
1852
  //#endregion
1853
+ //#region extensions/voice-call/src/websocket.ts
1854
+ const require = createRequire(import.meta.url);
1855
+ const { WebSocket, WebSocketServer } = require(path.join(path.dirname(require.resolve("ws/package.json")), "index.js"));
1856
+ //#endregion
1853
1857
  //#region extensions/voice-call/src/media-stream.ts
1854
1858
  const DEFAULT_PRE_START_TIMEOUT_MS = 5e3;
1855
1859
  const DEFAULT_MAX_PENDING_CONNECTIONS = 32;
@@ -2687,7 +2691,7 @@ const MAX_WEBHOOK_BODY_BYTES = WEBHOOK_BODY_READ_DEFAULTS.preAuth.maxBytes;
2687
2691
  const WEBHOOK_BODY_TIMEOUT_MS = WEBHOOK_BODY_READ_DEFAULTS.preAuth.timeoutMs;
2688
2692
  const MISSING_REMOTE_ADDRESS_IN_FLIGHT_KEY = "__voice_call_no_remote__";
2689
2693
  const loadRealtimeTranscriptionRuntime = createLazyRuntimeModule(() => import("./realtime-transcription.runtime-CbJAs5t_.js"));
2690
- const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-BK43h7yV.js"));
2694
+ const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-IX26g0hi.js"));
2691
2695
  function appendRecentTalkEventMetadata(call, event) {
2692
2696
  const metadata = call.metadata ?? {};
2693
2697
  const recent = Array.isArray(metadata.recentTalkEvents) ? metadata.recentTalkEvents.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
@@ -3413,12 +3417,12 @@ const REALTIME_VOICE_CONSULT_SYSTEM_PROMPT = [
3413
3417
  "Do not print secret values or dump environment variables; only check whether required configuration is present.",
3414
3418
  "Be accurate, brief, and speakable."
3415
3419
  ].join(" ");
3416
- const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-DCbnTTjn.js"));
3417
- const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-BwJFcA2z.js"));
3418
- const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-qIMf0pd2.js"));
3420
+ const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-B8shXuBM.js"));
3421
+ const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-DhsTO8-E.js"));
3422
+ const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-qSdVTUcE.js"));
3419
3423
  const loadMockProvider = createLazyRuntimeModule(() => import("./mock-C57qj18W.js"));
3420
3424
  const loadRealtimeVoiceRuntime = createLazyRuntimeModule(() => import("./realtime-voice.runtime-vtdCOWg-.js"));
3421
- const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-CHCnMJfl.js"));
3425
+ const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-BSW48gqM.js"));
3422
3426
  function resolveVoiceCallConsultSessionKey(call) {
3423
3427
  return resolveVoiceCallSessionKey({
3424
3428
  config: call.config,
@@ -3760,4 +3764,4 @@ async function createVoiceCallRuntime(params) {
3760
3764
  }
3761
3765
  }
3762
3766
  //#endregion
3763
- export { resolveUserPath as _, normalizeProviderStatus as a, resolveWebhookExposureStatus as c, setupTailscaleExposureRoutes as d, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS as f, resolveVoiceCallAgentId as g, resolveCallAgentId as h, mapProviderStatusToEndReason as i, cleanupTailscaleExposureRoute as l, resolveVoiceResponseModel as m, normalizeProxyIp as n, canonicalizeVoiceCallMediaBase64 as o, chunkAudio as p, isProviderStatusTerminal as r, getHeader as s, createVoiceCallRuntime as t, getTailscaleSelfInfo as u, escapeXml as v, mapVoiceToPolly as y };
3767
+ 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 };
@@ -1,2 +1,2 @@
1
- import { t as createVoiceCallRuntime } from "./runtime-entry-DNmi-vZR.js";
1
+ import { t as createVoiceCallRuntime } from "./runtime-entry-B8SNb2qD.js";
2
2
  export { createVoiceCallRuntime };
@@ -10,34 +10,6 @@ const ProviderNameSchema = z.enum([
10
10
  "plivo",
11
11
  "mock"
12
12
  ]);
13
- const CallStateSchema = z.enum([
14
- "initiated",
15
- "ringing",
16
- "answered",
17
- "active",
18
- "speaking",
19
- "listening",
20
- "completed",
21
- "hangup-user",
22
- "hangup-bot",
23
- "timeout",
24
- "error",
25
- "failed",
26
- "no-answer",
27
- "busy",
28
- "voicemail"
29
- ]);
30
- const TerminalStates = /* @__PURE__ */ new Set([
31
- "completed",
32
- "hangup-user",
33
- "hangup-bot",
34
- "timeout",
35
- "error",
36
- "failed",
37
- "no-answer",
38
- "busy",
39
- "voicemail"
40
- ]);
41
13
  const EndReasonSchema = z.enum([
42
14
  "completed",
43
15
  "hangup-user",
@@ -49,54 +21,16 @@ const EndReasonSchema = z.enum([
49
21
  "busy",
50
22
  "voicemail"
51
23
  ]);
52
- const BaseEventSchema = z.object({
53
- id: z.string(),
54
- dedupeKey: z.string().optional(),
55
- callId: z.string(),
56
- providerCallId: z.string().optional(),
57
- timestamp: z.number(),
58
- turnToken: z.string().optional(),
59
- direction: z.enum(["inbound", "outbound"]).optional(),
60
- from: z.string().optional(),
61
- to: z.string().optional()
62
- });
63
- z.discriminatedUnion("type", [
64
- BaseEventSchema.extend({ type: z.literal("call.initiated") }),
65
- BaseEventSchema.extend({ type: z.literal("call.ringing") }),
66
- BaseEventSchema.extend({ type: z.literal("call.answered") }),
67
- BaseEventSchema.extend({ type: z.literal("call.active") }),
68
- BaseEventSchema.extend({
69
- type: z.literal("call.speaking"),
70
- text: z.string()
71
- }),
72
- BaseEventSchema.extend({
73
- type: z.literal("call.assistant-speech"),
74
- transcript: z.string()
75
- }),
76
- BaseEventSchema.extend({
77
- type: z.literal("call.speech"),
78
- transcript: z.string(),
79
- isFinal: z.boolean(),
80
- confidence: z.number().min(0).max(1).optional()
81
- }),
82
- BaseEventSchema.extend({
83
- type: z.literal("call.silence"),
84
- durationMs: z.number()
85
- }),
86
- BaseEventSchema.extend({
87
- type: z.literal("call.dtmf"),
88
- digits: z.string()
89
- }),
90
- BaseEventSchema.extend({
91
- type: z.literal("call.ended"),
92
- reason: EndReasonSchema
93
- }),
94
- BaseEventSchema.extend({
95
- type: z.literal("call.error"),
96
- error: z.string(),
97
- retryable: z.boolean().optional()
98
- })
24
+ const CallStateSchema = z.enum([
25
+ "initiated",
26
+ "ringing",
27
+ "answered",
28
+ "active",
29
+ "speaking",
30
+ "listening",
31
+ ...EndReasonSchema.options
99
32
  ]);
33
+ const TerminalStates = new Set(EndReasonSchema.options);
100
34
  const CallDirectionSchema = z.enum(["outbound", "inbound"]);
101
35
  const TranscriptEntrySchema = z.object({
102
36
  timestamp: z.number(),
@@ -358,12 +292,14 @@ function pruneCallRecordEvents(stores) {
358
292
  for (const row of sorted.slice(0, rows.length - MAX_CALL_RECORD_EVENTS)) deleteCallRecordEventRows(stores, row.key);
359
293
  }
360
294
  /** Read and reassemble one chunked call record event. */
361
- function readCallRecordEvent(stores, eventKey) {
362
- const meta = stores.events.lookup(eventKey);
363
- if (!meta) return null;
295
+ function readCallRecordEvent(stores, eventKey, meta) {
296
+ if (!Number.isSafeInteger(meta.chunkCount) || meta.chunkCount < 1 || meta.chunkCount > 48) return null;
297
+ const records = stores.chunks.lookupMany?.(Array.from({ length: meta.chunkCount }, (_, index) => buildChunkKey(eventKey, index)));
364
298
  const chunks = [];
365
299
  for (let index = 0; index < meta.chunkCount; index += 1) {
366
- const chunk = stores.chunks.lookup(buildChunkKey(eventKey, index));
300
+ const result = records?.[index];
301
+ if (result && !result.ok) throw result.error;
302
+ const chunk = records ? result?.value : stores.chunks.lookup(buildChunkKey(eventKey, index));
367
303
  if (!chunk || chunk.index !== index) return null;
368
304
  chunks.push(Buffer.from(chunk.dataBase64, "base64"));
369
305
  }
@@ -372,7 +308,7 @@ function readCallRecordEvent(stores, eventKey) {
372
308
  /** Read all persisted call records in stable persisted order. */
373
309
  function readCallRecordEvents(stores) {
374
310
  return stores.events.entries().toSorted((a, b) => a.createdAt - b.createdAt || a.key.localeCompare(b.key)).map((entry) => {
375
- const call = readCallRecordEvent(stores, entry.key);
311
+ const call = readCallRecordEvent(stores, entry.key, entry.value);
376
312
  return call ? {
377
313
  call,
378
314
  persistedAt: entry.value.persistedAt ?? entry.createdAt,
@@ -1,4 +1,4 @@
1
- import { s as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-BhLtja0F.js";
1
+ import { s as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Z9SuGiD_.js";
2
2
  import crypto from "node:crypto";
3
3
  //#region extensions/voice-call/src/providers/telnyx.ts
4
4
  function normalizeTelnyxDirection(direction) {
@@ -1,8 +1,8 @@
1
1
  import { fetchWithSsrFGuard } from "./runtime-api.js";
2
2
  import "./api.js";
3
3
  import { n as requireSupportedTwilioApiHostname, r as resolveTwilioApiBaseUrl } from "./twilio-region-4fkgz3UG.js";
4
- import { a as normalizeProviderStatus, i as mapProviderStatusToEndReason, p as chunkAudio, r as isProviderStatusTerminal, s as getHeader, v as escapeXml, y as mapVoiceToPolly } from "./runtime-entry-DNmi-vZR.js";
5
- import { c as verifyTwilioWebhook, i as readVoiceCallProviderJsonResponse, n as cancelProviderResponseBody, r as readProviderErrorResponseSnippet, t as guardedJsonApiRequest } from "./guarded-json-api-BhLtja0F.js";
4
+ import { a as normalizeProviderStatus, b as escapeXml, h as chunkAudio, i as mapProviderStatusToEndReason, l as getHeader, r as isProviderStatusTerminal, x as mapVoiceToPolly } from "./runtime-entry-B8SNb2qD.js";
5
+ import { c as verifyTwilioWebhook, i as readVoiceCallProviderJsonResponse, n as cancelProviderResponseBody, r as readProviderErrorResponseSnippet, t as guardedJsonApiRequest } from "./guarded-json-api-Z9SuGiD_.js";
6
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
8
8
  import crypto from "node:crypto";
@@ -2,7 +2,7 @@
2
2
  "id": "voice-call",
3
3
  "doctorContract": {
4
4
  "resolveSessionStoreAgentIds": true,
5
- "stateMigrations": true
5
+ "stateMigrations": [{ "id": "voice-call-calls-jsonl-to-plugin-state" }]
6
6
  },
7
7
  "name": "Voice Call",
8
8
  "description": "OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/voice-call",
3
- "version": "2026.9.2",
3
+ "version": "2026.9.3",
4
4
  "description": "OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,7 +13,7 @@
13
13
  "zod": "4.4.3"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.9.2"
16
+ "openclaw": ">=2026.9.3"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
@@ -31,10 +31,10 @@
31
31
  "minHostVersion": ">=2026.4.10"
32
32
  },
33
33
  "compat": {
34
- "pluginApi": ">=2026.9.2"
34
+ "pluginApi": ">=2026.9.3"
35
35
  },
36
36
  "build": {
37
- "openclawVersion": "2026.9.2"
37
+ "openclawVersion": "2026.9.3"
38
38
  },
39
39
  "release": {
40
40
  "publishToClawHub": true,