Agent tools
A plugin can give the AI agent new tools. Declare them in contributes.agentTools in the
manifest, and handle them in your main script with popcraft.agent.onTool. The agent can then call
them in the agent panel, and so can the agents it delegates to. A skill can list them by name too.
"permissions": ["read"],
"contributes": {
"agentTools": [
{
"name": "count_words",
"description": "Count the words in every text layer on the current page.",
"parameters": {
"type": "object",
"properties": { "minLength": { "type": "integer", "description": "Ignore words shorter than this." } }
},
"readOnly": true
}
]
}popcraft.agent.onTool('count_words', async (args, { signal }) => {
const texts = await popcraft.findNodes({ type: 'TEXT' })
const words = texts.flatMap(t => (t.characters ?? '').split(/\s+/)).filter(w => w.length >= (args.minLength ?? 1))
return popcraft.agent.result({ summary: `${words.length} words`, data: { words: words.length } })
})Declaring a tool
| Field | Required | Description |
|---|---|---|
name | ✓ | Unique within the plugin. Starts with a lowercase letter, then lowercase letters, digits and _, at most 40 characters. |
description | ✓ | What the agent reads to decide when to call the tool. At most 1024 characters. Say what it does, what it returns and when it is the right tool. |
parameters | A JSON Schema for the arguments, with "type": "object". At most 8 KB as JSON. Defaults to no arguments. The agent's arguments are checked against it before your handler sees them. | |
readOnly | true when the tool only reads. |
A plugin may declare up to 16 tools, and it needs a main script to run them.
The agent sees each tool under a name that includes your plugin id: count_words from acme.words is
plugin_acme_words__count_words. So your tool can never replace one of PopCraft's own tools or another plugin's.
Its description starts with your plugin's name. In the agent panel, its calls are labelled with your plugin's name.
Handling a call
popcraft.agent.onTool(name, handler) registers the handler for one of your tools. Use the short name from the
manifest. The handler gets:
args: the arguments, already checked against your schema.- A context with
callId,tool, andsignal, anAbortSignalthat fires when the person stops the agent or the call times out.
The handler can return either of these:
- Any JSON value. The agent gets it as the result.
popcraft.agent.result({ summary, data, text, images }):summaryis one line for the tool row in the panel.datais JSON for the agent.textis prose for the agent.imagesis up to 8data:image/…URLs the agent can look at.
If the handler throws, the agent gets the error message and can try something else.
A result can be at most 256 KB. A call that takes longer than 60 seconds fails with a timeout.
When your plugin runs
When the agent calls a tool and your plugin isn't running, PopCraft starts it without a window. In that case
popcraft.command is "agent", so don't declare a command with that id. Register your handlers at the top level
of your script: a call that arrives before its handler is registered waits for it.
A plugin started this way closes after a quiet minute, unless it showed its UI. If your plugin is already running, for example with its panel open, the call goes to that session.
Permissions
A tool can do only what your plugin can do. Everything your handler does to the file goes through the same
permission checks as any other plugin call. So a tool in a plugin without write cannot change the file, whatever
its description says.
The agent gets your tools only after the person has allowed your plugin's permissions. The permission prompt lists the tools. If you add or change a tool in a new version, the person is asked again.
When a person disables or removes your plugin, its tools are taken away from the agent.
readOnly: true lets PopCraft run your tool when the file can't be edited, such as a view-only file or a version
being previewed. It also lets PopCraft run your tool alongside other read-only tools. PopCraft honours it only
while your plugin has no write permission.
Everything one tool call changes in the file is one undo step.