Back to home@EmmanuelMartinez

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

🖼️ Tolten Image Attach

CI

English · Español

License: MIT DeepSeek Harness Material Design 3 PRs welcome Share on X

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

FeatureWhat it does
📎 Compact MD3 buttonA 28×28 attach_file icon in the composer tool row (next to +, access mode, plan) — no bulky toolbar.
🗂️ Real file pickerOpens the native file dialog (multi-select), feeding the composer's own validated ingestion path.
👁 Auto vision routingOn attach → the session model switches to your vision model; on removal → the previous model is restored.
🖼️ Thumbnails + removeDraft previews with a ✕ per image; drag & drop and Ctrl+V keep working natively.
🔢 Live stateCount badge on the button and a green "vision active" dot.
🩺 Honest diagnosticsIf 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:

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

SeatRole
conversation.input.leftThe small attach button + a hidden <input type="file">. Selected files are queued in a module store.
conversation.input.attachmentsThe 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 agentDefaultModel instead 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.attachments is 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:

Share on X Share on LinkedIn

🤝 Contributing & support

WhereWhat for
CONTRIBUTING.mdStandards, dev loop and PR expectations.
IssuesBug reports and feature requests (templates provided).
DiscussionsQuestions, ideas, and showing what you built.
SECURITY.mdPrivate vulnerability reporting.
CHANGELOG.mdWhat changed in each version.
CODE_OF_CONDUCT.mdThe 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.