> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stewrd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Tools

> Give the agent access to your own functions. The model decides when to call them, you execute them, and the agent continues.

## Overview

Custom tools let the agent call functions you define. Instead of the agent completing everything in one shot, it can pause to request data or actions from your system, then continue once you provide the results.

This enables use cases like:

* Looking up order details from your database
* Sending emails through your email service
* Querying your internal APIs
* Creating records in your CRM

## How It Works

1. You send a request with `message` + `tools` (your function definitions)
2. The agent decides which tools to call based on the message
3. If tools are needed, the API returns `status: "requires_tool_outputs"` with the tool calls
4. You execute the functions in your system and submit the results
5. The agent continues until it has a final answer (or needs more tool calls)

<Info>
  Credits are charged once on the initial request. Tool output submissions are free.
</Info>

## Defining Tools

Each tool needs a `name`, `description`, and `parameters` (JSON Schema format):

```json theme={null}
{
  "tools": [
    {
      "name": "get_order",
      "description": "Look up an order by ID and return its details",
      "parameters": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "string",
            "description": "The order ID to look up"
          }
        },
        "required": ["order_id"]
      }
    }
  ]
}
```

### Tool Schema Rules

| Field         | Type   | Required | Constraints                              |
| :------------ | :----- | :------- | :--------------------------------------- |
| `name`        | string | Yes      | Alphanumeric + underscores, max 64 chars |
| `description` | string | Yes      | Max 1,024 chars                          |
| `parameters`  | object | Yes      | Must have `"type": "object"`             |

**Limits:**

* Maximum **20 tools** per request
* Maximum **10 tool call rounds** per execution
* **5-minute timeout** between submissions
* Maximum **100KB** per tool output

## Complete Example

### Step 1: Send a request with tools

<CodeGroup>
  ```typescript TypeScript theme={null}
  const response = await fetch('https://api.stewrd.dev/v1/agent', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${STEWRD_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      message: 'Check order #12345 and email the customer a summary',
      tools: [
        {
          name: 'get_order',
          description: 'Look up an order by ID',
          parameters: {
            type: 'object',
            properties: { order_id: { type: 'string' } },
            required: ['order_id'],
          },
        },
        {
          name: 'send_email',
          description: 'Send an email to a customer',
          parameters: {
            type: 'object',
            properties: {
              to: { type: 'string' },
              subject: { type: 'string' },
              body: { type: 'string' },
            },
            required: ['to', 'subject', 'body'],
          },
        },
      ],
    }),
  })

  const data = await response.json()
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.stewrd.dev/v1/agent \
    -H "Authorization: Bearer sk-stw_your_key" \
    -H "Content-Type: application/json" \
    -d '{
      "message": "Check order #12345 and email the customer a summary",
      "tools": [
        {
          "name": "get_order",
          "description": "Look up an order by ID",
          "parameters": {
            "type": "object",
            "properties": { "order_id": { "type": "string" } },
            "required": ["order_id"]
          }
        },
        {
          "name": "send_email",
          "description": "Send an email to a customer",
          "parameters": {
            "type": "object",
            "properties": {
              "to": { "type": "string" },
              "subject": { "type": "string" },
              "body": { "type": "string" }
            },
            "required": ["to", "subject", "body"]
          }
        }
      ]
    }'
  ```
</CodeGroup>

### Step 2: Handle `requires_tool_outputs`

The response tells you which tools the agent wants to call:

```json theme={null}
{
  "id": "req-abc-123",
  "object": "agent.response",
  "status": "requires_tool_outputs",
  "tool_calls": [
    {
      "id": "call_xyz",
      "name": "get_order",
      "arguments": { "order_id": "12345" }
    }
  ],
  "usage": { "credits_remaining": 4997, "credits_this_request": 1 },
  "_compute_instance": "e784079b"
}
```

### Step 3: Execute and submit results

Run the function in your system, then submit the output:

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Execute the tool call
  const order = await db.orders.findById('12345')

  // Submit the result
  const continuation = await fetch(
    `https://api.stewrd.dev/v1/agent/${data.id}/tool-outputs`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${STEWRD_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        tool_outputs: [
          {
            tool_call_id: 'call_xyz',
            output: JSON.stringify(order),
          },
        ],
        _compute_instance: data._compute_instance,
      }),
    }
  )

  const result = await continuation.json()
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.stewrd.dev/v1/agent/req-abc-123/tool-outputs \
    -H "Authorization: Bearer sk-stw_your_key" \
    -H "Content-Type: application/json" \
    -d '{
      "tool_outputs": [
        {
          "tool_call_id": "call_xyz",
          "output": "{\"order_id\":\"12345\",\"status\":\"shipped\",\"email\":\"jane@example.com\"}"
        }
      ],
      "_compute_instance": "e784079b"
    }'
  ```
</CodeGroup>

### Step 4: Get the final response

The agent may return another `requires_tool_outputs` (e.g., to send the email), or a `completed` response:

```json theme={null}
{
  "id": "req-abc-123",
  "object": "agent.response",
  "status": "completed",
  "message": "I've sent a summary email to jane@example.com with the shipping details for order #12345.",
  "usage": { "credits_this_request": 0, "tokens_used": 847 }
}
```

## Handling the Loop

In production, wrap the tool call flow in a loop:

```typescript theme={null}
async function runWithTools(message: string, tools: Tool[]) {
  let response = await fetch('https://api.stewrd.dev/v1/agent', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${STEWRD_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ message, tools }),
  })

  let data = await response.json()

  while (data.status === 'requires_tool_outputs') {
    // Execute each tool call
    const outputs = await Promise.all(
      data.tool_calls.map(async (call: ToolCall) => ({
        tool_call_id: call.id,
        output: JSON.stringify(await executeToolCall(call)),
      }))
    )

    // Submit results
    response = await fetch(
      `https://api.stewrd.dev/v1/agent/${data.id}/tool-outputs`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${STEWRD_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          tool_outputs: outputs,
          _compute_instance: data._compute_instance,
        }),
      }
    )

    data = await response.json()
  }

  return data.message
}
```

## Machine Affinity

The `_compute_instance` field ensures your tool output submissions are routed to the same server that holds the execution context. Always pass it back in subsequent requests.

<Warning>
  If you omit `_compute_instance`, the request may be routed to a different machine and return a `context_expired` error.
</Warning>

## Limitations

| Constraint            | Limit                              |
| :-------------------- | :--------------------------------- |
| Tools per request     | 20                                 |
| Tool call rounds      | 10                                 |
| Context TTL           | 5 minutes                          |
| Output size per tool  | 100KB                              |
| Streaming             | Not supported with tools           |
| Platform capabilities | Chat only (no browser, code, etc.) |

## Error Codes

| Code                    | HTTP | Description                           |
| :---------------------- | :--- | :------------------------------------ |
| `invalid_tools`         | 400  | Tool definitions are malformed        |
| `invalid_tool_outputs`  | 400  | Tool outputs array is malformed       |
| `context_expired`       | 404  | Execution context expired (5-min TTL) |
| `tool_output_too_large` | 400  | Single output exceeds 100KB           |
