module

Anthropic::ToolRunner

Bounded tool-runner loop for agentic workflows.

Manages the tool_use -> tool_result conversation loop with configurable bounds. The runner automatically handles the cycle of:

  1. Sending a request to the API
  2. Checking if the response contains tool_use blocks
  3. Executing each tool via the provided block
  4. Appending assistant response + tool results to the conversation
  5. Repeating until no tool_use or max_iterations is reached

Usage

client = Anthropic::Client.new

request = Anthropic::Messages::Request.new(
  model: Anthropic::Model.sonnet,
  messages: [Anthropic::Message.user("What's the weather in SF?")],
  max_tokens: 1024,
  tools: [weather_tool]
)

result = Anthropic::ToolRunner.run(client, request) do |tool_block|
  # Execute the tool and return JSON result
  if tool_block.name == "get_weather"
    JSON.parse(%({"temperature": 72, "condition": "sunny"}))
  else
    JSON.parse(%({"error": "Unknown tool"}))
  end
end

puts result.text # Final response after tool execution

Bounds

  • max_iterations: Maximum number of tool rounds (default: 10)
  • Returns early if stop_reason != "tool_use"

Class methods

run(client : Client, initial_request : Messages::Request, max_iterations : Int32 = 10, request_options : RequestOptions | Nil = nil, & : ResponseToolUseBlock -> String | JSON::Any) : Messages::Response

Run a bounded tool loop.

Parameters:

  • client: The Anthropic client to use
  • initial_request: The initial messages request
  • max_iterations: Maximum tool execution rounds (default: 10)
  • request_options: Per-request options forwarded to each API call
  • block: Executor that receives each tool_use block and returns a JSON result

Returns:

  • The final Messages::Response (when stop_reason != "tool_use" or max_iterations reached)

Yields:

  • ResponseToolUseBlock for each tool that needs execution

Example:

result = ToolRunner.run(client, request, max_iterations: 5) do |tool|
  execute_tool(tool.name, tool.input)
end
Source