@openclaw/voice-call 2026.5.30-beta.1 → 2026.5.31-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.
@@ -433,7 +433,7 @@ function normalizePhoneRouteKey(phone) {
433
433
  function resolveVoiceCallNumberRouteKey(config, phone) {
434
434
  const routes = config.numbers;
435
435
  if (!routes) return;
436
- if (phone && Object.prototype.hasOwnProperty.call(routes, phone)) return phone;
436
+ if (phone && Object.hasOwn(routes, phone)) return phone;
437
437
  const normalizedPhone = normalizePhoneRouteKey(phone);
438
438
  if (!normalizedPhone) return;
439
439
  return Object.keys(routes).find((routeKey) => normalizePhoneRouteKey(routeKey) === normalizedPhone);
@@ -1,4 +1,4 @@
1
- import { t as VoiceCallConfigSchema } from "./config-U-rgixyY.js";
1
+ import { t as VoiceCallConfigSchema } from "./config-BKyRNKHF.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";
@@ -61,7 +61,7 @@ function collectVoiceCallLegacyConfigIssues(value) {
61
61
  replacement: "streaming.providers.openai.vadThreshold",
62
62
  message: "Move streaming.vadThreshold to streaming.providers.openai.vadThreshold."
63
63
  });
64
- if (realtimeAgentContext && Object.prototype.hasOwnProperty.call(realtimeAgentContext, "includeSystemPrompt")) issues.push({
64
+ if (realtimeAgentContext && Object.hasOwn(realtimeAgentContext, "includeSystemPrompt")) issues.push({
65
65
  path: "realtime.agentContext.includeSystemPrompt",
66
66
  replacement: "realtime.agentContext",
67
67
  message: "Remove realtime.agentContext.includeSystemPrompt; realtime context now uses the generated agent prompt."
@@ -130,7 +130,7 @@ function migrateVoiceCallLegacyConfigInput(params) {
130
130
  else if (typeof streaming?.silenceDurationMs === "number") changes.push(`Removed invalid ${configPathPrefix}.streaming.silenceDurationMs.`);
131
131
  if (getNumber(streaming, "vadThreshold") !== void 0) changes.push(`Moved ${configPathPrefix}.streaming.vadThreshold → ${configPathPrefix}.streaming.providers.openai.vadThreshold.`);
132
132
  else if (typeof streaming?.vadThreshold === "number") changes.push(`Removed invalid ${configPathPrefix}.streaming.vadThreshold.`);
133
- if (realtimeAgentContext && Object.prototype.hasOwnProperty.call(realtimeAgentContext, "includeSystemPrompt")) changes.push(`Removed ${configPathPrefix}.realtime.agentContext.includeSystemPrompt.`);
133
+ if (realtimeAgentContext && Object.hasOwn(realtimeAgentContext, "includeSystemPrompt")) changes.push(`Removed ${configPathPrefix}.realtime.agentContext.includeSystemPrompt.`);
134
134
  return {
135
135
  config,
136
136
  changes,
@@ -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-CDCNtGtn.js";
3
+ import { a as getHeader } from "./runtime-entry-DXf7kdXt.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,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-U-rgixyY.js";
4
- import { c as getTailscaleSelfInfo, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-CDCNtGtn.js";
5
- import { i as parseVoiceCallPluginConfig, r as normalizeVoiceCallLegacyConfigInput, t as formatVoiceCallLegacyConfigWarnings } from "./config-compat-CokN3Zzr.js";
3
+ import { i as resolveVoiceCallConfig, s as validateProviderConfig } from "./config-BKyRNKHF.js";
4
+ import { _ as setVoiceCallStateRuntime, c as getTailscaleSelfInfo, g as getCallHistoryFromStore, l as setupTailscaleExposureRoute, o as resolveWebhookExposureStatus, p as resolveUserPath, s as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime } from "./runtime-entry-DXf7kdXt.js";
5
+ import { i as parseVoiceCallPluginConfig, r as normalizeVoiceCallLegacyConfigInput, t as formatVoiceCallLegacyConfigWarnings } from "./config-compat-BLdRz9GR.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 { MAX_TCP_PORT, MAX_TIMER_TIMEOUT_MS, addTimerTimeoutGraceMs, clampTimerTimeoutMs, parseStrictNonNegativeInteger, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
8
+ import { MAX_TCP_PORT, MAX_TIMER_TIMEOUT_MS, addTimerTimeoutGraceMs, clampTimerTimeoutMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
9
9
  import { isRecord, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
10
10
  import { Type } from "typebox";
11
11
  import fs from "node:fs";
@@ -70,7 +70,7 @@ function readGatewayOperationId(payload) {
70
70
  throw new Error("voicecall gateway response missing operationId");
71
71
  }
72
72
  function readGatewayPollTimeoutMs(payload, fallbackTimeoutMs) {
73
- if (isRecord(payload) && typeof payload.pollTimeoutMs === "number") return Math.max(1, Math.ceil(payload.pollTimeoutMs));
73
+ if (isRecord(payload) && typeof payload.pollTimeoutMs === "number") return clampTimerTimeoutMs(payload.pollTimeoutMs) ?? fallbackTimeoutMs;
74
74
  return fallbackTimeoutMs;
75
75
  }
76
76
  function readCompletedContinueResult(payload) {
@@ -221,7 +221,10 @@ async function initiateCallViaGatewayOrRuntime(params) {
221
221
  });
222
222
  }
223
223
  function registerVoiceCallCli(params) {
224
- const { program, config, ensureRuntime, logger } = params;
224
+ const { program, config, ensureRuntime, stateRuntime } = params;
225
+ const ensureHistoryStateRuntime = () => {
226
+ if (stateRuntime) setVoiceCallStateRuntime({ state: stateRuntime });
227
+ };
225
228
  const root = program.command("voicecall").description("Voice call utilities").addHelpText("after", () => `\nDocs: https://docs.openclaw.ai/cli/voicecall\n`);
226
229
  root.command("setup").description("Show Voice Call provider and webhook setup status").option("--json", "Print machine-readable JSON").action((options) => {
227
230
  const status = buildSetupStatus(config);
@@ -411,54 +414,81 @@ function registerVoiceCallCli(params) {
411
414
  const file = options.file;
412
415
  const since = parseVoiceCallIntOption(options.since, "--since", { min: 0 });
413
416
  const pollMs = parseVoiceCallIntOption(options.poll, "--poll", { min: 50 });
414
- if (!fs.existsSync(file)) {
415
- logger.error(`No log file at ${file}`);
416
- process.exit(1);
417
- }
418
- const initial = fs.readFileSync(file, "utf8");
419
- const lines = initial.split("\n").filter(Boolean);
420
- for (const line of lines.slice(Math.max(0, lines.length - since))) writeStdoutLine(line);
421
- let offset = Buffer.byteLength(initial, "utf8");
422
- for (;;) {
423
- try {
424
- const stat = fs.statSync(file);
425
- if (stat.size < offset) offset = 0;
426
- if (stat.size > offset) {
427
- const fd = fs.openSync(file, "r");
428
- try {
429
- const buf = Buffer.alloc(stat.size - offset);
430
- fs.readSync(fd, buf, 0, buf.length, offset);
431
- offset = stat.size;
432
- const text = buf.toString("utf8");
433
- for (const line of text.split("\n").filter(Boolean)) writeStdoutLine(line);
434
- } finally {
435
- fs.closeSync(fd);
436
- }
417
+ const tailSqliteHistory = async (initialLimit) => {
418
+ ensureHistoryStateRuntime();
419
+ const seen = /* @__PURE__ */ new Set();
420
+ const printCall = (call) => {
421
+ const line = JSON.stringify(call);
422
+ if (!seen.has(line)) {
423
+ seen.add(line);
424
+ writeStdoutLine(line);
437
425
  }
438
- } catch {}
439
- await sleep(pollMs);
440
- }
426
+ };
427
+ if (initialLimit > 0) for (const call of await getCallHistoryFromStore(path.dirname(file), initialLimit)) printCall(call);
428
+ for (;;) {
429
+ try {
430
+ for (const call of await getCallHistoryFromStore(path.dirname(file), 1e3)) printCall(call);
431
+ } catch {}
432
+ await sleep(pollMs);
433
+ }
434
+ };
435
+ if (fs.existsSync(file) && path.basename(file) !== "calls.jsonl") {
436
+ const initial = fs.readFileSync(file, "utf8");
437
+ const lines = initial.split("\n").filter(Boolean);
438
+ for (const line of lines.slice(Math.max(0, lines.length - since))) writeStdoutLine(line);
439
+ let offset = Buffer.byteLength(initial, "utf8");
440
+ for (;;) {
441
+ try {
442
+ const stat = fs.statSync(file);
443
+ if (stat.size < offset) offset = 0;
444
+ if (stat.size > offset) {
445
+ const fd = fs.openSync(file, "r");
446
+ try {
447
+ const buf = Buffer.alloc(stat.size - offset);
448
+ fs.readSync(fd, buf, 0, buf.length, offset);
449
+ offset = stat.size;
450
+ const text = buf.toString("utf8");
451
+ for (const line of text.split("\n").filter(Boolean)) writeStdoutLine(line);
452
+ } finally {
453
+ fs.closeSync(fd);
454
+ }
455
+ }
456
+ } catch {}
457
+ await sleep(pollMs);
458
+ }
459
+ } else await tailSqliteHistory(since);
441
460
  });
442
461
  root.command("latency").description("Summarize turn latency metrics from voice-call JSONL logs").option("--file <path>", "Path to calls.jsonl", resolveDefaultStorePath(config)).option("--last <n>", "Analyze last N records", "200").action(async (options) => {
443
462
  const file = options.file;
444
463
  const last = parseVoiceCallIntOption(options.last, "--last", { min: 1 });
445
- if (!fs.existsSync(file)) throw new Error("No log file at " + file);
446
- const lines = fs.readFileSync(file, "utf8").split("\n").filter(Boolean).slice(-last);
464
+ if (fs.existsSync(file) && path.basename(file) !== "calls.jsonl") writeVoiceCallLatencySummary(fs.readFileSync(file, "utf8").split("\n").filter(Boolean).slice(-last).map((line) => {
465
+ try {
466
+ const parsed = JSON.parse(line);
467
+ return parsed.call ?? parsed;
468
+ } catch {
469
+ return null;
470
+ }
471
+ }).filter((call) => call !== null));
472
+ else {
473
+ ensureHistoryStateRuntime();
474
+ writeVoiceCallLatencySummary(await getCallHistoryFromStore(path.dirname(file), last));
475
+ }
476
+ });
477
+ function writeVoiceCallLatencySummary(calls) {
447
478
  const turnLatencyMs = [];
448
479
  const listenWaitMs = [];
449
- for (const line of lines) try {
450
- const parsed = JSON.parse(line);
451
- const latency = parsed.metadata?.lastTurnLatencyMs;
452
- const listenWait = parsed.metadata?.lastTurnListenWaitMs;
480
+ for (const call of calls) {
481
+ const latency = call.metadata?.lastTurnLatencyMs;
482
+ const listenWait = call.metadata?.lastTurnListenWaitMs;
453
483
  if (typeof latency === "number" && Number.isFinite(latency)) turnLatencyMs.push(latency);
454
484
  if (typeof listenWait === "number" && Number.isFinite(listenWait)) listenWaitMs.push(listenWait);
455
- } catch {}
485
+ }
456
486
  writeStdoutJson({
457
- recordsScanned: lines.length,
487
+ recordsScanned: calls.length,
458
488
  turnLatency: summarizeSeries(turnLatencyMs),
459
489
  listenWait: summarizeSeries(listenWaitMs)
460
490
  });
461
- });
491
+ }
462
492
  root.command("expose").description("Enable/disable Tailscale serve/funnel for the webhook").option("--mode <mode>", "off | serve (tailnet) | funnel (public)", "funnel").option("--path <path>", "Tailscale path to expose (recommend matching serve.path)").option("--port <port>", "Local webhook port").option("--serve-path <path>", "Local webhook path").action(async (options) => {
463
493
  const mode = resolveMode(options.mode ?? "funnel");
464
494
  const servePort = parseVoiceCallIntOption(options.port ?? String(config.serve.port ?? 3334), "--port", {
@@ -512,7 +542,7 @@ function createVoiceCallContinueOperationStore(params) {
512
542
  const operations = /* @__PURE__ */ new Map();
513
543
  const resolvePollTimeoutMs = (rt) => {
514
544
  const ttsTimeoutMs = rt.config.tts?.timeoutMs ?? params.config.tts?.timeoutMs ?? params.coreConfig.messages?.tts?.timeoutMs ?? 8e3;
515
- return (rt.config.transcriptTimeoutMs ?? params.config.transcriptTimeoutMs) + ttsTimeoutMs + VOICE_CALL_CONTINUE_OPERATION_BUFFER_MS;
545
+ return resolveTimerTimeoutMs((rt.config.transcriptTimeoutMs ?? params.config.transcriptTimeoutMs) + ttsTimeoutMs + VOICE_CALL_CONTINUE_OPERATION_BUFFER_MS, VOICE_CALL_CONTINUE_OPERATION_BUFFER_MS);
516
546
  };
517
547
  const scheduleCleanup = (operationId) => {
518
548
  setTimeout(() => {
@@ -928,6 +958,7 @@ var voice_call_default = definePluginEntry({
928
958
  coreConfig: api.config,
929
959
  fullConfig: api.config,
930
960
  agentRuntime: api.runtime.agent,
961
+ stateRuntime: api.runtime.state,
931
962
  ttsRuntime: api.runtime.tts,
932
963
  logger: api.logger
933
964
  });
@@ -1300,6 +1331,7 @@ var voice_call_default = definePluginEntry({
1300
1331
  program,
1301
1332
  config,
1302
1333
  ensureRuntime,
1334
+ stateRuntime: api.runtime.state,
1303
1335
  logger: api.logger
1304
1336
  }), { commands: ["voicecall"] });
1305
1337
  api.registerService({
@@ -1,5 +1,5 @@
1
- import { a as getHeader, m as escapeXml } from "./runtime-entry-CDCNtGtn.js";
2
- import { n as reconstructWebhookUrl, r as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-BeaXjPdi.js";
1
+ import { a as getHeader, m as escapeXml } from "./runtime-entry-DXf7kdXt.js";
2
+ import { n as reconstructWebhookUrl, r as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-mCcsLRBb.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
@@ -100,8 +100,8 @@ var RealtimeAudioPacer = class {
100
100
  function calculateMulawRms(muLaw) {
101
101
  if (muLaw.length === 0) return 0;
102
102
  let sum = 0;
103
- for (let i = 0; i < muLaw.length; i += 1) {
104
- const normalized = (MULAW_LINEAR_SAMPLES[muLaw[i] ?? 0] ?? 0) / PCM16_MAX_AMPLITUDE;
103
+ for (const sample of muLaw) {
104
+ const normalized = (MULAW_LINEAR_SAMPLES[sample] ?? 0) / PCM16_MAX_AMPLITUDE;
105
105
  sum += normalized * normalized;
106
106
  }
107
107
  return Math.sqrt(sum / muLaw.length);
@@ -1,5 +1,5 @@
1
- import { o as resolveVoiceCallSessionKey } from "./config-U-rgixyY.js";
2
- import { f as resolveVoiceResponseModel } from "./runtime-entry-CDCNtGtn.js";
1
+ import { o as resolveVoiceCallSessionKey } from "./config-BKyRNKHF.js";
2
+ import { f as resolveVoiceResponseModel } from "./runtime-entry-DXf7kdXt.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";
@@ -1,6 +1,6 @@
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-U-rgixyY.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-BKyRNKHF.js";
4
4
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
5
5
  import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
6
6
  import { MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
@@ -10,8 +10,9 @@ import { z } from "zod";
10
10
  import fs from "node:fs";
11
11
  import os from "node:os";
12
12
  import path from "node:path";
13
- import crypto from "node:crypto";
13
+ import crypto, { createHash, randomUUID } from "node:crypto";
14
14
  import { appendRegularFile, privateFileStore, privateFileStoreSync, root } from "openclaw/plugin-sdk/security-runtime";
15
+ import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
15
16
  import { parseTtsDirectives } from "openclaw/plugin-sdk/speech";
16
17
  import { spawn } from "node:child_process";
17
18
  import http from "node:http";
@@ -180,12 +181,224 @@ function addTranscriptEntry(call, speaker, text) {
180
181
  call.transcript.push(entry);
181
182
  }
182
183
  //#endregion
184
+ //#region extensions/voice-call/src/runtime-state.ts
185
+ const { setRuntime: setVoiceCallStateRuntime, clearRuntime: clearVoiceCallStateRuntime, tryGetRuntime: getOptionalVoiceCallStateRuntime } = createPluginRuntimeStore({
186
+ pluginId: "voice-call-state",
187
+ errorMessage: "Voice Call state runtime not initialized"
188
+ });
189
+ //#endregion
183
190
  //#region extensions/voice-call/src/manager/store.ts
184
191
  const pendingPersistWrites = /* @__PURE__ */ new Set();
192
+ const CALL_RECORD_EVENTS_NAMESPACE = "call-record-events";
193
+ const CALL_RECORD_EVENT_CHUNKS_NAMESPACE = "call-record-event-chunks";
194
+ const CALL_RECORD_MIGRATIONS_NAMESPACE = "call-record-migrations";
195
+ const CALL_RECORD_JSONL_MIGRATION_KEY = "calls-jsonl-v1";
196
+ const MAX_CALL_RECORD_EVENTS = 1e3;
197
+ const CALL_RECORD_EVENT_META_MAX_ENTRIES = 1100;
198
+ const MAX_CHUNKS_PER_CALL_RECORD_EVENT = 48;
199
+ const CALL_RECORD_CHUNK_MAX_ENTRIES = 48048;
200
+ const RAW_CHUNK_BYTES = 36 * 1024;
201
+ let callRecordEventSequence = 0;
202
+ function resolveCallLogPath(storePath) {
203
+ return path.join(storePath, "calls.jsonl");
204
+ }
205
+ function resolvePluginStateEnv(storePath) {
206
+ return {
207
+ ...process.env,
208
+ OPENCLAW_STATE_DIR: storePath
209
+ };
210
+ }
211
+ function createCallRecordStateStores(storePath) {
212
+ const runtime = getOptionalVoiceCallStateRuntime();
213
+ if (!runtime) return null;
214
+ const env = resolvePluginStateEnv(storePath);
215
+ return {
216
+ events: runtime.state.openSyncKeyedStore({
217
+ namespace: CALL_RECORD_EVENTS_NAMESPACE,
218
+ maxEntries: CALL_RECORD_EVENT_META_MAX_ENTRIES,
219
+ env
220
+ }),
221
+ chunks: runtime.state.openSyncKeyedStore({
222
+ namespace: CALL_RECORD_EVENT_CHUNKS_NAMESPACE,
223
+ maxEntries: CALL_RECORD_CHUNK_MAX_ENTRIES,
224
+ env
225
+ }),
226
+ migrations: runtime.state.openSyncKeyedStore({
227
+ namespace: CALL_RECORD_MIGRATIONS_NAMESPACE,
228
+ maxEntries: 100,
229
+ env
230
+ })
231
+ };
232
+ }
233
+ function tryCreateCallRecordStateStores(storePath) {
234
+ try {
235
+ return createCallRecordStateStores(storePath);
236
+ } catch (err) {
237
+ console.error("[voice-call] Failed to open SQLite call record store:", err);
238
+ return null;
239
+ }
240
+ }
241
+ function buildChunkKey(eventKey, index) {
242
+ return `${eventKey}:chunk:${String(index).padStart(4, "0")}`;
243
+ }
244
+ function buildJsonlEventKey(line, index) {
245
+ return `jsonl:${String(index).padStart(8, "0")}:${createHash("sha256").update(line).digest("hex")}`;
246
+ }
247
+ function nextCallRecordOrder() {
248
+ const sequence = callRecordEventSequence;
249
+ callRecordEventSequence = (callRecordEventSequence + 1) % 1e6;
250
+ return {
251
+ persistedAt: Date.now(),
252
+ sequence
253
+ };
254
+ }
255
+ function buildNewEventKey(order) {
256
+ return `event:${order.persistedAt.toString(36)}:${String(order.sequence).padStart(6, "0")}:${randomUUID()}`;
257
+ }
258
+ function parseEventKeySequence(key) {
259
+ const match = /^event:[^:]+:(\d+):/.exec(key);
260
+ return match ? Number.parseInt(match[1], 10) : 0;
261
+ }
262
+ function parseCallRecordLine(line, sequence = 0) {
263
+ if (!line.trim()) return null;
264
+ try {
265
+ const parsed = JSON.parse(line);
266
+ if (parsed && typeof parsed === "object" && parsed.version === 2) {
267
+ const envelope = parsed;
268
+ return {
269
+ call: CallRecordSchema.parse(envelope.call),
270
+ persistedAt: typeof envelope.persistedAt === "number" && Number.isFinite(envelope.persistedAt) ? envelope.persistedAt : 0,
271
+ sequence: typeof envelope.sequence === "number" && Number.isFinite(envelope.sequence) ? envelope.sequence : sequence,
272
+ orderKey: ""
273
+ };
274
+ }
275
+ return {
276
+ call: CallRecordSchema.parse(parsed),
277
+ persistedAt: 0,
278
+ sequence,
279
+ orderKey: ""
280
+ };
281
+ } catch {
282
+ return null;
283
+ }
284
+ }
285
+ function registerCallRecordEvent(stores, eventKey, call, order) {
286
+ const serialized = JSON.stringify(call);
287
+ const buffer = Buffer.from(serialized, "utf8");
288
+ const chunkCount = Math.max(1, Math.ceil(buffer.byteLength / RAW_CHUNK_BYTES));
289
+ if (chunkCount > MAX_CHUNKS_PER_CALL_RECORD_EVENT) throw new Error(`voice-call record exceeds SQLite chunk limit (${chunkCount}/${MAX_CHUNKS_PER_CALL_RECORD_EVENT})`);
290
+ for (let index = 0; index < chunkCount; index += 1) {
291
+ const chunk = buffer.subarray(index * RAW_CHUNK_BYTES, (index + 1) * RAW_CHUNK_BYTES);
292
+ stores.chunks.register(buildChunkKey(eventKey, index), {
293
+ index,
294
+ dataBase64: chunk.toString("base64")
295
+ });
296
+ }
297
+ stores.events.register(eventKey, {
298
+ chunkCount,
299
+ byteLength: buffer.byteLength,
300
+ persistedAt: order?.persistedAt,
301
+ sequence: order?.sequence
302
+ });
303
+ pruneCallRecordEvents(stores);
304
+ }
305
+ function deleteCallRecordEventRows(stores, eventKey) {
306
+ const meta = stores.events.lookup(eventKey);
307
+ stores.events.delete(eventKey);
308
+ if (!meta) return;
309
+ for (let index = 0; index < meta.chunkCount; index += 1) stores.chunks.delete(buildChunkKey(eventKey, index));
310
+ }
311
+ function pruneCallRecordEvents(stores) {
312
+ const rows = stores.events.entries();
313
+ if (rows.length <= MAX_CALL_RECORD_EVENTS) return;
314
+ const sorted = rows.toSorted((a, b) => a.createdAt - b.createdAt || a.key.localeCompare(b.key));
315
+ for (const row of sorted.slice(0, rows.length - MAX_CALL_RECORD_EVENTS)) deleteCallRecordEventRows(stores, row.key);
316
+ }
317
+ function registerCallRecordEventIfAbsent(stores, eventKey, record) {
318
+ if (!stores.events.lookup(eventKey)) registerCallRecordEvent(stores, eventKey, record.call, {
319
+ persistedAt: record.persistedAt,
320
+ sequence: record.sequence
321
+ });
322
+ }
323
+ function readCallRecordEvent(stores, eventKey) {
324
+ const meta = stores.events.lookup(eventKey);
325
+ if (!meta) return null;
326
+ const chunks = [];
327
+ for (let index = 0; index < meta.chunkCount; index += 1) {
328
+ const chunk = stores.chunks.lookup(buildChunkKey(eventKey, index));
329
+ if (!chunk || chunk.index !== index) return null;
330
+ chunks.push(Buffer.from(chunk.dataBase64, "base64"));
331
+ }
332
+ return parseCallRecordLine(Buffer.concat(chunks, meta.byteLength).toString("utf8"))?.call ?? null;
333
+ }
334
+ function ensureLegacyCallLogImported(storePath, stores) {
335
+ const imported = stores.migrations.lookup(CALL_RECORD_JSONL_MIGRATION_KEY) !== void 0;
336
+ const logPath = resolveCallLogPath(storePath);
337
+ const content = privateFileStoreSync(storePath).readTextIfExists(path.basename(logPath));
338
+ if (content === null) {
339
+ if (!imported) stores.migrations.register(CALL_RECORD_JSONL_MIGRATION_KEY, { importedAt: (/* @__PURE__ */ new Date()).toISOString() });
340
+ return [];
341
+ }
342
+ const fallbackCalls = [];
343
+ {
344
+ let index = 0;
345
+ let importFailed = false;
346
+ for (const line of content.split("\n")) {
347
+ const parsed = parseCallRecordLine(line, index);
348
+ if (!parsed) {
349
+ index += 1;
350
+ continue;
351
+ }
352
+ try {
353
+ registerCallRecordEventIfAbsent(stores, buildJsonlEventKey(line, index), parsed);
354
+ } catch (err) {
355
+ importFailed = true;
356
+ fallbackCalls.push({
357
+ ...parsed,
358
+ orderKey: `jsonl:${String(index).padStart(8, "0")}`
359
+ });
360
+ console.error("[voice-call] Failed to import persisted call record:", err);
361
+ }
362
+ index += 1;
363
+ }
364
+ if (!importFailed) try {
365
+ fs.rmSync(logPath, { force: true });
366
+ } catch {}
367
+ }
368
+ if (!imported) stores.migrations.register(CALL_RECORD_JSONL_MIGRATION_KEY, { importedAt: (/* @__PURE__ */ new Date()).toISOString() });
369
+ return fallbackCalls;
370
+ }
371
+ function readCallRecordEvents(storePath, stores) {
372
+ const fallbackCalls = ensureLegacyCallLogImported(storePath, stores);
373
+ return [...stores.events.entries().toSorted((a, b) => a.createdAt - b.createdAt || a.key.localeCompare(b.key)).map((entry) => {
374
+ const call = readCallRecordEvent(stores, entry.key);
375
+ return call ? {
376
+ call,
377
+ persistedAt: entry.value.persistedAt ?? entry.createdAt,
378
+ sequence: entry.value.sequence ?? parseEventKeySequence(entry.key),
379
+ orderKey: entry.key
380
+ } : null;
381
+ }).filter((entry) => entry !== null), ...fallbackCalls].toSorted((a, b) => a.persistedAt - b.persistedAt || a.sequence - b.sequence || a.orderKey.localeCompare(b.orderKey)).map((entry) => entry.call);
382
+ }
185
383
  function persistCallRecord(storePath, call) {
384
+ const stores = tryCreateCallRecordStateStores(storePath);
385
+ if (stores) try {
386
+ ensureLegacyCallLogImported(storePath, stores);
387
+ const order = nextCallRecordOrder();
388
+ registerCallRecordEvent(stores, buildNewEventKey(order), call, order);
389
+ return;
390
+ } catch (err) {
391
+ console.error("[voice-call] Failed to persist call record:", err);
392
+ }
393
+ const logPath = resolveCallLogPath(storePath);
394
+ const order = nextCallRecordOrder();
186
395
  const write = appendRegularFile({
187
- filePath: path.join(storePath, "calls.jsonl"),
188
- content: `${JSON.stringify(call)}\n`,
396
+ filePath: logPath,
397
+ content: `${JSON.stringify({
398
+ version: 2,
399
+ ...order,
400
+ call
401
+ })}\n`,
189
402
  rejectSymlinkParents: true
190
403
  }).catch((err) => {
191
404
  console.error("[voice-call] Failed to persist call record:", err);
@@ -195,23 +408,22 @@ function persistCallRecord(storePath, call) {
195
408
  pendingPersistWrites.add(write);
196
409
  }
197
410
  function loadActiveCallsFromStore(storePath) {
198
- const logPath = path.join(storePath, "calls.jsonl");
199
- const content = privateFileStoreSync(storePath).readTextIfExists(path.basename(logPath));
200
- if (content === null) return {
411
+ const stores = tryCreateCallRecordStateStores(storePath);
412
+ let calls;
413
+ try {
414
+ calls = stores ? readCallRecordEvents(storePath, stores) : readCallRecordsFromLegacyLog(storePath);
415
+ } catch (err) {
416
+ console.error("[voice-call] Failed to read SQLite call records:", err);
417
+ calls = readCallRecordsFromLegacyLog(storePath);
418
+ }
419
+ if (calls.length === 0) return {
201
420
  activeCalls: /* @__PURE__ */ new Map(),
202
421
  providerCallIdMap: /* @__PURE__ */ new Map(),
203
422
  processedEventIds: /* @__PURE__ */ new Set(),
204
423
  rejectedProviderCallIds: /* @__PURE__ */ new Set()
205
424
  };
206
- const lines = content.split("\n");
207
425
  const callMap = /* @__PURE__ */ new Map();
208
- for (const line of lines) {
209
- if (!line.trim()) continue;
210
- try {
211
- const call = CallRecordSchema.parse(JSON.parse(line));
212
- callMap.set(call.callId, call);
213
- } catch {}
214
- }
426
+ for (const call of calls) callMap.set(call.callId, call);
215
427
  const activeCalls = /* @__PURE__ */ new Map();
216
428
  const providerCallIdMap = /* @__PURE__ */ new Map();
217
429
  const processedEventIds = /* @__PURE__ */ new Set();
@@ -230,17 +442,30 @@ function loadActiveCallsFromStore(storePath) {
230
442
  };
231
443
  }
232
444
  async function getCallHistoryFromStore(storePath, limit = 50) {
233
- const logPath = path.join(storePath, "calls.jsonl");
445
+ if (limit <= 0) return [];
446
+ const stores = tryCreateCallRecordStateStores(storePath);
447
+ if (stores) try {
448
+ return readCallRecordEvents(storePath, stores).slice(-limit);
449
+ } catch (err) {
450
+ console.error("[voice-call] Failed to read SQLite call history:", err);
451
+ }
452
+ const logPath = resolveCallLogPath(storePath);
234
453
  const content = await privateFileStore(storePath).readTextIfExists(path.basename(logPath));
235
454
  if (content === null) return [];
236
455
  const lines = content.trim().split("\n").filter(Boolean);
237
456
  const calls = [];
238
- for (const line of lines.slice(-limit)) try {
239
- const parsed = CallRecordSchema.parse(JSON.parse(line));
240
- calls.push(parsed);
241
- } catch {}
457
+ for (const [index, line] of lines.slice(-limit).entries()) {
458
+ const parsed = parseCallRecordLine(line, index);
459
+ if (parsed) calls.push(parsed.call);
460
+ }
242
461
  return calls;
243
462
  }
463
+ function readCallRecordsFromLegacyLog(storePath) {
464
+ const logPath = resolveCallLogPath(storePath);
465
+ const content = privateFileStoreSync(storePath).readTextIfExists(path.basename(logPath));
466
+ if (content === null) return [];
467
+ return content.split("\n").map((line, index) => parseCallRecordLine(line, index)?.call ?? null).filter((call) => call !== null);
468
+ }
244
469
  //#endregion
245
470
  //#region extensions/voice-call/src/manager/timer-delays.ts
246
471
  function resolveVoiceCallSecondsTimerDelayMs(seconds, minMs = 1) {
@@ -1360,7 +1585,7 @@ function createTelephonyTtsProvider(params) {
1360
1585
  const providerConfigs = collectTelephonyProviderConfigs(ttsConfig);
1361
1586
  const activeProvider = normalizeProviderId(ttsConfig?.provider);
1362
1587
  return {
1363
- synthesisTimeoutMs: mergedConfig.messages?.tts?.timeoutMs ?? 8e3,
1588
+ synthesisTimeoutMs: resolveTimerTimeoutMs(mergedConfig.messages?.tts?.timeoutMs, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS),
1364
1589
  synthesizeForTelephony: async (text) => {
1365
1590
  const directives = parseTtsDirectives(text, modelOverrides, {
1366
1591
  cfg: mergedConfig,
@@ -1518,7 +1743,6 @@ function runTailscaleCommand(args, timeoutMs = 2500) {
1518
1743
  text: ""
1519
1744
  };
1520
1745
  let settled = false;
1521
- let timer;
1522
1746
  const finish = (result) => {
1523
1747
  if (settled) return;
1524
1748
  settled = true;
@@ -1535,7 +1759,7 @@ function runTailscaleCommand(args, timeoutMs = 2500) {
1535
1759
  });
1536
1760
  }
1537
1761
  });
1538
- timer = setTimeout(() => {
1762
+ const timer = setTimeout(() => {
1539
1763
  proc.kill("SIGKILL");
1540
1764
  finish({
1541
1765
  code: -1,
@@ -1950,7 +2174,7 @@ var MediaStreamHandler = class {
1950
2174
  this.ttsPlaying = /* @__PURE__ */ new Map();
1951
2175
  this.ttsActiveControllers = /* @__PURE__ */ new Map();
1952
2176
  this.config = config;
1953
- this.preStartTimeoutMs = config.preStartTimeoutMs ?? DEFAULT_PRE_START_TIMEOUT_MS;
2177
+ this.preStartTimeoutMs = resolveTimerTimeoutMs(config.preStartTimeoutMs, DEFAULT_PRE_START_TIMEOUT_MS);
1954
2178
  this.maxPendingConnections = config.maxPendingConnections ?? DEFAULT_MAX_PENDING_CONNECTIONS;
1955
2179
  this.maxPendingConnectionsPerIp = config.maxPendingConnectionsPerIp ?? DEFAULT_MAX_PENDING_CONNECTIONS_PER_IP;
1956
2180
  this.maxConnections = config.maxConnections ?? DEFAULT_MAX_CONNECTIONS;
@@ -2600,7 +2824,7 @@ function loadRealtimeTranscriptionRuntime() {
2600
2824
  return realtimeTranscriptionRuntimePromise;
2601
2825
  }
2602
2826
  function loadResponseGeneratorModule() {
2603
- responseGeneratorModulePromise ??= import("./response-generator-BdzG0ajq.js");
2827
+ responseGeneratorModulePromise ??= import("./response-generator-Cu4sOiUO.js");
2604
2828
  return responseGeneratorModulePromise;
2605
2829
  }
2606
2830
  function sanitizeTranscriptForLog(value) {
@@ -2610,7 +2834,7 @@ function sanitizeTranscriptForLog(value) {
2610
2834
  }
2611
2835
  function appendRecentTalkEventMetadata(call, event) {
2612
2836
  const metadata = call.metadata ?? {};
2613
- const recent = Array.isArray(metadata.recentTalkEvents) ? metadata.recentTalkEvents.filter((entry) => !!entry && typeof entry === "object" && !Array.isArray(entry)) : [];
2837
+ const recent = Array.isArray(metadata.recentTalkEvents) ? metadata.recentTalkEvents.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
2614
2838
  recent.push({
2615
2839
  at: event.timestamp,
2616
2840
  type: event.type,
@@ -3284,15 +3508,15 @@ let mockProviderPromise;
3284
3508
  let realtimeVoiceRuntimePromise;
3285
3509
  let realtimeHandlerPromise;
3286
3510
  function loadTelnyxProvider() {
3287
- telnyxProviderPromise ??= import("./telnyx-hEvdLe74.js");
3511
+ telnyxProviderPromise ??= import("./telnyx-CxEuPBOJ.js");
3288
3512
  return telnyxProviderPromise;
3289
3513
  }
3290
3514
  function loadTwilioProvider() {
3291
- twilioProviderPromise ??= import("./twilio-DWgnLf2U.js");
3515
+ twilioProviderPromise ??= import("./twilio-DzQmSUQP.js");
3292
3516
  return twilioProviderPromise;
3293
3517
  }
3294
3518
  function loadPlivoProvider() {
3295
- plivoProviderPromise ??= import("./plivo-sYOZg1xm.js");
3519
+ plivoProviderPromise ??= import("./plivo-Dpf08ZVJ.js");
3296
3520
  return plivoProviderPromise;
3297
3521
  }
3298
3522
  function loadMockProvider() {
@@ -3304,7 +3528,7 @@ function loadRealtimeVoiceRuntime() {
3304
3528
  return realtimeVoiceRuntimePromise;
3305
3529
  }
3306
3530
  function loadRealtimeHandler() {
3307
- realtimeHandlerPromise ??= import("./realtime-handler-CtztDOAd.js");
3531
+ realtimeHandlerPromise ??= import("./realtime-handler-Crs3kty2.js");
3308
3532
  return realtimeHandlerPromise;
3309
3533
  }
3310
3534
  function resolveVoiceCallConsultSessionKey(call) {
@@ -3410,7 +3634,7 @@ async function resolveRealtimeProvider(params) {
3410
3634
  });
3411
3635
  }
3412
3636
  async function createVoiceCallRuntime(params) {
3413
- const { config: rawConfig, coreConfig, fullConfig, agentRuntime, ttsRuntime, logger } = params;
3637
+ const { config: rawConfig, coreConfig, fullConfig, agentRuntime, stateRuntime, ttsRuntime, logger } = params;
3414
3638
  const log = logger ?? {
3415
3639
  info: console.log,
3416
3640
  warn: console.warn,
@@ -3424,6 +3648,7 @@ async function createVoiceCallRuntime(params) {
3424
3648
  const validation = validateProviderConfig(config);
3425
3649
  if (!validation.valid) throw new Error(`Invalid voice-call config: ${validation.errors.join("; ")}`);
3426
3650
  const provider = await resolveProvider(config);
3651
+ if (stateRuntime) setVoiceCallStateRuntime({ state: stateRuntime });
3427
3652
  const manager = new CallManager(config);
3428
3653
  const realtimeProvider = config.realtime.enabled ? await resolveRealtimeProvider({
3429
3654
  config,
@@ -3568,4 +3793,4 @@ async function createVoiceCallRuntime(params) {
3568
3793
  }
3569
3794
  }
3570
3795
  //#endregion
3571
- export { getHeader as a, getTailscaleSelfInfo as c, chunkAudio as d, resolveVoiceResponseModel as f, mapVoiceToPolly as h, normalizeProviderStatus as i, setupTailscaleExposureRoute as l, escapeXml as m, isProviderStatusTerminal as n, resolveWebhookExposureStatus as o, resolveUserPath as p, mapProviderStatusToEndReason as r, cleanupTailscaleExposureRoute as s, createVoiceCallRuntime as t, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS as u };
3796
+ export { setVoiceCallStateRuntime as _, getHeader as a, getTailscaleSelfInfo as c, chunkAudio as d, resolveVoiceResponseModel as f, getCallHistoryFromStore as g, mapVoiceToPolly as h, normalizeProviderStatus as i, setupTailscaleExposureRoute as l, escapeXml as m, isProviderStatusTerminal as n, resolveWebhookExposureStatus as o, resolveUserPath as p, mapProviderStatusToEndReason as r, cleanupTailscaleExposureRoute as s, createVoiceCallRuntime as t, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS as u };
@@ -1,2 +1,2 @@
1
- import { t as createVoiceCallRuntime } from "./runtime-entry-CDCNtGtn.js";
1
+ import { t as createVoiceCallRuntime } from "./runtime-entry-DXf7kdXt.js";
2
2
  export { createVoiceCallRuntime };
package/dist/setup-api.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as migrateVoiceCallLegacyConfigInput } from "./config-compat-CokN3Zzr.js";
1
+ import { n as migrateVoiceCallLegacyConfigInput } from "./config-compat-BLdRz9GR.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-BeaXjPdi.js";
1
+ import { i as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-mCcsLRBb.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-CDCNtGtn.js";
4
- import { a as verifyTwilioWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-BeaXjPdi.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-DXf7kdXt.js";
4
+ import { a as verifyTwilioWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-mCcsLRBb.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";
@@ -164,10 +164,13 @@ export type TExtendsMapping<Input extends [unknown, unknown, unknown, unknown, u
164
164
  export declare function ExtendsMapping(input: [unknown, unknown, unknown, unknown, unknown, unknown] | []): unknown;
165
165
  export type TBaseMapping<Input extends [unknown, unknown, unknown] | unknown> = (Input extends ['(', infer Type extends T.TSchema, ')'] ? Type : Input extends infer Type extends T.TSchema ? Type : never);
166
166
  export declare function BaseMapping(input: [unknown, unknown, unknown] | unknown): unknown;
167
+ export type TWithMapping<Input extends [unknown, unknown] | []> = (Input extends ['with', infer Options extends Record<PropertyKey, unknown>] ? Options : []);
168
+ export declare function WithMapping(input: [unknown, unknown] | []): unknown;
167
169
  type TFactorIndexArray<Type extends T.TSchema, IndexArray extends unknown[]> = (IndexArray extends [infer Left extends T.TSchema[], ...infer Right extends unknown[]] ? (Left extends [infer Indexer extends T.TSchema] ? TFactorIndexArray<C.TIndexDeferred<Type, Indexer>, Right> : Left extends [] ? TFactorIndexArray<T.TArray<Type>, Right> : T.TNever) : Type);
168
170
  type TFactorExtends<Type extends T.TSchema, Extends extends unknown[]> = (Extends extends [infer Right extends T.TSchema, infer True extends T.TSchema, infer False extends T.TSchema] ? C.TConditionalDeferred<Type, Right, True, False> : Type);
169
- export type TFactorMapping<Input extends [unknown, unknown, unknown, unknown]> = (Input extends [infer KeyOf extends boolean, infer Type extends T.TSchema, infer IndexArray extends unknown[], infer Extend extends unknown[]] ? KeyOf extends true ? TFactorExtends<C.TKeyOfDeferred<TFactorIndexArray<Type, IndexArray>>, Extend> : TFactorExtends<TFactorIndexArray<Type, IndexArray>, Extend> : never);
170
- export declare function FactorMapping(input: [unknown, unknown, unknown, unknown]): unknown;
171
+ type TFactorWith<Type extends T.TSchema, With extends unknown> = (With extends Record<PropertyKey, unknown> ? C.TOptionsDeferred<Type, With> : Type);
172
+ export type TFactorMapping<Input extends [unknown, unknown, unknown, unknown, unknown]> = (Input extends [infer KeyOf extends boolean, infer Type extends T.TSchema, infer IndexArray extends unknown[], infer Extend extends unknown[], infer WithClause extends unknown] ? TFactorWith<KeyOf extends true ? TFactorExtends<C.TKeyOfDeferred<TFactorIndexArray<Type, IndexArray>>, Extend> : TFactorExtends<TFactorIndexArray<Type, IndexArray>, Extend>, WithClause> : never);
173
+ export declare function FactorMapping(input: [unknown, unknown, unknown, unknown, unknown]): unknown;
171
174
  type TExprBinaryMapping<Left extends T.TSchema, Rest extends unknown[]> = (Rest extends [infer Operator extends unknown, infer Right extends T.TSchema, infer Next extends unknown[]] ? (TExprBinaryMapping<Right, Next> extends infer Schema extends T.TSchema ? (Operator extends '&' ? (Schema extends T.TIntersect<infer Types extends T.TSchema[]> ? T.TIntersect<[Left, ...Types]> : T.TIntersect<[Left, Schema]>) : Operator extends '|' ? (Schema extends T.TUnion<infer Types extends T.TSchema[]> ? T.TUnion<[Left, ...Types]> : T.TUnion<[Left, Schema]>) : never) : never) : Left);
172
175
  export type TExprTermTailMapping<Input extends [unknown, unknown, unknown] | []> = (Input);
173
176
  export declare function ExprTermTailMapping(input: [unknown, unknown, unknown] | []): unknown;
@@ -185,27 +185,34 @@ export function BaseMapping(input) {
185
185
  ? input[1]
186
186
  : input;
187
187
  }
188
+ export function WithMapping(input) {
189
+ return Guard.IsEqual(input.length, 2) ? input[1] : [];
190
+ }
188
191
  // deno-coverage-ignore-start
189
- // ...
190
- const FactorIndexArray = (Type, indexArray) => {
192
+ function FactorIndexArray(Type, indexArray) {
191
193
  return indexArray.reduce((result, left) => {
192
194
  const _left = left;
193
195
  return (Guard.IsEqual(_left.length, 1) ? C.IndexDeferred(result, _left[0]) :
194
196
  Guard.IsEqual(_left.length, 0) ? T.Array(result) :
195
197
  Unreachable());
196
198
  }, Type);
197
- };
199
+ }
198
200
  // deno-coverage-ignore-stop
199
- const FactorExtends = (type, extend) => {
201
+ function FactorExtends(type, extend) {
200
202
  return Guard.IsEqual(extend.length, 3)
201
203
  ? C.ConditionalDeferred(type, extend[0], extend[1], extend[2])
202
204
  : type;
203
- };
205
+ }
206
+ function FactorWith(type, withClause) {
207
+ return Guard.IsArray(withClause) && Guard.IsEqual(withClause.length, 0)
208
+ ? type
209
+ : C.OptionsDeferred(type, withClause);
210
+ }
204
211
  export function FactorMapping(input) {
205
- const [keyOf, type, indexArray, extend] = input;
206
- return keyOf
212
+ const [keyOf, type, indexArray, extend, withClause] = input;
213
+ return FactorWith(keyOf
207
214
  ? FactorExtends(C.KeyOfDeferred(FactorIndexArray(type, indexArray)), extend)
208
- : FactorExtends(FactorIndexArray(type, indexArray), extend);
215
+ : FactorExtends(FactorIndexArray(type, indexArray), extend), withClause);
209
216
  }
210
217
  // deno-coverage-ignore-start
211
218
  function ExprBinaryMapping(left, rest) {
@@ -43,7 +43,8 @@ export type TIndexArray_0<Input extends string, Result extends unknown[] = []> =
43
43
  export type TIndexArray<Input extends string> = TIndexArray_0<Input> extends [infer _0 extends ([unknown, unknown, unknown] | [unknown, unknown])[], infer Input extends string] ? [S.TIndexArrayMapping<_0>, Input] : [];
44
44
  export type TExtends<Input extends string> = ((Token.TConst<'extends', Input> extends [infer _0, infer Input extends string] ? (TType<Input> extends [infer _1, infer Input extends string] ? (Token.TConst<'?', Input> extends [infer _2, infer Input extends string] ? (TType<Input> extends [infer _3, infer Input extends string] ? (Token.TConst<':', Input> extends [infer _4, infer Input extends string] ? (TType<Input> extends [infer _5, infer Input extends string] ? [[_0, _1, _2, _3, _4, _5], Input] : []) : []) : []) : []) : []) : []) extends [infer _0, infer Input extends string] ? [_0, Input] : [[], Input] extends [infer _0, infer Input extends string] ? [_0, Input] : []) extends [infer _0 extends [unknown, unknown, unknown, unknown, unknown, unknown] | [], infer Input extends string] ? [S.TExtendsMapping<_0>, Input] : [];
45
45
  export type TBase<Input extends string> = ((Token.TConst<'(', Input> extends [infer _0, infer Input extends string] ? (TType<Input> extends [infer _1, infer Input extends string] ? (Token.TConst<')', Input> extends [infer _2, infer Input extends string] ? [[_0, _1, _2], Input] : []) : []) : []) extends [infer _0, infer Input extends string] ? [_0, Input] : TKeyword<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : T_Object_<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TTuple<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TTemplateLiteral<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TLiteral<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TConstructor<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : T_Function_<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TMapped<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TOptions<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TGenericCall<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : TReference<Input> extends [infer _0, infer Input extends string] ? [_0, Input] : []) extends [infer _0 extends [unknown, unknown, unknown] | unknown, infer Input extends string] ? [S.TBaseMapping<_0>, Input] : [];
46
- export type TFactor<Input extends string> = (TKeyOf<Input> extends [infer _0, infer Input extends string] ? (TBase<Input> extends [infer _1, infer Input extends string] ? (TIndexArray<Input> extends [infer _2, infer Input extends string] ? (TExtends<Input> extends [infer _3, infer Input extends string] ? [[_0, _1, _2, _3], Input] : []) : []) : []) : []) extends [infer _0 extends [unknown, unknown, unknown, unknown], infer Input extends string] ? [S.TFactorMapping<_0>, Input] : [];
46
+ export type TWith<Input extends string> = ((Token.TConst<'with', Input> extends [infer _0, infer Input extends string] ? (TJsonObject<Input> extends [infer _1, infer Input extends string] ? [[_0, _1], Input] : []) : []) extends [infer _0, infer Input extends string] ? [_0, Input] : [[], Input] extends [infer _0, infer Input extends string] ? [_0, Input] : []) extends [infer _0 extends [unknown, unknown] | [], infer Input extends string] ? [S.TWithMapping<_0>, Input] : [];
47
+ export type TFactor<Input extends string> = (TKeyOf<Input> extends [infer _0, infer Input extends string] ? (TBase<Input> extends [infer _1, infer Input extends string] ? (TIndexArray<Input> extends [infer _2, infer Input extends string] ? (TExtends<Input> extends [infer _3, infer Input extends string] ? (TWith<Input> extends [infer _4, infer Input extends string] ? [[_0, _1, _2, _3, _4], Input] : []) : []) : []) : []) : []) extends [infer _0 extends [unknown, unknown, unknown, unknown, unknown], infer Input extends string] ? [S.TFactorMapping<_0>, Input] : [];
47
48
  export type TExprTermTail<Input extends string> = ((Token.TConst<'&', Input> extends [infer _0, infer Input extends string] ? (TFactor<Input> extends [infer _1, infer Input extends string] ? (TExprTermTail<Input> extends [infer _2, infer Input extends string] ? [[_0, _1, _2], Input] : []) : []) : []) extends [infer _0, infer Input extends string] ? [_0, Input] : [[], Input] extends [infer _0, infer Input extends string] ? [_0, Input] : []) extends [infer _0 extends [unknown, unknown, unknown] | [], infer Input extends string] ? [S.TExprTermTailMapping<_0>, Input] : [];
48
49
  export type TExprTerm<Input extends string> = (TFactor<Input> extends [infer _0, infer Input extends string] ? (TExprTermTail<Input> extends [infer _1, infer Input extends string] ? [[_0, _1], Input] : []) : []) extends [infer _0 extends [unknown, unknown], infer Input extends string] ? [S.TExprTermMapping<_0>, Input] : [];
49
50
  export type TExprTail<Input extends string> = ((Token.TConst<'|', Input> extends [infer _0, infer Input extends string] ? (TExprTerm<Input> extends [infer _1, infer Input extends string] ? (TExprTail<Input> extends [infer _2, infer Input extends string] ? [[_0, _1, _2], Input] : []) : []) : []) extends [infer _0, infer Input extends string] ? [_0, Input] : [[], Input] extends [infer _0, infer Input extends string] ? [_0, Input] : []) extends [infer _0 extends [unknown, unknown, unknown] | [], infer Input extends string] ? [S.TExprTailMapping<_0>, Input] : [];
@@ -172,6 +173,7 @@ export declare const IndexArray_0: (input: string, result?: unknown[]) => [unkno
172
173
  export declare const IndexArray: (input: string) => [unknown, string] | [];
173
174
  export declare const Extends: (input: string) => [unknown, string] | [];
174
175
  export declare const Base: (input: string) => [unknown, string] | [];
176
+ export declare const With: (input: string) => [unknown, string] | [];
175
177
  export declare const Factor: (input: string) => [unknown, string] | [];
176
178
  export declare const ExprTermTail: (input: string) => [unknown, string] | [];
177
179
  export declare const ExprTerm: (input: string) => [unknown, string] | [];
@@ -47,7 +47,8 @@ export const IndexArray_0 = (input, result = []) => If(If(If(Token.Const('[', in
47
47
  export const IndexArray = (input) => If(IndexArray_0(input), ([_0, input]) => [S.IndexArrayMapping(_0), input]);
48
48
  export const Extends = (input) => If(If(If(Token.Const('extends', input), ([_0, input]) => If(Type(input), ([_1, input]) => If(Token.Const('?', input), ([_2, input]) => If(Type(input), ([_3, input]) => If(Token.Const(':', input), ([_4, input]) => If(Type(input), ([_5, input]) => [[_0, _1, _2, _3, _4, _5], input])))))), ([_0, input]) => [_0, input], () => If([[], input], ([_0, input]) => [_0, input], () => [])), ([_0, input]) => [S.ExtendsMapping(_0), input]);
49
49
  export const Base = (input) => If(If(If(Token.Const('(', input), ([_0, input]) => If(Type(input), ([_1, input]) => If(Token.Const(')', input), ([_2, input]) => [[_0, _1, _2], input]))), ([_0, input]) => [_0, input], () => If(Keyword(input), ([_0, input]) => [_0, input], () => If(_Object_(input), ([_0, input]) => [_0, input], () => If(Tuple(input), ([_0, input]) => [_0, input], () => If(TemplateLiteral(input), ([_0, input]) => [_0, input], () => If(Literal(input), ([_0, input]) => [_0, input], () => If(Constructor(input), ([_0, input]) => [_0, input], () => If(_Function_(input), ([_0, input]) => [_0, input], () => If(Mapped(input), ([_0, input]) => [_0, input], () => If(Options(input), ([_0, input]) => [_0, input], () => If(GenericCall(input), ([_0, input]) => [_0, input], () => If(Reference(input), ([_0, input]) => [_0, input], () => [])))))))))))), ([_0, input]) => [S.BaseMapping(_0), input]);
50
- export const Factor = (input) => If(If(KeyOf(input), ([_0, input]) => If(Base(input), ([_1, input]) => If(IndexArray(input), ([_2, input]) => If(Extends(input), ([_3, input]) => [[_0, _1, _2, _3], input])))), ([_0, input]) => [S.FactorMapping(_0), input]);
50
+ export const With = (input) => If(If(If(Token.Const('with', input), ([_0, input]) => If(JsonObject(input), ([_1, input]) => [[_0, _1], input])), ([_0, input]) => [_0, input], () => If([[], input], ([_0, input]) => [_0, input], () => [])), ([_0, input]) => [S.WithMapping(_0), input]);
51
+ export const Factor = (input) => If(If(KeyOf(input), ([_0, input]) => If(Base(input), ([_1, input]) => If(IndexArray(input), ([_2, input]) => If(Extends(input), ([_3, input]) => If(With(input), ([_4, input]) => [[_0, _1, _2, _3, _4], input]))))), ([_0, input]) => [S.FactorMapping(_0), input]);
51
52
  export const ExprTermTail = (input) => If(If(If(Token.Const('&', input), ([_0, input]) => If(Factor(input), ([_1, input]) => If(ExprTermTail(input), ([_2, input]) => [[_0, _1, _2], input]))), ([_0, input]) => [_0, input], () => If([[], input], ([_0, input]) => [_0, input], () => [])), ([_0, input]) => [S.ExprTermTailMapping(_0), input]);
52
53
  export const ExprTerm = (input) => If(If(Factor(input), ([_0, input]) => If(ExprTermTail(input), ([_1, input]) => [[_0, _1], input])), ([_0, input]) => [S.ExprTermMapping(_0), input]);
53
54
  export const ExprTail = (input) => If(If(If(Token.Const('|', input), ([_0, input]) => If(ExprTerm(input), ([_1, input]) => If(ExprTail(input), ([_2, input]) => [[_0, _1, _2], input]))), ([_0, input]) => [_0, input], () => If([[], input], ([_0, input]) => [_0, input], () => [])), ([_0, input]) => [S.ExprTailMapping(_0), input]);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typebox",
3
3
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
4
- "version": "1.1.38",
4
+ "version": "1.1.39",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
@@ -16,22 +16,6 @@
16
16
  "types": "./build/index.d.mts",
17
17
  "module": "./build/index.mjs",
18
18
  "exports": {
19
- "./guard": {
20
- "import": "./build/guard/index.mjs",
21
- "default": "./build/guard/index.mjs"
22
- },
23
- "./error": {
24
- "import": "./build/error/index.mjs",
25
- "default": "./build/error/index.mjs"
26
- },
27
- "./compile": {
28
- "import": "./build/compile/index.mjs",
29
- "default": "./build/compile/index.mjs"
30
- },
31
- "./system": {
32
- "import": "./build/system/index.mjs",
33
- "default": "./build/system/index.mjs"
34
- },
35
19
  "./format": {
36
20
  "import": "./build/format/index.mjs",
37
21
  "default": "./build/format/index.mjs"
@@ -44,10 +28,26 @@
44
28
  "import": "./build/schema/index.mjs",
45
29
  "default": "./build/schema/index.mjs"
46
30
  },
31
+ "./compile": {
32
+ "import": "./build/compile/index.mjs",
33
+ "default": "./build/compile/index.mjs"
34
+ },
47
35
  "./value": {
48
36
  "import": "./build/value/index.mjs",
49
37
  "default": "./build/value/index.mjs"
50
38
  },
39
+ "./guard": {
40
+ "import": "./build/guard/index.mjs",
41
+ "default": "./build/guard/index.mjs"
42
+ },
43
+ "./system": {
44
+ "import": "./build/system/index.mjs",
45
+ "default": "./build/system/index.mjs"
46
+ },
47
+ "./error": {
48
+ "import": "./build/error/index.mjs",
49
+ "default": "./build/error/index.mjs"
50
+ },
51
51
  ".": {
52
52
  "import": "./build/index.mjs",
53
53
  "default": "./build/index.mjs"
@@ -55,18 +55,6 @@
55
55
  },
56
56
  "typesVersions": {
57
57
  "*": {
58
- "guard": [
59
- "./build/guard/index.d.mts"
60
- ],
61
- "error": [
62
- "./build/error/index.d.mts"
63
- ],
64
- "compile": [
65
- "./build/compile/index.d.mts"
66
- ],
67
- "system": [
68
- "./build/system/index.d.mts"
69
- ],
70
58
  "format": [
71
59
  "./build/format/index.d.mts"
72
60
  ],
@@ -76,9 +64,21 @@
76
64
  "schema": [
77
65
  "./build/schema/index.d.mts"
78
66
  ],
67
+ "compile": [
68
+ "./build/compile/index.d.mts"
69
+ ],
79
70
  "value": [
80
71
  "./build/value/index.d.mts"
81
72
  ],
73
+ "guard": [
74
+ "./build/guard/index.d.mts"
75
+ ],
76
+ "system": [
77
+ "./build/system/index.d.mts"
78
+ ],
79
+ "error": [
80
+ "./build/error/index.d.mts"
81
+ ],
82
82
  ".": [
83
83
  "./build/index.d.mts"
84
84
  ]
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@openclaw/voice-call",
3
- "version": "2026.5.30-beta.1",
3
+ "version": "2026.5.31-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.30-beta.1",
9
+ "version": "2026.5.31-beta.1",
10
10
  "dependencies": {
11
11
  "commander": "14.0.3",
12
- "typebox": "1.1.38",
12
+ "typebox": "1.1.39",
13
13
  "ws": "8.21.0",
14
14
  "zod": "4.4.3"
15
15
  },
16
16
  "peerDependencies": {
17
- "openclaw": ">=2026.5.30-beta.1"
17
+ "openclaw": ">=2026.5.31-beta.1"
18
18
  },
19
19
  "peerDependenciesMeta": {
20
20
  "openclaw": {
@@ -32,9 +32,9 @@
32
32
  }
33
33
  },
34
34
  "node_modules/typebox": {
35
- "version": "1.1.38",
36
- "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.38.tgz",
37
- "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==",
35
+ "version": "1.1.39",
36
+ "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.39.tgz",
37
+ "integrity": "sha512-vj0afVtOfLQvv0GR0VxVagYxsXN64btL7Z9XoaG0ZggH3mruMMkOO6hXdgMsjCY3shZgEvooAWVeznQVs5c43w==",
38
38
  "license": "MIT"
39
39
  },
40
40
  "node_modules/ws": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/voice-call",
3
- "version": "2026.5.30-beta.1",
3
+ "version": "2026.5.31-beta.1",
4
4
  "description": "OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,12 +9,12 @@
9
9
  "type": "module",
10
10
  "dependencies": {
11
11
  "commander": "14.0.3",
12
- "typebox": "1.1.38",
12
+ "typebox": "1.1.39",
13
13
  "ws": "8.21.0",
14
14
  "zod": "4.4.3"
15
15
  },
16
16
  "peerDependencies": {
17
- "openclaw": ">=2026.5.30-beta.1"
17
+ "openclaw": ">=2026.5.31-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.30-beta.1"
34
+ "pluginApi": ">=2026.5.31-beta.1"
35
35
  },
36
36
  "build": {
37
- "openclawVersion": "2026.5.30-beta.1"
37
+ "openclawVersion": "2026.5.31-beta.1"
38
38
  },
39
39
  "release": {
40
40
  "publishToClawHub": true,