Anthropic::SessionRunner
Runs local tools for a managed-agents session until it ends.
A synchronous port of the TypeScript SDK's SessionToolRunner: it
streams session events, executes matching local tools for
agent.tool_use / agent.custom_tool_use events, sends the results
back, and returns when the session terminates or goes idle.
- Reconnect: stream disconnects (and clean EOFs) reconnect with
jittered exponential backoff (500ms start, 10s cap, reset on every
received event). Permanent 4xx failures (any 4xx except 408/409/429)
abort the run instead of reconnecting.
max_reconnectsbounds the loop (nilreconnects forever, like TypeScript). - Reconcile: after each (re)connect the runner re-reads recent
history so tool calls emitted while disconnected still dispatch
(already-answered calls and already-seen tool uses are skipped). A
failed history read is non-fatal — the live stream carries on. A
terminal event in history ends the run immediately, and a trailing
end_turnidle re-arms the idle countdown. - Confirmation gating: calls the server gated (
evaluated_permission == "ask", or an unrecognized permission) are held until a matchinguser.tool_confirmationverdict arrives. Only an explicitallowruns the tool; anything else (including server-sidedeny, which overrides any recorded verdict) resolves the call without executing or posting, exactly like TypeScript. - Idle stop: after a
session.status_idleevent with anend_turnstop reason, the run ends oncemax_idleelapses with no further activity (any other event disarms the countdown; held confirmations defer it). Defaults to 60 seconds like TypeScript;nildisables it. Note the countdown is only evaluated when events arrive or the stream errors, so detection latency is bounded by event cadence and the client's read timeout — and the event that reveals an expired countdown is swallowed (never routed toon_event).
Tool calls naming an unregistered tool are skipped without posting a result: the name belongs to another client servicing the session, and claiming it would corrupt the conversation.
Divergences from TypeScript: the runner is synchronous (no async
iterator of outcomes — use on_call for per-call observability, and
on_event for live-stream events, which does not refire for
reconciled history), sends rely on the client's retry policy rather
than a dedicated send-retry loop, and a failed send aborts the run
instead of reconnecting (reconnecting would re-execute the tool).
Skipped unregistered calls are marked answered locally (TypeScript
leaves them pending for their owner; here that would re-surface them
on every reconnect), and tools have no execution timeout (TypeScript
aborts tools after 120s) — a hung tool blocks run.
runner = Anthropic::SessionRunner.new(
client: client,
session_id: "sess_123",
tools: [my_tool],
on_call: ->(call : Anthropic::SessionRunner::ToolCall) {
puts "#{call.name}: executed=#{call.executed?}"
nil
}
)
terminal = runner.run
Constants
Default idle stop after an end_turn idle.
History window re-read after each (re)connect.
Reconnect backoff: 500ms start, doubling to a 10s cap (jittered).
Session event types that end a run.
Constructors
Instance methods
Stream session events and execute local tools until the session
reaches a terminal event. Returns the terminal event, or nil
when the run stops another way (max_events / idle / reconnect
limit interplay aside, the reconnect limit raises).