Skip to main content
Build persistent, stateful chat sessions that handle long-running conversations across multiple interactions and users. In many scenarios, you have long-running multi-turn conversations with agents. A user might start a conversation now, respond hours later, and return again after a few days. Multiple users may be having separate conversations going on, and a single conversation may be open in multiple browser windows.

How does Restate help?

To implement stateful entities like chat sessions, or stateful agents, Restate provides Virtual Objects. Each Virtual Object instance maintains isolated state and is identified by a unique key. Virtual Objects let you build durable chat sessions that maintain conversation state across multiple interactions, survive process restarts, and handle concurrent messages gracefully. Chat playground Restate provides:
  • Durable state: Conversation history persists across failures and restarts
  • Session isolation: Each chat gets isolated state with automatic concurrency control
  • Works with any LLM SDK (Vercel AI, LangChain, LiteLLM, etc.) and any programming language supported by Restate (TypeScript, Python, Go, etc.).
  • Message ordering: Concurrent messages are queued and processed sequentially
Chat playground

Example

Use Virtual Objects to create persistent chat sessions. Each session is identified by a key (user_id or session_id) and maintains conversation state across multiple interactions.
async function message(ctx: ObjectContext, { message }: { message: string }) {
  const messages = (await ctx.get<Array<ModelMessage>>("memory")) ?? [];
  messages.push({ role: "user", content: message });

  // Use your preferred LLM SDK here
  const result = await ctx.run("LLM call", async () => llmCall(messages));

  messages.push({ role: "assistant", content: result.text });
  ctx.set("memory", messages);

  return result.text;
}

export default restate.object({
  name: "Chat",
  handlers: {
    message: restate.createObjectHandler(
      { input: zodPrompt(examplePrompt) },
      message,
    ),
  },
});
View on GitHub: TS / Python The UI lets you query the state of each chat session: Chat session state - UI
This pattern is complementary to AI memory solutions like mem0 or graffiti. You can use Virtual Objects to enforce session concurrency and queueing while storing the agent’s memory in specialized memory systems.
This pattern is implementable with any of our SDKs and any AI SDK. If you need help with a specific SDK, please reach out to us via Discord or Slack.
1

Requirements

  • AI SDK of your choice (e.g., OpenAI, LangChain, Pydantic AI, LiteLLM, etc.) to make LLM calls.
  • API key for your model provider.
2

Download the example

git clone https://github.com/restatedev/ai-examples.git &&
cd typescript-patterns &&
npm install
3

Start the Restate Server

restate-server
4

Start the Service

Export the API key of your model provider as an environment variable and then start the agent. For example, for OpenAI:
export OPENAI_API_KEY=your_openai_api_key
npm run dev
5

Register the services

  • UI
  • CLI
Service Registration
6

Send messages to a chat session

  • UI
  • curl
In the UI (http://localhost:9070), click on the on_message handler of the Chat service to open the playground. Enter a key for the chat session (e.g., session123) and send messages to start a conversation.Chat playground
The session state (conversation history) is automatically persisted and maintained across calls. Send additional messages with the same session ID to see how the conversation context is preserved. For example, ask to shorten the poem.
7

Check the Restate UI

In the State Tab, you can view what is stored in Restate for each chat session:Chat session state - UI