Tools
The shared registry — standard, HTTP, function, and built-in tools.
Tools live in one shared registry on the Tools page. An agent links a tool
by { id } and uses it exactly as saved: config, description, icon, sharing,
hooks, approval, and composer toggle all come from the shared row, and keys
written on the agent's entry are ignored. Only enabled is per agent, so
editing a shared tool changes every agent that links it.
An agent's tools list can also hold an inline tool, such as
{ "type": "http_client", "name": "get_order", "url": "…" }. Its entry is its
whole definition. Inline tools are mostly an API pattern; the agent editor's
Create New Tool saves a shared tool and links it.
Every tool carries a description (what the model reads), an icon, a sharing audience (unset means it inherits the agent's), optional hooks, an optional approval step, and a composer toggle. With Let the user select this tool on, the chat box shows a button for it. Pressing it tells the model the user wants that tool this turn. It is a hint, not a gate: the tool stays available either way.
Names
A custom tool's name is the function name the model calls. It starts with a
letter, uses only letters, digits, and underscores (^[a-zA-Z][a-zA-Z0-9_]*$),
is at most 64 characters, and is unique in the org. find_tools is reserved.
Standard tools are named after their type and can't be renamed.
Standard tools
| Tool | What it does | Settings |
|---|---|---|
web_search | The model provider's own web search, on OpenAI and Gemini models | searchContextSize: low, medium, high (OpenAI only) |
web_fetch | The provider's own page fetch, on Claude and Gemini models | maxUses, allowedDomains, blockedDomains (Claude only) |
search_knowledge | Searches the folders you pick and returns citable passages | See Knowledge |
create_record, read_record, update_record, delete_record, list_records | Work with records of an entity | See Entities |
web_search and web_fetch are created for every org and can't be deleted.
On a model with no native equivalent they're skipped for that turn. Every
other standard tool is a single shared row, created the first time you add it.
Built-in tools
run_codeis on every turn. The model writes Python (the default), TypeScript, or bash, and it runs in the shared sandbox with no network, no package installs, and a 30-second limit. Files it writes to$OUTPUT_DIRare attached to the reply, up to 10 files of 10 MB each per turn. Python has python-docx, openpyxl, xlsxwriter, python-pptx, reportlab, weasyprint, pandas, matplotlib, and pillow.run_codealso reads oversized tool results that were saved ashandle://URIs.find_toolsappears when an agent has more than 10 tools outside the core set (MCP tools, app actions, subagents, custom and entity tools). Those tools are then listed by name and description only, and the model loads the ones it needs on demand. Core tools are always loaded:web_search,search_knowledge,run_code, the skill tools,memory,handoff,delegate_task, andconnect_<slug>.
Three built-in tools are switched on per agent rather than saved in the
registry. memory lets the model write memories.
delegate_task starts helper agents (Subagents). handoff
hands the conversation to a person. Its strategy is set per agent: record
saves the request for your team, and link also shows the user a button to
your own case page. The link must be an http(s) URL and can include
{{subject}}, {{summary}}, {{reason}}, and {{threadId}}, each
URL-encoded. The button text is buttonLabel (up to 40 characters, default
"Open a case").
HTTP tools
An http_client tool calls one endpoint. Its URL, headers, query params, and
body are templates:
{{name}}is filled by the model. Each distinct name becomes one string parameter in the tool's schema.${user.id},${user.email},${tenantId},${user.accessToken}are filled by the platform, never by the model. The access token is filled only when the request goes to Assivy's own API. For any other host it's empty.{{auth_token}}is an older alias for it.
{
"url": "https://api.example.com/orders/{{orderId}}",
"method": "GET",
"headers": { "X-Customer": "${user.email}" }
}The method is GET, HEAD, POST, PUT, PATCH, or DELETE. It can also
be a single {{var}}, and the model then picks one of those. The body type
is json (the default), form_data, x_www_form_urlencoded, or raw.
GET and HEAD never send a body, and a JSON body must still parse after
substitution. The URL must start with http:// or https://, or be a
template.
Each call has a 30-second timeout by default (timeout, in ms). Responses
over 256 KB are cut off with a marker. A call follows at most 5 redirects, and
private and internal addresses are refused at every hop. A failed call isn't
retried. Errors come back to the model as text (HTTP Error 404: …). JSON
responses are parsed, and anything else is passed through as is. HTTP tools
don't go through Outbound access.
Function tools
A function_call tool runs a TypeScript or Python body in the shared Docker
sandbox, with a 30-second limit and no access to the host. TypeScript bodies
get fetch through the egress proxy, so they reach only the hosts allowed
under Outbound access. Python bodies have no
network. A TypeScript tool can run in the user's browser instead. See
Function tools for how to write the body, runtime, files,
limits, and log().
Approvals
Turn on Require approval before it runs (interruptConfig.interruptBefore)
and the turn pauses on every call until the user accepts or rejects it. To
replace the default Accept/Reject card, set interruptConfig.approvalWidget
to a widget, such as the built-in tool-approval or your own
(Widgets). Its state is { toolName, input }. Its buttons use
{ type: "approve_tool" }, { type: "reject_tool" }, or
{ type: "request_change" }. A rejection can carry a reason back to the
agent, and a reason field the user typed in the form takes priority.
web_search and search_knowledge draw their own results card. These are
result widgets, not approvals.
Hooks
Before and after hooks run on HTTP tools, search_knowledge, the entity
tools, and Composio apps attached to an agent (Integrations).
web_search and web_fetch ignore hooks. Function tools have none, because
their logic is already in the body. A hook is a function named after the
hook:
async function beforeExecute(data, runtime) {
// data is the tool's arguments. Return the arguments to use.
log('order lookup', { user: runtime.user?.email });
return { ...data, region: 'eu' };
}afterExecute(data, runtime) receives the tool's result and returns the
result to use. Hooks run in the same sandbox as function tools, with the same
runtime and log(). App hooks also get runtime.toolName and
runtime.appSlug. A hook that returns nothing passes data on, including any
edits it made in place. Hooks fail open: a throw, a timeout, a misnamed function, or a result over
128 KB lets the original data through.