Skip to main content
Submitted by admin on

We're introducing AI Neuron, a module that bridges Drupal with Neuron AI, a PHP framework for building agents, tools and multi-step workflows.

When you’re building AI features in Drupal, the AI module is the obvious place to start. It gives the whole site one place to configure providers and keys, and a default model for each kind of call.

Building an agentic solution means sequencing those calls into something that plans, decides what to do with a tool’s result, and calls another tool in response. The Drupal ecosystem already offers modules for that: AI Agents, ECA, the Tool API. Each gets you part of the way, but what’s left for the developer is gluing them together into one coherent solution. And that’s the hard part: each piece lives in its own module, configured on its own screen, in its own way, which makes iterating on the result, adjusting it, and evaluating it, slow.

What we wanted was one place to drive that development end to end, from a developer’s point of view: write the agent in PHP, iterate on its configuration quickly, and get real observability and evaluation, without ever leaving code to go configure something on a Drupal settings page.

Enter Neuron AI

Neuron AI is a PHP framework for building agents, tools and multi-step workflows. It handles the provider calls, the conversation memory, and the observability a run needs, so what’s left to write is the part specific to what your agent actually does.

Under the hood, five concepts drive it:

  • Agent holds the conversation: give it a provider, instructions and a list of tools, and it takes a message, calls the model, calls a tool if the model asks for one, and keeps going until it has an answer.
  • Tools are what an agent is allowed to do: a name and description the model reads to decide when to call one, the inputs it accepts, and the code that runs when it does.
  • Workflow is the layer underneath all of this: a graph of nodes wired by the events they emit and accept. An agent is really just a workflow built for the common case of holding a conversation. Because it is a workflow, a run can pause to wait on a person and resume later, in a different request, which is what a step that needs a human’s approval needs.
  • Chat history and memory keeps every conversation in a message store, from one scoped to a single request to one backed by a database that survives it. Once a thread grows past the model’s context window, the store trims the oldest messages to keep the next call from failing.
  • Streaming sends the same four kinds of chunk no matter who’s listening: text, a tool call, a tool’s result, and reasoning where the model produces it. What changes is the adapter: it translates that stream into the shape a given consumer expects, the Vercel AI SDK’s protocol, the AG-UI protocol, or a channel that keeps delivering chunks after the request that started the run has already ended.

Introducing the AI Neuron module

Reading the overview above, the shape of the integration seems obvious: translate each Drupal AI object into its Neuron equivalent, one for one. For providers, that’s exactly what happens. A Drupal AI provider becomes a native Neuron provider, and the site’s keys, default models and caching apply unchanged.

For tools and agents, we built something different. Neuron is a full framework in its own right, with its own tool-calling loop, its own memory, its own way of streaming and evaluating a run. Translating a Drupal tool or a Drupal agent into its Neuron equivalent would mean keeping two shapes in sync, and whatever came out the other end would still carry Drupal’s own assumptions into an object Neuron has to treat as entirely its own.

So instead, developers write Neuron objects directly, as Drupal plugins, with no translation step in between. A plugin is a factory for the agent, the tool or the workflow it declares, built fresh each time one is asked for: it reaches into Drupal, its service container, its permissions, whatever the site has configured, and uses all of that to build a native Neuron object.

What comes out is exactly what Neuron itself would build from its own API, with no Drupal shape to it, which is the point: Neuron can test it against its own fake providers and evaluate it with its own harness, with no idea Drupal was ever involved.

That division pays off later, too. When the AI module’s own tools and agents get bridged in, they’ll be built the same way: plugins that manufacture the native Neuron object itself.

What you don’t have to build: data persistence and logging

Every agent and workflow a plugin manager builds also gets storage, persistence and logging for free, on top of the provider bridge above.

  • Conversation storage: nothing to declare. Every message is a neuron_message entity row, keyed by the thread id, and already recording its own token usage. The entity is bundleable and fieldable, so a module that needs to track something else about a conversation extends the same entity with its own fields.
  • Workflow persistence: every agent and workflow gets a durable record of its run, so it can suspend in one request and resume in another, which is what a human approval step or a queue-driven agent actually needs.
  • Logging and observability: every run is tagged per agent and reported to the ai_neuron log channel.

That’s the original promise kept: iterate on the agent, while the storage, persistence, logging and provider connection around it stay fixed.

Manufacturing native Neuron objects

With the ai_neuron module, Neuron’s three building blocks, agent, tool and workflow, become Drupal plugins.

