---
name: temporal-durable-agents
description: "Crash-proof LLM agents with Temporal — durable workflows, activities, retries, and resumable state for the OpenAI Agents SDK. Production durable execution for long-running agents: wrap the agent loop in a Temporal Workflow and tool/LLM calls in Activities, using the OpenAI Agents SDK x Temporal integration. Covers deterministic workflow code, RetryPolicy with backoff and non-retryable errors, workflow.wait_condition and signals for human-in-the-loop, Continue-As-New for unbounded loops, heartbeats and timeouts on activities, and event-history replay for crash recovery across multi-day runs."
license: MIT
---

# Temporal Durable Agents

Run OpenAI Agents SDK agents as Temporal Workflows so a process crash, deploy, or network blip never loses progress. This skill gives Claude the patterns to wrap the agent loop in a durable Workflow, push every LLM and tool call into Activities with retries, and resume an in-flight run from exactly where it stopped. It's for engineers shipping long-running or high-stakes agents — research runs, multi-step automations, anything that can't afford to start over.

## When to use it

- An agent run spans minutes to hours and a worker restart would otherwise discard all state.
- A tool calls a flaky external API and you want automatic, backed-off retries instead of failing the whole run.
- You need an agent to pause for human approval or an external event, then continue days later.
- You want observability and replay (Temporal Web UI) over opaque in-memory agent loops.

## How it works

The integration ships in the `openai-agents` SDK under `agents.extensions.temporal`. You construct a `TemporalOpenAIRunner` (or use the Temporal plugin) so `Runner.run(...)` executes inside a Workflow, with model invocations and `function_tool` calls automatically dispatched as Activities. Your Workflow code stays deterministic — no direct I/O, clocks, or randomness; all side effects live in Activities.

Key building blocks:

- `@workflow.defn` / `@workflow.run` — the durable agent loop. State here is checkpointed to Temporal's event history.
- `RetryPolicy(initial_interval, backoff_coefficient, maximum_attempts, non_retryable_error_types=[...])` — set per Activity; mark validation or auth failures non-retryable.
- `workflow.wait_condition(lambda: ...)` plus Signals — pause for approvals or external input without burning compute.
- A `Worker` registers the workflow and activities; a `Client` starts runs.

## Usage

```python
from temporalio import workflow
from agents import Agent, Runner

@workflow.defn
class ResearchAgent:
    @workflow.run
    async def run(self, prompt: str) -> str:
        agent = Agent(name="Researcher", tools=[search])
        result = await Runner.run(agent, prompt)  # LLM + tools run as Activities
        return result.final_output
```

```python
# worker.py
worker = Worker(client, task_queue="agents",
                workflows=[ResearchAgent], activities=[search])
```

## Tips & gotchas

- Workflow code must be deterministic: use `workflow.now()` and `workflow.uuid4()`, never `datetime.now()` or `random`.
- Set Activity `start_to_close_timeout` generously for slow LLM calls — without a timeout, Temporal rejects the Activity.
- Use `non_retryable_error_types` for 4xx/auth errors so you don't retry a request that can never succeed.
- Keep large payloads out of workflow arguments; Temporal's event history has size limits — store blobs externally and pass references.

## FAQ

**Does my agent code change much?** Mostly no — the runner intercepts model/tool calls. The main shift is moving I/O into Activities and keeping the loop deterministic.

**What happens on a worker crash mid-run?** Temporal replays the event history on a new worker and continues from the last recorded step; completed Activities are not re-executed.

**Can a run wait for human input?** Yes — block on `workflow.wait_condition` and resume via a Signal when approval arrives.
