浏览器内智能体插件系统 (InPage Agent Plugin System)
1. 核心设计背景与架构目标 (Architecture Motivation & Goals)
在纯前端运行的轻量智能体(InPage Agent)中,传统网页插件或扩展系统常采用刷新页面(Reloading)或重载沙箱的方式生效与卸载。这种做法不仅会打断用户正在进行的对话流与编辑器状态,且在移动端和单页应用中体验极为生硬。
核心架构目标:
- 零刷新热启停 (Non-Refreshing Hot-Plugging):插件启用即生效,关闭即注销,绝不依赖
location.reload()。 - 可数可控度量 (Countable & Controllable Metrics):所有插件(内置、市场安装、用户自定义导入)状态全量受控,具备精确的运行态与安装态计数统计。
- 提示词糖 (Prompt Sugar) 与上下文胶囊 (Context Badge) 双态机制:对于前端用户展现为精简、可关闭的胶囊(Badge),但输入到底层大模型(LLM)时则是具备严格结构化上下文语义的 XML/Markdown 提示词块。
- 即插即用的宿主桥接 (Plugin Bridge):插件与宿主 UI(对话栏、工作区、全局通知)通过受控 API 交互,互不侵入。
2. 零刷新生命周期与资源追踪 (Zero-Refresh Disposable Pattern)
2.1 传统前端插件的泄漏困境
若插件随意调用 window.addEventListener、setInterval 或在 document.body 中注入 DOM 悬浮层,当用户点击“关闭插件”时,由于函数闭包引用未释放,会导致内存泄漏、幽灵弹窗以及事件重复绑定的恶性循环。
2.2 自动资源追踪容器 (Auto-Disposable Context Container)
插件引擎为每个运行中的插件实例分配一个专属的 PluginContext。插件的所有环境调用必须经过该容器:
export interface PluginContext {
pluginId: string;
api: PluginContextAPI;
// 自动生命周期追踪容器(卸载时自动清理,无需开发者手动一一注销)
addEventListener: <K extends keyof DocumentEventMap>(
target: EventTarget,
type: K | string,
listener: (e: any) => void,
options?: boolean | AddEventListenerOptions
) => () => void;
setTimeout: (handler: TimerHandler, timeout?: number) => number;
setInterval: (handler: TimerHandler, timeout?: number) => number;
trackDOM: <T extends HTMLElement>(element: T) => T;
onCleanup: (disposer: () => void) => void;
}当插件被停用(disablePlugin)时,系统自动执行:
- 逆序执行插件注册的
cleanups自定义析构函数。 - 遍历解绑全部记录在案的
addEventListener。 - 批量执行
clearTimeout与clearInterval。 - 从 DOM 树彻底移除插件注入的浮动元素和被
trackDOM追踪的节点。 - 释放上下文引用,实现纯净注销。
3. Prompt Sugar 与 Badge 提示词糖双态机制 (Dual-State Badge & Prompt Sugar)
3.1 提示词糖的本质
所谓的 Badge 胶囊,在本质上是交互层的提示词糖 (Prompt Sugar):
- 面向用户端 (User View):以极简的芯片胶囊形式挂载于输入框上方或用户消息气泡中,仅展示前 15~25 个字缩略(如
选中文本: "InPage Agent · 浏览器内轻量 ...")及删除按钮,避免冗长段落挤占视觉空间。 - 面向模型端 (Model View):在消息序列化发送时,将 Badge 内部携带的
fullContent完整映射入<user_contexts>或<user_attachments>结构化语义块中:
<user_contexts>
<context_badge type="selection" label="选中文本: "..."" preview="...">
这里是用户划选或引用的真实全量长文本,提供给大模型作为上下文分析。
</context_badge>
</user_contexts>
用户输入的实际提问...- 历史消息解构回显:当渲染历史记录时,UI 自动捕获
<user_contexts>块,将其转化为图形化的.user-context-chip标签置于气泡顶端,正文仅保留纯文本,兼顾了工程严谨性与界面高审美。
4. 划词智能体设计 (Select to AI, Select2AI)
作为插件体系的旗舰内置扩展,select2ai 展示了完整的划词智能体协同范式:
flowchart LR
A["用户在任意区域划词选中"] --> B{"选区校验 (非输入框/长度>0)"}
B -- 是 --> C["精确计算 getBoundingClientRect 坐标"]
C --> D["浮出三元悬浮菜单 (问AI | 解释 | 翻译)"]
D --> E1["点击 问AI: 注入 Badge -> 展开侧栏 -> 聚焦输入框"]
D --> E2["点击 解释: 携带 Badge + 深度解释 Prompt 立即提交"]
D --> E3["点击 翻译: 携带 Badge + 双语互译 Prompt 立即提交"]
B -- 否 --> F["悬浮菜单自动隐藏"]关键细节处理:
- 点击防丢焦:在三元浮层按钮上阻止
mousedown默认行为(e.preventDefault()),避免在点击按钮前导致原生划词选区(Selection)发生塌陷丢失。 - 边界碰撞保护:自动检测屏幕顶部与边缘空间,若顶部视口不足 40px,自动翻转至选区下方展示。
- 输入域避让:如果选区处于
#chat-input或其他编辑输入框内部,自动静默抑制浮层,不干扰正常打字与编辑。
5. 插件市场与外部 JS 导入机制 (Plugin Marketplace & Dynamic JS Ingestion)
5.1 预开插件市场 (Pre-Opened Marketplace)
内置插件市场目录包含分类筛选(AI 提效、工具箱、编辑增强、工作流)、评分、下载量、功能列表与一键安装能力。已内置插件与第三方插件共用统一的管理协议。
5.2 外部标准 JS 插件规范
系统支持导入标准 JavaScript 代码(ESM export default 或 CommonJS module.exports):
export default {
id: 'my-custom-plugin',
name: '自定义数据解析器',
version: '1.0.0',
description: '自动分析表格或文本',
category: 'tools',
tags: ['分析', '自定义'],
activate(ctx) {
// 监听按键或事件
ctx.addEventListener(window, 'keydown', (e) => {
// 业务逻辑
});
// 返回销毁清理函数
return () => {
// 清理逻辑
};
}
};系统通过安全的函数工厂与沙箱上下文包装执行,并将源码与启停状态持久化保存在 LocalStorage 中,页面二次加载时自动恢复。
6. 避坑指南与最佳实践 (Pitfalls & Best Practices)
- 绝对禁止刷新恢复:任何插件的开关切换必须通过
activeContext.dispose()彻底移除监听与 DOM。切勿为了“图省事”引入window.location.reload()。 - 异步运行时忙闲检测:在插件一键提交(如快捷解释或翻译)前,先检查 Agent Runtime 是否处于忙碌状态。若仍在生成上轮回答,应先安全中止或排队,防止
sendMessage被静默丢弃。 - 样式隔离与层级约束:插件创建的浮动元素必须挂载在具有独立命名前缀(如
inpage-plugin-floating)或由ctx.trackDOM统一纳管的容器上,z-index保持高位但低于模态对话框遮罩(Modal Overlay)。
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps