@openclaw/voice-call 2026.3.13 → 2026.5.2-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.
Files changed (103) hide show
  1. package/README.md +27 -5
  2. package/api.ts +16 -0
  3. package/cli-metadata.ts +10 -0
  4. package/config-api.ts +12 -0
  5. package/index.test.ts +943 -0
  6. package/index.ts +379 -149
  7. package/openclaw.plugin.json +384 -157
  8. package/package.json +35 -5
  9. package/runtime-api.ts +20 -0
  10. package/runtime-entry.ts +1 -0
  11. package/setup-api.ts +47 -0
  12. package/src/allowlist.test.ts +18 -0
  13. package/src/cli.ts +533 -68
  14. package/src/config-compat.test.ts +120 -0
  15. package/src/config-compat.ts +227 -0
  16. package/src/config.test.ts +273 -12
  17. package/src/config.ts +355 -72
  18. package/src/core-bridge.ts +2 -147
  19. package/src/deep-merge.test.ts +40 -0
  20. package/src/gateway-continue-operation.ts +200 -0
  21. package/src/http-headers.ts +6 -3
  22. package/src/manager/context.ts +6 -5
  23. package/src/manager/events.test.ts +243 -19
  24. package/src/manager/events.ts +61 -31
  25. package/src/manager/lifecycle.ts +53 -0
  26. package/src/manager/lookup.test.ts +52 -0
  27. package/src/manager/outbound.test.ts +528 -0
  28. package/src/manager/outbound.ts +163 -57
  29. package/src/manager/store.ts +18 -6
  30. package/src/manager/timers.test.ts +129 -0
  31. package/src/manager/timers.ts +4 -3
  32. package/src/manager/twiml.test.ts +13 -0
  33. package/src/manager/twiml.ts +8 -0
  34. package/src/manager.closed-loop.test.ts +30 -12
  35. package/src/manager.inbound-allowlist.test.ts +77 -10
  36. package/src/manager.notify.test.ts +344 -20
  37. package/src/manager.restore.test.ts +95 -8
  38. package/src/manager.test-harness.ts +8 -6
  39. package/src/manager.ts +79 -5
  40. package/src/media-stream.test.ts +578 -81
  41. package/src/media-stream.ts +235 -54
  42. package/src/providers/base.ts +19 -0
  43. package/src/providers/mock.ts +7 -1
  44. package/src/providers/plivo.test.ts +50 -6
  45. package/src/providers/plivo.ts +14 -6
  46. package/src/providers/shared/call-status.ts +2 -1
  47. package/src/providers/shared/guarded-json-api.test.ts +106 -0
  48. package/src/providers/shared/guarded-json-api.ts +1 -1
  49. package/src/providers/telnyx.test.ts +178 -6
  50. package/src/providers/telnyx.ts +40 -3
  51. package/src/providers/twilio/api.test.ts +145 -0
  52. package/src/providers/twilio/api.ts +67 -16
  53. package/src/providers/twilio/twiml-policy.ts +6 -10
  54. package/src/providers/twilio/webhook.ts +1 -1
  55. package/src/providers/twilio.test.ts +425 -25
  56. package/src/providers/twilio.ts +230 -77
  57. package/src/providers/twilio.types.ts +17 -0
  58. package/src/realtime-defaults.ts +3 -0
  59. package/src/realtime-fast-context.test.ts +88 -0
  60. package/src/realtime-fast-context.ts +165 -0
  61. package/src/realtime-transcription.runtime.ts +4 -0
  62. package/src/realtime-voice.runtime.ts +5 -0
  63. package/src/response-generator.test.ts +321 -0
  64. package/src/response-generator.ts +213 -53
  65. package/src/response-model.test.ts +71 -0
  66. package/src/response-model.ts +23 -0
  67. package/src/runtime.test.ts +429 -0
  68. package/src/runtime.ts +270 -24
  69. package/src/telephony-audio.test.ts +61 -0
  70. package/src/telephony-audio.ts +1 -79
  71. package/src/telephony-tts.test.ts +133 -12
  72. package/src/telephony-tts.ts +155 -2
  73. package/src/test-fixtures.ts +28 -7
  74. package/src/tts-provider-voice.test.ts +34 -0
  75. package/src/tts-provider-voice.ts +21 -0
  76. package/src/tunnel.test.ts +166 -0
  77. package/src/tunnel.ts +1 -1
  78. package/src/types.ts +24 -37
  79. package/src/utils.test.ts +17 -0
  80. package/src/voice-mapping.test.ts +34 -0
  81. package/src/voice-mapping.ts +3 -2
  82. package/src/webhook/realtime-handler.test.ts +598 -0
  83. package/src/webhook/realtime-handler.ts +485 -0
  84. package/src/webhook/stale-call-reaper.test.ts +88 -0
  85. package/src/webhook/stale-call-reaper.ts +5 -0
  86. package/src/webhook/tailscale.test.ts +214 -0
  87. package/src/webhook/tailscale.ts +19 -5
  88. package/src/webhook-exposure.test.ts +33 -0
  89. package/src/webhook-exposure.ts +84 -0
  90. package/src/webhook-security.test.ts +172 -21
  91. package/src/webhook-security.ts +43 -29
  92. package/src/webhook.hangup-once.lifecycle.test.ts +135 -0
  93. package/src/webhook.test.ts +1145 -27
  94. package/src/webhook.ts +523 -102
  95. package/src/webhook.types.ts +5 -0
  96. package/src/websocket-test-support.ts +72 -0
  97. package/tsconfig.json +16 -0
  98. package/CHANGELOG.md +0 -121
  99. package/src/providers/index.ts +0 -10
  100. package/src/providers/stt-openai-realtime.test.ts +0 -42
  101. package/src/providers/stt-openai-realtime.ts +0 -311
  102. package/src/providers/tts-openai.test.ts +0 -43
  103. package/src/providers/tts-openai.ts +0 -221
package/package.json CHANGED
@@ -1,17 +1,47 @@
1
1
  {
2
2
  "name": "@openclaw/voice-call",
3
- "version": "2026.3.13",
3
+ "version": "2026.5.2-beta.1",
4
4
  "description": "OpenClaw voice-call plugin",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/openclaw/openclaw"
8
+ },
5
9
  "type": "module",
6
10
  "dependencies": {
7
- "@sinclair/typebox": "0.34.48",
8
11
  "commander": "^14.0.3",
9
- "ws": "^8.19.0",
10
- "zod": "^4.3.6"
12
+ "typebox": "1.1.37",
13
+ "ws": "^8.20.0"
14
+ },
15
+ "devDependencies": {
16
+ "@openclaw/plugin-sdk": "workspace:*",
17
+ "openclaw": "workspace:*"
18
+ },
19
+ "peerDependencies": {
20
+ "openclaw": ">=2026.5.2-beta.1"
21
+ },
22
+ "peerDependenciesMeta": {
23
+ "openclaw": {
24
+ "optional": true
25
+ }
11
26
  },
12
27
  "openclaw": {
13
28
  "extensions": [
14
29
  "./index.ts"
15
- ]
30
+ ],
31
+ "install": {
32
+ "npmSpec": "@openclaw/voice-call",
33
+ "defaultChoice": "npm",
34
+ "minHostVersion": ">=2026.4.10"
35
+ },
36
+ "compat": {
37
+ "pluginApi": ">=2026.5.2-beta.1"
38
+ },
39
+ "build": {
40
+ "openclawVersion": "2026.5.2-beta.1"
41
+ },
42
+ "release": {
43
+ "publishToClawHub": true,
44
+ "publishToNpm": true
45
+ }
16
46
  }
17
47
  }
