Talk to us

Your AI agent shouldn't make everyone wait.

Give any Neuron AI agent background tools and sub-agents. It hands slow work to other processes, runs it side by side, and keeps talking with your user. When the work is done, the agent picks up the results and carries on, by itself.

An advanced extension of Neuron AI, available under a commercial license.

Support agent SupportAgent · thread 7c41e2
Ready
Compare our pricing with Acme, Globex and Initech.
I've started three research tasks, one for each competitor. I'll get back to you with the comparison.
While they run, draft the release notes for 2.3.
Here's a first draft: Version 2.3 - Export invoices to CSV from the billing page - Faster search on large projects - Weekly reports now use your timezone
Background results deliveredresearcher · 3 tasks · completed
All three reports are in. Acme charges per seat, while Globex and Initech charge per usage. Want me to put them side by side with our plans?
Message the agent

New to agents? Three words first

This page uses a few words that are still new to many developers. Here is all you need to follow along.

Agent
A program that uses a language model (LLM) to decide what to do next. You give it instructions and tools; it chooses which tools to call, reads their results and writes an answer.
Tool
A function the agent can call: search the web, query your database, run a shell command, send an email.
Turn
Everything that happens between a message and the agent's answer to it. In one turn the model may call many tools, one after another, before it replies.

Today, in most frameworks, a turn is synchronous: the agent cannot answer until every tool it called has returned. That is the problem this package solves.

The problem: one slow tool freezes the whole conversation

An agent works in a loop: the model thinks, calls a tool, waits for the result, thinks again, calls the next tool, and so on until it can answer. Every tool call is a wait, and the waits add up.

This is fine when tools take milliseconds. It breaks down as soon as your agent does real work:

  • Your user stares at a spinner. A research task that reads twenty web pages, a test suite, a data export, a deployment: minutes, not seconds. Nobody can use the chat in the meantime.
  • Work happens one step at a time. Three independent research jobs run one after another, even though nothing stops them from running at the same moment.
  • Web requests time out. PHP and the web servers in front of it often cut a request after 30 or 60 seconds. A turn that runs longer simply dies, and so does the work.
  • A crash loses everything. If the process serving the turn stops, the tools it was waiting for stop with it, and nobody knows how far they got.

The usual workaround is to build a job queue by hand, invent a way to send the result back to the model, and hope the conversation is in a sane state when it arrives. That is a lot of hard, easy-to-get-wrong code, and it is the same code in every project.

One synchronous turn

13 min, start to answer
Waiting…
web_research("Acme") 4 min
web_research("Globex") 4 min
web_research("Initech") 4 min
Write the answer 1 min
Chat input locked for 13 min

Times are illustrative.

The idea: delegate, don't wait

Think of how a team lead works. They don't stand at a colleague's desk until the job is done. They hand it over, go back to their own work, and read the report when it lands in their inbox.

Neuron Subagents gives your agent that same habit:

It's like the buzzer a restaurant gives you when you order: you go sit with your friends, and it buzzes when your food is ready. If you're in the middle of a sentence, you finish it first, then you go and pick it up.

Your agents stay ordinary Neuron agents. You keep your provider, your instructions and your other tools. You add one toolkit.

Support agent SupportAgent · thread 7c41e2
Ready
Research how Acme prices its plans.
researcher({"prompt": "Find out how Acme prices its plans: tiers, units and discounts."})
{"task_id": "sub_01a1c6da-...", "status": "pending"}
I've started a research task on Acme's pricing. I'll report back here when it's done.
Background result deliveredresearcher · sub_01a1c6da-... · completed
The research on Acme is back. They charge per seat, with a lower price on annual billing and a free plan for small teams. Want me to compare it with ours?
Message the agent
Behind the scenes
Turn 1 web request done
Worker process sub_01a1c6da done
Delivery dlv_01a1c6dc
Turn 2 background done
ResearchAgent wrote its report task sub_01a1c6da-... completed delivery dlv_01a1c6dc-..., conversation is free turn 2 started in a background process turn 2 ended

Do more at once, finish sooner

Run tools and sub-agents in parallel

Every background task runs in its own process. When the model starts three tasks, all three run at the same time, and the agent doesn't sit idle while they do: it can keep working on the parts of the job that don't depend on them.

