How to Use Server-Side Tools

Last verified 23 Jul 2026

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.

Server-side tools are capabilities you attach to an inference request that the Inference platform runs for you during the model turn. When the model decides to use a tool, the platform executes it and folds the result back into the conversation. Server-side tools differ from client-side tools, where the model returns which tool to call and with which arguments, and your app runs the function and sends the result back in a follow-up request.

We support server-side integrations that extend the model’s capabilities during inference. Instead of managing tool orchestration yourself, you add tool definitions in your API request and the platform handles discovery, execution, and response integration automatically. You can use the following server-side tools with serverless inference, dedicated inference, and inference routers:

Supported Tool Use For
Web Search (Public Preview) Search the web for real-time information.
We use a third-party web search service (Exa.ai) for all models.
Web Fetch (Public Preview) Fetch URLs and PDF content from the web.
We use a third-party web fetch service (Exa.ai) for non-Anthropic models. For Anthropic models, requests pass through to Anthropic’s web fetch service.
Model Synthesis (Public Preview) Multi-model tool that runs up to eight analysis models in parallel on the same task. A judge compares panel results, then the outer model writes one final answer.
Panel models can use server-side web search and fetch within configured limits. API only.
Knowledge Base Retrieval Query your private data sources during inference using retrieval-augmented generation (RAG).
MCP Enable the model to access remote MCP servers and orchestrate calls across them.
Tool Search (For Anthropic and OpenAI models only) Search the tools catalog to use during inference.
Computer Use (For Anthropic and OpenAI models only) UI action harness for interacting with the local system.
Bash/Local Shell (For Anthropic and OpenAI models only) Run commands in the local shell.
Web Fetch (For Anthropic models only) Fetch URL/PDF content from the web.
Text Editor (For Anthropic models only) Edit or view text files in the local workspace.
Apply Patch (For OpenAI models only) Apply a structured code patch.
Function Calling (For Anthropic and OpenAI models only) App-defined calls.

Web Search, Web Fetch for non-Anthropic models, Model Synthesis, Knowledge Base Retrieval, and MCP are DigitalOcean-hosted server-side tools. Passthrough tools to the provider include Tool Search, Computer Use, Bash, Local Shell, Web Fetch, and Text Editor.

For pricing information, see Tools Usage Pricing.

Get Started

Server-side tools work with both the Chat Completions API and the Responses API, and with the Messages API for Anthropic models. To use server-side tools, add the tool definitions to the tools array in your API request. Set tool_choice to auto to let the model decide when to query a tool, or required to always query it before responding.

To use tools with an inference router and dedicated inference deployments, set the model field to the name of your router or dedicated inference and model slug, respectively.

To use tools with dedicated inference and inference routers, update the model field, as described in Use Dedicated Inference and Use Inference Router.

The following example sends a Responses API request with knowledge base retrieval and web search tools enabled for serverless inference:

import os
from pydo.inference import Client

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

resp = client.responses.create(
    model="deepseek-v4-pro",
    input="What is actions infrastructure? Answer using the knowledge base and search the web for real-time information.",
    tools=[
        {
            "type": "knowledge_base_retrieval",
            "knowledge_base_id": "09d65da1-5225-11f1-b074-4e013e2xxxx",
        },
        {
            "type": "web_search",
            "max_uses": 3,
            "max_results": 5,
        },
    ],
    stream=False,
    max_output_tokens=1024,
)

print(resp)
import { InferenceClient } from "@digitalocean/dots";

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

const resp = await client.responses.create({
    model: "deepseek-v4-pro",
    input: "What is actions infrastructure? Answer using the knowledge base and search the web for real-time information.",
    tools: [
        {
            type: "knowledge_base_retrieval",
            knowledge_base_id: "09d65da1-5225-11f1-b074-4e013e2xxxx",
        },
        {
            type: "web_search",
            max_uses: 3,
            max_results: 5,
        },
    ],
    stream: false,
    max_output_tokens: 1024,
});

console.log(resp);
curl -X POST https://inference.do-ai.run/v1/responses \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-pro",
    "input": "What is actions infrastructure? Answer using the knowledge base and search the web for real-time information.",
    "tools": [
      {
        "type": "knowledge_base_retrieval",
        "knowledge_base_id": "09d65da1-5225-11f1-b074-4e013e2xxxx"
      },
      {
        "type": "web_search",
        "max_uses": 3,
        "max_results": 5
      }
    ],
    "stream": false,
    "max_output_tokens": 1024
  }'

Web search is a built-in tool that gives the model access to real-time web content during inference. When you add web search in your API request, the model decides when a web search is needed, and the results are incorporated into the model’s response.

We use a third-party web search service (Exa.ai) for all models.

To enable web search, include a tool object with type set to web_search in the tools array of your request. When the model determines that a prompt benefits from web search, it searches for relevant information and incorporates the results into its response.

The following examples send Responses API requests with web search enabled:

import os
from pydo.inference import Client

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

resp = client.responses.create(
    model="openai-gpt-4o",
    input="What are the latest pricing changes for DigitalOcean Droplets?",
    tools=[
        {
            "type": "web_search",
            "max_uses": 3,
            "max_results": 5,
        }
    ],
    max_output_tokens=1024,
    stream=False,
)

print(resp)
import { InferenceClient } from "@digitalocean/dots";

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

const resp = await client.responses.create({
    model: "openai-gpt-4o",
    input: "What are the latest pricing changes for DigitalOcean Droplets?",
    tools: [
        {
            type: "web_search",
            max_uses: 3,
            max_results: 5,
        },
    ],
    max_output_tokens: 1024,
    stream: false,
});