package/runtime-api.ts ADDED
@@ -0,0 +1,20 @@
1
+ // Private runtime barrel for the bundled Voice Call extension.
2
+ // Keep this barrel thin and aligned with the local extension surface.
3
+
4
+ export { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
5
+ export type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
6
+ export type { GatewayRequestHandlerOptions } from "openclaw/plugin-sdk/gateway-runtime";
7
+ export {
8
+ isRequestBodyLimitError,
9
+ readRequestBodyWithLimit,
10
+ requestBodyErrorToText,
11
+ } from "openclaw/plugin-sdk/webhook-request-guards";
12
+ export { fetchWithSsrFGuard, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
13
+ export type { SessionEntry } from "openclaw/plugin-sdk/session-store-runtime";
14
+ export {
15
+ TtsAutoSchema,
16
+ TtsConfigSchema,
17
+ TtsModeSchema,
18
+ TtsProviderSchema,
19
+ } from "openclaw/plugin-sdk/tts-runtime";
20
+ export { sleep } from "openclaw/plugin-sdk/runtime-env";
@@ -0,0 +1 @@
1
+ export { createVoiceCallRuntime, type VoiceCallRuntime } from "./src/runtime.js";
package/setup-api.ts ADDED
@@ -0,0 +1,47 @@
1
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/plugin-entry";
2
+ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
3
+ import { isRecord } from "openclaw/plugin-sdk/text-runtime";
4
+ import { migrateVoiceCallLegacyConfigInput } from "./config-api.js";
5
+
6
+ function migrateVoiceCallPluginConfig(config: OpenClawConfig): {
7
+ config: OpenClawConfig;
8
+ changes: string[];
9
+ } | null {
10
+ const rawVoiceCallConfig = config.plugins?.entries?.["voice-call"]?.config;
11
+ if (!isRecord(rawVoiceCallConfig)) {
12
+ return null;
13
+ }
14
+ const migration = migrateVoiceCallLegacyConfigInput({
15
+ value: rawVoiceCallConfig,
16
+ configPathPrefix: "plugins.entries.voice-call.config",
17
+ });
18
+ if (migration.changes.length === 0) {
19
+ return null;
20
+ }
21
+ const plugins = structuredClone(config.plugins ?? {});
22
+ const entries = { ...plugins.entries };
23
+ const existingVoiceCallEntry = isRecord(entries["voice-call"])
24
+ ? (entries["voice-call"] as Record<string, unknown>)
25
+ : {};
26
+ entries["voice-call"] = {
27
+ ...existingVoiceCallEntry,
28
+ config: migration.config,
29
+ };
30
+ plugins.entries = entries;
31
+ return {
32
+ config: {
33
+ ...config,
34
+ plugins,
35
+ },
36
+ changes: migration.changes,
37
+ };
38
+ }
39
+
40
+ export default definePluginEntry({
41
+ id: "voice-call",
42
+ name: "Voice Call Setup",
43
+ description: "Lightweight Voice Call setup hooks",
44
+ register(api) {
45
+ api.registerConfigMigration((config) => migrateVoiceCallPluginConfig(config));
46
+ },
47
+ });
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isAllowlistedCaller, normalizePhoneNumber } from "./allowlist.js";
3
+
4
+ describe("voice-call allowlist", () => {
5
+ it("normalizes phone numbers by stripping non-digits", () => {
6
+ expect(normalizePhoneNumber("+1 (415) 555-0123")).toBe("14155550123");
7
+ expect(normalizePhoneNumber(" 020-7946-0958 ")).toBe("02079460958");
8
+ expect(normalizePhoneNumber("")).toBe("");
9
+ expect(normalizePhoneNumber()).toBe("");
10
+ });
11
+
12
+ it("matches normalized allowlist entries and rejects blank callers", () => {
13
+ expect(isAllowlistedCaller("14155550123", ["+1 (415) 555-0123", " 020-7946-0958 "])).toBe(true);
14
+ expect(isAllowlistedCaller("02079460958", ["+1 (415) 555-0123", " 020-7946-0958 "])).toBe(true);
15
+ expect(isAllowlistedCaller("", ["+1 (415) 555-0123"])).toBe(false);
16
+ expect(isAllowlistedCaller("14155550123", ["", "abc"])).toBe(false);
17
+ });
18
+ });