news 2026/9/17 6:34:35

DeepChat Agent 浏览器原生画中画迁移指南:基于 NativeKit 0.6.3 的主进程浮层面板架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepChat Agent 浏览器原生画中画迁移指南:基于 NativeKit 0.6.3 的主进程浮层面板架构

DeepChat Agent 浏览器原生画中画迁移指南:基于 NativeKit 0.6.3 的主进程浮层面板架构

【免费下载链接】deepchat🐬DeepChat - A smart assistant that connects powerful AI to your personal world项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat

DeepChat 在 Agent 操控后台浏览器时,需要为用户提供一个可拖动、只读、不抢占聊天渲染的实时预览。本文将完整讲解 DeepChat 将这一"画中画(PiP)"能力从渲染进程 Canvas 实现迁移到 Electron 主进程 + @zerob13/nativekit 原生浮层的完整架构设计:从依赖演进史、NativeKit 0.6.3 的 API 契约与运行时能力矩阵,到表面选择(Surface Selection)、帧投递、生命周期矩阵、性能验收口径、打包校验与失败语义。读完本文,你将掌握如何在一个 Electron 应用中安全地接入进程级原生叠加层,理解"原生拖动 + 有界快照流"这一诚实的能力边界,并能直接对照 DeepChat 仓库中的实现与测试进行验证。

本文对应的架构规格位于 docs/architecture/nativekit-agent-browser-pip/spec.md,其用户侧契约与面板移交语义见 docs/features/agent-browser-pip/spec.md,与 Computer Use 快照 PiP 的共享协调见 docs/features/computer-use-snapshot-pip/spec.md。

1. 迁移背景与状态

1.1 为什么需要迁移

在旧实现中,Agent 浏览器预览是一张渲染进聊天界面的 Vue 卡片(由AgentBrowserPiP.vue挂载在ChatTabView.vue中)。每帧画面都要经历"页面捕获 → 缩放 → 编码 → 跨进程投递 → 结构化克隆 →createImageBitmap→ Canvas 绘制 → Vue DOM 布局"的完整链路。问题不在于后台页面或capturePage()本身,而在于链路的后半段:

  • 每一帧都要跨入聊天 renderer,与对话渲染、滚动竞争资源;
  • renderer 每帧都要分配并解码一个新的图像对象;
  • Canvas 替换参与了聊天 renderer 的 paint/compositing 工作;
  • 指针拖动通过 Vue 状态与布局完成,产生大量布局抖动;
  • PiP 随应用内容区域消失,且无法使用原生工作区(work area)边界钳制。

正确的归属层是Electron 主进程 + NativeKit:由操作系统原生栈(AppKit / Win32 / XCB)直接拥有窗口移动、工作区钳制、z-order 与面板控件,renderer 只负责资格协调与(原生能力不可用时的)Browser 侧面板移交。

1.2 依赖演进与版本锁定

迁移的最终落点是把 @zerob13/nativekit 精确锁定在0.6.3。从 0.5.1 到 0.6.3 的演进史本身就是一个典型的"原生模块跨平台发布"案例:

版本变更要点
0.5.1发布的 macOS arm64/x64 二进制声明的最低部署目标为 macOS 15.0
0.5.2修正两个 macOS 预编译产物为 macOS 12.0,与 DeepChat / Electron 40 的 Monterey 下限一致,API 与架构矩阵不变
0.5.3修复 macOS 手动放置:在 AppKit 异步原生拖动开始后记录NSWindowDidMove,图片刷新不再恢复锚点
0.5.4增加xwayland-satellite下的宿主内嵌拖动;仍是五个预编译产物、macOS 12.0 下限
0.5.5纯打包发布:把所有 N-API 二进制从nativekit.napi.node改名为node.napi.node;修复了 x64 查找,但@electron/rebuild把 arm64 映射到armv8预编译标签,macOS/Linux arm64 仍回退到源码编译
0.5.6修正 arm64 包名为node.napi.armv8.node,x64 保留node.napi.node,并用仅预编译的node-gyp-build解析验证每个 CI 产物
0.6.0用最多两个"调用方配置控件"取代固定的隐藏/重定位控件;根级面板改为按显示器工作区而非宿主边界定位
0.6.1增加固定样式自定义工具栏;DeepChat 提供透明 PNG 模板图(open-panel 与 close 按钮),几何、明暗、hover、按压反馈、缩放与对比度由 NativeKit 平台原生负责
0.6.2修复 AppKit 忽略NSButton.bezelColor导致的 macOS 工具栏背景问题,改为绘制样式感知的图层背景与边框
0.6.3Windows x64 预编译产物静态链接 MSVC 运行时,加载不再依赖单独安装的动态运行库

