Learn/Cookbook/Patterns
Chat with Conversation History
Build a chat agent that remembers previous messages using thread state
Use thread state to maintain conversation history across multiple requests. The thread persists for up to 1 hour, making it ideal for chat sessions.
The Pattern
Thread state stores conversation history automatically. Each browser session gets its own thread, and messages persist across requests.
import { createAgent, type AgentContext } from '@agentuity/runtime';
import { streamText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { s } from '@agentuity/schema';
interface Message {
role: 'user' | 'assistant';
content: string;
}
const agent = createAgent('Chat Agent', {
description: 'Conversational agent with memory',
schema: {
input: s.object({
message: s.string(),
}),
stream: true,
},
handler: async (ctx: AgentContext, input) => {
// Get or initialize conversation history
const messages = (ctx.thread.state.get('messages') as Message[]) || [];
// Add user message
messages.push({ role: 'user', content: input.message });
// Generate streaming response
const { textStream, text } = streamText({
model: anthropic('claude-sonnet-4-5'),
system: 'You are a helpful assistant. Be concise but friendly.',
messages: messages.map(m => ({
role: m.role,
content: m.content,
})),
});
// Save assistant response after streaming completes
ctx.waitUntil(async () => {
const fullResponse = await text;
messages.push({ role: 'assistant', content: fullResponse });
ctx.thread.state.set('messages', messages);
ctx.logger.info('Conversation updated', {
messageCount: messages.length,
threadId: ctx.thread.id,
});
});
return textStream;
},
});
export default agent;Key Points
- Thread state (
ctx.thread.state) persists for up to 1 hour - Messages array stores the full conversation history
waitUntilsaves the response after streaming completes- Thread ID (
ctx.thread.id) identifies the conversation
Route Example
import { createRouter } from '@agentuity/runtime';
import chatAgent from '@agent/chat';
const router = createRouter();
router.post('/', async (c) => {
const { message } = await c.req.json();
return chatAgent.run({ message });
});
// Reset conversation
router.delete('/', async (c) => {
await c.var.thread.destroy();
return c.json({ reset: true });
});
export default router;See Also
- State Management for all state scopes
- Streaming Responses for streaming patterns
Need Help?
Join our Community for assistance or just to hang with other humans building agents.
Send us an email at hi@agentuity.com if you'd like to get in touch.
Please Follow us on
If you haven't already, please Signup for your free account now and start building your first agent!