console.log(resp);
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-4o",
    "input": "What are the latest pricing changes for DigitalOcean Droplets?",
    "tools": [
      {
        "type": "web_search",
        "max_uses": 3,
        "max_results": 5
      }
    ],
    "max_output_tokens": 1024,
    "stream": false
  }'

Alternatively, specify model: <model_name>:web to enable model access to web search and web fetch. This is particularly useful in coding agents where you can only change the model name.

You can optionally limit the number of searches the model performs per request from 1 to 5 with max_uses and the number of results each search returns from 1 to 10 with max_results (defaults to 5). When the request reaches the limit, the model produces a final response using the results collected so far. For the full set of web search parameters, see the Serverless Inference API reference.

The response looks similar to the following:

{
  ...
  "output": [
    {
      "action": {
        "queries": [
          "DigitalOcean AI platform features"
        ],
        "query": "DigitalOcean AI platform features",
        "type": "search"
      },
      "id": "ws_call_t7eyYNbAWQOcEln1Ns2TxuOv",
      "status": "completed",
      "type": "web_search_call"
    },
    {
      "content": [
        {
          "annotations": [
            {
              "end_index": 1501,
              "start_index": 1439,
              "title": "DigitalOcean AI Platform Features | DigitalOcean Documentation",
              "type": "url_citation",
              "url": "https://docs.digitalocean.com/products/inference/details/features"
            },
            {
              "end_index": 1800,
              "start_index": 1729,
              "title": "DigitalOcean Inference Details | DigitalOcean Documentation",
              "type": "url_citation",
              "url": "https://docs.digitalocean.com/products/inference/details"
            },
            {
              "end_index": 2085,
              "start_index": 2028,
              "title": "Agent Platform | Build AI Agents with DigitalOcean",
              "type": "url_citation",
              "url": "https://www.digitalocean.com/products/inference/platform"
            }
          ],
          "logprobs": [],
          "text": "The DigitalOcean AI Platform offers a variety of features:\n\n1. **AI Agent Development**: Build fully-managed AI ...",
          "type": "output_text"
        }
      ],
...
  }
}

Use Web Fetch public

Web fetch is a built-in tool that retrieves the full content of specific web pages and PDF documents during inference. When you add web fetch to your API request, the model fetches URLs referenced in the conversation and incorporates the content into its response.

We use a third-party web fetch service (Exa.ai) for non-Anthropic models. For Anthropic models, requests pass through to Anthropic’s web fetch service.

To enable web fetch, include a tool object with type set to web_fetch in the tools array of your request. The following example sends a Responses API request with web fetch enabled:

import os
from pydo.inference import Client

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

resp = client.responses.create(
    model="openai-gpt-4o",
    input="Summarize the content at https://docs.digitalocean.com/products/inference/",
    tools=[
        {
            "type": "web_fetch",
            "max_uses": 3,
        }
    ],
    max_output_tokens=1024,
    stream=False,
)

print(resp)
import { InferenceClient } from "@digitalocean/dots";

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

const resp = await client.responses.create({
    model: "openai-gpt-4o",
    input: "Summarize the content at https://docs.digitalocean.com/products/inference/",
    tools: [
        {
            type: "web_fetch",
            max_uses: 3,
        },
    ],
    max_output_tokens: 1024,
    stream: false,
});

console.log(resp);
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-4o",
    "input": "Summarize the content at https://docs.digitalocean.com/products/inference/",
    "tools": [
      {
        "type": "web_fetch",
        "max_uses": 3
      }
    ],
    "max_output_tokens": 1024,
    "stream": false
  }'

You can optionally limit the number of fetches the model performs per request from 1 to 5 with max_uses. When the request reaches the limit, the model produces a final response using the content collected so far.

Alternatively, specify model: <model_name>:web to give the model access to web fetch and web search. This is particularly useful for coding agents where you can only change the model name.

Use the Model Synthesis Tool public

The model synthesis tool (API only) is a multi-model tool that runs multiple models on the same task and returns one synthesized answer. You can choose up to eight analysis models that work independently in parallel, plus a top-level model that produces the final completion returned to your application. Each panel model can answer from its training knowledge and, when useful, call server-side web search and web fetch within limits you configure.

The model synthesis tool runs three server-side steps:

  1. Analyze: Panel models receive the same task and answer in parallel.
  2. Judge: A judge model compares panel results, evidence, gaps, and conflicts.
  3. Synthesize: The top-level request model writes the final user-facing answer.

The top-level model in your API request is the outer model that returns the final completion. By default, it also acts as the judge. Set model on the model synthesis tool object to designate a different judge.

The model synthesis tool differs from Inference Router, which routes a request to a single best-fit model. The model synthesis tool intentionally asks several models to address the same problem, then judges and synthesizes their work. Use the model synthesis tool when multiple perspectives justify additional time and cost. Use a single model or a router when you need low latency, deterministic workflows, or routine extraction and classification.

The model synthesis tool works with the Chat Completions API, the Responses API, and the Messages API for Anthropic models. You can use the model synthesis tool with serverless inference, dedicated inference, and inference routers by setting the top-level model field accordingly. Add a tool object with type set to model_synthesis in the tools array. Existing pydo and @digitalocean/dots clients pass the model synthesis tool object through without SDK changes.

The application receives a normal completion from the top-level model. You do not need a separate multi-agent response format or client-side orchestration code.