仓库中 package.json 的dependencies明确写着"@zerob13/nativekit": "0.6.3"(无^~),与规格中"精确版本"的要求一致。npm registry 对 0.6.3 声明了 Electron>=28.0.0与 Node>=18的兼容范围,DeepChat 当前所用的 Electron 41(见 package.jsondevDependencies)位于其声明范围内。

1.3 与 Computer Use 快照 PiP 的关系

2026-07-28 起,Computer Use 最新快照 PiP 落地:AgentPreviewCoordinator现在持有进程级的 NativeKit 生命周期,仲裁 Browser 与 Computer Use 的"同一时刻仅一个展示"。Browser 保留页面、捕获、面板移交与Open in panel/Close行为;Computer Use 只贡献有界的最近快照与Close

2. 反方观点(Counterpoint):诚实的能力边界

规格文档专门用一节澄清 NativeKit 迁移到底保证了什么、没有保证什么:

  • 已确认:面板拖动是原生的、流畅的,面板可以完全脱离 DeepChat 窗口。被评审的实现直接把原生窗口放进 AppKit / Win32 / XCB,拖动采样不经过 renderer 状态或 IPC。
  • 未承诺:远程页面的内容刷新率并不因此变成视频级。NativeKit 0.6.3 仍然通过同步的overlay.pushImage()接收完整 PNG/JPEG data URL,原生解码每张图,不提供共享纹理、原始缓冲流、局部更新或动画 API

因此,这次迁移的对外表述是"原生移动 + 有界快照流"(native movement with a bounded snapshot stream),而不是"60 FPS 浏览器视频"。这一边界贯穿后续的性能验收口径。

3. 现状工程简报与热路径

3.1 目标与当前归属

现状
用户可见行为不强制打开 Browser 面板即展示只读 Agent 浏览器预览;用户可移动或关闭它而不打断 Agent
当前 renderer 归属AgentBrowserPiP.vue,由ChatTabView.vue挂载
当前主进程归属YoBrowserPresenter
触发路径renderer 会话、侧面板与窗口状态推导出capturing | rendering | stopped,再调用browser.setPreviewMode
既有原生页面一个WebContentsView,面板关闭时被重新挂到 1280 x 800 的透明离屏BaseWindow

3.2 迁移前的热路径

Agent WebContentsView at 1280 x 800 -> webContents.capturePage() -> NativeImage.resize(400 x 250) -> JPEG quality 72 Buffer -> typed main-to-renderer event -> structured clone / Uint8Array -> Blob -> createImageBitmap() -> Canvas resize + drawImage() -> Vue DOM card, toolbar, halo, and pointer drag

Browser 预览的调度策略是:活跃捕获完成后 500 ms 排下一次捕获,空闲捕获完成后 2000 ms 排下一次,即捕获成本之前的上限约 2 FPS 与 0.5 FPS;同一时刻只有一次捕获在途,帧不会排队。规格明确提醒:这些运行时调度设置并不代表下方首帧、帧龄、高刷新率验收预算已经达标——它们是"现状"而非"证据"。

3.3 诊断结论

开销与脆弱性不在于后台页面或capturePage(),而在于链路后半段(renderer 解码、Canvas 参与合成、Vue 拖动布局、随应用内容区域消失、无法原生钳制)。正确的浮面归属层是主进程 + NativeKit,renderer 只保留"资格协调"与"原生不可用时的侧面板移交"两项职责。

4. 用户需求与目标 / 非目标

用户需要一个满足以下条件的预览:直接原生输入移动(而非 renderer 指针事件);不与聊天渲染和滚动竞争;保持同一个活跃 Agent 页面与 CDP 目标;只读、不向远程页面转发输入;在用户主动激活时打开既有 Browser 面板;只关闭当前 run 的预览;在 NativeKit 0.6.3 无法提供浮层的平台上安全降级。

