The Anthropic Python SDK includes a tool_runner that handles the tool-calling loop automatically. Define Nimble tools with the @beta_tool decorator and the SDK manages execution, message history, and retries.
Python
import osimport jsonimport anthropicfrom anthropic import beta_toolfrom nimble_python import Nimbleclient = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])nimble_client = Nimble(api_key=os.environ["NIMBLE_API_KEY"])@beta_tooldef nimble_search(query: str) -> str: """Search the web using Nimble and return relevant results. Args: query: The search query to execute. """ result = nimble_client.search(query=query) return json.dumps(result, default=str)@beta_tooldef nimble_extract(url: str) -> str: """Extract clean content from a URL using Nimble. Args: url: The URL to extract content from. """ result = nimble_client.extract(url=url) return json.dumps(result, default=str)runner = client.beta.messages.tool_runner( model="claude-sonnet-4-6", max_tokens=4096, tools=[nimble_search, nimble_extract], messages=[{"role": "user", "content": "What are the latest trends in AI agents?"}],)for message in runner: for block in message.content: if hasattr(block, "text"): print(block.text)
The @beta_tool decorator auto-generates the JSON schema from type hints and doc strings — no manual schema definition needed.
Pass the tool definitions and user message to Claude. If Claude decides to use a tool, it returns a tool_use content block with the tool name and input.
2
Execute the tool
Parse the tool_use block and call the corresponding Nimble SDK method. Return the result as a tool_result message.
3
Get the final answer
Claude processes the tool result and responds with a text answer. If it needs more data, it may call another tool — the loop continues until stop_reason is end_turn.