When to Use the Model Synthesis Tool

Use the model synthesis tool for consequential comparisons, ambiguous research, technical or strategic decisions, complex troubleshooting, architecture and vendor evaluations, policy analysis, and incident retrospectives. Tasks where missed considerations are costly benefit from independent panel attempts and disciplined synthesis.

The model synthesis tool is not intended for every request. Text rewriting, data extraction, label classification, and interactions with strict latency or cost limits are usually better served by a single model.

Configure the Model Synthesis Tool

You can configure the model synthesis tool with a DigitalOcean preset, or set the synthesizer, panel, judge, and reasoning settings yourself. Use model slugs from the available models page for analysis_models, the model synthesis tool model field (judge), and the top-level request model.

Any model available for DigitalOcean Inference can act as a panel member or judge. Commercial models from OpenAI and Anthropic follow the same third-party model access restrictions as other inference features. When you configure the panel directly, tune it for the workload: a high-quality panel for critical analysis, a lower-cost panel for routine research, or a diverse mix to reduce shared reasoning gaps. More panel models increase cost and may increase latency. Start with a small, task-relevant panel and add models only when evaluation shows measurable value.

Use a Preset

Use DigitalOcean presets for common quality and cost tradeoffs without selecting panel models yourself:

Preset Description
budget The lowest-cost configuration, using a smaller model panel and lighter reasoning settings.
balanced A mid-size panel with moderate reasoning depth, balancing quality and cost.
quality The largest model panel and deepest reasoning configuration, at higher cost and latency.

DigitalOcean Inference resolves each preset to a validated synthesizer, model panel, and reasoning configuration. As models, pricing, and performance improve, the underlying configuration can be updated without requiring changes to your integration.

When you set preset, omit analysis_models. Specifying both returns HTTP 400. You can still set reasoning_effort, max_tokens, and max_tool_calls on the tool object to override the preset defaults for those fields.

The following Chat Completions example uses the balanced preset:

curl -X POST https://inference.do-ai.run/v1/chat/completions \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.2",
    "messages": [
      {
        "role": "user",
        "content": "Your research question here"
      }
    ],
    "tools": [
      {
        "type": "model_synthesis",
        "preset": "balanced"
      }
    ]
  }'

Configure Directly

When you configure the model synthesis tool directly, the top-level model is the synthesizer that returns the final completion. The analysis_models list on the tool object is the panel. Set model on the tool object to designate a judge that differs from the synthesizer; when omitted, the judge defaults to the top-level request model.

Set reasoning_effort in two places when you need separate control: the top-level value applies to the synthesizer, and the value on the tool object applies to panel models and the judge.

The following Chat Completions example sets the synthesizer, panel, judge, and reasoning effort directly:

curl -X POST https://inference.do-ai.run/v1/chat/completions \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.2",
    "messages": [
      {
        "role": "user",
        "content": "Your research question here"
      }
    ],
    "reasoning_effort": "high",
    "tools": [
      {
        "type": "model_synthesis",
        "model": "glm-5.2",
        "analysis_models": [
          "glm-5.2",
          "kimi-k2.6"
        ],
        "reasoning_effort": "high"
      }
    ]
  }'
Field Required Description
type Yes Set to model_synthesis.
preset No One of budget, balanced, or quality. Resolves a validated synthesizer, model panel, and reasoning configuration. Mutually exclusive with analysis_models. Specifying both returns HTTP 400.
analysis_models Conditional Slugs for one to eight unique panel models. Each model receives the same task in parallel. Required when you omit preset. Do not include this field when preset is set.
model No Slug for the judge model. Defaults to the top-level request model.
max_tool_calls No Maximum web search and web fetch steps per participant. Defaults to 8 when omitted. Allowed range is 0 to 15. Set to 0 to disable web search and web fetch on all model synthesis tool sub-calls and on any web tools the outer model might call after the model synthesis tool completes. Applies independently to each panel model, the judge, and the outer synthesis model. Within each participant’s turn, that budget is shared across web_search and web_fetch, not doubled per tool. The total web tool budget in one request can reach max_tool_calls multiplied by the number of panel models plus one judge for inner calls, plus up to another max_tool_calls on the outer synthesis step when max_tool_calls is greater than 0. For example, three panel models, one judge, and max_tool_calls: 5 allow up to 25 inner web tool calls and up to 5 more during synthesis.
max_tokens No Maximum output tokens for each inner model synthesis tool stage (panel, judge, and synthesis) on all endpoints, including reasoning tokens where the provider reports them. For research-style prompts, use 10000 to 16000; 16000 is a practical default for comprehensive answers. Values below 4000 risk truncating a stage.
allowed_domains No Restrict web fetch and web search to these domains for panel and judge calls.
blocked_domains No Block web fetch and web search for these domains on panel and judge calls.
reasoning_effort No Reasoning effort forwarded to panel models and the judge. Unsupported values are dropped for models that do not accept them. See accepted values below.

Set reasoning_effort on the model synthesis tool object for all APIs. Chat Completions accepts none, minimal, low, medium, high, and xhigh. Responses accepts none, low, medium, high, and xhigh. Messages uses the same field on the tool object. The value is forwarded to each panel and judge sub-call. On Chat Completions, you can also set top-level reasoning_effort for the synthesizer. If a target model’s catalog metadata does not support the effort you set, the value is dropped silently. Anthropic maps minimal to low and xhigh to max. Accepted values are ultimately per model from catalog metadata, not a fixed list per provider.

