@clawvoice/voice-assistant 1.0.0

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 (50) hide show
  1. package/.env.example +125 -0
  2. package/CHANGELOG.md +112 -0
  3. package/LICENSE +21 -0
  4. package/README.md +215 -0
  5. package/dist/cli.d.ts +10 -0
  6. package/dist/cli.js +272 -0
  7. package/dist/config.d.ts +42 -0
  8. package/dist/config.js +182 -0
  9. package/dist/diagnostics/health.d.ts +14 -0
  10. package/dist/diagnostics/health.js +182 -0
  11. package/dist/hooks.d.ts +16 -0
  12. package/dist/hooks.js +113 -0
  13. package/dist/inbound/classifier.d.ts +5 -0
  14. package/dist/inbound/classifier.js +72 -0
  15. package/dist/inbound/types.d.ts +30 -0
  16. package/dist/inbound/types.js +2 -0
  17. package/dist/index.d.ts +5 -0
  18. package/dist/index.js +52 -0
  19. package/dist/routes.d.ts +6 -0
  20. package/dist/routes.js +89 -0
  21. package/dist/services/memory-extraction.d.ts +42 -0
  22. package/dist/services/memory-extraction.js +117 -0
  23. package/dist/services/post-call.d.ts +56 -0
  24. package/dist/services/post-call.js +112 -0
  25. package/dist/services/relay.d.ts +9 -0
  26. package/dist/services/relay.js +19 -0
  27. package/dist/services/voice-call.d.ts +61 -0
  28. package/dist/services/voice-call.js +189 -0
  29. package/dist/telephony/telnyx.d.ts +12 -0
  30. package/dist/telephony/telnyx.js +60 -0
  31. package/dist/telephony/twilio.d.ts +12 -0
  32. package/dist/telephony/twilio.js +63 -0
  33. package/dist/telephony/types.d.ts +15 -0
  34. package/dist/telephony/types.js +2 -0
  35. package/dist/telephony/util.d.ts +2 -0
  36. package/dist/telephony/util.js +25 -0
  37. package/dist/tools.d.ts +5 -0
  38. package/dist/tools.js +167 -0
  39. package/dist/voice/bridge.d.ts +47 -0
  40. package/dist/voice/bridge.js +411 -0
  41. package/dist/voice/types.d.ts +168 -0
  42. package/dist/voice/types.js +42 -0
  43. package/dist/webhooks/verify.d.ts +30 -0
  44. package/dist/webhooks/verify.js +95 -0
  45. package/docs/FEATURES.md +36 -0
  46. package/docs/OPENCLAW_PLUGIN_GUIDE.md +1202 -0
  47. package/docs/SETUP.md +303 -0
  48. package/openclaw.plugin.json +137 -0
  49. package/package.json +37 -0
  50. package/skills/voice-assistant/SKILL.md +15 -0
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyTelnyxSignature = verifyTelnyxSignature;
4
+ exports.verifyTwilioSignature = verifyTwilioSignature;
5
+ exports.getVerifier = getVerifier;
6
+ const node_crypto_1 = require("node:crypto");
7
+ /**
8
+ * Verify Telnyx webhook signature using Ed25519 public-key cryptography.
9
+ * Telnyx sends `telnyx-signature-ed25519` and `telnyx-timestamp` headers.
10
+ * The signed payload is `timestamp|payload`.
11
+ * The `secret` parameter is the Ed25519 public key from the Telnyx dashboard.
12
+ */
13
+ function verifyTelnyxSignature(payload, signatureHeader, timestampHeader, publicKey) {
14
+ if (!publicKey) {
15
+ return {
16
+ valid: false,
17
+ provider: "telnyx",
18
+ reason: "No webhook public key configured (telnyxWebhookSecret)",
19
+ };
20
+ }
21
+ if (!signatureHeader || !timestampHeader) {
22
+ return {
23
+ valid: false,
24
+ provider: "telnyx",
25
+ reason: "Missing telnyx-signature-ed25519 or telnyx-timestamp header",
26
+ };
27
+ }
28
+ try {
29
+ const signedPayload = `${timestampHeader}|${payload}`;
30
+ const signatureBytes = Buffer.from(signatureHeader, "hex");
31
+ const publicKeyDer = Buffer.concat([
32
+ Buffer.from("302a300506032b6570032100", "hex"),
33
+ Buffer.from(publicKey, "base64"),
34
+ ]);
35
+ const valid = (0, node_crypto_1.verify)(null, Buffer.from(signedPayload), { key: publicKeyDer, format: "der", type: "spki" }, signatureBytes);
36
+ if (!valid) {
37
+ return { valid: false, provider: "telnyx", reason: "Signature mismatch" };
38
+ }
39
+ return { valid: true, provider: "telnyx" };
40
+ }
41
+ catch {
42
+ return { valid: false, provider: "telnyx", reason: "Signature verification failed" };
43
+ }
44
+ }
45
+ /**
46
+ * Verify Twilio webhook signature using HMAC-SHA1.
47
+ * Twilio computes HMAC-SHA1 of the request URL + sorted POST params.
48
+ */
49
+ function verifyTwilioSignature(url, params, signatureHeader, authToken) {
50
+ if (!authToken) {
51
+ return {
52
+ valid: false,
53
+ provider: "twilio",
54
+ reason: "No auth token configured (twilioAuthToken)",
55
+ };
56
+ }
57
+ if (!signatureHeader) {
58
+ return {
59
+ valid: false,
60
+ provider: "twilio",
61
+ reason: "Missing X-Twilio-Signature header",
62
+ };
63
+ }
64
+ // Twilio signature = Base64(HMAC-SHA1(AuthToken, URL + sorted-params-concatenated))
65
+ const sortedKeys = Object.keys(params).sort();
66
+ let dataToSign = url;
67
+ for (const key of sortedKeys) {
68
+ dataToSign += key + params[key];
69
+ }
70
+ const expectedSig = (0, node_crypto_1.createHmac)("sha1", authToken)
71
+ .update(dataToSign)
72
+ .digest("base64");
73
+ const sigBuffer = Buffer.from(signatureHeader);
74
+ const expectedBuffer = Buffer.from(expectedSig);
75
+ if (sigBuffer.length !== expectedBuffer.length) {
76
+ return {
77
+ valid: false,
78
+ provider: "twilio",
79
+ reason: "Signature mismatch",
80
+ };
81
+ }
82
+ const match = (0, node_crypto_1.timingSafeEqual)(sigBuffer, expectedBuffer);
83
+ if (!match) {
84
+ return { valid: false, provider: "twilio", reason: "Signature mismatch" };
85
+ }
86
+ return { valid: true, provider: "twilio" };
87
+ }
88
+ /**
89
+ * Get the appropriate verification function for the configured provider.
90
+ */
91
+ function getVerifier(config) {
92
+ return config.telephonyProvider === "telnyx"
93
+ ? { verify: verifyTelnyxSignature, secret: config.telnyxWebhookSecret }
94
+ : { verify: verifyTwilioSignature, token: config.twilioAuthToken };
95
+ }
@@ -0,0 +1,36 @@
1
+ # ClawVoice Features
2
+
3
+ ClawVoice is a voice calling plugin for OpenClaw that adds PSTN voice channels for AI agents.
4
+
5
+ ## Core Features
6
+
7
+ - OpenClaw voice channel plugin architecture (`kind: "channel"`, `channels: ["voice"]`).
8
+ - Inbound and outbound phone call support for agent-led conversations.
9
+ - Telephony provider support for Telnyx and Twilio.
10
+ - Voice provider configuration for Deepgram Agent and ElevenLabs Conversational modes.
11
+ - Agent tools for call workflows:
12
+ - `voice_assistant.call`
13
+ - `voice_assistant.hangup`
14
+ - `voice_assistant.status`
15
+ - `voice_assistant.promote_memory`
16
+ - Interactive setup wizard via CLI (`clawvoice setup`).
17
+ - Configurable voice persona via `voiceSystemPrompt` to define agent behavior on calls.
18
+ - Enable/disable inbound call answering via `inboundEnabled` config flag.
19
+ - Configuration precedence with deterministic resolution:
20
+ - environment variables
21
+ - plugin configuration
22
+ - defaults
23
+ - Runtime config validation that blocks startup on missing required fields.
24
+ - Voice session safety controls:
25
+ - optional tool restriction in voice sessions
26
+ - deny-list support for high-risk tools
27
+ - Voice memory isolation by redirecting voice writes to the `voice-memory` namespace.
28
+ - Call lifecycle service with active call tracking and provider adapter abstraction.
29
+ - Webhook route scaffolding for telephony provider event ingestion.
30
+
31
+ ## Interfaces Exposed
32
+
33
+ - Agent tool interface (`voice_assistant.*`).
34
+ - CLI interface (`openclaw clawvoice ...`).
35
+ - HTTP webhook routes (`/clawvoice/webhooks/...`).
36
+ - Hook integration for tool gating and memory write isolation.