Skip to content

Python API

The client and the integrations are the stable Python surface. Everything else is reached through the CLI.

callbus.client.CallBusClient

health

health()

{ready, mode}; a server still building its index is no error.

catalog

catalog(server=None)

{count, catalog, tools}: each tool's id (name), api_name, description, input schema, annotations and, for OpenAPI operations, the HTTP method.

search

search(
    query,
    *,
    k=None,
    instruction=None,
    full_schemas=False,
    session=None,
)

{search_id, mode, took_ms, rule, tools}, with confidence when the server has a calibration and note when the agent should know something about the list.

rank

rank(query, tools, *, instruction=None, session=None)

Score tools the caller has (MCP records: name, description, inputSchema, optional server) for query; -> [{index, name, server?, score}], best first, index being the tool's position in tools. Sent in chunks that stay under the server's limits (RANK_CHUNK tools, RANK_BYTES of JSON).

call

call(name, arguments=None, *, search_id=None, session=None)

{name, call_id, outcome, isError, http_status, content, structuredContent?}; a tool that fails is a result with isError, not an exception.

feedback

feedback(
    name,
    outcome,
    *,
    search_id=None,
    took_ms=None,
    session=None,
)

Report a call the client ran itself (outcome: ok or tool_error), so the server's usage log, and with it callbus learn, sees it; -> {name, call_id}.

callbus.client.AsyncCallBusClient

CallBusClient's API as coroutines: each method runs the standard-library client in a worker thread (asyncio.to_thread, which carries the caller's context). Takes the same arguments, or client= an existing one. Cancelling a call drops its answer; the request was sent, so the tool may still run.

search async

search(query, **kwargs)

CallBusClient.search: k, instruction, full_schemas, session.

rank async

rank(query, tools, **kwargs)

CallBusClient.rank: instruction, session.

feedback async

feedback(name, outcome, **kwargs)

CallBusClient.feedback: search_id, took_ms, session.

call async

call(name, arguments=None, **kwargs)

CallBusClient.call: search_id, session.

callbus.client.CallBusError

Bases: RuntimeError

callbus.integrations.anthropic.Toolbox

One conversation's tools: the frozen tool list for the API, and what callbus found and ran.

respond(response) answers a response's tool calls; approve(entry, arguments) may veto a call; on_event(kind, details) sees every search, call and turn. With inline (see the module's docstring) opening(task) gives the first messages and additions() the system message to append after each answer.

opening

opening(task)

The first messages: the task, and (prefetch) the tools a search for it finds.

additions

additions()

The role: "system" message that adds the tools found since the last one (inline), to append right after the message that answered their search; None when there are none.

respond

respond(response)

The user message that answers response's tool calls; None when there are none to answer (end of turn, max_tokens, refusal, pause_turn: see run).

callbus.integrations.anthropic.run

run(
    llm,
    callbus,
    task,
    *,
    model,
    max_tokens=4096,
    max_turns=12,
    **create,
)

A reference loop: llm is an anthropic.Anthropic() (or its .beta); create goes to every messages.create. Stops when a response asks for no tool, on max_tokens, refusal and unknown stop reasons, or after max_turns requests; pause_turn is sent back as is.

callbus.integrations.openai.Toolbox

One conversation's tools: what callbus found and loaded, and the calls it ran.

respond(response) answers a response's tool searches and calls; approve(entry, arguments) may veto a call; on_event(kind, details) sees every search, call and turn; namespaces groups the found tools by server and shrink=False loads every input schema in full (see the module's docstring).

respond

respond(response)

The items that answer response's tool searches and calls, in order; [] when it asks for none or is incomplete.

callbus.integrations.openai.run

run(llm, callbus, task, *, model, max_turns=12, **create)

A reference loop: llm is an openai.OpenAI(); create goes to every responses.create. Stops when a response has nothing to answer, is incomplete, or after max_turns requests.

LangChain