Send a Model Synthesis Tool Request

The following examples send model synthesis tool requests on the Chat Completions, Responses, and Messages APIs. In each case, the top-level model synthesizes the final answer after the panel models and judge complete their work.

Chat Completions API

import os
from pydo.inference import Client

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

resp = client.chat.completions.create(
    model="anthropic-claude-opus-4.8",
    messages=[
        {
            "role": "user",
            "content": (
                "Compare Kubernetes and Nomad for a small platform team running "
                "20 internal services. Give a concise recommendation with tradeoffs."
            ),
        },
    ],
    tools=[
        {
            "type": "model_synthesis",
            "analysis_models": [
                "openai-gpt-5.5",
                "deepseek-v4-pro",
            ],
            "max_tool_calls": 8,
            "max_tokens": 16000,
        }
    ],
    tool_choice="required",
    max_tokens=16000,
    stream=False,
)

print(resp.choices[0].message.content)
import { InferenceClient } from "@digitalocean/dots";

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

const completion = await client.chat.completions.create({
    model: "anthropic-claude-opus-4.8",
    messages: [
        {
            role: "user",
            content:
                "Compare Kubernetes and Nomad for a small platform team running " +
                "20 internal services. Give a concise recommendation with tradeoffs.",
        },
    ],
    tools: [
        {
            type: "model_synthesis",
            analysis_models: ["openai-gpt-5.5", "deepseek-v4-pro"],
            max_tool_calls: 8,
            max_tokens: 16000,
        },
    ],
    tool_choice: "required",
    max_tokens: 16000,
    stream: false,
});

console.log(completion.choices[0].message.content);
curl -X POST https://inference.do-ai.run/v1/chat/completions \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic-claude-opus-4.8",
    "messages": [
      {
        "role": "user",
        "content": "Compare Kubernetes and Nomad for a small platform team running 20 internal services. Give a concise recommendation with tradeoffs."
      }
    ],
    "tools": [
      {
        "type": "model_synthesis",
        "analysis_models": [
          "openai-gpt-5.5",
          "deepseek-v4-pro"
        ],
        "max_tool_calls": 8,
        "max_tokens": 16000
      }
    ],
    "tool_choice": "required",
    "max_tokens": 16000,
    "stream": false
  }'

Responses API

The following example sends a Responses API request with the model synthesis tool enabled. Set input instead of messages and use max_output_tokens at the top level. The model synthesis tool object always uses max_tokens on all endpoints.

import os
from pydo.inference import Client

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

resp = client.responses.create(
    model="openai-gpt-5.2",
    input=(
        "What are the tradeoffs between RAG and fine-tuning "
        "for domain-specific QA?"
    ),
    max_output_tokens=4096,
    tools=[
        {
            "type": "model_synthesis",
            "model": "openai-gpt-5.2",
            "analysis_models": [
                "anthropic-claude-opus-4.6",
                "google-gemini-3.1-pro",
            ],
            "max_tool_calls": 5,
            "max_tokens": 2048,
            "reasoning_effort": "high",
        }
    ],
    tool_choice={"type": "function", "name": "model_synthesis"},
    stream=False,
)

print(resp)
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.2",
    input:
        "What are the tradeoffs between RAG and fine-tuning " +
        "for domain-specific QA?",
    max_output_tokens: 4096,
    tools: [
        {
            type: "model_synthesis",
            model: "openai-gpt-5.2",
            analysis_models: [
                "anthropic-claude-opus-4.6",
                "google-gemini-3.1-pro",
            ],
            max_tool_calls: 5,
            max_tokens: 2048,
            reasoning_effort: "high",
        },
    ],
    tool_choice: { type: "function", name: "model_synthesis" },
    stream: false,
});

console.log(resp);
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.2",
    "input": "What are the tradeoffs between RAG and fine-tuning for domain-specific QA?",
    "max_output_tokens": 4096,
    "tools": [
      {
        "type": "model_synthesis",
        "model": "openai-gpt-5.2",
        "analysis_models": [
          "anthropic-claude-opus-4.6",
          "google-gemini-3.1-pro"
        ],
        "max_tool_calls": 5,
        "max_tokens": 2048,
        "reasoning_effort": "high"
      }
    ],
    "tool_choice": { "type": "function", "name": "model_synthesis" },
    "stream": false
  }'

Messages API

The following example sends a Messages API request with the model synthesis tool enabled. Set max_tokens at the top level. The model synthesis tool object always uses max_tokens on all endpoints.

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.6",
    max_tokens=4096,
    messages=[
        {
            "role": "user",
            "content": (
                "What are the tradeoffs between RAG and fine-tuning "
                "for domain-specific QA?"
            ),
        },
    ],
    tools=[
        {
            "type": "model_synthesis",
            "model": "anthropic-claude-opus-4.6",
            "analysis_models": [
                "openai-gpt-5.2",
                "google-gemini-3.1-pro",
            ],
            "max_tool_calls": 5,
            "max_tokens": 2048,
            "reasoning_effort": "high",
        }
    ],
    tool_choice={"type": "tool", "name": "model_synthesis"},
)

print(resp)
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.6",
    max_tokens: 4096,
    messages: [
        {
            role: "user",
            content:
                "What are the tradeoffs between RAG and fine-tuning " +
                "for domain-specific QA?",
        },
    ],
    tools: [
        {
            type: "model_synthesis",
            model: "anthropic-claude-opus-4.6",
            analysis_models: ["openai-gpt-5.2", "google-gemini-3.1-pro"],
            max_tool_calls: 5,
            max_tokens: 2048,
            reasoning_effort: "high",
        },
    ],
    tool_choice: { type: "tool", name: "model_synthesis" },
});