An example. Your user asks:

“Compare our pricing with Acme, Globex and Initech, and draft the release notes for version 2.3.”

Three research tasks and a draft

elapsed 13:00
Without background tasks comparison ready after 13 min
Research Acme 4 min
Research Globex 4 min
Research Initech 4 min
Draft the release notes 1 min
Chat locked for the user 13 min
With Neuron Subagents comparison ready after 4 min
Research Acme 4 min
Research Globex 4 min
Research Initech 4 min
Draft the release notes 1 min
Chat locked for the user 1 min
9 minutes back

The longer and more independent the jobs, the bigger the gain: the agent finishes in the time of its slowest task, not the sum of all of them.

Times are illustrative. How many tasks truly run at once depends on how you run them: one process each by default, or as many queue workers as you give them.

Step Without background tasks With Neuron Subagents
Research Acme (≈4 min) 0:00 → 4:00 0:00 → 4:00, in its own process
Research Globex (≈4 min) 4:00 → 8:00 0:00 → 4:00, in its own process
Research Initech (≈4 min) 8:00 → 12:00 0:00 → 4:00, in its own process
Draft the release notes 12:00 → 13:00 0:00 → 1:00, while the research runs
The user can use the chat after 13 minutes after about 1 minute
The comparison is ready after 13 minutes after about 4 minutes

Sub-agents: specialists with a clean desk

A sub-agent is a whole agent that your main agent can hand a job to: a researcher, a code reviewer, a data analyst. It gets only the instructions the main agent writes for it, not the whole conversation, so it starts focused and doesn't fill the main conversation with its intermediate steps. The main agent reads its final report.

The model sees a tool called researcher with one argument, prompt. ResearchAgent is any agent of yours: nothing in it is specific to this package.

PHP
new Subagent(
    'researcher',
    'Research a topic on the web and report the findings.',
    fn (Task $task): Agent => new ResearchAgent(),
)

Long commands in the background, a free chat for your user

Some tools are fast most of the time and slow some of the time. bash is the classic case: ls takes a millisecond, the full test suite takes twenty minutes.

With an on-demand background tool, the model picks the mode call by call:

  • A normal call runs right away inside the turn, and the model reads the output immediately, like any tool.
  • A call with run_in_background: true becomes a background task. The agent replies, and the user can keep chatting about something else while the command runs.

Here a normal bash call keeps its usual short time limit, while a background call may run for 25 minutes. You don't have to explain any of this in your prompts: the toolkit tells the model which tools run in the background, when to use run_in_background, and how to read results when they arrive.

For tools that are always slow, such as a deployment, skip onDemand(): every call then runs in the background, and the model sees the tool as deploy_background.

Dev agent DevAgent · thread 3b90af
Ready
Run the full test suite.
bash({"command": "vendor/bin/phpunit", "run_in_background": true})
{"task_id": "sub_01a1c6e1-...", "status": "pending"}
Started the full test suite in the background. It usually takes about 20 minutes, I'll tell you how it went.
Unrelated: which Laravel version are we on?
bash({"command": "composer show laravel/framework | grep versions"})
versions : * v11.31.0
You're on Laravel 11.31.0.
Background result deliveredbash · sub_01a1c6e1-... · completed
The test suite finished: 412 tests, 2 failures, both in InvoiceExportTest. The export now writes dates in UTC and the assertions still expect local time. Want me to update them?
Message the agent
PHP
(new ToolInBackground(BashTool::make(), leaseTimeout: 1800))
    ->onDemand(fn (BashTool $tool) => $tool->setTimeout(1500))

The agent picks up where it left off, on its own

This is what turns background tasks from a job queue into a real agent feature.

When a task finishes, you don't poll for it, and your user doesn't have to ask “is it done yet?”. The result is delivered into the conversation as a message, and that message starts a new turn of the agent. The model reads the result with the whole conversation in front of it, and continues the work: it summarises the research, fixes the failing test, or starts the next step.

