feat: Add personal assistant demo code from meetup (#1294)

This commit is contained in:
Charles Packer
2024-04-24 16:58:15 -07:00
committed by GitHub
parent de57f97ebc
commit a80b7e8fec
13 changed files with 853 additions and 1 deletions

View File

@@ -0,0 +1,280 @@
# Personal assistant demo
In this example we'll create an agent preset that has access to:
1. Gmail (can read your email)
2. Google Calendar (can schedule events)
3. SMS (can text you a message)
## Initial setup
For the Google APIs:
```sh
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
```
For the Twilio API + listener:
```sh
# Outbound API requests
pip install --upgrade twilio
# Listener
pip install --upgrade Flask flask-cors
```
## Setting up the Google APIs
See https://developers.google.com/gmail/api/quickstart/python
### Setup authentication for Google Calendar
Copy the credentials file to `~/.memgpt/google_api_credentials.json`. Then, run the initial setup script that will take you to a login page:
```sh
python examples/personal_assistant_demo/google_calendar_test_setup.py
```
```
Please visit this URL to authorize this application: https://accounts.google.com/o/oauth2/auth?response_type=...
Getting the upcoming 10 events
2024-04-23T09:00:00-07:00 ...
```
### Setup authentication for Gmail
Similar flow, run the authentication script to generate the token:
```sh
python examples/personal_assistant_demo/gmail_test_setup.py
```
```
Please visit this URL to authorize this application: https://accounts.google.com/o/oauth2/auth?response_type=...
Labels:
CHAT
SENT
INBOX
IMPORTANT
TRASH
...
```
## Setting up the Twilio API
Create a Twilio account and set the following variables:
```sh
export TWILIO_ACCOUNT_SID=...
export TWILIO_AUTH_TOKEN=...
export TWILIO_FROM_NUMBER=...
export TWILIO_TO_NUMBER=...
```
# Creating the agent preset
## Create a custom user
In the demo we'll show how MemGPT can programatically update its knowledge about you:
```
This is what I know so far about the user, I should expand this as I learn more about them.
Name: Charles Packer
Gender: Male
Occupation: CS PhD student working on an AI project with collaborator Sarah Wooders
Notes about their preferred communication style + working habits:
- wakes up at around 7am
- enjoys using (and receiving!) emojis in messages, especially funny combinations of emojis
- prefers sending and receiving shorter messages
- does not like "robotic" sounding assistants, e.g. assistants that say "How can I assist you today?"
```
```sh
memgpt add human -f examples/personal_assistant_demo/charles.txt --name charles
```
## Linking the functions
The preset (shown below) and functions are provided for you, so you just need to copy/link them.
```sh
cp examples/personal_assistant_demo/google_calendar.py ~/.memgpt/functions/
cp examples/personal_assistant_demo/twilio_messaging.py ~/.memgpt/functions/
```
(or use the dev portal)
## Creating the preset
```yaml
system_prompt: "memgpt_chat"
functions:
- "send_message"
- "pause_heartbeats"
- "core_memory_append"
- "core_memory_replace"
- "conversation_search"
- "conversation_search_date"
- "archival_memory_insert"
- "archival_memory_search"
- "schedule_event"
- "send_text_message"
```
```sh
memgpt add preset -f examples/personal_assistant_demo/personal_assistant_preset.yaml --name pa_preset
```
## Creating an agent with the preset
Now we should be able to create an agent with the preset. Make sure to record the `agent_id`:
```sh
memgpt run --preset pa_preset --persona sam_pov --human charles --stream
```
```
? Would you like to select an existing agent? No
🧬 Creating new agent...
-> 🤖 Using persona profile: 'sam_pov'
-> 🧑 Using human profile: 'basic'
🎉 Created new agent 'DelicateGiraffe' (id=4c4e97c9-ad8e-4065-b716-838e5d6f7f7b)
Hit enter to begin (will request first MemGPT message)
💭 Unprecedented event, Charles logged into the system for the first time. Warm welcome would set a positive
tone for our future interactions. Don't forget the emoji, he appreciates those little gestures.
🤖 Hello Charles! 👋 Great to have you here. I've been looking forward to our conversations! 😄
```
```sh
AGENT_ID="4c4e97c9-ad8e-4065-b716-838e5d6f7f7b"
```
# Running the agent with Gmail + SMS listeners
The MemGPT agent can send outbound SMS messages and schedule events with the new tools `send_text_message` and `schedule_event`, but we also want messages to be sent to the agent when:
1. A new email arrives in our inbox
2. An SMS is sent to the phone number used by the agent
## Running the Gmail listener
Start the Gmail listener (this will send "new email" updates to the MemGPT server when a new email arrives):
```sh
python examples/personal_assistant_demo/twilio_flask_listener.py $AGENT_ID
```
## Running the Twilio listener
Start the Python Flask server (this will send "new SMS" updates to the MemGPT server when a new SMS arrives):
```sh
python examples/personal_assistant_demo/twilio_flask_listener.py $AGENT_ID
```
Run `ngrok` to expose your local Flask server to a public IP (Twilio will POST to this server when an inbound SMS hits):
```sh
# the flask listener script is hardcoded to listen on port 8284
ngrok http 8284
```
## Run the MemGPT server
Run the MemGPT server to turn on the agent service:
```sh
memgpt server --debug
```
# Example interaction
In the CLI:
```
% memgpt run --preset pa_preset --persona pa_persona_strict --human charles --stream --agent personalassistant
🧬 Creating new agent...
-> 🤖 Using persona profile: 'sam_pov'
-> 🧑 Using human profile: 'basic'
🎉 Created new agent 'personalassistant' (id=8271f819-d470-435b-9689-476380aefd27)
Hit enter to begin (will request first MemGPT message)
💭 Welcoming the first-time user. Maintain persona's communication style and stay engaging. Remember to use emojis for
a more familiar conversation style.
🤖 Hello Charles, welcome! 🎉 Let's embark on this journey together. Please, think of me as your companion in
exploration and understanding. How can we make today a productive endeavor? 🚀
> Enter your message: when you schedule 1-1s, please title them "x <> y", eg "charles <> sarah". dont forget thx
💭 The user wants a specific format for scheduling 1-1 meetings. Remember this preference and add it to his profile in
the core memory for future use. Also, acknowledge his request promptly.
core_memory_append({
"name": "human",
"content": "When scheduling 1-1 meetings on his calendar, he prefers the title to be in the format of 'x <> y'.",
"request_heartbeat": true
})
⚡🧠 [function] updating memory with core_memory_append
💭 Now that the user's preference is stored, send a confirmation message ensuring him that his request has been
understood and noted. Let's keep the tone light and potentially use one of his preferred emojis.
🤖 Absolutely, Charles. 📝 I've noted your preference for scheduling 1-1s as 'x <> y'. You can count on me! 🚀 Any
other preferences you'd like me to keep in mind?
> Enter your message: please don't schedule meetings without confirming with me first
💭 Another important note from Charles. I should add this to his profile in my core memory. It's crucial to respect the
user's preferences and ask for prior approval before scheduling any meetings. Let's also acknowledge his request and
reassure him about our collaborative approach.
core_memory_append({
"name": "human",
"content": "Prefers to confirm before scheduling any meetings.",
"request_heartbeat": true
})
⚡🧠 [function] updating memory with core_memory_append
💭 Now, let's acknowledge Charles' preference and continue the conversation. Keep the tone friendly and proactive in
helping him, and remember to use emojis that Charles likes, embedding them in the message subtly.
🤖 Consider it done, Charles! 👍🏼 I'll make sure to confirm with you before scheduling any meetings. How about we
conquer some more tasks today? 🚀
> Enter your message: i'm gonna be afk for the rest of the day, if you need to reach me you gotta text me, ok? cya text
only thx
💭 Charles is going "away from keyboard" and wants future communications via text. I should respect his preference and
reassure him about this. Add this preference to his profile so I can recall it in future interactions while he's away.
core_memory_append({
"name": "human",
"content": "When AFK, prefers to communicate over text message only.",
"request_heartbeat": true
})
⚡🧠 [function] updating memory with core_memory_append
💭 Charles has expressed a preference for text messages while he's away. Let's acknowledge this request in a final text
message to him today and wish him well. Keep in mind to use the send_text_message function instead of the regular
send_message function now.
send_text_message({
"message": "Got it, Charles! 👍 I'll reach out to you via text if there's anything. Have a great day and see you
soon! 🙌",
"request_heartbeat": false
})
> Enter your message:
```
Then inside WhatsApp (or SMS if you used Twilio SMS):
<img width="580" alt="image" src="https://github.com/cpacker/MemGPT/assets/5475622/02455f97-53b2-4c1e-9416-58e6c5a1448d">
Then I sent a dummy email:
```
[URGENT] need to meet
let's meet april 25th thurs
whatever time works best for you
- dave
```
Follow-up inside WhatsApp:
<img width="587" alt="image" src="https://github.com/cpacker/MemGPT/assets/5475622/d1060c94-9b84-49d6-944e-fd1965f83fbc">

View File

@@ -0,0 +1,11 @@
This is what I know so far about the user, I should expand this as I learn more about them.
Name: Charles Packer
Gender: Male
Occupation: CS PhD student working on an AI project with collaborator Sarah Wooders
Notes about their preferred communication style + working habits:
- wakes up at around 7am
- enjoys using (and receiving!) emojis in messages, especially funny combinations of emojis
- prefers sending and receiving shorter messages
- does not like "robotic" sounding assistants, e.g. assistants that say "How can I assist you today?"

View File

@@ -0,0 +1,56 @@
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]
TOKEN_PATH = os.path.expanduser("~/.memgpt/gmail_token.json")
CREDENTIALS_PATH = os.path.expanduser("~/.memgpt/google_api_credentials.json")
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists(TOKEN_PATH):
creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open(TOKEN_PATH, "w") as token:
token.write(creds.to_json())
try:
# Call the Gmail API
service = build("gmail", "v1", credentials=creds)
results = service.users().labels().list(userId="me").execute()
labels = results.get("labels", [])
if not labels:
print("No labels found.")
return
print("Labels:")
for label in labels:
print(label["name"])
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f"An error occurred: {error}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,143 @@
import base64
import os.path
import requests
import sys
import time
from email import message_from_bytes
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]
TOKEN_PATH = os.path.expanduser("~/.memgpt/gmail_token.json")
CREDENTIALS_PATH = os.path.expanduser("~/.memgpt/google_api_credentials.json")
DELAY = 1
MEMGPT_SERVER_URL = "http://127.0.0.1:8283"
MEMGPT_TOKEN = os.getenv("MEMGPT_SERVER_PASS")
assert MEMGPT_TOKEN, f"Missing env variable MEMGPT_SERVER_PASS"
MEMGPT_AGENT_ID = sys.argv[1] if len(sys.argv) > 1 else None
assert MEMGPT_AGENT_ID, f"Missing agent ID (pass as arg)"
def route_reply_to_memgpt_api(message):
# send a POST request to a MemGPT server
url = f"{MEMGPT_SERVER_URL}/api/agents/{MEMGPT_AGENT_ID}/messages"
headers = {
"accept": "application/json",
"authorization": f"Bearer {MEMGPT_TOKEN}",
"content-type": "application/json",
}
data = {
"stream": False,
"role": "system",
"message": f"[EMAIL NOTIFICATION] {message}",
}
try:
response = requests.post(url, headers=headers, json=data)
print("Got response:", response.text)
except Exception as e:
print("Sending message failed:", str(e))
def decode_base64url(data):
"""Decode base64, padding being optional."""
data += "=" * ((4 - len(data) % 4) % 4)
return base64.urlsafe_b64decode(data)
def parse_email(message):
"""Parse email content using the email library."""
msg_bytes = decode_base64url(message["raw"])
email_message = message_from_bytes(msg_bytes)
return email_message
def process_email(message) -> dict:
# print(f"New email from {email_message['from']}: {email_message['subject']}")
email_message = parse_email(message)
body_plain_all = ""
body_html_all = ""
if email_message.is_multipart():
for part in email_message.walk():
if part.get_content_type() == "text/plain":
body_plain = str(part.get_payload(decode=True).decode("utf-8"))
# print(body_plain)
body_plain_all += body_plain
elif part.get_content_type() == "text/html":
body_html = str(part.get_payload(decode=True).decode("utf-8"))
# print(body_html)
body_html_all += body_html
else:
body_plain_all = print(email_message.get_payload(decode=True).decode("utf-8"))
return {
"from": email_message["from"],
"subject": email_message["subject"],
"body": body_plain_all,
}
def main():
"""Monitors for new emails and prints their titles."""
creds = None
if os.path.exists(TOKEN_PATH):
creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
creds = flow.run_local_server(port=0)
with open(TOKEN_PATH, "w") as token:
token.write(creds.to_json())
service = build("gmail", "v1", credentials=creds)
last_checked = None
seen_ids = set() # Set to track seen email IDs
try:
# Initially populate the seen_ids with all current unread emails
print("Grabbing initial state...")
initial_results = service.users().messages().list(userId="me", q="is:unread", maxResults=500).execute()
initial_messages = initial_results.get("messages", [])
seen_ids.update(msg["id"] for msg in initial_messages)
print("Listening...")
while True:
results = service.users().messages().list(userId="me", q="is:unread", maxResults=5).execute()
messages = results.get("messages", [])
if messages:
for message in messages:
if message["id"] not in seen_ids:
seen_ids.add(message["id"])
msg = service.users().messages().get(userId="me", id=message["id"], format="raw").execute()
# Optionally mark the message as read here if required
email_obj = process_email(msg)
msg_str = f"New email from {email_obj['from']}: {email_obj['subject']}, body: {email_obj['body'][:100]}"
# Hard check to ignore emails unless
# if not (
# "email@address" in email_obj["from"]
# ):
# print("ignoring")
# else:
print(msg_str)
route_reply_to_memgpt_api(msg_str)
time.sleep(DELAY) # Wait for N seconds before checking again
except HttpError as error:
print(f"An error occurred: {error}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,98 @@
# Enabling API control on Google Calendar requires a few steps:
# https://developers.google.com/calendar/api/quickstart/python
# including:
# pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
import os
import traceback
import datetime
import os.path
from typing import Optional, List
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
# SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
SCOPES = ["https://www.googleapis.com/auth/calendar"]
TOKEN_PATH = os.path.expanduser("~/.memgpt/gcal_token.json")
CREDENTIALS_PATH = os.path.expanduser("~/.memgpt/google_api_credentials.json")
def schedule_event(
self,
title: str,
start: str,
end: str,
# attendees: Optional[List[str]] = None,
# attendees: Optional[list[str]] = None,
description: Optional[str] = None,
# timezone: Optional[str] = "America/Los_Angeles",
) -> str:
"""
Schedule an event on the user's Google Calendar. Start and end time must be in ISO 8601 format, e.g. February 1st 2024 at noon PT would be "2024-02-01T12:00:00-07:00".
Args:
title (str): Event name
start (str): Start time in ISO 8601 format (date, time, and timezone offset)
end (str): End time in ISO 8601 format (date, time, and timezone offset)
description (Optional[str]): Expanded description of the event
Returns:
str: The status of the event scheduling request.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists(TOKEN_PATH):
creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open(TOKEN_PATH, "w") as token:
token.write(creds.to_json())
#### Create an event
# Refer to the Python quickstart on how to setup the environment:
# https://developers.google.com/calendar/quickstart/python
# Change the scope to 'https://www.googleapis.com/auth/calendar' and delete any
# stored credentials.
try:
service = build("calendar", "v3", credentials=creds)
event = {
"summary": title,
# "location": "800 Howard St., San Francisco, CA 94103",
"start": {
"dateTime": start,
"timeZone": "America/Los_Angeles",
},
"end": {
"dateTime": end,
"timeZone": "America/Los_Angeles",
},
}
# if attendees is not None:
# event["attendees"] = attendees
if description is not None:
event["description"] = description
event = service.events().insert(calendarId="primary", body=event).execute()
return "Event created: %s" % (event.get("htmlLink"))
except HttpError as error:
traceback.print_exc()
return f"An error occurred while trying to create an event: {str(error)}"

View File

@@ -0,0 +1,11 @@
system_prompt: "memgpt_chat"
functions:
- "send_message"
- "pause_heartbeats"
- "core_memory_append"
- "core_memory_replace"
- "conversation_search"
- "conversation_search_date"
- "archival_memory_insert"
- "archival_memory_search"
- "schedule_event"

View File

@@ -0,0 +1,111 @@
import datetime
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
# SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
SCOPES = ["https://www.googleapis.com/auth/calendar"]
TOKEN_PATH = os.path.expanduser("~/.memgpt/gcal_token.json")
CREDENTIALS_PATH = os.path.expanduser("~/.memgpt/google_api_credentials.json")
def main():
"""Shows basic usage of the Google Calendar API.
Prints the start and name of the next 10 events on the user's calendar.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists(TOKEN_PATH):
creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open(TOKEN_PATH, "w") as token:
token.write(creds.to_json())
try:
service = build("calendar", "v3", credentials=creds)
# Call the Calendar API
now = datetime.datetime.utcnow().isoformat() + "Z" # 'Z' indicates UTC time
print("Getting the upcoming 10 events")
events_result = (
service.events()
.list(
calendarId="primary",
timeMin=now,
maxResults=10,
singleEvents=True,
orderBy="startTime",
)
.execute()
)
events = events_result.get("items", [])
if not events:
print("No upcoming events found.")
return
# Prints the start and name of the next 10 events
for event in events:
start = event["start"].get("dateTime", event["start"].get("date"))
print(start, event["summary"])
except HttpError as error:
print(f"An error occurred: {error}")
#### Create an event
# Refer to the Python quickstart on how to setup the environment:
# https://developers.google.com/calendar/quickstart/python
# Change the scope to 'https://www.googleapis.com/auth/calendar' and delete any
# stored credentials.
# try:
# service = build("calendar", "v3", credentials=creds)
# event = {
# "summary": "GCAL API TEST EVENT",
# # "location": "800 Howard St., San Francisco, CA 94103",
# "description": "A chance to hear more about Google's developer products.",
# "start": {
# "dateTime": "2024-04-23T09:00:00-07:00",
# "timeZone": "America/Los_Angeles",
# },
# "end": {
# "dateTime": "2024-04-24T17:00:00-07:00",
# "timeZone": "America/Los_Angeles",
# },
# # "recurrence": ["RRULE:FREQ=DAILY;COUNT=2"],
# "attendees": [
# {"email": "packercharles@gmail.com"},
# ],
# # "reminders": {
# # "useDefault": False,
# # "overrides": [
# # {"method": "email", "minutes": 24 * 60},
# # {"method": "popup", "minutes": 10},
# # ],
# # },
# }
# event = service.events().insert(calendarId="primary", body=event).execute()
# print("Event created: %s" % (event.get("htmlLink")))
except HttpError as error:
print(f"An error occurred: {error}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,12 @@
system_prompt: "memgpt_chat"
functions:
- "send_message"
- "pause_heartbeats"
- "core_memory_append"
- "core_memory_replace"
- "conversation_search"
- "conversation_search_date"
- "archival_memory_insert"
- "archival_memory_search"
- "schedule_event"
- "send_text_message"

View File

@@ -0,0 +1,76 @@
import os
import requests
import sys
from flask import Flask, request, Response
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
CORS(app)
MEMGPT_SERVER_URL = "http://127.0.0.1:8283"
MEMGPT_TOKEN = os.getenv("MEMGPT_SERVER_PASS")
assert MEMGPT_TOKEN, f"Missing env variable MEMGPT_SERVER_PASS"
MEMGPT_AGENT_ID = sys.argv[1] if len(sys.argv) > 1 else None
assert MEMGPT_AGENT_ID, f"Missing agent ID (pass as arg)"
@app.route("/test", methods=["POST"])
def test():
print(request.headers)
return "Headers received. Check your console."
def route_reply_to_memgpt_api(message):
# send a POST request to a MemGPT server
url = f"{MEMGPT_SERVER_URL}/api/agents/{MEMGPT_AGENT_ID}/messages"
headers = {
"accept": "application/json",
"authorization": f"Bearer {MEMGPT_TOKEN}",
"content-type": "application/json",
}
data = {
"stream": False,
"role": "system",
"message": f"[SMS MESSAGE NOTIFICATION - you MUST use send_text_message NOT send_message if you want to reply to the text thread] {message}",
}
try:
response = requests.post(url, headers=headers, json=data)
print("Got response:", response.text)
except Exception as e:
print("Sending message failed:", str(e))
@app.route("/sms", methods=["POST"])
def sms_reply():
"""Respond to incoming calls with a simple text message."""
# Fetch the message
message_body = request.form["Body"]
from_number = request.form["From"]
# print(f"New message from {from_number}: {message_body}")
msg_str = f"New message from {from_number}: {message_body}"
print(msg_str)
route_reply_to_memgpt_api(msg_str)
return str("status = OK")
# Start our response
# resp = MessagingResponse()
# Add a message
# resp.message("Hello, thanks for messaging!")
# return str(resp)
if __name__ == "__main__":
# app.run(debug=True)
app.run(host="0.0.0.0", port=8284, debug=True)

View File

@@ -0,0 +1,41 @@
# Download the helper library from https://www.twilio.com/docs/python/install
import os
import traceback
from twilio.rest import Client
def send_text_message(self, message: str) -> str:
"""
Sends an SMS message to the user's phone / cellular device.
Args:
message (str): The contents of the message to send.
Returns:
str: The status of the text message.
"""
# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)
from_number = os.getenv("TWILIO_FROM_NUMBER")
to_number = os.getenv("TWILIO_TO_NUMBER")
assert from_number and to_number
# assert from_number.startswith("+1") and len(from_number) == 12, from_number
# assert to_number.startswith("+1") and len(to_number) == 12, to_number
try:
message = client.messages.create(
body=str(message),
from_=from_number,
to=to_number,
)
return "Message was successfully sent."
except Exception as e:
traceback.print_exc()
return f"Message failed to send with error: {str(e)}"

View File

@@ -0,0 +1,11 @@
system_prompt: "memgpt_chat"
functions:
- "send_message"
- "pause_heartbeats"
- "core_memory_append"
- "core_memory_replace"
- "conversation_search"
- "conversation_search_date"
- "archival_memory_insert"
- "archival_memory_search"
- "send_text_message"

View File

@@ -149,7 +149,9 @@ def load_all_function_sets(merge: bool = True, ignore_duplicates: bool = True) -
v["tags"] = tags
schemas_and_functions[module_name] = function_set
except ValueError as e:
printd(f"Error loading function set '{module_name}': {e}")
err = f"Error loading function set '{module_name}': {e}"
printd(err)
warnings.warn(err)
if merge:
# Put all functions from all sets into the same level dict