Skip to content

多上下文通信机制 ​

本文引用的源码文件

本文引用的文件

目录 ​

  1. 引言
  2. 项目结构与上下文边界
  3. 核心上下文职责划分
  4. 架构总览与权限模型
  5. 消息路由表设计模式
  6. 短消息与长连接选择策略
  7. MV3 安全沙箱与剪贴板绕过方案
  8. 关键通信时序
  9. 序列化、大数据与安全验证
  10. 故障排查指南
  11. 结论

引言 ​

本扩展采用 Manifest V3 双进程架构:Chrome 扩展端位于 src/,版本为 2.3.1;独立本地 Agent 端为 Node.js 服务,入口为 agent/src/server.js。两者通过本地 HTTP/WebSocket 通信,但本文聚焦于 Chrome 扩展内部四个核心上下文的通信机制:Background Service Worker、Side Panel、Content Scripts 和 Offscreen Document。

在 MV3 中,Service Worker 生命周期受系统控制,空闲时可能被终止;Side Panel 是用户交互主界面;Content Script 注入网页执行页面级工具;Offscreen Document 则用于突破 MV3 对剪贴板等 API 的限制。这些上下文之间通过 chrome.runtime.sendMessage、chrome.runtime.connect、chrome.tabs.sendMessage 以及 Offscreen 文档的 chrome.runtime.onMessage 进行协作。

项目结构与上下文边界 ​

扩展的上下文边界由 manifest.json 明确声明:

上下文入口或声明位置主要职责
Background Service Workermanifest.json.background.service_worker → src/background/index.js全局状态、消息路由、ReAct 执行循环、Agent 客户端、侧边栏控制、通知、定时任务
Side Panelmanifest.json.side_panel.default_path → side_panel.html + src/side_panel/index.js聊天 UI、会话管理、工具面板、截图、导出、工作区、Agent 管理
Content Scriptsmanifest.json.content_scripts → src/content/index.js页面内容读取、DOM 交互、选区工具栏、区域截图、页面度量
Offscreen Documentmanifest.json.permissions.offscreen + src/offscreen/offscreen.html剪贴板读写(MV3 兼容桥)
Options Pagemanifest.json.options_page → options.html + src/options/index.js配置页、Agent 配对、工具箱、MCP/Skill/RAG 设置
graph TB
A["Side Panel<br/>src/side_panel/index.js"] --> B["Background Service Worker<br/>src/background/index.js"]
C["Content Scripts<br/>src/content/index.js"] --> B
D["Options Page<br/>src/options/index.js"] --> B
B --> E["Offscreen Document<br/>src/offscreen/offscreen.html"]
B --> F["Agent 本地服务<br/>agent/src/server.js"]
B --> G["IndexedDB / chrome.storage"]

图表来源

章节来源

核心上下文职责划分 ​

Background Service Worker ​

Background 是扩展的核心调度层。它承担以下职责:

  1. 消息路由中心:统一接收 Side Panel、Content Script、Options Page 发来的 chrome.runtime.sendMessage,按 message.type 分发处理。
  2. ReAct 执行循环:协调工具预筛选、工具执行、流式输出、完成度校验、Token 统计。
  3. Side Panel 生命周期管理:打开/关闭侧边栏、脱离窗口、Tab 分组、作用域模式。
  4. Keepalive 长连接:通过 chrome.runtime.connect 建立命名端口,防止 SW 被系统回收。
  5. Agent 健康检查与心跳:定期检测本地 Agent 可达性,自动重连并刷新 MCP/RAG 工具。
  6. 通知与可见性判定:根据焦点、面板状态、发起实例身份决定是否弹出桌面通知。
  7. Checkpoint 恢复:SW 被回收后通过闹钟唤醒,从 IndexedDB 恢复 ReAct 任务。

章节来源

Side Panel ​

Side Panel 是用户交互主界面,负责:

  1. 聊天与会话管理:发送消息、流式渲染、历史恢复、压缩摘要。
  2. 工具面板与技能选择器:展示 MCP/Skill/RAG 工具,支持 @ 引用知识库。
  3. 截图与图片识别:全屏截图、区域截图、图片附件。
  4. Agent 管理:配对、连接、重启、更新、停止。
  5. 配置同步:监听 chrome.storage.onChanged,实时更新记忆限制、自动压缩等开关。
  6. 与 Background 双向通信:通过 sendMessage 发起请求,通过 connect 维持长连接保活。

章节来源

Content Scripts ​

