Client tools

Let the agent call a function in your own app over the websocket, and return the result.
View as Markdown

A client tool doesn’t call an API — the platform hands the call to your app over the websocket, your app runs the function, and returns the result. Use it when the “tool” is really a function in your frontend: update a cart, navigate a screen, or look up data that must not leave your side.

Client tools only run on websocket sessions (webcall, widget). On phone calls the definition is dropped — a phone agent can’t reach your app. Use an API tool for anything that must work over telephony.

Configuration

A client tool has:

  • Name / Description — the model reads the description to decide when to call it.
  • Parameters — typed arguments the model fills from the conversation (name, type, description, required), same shape as an API tool’s LLM parameters.
  • Wait for response — if on, the agent pauses until your app returns a result, and a timeout applies (1–60s, default 1s). If off, it’s fire-and-forget: your app acts on the event and the agent doesn’t wait.
  • Filler phrases — spoken while the tool runs so the pause isn’t silent.

The protocol

Your app is the other end of the websocket and is responsible for executing the function. Two messages:

Agent → your app — the agent wants the tool run:

1{
2 "type": "function_call",
3 "call_id": "<unique id>",
4 "name": "<tool name>",
5 "arguments": "<JSON-encoded string>"
6}

Your app → agent — you return the result:

1{
2 "type": "function_call.result",
3 "call_id": "<same id>",
4 "output": "<JSON-encoded string>"
5}

Rules:

  • Echo the call_id back on the result so the agent can match it.
  • Reply within the tool’s timeout. If you don’t, the agent stops waiting and recovers verbally.
  • arguments and output are JSON strings — parse the arguments, and JSON-encode your result into output.
  • If Wait for response is off, don’t reply — just act on the event.

Minimal handler

1socket.onmessage = (event) => {
2 const msg = JSON.parse(event.data);
3 if (msg.type !== "function_call") return;
4
5 const args = JSON.parse(msg.arguments);
6 const output = handlers[msg.name](args); // your function, returns a value
7
8 socket.send(JSON.stringify({
9 type: "function_call.result",
10 call_id: msg.call_id,
11 output: JSON.stringify(output),
12 }));
13};

Open the websocket with a short-lived token (mint one, then connect to the agent websocket) and keep this handler running for the length of the session.