> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agenite.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Middleware APIs

> Reference for middleware in Agenite

## Overview

Middleware in Agenite allows you to intercept and modify agent behavior at various stages of execution. Middleware can be used for logging, error handling, state management, and more.

## Interface

```typescript theme={null}
type AsyncGeneratorMiddleware<
  Yield extends MiddlewareBaseYieldValue = MiddlewareBaseYieldValue,
  Return = unknown,
  Next extends MiddlewareBaseNextValue = MiddlewareBaseNextValue,
  Generator extends AsyncGenerator<
    BaseYieldValue & {
      executionContext: StepContext<any>;
    },
    unknown,
    BaseNextValue
  > = BaseAgeniteIterateGenerator,
> = (
  generator: Generator,
  context: StepContext<any>
) => AsyncGenerator<
  Yield | GeneratorYieldType<Generator>,
  Return,
  Next | GeneratorNextType<Generator>
>;
```

The middleware wraps the agent's execution generator, allowing you to:

* Intercept and modify values yielded by the generator
* Process the final return value
* Handle next values passed into the generator
* Access the execution context

## Middleware Types

```typescript theme={null}
export type MiddlewareBaseYieldValue = {
  type: `middleware.${string}`;
  [key: string]: unknown;
};

export type MiddlewareBaseNextValue = {
  type: `middleware.${string}`;
  [key: string]: unknown;
};
```

## Using middleware with an agent

```typescript theme={null}
const agent = new Agent({
  name: 'my-agent',
  provider: new BedrockProvider({ model: 'anthropic.claude-3-5-sonnet-20240620-v1:0' }),
  middlewares: [
    // Your middleware functions
    loggingMiddleware(),
    errorHandlingMiddleware()
  ],
  // ... other options
});
```

## Custom middleware examples

### Logging middleware

```typescript theme={null}
function loggingMiddleware(): AsyncGeneratorMiddleware {
  return async function* (generator, context) {
    console.log('Agent execution started');
    
    let nextValue = undefined;
    try {
      while (true) {
        const { value, done } = await generator.next(nextValue);
        
        if (done) {
          console.log('Agent execution completed');
          return value;
        }
        
        // Log each yielded value
        console.log('Event:', value.type);
        
        // Pass through to the caller
        nextValue = yield value;
      }
    } catch (error) {
      console.error('Agent execution error:', error);
      throw error;
    }
  };
}
```

### Metrics middleware

```typescript theme={null}
function metricsMiddleware(): AsyncGeneratorMiddleware {
  return async function* (generator, context) {
    const metrics = {
      startTime: Date.now(),
      yields: 0,
      toolCalls: 0,
    };
    
    let nextValue = undefined;
    try {
      while (true) {
        const { value, done } = await generator.next(nextValue);
        
        if (done) {
          const duration = Date.now() - metrics.startTime;
          console.log('Execution metrics:', {
            ...metrics,
            duration,
          });
          return value;
        }
        
        metrics.yields++;
        if (value.type === 'agenite.tool-call.params') {
          metrics.toolCalls++;
        }
        
        nextValue = yield value;
      }
    } catch (error) {
      throw error;
    }
  };
}
```

### State persistence middleware

```typescript theme={null}
function persistenceMiddleware(storage: Storage): AsyncGeneratorMiddleware {
  return async function* (generator, context) {
    // Load persisted state if exists
    const persistedState = await storage.get(`agent:${context.agent.agentConfig.name}`);
    if (persistedState) {
      Object.assign(context.state, JSON.parse(persistedState));
    }
    
    let nextValue = undefined;
    try {
      while (true) {
        const { value, done } = await generator.next(nextValue);
        
        if (done) {
          // Save final state
          await storage.set(
            `agent:${context.agent.agentConfig.name}`,
            JSON.stringify(value)
          );
          return value;
        }
        
        nextValue = yield value;
      }
    } catch (error) {
      throw error;
    }
  };
}
```

## Best practices

1. **Order matters**: Middlewares execute in the order specified in the array, with each wrapping the ones that come after it
2. **Keep it focused**: Each middleware should have a single responsibility
3. **Error handling**: Implement proper error handling within the middleware
4. **Performance**: Be mindful of performance impacts, especially in middleware that runs for every yield
5. **Typing**: Use proper TypeScript types for your custom middleware

## Next steps

* Learn about [providers](/api-reference/providers)
* See [examples](/examples)
* Read about [core concepts](/core-concepts/agents)