Content Script 注入所有匹配 URL,提供页面级能力:

  1. 消息路由表:使用 HANDLERS Map 实现 O(1) 查找,按 message.type 分发到具体处理器。
  2. 页面读取:获取文本、HTML、选中内容、表格、元数据、链接、表单、图片。
  3. 页面交互:点击元素、填写表单、滚动、键盘输入、文件上传。
  4. 异步工具标记:通过 ASYNC_HANDLERS Set 判断是否需要保持消息通道开放。
  5. 顶层帧保护:通过 TOP_FRAME_ONLY_TYPES 避免 iframe 响应覆盖主页面。
  6. 区域截图选择:在页面创建遮罩层,让用户拖拽选择截图区域。

章节来源

Offscreen Document ​

Offscreen Document 是 MV3 下剪贴板访问的专用上下文:

  1. 剪贴板读写桥:通过 navigator.clipboard.writeText/readText 实现复制粘贴。
  2. 降级回退:当现代剪贴板 API 失败时,回退到 document.execCommand('copy/paste')。
  3. 国际化文案:复用 ../shared/i18n.js 的多语言支持。
  4. 最小化 HTML:仅包含一个隐藏 textarea 作为剪贴板操作容器。

章节来源

架构总览与权限模型 ​

上下文间通信架构图 ​

sequenceDiagram
participant SP as "Side Panel"
participant BG as "Background Service Worker"
participant CS as "Content Script"
participant OD as "Offscreen Document"
participant AG as "Agent 本地服务"
SP->>BG : "chrome.runtime.sendMessage(CALL_API)"
BG->>BG : "工具预筛选 + ReAct 循环"
BG->>CS : "chrome.tabs.sendMessage(页面工具)"
CS-->>BG : "页面结果"
BG->>OD : "chrome.runtime.sendMessage(COPY_TO_CLIPBOARD)"
OD-->>BG : "剪贴板结果"
BG->>AG : "HTTP/WebSocket 调用"
AG-->>BG : "工具执行结果"
BG-->>SP : "API_COMPLETE / STREAM_*"

图表来源

权限模型说明 ​

权限用途影响范围
offscreen创建 Offscreen Document允许访问剪贴板等受限 API
clipboardRead从剪贴板读取文本通过 Offscreen Document 实现
clipboardWrite写入剪贴板文本通过 Offscreen Document 实现
sidePanel打开/关闭侧边栏控制 Side Panel 生命周期
scripting动态注入脚本配合 Content Script 使用
tabs标签页操作截图、消息转发、窗口管理
storage / unlimitedStorage配置与持久化Session、Checkpoint、Token 统计
debugger调试功能页面调试、CDP 操作
webNavigation导航事件页面加载状态监听

章节来源

消息路由表设计模式 ​

Background 消息路由 ​

Background 使用 if-chain 方式按 message.type 分发消息,注释中明确列出了所有消息类型、来源和用途:

消息类型来源用途是否异步
CANCEL_REACTSide Panel取消 ReAct 循环否
TERMINATE_COMMANDSide Panel终止命令(不取消 ReAct)否
RELOAD_MCP_TOOLSSide Panel强制重载 MCP 工具列表是
RAG_SEARCHSide Panel知识库检索是
GET_MCP_TOOLSSide Panel获取 MCP 工具(30s 缓存)是
CAPTURE_TABSide Panel截取可见标签页是
CALL_APISide Panel主 API 调用入口否(内部异步)
SELECTION_TOOLBAR_ACTIONContent Script划词工具栏操作否
FILL_SIDEPANEL_INPUTContent Script填充侧边栏输入框否
DIRECT_SENDContent Script直接发送文本否

章节来源

Content Script 消息路由 ​

Content Script 使用 Map 实现 O(1) 查找的消息路由表:

flowchart TD
A["收到 chrome.runtime.onMessage"] --> B{"message.type 是否存在于 HANDLERS?"}
B --> |否| C["忽略消息"]
B --> |是| D["调用对应处理器"]
D --> E{"处理器返回 Promise 或属于 ASYNC_HANDLERS?"}
E --> |是| F["return true 保持通道开放"]
E --> |否| G["sendResponse 同步回复"]

图表来源

章节来源

短消息与长连接选择策略 ​

chrome.runtime.sendMessage 的使用场景 ​

sendMessage 适用于短消息、一次性请求-响应场景:

  1. Side Panel → Background:CALL_API、CAPTURE_TAB、GET_CHAT_CONFIG
  2. Content Script → Background:SELECTION_TOOLBAR_ACTION、FILL_SIDEPANEL_INPUT、DIRECT_SEND
  3. Background → Offscreen:COPY_TO_CLIPBOARD、PASTE_FROM_CLIPBOARD
  4. Background → Content Script:SCREENSHOT_RESULT、STREAM_PRESELECT

