Introduction

When developing agents in DeepSeek Harness (DSH), you often encounter an awkward problem: the main model is a pure text model, but users send screenshots to the conversation. dsh 0.1.1+ has built-in fallbacks for this situation—the request won’t error, but the model can only see an image placeholder and cannot actually see the image content. To make the model truly answer based on the image, you either have to switch the main model or write a layer of forwarding logic yourself.

dsh-image-vision-bridge solves this problem: it automatically sends images from user messages to the vision model (default is mimo-v2.5 on the opencode-go router), feeds the returned text description to the main text model, and keeps the chat history showing the original image. DSH’s philosophy is “everything is a plugin,” and capabilities like image understanding can be filled by plugins. Below is an introduction to its principles, installation, and configuration.

What is it

dsh-image-vision-bridge is a DSH host plugin maintained by Icestab, licensed under MIT, with the current version being 0.1.2. It operates on the llm/stream pipeline: it replaces image blocks (including tool-result nesting) in requests sent to the main model with text descriptions generated by the vision model, constructing a rewritten request without modifying the original request object or session logs.

It declares dsh.bundle, a standard distributable bundle, which automatically inserts the plugin line during installation without requiring manual editing of cordis.patch.yml. The plugin does not modify the DSH installation, does not write to the DSH directory, and does not touch session logs.

Core Features

  • Pipeline Rewriting: Replaces image blocks (including tool-result nesting) in the main model request on the llm/stream pipeline with text descriptions generated by the vision model mimo-v2.5, without modifying the original request object or session logs.
  • Keep Original Images in Chat: Images are passed to the agent and written to session logs as-is; the chat history displays the images sent by the user; descriptions only enter the model, not the chat.
  • In-process Cache: Description results are cached by attachment ID, preventing repeated calls to the vision model for retries and subsequent turns.
  • Failure Fallback: Falls back to a failure explanation text when the vision call fails, without interrupting the conversation; errors are thrown normally when the user cancels.
  • Multiple Installation Methods: Supports npm / GitHub / Local directory / tarball installation, and also provides manual flat installation without using dsh plugin.
  • Configurable Options: enabled, provider, model, maxTokens, maxDescriptionChars, prompt.

Installation and Enablement

Standard Installation

This package is a standard bundle and can be installed with a single dsh plugin add command. For GitHub, you can lock the version:

dsh plugin --profile web add github:Icestab/dsh-image-vision-bridge#c67b4b3

You can also use the npm package name, local directory, or tarball:

dsh plugin --profile web add dsh-image-vision-bridge              # npm
dsh plugin --profile web add ./dsh-image-vision-bridge            # Local directory
dsh plugin --profile web add ./dsh-image-vision-bridge-0.1.0.tgz  # tarball

Essential Configuration: Let the Main Model Declare Image Support

This step cannot be done by the plugin. The host API boundary (dsh-host-apiproxy) validates the message against the current model’s input modality. If the main model does not declare input containing image, image messages will be rejected directly, and the client will prompt “Current model does not support images.”

First, edit $DSH_HOME/settings.yaml (you can also maintain this via the Models page in the Web UI; the file supports hot reload and no restart is needed), and add modelOverrides for the main model under llm-pi-ai.providers.<router>:

llm-pi-ai:
  providers:
    opencode-go:
      modelOverrides:
        deepseek-v4-pro:
          input: [text, image]

This declaration simply allows the API boundary to pass: the plugin replaces the image with a text description on the pipeline, so the image block will not actually appear in the main model request.

Then restart dsh web — the web profile has HMR disabled, so the plugin changes only take effect after a restart.

Manual Flat Installation (Optional)

If you don’t want to use dsh plugin, you can first copy the package directory to the profile’s module resolution path:

cp -r ./dsh-image-vision-bridge "$DSH_HOME/profiles/node_modules/"

Then add the plugin line in $DSH_HOME/profiles/<name>/cordis.patch.yml:

- insert:
    - id: image-vision-bridge
      name: 'dsh-image-vision-bridge'
      config:
        provider: opencode-go
        model: mimo-v2.5

The modelOverrides configuration in settings.yaml is also a prerequisite. Restart dsh web after changing it. Note: If you run dsh plugin add/install in the profile later, pnpm might clean up this manually placed directory. Simply re-run the cp command above to restore it.

Configuration

The six configuration options serve the following purposes: when enabled is set to false, it fully passes through without bridging; provider is the LLM router where the vision model is located (must be configured in llm-pi-ai.providers in settings.yaml); model is the vision model ID; maxTokens limits the maximum output token for the vision call; maxDescriptionChars limits the description length before injecting it into the main model; prompt is the instruction sent to the vision model. By default, it uses mimo-v2.5 on the opencode-go router and reuses OPENCODE_GO_API_KEY.

The bundle’s default configuration can be overridden in the profile’s own cordis.patch.yml by the line ID image-vision-bridge (the later one wins). Custom example:

- insert:
    - id: image-vision-bridge
      name: 'dsh-image-vision-bridge'
      config:
        model: mimo-v2.5
        maxTokens: 4096
        prompt: 'Describe this image in English, including all visible text.'

Self-test

After installation, you can run an offline self-test first to confirm the plugin works correctly in your current environment:

cd "$DSH_HOME/profiles"
node node_modules/dsh-image-vision-bridge/test/transform.test.mjs

The author has tested on DeepSeek Harness 0.1.0-rc.6 and 0.1.1-rc.2 (@deepseek-ai/dsh, dsh-llm same version, cordis 4.0.1), and all 11 offline self-tests passed. The plugin’s peerDependencies are @deepseek-ai/cordis ^4.0.1 and @deepseek-ai/dsh-llm ^0.1.0-rc.6, both optional.

Applicable Scenarios and Notes

Applicable Scenarios

  • The main model is fixed as a pure text model (e.g., deepseek-v4-pro), but users send screenshots/photos and expect the model to answer based on image content;
  • You want the chat history to show original images without intermediate text like “image parsing result”;
  • There is already a configured LLM router capable of calling a vision model in the environment.

Usage Notes

  • Non-official usage promise: The plugin rewrites requests entering the pipeline, while framework documentation requires listeners to be read-only. Before upgrading dsh, it is recommended to smoke test in a temporary profile — sending one image is enough.
  • Complementary to built-in fallback: dsh 0.1.1+ built-in image placeholder fallback does not error but the model cannot see image content; this plugin provides real visual descriptions; they are complementary.
  • Runtime permissions: The plugin runs with the permissions of the current dsh process. It is recommended to check the source code and license before installing (this project is MIT).

Summary

dsh-image-vision-bridge does a single thing: turns images into text descriptions, allowing a pure text main model to handle image input without polluting the chat history. If you already have a usable vision model router in your DSH environment, installing the plugin, adding a modelOverrides line, and restarting dsh web will get it running.

  • GitHub: https://github.com/Icestab/dsh-image-vision-bridge
  • Community Directory: https://www.skillhub.cn/plugins/Icestab/dsh-image-vision-bridge