---
title: How to Use Provider Passthrough Tools
description: Use Anthropic and OpenAI passthrough tools on DigitalOcean Inference, including tool search, computer use, bash, local shell, web fetch, code editing, …
product: Inference
url: https://docs.digitalocean.com/products/inference/how-to/use-server-side-tools/use-provider-agentic-tools/
last_updated: "2026-08-24"
---

> **For AI agents:** The documentation index is at [https://docs.digitalocean.com/llms.txt](https://docs.digitalocean.com/llms.txt). Markdown versions of pages use the same URL with `index.html.md` in place of the HTML page (for example, append `index.html.md` to the directory path instead of opening the HTML document).

# How to Use Provider Passthrough Tools

Inference provides a single control plane for managing inference workflows. It includes a Model Catalog where you can view available foundation models, including both DigitalOcean-hosted and third-party commercial models, compare model capabilities and pricing, use routing to match inference requests to the best-fit model, and run inference using serverless or dedicated deployments.

Provider passthrough tools on DigitalOcean Inference let Anthropic and OpenAI models search and load tools on demand, control a desktop, run shell commands, fetch web content, edit files, and call your application-defined functions. These tools forward to the model provider, which runs each tool according to its own schema and agent loop. Provide the Anthropic-schema tools on the [Messages API](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/index.html.md) and the OpenAI-schema tools on the [Responses API](https://docs.digitalocean.com/products/inference/how-to/use-responses-api/index.html.md).

## Tool Search

Tool search enables searching and loading of tools on demand in agentic workflows, reducing token usage and cost by avoiding loading all tool definitions up front. Use tool search on the [Messages API](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/index.html.md) for Anthropic models and the [Responses API](https://docs.digitalocean.com/products/inference/how-to/use-responses-api/index.html.md) for OpenAI models.

### Tool Search with Anthropic Models

Include a tool search tool by either using regex or BM25 as the `type` in your `tools` array:

- **Regex** (`tool_search_tool_regex_20251119`): Allows Claude to construct regex patterns to search for tools using Python `re.search()` syntax.
- **BM25** (`tool_search_tool_bm25_20251119`): Allows Claude to use natural language queries to search for tools.

Then, set `defer_loading: true` on tools that should not load immediately. The model calls the tool search tool when it needs those tools. Both tool search variants search tool names, descriptions, argument names, and argument descriptions. Note the following about tool search:

- The tool search tool itself must not have `"defer_loading": true`.
- Tools without `defer_loading` load into context immediately while tools with `"defer_loading": true` load only when Claude discovers them through search.
- For best performance, keep your 3-5 most frequently used tools non-deferred.

The following example sends a Messages API request with regex tool search enabled.

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.messages.create(
    model="anthropic-claude-opus-4.8",
    max_tokens=2048,
    messages=[
        {"role": "user", "content": "What is the weather in zip code 94107?"},
    ],
    tools=[
        {
            "type": "tool_search_tool_regex_20251119",
            "name": "tool_search_tool_regex",
        },
        {
            "name": "get_weather_by_zip",
            "description": "Return current weather conditions for a US zip code.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "zip_code": {"type": "string"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["zip_code"],
            },
            "defer_loading": True,
        },
        {
            "name": "search_files",
            "description": "Search through files in the workspace",
            "input_schema": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "file_types": {"type": "array", "items": {"type": "string"}},
                },
                "required": ["query"],
            },
            "defer_loading": True,
        },
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.messages.create({
    model: "anthropic-claude-opus-4.8",
    max_tokens: 2048,
    messages: [
        { role: "user", content: "What is the weather in zip code 94107?" },
    ],
    tools: [
        {
            type: "tool_search_tool_regex_20251119",
            name: "tool_search_tool_regex",
        },
        {
            name: "get_weather_by_zip",
            description: "Return current weather conditions for a US zip code.",
            input_schema: {
                type: "object",
                properties: {
                    zip_code: { type: "string" },
                    unit: { type: "string", enum: ["celsius", "fahrenheit"] },
                },
                required: ["zip_code"],
            },
            defer_loading: true,
        },
        {
            name: "search_files",
            description: "Search through files in the workspace",
            input_schema: {
                type: "object",
                properties: {
                    query: { type: "string" },
                    file_types: { type: "array", items: { type: "string" } },
                },
                required: ["query"],
            },
            defer_loading: true,
        },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/messages \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic-claude-opus-4.8",
    "max_tokens": 2048,
    "messages": [
      {
        "role": "user",
        "content": "What is the weather in zip code 94107?"
      }
    ],
    "tools": [
      {
        "type": "tool_search_tool_regex_20251119",
        "name": "tool_search_tool_regex"
      },
      {
        "name": "get_weather_by_zip",
        "description": "Return current weather conditions for a US zip code.",
        "input_schema": {
          "type": "object",
          "properties": {
            "zip_code": {"type": "string"},
            "unit": {
              "type": "string",
              "enum": ["celsius", "fahrenheit"]
            }
          },
          "required": ["zip_code"]
        },
        "defer_loading": true
      },
      {
        "name": "search_files",
        "description": "Search through files in the workspace",
        "input_schema": {
          "type": "object",
          "properties": {
            "query": {"type": "string"},
            "file_types": {
              "type": "array",
              "items": {"type": "string"}
            }
          },
          "required": ["query"]
        },
        "defer_loading": true
      }
    ]
  }'
```

The response includes additional block types before any client tool call:

- **`server_tool_use`:** Indicates that Claude is calling the tool search tool.
- **`tool_search_tool_result`:** Contains search results with a nested `tool_search_tool_search_result` object.
- **`tool_use`:** Claude calling a discovered tool.
- **`tool_references`:** Points to discovered tools.

The response looks similar to the following:

## Show the example response

```json
{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "I'll search for tools to help with the weather information."
    },
    {
      "type": "server_tool_use",
      "id": "srvtoolu_01ABC123",
      "name": "tool_search_tool_regex",
      "input": {
        "query": "weather"
      }
    },
    {
      "type": "tool_search_tool_result",
      "tool_use_id": "srvtoolu_01ABC123",
      "content": {
        "type": "tool_search_tool_search_result",
        "tool_references": [{ "type": "tool_reference", "tool_name": "get_weather_by_zip" }]
      }
    },
    {
      "type": "text",
      "text": "I found a weather tool. Let me get the weather for zip code 94107."
    },
    {
      "type": "tool_use",
      "id": "toolu_01XYZ789",
      "name": "get_weather_by_zip",
      "input": { "zip_code": "94107", "unit": "fahrenheit" }
    }
  ],
  "stop_reason": "tool_use"
}
```

Tool search tool usage is tracked in the usage object in the response:

## Show the example response

```json
{
  "usage": {
    "input_tokens": 1024,
    "output_tokens": 256,
    "server_tool_use": {
      "tool_search_requests": 2
    }
  }
}
```

For more information on how to use tool search with MCP integration and best practices, see the [Anthropic tool search documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool).

### Tool Search with OpenAI Models

Only GPT-5.4 and later models support tool search. To enable tool search, add a tool object with `"type": "tool_search"` to the `tools` array. Then, mark tools to defer with `"defer_loading": true`. The following example sends a Responses API request with hosted tool search enabled.

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.responses.create(
    model="openai-gpt-5.5",
    input="Compare the current weather in zip code 94107 and 10001.",
    tools=[
        {
            "type": "namespace",
            "name": "weather",
            "description": "Weather lookup tools for US zip codes.",
            "tools": [
                {
                    "type": "function",
                    "name": "get_weather_by_zip",
                    "description": "Return current weather conditions for a US zip code.",
                    "defer_loading": True,
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "zip_code": {"type": "string"},
                        },
                        "required": ["zip_code"],
                        "additionalProperties": False,
                    },
                }
            ],
        },
        {"type": "tool_search"},
    ],
    parallel_tool_calls=False,
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.responses.create({
    model: "openai-gpt-5.5",
    input: "Compare the current weather in zip code 94107 and 10001.",
    tools: [
        {
            type: "namespace",
            name: "weather",
            description: "Weather lookup tools for US zip codes.",
            tools: [
                {
                    type: "function",
                    name: "get_weather_by_zip",
                    description: "Return current weather conditions for a US zip code.",
                    defer_loading: true,
                    parameters: {
                        type: "object",
                        properties: {
                            zip_code: { type: "string" },
                        },
                        required: ["zip_code"],
                        additionalProperties: false,
                    },
                },
            ],
        },
        { type: "tool_search" },
    ],
    parallel_tool_calls: false,
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/responses \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai-gpt-5.5",
    "input": "Compare the current weather in zip code 94107 and 10001.",
    "tools": [
      {
        "type": "namespace",
        "name": "weather",
        "description": "Weather lookup tools for US zip codes.",
        "tools": [
          {
            "type": "function",
            "name": "get_weather_by_zip",
            "description": "Return current weather conditions for a US zip code.",
            "defer_loading": true,
            "parameters": {
              "type": "object",
              "properties": {
                "zip_code": { "type": "string" }
              },
              "required": ["zip_code"],
              "additionalProperties": false
            }
          }
        ]
      },
      {
        "type": "tool_search"
      }
    ],
    "parallel_tool_calls": false
  }'
```

For MCP servers, set `defer_loading: true` on the MCP server tool definition (or on individual tools within the server). For maximum token savings, group deferred functions into namespaces or MCP servers with clear, high-level descriptions so that the model can effectively search and load only the relevant functions. For other best practices, see the [OpenAI tool search documentation](https://developers.openai.com/api/docs/guides/tools-tool-search).

If the model needs a deferred tool, the response includes two additional output items before the eventual function call: `tool_search_call` which records the hosted search step, and `tool_search_output`, which contains the loaded subset that becomes callable. The response looks similar to the following:

## Show the example response

```js
[
  {
    "type": "tool_search_call",
    "execution": "server",
    "call_id": null,
    "status": "completed",
    "arguments": {
      "paths": ["weather"]
    }
  },
  {
    "type": "tool_search_output",
    "execution": "server",
    "call_id": null,
    "status": "completed",
    "tools": [
  ....
  },
  {
    "type": "function_call",
    "name": "get_weather_by_zip",
    "namespace": "weather",
    "call_id": "call_abc123",
    "arguments": "{\"zip_code\":\"94107\"}"
  }
]
```

## Computer Use

With the computer use tool, you can interact with computer environments for autonomous desktop interaction such as screenshots, mouse and keyboard control, and desktop automation. You can use the computer use tool in combination with other tools such as bash and text editor for more comprehensive automation workflows.

### Computer Use with Anthropic Models

Add the computer use tool to the model using the [Messages API](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/index.html.md). The tool requires the `anthropic-beta: computer-use-2025-11-24` header. Set `display_width_px` and `display_height_px` to match the resolution of the environment the model controls. The following example sends a Messages API request with the computer use tool enabled:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.messages.create(
    model="anthropic-claude-opus-4.8",
    max_tokens=1024,
    tools=[
        {
            "type": "computer_20251124",
            "name": "computer",
            "display_width_px": 1024,
            "display_height_px": 768,
            "display_number": 1,
        }
    ],
    messages=[
        {"role": "user", "content": "Save a picture of a cat to my desktop."}
    ],
    headers={"anthropic-beta": "computer-use-2025-11-24"},
)

print(resp)
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/messages \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-beta: computer-use-2025-11-24" \
  -d '{
    "model": "anthropic-claude-opus-4.8",
    "max_tokens": 1024,
    "tools": [
      {
        "type": "computer_20251124",
        "name": "computer",
        "display_width_px": 1024,
        "display_height_px": 768,
        "display_number": 1
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "Save a picture of a cat to my desktop."
      }
    ]
  }'
```

Computer use runs as an agent loop. The model does not control the environment directly. Instead, it returns a `tool_use` block with an action such as `screenshot`, `left_click`, or `type`, and your application runs that action in a sandboxed environment (such as a virtual machine or container). Your application then returns the result, often a new screenshot, in a `tool_result` block and continues the conversation. The model evaluates the result and either requests another action or returns a final response when the task is complete.

Because the model can control a real environment, run computer use only in an isolated, low-privilege sandbox, keep sensitive data and credentials out of reach, and require human confirmation for consequential actions. For the full set of actions, response handling, and security guidance, see the [Anthropic computer use tool documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool).

### Computer Use with OpenAI Models

Provide the computer use tool to the model using the [Responses API](https://docs.digitalocean.com/products/inference/how-to/use-responses-api/index.html.md). Add a tool object with `"type": "computer"` to the `tools` array and then describe the task in plain language. The following example sends a Responses API request with the computer use tool enabled:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.responses.create(
    model="openai-gpt-5.5",
    input="Check whether the Filters panel is open. If it is not open, click Show filters. Then type penguin in the search box. Use the computer tool for UI interaction.",
    tools=[
        {"type": "computer"}
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.responses.create({
    model: "openai-gpt-5.5",
    input: "Check whether the Filters panel is open. If it is not open, click Show filters. Then type penguin in the search box. Use the computer tool for UI interaction.",
    tools: [
        { type: "computer" },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/responses \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai-gpt-5.5",
    "input": "Check whether the Filters panel is open. If it is not open, click Show filters. Then type penguin in the search box. Use the computer tool for UI interaction.",
    "tools": [
      {
        "type": "computer"
      }
    ]
  }'
```

Computer use runs as a built-in loop that your harness drives. Inspect the returned `computer_call` and run every action in its `actions[]` array, in order. The first turn often requests a `screenshot` before the model commits to UI actions. Then, capture the updated screen and send it back as a `computer_call_output` item that references the `call_id`. Repeat until the model stops returning `computer_call` items and returns a final response.

Because the model can control a real environment, run computer use only in an isolated, low-privilege sandbox (such as a dedicated browser or container), keep an allowlist of permitted domains and actions, and require human confirmation for purchases, authenticated flows, and other consequential actions. For the full action set, screenshot handling, and security guidance, see the [OpenAI computer use tool documentation](https://developers.openai.com/api/docs/guides/tools-computer-use).

## Bash and Local Shell

Use the local shell tool to execute shell commands in a persistent session, allowing system operations, script execution, access to environment variables, and command-line automation. Use the bash tool with the [Messages API](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/index.html.md) for Anthropic models and the local shell tool with the [Responses API](https://docs.digitalocean.com/products/inference/how-to/use-responses-api/index.html.md) for OpenAI models:

### Bash Tool with Anthropic Models

Provide the bash tool to the model using the Messages API. Use the `bash_20250124` tool type with the name `bash`. The following example sends a Messages API request with the bash tool enabled:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.messages.create(
    model="anthropic-claude-opus-4.8",
    max_tokens=1024,
    tools=[
        {"type": "bash_20250124", "name": "bash"}
    ],
    messages=[
        {"role": "user", "content": "List all Python files in the current directory."}
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.messages.create({
    model: "anthropic-claude-opus-4.8",
    max_tokens: 1024,
    tools: [
        { type: "bash_20250124", name: "bash" },
    ],
    messages: [
        { role: "user", content: "List all Python files in the current directory." },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/messages \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic-claude-opus-4.8",
    "max_tokens": 1024,
    "tools": [
      {
        "type": "bash_20250124",
        "name": "bash"
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "List all Python files in the current directory."
      }
    ]
  }'
```

The bash tool runs as an agent loop against a persistent session that your application maintains. The model returns a `tool_use` block with a `command` to run (for example, `ls -la *.py`), your application runs that command in a bash shell and returns the combined stdout and stderr in a `tool_result` block, and the conversation continues. Session state, such as the working directory and environment variables, persists between commands, so the model can chain steps like installing a package, writing a script, and running it. To reset the session, the model can send `{"restart": true}` instead of a command.

The bash tool provides direct system access, so run it only in an isolated environment (such as a container or virtual machine), restrict commands with an allowlist, set resource limits, run with minimal permissions, and log every command. For the full parameter set, response handling, and security guidance, see the [Anthropic bash tool documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/bash-tool).

### Local Shell Tool with OpenAI Models

Provide the shell tool to the model using the Responses API. Add a tool object with `"type": "shell"` to the `tools` array and set `environment` to `local` to run commands in your own runtime. The following example sends a Responses API request with the shell tool enabled for local execution:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.responses.create(
    model="openai-gpt-5.5",
    instructions="The local bash shell environment is on Linux.",
    input="List all Python files in the current directory.",
    tools=[
        {
            "type": "shell",
            "environment": {
                "type": "local",
            },
        }
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.responses.create({
    model: "openai-gpt-5.5",
    instructions: "The local bash shell environment is on Linux.",
    input: "List all Python files in the current directory.",
    tools: [
        {
            type: "shell",
            environment: {
                type: "local",
            },
        },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/responses \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai-gpt-5.5",
    "instructions": "The local bash shell environment is on Linux.",
    "input": "List all Python files in the current directory.",
    "tools": [
      {
        "type": "shell",
        "environment": {
          "type": "local"
        }
      }
    ]
  }'
```

For the full parameter set and response handling, see the [OpenAI shell tool documentation](https://developers.openai.com/api/docs/guides/tools-shell).

## Web Fetch with Anthropic Models

Using an Anthropic-schema web fetch tool, the model can retrieve the full content of specific web pages and PDF documents to augment its context with live web content. The model fetches and reads the URL within a single request instead of running a multi-step agent loop.

Provide the web fetch tool to the model using the [Messages API](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/index.html.md). Use the `web_fetch_20250910` tool type with the name `web_fetch`. Optionally set `max_uses` to cap the number of fetches per request and `allowed_domains` or `blocked_domains` to restrict which sites the model can fetch. The following example sends a Messages API request with the web fetch tool enabled:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.messages.create(
    model="anthropic-claude-opus-4.8",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": "Please analyze the content at https://docs.digitalocean.com/products/inference/",
        }
    ],
    tools=[
        {
            "type": "web_fetch_20250910",
            "name": "web_fetch",
            "max_uses": 5,
        }
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.messages.create({
    model: "anthropic-claude-opus-4.8",
    max_tokens: 1024,
    messages: [
        {
            role: "user",
            content: "Please analyze the content at https://docs.digitalocean.com/products/inference/",
        },
    ],
    tools: [
        {
            type: "web_fetch_20250910",
            name: "web_fetch",
            max_uses: 5,
        },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/messages \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic-claude-opus-4.8",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "Please analyze the content at https://docs.digitalocean.com/products/inference/"
      }
    ],
    "tools": [
      {
        "type": "web_fetch_20250910",
        "name": "web_fetch",
        "max_uses": 5
      }
    ]
  }'
```

The response includes additional block types before the model’s final answer:

- **`server_tool_use`:** Indicates that the model is fetching a URL.
- **`web_fetch_tool_result`:** Contains the fetched page as a `web_fetch_result` object with a `document` block.

The response looks similar to the following:

## Show the example response

```js
{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "I'll fetch the content from the page to analyze it."
    },
    {
      "type": "server_tool_use",
      "id": "srvtoolu_01234567890abcdef",
      "name": "web_fetch",
      "input": {
        "url": "https://docs.digitalocean.com/products/inference/"
      }
    },
    {
      "type": "web_fetch_tool_result",
      "tool_use_id": "srvtoolu_01234567890abcdef",
      "content": {
        "type": "web_fetch_result",
        "url": "https://docs.digitalocean.com/products/inference/",
        "content": {
          "type": "document",
          "source": {
            "type": "text",
            "media_type": "text/plain",
            "data": "DigitalOcean Inference provides serverless and dedicated access to foundation models..."
          },
          "title": "Inference | DigitalOcean Documentation"
        },
        "retrieved_at": "2025-08-25T10:30:00Z"
      }
    },
    {
      "type": "text",
      "text": "Based on the documentation, DigitalOcean Inference is a managed AI platform that provides access to foundation models through serverless and dedicated endpoints..."
    }
  ],
  ....
  }
}
```

For PDF documents, the `document` block uses base64-encoded data in `source.data` instead of plain text. Web fetch usage is tracked in `usage.server_tool_use.web_fetch_requests`.

The model decides when to fetch based on the prompt and the URLs available in the conversation. For security, the model can only fetch URLs that already appear in the conversation, such as a URL in a user message or one returned by a previous web search or web fetch result. The model then analyzes the fetched content and returns its answer, with optional citations when you set `"citations": {"enabled": true}` on the tool.

Because the model processes external web content, enable web fetch only in trusted environments or when handling non-sensitive data, and use `max_uses`, `allowed_domains`, and `max_content_tokens` to limit exposure and token usage. For the full parameter set, response handling, and security guidance, see the [Anthropic web fetch tool documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-fetch-tool).

## Code Editing

Both Anthropic and OpenAI models can edit files in your codebase. Anthropic models use the text editor tool with the [Messages API](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/index.html.md), and OpenAI models use the apply patch tool with the [Responses API](https://docs.digitalocean.com/products/inference/how-to/use-responses-api/index.html.md):

### Code Editing with Anthropic Models

Using an Anthropic-schema text editor tool, you can directly view and modify text files, and interact with them to debug, refactor, and write tests to improve your code or other text documents.

Provide the text editor tool (named `str_replace_based_edit_tool`) to the model using the Messages API. Use the `text_editor_20250728` tool type, and optionally set `max_characters` to control truncation when the model views large files. The following example sends a Messages API request with the text editor tool enabled:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.messages.create(
    model="anthropic-claude-opus-4.8",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": "There's a syntax error in my primes.py file. Can you help me fix it?",
        }
    ],
    tools=[
        {
            "type": "text_editor_20250728",
            "name": "str_replace_based_edit_tool",
            "max_characters": 10000,
        }
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.messages.create({
    model: "anthropic-claude-opus-4.8",
    max_tokens: 1024,
    messages: [
        {
            role: "user",
            content: "There's a syntax error in my primes.py file. Can you help me fix it?",
        },
    ],
    tools: [
        {
            type: "text_editor_20250728",
            name: "str_replace_based_edit_tool",
            max_characters: 10000,
        },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/messages \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic-claude-opus-4.8",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "There'\''s a syntax error in my primes.py file. Can you help me fix it?"
      }
    ],
    "tools": [
      {
        "type": "text_editor_20250728",
        "name": "str_replace_based_edit_tool",
        "max_characters": 10000
      }
    ]
  }'
```

The model first responds with a `tool_use` block containing a `view` command to examine the file. Your application reads the file, returns its contents in a `tool_result` block, and continues the conversation. The model then issues commands such as `str_replace`, `insert`, or `create` to make edits. For the full set of commands and the request and response flow, see the [Anthropic text editor tool documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/text-editor-tool).

### Code Editing with OpenAI Models

Using the apply patch tool, you can create, update (refactor, fix bugs, test files), and delete files in your codebase using structured diffs. The model emits patch operations that your application applies and then reports back on, enabling iterative, multi-step code editing workflows.

Provide the apply patch tool to the model using the Responses API. Add a tool object with `"type": "apply_patch"` to the `tools` array and give the model context about the relevant files in your `input` (or provide tools for exploring the file system). The following example sends a Responses API request with the apply patch tool enabled:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.responses.create(
    model="openai-gpt-5.5",
    input="The file lib/fib.py defines a function fib(n). Rename the fib() function to fibonacci() and update any references.",
    tools=[
        {"type": "apply_patch"}
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.responses.create({
    model: "openai-gpt-5.5",
    input: "The file lib/fib.py defines a function fib(n). Rename the fib() function to fibonacci() and update any references.",
    tools: [
        { type: "apply_patch" },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/responses \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai-gpt-5.5",
    "input": "The file lib/fib.py defines a function fib(n). Rename the fib() function to fibonacci() and update any references.",
    "tools": [
      {
        "type": "apply_patch"
      }
    ]
  }'
```

The apply patch tool runs as an agent loop that your application maintains. The model returns one or more `apply_patch_call` output items, each describing a single file `operation` (`create_file`, `update_file`, or `delete_file`) with a `diff` and `path`. Your application applies each patch in its working directory, then sends the result back as an `apply_patch_call_output` item that references the `call_id`, with a `status` of `completed` or `failed` and an optional `output` string. Pass the results back using `previous_response_id` (or by including the items in `input`) and keep the apply patch tool enabled so the model can continue editing or explain its changes. If a patch fails, set `status` to `failed` and include a helpful `output` message so the model can recover.

The apply patch tool modifies files in your codebase, so apply patches only in an isolated working directory or version-controlled repository, review the diffs before applying them, and keep a human in the loop for consequential changes. For the full operation set and response handling, see the [OpenAI apply patch tool documentation](https://developers.openai.com/api/docs/guides/tools-apply-patch).

## Function Calling

Using function calling, models can interface with external systems and access data outside their training data. Unlike DigitalOcean-hosted server-side tools, function calling is client-side: you define your own functions, the model decides when to call them and returns the arguments, and your application runs the function and returns the result. Define functions with the [Messages API](https://docs.digitalocean.com/products/inference/how-to/use-messages-api/index.html.md) for Anthropic models and the [Responses API](https://docs.digitalocean.com/products/inference/how-to/use-responses-api/index.html.md) for OpenAI models.

### Function Calling with Anthropic Models

Define each function in the `tools` array with a `name`, `description`, and `input_schema` to describe its parameters. The following example sends a Messages API request with a single `get_weather` function defined:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.messages.create(
    model="anthropic-claude-opus-4.8",
    max_tokens=1024,
    tools=[
        {
            "name": "get_weather",
            "description": "Get the current weather for a location.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, for example San Francisco, CA",
                    }
                },
                "required": ["location"],
            },
        }
    ],
    messages=[
        {"role": "user", "content": "What is the weather in San Francisco?"}
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.messages.create({
    model: "anthropic-claude-opus-4.8",
    max_tokens: 1024,
    tools: [
        {
            name: "get_weather",
            description: "Get the current weather for a location.",
            input_schema: {
                type: "object",
                properties: {
                    location: {
                        type: "string",
                        description: "The city and state, for example San Francisco, CA",
                    },
                },
                required: ["location"],
            },
        },
    ],
    messages: [
        { role: "user", content: "What is the weather in San Francisco?" },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/messages \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic-claude-opus-4.8",
    "max_tokens": 1024,
    "tools": [
      {
        "name": "get_weather",
        "description": "Get the current weather for a location.",
        "input_schema": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "The city and state, for example San Francisco, CA"
            }
          },
          "required": ["location"]
        }
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "What is the weather in San Francisco?"
      }
    ]
  }'
```

When the model decides to call a function, it returns a `tool_use` block with the function `name` and an `input` object containing the arguments. Your application runs the function, then continues the conversation by sending a `tool_result` block that references the `tool_use_id` and contains the function output. The model uses that result to produce its final response. For the full request and response flow, see the [Anthropic tool use documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview).

### Function Calling with OpenAI Models

Define each function in the `tools` array with `"type": "function"`, `name`, `description`, and `parameters` JSON schema. The following example sends a Responses API request with a single `get_horoscope` function defined:

### Python

```python
import os
from pydo.inference import Client

client = Client(token=os.environ.get("MODEL_ACCESS_KEY"))

resp = client.responses.create(
    model="openai-gpt-5.5",
    input="What is my horoscope? I am an Aquarius.",
    tools=[
        {
            "type": "function",
            "name": "get_horoscope",
            "description": "Get today's horoscope for an astrological sign.",
            "parameters": {
                "type": "object",
                "properties": {
                    "sign": {
                        "type": "string",
                        "description": "An astrological sign like Taurus or Aquarius",
                    }
                },
                "required": ["sign"],
            },
        }
    ],
)

print(resp)
```

### JavaScript

```javascript
import { InferenceClient } from "@digitalocean/dots";

const client = new InferenceClient({
    apiKey: process.env.MODEL_ACCESS_KEY,
});

const resp = await client.responses.create({
    model: "openai-gpt-5.5",
    input: "What is my horoscope? I am an Aquarius.",
    tools: [
        {
            type: "function",
            name: "get_horoscope",
            description: "Get today's horoscope for an astrological sign.",
            parameters: {
                type: "object",
                properties: {
                    sign: {
                        type: "string",
                        description: "An astrological sign like Taurus or Aquarius",
                    },
                },
                required: ["sign"],
            },
        },
    ],
});

console.log(resp);
```

### cURL

```shell
curl -X POST https://inference.do-ai.run/v1/responses \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai-gpt-5.5",
    "input": "What is my horoscope? I am an Aquarius.",
    "tools": [
      {
        "type": "function",
        "name": "get_horoscope",
        "description": "Get today'\''s horoscope for an astrological sign.",
        "parameters": {
          "type": "object",
          "properties": {
            "sign": {
              "type": "string",
              "description": "An astrological sign like Taurus or Aquarius"
            }
          },
          "required": ["sign"]
        }
      }
    ]
  }'
```

When the model decides to call a function, it returns a `function_call` output item with the function `name`, a `call_id`, and an `arguments` JSON string. Your application runs the function, then sends the result back as a `function_call_output` item that references the `call_id` (using `previous_response_id` or by including the items in `input`). The model uses that result to produce its final response. For the full request and response flow, see the [OpenAI function calling documentation](https://developers.openai.com/api/docs/guides/function-calling).