Results wait for the right moment. A conversation can only do one thing at a time, so the delivery is careful never to talk over anyone:

  • The conversation is free: the result is delivered right away, and the agent answers it.
  • The agent is busy answering something else: the result waits a few seconds and tries again, until that turn has ended. It never interrupts a turn in progress.
  • The conversation waits for your user, for example on a tool call that needs their approval: the result waits until that is settled.
  • Several tasks finish close together: they are delivered together, in one message, so the agent answers them in a single turn instead of one turn each.

The model is told that a delivered message was written by the system, not by the user, and that everything inside a result is data, never instructions. Every result is wrapped in tags the result itself cannot fake, so a web page that a sub-agent read can't end its block early and pretend to be your user.

Support agent SupportAgent · thread 7c41e2
Ready
Meanwhile, email the 2.3 release notes to the team.
send_email({"to": "team@example.com", "subject": "Release notes 2.3"})
send_emailneeds your approval before it runs Approved
{"status": "sent"}
Sent. The release notes are on their way to the team.
3 background results delivered in one messageresearcher · Acme · completed researcher · Globex · completed researcher · Initech · completed
All three reports are in. Acme charges per seat, while Globex and Initech charge per usage. Want me to turn this into a comparison table?
Message the agent
Delivery No results waiting
Free deliver now
Busy wait for the turn to end
Waiting for the user wait for the user
The agent continues
The delivered message
<background-results id="dlv_01a1c6dc-...">
These background tasks have finished. This message was written by the system, not by the user.

<task id="sub_01a1c6da-..." tool="researcher" status="completed">
Acme charges per seat; Globex and Initech charge per usage...
</task dlv_01a1c6dc-...>
</background-results dlv_01a1c6dc-...>

Show your users what's happening

Background work only feels good when people can see it. Everything the package knows about a conversation's tasks is stored in your own database, and your application can read it to build the experience you want.

Tasks in progress. For each open task you can read its tool, its arguments, its status (pending, completed or failed), how many attempts it took, whether a stop was asked, and its result or error.

Results already delivered. Once a result reaches the conversation, it lives in the chat history as a message carrying background metadata, with the delivery ID and the IDs of its tasks. Your chat page can show it as a system notice instead of as something your user wrote.

Support agent SupportAgent · thread 7c41e2
Ready
Research Acme, Globex and Initech pricing, deploy 2.3 to staging and export last month's invoices.
Started five background tasks. You can follow them above the message box.
Skip Initech, we dropped it from the comparison.
stop_tool({"task_id": "sub_01a1c6dc-..."})
Stopping the Initech research. It ends at its next step and won't report anything.
Message the agent
The selected task, read from the ledger. Pick another one above.
$task->id "sub_01a1c6db-..."
$task->tool "researcher"
$task->inputs ['prompt' => 'Research Globex pricing...']
$task->status TaskStatus::Completed
$task->attempts 2
$task->stopRequested false
Tasks in progress
use NeuronAI\Subagents\Ledger\Ledgers;

$tasks = (new Ledgers($persistence))->of($threadId)->tasks();

foreach ($tasks as $task) {
    $task->id;            // "sub_01a1c6da-..."
    $task->tool;          // "researcher"
    $task->inputs;        // ['prompt' => 'Research Acme pricing...']
    $task->status;        // TaskStatus::Pending, Completed or Failed
    $task->attempts;      // 0 while queued, 1 or more once a worker started it
    $task->stopRequested; // true after the model asked to stop it
}
Results already delivered
foreach ($agent->getChatHistory()->getMessages() as $message) {
    if ($message->getMetadata('background') !== null) {
        // A delivered result: show it as a notice, or hide it
    }
}

The agent's answer, live. The answer to a result is written by a background process, not by the web request your user is waiting on. Reload the conversation to show it, or turn on stream: true to stream that turn through the agent's streaming channel, straight to your front end.

The model can check too. Next to the background tools, the agent gets two more: check_tool, to tell the user how a task is doing when they ask, and stop_tool, to cancel a task that is no longer needed.

With this you can build:

  • a “3 tasks running” tray above the chat input,
  • a status chip for each task: queued, running, stopping, done, failed,
  • a timeline that shows where each result entered the conversation,
  • notifications when a long job finishes while the user is on another page.

Built for production, not just for the demo

