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)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()

result, err := a.Run(ctx, "Hello", nil)
Works with Run, Stream, and RunAsync. The context deadline applies to the entire call.

Option 2 — WithTimeout (agent default)

a, _ := agent.NewAgent(
    agent.WithLLMClient(llmClient),
    agent.WithTimeout(5 * time.Minute),
)

result, err := a.Run(context.Background(), "Hello", nil)
Used when the context has no deadline. Agent-only — ignored by NewAgentWorker.

Precedence

RuleBehavior
Context deadlineAlways wins — if ctx expires in 2 min but WithTimeout is 10 min, the run ends at 2 min
Default when unsetFollows agent mode — see below

Agent modes

Set with WithAgentMode:
ModeDefault timeoutWorker check (Temporal)Best for
AgentModeInteractive (default)5 minutesWhen DisableLocalWorker is set, checks for available workers before submitting — returns a clear error if none are readyChat, REPL, web apps where a human is waiting
AgentModeAutonomous60 minutesSkipped — Temporal queues the workflow until a worker is availableBackground jobs, pipelines, long-running tasks
// Interactive (default) — 5 min timeout, worker pre-check
a, _ := agent.NewAgent(
    agent.WithLLMClient(llmClient),
    agent.WithAgentMode(agent.AgentModeInteractive),
)

// Autonomous — 60 min timeout, no worker pre-check
a, _ := agent.NewAgent(
    agent.WithLLMClient(llmClient),
    agent.WithAgentMode(agent.AgentModeAutonomous),
)
Agent mode is included in the Temporal agent fingerprint — caller and worker must agree. Worker-check and queueing behavior apply primarily to the Temporal runtime. 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.
SettingDefault
WithApprovalTimeoutAgent timeout − 30 seconds
Maximum31 days (MaxApprovalTimeout)
Must be less than the agent run timeout. Validation fails at NewAgent if approvalTimeout >= timeout.
a, _ := agent.NewAgent(
    agent.WithLLMClient(llmClient),
    agent.WithTimeout(10 * time.Minute),
    agent.WithApprovalTimeout(9 * time.Minute),
    agent.WithApprovalHandler(approvalHandler),
)

On approval timeout

MethodBehavior
RunReturns error
StreamEmits AgentEventTypeRunError
RunAsyncresultCh receives result with Error set
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 (default 5). When reached, the run finishes with finish reason max_iterations on telemetry. Separate from wall-clock timeout — a run can hit max iterations before the timeout fires.

Behavior under failure

FailureRunStreamRunAsync
Context deadline exceededReturns context.DeadlineExceededEmits AgentEventTypeRunErrorChannel receives result with Error set
Agent timeout firesReturns timeout errorEmits AgentEventTypeRunErrorChannel receives result with Error set
Approval timeoutReturns error after approval window expiresEmits AgentEventTypeRunErrorChannel receives result with Error set
Max iterations reachedReturns result with FinishReason: max_iterationsEmits RUN_FINISHED with reason setChannel receives result normally
LLM provider errorReturns the provider errorEmits AgentEventTypeRunErrorChannel receives result with Error set
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:
a, _ := agent.NewAgent(
    agent.WithTemporalConfig(cfg),
    agent.WithLLMClient(llmClient),
    agent.DisableLocalWorker(),
    agent.EnableRemoteWorkers(),
    agent.WithAgentMode(agent.AgentModeInteractive),
    agent.WithTimeout(5 * time.Minute),
    agent.WithStream(true),
)
Background pipeline:
a, _ := agent.NewAgent(
    agent.WithTemporalConfig(cfg),
    agent.WithLLMClient(llmClient),
    agent.WithAgentMode(agent.AgentModeAutonomous),
    agent.WithTimeout(45 * time.Minute),
    agent.WithToolApprovalPolicy(agent.AutoToolApprovalPolicy()),
)
Per-request override:
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
result, err := a.Run(ctx, quickPrompt, nil) // 30s cap regardless of agent timeout

Approvals

Approval handler and OnApproval flows

Worker Separation

Interactive worker pre-check with DisableLocalWorker

Temporal Runtime

Agent mode on Temporal

Configuration

WithTimeout, WithApprovalTimeout, WithAgentMode