Relay tools — declaration-only
Python · package toolnexus · SPEC §10
Declare a tool the host executes, not the library: the call rides out on the suspension. A
relay tool carries a schema but no host-side behavior — the model emits a call, the call
surfaces to the host as a kind:"tool_call" suspension carrying data.calls, the host
executes it, and the host’s output feeds back as that call’s result. This is what lets a port
act as a pure translator/proxy while still supporting standard function calling, where the
client owns execution.
What to use instead
Section titled “What to use instead”If you’re building a proxy in Python and want the caller to own tool execution rather than
toolnexus, reach for translate (SPEC §11) instead:
declare your toolkit to the provider, get back exactly one turn’s tool calls in OpenAI shape
(TranslateResult.tool_calls), and execute them yourself — no suspension, no loop, no state
kept between calls. SPEC’s own guidance (ADR-0011) is explicit about this: translation is the
right mechanism for a pass-through posture; relay is for proxy-managed memory, which is a
narrower Go-only use case today.
If you specifically need the suspend/resume mechanics relay rides on — parking a run and
resuming it with an out-of-band answer — that primitive itself is fully available in Python
via pending / WaitFor:
write your own tool that returns pending(kind="tool_call", data={"calls": [...]}) and a
wait_for that executes the calls and returns an Answer — you get the same shape relay
would give you, just without the built-in constructor and collision guard Go ships.