Background work is where the hard problems live: processes die, jobs get delivered twice, two workers grab the same task. The package handles them so you don't have to.

  • Nothing is lost when a process dies. A scheduled sweep runs every minute and starts again any work whose process disappeared. It executes nothing itself, it only rings the bell again.
  • Sub-agents resume where they stopped. A sub-agent whose process crashed is picked up by another one and continues its own conversation, up to three attempts.
  • A tool call never runs twice. If a background tool call crashes halfway, the package can't know whether it already took effect (did the email go out?), so it reports the task as failed instead of running it again.
  • Duplicates are harmless. A signal delivered twice, late, or to two workers at once changes nothing: only one of them does the work, and the result is reported once.
  • Approval happens before the work starts. A tool that needs a human's approval asks for it in the conversation, before the task is created, never in a process nobody is watching.
  • Stop when you want. stop_tool ends a task at its next step, and a stopped task reports nothing.
  • Each conversation sees only its own tasks. The toolkit works for the conversation your application bound the agent to: the model can never look at, or stop, another conversation's tasks.
  • No new tables. Everything is kept in the stores your agents already use: Neuron's workflow persistence and message store, on a database or Redis.
  • Your infrastructure, your choice. Start tasks as local PHP processes with zero setup, or send them to any job queue by implementing one method.
  • Easy to test. FakeRunner keeps the work in memory and runs it when your test says so, so you can test the full round trip, from the tool call to the agent's answer, in one PHPUnit test.

Getting started

1. Get your license

Neuron Subagents is an advanced extension of Neuron AI, released under a commercial license. Talk to us to get yours: it gives your team access to the package, with the details to add it to your projects through Composer.

2. Install the package

Once your project has access, install it like any other Composer package:

Terminal
composer require neuron-core/subagents

It requires PHP 8.1 or later and an application that already uses Neuron AI.

3. Wire it in

Three parts, all built the same way in every process of your application.

  • The Background object holds what your whole application shares: the storage, the way to start other processes, and the way to build your agent for a conversation.
  • Your agent declares its background tools next to its other tools, through toolkit(). Two agents can have different background tools.
  • A scheduler runs the sweep every minute, to recover from crashes.
background.php
// background.php: loaded by every process of your application
$pdo = new PDO('sqlite:' . __DIR__ . '/app.sqlite', options: [PDO::ATTR_TIMEOUT => 5]);

return new Background(
    persistence: new DatabasePersistence($pdo),
    runner: new ProcessRunner(__FILE__),
    parent: fn (string $agent, string $threadId, Background $background): Agent
        => (new $agent($background))->for($threadId),
);
SupportAgent.php
class SupportAgent extends Agent
{
    public function __construct(protected Background $background)
    {
        parent::__construct();
    }

    protected function tools(): array
    {
        return [
            $this->background->toolkit($this, [
                // A sub-agent, always in the background
                new Subagent(
                    'researcher',
                    'Research a topic and report the findings.',
                    fn (Task $task): Agent => new ResearchAgent(),
                ),
                // bash: a normal call, or a background one when the model asks for it
                (new ToolInBackground(BashTool::make(), leaseTimeout: 1800))
                    ->onDemand(fn (BashTool $tool) => $tool->setTimeout(1500)),
            ]),
            // ...your other tools
        ];
    }
}
PHP
// Serve the conversation as usual
$agent = (new SupportAgent($background))->for($threadId);

$agent->chat(new UserMessage('Compare our pricing with Acme, Globex and Initech'));
crontab
# crontab: recover lost work every minute
* * * * * php /path/to/app/vendor/bin/neuron background sweep --bootstrap=/path/to/app/background.php

That's the whole setup for a plain PHP application. On Laravel and Symfony, the integration packages do it for you.

Ready for Laravel and Symfony

Dedicated integration packages wire everything into your framework: no bootstrap file, no process runner to configure, no crontab line to remember. They build on Neuron Subagents, so your project needs a license for it, and they install the same way once it has access.

Laravel