特点:

  • 单次请求,立即响应
  • 最大消息大小 64MiB(Background 中对 executionLog 做了截断)
  • 适合状态查询、工具调用、截图等

chrome.runtime.connect 的使用场景 ​

connect 适用于长连接、双向通信、保活场景:

  1. Side Panel → Background Keepalive:命名端口 keepalive-{sessionId}
  2. 身份上报:KEEPALIVE_IDENTITY 携带 windowId 和 hostTabId
  3. SW 重启检测:SW_RESTARTED 通知前端可恢复的 checkpoint
  4. 面板断开提醒:延迟复核后触发桌面通知

特点:

  • 持久连接,可多次 postMessage
  • 防止 SW 被系统回收
  • 适合长时间运行的任务(如 ReAct 循环)

选择策略总结 ​

场景推荐方式原因
一次性工具调用sendMessage简单、轻量、有超时
实时流式输出sendMessage + StreamController分片传输,避免大消息
保活防回收connect长连接保持 SW 活跃
双向身份同步connect端口级别的状态共享
剪贴板操作sendMessage to Offscreen隔离敏感 API

章节来源

MV3 安全沙箱与剪贴板绕过方案 ​

MV3 限制背景 ​

MV3 的 Service Worker 和 Content Script 无法直接访问某些浏览器 API,特别是剪贴板。这是出于安全考虑,防止恶意扩展随意读取用户剪贴板内容。

Offscreen Document 解决方案 ​

项目通过 Offscreen Document 绕过限制:

  1. 权限声明:manifest.json 中声明 offscreen、clipboardRead、clipboardWrite
  2. 按需创建:Background 通过 chrome.offscreen.createDocument 按需创建 Offscreen 文档
  3. 单例保护:通过 creatingOffscreenDocument Promise 避免重复创建
  4. 剪贴板桥接:Offscreen 文档暴露 COPY_TO_CLIPBOARD 和 PASTE_FROM_CLIPBOARD 消息
sequenceDiagram
participant BG as "Background"
participant OD as "Offscreen Document"
participant CL as "Clipboard API"
BG->>BG : "ensureOffscreenDocument()"
BG->>OD : "chrome.runtime.sendMessage(COPY_TO_CLIPBOARD)"
OD->>CL : "navigator.clipboard.writeText()"
CL-->>OD : "成功/失败"
OD-->>BG : "{success, message/error}"

图表来源

降级策略 ​

当现代剪贴板 API 失败时,Offscreen 文档会回退到 document.execCommand('copy/paste'):

  1. 创建一个隐藏的 textarea
  2. 设置值并 select()
  3. 调用 execCommand 执行复制/粘贴
  4. 清理临时元素

这种双重策略确保在不同浏览器版本和环境下的兼容性。

章节来源

关键通信时序 ​

CALL_API 完整流程 ​

sequenceDiagram
participant SP as "Side Panel"
participant BG as "Background"
participant TS as "Tool Executor"
participant RL as "React Loop"
participant CS as "Content Script"
participant OD as "Offscreen"
participant AG as "Agent"
SP->>BG : "CALL_API(messages, model, useTools)"
BG->>BG : "重置 API 调用计数"
BG->>TS : "getTools(agentToolIds, agentId)"
TS-->>BG : "可用工具列表"
BG->>BG : "工具预筛选"
BG->>RL : "reactLoop(messages, tools, tabId)"
loop ReAct 循环
RL->>CS : "chrome.tabs.sendMessage(页面工具)"
CS-->>RL : "页面操作结果"
RL->>OD : "chrome.runtime.sendMessage(COPY_TO_CLIPBOARD)"
OD-->>RL : "剪贴板操作结果"
RL->>AG : "HTTP/WebSocket 调用"
AG-->>RL : "AI 响应"
RL->>SP : "STREAM_* 流式消息"
end
RL-->>BG : "最终结果"
BG-->>SP : "API_COMPLETE"

图表来源

Keepalive 保活流程 ​

