Deep Agents integration
Temporal's integration with Deep Agents makes an existing LangChain
Deep Agent durable by adding one plugin. Build your agent with create_deep_agent(...) inside a Workflow, add
DeepAgentsPlugin to your Client or Worker, and each LLM call and each I/O tool call becomes a Temporal Activity —
while the agent's control loop runs, and deterministically replays, inside the Workflow.
The code you already wrote against deepagents doesn't change. Sub-agents, planning and todo state, the filesystem
middleware, human-in-the-loop interrupts, and agent.ainvoke(...) all keep working. On top of that you get
crash durability, automatic retries and timeouts on every model and tool call, resumable human-in-the-loop, and
bounded Workflow history for long-running agents.
The temporalio.contrib.deepagents plugin is experimental and its API may change in future versions.
Code snippets in this guide are taken from the Deep Agents plugin samples. Refer to the samples for the complete code.
Prerequisites
- This guide assumes you are already familiar with Deep Agents. If you aren't, refer to the Deep Agents documentation for more details.
- If you are new to Temporal, we recommend reading Understanding Temporal or taking the Temporal 101 course.
- Ensure you have set up your local development environment by following the Set up your local development environment guide. When you're done, leave the Temporal development server running if you want to test your code locally.
Install the plugin
Install the Temporal Python SDK with Deep Agents support:
uv add "temporalio[deepagents]"
or with pip:
pip install "temporalio[deepagents]"
The integration is experimental and ships with an upcoming Temporal Python SDK release. It requires Python 3.11 or
newer, the same floor that deepagents sets.
Hello World
A Deep Agent becomes durable without changing the agent code itself. The Workflow below builds a vanilla
create_deep_agent(...) and drives it with await agent.ainvoke(...) — exactly the code you would write outside
Temporal. Because model= is a bare "provider:name" string, the plugin auto-routes the model call through the
deepagents.invoke_model Activity, so the LLM call gets Temporal-managed retries and timeouts while the agent's control
loop replays deterministically in the Workflow.
DeepAgentsPlugin is a client-level plugin: add it to Client.connect(...) and the SDK propagates it to any Worker
built from that Client. Add it on exactly one side. The plugin registers the deepagents.* Activities and installs the
LangChain-aware data converter, so the Worker needs no other wiring.
Use model_activity_options on the plugin to control the timeout and retry policy for each model call. API keys live on
the Worker via the model provider (LangChain's init_chat_model by default), never in Workflow inputs or history —
the Workflow ships only the model name, and the Worker builds the real client. LLM-SDK-side retries are disabled so that
Temporal owns retries and timeouts.
Start the Workflow like any other:
Choose Workflow or Activity execution per tool
A Deep Agent holds its tools in-Workflow. A tool that only reads or writes agent state is pure and belongs there; a tool that does real I/O must not run in Workflow code. The plugin gives you two explicit ways to move a tool's work into an Activity:
activity_as_tool(my_activity, ...)surfaces an existing@activity.defnfunction as a Deep Agents tool without re-declaring it.tool_as_activity(tool, ...)wraps a LangChain tool whose body does I/O so its execution runs as adeepagents.invoke_toolActivity.
An unwrapped, non-builtin tool runs in-Workflow and the plugin warns at construction, so that choice is never silent.
Deep Agents' pure built-ins (write_todos, the state-backed file tools) stay in-Workflow by design.
This sample wraps an existing activity and an I/O tool, and constructs the model explicitly as TemporalModel(...) to
show the non-auto path:
Durable backends
A Deep Agent's built-in file tools (write_file, read_file, ls, and so on) delegate to a backend. The default
StateBackend keeps files in agent state — pure Workflow state, replay-safe, and needs no wrapping. A FilesystemBackend,
LocalShellBackend, or StoreBackend touches real resources, which must not happen from Workflow code.
Wrap such a backend with TemporalBackend(inner, activity_options=...) so each file or shell operation the agent's tools
invoke becomes a deepagents.backend_op Activity instead of running in the Workflow. The agent code is unchanged; only
the backend is wrapped.
Sub-agents
A coordinator built with create_deep_agent(..., subagents=[...]) delegates to its sub-agents via the built-in task
tool. Deep Agents builds each sub-agent as a separate graph, but they inherit the parent's model object by default.
Because the plugin makes that model object durable, every sub-agent's model call is automatically durable too — you wire
the plugin once and the whole agent tree is covered, with no per-sub-agent wiring.
Human-in-the-loop
create_deep_agent(..., interrupt_on=...) makes the agent pause before a guarded tool runs. With an in-Workflow
InMemorySaver checkpointer, LangGraph does not raise out of ainvoke — it returns the current state with an
__interrupt__ entry describing the pending approval. Because the agent loop runs in the Workflow, that pause surfaces
directly in Workflow code.
The plugin adds no shim here; the native LangGraph resume protocol is used as-is. The recommended Temporal mapping is to
expose the pending approval via a Query and resume via an
Update that feeds the human's decision back with
Command(resume={"decisions": [...]}). The InMemorySaver is replay-safe because its state lives in the Workflow's own
memory, rehydrated by deterministic replay, and the stable Workflow ID is used as the thread_id.
Continue-as-new
Long conversations bloat Workflow history until it hits Temporal's limits. run_deep_agent(agent, input, continue_as_new_after=N, state_snapshot=...) snapshots state and continues into a fresh run once history passes N
events and the agent still has pending todos.
- Carries forward: the accumulated messages and the model/tool result cache, so an LLM or tool call completed before the continue-as-new is not re-run afterward.
- Does not carry forward: anything held only in an in-memory checkpointer's own structures beyond the messages/todos snapshot.
Your @workflow.run method must accept the carried state — its signature is run(self, input, state_snapshot=None).
On a continue-as-new, run_deep_agent re-invokes the method with args=[input, snapshot], so input must be passed
straight through, not re-wrapped, or the carried conversation is corrupted.
Streaming
Constructing the plugin with DeepAgentsPlugin(streaming_topic="...") flips model dispatch from
deepagents.invoke_model to deepagents.invoke_model_streaming: the streaming Activity coalesces chunk batches and
publishes them to a WorkflowStream
topic for external subscribers, while the aggregated final message is still returned to the Workflow. The durable result
is identical to the non-streaming path.
Streaming is async-only, so the Workflow drives an explicit TemporalModel.astream(...) and hosts a WorkflowStream
so external subscribers can attach by Workflow ID.
Compose with an observability plugin
This plugin carries no tracing context of its own. For observability, compose it with an observability plugin such as
temporalio.contrib.langsmith or
temporalio.contrib.opentelemetry. Register the observability plugin before DeepAgentsPlugin so it can capture
the LLM calls that DeepAgentsPlugin runs as Activities. The Workflow itself is an ordinary Deep Agent — the tracing
comes entirely from composing the plugins on the Client.
For agents built directly as LangGraph graphs rather than a compiled Deep Agent, see the LangGraph integration.
Runtime behavior and limitations
- Auto-routing is Workflow-scoped. While a Worker built with this plugin is running, the plugin patches Deep Agents'
model-resolution seam so a bare
model="provider:name"string is auto-routed through an Activity, regardless of how you importedcreate_deep_agent. This seam is shared by the agent and every sub-agent, and it only rewrites the model when resolved inside a Workflow, so importingdeepagentson a plain client or Activity Worker is unaffected, and the patched seam is restored when the Worker stops. PassTemporalModel("provider:name")yourself if you would rather be explicit. - Built-ins stay in-Workflow. Deep Agents' pure built-in tools (
write_todos, state-backed file tools) run in-Workflow by design and do not need wrapping. Only tools and backends that do real I/O should be moved to Activities. - Durable checkpointers are not replay-safe. The default in-Workflow
InMemorySaveris rehydrated for free by deterministic replay. A durable checkpointer that does its own I/O is not replay-safe from inside a Workflow, and the plugin warns if you pass one — prefer the snapshot plus continue-as-new path above.
Samples
The Deep Agents plugin samples demonstrate all supported patterns, including tool choice, durable backends, sub-agents, human-in-the-loop, continue-as-new, streaming, and observability composition.