A stateful AI agent actor built with the Effect SDK for Rivet Actors and Effect AI. The agent persists its conversation history in actor state, so it remembers every turn across calls and restarts.
Running against a real model needs an OpenAI API key:
export OPENAI_API_KEY=sk-...The test suite needs neither a key nor network access: it runs a real in-process mock LLM server instead.
git clone https://github.com/rivet-dev/rivet.git
cd rivet/examples/ai-agent-effect
npm install
npm run devIn a separate terminal, run the client against the server:
npm run client- Persistent conversation memory: Every user and assistant turn is stored in persisted actor state (a
Schema.Arrayof role/content messages), so the model sees the full history on each call, even after the actor sleeps or restarts - Effect AI integration: The agent calls
LanguageModel.generateTextfromeffect/aiwith the running history as the prompt - Swappable model via Layer: The actor requires the
LanguageModelservice but never constructs it. The concrete model is provided as an EffectLayerwhere the actor is composed: a real OpenAI model indev, a mock model in tests - Effect-native actor: Defined with
Actor.makeand implemented withtoLayer, returning action handlers from an Effect wake scope - Typed errors across the wire:
SendMessagedeclares anEmptyMessageErrorthat arrives on the caller as a real tagged instance, caught withEffect.catchTag
The actor is split into a public contract and a server-only implementation:
- Contract (
src/actors/agent/api.ts): Declares theAgentactor, theMessagetype, theSendMessage/GetHistoryactions, and theEmptyMessageError - Implementation (
src/actors/agent/live.ts): Implements the wake scope, the conversation-history state schema, and the action handlers that call the LLM - Model wiring (
src/model.ts): Composes aLayer<LanguageModel>fromOpenAiLanguageModel,OpenAiClient, andFetchHttpClient - Server (
src/main.ts): Provides the model Layer to the actor layer and serves it withRegistry.serve - Client (
src/client.ts): An Effect client using the typedAgent.clientaccessor - Test (
tests/agent.test.ts): Runs the actor against a real engine and a real in-process mock LLM server, swapping in a mock model Layer
Read more about actions, state, and the Effect quickstart.
MIT