4.1 核心目标

  • 精确使用@zerob13/nativekit@0.6.3
  • 在其支持的运行时矩阵上,NativeKit 成为首选 PiP 表面;
  • PiP 可拖到当前显示器工作区内的任意位置,包括完全离开 DeepChat 窗口;
  • 保留既有 1280 x 800 无焦点渲染宿主与同一个页面WebContentsView
  • 已完成的 JPEG 帧由YoBrowserPresenter直接送 NativeKit,原生路径不做 renderer 帧投递;
  • 拖动、工作区钳制、z-order、原生面板控件全部交给 AppKit / Win32 / XCB;
  • 保持单捕获在途、epoch/run 校验、末帧有效保留、图像尺寸有界;
  • NativeKit 不进应用启动路径,只在出现具体 PiP 请求时加载;
  • NativeKit 不可用时:打开既有侧面板 Browser,抑制 Computer Use PiP,两个 Agent 工具都不受影响;
  • 会话过期、面板可见性、宿主 blur/hide/minimize、run 终结、页面销毁、应用退出时同步隐藏原生面板;
  • 增加打包校验,确保受支持的目标构建不会静默遗漏.node预编译产物;
  • 迁移完成前必须实测拖动行为、首帧延迟、帧新鲜度与同步原生解码成本。

4.2 非目标(明确不做)

全帧率视频、共享纹理、WebRTC 或 GPU 表面共享;PiP 内远程页面交互;把活体WebContentsView放进原生浮层;维护下游 NativeKit fork 或安装期二进制改名;在原生面板上方再造第二个透明 Vue 工具栏窗口;强制所有 Linux 用户以--ozone-platform=x11启动;多个同时可见的 PiP 面板;跨应用重启持久化面板位置;原 SDD 中推迟的多标签 / Fit-desktop 工作;围绕单一 NativeKit 消费方搭建通用原生能力框架。

5. NativeKit 0.6.3 契约

5.1 有效 API 与 DeepChat 用途

APIDeepChat 用途
overlay.start({ toolbar })配置高对比深色工具栏:Open in panel在前,Close在后
overlay.attachHost()按 content bounds 与原生句柄绑定一个聊天BrowserWindow
overlay.setMaxSize(360)把 400 x 250 的源画面渲染为 360 x 225 DIP 面板
overlay.pushImage()创建或替换当前 Agent 浏览器 JPEG
overlay.setActiveSession()显示前先把当前逻辑 Agent 会话置为第一
overlay.setVisible()临时不合规时隐藏而不删除当前展示
overlay.removeImage()清除终结的、销毁的或被替换的展示
overlay.detachHost()释放已关闭的聊天窗口
overlay.stop()presenter 关闭时释放全部原生资源
activate双击意图:聚焦 DeepChat 并打开既有 Browser 面板
control配置的控件 ID,映射到 open-panel 或当前 run 的关闭

suppressSessionscompleteSession、应用图标查找与系统窗口查询在此迁移中不需要——"同一时刻一个 PiP、一个当前目标"使其成为冗余。

5.2 运行时特征

  • 仅主进程使用,绝不能被 renderer 或 preload 导入
  • Node-API v8 预编译;DeepChat 所用 Electron 版本在声明的 peer 范围内;
  • pushImage()接受PNG/JPEG base64 data URL,而非Buffer
  • JavaScript 边界上的调用全部是同步的;
  • macOS 在主线程解码并更新NSPanel
  • Windows 将更新同步编组到其 STA 浮层线程,经 WIC 解码后用UpdateLayeredWindow呈现;
  • Linux 同步更新其专用 XCB 浮层线程,经 GdkPixbuf 解码;
  • 拖动完全留在平台实现内部,不产生任何 renderermousemoveIPC
  • 移动与过渡即时生效;0.6.3 无动画 API;
  • 原生control事件携带调用方定义的 ID,但不携带展示 ID——只有当 DeepChat 强制"单可见 PiP"不变式时才安全。

5.3 已发布的运行时能力矩阵