As outlined above, a plugin is a factory for native Neuron objects: ask the related plugin manager for one by its id and get back a native Neuron object.

Here’s an example of a Drupal plugin that builds the matching Neuron object. Extend the base class and fill in the same methods you’d write against Neuron directly:

#[NeuronAgent(
  id: 'reporter',
  label: new TranslatableMarkup('Reporter'),
)]
final class ReporterNeuronAgent extends NeuronAgentPluginBase {

  protected function instructions(): string {
    return 'Summarize the content that changed.';
  }

}

A tool is a plugin too. Declare its properties, then put the tool’s logic in __invoke():

#[NeuronTool(
  id: 'count_posts',
  description: 'Count the published posts of a content type.',
)]
final class CountPostsNeuronTool extends NeuronToolPluginBase {

  protected function properties(): array {
    return [new ToolProperty('type', PropertyType::STRING, 'The content type.', TRUE)];
  }

  public function __invoke(string $type): string {
    // Count them and say so.
  }

}

A workflow is declared the same way: list the nodes it’s made of, and Neuron takes care of the rest:

#[NeuronWorkflow(
  id: 'edit_post',
  label: new TranslatableMarkup('Edit a post'),
)]
final class EditPostNeuronWorkflow extends NeuronWorkflowPluginBase {

  protected function nodes(): array {
    return [
      new LoadPostNode($this->entityTypeManager),
      new ReviseNode($this->agents),
      new SavePostNode($this->entityTypeManager),
    ];
  }

}

Each node declares, in its own method signature, the one event it accepts, but it can fire any event back. That’s the whole wiring: whichever node listens for the fired event starts next, with nothing left to configure by hand.

It also means a node can fire a different event depending on what it finds, starting a different node in response, which is what lets developers build workflows that branch and loop, as complex as they need.

Declaring these as Drupal plugins buys the usual things for free. The site discovers them with no manual registration, from any module that declares one, and a constructor asking for EntityTypeManagerInterface, or any other Drupal service, gets it through dependency injection like any other plugin.

Fetching and using one goes through its manager, which hands back a native Neuron object each time, a new one, because an agent carries the conversation it’s having:

$agent = \Drupal::service(NeuronAgentManagerInterface::class)->createAgent('reporter');
$agent->chat($message);

From there it goes anywhere Neuron takes it, straight through Neuron’s own API: chat(), stream(), tools, middleware, chat history.

getNeuron() is the factory method behind all of this: it builds the native object, wiring in the provider, the tools, the error handler, whatever the plugin declared.

Overriding getNeuron() is the escape hatch, and it goes both ways. Drop in a hand-written Neuron agent, tool or workflow wholesale, and the base class configures nothing on top of it. That’s also the door for anything built outside Drupal entirely: NeuronHub, Neuron’s own package registry, publishes ready-made agents, workflows and toolkits, and any of them plugs into a site the same way, through the same override.

Try it

The easiest way to try it is to clone the repo and follow the instructions in its README.md: they set up a working site with the example module already enabled.

The ai_neuron_example submodule is a working agent you can talk to from the terminal: a Ghostwriter that writes blog posts for you. It ships a minimal Blog content type, three tools that create, list and edit posts, and an editing workflow of three nodes that the agent reaches through a tool, so one command exercises all three plugin types, plus structured output for the node that rewrites a post:

ddev drush ghost

It asks for a title and a body, and only invents them when you tell it to (“you decide”, “don’t ask, just create it”), in which case it writes whatever’s missing and creates the post in the same reply. Every event a run emits prints to the terminal as it happens, tool calls and workflow nodes included, so you watch a run happen live. The command also names the conversation it reopens, so you can leave it and pick it back up later, which is the conversation store’s work made visible.

What’s next

Five things are planned, in no particular order:

  • Neuron tools derived from Tool API: one Neuron tool per tool plugin installed on the site, built from the typed inputs and JSON schema it already declares, so a tool written once is callable from a Neuron agent exactly as it already is from AI Agents, ECA, etc.
  • Neuron agents derived from the AI module’s own agent plugins: one Neuron agent per configured AI Agents entity, usable as a step in a larger workflow.
  • Evaluations, running Neuron’s own harness against agents the site already has.
  • Channels, so a long-running agent can run in the background and stream its output to the UI through them, even after the request that started it has ended.
  • Providers running both ways: a Neuron provider exposed as a Drupal AI provider too.

Tags: Drupal Planet, AI

Aggregate 核验溯源
Domain Tag
drupal
Source Name
Drupal.org Planet