Skip to main content
Middleware provides a powerful way to intercept and modify agent behavior at three levels: agent invocations, chat client requests, and function/tool executions. Middleware enables cross-cutting concerns like logging, authentication, caching, rate limiting, and error handling without modifying core agent logic.

Middleware Types

The framework provides three middleware types:

Agent Middleware

Intercepts agent.run() calls. Use for request validation, session management, and result transformation.

Chat Middleware

Intercepts chat client requests. Use for prompt engineering, message filtering, and response caching.

Function Middleware

Intercepts tool/function invocations. Use for argument validation, result caching, and execution logging.

How Middleware Works

Middleware forms a pipeline where each middleware can:
  1. Inspect the incoming request (context object)
  2. Modify the request before it reaches the next layer
  3. Call the next middleware via call_next()
  4. Inspect/modify the response after execution
  5. Short-circuit execution by not calling call_next()

Agent Middleware

Class-Based Middleware

Function-Based Middleware

Context Properties

AgentContext provides:
  • agent - The agent instance
  • messages - Input messages
  • session - Agent session (if provided)
  • options - Runtime options dict
  • stream - Whether streaming is enabled
  • result - Agent response (available after call_next())
  • metadata - Shared metadata dict for cross-middleware communication
  • kwargs - Additional keyword arguments

Function Middleware

Class-Based Function Middleware

Function-Based Function Middleware

Context Properties

FunctionInvocationContext provides:
  • function - The FunctionTool being invoked
  • arguments - Validated function arguments
  • result - Function result (available after call_next())
  • metadata - Shared metadata dict
  • kwargs - Runtime keyword arguments

Chat Middleware

Class-Based Chat Middleware

Function-Based Chat Middleware

Context Properties

ChatContext provides:
  • client - The chat client instance
  • messages - Messages being sent
  • options - Chat options dict
  • stream - Whether streaming is enabled
  • result - Chat response (available after call_next())
  • metadata - Shared metadata dict
  • kwargs - Runtime keyword arguments

Middleware Composition

Middleware can be registered at agent creation or per-run:

Advanced Patterns

Short-Circuiting Execution

Shared State Between Middleware

Conditional Middleware

Example: Complete Middleware Stack

Best Practices

Middleware Design Tips
  1. Single Responsibility: Each middleware should do one thing well
  2. Order Matters: Security/auth middleware should run first
  3. Performance: Keep middleware lightweight; avoid heavy computation
  4. Error Handling: Handle exceptions gracefully, don’t break the pipeline
  5. Metadata: Use context.metadata for cross-middleware communication
  6. Idempotency: Middleware should be safe to run multiple times
Production Considerations
  • Security First: Always validate authentication/authorization early in the pipeline
  • Monitoring: Add telemetry middleware for production observability
  • Rate Limiting: Implement rate limiting to prevent abuse
  • Timeout Handling: Set timeouts to prevent hanging requests
  • Error Logging: Log all errors for debugging
  • Testing: Test middleware in isolation before integration

Next Steps

Observability

Monitor middleware execution with OpenTelemetry

Sessions

Manage state across middleware invocations

Tools

Learn about function middleware for tools

Agents

Understand agent middleware integration