运行时首选表面原因
macOS arm64/x64原生浮层已发布预编译;非激活NSPanel
Windows x64原生浮层已发布预编译;自有的 layered topmostHWND
Windows arm64Browser 侧面板;无 Computer Use PiPNativeKit 0.6.3 未发布 win32-arm64 预编译
Linux x64/arm64(X11 / 集成 XWayland)原生浮层已发布预编译与全局 XCB 窗口模型
Linux x64/arm64(xwayland-satellite原生浮层0.5.4 起 XCB 面板内嵌于 Electron 宿主;拖动被钳制在宿主边界内
Linux 原生 WaylandBrowser 侧面板;无 Computer Use PiP无全局定位、无兼容的 X11 窗口句柄
缺失/损坏 addon 或原生启动失败Browser 侧面板;无 Computer Use PiP应用启动与 Agent 工具保持可用

DeepChat不会为了启用 PiP 而改变用户的 Linux 显示后端。这一点与 AgentPreviewCoordinator.ts 中isPublishedTarget()的实现完全一致:它只对darwin:arm64darwin:x64win32:x64linux:arm64linux:x64五个组合放行。

6. 目标架构与归属

one live page / one CDP target | v focusless render-host BaseWindow -> Agent WebContentsView at 1280 x 800 | v capturePage (one in flight) | v resize 400 x 250 / JPEG 72 | +-------------------+-------------------+ | | native capability native unavailable | | v +--------+--------+ JPEG Buffer -> base64 data URL | | | v v v Browser activate event Computer Use @zerob13/nativekit overlay -> existing side panel no PiP | AppKit / Win32 / XCB panel

6.1 三方归属划分

YoBrowserPresenter(见 src/main/desktop/browser/YoBrowserPresenter.ts)仍是页面、run、渲染宿主、捕获 epoch 与预览模式的权威:校验发送方的BrowserWindow与当前 Agent run;按原生能力选择native-overlaynone;原生能力不可用时请求既有 Browser 侧面板;把完成帧分叉到恰好一个表面;在每个既有生命周期边界上停止捕获并清理表面。

AgentPreviewCoordinator(进程级、聚焦的协调器,见 src/main/desktop/preview/AgentPreviewCoordinator.ts)只负责:

  • 动态包加载与一次性能力探测;
  • overlay.start()/stop()生命周期;
  • 一个活跃宿主与一个活跃展示;
  • Browser 与 Computer Use 工具栏配置切换(源码中toolbarOptions(source)source === 'browser'决定按钮组:Browser 为 open-panel + close,Computer Use 仅 close,见OPEN_PANEL_CONTROL_ID/CLOSE_CONTROL_ID常量);
  • 最新显式源声明(claim)与共享的 run 级关闭;
  • 宿主 move/resize/close 同步;
  • JPEGBuffer→ data URL 转换(present()data:image/jpeg;base64,${jpeg.toString('base64')});
  • 显示前预绘帧(prepaint-before-show)排序;
  • 把 NativeKit 的 activate 与配置控件映射到当前源特定的处理器;
  • 同步原生调用周围的计时计数器(recordPushDuration,25 ms 慢推送告警阈值、60 s 限频)。

RendererAgentBrowserPiP.vue)保留:当前会话 / 面板 / run / 窗口资格推导;既有setPreviewMode请求合并;处理 open-panel 与 run 关闭的类型化原生动作。在native-overlay下它不渲染任何 PiD DOM、不接收任何帧字节;原生能力失败时同一类型化激活路径打开 Browser 侧面板。

6.2 协调器源码要点

从 AgentPreviewCoordinator.ts 的实现可以看到几个关键常量与设计:

  • PREVIEW_MAX_EDGE = 360:原生面板最大边长;
  • HOST_ANCHOR_OFFSET = 16HOST_SYNC_DELAY_MS = 50:宿主锚点偏移与去抖后的宿主同步延迟;
  • SLOW_PUSH_WARNING_MS = 25/SLOW_PUSH_WARNING_INTERVAL_MS = 60_000:同步pushImage()耗时告警阈值与限频;
  • attachHost()使用真实BrowserWindow.getNativeWindowHandle()getContentBounds(),锚定edge: 'trailing'
  • start()中动态import('@zerob13/nativekit'),依次调用overlay.start(toolbarOptions('browser'))overlay.setMaxSize(360)overlay.setVisible(false)(保持全局隐藏),并监听activate/control事件;
  • 展示身份函数:hostId = chat-window:<windowId>presentationId = agent-preview:<source>:<windowId>:<sessionId>nativeSessionId = agent-preview:<source>:<sessionId>
  • 宿主事件绑定覆盖 focus / blur / show / hide / minimize / restore / move / resize / closed,配合screen的 display-added / removed / metrics-changed 监听;
  • shutdown()幂等清理:清空 claims / dismissedRuns / handlers,置unavailable = truestopNative()

7. 表面选择契约(Surface Selection)

browser.setPreviewMode的返回值类型(YoBrowserPresenter.setPreviewMode在 src/main/desktop/browser/YoBrowserPresenter.ts 中实现并返回该结构):

type BrowserPreviewSurface = 'native-overlay' | 'renderer-canvas' | 'none' type BrowserPreviewModeResult = { updated: boolean surface: BrowserPreviewSurface }

选择过程在按需 NativeKit 初始化后进程级稳定

  1. 不从应用启动、Browser 后台渲染或 Computer Use 资格判断中导入 NativeKit;
  2. 在第一次具体 Browser 捕获或 Computer Use 目标出现时动态导入@zerob13/nativekit
  3. 启动浮层并保持全局隐藏;
  4. 在第一个合格宿主上用真实BrowserWindow.getNativeWindowHandle()验证attachHost()
  5. 两步都成功则使用native-overlay
  6. 否则记录一次脱敏能力告警,本进程内保持能力禁用,打开既有侧面板 Browser,且不暴露 Computer Use PiP。

