Bundle
dsh-image-base64
DeepSeek Harness plugin: transcodes images to a base64-safe format (PNG) before a vision request, fixing gateways like LM Studio that reject non-PNG/JPEG/GIF data URLs with "'url' field must be a base64 encoded image."
- Source
- pureexe
- License
- MIT
- Updated
- Updated 6 hours ago
Readme
# dsh-image-base64
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin that fixes:
```
This turn failed 400 "'url' field must be a base64 encoded image."
INVALID_REQUEST
```
when a vision-capable model (e.g. `meta/muse-glimmer`) is served through an
OpenAI-compatible gateway that validates the image MIME type strictly, such
as **LM Studio**.
## Why this happens
See [deepseek-ai/deepseek-harness#4615](https://github.com/deepseek-ai/deepseek-harness/discussions/4615)
for the full discussion. The short version:
- `dsh-attachment-local`'s request-image quality ladder re-encodes an image
as `image/webp` whenever the source has an alpha channel (JPEG has no
alpha channel to fall back to). A pasted screenshot or a PNG with
transparency very often has one.
- LM Studio's OpenAI-compatible endpoint only accepts `image/png`,
`image/jpeg`, and `image/gif` inside a base64 `data:` URL. It rejects
`image/webp` (and anything else) at the protocol layer with `400`, before
the request reaches the model.
- `dsh-llm-pi-ai` forwards whatever `mediaType` the attachment store gives
it straight into the request — there's no format negotiation between the
two, so the mismatch reaches LM Studio unchanged.
## What this plugin does
It wraps the attachment store's `readImageRequest()` (the call
`dsh-llm-pi-ai` makes to get the exact bytes/MIME type that go into the
request) and transcodes the result to `image/png` with `sharp` whenever its
media type isn't in an accepted list (`image/png`, `image/jpeg`, `image/gif`
by default). Everything already in an accepted format passes through
untouched — only the images that would otherwise be rejected pay the
transcode cost.
## Install
From your DSH profile directory (or via `dsh plugin --profile <name> add`,
which forwards to `pnpm` inside the profile):
```sh
dsh plugin --profile <name> add /home/pakkapon/dsh-image-base64
```
Then list it in that profile's `package.json` under `dsh.profile.bundles`:
```json
{
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-image-base64"
]
}
}
}
```
Restart the profile (or let it pick it up automatically if
`patchReload: live` is set) to load it.
## Configuration
Accepted media types default to `[image/png, image/jpeg, image/gif]` (LM
Studio's whitelist). To widen or narrow that, target the plugin's `id` from
your own patch layer (profile `cordis.patch.yml` or `$DSH_HOME/cordis.patch.yml`):
```yaml
- id: image-base64-compat
config:
acceptedMediaTypes: [image/png, image/jpeg, image/gif, image/webp]
```
## Caveats
- This patches the attachment store's *request-image* projection only — it
doesn't touch how images are stored, just what's sent on the wire for a
model request.
- Transcoding to PNG is lossless for the pixels it's given, but a PNG
re-encode of a large photo is bigger than an equivalent JPEG/WebP. If your
gateway actually accepts WebP, add it to `acceptedMediaTypes` instead of
relying on the default.
## License
MIT
Install
dsh plugin --profile web add github:pureexe/dsh-image-base64
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-image-base64 from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.