@openclaw/voice-call 2026.6.8 → 2026.6.9
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.
- package/dist/{guarded-json-api-tNxwxQt0.js → guarded-json-api-DHj6sSuY.js} +63 -5
- package/dist/index.js +1 -1
- package/dist/{plivo-K3Nv0D8o.js → plivo-14MWaE98.js} +2 -2
- package/dist/{response-generator-39zOYri_.js → response-generator-D5yL0gt3.js} +1 -1
- package/dist/{runtime-entry-DeDXZz2k.js → runtime-entry-B8fUMehO.js} +76 -40
- package/dist/runtime-entry.js +1 -1
- package/dist/{telnyx-YbJp3QiY.js → telnyx-COPVE0cj.js} +1 -1
- package/dist/{twilio-DBcVB36L.js → twilio-BD7lW2wp.js} +8 -8
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fetchWithSsrFGuard } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
|
-
import { a as getHeader } from "./runtime-entry-
|
|
3
|
+
import { a as getHeader } from "./runtime-entry-B8fUMehO.js";
|
|
4
4
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
5
5
|
import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
|
|
6
6
|
import { isFutureDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
@@ -560,6 +560,61 @@ function verifyPlivoWebhook(ctx, authToken, options) {
|
|
|
560
560
|
};
|
|
561
561
|
}
|
|
562
562
|
//#endregion
|
|
563
|
+
//#region extensions/voice-call/src/providers/shared/response-body.ts
|
|
564
|
+
const PROVIDER_JSON_RESPONSE_MAX_BYTES = 1 * 1024 * 1024;
|
|
565
|
+
const PROVIDER_ERROR_RESPONSE_MAX_BYTES = 8 * 1024;
|
|
566
|
+
const TRUNCATED_SUFFIX = "... [truncated]";
|
|
567
|
+
async function cancelProviderResponseBody(response) {
|
|
568
|
+
await response.body?.cancel().catch(() => void 0);
|
|
569
|
+
}
|
|
570
|
+
function appendTruncatedSuffix(text) {
|
|
571
|
+
return `${text.trimEnd()}${TRUNCATED_SUFFIX}`;
|
|
572
|
+
}
|
|
573
|
+
async function readProviderResponseTextWithLimit(params) {
|
|
574
|
+
if (!params.response.body) return "";
|
|
575
|
+
const reader = params.response.body.getReader();
|
|
576
|
+
const decoder = new TextDecoder();
|
|
577
|
+
let totalBytes = 0;
|
|
578
|
+
let text = "";
|
|
579
|
+
try {
|
|
580
|
+
while (true) {
|
|
581
|
+
const { done, value } = await reader.read();
|
|
582
|
+
if (done) return text + decoder.decode();
|
|
583
|
+
if (!value?.byteLength) continue;
|
|
584
|
+
const remainingBytes = params.maxBytes - totalBytes;
|
|
585
|
+
if (value.byteLength > remainingBytes) {
|
|
586
|
+
if (params.truncateOnLimit) {
|
|
587
|
+
const clipped = remainingBytes > 0 ? value.slice(0, remainingBytes) : void 0;
|
|
588
|
+
if (clipped) text += decoder.decode(clipped, { stream: true });
|
|
589
|
+
await reader.cancel().catch(() => void 0);
|
|
590
|
+
return appendTruncatedSuffix(text + decoder.decode());
|
|
591
|
+
}
|
|
592
|
+
await reader.cancel().catch(() => void 0);
|
|
593
|
+
throw new Error(`provider response body too large: ${totalBytes + value.byteLength} bytes (limit: ${params.maxBytes} bytes)`);
|
|
594
|
+
}
|
|
595
|
+
text += decoder.decode(value, { stream: true });
|
|
596
|
+
totalBytes += value.byteLength;
|
|
597
|
+
}
|
|
598
|
+
} finally {
|
|
599
|
+
try {
|
|
600
|
+
reader.releaseLock();
|
|
601
|
+
} catch {}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
async function readProviderJsonResponseText(response) {
|
|
605
|
+
return await readProviderResponseTextWithLimit({
|
|
606
|
+
response,
|
|
607
|
+
maxBytes: PROVIDER_JSON_RESPONSE_MAX_BYTES
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
async function readProviderErrorResponseSnippet(response) {
|
|
611
|
+
return await readProviderResponseTextWithLimit({
|
|
612
|
+
response,
|
|
613
|
+
maxBytes: PROVIDER_ERROR_RESPONSE_MAX_BYTES,
|
|
614
|
+
truncateOnLimit: true
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
//#endregion
|
|
563
618
|
//#region extensions/voice-call/src/providers/shared/guarded-json-api.ts
|
|
564
619
|
/** Send a provider JSON request through the SSRF guard and parse bounded JSON responses. */
|
|
565
620
|
async function guardedJsonApiRequest(params) {
|
|
@@ -575,11 +630,14 @@ async function guardedJsonApiRequest(params) {
|
|
|
575
630
|
});
|
|
576
631
|
try {
|
|
577
632
|
if (!response.ok) {
|
|
578
|
-
if (params.allowNotFound && response.status === 404)
|
|
579
|
-
|
|
633
|
+
if (params.allowNotFound && response.status === 404) {
|
|
634
|
+
await cancelProviderResponseBody(response);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const errorText = await readProviderErrorResponseSnippet(response);
|
|
580
638
|
throw new Error(`${params.errorPrefix}: ${response.status} ${errorText}`);
|
|
581
639
|
}
|
|
582
|
-
const text = await response
|
|
640
|
+
const text = await readProviderJsonResponseText(response);
|
|
583
641
|
if (!text) return;
|
|
584
642
|
try {
|
|
585
643
|
return JSON.parse(text);
|
|
@@ -591,4 +649,4 @@ async function guardedJsonApiRequest(params) {
|
|
|
591
649
|
}
|
|
592
650
|
}
|
|
593
651
|
//#endregion
|
|
594
|
-
export {
|
|
652
|
+
export { reconstructWebhookUrl as a, verifyTwilioWebhook as c, readProviderJsonResponseText as i, cancelProviderResponseBody as n, verifyPlivoWebhook as o, readProviderErrorResponseSnippet as r, verifyTelnyxWebhook as s, guardedJsonApiRequest as t };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { definePluginEntry, sleep } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
3
|
import { i as resolveVoiceCallConfig, s as validateProviderConfig } from "./config-jaA6vOZ2.js";
|
|
4
|
-
import { c as getTailscaleSelfInfo, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-
|
|
4
|
+
import { c as getTailscaleSelfInfo, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-B8fUMehO.js";
|
|
5
5
|
import { c as getCallHistoryFromStore, m as setVoiceCallStateRuntime } from "./store-8M2m4Isq.js";
|
|
6
6
|
import { i as parseVoiceCallPluginConfig, r as normalizeVoiceCallLegacyConfigInput, t as formatVoiceCallLegacyConfigWarnings } from "./config-compat-BPPFhsJ7.js";
|
|
7
7
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as getHeader, m as escapeXml } from "./runtime-entry-
|
|
2
|
-
import {
|
|
1
|
+
import { a as getHeader, m as escapeXml } from "./runtime-entry-B8fUMehO.js";
|
|
2
|
+
import { a as reconstructWebhookUrl, o as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-DHj6sSuY.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 { o as resolveVoiceCallSessionKey } from "./config-jaA6vOZ2.js";
|
|
2
|
-
import { f as resolveVoiceResponseModel } from "./runtime-entry-
|
|
2
|
+
import { f as resolveVoiceResponseModel } from "./runtime-entry-B8fUMehO.js";
|
|
3
3
|
import { isRecord, normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import crypto from "node:crypto";
|
|
5
5
|
import { applyModelOverrideToSessionEntry } from "openclaw/plugin-sdk/model-session-runtime";
|
|
@@ -107,6 +107,16 @@ function startMaxDurationTimer(params) {
|
|
|
107
107
|
}, maxDurationMs);
|
|
108
108
|
params.ctx.maxDurationTimers.set(params.callId, timer);
|
|
109
109
|
}
|
|
110
|
+
/** Backfill max-duration enforcement from the first live conversation signal. */
|
|
111
|
+
function ensureMaxDurationTimerForLiveCall(params) {
|
|
112
|
+
if (params.call.answeredAt) return;
|
|
113
|
+
params.call.answeredAt = params.liveAt;
|
|
114
|
+
startMaxDurationTimer({
|
|
115
|
+
ctx: params.ctx,
|
|
116
|
+
callId: params.call.callId,
|
|
117
|
+
onTimeout: params.onTimeout
|
|
118
|
+
});
|
|
119
|
+
}
|
|
110
120
|
/** Clear and forget a pending final-transcript waiter. */
|
|
111
121
|
function clearTranscriptWaiter(ctx, callId) {
|
|
112
122
|
const waiter = ctx.transcriptWaiters.get(callId);
|
|
@@ -418,6 +428,14 @@ async function speak(ctx, callId, text) {
|
|
|
418
428
|
};
|
|
419
429
|
const { call, providerCallId, provider } = connected;
|
|
420
430
|
try {
|
|
431
|
+
ensureMaxDurationTimerForLiveCall({
|
|
432
|
+
ctx,
|
|
433
|
+
call,
|
|
434
|
+
liveAt: Date.now(),
|
|
435
|
+
onTimeout: async (id) => {
|
|
436
|
+
await endCall(ctx, id, { reason: "timeout" });
|
|
437
|
+
}
|
|
438
|
+
});
|
|
421
439
|
transitionState(call, "speaking");
|
|
422
440
|
persistCallRecord(ctx.storePath, call);
|
|
423
441
|
const numberRouteKey = typeof call.metadata?.numberRouteKey === "string" ? call.metadata.numberRouteKey : call.to;
|
|
@@ -795,6 +813,14 @@ function processEvent(ctx, event) {
|
|
|
795
813
|
transitionState(call, "active");
|
|
796
814
|
break;
|
|
797
815
|
case "call.speaking":
|
|
816
|
+
ensureMaxDurationTimerForLiveCall({
|
|
817
|
+
ctx,
|
|
818
|
+
call,
|
|
819
|
+
liveAt: event.timestamp,
|
|
820
|
+
onTimeout: async (callId) => {
|
|
821
|
+
await endCall(ctx, callId, { reason: "timeout" });
|
|
822
|
+
}
|
|
823
|
+
});
|
|
798
824
|
transitionState(call, "speaking");
|
|
799
825
|
break;
|
|
800
826
|
case "call.speech":
|
|
@@ -807,6 +833,14 @@ function processEvent(ctx, event) {
|
|
|
807
833
|
}
|
|
808
834
|
addTranscriptEntry(call, "user", event.transcript);
|
|
809
835
|
}
|
|
836
|
+
ensureMaxDurationTimerForLiveCall({
|
|
837
|
+
ctx,
|
|
838
|
+
call,
|
|
839
|
+
liveAt: event.timestamp,
|
|
840
|
+
onTimeout: async (callId) => {
|
|
841
|
+
await endCall(ctx, callId, { reason: "timeout" });
|
|
842
|
+
}
|
|
843
|
+
});
|
|
810
844
|
transitionState(call, "listening");
|
|
811
845
|
break;
|
|
812
846
|
case "call.silence":
|
|
@@ -857,6 +891,9 @@ function incrementRestoreStatusCount(counts, status) {
|
|
|
857
891
|
const key = normalizeOptionalString(status) ?? "terminal";
|
|
858
892
|
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
859
893
|
}
|
|
894
|
+
function resolveRestoredMaxDurationAnchor(call) {
|
|
895
|
+
return call.answeredAt ?? (call.state === "speaking" || call.state === "listening" ? call.startedAt : void 0);
|
|
896
|
+
}
|
|
860
897
|
function resolveDefaultStoreBase(config, storePath) {
|
|
861
898
|
const rawOverride = storePath?.trim() || config.store?.trim();
|
|
862
899
|
if (rawOverride) return resolveUserPath(rawOverride);
|
|
@@ -903,24 +940,31 @@ var CallManager = class {
|
|
|
903
940
|
this.providerCallIdMap = /* @__PURE__ */ new Map();
|
|
904
941
|
for (const [callId, call] of verified) if (call.providerCallId) this.providerCallIdMap.set(call.providerCallId, callId);
|
|
905
942
|
let skippedAlreadyElapsedTimers = 0;
|
|
906
|
-
for (const [callId, call] of verified)
|
|
907
|
-
const
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
if (
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
ctx: this.getContext(),
|
|
917
|
-
callId,
|
|
918
|
-
timeoutMs: maxDurationMs - elapsed,
|
|
919
|
-
onTimeout: async (id) => {
|
|
920
|
-
await endCall(this.getContext(), id, { reason: "timeout" });
|
|
943
|
+
for (const [callId, call] of verified) {
|
|
944
|
+
const maxDurationAnchor = resolveRestoredMaxDurationAnchor(call);
|
|
945
|
+
if (maxDurationAnchor !== void 0 && !TerminalStates.has(call.state)) {
|
|
946
|
+
const elapsed = Date.now() - maxDurationAnchor;
|
|
947
|
+
const maxDurationMs = resolveVoiceCallSecondsTimerDelayMs(this.config.maxDurationSeconds);
|
|
948
|
+
if (elapsed >= maxDurationMs) {
|
|
949
|
+
verified.delete(callId);
|
|
950
|
+
if (call.providerCallId) this.providerCallIdMap.delete(call.providerCallId);
|
|
951
|
+
skippedAlreadyElapsedTimers += 1;
|
|
952
|
+
continue;
|
|
921
953
|
}
|
|
922
|
-
|
|
923
|
-
|
|
954
|
+
if (call.answeredAt === void 0) {
|
|
955
|
+
call.answeredAt = maxDurationAnchor;
|
|
956
|
+
persistCallRecord(this.storePath, call);
|
|
957
|
+
}
|
|
958
|
+
startMaxDurationTimer({
|
|
959
|
+
ctx: this.getContext(),
|
|
960
|
+
callId,
|
|
961
|
+
timeoutMs: maxDurationMs - elapsed,
|
|
962
|
+
onTimeout: async (id) => {
|
|
963
|
+
await endCall(this.getContext(), id, { reason: "timeout" });
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
console.log(`[voice-call] Restarted max-duration timer for restored call ${callId}`);
|
|
967
|
+
}
|
|
924
968
|
}
|
|
925
969
|
if (skippedAlreadyElapsedTimers > 0) console.log(`[voice-call] Skipped ${skippedAlreadyElapsedTimers} restored call(s) whose max-duration timer already elapsed`);
|
|
926
970
|
if (verified.size > 0) console.log(`[voice-call] Restored ${verified.size} active call(s) from store`);
|
|
@@ -2290,23 +2334,6 @@ Content-Length: ${Buffer.byteLength(body)}\r\n\r
|
|
|
2290
2334
|
}
|
|
2291
2335
|
this.clearAudio(streamSid);
|
|
2292
2336
|
}
|
|
2293
|
-
/**
|
|
2294
|
-
* Get active session by call ID.
|
|
2295
|
-
*/
|
|
2296
|
-
getSessionByCallId(callId) {
|
|
2297
|
-
return [...this.sessions.values()].find((session) => session.callId === callId);
|
|
2298
|
-
}
|
|
2299
|
-
/**
|
|
2300
|
-
* Close all sessions.
|
|
2301
|
-
*/
|
|
2302
|
-
closeAll() {
|
|
2303
|
-
for (const session of this.sessions.values()) {
|
|
2304
|
-
this.clearTtsState(session.streamSid);
|
|
2305
|
-
session.sttSession.close();
|
|
2306
|
-
session.ws.close();
|
|
2307
|
-
}
|
|
2308
|
-
this.sessions.clear();
|
|
2309
|
-
}
|
|
2310
2337
|
getTtsQueue(streamSid) {
|
|
2311
2338
|
const existing = this.ttsQueues.get(streamSid);
|
|
2312
2339
|
if (existing) return existing;
|
|
@@ -2442,6 +2469,11 @@ function isProviderStatusTerminal(status) {
|
|
|
2442
2469
|
//#endregion
|
|
2443
2470
|
//#region extensions/voice-call/src/webhook/stale-call-reaper.ts
|
|
2444
2471
|
const CHECK_INTERVAL_MS = 3e4;
|
|
2472
|
+
/** States that indicate a live conversation with speech/transcription.
|
|
2473
|
+
* Inbound Twilio calls may never fire a call.answered event, so answeredAt
|
|
2474
|
+
* can be absent even while the call is actively transcribing. These states
|
|
2475
|
+
* prove the call is live and should not be reaped. */
|
|
2476
|
+
const LiveConversationStates = new Set(["speaking", "listening"]);
|
|
2445
2477
|
/** Start a stale-call reaper and return its cleanup callback. */
|
|
2446
2478
|
function startStaleCallReaper(params) {
|
|
2447
2479
|
const maxAgeSeconds = params.staleCallReaperSeconds;
|
|
@@ -2450,7 +2482,7 @@ function startStaleCallReaper(params) {
|
|
|
2450
2482
|
const interval = setInterval(() => {
|
|
2451
2483
|
const now = Date.now();
|
|
2452
2484
|
for (const call of params.manager.getActiveCalls()) {
|
|
2453
|
-
if (call.answeredAt || TerminalStates.has(call.state)) continue;
|
|
2485
|
+
if (call.answeredAt || TerminalStates.has(call.state) || LiveConversationStates.has(call.state)) continue;
|
|
2454
2486
|
const age = now - call.startedAt;
|
|
2455
2487
|
if (age > maxAgeMs) {
|
|
2456
2488
|
console.log(`[voice-call] Reaping stale call ${call.callId} (age: ${Math.round(age / 1e3)}s, state: ${call.state})`);
|
|
@@ -2478,7 +2510,7 @@ function loadRealtimeTranscriptionRuntime() {
|
|
|
2478
2510
|
return realtimeTranscriptionRuntimePromise;
|
|
2479
2511
|
}
|
|
2480
2512
|
function loadResponseGeneratorModule() {
|
|
2481
|
-
responseGeneratorModulePromise ??= import("./response-generator-
|
|
2513
|
+
responseGeneratorModulePromise ??= import("./response-generator-D5yL0gt3.js");
|
|
2482
2514
|
return responseGeneratorModulePromise;
|
|
2483
2515
|
}
|
|
2484
2516
|
function sanitizeTranscriptForLog(value) {
|
|
@@ -3055,7 +3087,11 @@ var VoiceCallWebhookServer = class {
|
|
|
3055
3087
|
try {
|
|
3056
3088
|
const pathname = buildRequestUrl(req.url).pathname;
|
|
3057
3089
|
const pattern = this.realtimeHandler?.getStreamPathPattern();
|
|
3058
|
-
|
|
3090
|
+
if (!pattern) return false;
|
|
3091
|
+
const normalizedPattern = this.normalizeWebhookPathForMatch(pattern);
|
|
3092
|
+
const normalizedPathname = this.normalizeWebhookPathForMatch(pathname);
|
|
3093
|
+
if (normalizedPattern === "/") return true;
|
|
3094
|
+
return normalizedPathname === normalizedPattern || normalizedPathname.startsWith(`${normalizedPattern}/`);
|
|
3059
3095
|
} catch {
|
|
3060
3096
|
return false;
|
|
3061
3097
|
}
|
|
@@ -3162,15 +3198,15 @@ let mockProviderPromise;
|
|
|
3162
3198
|
let realtimeVoiceRuntimePromise;
|
|
3163
3199
|
let realtimeHandlerPromise;
|
|
3164
3200
|
function loadTelnyxProvider() {
|
|
3165
|
-
telnyxProviderPromise ??= import("./telnyx-
|
|
3201
|
+
telnyxProviderPromise ??= import("./telnyx-COPVE0cj.js");
|
|
3166
3202
|
return telnyxProviderPromise;
|
|
3167
3203
|
}
|
|
3168
3204
|
function loadTwilioProvider() {
|
|
3169
|
-
twilioProviderPromise ??= import("./twilio-
|
|
3205
|
+
twilioProviderPromise ??= import("./twilio-BD7lW2wp.js");
|
|
3170
3206
|
return twilioProviderPromise;
|
|
3171
3207
|
}
|
|
3172
3208
|
function loadPlivoProvider() {
|
|
3173
|
-
plivoProviderPromise ??= import("./plivo-
|
|
3209
|
+
plivoProviderPromise ??= import("./plivo-14MWaE98.js");
|
|
3174
3210
|
return plivoProviderPromise;
|
|
3175
3211
|
}
|
|
3176
3212
|
function loadMockProvider() {
|
package/dist/runtime-entry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createVoiceCallRuntime } from "./runtime-entry-
|
|
1
|
+
import { t as createVoiceCallRuntime } from "./runtime-entry-B8fUMehO.js";
|
|
2
2
|
export { createVoiceCallRuntime };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-DHj6sSuY.js";
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
//#region extensions/voice-call/src/providers/telnyx.ts
|
|
4
4
|
function normalizeTelnyxDirection(direction) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fetchWithSsrFGuard } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
|
-
import { a as getHeader, d as chunkAudio, h as mapVoiceToPolly, i as normalizeProviderStatus, m as escapeXml, n as isProviderStatusTerminal, r as mapProviderStatusToEndReason } from "./runtime-entry-
|
|
4
|
-
import {
|
|
3
|
+
import { a as getHeader, d as chunkAudio, h as mapVoiceToPolly, i as normalizeProviderStatus, m as escapeXml, n as isProviderStatusTerminal, r as mapProviderStatusToEndReason } from "./runtime-entry-B8fUMehO.js";
|
|
4
|
+
import { c as verifyTwilioWebhook, i as readProviderJsonResponseText, n as cancelProviderResponseBody, r as readProviderErrorResponseSnippet, t as guardedJsonApiRequest } from "./guarded-json-api-DHj6sSuY.js";
|
|
5
5
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
6
|
import crypto from "node:crypto";
|
|
7
7
|
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
@@ -57,11 +57,14 @@ async function twilioApiRequest(params) {
|
|
|
57
57
|
});
|
|
58
58
|
try {
|
|
59
59
|
if (!response.ok) {
|
|
60
|
-
if (params.allowNotFound && response.status === 404)
|
|
61
|
-
|
|
60
|
+
if (params.allowNotFound && response.status === 404) {
|
|
61
|
+
await cancelProviderResponseBody(response);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const errorText = await readProviderErrorResponseSnippet(response);
|
|
62
65
|
throw new TwilioApiError(response.status, errorText);
|
|
63
66
|
}
|
|
64
|
-
const text = await response
|
|
67
|
+
const text = await readProviderJsonResponseText(response);
|
|
65
68
|
if (!text) return;
|
|
66
69
|
try {
|
|
67
70
|
return JSON.parse(text);
|
|
@@ -202,9 +205,6 @@ var TwilioProvider = class TwilioProvider {
|
|
|
202
205
|
setPublicUrl(url) {
|
|
203
206
|
this.currentPublicUrl = url;
|
|
204
207
|
}
|
|
205
|
-
getPublicUrl() {
|
|
206
|
-
return this.currentPublicUrl;
|
|
207
|
-
}
|
|
208
208
|
setTTSProvider(provider) {
|
|
209
209
|
this.ttsProvider = provider;
|
|
210
210
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/voice-call",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.9",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/voice-call",
|
|
9
|
-
"version": "2026.6.
|
|
9
|
+
"version": "2026.6.9",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"commander": "14.0.3",
|
|
12
12
|
"typebox": "1.1.39",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"zod": "4.4.3"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"openclaw": ">=2026.6.
|
|
17
|
+
"openclaw": ">=2026.6.9"
|
|
18
18
|
},
|
|
19
19
|
"peerDependenciesMeta": {
|
|
20
20
|
"openclaw": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/voice-call",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.9",
|
|
4
4
|
"description": "OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"zod": "4.4.3"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"openclaw": ">=2026.6.
|
|
17
|
+
"openclaw": ">=2026.6.9"
|
|
18
18
|
},
|
|
19
19
|
"peerDependenciesMeta": {
|
|
20
20
|
"openclaw": {
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"minHostVersion": ">=2026.4.10"
|
|
32
32
|
},
|
|
33
33
|
"compat": {
|
|
34
|
-
"pluginApi": ">=2026.6.
|
|
34
|
+
"pluginApi": ">=2026.6.9"
|
|
35
35
|
},
|
|
36
36
|
"build": {
|
|
37
|
-
"openclawVersion": "2026.6.
|
|
37
|
+
"openclawVersion": "2026.6.9"
|
|
38
38
|
},
|
|
39
39
|
"release": {
|
|
40
40
|
"publishToClawHub": true,
|