# L1 · 工具与命令 > 前置:[L0](./01-hello-plugin.md)。`api.pi` 就是 pi 的原生 `ExtensionAPI`——pi CLI 扩展能做的这里都能做,语义一致。 ## 1. 注册一个带参数的工具 工具是 Agent 的「手」:注册后自动进入系统提示词与工具列表,受审批拦截管理。 ```js export default function definePlugin(api) { api.pi.registerTool({ name: 'dice_roll', description: '掷一个 N 面骰子,返回点数', parameters: { type: 'object', properties: { sides: { type: 'number', description: '面数,默认 6' } } }, async execute(_id, params) { const sides = Number(params.sides) || 6 const value = 1 + Math.floor(Math.random() * sides) api.log.info('dice rolled', { sides, value }) return { output: String(value), metadata: { sides, value } } } }) } ``` 要点: - `description` 会注入系统提示词,写清楚「什么时候该用这个工具」,Agent 的调用准确率取决于它 - `execute` 返回 `{ output: string }`——output 是喂回模型的内容,保持精炼 - 工具名全局唯一,用 `<插件名>_<动作>` 前缀避免撞名 ## 2. 注册斜杠命令 命令是用户的「入口」:聊天框输入 `/` 出现,回车触发。 ```js export default function definePlugin(api) { api.pi.registerCommand({ name: 'dice', description: '掷骰子', handler: async (ctx, args) => { const sides = Number(args) || 6 ctx.notify(`🎲 ${1 + Math.floor(Math.random() * sides)} / ${sides}`) } }) } ``` ## 3. 订阅事件 在 Agent 生命周期钩子上挂逻辑(发消息前注入、工具调用前后处理等): ```js export default function definePlugin(api) { const off = api.pi.on('before_agent_start', (event) => { api.log.debug('agent starting', { prompt: event.prompt?.slice(0, 50) }) }) // 返回的取消函数放进 dispose,宿主在禁用/重载时调用 return () => off() } ``` 常用事件:`before_agent_start` / `agent_start` / `tool_call` / `tool_result` / `before_provider_request` / `agent_end`。全集见 pi 的 `ExtensionAPI` 类型(`@earendil-works/pi-coding-agent`)。 ## 4. 与插件私有存储配合 需要跨回合记住状态时用 `api.storage`(按插件隔离,落盘 `aso-plugin-storage.json`): ```js let count = api.storage.get('count') ?? 0 api.storage.set('count', ++count) ``` ## 5. 验证 1. 重载插件(开关切换或重启) 2. 日志确认 `plugin activated` 3. 聊天框输入 `/dice` 回车 → 收到点数;对 Agent 说「掷个 20 面骰」→ 观察它调用 `dice_roll` 4. 日志中应出现 `dice rolled sides=20 value=…` ## 排障 - 工具没出现在 Agent 里:日志搜 `plugin activated` 确认激活成功;`registerTool` 抛错会记为 `plugin activation failed` - 命令没出现在 `/` 面板:命令名冲突(重名被去重),换名再试 --- **上一篇** [L0](./01-hello-plugin.md) · **下一篇**:[L2 设置表单](./03-settings.md)——让用户能配置你的插件。