Relay tools — declaration-only
C# · package Toolnexus · SPEC §10
Declare a tool the host executes, not the library: the call rides out on the suspension.
What to use instead
Section titled “What to use instead”Relay exists for exactly one posture: a proxy that owns no execution at all — every tool call, even a plain function call, is surfaced to the host and run there, with toolnexus doing nothing but wire-format translation. Two ordinary C# mechanisms get you close to that outcome today, depending on which half of “proxy” you actually need:
- The caller executes tools itself, and owns the conversation. This is the standard OpenAI
function-calling posture relay is a stand-in for. Use
LlmClient.TranslateAsync(SPEC §11): declare aToolkitor rawtoolsarray, get back the model’sToolCallscompletely undeclared-and-unexecuted, and run them however you like on your side. No suspension involved at all. - toolnexus owns the conversation, but one specific call needs the host to answer it. Return
ToolResult.Pendingfrom that tool and resolve it viaLlmClient.WaitFor— the same primitive relay is built on (SPEC §10 opening: “relay is a use of the suspension primitive, exactly as auth is”), just scoped to one tool instead of every call in a turn.
Neither reproduces relay’s specific “all N calls in one turn ride a single suspension, in OpenAI
tool_calls shape” contract — if you need that exact shape, it’s Go-only for now.
See also
Section titled “See also”ToolResult.Pending— Return a Pending from a tool to park the run until someone answers.ToolResult.AuthRequired— The auth-shaped suspension: hand back a URL, resume once the user has granted access.LlmClient.WaitFor— The single hook where the host resolves a suspension — in-process prompt or durable queue, same contract.ToolResult.PendingOf— Detect that a RunResult is parked rather than finished, and get the Request that parked it.LlmClient.TranslateAsync— The closest shipped C# mechanism: pure translation, no toolnexus-owned execution at all.