Plugins - AI Tools
An AI Tool Plugin is a Plugin the AI agent can call. Set a Plugin's run location to AI Tool and it stops being a piece of UI: it has no container, no HTML, and no button. Instead it is offered to the agent alongside Navigator's built-in tools, and the agent decides when to call it and with what arguments.
This is the way to teach the agent something only your account knows: a lookup against a site system, a calculation over your own attributes, a rule about your own data. You write the function, and the agent works out when it is the right one to reach for.
Invoke, not Run
A UI Plugin exports Run(params) and returns a dispose function. An AI Tool exports Invoke(args, context) and returns a result. There is nothing to dispose, because there is nothing on screen.
Both forms may live in the same file. Only the one the location calls for is used, so a Plugin can present a panel and expose the same capability to the agent.
Declaring the tool
The agent cannot see your code, only what the Plugin declares. That declaration lives in the Plugin's Settings under a tool key, and Operator refuses to save an AI Tool without it.
Note what an AI Tool is not given. There is no pluginParams, so no viewer, no visual register, and no BModels or BEngine: those are passed to a UI Plugin by its host, and an AI Tool has no host. An AI Tool sees its arguments, its context, and the browser's own APIs. Anything it needs to reach an API with, a base URL, a header name and a token, belongs in Settings.config, which is also what keeps one Plugin working across accounts without a code change.
Rules the platform enforces
These are refused at save time rather than at call time, so a mistake here shows up in Operator, not in a conversation with the agent.
| Rule | Why |
|---|---|
| The Plugin ID becomes the tool name | The agent calls it as plugin_<pluginId>. The ID may hold letters, numbers, hyphens and underscores only. |
| A description is required | The tool name is an opaque ID and carries no meaning, so the description is the only thing the agent can select on. Without one the tool is registered and never chosen. Set tool.description, or fill in the Plugin's Name and Description. Say what it returns and when to use it. |
inputSchema must be an inline object schema | Its type must be object, and $ref, $defs, allOf and not are refused: each silently drops the tool out of strict mode, so the arguments stop being structurally guaranteed and nothing reports that it happened. Inline the schema instead. |
annotations.sideEffect | Either none, or external for a reviewed read-only external request. AI Tools are read-only in this release, so a tool that writes is refused. |
annotations.timeoutMs | A positive number of milliseconds. Defaults to 15000 and is clamped to 120000, so no tool can pin a call open. The whole operation is inside that budget, source fetch included. |
| The result must be JSON and under 100,000 characters | A result that cannot be serialized, or that is larger than the cap, is reported to the agent as a failure rather than truncated. Return a summary and let the agent ask again for detail. |
What to expect at call time
The Plugin's code runs in the user's own browser with the user's own permissions, and the Plugin record is re-read server side with that user's session immediately before the call is forwarded. A Plugin the user cannot see is a Plugin the agent cannot call on their behalf, regardless of what any browser has cached.
Timeouts free the caller, not the Plugin. Honouring context.signal is up to you, and aborting a signal cannot stop JavaScript that is already blocking the browser thread: a Plugin that blocks stalls Navigator itself. Thread the signal into every request you make.
Throwing is the correct way to report a problem. The failure is turned into a standard envelope carrying a reason the agent can act on, so an Errorwhose message says what was wrong with the arguments lets the agent correct itself and call again.
Before enabling one in production
An AI Tool is the one Plugin location where nobody clicks a button to run the code. Review it as you would review anything triggered automatically:
- Validate every argument. They are model-generated, they are not trusted, and a Plugin is the last thing standing between them and your API.
- Keep the tool narrow. One tool that answers one question is chosen correctly far more often than one that does six things behind a mode argument.
- Return only what the answer needs, both because the cap is real and because everything returned is spent as agent context.
- Restrict access where the data warrants it, through the Plugin's login and permission settings, rather than assuming the agent is a safe caller.