tolten-image-attach
Attach an image to the DeepSeek Harness composer and the session model switches itself to a vision model — then restores your previous model when the image is removed. Material Design 3 button, native file picker, thumbnails. MIT.
- Stars
- 0
- Language
- JavaScript
- Created
- Sep 10, 2026
- Updated
- Sep 10, 2026
Introduction
🖼️ Tolten Image Attach
English · Español
Attach an image. The model switches itself to vision. Send.
A one-click, MD3 image attachment for the DeepSeek Harness composer — with automatic per-session vision-model routing.
Tolten Image Attach is a premium plugin for DeepSeek Harness that puts a compact Material Design 3 attach button in the composer tool row, and — the interesting part — switches your session to a vision model the moment you attach an image, then restores your previous model when the images are removed.
No more "I attached a screenshot but the text-only model can't see it."
🇲🇽 Hecho en México — crafted with pride by Ing. Oscar Emmanuel Martínez Galán · oe.martinez03@gmail.com
✨ Features
| Feature | What it does |
|---|---|
| 📎 Compact MD3 button | A 28×28 attach_file icon in the composer tool row (next to +, access mode, plan) — no bulky toolbar. |
| 🗂️ Real file picker | Opens the native file dialog (multi-select), feeding the composer's own validated ingestion path. |
| 👁 Auto vision routing | On attach → the session model switches to your vision model; on removal → the previous model is restored. |
| 🖼️ Thumbnails + remove | Draft previews with a ✕ per image; drag & drop and Ctrl+V keep working natively. |
| 🔢 Live state | Count badge on the button and a green "vision active" dot. |
| 🩺 Honest diagnostics | If model switching is unavailable, the rail says so instead of failing silently. |
🚀 Install (dynamic plugin)
In any DSH session, load the plugin with the cordis_define tool:
code.host→ the full contents ofplugin/host.jscode.client→ the full contents ofplugin/client.js
then cordis_run and approve the run (the Client half needs a checkmark).
Both halves are required in every package — that is a DSH rule, not a quirk.
⚙️ How it works
Two seats, one shared store
| Seat | Role |
|---|---|
conversation.input.left | The small attach button + a hidden <input type="file">. Selected files are queued in a module store. |
conversation.input.attachments | The only seat that receives onAddImages(files) — it drains the queue (real attachment) and renders thumbnails with onRemoveImage. |
This split is deliberate: the visual position you want (tool row) and the capability you
need (onAddImages) live in different slots, so the plugin bridges them.
Per-session vision routing
Model selection is per session, not a global default:
const dir = ctx.get('modelDirectories').directoryFor(sessionId)
await dir.select({ provider: 'deepseek-official', model: 'deepseek-v4-flash-vision-exp' })
// └─► session.selectModel RPC
The previous selection (including reasoningEffort) is captured before switching and
restored when the last image is removed.
Using
agentDefaultModelinstead does not work — that only changes the global default, not the running session. This plugin uses the same path as the shipped model picker.
🎛️ Configuration
Point it at whatever vision model your provider catalog exposes — edit the two constants
at the top of plugin/client.js:
const VISION_MODEL = 'deepseek-v4-flash-vision-exp'
const VISION_PROVIDER = 'deepseek-official'
Your model must declare image input in the provider catalog
(inputModalities: ["text", "image"]), or the request will be rejected.
⚠️ Notes & caveats
- Single seat:
conversation.input.attachmentsis the product's optional attachment rail. While this plugin runs, it holds that seat (the shipped rail is inactive). Stop the plugin to restore it — nothing is destroyed. - Images only: the composer's attachment pipeline accepts raster images
(
image/*). PDFs need a separate file-upload path, not this rail. - One active composer: the vision toggle follows the draft of the mounted session.
🧱 Repo layout
tolten-image-attach/
├── package.json ← @tolten/image-attach scaffold
├── plugin/
│ ├── host.js ← Host half
│ ├── client.js ← Client half (button + rail + vision routing)
│ ├── install.md
│ └── PACKAGING.md
└── README.md
🤝 Sharing & contributing
Ideas very welcome — especially: paste-from-clipboard affordance, per-image progress, and a generic (non-DeepSeek) vision-model preset. See CONTRIBUTING.md.
Help it reach more developers — everything is pre-written in docs/LAUNCH.md: the GitHub About text, topics, a Show HN post, an X thread, a LinkedIn post, a Reddit/Dev.to plan, and a 30-second demo script.
If this saved you a manual model switch, a ⭐ and a share go a long way:
🤝 Contributing & support
| Where | What for |
|---|---|
| CONTRIBUTING.md | Standards, dev loop and PR expectations. |
| Issues | Bug reports and feature requests (templates provided). |
| Discussions | Questions, ideas, and showing what you built. |
| SECURITY.md | Private vulnerability reporting. |
| CHANGELOG.md | What changed in each version. |
| CODE_OF_CONDUCT.md | The community standard we hold ourselves to. |
Run the same check CI runs, locally:
node scripts/validate.js
📄 License
MIT © 2025 Ing. Oscar Emmanuel Martínez Galán — sibling of Tolten Aegis and Tolten Workspace Explorer.