☰
OpenTabs插件SDK核心参考:OpenTabsPlugin、defineTool与生命周期钩子一篇讲透
2026/10/22 1:17:51 网站建设 项目流程

【免费下载链接】opentabs

Browser automation clicks buttons. OpenTabs calls APIs.

项目地址:https://gitcode.com/gh_mirrors/ope/opentabs
点击查看免费下载

OpenTabs 的定位是"Browser automation clicks buttons. OpenTabs calls APIs."——AI 不再去点按钮,而是直接通过你浏览器里已登录的会话调用真实网页 API。而要开发 OpenTabs 插件,核心就是本文要讲透的三件套:OpenTabsPlugin基类、defineTool工具工厂,以及onActivate / onDeactivate等生命周期钩子。读完这篇 OpenTabs 插件 SDK 核心参考,你就能独立写出并发布自己的 OpenTabs 插件。

一、SDK 是什么:一个插件的最小骨架

OpenTabs 插件 SDK 的包名是@opentabs-dev/plugin-sdk,它提供三样东西:

  1. OpenTabsPlugin:所有插件必须继承的抽象基类(插件的"身份证 + 工具箱")
  2. defineTool:类型安全的工具定义工厂,让 AI Agent 通过 Zod Schema 调用你的 API 函数
  3. 页面端工具集:DOM 等待、带会话 Cookie 的 fetch、存储、重试、日志等,全部运行在真实页面上下文里

核心 API 定义在 platform/plugin-sdk/src/index.ts,完整说明见 platform/plugin-sdk/CLAUDE.md。

二、OpenTabsPlugin:插件的必选与可选项

每个 OpenTabs 插件都是OpenTabsPlugin的子类。抽象类签名见 platform/plugin-sdk/src/index.ts#L77-L103。

必选字段(抽象属性/方法)

字段类型作用
namestring唯一标识,小写字母+连字符,会成为工具名前缀(如slack__send_message)
displayNamestring侧边面板显示名
descriptionstring插件用途描述,展示给 MCP 客户端
urlPatternsstring[]Chrome match pattern,决定哪些标签页会注入适配器
toolsToolDefinition[]本插件的全部工具定义
isReady()Promise<boolean>就绪探针:返回 true 表示用户已登录、服务可用

可选字段

字段作用
excludePatterns排除与urlPatterns重叠但不想匹配的 URL
homepage侧边面板"打开标签页"按钮跳转的具体 URL
configSchema声明用户配置项(如自托管的 Instance URL),通过侧边面板或 config.json 填写

一个真实的最小示例是 Hacker News 插件,完整源码见 plugins/hackernews/src/index.ts:

class HackerNewsPlugin extends OpenTabsPlugin { readonly name = 'hackernews'; override readonly displayName = 'Hacker News'; readonly urlPatterns = ['*://news.ycombinator.com/*']; override readonly homepage = 'https://news.ycombinator.com'; readonly tools: ToolDefinition[] = [getItem, getUser, listTopStories /* ... */]; async isReady(): Promise<boolean> { try { await waitUntil(() => document.readyState === 'complete', { timeout: 5000 }); return true; } catch { return document.readyState === 'complete'; } } }

💡 注意:脚手架生成的tsconfig.json开启了noImplicitOverride,覆写父类成员必须加override关键字,否则构建时报 TS4114。

三、defineTool:定义一个 AI 可调用的类型安全工具

工具是插件与 AI Agent 对话的接口。defineTool本身是个恒等函数,没有运行时行为,它的价值在于TypeScript 泛型推断:输入输出都用 Zod Schema 声明,handle的参数和返回值自动获得类型。

ToolDefinition 字段速查

字段说明
namesnake_case工具名,注册 MCP 时自动加插件名前缀
displayName侧边面板显示名,省略时由name自动生成
description展示给 AI Agent 的描述——这是 Agent 决定何时调用它的依据,要写得具体
summary/icon/groupUI 摘要、Lucide 图标、分组标题
input/outputZod Schema,会序列化为 JSON Schema 供 MCP 注册与服务器端校验
handle(params, context?)异步处理函数,运行在真实页面上下文,输入已预校验

来自 Hacker News 插件的真实工具(plugins/hackernews/src/tools/list-top-stories.ts):

export const listTopStories = defineTool({ name: 'list_top_stories', description: 'Get the current top stories from the Hacker News front page.', input: z.object({ page: z.number().int().min(1).optional().describe('Page number (default 1)'), }), output: z.object({ stories: z.array(storySchema), has_more: z.boolean(), }), handle: async params => { const { stories, has_more } = await fetchStoryPage('/news', params.page ?? 1); return { stories: stories.map(mapStory), has_more }; }, });

ToolHandlerContext:给长时间任务报告进度

handle的第二个参数context由适配器运行时注入,提供reportProgress({ progress, total, message }),用于长任务的分步进度提示(进度条会实时显示在侧边面板)。长任务建议始终用context?.reportProgress(...)可选链调用。