瞬时坏帧不切换表面:NativeKit 保留上一个有效展示,下一次有界捕获重试。另外,renderer-canvas表面值及其组件对既有调用方仍然可用,但原生能力失败不再自动选择它作为产品回退——唯一的产品回退是既有 Browser 侧面板。

8. 原生展示身份与帧投递

8.1 单展示身份模型

hostId = chat-window:<windowId> presentationId = agent-browser:<windowId>:<sessionId> native session = agent-browser:<sessionId> logical target = { windowId, sessionId, runId, captureEpoch }

逻辑目标(而非 NativeKit 无作用域的回调)才用于识别 activate 与 dismiss 动作。窗口或会话改变时,先移除上一个展示再挂接下一个宿主。展示在 Browser 面板暂时可见或宿主短暂失去资格时保持分配但隐藏,从而保留 NativeKit 的手动拖动位置;run 终结、会话/页面销毁、宿主关闭与关机时移除它。

8.2 帧投递规则

既有捕获安全规则全部保留:

  • 1280 x 800 源视口;400 x 250 输出;最大原生面板 360 x 225(对 400 x 250 帧降采样);
  • JPEG quality 72;512 KiB 的 DeepChat 帧上限(远低于 NativeKit 的 32 MiB 输入上限);
  • 单捕获在途;捕获、缩放、编码、呈现全部结束后才排下一次;
  • 呈现前即时校验模式、run ID、目标窗口与 epoch;陈旧结果直接丢弃;
  • 捕获或解码失败时保留最后一张有效原生图像。

原生分支的帧路径只有一步:

JPEG Buffer -> data:image/jpeg;base64,<Buffer.toString('base64')> -> overlay.pushImage()

该分支不向 renderer 发送任何帧。浮层初始隐藏;首次显示或恢复时,DeepChat 在隐藏状态下推入当前帧,且只有pushImage()成功后才会调用setVisible(true),避免闪烁出陈旧或空面板。

首帧语义:第一张成功帧还会调用一次setActiveSession()选定 NativeKit 会话;后续图像刷新只调用pushImage()(同一 host / presentation / session ID),不重复attachHost()setActiveSession()setVisible(true)或任何移除操作。NativeKit 按稳定的presentationId拥有手动帧,因此图像替换只改变像素与尺寸,不会重置用户拖动的原点;宿主 move/resize 同步是独立的、去抖的路径。

9. 交互契约与 UI 布局

9.1 原生交互面

NativeKit 0.6.3 定义:工具栏按钮之外的任意图像区域可拖动;双击图像激活;点击Open in panel关闭 PiP 并激活既有 Browser 面板;点击Close关闭当前 Agent run 的预览;面板永不成为 key/main window,永不向远程页面转发输入。

activate 映射:① 显示并聚焦属主聊天窗口 → ② 为精确的 window/session/run 发布类型化browser.preview.action事件 → ③ 由当前 renderer 打开既有 Browser 面板 → ④ 停止原生捕获并把同一页面 View 重挂到稳定面板边界。

Close 映射:① 标记逻辑 run 已关闭 → ② 停止捕获但让页面继续在隐藏渲染宿主中渲染 → ③ 发布同一类型化动作事件使 renderer 资格一致 → ④ 允许后续 run 再次显示 PiP。

原生路径只配置 NativeKit 的两个内置图标类型并在 DeepChat 内映射其 ID,不保留 Canvas 时代的标题工具栏、居中拖动提示或活动光晕——用另一个浮层重建它们会重新引入本次迁移要消除的焦点、z-order 与跨窗口协调问题。两种表面都保持只读,绝不把点击转发进远程页面。

9.2 UI 布局前后对比

迁移前:对话内 renderer 卡片

+----------------------------------------------------------------+ | DeepChat | | | | Conversation +----------------------+ | | | Vue toolbar | | | | Canvas page mirror | | | | drag / open / close | | | +----------------------+ | +----------------------------------------------------------------+

迁移后:桌面工作区中的原生面板

+------------------------------------------+ +----------------------+ | DeepChat | | Native PiP | | | | | | Conversation | | Agent page snapshot | | Browser panel remains closed | | [▯][×]| | | | drag; double-click | +------------------------------------------+ +----------------------+ AppKit/Win32/XCB

控件从左到右配置为Open in panelClose(实际 NativeKit 符号为平台原生,上图只表达结构而非确切图标)。

原生能力不可用

