Tool Round-Trips

Client-side tool execution for safe, transparent function calling.

Overview

All tools in Sixerr are client tools. When the agent wants to call a tool, the call is routed back to the client. The client executes the tool locally and sends the result back in a follow-up request. This is the core safety mechanism — nothing executes on the plugin owner's machine.

The plugin agent runs with tools deny [*], preventing any local tool execution. Even if a tool definition were somehow executed locally, the clientTools conversion provides defense-in-depth.

Defining Tools

Include tool definitions in the tools array of your request:

{
  "model": "claude-sonnet-4-20250514",
  "input": "What's the weather in San Francisco?",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather for a location",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name"
            }
          }
        }
      }
    }
  ]
}

You can control when tools are used with tool_choice:

ValueBehavior
"auto"Agent decides whether to call a tool (default)
"none"Agent will not call any tools
"required"Agent must call at least one tool
{"type":"function","function":{"name":"get_weather"}}Agent must call the specified tool

Tool Call Flow

Tool execution is a multi-turn conversation. Here is the complete flow:

1 Client sends request with tools

Send a POST /v1/responses request with tool definitions in the tools array.

2 Agent decides to call a tool

The response comes back with status: "completed" and an output item of type function_call:

{
  "id": "resp_1",
  "status": "completed",
  "output": [
    {
      "type": "function_call",
      "id": "fc_1",
      "call_id": "call_abc123",
      "name": "get_weather",
      "arguments": "{\"location\":\"San Francisco\"}"
    }
  ],
  "usage": { "input_tokens": 25, "output_tokens": 15, "total_tokens": 40 }
}
3 Client executes the tool locally

Parse the arguments JSON string, execute your function, and produce a result.

4 Client sends a new request with the full conversation

Send a new POST /v1/responses request with the entire conversation history, including the tool call and its output:

{
  "model": "claude-sonnet-4-20250514",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": "What's the weather in San Francisco?"
    },
    {
      "type": "function_call",
      "call_id": "call_abc123",
      "name": "get_weather",
      "arguments": "{\"location\":\"San Francisco\"}"
    },
    {
      "type": "function_call_output",
      "call_id": "call_abc123",
      "output": "{\"temp\":72,\"condition\":\"sunny\",\"humidity\":45}"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather for a location",
        "parameters": {
          "type": "object",
          "properties": {
            "location": { "type": "string" }
          }
        }
      }
    }
  ]
}
5 Agent produces the final response

The agent processes the tool result and generates a text response:

{
  "id": "resp_2",
  "status": "completed",
  "output": [
    {
      "type": "message",
      "id": "msg_1",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "The weather in San Francisco is currently sunny, 72 degrees with 45% humidity."
        }
      ]
    }
  ],
  "usage": { "input_tokens": 80, "output_tokens": 20, "total_tokens": 100 }
}

Key Points

  • Stateless conversation: The client must send the full conversation history with each request. The server does not store any state between requests.
  • Multiple tool calls: A single response may contain multiple function_call output items. Check all output items and execute each tool before sending the follow-up request.
  • call_id matching: The call_id field connects tool calls to their outputs. It must match exactly between the function_call and function_call_output items.
  • Streaming tool calls: In streaming mode, watch for response.function_call_arguments.delta events to receive argument chunks, and response.function_call_arguments.done for the complete call. See the Streaming page for details.
  • Each turn is a separate payment: Every POST /v1/responses request requires its own x402 payment. A multi-turn tool conversation results in multiple payments.

Tool Security

Sixerr implements defense-in-depth for tool safety:

  1. Client-side execution only: All tool calls are returned to the client. The agent never executes tools directly.
  2. tools deny [*]: The plugin agent's configuration explicitly denies all local tool execution.
  3. clientTools conversion: Tool definitions are converted to clientTools format, ensuring they are treated as client-executed even if the deny list is somehow bypassed.

The client is responsible for validating tool arguments before execution. Always sanitize inputs from the agent, especially for tools that interact with file systems, databases, or external services.