Independent AI intelligence Two editions daily · ET
Fervor AI

Analysis · November 7, 2026 · concept

LangChain Deep Agentsmulti-agentagent-harnessagent-infrastructure

Async Subagents: The One Setting That Decides What Your AI Agent Does When You Change Your Mind

Background workers make agents faster. They also make "wait, change that" a design decision. LangChain just turned it into one field.

An AI agent that disappears for ten minutes while one tool runs feels broken, even when it is working perfectly.

You ask for a research report, the agent starts a long search, and the chat goes silent. You think of a better angle two minutes in. You can't tell it. The loop is busy, and everything you type waits in line behind that one call.

That is changing fast. On November 5, LangChain published "Agents Are Going Async", which adds background subagents to Deep Agents, its open-source agent framework. The post points out that Claude Code already starts subagents in the background by default, and that OpenAI's dots and DeepSeek Harness are built around background workers too.

So the hard question moves. It used to be "how do I keep the agent from blocking?" Now it is "what happens when I change my mind while a worker I can't see is halfway through?"

LangChain answers it with a setting called update_strategy. It has two values: interrupt stops the job in flight and restarts it with your correction, and enqueue lets the job finish and runs your message next. Picking between them on purpose is the most useful thing in the release.

What "async subagents" means in plain words

A subagent is a helper agent that the main agent hands a job to: research this, write that function, run those tests.

In the classic setup, the main agent waits for the helper to finish. LangChain's post names the problem directly: "In a standard ReAct loop, each long tool call blocks the loop and every other task queues behind it." (ReAct is the common think, act, observe loop most agents run.)

An async subagent works more like a restaurant kitchen. The person at the counter (LangChain calls it the orchestrator, or supervisor) keeps taking your orders. The cooks (the subagents) work in the back on their own tickets and ring a bell when a dish is ready. Programmers will recognize it from the post's own comparison: it works "like a task started with asyncio.create_task or a Promise you don't await yet."

The orchestrator runs the kitchen with five tools:

  • start_async_task starts a subagent on its own thread and returns right away.
  • check_async_task gets a task's status and, once it's done, its result.
  • update_async_task sends a running task new instructions.
  • cancel_async_task stops a task.
  • list_async_tasks lists every task and its status.

The third tool is where things get interesting.

Interrupt or enqueue: the choice that decides what a correction costs

When you send a follow-up to a running subagent, update_strategy decides what happens to the work already in progress. The Deep Agents docs define two options:

  • "interrupt" (the default) stops the current run and restarts the subagent with your new instruction.
  • "enqueue" holds your follow-up until the current run finishes, then starts it.

LangChain's examples make the split easy to remember. Interrupt fits a correction like "use Postgres instead." Enqueue fits an addition like "run the tests when you're done."

Think about what each one does to a twenty-minute job.

With interrupt, a correction at minute fifteen stops that run. The subagent starts again from your new instruction, and the run you stopped does not finish. That is exactly right when the old direction was wrong. Finishing a migration against the wrong database is worse than starting over.

With enqueue, the same message at minute fifteen waits. The current run completes, then your follow-up starts as the next run. That is right when the work in flight is still good and you only want to add to it.

The trap is the default. Interrupt protects you from wasted work in the wrong direction, but it also means a casual "oh, and also..." can throw away a run that was nearly done. Nothing in the message itself tells the subagent which kind it is. The setting on that subagent's definition decides.

That's why I'd treat update_strategy as something you write down for every subagent, even when you want the default. A research worker whose direction you often adjust is a good fit for interrupt. A worker that runs a long build or a test suite usually wants enqueue, because a half-finished build you restart is just a slower build.

The docs add one sharp edge for enqueue: if the current run pauses to ask for input or approval before your queued follow-up starts, "the follow-up still starts and that request is dropped." A question the worker asked you can vanish without a word because you queued something behind it.

Who answers when a background worker needs permission

Background work raises a second question: what happens when a worker needs your approval and you're not looking at it?

LangChain's answer is that the request stays yours. A subagent that needs approval shows up with the status waiting, and per the docs, "The supervisor cannot answer or approve on the user's behalf. The request is for the user." You answer on the subagent's own thread, without interrupting the main conversation.

Two details are worth knowing before you rely on it. Sending an update to a waiting task drops its pending request. Cancelling one only marks it "cancelled", since nothing is running.

