@framers/agentos-ext-voice-twilio 0.1.0 → 0.1.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.
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ // @ts-nocheck
3
+ /**
4
+ * @fileoverview Twilio REST API wrapper for voice call operations.
5
+ * Handles Twilio client lifecycle, call creation, TwiML generation,
6
+ * and webhook signature verification.
7
+ *
8
+ * @module @framers/agentos-ext-voice-twilio/TwilioVoiceService
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.TwilioVoiceService = void 0;
45
+ const agentos_1 = require("@framers/agentos");
46
+ // ============================================================================
47
+ // Service
48
+ // ============================================================================
49
+ class TwilioVoiceService {
50
+ constructor(config) {
51
+ this.client = null;
52
+ this.running = false;
53
+ this.config = config;
54
+ }
55
+ /**
56
+ * Initialize the Twilio client.
57
+ * Lazily imports the twilio SDK to avoid hard failures if it's not installed.
58
+ */
59
+ async initialize() {
60
+ if (this.running)
61
+ return;
62
+ try {
63
+ // Dynamic import so the module fails gracefully if twilio isn't available
64
+ const twilio = await Promise.resolve().then(() => __importStar(require('twilio')));
65
+ const TwilioClient = twilio.default || twilio;
66
+ this.client = TwilioClient(this.config.accountSid, this.config.authToken);
67
+ }
68
+ catch (err) {
69
+ throw new Error(`Failed to initialize Twilio client. Ensure the 'twilio' package is installed. ${err}`);
70
+ }
71
+ this.running = true;
72
+ }
73
+ /**
74
+ * Shutdown and release the Twilio client.
75
+ */
76
+ async shutdown() {
77
+ if (!this.running)
78
+ return;
79
+ this.client = null;
80
+ this.running = false;
81
+ }
82
+ get isRunning() {
83
+ return this.running;
84
+ }
85
+ // ── Call Operations ──
86
+ /**
87
+ * Create an outbound call via the Twilio REST API.
88
+ *
89
+ * @param to - E.164 destination number.
90
+ * @param from - E.164 caller ID number.
91
+ * @param url - Webhook URL Twilio will request when the call connects.
92
+ * @param statusCallback - URL for call status change notifications.
93
+ * @param twiml - Optional inline TwiML (used instead of `url` if provided).
94
+ * @returns The Twilio call resource.
95
+ */
96
+ async createCall(to, from, url, statusCallback, twiml) {
97
+ this.ensureClient();
98
+ const params = {
99
+ to,
100
+ from,
101
+ statusCallback,
102
+ statusCallbackEvent: ['initiated', 'ringing', 'answered', 'completed'],
103
+ statusCallbackMethod: 'POST',
104
+ };
105
+ // If inline TwiML is provided, use it directly; otherwise point to the webhook URL
106
+ if (twiml) {
107
+ params.twiml = twiml;
108
+ }
109
+ else {
110
+ params.url = url;
111
+ }
112
+ const call = await this.client.calls.create(params);
113
+ return call;
114
+ }
115
+ /**
116
+ * Update an in-progress call (e.g., to hang up or redirect).
117
+ *
118
+ * @param callSid - The Twilio Call SID to update.
119
+ * @param updates - Fields to update on the call.
120
+ */
121
+ async updateCall(callSid, updates) {
122
+ this.ensureClient();
123
+ await this.client.calls(callSid).update(updates);
124
+ }
125
+ // ── TwiML Generation ──
126
+ /**
127
+ * Generate TwiML for "notify" mode: speak a message and hang up.
128
+ *
129
+ * @param message - The text to speak.
130
+ * @param voice - Twilio TTS voice name (default: 'Polly.Joanna').
131
+ * @returns TwiML XML string.
132
+ */
133
+ generateNotifyTwiml(message, voice = 'Polly.Joanna') {
134
+ const escapedMessage = (0, agentos_1.escapeXml)(message);
135
+ const escapedVoice = (0, agentos_1.escapeXml)(voice);
136
+ return [
137
+ '<?xml version="1.0" encoding="UTF-8"?>',
138
+ '<Response>',
139
+ ` <Say voice="${escapedVoice}">${escapedMessage}</Say>`,
140
+ ' <Hangup/>',
141
+ '</Response>',
142
+ ].join('\n');
143
+ }
144
+ /**
145
+ * Generate TwiML for "conversation" mode: connect a bidirectional media stream.
146
+ *
147
+ * @param mediaStreamUrl - WebSocket URL for the media stream.
148
+ * @param token - Optional auth token appended as a query param.
149
+ * @returns TwiML XML string.
150
+ */
151
+ generateConversationTwiml(mediaStreamUrl, token) {
152
+ const url = token
153
+ ? `${mediaStreamUrl}${mediaStreamUrl.includes('?') ? '&' : '?'}token=${encodeURIComponent(token)}`
154
+ : mediaStreamUrl;
155
+ const escapedUrl = (0, agentos_1.escapeXml)(url);
156
+ return [
157
+ '<?xml version="1.0" encoding="UTF-8"?>',
158
+ '<Response>',
159
+ ' <Connect>',
160
+ ` <Stream url="${escapedUrl}">`,
161
+ ' <Parameter name="direction" value="both"/>',
162
+ ' </Stream>',
163
+ ' </Connect>',
164
+ '</Response>',
165
+ ].join('\n');
166
+ }
167
+ // ── Webhook Verification ──
168
+ /**
169
+ * Verify a Twilio webhook signature using HMAC-SHA1.
170
+ *
171
+ * Twilio signs requests by concatenating the URL with sorted POST body params,
172
+ * then computing HMAC-SHA1 with the auth token. The signature is sent in the
173
+ * `X-Twilio-Signature` header.
174
+ *
175
+ * @param url - The full URL Twilio made the request to.
176
+ * @param params - The parsed POST body parameters.
177
+ * @param signature - The value of the X-Twilio-Signature header.
178
+ * @param authToken - The Twilio auth token (HMAC key).
179
+ * @returns Whether the signature is valid.
180
+ */
181
+ verifySignature(url, params, signature, authToken) {
182
+ try {
183
+ // Use twilio's built-in validator if available
184
+ const twilio = require('twilio');
185
+ const validateRequest = twilio.validateRequest || twilio.default?.validateRequest;
186
+ if (typeof validateRequest === 'function') {
187
+ return validateRequest(authToken, signature, url, params);
188
+ }
189
+ // Fallback: manual HMAC-SHA1 verification
190
+ return this.manualVerifySignature(url, params, signature, authToken);
191
+ }
192
+ catch {
193
+ // If twilio SDK isn't loadable synchronously, fall back to manual
194
+ return this.manualVerifySignature(url, params, signature, authToken);
195
+ }
196
+ }
197
+ /**
198
+ * Manual HMAC-SHA1 signature verification following Twilio's algorithm:
199
+ * 1. Take the full URL
200
+ * 2. Sort POST params by key, append key+value to URL
201
+ * 3. HMAC-SHA1 the result with auth token
202
+ * 4. Base64 encode and compare to X-Twilio-Signature
203
+ */
204
+ manualVerifySignature(url, params, signature, authToken) {
205
+ const crypto = require('node:crypto');
206
+ // Build the data string: URL + sorted params concatenated as key+value
207
+ let data = url;
208
+ const sortedKeys = Object.keys(params).sort();
209
+ for (const key of sortedKeys) {
210
+ data += key + params[key];
211
+ }
212
+ const computed = crypto
213
+ .createHmac('sha1', authToken)
214
+ .update(data, 'utf-8')
215
+ .digest('base64');
216
+ // Constant-time comparison
217
+ try {
218
+ return crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(signature));
219
+ }
220
+ catch {
221
+ // Lengths differ — not equal
222
+ return false;
223
+ }
224
+ }
225
+ // ── Private ──
226
+ ensureClient() {
227
+ if (!this.client) {
228
+ throw new Error('TwilioVoiceService not initialized. Call initialize() first.');
229
+ }
230
+ }
231
+ }
232
+ exports.TwilioVoiceService = TwilioVoiceService;
233
+ //# sourceMappingURL=TwilioVoiceService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TwilioVoiceService.js","sourceRoot":"","sources":["../src/TwilioVoiceService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @fileoverview Twilio Voice Call Extension for AgentOS.
3
+ *
4
+ * Provides an IVoiceCallProvider implementation for Twilio, plus an ITool
5
+ * descriptor that lets agents make and manage phone calls programmatically.
6
+ *
7
+ * Follows the same extension-pack pattern as the Telegram channel extension.
8
+ *
9
+ * @module @framers/agentos-ext-voice-twilio
10
+ */
11
+ import type { ExtensionContext, ExtensionPack } from '@framers/agentos';
12
+ import { TwilioVoiceService } from './TwilioVoiceService';
13
+ import { TwilioVoiceProvider } from './TwilioVoiceProvider';
14
+ import { VoiceCallTool } from './tools/voiceCall';
15
+ export interface TwilioVoiceOptions {
16
+ /** Twilio Account SID. */
17
+ accountSid?: string;
18
+ /** Twilio Auth Token. */
19
+ authToken?: string;
20
+ /** Default E.164 "from" phone number. */
21
+ fromNumber?: string;
22
+ /** Base URL for webhook callbacks (e.g., https://yourdomain.com). */
23
+ webhookBaseUrl?: string;
24
+ /** Env var name for account SID (default: TWILIO_ACCOUNT_SID). */
25
+ accountSidEnv?: string;
26
+ /** Env var name for auth token (default: TWILIO_AUTH_TOKEN). */
27
+ authTokenEnv?: string;
28
+ /** Env var name for from number (default: TWILIO_FROM_NUMBER). */
29
+ fromNumberEnv?: string;
30
+ /** Extension descriptor priority (default: 50). */
31
+ priority?: number;
32
+ /** Secrets map passed from registry. */
33
+ secrets?: Record<string, string>;
34
+ }
35
+ export declare function createExtensionPack(context: ExtensionContext): ExtensionPack;
36
+ export { TwilioVoiceService, TwilioVoiceProvider, VoiceCallTool };
37
+ export type { TwilioServiceConfig } from './TwilioVoiceService';
38
+ export type { VoiceCallToolHandler } from './tools/voiceCall';
39
+ export default createExtensionPack;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAA4B,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAA6B,MAAM,mBAAmB,CAAC;AAM7E,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAoCD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAmF5E;AAsCD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAE,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,eAAe,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ // @ts-nocheck
3
+ /**
4
+ * @fileoverview Twilio Voice Call Extension for AgentOS.
5
+ *
6
+ * Provides an IVoiceCallProvider implementation for Twilio, plus an ITool
7
+ * descriptor that lets agents make and manage phone calls programmatically.
8
+ *
9
+ * Follows the same extension-pack pattern as the Telegram channel extension.
10
+ *
11
+ * @module @framers/agentos-ext-voice-twilio
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.VoiceCallTool = exports.TwilioVoiceProvider = exports.TwilioVoiceService = void 0;
15
+ exports.createExtensionPack = createExtensionPack;
16
+ const TwilioVoiceService_1 = require("./TwilioVoiceService");
17
+ Object.defineProperty(exports, "TwilioVoiceService", { enumerable: true, get: function () { return TwilioVoiceService_1.TwilioVoiceService; } });
18
+ const TwilioVoiceProvider_1 = require("./TwilioVoiceProvider");
19
+ Object.defineProperty(exports, "TwilioVoiceProvider", { enumerable: true, get: function () { return TwilioVoiceProvider_1.TwilioVoiceProvider; } });
20
+ const voiceCall_1 = require("./tools/voiceCall");
21
+ Object.defineProperty(exports, "VoiceCallTool", { enumerable: true, get: function () { return voiceCall_1.VoiceCallTool; } });
22
+ // ============================================================================
23
+ // Secret Resolution
24
+ // ============================================================================
25
+ function resolveSecret(optionValue, secrets, secretKey, envVarOverride, defaultEnvVar, ...fallbackEnvVars) {
26
+ // 1. Direct option value
27
+ if (optionValue)
28
+ return optionValue;
29
+ // 2. Secrets map from registry
30
+ if (secrets?.[secretKey])
31
+ return secrets[secretKey];
32
+ // 3. Custom env var
33
+ const envName = envVarOverride ?? defaultEnvVar;
34
+ if (process.env[envName])
35
+ return process.env[envName];
36
+ // 4. Fallback env vars
37
+ for (const v of fallbackEnvVars) {
38
+ if (process.env[v])
39
+ return process.env[v];
40
+ }
41
+ return '';
42
+ }
43
+ // ============================================================================
44
+ // Factory
45
+ // ============================================================================
46
+ function createExtensionPack(context) {
47
+ const options = (context.options ?? {});
48
+ const accountSid = resolveSecret(options.accountSid, options.secrets, 'twilio.accountSid', options.accountSidEnv, 'TWILIO_ACCOUNT_SID');
49
+ const authToken = resolveSecret(options.authToken, options.secrets, 'twilio.authToken', options.authTokenEnv, 'TWILIO_AUTH_TOKEN');
50
+ const fromNumber = resolveSecret(options.fromNumber, options.secrets, 'twilio.fromNumber', options.fromNumberEnv, 'TWILIO_FROM_NUMBER', 'TWILIO_PHONE_NUMBER');
51
+ if (!accountSid || !authToken) {
52
+ throw new Error('Twilio credentials not found. Provide via options.accountSid/authToken, ' +
53
+ 'secrets["twilio.accountSid"/"twilio.authToken"], or ' +
54
+ 'TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN env vars.');
55
+ }
56
+ const config = {
57
+ accountSid,
58
+ authToken,
59
+ fromNumber,
60
+ webhookBaseUrl: options.webhookBaseUrl ?? process.env['TWILIO_WEBHOOK_BASE_URL'],
61
+ };
62
+ // ── Instantiate components ──
63
+ const service = new TwilioVoiceService_1.TwilioVoiceService(config);
64
+ const provider = new TwilioVoiceProvider_1.TwilioVoiceProvider(service);
65
+ // The tool handler delegates to a CallManager, but since the CallManager
66
+ // is owned by the host application (not this extension), we provide a
67
+ // no-op placeholder handler that can be replaced at runtime via the
68
+ // exported `setToolHandler()`.
69
+ let activeHandler = createPlaceholderHandler();
70
+ const voiceCallTool = new voiceCall_1.VoiceCallTool(
71
+ // Proxy handler so it always uses the latest activeHandler reference
72
+ {
73
+ initiateCall: (...args) => activeHandler.initiateCall(...args),
74
+ speakText: (...args) => activeHandler.speakText(...args),
75
+ hangupCall: (...args) => activeHandler.hangupCall(...args),
76
+ getCallStatus: (...args) => activeHandler.getCallStatus(...args),
77
+ getActiveCalls: () => activeHandler.getActiveCalls(),
78
+ });
79
+ const priority = options.priority ?? 50;
80
+ return {
81
+ name: '@framers/agentos-ext-voice-twilio',
82
+ version: '0.1.0',
83
+ descriptors: [
84
+ { id: 'twilioVoiceCall', kind: 'tool', priority, payload: voiceCallTool },
85
+ { id: 'twilioVoiceProvider', kind: 'voice-provider', priority, payload: provider },
86
+ ],
87
+ onActivate: async () => {
88
+ await service.initialize();
89
+ context.logger?.info('[TwilioVoice] Extension activated');
90
+ },
91
+ onDeactivate: async () => {
92
+ await service.shutdown();
93
+ context.logger?.info('[TwilioVoice] Extension deactivated');
94
+ },
95
+ };
96
+ }
97
+ // ============================================================================
98
+ // Placeholder Handler
99
+ // ============================================================================
100
+ /**
101
+ * Creates a placeholder VoiceCallToolHandler that returns sensible errors.
102
+ * The host application should replace this with a real handler backed by
103
+ * a CallManager instance via `setToolHandler()`.
104
+ */
105
+ function createPlaceholderHandler() {
106
+ return {
107
+ async initiateCall(_toNumber, _message, _mode) {
108
+ throw new Error('VoiceCallToolHandler not configured. The host application must provide a handler ' +
109
+ 'backed by a CallManager instance.');
110
+ },
111
+ speakText(_callId, _text) {
112
+ throw new Error('VoiceCallToolHandler not configured.');
113
+ },
114
+ async hangupCall(_callId) {
115
+ throw new Error('VoiceCallToolHandler not configured.');
116
+ },
117
+ getCallStatus(_callId) {
118
+ return undefined;
119
+ },
120
+ getActiveCalls() {
121
+ return [];
122
+ },
123
+ };
124
+ }
125
+ exports.default = createExtensionPack;
126
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @fileoverview ITool implementation for making and managing phone calls via Twilio.
3
+ *
4
+ * Provides agents with the ability to initiate calls, speak text, end calls,
5
+ * and query call status through a unified tool interface.
6
+ *
7
+ * @module @framers/agentos-ext-voice-twilio/tools/voiceCall
8
+ */
9
+ import type { ITool, ToolExecutionContext, ToolExecutionResult, CallMode, CallRecord } from '@framers/agentos';
10
+ /**
11
+ * Abstraction over call management that the tool delegates to.
12
+ * Typically backed by a {@link CallManager} instance, but can be mocked for testing.
13
+ */
14
+ export interface VoiceCallToolHandler {
15
+ /** Initiate an outbound call. */
16
+ initiateCall(toNumber: string, message?: string, mode?: CallMode): Promise<CallRecord>;
17
+ /** Speak text into an active call. */
18
+ speakText(callId: string, text: string): void;
19
+ /** Hang up an active call. */
20
+ hangupCall(callId: string): Promise<void>;
21
+ /** Get the current status of a call. */
22
+ getCallStatus(callId: string): CallRecord | undefined;
23
+ /** Get all active (non-terminal) calls. */
24
+ getActiveCalls(): CallRecord[];
25
+ }
26
+ interface VoiceCallToolInput {
27
+ /** The action to perform. */
28
+ action: 'initiate_call' | 'speak' | 'end_call' | 'get_status';
29
+ /** E.164 phone number to call (required for initiate_call). */
30
+ toNumber?: string;
31
+ /** Message text to speak (used for initiate_call in notify mode and speak action). */
32
+ message?: string;
33
+ /** Call ID (required for speak, end_call, get_status). */
34
+ callId?: string;
35
+ /** Call mode: 'notify' for one-way TTS, 'conversation' for bidirectional. */
36
+ mode?: CallMode;
37
+ }
38
+ export declare class VoiceCallTool implements ITool<VoiceCallToolInput> {
39
+ private readonly handler;
40
+ readonly id = "twilioVoiceCall";
41
+ readonly name = "twilioVoiceCall";
42
+ readonly displayName = "Twilio Voice Call";
43
+ readonly description: string;
44
+ readonly category = "communication";
45
+ readonly version = "0.1.0";
46
+ readonly hasSideEffects = true;
47
+ readonly inputSchema: {
48
+ type: "object";
49
+ required: readonly ["action"];
50
+ properties: {
51
+ action: {
52
+ type: string;
53
+ enum: string[];
54
+ description: string;
55
+ };
56
+ toNumber: {
57
+ type: string;
58
+ description: string;
59
+ };
60
+ message: {
61
+ type: string;
62
+ description: string;
63
+ };
64
+ callId: {
65
+ type: string;
66
+ description: string;
67
+ };
68
+ mode: {
69
+ type: string;
70
+ enum: string[];
71
+ description: string;
72
+ };
73
+ };
74
+ };
75
+ readonly outputSchema: {
76
+ type: "object";
77
+ properties: {
78
+ callId: {
79
+ type: string;
80
+ description: string;
81
+ };
82
+ state: {
83
+ type: string;
84
+ description: string;
85
+ };
86
+ provider: {
87
+ type: string;
88
+ description: string;
89
+ };
90
+ providerCallId: {
91
+ type: string;
92
+ description: string;
93
+ };
94
+ direction: {
95
+ type: string;
96
+ description: string;
97
+ };
98
+ mode: {
99
+ type: string;
100
+ description: string;
101
+ };
102
+ fromNumber: {
103
+ type: string;
104
+ description: string;
105
+ };
106
+ toNumber: {
107
+ type: string;
108
+ description: string;
109
+ };
110
+ activeCalls: {
111
+ type: string;
112
+ items: {
113
+ type: string;
114
+ };
115
+ description: string;
116
+ };
117
+ };
118
+ };
119
+ constructor(handler: VoiceCallToolHandler);
120
+ execute(args: VoiceCallToolInput, _context: ToolExecutionContext): Promise<ToolExecutionResult>;
121
+ validateArgs(args: Record<string, any>): {
122
+ isValid: boolean;
123
+ errors?: string[];
124
+ };
125
+ private handleInitiateCall;
126
+ private handleSpeak;
127
+ private handleEndCall;
128
+ private handleGetStatus;
129
+ }
130
+ export {};
131
+ //# sourceMappingURL=voiceCall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voiceCall.d.ts","sourceRoot":"","sources":["../../src/tools/voiceCall.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,KAAK,EACL,oBAAoB,EACpB,mBAAmB,EACnB,QAAQ,EACR,UAAU,EACX,MAAM,kBAAkB,CAAC;AAM1B;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACvF,sCAAsC;IACtC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,8BAA8B;IAC9B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,wCAAwC;IACxC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IACtD,2CAA2C;IAC3C,cAAc,IAAI,UAAU,EAAE,CAAC;CAChC;AAMD,UAAU,kBAAkB;IAC1B,6BAA6B;IAC7B,MAAM,EAAE,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;IAC9D,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAMD,qBAAa,aAAc,YAAW,KAAK,CAAC,kBAAkB,CAAC;IA4DjD,OAAO,CAAC,QAAQ,CAAC,OAAO;IA3DpC,SAAgB,EAAE,qBAAqB;IACvC,SAAgB,IAAI,qBAAqB;IACzC,SAAgB,WAAW,uBAAuB;IAClD,SAAgB,WAAW,SAGkD;IAC7E,SAAgB,QAAQ,mBAAmB;IAC3C,SAAgB,OAAO,WAAW;IAClC,SAAgB,cAAc,QAAQ;IAEtC,SAAgB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2BzB;IAEF,SAAgB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAiB1B;gBAE2B,OAAO,EAAE,oBAAoB;IAEpD,OAAO,CACX,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC;IA6B/B,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;YAmClE,kBAAkB;IA0BhC,OAAO,CAAC,WAAW;YAqBL,aAAa;IAkB3B,OAAO,CAAC,eAAe;CAwCxB"}