1+ import { createLogger } from '@/lib/logs/console-logger'
2+ import { ToolConfig } from '../types'
3+ import { TwilioSMSBlockOutput , TwilioSendSMSParams } from './types'
4+
5+ const logger = createLogger ( 'Twilio Send SMS Tool' )
6+
7+ export const sendSMSTool : ToolConfig < TwilioSendSMSParams , TwilioSMSBlockOutput > = {
8+ id : 'twilio_send_sms' ,
9+ name : 'Twilio Send SMS' ,
10+ description : 'Send text messages to single or multiple recipients using the Twilio API.' ,
11+ version : '1.0.0' ,
12+
13+ params : {
14+ phoneNumbers : {
15+ type : 'string' ,
16+ required : true ,
17+ description : 'Phone numbers to send the message to, separated by newlines'
18+ } ,
19+ message : {
20+ type : 'string' ,
21+ required : true ,
22+ description : 'Message to send'
23+ } ,
24+ accountSid : {
25+ type : 'string' ,
26+ required : true ,
27+ description : 'Twilio Account SID' ,
28+ requiredForToolCall : true
29+ } ,
30+ authToken : {
31+ type : 'string' ,
32+ required : true ,
33+ description : 'Twilio Auth Token' ,
34+ requiredForToolCall : true
35+ } ,
36+ fromNumber : {
37+ type : 'string' ,
38+ required : true ,
39+ description : 'Twilio phone number to send the message from'
40+ }
41+ } ,
42+
43+ request : {
44+ url : ( params ) => {
45+ if ( ! params . accountSid ) {
46+ throw new Error ( 'Twilio Account SID is required' )
47+ }
48+ const url = `https://api.twilio.com/2010-04-01/Accounts/${ params . accountSid } /Messages.json` ;
49+ return url
50+ } ,
51+ method : 'POST' ,
52+ headers : ( params ) => {
53+ if ( ! params . accountSid || ! params . authToken ) {
54+ throw new Error ( 'Twilio credentials are required' )
55+ }
56+ // Use Buffer instead of btoa for Node.js compatibility
57+ const authToken = Buffer . from ( `${ params . accountSid } :${ params . authToken } ` ) . toString ( 'base64' )
58+ const headers = {
59+ Authorization : `Basic ${ authToken } ` ,
60+ 'Content-Type' : 'application/x-www-form-urlencoded'
61+ }
62+ return headers
63+ } ,
64+ body : ( params ) => {
65+ if ( ! params . phoneNumbers ) {
66+ throw new Error ( 'Phone numbers are required but not provided' )
67+ }
68+ if ( ! params . message ) {
69+ throw new Error ( 'Message content is required but not provided' )
70+ }
71+ if ( ! params . fromNumber ) {
72+ throw new Error ( 'From number is required but not provided' )
73+ }
74+
75+ // Get first phone number if multiple are provided
76+ const toNumber = params . phoneNumbers . split ( '\n' ) [ 0 ] . trim ( )
77+
78+ // Create a URLSearchParams object and convert to string
79+ const formData = new URLSearchParams ( )
80+ formData . append ( 'To' , toNumber )
81+ formData . append ( 'From' , params . fromNumber )
82+ formData . append ( 'Body' , params . message )
83+
84+ const formDataString = formData . toString ( )
85+ return { body : formDataString }
86+ }
87+ } ,
88+
89+ transformResponse : async ( response ) => {
90+ const data = await response . json ( )
91+
92+ if ( ! response . ok ) {
93+ const errorMessage = data . error ?. message || data . message || `Failed to send SMS (HTTP ${ response . status } )`
94+ logger . error ( 'Twilio API error:' , data )
95+ throw new Error ( errorMessage )
96+ }
97+
98+ logger . info ( 'Twilio Response:' , data )
99+ logger . info ( 'Twilio Response type:' , typeof data )
100+ return {
101+ success : true ,
102+ output : {
103+ success : true ,
104+ messageId : data . sid ,
105+ status : data . status
106+ } ,
107+ error : undefined
108+ }
109+ } ,
110+
111+ transformError : ( error ) => {
112+ logger . error ( 'Twilio tool error:' , { error } )
113+ return `SMS sending failed: ${ error . message || 'Unknown error occurred' } `
114+ }
115+ }
0 commit comments