History
Learn how to persist conversations for your agents and networks
Overview
AgentKit enables persistent conversations that maintain context across multiple runs. By implementing a History Adapter, you can connect your agents and networks to any database or storage solution, allowing conversations to resume exactly where they left off.
A History Adapter is a configuration object that bridges AgentKit’s execution lifecycle with your database. It tells AgentKit how to:
- Create new conversation threads
- Load existing conversation history
- Save new messages and results
AgentKit is database-agnostic. You can use PostgreSQL, MongoDB, Redis, or any
storage solution by implementing the HistoryConfig
interface.
The adapter is passed to createAgent()
or createNetwork()
and AgentKit automatically calls your adapter’s methods at the appropriate times during execution.
HistoryConfig Interface
The HistoryConfig
interface has three optional methods. Below is an expanded view of the interface showing the context and parameters passed to each method.
createThread
- Creates a new conversation thread in your database
- Invoked at the start of a run if no
threadId
exists in the state - Returns an object with the new
threadId
get
- Retrieves conversation history from your database
- Invoked after thread initialization, but only if the client didn’t provide
results
ormessages
- Returns an array of
AgentResult[]
representing the conversation history
appendResults
- Saves new messages to your database after a network or agent run
- Invoked at the end of a successful agent or network run
- Receives only the new results generated during this run (prevents duplicates)
Usage
Here’s a complete example of creating a network with history persistence:
Once you’ve created your adapter, pass it to the history
property when creating an agent or network:
Persistence Patterns
AgentKit supports two distint patterns for managing conversation history.
Server-Authoritative
The client sends a message with a threadId
. AgentKit automatically loads the full conversation context from your database before the network runs.
Use case: Perfect for restoring conversations after page refresh or when opening the app on a new device.
Client-Authoritative (Performance Optimized)
The client maintains conversation state locally and sends the complete history with each request. AgentKit detects this and skips the database read for better performance.
Use case: Ideal for interactive chat applications where the frontend maintains conversation state and fetches messages from an existing/seperate API
Server/Client Hybrid Pattern
You can combine the Server-Authoritative and Client-Authoritative patterns for an optimal user experience. This hybrid approach allows for fast initial conversation loading and high-performance interactive chat.
- Initial Load (Server-Authoritative): When a user opens a conversation thread, the client sends only the
threadId
. AgentKit fetches the history from your database usinghistory.get()
. The application then hydrates the client-side state with this history. - Interactive Session (Client-Authoritative): For all subsequent requests within the session, the client sends the full, up-to-date history (
results
ormessages
) along with thethreadId
. AgentKit detects the client-provided history and skips the database read, resulting in a faster response.
Use case: Ideal for interactive chat applications where the frontend maintains conversation state but lets AgentKit fetch messages via their history adapter
How Thread IDs Are Managed
AgentKit offers a flexible system for managing conversation thread IDs, ensuring that history is handled correctly whether you’re starting a new conversation or continuing an existing one. Here’s how AgentKit determines which threadId
to use, in order of precedence:
-
Explicit
threadId
(Highest Priority): The most direct method is to provide athreadId
when you create your state. This is the standard way to resume a specific, existing conversation. AgentKit will use this ID to load the relevant history via thehistory.get()
method. -
Automatic Creation via
createThread
: If you don’t provide athreadId
, AgentKit checks if your history adapter has acreateThread
method. If so, AgentKit calls it to create a new conversation thread in your database. YourcreateThread
function is responsible for generating and returning the new uniquethreadId
. This is the recommended approach for starting new conversations, as it ensures a record is created in your backend from the very beginning. -
Automatic Generation (Fallback): In cases where you don’t provide a
threadId
and your history adapter does not have acreateThread
method but does have aget
method, AgentKit provides a fallback. It will automatically generate a standard UUID and assign it as thethreadId
for the current run. This convenience ensures the conversation can proceed with a unique identifier for saving and loading history, even without an explicit creation step.
Best Practices
Leverage Inngest's Durable Steps
Leverage Inngest's Durable Steps
Wrap database operations in step.run()
for automatic retries and durability.
Handle Missing Threads Gracefully
Handle Missing Threads Gracefully
If a thread doesn’t exist, return an empty array rather than throwing an error.
Index Your Database Properly
Index Your Database Properly
Ensure you have indexes on thread_id
and created_at
columns for fast queries.
Future Enhancements
The history system provides a foundation for advanced features to be released in the coming future including:
- Database Adapters: Pre-built adapters for popular databases (coming soon)
- Progressive Summarization: Automatic conversation compression for long threads
- Search & Retrieval: Semantic search across conversation history
Complete Example
Check out the AgentKit Starter for a complete implementation featuring:
- PostgreSQL history adapter
- ChatGPT-style UI with thread management
- Real-time streaming responses
- Both server and client-authoritative patterns
The starter includes everything you need to build a conversational AI application with persistent history.