⚠️ Zod Schema 三条军规

工具 Schema 会被序列化为 JSON Schema(docs/content/docs/sdk/tools.mdx):

  • 禁用.transform()/.pipe()/.preprocess()——无法序列化,输入归一化逻辑放到handle里做
  • .refine()回调绝不能抛异常——即使前面的校验已失败,回调仍会执行
  • 修源头而不是序列化器:与 JSON Schema 冲突时,简化 Schema、把逻辑移入 handler

四、生命周期钩子完全参考:6 个可选方法一篇讲透

钩子让你在页面里"感知"适配器的状态变化,全部是可选方法,只实现你需要的那些即可。完整参考见 docs/content/docs/sdk/lifecycle-hooks.mdx,源码签名在 platform/plugin-sdk/src/index.ts#L125-L168。

钩子触发时机典型用途
onActivate()适配器注册成功后,仅一次注册事件监听、MutationObserver 等页面级资源
onNavigate(url)页内 URL 变化(pushState/replaceState/popstate/hashchange)SPA 路由切换时刷新状态
onToolInvocationStart(toolName)每次handle()执行前埋点、前置检查
onToolInvocationEnd(toolName, success, durationMs)每次handle()结束后(无论成败)耗时统计、日志上报
onDeactivate()适配器被移除(插件更新/卸载/离开匹配页)清理onActivate创建的资源
teardown()插件更新重注入前,紧随onDeactivate之后清理定时器、window全局等持久副作用

三个关键细节:

  • 所有钩子运行在页面上下文;钩子内抛出的错误会被捕获并记录日志,绝不影响适配器注册或工具执行
  • 标签页直接关闭时两个清理钩子都不会触发(浏览器先销毁了 JS 上下文)
  • 钩子由opentabs-plugin build生成的 IIFE 包装器自动接线,作者只需实现方法本身

经典"激活时注册、失活时清理"的配对写法:

override onActivate() { const handler = (e: KeyboardEvent) => { /* ... */ }; document.addEventListener('keydown', handler); this.cleanup = () => document.removeEventListener('keydown', handler); } override onDeactivate() { this.cleanup?.(); }

五、加分项:ToolError 结构化错误与常用工具函数

结构化错误:让 AI 知道该不该重试

ToolError(platform/plugin-sdk/src/errors.ts#L19-L69)携带category、retryable、retryAfterMs元数据,一路透传到 MCP 服务器的结构化错误响应,AI Agent 可据此自动决策"重试还是放弃"。优先使用静态工厂方法:

工厂方法分类可重试
ToolError.auth(msg)auth❌
ToolError.rateLimited(msg, retryAfterMs?)rate_limit✅
ToolError.notFound(msg)not_found❌
ToolError.timeout(msg)timeout✅
ToolError.validation(msg)/ToolError.internal(msg)validation/internal❌

页面端工具函数一览

SDK 还内置了跑在页面上下文的工具函数(platform/plugin-sdk/CLAUDE.md):

  • DOM:waitForSelector、observeDOM、getTextContent——基于 MutationObserver 等待元素
  • Fetch:fetchJSON、postJSON、fetchText等——自动携带页面会话 Cookie,并内置超时与限流头解析
  • 存储:getLocalStorage、getCookie、getAuthCache——安全读写页面存储
  • 计时:retry(指数退避重试)、sleep、waitUntil(轮询断言)
  • 日志:log.info/warn/error——适配器运行时内直连 MCP 服务器日志流

六、延伸阅读:官方文档与源码路径

主题位置
插件基类 API 参考docs/content/docs/sdk/plugin-class.mdx
defineTool 工具参考docs/content/docs/sdk/tools.mdx
生命周期钩子参考docs/content/docs/sdk/lifecycle-hooks.mdx
结构化错误类型docs/content/docs/sdk/error-types.mdx
10 分钟写第一个插件docs/content/docs/first-plugin.mdx
SDK 源码入口platform/plugin-sdk/src/index.ts
真实插件示例plugins/hackernews/src/
侧边面板权限管理assets/demo-todoist-permissions.gif

掌握OpenTabsPlugin骨架 +defineTool工具定义 + 生命周期钩子这三个核心,再配合ToolError和页面工具函数,你就具备了开发任何 OpenTabs 插件的全部核心知识。用一条命令opentabs plugin create脚手架,写一个isReady和一个defineTool,你的 AI 就能通过浏览器登录态调用任意网页 API 了。

【免费下载链接】opentabs

Browser automation clicks buttons. OpenTabs calls APIs.

项目地址:https://gitcode.com/gh_mirrors/ope/opentabs
点击查看免费下载
上一篇:EcoPaste 仓库内 Trellis Channel 多智能体协作运行时完全指南:从事件日志到 Worker 调度的实战手册
下一篇:qlImageSize:终极Mac图片预览插件,完美解决Pixelmator与WebP格式冲突

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询