Windows arm64 / native Wayland / unavailable addon -> Browser: open the existing side-panel browser -> Computer Use: continue without PiP

10. 生命周期矩阵

事件原生动作页面动作
合格捕获开始Attach/update host;push current frame;show保持在 1280 x 800 渲染宿主
新帧只替换同一展示;保留手动原点不重挂
Browser 面板打开隐藏展示;停止捕获同一 View 重挂进面板
合格 run 中面板关闭Show 前 push 当前帧重挂进渲染宿主
原生Close控件隐藏,记录 run 关闭保留渲染宿主;停止捕获
原生Open in panel控件聚焦宿主;请求 Browser 面板稳定边界后重挂
原生双击聚焦宿主;请求 Browser 面板稳定边界后重挂
宿主 move/resize/显示变化去抖attachHost()刷新页面不变
宿主 blur/hide/minimize同步隐藏仅当 Agent 仍需要时继续渲染
宿主重新聚焦重评估;push-before-show不重载
run 终结移除展示停止捕获;释放渲染宿主
会话/页面销毁移除展示销毁既有页面资源
宿主关闭移除展示;detach host清理目标
应用退出overlay.stop()一次既有 presenter 关闭流程

一个值得注意的产品策略:尽管 macOS 的 NativeKit 面板可以加入所有 Spaces,DeepChat 仍保留现行产品策略——Agent 页面预览在其属主聊天窗口不在前台时隐藏;让它持续悬浮在无关应用之上是独立的产品决策,不在本次迁移范围。

11. 性能契约:两个可测量的承诺

原生手感被拆成两个可测量承诺,避免把"感觉流畅"变成不可验证的营销话术。

11.1 原生移动

  • 原生路径无 renderer 指针移动处理器、无拖动位置 IPC;
  • 拖动、钳制、z-order 全部在 NativeKit 内完成;
  • 面板可越过 DeepChat 的每一条窗口边缘,仅受显示器工作区约束;
  • 捕获工作不得在 60 Hz / 120 Hz 参考显示器上产生可见拖动卡顿。

11.2 页面新鲜度验收目标

  • 活跃 Agent 活动:目标至多 8 FPS,上一完整周期结束后 125 ms 调度;
  • 空闲页面目标:1 FPS;
  • 捕获绝不排队或重叠;
  • 暖启动"合格 → 首可见帧"p95 ≤ 300 ms;
  • 活跃端到端帧龄 p95 ≤ 250 ms;
  • overlay.pushImage()p95 ≤ 8 ms、p99 ≤ 25 ms(受支持参考平台);
  • 归因于 PiP 帧呈现的主进程任务不得有单次超过 50 ms。

规格反复强调:当前 Browser 调度仍是"每完整周期后 500 ms 活跃 / 2000 ms 空闲",提升节奏必须以同步 NativeKit 解码/呈现与实体显示器验收为前提;当前调度不是新鲜度目标已通过的证据。在 NativeKit 0.6.3 下目标上限不得超过 8 FPS。这些是发布门槛(release gates)而非任意硬件的运行时承诺——对外可见的说法只能是"原生移动 + 新鲜只读预览",而非"原生速率浏览器视频"。

12. 安全与隐私

  • NativeKit 只在 Electron 主进程导入;任何 NativeKit 对象、原生句柄、原始 IPC 通道或通用能力都不经 preload 暴露;
  • 远程页面执行继续留在既有 YoBrowser 会话的沙箱中;
  • 原生面板只接收降采样后的 JPEG data URL;
  • 帧只存在于内存,绝不记日志、缓存、持久化或写盘;
  • 日志只包含平台、表面、时长、尺寸与脱敏生命周期原因,不含图像字节、URL、标题、DOM 或会话内容;
  • 主进程在每次显示前校验目标BrowserWindow、会话、run ID、模式与 epoch;陈旧捕获不能替换当前会话的面板;
  • 宿主 blur/hide/minimize 与会话失活由主进程直接隐藏原生面板,不等 renderer 清理。

13. 打包与兼容性

13.1 五项打包约束

  1. 精确依赖"@zerob13/nativekit": "0.6.3"
  2. 在 pnpm-workspace.yaml 中把@zerob13/nativekit标记为禁止安装期构建allowBuilds: '@zerob13/nativekit': false)——已发布预编译在运行时解析,不支持的目标必须禁用原生 PiP 而不是现场编译本地 addon;
  3. 保持它位于 Electron 主 bundle 之外,让node-gyp-build能解析打包后的原生 addon;
  4. 从 ASAR 解包node_modules/@zerob13/nativekit/prebuilds/**/*——对应 electron-builder.yml 的asarUnpack规则'**/node_modules/@zerob13/nativekit/prebuilds/**/*'
  5. 打包后校验:darwin-arm64 与 linux-arm64 验证node.napi.armv8.node,darwin-x64、win32-x64、linux-x64 验证node.napi.node

