@openclaw/voice-call 2026.6.11 → 2026.7.1-beta.2
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-BKDAAd8j.js → config-DNtTB7Iw.js} +40 -4
- package/dist/{config-compat-qDCcKTUt.js → config-compat-CCEjHjAJ.js} +1 -1
- package/dist/doctor-contract-api.js +22 -1
- package/dist/{guarded-json-api-BXeBxB7w.js → guarded-json-api-7ITxTL6G.js} +1 -1
- package/dist/index.js +20 -7
- package/dist/{plivo-CPxvHw8k.js → plivo-wmeT9r_t.js} +2 -2
- package/dist/{realtime-handler-rYbJUshl.js → realtime-handler-DdViwdCW.js} +4 -3
- package/dist/{response-generator-DBzGujH_.js → response-generator-CXBGKbAp.js} +10 -5
- package/dist/{runtime-entry-DIAae7sB.js → runtime-entry-DN7HllXj.js} +24 -51
- package/dist/runtime-entry.js +1 -1
- package/dist/setup-api.js +1 -1
- package/dist/{telnyx-CYS_IihO.js → telnyx-DuUBsPW2.js} +1 -1
- package/dist/{twilio-Bn1ta3tQ.js → twilio-CsJBvC3a.js} +2 -2
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
|
@@ -2,7 +2,9 @@ import { TtsConfigSchema } from "./runtime-api.js";
|
|
|
2
2
|
import "./api.js";
|
|
3
3
|
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, REALTIME_VOICE_AGENT_CONSULT_TOOL_POLICIES } from "openclaw/plugin-sdk/realtime-voice";
|
|
5
|
+
import { normalizeAgentId, parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
5
6
|
import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
7
|
+
import { canonicalizeMainSessionAlias } from "openclaw/plugin-sdk/session-store-runtime";
|
|
6
8
|
import { z } from "zod";
|
|
7
9
|
//#region extensions/voice-call/src/deep-merge.ts
|
|
8
10
|
const BLOCKED_MERGE_KEYS = new Set([
|
|
@@ -442,6 +444,13 @@ function resolveVoiceCallNumberRouteKey(config, phone) {
|
|
|
442
444
|
if (!normalizedPhone) return;
|
|
443
445
|
return Object.keys(routes).find((routeKey) => normalizePhoneRouteKey(routeKey) === normalizedPhone);
|
|
444
446
|
}
|
|
447
|
+
/** Resolve inbound-only number routing from a persisted call record. */
|
|
448
|
+
function resolveVoiceCallNumberRouteKeyForCall(call) {
|
|
449
|
+
if (call.direction !== "inbound") return;
|
|
450
|
+
const storedRouteKey = call.metadata?.numberRouteKey;
|
|
451
|
+
if (typeof storedRouteKey === "string") return storedRouteKey;
|
|
452
|
+
return call.to;
|
|
453
|
+
}
|
|
445
454
|
function resolveVoiceCallEffectiveConfig(config, phoneOrRouteKey) {
|
|
446
455
|
const numberRouteKey = resolveVoiceCallNumberRouteKey(config, phoneOrRouteKey);
|
|
447
456
|
if (!numberRouteKey) return { config };
|
|
@@ -538,10 +547,37 @@ function normalizeVoiceCallConfig(config) {
|
|
|
538
547
|
}
|
|
539
548
|
function resolveVoiceCallSessionKey(params) {
|
|
540
549
|
const explicit = params.explicitSessionKey?.trim();
|
|
541
|
-
if (explicit) return
|
|
542
|
-
|
|
550
|
+
if (explicit) return resolveVoiceCallAgentSessionKey({
|
|
551
|
+
config: params.config,
|
|
552
|
+
sessionKey: explicit,
|
|
553
|
+
coreSession: params.coreSession
|
|
554
|
+
});
|
|
555
|
+
const prefix = `agent:${normalizeAgentId(params.config.agentId)}:voice`;
|
|
556
|
+
if (params.config.sessionScope === "per-call") return `${prefix}:call:${params.callId}`.toLowerCase();
|
|
543
557
|
const normalizedPhone = params.phone?.replace(/\D/g, "");
|
|
544
|
-
return normalizedPhone ?
|
|
558
|
+
return (normalizedPhone ? `${prefix}:${normalizedPhone}` : `${prefix}:${params.callId}`).toLowerCase();
|
|
559
|
+
}
|
|
560
|
+
/** Resolve persisted or integration-provided keys into the configured agent namespace. */
|
|
561
|
+
function resolveVoiceCallAgentSessionKey(params) {
|
|
562
|
+
const sessionKey = params.sessionKey.trim();
|
|
563
|
+
if (!sessionKey) throw new Error("Voice Call session key cannot be empty");
|
|
564
|
+
const lower = sessionKey.toLowerCase();
|
|
565
|
+
const agentId = normalizeAgentId(params.config.agentId);
|
|
566
|
+
if (lower === "global" || lower === "unknown") return lower;
|
|
567
|
+
const parsedInput = parseAgentSessionKey(sessionKey);
|
|
568
|
+
let normalizedScopedKey;
|
|
569
|
+
if (parsedInput && normalizeAgentId(parsedInput.agentId) === parsedInput.agentId && parsedInput.agentId === agentId) normalizedScopedKey = `agent:${parsedInput.agentId}:${parsedInput.rest}`;
|
|
570
|
+
else {
|
|
571
|
+
const wrappedInput = parseAgentSessionKey(`agent:${agentId}:${sessionKey}`);
|
|
572
|
+
if (!wrappedInput) throw new Error("Voice Call session key could not be normalized");
|
|
573
|
+
normalizedScopedKey = `agent:${agentId}:${wrappedInput.rest}`;
|
|
574
|
+
}
|
|
575
|
+
const canonicalMain = canonicalizeMainSessionAlias({
|
|
576
|
+
cfg: { session: params.coreSession },
|
|
577
|
+
agentId,
|
|
578
|
+
sessionKey: normalizedScopedKey
|
|
579
|
+
});
|
|
580
|
+
return canonicalMain === normalizedScopedKey ? normalizedScopedKey : canonicalMain;
|
|
545
581
|
}
|
|
546
582
|
/**
|
|
547
583
|
* Resolves the configuration by merging environment variables into missing fields.
|
|
@@ -616,4 +652,4 @@ function validateProviderConfig(config) {
|
|
|
616
652
|
};
|
|
617
653
|
}
|
|
618
654
|
//#endregion
|
|
619
|
-
export { resolveVoiceCallEffectiveConfig as a,
|
|
655
|
+
export { resolveVoiceCallEffectiveConfig as a, validateProviderConfig as c, resolveVoiceCallConfig as i, normalizePath as l, normalizeVoiceCallConfig as n, resolveVoiceCallNumberRouteKeyForCall as o, resolveTwilioAuthToken as r, resolveVoiceCallSessionKey as s, VoiceCallConfigSchema as t, deepMergeDefined as u };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as VoiceCallConfigSchema } from "./config-
|
|
1
|
+
import { t as VoiceCallConfigSchema } from "./config-DNtTB7Iw.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
|
/** Version where legacy voice-call config shape support is removed. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { a as MAX_CALL_RECORD_EVENTS, f as prepareVoiceCallRecordForStorage, i as CALL_RECORD_EVENT_META_MAX_ENTRIES, n as CALL_RECORD_EVENTS_NAMESPACE, o as RAW_CALL_RECORD_CHUNK_BYTES, p as resolveVoiceCallLegacyCallLogPath, r as CALL_RECORD_EVENT_CHUNKS_NAMESPACE, s as buildVoiceCallLegacyJsonlEventKey, t as CALL_RECORD_CHUNK_MAX_ENTRIES, u as parseVoiceCallRecordLine } from "./store-8M2m4Isq.js";
|
|
2
|
+
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
2
3
|
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import fs from "node:fs/promises";
|
|
@@ -24,6 +25,26 @@ function getVoiceCallConfigStore(config) {
|
|
|
24
25
|
}
|
|
25
26
|
return "";
|
|
26
27
|
}
|
|
28
|
+
function asRecord(value) {
|
|
29
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
30
|
+
}
|
|
31
|
+
/** Return Voice Call agents whose templated core session stores need migration. */
|
|
32
|
+
function resolveSessionStoreAgentIds(params) {
|
|
33
|
+
const agentIds = /* @__PURE__ */ new Set();
|
|
34
|
+
for (const pluginId of ["voice-call", "@openclaw/voice-call"]) {
|
|
35
|
+
const entry = params.cfg.plugins?.entries?.[pluginId];
|
|
36
|
+
if (!entry) continue;
|
|
37
|
+
const config = entry.config === void 0 ? {} : asRecord(entry.config);
|
|
38
|
+
if (!config) continue;
|
|
39
|
+
agentIds.add(normalizeAgentId(typeof config.agentId === "string" ? config.agentId : void 0));
|
|
40
|
+
const numbers = asRecord(config.numbers);
|
|
41
|
+
for (const route of Object.values(numbers ?? {})) {
|
|
42
|
+
const agentId = asRecord(route)?.agentId;
|
|
43
|
+
if (typeof agentId === "string") agentIds.add(normalizeAgentId(agentId));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return [...agentIds].toSorted();
|
|
47
|
+
}
|
|
27
48
|
/** Resolve the voice-call store path used by legacy and plugin-state call records. */
|
|
28
49
|
function resolveVoiceCallStorePath(params) {
|
|
29
50
|
const configuredStore = getVoiceCallConfigStore(params.config);
|
|
@@ -220,4 +241,4 @@ const stateMigrations = [{
|
|
|
220
241
|
}
|
|
221
242
|
}];
|
|
222
243
|
//#endregion
|
|
223
|
-
export { stateMigrations };
|
|
244
|
+
export { resolveSessionStoreAgentIds, stateMigrations };
|
|
@@ -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-DN7HllXj.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";
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { definePluginEntry, sleep } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
|
-
import {
|
|
4
|
-
import { c as getTailscaleSelfInfo, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-
|
|
3
|
+
import { c as validateProviderConfig, i as resolveVoiceCallConfig } from "./config-DNtTB7Iw.js";
|
|
4
|
+
import { c as getTailscaleSelfInfo, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-DN7HllXj.js";
|
|
5
5
|
import { c as getCallHistoryFromStore, m as setVoiceCallStateRuntime } from "./store-8M2m4Isq.js";
|
|
6
|
-
import { i as parseVoiceCallPluginConfig, r as normalizeVoiceCallLegacyConfigInput, t as formatVoiceCallLegacyConfigWarnings } from "./config-compat-
|
|
6
|
+
import { i as parseVoiceCallPluginConfig, r as normalizeVoiceCallLegacyConfigInput, t as formatVoiceCallLegacyConfigWarnings } from "./config-compat-CCEjHjAJ.js";
|
|
7
7
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
8
8
|
import { ErrorCodes, callGatewayFromCli, errorShape } from "openclaw/plugin-sdk/gateway-runtime";
|
|
9
9
|
import { MAX_TCP_PORT, MAX_TIMER_TIMEOUT_MS, addTimerTimeoutGraceMs, clampTimerTimeoutMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
@@ -915,6 +915,19 @@ function asParamRecord(params) {
|
|
|
915
915
|
function isCliOnlyProcess() {
|
|
916
916
|
return process.env.OPENCLAW_CLI === "1" && !process.argv.slice(2).includes("gateway");
|
|
917
917
|
}
|
|
918
|
+
function toVoiceCallStatus(call) {
|
|
919
|
+
return {
|
|
920
|
+
callId: call.callId,
|
|
921
|
+
...call.providerCallId !== void 0 ? { providerCallId: call.providerCallId } : {},
|
|
922
|
+
provider: call.provider,
|
|
923
|
+
direction: call.direction,
|
|
924
|
+
state: call.state,
|
|
925
|
+
startedAt: call.startedAt,
|
|
926
|
+
...call.answeredAt !== void 0 ? { answeredAt: call.answeredAt } : {},
|
|
927
|
+
...call.endedAt !== void 0 ? { endedAt: call.endedAt } : {},
|
|
928
|
+
...call.endReason !== void 0 ? { endReason: call.endReason } : {}
|
|
929
|
+
};
|
|
930
|
+
}
|
|
918
931
|
const VOICE_CALL_RUNTIME_KEY = Symbol.for("openclaw.voice-call.runtime");
|
|
919
932
|
const VOICE_CALL_RUNTIME_PROMISE_KEY = Symbol.for("openclaw.voice-call.runtimePromise");
|
|
920
933
|
const VOICE_CALL_RUNTIME_STOP_PROMISE_KEY = Symbol.for("openclaw.voice-call.runtimeStopPromise");
|
|
@@ -1183,7 +1196,7 @@ var voice_call_default = definePluginEntry({
|
|
|
1183
1196
|
if (!raw) {
|
|
1184
1197
|
respond(true, {
|
|
1185
1198
|
found: true,
|
|
1186
|
-
calls: rt.manager.getActiveCalls()
|
|
1199
|
+
calls: rt.manager.getActiveCalls().map(toVoiceCallStatus)
|
|
1187
1200
|
});
|
|
1188
1201
|
return;
|
|
1189
1202
|
}
|
|
@@ -1194,7 +1207,7 @@ var voice_call_default = definePluginEntry({
|
|
|
1194
1207
|
}
|
|
1195
1208
|
respond(true, {
|
|
1196
1209
|
found: true,
|
|
1197
|
-
call
|
|
1210
|
+
call: toVoiceCallStatus(call)
|
|
1198
1211
|
});
|
|
1199
1212
|
} catch (err) {
|
|
1200
1213
|
sendError(respond, err);
|
|
@@ -1299,7 +1312,7 @@ var voice_call_default = definePluginEntry({
|
|
|
1299
1312
|
const call = rt.manager.getCall(callId) || rt.manager.getCallByProviderCallId(callId);
|
|
1300
1313
|
return json(call ? {
|
|
1301
1314
|
found: true,
|
|
1302
|
-
call
|
|
1315
|
+
call: toVoiceCallStatus(call)
|
|
1303
1316
|
} : { found: false });
|
|
1304
1317
|
}
|
|
1305
1318
|
}
|
|
@@ -1309,7 +1322,7 @@ var voice_call_default = definePluginEntry({
|
|
|
1309
1322
|
const call = rt.manager.getCall(sid) || rt.manager.getCallByProviderCallId(sid);
|
|
1310
1323
|
return json(call ? {
|
|
1311
1324
|
found: true,
|
|
1312
|
-
call
|
|
1325
|
+
call: toVoiceCallStatus(call)
|
|
1313
1326
|
} : { found: false });
|
|
1314
1327
|
}
|
|
1315
1328
|
const to = normalizeOptionalString(rawParams.to) ?? rt.config.toNumber;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as getHeader, m as escapeXml } from "./runtime-entry-
|
|
2
|
-
import { a as reconstructWebhookUrl, o as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-
|
|
1
|
+
import { a as getHeader, m as escapeXml } from "./runtime-entry-DN7HllXj.js";
|
|
2
|
+
import { a as reconstructWebhookUrl, o as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-7ITxTL6G.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,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as normalizePath } from "./config-DNtTB7Iw.js";
|
|
2
2
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
3
3
|
import { isFutureDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
4
4
|
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
@@ -6,6 +6,7 @@ import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, buildRealtimeVoiceAgentConsultW
|
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
import "node:http";
|
|
8
8
|
import WebSocket, { WebSocketServer } from "ws";
|
|
9
|
+
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
9
10
|
//#region extensions/voice-call/src/webhook/realtime-audio-pacer.ts
|
|
10
11
|
const TELEPHONY_SAMPLE_RATE = 8e3;
|
|
11
12
|
const TELEPHONY_CHUNK_BYTES = 160;
|
|
@@ -379,7 +380,7 @@ function appendTranscriptText(base, fragment) {
|
|
|
379
380
|
}
|
|
380
381
|
function limitPartialUserTranscript(text) {
|
|
381
382
|
if (text.length <= MAX_PARTIAL_USER_TRANSCRIPT_CHARS) return text;
|
|
382
|
-
const tail = text
|
|
383
|
+
const tail = sliceUtf16Safe(text, -1200);
|
|
383
384
|
return tail.replace(/^\S+\s+/, "").trimStart() || tail.trimStart();
|
|
384
385
|
}
|
|
385
386
|
function withFallbackConsultQuestion(args, fallback) {
|
|
@@ -412,7 +413,7 @@ function buildForcedConsultSpeechPrompt(result) {
|
|
|
412
413
|
"Internal OpenClaw consult result is ready.",
|
|
413
414
|
"Do not call tools for this internal result.",
|
|
414
415
|
"Speak the following answer to the caller now, briefly and naturally:",
|
|
415
|
-
trimmed.length <= FORCED_CONSULT_RESULT_MAX_CHARS ? trimmed : `${trimmed
|
|
416
|
+
trimmed.length <= FORCED_CONSULT_RESULT_MAX_CHARS ? trimmed : `${truncateUtf16Safe(trimmed, FORCED_CONSULT_RESULT_MAX_CHARS - 16).trimEnd()} [truncated]`
|
|
416
417
|
].join("\n");
|
|
417
418
|
}
|
|
418
419
|
function appendRecentTalkEventMetadata(call, event) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { f as resolveVoiceResponseModel } from "./runtime-entry-
|
|
1
|
+
import { s as resolveVoiceCallSessionKey } from "./config-DNtTB7Iw.js";
|
|
2
|
+
import { f as resolveVoiceResponseModel } from "./runtime-entry-DN7HllXj.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";
|
|
@@ -106,7 +106,8 @@ async function generateVoiceResponse(params) {
|
|
|
106
106
|
config: voiceConfig,
|
|
107
107
|
callId,
|
|
108
108
|
phone: from,
|
|
109
|
-
explicitSessionKey: sessionKey
|
|
109
|
+
explicitSessionKey: sessionKey,
|
|
110
|
+
coreSession: coreConfig.session
|
|
110
111
|
});
|
|
111
112
|
const agentId = voiceConfig.agentId ?? "main";
|
|
112
113
|
const toolsAllow = resolveVoiceAgentToolsAllow(cfg, agentId);
|
|
@@ -154,7 +155,6 @@ async function generateVoiceResponse(params) {
|
|
|
154
155
|
error: "Voice response session could not be initialized"
|
|
155
156
|
};
|
|
156
157
|
const sessionId = sessionEntry.sessionId;
|
|
157
|
-
const sessionFile = agentRuntime.session.resolveSessionFilePath(sessionId, sessionEntry, { agentId });
|
|
158
158
|
const thinkLevel = agentRuntime.resolveThinkingDefault({
|
|
159
159
|
cfg,
|
|
160
160
|
provider,
|
|
@@ -171,10 +171,15 @@ async function generateVoiceResponse(params) {
|
|
|
171
171
|
const result = await agentRuntime.runEmbeddedAgent({
|
|
172
172
|
sessionId,
|
|
173
173
|
sessionKey: resolvedSessionKey,
|
|
174
|
+
sessionTarget: {
|
|
175
|
+
agentId,
|
|
176
|
+
sessionId,
|
|
177
|
+
sessionKey: resolvedSessionKey,
|
|
178
|
+
storePath
|
|
179
|
+
},
|
|
174
180
|
sandboxSessionKey: resolveVoiceSandboxSessionKey(agentId, resolvedSessionKey),
|
|
175
181
|
agentId,
|
|
176
182
|
messageProvider: "voice",
|
|
177
|
-
sessionFile,
|
|
178
183
|
workspaceDir,
|
|
179
184
|
config: cfg,
|
|
180
185
|
prompt: userMessage,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { isBlockedHostnameOrIp, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "./runtime-api.js";
|
|
2
2
|
import "./api.js";
|
|
3
|
-
import { a as resolveVoiceCallEffectiveConfig,
|
|
3
|
+
import { a as resolveVoiceCallEffectiveConfig, c as validateProviderConfig, i as resolveVoiceCallConfig, n as normalizeVoiceCallConfig, o as resolveVoiceCallNumberRouteKeyForCall, r as resolveTwilioAuthToken, s as resolveVoiceCallSessionKey, u as deepMergeDefined } from "./config-DNtTB7Iw.js";
|
|
4
4
|
import { c as getCallHistoryFromStore, d as persistCallRecord, h as TerminalStates, l as loadActiveCallsFromStore, m as setVoiceCallStateRuntime } from "./store-8M2m4Isq.js";
|
|
5
5
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
6
6
|
import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
|
|
7
7
|
import { MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
8
8
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
9
10
|
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, buildRealtimeVoiceAgentConsultPolicyInstructions, consultRealtimeVoiceAgent, convertPcmToMulaw8k, createTalkSessionController, recordTalkObservabilityEvent, resolveRealtimeVoiceAgentConsultTools, resolveRealtimeVoiceAgentConsultToolsAllow, resolveRealtimeVoiceFastContextConsult } from "openclaw/plugin-sdk/realtime-voice";
|
|
10
11
|
import fs from "node:fs";
|
|
11
12
|
import os from "node:os";
|
|
@@ -356,7 +357,8 @@ async function initiateCall(ctx, to, sessionKey, options) {
|
|
|
356
357
|
config: ctx.config,
|
|
357
358
|
callId,
|
|
358
359
|
phone: to,
|
|
359
|
-
explicitSessionKey: sessionKey
|
|
360
|
+
explicitSessionKey: sessionKey,
|
|
361
|
+
coreSession: ctx.coreSession
|
|
360
362
|
}),
|
|
361
363
|
startedAt: Date.now(),
|
|
362
364
|
transcript: [],
|
|
@@ -438,7 +440,7 @@ async function speak(ctx, callId, text) {
|
|
|
438
440
|
});
|
|
439
441
|
transitionState(call, "speaking");
|
|
440
442
|
persistCallRecord(ctx.storePath, call);
|
|
441
|
-
const numberRouteKey =
|
|
443
|
+
const numberRouteKey = resolveVoiceCallNumberRouteKeyForCall(call);
|
|
442
444
|
const voice = resolvePreferredTtsVoice(resolveVoiceCallEffectiveConfig(ctx.config, numberRouteKey).config);
|
|
443
445
|
await provider.playTts({
|
|
444
446
|
callId,
|
|
@@ -910,7 +912,7 @@ function resolveDefaultStoreBase(config, storePath) {
|
|
|
910
912
|
* Manages voice calls: state ownership and delegation to manager helper modules.
|
|
911
913
|
*/
|
|
912
914
|
var CallManager = class {
|
|
913
|
-
constructor(config, storePath) {
|
|
915
|
+
constructor(config, storePath, coreSession) {
|
|
914
916
|
this.activeCalls = /* @__PURE__ */ new Map();
|
|
915
917
|
this.providerCallIdMap = /* @__PURE__ */ new Map();
|
|
916
918
|
this.processedEventIds = /* @__PURE__ */ new Set();
|
|
@@ -922,6 +924,7 @@ var CallManager = class {
|
|
|
922
924
|
this.maxDurationTimers = /* @__PURE__ */ new Map();
|
|
923
925
|
this.initialMessageInFlight = /* @__PURE__ */ new Set();
|
|
924
926
|
this.config = config;
|
|
927
|
+
this.coreSession = coreSession;
|
|
925
928
|
this.storePath = resolveDefaultStoreBase(config, storePath);
|
|
926
929
|
}
|
|
927
930
|
/**
|
|
@@ -1085,6 +1088,7 @@ var CallManager = class {
|
|
|
1085
1088
|
rejectedProviderCallIds: this.rejectedProviderCallIds,
|
|
1086
1089
|
provider: this.provider,
|
|
1087
1090
|
config: this.config,
|
|
1091
|
+
coreSession: this.coreSession,
|
|
1088
1092
|
storePath: this.storePath,
|
|
1089
1093
|
webhookUrl: this.webhookUrl,
|
|
1090
1094
|
activeTurnCalls: this.activeTurnCalls,
|
|
@@ -2503,16 +2507,8 @@ const WEBHOOK_BODY_TIMEOUT_MS = WEBHOOK_BODY_READ_DEFAULTS.preAuth.timeoutMs;
|
|
|
2503
2507
|
const MISSING_REMOTE_ADDRESS_IN_FLIGHT_KEY = "__voice_call_no_remote__";
|
|
2504
2508
|
const STREAM_DISCONNECT_HANGUP_GRACE_MS = 2e3;
|
|
2505
2509
|
const TRANSCRIPT_LOG_MAX_CHARS = 200;
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
function loadRealtimeTranscriptionRuntime() {
|
|
2509
|
-
realtimeTranscriptionRuntimePromise ??= import("./realtime-transcription.runtime-CbJAs5t_.js");
|
|
2510
|
-
return realtimeTranscriptionRuntimePromise;
|
|
2511
|
-
}
|
|
2512
|
-
function loadResponseGeneratorModule() {
|
|
2513
|
-
responseGeneratorModulePromise ??= import("./response-generator-DBzGujH_.js");
|
|
2514
|
-
return responseGeneratorModulePromise;
|
|
2515
|
-
}
|
|
2510
|
+
const loadRealtimeTranscriptionRuntime = createLazyRuntimeModule(() => import("./realtime-transcription.runtime-CbJAs5t_.js"));
|
|
2511
|
+
const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-CXBGKbAp.js"));
|
|
2516
2512
|
function sanitizeTranscriptForLog(value) {
|
|
2517
2513
|
const sanitized = value.replace(/\p{Cc}/gu, " ").replace(/\s+/g, " ").trim();
|
|
2518
2514
|
if (sanitized.length <= TRANSCRIPT_LOG_MAX_CHARS) return sanitized;
|
|
@@ -3156,7 +3152,7 @@ var VoiceCallWebhookServer = class {
|
|
|
3156
3152
|
}
|
|
3157
3153
|
try {
|
|
3158
3154
|
const { generateVoiceResponse } = await loadResponseGeneratorModule();
|
|
3159
|
-
const numberRouteKey =
|
|
3155
|
+
const numberRouteKey = resolveVoiceCallNumberRouteKeyForCall(call);
|
|
3160
3156
|
const effectiveConfig = resolveVoiceCallEffectiveConfig(this.config, numberRouteKey).config;
|
|
3161
3157
|
const result = await generateVoiceResponse({
|
|
3162
3158
|
voiceConfig: effectiveConfig,
|
|
@@ -3191,43 +3187,19 @@ const REALTIME_VOICE_CONSULT_SYSTEM_PROMPT = [
|
|
|
3191
3187
|
"Do not print secret values or dump environment variables; only check whether required configuration is present.",
|
|
3192
3188
|
"Be accurate, brief, and speakable."
|
|
3193
3189
|
].join(" ");
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
function loadTelnyxProvider() {
|
|
3201
|
-
telnyxProviderPromise ??= import("./telnyx-CYS_IihO.js");
|
|
3202
|
-
return telnyxProviderPromise;
|
|
3203
|
-
}
|
|
3204
|
-
function loadTwilioProvider() {
|
|
3205
|
-
twilioProviderPromise ??= import("./twilio-Bn1ta3tQ.js");
|
|
3206
|
-
return twilioProviderPromise;
|
|
3207
|
-
}
|
|
3208
|
-
function loadPlivoProvider() {
|
|
3209
|
-
plivoProviderPromise ??= import("./plivo-CPxvHw8k.js");
|
|
3210
|
-
return plivoProviderPromise;
|
|
3211
|
-
}
|
|
3212
|
-
function loadMockProvider() {
|
|
3213
|
-
mockProviderPromise ??= import("./mock-YAo3QDri.js");
|
|
3214
|
-
return mockProviderPromise;
|
|
3215
|
-
}
|
|
3216
|
-
function loadRealtimeVoiceRuntime() {
|
|
3217
|
-
realtimeVoiceRuntimePromise ??= import("./realtime-voice.runtime-vtdCOWg-.js");
|
|
3218
|
-
return realtimeVoiceRuntimePromise;
|
|
3219
|
-
}
|
|
3220
|
-
function loadRealtimeHandler() {
|
|
3221
|
-
realtimeHandlerPromise ??= import("./realtime-handler-rYbJUshl.js");
|
|
3222
|
-
return realtimeHandlerPromise;
|
|
3223
|
-
}
|
|
3190
|
+
const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-DuUBsPW2.js"));
|
|
3191
|
+
const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-CsJBvC3a.js"));
|
|
3192
|
+
const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-wmeT9r_t.js"));
|
|
3193
|
+
const loadMockProvider = createLazyRuntimeModule(() => import("./mock-YAo3QDri.js"));
|
|
3194
|
+
const loadRealtimeVoiceRuntime = createLazyRuntimeModule(() => import("./realtime-voice.runtime-vtdCOWg-.js"));
|
|
3195
|
+
const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-DdViwdCW.js"));
|
|
3224
3196
|
function resolveVoiceCallConsultSessionKey(call) {
|
|
3225
|
-
if (call.sessionKey) return call.sessionKey;
|
|
3226
|
-
const phone = call.direction === "outbound" ? call.to : call.from;
|
|
3227
3197
|
return resolveVoiceCallSessionKey({
|
|
3228
3198
|
config: call.config,
|
|
3229
3199
|
callId: call.callId,
|
|
3230
|
-
phone
|
|
3200
|
+
phone: call.direction === "outbound" ? call.to : call.from,
|
|
3201
|
+
explicitSessionKey: call.sessionKey,
|
|
3202
|
+
coreSession: call.coreSession
|
|
3231
3203
|
});
|
|
3232
3204
|
}
|
|
3233
3205
|
function mapVoiceCallConsultTranscript(call, context) {
|
|
@@ -3339,7 +3311,7 @@ async function createVoiceCallRuntime(params) {
|
|
|
3339
3311
|
if (!validation.valid) throw new Error(`Invalid voice-call config: ${validation.errors.join("; ")}`);
|
|
3340
3312
|
const provider = await resolveProvider(config);
|
|
3341
3313
|
if (stateRuntime) setVoiceCallStateRuntime({ state: stateRuntime });
|
|
3342
|
-
const manager = new CallManager(config);
|
|
3314
|
+
const manager = new CallManager(config, void 0, cfg.session);
|
|
3343
3315
|
const realtimeProvider = config.realtime.enabled ? await resolveRealtimeProvider({
|
|
3344
3316
|
config,
|
|
3345
3317
|
fullConfig: cfg
|
|
@@ -3361,11 +3333,12 @@ async function createVoiceCallRuntime(params) {
|
|
|
3361
3333
|
if (config.realtime.toolPolicy !== "none") realtimeHandler.registerToolHandler(REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, async (args, callId, handlerContext) => {
|
|
3362
3334
|
const call = manager.getCall(callId);
|
|
3363
3335
|
if (!call) return { error: `Call "${callId}" not found` };
|
|
3364
|
-
const effectiveConfig = resolveVoiceCallEffectiveConfig(config,
|
|
3336
|
+
const effectiveConfig = resolveVoiceCallEffectiveConfig(config, resolveVoiceCallNumberRouteKeyForCall(call)).config;
|
|
3365
3337
|
const agentId = effectiveConfig.agentId ?? "main";
|
|
3366
3338
|
const sessionKey = resolveVoiceCallConsultSessionKey({
|
|
3367
3339
|
...call,
|
|
3368
|
-
config: effectiveConfig
|
|
3340
|
+
config: effectiveConfig,
|
|
3341
|
+
coreSession: cfg.session
|
|
3369
3342
|
});
|
|
3370
3343
|
const requesterSessionKey = typeof call.metadata?.requesterSessionKey === "string" ? call.metadata.requesterSessionKey : void 0;
|
|
3371
3344
|
const fastContext = await resolveRealtimeFastContextConsult({
|
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-DN7HllXj.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-CCEjHjAJ.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 { s as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-
|
|
1
|
+
import { s as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-7ITxTL6G.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 { c as verifyTwilioWebhook, i as readProviderJsonResponseText, n as cancelProviderResponseBody, r as readProviderErrorResponseSnippet, 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-DN7HllXj.js";
|
|
4
|
+
import { c as verifyTwilioWebhook, i as readProviderJsonResponseText, n as cancelProviderResponseBody, r as readProviderErrorResponseSnippet, t as guardedJsonApiRequest } from "./guarded-json-api-7ITxTL6G.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";
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/voice-call",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.7.1-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/voice-call",
|
|
9
|
-
"version": "2026.
|
|
9
|
+
"version": "2026.7.1-beta.2",
|
|
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.
|
|
17
|
+
"openclaw": ">=2026.7.1-beta.2"
|
|
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.
|
|
3
|
+
"version": "2026.7.1-beta.2",
|
|
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.
|
|
17
|
+
"openclaw": ">=2026.7.1-beta.2"
|
|
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.
|
|
34
|
+
"pluginApi": ">=2026.7.1-beta.2"
|
|
35
35
|
},
|
|
36
36
|
"build": {
|
|
37
|
-
"openclawVersion": "2026.
|
|
37
|
+
"openclawVersion": "2026.7.1-beta.2"
|
|
38
38
|
},
|
|
39
39
|
"release": {
|
|
40
40
|
"publishToClawHub": true,
|