Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added plugin-twilio this can send message using sms or whatsapp #1822

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1cb3af7
added plugin-twilio this can send message using sms or whatsapp
juanc07 Jan 4, 2025
f068a62
remove hello action in index.ts
juanc07 Jan 4, 2025
e34e5ae
added plugin-twilio to agent
juanc07 Jan 4, 2025
026c821
added check gated the plugin-twilio in agent runtime only add it when…
juanc07 Jan 5, 2025
7be0584
Merge branch 'develop' into feature/plugin-twilio
odilitime Jan 5, 2025
d2ce806
update repo from develop and fix conflict
juanc07 Jan 5, 2025
7370922
added core from main
juanc07 Jan 5, 2025
4ca602c
added prune before installing in integrationTests.yaml file
juanc07 Jan 5, 2025
4a35293
modify the package.json of elizaos/core added require ./dist/index.js…
juanc07 Jan 5, 2025
d8dec47
use node version 20 for integration test yaml
juanc07 Jan 5, 2025
ee05362
use node version 23.5.0 for integration test yaml
juanc07 Jan 5, 2025
535c755
modify exports package.json of core and plugin-node
juanc07 Jan 5, 2025
7da65a8
added pnpm build command before post install in plugin node
juanc07 Jan 5, 2025
9d7d15f
use plugin-node from main
juanc07 Jan 5, 2025
04f1e3c
test remove post install js call
juanc07 Jan 5, 2025
350a2ec
increase version of plugin-node
juanc07 Jan 5, 2025
b220182
change node version integrationTest.yaml to 23.3.0
juanc07 Jan 5, 2025
8a2be86
do some cleaning and rebuild
juanc07 Jan 5, 2025
15895d2
pmpm-lock changes
juanc07 Jan 5, 2025
74b6562
added todo in code
juanc07 Jan 5, 2025
9583616
applied fix from develop branch
juanc07 Jan 5, 2025
52ff515
get changes from develop and fix conflict
juanc07 Jan 6, 2025
30a250a
fixed pnpm-lock file
juanc07 Jan 6, 2025
aebb861
merged branch with develop branch
juanc07 Jan 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@elizaos/plugin-fuel": "workspace:*",
"@elizaos/plugin-avalanche": "workspace:*",
"@elizaos/plugin-web-search": "workspace:*",
"@elizaos/plugin-twilio": "workspace:*",
"readline": "1.3.0",
"ws": "8.18.0",
"yargs": "17.7.2"
Expand Down
7 changes: 7 additions & 0 deletions agent/src/index.ts
juanc07 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import { abstractPlugin } from "@elizaos/plugin-abstract";
import { avalanchePlugin } from "@elizaos/plugin-avalanche";
import { webSearchPlugin } from "@elizaos/plugin-web-search";
import { echoChamberPlugin } from "@elizaos/plugin-echochambers";
import { twilioPlugin } from "@elizaos/plugin-twilio";
import Database from "better-sqlite3";
import fs from "fs";
import path from "path";
Expand Down Expand Up @@ -525,6 +526,12 @@ export async function createAgent(
// character.plugins are handled when clients are added
plugins: [
bootstrapPlugin,
getSecret(character, "TWILIO_ACCOUNT_SID") &&
getSecret(character, "TWILIO_AUTH_TOKEN") &&
getSecret(character, "TWILIO_PHONE_NUMBER") &&
getSecret(character, "TWILIO_WHATSAPP_PHONE_NUMBER")
? twilioPlugin
: null,
getSecret(character, "CONFLUX_CORE_PRIVATE_KEY")
? confluxPlugin
: null,
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-twilio/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*

!dist/**
!package.json
!readme.md
!tsup.config.ts
78 changes: 78 additions & 0 deletions packages/plugin-twilio/ReadMe.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#The ENV file should contain this information

# Cache Configs
CACHE_STORE=database

# Discord Configuration
DISCORD_APPLICATION_ID=
DISCORD_API_TOKEN=

# AI Model API Keys
OPENAI_API_KEY=

# Twitter/X Configuration
TWITTER_USERNAME=
TWITTER_PASSWORD=
TWITTER_EMAIL=
TWITTER_POLL_INTERVAL=120 # How often (in seconds) the bot should check for interactions
TWITTER_SEARCH_ENABLE=FALSE # Enable timeline search, WARNING this greatly increases your chance of getting banned
#TWITTER_TARGET_USERS=

# Twilio Part
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_PHONE_NUMBER=
TWILIO_WHATSAPP_PHONE_NUMBER=

# Server Configuration
SERVER_PORT=3000

# How to use
1. create your .env file , if you don't have it yet and then populate it with the information above, make sure to fill in all information
2. Add this project into your eliza os project under packages
3. using terminal go inside plugin-twilio then type pnpm install twilio
4. go inside your agent folder update the package.json add this "@elizaos/plugin-twilio": "workspace:*"
5. add this inside your Agent index.ts import { twilioPlugin } from "@elizaos/plugin-twilio";
6. Add twilioPlugin in Agent Runtime still inside Agent index.ts
7. pnpm install
8. pnpm build
9. pmpn start --character="characters/nameofyouragentcharacterfile.character.json"

#Note: Make sure you have a twilio developer account and it is verified with verified phone number and have enough credits but they provide free small credits when your account is new
visit twilio: https://www.twilio.com
twilio quick start guides: https://www.twilio.com/docs/messaging/quickstart
twilio documentation: https://www.twilio.com/docs/messaging
Free Trial Account: https://www.twilio.com/docs/messaging/guides/how-to-use-your-free-trial-account

# For WhatsApp guides follow the link below you need to have a separate twilio whatsapp enabled phone number
https://www.twilio.com/docs/whatsapp
https://www.twilio.com/docs/whatsapp/quickstart/node
https://www.twilio.com/docs/whatsapp/getting-started#registering-a-whatsapp-sender
https://www.twilio.com/docs/verify/whatsapp


#Some Other Whats App Info that you might need
https://www.twilio.com/docs/whatsapp

#Twilio Phone Number guidelines
https://www.twilio.com/en-us/guidelines


# Clarification this project is intended to be use/place inside elizaos project packages, this can't work alone

# Sample implementation can be found here
https://github.com/juanc07/AgentSoulSpark

# Usage Sample

The message that you want to send must be inside a Single Quote or double quotes

Example 1:
Please send sms to [phone number], and my message is '[your message here]'
Please send whats app message to [phone number], and my message is '[your message here]'

Example 2:
Please send sms to [phone number], and my message is "[your message here]"
Please send whats app message to [phone number], and my message is "[your message here]"

#Note I haven't tested any other complex string or sentence yet, this could be improve ofcourse but for now it works that way
3 changes: 3 additions & 0 deletions packages/plugin-twilio/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import eslintGlobalConfig from "../../eslint.config.mjs";

export default [...eslintGlobalConfig];
20 changes: 20 additions & 0 deletions packages/plugin-twilio/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@elizaos/plugin-twilio",
"version": "0.1.7-alpha.2",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
"dependencies": {
"@elizaos/core": "workspace:*",
"tsup": "8.3.5",
"twilio": "^5.4.0"
},
"scripts": {
"build": "tsup --format esm --dts",
"dev": "tsup --format esm --dts --watch",
"lint": "eslint --fix --cache ."
},
"peerDependencies": {
"whatwg-url": "7.1.0"
}
}
2 changes: 2 additions & 0 deletions packages/plugin-twilio/src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./sendSms.ts";
export * from "./sendWhatsAppMessage.ts";
168 changes: 168 additions & 0 deletions packages/plugin-twilio/src/actions/sendSms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import {
ActionExample,
generateText,
HandlerCallback,
IAgentRuntime,
Memory,
ModelClass,
State,
type Action,
} from "@elizaos/core";
import twilio from 'twilio';

export const sendSmsAction: Action = {
name: "SendSms",
similes: [
"SendSms"
],
validate: async (_runtime: IAgentRuntime, _message: Memory) => {
return true;
},
description:
"Send SMS to the mobile number provided by the user",
handler: async (
_runtime: IAgentRuntime,
_message: Memory,
_state: State,
_options:{[key:string]: unknown},
_callback: HandlerCallback,
): Promise<boolean> => {
// Check if environment variables are set
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;

if (!accountSid || !authToken) {
console.error('TWILIO_ACCOUNT_SID or TWILIO_AUTH_TOKEN is not set');
return false;
}

// Extract the mobile number from the message
const mobileNumberRegex = /(?:\+|00)(\d{1,3})\s?(\d{3,5})\s?(\d{4,10})/; // This regex matches numbers like +1 123 4567890 or 001 123 4567890
const text = (_message.content as { text?: string })?.text || '';
const matches = text.match(mobileNumberRegex);

const messageRegex = /(['"])(.*?)\1/;
const messageMatch = text.match(messageRegex);

let mobileNumberProvidedByUser = null;
let messageToSendFromUser = null;

if(messageMatch){
messageToSendFromUser = messageMatch[2];
}
if (matches) {
// Combine the parts of the number into a single string, removing spaces and plus signs
mobileNumberProvidedByUser = `+${matches[1]}${matches[2]}${matches[3]}`;
}else{
const alternativeMobileNumberRegex = /\b(\d{3})[-.]?(\d{3})[-.]?(\d{4})\b/; // For formats like 123-456-7890 or 123.456.7890
if (!mobileNumberProvidedByUser) {
const alternativeMatches = text.match(alternativeMobileNumberRegex);
if (alternativeMatches) {
mobileNumberProvidedByUser = `${alternativeMatches[1]}${alternativeMatches[2]}${alternativeMatches[3]}`;
}
}
}

const twilioNumber = process.env.TWILIO_PHONE_NUMBER; // Your Twilio phone number

if (!twilioNumber) {
console.error('Twilio phone number is missing');

_callback({
text: `Sorry there was an issue send sms, please try again later`,
});
return false;
}

const recentMessages = `Extract the phone number from the user recent messages ${_state.recentMessages}`;

if (!mobileNumberProvidedByUser) {
console.error('Mobile number is missing will try to get the phone number or mobile number from recent messages');

mobileNumberProvidedByUser = await generateText(
{
runtime: _runtime,
context: recentMessages,
modelClass: ModelClass.SMALL,
stop: ["\n"],
customSystemPrompt: "only extract the message that the user intend to send and only get the last one"
}
);
}

if (!mobileNumberProvidedByUser) {
console.error('Mobile number is missing');

_callback({
text: `Sorry, there was an issue send sms, please try again later`,
});
return false;
}

const recentUserMessages = `Extract the message intended for SMS or text: ${_state.recentMessages}`;

if (!messageToSendFromUser) {
console.error('messageToSendFromUser is missing will try to get the user message from recent messages');

messageToSendFromUser = await generateText(
{
runtime: _runtime,
context: recentUserMessages,
modelClass: ModelClass.SMALL,
stop: ["\n"]
}
);
}

if(messageToSendFromUser==null){
console.error('messageToSendFromUser is empty or null');

_callback({
text: `Sorry there was an issue sending the WhatsApp message, please try again later`,
});
return false;
}

try {
// Initialize Twilio client
const client = twilio(accountSid, authToken);

// Send the SMS
const message= await client.messages.create({
body: messageToSendFromUser, // The message body
to: mobileNumberProvidedByUser, // The recipient's phone number
from: twilioNumber, // Your Twilio phone number
});

// for debug purposes uncomment this
console.log("check twilio message body: ", message);

const messageFromAgent = `SMS sent successfully to ${mobileNumberProvidedByUser}`;

// Call the callback to notify the user
_callback({
text: messageFromAgent,
});

return true;
} catch (error) {
console.error('Failed to send SMS:', error);
_callback({
text: `Failed to send SMS to ${mobileNumberProvidedByUser}`,
});
return false;
}
},
examples: [
[
{
user: "{{user1}}",
content: { text: "please send my message via sms to target mobile number" },
},
{
user: "{{user2}}",
content: { text: "", action: "SEND_SMS" },
},
],
] as ActionExample[][],
} as Action;
Loading
Loading