Why Providers?
Your agent needs to understand the world around it. Without context, it’s flying blind:
Who is the user? What’s their history?
What actions are available right now?
What does the agent know about this topic?
Providers are the senses of your agent. They gather data from memory, services, and external sources, then feed it into the LLM prompt.
Think of providers as context injectors. Each provider contributes a piece of the puzzle - conversation history, user facts, available actions - assembled into the prompt at runtime.
Provider Interface
Providers supply contextual information that forms the agent’s understanding of the current situation. They gather data from various sources to build comprehensive state.
Core Interface
interface Provider {
name : string ;
description : string ;
dynamic ?: boolean ; // Only executed when explicitly requested
private ?: boolean ; // Internal-only, not included in default state
position ?: number ; // Execution order (lower runs first)
get : (
runtime : IAgentRuntime ,
message : Memory ,
state ?: State
) => Promise < ProviderResult >;
}
interface ProviderResult {
values : Record < string , any >; // Key-value pairs for templates
data : Record < string , any >; // Structured data
text : string ; // Textual context
}
Provider Types
Standard Providers : Included by default in state composition
Dynamic Providers : Only executed when explicitly requested
Private Providers : Internal use only, not exposed in default state
Built-in Providers
Provider Summary Table
Provider Name Dynamic Position Default Included Purpose ACTIONS No -1 Yes Lists available actions ACTION_STATE No 150 Yes Action execution state ANXIETY No Default Yes Response style guidelines ATTACHMENTS Yes Default No File/media attachments CAPABILITIES No Default Yes Service capabilities CHARACTER No Default Yes Agent personality CHOICE No Default Yes Pending user choices ENTITIES Yes Default No Conversation participants EVALUATORS No Default No (private) Post-processing options FACTS Yes Default No Stored knowledge PROVIDERS No Default Yes Available providers list RECENT_MESSAGES No 100 Yes Conversation history RELATIONSHIPS Yes Default No Social connections ROLES No Default Yes Server roles (groups only) SETTINGS No Default Yes Configuration state TIME No Default Yes Current UTC time WORLD Yes Default No Server/world context
Provider Details
Actions Provider (ACTIONS)
Lists all available actions the agent can execute.
Position : -1 (runs early)
Dynamic : No (included by default)
Data Provided :
actionNames: Comma-separated list of action names
actionsWithDescriptions: Formatted action details
actionExamples: Example usage for each action
actionsData: Raw action objects
{
values : {
actionNames : "Possible response actions: 'SEND_MESSAGE', 'SEARCH', 'CALCULATE'" ,
actionExamples : "..."
},
data : { actionsData : [ ... ] },
text : "# Available Actions \n ..."
}
Action State Provider (ACTION_STATE)
Shares execution state between chained actions.
Position : 150 (runs later)
Dynamic : No (included by default)
Data Provided :
actionResults: Previous action execution results
actionPlan: Multi-step action execution plan
workingMemory: Temporary data shared between actions
recentActionMemories: Historical action executions
Character Provider (CHARACTER)
Core personality and behavior definition.
Dynamic : No (included by default)
Data Provided :
agentName: Character name
bio: Character background
topics: Current interests
adjective: Current mood/state
directions: Style guidelines
examples: Example conversations/posts
{
values : {
agentName : "Alice" ,
bio : "AI assistant focused on..." ,
topics : "technology, science, education" ,
adjective : "helpful"
},
data : { character : { ... } },
text : "# About Alice \n ..."
}
Recent Messages Provider (RECENT_MESSAGES)
Provides conversation history and context.
Position : 100 (runs later to access other data)
Dynamic : No (included by default)
Data Provided :
recentMessages: Formatted conversation history
recentInteractions: Previous interactions
actionResults: Results from recent actions
{
values : {
recentMessages : "User: Hello \n Alice: Hi there!" ,
recentInteractions : "..."
},
data : {
recentMessages : [ ... ],
actionResults : [ ... ]
},
text : "# Conversation Messages \n ..."
}
Facts Provider (FACTS)
Retrieves contextually relevant stored facts.
Dynamic : Yes (must be explicitly included)
Behavior : Uses embedding search to find relevant facts
Data Provided :
Relevant facts based on context
Fact metadata and sources
Relationships Provider (RELATIONSHIPS)
Social graph and interaction history.
Dynamic : Yes (must be explicitly included)
Data Provided :
Known entities and their relationships
Interaction frequency
Relationship metadata
State Composition
The composeState method aggregates data from multiple providers to create comprehensive state.
Method Signature
async composeState (
message : Memory ,
includeList : string [] | null = null ,
onlyInclude = false ,
skipCache = false
): Promise < State >
Parameters
message : The current message/memory object being processed
includeList : Array of provider names to include (optional)
onlyInclude : If true, ONLY include providers from includeList
skipCache : If true, bypass cache and fetch fresh data
Composition Process
Provider Selection : Determines which providers to run based on filters
Parallel Execution : Runs all selected providers concurrently
Result Aggregation : Combines results from all providers
Caching : Stores the composed state for reuse
Usage Patterns
// Default state (all non-dynamic, non-private providers)
const state = await runtime . composeState ( message );
// Include specific dynamic providers
const state = await runtime . composeState ( message , [ 'FACTS' , 'ENTITIES' ]);
// Only specific providers
const state = await runtime . composeState ( message , [ 'CHARACTER' ], true );
// Force fresh data (skip cache)
const state = await runtime . composeState ( message , null , false , true );
Provider Registration
Registering a Provider
runtime . registerProvider ( provider );
Providers are registered during plugin initialization:
const myPlugin : Plugin = {
name: 'my-plugin' ,
providers: [ customProvider ],
init : async ( config , runtime ) => {
// Providers auto-registered
}
};
Provider Position
Position determines execution order:
const earlyProvider : Provider = {
name: 'EARLY' ,
position: - 100 , // Runs very early
get : async () => { ... }
};
const lateProvider : Provider = {
name: 'LATE' ,
position: 200 , // Runs late
get : async () => { ... }
};
Custom Providers
Creating a Custom Provider
const customDataProvider : Provider = {
name: 'CUSTOM_DATA' ,
description: 'Custom data from external source' ,
dynamic: true ,
position: 150 ,
get : async ( runtime , message , state ) => {
try {
// Fetch data from service or database
const customData = await runtime . getService ( 'customService' )?. getData ();
if ( ! customData ) {
return { values: {}, data: {}, text: '' };
}
return {
values: { customData: customData . summary },
data: { customData },
text: `Custom data: ${ customData . summary } ` ,
};
} catch ( error ) {
runtime . logger . error ( 'Error in custom provider:' , error );
return { values: {}, data: {}, text: '' };
}
},
};
Provider Best Practices
Return quickly : Use timeouts for external calls
Handle errors gracefully : Return empty result on failure
Keep data size reasonable : Don’t return excessive data
Use appropriate flags : Set dynamic for optional providers
Consider position : Order matters for dependent providers
Provider Dependencies
Providers can access data from previously executed providers through the state parameter:
const dependentProvider : Provider = {
name: 'DEPENDENT' ,
position: 200 , // Runs after other providers
get : async ( runtime , message , state ) => {
// Access data from earlier providers
const characterData = state ?. data ?. providers ?. CHARACTER ?. data ;
if ( ! characterData ) {
return { values: {}, data: {}, text: '' };
}
// Process based on character data
const processed = processCharacterData ( characterData );
return {
values: { processed: processed . summary },
data: { processed },
text: `Processed: ${ processed . summary } `
};
}
};
State Cache Management
Cache Architecture
The runtime maintains an in-memory cache of composed states:
// Cache is stored by message ID
this . stateCache . set ( message . id , newState );
Cache Usage
// Use cached data (default behavior)
const cachedState = await runtime . composeState ( message );
// Force fresh data
const freshState = await runtime . composeState ( message , null , false , true );
Cache Optimization
// Clear old cache entries periodically
setInterval (() => {
const fiveMinutesAgo = Date . now () - 5 * 60 * 1000 ;
for ( const [ messageId , _ ] of runtime . stateCache . entries ()) {
runtime . getMemoryById ( messageId ). then (( memory ) => {
if ( memory && memory . createdAt < fiveMinutesAgo ) {
runtime . stateCache . delete ( messageId );
}
});
}
}, 60000 ); // Run every minute
Provider Execution Flow
Parallel Execution
Providers run concurrently for optimal performance:
const results = await Promise . all (
providers . map ( provider =>
provider . get ( runtime , message , partialState )
)
);
Timeout Handling
Implement timeouts to prevent slow providers from blocking:
const timeoutProvider : Provider = {
name: 'TIMEOUT_SAFE' ,
get : async ( runtime , message ) => {
const fetchData = async () => {
// Potentially slow operation
const data = await externalAPI . fetch ();
return formatProviderResult ( data );
};
return Promise . race ([
fetchData (),
new Promise (( _ , reject ) =>
setTimeout (() => reject ( new Error ( 'Timeout' )), 5000 )
)
]). catch ( error => {
runtime . logger . warn ( `Provider timeout: ${ error . message } ` );
return { values: {}, data: {}, text: '' };
});
}
};
Common Issues and Solutions
Circular Dependencies
Avoid providers that depend on each other circularly:
// BAD: Circular dependency
const providerA : Provider = {
get : async ( runtime , message ) => {
const state = await runtime . composeState ( message , [ 'B' ]);
// Uses B's data
}
};
const providerB : Provider = {
get : async ( runtime , message ) => {
const state = await runtime . composeState ( message , [ 'A' ]);
// Uses A's data - CIRCULAR!
}
};
// GOOD: Use position and state parameter
const providerA : Provider = {
position: 100 ,
get : async ( runtime , message ) => {
// Generate data independently
return { data: { aData: 'value' } };
}
};
const providerB : Provider = {
position: 200 ,
get : async ( runtime , message , state ) => {
// Access A's data from state
const aData = state ?. data ?. providers ?. A ?. data ;
return { data: { bData: processData ( aData ) } };
}
};
Memory Leaks
Prevent memory leaks with proper cache management:
class BoundedCache extends Map {
private maxSize : number ;
constructor ( maxSize : number = 1000 ) {
super ();
this . maxSize = maxSize ;
}
set ( key : string , value : any ) {
if ( this . size >= this . maxSize ) {
const firstKey = this . keys (). next (). value ;
this . delete ( firstKey );
}
return super . set ( key , value );
}
}
Debugging State Composition
// Debug helper to trace provider execution
async function debugComposeState ( runtime : IAgentRuntime , message : Memory , includeList ?: string []) {
console . log ( '=== State Composition Debug ===' );
console . log ( 'Message ID:' , message . id );
console . log ( 'Include List:' , includeList || 'default' );
// Monkey patch provider execution
const originalProviders = runtime . providers ;
runtime . providers = runtime . providers . map (( provider ) => ({
... provider ,
get : async ( ... args ) => {
const start = Date . now ();
console . log ( `[ ${ provider . name } ] Starting...` );
try {
const result = await provider . get ( ... args );
const duration = Date . now () - start ;
console . log ( `[ ${ provider . name } ] Completed in ${ duration } ms` );
console . log ( `[ ${ provider . name } ] Data size:` , JSON . stringify ( result ). length );
return result ;
} catch ( error ) {
console . error ( `[ ${ provider . name } ] Error:` , error );
throw error ;
}
},
}));
const state = await runtime . composeState ( message , includeList );
// Restore original providers
runtime . providers = originalProviders ;
console . log ( '=== Final State Summary ===' );
console . log ( 'Total providers run:' , Object . keys ( state . data . providers || {}). length );
console . log ( 'State text length:' , state . text . length );
console . log ( '===============================' );
return state ;
}
See Also
Models Learn how models use provider context
Services Build services that use providers
Messaging Real-time provider updates
Sessions API See providers in conversational context