Provider-executed tools
Capabilities the model provider runs inside the turn — web search, code execution.
tool() declares code you write and Plane runs. providerTool() declares a capability
the model provider runs inside the turn — so there is no handler, nothing to
serve, and nothing for sync to register.
import { definePlane, providerTool } from "@plane/sdk"
export default definePlane({
agent: {
slug: "researcher",
model: { provider: "gateway", model: "anthropic/claude-opus-5" },
system: "Answer with current information and cite what you used.",
tools: [
providerTool("web_search", { maxUses: 5, allowedDomains: ["arxiv.org"] }),
providerTool("code_execution")
]
}
})The canonical names are web_search, web_fetch, code_execution, file_search,
image_generation, computer_use and memory. The config is camelCase and Plane's
own, so the same entry works on Anthropic and on OpenAI even though they spell the
fields allowed_domains and filters.allowed_domains. It is narrowed by the name —
providerTool("web_search", { vectorStoreIds: [] }) does not compile.
Refusal is at write time
Where a provider cannot honour an entry, Plane refuses the definition with
ProviderToolUnsupported rather than dropping it — and it checks the primary model
and every fallback rung. An agent that quietly stops searching returns confident
stale facts.
Pass required: false to opt into degradation instead, in which case the tool is
dropped for that rung and a session.error says so.
A provider type that cannot carry provider tools at all (openai-compatible, and
the gateway's non-anthropic/* routes) is refused regardless of required: the
adapter would declare the tool as an ordinary function the model expects Plane to
run, which is the worst of both.
What you see on the stream
- A
tool.call.started/.completedpair carryingexecutedBy: "provider". The call and its result arrive together, because the provider already ran it. - The model's citations on
agent.message.sources. - What the provider billed beyond tokens, in
model.request.completed.usage.serverToolRequests— web search is about $10 per 1,000 calls on both providers, which is real money on an agent that searches five times a turn.
The gate never sees one
policies.toolCalls is evaluated over the calls the model asks Plane to run. A
provider-executed call is already finished when it arrives, before any hook could have
been asked, so it can never become a tool.call.pending. A capability the provider
runs is one Plane does not sign for or gate. That is also why a provider-dialled MCP
server is refused.
Long turns
Anthropic can pause a turn mid-flight while a server-side tool runs. Plane continues it rather than settling the turn, with fallback disabled while paused (the continuation carries blocks another provider cannot read), and a code-execution container is carried across steps. None of that needs anything from you.