3.0 KiB
3.0 KiB
L1 · 工具与命令
前置:L0。
api.pi就是 pi 的原生ExtensionAPI——pi CLI 扩展能做的这里都能做,语义一致。
1. 注册一个带参数的工具
工具是 Agent 的「手」:注册后自动进入系统提示词与工具列表,受审批拦截管理。
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. 注册斜杠命令
命令是用户的「入口」:聊天框输入 / 出现,回车触发。
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 生命周期钩子上挂逻辑(发消息前注入、工具调用前后处理等):
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):
let count = api.storage.get('count') ?? 0
api.storage.set('count', ++count)
5. 验证
- 重载插件(开关切换或重启)
- 日志确认
plugin activated - 聊天框输入
/dice回车 → 收到点数;对 Agent 说「掷个 20 面骰」→ 观察它调用dice_roll - 日志中应出现
dice rolled sides=20 value=…
排障
- 工具没出现在 Agent 里:日志搜
plugin activated确认激活成功;registerTool抛错会记为plugin activation failed - 命令没出现在
/面板:命令名冲突(重名被去重),换名再试