Client Tools

Tools executed by your code via a handler function.


Basic Usage

1from inferencesh import tool, string23greet = (4    tool("greet")5    .describe("Greet a user by name")6    .param("name", string("User's name"))7    .handler(lambda args: f"Hello, {args['name']}!")8    .build()9)

Builder Methods

MethodDescription
tool(name)Create a client tool
.describe(text)Set description for LLM
.display(name)Human-readable name
.param(name, schema)Add a parameter
.handler(fn)Function to execute
.requireApproval()Require user approval
.build()Build the tool

Sync Handlers

1def get_weather(args):2    city = args["city"]3    # Call weather API...4    return f"Weather in {city}: 72°F, Sunny"56weather = (7    tool("get_weather")8    .describe("Get current weather for a city")9    .param("city", string("City name"))10    .handler(get_weather)11    .build()12)

Async Handlers

1import aiohttp23async def fetch_data(args):4    async with aiohttp.ClientSession() as session:5        async with session.get(args["url"]) as response:6            return await response.text()78fetcher = (9    tool("fetch")10    .describe("Fetch data from URL")11    .param("url", string("URL to fetch"))12    .handler(fetch_data)13    .build()14)

Multiple Parameters

1from inferencesh import tool, string, number, boolean23search = (4    tool("search")5    .describe("Search the database")6    .param("query", string("Search query"))7    .param("limit", number("Max results"))8    .param("include_archived", boolean("Include archived items"))9    .handler(lambda args: do_search(**args))10    .build()11)

Complex Parameters

1from inferencesh import tool, obj, string, array23create_order = (4    tool("create_order")5    .describe("Create a new order")6    .param("product", string("Product name"))7    .param("shipping", obj({8        "address": string("Street address"),9        "city": string("City"),10        "zip": string("ZIP code")11    }, "Shipping details"))12    .param("tags", array(string(), "Order tags"))13    .handler(process_order)14    .build()15)

Automatic handler dispatch

When you attach a .handler() to a client tool, the JavaScript SDK runs it automatically as soon as the invocation reaches in_progress. You do not need to poll for awaiting_input on the chat — client tools keep the chat in busy while they run.

The SDK also accepts awaiting_input for backwards compatibility. Interactive widgets use awaiting_input on the invocation and typically move the chat to awaiting_input as well.

If a handler throws, the SDK submits a JSON error result. If no handler is registered for a tool name, it submits { "status": "not_available" }.

Tool invocation status · Polling transport


Tools Without Handler

If you omit the handler, the tool becomes "pending" — your code must handle it manually:

1calculator = (2    tool("calculator")3    .describe("Calculate math")4    .param("expression", string("Math expression"))5    .build()  # No handler!6)78# Later, check for pending tool calls:9response = agent.send_message("What's 42 * 17?")10if response.pending_tool_calls:11    for tc in response.pending_tool_calls:12        result = eval(tc.arguments["expression"])13        agent.submit_tool_result(tc.id, str(result))

we use cookies

we use cookies to ensure you get the best experience on our website. for more information on how we use cookies, please see our cookie policy.

by clicking "accept", you agree to our use of cookies.
learn more.