@openclaw/voice-call 2026.5.24-beta.1 → 2026.5.25-beta.1
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/{config-CmO0pHE1.js → config-cNGVtrwa.js} +2 -4
- package/dist/{config-compat-HORl1Cdw.js → config-compat-4gaIelu_.js} +1 -1
- package/dist/{guarded-json-api-BveGhYhl.js → guarded-json-api-Dkeawg_W.js} +3 -3
- package/dist/index.js +12 -15
- package/dist/{plivo-cga35v6d.js → plivo-CNtzf7Do.js} +2 -2
- package/dist/{realtime-handler-GzCyjKXl.js → realtime-handler-NP8w71q9.js} +46 -44
- package/dist/{response-generator-CzGdOMuc.js → response-generator-D7HL2sFM.js} +9 -12
- package/dist/{runtime-entry-Ckt5k9pK.js → runtime-entry-CxeSe0VA.js} +14 -17
- package/dist/runtime-entry.js +1 -1
- package/dist/setup-api.js +1 -1
- package/dist/{telnyx-7YcRSSf6.js → telnyx-CJAhbDYn.js} +1 -1
- package/dist/{twilio-BAcJzoFs.js → twilio-Dn84Eomh.js} +2 -2
- package/node_modules/ws/lib/receiver.js +54 -0
- package/node_modules/ws/lib/websocket-server.js +8 -0
- package/node_modules/ws/lib/websocket.js +14 -0
- package/node_modules/ws/package.json +1 -1
- package/npm-shrinkwrap.json +7 -7
- package/package.json +5 -5
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TtsConfigSchema } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
4
|
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, REALTIME_VOICE_AGENT_CONSULT_TOOL_POLICIES } from "openclaw/plugin-sdk/realtime-voice";
|
|
4
5
|
import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
5
6
|
import { z } from "zod";
|
|
@@ -10,7 +11,7 @@ const BLOCKED_MERGE_KEYS = new Set([
|
|
|
10
11
|
"constructor"
|
|
11
12
|
]);
|
|
12
13
|
function deepMergeDefined(base, override) {
|
|
13
|
-
if (!
|
|
14
|
+
if (!isRecord(base) || !isRecord(override)) return override === void 0 ? base : override;
|
|
14
15
|
const result = { ...base };
|
|
15
16
|
for (const [key, value] of Object.entries(override)) {
|
|
16
17
|
if (BLOCKED_MERGE_KEYS.has(key) || value === void 0) continue;
|
|
@@ -19,9 +20,6 @@ function deepMergeDefined(base, override) {
|
|
|
19
20
|
}
|
|
20
21
|
return result;
|
|
21
22
|
}
|
|
22
|
-
function isPlainObject(value) {
|
|
23
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
24
|
-
}
|
|
25
23
|
//#endregion
|
|
26
24
|
//#region extensions/voice-call/src/realtime-defaults.ts
|
|
27
25
|
const DEFAULT_VOICE_CALL_REALTIME_INSTRUCTIONS = `You are OpenClaw's phone-call realtime voice interface. Keep spoken replies brief and natural. When a question needs deeper reasoning, current information, or tools, call ${REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME} before answering.`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as VoiceCallConfigSchema } from "./config-
|
|
1
|
+
import { t as VoiceCallConfigSchema } from "./config-cNGVtrwa.js";
|
|
2
2
|
import { asOptionalRecord, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
//#region extensions/voice-call/src/config-compat.ts
|
|
4
4
|
const VOICE_CALL_LEGACY_CONFIG_REMOVAL_VERSION = "2026.6.0";
|
|
@@ -1,9 +1,9 @@
|
|
|
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-CxeSe0VA.js";
|
|
4
4
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
5
5
|
import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
|
|
6
|
-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
|
+
import { normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
7
|
import crypto from "node:crypto";
|
|
8
8
|
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
9
9
|
//#region extensions/voice-call/src/webhook-security.ts
|
|
@@ -451,7 +451,7 @@ function validatePlivoV3Signature(params) {
|
|
|
451
451
|
postParams: params.postParams
|
|
452
452
|
})}.${params.nonce}`;
|
|
453
453
|
const expected = normalizeSignatureBase64(crypto.createHmac("sha256", params.authToken).update(hmacBase).digest("base64"));
|
|
454
|
-
const provided = params.signatureHeader.split(",")
|
|
454
|
+
const provided = normalizeStringEntries(params.signatureHeader.split(",")).map((s) => normalizeSignatureBase64(s));
|
|
455
455
|
for (const sig of provided) if (timingSafeEqualString(expected, sig)) return true;
|
|
456
456
|
return false;
|
|
457
457
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { definePluginEntry, sleep } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
|
-
import { i as resolveVoiceCallConfig, s as validateProviderConfig } from "./config-
|
|
4
|
-
import { c as getTailscaleSelfInfo, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-
|
|
5
|
-
import { i as parseVoiceCallPluginConfig, r as normalizeVoiceCallLegacyConfigInput, t as formatVoiceCallLegacyConfigWarnings } from "./config-compat-
|
|
3
|
+
import { i as resolveVoiceCallConfig, s as validateProviderConfig } from "./config-cNGVtrwa.js";
|
|
4
|
+
import { c as getTailscaleSelfInfo, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-CxeSe0VA.js";
|
|
5
|
+
import { i as parseVoiceCallPluginConfig, r as normalizeVoiceCallLegacyConfigInput, t as formatVoiceCallLegacyConfigWarnings } from "./config-compat-4gaIelu_.js";
|
|
6
6
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
7
7
|
import { ErrorCodes, callGatewayFromCli, errorShape } from "openclaw/plugin-sdk/gateway-runtime";
|
|
8
|
-
import { normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
|
+
import { isRecord, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
9
|
import { Type } from "typebox";
|
|
10
10
|
import fs from "node:fs";
|
|
11
11
|
import os from "node:os";
|
|
@@ -30,9 +30,6 @@ function parseVoiceCallIntOption(raw, optionName, opts) {
|
|
|
30
30
|
if (!Number.isInteger(parsed) || parsed < min) throw new Error(`Invalid numeric value for ${optionName}: ${raw ?? ""}`);
|
|
31
31
|
return parsed;
|
|
32
32
|
}
|
|
33
|
-
function isRecord$1(value) {
|
|
34
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
35
|
-
}
|
|
36
33
|
function isGatewayUnavailableForLocalFallback(err) {
|
|
37
34
|
const message = formatErrorMessage(err);
|
|
38
35
|
return message.includes("ECONNREFUSED") || message.includes("ECONNRESET") || message.includes("EHOSTUNREACH") || message.includes("ENOTFOUND") || message.includes("gateway closed (1006") || message.includes("gateway not connected");
|
|
@@ -65,15 +62,15 @@ function isUnknownGatewayMethod(err, method) {
|
|
|
65
62
|
return formatErrorMessage(err).includes(`unknown method: ${method}`);
|
|
66
63
|
}
|
|
67
64
|
function readGatewayOperationId(payload) {
|
|
68
|
-
if (isRecord
|
|
65
|
+
if (isRecord(payload) && typeof payload.operationId === "string" && payload.operationId) return payload.operationId;
|
|
69
66
|
throw new Error("voicecall gateway response missing operationId");
|
|
70
67
|
}
|
|
71
68
|
function readGatewayPollTimeoutMs(payload, fallbackTimeoutMs) {
|
|
72
|
-
if (isRecord
|
|
69
|
+
if (isRecord(payload) && typeof payload.pollTimeoutMs === "number") return Math.max(1, Math.ceil(payload.pollTimeoutMs));
|
|
73
70
|
return fallbackTimeoutMs;
|
|
74
71
|
}
|
|
75
72
|
function readCompletedContinueResult(payload) {
|
|
76
|
-
if (!isRecord
|
|
73
|
+
if (!isRecord(payload)) throw new Error("voicecall gateway response missing operation status");
|
|
77
74
|
if (payload.status === "pending") return { status: "pending" };
|
|
78
75
|
if (payload.status === "failed") return {
|
|
79
76
|
status: "failed",
|
|
@@ -191,11 +188,11 @@ async function initiateCallAndPrintId(params) {
|
|
|
191
188
|
writeStdoutJson({ callId: result.callId });
|
|
192
189
|
}
|
|
193
190
|
function writeGatewayCallId(payload) {
|
|
194
|
-
if (isRecord
|
|
191
|
+
if (isRecord(payload) && typeof payload.callId === "string") {
|
|
195
192
|
writeStdoutJson({ callId: payload.callId });
|
|
196
193
|
return;
|
|
197
194
|
}
|
|
198
|
-
if (isRecord
|
|
195
|
+
if (isRecord(payload) && typeof payload.error === "string") throw new Error(payload.error);
|
|
199
196
|
throw new Error("voicecall gateway response missing callId");
|
|
200
197
|
}
|
|
201
198
|
async function initiateCallViaGatewayOrRuntime(params) {
|
|
@@ -273,7 +270,7 @@ function registerVoiceCallCli(params) {
|
|
|
273
270
|
mode
|
|
274
271
|
}, { timeoutMs: resolveGatewayOperationTimeoutMs(config) });
|
|
275
272
|
let callId;
|
|
276
|
-
if (gateway.ok) callId = isRecord
|
|
273
|
+
if (gateway.ok) callId = isRecord(gateway.payload) ? gateway.payload.callId : void 0;
|
|
277
274
|
else {
|
|
278
275
|
const result = await (await ensureRuntime()).manager.initiateCall(options.to, void 0, {
|
|
279
276
|
message: options.message,
|
|
@@ -330,7 +327,7 @@ function registerVoiceCallCli(params) {
|
|
|
330
327
|
}, { timeoutMs: resolveGatewayContinueTimeoutMs(config) });
|
|
331
328
|
}
|
|
332
329
|
if (gateway.ok) {
|
|
333
|
-
if (isRecord
|
|
330
|
+
if (isRecord(gateway.payload) && typeof gateway.payload.operationId === "string") {
|
|
334
331
|
writeStdoutJson(await pollVoiceCallContinueGateway({
|
|
335
332
|
operationId: readGatewayOperationId(gateway.payload),
|
|
336
333
|
timeoutMs: readGatewayPollTimeoutMs(gateway.payload, resolveGatewayContinueTimeoutMs(config))
|
|
@@ -383,7 +380,7 @@ function registerVoiceCallCli(params) {
|
|
|
383
380
|
root.command("status").description("Show call status").option("--call-id <id>", "Call ID").option("--json", "Print machine-readable JSON").action(async (options) => {
|
|
384
381
|
const gateway = await callVoiceCallGateway("voicecall.status", options.callId ? { callId: options.callId } : void 0);
|
|
385
382
|
if (gateway.ok) {
|
|
386
|
-
if (options.callId && isRecord
|
|
383
|
+
if (options.callId && isRecord(gateway.payload)) {
|
|
387
384
|
if (gateway.payload.found === true && "call" in gateway.payload) {
|
|
388
385
|
writeStdoutJson(gateway.payload.call);
|
|
389
386
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as getHeader, m as escapeXml } from "./runtime-entry-
|
|
2
|
-
import { n as reconstructWebhookUrl, r as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-
|
|
1
|
+
import { a as getHeader, m as escapeXml } from "./runtime-entry-CxeSe0VA.js";
|
|
2
|
+
import { n as reconstructWebhookUrl, r as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Dkeawg_W.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,7 +1,8 @@
|
|
|
1
1
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
2
2
|
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
3
|
-
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, buildRealtimeVoiceAgentConsultWorkingResponse, createRealtimeVoiceBridgeSession, createTalkSessionController, recordTalkObservabilityEvent } from "openclaw/plugin-sdk/realtime-voice";
|
|
3
|
+
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, buildRealtimeVoiceAgentConsultWorkingResponse, createRealtimeVoiceBridgeSession, createRealtimeVoiceForcedConsultCoordinator, createTalkSessionController, readRealtimeVoiceConsultQuestion, readSpeakableRealtimeVoiceToolResult, recordTalkObservabilityEvent } from "openclaw/plugin-sdk/realtime-voice";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
|
+
import "node:http";
|
|
5
6
|
import WebSocket, { WebSocketServer } from "ws";
|
|
6
7
|
//#region extensions/voice-call/src/webhook/realtime-audio-pacer.ts
|
|
7
8
|
const TELEPHONY_SAMPLE_RATE = 8e3;
|
|
@@ -316,21 +317,13 @@ function buildGreetingInstructions(baseInstructions, greeting) {
|
|
|
316
317
|
const intro = "Start the call by greeting the caller naturally. Include this greeting in your first spoken reply:";
|
|
317
318
|
return baseInstructions ? `${baseInstructions}\n\n${intro} "${trimmedGreeting}"` : `${intro} "${trimmedGreeting}"`;
|
|
318
319
|
}
|
|
319
|
-
function readSpeakableToolResultText(result) {
|
|
320
|
-
if (typeof result === "string") return result.trim() || void 0;
|
|
321
|
-
if (!result || typeof result !== "object" || Array.isArray(result)) return;
|
|
322
|
-
const text = result.text;
|
|
323
|
-
if (typeof text === "string" && text.trim()) return text.trim();
|
|
324
|
-
const output = result.output;
|
|
325
|
-
return typeof output === "string" && output.trim() ? output.trim() : void 0;
|
|
326
|
-
}
|
|
327
320
|
function readConsultArgText(args, key) {
|
|
328
321
|
if (!args || typeof args !== "object" || Array.isArray(args)) return;
|
|
329
322
|
const value = args[key];
|
|
330
323
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
331
324
|
}
|
|
332
325
|
function readConsultQuestionText(args) {
|
|
333
|
-
return
|
|
326
|
+
return readRealtimeVoiceConsultQuestion(args);
|
|
334
327
|
}
|
|
335
328
|
function normalizeTranscriptText(text) {
|
|
336
329
|
return text.replace(/\s+/g, " ").trim();
|
|
@@ -435,10 +428,8 @@ var RealtimeCallHandler = class {
|
|
|
435
428
|
this.partialUserTranscriptUpdatedAtByCallId = /* @__PURE__ */ new Map();
|
|
436
429
|
this.recentFinalUserTranscriptsByCallId = /* @__PURE__ */ new Map();
|
|
437
430
|
this.recentFinalUserTranscriptTimersByCallId = /* @__PURE__ */ new Map();
|
|
438
|
-
this.
|
|
439
|
-
this.forcedConsultInFlightByCallId = /* @__PURE__ */ new Set();
|
|
431
|
+
this.forcedConsultCoordinatorsByCallId = /* @__PURE__ */ new Map();
|
|
440
432
|
this.forcedConsultsByCallId = /* @__PURE__ */ new Map();
|
|
441
|
-
this.lastProviderConsultAtByCallId = /* @__PURE__ */ new Map();
|
|
442
433
|
this.nativeConsultsInFlightByCallId = /* @__PURE__ */ new Map();
|
|
443
434
|
this.publicOrigin = null;
|
|
444
435
|
this.publicPathPrefix = "";
|
|
@@ -1002,14 +993,16 @@ var RealtimeCallHandler = class {
|
|
|
1002
993
|
}
|
|
1003
994
|
}
|
|
1004
995
|
clearForcedConsultState(callId) {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
clearTimeout(timer);
|
|
1008
|
-
this.forcedConsultTimersByCallId.delete(callId);
|
|
1009
|
-
}
|
|
1010
|
-
this.forcedConsultInFlightByCallId.delete(callId);
|
|
996
|
+
this.forcedConsultCoordinatorsByCallId.get(callId)?.clear();
|
|
997
|
+
this.forcedConsultCoordinatorsByCallId.delete(callId);
|
|
1011
998
|
this.forcedConsultsByCallId.delete(callId);
|
|
1012
|
-
|
|
999
|
+
}
|
|
1000
|
+
forcedConsultCoordinator(callId) {
|
|
1001
|
+
const existing = this.forcedConsultCoordinatorsByCallId.get(callId);
|
|
1002
|
+
if (existing) return existing;
|
|
1003
|
+
const created = createRealtimeVoiceForcedConsultCoordinator();
|
|
1004
|
+
this.forcedConsultCoordinatorsByCallId.set(callId, created);
|
|
1005
|
+
return created;
|
|
1013
1006
|
}
|
|
1014
1007
|
closeTelephonyBridge(callIdOrSid, bridge, reason) {
|
|
1015
1008
|
const closer = this.activeTelephonyClosersByCallId.get(callIdOrSid);
|
|
@@ -1025,36 +1018,43 @@ var RealtimeCallHandler = class {
|
|
|
1025
1018
|
if (!question) return;
|
|
1026
1019
|
const handler = this.toolHandlers.get(REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME);
|
|
1027
1020
|
if (!handler) return;
|
|
1028
|
-
const
|
|
1029
|
-
if (
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1021
|
+
const existingForcedConsult = this.forcedConsultsByCallId.get(params.callId);
|
|
1022
|
+
if (existingForcedConsult && !existingForcedConsult.completedAt) return;
|
|
1023
|
+
const coordinator = this.forcedConsultCoordinator(params.callId);
|
|
1024
|
+
if (coordinator.hasRecentNativeConsult(question, { allowUnknownQuestion: true })) return;
|
|
1025
|
+
coordinator.clearPending();
|
|
1026
|
+
const pending = coordinator.prepare(question);
|
|
1027
|
+
if (!pending) return;
|
|
1028
|
+
coordinator.schedule(pending, FORCED_CONSULT_FALLBACK_DELAY_MS, (handle) => {
|
|
1029
|
+
const activeForcedConsult = this.forcedConsultsByCallId.get(params.callId);
|
|
1030
|
+
if (activeForcedConsult && !activeForcedConsult.completedAt) return;
|
|
1035
1031
|
this.runForcedAgentConsult({
|
|
1036
1032
|
...params,
|
|
1037
|
-
|
|
1033
|
+
handle,
|
|
1038
1034
|
handler
|
|
1039
1035
|
});
|
|
1040
|
-
}
|
|
1041
|
-
this.forcedConsultTimersByCallId.set(params.callId, timer);
|
|
1036
|
+
});
|
|
1042
1037
|
}
|
|
1043
1038
|
async runForcedAgentConsult(params) {
|
|
1044
|
-
this.
|
|
1039
|
+
const coordinator = this.forcedConsultCoordinator(params.callId);
|
|
1040
|
+
coordinator.markStarted(params.handle);
|
|
1045
1041
|
const startedAt = Date.now();
|
|
1046
|
-
logger.debug(`[voice-call] realtime forced agent consult reason=${FORCED_CONSULT_REASON} consultPolicy=always callId=${params.callId} providerCallId=${params.callSid} chars=${params.question.length}`);
|
|
1047
|
-
console.log(`[voice-call] realtime forced agent consult starting callId=${params.callId} providerCallId=${params.callSid} chars=${params.question.length}`);
|
|
1042
|
+
logger.debug(`[voice-call] realtime forced agent consult reason=${FORCED_CONSULT_REASON} consultPolicy=always callId=${params.callId} providerCallId=${params.callSid} chars=${params.handle.question.length}`);
|
|
1043
|
+
console.log(`[voice-call] realtime forced agent consult starting callId=${params.callId} providerCallId=${params.callSid} chars=${params.handle.question.length}`);
|
|
1048
1044
|
params.clearAudio();
|
|
1049
1045
|
const state = {
|
|
1050
1046
|
sendSpeechPrompt: true,
|
|
1051
|
-
promise: Promise.resolve().then(() => params.handler({ question: params.question }, params.callId, {}))
|
|
1047
|
+
promise: Promise.resolve().then(() => params.handler({ question: params.handle.question }, params.callId, {}))
|
|
1052
1048
|
};
|
|
1053
1049
|
this.forcedConsultsByCallId.set(params.callId, state);
|
|
1054
1050
|
try {
|
|
1055
1051
|
const result = await state.promise;
|
|
1056
1052
|
state.completedAt = Date.now();
|
|
1057
|
-
|
|
1053
|
+
coordinator.markDelivered(params.handle);
|
|
1054
|
+
const text = readSpeakableRealtimeVoiceToolResult(result, {
|
|
1055
|
+
keys: ["text", "output"],
|
|
1056
|
+
maxChars: FORCED_CONSULT_RESULT_MAX_CHARS
|
|
1057
|
+
});
|
|
1058
1058
|
if (!text) {
|
|
1059
1059
|
console.warn(`[voice-call] realtime forced agent consult returned no speakable text callId=${params.callId} providerCallId=${params.callSid}`);
|
|
1060
1060
|
return;
|
|
@@ -1064,13 +1064,15 @@ var RealtimeCallHandler = class {
|
|
|
1064
1064
|
params.session.sendUserMessage(buildForcedConsultSpeechPrompt(text));
|
|
1065
1065
|
}
|
|
1066
1066
|
console.log(`[voice-call] realtime forced agent consult completed callId=${params.callId} providerCallId=${params.callSid} elapsedMs=${Date.now() - startedAt}`);
|
|
1067
|
-
this.consumePartialUserTranscript(params.callId, params.question);
|
|
1067
|
+
this.consumePartialUserTranscript(params.callId, params.handle.question);
|
|
1068
1068
|
} catch (error) {
|
|
1069
1069
|
console.warn(`[voice-call] realtime forced agent consult failed callId=${params.callId} providerCallId=${params.callSid} error=${formatErrorMessage(error)}`);
|
|
1070
1070
|
} finally {
|
|
1071
|
-
this.forcedConsultInFlightByCallId.delete(params.callId);
|
|
1072
1071
|
setTimeout(() => {
|
|
1073
|
-
if (this.forcedConsultsByCallId.get(params.callId) === state)
|
|
1072
|
+
if (this.forcedConsultsByCallId.get(params.callId) === state) {
|
|
1073
|
+
this.forcedConsultsByCallId.delete(params.callId);
|
|
1074
|
+
coordinator.remove(params.handle);
|
|
1075
|
+
}
|
|
1074
1076
|
}, FORCED_CONSULT_NATIVE_DEDUPE_MS).unref?.();
|
|
1075
1077
|
}
|
|
1076
1078
|
}
|
|
@@ -1161,15 +1163,15 @@ var RealtimeCallHandler = class {
|
|
|
1161
1163
|
}
|
|
1162
1164
|
};
|
|
1163
1165
|
if (name === REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME) {
|
|
1164
|
-
this.
|
|
1165
|
-
const
|
|
1166
|
-
if (
|
|
1167
|
-
|
|
1168
|
-
|
|
1166
|
+
const coordinator = this.forcedConsultCoordinator(callId);
|
|
1167
|
+
const forcedMatch = coordinator.recordNativeConsult(args, bridgeCallId);
|
|
1168
|
+
if (forcedMatch.kind === "none") {
|
|
1169
|
+
const pending = coordinator.consumePending();
|
|
1170
|
+
if (pending) coordinator.remove(pending);
|
|
1169
1171
|
}
|
|
1170
1172
|
const forcedConsult = this.forcedConsultsByCallId.get(callId);
|
|
1171
1173
|
if (forcedConsult) {
|
|
1172
|
-
if (forcedConsult.completedAt) {
|
|
1174
|
+
if (forcedConsult.completedAt || forcedMatch.kind === "already_delivered") {
|
|
1173
1175
|
submitFinalToolResult({
|
|
1174
1176
|
status: "already_delivered",
|
|
1175
1177
|
message: "OpenClaw already delivered this consult result internally. Do not repeat it."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as resolveVoiceCallSessionKey } from "./config-
|
|
2
|
-
import { f as resolveVoiceResponseModel } from "./runtime-entry-
|
|
3
|
-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
1
|
+
import { o as resolveVoiceCallSessionKey } from "./config-cNGVtrwa.js";
|
|
2
|
+
import { f as resolveVoiceResponseModel } from "./runtime-entry-CxeSe0VA.js";
|
|
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";
|
|
6
6
|
//#region extensions/voice-call/src/response-generator.ts
|
|
@@ -8,20 +8,17 @@ import { applyModelOverrideToSessionEntry } from "openclaw/plugin-sdk/model-sess
|
|
|
8
8
|
* Voice call response generator - uses the embedded Pi agent for tool support.
|
|
9
9
|
* Routes voice responses through the same agent infrastructure as messaging.
|
|
10
10
|
*/
|
|
11
|
-
function isRecord$1(value) {
|
|
12
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
-
}
|
|
14
11
|
function readExplicitToolsAllow(value) {
|
|
15
|
-
if (!isRecord
|
|
12
|
+
if (!isRecord(value)) return;
|
|
16
13
|
const allow = value.allow;
|
|
17
14
|
if (!Array.isArray(allow)) return;
|
|
18
15
|
return allow.filter((entry) => typeof entry === "string");
|
|
19
16
|
}
|
|
20
17
|
function resolveVoiceAgentToolsAllow(config, agentId) {
|
|
21
|
-
const agents = isRecord
|
|
22
|
-
const agent = (Array.isArray(agents?.list) ? agents.list : []).find((entry) => isRecord
|
|
23
|
-
if (!isRecord
|
|
24
|
-
return readExplicitToolsAllow(isRecord
|
|
18
|
+
const agents = isRecord(config.agents) ? config.agents : void 0;
|
|
19
|
+
const agent = (Array.isArray(agents?.list) ? agents.list : []).find((entry) => isRecord(entry) && entry.id === agentId);
|
|
20
|
+
if (!isRecord(agent)) return;
|
|
21
|
+
return readExplicitToolsAllow(isRecord(agent.tools) ? agent.tools : void 0);
|
|
25
22
|
}
|
|
26
23
|
const VOICE_SPOKEN_OUTPUT_CONTRACT = [
|
|
27
24
|
"Output format requirements:",
|
|
@@ -69,7 +66,7 @@ function isLikelyMetaReasoningParagraph(paragraph) {
|
|
|
69
66
|
function sanitizePlainSpokenText(text) {
|
|
70
67
|
const withoutCodeFences = text.replace(/```[\s\S]*?```/g, " ").trim();
|
|
71
68
|
if (!withoutCodeFences) return null;
|
|
72
|
-
const paragraphs = withoutCodeFences.split(/\n\s*\n+/)
|
|
69
|
+
const paragraphs = normalizeStringEntries(withoutCodeFences.split(/\n\s*\n+/));
|
|
73
70
|
while (paragraphs.length > 1 && isLikelyMetaReasoningParagraph(paragraphs[0])) paragraphs.shift();
|
|
74
71
|
return normalizeSpokenText(paragraphs.join(" "));
|
|
75
72
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isBlockedHostnameOrIp, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
|
-
import { a as resolveVoiceCallEffectiveConfig, c as deepMergeDefined, i as resolveVoiceCallConfig, n as normalizeVoiceCallConfig, o as resolveVoiceCallSessionKey, r as resolveTwilioAuthToken, s as validateProviderConfig } from "./config-
|
|
3
|
+
import { a as resolveVoiceCallEffectiveConfig, c as deepMergeDefined, i as resolveVoiceCallConfig, n as normalizeVoiceCallConfig, o as resolveVoiceCallSessionKey, r as resolveTwilioAuthToken, s as validateProviderConfig } from "./config-cNGVtrwa.js";
|
|
4
4
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
5
5
|
import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
|
|
6
|
-
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
|
+
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
7
|
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, buildRealtimeVoiceAgentConsultPolicyInstructions, consultRealtimeVoiceAgent, convertPcmToMulaw8k, createTalkSessionController, recordTalkObservabilityEvent, resolveRealtimeVoiceAgentConsultTools, resolveRealtimeVoiceAgentConsultToolsAllow, resolveRealtimeVoiceFastContextConsult } from "openclaw/plugin-sdk/realtime-voice";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import fs from "node:fs";
|
|
@@ -1250,15 +1250,12 @@ var CallManager = class {
|
|
|
1250
1250
|
};
|
|
1251
1251
|
//#endregion
|
|
1252
1252
|
//#region extensions/voice-call/src/realtime-agent-context.ts
|
|
1253
|
-
function normalizeString(value) {
|
|
1254
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
1255
|
-
}
|
|
1256
1253
|
function readAgentEntries(cfg) {
|
|
1257
1254
|
const agents = cfg.agents;
|
|
1258
1255
|
return Array.isArray(agents?.list) ? agents.list.filter((entry) => Boolean(entry && typeof entry === "object")) : [];
|
|
1259
1256
|
}
|
|
1260
1257
|
function resolveAgentSystemPromptOverride(cfg, agentId) {
|
|
1261
|
-
return
|
|
1258
|
+
return normalizeOptionalString(readAgentEntries(cfg).find((candidate) => normalizeOptionalString(candidate.id) === agentId)?.systemPromptOverride) ?? normalizeOptionalString(cfg.agents?.defaults?.systemPromptOverride);
|
|
1262
1259
|
}
|
|
1263
1260
|
function limitText(text, maxChars) {
|
|
1264
1261
|
if (text.length <= maxChars) return text;
|
|
@@ -1296,11 +1293,11 @@ async function buildRealtimeVoiceInstructions(params) {
|
|
|
1296
1293
|
if (contextConfig.includeIdentity) {
|
|
1297
1294
|
const identity = params.agentRuntime.resolveAgentIdentity(params.coreConfig, agentId);
|
|
1298
1295
|
const identityLines = [
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1296
|
+
normalizeOptionalString(identity?.name) ? `- Name: ${normalizeOptionalString(identity?.name)}` : void 0,
|
|
1297
|
+
normalizeOptionalString(identity?.emoji) ? `- Emoji: ${normalizeOptionalString(identity?.emoji)}` : void 0,
|
|
1298
|
+
normalizeOptionalString(identity?.vibe) ? `- Vibe: ${normalizeOptionalString(identity?.vibe)}` : void 0,
|
|
1299
|
+
normalizeOptionalString(identity?.theme) ? `- Theme: ${normalizeOptionalString(identity?.theme)}` : void 0,
|
|
1300
|
+
normalizeOptionalString(identity?.creature) ? `- Creature/persona: ${normalizeOptionalString(identity?.creature)}` : void 0
|
|
1304
1301
|
].filter(Boolean);
|
|
1305
1302
|
if (identityLines.length > 0) capsule.push(`Configured identity:\n${identityLines.join("\n")}`);
|
|
1306
1303
|
}
|
|
@@ -2531,7 +2528,7 @@ function loadRealtimeTranscriptionRuntime() {
|
|
|
2531
2528
|
return realtimeTranscriptionRuntimePromise;
|
|
2532
2529
|
}
|
|
2533
2530
|
function loadResponseGeneratorModule() {
|
|
2534
|
-
responseGeneratorModulePromise ??= import("./response-generator-
|
|
2531
|
+
responseGeneratorModulePromise ??= import("./response-generator-D7HL2sFM.js");
|
|
2535
2532
|
return responseGeneratorModulePromise;
|
|
2536
2533
|
}
|
|
2537
2534
|
function sanitizeTranscriptForLog(value) {
|
|
@@ -2572,7 +2569,7 @@ function resolveForwardedClientIp(request, trustedProxyIPs) {
|
|
|
2572
2569
|
const normalizedTrustedProxyIps = new Set(trustedProxyIPs.map((ip) => normalizeProxyIp(ip)).filter((ip) => Boolean(ip)));
|
|
2573
2570
|
const forwardedFor = getHeader(request.headers, "x-forwarded-for");
|
|
2574
2571
|
if (forwardedFor) {
|
|
2575
|
-
const forwardedIps = forwardedFor.split(",")
|
|
2572
|
+
const forwardedIps = normalizeStringEntries(forwardedFor.split(","));
|
|
2576
2573
|
if (forwardedIps.length > 0) {
|
|
2577
2574
|
if (normalizedTrustedProxyIps.size === 0) return forwardedIps[0];
|
|
2578
2575
|
for (let index = forwardedIps.length - 1; index >= 0; index -= 1) {
|
|
@@ -3148,15 +3145,15 @@ let mockProviderPromise;
|
|
|
3148
3145
|
let realtimeVoiceRuntimePromise;
|
|
3149
3146
|
let realtimeHandlerPromise;
|
|
3150
3147
|
function loadTelnyxProvider() {
|
|
3151
|
-
telnyxProviderPromise ??= import("./telnyx-
|
|
3148
|
+
telnyxProviderPromise ??= import("./telnyx-CJAhbDYn.js");
|
|
3152
3149
|
return telnyxProviderPromise;
|
|
3153
3150
|
}
|
|
3154
3151
|
function loadTwilioProvider() {
|
|
3155
|
-
twilioProviderPromise ??= import("./twilio-
|
|
3152
|
+
twilioProviderPromise ??= import("./twilio-Dn84Eomh.js");
|
|
3156
3153
|
return twilioProviderPromise;
|
|
3157
3154
|
}
|
|
3158
3155
|
function loadPlivoProvider() {
|
|
3159
|
-
plivoProviderPromise ??= import("./plivo-
|
|
3156
|
+
plivoProviderPromise ??= import("./plivo-CNtzf7Do.js");
|
|
3160
3157
|
return plivoProviderPromise;
|
|
3161
3158
|
}
|
|
3162
3159
|
function loadMockProvider() {
|
|
@@ -3168,7 +3165,7 @@ function loadRealtimeVoiceRuntime() {
|
|
|
3168
3165
|
return realtimeVoiceRuntimePromise;
|
|
3169
3166
|
}
|
|
3170
3167
|
function loadRealtimeHandler() {
|
|
3171
|
-
realtimeHandlerPromise ??= import("./realtime-handler-
|
|
3168
|
+
realtimeHandlerPromise ??= import("./realtime-handler-NP8w71q9.js");
|
|
3172
3169
|
return realtimeHandlerPromise;
|
|
3173
3170
|
}
|
|
3174
3171
|
function resolveVoiceCallConsultSessionKey(call) {
|
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-CxeSe0VA.js";
|
|
2
2
|
export { createVoiceCallRuntime };
|
package/dist/setup-api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as migrateVoiceCallLegacyConfigInput } from "./config-compat-
|
|
1
|
+
import { n as migrateVoiceCallLegacyConfigInput } from "./config-compat-4gaIelu_.js";
|
|
2
2
|
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
4
4
|
//#region extensions/voice-call/setup-api.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-
|
|
1
|
+
import { i as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Dkeawg_W.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 { a as verifyTwilioWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-
|
|
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-CxeSe0VA.js";
|
|
4
|
+
import { a as verifyTwilioWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Dkeawg_W.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";
|
|
@@ -40,6 +40,10 @@ class Receiver extends Writable {
|
|
|
40
40
|
* extensions
|
|
41
41
|
* @param {Boolean} [options.isServer=false] Specifies whether to operate in
|
|
42
42
|
* client or server mode
|
|
43
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
44
|
+
* buffered data chunks
|
|
45
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
46
|
+
* fragments
|
|
43
47
|
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
44
48
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
45
49
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -54,6 +58,8 @@ class Receiver extends Writable {
|
|
|
54
58
|
this._binaryType = options.binaryType || BINARY_TYPES[0];
|
|
55
59
|
this._extensions = options.extensions || {};
|
|
56
60
|
this._isServer = !!options.isServer;
|
|
61
|
+
this._maxBufferedChunks = options.maxBufferedChunks | 0;
|
|
62
|
+
this._maxFragments = options.maxFragments | 0;
|
|
57
63
|
this._maxPayload = options.maxPayload | 0;
|
|
58
64
|
this._skipUTF8Validation = !!options.skipUTF8Validation;
|
|
59
65
|
this[kWebSocket] = undefined;
|
|
@@ -89,6 +95,22 @@ class Receiver extends Writable {
|
|
|
89
95
|
_write(chunk, encoding, cb) {
|
|
90
96
|
if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
|
|
91
97
|
|
|
98
|
+
if (
|
|
99
|
+
this._maxBufferedChunks > 0 &&
|
|
100
|
+
this._buffers.length >= this._maxBufferedChunks
|
|
101
|
+
) {
|
|
102
|
+
cb(
|
|
103
|
+
this.createError(
|
|
104
|
+
RangeError,
|
|
105
|
+
'Too many buffered chunks',
|
|
106
|
+
false,
|
|
107
|
+
1008,
|
|
108
|
+
'WS_ERR_TOO_MANY_BUFFERED_PARTS'
|
|
109
|
+
)
|
|
110
|
+
);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
92
114
|
this._bufferedBytes += chunk.length;
|
|
93
115
|
this._buffers.push(chunk);
|
|
94
116
|
this.startLoop(cb);
|
|
@@ -485,6 +507,22 @@ class Receiver extends Writable {
|
|
|
485
507
|
}
|
|
486
508
|
|
|
487
509
|
if (data.length) {
|
|
510
|
+
if (
|
|
511
|
+
this._maxFragments > 0 &&
|
|
512
|
+
this._fragments.length >= this._maxFragments
|
|
513
|
+
) {
|
|
514
|
+
const error = this.createError(
|
|
515
|
+
RangeError,
|
|
516
|
+
'Too many message fragments',
|
|
517
|
+
false,
|
|
518
|
+
1008,
|
|
519
|
+
'WS_ERR_TOO_MANY_BUFFERED_PARTS'
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
cb(error);
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
|
|
488
526
|
//
|
|
489
527
|
// This message is not compressed so its length is the sum of the payload
|
|
490
528
|
// length of all fragments.
|
|
@@ -524,6 +562,22 @@ class Receiver extends Writable {
|
|
|
524
562
|
return;
|
|
525
563
|
}
|
|
526
564
|
|
|
565
|
+
if (
|
|
566
|
+
this._maxFragments > 0 &&
|
|
567
|
+
this._fragments.length >= this._maxFragments
|
|
568
|
+
) {
|
|
569
|
+
const error = this.createError(
|
|
570
|
+
RangeError,
|
|
571
|
+
'Too many message fragments',
|
|
572
|
+
false,
|
|
573
|
+
1008,
|
|
574
|
+
'WS_ERR_TOO_MANY_BUFFERED_PARTS'
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
cb(error);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
|
|
527
581
|
this._fragments.push(buf);
|
|
528
582
|
}
|
|
529
583
|
|
|
@@ -43,6 +43,10 @@ class WebSocketServer extends EventEmitter {
|
|
|
43
43
|
* called
|
|
44
44
|
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
45
45
|
* @param {String} [options.host] The hostname where to bind the server
|
|
46
|
+
* @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
|
|
47
|
+
* buffered data chunks
|
|
48
|
+
* @param {Number} [options.maxFragments=131072] The maximum number of message
|
|
49
|
+
* fragments
|
|
46
50
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
47
51
|
* size
|
|
48
52
|
* @param {Boolean} [options.noServer=false] Enable no server mode
|
|
@@ -65,6 +69,8 @@ class WebSocketServer extends EventEmitter {
|
|
|
65
69
|
options = {
|
|
66
70
|
allowSynchronousEvents: true,
|
|
67
71
|
autoPong: true,
|
|
72
|
+
maxBufferedChunks: 1024 * 1024,
|
|
73
|
+
maxFragments: 128 * 1024,
|
|
68
74
|
maxPayload: 100 * 1024 * 1024,
|
|
69
75
|
skipUTF8Validation: false,
|
|
70
76
|
perMessageDeflate: false,
|
|
@@ -424,6 +430,8 @@ class WebSocketServer extends EventEmitter {
|
|
|
424
430
|
|
|
425
431
|
ws.setSocket(socket, head, {
|
|
426
432
|
allowSynchronousEvents: this.options.allowSynchronousEvents,
|
|
433
|
+
maxBufferedChunks: this.options.maxBufferedChunks,
|
|
434
|
+
maxFragments: this.options.maxFragments,
|
|
427
435
|
maxPayload: this.options.maxPayload,
|
|
428
436
|
skipUTF8Validation: this.options.skipUTF8Validation
|
|
429
437
|
});
|
|
@@ -201,6 +201,10 @@ class WebSocket extends EventEmitter {
|
|
|
201
201
|
* multiple times in the same tick
|
|
202
202
|
* @param {Function} [options.generateMask] The function used to generate the
|
|
203
203
|
* masking key
|
|
204
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
205
|
+
* buffered data chunks
|
|
206
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
207
|
+
* fragments
|
|
204
208
|
* @param {Number} [options.maxPayload=0] The maximum allowed message size
|
|
205
209
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
206
210
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -212,6 +216,8 @@ class WebSocket extends EventEmitter {
|
|
|
212
216
|
binaryType: this.binaryType,
|
|
213
217
|
extensions: this._extensions,
|
|
214
218
|
isServer: this._isServer,
|
|
219
|
+
maxBufferedChunks: options.maxBufferedChunks,
|
|
220
|
+
maxFragments: options.maxFragments,
|
|
215
221
|
maxPayload: options.maxPayload,
|
|
216
222
|
skipUTF8Validation: options.skipUTF8Validation
|
|
217
223
|
});
|
|
@@ -640,6 +646,10 @@ module.exports = WebSocket;
|
|
|
640
646
|
* masking key
|
|
641
647
|
* @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
|
|
642
648
|
* handshake request
|
|
649
|
+
* @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
|
|
650
|
+
* buffered data chunks
|
|
651
|
+
* @param {Number} [options.maxFragments=131072] The maximum number of message
|
|
652
|
+
* fragments
|
|
643
653
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
644
654
|
* size
|
|
645
655
|
* @param {Number} [options.maxRedirects=10] The maximum number of redirects
|
|
@@ -660,6 +670,8 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
660
670
|
autoPong: true,
|
|
661
671
|
closeTimeout: CLOSE_TIMEOUT,
|
|
662
672
|
protocolVersion: protocolVersions[1],
|
|
673
|
+
maxBufferedChunks: 1024 * 1024,
|
|
674
|
+
maxFragments: 128 * 1024,
|
|
663
675
|
maxPayload: 100 * 1024 * 1024,
|
|
664
676
|
skipUTF8Validation: false,
|
|
665
677
|
perMessageDeflate: true,
|
|
@@ -1017,6 +1029,8 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
1017
1029
|
websocket.setSocket(socket, head, {
|
|
1018
1030
|
allowSynchronousEvents: opts.allowSynchronousEvents,
|
|
1019
1031
|
generateMask: opts.generateMask,
|
|
1032
|
+
maxBufferedChunks: opts.maxBufferedChunks,
|
|
1033
|
+
maxFragments: opts.maxFragments,
|
|
1020
1034
|
maxPayload: opts.maxPayload,
|
|
1021
1035
|
skipUTF8Validation: opts.skipUTF8Validation
|
|
1022
1036
|
});
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/voice-call",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.25-beta.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/voice-call",
|
|
9
|
-
"version": "2026.5.
|
|
9
|
+
"version": "2026.5.25-beta.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"commander": "14.0.3",
|
|
12
12
|
"typebox": "1.1.38",
|
|
13
|
-
"ws": "8.
|
|
13
|
+
"ws": "8.21.0",
|
|
14
14
|
"zod": "4.4.3"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"openclaw": ">=2026.5.
|
|
17
|
+
"openclaw": ">=2026.5.25-beta.1"
|
|
18
18
|
},
|
|
19
19
|
"peerDependenciesMeta": {
|
|
20
20
|
"openclaw": {
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"license": "MIT"
|
|
39
39
|
},
|
|
40
40
|
"node_modules/ws": {
|
|
41
|
-
"version": "8.
|
|
42
|
-
"resolved": "https://registry.npmjs.org/ws/-/ws-8.
|
|
43
|
-
"integrity": "sha512-
|
|
41
|
+
"version": "8.21.0",
|
|
42
|
+
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
|
|
43
|
+
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
|
|
44
44
|
"license": "MIT",
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=10.0.0"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/voice-call",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.25-beta.1",
|
|
4
4
|
"description": "OpenClaw voice-call plugin",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"commander": "14.0.3",
|
|
12
12
|
"typebox": "1.1.38",
|
|
13
|
-
"ws": "8.
|
|
13
|
+
"ws": "8.21.0",
|
|
14
14
|
"zod": "4.4.3"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"openclaw": ">=2026.5.
|
|
17
|
+
"openclaw": ">=2026.5.25-beta.1"
|
|
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.5.
|
|
34
|
+
"pluginApi": ">=2026.5.25-beta.1"
|
|
35
35
|
},
|
|
36
36
|
"build": {
|
|
37
|
-
"openclawVersion": "2026.5.
|
|
37
|
+
"openclawVersion": "2026.5.25-beta.1"
|
|
38
38
|
},
|
|
39
39
|
"release": {
|
|
40
40
|
"publishToClawHub": true,
|