Terminal
composer require neuron-core/subagents-laravel
  • Installs itself. The service provider is discovered automatically and there is nothing to migrate.
  • Runs on your Laravel queue. Every task and every delivery is a queued job, on the connection and queue you choose. Give a single tool a queue of its own, for example a dedicated research queue for long sub-agents.
  • Uses the stores you already have. Background work is kept in the workflow persistence your agents already use, taken from the container.
  • Sweeps on its own. The sweep is added to your schedule, every minute, on one server, without overlapping.
  • Tells you when it needs help. Set an email address and you're notified when a sweep fails, or takes longer than its minute because you've outgrown a single sweeper.
  • Built for your tests. Swap in FakeRunner, or use Queue::fake() as with any other job.
PHP
$agent = app(SupportAgent::class)->for($conversation->id);

$agent->chat(new UserMessage($request->input('message')));

Symfony

Terminal
composer require neuron-core/subagents-symfony
  • A bundle that registers everything in the service container, so your agents receive the Background by autowiring.
  • Runs on your application's own queue and scheduler, in the processes Symfony already runs, instead of a separate runner and crontab.
  • Uses the stores your agents already share, so there's nothing new to set up in your database.

Three kinds of background work

Kind What the model sees Runs in the background Typical use
Sub-agent a tool with a prompt argument always research, code review, analysis: anything that needs its own reasoning
Background tool <tool>_background, with the tool's own arguments always deployments, exports, long reports: tools that are always slow
On-demand tool the tool itself, plus run_in_background when the model asks for it bash, builds, test suites: tools that are fast or slow depending on the call

Need something else? Any Neuron workflow can become a background task by implementing one interface.

Frequently asked questions

How is Neuron Subagents licensed?

Neuron AI is open source, under the MIT license. Neuron Subagents is an advanced extension built on top of it, released under a commercial license. The Laravel and Symfony integrations build on it, so they need that license too. Talk to us to find the license that fits your team.

Do I need to change my agents?

No. Your agents stay ordinary Neuron agents. You add the background toolkit to their tools(), and give them stores every process can see, such as a database.

Do I need a queue?

No. Out of the box, each task runs in its own PHP process, started from your application. When you want a queue, the Laravel and Symfony packages use your framework's, and on any other stack you implement one small interface.

What storage do I need?

A store every process of your application can reach: a database or Redis. A single SQLite file is enough on one machine. In-memory stores only work in tests, where everything runs in one process.

What happens if my server restarts in the middle of a task?

The sweep notices the task has no live worker and starts it again. A sub-agent continues from where it stopped. A single tool call is reported as failed rather than run twice, because nobody can tell whether it already took effect.

Will a result interrupt my user while they're chatting?

Never. A result waits until the agent has finished its current turn, and is delivered as soon as the conversation is free.

Can the user, or the agent, cancel a task?

The agent can, with stop_tool, whenever the user asks or the task is no longer needed. The task ends at its next step. A single long call, such as one 20-minute command, stops when it returns.

Does the sub-agent see the whole conversation?

No. It only receives the instructions the main agent writes for it. That keeps it focused, cheaper to run, and keeps the main conversation free of its intermediate steps.

Can a sub-agent start background tasks of its own?

Yes, if you give it the background toolkit. Its results then come back to its own conversation, not to your user's.

What about tools that need human approval?

The approval is asked in the conversation, before the task starts. A task never waits for a person that isn't there.

Does it work on Windows?

The built-in process runner needs a POSIX shell, so it runs on Linux and macOS. On Windows, run the tasks on a queue.

Glossary

Agent
a program that uses a language model to decide which tools to call and how to answer.
Tool
a function the agent can call.
Turn
everything between a message and the agent's answer to it, tool calls included.
Thread (conversation)
the history of messages between a user and an agent, identified by a thread ID your application owns.
Sub-agent
an agent that another agent hands a job to, and whose final answer it reads.
Background task
a tool call or a sub-agent job that runs in another process, identified by a task ID.
Worker
the process that runs a background task.
Delivery
the step that brings finished results back into the conversation and starts the agent's next turn.
Sweep
a small command, scheduled every minute, that restarts work lost to a crash.
Persistence
the database where Neuron keeps the state of agents and tasks, shared by every process.

Stop making your users wait for your agent.

Tell us about your agents, your stack and the work you want them to take on. We'll help you plan it, and set you up with the license that fits your team.

Neuron AI is open source. Neuron Subagents is an advanced extension available under a commercial license.