环境信息
| 项 |
值 |
| DSH Desktop |
2.0.3(Windows 11) |
| DeepSeek Harness |
web UI(desktop-hosted) |
| 插件 |
@wxg-prc-cpg/browser-skill-dsh-plugin v0.1.1(经 dshmarket 安装到 web profile) |
| 上游 |
本仓库 packages/dsh-plugin-browserskill |
| BrowserSkill (bsk) |
CLI + 浏览器扩展(已连接) |
Bug 1:browser_screenshot 100% 复现——截图字节被硬编码为 image/png 存库,毒死整个会话
现象
AI 调用 browser_screenshot 后:
- 工具结果返回一条图片附件引用:
{ mediaType: "image/png", bytes: 87349, width: 820, height: 582 }(第二次测试:bytes: 82935);
- 但实际存入 DSH 附件库的字节是 JPEG(magic
FF D8 FF DB),解析出的真实尺寸是 52×70(第二次 108×48)——与引用完全不符;
- 该引用进入会话历史后,任何包含它的模型请求(包括后续轮次)都在附件解析阶段失败,DSH 将其包装为
DeepSeek API stream from https://api.deepseek.com failed (code: TRANSPORT),重试策略 5/5 全部失败(每次约 0.5s 内即失败),会话从此无法继续——失败是确定性的,与网络无关(同一时刻其它会话的模型请求均正常)。
两次独立测试均复现(一次"任务完成时收尾截图",一次"任意任务中截图"),概率 100%。
代码定位(lib/index.mjs)
trySaveScreenshot()(约 L906–L917):保存时硬编码 mediaType: "image/png",完全不校验 bsk screenshot 实际返回的字节格式:
return await attachments.saveImage({ data, mediaType: "image/png", name });
browser_screenshot 工具(约 L1738–L1770):
- 临时文件扩展名硬编码
.png(bsk-screenshot-${Date.now()}-...png,--out 也是 .png);
- 返回给模型的图片引用同样硬编码
mediaType: "image/png",且 width/height 直接取 reply.width/height(bsk 报告的视口尺寸),与实际字节无关。
复现步骤
- 安装
@wxg-prc-cpg/browser-skill-dsh-plugin@0.1.1,确保 bsk CLI + 扩展连接正常;
- 任意 DSH 会话中让模型执行一个浏览器任务并调用
browser_screenshot;
- 观察:截图工具返回后,下一次模型请求立即出现
DeepSeek API stream from https://api.deepseek.com failed(TRANSPORT),重试 5/5 失败;之后所有轮次均失败。
证据
- 会话记录(zstd 分帧 jsonl):两次调用后的 tool/result 分别引用
sha256:79d3e829…(声称 image/png 820×582)和 sha256:4228a140…(声称 image/png);各自紧随其后的 finish: error …TRANSPORT × 6(首次 + 5 次重试)。
- 附件库实际字节:
79d3e829…:JPEG(FF D8 FF DB),87,349 B,SOF0 52×70;
4228a140…:JPEG(FF D8 FF DB),82,935 B,SOF0 108×48。
- DSH 侧告警:
AttachmentError: Stored attachment metadata does not match its reference.(dsh-attachment-local 的 readImageFile 校验输出)。
期望 / 修复建议
trySaveScreenshot / browser_screenshot:对 bsk 输出的实际字节做格式探测(magic / 解码结果),以探测值写入 mediaType/width/height;无法确认时不要附加图片(降级为仅返回路径);
- 建议 bsk 侧一并确认:
bsk screenshot --out x.png 输出的就是 PNG(本次观察到输出为 JPEG 且是 52×70 / 108×48 的小图,与视口 820×582 不符,疑似输出了缩略图/预览帧而非全尺寸截图)——若 bsk 端输出格式可控,请保证与扩展名一致。
Bug 2:PiP 观察预览窗口("browser unavailable")弹出后无法关闭,会话失败后卡死
现象
- 浏览器任务运行期间,插件会显示一个浏览器观察悬浮层(ObservationOverlay);
- 点击其中的 "Pop out into a mini window" 后,以浏览器 Document Picture-in-Picture 打开独立小窗,实时显示浏览器缩略帧;
- 会话模型请求失败(见 Bug 1)后,该小窗变为:标题栏红色圆点 + "browser unavailable",内容区保留最后一帧("last frame kept");预览框卡死且没有任何关闭入口——没有关闭按钮、点击无效、独立于 DSH 主窗口(关闭/刷新主界面也关不掉),只能整体重启。
代码定位(lib/client.cjs)
pipApi() / popOut()(约 L3564 / L3907–L3919):使用 documentPictureInPicture.requestWindow({ width, height }) 创建窗口,随后 cloneStylesInto(win),仅监听 win.addEventListener("pagehide", …) 清理;
- 核心问题:弹出 PiP 后所有关闭/退回入口都被置空(约 L3930–L3932):
onPopOut: pipWindow === null && pipApi() !== void 0 ? () => void popOut() : void 0,
onCollapse: pipWindow === null ? () => setCollapsed(true) : void 0,
onHeaderPointerDown: pipWindow === null ? beginMove : void 0
即 PiP 窗口内没有任何关闭(win.close())或返回浮动卡片的按钮;
- 会话失败 / bsk 观察通道断开后,store 不再更新(
available=false → "browser unavailable",thumb 停在 "last frame kept"),窗口渲染停摆、看起来"卡死"。
复现步骤
- 运行任意浏览器任务,出现 ObservationOverlay;
- 点击 "Pop out into a mini window";
- 令会话失败(例如触发 Bug 1 的
browser_screenshot);
- 观察:PiP 小窗显示 "browser unavailable" + 保留最后一帧,无法通过任何 UI 操作关闭。
期望 / 修复建议
- PiP 窗口内提供关闭按钮(调用
pipWindow.close())或"回到浮动卡片"入口,不要只在 pipWindow === null 时展示操作;
available=false / 会话 dead 状态下:显示可关闭/重连的状态,而非停留在不可操作的"last frame kept";
- 建议确认 Document PiP 窗口生命周期与主窗口的关系(主窗口关闭时是否随之销毁;当前表现为独立残留)。
附件:本地证据速查
| 证据 |
内容 |
| 附件对象 1 |
sha256:79d3e8293c1746d1710b8b87c2a62ae99012b2c0a27fce1351ed379597978c9f(JPEG 52×70,被标为 PNG 820×582) |
| 附件对象 2 |
sha256:4228a140df28101dd47c80b96db7a9b4459ea2a17d4edb494ee104abef48e804(JPEG 108×48,被标为 PNG) |
| 插件版本 |
@wxg-prc-cpg/browser-skill-dsh-plugin@0.1.1 |
环境信息
@wxg-prc-cpg/browser-skill-dsh-pluginv0.1.1(经 dshmarket 安装到 web profile)packages/dsh-plugin-browserskillBug 1:
browser_screenshot100% 复现——截图字节被硬编码为image/png存库,毒死整个会话现象
AI 调用
browser_screenshot后:{ mediaType: "image/png", bytes: 87349, width: 820, height: 582 }(第二次测试:bytes: 82935);FF D8 FF DB),解析出的真实尺寸是 52×70(第二次 108×48)——与引用完全不符;DeepSeek API stream from https://api.deepseek.com failed (code: TRANSPORT),重试策略 5/5 全部失败(每次约 0.5s 内即失败),会话从此无法继续——失败是确定性的,与网络无关(同一时刻其它会话的模型请求均正常)。两次独立测试均复现(一次"任务完成时收尾截图",一次"任意任务中截图"),概率 100%。
代码定位(
lib/index.mjs)trySaveScreenshot()(约 L906–L917):保存时硬编码mediaType: "image/png",完全不校验bsk screenshot实际返回的字节格式:browser_screenshot工具(约 L1738–L1770):.png(bsk-screenshot-${Date.now()}-...png,--out也是.png);mediaType: "image/png",且width/height直接取reply.width/height(bsk 报告的视口尺寸),与实际字节无关。复现步骤
@wxg-prc-cpg/browser-skill-dsh-plugin@0.1.1,确保 bsk CLI + 扩展连接正常;browser_screenshot;DeepSeek API stream from https://api.deepseek.com failed(TRANSPORT),重试 5/5 失败;之后所有轮次均失败。证据
sha256:79d3e829…(声称 image/png 820×582)和sha256:4228a140…(声称 image/png);各自紧随其后的finish: error …TRANSPORT× 6(首次 + 5 次重试)。79d3e829…:JPEG(FF D8 FF DB),87,349 B,SOF0 52×70;4228a140…:JPEG(FF D8 FF DB),82,935 B,SOF0 108×48。AttachmentError: Stored attachment metadata does not match its reference.(dsh-attachment-local的readImageFile校验输出)。期望 / 修复建议
trySaveScreenshot/browser_screenshot:对 bsk 输出的实际字节做格式探测(magic / 解码结果),以探测值写入mediaType/width/height;无法确认时不要附加图片(降级为仅返回路径);bsk screenshot --out x.png输出的就是 PNG(本次观察到输出为 JPEG 且是 52×70 / 108×48 的小图,与视口 820×582 不符,疑似输出了缩略图/预览帧而非全尺寸截图)——若 bsk 端输出格式可控,请保证与扩展名一致。Bug 2:PiP 观察预览窗口("browser unavailable")弹出后无法关闭,会话失败后卡死
现象
代码定位(
lib/client.cjs)pipApi()/popOut()(约 L3564 / L3907–L3919):使用documentPictureInPicture.requestWindow({ width, height })创建窗口,随后cloneStylesInto(win),仅监听win.addEventListener("pagehide", …)清理;即 PiP 窗口内没有任何关闭(
win.close())或返回浮动卡片的按钮;available=false→ "browser unavailable",thumb停在 "last frame kept"),窗口渲染停摆、看起来"卡死"。复现步骤
browser_screenshot);期望 / 修复建议
pipWindow.close())或"回到浮动卡片"入口,不要只在pipWindow === null时展示操作;available=false/ 会话dead状态下:显示可关闭/重连的状态,而非停留在不可操作的"last frame kept";附件:本地证据速查
sha256:79d3e8293c1746d1710b8b87c2a62ae99012b2c0a27fce1351ed379597978c9f(JPEG 52×70,被标为 PNG 820×582)sha256:4228a140df28101dd47c80b96db7a9b4459ea2a17d4edb494ee104abef48e804(JPEG 108×48,被标为 PNG)@wxg-prc-cpg/browser-skill-dsh-plugin@0.1.1