DeepSeek Harness plugin

dsh-vision-bridge-yulee314

自包含的 DeepSeek Harness 视觉系统:DeepSeek 视觉孪生路由(原生图片体验 + 视觉桥请求层拦截)+ 本地 Ollama Agentic Vision 工具(describe/OCR/结构化扫描/区域查询/元素定位/双图对比/剪贴板)+ 粘贴分流(paste-to-path)。安装即用,无本机路径依赖。

Jump to install

Source facts

Repository
YuLee-314/dsh-vision-bridge
Latest update
Aug 16, 2026
Category
Models & Providers
GitHub stars
1
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/YuLee-314/dsh-vision-bridge
Plugin: dsh-vision-bridge-yulee314
Author: YuLee-314

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.mdSource · read only
README language

dsh-vision-bridge

A DeepSeek Harness plugin that lets text-only models receive and understand images. The vision work is done by a local model on your machine.

![Plugin](https://github.com/deepseek-ai/deepseek-harness) ![Version](#) ![License](LICENSE) ![Node](#) ![Platform](#)

English · 简体中文

---

What is this?

DeepSeek Harness (dsh) is an open-source AI coding environment built entirely from plugins. Its chat models — deepseek-v4-flash and deepseek-v4-pro — are text-only: their API rejects image data. As a result, in Harness you cannot paste a screenshot into a session that uses them, attach an image to a message, or use the built-in read_image tool.

This plugin fixes that. It works in three layers:

1. A second model route that accepts images. The same DeepSeek models are registered again as a "twin" provider (deepseek-vision). Because the twin declares image support, the normal image features work: pasting produces a thumbnail and an image block, and read_image is allowed. Before each request is sent to the DeepSeek API, the plugin converts every image in the conversation into a text description produced by a local vision model. The API only ever receives text; the model answers as if it had seen the image. 2. Nine inspection tools. describe_image, extract_text, structured_scan, query_region, detect_elements, locate_object, compare_images, read_clipboard, and check_health let the model look at an image at different levels of detail — from a general description down to per-element coordinates — and let you do the same through chat. 3. Paste routing. When you paste an image, a small browser component asks the server whether the current model can handle images. If yes (twin route), the paste stays a normal image. If no (official text-only route), the image is saved to a private local file and the path is inserted as text, which the inspection tools can then read.

The vision model (Ollama + qwen2.5vl) runs on your machine. No image bytes are ever sent to DeepSeek's API or to any cloud vision service.

If you only use the official route, the plugin still helps: pasted images become local paths and the inspection tools work on them. If you only want the tools, you can ignore the twin route entirely.

Table of Contents

  • [What is this?](#what-is-this)
  • [The Problem](#the-problem)
  • [The Solution](#the-solution)
  • [Features](#features)
  • [Architecture](#architecture)
  • [Interaction Logic](#interaction-logic)
  • [Installation](#installation)
  • [Usage](#usage)
  • [Configuration](#configuration)
  • [Vision Tools](#vision-tools)
  • [Project Structure](#project-structure)
  • [Security & Privacy](#security--privacy)
  • [Requirements](#requirements)
  • [Troubleshooting](#troubleshooting)
  • [License](#license)

---

The Problem

DeepSeek's flagship chat models (deepseek-v4-flash, deepseek-v4-pro) are text-only: their API endpoints cannot receive image bytes, and their model metadata declares inputModalities: ['text']. DeepSeek Harness builds on that metadata in three hard places:

GateLocationEffect
Composer admissionapi-proxy prompt handlerPasting an image is rejected: "the current model does not support images" — the image part never enters the conversation
read_image tooldsh-tool-fsRefuses to read an image into context unless the active route declares image input
Adapter serializerllm-deepseekCore image blocks are rejected (UNSUPPORTED_CONTENT) — images physically cannot reach the provider

Workarounds in the wild either fork presets (fragile), require cloud vision keys (Gemini etc.), or force you to switch to a weaker vision model for the whole session — losing DeepSeek's coding ability. None of them deliver what users actually want: DeepSeek, plus native image UX, plus the ability to see.

The Solution

One self-contained plugin, three cooperating layers:

1. Vision twin route (deepseek-vision) — the same DeepSeek models re-registered with inputModalities: ['text', 'image']. Every native gate opens: paste admission, thumbnails, durable image blocks, read_image. Under the hood the twin intercepts image blocks at the request layer, runs the local vision bridge, and forwards only text to DeepSeek's API. 2. Agentic vision tools — nine native tools (describe_image, structured_scan, query_region, ...) powered by a local Ollama vision model, with structured output, validation-with-retry, and content-addressed caching. 3. Paste router — a browser half that asks the host for a verdict based on real model metadata: vision-capable routes keep the native photo flow; text-only routes fall back to a local path so the bridge tools can take over.

Features

  • Native image experience for text-only models — paste a screenshot, get a thumbnail, image

block, and a DeepSeek that actually saw it, without a single image byte ever reaching the API.

  • No cloud keys required — the vision engine is local Ollama (qwen2.5vl); the twin reuses your

existing DEEPSEEK_API_KEY credential with the official route's own resolution logic.

  • Request-layer transparency — no prompt hacks, no preset forks, no dynamic injection that can

race; the interception happens in the adapter, exactly once, per request.

  • Structured output with coordinates — element bounding boxes ([0,1000] normalized), region

cropping, two-stage localization, image comparison, clipboard reads, schema-validated output with automatic retry on malformed responses.

  • Repeated images are cached — repeated images hit the content-hash cache: zero extra inference, stable

prefix-cache behavior.

  • Self-contained & distributable — a single 29 KB tarball with no machine-specific paths;

installs on any Harness via dsh plugin --profile web add.

  • Coexists with the official route — the official provider stays untouched as the fallback;

the paste verdict decides per session, from live metadata, which flow runs.

Architecture

┌──────────────────────────── Browser · client.js ────────────────────────────┐
│ paste / drop image                                                          │
│   → capture-phase listener (before the composer's own)                      │
│   → GET /vision-bridge/paste?model=<selector label>   (host verdict)        │
│        ├─ takeover:true   (confirmed text-only route)                       │
│        │    → POST bytes → host saves private temp file → path text         │
│        │      inserted into the composer; bridge tools take over            │
│        └─ takeover:false  (image-capable route)                             │
│             → native paste: image part + thumbnail, untouched               │
└─────────────────────────────────────┬───────────────────────────────────────┘
                                      ▼
┌──────────────────────── Host plugin · lib/index.js ────────────────────────┐
│  · POST /vision-bridge/paste → magic-byte sniff → 0600 temp file → {path}  │
│  · 9 tools registered into ctx.tools (native catalog, no mcp__ prefix)     │
│  · registerAdapter('deepseek-vision', VisionDeepSeekAdapter)               │
└──────────────┬───────────────────────────────────────────┬─────────────────┘
               ▼                                           ▼
     ┌────────────────────┐                  ┌──────────────────────────────┐
     │ vision-core         │                  │ VisionDeepSeekAdapter (twin) │
     │ · prepare/validate  │                  │ · listModels/resolveModel:  │
     │ · queue (serial)    │                  │   image-capable metadata     │
     │ · LRU cache         │                  │ · stream(): ImageBlock ──►   │
     │ · 9 tool handlers   │                  │   bridge analysis text ──►   │
     │                     │                  │   DeepSeek API (text-only)  │
     └──────────┬──────────┘                  └───────────────┬──────────────┘
                ▼                                              ▼
        Ollama · qwen2.5vl                        DeepSeek API · same endpoint,
        localhost · private · free                same credential as official

lib/core/ is the host-agnostic vision core shared with the author's MCP vision bridge (scripts/sync-core.mjs re-syncs it — one source of truth, two delivery forms).

Interaction Logic

1. Paste routing (per paste, decided by live model metadata)

Session modelVerdictWhat happens when you paste
DeepSeek-V4-Flash/Pro (视觉桥) (twin)takeover:falseNative photo: thumbnail + image block; the twin analyses it at the request layer
DeepSeek-V4-Flash (official)takeover:truePaste bytes → private temp file → path text; the model calls bridge tools on the path
Any future vision-capable routetakeover:falseNative paste preserved automatically — the verdict is evidence-based, never a name regex

The client caches verdicts per selector label (60 s TTL) and refreshes on focus, so the first paste of a session is already correct. Unknown metadata never hijacks a paste — the native path is the safe default.

2. Request-layer interception (vision twin only)

user pastes image ──► durable image block in session history
        │
        ▼
next model request ──► VisionDeepSeekAdapter.stream()
        │
        ▼
sanitize(): for every image block ──► attachments.readImage(bytes)
        │                                 │
        │                                 ▼
        │               write content-addressed file
        │               (~/.dsh/vision-bridge/images/<sha1>.png)
        │                                 │
        │                                 ▼
        │               vision-core.describe_image(path)   ← cache hit ⇒ zero inference
        │                                 │
        │                                 ▼
        │               text: [图片(视觉桥分析)] … + local path
        │
        ▼
text-only request ──► DeepSeek API (identical endpoint/credential as official route)
        │
        ▼
DeepSeek answers WITH the vision analysis; it may also call query_region / extract_text
on the embedded path for deeper, coordinate-accurate inspection.

3. Tool chain (evidence workflow)

structured_scan ──► element list with bboxes (heading/table/chart/button/…)
        │
        ├──► query_region(bbox) ──► the region is REALLY cropped and analyzed alone
        ├──► extract_text(with_coordinates) ──► OCR blocks with normalized coordinates
        └──► locate_object(desc) ──► coarse locate → crop ×1.3 → fine locate → full-image bbox

Installation

# 1. Prerequisites: Ollama running with a vision model (e.g. qwen2.5vl:7b),
#    and DEEPSEEK_API_KEY stored (for the twin route).

# 2. Install the plugin (any form works)
dsh plugin --profile web add .\dsh-external-dsh-vision-bridge-2.0.0.tgz   # tarball
#   dsh plugin --profile web add <directory>                             # checkout
#   dsh plugin --profile web add @yulee-314/dsh-vision-bridge            # npm

# 3. Restart dsh web (bundle layers load at boot)

Usage

1. In any session, open the model selector and pick: - DeepSeek (视觉桥) → DeepSeek-V4-Flash (视觉桥) — recommended: coding + native image UX, vision supplied by the bridge. - Official DeepSeek route — paste falls back to path text; bridge tools remain available. 2. Paste or drop an image. A thumbnail appears (twin) or a path is inserted (official). 3. Ask normally. DeepSeek answers from the bridge analysis; use query_region / extract_text for coordinate-level detail.

To make the twin the default for every new session:

# ~/.dsh/settings.yaml
agent-default-model:
  provider: deepseek-vision
  model: deepseek-v4-flash-vision
  reasoningEffort: max

Configuration

VariableDefaultPurpose
OLLAMA_BASE_URLhttp://127.0.0.1:11434/v1Vision engine endpoint (OpenAI-compatible)
OLLAMA_VISION_MODELqwen2.5vl:7b-q3_K_MVision model used by the bridge tools
OLLAMA_API_KEYollamaCompatible key for the engine
VISION_MAX_TOKENS / VISION_TEMPERATURE / VISION_MAX_RETRIES / VISION_CONCURRENCY8192 / 0.1 / 1 / 1Inference parameters
DEEPSEEK_API_KEYcredentials serviceTwin-route key — same source as the official route
DEEPSEEK_BASE_URLpublic APITwin-route endpoint — same resolution as the official route

Tool rows are disabled by setting pasteToPath: false on the bundle row if the paste router is undesired on a specific deployment.

Vision Tools

ToolWhat it does
describe_imageFull-image understanding in Chinese; accepts paths and URLs
extract_textOCR — plain text, or block-level JSON with normalized coordinates
structured_scanElement detection (heading/text/table/image/chart/formula/button/list) with bboxes + confidence, schema-validated
query_regionRegion-focused query — the region is really cropped before inference
detect_elementsBbox-only localization for selected element types
locate_objectTwo-stage localization: coarse full-image → ×1.3 crop → fine → full-image bbox
compare_imagesBefore/after visual regression: side-by-side composite, structured diff JSON
read_clipboardWindows clipboard image → exported PNG path
check_healthOllama reachability, model presence, config summary, cache size — zero inference

Project Structure

dsh-vision-bridge/
├── package.json              # dsh.bundle + dsh.client manifests, self-contained deps
├── cordis.patch.yml          # loader row (bundle layer)
├── client.js                 # browser half: paste interception + verdict protocol
├── README.md / README.zh-CN.md
├── scripts/sync-core.mjs     # re-sync lib/core from the MCP vision bridge
└── lib/
    ├── index.js              # host plugin: tools, paste route, adapter registration
    ├── deepseek-vision.mjs   # vision twin route (extends the official DeepSeek adapter)
    └── core/                 # host-agnostic vision core (vendored, self-contained)
        ├── vision-core.mjs   #   tools + prompts + retry/validation orchestration
        ├── image.js          #   preprocessing, crop, data URLs
        ├── validate.js       #   schema validation + retry hints
        ├── cache.js          #   content-hash LRU
        ├── queue.js          #   serial inference queue
        ├── errors.js         #   error taxonomy (ollama_down / model_not_found / …)
        ├── grounding.js      #   two-stage localization math
        ├── compare.js        #   side-by-side comparison composition
        └── clipboard.js      #   Windows clipboard reader

Security & Privacy

  • Images never leave your machine. The vision engine is localhost Ollama; the twin route

sends only the bridge's text analysis to DeepSeek's API.

  • Pasted bytes are magic-byte checked (PNG/JPEG/WebP/GIF), size-capped (25 MB), and stored 0600

in fresh unpredictable temp directories.

  • The twin reuses the official route's credential resolution — no second key, no plaintext config.
  • Paste hijacking is strictly evidence-based: without a positive text-only confirmation the native

path stays untouched.

Requirements

ComponentRequirement
DeepSeek Harnessweb profile, rc.5+ (tested on 0.1.0-rc.5)
Node.js≥ 22.19
Ollamarunning, with a vision model (tested: qwen2.5vl:7b)
API keyDEEPSEEK_API_KEY for the twin route (same as official)

Troubleshooting

SymptomCause / fix
Paste still inserts a path textThe session is on the official route — select the (视觉桥) variant, or check the latest verdict entry in ~/.dsh/vision-bridge-activity.jsonl for the real selector label
Tools report [ollama_down]ollama serve not running, or the model missing (ollama pull qwen2.5vl:7b)
Twin route fails with MISSING_CREDENTIALStore DEEPSEEK_API_KEY on the Web Models page or export it in the environment
read_image refuses on the twinOnly possible if the twin's metadata is not loaded — restart dsh after installing
Plugin changes not activeBundle layers load at boot; restart dsh web after dsh plugin operations

License

MIT. The vision core originates from the author's MCP vision bridge project.