Gives a text-only model image understanding via a vision-language model, exposed as a `describe_image` tool.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:DamonKoy/dsh-web-ui#path:/packages/dsh-tool-describe-image
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 中文
Model-facing describe_image tool: gives text-only models (DeepSeek V4 etc.) image understanding.
Each call loads one image — a local file path, an http(s) URL, or a session attachment reference —
and asks an OpenAI-compatible vision endpoint (Qwen-VL, GLM-4V, GPT-4o, a local Ollama endpoint…) to
answer over the Chat Completions or Responses protocol; only the returned text enters the
conversation, the image itself never enters the session log.
Ported from deepseek-harness packages/vision/tool-describe-image (mirrored at
whitelonng/dsh-plugin-describe-image),
adapted to the dsh-web-ui family conventions: official NPM SDK only, host-side plugin with a
browser half, live settings, no dsh source changes.
Capabilities
| Capability | Description |
|---|---|
| Three inputs | Local absolute path, http(s) URL (redirects refused), an [image attachment …] JSON note, or the short markdown reference a drag/paste produces ( — the model passes the id from the URL; the in-process attach registry resolves it and the store's digest verification still runs) |
| Direct image send | Dragging or pasting an image into a text-only session is rewritten at send time into a describe-image reference () instead of an image block the model cannot read, so the image renders in the conversation and the model analyzes it through the tool |
| Custom instructions | The prompt argument carries your precise instruction (OCR, chart reading, UI diagnosis, translation…); the defaultPrompt config sets the fallback when the model passes none |
| Live config card | Settings → Plugin config → Web UI Plugins → "Image understanding" card edits baseURL / apiStyle / model / API key / default instruction / bounds (through the settings seam); effective immediately, no restart |
| Protocol styles | apiStyle: chat-completions (default) posts to baseURL/chat/completions; apiStyle: responses posts to baseURL/responses with input / max_output_tokens and reads output_text |
| Raw image route | GET /describe-image/raw/<id> serves the stored bytes (loopback-only, content-addressed id) so the pasted reference renders in the conversation |
| Per-call key resolution | Inline apiKey → credential seam (apiKeyEnv, default VISION_API_KEY) → launch environment, tiered fallback |
| Safety and bounds | All requests refuse redirects; maxBytes / maxOutputTokens / timeoutMs caps; magic-byte type gate; bounded error excerpts (200 chars); keys never logged |
| Canonical return | { text, model, image, mimeType, bytes } — the model only sees text |
Security model
- Vision requests and image downloads both refuse HTTP redirects (
redirect: 'error'); bearer credentials and image bytes never reach a source other than the configured deployment. - The request body carries the base64 image but no key; request headers and resolved credentials are not logged.
- Only
http(s)URLs and local paths are accepted; every other URL scheme is rejected. - The attach route validates base64, magic bytes, and the byte bound before the attachment store persists anything; only the reference JSON (text) crosses into the conversation.
- Response bodies are truncated at the cap (
maxOutputTokens * 8 + 64 KiB) before parsing.
Installation
Install the family aggregate @linxin666/dsh-web-ui-all (all plugins and skins in one package), or this plugin alone:
# Recommended: install directly from npm
dsh plugin --profile web add @linxin666/dsh-tool-describe-image
The aggregate mounts this plugin without configuration: loading is unaffected, and the first call
fails with a clear error (describe-image: baseURL must be an absolute http(s) URL) until configured.
Fill in the endpoint and model on the "Image understanding" card under Settings → Plugin config to
start immediately, no restart needed. (Difference from upstream: upstream validates eagerly at load;
the family aggregate has no config entry, so validation is eager only when a composition entry
actually configures it and per-call otherwise.)
Configuration
| Key | Default | Meaning |
|---|---|---|
baseURL |
— (required) | OpenAI-compatible endpoint root (e.g. https://dashscope.aliyuncs.com/compatible-mode/v1); trailing slashes stripped |
apiStyle |
chat-completions |
Protocol style: chat-completions appends /chat/completions; responses appends /responses (OpenAI Responses API input / max_output_tokens / output_text shapes) |
model |
— (required) | Vision model id |
apiKey |
— | Inline key for local debugging; prefer !!js process.env.VISION_API_KEY over a hardcoded secret |
apiKeyEnv |
VISION_API_KEY |
Credential reference (environment-variable name); empty string disables reference resolution |
defaultPrompt |
see source | The instruction used when a call omits its prompt — tune it to your workload (OCR, UI review, translation…) |
maxBytes |
10485760 |
Image byte bound (local files and downloads alike) |
maxOutputTokens |
1024 |
Output-token cap: max_tokens under chat-completions, max_output_tokens under responses |
timeoutMs |
60000 |
Per-call vision request timeout |
Configured mount example (profile cordis.patch.yml / composition file):
- id: describe-image
name: '@linxin666/dsh-tool-describe-image'
config:
baseURL: https://dashscope.aliyuncs.com/compatible-mode/v1
model: qwen-vl-max
apiKey: !!js process.env.VISION_API_KEY
Endpoints exposing only the Responses API set apiStyle: responses:
- id: describe-image
name: '@linxin666/dsh-tool-describe-image'
config:
baseURL: https://api.openai.com/v1
apiStyle: responses
model: gpt-4o-mini
apiKey: !!js process.env.VISION_API_KEY
Usage
Custom instructions
The tool takes a prompt argument: tell the vision model exactly what you need — "transcribe all
text", "extract the table as CSV", "diagnose the UI layout problems", "translate the text into
Chinese". A targeted instruction beats a generic description; the tool description steers the
text model toward passing one. Calls without a prompt fall back to defaultPrompt.
Sending images directly
Text-only models have no image entry in the DSH input box, so drag or paste an image into the
composer: at send time the plugin rewrites the image-bearing send into a describe-image reference
() instead of an image block the model cannot read — the
image renders in the conversation and the model analyzes it through the tool. The bytes travel to
the host /describe-image/attach route (validated for size and magic bytes, persisted in the
attachment store); only the reference text enters the session log.
Known limitations
- Only the magic-byte gate checks the type; the image is not decoded, so a header-valid but corrupt file fails only at the vision endpoint.
- One image per answer: no multi-image input, no follow-up on the previous image, no structured output (coordinates / boxes).
- Extracting text still costs one VLM call: OCR-only deployments can point
baseURLat a cheaper OCR model. - OpenAI-compatible protocol only: Chat Completions (
/chat/completions) and Responses (/responses) are supported; vendors with other request/response shapes need separate adapters.
Source and copyright
- Source: ported from whitelonng/dsh-plugin-describe-image
(deepseek-harness
packages/vision/tool-describe-image), moved in 2026-08; tests ported with the source (pnpm --filter @linxin666/dsh-tool-describe-image test). - Copyright: the original code belongs to its authors (deepseek-ai / whitelonng); this repository only hosts and maintains it and claims no copyright; the ported contribution is licensed by its contributor under the family license.
- License: the family is licensed under Apache-2.0 (repository root LICENSE); this
package's
licensefield isApache-2.0.
Links
More in this category
liustack/modlens★ 4100
Vision bridge for text-only models: paste an image, get structured JSON evidence (OCR, layout, semantics).
ysr666/dsh-vision-router★ 1128
Free vision for text-only agents: built-in keyless vision chain plus pixel tools (Q&A, grounding, crop, pixel diff, colors, OCR, SVG trace, cutout, screenshots); paste an image to use it.
Anionex/dsh-vision-toolkit★ 887
Vision for text-only models: paste an image and the model switches to a Vision Toolkit variant for image Q&A, multi-image comparison, long-screenshot OCR, screenshot-to-UI reproduction, element grounding, and pixel diff. No API key by default — images are processed by the author-hosted free service, 100 per machine per day; configurable to your own provider.
dickpy/dsh-imagegen★ 99
AI image generation for the DSH Web GUI: text-to-image and image-to-image through a configurable OpenAI-compatible endpoint (gpt-image-2 / gpt-image-1 / dall-e-3), with an api_url/api_key settings card and a sidebar split-pane generation studio.
fandc520/dsh-comfyui★ 94
Drive a local or remote ComfyUI server from DeepSeek Harness: comfyui_run / comfyui_object_info / comfyui_workflow tools generate and edit images and videos, with a workflow library (graph extraction: per component / main flow / all), a load area with resolution auto-match, a live queue, SDXL and Wan 2.1 templates, a companion skill, and a same-origin media proxy.
sunxin-ai/dsh-design-qa★ 44
Design-fidelity QA for text-only models: a `deepseek_vision` tool borrows an eye from any OpenAI-compatible vision route, so the model can judge whether an implementation matches its mock — shipped with the benchmark behind that judgement (four fixtures, 23 injected defects, raw transcripts) and the questioning discipline it depends on.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.