CallBusToolSelector is built lazily, on first use (langchain is an optional extra), so the module carries its documentation:

callbus.integrations.langchain

callbus as the tool selection of a LangChain 1.x agent (langchain.agents.create_agent).

CallBusToolSelector is an AgentMiddleware: before each model call it narrows the tools the model is shown to the ones callbus finds for the conversation's last user message. Two ways:

  • The agent's own tools, any LangChain tools: they go to callbus serve's /v1/rank (any tool list works, not only callbus's catalogue), and the model sees what callbus's adaptive K keeps. It is LangChain's LLMToolSelectorMiddleware without the extra model call.

    from langchain.agents import create_agent from callbus.integrations.langchain import CallBusToolSelector

    agent = create_agent(model, tools=my_tools, middleware=[CallBusToolSelector()])

  • callbus's catalogue: with toolbox=, the agent has Toolbox.registry() among its tools and the catalogue's tools are picked by a callbus search (/v1/search, the server's index, with the toolbox's k and instruction). callbus serve runs their calls and links each to that search in its usage log, which callbus learn reads. The agent's other tools are shown as they are.

    from callbus.client import CallBusClient from callbus.integrations.langgraph import Toolbox

    box = Toolbox(CallBusClient()) agent = create_agent(model, tools=[box.registry().values(), my_tools], middleware=[CallBusToolSelector(toolbox=box)])

Either way the model keeps the tools the conversation already called, any tool tool_choice names, always_include and provider tools (dicts, such as web search); shown tools keep the agent's order. A model call goes on with every tool when there are at most min_tools to choose from, when a tool is deferred to the provider's own tool search (extras["defer_loading"]), when there is no user text, and when callbus fails or does not answer within timeout_s: the selection then carries on in the background and is kept, so a later call is fast. With a toolbox a failure shows the catalogue's tools of the session's last selection (and the fixed ones), not the whole catalogue, which no model takes in one request. An agent makes several model calls per user message; a selection is kept for ttl_s seconds, and a call that comes while the same selection is still being made waits for that one, so they ask callbus once. Selections run in daemon threads, four at a time: one still running never holds up the interpreter's exit.

Needs langchain 1.x (callbus[langchain]), imported when CallBusToolSelector is first used. Selector is the same work without LangChain's class.

Selector

The middleware's work: select(request) -> request (aselect), the request a model call should get. on_select(details) sees every selection made or reused and every failure (outcome selected or skipped), not the calls with nothing to choose from (few tools, deferred ones, no user text).

LangGraph

callbus.integrations.langgraph.Toolbox

The catalogue (taken once) as LangChain tools, and the searches and calls made with it.

retrieve_tools(query) -> list[str] and aretrieve_tools search; k and instruction go to every search (default: the server's); hits outside servers are dropped. approve(entry, arguments) may veto a call; on_event(kind, details) sees every search and call.

registry

registry()

{api_name: tool} for every catalogue tool (langchain_core.tools.BaseTools).

current_session

current_session()

The session a search or call made now carries: the LangGraph thread's, else the toolbox's own.

run

run(name, arguments)

Run a catalogue tool (by api name) through callbus; -> its output as text. A failed, refused or declined call raises ToolException.

LlamaIndex

callbus.integrations.llamaindex.CallBusToolRetriever

Bases: ObjectRetriever

An agent's tools from callbus searches (see the module docstring).

k and instruction go to every search (default: the server's). approve(hit, arguments) may veto a call; on_event(kind, details) sees every search and call.

run

run(tool, arguments)

Run tool through callbus; -> its ToolOutput.

LiteLLM

callbus.integrations.litellm.ToolFilter

The filter without LiteLLM: await ToolFilter(...)(data, call_type) -> a new request dict with fewer tools, or None to send the request as it came.

warm_up

warm_up()

Rank each warm list once, so callbus has embedded its tools before a request needs them; -> how many lists it took. A failure is logged, never raised: the filter fails open.