ysr666/dsh-vision-router
ysr666/dsh-vision-router为纯文本 Agent 提供视觉能力:内置免 Key 视觉链 + 像素级视觉工具(看图问答、定位、裁剪、像素对比、取色、OCR、矢量化、抠图、截图);粘贴图片即可用。
本地 Windows 引擎(Windows.Media.Ocr)识别附加图片:只把识别出的文字发送给模型,图片字节不进入上下文;视觉直通可选开启。
English | 简体中文
DeepSeek Harness (dsh) plugin that lets text-only models accept attached images: every image is recognized locally with the built-in Windows OCR engine (Windows.Media.Ocr) and only the recognized text is sent to the model API.
Privacy default: image bytes are OCR'd locally and not sent to the provider. Set passthrough: true only if you intentionally want genuine vision models to receive original image bytes.
input: [text, image] hacks in settings.yaml.passthrough: true).image).dsh plugin --profile web add dsh-windows-ocr
(Replace web with your profile, e.g. tui.) Prebuilt and published with Sigstore provenance — no source build or allowBuilds approval needed. Installing from source (this repo) still works via the agent guide or the manual steps below.
or from the repository / a tarball:
dsh plugin --profile web add ./dsh-windows-ocr # source checkout
dsh plugin --profile web add ./dsh-windows-ocr-0.8.0.tgz
dsh plugin --profile web add github:maxwell-feng/dsh-windows-ocr
Git installs fetch sources, not built artifacts: the package's
preparescript runstscto rebuildlib/from source, and pnpm ≥ 10 requires you to allow the build once (it prints the exactpnpm-workspace.yamlsnippet).
npm install registers the
windows-ocrrow by itself. The package ships a bundle patch (dsh.bundle+ its owncordis.patch.yml) that inserts thewindows-ocrloader entry. Do not also add a manual- insert:row with the same id to your profile — dsh0.1.5-rc.2(cordis-plugin-loader1.0.2) rejects duplicate loader entry ids anddsh webfails to boot withduplicate loader entry id: windows-ocr.
Hand this repository to any AI agent, or paste the instruction below, and the agent will install and verify the plugin for you:
Please install the dsh plugin in this repository by following https://github.com/maxwell-feng/dsh-windows-ocr/blob/main/agents-install.md. Run every preflight check, choose an install mode, then complete the mandatory verification: attach an image to a text-only model session and confirm the model answers with the recognized text.
agents-install.md is a step-by-step guide written for
AI agents: preflight checks, both install modes (permanent profile patch /
temporary --patch overlay), mandatory functional verification, and
troubleshooting for the failure modes you are likely to hit. Manual install
instructions are below.
dsh skills are Markdown instruction files injected into the model context — they cannot execute code, cannot hook the request pipeline, and cannot stop an image from being serialized. This feature needs exactly that, so it is a cordis plugin that hooks two public seams of the llm service:
ctx.llm.resolveModelInfo (also listModels). The host gates image attachments on inputModalities.includes("image") at three places: message admission, model switching, and the read_image tool. The shim answers "yes", so text models admit images.agent/pre-step, the harness's official seam for replacing the messages that enter a model call ("Reject a proposed step or replace the messages that enter it"). Every image content block is replaced with an OCR text block before the request is built, so no attachment bytes are ever serialized and no image_url is ever built. It covers every dispatch path — ctx.llm.stream and prepareCall().stream both build from the step's messages; wrapping adapter.stream no longer works because the bundled adapters override prepareCall() and dispatch through generation-bound closures.you attach an image
→ admission asks ctx.llm.resolveModelInfo (shimmed: "image" ✓)
→ image stored in the local attachment store (session log, UI preview)
→ agent loop proposes a step → agent/pre-step (rewritten)
→ image block read locally (ctx.attachments.readImage) → Windows OCR
→ block replaced with <image_ocr>…text…</image_ocr>
→ request built from OCR'd messages → adapter serializes text only → provider
dsh with a profile (tested against dsh 0.1.5-rc.2)agents-install.md in this repository is a
step-by-step installation guide written for AI agents (and careful
humans). Give it to an agent — e.g. "install this plugin per
agents-install.md from https://github.com/maxwell-feng/dsh-windows-ocr" —
and the agent can perform the preflight checks, install, verification, and
troubleshooting on its own. The guide covers both install modes, the
mandatory functional verification (attach an image → model answers with the
OCR text), and the failure modes you are likely to hit.
Two official ways to load this plugin, both referencing the plugin file by
absolute path (see docs/user/develop/basic). On Windows the path must be
a file:// URL — a bare C:/... path is parsed as the c: URL scheme and
the loader rejects it.
Append to your profile's cordis.patch.yml (e.g. ~/.dsh/profiles/web/cordis.patch.yml):
- insert:
- id: windows-ocr
name: 'file:///C:/absolute/path/to/windows-ocr/lib/index.js'
config:
language: ''
passthrough: false
Then restart dsh web. Remove the rows to uninstall — the plugin restores the original llm / adapter methods on unload.
Choose one way to load the plugin: the npm bundle (above) or this manual insert — never both. Both register the same
windows-ocrentry id, and dsh0.1.5-rc.2fails the boot withduplicate loader entry id: windows-ocrwhen the row exists twice. If the row is already present (for example after an npm bundle install), configure it with an id-targeted override (see Configuration below) instead of inserting a second row.
--patch overlayPut the same rows in an overlay file and boot with it; your profile stays untouched:
dsh --profile web --patch C:/path/to/overlay.yml
dsh web fails with EADDRINUSE on port 3080 when an older instance is
still running: find it with netstat -ano | findstr :3080 and stop it
(taskkill /PID /F) before starting a new one.github:user/repo), package the
plugin as a bundle (dsh.bundle + cordis.patch.yml, see
docs/user/develop/basic/publish); a git install additionally needs a
prepare build script and pnpm allowBuilds consent.To verify the plugin loaded, look for windows-ocr in the boot logs, or check the OCR smoke test below.
All settings live in the patch row windows-ocr (cordis.patch.yml here) and can be overridden from your profile's cordis.patch.yml. Configuration is validated at load time (Schemastery Config schema) — an invalid value fails the boot with an actionable error instead of being silently ignored:
| Key | Default | Meaning |
|---|---|---|
language | "" | BCP-47 tag for Windows OCR, e.g. zh-Hans, en-US. Empty = user profile languages. |
passthrough | false | false (default): OCR every image. true: genuine vision models receive images untouched. |
ocrScript | bundled lib/ocr.ps1 | Absolute path override for the PowerShell OCR script. |
timeoutMs | 60000 | Per-image OCR timeout. |
maxCacheEntries | 200 | Bound on the per-run OCR cache (keyed by attachment id). |
Example override in ~/.dsh/profiles/web/cordis.patch.yml — an id-targeted
row (not insert:) replaces the existing windows-ocr row's config:
- id: windows-ocr
config:
language: zh-Hans
Attach any image to a text-model session and send a message — the plugin intercepts agent/pre-step, OCRs the image locally via Windows.Media.Ocr, and replaces the image block with a text block before the request is built. No code or model-config changes needed; every provider/model in dsh benefits.
Each image block becomes a text block (local filenames are not forwarded):
<image_ocr>
…recognized lines…
</image_ocr>
Recognition text is cached per attachment id for the lifetime of the dsh process, so repeated turns do not re-run OCR.
Every OCR run writes its input image and output text into a fresh temporary
directory (windows-ocr-* under the system temp dir). The directory is
removed automatically in finally — on success, on OCR error, and on timeout —
so no per-run script, image, or output file survives. At plugin start, any
orphaned windows-ocr-* directories left behind by a previously crashed
process are swept as well. Nothing is written outside the plugin's own
temporary directory and the dsh attachment store.
# 1x1 PNG — exercises WinRT loading, language availability, recognition
powershell.exe -NoProfile -ExecutionPolicy Bypass -File lib/ocr.ps1 -ImagePath test.png -OutFile out.txt
Get-Content out.txt
Exit code 0 with an empty/whitespace out.txt means the OCR engine works (a 1×1 image has no text). Exit 2/3 means a language pack is missing.
text content parts (no image_url / data URI).dsh plugin --profile web remove dsh-windows-ocr
For manual installs, delete the windows-ocr row from your profile's cordis.patch.yml and restart dsh --profile web. The plugin restores the original llm shims on unload; a full restart is safest after removal. After uninstall, text-model image attachments are refused again (fail-closed).
maxCacheEntries.agent/pre-step listener and restores the llm capability shims on unload. A full restart is still the safest path after any dsh update.listModels is shimmed consistently).MIT