Important: This guide provides comprehensive documentation for the composeState
method and Providers in v1.x, including comparisons with v0.
Table of Contents
State Management with composeState
The composeState
method is the central mechanism for building the context state that powers agent responses. In v1, it has been enhanced with powerful filtering capabilities.
Basic Usage
// v1: Basic state composition
const state = await runtime.composeState(message);
This creates a complete state object containing all available context:
- Agent information (bio, lore, personality)
- Conversation history
- Room and participant details
- Available actions and evaluators
- Knowledge and RAG data
- Provider-generated context
State Filtering
The v1 composeState
method introduces filtering capabilities for performance optimization:
// v1: Signature
composeState(
message: Memory,
includeList?: string[], // Keys to include
onlyInclude?: boolean, // If true, ONLY include listed keys
skipCache?: boolean // Skip caching mechanism
): Promise<State>
Filtering Examples
// Include only specific state keys
const minimalState = await runtime.composeState(
message,
['agentName', 'bio', 'recentMessages'],
true // onlyInclude = true
);
// Update only specific parts of existing state
const updatedState = await runtime.composeState(
message,
['RECENT_MESSAGES', 'GOALS'] // Update only these
);
// Skip cache for fresh data
const freshState = await runtime.composeState(
message,
undefined,
false,
true // skipCache = true
);
Available State Keys
Here are the primary state keys you can filter:
agentId
- Agent’s UUID
agentName
- Agent’s display name
bio
- Agent biography (string or selected from array)
lore
- Random selection of lore bits
adjective
- Random adjective from character
topic
/ topics
- Agent’s interests
Conversation Context
recentMessages
- Formatted recent messages
recentMessagesData
- Raw message Memory objects
recentPosts
- Formatted posts in thread
attachments
- Formatted attachment information
Interaction History
recentMessageInteractions
- Past interactions as messages
recentPostInteractions
- Past interactions as posts
recentInteractionsData
- Raw interaction Memory[]
Character Examples
characterPostExamples
- Example posts from character
characterMessageExamples
- Example conversations
Directions & Style
messageDirections
- Message style guidelines
postDirections
- Post style guidelines
Room & Participants
roomId
- Current room UUID
actors
- Formatted actor information
actorsData
- Raw Actor[] array
senderName
- Name of message sender
Goals & Actions
goals
- Formatted goals string
goalsData
- Raw Goal[] array
actionNames
- Available action names
actions
- Formatted action descriptions
actionExamples
- Action usage examples
Evaluators
evaluators
- Formatted evaluator information
evaluatorNames
- List of evaluator names
evaluatorExamples
- Evaluator examples
evaluatorsData
- Raw Evaluator[] array
Knowledge
knowledge
- Formatted knowledge text
knowledgeData
- Knowledge items
ragKnowledgeData
- RAG knowledge items
Providers
providers
- Additional context from providers
Use filtering to optimize performance by only computing needed state:
// Minimal state for simple responses
const quickResponse = await runtime.composeState(
message,
['agentName', 'bio', 'recentMessages', 'messageDirections'],
true
);
// Full state for complex decision-making
const fullState = await runtime.composeState(message);
// Update pattern for ongoing conversations
let state = await runtime.composeState(message);
// ... later in conversation ...
state = await runtime.composeState(newMessage, ['RECENT_MESSAGES', 'GOALS', 'attachments']);
Providers in v1
Providers supply dynamic contextual information to the agent, acting as the agent’s “senses” for perceiving external data.
Provider Interface
interface Provider {
// REQUIRED: Unique identifier
name: string;
// Optional metadata
description?: string;
dynamic?: boolean;
position?: number;
private?: boolean;
// The data retrieval method
get: (runtime: IAgentRuntime, message: Memory, state: State) => Promise<ProviderResult>;
}
interface ProviderResult {
values?: {
[key: string]: any;
};
data?: {
[key: string]: any;
};
text?: string;
}
Creating Providers
Simple Text Provider
const weatherProvider: Provider = {
name: 'weatherProvider',
description: 'Provides current weather information',
dynamic: true,
get: async (runtime, message, state) => {
const weather = await fetchWeatherData();
return {
text: `Current weather: ${weather.temp}°F, ${weather.condition}`,
values: {
temperature: weather.temp,
condition: weather.condition,
},
};
},
};
Complex Data Provider
const marketDataProvider: Provider = {
name: 'marketDataProvider',
description: 'Provides real-time market data',
dynamic: true,
position: 10, // Higher priority
get: async (runtime, message, state) => {
const symbols = extractSymbolsFromMessage(message.content.text);
const marketData = await fetchMarketData(symbols);
const summary = formatMarketSummary(marketData);
return {
text: summary,
data: marketData,
values: {
mentionedSymbols: symbols,
marketStatus: marketData.status,
},
};
},
};
Conditional Provider
const contextualProvider: Provider = {
name: 'contextualProvider',
description: 'Provides context based on conversation',
get: async (runtime, message, state) => {
// Access state to make decisions
const topic = state.topic;
const recentTopics = analyzeRecentTopics(state.recentMessagesData);
if (!topic || !recentTopics.includes(topic)) {
return { text: '' }; // No additional context needed
}
const relevantInfo = await fetchTopicInfo(topic);
return {
text: `Relevant ${topic} information: ${relevantInfo}`,
data: { topic, info: relevantInfo },
};
},
};
Provider Options
dynamic
Property
Set to true
for providers that return different data based on context:
const timeProvider: Provider = {
name: 'timeProvider',
dynamic: true, // Time always changes
get: async () => ({
text: `Current time: ${new Date().toLocaleString()}`,
values: { timestamp: Date.now() },
}),
};
position
Property
Controls provider priority (higher = higher priority):
const criticalProvider: Provider = {
name: 'criticalProvider',
position: 100, // Will be processed before lower position providers
get: async () => ({ text: 'Critical information...' }),
};
private
Property
Hide from public provider lists:
const internalProvider: Provider = {
name: 'internalProvider',
private: true, // Won't appear in provider lists
get: async () => ({ text: 'Internal data...' }),
};
Provider Best Practices
- Always Return ProviderResult
// ❌ Bad - returning raw value
get: async () => 'Some text';
// ✅ Good - returning ProviderResult
get: async () => ({ text: 'Some text' });
- Use Appropriate Return Fields
return {
// Human-readable summary
text: 'Market is up 2.5% today',
// Simple key-value pairs for templates
values: {
marketChange: 2.5,
marketStatus: 'bullish'
},
// Complex nested data for processing
data: {
stocks: [...],
analysis: {...}
}
};
- Handle Errors Gracefully
get: async (runtime, message, state) => {
try {
const data = await fetchExternalData();
return { text: formatData(data), data };
} catch (error) {
elizaLogger.error('Provider error:', error);
return {
text: 'Unable to fetch data at this time',
values: { error: true },
};
}
};
- Optimize Performance
const cachedProvider: Provider = {
name: 'cachedProvider',
dynamic: false, // Indicates static data
get: async (runtime) => {
// Check cache first
const cached = await runtime.getSetting('providerCache');
if (cached && !isExpired(cached)) {
return { data: cached.data };
}
// Fetch fresh data
const fresh = await fetchData();
await runtime.setSetting('providerCache', {
data: fresh,
timestamp: Date.now(),
});
return { data: fresh };
},
};
v0 vs v1 Comparison
composeState Changes
Method Signature
// v0: Simple with additional keys
composeState(
message: Memory,
additionalKeys?: { [key: string]: unknown }
): Promise<State>
// v1: Advanced with filtering
composeState(
message: Memory,
includeList?: string[],
onlyInclude?: boolean,
skipCache?: boolean
): Promise<State>
Key Differences:
- Filtering: v1 allows selective state composition
- Performance: Can request only needed state keys
- Caching: Explicit cache control with
skipCache
- Update Pattern: Use same method for updates with specific keys
Migration Example:
// v0: Update pattern
state = await runtime.updateRecentMessageState(state);
// v1: Update pattern
state = await runtime.composeState(message, ['RECENT_MESSAGES']);
Provider Changes
Interface Changes
// v0: Minimal interface
interface Provider {
get: (runtime, message, state?) => Promise<any>;
}
// v1: Rich interface
interface Provider {
name: string; // REQUIRED
description?: string;
dynamic?: boolean;
position?: number;
private?: boolean;
get: (runtime, message, state) => Promise<ProviderResult>;
}
Return Type Changes
// v0: Return anything
return 'Some text';
return { data: 'value' };
// v1: Return ProviderResult
return {
text: 'Human readable',
values: { key: 'value' },
data: { complex: 'object' },
};
Key Differences:
- Required Name: Every provider must have unique
name
- Structured Returns: Must return
ProviderResult
object
- Rich Metadata: Can specify behavior with options
- State Parameter: No longer optional in
get
method
- Better Organization: Clear separation of text, values, and data
Migration Checklist
Examples & Patterns
State Filtering Pattern
// Initial load - get essential state
const initialState = await runtime.composeState(
message,
['agentName', 'bio', 'recentMessages', 'actions', 'providers'],
true
);
// Process message...
// Update only what changed
const updatedState = await runtime.composeState(message, [
'RECENT_MESSAGES',
'goals',
'attachments',
]);
Provider Chain Pattern
const providers = [
weatherProvider, // position: 10
newsProvider, // position: 5
marketProvider, // position: 15
fallbackProvider, // position: 1
];
// Will be processed in order: market, weather, news, fallback
runtime.providers = providers.sort((a, b) => (b.position || 0) - (a.position || 0));
Conditional State Building
const buildState = async (message: Memory, isDetailedResponse: boolean) => {
const baseKeys = ['agentName', 'bio', 'recentMessages'];
const keys = isDetailedResponse
? [...baseKeys, 'lore', 'topics', 'characterMessageExamples', 'knowledge']
: baseKeys;
return runtime.composeState(message, keys, true);
};