console.log(resp);
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.6",
    "max_tokens": 4096,
    "messages": [
      {
        "role": "user",
        "content": "What are the tradeoffs between RAG and fine-tuning for domain-specific QA?"
      }
    ],
    "tools": [
      {
        "type": "model_synthesis",
        "model": "anthropic-claude-opus-4.6",
        "analysis_models": [
          "openai-gpt-5.2",
          "google-gemini-3.1-pro"
        ],
        "max_tool_calls": 5,
        "max_tokens": 2048,
        "reasoning_effort": "high"
      }
    ],
    "tool_choice": { "type": "tool", "name": "model_synthesis" }
  }'

Set tool_choice to required on the Chat Completions API to run the model synthesis tool on every request. On the Responses API, use {"type": "function", "name": "model_synthesis"}. On the Messages API, use {"type": "tool", "name": "model_synthesis"} or any to require the model synthesis tool. Set tool_choice to auto on any endpoint to let the top-level model invoke the model synthesis tool only when the prompt benefits from multiple perspectives. Simple prompts such as greetings usually complete without invoking the model synthesis tool.

Streaming

Panel model calls are always non-streaming. When you set stream to true at the top level, only the outer model’s final synthesis streams back to your application. stream_options.include_usage behaves as it does for other inference requests.

Latency and Timeouts

The model synthesis tool is a long-running call. Plan for long client read timeouts in your application.

Research-style model synthesis tool requests typically take 3 to 6 minutes end-to-end while panel models run in parallel, the judge compares results, and the outer model synthesizes the final answer. Web-heavy prompts, more or larger panel models, or higher reasoning_effort can increase latency to as much as 8 to 10 minutes.

The main latency settings are the number and size of panel models, web search volume (max_tool_calls), and reasoning_effort.

Panel sub-calls time out after 12 minutes. Judge sub-calls time out after 8 minutes. Sub-call timeouts are not retried. The inference gateway terminates long requests at 20 minutes (1200 seconds). Set your client read timeout to at least 20 minutes. Treat an HTTP 504 from the gateway as retryable, not a hard failure.

Usage and Cost

Panel models run concurrently, which is faster than calling each model sequentially. The model synthesis tool still waits for panel, judge, and tool work before the outer model writes the final answer, so a model synthesis tool request generally costs more and takes longer than a single-model completion.

One model synthesis tool API request is not one model call. Usage reflects token consumption and tool calls for every panel model, the judge, the outer model, and any web search or web fetch steps those models perform. The model synthesis tool does not add a separate charge. You are billed at the existing per-model token rates and web tool rates.

The response includes per-model usage throughout the request. The final usage message aggregates token counts across all participating models. To inspect individual model consumption, review usage on each model response in the stream or completion payload, not only the final aggregate.

Failure and Degradation

The model synthesis tool returns HTTP 200 for most partial failures and lets the outer model produce a final answer when possible. The result depends on which stage fails:

  • If some panel models fail or return empty output, the model synthesis tool continues. The summary it sends to the outer model includes failure details. The outer model may mention gaps only when they affect the final answer.
  • If all panel models fail, the summary reports that the model synthesis tool failed. The outer model answers from its own knowledge. The response may include a failure_reason such as all_panels_failed, rate_limited, or insufficient_credits.
  • If the judge fails or returns bad or truncated JSON, panel responses are retained, but structured analysis is omitted. The summary notes that judge comparison is unavailable.
  • If web tools are disabled with max_tool_calls: 0 but a model emits tool calls, the inner model call fails as empty content and follows the partial or total failure paths above. Setting max_tool_calls to 0 also disables web tools on the outer synthesis step.

Failed panel or judge models may appear in a failed_models list when orchestration continues with other participants.

Use the Model Synthesis Tool with Other Server-Side Tools

You can include the model synthesis tool in the tools array with other server-side tools such as web_search in the same request. In one turn, the model synthesis tool and other built-in tools can all execute. Results from other tools are included in the summary the model synthesis tool sends to the outer model.

The model synthesis tool runs at most once per turn. Duplicate model synthesis tool entries in the same request are ignored after the first invocation. Nested model synthesis tool calls are blocked.

After the model synthesis tool executes, it is unavailable for the rest of that turn. Other tools remain available. On the Chat Completions and Responses APIs, tool_choice set to required or a named function choice is changed to auto after the first built-in tool executes so the follow-up turn is not forced to call another tool. On the Messages API, any or a specific tool choice is changed to auto after a built-in call.

Limitations and Review

The model synthesis tool does not guarantee a correct answer. Several models can repeat the same outdated fact, rely on the same weak source, or share a reasoning error. Agreement among panel models is one signal, but not proof of accuracy.

The model synthesis tool does not replace source verification or human review for important decisions. Review outputs and supporting evidence before acting on them.

Data Governance

Model synthesis tool requests are not stored by DigitalOcean. Retention follows the same policies as the underlying model calls. A model synthesis tool request is evaluated by every model on the panel, so model selection is a data-governance decision. Confirm that your prompt and context are appropriate for each provider in the panel. For provider terms, see Third-Party AI Models.

Retrieve Knowledge Base

