🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

视觉桥接 GooDAnDReaDY/dsh-vision-bridge

DeepSeek Harnessv0.6.19
GooDAnDReaDY13 天前有提交已提供中文文档扫描:含敏感能力

为 DeepSeek Harness 打通通用视觉:原生模型处理附件,40+ 工具,支持 PDF、OCR、图表。

31.5/100
综合分
2
GitHub 星标
766
npm 周下载
—/5
用户评分

数据截至 2026/10/22 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add @goodandready/dsh-vision-bridge
npm 源 · @goodandready/dsh-vision-bridge 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · vision
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 13 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包@goodandready/dsh-vision-bridge @ 0.6.19
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 09:36:35

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 67 处,展示前 54 条)
  • 读取本地文件
    lib/index.js:91
    readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
  • 发起网络请求
    lib/client.js:496
    const res = await fetch('/dsh-vision-bridge/config', {
  • 发起网络请求
    lib/client.js:507
    const res = await fetch('/dsh-vision-bridge/models', { cache: 'no-store' })
  • 发起网络请求
    lib/client.js:527
    const res = await fetch('/api/dsh-vision-bridge/update', {
  • 发起网络请求
    lib/client.js:546
    const res = await fetch('/api/dsh-vision-bridge/update', {
  • 发起网络请求
    lib/client.js:693
    const [cfg, list, ch] = await Promise.all([api('GET'), fetchModels(), fetch('/dsh-vision-bridge/channels', { cache: 'no-store' }).then((r) => r.json()
  • 发起网络请求
    lib/client.js:773
    const res = await fetch('/dsh-vision-bridge/channels', {
  • 读取本地文件
    lib/updater.js:62
    if (!existsSync(entry)) return undefined;
  • 读取本地文件
    lib/updater.js:65
    if (existsSync(manifestPath)) {
  • 读取本地文件
    lib/updater.js:67
    const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
  • 发起网络请求
    lib/updater.js:139
    const response = await fetch(`${registry.replace(/ $/, '')}/${encodeURIComponent(packageName)}/latest`, {
  • 读取本地文件
    lib/updater.js:153
    const value = JSON.parse(await readFile(manifestUrl, 'utf8'));
  • 执行外部命令来自配置/变量
    lib/updater.js:181
    const child = spawn(process.execPath, args, {
  • 执行外部命令来自配置/变量
    lib/process.js:16
    const child = execFile(bin, args, { timeout, signal, maxBuffer, encoding: 'utf8' }, (error, stdout, stderr) => {
  • 写入本地文件
    lib/storage.js:9
    writeFileSync(probePath, 'probe')
  • 读取本地文件
    lib/storage.js:10
    const ok = readFileSync(probePath, 'utf8') === 'probe'
  • 删除本地文件
    lib/storage.js:11
    unlinkSync(probePath)
  • 读取本地文件
    lib/storage.js:44
    if (existsSync(defaultDsh)) {
  • 写入本地文件
    lib/tools/ocr.js:69
    writeFileSync(tmpFile, src.bytes)
  • 删除本地文件
    lib/tools/ocr.js:76
    bestEffort('ocr.unlink', () => unlinkSync(tmpFile))
  • 写入本地文件
    lib/tools/ocr.js:161
    writeFileSync(inFile, src.bytes)
  • 删除本地文件
    lib/tools/ocr.js:168
    bestEffort('ocr.unlink', () => unlinkSync(inFile))
  • 读取本地文件
    lib/tools/document.js:62
    const frames = existsSync(dir) ? readdirSync(dir).filter((f) => frameRe.test(f)).sort() : []
  • 读取本地文件
    lib/tools/document.js:62
    const frames = existsSync(dir) ? readdirSync(dir).filter((f) => frameRe.test(f)).sort() : []
  • 读取本地文件
    lib/tools/document.js:66
    const bytes = readFileSync(join(dir, f)); bestEffort('vision_pdf_pages.unlink', () => unlinkSync(join(dir, f)))
  • 删除本地文件
    lib/tools/document.js:66
    const bytes = readFileSync(join(dir, f)); bestEffort('vision_pdf_pages.unlink', () => unlinkSync(join(dir, f)))
  • 读取本地文件
    lib/tools/media.js:10
    if (!existsSync(out) || r.code !== 0) {
  • 读取本地文件
    lib/tools/media.js:14
    const bytes = readFileSync(out)
  • 删除本地文件
    lib/tools/media.js:15
    bestEffort('media.unlinkViewportShot', () => unlinkSync(out))
  • 写入本地文件
    lib/tools/media.js:195
    writeFileSync(targetPath, src.bytes);
  • 读取本地文件
    lib/tools/media.js:216
    for (let i = 1; i <= n; i++) { const f = join(dir, `${stem}-${String(i).padStart(2, '0')}.jpg`); if (existsSync(f)) outFrames.push(f) }
  • 读取本地文件
    lib/tools/media.js:221
    const bytes = readFileSync(f); bestEffort('media.unlinkFrame', () => unlinkSync(f))
  • 删除本地文件
    lib/tools/media.js:221
    const bytes = readFileSync(f); bestEffort('media.unlinkFrame', () => unlinkSync(f))
  • 读取本地文件
    lib/tools/media.js:244
    if (!existsSync(out)) {
  • 读取本地文件
    lib/tools/media.js:248
    const bytes = readFileSync(out); bestEffort('media.unlink', () => unlinkSync(out))
  • 删除本地文件
    lib/tools/media.js:248
    const bytes = readFileSync(out); bestEffort('media.unlink', () => unlinkSync(out))
  • 写入本地文件
    lib/tools/media.js:509
    writeFileSync(inHtml, htmlContent, 'utf8')
  • 删除本地文件
    lib/tools/media.js:534
    if (existsSync(inHtml)) unlinkSync(inHtml)
  • 删除本地文件
    lib/tools/media.js:535
    if (existsSync(outPdf)) unlinkSync(outPdf)
  • 读取本地文件
    lib/tools/attach.js:188
    let frames = existsSync(dir) ? readdirSync(dir).filter((f) => frameRe.test(f)).sort() : []
  • 读取本地文件
    lib/tools/attach.js:188
    let frames = existsSync(dir) ? readdirSync(dir).filter((f) => frameRe.test(f)).sort() : []
  • 读取本地文件
    lib/tools/attach.js:201
    items.push({ bytes: readFileSync(file), contentType: 'image/png', name: f.replace(stem + '-', 'page-') })
  • 删除本地文件
    lib/tools/attach.js:204
    for (const f of frames) { bestEffort('attach.unlinkFrame', () => unlinkSync(join(dir, f))) }
  • 读取本地文件
    lib/tools/attach.js:245
    if (existsSync(f)) files.push(f)
  • 读取本地文件
    lib/tools/attach.js:250
    for (const f of files) items.push({ bytes: readFileSync(f), contentType: 'image/jpeg', name: f.split('/').pop() })
  • 删除本地文件
    lib/tools/attach.js:252
    for (const f of files) { bestEffort('attach.unlinkFile', () => unlinkSync(f)) }
  • 读取本地文件
    lib/tools/attach.js:295
    try { names = readdirSync(dirPath).filter((f) => IMAGE_RE.test(f)).sort() } catch (err) { getPluginLogger().debug('[dsh-vision-bridge] readdirSync fai
  • 读取密钥环境变量
    lib/security.js:35
    || process.env.DSH_AUTH_TOKEN
  • 读取密钥环境变量
    lib/security.js:36
    || process.env.DSH_TOKEN
  • 发起网络请求
    lib/channels.js:62
    const res = await fetch(baseURL.replace(/ v1 ?$/, '') + '/api/tags', {
  • 发起网络请求
    lib/channels.js:196
    const res = await fetch(url, { method: 'POST', headers, body, signal: mergeSignal(timeoutMs, signal) })
  • 发起网络请求
    lib/channels.js:248
    const res = await fetch(baseURL + '/chat/completions', {
  • 发起网络请求
    lib/channels.js:329
    const res = await fetch(baseURL + '/chat/completions', {
  • 发起网络请求
    lib/channels.js:429
    const res = await fetch(channel.baseURL, {
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/dsh-llm@deepseek-ai/dsh-attachment@deepseek-ai/dsh-agent@deepseek-ai/dsh-host-webserver
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 原生模型处理附件
  • 支持PDF与OCR
  • 图表解析
v0.6.222026-10-21
核心领域解耦与模块化 (#438) 领域拆分:把原先庞大的 lib/vision-core.js(1317 行)拆成 4 个高内聚、低耦合的模块: - lib/vision-config.js(338 行):配置 Schema(Config)、wrapConfig、plainConfig、插件元数据(name、inject),以及模型能力判定(sanitizeAllowed、shouldBridgeForModel、acceptsImages、blocksHaveImage)。 - lib/security.js(439 行):设置鉴权(isTrustedSettingsRequest、isLoopbackAddress)、API 密钥脱敏与稳定标签生成(deriveKeyLabel)、路径穿越防御(resolveInside、isPathAllowed)、SSRF 防御(safeFetch、isSafeFetchUrl、isPrivateIp)、脱敏辅助函数,以及请求体限长读取(readBoundedBody)。 - lib/providers.js(33 行):服务商定义(FREE_VISION_PROVIDERS)与密钥解析(resolveChannelApiKey)。 - lib/media-utils.js(504 行):Sharp 图像变换(compressImage、stripEXIF、deskewImage、enhanceImage)、OCR(runLocalOCR)、图像检查、感知哈希(contentHash、pHash),以及会话级附件隔离(SessionScopedAttachmentMap)。 透明且向后兼容的门面:lib/vision-core.js 缩减为 14 行门面,100% 重导出全部符号(48 个导出),现有工具、路由和测试零破坏。 严格行数预算:所有手写模块严格满足 <= 600 行上限。 验证:新增 test/438_vision_core_domains.test.js。145 个测试套件共 509 项测试 100% 通过。Preflight:FAIL=0 WARN=5。 提交对应关系 Gitea 提交:e8ffc72ed7b8dd062492f39257e8ce358a329fa5 镜像提交:c56d230fcafb6d24c7e7c5e8dddbe27a0c494bd5
v0.6.212026-10-15
· 客户端插槽现代化与存储目录限制 (#435) · 设置插槽现代化:从 lib/client.js 移除已废弃的 settings.plugin.item 插槽注册。设置卡片现在只绑定 DSH 的现代活动席位:plugins.row.config(行席位)和 plugins.item(插件列表席位)。 · 存储目录限制:在 lib/storage.js(resolveStorageDir)里用 resolveInside 把相对路径 evidenceDir 限制在插件的基础存储目录内,防止目录遍历逃逸(../..)。 · 完整回归测试:新增 test/issue-435-audit-dead-slot-storage.test.js,验证废弃插槽已移除、存储目录边界限制生效。全套 505 项测试(145 个测试套件)全部通过。 · 提交对应关系 · Gitea 提交:547fa4e5d4294f162cc6feef6928e761077a6cdd · 镜像提交:fb93090239edb736a6eedfc4a79d0acaa519930a
v0.6.202026-10-12
· 频道配置持久化错误处理与回滚保护 (#432) · 设置持久化错误传递:在 POST /dsh-vision-bridge/channels (lib/routes/config.js) 中不再静默吞掉持久化失败。scope.set('channels', ...) 失败时改用 logger.error 记录日志,并返回 HTTP 500 和详细错误信息。 · 内存配置回滚:频道持久化失败时,把内存里的 config.channels 回滚到变更前状态,避免状态不一致,也避免重启后丢数据。 · 持久化状态反馈:HTTP 200 的频道保存响应新增 persisted: Boolean(...) 字段,调用方和 Web UI 可据此确认是否真正写入存储。 · Web UI 诊断与反馈:Web UI 检查频道配置响应里的 persisted 标志,存储不支持持久化时提醒用户,中英文文案均已补齐。 · 回归测试:在 test/issue-410-channels-persistence.test.js 中新增完整测试用例,覆盖错误传递、回滚和日志调用。全部 499 项测试通过。 · 提交对应关系 · Gitea 提交: ccf93085c36052569c110a1a08422edaf89906c6 · 镜像提交: c11af2a57c3c3eaa7b7a365e7a0e95d76f67a41f
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
📦 @goodandready/dsh-vision-bridge DeepSeek Harness 通用视觉桥接插件:为纯文本模型提供无缝多模态图像支持 🇬🇧 English • 🇷🇺 Русский • 🇨🇳 中文说明 ⭐ 如果您喜欢这个插件,请在 GitHub 上为它点亮 Star — 这能让我知道插件对您有用,并鼓励我继续开发和维护它。 🐛 如果您发现 Bug 或希望增加功能,请使用任意语言在 GitHub 上提交 Issue — 我会评估您的建议,并在后续版本中实现有价值的改进。 ⚡ 概述与核心解决问题 在 DeepSeek Harness 中与纯文本聊天模型(任何仅接受文本的 provider/model)对话时,用户无法直接在聊天窗口附加和发送图片: 1. 在 DSH 0.1.2-alpha.2+ 中,后端会话控制器进行严格的模态校验 (ctx.llm.resolveModelInfo)。如果当前对话模型的 inputModalities 中不包含 'image',请求会被直接拒绝并报错 session/attachment-invalid ("Model does not support image input")。 2. 纯文本适配器如果直接接收到多模态图像块,会抛出请求错误。
展开完整文档(README 剩余 1 节)
📦 @goodandready/dsh-vision-bridge

DeepSeek Harness 通用视觉桥接插件:为纯文本模型提供无缝多模态图像支持

🇬🇧 English •
🇷🇺 Русский •
🇨🇳 中文说明

⭐ 如果您喜欢这个插件,请在 GitHub 上为它点亮 Star — 这能让我知道插件对您有用,并鼓励我继续开发和维护它。

🐛 如果您发现 Bug 或希望增加功能,请使用任意语言在 GitHub 上提交 Issue — 我会评估您的建议,并在后续版本中实现有价值的改进。

⚡ 概述与核心解决问题

在 DeepSeek Harness 中与纯文本聊天模型(任何仅接受文本的 provider/model)对话时,用户无法直接在聊天窗口附加和发送图片:

1. 在 DSH 0.1.2-alpha.2+ 中,后端会话控制器进行严格的模态校验 (ctx.llm.resolveModelInfo)。如果当前对话模型的 inputModalities 中不包含 'image',请求会被直接拒绝并报错 session/attachment-invalid ("Model does not support image input")。
2. 纯文本适配器如果直接接收到多模态图像块,会抛出请求错误。

dsh-vision-bridge 解决方案

dsh-vision-bridge 在 Cordis 运行时内建立透明代理:
* 服务端模态桥接 (v0.5.3+):自动包装 ctx.llm.resolveModelInfo 和 ctx.llm.listModels,使会话网关允许所有模型接收图像附件。
* 自动图像改写 (agent/pre-step 与 llm/stream):自动拦截图片,调用所配置的视觉模型(目录中的 provider/model,或本地 OpenAI 兼容端点)生成描述,并将图片替换为文本提示 [用户上传了图片。内容描述:...] 传递给纯文本模型。
* 原生直通 (Native Passthrough):自动识别原生支持视觉的模型并直接传递图像,无需重复转换。
* 约 40 个专用视觉工具:提供 OCR、目标定位 (grounding)、UI 结构解析、表格/公式提取、二维码识别、UI 流程重建与多模型共识等完整工具套件。

🏗️ 架构图

graph LR
User["用户在 Web UI 上传图片"] --> Gateway["DSH 会话控制器"]
Gateway --> BridgeCheck{"模态桥接 (v0.5.3)"}
BridgeCheck -->|"inputModalities 扩展 image"| SessionAllowed["网关放行请求"]
SessionAllowed --> Hook["agent/pre-step 钩子"]

Hook --> CheckNative{"对话模型是否原生支持视觉?"}
CheckNative -->|"是 (Native Passthrough)"| NativeLLM["直接传递原始图像"]
CheckNative -->|"否 (纯文本模型)"| VisionRouter["视觉桥接通道"]

VisionRouter --> VisionModel["专用视觉模型\n(DSH / OpenAI / Ollama / Webhook)"]
VisionModel --> Description["生成文字描述与 OCR"]
Description --> Rewrite["将图片替换为文字描述标记"]
Rewrite --> ChatModel["将增强文本发送给对话模型"]
ChatModel --> Answer["助手在聊天窗口返回答案"]

✨ 核心特性

1. 运行模式

* hybrid (默认):对话中自动改写图片为文本描述,同时保留约 40 个工具供模型显式调用。
* llm:纯自动改写模式;工具依然可供调用。
* tools:禁用自动改写,必须由模型显式调用 describe_image 等工具。

2. 多通道故障转移 (Multi-Channel Fallback)

支持多视觉后端级联、故障熔断与并发竞速:
* dsh-catalog:自动或手动选择 DSH 中已注册的视觉模型。
* openai-compatible:支持 vLLM、SGLang、OpenRouter 等 OpenAI 兼容视觉接口。
* ollama:自动发现并调用本地 Ollama 实例提供的任意视觉模型。
* webhook / custom:外部 HTTP / JSON-RPC 服务。

3. LRU 响应缓存

基于 hash(bytes + prompt + model + mode) 的内存缓存,避免重复分析相同图片,节省 Token 开销。

4. 完整工具清单(约 40 个工具)

| 工具类别 | 工具 | 说明 |
| 核心 | describe_image, read_image, inspect_image | 通过附件 ID、文件路径或 URL 进行通用图像分析。 |
| 几何与检测 | vision_ground, vision_crop, vision_detect, vision_compare, vision_present | 边界框坐标(0–1000 刻度)、目标清单、多图对比。 |
| OCR 与文本 | vision_ocr, vision_ocr_local, vision_long_ocr, vision_trace, vision_colors, vision_extract_foreground | 文字识别、本地 Tesseract OCR(离线)、长截图拼接、SVG 描摹、调色板。 |
| 结构化与界面 | vision_describe_structured, vision_vqa, vision_ui_layout, vision_translate_image | JSON 结构输出({summary, ocr, layout, entities})、简短 VQA、界面区块分析。 |
| 像素与诊断 | vision_pixel_diff, vision_quality_check | 语义化视觉差异、质量评分(模糊/曝光)。 |
| 文档与智能 | vision_extract_formula, vision_extract_table, vision_scan_barcode, vision_extract_structured, vision_audit_accessibility | 公式(LaTeX)、表格(Markdown/HTML)、二维码/条码识别、JSON Schema 抽取、WCAG 无障碍审计。 |
| 场景、共识与记忆 | vision_ui_flow, vision_consensus, vision_memory_search | 用户旅程图(Mermaid)、多模型共识、已记住图片的语义检索。 |
| 附件(v0.5.33) | vision_attach_pages, vision_attach_frames, vision_attach_images | 将 PDF 页面、视频帧、本地/远程图片作为会话附件发布,供原生视觉模型直接查看。 |

📦 安装方法

dsh plugin --profile web add @goodandready/dsh-vision-bridge

安装完成后重启 DSH Web UI。配置卡片位于 设置 → 插件 → vision-bridge。

⚙️ 配置示例 (settings.yaml)

dsh-vision-bridge:
mode: hybrid
visionProvider: ""
visionModel: ""
nativePassthrough: prefer
cacheEnabled: true
cacheMaxEntries: 200
timeoutMs: 120000
channels: []
channelFallback: sequential
hideRedundantTools: true # 当聊天模型本身已能看图时隐藏桥接工具 attachMaxItems: 8 # 单次 attach 调用可发布的页面/帧/文件数

参数说明

| 参数 | 类型 | 默认值 | 说明 |
| mode | string | "hybrid" | 处理模式(hybrid、llm、tools)。 |
| visionProvider | string | "" | 视觉服务的 provider ID(留空 = 自动选择)。 |
| visionModel | string | "" | 视觉模型 ID(留空 = 自动选择)。 |
| nativePassthrough | string | "prefer" | 原生视觉模型的处理方式(prefer、never、always)。 |
| hideRedundantTools | boolean | true | 当聊天模型原生支持图片时,对该 agent 隐藏补偿类工具,仅保留扩展工具。 |
| attachMaxItems | number | 8 | 单次 vision_attach_ 调用最多发布的图片数(PDF 页面、视频帧、文件)。硬上限 32。 |
| cacheEnabled | boolean | true | 是否启用描述结果的 LRU 缓存。 |
| cacheMaxEntries | number | 200 | 内存中缓存的条目上限。 |
| timeoutMs | number | 120000 | 执行超时(毫秒)。 |
| channelFallback | string | "sequential" | 通道调度方式(sequential、parallel-race);顺序由 channelOrderMode 决定。 |

📝 v0.5.30 中的变更

安全与诚实性发布。面向用户的简要总结:

SSRF 抓取策略:模型提供的图片 URL(describe_image 的 urls、inspect_image 以及 headless-chrome 工具)只能通过策略层抓取——非 http(s) 协议、localhost 名称以及私有/回环/链路本地主机(包括 IPv4 映射 IPv6 和 NAT64)在每一次重定向跳转中都会被拒绝;响应体有大小上限。新设置 allowedUrlHosts(精确主机名白名单)可显式放行内部端点。
* apiKeyRef:通道可以按名称引用凭据服务条目或环境变量——settings.yaml 中不再需要明文 apiKey。现有的内联 apiKey 继续有效;保存时掩码密钥的保留按通道标识匹配,而非数组位置。
* 路由防护:POST /bench、POST /batch、DELETE /batch/:id、DELETE /journal、DELETE /cache 与其他变更类路由一样要求同源。GET /doctor 默认为静态;仅 ?probe=1 时进行通道探测(需要同源)。
* 设置诚实性:maskPII、stripEXIF、auditLog、consensusEnabled 已端到端生效。此前仅具装饰性的 blurFaces、nsfwFilter、tileLargeImages/tileThreshold 开关和无效的 Local/Cloud/LM Studio 预设已被移除。Changed in v0.5.30:如果您曾依赖它们,请注意它们从未产生过效果。
* 英语为源语言:所有用户可见字符串均为英语;捆绑的俄语字典已移除——运行时的俄语由翻译插件提供。
* 核心拆分:纯内核(配置模式 + 辅助函数)移至 lib/vision-core.js;lib/index.js 对其进行重新导出——API 无变化。修复了 v0.5.13 中 describe_image 返回空描述的回归;vision_annotate 恢复工作;pHash 缓存不再混淆相似图片。

📝 v0.5.31 中的变更

维护版本——用户行为无变化。

* 内部结构:工具注册已迁移到 lib/tools/ 领域模块(core / grounding / ocr / document / analysis / media);lib/index.js 像以前一样重新导出所有内容。文件更小,宿主与工具领域之间的依赖显式化。
设置卡片加固:容错的 locale 注册、移除冗余的侧边栏回退、通过安全的 ctx.get 包装访问插件服务、/config 接受扩展字段集(cacheMaxEntries、channelFallback)。

📝 v0.5.32 中的变更

稳定性与架构版本。

* 内部结构:全部约 44 个工具注册迁移到 lib/tools/ 领域模块(core / grounding / ocr / document / analysis / media),依赖显式传递;lib/index.js 仍为主机入口。
稳定性修复:完成的批处理记录在 10 分钟轮询窗口后释放(修复内存增长);/upload-pdf 拒绝超过新设置 maxPdfBytes(默认 20 MiB)的负载;vision_memory_search 按每个附件自身的描述评分;移除宿主死代码;日志标签一致化。
* 设置:新增 maxPdfBytes(上传硬上限)。

📝 v0.5.33 中的变更

以原生视觉为核心的版本:桥接不再只服务纯文本模型,也服务本身能看图的模型。

* 附件域(vision_attach_pages、vision_attach_frames、vision_attach_images):PDF 页面、抽取的视频帧以及来自文件、目录和 URL 的图片会作为会话附件发布,原生视觉模型直接查看像素,无需再支付一次视觉调用。图片按 imageMaxWidth/imageMaxHeight/imageQuality 压缩并受 maxImageBytes 限制;URL 走与其他路径相同的 SSRF 策略,本地路径受 allowedImageDirs 限制。
* 按模型决定工具集:当聊天模型本身支持图片时,对该 agent 隐藏桥接的补偿类工具,仅保留扩展工具;纯文本路由则相反——隐藏附件工具,因为这类模型看不到附件。该行为由新设置 hideRedundantTools 控制(默认开启)。
* 配置卡片新增设置:Attachments 分组提供 attachMaxItems(整数 1–32,默认 8,即单次 attach 调用发布的图片数)与 hideRedundantTools。保存时会校验,超出范围会给出明确错误。图片尺寸字段现在也会写入实时设置快照,而不只是路由。
* Batch API:DELETE /batch/:id 可立即释放已完成的批量任务,与 start/cancel 使用相同的同源保护。批量记录的 TTL 定时器不再让短生命周期进程挂住,测试套件因此从 10 分钟降到约 3.5 秒。
* tools 模式:聊天中附加的图片现在会在净化门之前建立索引,因此按附件 ID 工作的工具(以及 read_image 别名)在 tools 模式下同样可用;此前这些 ID 在该模式下不可用。
* 修复:单个不可读来源不再中断 vision_attach_images,而是记为 Skipped N: <名称>: <原因>,其余来源照常附加;fetch 策略拒绝仍然是硬错误。PDF 文本层现在真正生效(此前 pdftotext 一直未被识别,文本层静默缺失)。被上限截断的页码范围或帧数会在 truncated 与提示中体现。
* 内部:CI 无需 sudo 安装 poppler、每个提交只跑一次、按 ref 串行,并为帧测试安装 ffmpeg;仓库新增 PR 模板并忽略 .worktrees/。

📝 v0.6.0 中的变更

重大稳定性、可靠性及生命周期升级版本。

* 应用内一键自动更新:新增专用更新端点(/api/dsh-vision-bridge/update)以及设置卡片中的控件(settings.plugin.item 中的 UpdaterBlock)。支持实时检查 npm 最新版本、显示更新状态和重启提示,并受到环回(loopback)与 CSRF 源验证的严格安全保护。
* 错误韧性与消除空 catch:全面审查并替换了核心运行时和所有工具中的全部 76 个未标注空 catch 块。引入 bestEffort(label, fn, fallback) 辅助函数用于安全的非关键副作用,并在图像预处理中显式传递降级告警(smartOptimizeImage 返回 preprocessed: boolean 和 warnings: string[])。
* Scoped 作用域名称一致性:在 package.json、Cordis 补丁、客户端模块加载器及内核元数据中统一保持 @goodandready/dsh-vision-bridge。
* 加固设置安全校验:设置保存路由升级为严格的 fail-closed 校验器(isTrustedSettingsRequest),强制校验环回来源、CSRF 头与 Bearer Token,并拒绝可疑的外部转发请求头。
* 原生主题 CSS 变量支持:客户端诊断和卡片样式完全迁移至 DSH 设计系统变量(--dsw-alias-),移除了所有硬编码颜色值。
净化的公开仓库发布流程:集成基于 Git 底层命令的发布脚本(publish.sh)及 .gitattributes 导出过滤器,确保公开 GitHub 镜像和 npm 归档中不包含任何内部开发文件。

📝 v0.6.2 中的变更

可靠性加固、错误可见性与降级告警版本。

* 真实 bestEffort 追踪:彻底移除所有虚拟 /* bestEffort ... / void err,错误由 bestEffort(label, fn) 捕获并通过 console.debug 输出。
工具降级告警 (warnings):所有工具模块在 output.schema 中声明 warnings: string[],当模型 JSON 解析异常或降级时透明反馈。
* 预处理故障捕获:图片倾斜校正、增强、EXIF 清除与压缩中的异常被记录为 warnings 并传递给调用方。
* 完整测试验证:新增 test/issue-314-besteffort-warnings.test.js 测试集,总测试用例达到 329 个(104 个套件,100% 通过)。

📄 开源许可

MIT © GooDAnDReaDY
预览分享卡片长什么样 ↓GooDAnDReaDY/dsh-vision-bridge
分享 · DeepSeek Harness Hub
GooDAnDReaDY/dsh-vision-bridge

为 DeepSeek Harness 打通通用视觉:原生模型处理附件,40+ 工具,支持 PDF、OCR、图表。

这是你的仓库?认领条目

回到顶部