@openclaw/voice-call 2026.7.2-beta.3 → 2026.7.2-beta.5

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.
Files changed (30) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-metadata.js +5 -1
  3. package/dist/cli-output-mode.js +27 -0
  4. package/dist/{guarded-json-api-Dm4NvtGo.js → guarded-json-api-Dxhe25Zi.js} +1 -2
  5. package/dist/index.js +15 -7
  6. package/dist/{plivo-rISw-5A8.js → plivo-B-KvPVji.js} +2 -3
  7. package/dist/{realtime-handler-HSxcgwY_.js → realtime-handler-hIVPEZxN.js} +4 -10
  8. package/dist/{response-generator-r9wHPOEl.js → response-generator-z6M9229t.js} +1 -1
  9. package/dist/{runtime-entry-D8Mkwy8G.js → runtime-entry-CQtitvRd.js} +29 -13
  10. package/dist/runtime-entry.js +1 -1
  11. package/dist/{telnyx-DTD9jTqC.js → telnyx-BG56lL7z.js} +1 -1
  12. package/dist/{twilio-GzbIb5fv.js → twilio-B3FQ_P9x.js} +2 -2
  13. package/node_modules/typebox/build/compile/validator.d.mts +1 -4
  14. package/node_modules/typebox/build/guard/guard.d.mts +1 -1
  15. package/node_modules/typebox/build/guard/guard.mjs +5 -2
  16. package/node_modules/typebox/build/guard/string.mjs +16 -4
  17. package/node_modules/typebox/build/schema/engine/_functions.mjs +34 -15
  18. package/node_modules/typebox/build/type/action/readonly_object.d.mts +5 -0
  19. package/node_modules/typebox/build/type/action/readonly_object.mjs +8 -0
  20. package/node_modules/typebox/build/typebox.d.mts +1 -1
  21. package/node_modules/typebox/build/typebox.mjs +1 -1
  22. package/node_modules/typebox/package.json +1 -1
  23. package/node_modules/typebox/readme.md +29 -32
  24. package/node_modules/ws/lib/receiver.js +15 -32
  25. package/node_modules/ws/lib/websocket-server.js +4 -4
  26. package/node_modules/ws/lib/websocket.js +4 -4
  27. package/node_modules/ws/package.json +5 -1
  28. package/openclaw.plugin.json +1 -15
  29. package/package.json +6 -7
  30. package/npm-shrinkwrap.json +0 -61
package/README.md CHANGED
@@ -115,7 +115,7 @@ See the plugin docs for recommended ranges and production examples:
115
115
 
116
116
  ## TTS for calls
117
117
 
118
- Voice Call uses the core `messages.tts` configuration for
118
+ Voice Call uses the core `tts` configuration for
119
119
  streaming speech on calls. Override examples and provider caveats live here:
120
120
  `https://docs.openclaw.ai/plugins/voice-call#tts-for-calls`
121
121
 
@@ -1,3 +1,4 @@
1
+ import { VOICE_CALL_CLI_DESCRIPTOR } from "./cli-output-mode.js";
1
2
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
2
3
  //#region extensions/voice-call/cli-metadata.ts