Knowledge base retrieval lets the model query your private data sources during inference using retrieval-augmented generation (RAG). You add the knowledge_base_retrieval tool to your API request and the inference API handles retrieval and incorporates the results into the model’s response automatically.

To use knowledge base retrieval, send a POST request with your knowledge base ID. You can find the ID in the DigitalOcean Control Panel or by querying the API. For example, use the Chat Completions API with knowledge base retrieval:

import os
from pydo.inference import Client

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

resp = client.chat.completions.create(
    model="openai-gpt-4o",
    messages=[
        {"role": "user", "content": "What are some features of DigitalOcean Inference?"},
    ],
    tools=[
        {
            "type": "knowledge_base_retrieval",
            "knowledge_base_id": "<your-knowledge-base-id>",
        }
    ],
    tool_choice="auto",
    stream=False,
    max_tokens=1024,
)

print(resp.choices[0].message.content)
import { InferenceClient } from "@digitalocean/dots";

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

const completion = await client.chat.completions.create({
    model: "openai-gpt-4o",
    messages: [
        { role: "user", content: "What are some features of DigitalOcean Inference?" },
    ],
    tools: [
        {
            type: "knowledge_base_retrieval",
            knowledge_base_id: "<your-knowledge-base-id>",
        },
    ],
    tool_choice: "auto",
    stream: false,
    max_tokens: 1024,
});

console.log(completion.choices[0].message.content);
curl -X POST https://inference.do-ai.run/v1/chat/completions \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai-gpt-4o",
    "messages": [
      {
        "role": "user",
        "content": "What are some features of DigitalOcean Inference?"
      }
    ],
    "tools": [
      {
        "type": "knowledge_base_retrieval",
        "knowledge_base_id": "<your-knowledge-base-id>"
      }
    ],
    "tool_choice": "auto",
    "stream": false,
    "max_tokens": 1024
  }'

For the full set of parameters, see the Serverless Inference API reference. The response looks like the following:

{
    "choices": [
        {
            "finish_reason": "stop",
            "index": 0,
            "logprobs": null,
            "message": {
                "annotations": [
                    {
                        "type": "tool_use",
                        "tool_use": {
                            "name": "knowledge_base_retrieval",
                            "call_id": "call_y6aBCI2IrnS8ZgPR6DKjXl9T",
                            "arguments": "{\"query\":\"features of DigitalOcean Inference\"}",
                            "status": "completed",
                            "output": "{\"knowledge_base_id\":\"e7651dee-da73-11ef-bf8f-4e013e2dxxxx\",\"query\":\"features of DigitalOcean Inference\",\"results\":[{\"metadata\":{\"chunk_category\":\"CompositeElement\",\"ingested_timestamp\":\"2026-05-11T18:15:46.532085+00:00\",\"item_name\":\"https://docs.digitalocean.com/\",\"page_number\":null},\"text_content\":\"### 1 May 2026 [ ](https://docs.digitalocean.com/#1-may-2026) * The following DeepSeek model is now available on DigitalOcean Inference for [serverless inference](https://docs.digitalocean.com/products/inference/how-to/use-serverless-inference/), [Agent Development Kit](https://docs.digitalocean.com/products/inference/how-to/build-agents-using-adk/) and [agents](https://docs.digitalocean.com/products/inference/how-to/create-agents/): For more information, see the [Available Models page](https://docs.digitalocean.com/products/inference/details/models/).\"},{\"metadata\":{\"chunk_category\":\"CompositeElement\",\"ingested_timestamp\":\"2026-05-11T18:15:46.532085+00:00\",\"item_name\":\"https://docs.digitalocean.com/\",\"page_number\":null},\"text_content\":\"### 5 May 2026 [ ](https://docs.digitalocean.com/#5-may-2026) ....\"}],\"total_results\":3}"
                        }
                    }
                ],
                "content": "DigitalOcean Inference includes several features designed to support serverless inference and facilitate the development and deployment of AI models and agents. ...",
                "reasoning_content": null,
                "refusal": null,
                "role": "assistant"
            }
        }
    ],
    ...
    }
}

Use the Responses API with knowledge base retrieval:

curl -X POST https://inference.do-ai.run/v1/responses \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-pro",
    "input": "What is actions infrastructure? Answer using the knowledge base.",
    "tools": [
      {
        "type": "knowledge_base_retrieval",
        "knowledge_base_id": "09d65da1-5225-11f1-b074-4e013e2dxxxx"
      }
    ],
    "stream": false,
    "max_output_tokens": 1024
  }'

The response looks similar to the following:

{
  "background": false,
  "completed_at": 0,
  "created_at": 1779045957,
  "error": {
    "code": "",
    "message": ""
  },
  "frequency_penalty": 0,
  "id": "resp_b999e07cebb3dd7a",
  "incomplete_details": {
    "reason": ""
  },
  "instructions": {
    "OfInputItemList": null,
    "OfString": ""
  },
  "max_output_tokens": 1024,
  "max_tool_calls": 0,
  "metadata": null,
  "model": "deepseek-v4-pro",
  "object": "response",
  "output": [
    {
      "arguments": "{\"query\": \"What is actions infrastructure?\"}",
      "call_id": "chatcmpl-tool-8e9ce86361b0fe64",
      "name": "knowledge_base_retrieval",
      "status": "completed",
      "type": "function_call"
    },
    {
      "call_id": "chatcmpl-tool-8e9ce86361b0fe64",
      "output": "{\"knowledge_base_id\":\"09d65da1-5225-11f1-b074-4e013e2dxxxx\",\"query\":\"What is actions infrastructure?\",\"results\":[{\"metadata\":{\"chunk_category\":\"CompositeElement\",\"ingested_timestamp\":\"2026-05-17T19:23:20.695776+00:00\",\"item_name\":\"example-document.pdf\",\"page_number\":45},\"text_content\":\"Example content retrieved from your knowledge base.\"}],\"total_results\":1}",
      "status": "completed",
      "type": "function_call_output"
    }
  ]
}

