ARTICLE · 1270597
OpenCode 技巧:插件开发的基本流程
Plugin.define({ id, setup })。现在拿之前的文章Hermes接DeepSeek搜索API:插件写法与实测中的例子在OpenCode中实现一遍:把OpenCode的网页搜索换成DeepSeek api。
OpenCode插件的基本结构
import{Plugin} from "@opencode/plugin"export default Plugin.define({id:"example", async setup(ctx){await ctx.storage.set("loaded", true) },})三个硬要求。用Plugin.define导出,id要稳定,storage按id作用域、诊断也按它标识;包名是@opencode/plugin,v1那个@opencode-ai/plugin对不上。
setup里的ctx参数能做什么
ctx是插件唯一入口,常挂的就这几类:
ctx.tool.transform(...) 加工具、改工具、拦工具调用(hook)ctx.websearch.transform(...) 注册搜索provider、切默认ctx.session.hook("context") 模型请求前改上下文ctx.event.subscribe() 订阅事件,配AbortController管生命周期ctx.storage.set / get 按插件id持久化setup返回一个函数 插件卸载时执行,定时器、子进程都挂这里开发流程五步
1 建目录 .opencode/plugins/<name>/index.ts2 写骨架 Plugin.define({ id, setup })3 挂能力 ctx.websearch.transform(editor => editor.add(...))4 挂配置 opencode.json 的 plugins 里写目录(写目录,不是文件)5 重启服务 opencode service restart,然后再验一次这个插件的流程
真正的代码在后面截图里,流程就这么几步:
setup(ctx) ├─ 读 DEEPSEEK_API_KEY,没有就直接抛错 ├─ ctx.websearch.transform(editor => …) │ ├─ editor.add({ id:"deepseek", name:"DeepSeek Search", execute }) │ └─ editor.default.set("deepseek") ← 设置为默认提供商 └─ execute 被调用时(模型每搜一次走一次) ├─ 组 {"query":…, "count":5, "need_content":false} ├─ POST https://api.deepseek.com/v1/tools/search ├─ 失败抛错,HTTP 状态码带上 └─ 成功映射成 [{url, title, content, time}] 返回整套流程成立的关键:内置搜索的provider是可插拔的,注册一个再用editor.default.set切过去就行。模型侧完全无感,它还是调websearch工具,只是后端换了。网页搜索走的是websearch这个权限动作、资源名就是搜索词,换成自己的实现之后权限规则照样生效。
比较容易写错的细节:execute收两个参数,第二个是{ signal },要传给fetch,会话被停掉时请求跟着断;返回值是一个数组,每项要有url、title、content、time四个字段;注册完必须调用editor.default.set("deepseek")设置为默认提供商。
还有错误处理。查不到东西返回空数组,接口挂了直接抛异常,两种别搞错。抛异常在工具层面是个失败,模型知道要改策略;但返回空数组,它会当成正常操作只是空列表。
完整代码

插件写完需要重启服务
重启服务才生效,OpenCode启动时会重扫一遍插件列表。我第一遍就没重启,模型还在用旧的工具表,而且不报错。
生效之后搜索提示行写的是Web Search via Deepseek,没生效时是via OpenCode。
完!
往期精选:
OpenCode 技巧:给Agent写本技能书(SKILL ),它会自己翻出来用
📮
📈 据说关注我的人都升职加薪了















































































