Documentation

Client Tools

Let a managed Agent call functions implemented by its host application.

A client tool is a function contract stored on an Agent whose implementation lives in the application that calls it. Use one when the application must own the action or render a domain-specific interface, such as product cards, an approval dialog, or a checkout summary.

"Client" means the Responses API client. The function normally runs in your server or application backend, not inside Rebyte and not necessarily in a web browser.

Client tools and MCP tools

Client toolMCP tool
DefinitionStored on the AgentMCP server reference stored on the Agent
ImplementationHost applicationMCP server
ExecutionHost application receives a function_callRebyte calls the MCP server
ResultHost submits function_call_outputRebyte records the MCP result automatically

Define the tool once

Add the definition when creating or updating the Agent:

{
  "clientTools": [
    {
      "type": "function",
      "name": "present_products",
      "description": "Render product cards in the host application.",
      "parameters": {
        "type": "object",
        "properties": {
          "product_ids": {
            "type": "array",
            "items": {"type": "string"}
          }
        },
        "required": ["product_ids"],
        "additionalProperties": false
      },
      "strict": true
    }
  ]
}

The equivalent agent.toml is:

[[client_tools]]
type = "function"
name = "present_products"
description = "Render product cards in the host application."
strict = true

[client_tools.parameters]
type = "object"
required = ["product_ids"]
additionalProperties = false

[client_tools.parameters.properties.product_ids]
type = "array"
minItems = 1
maxItems = 20
items = { type = "string" }

Every field is required. name must be unique within the Agent and contain 1–64 letters, numbers, underscores, or hyphens. parameters is a JSON object; Rebyte stores the schema without choosing or hosting its implementation.

The Agent API also accepts the function object produced by the official SDK's Zod helper, provided it has a description:

import { zodResponsesFunction } from "openai/helpers/zod";
import { z } from "zod";

const presentProducts = zodResponsesFunction({
  name: "present_products",
  description: "Render product cards in the host application.",
  parameters: z.object({ product_ids: z.array(z.string()).min(1).max(20) }),
});

// Include `presentProducts` in `clientTools` when creating or updating the Agent.

Strict parameter schemas

Client tools use the OpenAI strict function-schema subset. The root must have type: "object". Every object schema, including nested objects and object branches inside anyOf, must define properties, list every property exactly once in required, and set additionalProperties: false.

Every nested schema uses exactly one structural form: type, anyOf, or a local $ref to #, a root $defs entry, or a root draft-07 definitions entry. Array schemas must define items.

To make a value optional, keep its property name in required and use exactly one value type plus null, for example type = ["string", "null"] in TOML. Non-nullable schemas use a single string for type.

The supported schema keywords are:

PurposeKeywords
Structuretype, properties, required, additionalProperties, items
Dialect, composition, and reuse$schema, anyOf, $defs, definitions, $ref
Values and descriptionsenum, const, description
StringsminLength, maxLength, pattern, format
NumbersmultipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum
ArraysminItems, maxItems

format accepts date-time, time, date, duration, email, hostname, ipv4, ipv6, or uuid.

$schema accepts the draft-07 URI emitted by the official OpenAI SDK's Zod helper. minLength, maxLength, minItems, and maxItems are supported. default, allOf, oneOf, not, conditional schemas, and other unlisted keywords are rejected instead of being silently ignored.

A schema may nest up to 10 levels and contain up to 5,000 object properties and 1,000 enum values. Property names, $defs names, string enum values, and string constants may contain at most 120,000 characters in total. An enum with more than 250 values may contain at most 15,000 characters across its string values.

Execution lifecycle

Host application                         Rebyte Agent
       │                                      │
       │  Response A: user input              │
       ├─────────────────────────────────────►│
       │  function_call(name, call_id, args)  │
       │◄─────────────────────────────────────┤
       │                                      │
       │  execute function locally            │
       │                                      │
       │  Response B: function_call_output    │
       ├─────────────────────────────────────►│
       │  continued Agent output              │
       │◄─────────────────────────────────────┤

Response A and Response B use the same Conversation. When Response A contains multiple calls, execute all of them and submit all results together. Each result identifies its pending call by call_id; in Rebyte's focused Responses subset, function_call_output.output must be a string, so serialize structured results with JSON.stringify:

const first = await rebyte.responses.create({
  model: process.env.REBYTE_AGENT_ID,
  input: "Find a tent and show me the choices.",
});

const calls = first.output.filter((item) => item.type === "function_call");
if (calls.length === 0) throw new Error("No client tool call returned");

const outputs = await Promise.all(calls.map(async (call) => ({
  type: "function_call_output",
  call_id: call.call_id,
  output: JSON.stringify(
    await executeClientTool(call.name, JSON.parse(call.arguments)),
  ),
})));

const continued = await rebyte.responses.create({
  model: process.env.REBYTE_AGENT_ID,
  conversation: first.conversation.id,
  input: outputs,
});

Use the official OpenAI SDK for both calls. It already supports the standard function_call and function_call_output objects; there is no Rebyte Responses SDK to install or modify.

Do not send the tool schemas with either Response. They belong to the Agent. Do not use previous_response_id; the Conversation associates the call and its result. A continuation containing function_call_output requires the Conversation returned by the Response that emitted the call.

Streaming

With stream: true, accumulate arguments from response.function_call_arguments.delta or use the complete JSON string from response.function_call_arguments.done. Execute only completed calls, collect every result, and wait for response.completed before submitting the result batch in the same Conversation.

The host application is responsible for validating arguments before acting, authorizing access to its own resources, handling idempotency for side effects, and returning only the data the Agent needs.