Use Model Context Protocol (MCP)

MCP servers expose tools that the model can call, such as fetching account data, managing schedules, or interacting with third-party APIs. The MCP built-in tool connects the model to remote Model Context Protocol (MCP) servers and orchestrates calls to them.

Connect to an Authenticated MCP Server

You can connect to authenticated MCP servers using bearer token authentication. The following example sends a Chat Completions request that connects to the DigitalOcean Accounts MCP server. Replace $DIGITALOCEAN_API_TOKEN with a valid DigitalOcean personal access token.

import os
from pydo.inference import Client

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

resp = client.chat.completions.create(
    model="openai-gpt-4o",
    messages=[
        {"role": "user", "content": "Fetch my DigitalOcean account information and summarize it in 2 bullets."},
    ],
    tools=[
        {
            "type": "mcp",
            "server_label": "digitalocean",
            "server_url": "https://accounts.mcp.digitalocean.com/mcp",
            "authorization": f"Bearer {os.environ.get('DIGITALOCEAN_API_TOKEN')}",
            "allowed_tools": ["account-get-information"],
        }
    ],
    tool_choice="required",
    stream=False,
    max_tokens=512,
)

print(resp.choices[0].message.content)
import { InferenceClient } from "@digitalocean/dots";

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

const completion = await client.chat.completions.create({
    model: "openai-gpt-4o",
    messages: [
        { role: "user", content: "Fetch my DigitalOcean account information and summarize it in 2 bullets." },
    ],
    tools: [
        {
            type: "mcp",
            server_label: "digitalocean",
            server_url: "https://accounts.mcp.digitalocean.com/mcp",
            authorization: `Bearer ${process.env.DIGITALOCEAN_API_TOKEN}`,
            allowed_tools: ["account-get-information"],
        },
    ],
    tool_choice: "required",
    stream: false,
    max_tokens: 512,
});

console.log(completion.choices[0].message.content);
curl -X POST https://inference.do-ai.run/v1/chat/completions \
  -H "Authorization: Bearer $MODEL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai-gpt-4o",
    "messages": [
      {
        "role": "user",
        "content": "Fetch my DigitalOcean account information and summarize it in 2 bullets."
      }
    ],
    "tools": [
      {
        "type": "mcp",
        "server_label": "digitalocean",
        "server_url": "https://accounts.mcp.digitalocean.com/mcp",
        "authorization": "Bearer $DIGITALOCEAN_API_TOKEN",
        "allowed_tools": ["account-get-information"]
      }
    ],
    "tool_choice": "required",
    "stream": false,
    "max_tokens": 512
  }'

The allowed_tools array restricts which tools from the MCP server the model can call. In this example, only the account-get-information tool is available. When omitted, the model can use any tool the server exposes. For the full set of MCP tool parameters, see the Serverless Inference API reference. The response looks like the following:

{
    "choices": [
        {
            "finish_reason": "stop",
            "index": 0,
            "logprobs": null,
            "message": {
                "annotations": [
                    {
                        "type": "tool_use",
                        "tool_use": {
                            "name": "digitalocean__account-get-information",
                            "call_id": "call_xasb9Xk1HAfT564P3bteZZTT",
                            "arguments": "{}",
                            "status": "completed",
                            "output": "{\n  \"droplet_limit\": 100,\n  \"floating_ip_limit\": 75,\n  \"reserved_ip_limit\": 75,\n  \"volume_limit\": 5000,\n  \"email\": \"[email protected]\",\n  \"name\": \"dev-sammy\",\n  \"uuid\": \"de55ee97-21ab-452d-aaf0-d4046480xxxx\",\n  \"email_verified\": true,\n  \"status\": \"active\",\n  \"team\": {\n    \"name\": \"My Team\",\n    \"uuid\": \"de55ee97-21ab-452d-aaf0-d4046480xxxx\"\n  }\n}"
                        }
                    }
                ],
                "content": "- Your account (\"dev-sammy\") is active with email \"[email protected]\", which is verified. You are part of \"My Team\" with a UUID of \"de55ee97-21ab-452d-aaf0-d4046480xxxx\".\n- You have a resource allocation limit of 100 droplets, 75 floating IPs, 75 reserved IPs, and 5000 volumes.",
                "reasoning_content": null,
                "refusal": null,
                "role": "assistant"
            }
        }
    ],
....    }
}

Connect to an Unauthenticated MCP Server

You can also connect to public MCP servers that do not require authentication. The following example sends a Responses API request:

import os
from pydo.inference import Client

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

resp = client.responses.create(
    model="openai-gpt-4o",
    input="Create a scheduling poll called Team Lunch with two time options for tomorrow at noon and the day after at noon.",
    tools=[
        {
            "type": "mcp",
            "server_label": "timergy",
            "server_url": "https://api.timergy.com/mcp",
        }
    ],
    tool_choice="required",
    stream=False,
    max_output_tokens=512,
)

print(resp)
import { InferenceClient } from "@digitalocean/dots";

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

const resp = await client.responses.create({
    model: "openai-gpt-4o",
    input: "Create a scheduling poll called Team Lunch with two time options for tomorrow at noon and the day after at noon.",
    tools: [
        {
            type: "mcp",
            server_label: "timergy",
            server_url: "https://api.timergy.com/mcp",
        },
    ],
    tool_choice: "required",
    stream: false,
    max_output_tokens: 512,
});

console.log(resp);
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-4o",
    "input": "Create a scheduling poll called Team Lunch with two time options for tomorrow at noon and the day after at noon.",
    "tools": [
      {
        "type": "mcp",
        "server_label": "timergy",
        "server_url": "https://api.timergy.com/mcp"
      }
    ],
    "tool_choice": "required",
    "stream": false,
    "max_output_tokens": 512
  }'

The response looks like the following:

{
...
  "model": "openai-gpt-4o",
  "object": "response",
  "output": [
    {
      "arguments": "{\"autoFinalize\":false,\"creatorName\":\"Assistant for Team\",\"deadline\":\"2026-04-08T12:00:00-05:00\",\"description\":\"Scheduling poll for a team lunch\",\"invitees\":[],\"location\":\"Office Cafeteria\",\"options\":[{\"end\":\"2026-04-10T13:00:00-05:00\",\"start\":\"2026-04-10T12:00:00-05:00\"},{\"end\":\"2026-04-11T13:00:00-05:00\",\"start\":\"2026-04-11T12:00:00-05:00\"}],\"title\":\"Team Lunch\"}",
      "call_id": "call_uallF71f2THNYsEvZUubSUhQ",
      "name": "timergy__create_poll",
      "status": "completed",
      "type": "function_call"
    },
    {
      "call_id": "call_uallF71f2THNYsEvZUubSUhQ",
      "output": "{\n  \"pollId\": \"fdc8110b-274d-45b4-b791-0149f6cfc4bc\",\n  \"title\": \"Team Lunch\",\n  \"url\": \"https://timergy.com/en/polls/fdc8110b-274d-45b4-b791-0149f6cfc4bc\",\n  \"passphrase\": \"horse-sword-thumb\",\n  \"options\": [\n    {\n      \"id\": \"c8879755-9136-497d-aedc-81b50fafbb13\",\n      \"start\": \"2026-04-10T17:00:00.000Z\",\n      \"end\": \"2026-04-10T18:00:00.000Z\",\n      \"label\": null\n    },\n    {\n      \"id\": \"58c474c6-12b4-42d5-a96e-c6c977d8a3b2\",\n      \"start\": \"2026-04-11T17:00:00.000Z\",\n      \"end\": \"2026-04-11T18:00:00.000Z\",\n      \"label\": null\n    }\n  ],\n  \"expiresAt\": \"2026-04-21T18:00:00.000Z\",\n  \"autoFinalize\": false,\n  \"inviteesSent\": 0,\n  \"note\": \"Share the URL with participants. The passphrase is saved for finalization. Assistant for Team's \\\"yes\\\" votes have been auto-submitted.\"\n}",
      "status": "completed",
      "type": "function_call_output"
    },
    {
      "content": [
        {
          "annotations": [],
          "logprobs": [],
          "text": "The scheduling poll \"Team Lunch\" has been created. You can share the following URL with participants to vote:\n\n**Poll URL:** [Team Lunch Poll](https://timergy.com/en/polls/fdc8110b-274d-45b4-b791-0149f6cfc4bc)\n\nFor admin access and to finalize the poll, you can use the passphrase:\n\n**Passphrase:** `horse-sword-thumb`\n\nThe poll includes two time slot options:\n- April 10, 2026, from 12:00 PM to 1:00 PM (local time)\n- April 11, 2026, from 12:00 PM to 1:00 PM (local time)",
          "type": "output_text"
        }
      ],
...
  "tool_choice": "auto",
  "tools": [
    {
      "type": "mcp",
      "server_label": "timergy",
      "server_url": "https://api.timergy.com/mcp"
    }
  ],
...
  }
}

Supported Anthropic and OpenAI Tools

Tool search enables searching and loading of tools on demand in the model’s context in agentic workflows. This allows you to avoid loading all tool definitions up front and can reduce overall token usage and cost. Use the passthrough tool search tool on the Messages API for Anthropic models and the Responses API for OpenAI 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.

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)
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 -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:

{
  "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:

{
  "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.

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.

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)
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 -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.

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:

[
  {
    "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.

Add the computer use tool to the model using the Messages API. 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:

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 -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.

Provide the computer use tool to the model using the Responses API. 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:

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)
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 -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.

Local Shell/Bash

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 for Anthropic models and the local shell tool with the Responses API for OpenAI 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:

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)
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 -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.

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:

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)
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 -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.

Web Fetch

(For 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. 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:

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)
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 -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:

{
  "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.

Code Editing

Both Anthropic and OpenAI models can edit files in your codebase. Anthropic models use the text editor tool with the Messages API, and OpenAI models use the apply patch tool with the Responses API:

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:

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)
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 -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.

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:

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)
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 -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.

Function (Tool) Calling

Using function calling, models can interface with external systems and access data outside their training data. Unlike the hosted server-side tools on this page, function calling is client-side: you define your own functions, the model decides when to call them and returns the arguments. Your application runs the function and returns the result. Anthropic models define functions with the Messages API, and OpenAI models define functions with the Responses API:

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:

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)
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 -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.

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:

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)
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 -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.

We can't find any results for your search.

Try using different keywords or simplifying your search terms.