13.2 打包期校验的实现

scripts/afterPack.js 中的validateNativeKitPrebuilds()正是这条规则的落地:它按目标平台/架构映射预编译目录(darwin-universal 同时覆盖 x64 与 arm64),并在app.asar.unpacked/node_modules/@zerob13/nativekit/prebuilds/<platform>-<arch>/下检查对应文件名,缺失即抛错"Missing NativeKit prebuild"。配套的打包配置测试见 test/main/build/electronBuilderConfig.test.ts 与 test/main/scripts/afterPack.test.ts。

关键区分:win32-arm64 打包不得失败——该目标在 0.6.3 下有意使用"按源禁用"行为;缺失受支持预编译是打包失败,不支持的运行时只是禁用原生 PiP,不阻塞应用启动与 Agent 工具。同时禁止在正常 DeepChat 发布流程中源码编译该 addon。本次迁移不需要任何持久化数据或设置 schema 变更。

14. 回滚、失败语义与验收标准

14.1 回滚

回滚是纯代码层面的三步:① 无条件选择renderer-canvas;② 停止加载 NativeKit;③ 确认无其他消费方后移除精确依赖与 ASAR 规则。由于浏览器页面、路由、渲染宿主、捕获格式与 Canvas 实现保持兼容,回滚不涉及页面导航、用户数据迁移或已存设置变更。

14.2 失败语义速查

失败点行为
动态导入或overlay.start()失败记一次日志并为本进程禁用原生 PiP
首个真实宿主attachHost()失败本进程内标记原生能力不可用
Browser 原生能力失败发布既有 activate 动作并打开侧面板
Computer Use 原生能力失败不暴露预览表面,工具执行不变
帧捕获/缩放/编码失败保留上一帧,下个有界 tick 重试
pushImage()失败NativeKit 事务性保留上一展示;限频告警后重试
模式/run/窗口变更后的陈旧帧pushImage()前丢弃
无当前逻辑目标的原生动作忽略
面板激活超时保留或恢复原生 PiP,绝不丢失活体页面
宿主关闭或 addon 关闭清理幂等

14.3 验收标准要点

受支持平台恰好加载 NativeKit 0.6.3 并使用其原生浮层;Windows arm64、原生 Wayland、addon 不可用三类情况打开既有侧面板 Browser 且不显示 Computer Use PiP;首选路径不向 renderer 发送browser.preview.frame负载;远程页面在原生 PiP 与 Browser 面板移交间保持同一WebContents/WebContentsView/ 会话 / URL / DOM / 滚动状态 / cookies / CDP 目标;面板只读、可拖、工作区钳制、非激活;可拖到完全离开 DeepChat 窗口而不弹回;同展示下替换图像不 reattach / reactivate / re-show / remove / 重置手动位置;双击与Open in panel打开既有面板、Close只关闭当前 run;进程内恰好一个原生 PiP 可见;首显与恢复先 push 当前帧再可见;宿主 blur/hide/minimize、面板打开、run 终结、页面销毁、关机确定性隐藏/移除;拖动零 renderermousemoveIPC 并通过原生移动 QA 门槛;帧延迟与同步调用预算达标前不提升捕获节奏;打包应用在受支持目标上含正确预编译;renderer/preload 安全边界不变;测试覆盖按需加载、进程级禁用、Browser 侧面板移交、Computer Use 无表面、原生适配器选择、动作映射与打包;pnpm run formatpnpm run i18npnpm run lint、typecheck、聚焦测试、构建与打包平台检查全部通过。

15. 实现证据与测试落点

规格文档记录的实现证据(截至 2026-07-29)包括:@zerob13/nativekit锁定 0.6.3 且保持主 bundle 外部与 ASAR 解包;0.5.5 tarball 五平台全部使用node.napi.node导致 Linux arm64 回退源码编译失败、0.5.6 修正为架构特定文件名;macOS arm64 安装electron-builder install-app-deps配合PREBUILDS_ONLY=1可解析 arm64 预编译且不产生build/Release回退二进制;0.6.3 静态链接 Windows MSVC 运行时;0.5.4 的 macOS 二进制报minos 12.0;真实 Electron smoke test 完成start -> attachHost -> pushImage -> removeImage -> detachHost -> stop;250 ms 替换同展示时面板 3 秒后仍停在(180, 420)证明图片刷新不再恢复右上锚点;macOS arm64 目录包内app.asar.unpacked/node_modules/@zerob13/nativekit/prebuilds/darwin-arm64/nativekit.napi.node与已装预编译逐字节一致。

