Skip to main content
The problem: An agent run that calls slow tools, waits for human approval, or hits an LLM provider delay can hang indefinitely. For interactive apps, that means a frozen UI. For background pipelines, it means a stuck job that never retries or terminates. The solution: Bound every run with a deadline, choose an agent mode that matches your use case (interactive vs autonomous), and set explicit approval timeouts. When a limit fires the SDK fails the run cleanly with a typed error — no silent hangs.

Run timeouts

Two ways to limit how long a run waits:

Option 1 — Context deadline (per call)

Works with Run and Stream. A deadline on the Run / Stream context bounds (and cancels) the agent run. Cancelling Get’s context only unblocks the waiter; cancelling Events’ context only stops that subscriber (Temporal) — use Cancel() on the handle if you need to stop the run without cancelling the Stream ctx.

Option 2 — WithTimeout (agent default)

Used when the context has no deadline. Agent-only — ignored by NewAgentWorker.

Precedence

What each context does

How context affects reconnect

  • Keep Run / Stream on a long-lived ctx (context.Background(), process-lifetime, or context.WithoutCancel(r.Context())) so the Temporal workflow can keep running after HTTP disconnect or API restart.
  • Bound run length with WithTimeout, not the request ctx.
  • Use a separate Get / Events ctx to detach the subscriber; call handle.Cancel only when you intend to stop the run.
  • Cancelling Run / Stream ctx stops the workflow — reconnect cannot resume that run.
See Durable Execution. Common case — pass the same ctx to both Run and Get:
When the ctx fires, driveRun cancels the workflow and Get returns context.DeadlineExceeded. If the run finishes first, Get returns the result. Either way the behaviour is correct and predictable. Advanced — separate wait ctx (reconnect / partial wait): use a different, shorter ctx on Get only when you want to stop waiting and reconnect later while leaving the run alive.

Timeouts after reconnect (Temporal)

GetAgentRun / GetAgentStream do not take over the original Run / Stream context.
  • Cancelling the reconnect ctx does not stop the run.
  • If the agent has WithTimeout, that limit applies again from the moment you reconnect — it is a fresh timeout, not “time left” from the original start. A run that executed for 4 minutes before a crash gets a full fresh timeout window after reconnect. If you need a hard ceiling across the full run lifetime, call Cancel() on the handle after reconnect instead of relying on WithTimeout.
  • To stop the run after reconnect, call Cancel() on the handle.

Agent modes

Set with WithAgentMode:
Agent mode is included in the Temporal agent fingerprint — caller and worker must agree. Interactive worker check: in AgentModeInteractive with DisableLocalWorker, the agent checks for available workers before submitting the workflow. If no worker is ready within the check window, the call returns a clear error immediately — so a user waiting at a chat prompt gets an error rather than a frozen spinner. In AgentModeAutonomous, this check is skipped; Temporal queues the workflow and waits for a worker naturally, which is correct for background jobs. Worker-check and queueing behavior apply to the Temporal runtime only. In-process agents use the same default timeouts but do not perform worker pre-checks.

Approval timeout

WithApprovalTimeout limits how long the user has to approve or reject each tool call. Agent-only. Must be less than the agent run timeout. Validation fails at NewAgent if approvalTimeout >= timeout.

On approval timeout

If you use a long context deadline but omit WithTimeout, approval still expires at ~4.5 minutes (interactive default 5 min − 30s). Set WithTimeout or WithApprovalTimeout explicitly for longer approval windows.
See Approvals.

Max iterations

WithMaxIterations caps LLM rounds per run (default 5). Each round is one LLM call — the model generates either a final answer or tool calls, tools execute, and then the next round begins with those results. Separate from wall-clock timeout — a run can hit max_iterations before any timeout fires. When the limit is reached the run returns normally with FinishReason: max_iterations on AgentRunResult.Telemetry — it is not an error. Use ErrMaxIterationsReached if you need to detect it programmatically. When to increase from the default of 5:
If finish_reason: max_iterations appears in telemetry but the task wasn’t complete, increase WithMaxIterations. If you see it frequently on simple tasks, your system prompt or tools may not be guiding the model to terminate — review your prompt before just raising the limit.

Behavior under failure

On the Temporal runtime, process crashes and worker restarts do not appear as failures — the workflow resumes from the last recorded step. Only deadline expiry, max iterations, and provider errors surface as run failures. See Temporal runtime.

Practical combinations

Chat UI with Temporal split processes:
Background pipeline:
Per-request override:

Execution config

WithTimeout sets a ceiling on the entire run. For finer control — giving the LLM call a different deadline from tool execution, or tuning retry budgets per operation — use With*ExecutionConfig:
See Execution config for the full defaults table and usage guide.

Execution config

Timeout and retry budget per operation

Approvals

Approval handler and AgentStream.Approve flows

Distributed Execution

Interactive worker pre-check with DisableLocalWorker