DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

lmh-2026 /

lmh-2026/dsh-periscope

Verified

DSH plugin: keep text-only DeepSeek models (V4-Flash / V4-Pro) and auto-route image-bearing requests to the official vision model (deepseek-v4-flash-vision-exp) - no manual model switching.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@8bd6f825

🔭 dsh-periscope

让 DSH Desktop 的纯文本模型也能「看」图,并把任意文件拖进对话交给 agent 读取。


DSH Desktop Windows Node.js License MIT

Stars Forks Issues


文件附件卡片


🇨🇳 简体中文 · English


✨ 特性

能力 说明
🔀 视觉自动路由 纯文本会话里贴图,无需手动切换——含图请求自动改派官方视觉模型 deepseek-v4-flash-vision-exp,文字请求零开销走文本模型
📎 通用文件附件 原版只收图片;本插件支持拖入/粘贴任意文件(docx/xlsx/pdf/txt/zip…)→ 附件卡片 → 落盘 → agent 按路径读取
🗂️ 文件类型图标 附件卡片按扩展名显示彩色类型方块(Word 蓝 W / Excel 绿 X / PDF 红 P…)
💾 持久化落盘 文件保存到 ~/.dsh/attachments/v1/files/,会话历史保留附件块与完整绝对路径
🛡️ 崩溃修复 修复文件草稿发送/删除时 Cannot read properties of undefined (reading 'startsWith')
🧩 随包核心补丁 6 个核心文件的替换清单 + 一键原位重打包器,改的是 DSH 桌面端核心

⚠️ 开关说明:两种功能、两套机制(重要)

很多用户会困惑「DSH 插件列表里的滑块开关为什么管不住文件附件」。因为这两个功能挂在完全不同的两层:

功能 挂在哪一层 怎么生效 滑块开关(启用中)管得到吗
🔀 视觉路由 dsh-periscope 插件 bundle DSH 启动时按插件列表加载 ✅ 管得到——开关切换的就是它
📎 文件附件 DSH 核心 6 个包(app.asar 内) 用 install.ps1 给 app.asar 原位打补丁,一经打包即固定 ❌ 管不到

为什么?

  • 视觉路由是插件:它通过 DSH 的插件系统在运行时加载。插件列表的滑块开关,控制的就是「dsh-periscope 插件是否被加载」,所以只影响视觉路由。
  • 文件附件是核心补丁:DSH 核心的 session.prompt wire 校验 schema 是 dsh-host-apiproxy 模块内部常量,第三方插件在运行时无法扩展。要给 DSH 增加「任意文件」能力,只能直接修改核心,而 app.asar 是一次性打包的——它不属于插件的运行时开关范畴。

实际表现:

  • 文件附件是否生效,只取决于 app.asar 是否被打过补丁(有没有跑过 install.ps1)。跟滑块开关无关:打过补丁 → 关掉滑块文件附件照样生效;没打过 → 滑块开再大也没用。
  • 滑块开关在「插件列表里」看到的效果仅限视觉路由那一半。

✅ 所以滑块开关不是「没用」,而是它只管视觉路由;文件附件需用 install.ps1 打 app.asar 补丁。这两件事要分开看待。


🚀 一键安装(推荐)

只适配 DSH Desktop 桌面客户端(以单个 app.asar 打包核心的形态)。请在 Windows 上操作,且每次 DSH 升级后都要重做一次。

本插件已发布到 npm:dsh-periscope@0.3.4。仓库根目录自带一个一键安装脚本 install.ps1,它会一次性完成「安装 bundle + 修正确版本号 + 重打包 app.asar」,用户不必手工拆两步。

方式 A:从 GitHub 仓库(zip / clone)

# 1) 完全退出 DSH Desktop
# 2) 进入仓库目录(解压 zip 或 clone 后的目录),运行:
Set-ExecutionPolicy -Scope Process Bypass -Force
.\install.ps1

方式 B:从 npm 安装

npm install dsh-periscope
npx dsh-periscope-install

也可以直接用 DSH 的插件入口:

dsh plugin add dsh-periscope@0.3.4     # 精确版本 → 插件列表正确显示版本

脚本会自动做这几件事:退出检测 → 备份 app.asar → 以精确版本 dsh plugin add dsh-periscope@<ver> 安装/更新 bundle(把依赖从 ^0.2.0 修正为 ^0.3.3,从而让 DSH 插件列表正确显示版本)→ 用已安装包内的 scripts/repack-inplace.mjs 对 app.asar 做原位重打包(注入 6 个补丁核心文件,保留原生模块)→ 校验 + 提示重启。

  • 手动指定版本 / profile:.\install.ps1 -Version 0.3.3 -Profile desktop
  • 离线(不走 npm registry):.\install.ps1 -FromLocal

⚠️ 关键点:插件列表显示的是本地安装版本。此前停在 0.2.0 是因为依赖写成了 ^0.2.0(^0.2.0 = >=0.2.0 <0.3.0,永远够不到 0.3.x)。用精确版本安装即可绕过该限制,让版本号正确显示。

3. 重新打开 DSH

拖入 / 粘贴一个非图片文件,即可看到带类型图标的附件卡片;发送后 agent 会按路径读取它。DSH 插件列表应显示 dsh-periscope v0.3.3。


📖 工作原理

文件附件功能位于 DSH 核心包(wire 协议、附件存储、composer、模型适配器),而核心校验 schema 是 dsh-host-apiproxy 模块内部的常量,第三方插件运行时无法扩展——因此本插件随包携带对桌面端核心的补丁。

