Register provider-hosted tools#

A server tool runs inside a model provider, unlike an ordinary AgentTool executed by the Agent loop. Install one provider-specific extension for each hosted capability you want to expose:

from zett_agent.extensions.server_tools.google import GoogleServerToolExtension
from zett_agent.client import create_agent
from zett_agent.model import ServerToolDefinition

client = await create_agent(
    model,
    extensions=[
        GoogleServerToolExtension([
            "google_search",
            "url_context",
        ]),
    ],
)

Every extension calls register_server_tool() during on_tool. The resulting definitions are request-scoped and reach every subsequent before-model hook and the final ModelRequest. They never enter the Agent’s local tool executor.

Choose the extension that matches the endpoint#

Built-in declarations#

Extension

Default type

Transport requirement

GoogleServerToolExtension

google_search + url_context

Gemini GenerateContent; supported by GoogleProvider.

AnthropicServerToolExtension

web_search_20260318 + web_fetch_20260318

Anthropic Messages; supported by AnthropicProvider.

OpenRouterServerToolExtension

openrouter:web_search + openrouter:web_fetch

OpenRouter-compatible Chat Completions endpoint.

OpenAIServerToolExtension

web_search

OpenAI Responses API; not OpenAI Chat Completions.

DeepSeekServerToolExtension

web_search

DeepSeek Responses API; not legacy Chat Completions.

OpenAIProvider and DeepSeekProvider use Chat Completions by default. Construct either adapter with response=True to use its Responses endpoint and enable its hosted tools explicitly:

model = OpenAIProvider(
    model="gpt-5",
    api_key=os.environ["OPENAI_API_KEY"],
    response=True,
)

The Responses adapter sends complete history on every request. It preserves provider output items for later function-result turns and maps hosted-tool start/completion records into the common server-tool event lifecycle. Available tool types still depend on the selected provider endpoint and model.

OpenAI and DeepSeek publish no separate web_fetch type. Their hosted web-search workflow retrieves relevant pages itself. The defaults intentionally use documented types instead of sending an invented fetch discriminator.

Allow protocol evolution#

Tool types are open strings and configurations are opaque mappings. New provider versions therefore do not require a zett-agent enum update:

extension = AnthropicServerToolExtension(
    [
        ServerToolDefinition(
            "web_fetch_20260318",
            {
                "name": "web_fetch",
                "max_uses": 3,
                "allowed_domains": ["docs.python.org"],
            },
        ),
        ServerToolDefinition("code_execution_20260521"),
    ],
)

The provider remains responsible for model compatibility and field validation. Duplicate types in one request are rejected before network I/O because their ordering would otherwise make the active configuration ambiguous.

When none of the tools needs configuration, pass their type strings directly:

extension = GoogleServerToolExtension([
    "google_search",
    "url_context",
    "code_execution",
])