sequenceDiagram
participant SP as "Side Panel"
participant BG as "Background"
participant SW as "Service Worker"
SP->>BG : "chrome.runtime.connect('keepalive-{sessionId}')"
BG->>BG : "registerKeepalivePort(sessionId, port)"
SP->>BG : "port.postMessage(KEEPALIVE_IDENTITY)"
BG->>BG : "setKeepaliveIdentity(sessionId, identity)"
BG-->>SP : "HOST_TAB_RESOLVED(hostTabId)"
Note over BG : "SW 被回收前,连接断开"
BG->>BG : "onDisconnect 延迟复核"
BG->>BG : "shouldNotifyPanelDetached()"
BG-->>SP : "桌面通知如果面板确实关闭"

图表来源

章节来源

序列化、大数据与安全验证 ​

消息序列化限制 ​

Chrome 扩展的消息传递基于结构化克隆算法,不支持函数、循环引用、undefined 等类型。Background 中对大消息的处理:

  1. executionLog 截断:truncateLogForMessage 函数保留最后 1000 条日志,同时确保 subtask_plan 条目不被丢弃
  2. MAX_LOG_ENTRIES_FOR_MSG:常量定义最大日志条目数
  3. JSON.stringify 安全:所有跨上下文消息都经过 JSON 序列化

大数据传输优化 ​

  1. 流式传输:ReAct 循环通过 STREAM_* 消息分片传输 AI 响应
  2. 缓存机制:MCP 工具列表 30s 缓存,Skill Prompts 60s 缓存
  3. 按需加载:Offscreen Document 按需创建,避免启动开销
  4. 分页处理:Content Script 的页面交互工具支持 waitTime/timeout 参数

安全验证机制 ​

  1. Source 校验:Content Script 中部分消息处理检查 sender.tab?.id
  2. Frame 隔离:TOP_FRAME_ONLY_TYPES 防止 iframe 响应污染主页面
  3. 权限最小化:Offscreen Document 仅暴露剪贴板相关消息
  4. 错误降级:所有跨上下文调用都使用 .catch() 静默失败,避免扩展崩溃

章节来源

故障排查指南 ​

常见问题与解决方案 ​

1. Service Worker 被回收导致消息丢失 ​

现象:长时间运行任务后,Side Panel 无响应或显示“未连接”

原因:MV3 Service Worker 空闲时被系统回收,内存中的 activeReactLoops 清空

解决方案:

  • 使用 Keepalive 长连接防止回收
  • 利用 Checkpoint 机制自动恢复任务
  • 监听 SW_RESTARTED 消息提示用户继续执行

章节来源

2. 侧边栏无法打开或关闭 ​

现象:快捷键无效,或点击插件图标无反应

原因:手势上下文丢失、Tab 分组状态异常、Chrome 版本兼容性问题

解决方案:

  • 确保在用户手势同步栈内调用 sidePanel.open()
  • 检查 _openPanelsByWindow 镜像状态
  • 使用 bindSidePanelToTab 绑定 Tab 专属面板

章节来源

3. 剪贴板操作失败 ​

现象:复制粘贴功能不可用

原因:Offscreen Document 未创建、权限不足、浏览器 API 不支持

解决方案:

  • 检查 chrome.offscreen.createDocument 是否成功
  • 确认 manifest 中声明了 offscreen、clipboardRead、clipboardWrite 权限
  • 查看 Offscreen 文档的控制台错误

章节来源

4. Content Script 消息无响应 ​

现象:Content Script 注册的消息处理器未被调用

原因:消息类型不在 HANDLERS 中、iframe 响应冲突、扩展上下文失效

解决方案:

  • 检查 message.type 是否在 HANDLERS 中定义
  • 对于顶层帧独占操作,使用 TOP_FRAME_ONLY_TYPES
  • 监听 Extension context invalidated 错误

章节来源

结论 ​

本项目实现了完整的 Chrome 扩展多上下文通信机制,通过精心设计的消息路由表、长连接保活策略和 Offscreen Document 权限绕过方案,解决了 MV3 架构下的核心挑战。

关键设计要点包括:

  1. 分层职责清晰:Background 负责调度和状态管理,Side Panel 专注 UI,Content Script 处理页面交互,Offscreen 隔离敏感 API
  2. O(1) 消息路由:使用 Map 实现高效的消息分发,支持异步处理器和顶层帧保护
  3. 保活与恢复:Keepalive 长连接防止 SW 回收,Checkpoint 机制支持任务自动恢复
  4. 权限最小化:Offscreen Document 仅暴露必要接口,降低安全风险
  5. 容错设计:所有跨上下文调用都有错误处理和降级策略

这套架构不仅满足了当前功能需求,也为未来的扩展提供了良好的基础。通过持续优化消息序列化、大数据传输和安全验证机制,可以进一步提升性能和安全性。