拖入/粘贴任意文件 📎
  → composer 附件卡片(类型图标 + 文件名 + 大小,可删除)
  → 发送:文件字节(base64) 作为 {type:"file"} 部件随 prompt 上送
  → host 校验并落盘:~/.dsh/attachments/v1/files/<sha256>-<文件名>
  → 会话持久化:{type:"file", file:{name, size, path, …}} 内容块(历史渲染附件卡片)
  → 模型请求:file 块投影为文本
      [附件:名称(大小)\n完整路径:<绝对路径>\n请读取该文件内容后继续。]
  → agent 用文件工具按路径读取并处理 🔧

为什么不是把文件直接发给模型? DeepSeek 官方 Files API 仅支持 JPEG/PNG/GIF/WebP 图片,非图片文档无法直接送入模型。路径式消费是 agent 架构下的等价体验(Codex 同款做法):文件真实落盘,agent 用 read/bash/pwsh 等工具读取。

默认限制(可通过 dsh-attachment-local 配置调整):单文件 20 MiB、单条消息 20 个文件、单条合计 200 MiB;客户端与 host 双重校验。


🛠️ 配置

官方 DeepSeek 无需任何设置即开箱即用:

字段 默认值 说明
provider deepseek-official 承载模型的路由 provider
textModels ["deepseek-v4-flash", "deepseek-v4-pro"] 含图请求会被路由到视觉模型的文本模型
visionModel deepseek-v4-flash-vision-exp 含图请求使用的视觉模型

在 profile 的 cordis.patch.yml(用户层会整体替换该行配置)覆盖:

- id: periscope
  config:
    provider: deepseek-official
    textModels: [deepseek-v4-flash, deepseek-v4-pro]
    visionModel: deepseek-v4-flash-vision-exp

该 provider 的模型目录需同时包含这些文本模型与一个声明了 image 输入的视觉模型(DeepSeek 目录已满足)✅


📁 仓库结构

路径 说明
patches/manifest.mjs 6 个核心文件的 old→new 替换清单(约 30 处,供审查/演进)
patches/asar-patched/ 已打补丁的 6 个核心文件(重打包时直接打进 app.asar)
scripts/repack-inplace.mjs 原位重打包:只替换 6 个文件,保留其余文件字节与原生模块结构
scripts/apply-file-attachments.ps1 一键入口:退出检测 → 备份 → 重打包 → 校验
scripts/patch-core.mjs apply / revert / verify / diff(面向松散核心的历史方式)
lib/ · cordis.patch.yml 插件本体与 DSH 补丁声明

涉及的 6 个核心包:@deepseek-ai/dsh-attachment、dsh-attachment-local、dsh-host-apiproxy、dsh-llm-deepseek、dsh-client-ui-conversation、dsh-client-ui-attachment。


❓ FAQ

Q:DSH 升级后文件附件不能用了? A:正常。DSH 每次升级都会重新打包 app.asar,功能随之失效。重新运行一次 apply-file-attachments.ps1 即可(升级前先备份 app.asar)。

Q:用官方 asar extract→pack 行不行? A:不行。naive 的 extract→pack 会孤立 unpacked 原生模块(conpty / sharp / koffi),导致 DSH 无法启动。请使用仓库自带的原位重打包器。

Q:支持 Web / CLI / 源码形态吗? A:不支持。本插件只适配 DSH Desktop 桌面端以单个 app.asar 打包核心的形态。

Q:为什么非图片文件要 agent 按路径读,而不是直接发给模型? A:DeepSeek 官方 Files API 只接受图片。路径式消费是 agent 架构下的等价体验。

Q:node 路径找不到? A:脚本内置了 DSH runtime 与 Codex runtime 两个候选;仍不行时改 scripts/apply-file-attachments.ps1 里的 $node。


⚠️ 风险与免责声明

本插件通过直接修改 DSH 桌面端的核心文件来工作,属于非官方行为。 请在使用前充分了解:

风险 说明
🔄 DSH 升级即失效 升级重新打包 app.asar,功能随之失效,需重跑脚本。
💥 损坏与不可启动 重打包有误或补丁与新版核心不匹配时 DSH 可能无法启动。脚本每次自动备份 app.asar → app.asar.bak。
🧩 内核不匹配 补丁针对编写时的核心版本;升级后替换项可能对不上,需按新版核心重新生成。
🔬 非官方行为 修改的是核心文件而非插件 API;DSH 官方不承诺稳定。
💾 本地落盘 附件明文保存到 ~/.dsh/attachments/v1/files/,路径与块会持久化,注意隐私与磁盘占用。
📎 非图片需 agent 读 非图片文档由 agent 按路径读取;read_image 工具自身的准入不受影响。
🧪 仅 Windows 桌面端 当前脚本面向 Windows + app.asar 形态。

还原方法(DSH 完全退出后运行):

Copy-Item "D:\DSH\DSH Desktop\resources\app.asar.bak" "D:\DSH\DSH Desktop\resources\app.asar" -Force

若 DSH 已无法启动,先还原备份;如首次运行无 .bak,直接到 DSH 官网重新下载覆盖安装。


🗺️ 路线图

  • 面向新版 DSH 核心的自动补丁重生成
  • 会话导出时打包附件字节
  • 支持更多平台的桌面端形态
  • 上游原生支持文件附件(长期方向)

🤖 关于 vibecoding

本项目全程由 AI 结对编程(vibecoding)完成:需求描述、实现、调试、核心 app.asar 重打包器、文档均由 AI 编码代理协作产出,作者负责验证与发布。欢迎 PR / Issue。


📣 加入交流群 / 支持项目

🐧 QQ 交流群:332689798(小鲸子TV)——欢迎扫码加入,提交 Bug、交流使用心得:

QQ 群二维码

⭐ 如果觉得好用,请给项目点个 Star 支持一下!你的反馈能帮助它变得更好。


📄 许可证

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 8bd6f825de8f

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout