@openclaw/voice-call 2026.9.8 → 2026.10.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/.setup/{cli-D6uwMXyS.mjs → cli-Cn1leykM.mjs} +57 -37
- package/dist/.setup/{config-Ds7xoZbI.mjs → config-CX9J-053.mjs} +18 -119
- package/dist/.setup/{guarded-json-api-Bqc6QS8A.mjs → guarded-json-api-x55yqHvW.mjs} +39 -94
- package/dist/.setup/{mock-ClWW6Ufu.mjs → mock-eLv_Dc4o.mjs} +3 -6
- package/dist/.setup/{plivo-69ObrQPk.mjs → plivo-CpPIENu4.mjs} +48 -101
- package/dist/.setup/{realtime-handler-BgDPcPZt.mjs → realtime-handler-Do7Sz7Gh.mjs} +123 -235
- package/dist/.setup/{response-generator-BzKrJMEb.mjs → response-generator-DAhbXEta.mjs} +6 -25
- package/dist/.setup/{runtime-entry-BNOQRXii.mjs → runtime-entry-CbSKxSKk.mjs} +554 -425
- package/dist/.setup/state-retention-api-ONgqE-_V.mjs +201 -0
- package/dist/.setup/store-path-Cfwff6j7.mjs +33 -0
- package/dist/.setup/{telnyx-DjFGCfy1.mjs → telnyx-DPilutCH.mjs} +10 -29
- package/dist/.setup/{twilio-Bp3gfmUB.mjs → twilio-BWFNGyVx.mjs} +78 -201
- package/dist/.setup/{twilio-region-4fkgz3UG.mjs → twilio-region-wBOx-8sz.mjs} +1 -4
- package/dist/.setup/voice-mapping-B_iAUkER.mjs +31 -0
- package/dist/.setup/{webhook-replay-CCQSoBNF.mjs → webhook-replay-B7RJNWNG.mjs} +2 -5
- package/dist/doctor-contract-api.js +7 -330
- package/dist/index.js +18 -16
- package/dist/runtime-entry.js +1 -1
- package/dist/state-retention-api.js +2 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -6
- package/dist/.setup/utils-B5pnM_Ij.mjs +0 -437
- package/node_modules/ws/LICENSE +0 -20
- package/node_modules/ws/README.md +0 -548
- package/node_modules/ws/browser.js +0 -8
- package/node_modules/ws/index.js +0 -22
- package/node_modules/ws/lib/buffer-util.js +0 -131
- package/node_modules/ws/lib/constants.js +0 -19
- package/node_modules/ws/lib/event-target.js +0 -292
- package/node_modules/ws/lib/extension.js +0 -203
- package/node_modules/ws/lib/limiter.js +0 -55
- package/node_modules/ws/lib/permessage-deflate.js +0 -530
- package/node_modules/ws/lib/receiver.js +0 -743
- package/node_modules/ws/lib/sender.js +0 -607
- package/node_modules/ws/lib/stream.js +0 -161
- package/node_modules/ws/lib/subprotocol.js +0 -62
- package/node_modules/ws/lib/validation.js +0 -152
- package/node_modules/ws/lib/websocket-server.js +0 -562
- package/node_modules/ws/lib/websocket.js +0 -1407
- package/node_modules/ws/package.json +0 -74
- package/node_modules/ws/wrapper.mjs +0 -21
|
@@ -1,204 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "
|
|
1
|
+
import { n as stateMigrations$1 } from "./.setup/state-retention-api-ONgqE-_V.mjs";
|
|
2
|
+
import { n as resolveVoiceCallStorePath } from "./.setup/store-path-Cfwff6j7.mjs";
|
|
3
3
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
4
4
|
import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
|
-
import os from "node:os";
|
|
7
|
-
import fs$1 from "node:fs/promises";
|
|
8
|
-
//#region \0rolldown/runtime.js
|
|
9
|
-
var __defProp = Object.defineProperty;
|
|
10
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
13
|
-
var __exportAll = (all, no_symbols) => {
|
|
14
|
-
let target = {};
|
|
15
|
-
for (var name in all) __defProp(target, name, {
|
|
16
|
-
get: all[name],
|
|
17
|
-
enumerable: true
|
|
18
|
-
});
|
|
19
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
20
|
-
return target;
|
|
21
|
-
};
|
|
22
|
-
var __copyProps = (to, from, except, desc) => {
|
|
23
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
24
|
-
key = keys[i];
|
|
25
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
26
|
-
get: ((k) => from[k]).bind(null, key),
|
|
27
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
return to;
|
|
31
|
-
};
|
|
32
|
-
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
33
|
-
//#endregion
|
|
34
|
-
//#region packages/normalization-core/src/record-coerce.ts
|
|
35
|
-
/** Type guard for non-array object records at browser-safe boundaries. */
|
|
36
|
-
function isRecord$1(value) {
|
|
37
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
38
|
-
}
|
|
39
|
-
/** Returns a non-array record or null. */
|
|
40
|
-
function asNullableRecord$1(value) {
|
|
41
|
-
return isRecord$1(value) ? value : null;
|
|
42
|
-
}
|
|
43
|
-
//#endregion
|
|
44
|
-
//#region src/config/channel-config-normalization.ts
|
|
45
|
-
/** Applies one channel-specific doctor migration to every object-shaped account. */
|
|
46
|
-
function normalizeChannelAccounts(params) {
|
|
47
|
-
const rawAccounts = asNullableRecord$1(params.entry.accounts);
|
|
48
|
-
if (!rawAccounts) return {
|
|
49
|
-
entry: params.entry,
|
|
50
|
-
changed: false
|
|
51
|
-
};
|
|
52
|
-
let changed = false;
|
|
53
|
-
const accounts = { ...rawAccounts };
|
|
54
|
-
for (const [accountId, value] of Object.entries(rawAccounts)) {
|
|
55
|
-
const account = asNullableRecord$1(value);
|
|
56
|
-
if (!account) continue;
|
|
57
|
-
const normalized = params.normalizeAccount({
|
|
58
|
-
account,
|
|
59
|
-
accountId,
|
|
60
|
-
pathPrefix: `${params.pathPrefix}.accounts.${accountId}`,
|
|
61
|
-
changes: params.changes
|
|
62
|
-
});
|
|
63
|
-
if (normalized.changed) {
|
|
64
|
-
accounts[accountId] = normalized.entry;
|
|
65
|
-
changed = true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return changed ? {
|
|
69
|
-
entry: {
|
|
70
|
-
...params.entry,
|
|
71
|
-
accounts
|
|
72
|
-
},
|
|
73
|
-
changed: true
|
|
74
|
-
} : {
|
|
75
|
-
entry: params.entry,
|
|
76
|
-
changed: false
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
/** Applies the same channel-specific doctor migration at root and account scope. */
|
|
80
|
-
function normalizeChannelConfigEntries(params) {
|
|
81
|
-
const changes = params.changes ?? [];
|
|
82
|
-
const channels = params.cfg.channels;
|
|
83
|
-
const entry = asNullableRecord$1(channels?.[params.channelId]);
|
|
84
|
-
if (!entry) return {
|
|
85
|
-
config: params.cfg,
|
|
86
|
-
changes
|
|
87
|
-
};
|
|
88
|
-
const channelPath = `channels.${params.channelId}`;
|
|
89
|
-
const root = params.normalizeEntry({
|
|
90
|
-
entry,
|
|
91
|
-
pathPrefix: channelPath,
|
|
92
|
-
changes
|
|
93
|
-
});
|
|
94
|
-
const accounts = normalizeChannelAccounts({
|
|
95
|
-
entry: root.entry,
|
|
96
|
-
pathPrefix: channelPath,
|
|
97
|
-
changes,
|
|
98
|
-
normalizeAccount: (accountParams) => params.normalizeEntry({
|
|
99
|
-
entry: accountParams.account,
|
|
100
|
-
accountId: accountParams.accountId,
|
|
101
|
-
pathPrefix: accountParams.pathPrefix,
|
|
102
|
-
changes: accountParams.changes
|
|
103
|
-
})
|
|
104
|
-
});
|
|
105
|
-
if (!root.changed && !accounts.changed) return {
|
|
106
|
-
config: params.cfg,
|
|
107
|
-
changes
|
|
108
|
-
};
|
|
109
|
-
return {
|
|
110
|
-
config: {
|
|
111
|
-
...params.cfg,
|
|
112
|
-
channels: {
|
|
113
|
-
...channels,
|
|
114
|
-
[params.channelId]: accounts.entry
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
changes
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/plugin-sdk/legacy-webhook-listener-migration.ts
|
|
122
|
-
/** Preserve explicitly configured webhook listeners while moving ingress onto Gateway routes. */
|
|
123
|
-
function createLegacyWebhookListenerDoctorContract(params) {
|
|
124
|
-
const portKey = params.portKey ?? "webhookPort";
|
|
125
|
-
const hostKey = params.hostKey === void 0 ? "webhookHost" : params.hostKey;
|
|
126
|
-
const source = (entry) => params.webhookKey ? asNullableRecord$1(entry[params.webhookKey]) : entry;
|
|
127
|
-
const hasLegacy = (value) => {
|
|
128
|
-
const entry = asNullableRecord$1(value);
|
|
129
|
-
const listener = entry && source(entry);
|
|
130
|
-
return Boolean(listener && (Object.hasOwn(listener, portKey) || hostKey && Object.hasOwn(listener, hostKey)));
|
|
131
|
-
};
|
|
132
|
-
const prefix = `channels.${params.channelKey}`;
|
|
133
|
-
return {
|
|
134
|
-
legacyConfigRules: [{
|
|
135
|
-
path: ["channels", params.channelKey],
|
|
136
|
-
message: `${prefix} webhook listeners moved to Gateway routes. Run "openclaw doctor --fix" to preserve explicitly configured listener settings as legacyWebhook.`,
|
|
137
|
-
match: (value) => {
|
|
138
|
-
const accounts = asNullableRecord$1(asNullableRecord$1(value)?.accounts);
|
|
139
|
-
return hasLegacy(value) || Object.values(accounts ?? {}).some(hasLegacy);
|
|
140
|
-
}
|
|
141
|
-
}],
|
|
142
|
-
normalizeCompatibilityConfig: ({ cfg }) => {
|
|
143
|
-
const root = asNullableRecord$1(asNullableRecord$1(cfg.channels)?.[params.channelKey]);
|
|
144
|
-
const inherited = root && source(root);
|
|
145
|
-
const canonicalRoot = asNullableRecord$1(root?.legacyWebhook);
|
|
146
|
-
return normalizeChannelConfigEntries({
|
|
147
|
-
cfg,
|
|
148
|
-
channelId: params.channelKey,
|
|
149
|
-
normalizeEntry: ({ entry, accountId, pathPrefix, changes }) => {
|
|
150
|
-
const listener = source(entry);
|
|
151
|
-
if (!listener || !hasLegacy(entry)) return {
|
|
152
|
-
entry,
|
|
153
|
-
changed: false
|
|
154
|
-
};
|
|
155
|
-
const next = { ...entry };
|
|
156
|
-
const port = Object.hasOwn(listener, portKey) ? listener[portKey] : (accountId ? canonicalRoot?.port ?? inherited?.[portKey] : void 0) ?? params.defaultPort;
|
|
157
|
-
const inheritedHost = accountId ? canonicalRoot ? canonicalRoot.host : (hostKey ? inherited?.[hostKey] : void 0) ?? params.defaultHost : params.defaultHost;
|
|
158
|
-
const host = hostKey ? listener[hostKey] ?? inheritedHost : inheritedHost;
|
|
159
|
-
const legacyPath = [pathPrefix, params.webhookKey].filter(Boolean).join(".");
|
|
160
|
-
if (Object.hasOwn(entry, "legacyWebhook")) changes.push(`Removed ${legacyPath} legacy listener keys; ${pathPrefix}.legacyWebhook is already configured.`);
|
|
161
|
-
else if (accountId && root?.legacyWebhook === false) changes.push(`Removed ${legacyPath} legacy listener keys; ${prefix}.legacyWebhook: false keeps this account's inherited listener disabled.`);
|
|
162
|
-
else {
|
|
163
|
-
next.legacyWebhook = {
|
|
164
|
-
port,
|
|
165
|
-
...host !== void 0 ? { host } : {}
|
|
166
|
-
};
|
|
167
|
-
changes.push(`Moved ${legacyPath} listener settings to ${pathPrefix}.legacyWebhook. Point the external callback or reverse proxy at the Gateway port and webhook path, verify delivery, then set legacyWebhook: false to disable legacy forwarding.`);
|
|
168
|
-
}
|
|
169
|
-
const updated = params.webhookKey ? { ...listener } : next;
|
|
170
|
-
delete updated[portKey];
|
|
171
|
-
if (hostKey) delete updated[hostKey];
|
|
172
|
-
if (params.webhookKey) {
|
|
173
|
-
if (Object.keys(updated).length) next[params.webhookKey] = updated;
|
|
174
|
-
else delete next[params.webhookKey];
|
|
175
|
-
}
|
|
176
|
-
return {
|
|
177
|
-
entry: next,
|
|
178
|
-
changed: true
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
//#endregion
|
|
186
|
-
//#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/runtime-doctor-migrations
|
|
187
|
-
var runtime_doctor_migrations_exports = /* @__PURE__ */ __exportAll({ createLegacyWebhookListenerDoctorContract: () => createLegacyWebhookListenerDoctorContract });
|
|
188
|
-
import * as import_openclaw_plugin_sdk_runtime_doctor_migrations from "openclaw/plugin-sdk/runtime-doctor-migrations";
|
|
189
|
-
__reExport(runtime_doctor_migrations_exports, import_openclaw_plugin_sdk_runtime_doctor_migrations);
|
|
190
|
-
//#endregion
|
|
191
6
|
//#region extensions/voice-call/doctor-contract-api.ts
|
|
192
|
-
/** Read the configured voice-call store path from either package id. */
|
|
193
|
-
function getVoiceCallConfigStore(config) {
|
|
194
|
-
for (const pluginId of ["voice-call", "@openclaw/voice-call"]) {
|
|
195
|
-
const rawConfig = config.plugins?.entries?.[pluginId]?.config;
|
|
196
|
-
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) continue;
|
|
197
|
-
const store = rawConfig.store;
|
|
198
|
-
if (typeof store === "string" && store.trim()) return store.trim();
|
|
199
|
-
}
|
|
200
|
-
return "";
|
|
201
|
-
}
|
|
202
7
|
/** Return Voice Call agents whose templated core session stores need migration. */
|
|
203
8
|
function resolveSessionStoreAgentIds(params) {
|
|
204
9
|
const agentIds = /* @__PURE__ */ new Set();
|
|
@@ -216,12 +21,6 @@ function resolveSessionStoreAgentIds(params) {
|
|
|
216
21
|
}
|
|
217
22
|
return [...agentIds].toSorted();
|
|
218
23
|
}
|
|
219
|
-
/** Resolve the voice-call store path used by legacy and plugin-state call records. */
|
|
220
|
-
function resolveVoiceCallStorePath(params) {
|
|
221
|
-
const configuredStore = getVoiceCallConfigStore(params.config);
|
|
222
|
-
if (configuredStore) return resolveUserPath(configuredStore, () => params.env.HOME?.trim() || os.homedir());
|
|
223
|
-
return resolveDefaultVoiceCallStoreDir(params.env);
|
|
224
|
-
}
|
|
225
24
|
function resolveVoiceCallStateDatabaseEnv(params) {
|
|
226
25
|
return {
|
|
227
26
|
...params.env,
|
|
@@ -250,103 +49,17 @@ function describeVoiceCallSchemaMigration(migration) {
|
|
|
250
49
|
}
|
|
251
50
|
return migration.kind;
|
|
252
51
|
}
|
|
253
|
-
/** Read and prepare legacy JSONL call records, collecting line-level warnings. */
|
|
254
|
-
async function readLegacyCallRecords(filePath) {
|
|
255
|
-
let content;
|
|
256
|
-
try {
|
|
257
|
-
content = await fs$1.readFile(filePath, "utf8");
|
|
258
|
-
} catch {
|
|
259
|
-
return {
|
|
260
|
-
entries: [],
|
|
261
|
-
warnings: []
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
const entries = [];
|
|
265
|
-
const warnings = [];
|
|
266
|
-
let index = 0;
|
|
267
|
-
for (const line of content.split("\n")) {
|
|
268
|
-
const parsed = parseVoiceCallRecordLine(line, index);
|
|
269
|
-
if (!parsed) {
|
|
270
|
-
if (line.trim()) warnings.push(`Skipped malformed Voice Call call-log line ${index + 1}`);
|
|
271
|
-
index += 1;
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
try {
|
|
275
|
-
const prepared = encodeCallRecordEvent(parsed.call);
|
|
276
|
-
const chunks = Array.from({ length: prepared.meta.chunkCount }, (_, chunkIndex) => prepared.chunk(chunkIndex));
|
|
277
|
-
entries.push({
|
|
278
|
-
eventKey: buildVoiceCallLegacyJsonlEventKey(line, index),
|
|
279
|
-
lineNumber: index + 1,
|
|
280
|
-
chunks,
|
|
281
|
-
meta: {
|
|
282
|
-
...prepared.meta,
|
|
283
|
-
persistedAt: parsed.persistedAt,
|
|
284
|
-
sequence: parsed.sequence
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
} catch (err) {
|
|
288
|
-
warnings.push(`Skipped Voice Call call-log line ${index + 1}: ${String(err)}`);
|
|
289
|
-
}
|
|
290
|
-
index += 1;
|
|
291
|
-
}
|
|
292
|
-
return {
|
|
293
|
-
entries,
|
|
294
|
-
warnings
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
/** Select newest missing records that fit remaining plugin state capacity. */
|
|
298
|
-
async function selectEntriesForImport(params) {
|
|
299
|
-
const existingEventKeys = new Set((await params.eventStore.entries()).map((entry) => entry.key));
|
|
300
|
-
const missingEntries = params.entries.filter((entry) => !existingEventKeys.has(entry.eventKey));
|
|
301
|
-
const existingChunks = await params.chunkStore.entries();
|
|
302
|
-
let eventRoom = Math.max(0, MAX_CALL_RECORD_EVENTS - existingEventKeys.size);
|
|
303
|
-
let chunkRoom = Math.max(0, CALL_RECORD_CHUNK_MAX_ENTRIES - existingChunks.length);
|
|
304
|
-
const selected = [];
|
|
305
|
-
let pruned = 0;
|
|
306
|
-
for (const entry of missingEntries.toReversed()) {
|
|
307
|
-
if (eventRoom <= 0 || entry.chunks.length > chunkRoom) {
|
|
308
|
-
pruned++;
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
selected.push(entry);
|
|
312
|
-
eventRoom--;
|
|
313
|
-
chunkRoom -= entry.chunks.length;
|
|
314
|
-
}
|
|
315
|
-
if (pruned > 0) params.warnings.push(`Pruned ${pruned} older Voice Call call-log ${pruned === 1 ? "record" : "records"} during migration because plugin state keeps the newest ${MAX_CALL_RECORD_EVENTS} records`);
|
|
316
|
-
return {
|
|
317
|
-
existingEventKeys,
|
|
318
|
-
entries: selected.toReversed()
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
/** Import prepared legacy call records into plugin state. */
|
|
322
|
-
async function importLegacyCallRecords(params) {
|
|
323
|
-
const selected = await selectEntriesForImport(params);
|
|
324
|
-
let imported = 0;
|
|
325
|
-
for (const entry of selected.entries) {
|
|
326
|
-
if (selected.existingEventKeys.has(entry.eventKey)) continue;
|
|
327
|
-
try {
|
|
328
|
-
for (const chunk of entry.chunks) await params.chunkStore.register(buildChunkKey(entry.eventKey, chunk.index), chunk);
|
|
329
|
-
await params.eventStore.register(entry.eventKey, entry.meta);
|
|
330
|
-
selected.existingEventKeys.add(entry.eventKey);
|
|
331
|
-
imported++;
|
|
332
|
-
} catch (err) {
|
|
333
|
-
params.warnings.push(`Failed migrating Voice Call call-log line ${entry.lineNumber}: ${String(err)}`);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return imported;
|
|
337
|
-
}
|
|
338
52
|
/** Doctor migrations owned by the voice-call plugin. */
|
|
339
|
-
const stateMigrations = [{
|
|
340
|
-
id: "voice-call-
|
|
341
|
-
label: "Voice Call
|
|
53
|
+
const stateMigrations = [...stateMigrations$1, {
|
|
54
|
+
id: "voice-call-sqlite-schema",
|
|
55
|
+
label: "Voice Call SQLite schema",
|
|
342
56
|
async detectLegacyState(params) {
|
|
343
57
|
const storePath = resolveVoiceCallStorePath(params);
|
|
344
58
|
if (!existsSync(storePath)) return null;
|
|
345
59
|
const { detectOpenClawStateDatabaseSchemaMigrations } = await import("openclaw/plugin-sdk/doctor-repair-runtime");
|
|
346
|
-
const { entries } = await readLegacyCallRecords(resolveVoiceCallLegacyCallLogPath(storePath));
|
|
347
60
|
const schemaMigrations = detectOpenClawStateDatabaseSchemaMigrations({ env: resolveVoiceCallStateDatabaseEnv(params) });
|
|
348
|
-
if (
|
|
349
|
-
return { preview:
|
|
61
|
+
if (schemaMigrations.length === 0) return null;
|
|
62
|
+
return { preview: schemaMigrations.map((migration) => `- Voice Call SQLite schema: ${describeVoiceCallSchemaMigration(migration)}`) };
|
|
350
63
|
},
|
|
351
64
|
async migrateLegacyState(params) {
|
|
352
65
|
const changes = [];
|
|
@@ -357,9 +70,6 @@ const stateMigrations = [{
|
|
|
357
70
|
warnings
|
|
358
71
|
};
|
|
359
72
|
const { detectOpenClawStateDatabaseSchemaMigrations, repairOpenClawStateDatabaseSchema } = await import("openclaw/plugin-sdk/doctor-repair-runtime");
|
|
360
|
-
const filePath = resolveVoiceCallLegacyCallLogPath(storePath);
|
|
361
|
-
const { entries, warnings: readWarnings } = await readLegacyCallRecords(filePath);
|
|
362
|
-
warnings.push(...readWarnings);
|
|
363
73
|
const stateDatabaseEnv = resolveVoiceCallStateDatabaseEnv(params);
|
|
364
74
|
if (detectOpenClawStateDatabaseSchemaMigrations({ env: stateDatabaseEnv }).length > 0) {
|
|
365
75
|
const repaired = repairOpenClawStateDatabaseSchema({ env: stateDatabaseEnv });
|
|
@@ -370,39 +80,6 @@ const stateMigrations = [{
|
|
|
370
80
|
};
|
|
371
81
|
changes.push(...repaired.changes.map((change) => change.replace(/^Migrated shared state /, "Migrated Voice Call SQLite ").replaceAll("→", "->")));
|
|
372
82
|
}
|
|
373
|
-
if (entries.length === 0) return {
|
|
374
|
-
changes,
|
|
375
|
-
warnings
|
|
376
|
-
};
|
|
377
|
-
const env = stateDatabaseEnv;
|
|
378
|
-
const imported = await importLegacyCallRecords({
|
|
379
|
-
entries,
|
|
380
|
-
eventStore: params.context.openPluginStateKeyedStore({
|
|
381
|
-
namespace: CALL_RECORD_EVENTS_NAMESPACE,
|
|
382
|
-
maxEntries: CALL_RECORD_EVENT_META_MAX_ENTRIES,
|
|
383
|
-
env
|
|
384
|
-
}),
|
|
385
|
-
chunkStore: params.context.openPluginStateKeyedStore({
|
|
386
|
-
namespace: CALL_RECORD_EVENT_CHUNKS_NAMESPACE,
|
|
387
|
-
maxEntries: CALL_RECORD_CHUNK_MAX_ENTRIES,
|
|
388
|
-
env
|
|
389
|
-
}),
|
|
390
|
-
warnings
|
|
391
|
-
});
|
|
392
|
-
if (imported > 0) changes.push(`Migrated ${imported} Voice Call call-log ${imported === 1 ? "record" : "records"} -> plugin state`);
|
|
393
|
-
if (warnings.some((warning) => warning.startsWith("Failed migrating Voice Call") || warning.startsWith("Skipped malformed Voice Call call-log line") || warning.startsWith("Skipped Voice Call call-log line") || warning.startsWith("Skipped Voice Call call-log migration"))) {
|
|
394
|
-
warnings.push("Left Voice Call call-log source in place because migration was incomplete");
|
|
395
|
-
return {
|
|
396
|
-
changes,
|
|
397
|
-
warnings
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
await (0, runtime_doctor_migrations_exports.archiveLegacyStateSource)({
|
|
401
|
-
filePath,
|
|
402
|
-
label: "Voice Call call-log",
|
|
403
|
-
changes,
|
|
404
|
-
warnings
|
|
405
|
-
});
|
|
406
83
|
return {
|
|
407
84
|
changes,
|
|
408
85
|
warnings
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { definePluginEntry } from "./api.js";
|
|
2
2
|
import { VOICE_CALL_CLI_DESCRIPTOR } from "./cli-output-mode.js";
|
|
3
|
-
import { i as resolveVoiceCallConfig, t as VoiceCallConfigSchema, u as validateProviderConfig } from "./.setup/config-
|
|
4
|
-
import { t as createVoiceCallRuntime } from "./.setup/runtime-entry-
|
|
3
|
+
import { i as resolveVoiceCallConfig, t as VoiceCallConfigSchema, u as validateProviderConfig } from "./.setup/config-CX9J-053.mjs";
|
|
4
|
+
import { t as createVoiceCallRuntime } from "./.setup/runtime-entry-CbSKxSKk.mjs";
|
|
5
5
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
6
6
|
import { ErrorCodes, errorShape } from "openclaw/plugin-sdk/gateway-runtime";
|
|
7
7
|
import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
|
|
8
8
|
import { normalizeAgentId, parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
9
|
+
import { resolvePluginServiceScheduler } from "openclaw/plugin-sdk/runtime";
|
|
9
10
|
import { asNonArrayRecord, asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
10
11
|
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
|
|
11
12
|
import { Type } from "typebox";
|
|
@@ -140,11 +141,6 @@ function createVoiceCallContinueOperationStore(params) {
|
|
|
140
141
|
const ttsTimeoutMs = rt.config.tts?.timeoutMs ?? params.config.tts?.timeoutMs ?? params.coreConfig.tts?.timeoutMs ?? 8e3;
|
|
141
142
|
return resolveTimerTimeoutMs((rt.config.transcriptTimeoutMs ?? params.config.transcriptTimeoutMs) + ttsTimeoutMs + VOICE_CALL_CONTINUE_OPERATION_BUFFER_MS, VOICE_CALL_CONTINUE_OPERATION_BUFFER_MS);
|
|
142
143
|
};
|
|
143
|
-
const scheduleCleanup = (operationId) => {
|
|
144
|
-
setTimeout(() => {
|
|
145
|
-
operations.delete(operationId);
|
|
146
|
-
}, VOICE_CALL_CONTINUE_OPERATION_CLEANUP_MS).unref?.();
|
|
147
|
-
};
|
|
148
144
|
const start = (request) => {
|
|
149
145
|
const operationId = randomUUID();
|
|
150
146
|
const pollTimeoutMs = resolvePollTimeoutMs(request.rt);
|
|
@@ -154,8 +150,6 @@ function createVoiceCallContinueOperationStore(params) {
|
|
|
154
150
|
pollTimeoutMs
|
|
155
151
|
});
|
|
156
152
|
request.run().then((result) => {
|
|
157
|
-
const current = operations.get(operationId);
|
|
158
|
-
if (!current || current.status !== "pending") return;
|
|
159
153
|
operations.set(operationId, {
|
|
160
154
|
operationId,
|
|
161
155
|
status: "completed",
|
|
@@ -165,15 +159,15 @@ function createVoiceCallContinueOperationStore(params) {
|
|
|
165
159
|
}
|
|
166
160
|
});
|
|
167
161
|
}).catch((err) => {
|
|
168
|
-
const current = operations.get(operationId);
|
|
169
|
-
if (!current || current.status !== "pending") return;
|
|
170
162
|
operations.set(operationId, {
|
|
171
163
|
operationId,
|
|
172
164
|
status: "failed",
|
|
173
165
|
error: formatErrorMessage(err)
|
|
174
166
|
});
|
|
175
167
|
}).finally(() => {
|
|
176
|
-
|
|
168
|
+
setTimeout(() => {
|
|
169
|
+
operations.delete(operationId);
|
|
170
|
+
}, VOICE_CALL_CONTINUE_OPERATION_CLEANUP_MS).unref?.();
|
|
177
171
|
});
|
|
178
172
|
return {
|
|
179
173
|
operationId,
|
|
@@ -338,10 +332,13 @@ var voice_call_default = definePluginEntry({
|
|
|
338
332
|
};
|
|
339
333
|
return createdRuntime;
|
|
340
334
|
}
|
|
335
|
+
const scheduler = runtimeGeneration.scheduler;
|
|
336
|
+
if (!scheduler || scheduler.signal.aborted) throw new VoiceCallRuntimeLifecycleError("Voice call service is not running; start the Gateway and retry");
|
|
341
337
|
const startingSlot = {
|
|
342
338
|
state: "starting",
|
|
343
339
|
owner: runtimeGeneration,
|
|
344
340
|
promise: createVoiceCallRuntime({
|
|
341
|
+
scheduler,
|
|
345
342
|
config,
|
|
346
343
|
coreConfig: api.config,
|
|
347
344
|
fullConfig: api.config,
|
|
@@ -478,14 +475,16 @@ var voice_call_default = definePluginEntry({
|
|
|
478
475
|
}
|
|
479
476
|
}));
|
|
480
477
|
api.registerCli(async ({ program }) => {
|
|
481
|
-
const { registerVoiceCallCli } = await import("./.setup/cli-
|
|
478
|
+
const { registerVoiceCallCli } = await import("./.setup/cli-Cn1leykM.mjs");
|
|
482
479
|
registerVoiceCallCli({
|
|
483
480
|
program,
|
|
484
481
|
config,
|
|
485
482
|
coreConfig: api.config,
|
|
486
|
-
ensureRuntime
|
|
487
|
-
|
|
488
|
-
|
|
483
|
+
ensureRuntime: () => {
|
|
484
|
+
runtimeRegistration.generation.scheduler = resolvePluginServiceScheduler();
|
|
485
|
+
return ensureRuntime();
|
|
486
|
+
},
|
|
487
|
+
stateRuntime: api.runtime.state
|
|
489
488
|
});
|
|
490
489
|
}, {
|
|
491
490
|
commands: ["voicecall"],
|
|
@@ -493,6 +492,7 @@ var voice_call_default = definePluginEntry({
|
|
|
493
492
|
});
|
|
494
493
|
api.registerService({
|
|
495
494
|
id: "voicecall",
|
|
495
|
+
apiVersion: 2,
|
|
496
496
|
start: (ctx) => {
|
|
497
497
|
if (isCliOnlyProcess()) return;
|
|
498
498
|
try {
|
|
@@ -500,6 +500,7 @@ var voice_call_default = definePluginEntry({
|
|
|
500
500
|
if (runtimeCoordinator.current !== runtimeRegistration) throw new VoiceCallRuntimeLifecycleError("Voice call runtime generation was superseded; use the current plugin registration");
|
|
501
501
|
runtimeRegistration.generation = { retired: false };
|
|
502
502
|
}
|
|
503
|
+
runtimeRegistration.generation.scheduler = ctx.scheduler;
|
|
503
504
|
runtimeRegistration.generation.serviceHealth = ctx.serviceHealth;
|
|
504
505
|
activateRuntimeGeneration(runtimeRegistration.generation);
|
|
505
506
|
} catch (err) {
|
|
@@ -527,6 +528,7 @@ var voice_call_default = definePluginEntry({
|
|
|
527
528
|
try {
|
|
528
529
|
await stopVoiceCallRuntimeGeneration(runtimeCoordinator, runtimeGeneration);
|
|
529
530
|
} finally {
|
|
531
|
+
runtimeGeneration.scheduler = void 0;
|
|
530
532
|
runtimeGeneration.serviceHealth = void 0;
|
|
531
533
|
}
|
|
532
534
|
}
|
package/dist/runtime-entry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createVoiceCallRuntime } from "./.setup/runtime-entry-
|
|
1
|
+
import { t as createVoiceCallRuntime } from "./.setup/runtime-entry-CbSKxSKk.mjs";
|
|
2
2
|
export { createVoiceCallRuntime };
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"categories": ["voice"],
|
|
4
4
|
"doctorContract": {
|
|
5
5
|
"resolveSessionStoreAgentIds": true,
|
|
6
|
-
"stateMigrations": [{ "id": "voice-call-calls-jsonl-to-plugin-state" }]
|
|
6
|
+
"stateMigrations": [{ "id": "voice-call-calls-jsonl-to-plugin-state" }, { "id": "voice-call-sqlite-schema" }]
|
|
7
7
|
},
|
|
8
8
|
"name": "Voice Call",
|
|
9
9
|
"description": "OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/voice-call",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.10.1-beta.2",
|
|
4
4
|
"description": "OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
"type": "module",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"typebox": "1.3.34",
|
|
12
|
-
"ws": "8.21.3",
|
|
13
12
|
"zod": "4.6.5"
|
|
14
13
|
},
|
|
15
14
|
"peerDependencies": {
|
|
16
|
-
"openclaw": ">=2026.
|
|
15
|
+
"openclaw": ">=2026.10.1-beta.2"
|
|
17
16
|
},
|
|
18
17
|
"peerDependenciesMeta": {
|
|
19
18
|
"openclaw": {
|
|
@@ -32,10 +31,10 @@
|
|
|
32
31
|
"minHostVersion": ">=2026.4.10"
|
|
33
32
|
},
|
|
34
33
|
"compat": {
|
|
35
|
-
"pluginApi": ">=2026.
|
|
34
|
+
"pluginApi": ">=2026.10.1-beta.2"
|
|
36
35
|
},
|
|
37
36
|
"build": {
|
|
38
|
-
"openclawVersion": "2026.
|
|
37
|
+
"openclawVersion": "2026.10.1-beta.2"
|
|
39
38
|
},
|
|
40
39
|
"release": {
|
|
41
40
|
"publishToClawHub": true,
|
|
@@ -56,7 +55,6 @@
|
|
|
56
55
|
],
|
|
57
56
|
"bundledDependencies": [
|
|
58
57
|
"typebox",
|
|
59
|
-
"ws",
|
|
60
58
|
"zod"
|
|
61
59
|
]
|
|
62
60
|
}
|