---
title: "Providers"
description: "Real data, real-time - give your agent situational awareness"
---

## 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.

<Tip>
  **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.
</Tip>

## 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

```typescript
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, unknown>; // Key-value pairs for templates
  data: Record<string, unknown>; // 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

```typescript
{
  values: {
    actionNames: "Possible response actions: '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

```typescript
{
  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

```typescript
{
  values: {
    recentMessages: "User: Hello\nAlice: 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

```typescript
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

1. **Provider Selection**: Determines which providers to run based on filters
2. **Parallel Execution**: Runs all selected providers concurrently
3. **Result Aggregation**: Combines results from all providers
4. **Caching**: Stores the composed state for reuse

### Usage Patterns

```typescript
// 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

```typescript
runtime.registerProvider(provider);
```

Providers are registered during plugin initialization:

```typescript
const myPlugin: Plugin = {
  name: "my-plugin",
  providers: [customProvider],

  init: async (config, runtime) => {
    // Providers auto-registered
  },
};
```

### Provider Position

Position determines execution order:

```typescript
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

```typescript
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 = 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

1. **Return quickly**: Use timeouts for external calls
2. **Handle errors gracefully**: Return empty result on failure
3. **Keep data size reasonable**: Don't return excessive data
4. **Use appropriate flags**: Set `dynamic` for optional providers
5. **Consider position**: Order matters for dependent providers

### Provider Dependencies

Providers can access data from previously executed providers through the state parameter:

```typescript
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:

```typescript
// Cache is stored by message ID
this.stateCache.set(message.id, newState);
```

### Cache Usage

```typescript
// 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

```typescript
// 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

```mermaid
flowchart TD
    Start[composeState called] --> Select[Select Providers]
    Select --> Check{Check Cache}
    Check -->|Cache Hit| Return[Return Cached State]
    Check -->|Cache Miss| Sort[Sort by Position]
    Sort --> Execute[Execute in Parallel]
    Execute --> Aggregate[Aggregate Results]
    Aggregate --> Cache[Store in Cache]
    Cache --> Return

    classDef process fill:#2196f3,color:#fff
    classDef decision fill:#ff9800,color:#fff
    classDef execution fill:#4caf50,color:#fff
    classDef result fill:#9c27b0,color:#fff

    class Start,Select,Sort process
    class Check decision
    class Execute,Aggregate execution
    class Return,Cache result
```

## Performance Optimization

### Parallel Execution

Providers run concurrently for optimal performance:

```typescript
const results = await Promise.all(
  providers.map((provider) => provider.get(runtime, message, partialState)),
);
```

### Timeout Handling

Implement timeouts to prevent slow providers from blocking:

```typescript
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:

```typescript
// 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:

```typescript
class BoundedCache extends Map {
  private maxSize: number;

  constructor(maxSize: number = 1000) {
    super();
    this.maxSize = maxSize;
  }

  set(key: string, value: unknown) {
    if (this.size >= this.maxSize) {
      const firstKey = this.keys().next().value;
      this.delete(firstKey);
    }
    return super.set(key, value);
  }
}
```

### Debugging State Composition

```typescript
// 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

<CardGroup cols={2}>
  <Card title="Models" icon="robot" href="/runtime/models">
    Learn how models use provider context
  </Card>

<Card title="Services" icon="server" href="/runtime/services">
  Build services that use providers
</Card>

<Card title="Messaging" icon="message" href="/runtime/messaging">
  Real-time provider updates
</Card>

  <Card title="Sessions API" icon="comments" href="/runtime/sessions-api">
    See providers in conversational context
  </Card>
</CardGroup>