3
4
  var cli_metadata_default = definePluginEntry({
@@ -5,7 +6,10 @@ var cli_metadata_default = definePluginEntry({
5
6
  name: "Voice Call",
6
7
  description: "Voice call channel plugin",
7
8
  register(api) {
8
- api.registerCli(() => {}, { commands: ["voicecall"] });
9
+ api.registerCli(() => {}, {
10
+ commands: ["voicecall"],
11
+ descriptors: [VOICE_CALL_CLI_DESCRIPTOR]
12
+ });
9
13
  }
10
14
  });
11
15
  //#endregion
@@ -0,0 +1,27 @@
1
+ import { getRootOptionAwareCommandPath } from "openclaw/plugin-sdk/cli-argv";
2
+ //#region extensions/voice-call/cli-output-mode.ts
3
+ const MACHINE_OUTPUT_COMMANDS = /* @__PURE__ */ new Set([
4
+ "call",
5
+ "continue",
6
+ "dtmf",
7
+ "end",
8
+ "expose",
9
+ "latency",
10
+ "speak",
11
+ "start",
12
+ "status",
13
+ "tail"
14
+ ]);
15
+ /** Voice-call result actions emit JSON, while tail reserves stdout for JSONL. */
16
+ function isVoiceCallMachineOutput(params) {
17
+ const [, command] = getRootOptionAwareCommandPath(params.argv, 2);
18
+ return MACHINE_OUTPUT_COMMANDS.has(command ?? "");
19
+ }
20
+ const VOICE_CALL_CLI_DESCRIPTOR = {
21
+ name: "voicecall",
22
+ description: "Voice call utilities",
23
+ hasSubcommands: true,
24
+ machineOutput: isVoiceCallMachineOutput
25
+ };
26
+ //#endregion
27
+ export { VOICE_CALL_CLI_DESCRIPTOR };
@@ -1,6 +1,6 @@
1
1
  import { fetchWithSsrFGuard } from "./runtime-api.js";
2
2
  import "./api.js";
3
- import { n as normalizeProxyIp, o as getHeader } from "./runtime-entry-D8Mkwy8G.js";
3
+ import { n as normalizeProxyIp, s as getHeader } from "./runtime-entry-CQtitvRd.js";
4
4
  import { n as markWebhookReplay, t as createWebhookReplayCache } from "./webhook-replay-aaP79dI8.js";
5
5
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6
6
  import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
@@ -462,7 +462,6 @@ function verifyPlivoWebhook(ctx, authToken, options) {
462
462
  if (options?.publicUrl) try {
463
463
  const req = new URL(reconstructed);
464
464
  const base = new URL(options.publicUrl);
465
- base.pathname = req.pathname;
466
465
  base.search = req.search;
467
466
  verificationUrl = base.toString();
468
467
  } catch {
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { definePluginEntry, sleep } from "./runtime-api.js";
2
2
  import "./api.js";
3
- import { c as cleanupTailscaleExposureRoute, h as resolveUserPath, l as getTailscaleSelfInfo, s as resolveWebhookExposureStatus, t as createVoiceCallRuntime, u as setupTailscaleExposureRoute, v as VoiceCallConfigSchema, x as validateProviderConfig, y as resolveVoiceCallConfig } from "./runtime-entry-D8Mkwy8G.js";
3
+ import { VOICE_CALL_CLI_DESCRIPTOR } from "./cli-output-mode.js";
4
+ import { S as validateProviderConfig, b as resolveVoiceCallConfig, c as resolveWebhookExposureStatus, d as setupTailscaleExposureRoute, g as resolveUserPath, l as cleanupTailscaleExposureRoute, t as createVoiceCallRuntime, u as getTailscaleSelfInfo, y as VoiceCallConfigSchema } from "./runtime-entry-CQtitvRd.js";
4
5
  import { g as setVoiceCallStateRuntime, t as resolveDefaultVoiceCallStoreDir, u as getCallHistoryFromStore } from "./store-path-nYL-yM0S.js";
5
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6
7
  import { ErrorCodes, callGatewayFromCli, errorShape } from "openclaw/plugin-sdk/gateway-runtime";
@@ -87,13 +88,17 @@ function readCompletedContinueResult(payload) {
87
88
  }
88
89
  async function pollVoiceCallContinueGateway(params) {
89
90
  const deadlineMs = resolveVoiceCallDeadlineMs(params.timeoutMs);
90
- while (Date.now() <= deadlineMs) {
91
- const gateway = await callVoiceCallGateway("voicecall.continue.result", { operationId: params.operationId }, { timeoutMs: VOICE_CALL_GATEWAY_DEFAULT_TIMEOUT_MS });
91
+ for (;;) {
92
+ const remainingMs = deadlineMs - Date.now();
93
+ if (remainingMs <= 0) break;
94
+ const gateway = await callVoiceCallGateway("voicecall.continue.result", { operationId: params.operationId }, { timeoutMs: Math.min(VOICE_CALL_GATEWAY_DEFAULT_TIMEOUT_MS, remainingMs) });
92
95
  if (!gateway.ok) throw new Error(`gateway unavailable while waiting for voicecall continue result: ${formatErrorMessage(gateway.error)}`);
93
96
  const result = readCompletedContinueResult(gateway.payload);
94
97
  if (result.status === "completed") return result.result;
95
98
  if (result.status === "failed") throw new Error(result.error);
96
- await sleep(Math.min(VOICE_CALL_GATEWAY_POLL_INTERVAL_MS, Math.max(1, deadlineMs - Date.now())));
99
+ const sleepMs = Math.min(VOICE_CALL_GATEWAY_POLL_INTERVAL_MS, deadlineMs - Date.now());
100
+ if (sleepMs <= 0) break;
101
+ await sleep(sleepMs);
97
102
  }
98
103
  throw new Error("voicecall continue timed out waiting for gateway operation");
99
104
  }
@@ -533,7 +538,7 @@ const VOICE_CALL_CONTINUE_OPERATION_CLEANUP_MS = 300 * 1e3;
533
538
  function createVoiceCallContinueOperationStore(params) {
534
539
  const operations = /* @__PURE__ */ new Map();
535
540
  const resolvePollTimeoutMs = (rt) => {
536
- const ttsTimeoutMs = rt.config.tts?.timeoutMs ?? params.config.tts?.timeoutMs ?? params.coreConfig.messages?.tts?.timeoutMs ?? 8e3;
541
+ const ttsTimeoutMs = rt.config.tts?.timeoutMs ?? params.config.tts?.timeoutMs ?? params.coreConfig.tts?.timeoutMs ?? 8e3;
537
542
  return resolveTimerTimeoutMs((rt.config.transcriptTimeoutMs ?? params.config.transcriptTimeoutMs) + ttsTimeoutMs + VOICE_CALL_CONTINUE_OPERATION_BUFFER_MS, VOICE_CALL_CONTINUE_OPERATION_BUFFER_MS);
538
543
  };
539
544
  const scheduleCleanup = (operationId) => {
@@ -822,7 +827,7 @@ const voiceCallConfigSchema = {
822
827
  },
823
828
  "tts.provider": {
824
829
  label: "TTS Provider Override",
825
- help: "Deep-merges with messages.tts (Microsoft is ignored for calls).",
830
+ help: "Deep-merges with tts (Microsoft is ignored for calls).",
826
831
  advanced: true
827
832
  },
828
833
  "tts.providers": {
@@ -1345,7 +1350,10 @@ var voice_call_default = definePluginEntry({
1345
1350
  ensureRuntime,
1346
1351
  stateRuntime: api.runtime.state,
1347
1352
  logger: api.logger
1348
- }), { commands: ["voicecall"] });
1353
+ }), {
1354
+ commands: ["voicecall"],
1355
+ descriptors: [VOICE_CALL_CLI_DESCRIPTOR]
1356
+ });
1349
1357
  api.registerService({
1350
1358
  id: "voicecall",
1351
1359
  start: () => {
@@ -1,5 +1,5 @@
1
- import { g as escapeXml, o as getHeader } from "./runtime-entry-D8Mkwy8G.js";
2
- import { a as reconstructWebhookUrl, o as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Dm4NvtGo.js";
1
+ import { _ as escapeXml, s as getHeader } from "./runtime-entry-CQtitvRd.js";
2
+ import { a as reconstructWebhookUrl, o as verifyPlivoWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Dxhe25Zi.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
@@ -371,7 +371,6 @@ var PlivoProvider = class PlivoProvider {
371
371
  try {
372
372
  if (this.options.publicUrl) {
373
373
  const base = new URL(this.options.publicUrl);
374
- base.pathname = new URL(ctx.url).pathname;
375
374
  return `${base.origin}${base.pathname}`;
376
375
  }
377
376
  const u = new URL(reconstructWebhookUrl(ctx, {
@@ -1,3 +1,4 @@
1
+ import { o as canonicalizeVoiceCallMediaBase64 } from "./runtime-entry-CQtitvRd.js";
1
2
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
2
3
  import { isFutureDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
3
4
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
@@ -129,22 +130,15 @@ function readRecordField(record, field) {
129
130
  const value = record[field];
130
131
  return typeof value === "object" && value !== null ? value : void 0;
131
132
  }
132
- /** Normalize base64/base64url padding differences for validation. */
133
- function normalizeBase64ForCompare(value) {
134
- return value.replace(/=+$/u, "").replace(/-/gu, "+").replace(/_/gu, "/");
135
- }
136
- /** Return true when a payload round-trips as base64. */
137
- function isValidBase64Payload(value) {
138
- return normalizeBase64ForCompare(Buffer.from(value, "base64").toString("base64")) === normalizeBase64ForCompare(value);
139
- }
140
133
  /** Parse a common provider media frame. */
141
134
  function parseMediaFrame(msg) {
142
135
  const mediaData = readRecordField(msg, "media");
143
136
  const payload = typeof mediaData?.payload === "string" ? mediaData.payload : void 0;
144
- if (!payload || !isValidBase64Payload(payload)) return { kind: "ignored" };
137
+ const canonicalPayload = payload ? canonicalizeVoiceCallMediaBase64(payload) : void 0;
138
+ if (!canonicalPayload) return { kind: "ignored" };
145
139
  return {
146
140
  kind: "media",
147
- payloadBase64: payload,
141
+ payloadBase64: canonicalPayload,
148
142
  timestampMs: parseTimestampMs(mediaData?.timestamp),
149
143
  track: typeof mediaData?.track === "string" ? mediaData.track : void 0
150
144
  };
@@ -1,4 +1,4 @@
1
- import { b as resolveVoiceCallSessionKey, m as resolveCallAgentId, p as resolveVoiceResponseModel } from "./runtime-entry-D8Mkwy8G.js";
1
+ import { h as resolveCallAgentId, m as resolveVoiceResponseModel, x as resolveVoiceCallSessionKey } from "./runtime-entry-CQtitvRd.js";
2
2
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import crypto from "node:crypto";
4
4
  import { ModelSelectionLockedError, applyModelOverrideToSessionEntry, resolvePersistedSessionRuntimeId } from "openclaw/plugin-sdk/model-session-runtime";
@@ -8,6 +8,7 @@ import { MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, resolveExpiresAtMsFromDuration
8
8
  import { normalizeAgentId, parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
9
9
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
10
10
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
11
+ import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
11
12
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
12
13
  import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, REALTIME_VOICE_AGENT_CONSULT_TOOL_POLICIES, assertRealtimeVoiceAgentConsultModelSelectionUnlocked, buildRealtimeVoiceAgentConsultPolicyInstructions, consultRealtimeVoiceAgent, convertPcmToMulaw8k, createTalkSessionController, recordTalkObservabilityEvent, resolveRealtimeVoiceAgentConsultTools, resolveRealtimeVoiceAgentConsultToolsAllow, resolveRealtimeVoiceFastContextConsult } from "openclaw/plugin-sdk/realtime-voice";
13
14
  import { mergeDeep } from "openclaw/plugin-sdk/plugin-config-runtime";
@@ -29,6 +30,7 @@ import http from "node:http";
29
30
  import { URL as URL$1 } from "node:url";
30
31
  import { resolveConfiguredCapabilityProvider } from "openclaw/plugin-sdk/provider-selection-runtime";
31
32
  import { WebSocket, WebSocketServer } from "ws";
33
+ import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
32
34
  //#region extensions/voice-call/src/realtime-defaults.ts
33
35
  /** Baseline instructions that keep realtime calls brief and route deep work to agent consult. */
34
36
  const DEFAULT_VOICE_CALL_REALTIME_INSTRUCTIONS = `You are OpenClaw's phone-call realtime voice interface. Keep spoken replies brief and natural. When a question needs deeper reasoning, current information, or tools, call ${REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME} before answering.`;
@@ -404,7 +406,7 @@ const VoiceCallConfigSchema = z.object({
404
406
  publicUrl: z.string().url().optional(),
405
407
  /** Skip webhook signature verification (development only, NOT for production) */
406
408
  skipSignatureVerification: z.boolean().default(false),
407
- /** TTS override (deep-merges with core messages.tts) */
409
+ /** TTS override (deep-merges with core tts) */
408
410
  tts: TtsConfigSchema,
409
411
  /** Store path for call logs */
410
412
  store: z.string().optional(),
@@ -1838,7 +1840,7 @@ async function buildRealtimeVoiceInstructions(params) {
1838
1840
  if (consultGuidance) sections.push(consultGuidance);
1839
1841
  const contextConfig = config.realtime.agentContext;
1840
1842
  if (!contextConfig.enabled) return sections.filter(Boolean).join("\n\n");
1841
- const agentId = config.agentId ?? "main";
1843
+ const { agentId } = params;
1842
1844
  const capsule = [
1843
1845
  "OpenClaw agent voice context:",
1844
1846
  `- Agent id: ${agentId}`,
@@ -1920,7 +1922,7 @@ async function createTelephonyTtsProvider(params) {
1920
1922
  text: ""
1921
1923
  });
1922
1924
  return {
1923
- synthesisTimeoutMs: resolveTimerTimeoutMs(preparedConfig.cfg.messages?.tts?.timeoutMs, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS),
1925
+ synthesisTimeoutMs: resolveTimerTimeoutMs(preparedConfig.cfg.tts?.timeoutMs, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS),
1924
1926
  synthesizeForTelephony: async (text) => {
1925
1927
  const prepared = await runtime.prepareTtsRequest({
1926
1928
  cfg: preparedConfig.cfg,
@@ -2367,6 +2369,11 @@ function getHeader(headers, name) {
2367
2369
  return value;
2368
2370
  }
2369
2371
  //#endregion
2372
+ //#region extensions/voice-call/src/media-base64.ts
2373
+ function canonicalizeVoiceCallMediaBase64(payloadBase64) {
2374
+ return canonicalizeBase64(payloadBase64.replaceAll("-", "+").replaceAll("_", "/"));
2375
+ }
2376
+ //#endregion
2370
2377
  //#region extensions/voice-call/src/media-stream.ts
2371
2378
  const DEFAULT_PRE_START_TIMEOUT_MS = 5e3;
2372
2379
  const DEFAULT_MAX_PENDING_CONNECTIONS = 32;
@@ -2481,7 +2488,9 @@ var MediaStreamHandler = class {
2481
2488
  break;
2482
2489
  case "media":
2483
2490
  if (session && message.media?.payload) {
2484
- const audioBuffer = Buffer.from(message.media.payload, "base64");
2491
+ const canonicalPayload = canonicalizeVoiceCallMediaBase64(message.media.payload);
2492
+ if (!canonicalPayload) break;
2493
+ const audioBuffer = Buffer.from(canonicalPayload, "base64");
2485
2494
  const turnId = this.ensureActiveTurn(session);
2486
2495
  this.emitTalkEvent(session, {
2487
2496
  type: "input.audio.delta",
@@ -3062,7 +3071,7 @@ const WEBHOOK_BODY_TIMEOUT_MS = WEBHOOK_BODY_READ_DEFAULTS.preAuth.timeoutMs;
3062
3071
  const MISSING_REMOTE_ADDRESS_IN_FLIGHT_KEY = "__voice_call_no_remote__";
3063
3072
  const STREAM_DISCONNECT_HANGUP_GRACE_MS = 2e3;
3064
3073
  const loadRealtimeTranscriptionRuntime = createLazyRuntimeModule(() => import("./realtime-transcription.runtime-CbJAs5t_.js"));
3065
- const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-r9wHPOEl.js"));
3074
+ const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-z6M9229t.js"));
3066
3075
  function appendRecentTalkEventMetadata(call, event) {
3067
3076
  const metadata = call.metadata ?? {};
3068
3077
  const recent = Array.isArray(metadata.recentTalkEvents) ? metadata.recentTalkEvents.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
@@ -3737,12 +3746,12 @@ const REALTIME_VOICE_CONSULT_SYSTEM_PROMPT = [
3737
3746
  "Do not print secret values or dump environment variables; only check whether required configuration is present.",
3738
3747
  "Be accurate, brief, and speakable."
3739
3748
  ].join(" ");
3740
- const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-DTD9jTqC.js"));
3741
- const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-GzbIb5fv.js"));
3742
- const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-rISw-5A8.js"));
3749
+ const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-BG56lL7z.js"));
3750
+ const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-B3FQ_P9x.js"));
3751
+ const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-B-KvPVji.js"));
3743
3752
  const loadMockProvider = createLazyRuntimeModule(() => import("./mock-YsvBTX-7.js"));
3744
3753
  const loadRealtimeVoiceRuntime = createLazyRuntimeModule(() => import("./realtime-voice.runtime-vtdCOWg-.js"));
3745
- const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-HSxcgwY_.js"));
3754
+ const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-hIVPEZxN.js"));
3746
3755
  function resolveVoiceCallConsultSessionKey(call) {
3747
3756
  return resolveVoiceCallSessionKey({
3748
3757
  config: call.config,
@@ -3867,7 +3876,8 @@ async function createRealtimeInstructionsResolver(params) {
3867
3876
  baseInstructions: params.config.realtime.instructions,
3868
3877
  config: genericConfig,
3869
3878
  coreConfig: params.coreConfig,
3870
- agentRuntime: params.agentRuntime
3879
+ agentRuntime: params.agentRuntime,
3880
+ agentId: params.config.agentId
3871
3881
  });
3872
3882
  const entries = await Promise.all(listRealtimeAgentIds(params.config, params.coreConfig).map(async (agentId) => {
3873
3883
  return [agentId, await buildRealtimeVoiceInstructions({
@@ -3877,7 +3887,8 @@ async function createRealtimeInstructionsResolver(params) {
3877
3887
  agentId
3878
3888
  },
3879
3889
  coreConfig: params.coreConfig,
3880
- agentRuntime: params.agentRuntime
3890
+ agentRuntime: params.agentRuntime,
3891
+ agentId
3881
3892
  })];
3882
3893
  }));
3883
3894
  const instructionsByAgentId = new Map(entries);
@@ -3895,8 +3906,13 @@ async function createVoiceCallRuntime(params) {
3895
3906
  error: console.error,
3896
3907
  debug: console.debug
3897
3908
  };
3898
- const config = resolveVoiceCallConfig(rawConfig);
3899
3909
  const cfg = fullConfig ?? coreConfig;
3910
+ const unresolvedConfig = resolveVoiceCallConfig(rawConfig);
3911
+ const configuredAgentId = unresolvedConfig.agentId ? normalizeAgentId(unresolvedConfig.agentId) : resolveDefaultAgentId(cfg);
3912
+ const config = {
3913
+ ...unresolvedConfig,
3914
+ agentId: configuredAgentId
3915
+ };
3900
3916
  if (!config.enabled) throw new Error("Voice call disabled. Enable the plugin entry in config.");
3901
3917
  if (config.skipSignatureVerification) log.warn("[voice-call] SECURITY WARNING: skipSignatureVerification=true disables webhook signature verification (development only). Do not use in production.");
3902
3918
  const validation = validateProviderConfig(config);
@@ -4061,4 +4077,4 @@ async function createVoiceCallRuntime(params) {
4061
4077
  }
4062
4078
  }
4063
4079
  //#endregion
4064
- export { mapVoiceToPolly as _, normalizeProviderStatus as a, resolveVoiceCallSessionKey as b, cleanupTailscaleExposureRoute as c, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS as d, chunkAudio as f, escapeXml as g, resolveUserPath as h, mapProviderStatusToEndReason as i, getTailscaleSelfInfo as l, resolveCallAgentId as m, normalizeProxyIp as n, getHeader as o, resolveVoiceResponseModel as p, isProviderStatusTerminal as r, resolveWebhookExposureStatus as s, createVoiceCallRuntime as t, setupTailscaleExposureRoute as u, VoiceCallConfigSchema as v, validateProviderConfig as x, resolveVoiceCallConfig as y };
4080
+ export { validateProviderConfig as S, escapeXml as _, normalizeProviderStatus as a, resolveVoiceCallConfig as b, resolveWebhookExposureStatus as c, setupTailscaleExposureRoute as d, TELEPHONY_DEFAULT_TTS_TIMEOUT_MS as f, resolveUserPath as g, resolveCallAgentId as h, mapProviderStatusToEndReason as i, cleanupTailscaleExposureRoute as l, resolveVoiceResponseModel as m, normalizeProxyIp as n, canonicalizeVoiceCallMediaBase64 as o, chunkAudio as p, isProviderStatusTerminal as r, getHeader as s, createVoiceCallRuntime as t, getTailscaleSelfInfo as u, mapVoiceToPolly as v, resolveVoiceCallSessionKey as x, VoiceCallConfigSchema as y };
@@ -1,2 +1,2 @@
1
- import { t as createVoiceCallRuntime } from "./runtime-entry-D8Mkwy8G.js";
1
+ import { t as createVoiceCallRuntime } from "./runtime-entry-CQtitvRd.js";
2
2
  export { createVoiceCallRuntime };
@@ -1,4 +1,4 @@
1
- import { s as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Dm4NvtGo.js";
1
+ import { s as verifyTelnyxWebhook, t as guardedJsonApiRequest } from "./guarded-json-api-Dxhe25Zi.js";
2
2
  import crypto from "node:crypto";
3
3
  //#region extensions/voice-call/src/providers/telnyx.ts
4
4
  function normalizeTelnyxDirection(direction) {
@@ -1,8 +1,8 @@
1
1
  import { fetchWithSsrFGuard } from "./runtime-api.js";
2
2
  import "./api.js";
3
3
  import { n as requireSupportedTwilioApiHostname, r as resolveTwilioApiBaseUrl } from "./twilio-region-4fkgz3UG.js";
4
- import { _ as mapVoiceToPolly, a as normalizeProviderStatus, f as chunkAudio, g as escapeXml, i as mapProviderStatusToEndReason, o as getHeader, r as isProviderStatusTerminal } from "./runtime-entry-D8Mkwy8G.js";
5
- import { c as verifyTwilioWebhook, i as readProviderJsonResponseText, n as cancelProviderResponseBody, r as readProviderErrorResponseSnippet, t as guardedJsonApiRequest } from "./guarded-json-api-Dm4NvtGo.js";
4
+ import { _ as escapeXml, a as normalizeProviderStatus, i as mapProviderStatusToEndReason, p as chunkAudio, r as isProviderStatusTerminal, s as getHeader, v as mapVoiceToPolly } from "./runtime-entry-CQtitvRd.js";
5
+ import { c as verifyTwilioWebhook, i as readProviderJsonResponseText, n as cancelProviderResponseBody, r as readProviderErrorResponseSnippet, t as guardedJsonApiRequest } from "./guarded-json-api-Dxhe25Zi.js";
6
6
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
8
8
  import crypto from "node:crypto";
@@ -1,14 +1,11 @@
1
1
  import { type TLocalizedValidationError } from '../error/index.mjs';
2
2
  import { type StaticDecode, type StaticEncode, type TProperties, type TSchema } from '../type/index.mjs';
3
- import { BuildResult, EvaluateResult } from '../schema/index.mjs';
4
3
  export declare class Validator<Context extends TProperties = TProperties, Type extends TSchema = TSchema, Encode extends unknown = StaticEncode<Type, Context>, Decode extends unknown = StaticDecode<Type, Context>> {
5
4
  private readonly hasCodec;
6
5
  private readonly buildResult;
7
6
  private readonly evaluateResult;
8
- /** Constructs a Validator with the given Context and Type. */
7
+ /** Constructs a Validator. */
9
8
  constructor(context: Context, type: Type);
10
- /** Constructs a Validator with the given arguments. */
11
- constructor(hasCodec: boolean, buildResult: BuildResult, evaluateResult: EvaluateResult);
12
9
  /** Returns true if this Validator is using JIT acceleration. */
13
10
  IsAccelerated(): boolean;
14
11
  /** Returns the Context for this validator. */
@@ -61,5 +61,5 @@ export declare function Keys(value: Record<PropertyKey, unknown>): string[];
61
61
  export declare function Symbols(value: Record<PropertyKey, unknown>): symbol[];
62
62
  /** Returns the property values for the given object via `Object.values()` */
63
63
  export declare function Values(value: Record<PropertyKey, unknown>): unknown[];
64
- /** Tests values for deep equality */
64
+ /** Returns true if left and right values are structurally equal */
65
65
  export declare function IsDeepEqual(left: unknown, right: unknown): boolean;
@@ -1,3 +1,4 @@
1
+ // deno-fmt-ignore-file
1
2
  import * as String from './string.mjs';
2
3
  // --------------------------------------------------------------------------
3
4
  // Guards
@@ -203,7 +204,9 @@ function DeepEqualArray(left, right) {
203
204
  return IsArray(right) && IsEqual(left.length, right.length) &&
204
205
  left.every((_, index) => IsDeepEqual(left[index], right[index]));
205
206
  }
206
- /** Tests values for deep equality */
207
+ /** Returns true if left and right values are structurally equal */
207
208
  export function IsDeepEqual(left, right) {
208
- return (IsArray(left) ? DeepEqualArray(left, right) : IsObject(left) ? DeepEqualObject(left, right) : IsEqual(left, right));
209
+ return (IsArray(left) ? DeepEqualArray(left, right) :
210
+ IsObject(left) ? DeepEqualObject(left, right) :
211
+ IsEqual(left, right));
209
212
  }
@@ -5,6 +5,18 @@ function IsBetween(value, min, max) {
5
5
  return value >= min && value <= max;
6
6
  }
7
7
  // --------------------------------------------------------------------------
8
+ // IsZeroWidthJoiner
9
+ // --------------------------------------------------------------------------
10
+ function IsZeroWidthJoiner(value) {
11
+ return (value === 0x200D);
12
+ }
13
+ // --------------------------------------------------------------------------
14
+ // IsHighSurrogate
15
+ // --------------------------------------------------------------------------
16
+ function IsHighSurrogate(value) {
17
+ return IsBetween(value, 0xD800, 0xDBFF);
18
+ }
19
+ // --------------------------------------------------------------------------
8
20
  // IsRegionalIndicator
9
21
  // --------------------------------------------------------------------------
10
22
  function IsRegionalIndicator(value) {
@@ -72,10 +84,10 @@ function NextGraphemeClusterIndex(value, clusterStart) {
72
84
  // IsGraphemeCodePoint
73
85
  // --------------------------------------------------------------------------
74
86
  function IsGraphemeCodePoint(value) {
75
- return (IsBetween(value, 0xD800, 0xDBFF) || // High surrogate
76
- IsBetween(value, 0x0300, 0x036F) || // Combining diacritical marks
77
- (value === 0x200D) // Zero-width joiner
78
- );
87
+ return (IsHighSurrogate(value) ||
88
+ IsCombiningMark(value) ||
89
+ IsVariationSelector(value) ||
90
+ IsZeroWidthJoiner(value));
79
91
  }
80
92
  // --------------------------------------------------------------------------
81
93
  // GraphemeCount
@@ -1,47 +1,66 @@
1
1
  // deno-fmt-ignore-file
2
- import * as Schema from '../types/index.mjs';
3
2
  import { Hashing } from '../../system/hashing/index.mjs';
4
3
  import { EmitGuard as E } from '../../guard/index.mjs';
5
4
  import { BuildSchema } from './schema.mjs';
6
- const functions = new Map();
5
+ const index = [0];
6
+ const names = new Map;
7
+ const funcs = new Map();
8
+ // ------------------------------------------------------------------
9
+ // CreateName
10
+ // ------------------------------------------------------------------
11
+ function NextName() {
12
+ return Hashing.Hash(index[0]++);
13
+ }
14
+ function CreateName(schema, href) {
15
+ if (!names.has(schema))
16
+ names.set(schema, new Map());
17
+ const hrefs = names.get(schema);
18
+ if (hrefs.has(href))
19
+ return hrefs.get(href);
20
+ const name = NextName();
21
+ hrefs.set(href, name);
22
+ return name;
23
+ }
7
24
  // ------------------------------------------------------------------
8
25
  // CreateCallExpression
9
26
  // ------------------------------------------------------------------
10
- function CreateCallExpression(context, _schema, hash, value) {
27
+ function CreateCallExpression(context, _schema, name, value) {
11
28
  return context.UseUnevaluated()
12
- ? E.Call(`check_${hash}`, ['context', value])
13
- : E.Call(`check_${hash}`, [value]);
29
+ ? E.Call(`check_${name}`, ['context', value])
30
+ : E.Call(`check_${name}`, [value]);
14
31
  }
15
32
  // ------------------------------------------------------------------
16
33
  // CreateFunctionExpression
17
34
  // ------------------------------------------------------------------
18
- function CreateFunctionExpression(stack, context, schema, hash) {
35
+ function CreateFunctionExpression(stack, context, schema, name) {
19
36
  const expression = BuildSchema(stack, context, schema, 'value');
20
37
  return context.UseUnevaluated()
21
- ? E.ConstDeclaration(`check_${hash}`, E.ArrowFunction(['context', 'value'], expression))
22
- : E.ConstDeclaration(`check_${hash}`, E.ArrowFunction(['value'], expression));
38
+ ? E.ConstDeclaration(`check_${name}`, E.ArrowFunction(['context', 'value'], expression))
39
+ : E.ConstDeclaration(`check_${name}`, E.ArrowFunction(['value'], expression));
23
40
  }
24
41
  // ------------------------------------------------------------------
25
42
  // ResetFunctions
26
43
  // ------------------------------------------------------------------
27
44
  export function ResetFunctions() {
28
- functions.clear();
45
+ index[0] = 0;
46
+ names.clear();
47
+ funcs.clear();
29
48
  }
30
49
  // ------------------------------------------------------------------
31
50
  // GetFunctions
32
51
  // ------------------------------------------------------------------
33
52
  export function GetFunctions() {
34
- return [...functions.values()];
53
+ return [...funcs.values()];
35
54
  }
36
55
  // ------------------------------------------------------------------
37
56
  // CreateFunction
38
57
  // ------------------------------------------------------------------
39
58
  export function CreateFunction(stack, context, schema, value) {
40
- const hash = Schema.IsSchemaObject(schema) ? Hashing.Hash({ __baseURL: stack.BaseURL().href, ...schema }) : Hashing.Hash(schema);
41
- const call = CreateCallExpression(context, schema, hash, value);
42
- if (functions.has(hash))
59
+ const name = CreateName(schema, stack.BaseURL().href);
60
+ const call = CreateCallExpression(context, schema, name, value);
61
+ if (funcs.has(name))
43
62
  return call;
44
- functions.set(hash, '');
45
- functions.set(hash, CreateFunctionExpression(stack, context, schema, hash));
63
+ funcs.set(name, '');
64
+ funcs.set(name, CreateFunctionExpression(stack, context, schema, name));
46
65
  return call;
47
66
  }
@@ -9,3 +9,8 @@ export declare function ReadonlyObjectDeferred<Type extends TSchema>(type: Type,
9
9
  export type TReadonlyObject<Type extends TSchema> = (TReadonlyObjectAction<Type>);
10
10
  /** This type is an alias for TypeScript's `Readonly<T>` utility type. It will make all properties of a TObject readonly or marks an TArray or TTuple as immutable `readonly T[]`. */
11
11
  export declare function ReadonlyObject<Type extends TSchema>(type: Type, options?: TSchemaOptions): TReadonlyObject<Type>;
12
+ /**
13
+ * This type has been renamed to ReadonlyObject.
14
+ * @deprecated
15
+ */
16
+ export declare const ReadonlyType: typeof ReadonlyObject;
@@ -9,3 +9,11 @@ export function ReadonlyObjectDeferred(type, options = {}) {
9
9
  export function ReadonlyObject(type, options = {}) {
10
10
  return ReadonlyObjectAction(type, options);
11
11
  }
12
+ // ------------------------------------------------------------------
13
+ // Alias
14
+ // ------------------------------------------------------------------
15
+ /**
16
+ * This type has been renamed to ReadonlyObject.
17
+ * @deprecated
18
+ */
19
+ export const ReadonlyType = ReadonlyObject;
@@ -19,7 +19,7 @@ export { Omit, type TOmit, type TOmitDeferred } from './type/action/omit.mjs';
19
19
  export { Parameters, type TParameters, type TParametersDeferred } from './type/action/parameters.mjs';
20
20
  export { Partial, type TPartial, type TPartialDeferred } from './type/action/partial.mjs';
21
21
  export { Pick, type TPick, type TPickDeferred } from './type/action/pick.mjs';
22
- export { ReadonlyObject, type TReadonlyObject, type TReadonlyObjectDeferred } from './type/action/readonly_object.mjs';
22
+ export { ReadonlyObject, ReadonlyType, type TReadonlyObject, type TReadonlyObjectDeferred } from './type/action/readonly_object.mjs';
23
23
  export { Required, type TRequired, type TRequiredDeferred } from './type/action/required.mjs';
24
24
  export { ReturnType, type TReturnType, type TReturnTypeDeferred } from './type/action/return_type.mjs';
25
25
  export { type TUncapitalize, type TUncapitalizeDeferred, Uncapitalize } from './type/action/uncapitalize.mjs';
@@ -31,7 +31,7 @@ export { Omit } from './type/action/omit.mjs';
31
31
  export { Parameters } from './type/action/parameters.mjs';
32
32
  export { Partial } from './type/action/partial.mjs';
33
33
  export { Pick } from './type/action/pick.mjs';
34
- export { ReadonlyObject } from './type/action/readonly_object.mjs';
34
+ export { ReadonlyObject, ReadonlyType } from './type/action/readonly_object.mjs';
35
35
  export { Required } from './type/action/required.mjs';
36
36
  export { ReturnType } from './type/action/return_type.mjs';
37
37
  export { Uncapitalize } from './type/action/uncapitalize.mjs';
@@ -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.3.3",
4
+ "version": "1.3.6",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
@@ -111,27 +111,24 @@ type User = Type.Static<typeof User> // type User = {
111
111
 
112
112
  ## Script
113
113
 
114
- [Documentation](https://sinclairzx81.github.io/typebox/#/docs/script/overview) | [Example 1](https://www.typescriptlang.org/play/?target=99&module=7#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFonmXW32POv3b7k0AdAGUAxlGBgYACjwC5eAJS9G3VWvXdqdOADkAhiFQBnMHpGpKIiADsj8ALJ6YACzgBeREWFiJ0gAaUcHCEaHAAaqgiMNAATO5wAN5wZABccNYAriDEqFAANHBIaZnZuXAAvoHBROGR0VAAzPEAogBuegA2GU6oADwRUbFwAGSJcABexVk5UBUAfFUh6AP1ACwt7V09-XXQTaNJAO5TpbPlC35KygAiqGjWACao1vD6hiZmFla28En2xq5yvF+KhvOJJFIknIBI4XBUCn4gosahFYKgyPEElUgpAjMAYMAbGkVtBVnlseloCBOsTdo1yUEghlWrTBlAYlVKkElnAAOKoHCoGBQJCYimtXIE8xGWlosgAbQAugzGcBHsBpScZkrOcjQrDcsBOmLGXADMRgM8YKy1iqgg9gBgMBkjKgbaS7XATJEMh09FB3VBVrruTV-kZXB4saaAOYCwzCop8+NCkWe6kwQ00uAG8SdXWXLT0ABKGReoHQxdQGA6dUJ1ko4ecAjA2DQsEtRgEccFiZbbclnYEEo70oE+NQIC7rYg7YJxhbEDxBJs-dng4XZEbALXc6HPYTIt3G67I6lC4nU+PHYX1ipnWv867W6bj-3Kb7M73C7PGovmavL8TwEZk303bcIzArsMyzDooIEB0nRdUEgJvZ8IObVCnwEGC8zgrCh3NS0Xngl8dwIhdcKNfCBzQgRvREX1-VIos4CEGAnA1OAAElrAwXJnnMShnWsKJ6zgKBnieKApHeZw0hBYQOKlXolggDAcwBOYFESKo5O7D8j1-aV5QABkVRdl3rAQtyCfSD1TJBh0HEzzIEO8oGpODbLgezDKc4zjDMizQJ8-SqIfRDnVdGy9J3CK4KIq1Yrs+Kejw+i0EYv0oFi8ogA) | [Example 2](https://www.typescriptlang.org/play/?target=99&module=7#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFonmXW32POv3b7k0AdACpejbuImTu1OnAByAQxCoAzmAUBjVJQB2S1eq1wAsgpgALOAG9KcOKjKRYcDRB0r4ANVQaY0AExwALyIRAIA8sQAVj4wABRWcGQAXKGCcgCuIMSoUHEAlAA0cEip-KgCmdm5BXAAvvm29o7Q8K7uXrHQAMzBaRUAogBuCgA2GWaoceUCAJI6MLkqsXEA2t6+AcUzkTG+CXAAXmVhVTl5+fX5ALr5jXYOTm1uHnAbflAALH0zw2MTi2mYXmiygy326y6UG62zCuxWiQA7id0llzrUGrdGnUZPQACKoNA6AAmqAW8n0ak02nar28sAcPzh0QRTUgKmAMGAblSpgsAne0E+hSaOmgIDGvLM5gFUJhTQyQyl-MFUH8lAalFp8AA4qgcKgYFAkEzBPD9jY7ENclytCoURUAIJQKAKJBxemLMhFJrAEnAO0OgTO13umZnGp3DWNbUmSZQYBjU0Vc3xS1wJTEYBkmDKmWq4VNYnADAYDLLPOyzZfEV2NQ+DKjBRQSsF6Nal7wYyqSwhHYsi1NADm+uURtKcD1BvHtbgEtBidGytyi-bogAShkFqB0OvUBhRrFuTpKN2VDKwNg0LBsyoBCPp8aBJeINeuaoBNab3aBJzUCA7xfN9b2fCAOS5NxnyvG0QLIU8eyg18YI-B8xyfIDkLvL9bQ-P8AMQ4CPzFKAJVGAjMIEOCzwvaCbxQ0dDXQ2j3ywmCfzwwDmJAxVyLou8qIQjC+IEecVzGXiWIEYtS3LCohMkgTzwkkDRITcT5JAzNswWZSP0UmikOE1TF10u96w0Rtm1MyjcTgABlGAzADOB5gwXIyS0Sgyx0XxjzgKAyVJPJlHPIMHKcjQAB5CDQCAMBMHsAD5LnTEKZVQxikE-NjVFWAAGa5QPA48bLsNL7wY8dsu-XKCoEYjSNKucEIyqrsIDWrCp4uCyoQ4zxOkstlia8r+rIrScxGvr4xM8zLKgGy6iAA) | [Challenge](test/typescript/readme.md)
115
-
116
- TypeBox includes a syntax engine that can transform TypeScript declarations into JSON Schema. The engine is a full syntactic frontend to Type.* and supports many advanced type-level constructs such as Conditional, Mapped, Indexed, Infer, Generics, Distributed types and more. This feature is implemented symmetrically at runtime and statically via TypeScript Template Literal types.
117
-
118
- Syntax highlighting is available via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=sinclairzx81.typebox-script)
114
+ [Documentation](https://sinclairzx81.github.io/typebox/#/docs/script/overview) | [Example 1](https://www.typescriptlang.org/play/?target=99&module=7#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFkIATAVwBtVKBjCAOwDO8BgEMYACzgBeREQB0AZW5RgYGAAoABpThxCaOADVU3GNABM0uAG84ZAFxw+rEMVRQANHCSPnr93AAvjp6REYmZlAAzFa2Dk4ubp7evonuXgBeqf5QQSH66Mam0AAssXbZSV4+CTmZlelwAO4NucGaAJTUdHAAIqhofMyofMIsHFy8gvC2DKgCkoFWyGiKyqoaohJemrr5YcawqGSxIbqQAsAwwPyORZElHmdO0CAi7HcR0FFPurqsADdPsUoOYQsFdAU4ABxVA4VAwKBIU5-OAA9zXbjzT5HMgAbQAur8-sAhsAsQJWoTwfsDFt3MB3ii-iJXMARjBgQ9ibpmMAMBhWAJUFzSjy4AI0NwOCIoKKoCUaZCwnMFszdABzOEgBFIxyw+GIpDit4wBnvRz0lTvGmdbr0ABKrFGoHQDtQGE4phufEoqvEcjA2DQsHZAjkWsNSMDwYxYbk6NDFLkV1QIHDQYgIeu80DEEu134MazcdzZD98wDmez8cjOqNxZrucTmNzqfTjdL4b4r3endDZYrC37OfDdd1SBH8Zb5LbZo71a7ckBU8H-tX4dN5vYG7kfIFQtQu-L68XA83Ym3u9ZxHZo2PQ6rsfPci31p3Z9HcklJhlUAftD0AoMBiOScAAJJ8Bg7gjFilCCnw3r8HAUAjMMUDqDqCyOCsR7AaB3AADwFBAGCMJWAB8HQ2CEWEBuODYzhSeIAAwEnmBY+nI5a6HREbahOCZxsxbFyD2UBvDuPFwHxDHRkx8ysexK7SXxb6Mju+6CsK3G0ZWr6Xu+cg3neMC6bx+nqX2P7Suwsq6YEQA) | [Example 2](https://www.typescriptlang.org/play/?target=99&module=7#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFkIATAVwBtVKA7AQxFQBnMLwDG6BrxgALOAG9KcOKjKRYcURG6D4ANVSiY0AExwAvIiIA6APLEAVgZgAKOXDIAuS2isA5ViDEqFDOAJQANHBIXsg+-oHBYXAAvqGKyqrQ8Jraek7QAMzm3qi2Dk6u7jHW8UEhEVHVcQF1YZEAXk2ltYmhKWlKKmrZWjpw+obQACzFsaV2joaVniV+Lb2R0as99R1dawm7cADu+ztJqZTJ1HRwACKoaNzMqNzwTGyclDlj+rAqs2sCwqCiUkEEwBgwC0XkkMisEyMUCm4XS3GgIF47FhUmkCPyUAKqKUrAAbjj4YiTFc0j94ABxVA4VAwKBIQE+YFLUFwUnBKHiQT7ACCUCgvCQzj+MBUEXSwGewEFIrFEuccwOrVCaUudMYUmCwCxHPm5W56X4xGArxgFLxVORxLgzGAGAwrEEqDt+MmjvSwgMHF4UG9DqmNO+o3eQlkFg1XJcPIA5kyBKytozmemnZiZVAjdj9XmCxHaPQAEqsN6gdDl1AYTiGaHcSgMGNWMDYNCwa2CKwprNsjtd-m9qx8nuCqyQ1AgPudiDdqFCDsQCFQrTDxejldkVvthdLscDtNDw87vsTgUrmdzrdHlfoqCY9j3i9WPdtwR4889lcnlkzxHP9L1HKdb3nYDlz7Mk3xAj992-ODoKsXNDSxZCxxdN0PVKX8UM-A8oLHND8ww-Cx0ta03kw3dEJ-YiV1IgtaL7ANRCDKBWIQss4AAZRgKQlTgABJbgMGCV5xEod1uCbLQ4CgV4XhCARv32AShNEAAeQg0AgDBGBjAA+PoeTUvEAPTccwKEABtAAGABdVd12bBClAs-tU0ApAbMneznKsJ8Xw8uAvKsocryVQKXNgvdPPbZiMOw91PTCrzktfKibQypKDTI192M4hDkiAA) | [Challenge](test/typescript/readme.md)
119
115
 
116
+ TypeBox includes a runtime scripting engine that can transform TypeScript definitions into JSON Schema. The engine is implemented symmetrically at runtime and inside TypeScript's type system. It supports many programmable type-level constructs such as Conditional, Mapped, Indexed, Generic, Distributive Conditional, and more. The engine is designed for TypeScript 7 but is supported in TypeScript 5 and above.
120
117
 
121
118
  ### Example
122
119
 
123
- The following uses Script to parse TypeScript declarations into JSON Schema.
120
+ Syntax highlighting is available via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=sinclairzx81.typebox-script)
124
121
 
125
122
  ```typescript
126
123
  // Module
127
124
  const Math = Type.Script(`
128
125
  type Vector2 = { x: number, y: number }
129
- type Vector3 = Evaluate<Vector2 & { z: number }>
130
- type Vector4 = Evaluate<Vector3 & { w: number }>
126
+ type Vector3 = { x: number, y: number, z: number }
127
+ type Vector4 = { x: number, y: number, z: number, w: number }
131
128
  `)
132
129
 
133
130
  // Dependent Module
134
- const { Mesh } = Type.Script({ ...Math }, `
131
+ const { Mesh } = Type.Script(Math, `
135
132
  type Vertex = {
136
133
  position: Vector4,
137
134
  normal: Vector3,
@@ -298,29 +295,29 @@ The following table shows compile performance for various JSON Schema structures
298
295
  ┌──────────────────────┬─────────────┬─────────────┐
299
296
  │ Compile │ TB1X │ AJV8 │
300
297
  ├──────────────────────┼─────────────┼─────────────┤
301
- │ Boolean │ 29.2K ops/s │ 7.1K ops/s │
302
- │ Number │ 34.5K ops/s │ 7.6K ops/s │
303
- │ String │ 48.9K ops/s │ 8.7K ops/s │
304
- │ Null │ 39.6K ops/s │ 7.6K ops/s │
305
- │ Literal_String │ 46.8K ops/s │ 6.8K ops/s │
306
- │ Literal_Number │ 48.3K ops/s │ 7.4K ops/s │
307
- │ Literal_Boolean │ 48.8K ops/s │ 7.3K ops/s │
308
- │ Pattern │ 32.5K ops/s │ 6.1K ops/s │
309
- │ Object_Open │ 6.6K ops/s │ 1.4K ops/s │
310
- │ Object_Close │ 7.6K ops/s │ 1K ops/s │
311
- │ Object_Vector3 │ 20.8K ops/s │ 2.8K ops/s │
312
- │ Object_Basis3 │ 7.5K ops/s │ 1K ops/s │
313
- │ Intersect_And │ 23K ops/s │ 3.9K ops/s │
314
- │ Intersect_Structural │ 8.7K ops/s │ 1.2K ops/s │
315
- │ Union_Or │ 17.9K ops/s │ 3.4K ops/s │
316
- │ Union_Structural │ 11.3K ops/s │ 2.1K ops/s │
317
- │ Tuple_Values │ 9.6K ops/s │ 2.1K ops/s │
318
- │ Tuple_Objects │ 2.1K ops/s │ 350 ops/s │
319
- │ Array_Numbers_4 │ 33.6K ops/s │ 4.2K ops/s │
320
- │ Array_Numbers_8 │ 39K ops/s │ 3.7K ops/s │
321
- │ Array_Numbers_16 │ 29.6K ops/s │ 3.8K ops/s │
322
- │ Array_Objects_Open │ 7.7K ops/s │ 833 ops/s │
323
- │ Array_Objects_Close │ 7.6K ops/s │ 860 ops/s │
298
+ │ Boolean │ 39.7K ops/s │ 6.8K ops/s │
299
+ │ Number │ 86.2K ops/s │ 7.5K ops/s │
300
+ │ String │ 82.6K ops/s │ 8.2K ops/s │
301
+ │ Null │ 62K ops/s │ 7.3K ops/s │
302
+ │ Literal_String │ 72.1K ops/s │ 5.7K ops/s │
303
+ │ Literal_Number │ 72.7K ops/s │ 6.9K ops/s │
304
+ │ Literal_Boolean │ 80.9K ops/s │ 7K ops/s │
305
+ │ Pattern │ 38.7K ops/s │ 5.7K ops/s │
306
+ │ Object_Open │ 16.3K ops/s │ 1.3K ops/s │
307
+ │ Object_Close │ 15.7K ops/s │ 952 ops/s │
308
+ │ Object_Vector3 │ 40.2K ops/s │ 3.2K ops/s │
309
+ │ Object_Basis3 │ 16.1K ops/s │ 834 ops/s │
310
+ │ Intersect_And │ 45.7K ops/s │ 3.5K ops/s │
311
+ │ Intersect_Structural │ 21K ops/s │ 1.6K ops/s │
312
+ │ Union_Or │ 45.1K ops/s │ 3.4K ops/s │
313
+ │ Union_Structural │ 27.6K ops/s │ 2K ops/s │
314
+ │ Tuple_Values │ 14.7K ops/s │ 2K ops/s │
315
+ │ Tuple_Objects │ 3.7K ops/s │ 380 ops/s │
316
+ │ Array_Numbers_4 │ 73.6K ops/s │ 4.3K ops/s │
317
+ │ Array_Numbers_8 │ 50.9K ops/s │ 3.8K ops/s │
318
+ │ Array_Numbers_16 │ 85K ops/s │ 3.9K ops/s │
319
+ │ Array_Objects_Open │ 18.9K ops/s │ 789 ops/s │
320
+ │ Array_Objects_Close │ 17.9K ops/s │ 909 ops/s │
324
321
  └──────────────────────┴─────────────┴─────────────┘
325
322
  ```
326
323
 
@@ -77,6 +77,7 @@ class Receiver extends Writable {
77
77
 
78
78
  this._totalPayloadLength = 0;
79
79
  this._messageLength = 0;
80
+ this._numFragments = 0;
80
81
  this._fragments = [];
81
82
 
82
83
  this._errored = false;
@@ -500,6 +501,19 @@ class Receiver extends Writable {
500
501
  return;
501
502
  }
502
503
 
504
+ if (this._maxFragments > 0 && ++this._numFragments > this._maxFragments) {
505
+ const error = this.createError(
506
+ RangeError,
507
+ 'Too many message fragments',
508
+ false,
509
+ 1008,
510
+ 'WS_ERR_TOO_MANY_BUFFERED_PARTS'
511
+ );
512
+
513
+ cb(error);
514
+ return;
515
+ }
516
+
503
517
  if (this._compressed) {
504
518
  this._state = INFLATING;
505
519
  this.decompress(data, cb);
@@ -507,22 +521,6 @@ class Receiver extends Writable {
507
521
  }
508
522
 
509
523
  if (data.length) {
510
- if (
511
- this._maxFragments > 0 &&
512
- this._fragments.length >= this._maxFragments
513
- ) {
514
- const error = this.createError(
515
- RangeError,
516
- 'Too many message fragments',
517
- false,
518
- 1008,
519
- 'WS_ERR_TOO_MANY_BUFFERED_PARTS'
520
- );
521
-
522
- cb(error);
523
- return;
524
- }
525
-
526
524
  //
527
525
  // This message is not compressed so its length is the sum of the payload
528
526
  // length of all fragments.
@@ -562,22 +560,6 @@ class Receiver extends Writable {
562
560
  return;
563
561
  }
564
562
 
565
- if (
566
- this._maxFragments > 0 &&
567
- this._fragments.length >= this._maxFragments
568
- ) {
569
- const error = this.createError(
570
- RangeError,
571
- 'Too many message fragments',
572
- false,
573
- 1008,
574
- 'WS_ERR_TOO_MANY_BUFFERED_PARTS'
575
- );
576
-
577
- cb(error);
578
- return;
579
- }
580
-
581
563
  this._fragments.push(buf);
582
564
  }
583
565
 
@@ -604,6 +586,7 @@ class Receiver extends Writable {
604
586
  this._totalPayloadLength = 0;
605
587
  this._messageLength = 0;
606
588
  this._fragmented = 0;
589
+ this._numFragments = 0;
607
590
  this._fragments = [];
608
591
 
609
592
  if (this._opcode === 2) {
@@ -43,9 +43,9 @@ class WebSocketServer extends EventEmitter {
43
43
  * called
44
44
  * @param {Function} [options.handleProtocols] A hook to handle protocols
45
45
  * @param {String} [options.host] The hostname where to bind the server
46
- * @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
46
+ * @param {Number} [options.maxBufferedChunks=262144] The maximum number of
47
47
  * buffered data chunks
48
- * @param {Number} [options.maxFragments=131072] The maximum number of message
48
+ * @param {Number} [options.maxFragments=16384] The maximum number of message
49
49
  * fragments
50
50
  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
51
51
  * size
@@ -69,8 +69,8 @@ class WebSocketServer extends EventEmitter {
69
69
  options = {
70
70
  allowSynchronousEvents: true,
71
71
  autoPong: true,
72
- maxBufferedChunks: 1024 * 1024,
73
- maxFragments: 128 * 1024,
72
+ maxBufferedChunks: 256 * 1024,
73
+ maxFragments: 16 * 1024,
74
74
  maxPayload: 100 * 1024 * 1024,
75
75
  skipUTF8Validation: false,
76
76
  perMessageDeflate: false,
@@ -646,9 +646,9 @@ module.exports = WebSocket;
646
646
  * masking key
647
647
  * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
648
648
  * handshake request
649
- * @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
649
+ * @param {Number} [options.maxBufferedChunks=262144] The maximum number of
650
650
  * buffered data chunks
651
- * @param {Number} [options.maxFragments=131072] The maximum number of message
651
+ * @param {Number} [options.maxFragments=16384] The maximum number of message
652
652
  * fragments
653
653
  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
654
654
  * size
@@ -670,8 +670,8 @@ function initAsClient(websocket, address, protocols, options) {
670
670
  autoPong: true,
671
671
  closeTimeout: CLOSE_TIMEOUT,
672
672
  protocolVersion: protocolVersions[1],
673
- maxBufferedChunks: 1024 * 1024,
674
- maxFragments: 128 * 1024,
673
+ maxBufferedChunks: 256 * 1024,
674
+ maxFragments: 16 * 1024,
675
675
  maxPayload: 100 * 1024 * 1024,
676
676
  skipUTF8Validation: false,
677
677
  perMessageDeflate: true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ws",
3
- "version": "8.21.0",
3
+ "version": "8.21.1",
4
4
  "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
5
5
  "keywords": [
6
6
  "HyBi",
@@ -66,5 +66,9 @@
66
66
  "nyc": "^15.0.0",
67
67
  "prettier": "^3.0.0",
68
68
  "utf-8-validate": "^6.0.0"
69
+ },
70
+ "allowScripts": {
71
+ "bufferutil": true,
72
+ "utf-8-validate": true
69
73
  }
70
74
  }
@@ -11,20 +11,6 @@
11
11
  "contracts": {
12
12
  "tools": ["voice_call"]
13
13
  },
14
- "channelEnvVars": {
15
- "voice-call": [
16
- "TELNYX_API_KEY",
17
- "TELNYX_CONNECTION_ID",
18
- "TELNYX_PUBLIC_KEY",
19
- "TWILIO_ACCOUNT_SID",
20
- "TWILIO_AUTH_TOKEN",
21
- "TWILIO_FROM_NUMBER",
22
- "PLIVO_AUTH_ID",
23
- "PLIVO_AUTH_TOKEN",
24
- "NGROK_AUTHTOKEN",
25
- "NGROK_DOMAIN"
26
- ]
27
- },
28
14
  "uiHints": {
29
15
  "provider": {
30
16
  "label": "Provider",
@@ -219,7 +205,7 @@
219
205
  },
220
206
  "tts.provider": {
221
207
  "label": "TTS Provider Override",
222
- "help": "Deep-merges with messages.tts (Microsoft is ignored for calls).",
208
+ "help": "Deep-merges with top-level tts (Microsoft is ignored for calls).",
223
209
  "advanced": true
224
210
  },
225
211
  "tts.providers": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/voice-call",
3
- "version": "2026.7.2-beta.3",
3
+ "version": "2026.7.2-beta.5",
4
4
  "description": "OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,12 +8,12 @@
8
8
  },
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "typebox": "1.3.3",
12
- "ws": "8.21.0",
11
+ "typebox": "1.3.6",
12
+ "ws": "8.21.1",
13
13
  "zod": "4.4.3"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.7.2-beta.3"
16
+ "openclaw": ">=2026.7.2-beta.5"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
@@ -30,10 +30,10 @@
30
30
  "minHostVersion": ">=2026.4.10"
31
31
  },
32
32
  "compat": {
33
- "pluginApi": ">=2026.7.2-beta.3"
33
+ "pluginApi": ">=2026.7.2-beta.5"
34
34
  },
35
35
  "build": {
36
- "openclawVersion": "2026.7.2-beta.3"
36
+ "openclawVersion": "2026.7.2-beta.5"
37
37
  },
38
38
  "release": {
39
39
  "publishToClawHub": true,
@@ -46,7 +46,6 @@
46
46
  "files": [
47
47
  "dist/**",
48
48
  "openclaw.plugin.json",
49
- "npm-shrinkwrap.json",
50
49
  "README.md",
51
50
  "skills/**"
52
51
  ],
@@ -1,61 +0,0 @@
1
- {
2
- "name": "@openclaw/voice-call",
3
- "version": "2026.7.2-beta.3",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "@openclaw/voice-call",
9
- "version": "2026.7.2-beta.3",
10
- "dependencies": {
11
- "typebox": "1.3.3",
12
- "ws": "8.21.0",
13
- "zod": "4.4.3"
14
- },
15
- "peerDependencies": {
16
- "openclaw": ">=2026.7.2-beta.3"
17
- },
18
- "peerDependenciesMeta": {
19
- "openclaw": {
20
- "optional": true
21
- }
22
- }
23
- },
24
- "node_modules/typebox": {
25
- "version": "1.3.3",
26
- "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.3.tgz",
27
- "integrity": "sha512-URXGUE31PJDQC+PtRMJeLdF4kmmOdFoVPikPCtV2oOIhUpNpppEdIz7W8bH8cFYPYHdDpaRvqwdegMTmHliudg==",
28
- "license": "MIT"
29
- },
30
- "node_modules/ws": {
31
- "version": "8.21.0",
32
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
33
- "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
34
- "license": "MIT",
35
- "engines": {
36
- "node": ">=10.0.0"
37
- },
38
- "peerDependencies": {
39
- "bufferutil": "^4.0.1",
40
- "utf-8-validate": ">=5.0.2"
41
- },
42
- "peerDependenciesMeta": {
43
- "bufferutil": {
44
- "optional": true
45
- },
46
- "utf-8-validate": {
47
- "optional": true
48
- }
49
- }
50
- },
51
- "node_modules/zod": {
52
- "version": "4.4.3",
53
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
54
- "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
55
- "license": "MIT",
56
- "funding": {
57
- "url": "https://github.com/sponsors/colinhacks"
58
- }
59
- }
60
- }
61
- }