The orchestrator also has to learn when work finishes. The post describes three cases: if it is busy, it checks unfinished tasks before each model call; if it is idle, a finished subagent wakes it with a new run; and if it is paused on an approval, the result waits until you answer. Every unfinished task is also listed in the orchestrator's system prompt, so it always knows what is in flight.

Claude Code made a similar call from the other direction. Its subagent docs say background subagents surface their permission prompts in your main session and name the subagent asking. They also carry a warning worth reading twice: when you answer one of those prompts with a grant that lasts beyond that single tool call, Claude Code applies it to the whole session, including your main conversation. A "yes for the rest of this session" given to a background worker is a yes for everything.

Different tools, same lesson. Background agents don't remove approval decisions. They move them to moments when you're paying less attention.

Put this into practice

Here's the lowest-friction way to try async subagents and set the correction behavior on purpose.

1. Install a version that has the settings. The docs say update_strategy, webhook and notify_parent need deepagents>=0.7.30, and task notifications plus the waiting status need 0.7.26 or later.

pip install -U "deepagents>=0.7.30"

Since these features are beta, pin the exact version you tested once something works, so an upgrade can't change correction behavior under you.

2. Define each subagent with an explicit strategy. This follows the docs' own example, with update_strategy written out on both workers:

from deepagents import AsyncSubAgent, create_deep_agent

async_subagents = [
    AsyncSubAgent(
        name="researcher",
        description="Research agent for information gathering and synthesis",
        graph_id="researcher",
        update_strategy="interrupt",   # corrections should redirect it
    ),
    AsyncSubAgent(
        name="coder",
        description="Coding agent for code generation and review",
        graph_id="coder",
        update_strategy="enqueue",     # let the current change finish first
    ),
]

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    subagents=async_subagents,
)

The model string is the docs' example; swap in a provider you already have a key for. graph_id is the name of the subagent's own agent graph (the program that runs it), and it must match a graph registered in your langgraph.json. Leave out url and the subagent runs in the same deployment; add a url to call a remote server.

3. Give it enough workers. A worker slot is one unit of capacity on the server that runs your agents, and each running task occupies one. The docs' math: a supervisor with three subagent tasks running needs four slots. Locally, that means starting the dev server with room to spare:

langgraph dev --n-jobs-per-worker 10

Too few slots and new tasks sit in a queue until one frees up, which looks a lot like the blocking you were trying to escape.

4. Test the correction path before you trust it. Start a long task, then send one correction and one addition. Check which runs restarted, which waited, and whether any approval request vanished. Five minutes of this tells you more than the docs will.

A concrete version: ask the coder subagent to refactor a module and run the tests, then send "also update the README" a minute later. With enqueue, list_async_tasks should show the task as pending behind the running job, and the README change should arrive as a second run. Switch the same subagent to interrupt and repeat. This time the refactor run stops and the subagent restarts with your new instruction, which is a good way to see why the default deserves a second look.

If you want a working starting point, LangChain's async-deep-agents repo has a supervisor with researcher and coder subagents in Python and TypeScript. It needs Python 3.11+ or Node.js 20+, and an Anthropic API key unless you swap the model.

Honest limitations

This is early, and the docs say so.

  • Much of it is beta. update_strategy, task notifications, the waiting status and notify_parent all carry beta labels, and "APIs and behavior may change between releases." Fork mode is marked experimental.
  • Automatic notifications need a server. The supervisor learns about finished, failed or waiting tasks on its own only when running on an Agent Protocol server, such as LangSmith Deployments or a self-hosted equivalent. Outside that, it has to poll.
  • Worker slots cost money in production. Background work scales with the number of workers, and every worker is capacity you pay for.
  • The reference repo is rough. Its README clones a repository called async-subagents while the repo is named async-deep-agents, and no license is shown on its GitHub page as of November 7. Read it as an example, not a dependency.
  • The default is a guess. Interrupt is a sensible default for corrections. It is the wrong one for a worker halfway through something expensive, and nothing warns you.

The question to answer before you go async

Background subagents are worth it the moment your agent's longest tool call is longer than your patience. The speedup is real, and the pattern is spreading across Claude Code, OpenAI's dots and DeepSeek Harness.

But a background worker turns every "actually, change that" into a decision about work you can't see. Before you flip a subagent to async, write down what a correction should do to it. Restart it, or let it finish? You will be making that call either way. Better to make it once, in the definition, than at minute fifteen.

Sources: LangChain, "Agents Are Going Async" (Nov 5, 2026); Deep Agents async subagents docs; langchain-ai/async-deep-agents; Claude Code subagent docs. Docs read November 7, 2026.