Separating an agent's session transcript from long-term customer facts Twilio and Vercel's eve framework can be combined so that an AI agent keeps short-term conversation transcripts in eve while Twilio Conversations' Memory Store persists long-term per-customer facts across SMS and WhatsApp threads. The tutorial describes building a multi-channel agent that unifies SMS and WhatsApp into one thread per customer, extracts traits such as name and preferences plus observations from past conversations, and injects relevant facts via a dynamic instruction at the start of each session. Twilio Conversations comprises the Conversation Orchestrator, Memory Store, and Conversation Intelligence, while eve is Vercel's open-source file-system-first framework for durable AI agents. Building a Multi-Channel AI Agent with Twilio Conversations and eve Time to read: Written by Reviewed by Building a Multi-Channel AI Agent Twilio with Conversations and eve introduction Building a Multi-Channel AI Agent with Twilio Conversations and eve toc-heading-0c4c1e8d-1784-4ff7-91b1-e0ef9e84ab36 Getting an AI agent to answer a customer's SMS is easy. Getting it to remember that customer next week when they message you on a different channel? That’s where most agent projects give up and start writing their own memory layer. Twilio helps remove that step with one of our tools that we launched earlier this year: Twilio Conversations https://www.twilio.com/en-us/blog/developers/tutorials/product/orchestrate-multi-call-conversations-with-llm-twilio-conversation-memory . Pair it with Vercel's eve framework https://eve.dev/docs , and together, they draw a clean line between the two types of memory an agent needs: 1. Vercel’s eve: holds the short-term memory the running transcript of the current conversation 2. Twilio Conversations: hold the long-term memory knowledge of the current person customer profiles and observations extracted automatically With these two tools, you can spend your time on the agent's behavior rather than the plumbing. Now you can plug in the LLM that you want. In this post, you'll build an agent that unifies SMS https://www.twilio.com/en-us/messaging/channels/sms and WhatsApp https://www.twilio.com/en-us/messaging/channels/whatsapp into one thread, remembers what each customer told you last month, and lets you swap the model in just one line. What you'll build toc-heading-9ca74bc9-9053-4a0b-ae2c-10ffb8236018 What you'll build Picture this: a customer texts your support line asking about the return policy on the blue running shoes they ordered. Ten days later they message you on WhatsApp, follow up on that same order, and ask a new question. The interesting facts about that customer are things like their name, the products they bought, that they prefer WhatsApp for anything urgent, and the last few questions they asked. If you persist only those facts and inject the relevant ones selectively, prompts stay small, debuggable, and stable across sessions. This is the separation of concerns you'll build below. eve keeps a compact per-conversation transcript for the current thread. Twilio's Memory Store https://www.twilio.com/docs/conversations/memory/memory-stores keeps the extracted facts across every past thread. A dynamic instruction merges these two types of information pieces at the start of each session. Figure 1: Architecture diagram showing how Twilio Conversations and Vercel’s eve integrate with each other Meet the stack toc-heading-1901cc07-3d18-43ef-92b7-ddc93d10480b Meet the stack eve https://eve.dev/docs is Vercel's file-system-first framework for durable AI agents. You author files, and eve compiles them into a runtime that manages sessions, tool calls, streaming, and durable state across crashes and redeploys. The project is also open source on GitHub https://github.com/vercel/eve . Twilio Conversations is our suite of AI-native products https://www.twilio.com/docs/conversations that go beyond the traditional scope of our communications APIs. Underneath it, there are three pieces: - Conversation Orchestrator :a durable, cross-channel conversation resource that stitches SMS, WhatsApp, RCS, chat, and voice into one thread per customer. As the developer, you decide how traffic on each channel should be treated and whether to connect it to the two other Conversations sub-products below. - Memory Store: a persistent, per-customer profile database with traits such as name , phone , preferences and observations such as facts extracted from past conversations . - Conversation Intelligence: runs language operators for summaries, sentiment, and observation extraction against conversations, either in real time or at the end of a conversation. The mental model to hold onto: Orchestrator handles the "who is this and where do I reply?" question. Memory Store handles the "what do I already know about them?" question, and Intelligence writes new facts to Memory Store. Prerequisites toc-heading-e9af6469-4037-4170-96de-5e92ab5ed5c4 Prerequisites You'll need a handful of things before you start: - Node.js https://nodejs.org/en/download 24 or newer - A Twilio account with an Account SID and Auth Token find both in the Twilio Console https://console.twilio.com - At least one SMS-capable Twilio phone number https://help.twilio.com/articles/223135247 - A WhatsApp sender https://www.twilio.com/docs/whatsapp/self-sign-up attached to a phone number. It can be the same number you use for SMS, or a second dedicated number. Both work with this setup. - An OpenAI API key, or your provider of choice any AI SDK provider https://ai-sdk.dev/providers/ai-sdk-providers works - A shell for the provisioning calls. macOS and Linux ship with curl . On Windows, to run the curl versions verbatim, use WSL or Git Bash. - ngrok https://ngrok.com/ or a similar tool for local webhook tunneling. ngrok is a tool that gives you a public HTTPS URL that forwards to a port on your laptop, so Twilio can reach your webhook while you develop. Bootstrap the project toc-heading-66d06517-6215-435e-ad1f-3a29f198daae Bootstrap the project Let’s initialize a new project, and get all the packages we need. In your terminal, use the following command: You might be asked to “install the following packages” and a reference to eve’s latest version. It’s okay to hit “y” here to install eve. The twilio npm package is what you'll use later to verify Orchestrator webhook signatures. @ai-sdk/openai is the AI SDK provider you'll wire the model through. eve init generates the project scaffold with everything a hello-world agent needs: For this tutorial, the default instructions.md is fine. Configure the model toc-heading-ab35875e-a24a-48da-8c3f-2e8279740e3f Configure the model Now let’s configure our agent/agent.ts file. Open the file in your editor of choice, and you’ll see the file contains: To use a different provider, install its AI SDK package and swap the model where it’s referenced in the file. Set up environment variables toc-heading-3f480d02-1d6b-4f3a-93f8-09e93bf33e73 Set up environment variables Create a .env file at the project root. The comments below tell you where each value comes from, so you can fill in the top block before moving onto the next step Leave the last two empty for now, as you'll fill them in a few steps below. Start ngrok before provisioning toc-heading-3a136485-1591-44da-83c0-c00ee4d4d141 Start ngrok before provisioning You need a public HTTPS URL before you create the Orchestrator Configuration, because that curl call registers the webhook URL Twilio will call. If you are using a free ngrok account, it will get a fresh random hostname on every start. Start the tunnel now and paste the URL into .env as PUBLIC BASE URL : Copy the https://…ngrok… hostname from the ngrok output, set it in .env as PUBLIC BASE URL . Once the file is saved on disk, load every variable into your current shell so that curl and pnpm dev see the same values: Provision the Twilio side toc-heading-12bd0715-1b13-4f92-9889-88fe8b0b4d77 Provision the Twilio side Memory Store and Orchestrator Configuration are a one-time setup. Both are REST resources. Create the Memory Store toc-heading-0550316f-f179-4ba4-838f-8ced0b6064dc Create the Memory Store Now let’s create the Memory Store. In the terminal, use the following commands: The response is a 202 with a statusUrl that looks like https://memory.twilio.com/v1/ControlPlane/Operations/mem configop XXXXXXXX . That's Twilio's way of saying "I've accepted the job, check this URL when you're ready." Confirm with a plain “GET” against the statusUrl from your own response substitute your op ... id for the placeholder below : Look for "status": "COMPLETED" and the mem store ... id in the response body. Copy the id into .env as MEMORY STORE ID , then reload the shell: Create the Orchestrator Configuration with GROUP BY PROFILE toc-heading-00b3c101-d1d4-471c-ab72-0bc41c4ced68 Create the Orchestrator Configuration with GROUP BY PROFILE Now all the values that your requests need are now in your environment. Use a heredoc https://en.wikipedia.org/wiki/Here document so Bash substitutes the variables inline. Two settings are worth calling out: - conversationGroupingType: GROUP BY PROFILE unifies the same customer across channels into one conversation, keyed on the Memory Store profile rather than on the address the customer uses. The default, GROUP BY PARTICIPANT ADDRESSES AND CHANNEL TYPE , separates SMS and WhatsApp into separate conversations. GROUP BY PARTICIPANT ADDRESSES groups channels together, but only when the customer uses the same address on each. This means that if a customer sends an SMS from one number, but a WhatsApp message from another number, then those channels won’t be grouped. GROUP BY PROFILE is what Twilio recommends for production. - memoryExtractionEnabled: true turns on the intelligence pipeline that writes observations back to Memory Store when a conversation closes. Note: don't configure a webhook on the phone number or on the WhatsApp sender. The captureRules https://www.twilio.com/docs/conversations/orchestrator/concepts/ingestion mode-overview above are what pull traffic in, and the single statusCallbacks URL is where Orchestrator delivers it. Here's what GROUP BY PROFILE buys you, once everything below is wired up: Figure 2: One continuous conversation that started on the left via SMS and continues on the right via WhatsApp Notice that the WhatsApp message didn’t contain information about the product, the order, or any reminder of the earlier conversation. That context came from the Memory Store profile that Conversation Orchestrator grouped both channels into. This call also returns a 202 with a statusUrl . You can confirm the call in the same way, substituting your own op ... id: Once the response shows "status": "COMPLETED" , copy the conv configuration ... id into .env as ORCHESTRATOR CONFIG ID . First attempt: eve's built-in Twilio adapter toc-heading-85d7502b-15c1-4701-a572-1b2fd1bb8edc First attempt: eve's built-in Twilio adapter Before you write anything custom,try eve’s built-in Twilio adapter: Point your Twilio phone number's inbound messaging webhook at $PUBLIC BASE URL/eve/v1/twilio/messages , run pnpm dev , and text your number. Awesome, you built a working SMS agent with just a few lines of code Figure 3: A green outgoing bubble reads "Hi 👋 This is a test"; the gray reply below it echos the message Eve’s Twilio adapter is a well-organized cluster of eight TypeScript modules under packages/eve/src/public/channels/twilio https://github.com/vercel/eve/tree/68c1b5fad1f342a9d16b8073180fe2cda5891743/packages/eve/src/public/channels/twilio that handle: - Webhook signature verification https://www.twilio.com/docs/usage/security validating-requests against Twilio's HMAC scheme https://www.twilio.com/docs/usage/webhooks/webhooks-security - Parsing the form-encoded body SMS, MMS metadata, voice transcription callbacks - Building continuation tokens so a caller keeps the same session between messages - A sendMessage helper that resolves the reply's from and to from the inbound - Voice support via