测试与代码落点(可在仓库中直接验证):

  • 协调器核心实现:src/main/desktop/preview/AgentPreviewCoordinator.ts
  • 协调器单元测试:test/main/desktop/preview/AgentPreviewCoordinator.test.ts
  • Browser presenter 集成:src/main/desktop/browser/YoBrowserPresenter.ts(setPreviewMode在 L351 附近)
  • Computer Use presenter:src/main/desktop/computerUse/ComputerUsePreviewPresenter.ts 及其测试 test/main/desktop/computerUse/ComputerUsePreviewPresenter.test.ts
  • 组合与装配:src/main/app/composition.ts
  • 依赖锁定:package.json、pnpm-workspace.yaml、pnpm-lock.yaml
  • 打包解包与校验:electron-builder.yml、scripts/afterPack.js

规格同时如实记录尚未关闭的验证项:Windows / Linux / macOS x64 实体机交互、原生 Wayland 不可用行为、窗口外视觉交互,以及 60/120 Hz 性能测量仍需在真实目标环境上完成;renderer 套件的App.startup.test.ts基线 mock 问题(initAppStores()返回undefined而生产链路.then())与本迁移无关。

16. 已解决决策汇总

  • NativeKit 版本精确为 0.6.3;
  • 原生移动是主要流畅性收益,页面仍是有界快照流
  • NativeKit 绝不因应用启动或仅资格判断而加载;
  • 原生能力失败 → 打开既有侧面板 Browser 并禁用 Computer Use PiP;
  • 不强制 Linux 显示后端;
  • 使用 NativeKit 调用方配置工具栏,不新增配套 Vue/原生工具栏窗口;
  • "单可见 PiP"使得 NativeKit 无作用域动作回调安全;
  • 保留既有前台窗口可见性策略;
  • 无阻塞实现的遗留澄清标记。

这份规格与实现的完整配合,为任何需要在 Electron 主进程中接入原生叠加层的项目提供了一个可复用的参考样本:把"流畅"拆成"原生移动"与"快照新鲜度"两个可测量承诺,用能力矩阵 + 生命周期矩阵 + 失败语义表把边界钉死,再用打包期预编译校验守住分发底线。

【免费下载链接】deepchat🐬DeepChat - A smart assistant that connects powerful AI to your personal world项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 6:32:32

羽毛球场景目标检测实战:YOLO训练、小目标识别与标注格式转换全解析

做体育场景的目标检测项目时&#xff0c;我经常在通用数据集上碰一鼻子灰。尤其是羽毛球这种小目标、快速度、强遮挡的运动项目&#xff0c;直接用COCO预训练权重下场识别&#xff0c;效果只能用"惨烈"来形容——运动员漏检、裁判框错、羽毛球根本看不见。最近拿到了…

作者头像 李华
网站建设 2026/9/17 6:30:19

小爱音箱放本地音乐的完整指南:xiaomusic 从安装到开口点播

小爱音箱放本地音乐的完整指南&#xff1a;xiaomusic 从安装到开口点播 【免费下载链接】xiaomusic 使用小爱音箱播放音乐&#xff0c;音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic 周六早晨你随口一句"小爱同学&#xff…

作者头像 李华
网站建设 2026/9/17 6:29:53

Modbus TCP调试避坑指南:IP、Unit ID、Server/Client一个都不能错

做自动化这些年&#xff0c;被问到最多的问题之一就是&#xff1a;Modbus TCP参数看着都对&#xff0c;为啥就是不行&#xff1f;说实话&#xff0c;我也在这个坑里摔过不少次。尤其现在PLC、HMI、上位机、第三方板卡到处都要走Modbus TCP&#xff0c;明明协议是公开的、报文结…

作者头像 李华
网站建设 2026/9/17 6:28:52

PyCharm+MicroPython开发环境搭建实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 6:26:25

拆解99.75%成功率的通达信副图:CCI、RSI、KDJ三线共振选股

简介&#xff1a;通达信 99.75% 成功率指标公式源码以 doc 文档收录&#xff0c;面向借助通达信复盘与自编指标的股票交易者、量化入门学习者&#xff0c;用于解决指标逻辑难复现、买卖信号条件不清晰的问题。文档给出完整公式源码&#xff0c;可看到 TYP 典型价与 AVEDEV 构建…

作者头像 李华