Middleware

Control and customize agent execution at every step

What is a Middleware

Middleware provides a way to more tightly control what happens inside the workflow. The core Workflow execution involves calling nodes based on the events returned by other nodes. Middleware exposes hooks before and after each of those steps:

What can middleware do?

Modify

Transform prompts, tool selection, and output formatting.

Control

Add retries, fallbacks, and early termination logic, rate limits, guardrails.

Monitor

Track agent behavior with logging, analytics, and debugging.

Creating Middleware

You can use the command below to create a middleware class:

php vendor/bin/neuron make:middleware CustomMiddleware

A new class will be created in your project with the default middleware structure:

<?php

namespace App\Neuron\Middleware;

class CustomMiddleware implements WorkflowMiddleware
{
    /**
     * Execute before the node runs.
     */
    public function before(NodeInterface $node, Event $event, WorkflowState $state): void
    {
        // ...
    }
    
    /**
     * Execute after the node runs.
     */
    public function after(NodeInterface $node, Event $event, Event|Generator $result, WorkflowState $state): void
    {
        // ...
    }
}

Registering Middleware

If you would like to assign middleware to specific nodes, you may override the middleware method when defining the workflow:

class MyWorkflow extends Workflow
{
    /**
     * Define the nodes middleware.
     *
     * @return array<class-string<NodeInterface>, WorkflowMiddleware[]>
     */
    protected function middleware(): array
    {
        return [
            NodeOne::class => new CustomMiddleware(),
        ];
    }
}

You can also assign multiple middleware to ta node, defining an array:

class MyWorkflow extends Workflow
{
    /**
     * Define the nodes middleware.
     *
     * @return array<class-string<NodeInterface>, WorkflowMiddleware|WorkflowMiddleware[]>
     */
    protected function middleware(): array
    {
        return [
            NodeOne::class => [
                new CustomMiddleware(),
                new AnotherMiddleware(),
            ]
        ];
    }
}

Global Middleware

If you want a middleware to run before and after every node, you may append it to the global middleware stack in your workflow:

class MyWorkflow extends Workflow
{
    /**
     * Define the global middleware.
     *
     * @return WorkflowMiddleware[]
     */
    protected function globalMiddleware(): array
    {
        return [
            new CustomMiddleware(),
        ];
    }
}

Examples

Neuron provides prebuilt middleware for common use cases, like tool approval, or context summarization. You can check them out in the Agent section:

Middleware

Last updated