Problem
dsh-vision-toolkit (and upstream vision_client.py) hard-requires an OpenAI-compatible endpoint: it POSTs {baseUrl}/chat/completions with image_url content blocks. But some subscriptions expose their best vision models only on the Anthropic protocol:
- OpenCode Go ($10/mo) serves
Qwen3.7 Plus / Qwen3.7 Max / Qwen3.8 Max / MiniMax M3·M2.7·M2.5 exclusively at https://opencode.ai/zen/go/v1/messages (Anthropic Messages format), while the cheaper vision models on /chat/completions (glm-5.1 etc.) are ~3.5× more expensive per token.
- Concretely:
qwen3.7-plus ≈ 21,600 requests/month within Go's included quota vs ~4,300 for glm-5.1. That's a big deal for vision-heavy workflows (UI restoration, chart/screenshot analysis) running on text-only DeepSeek agents — exactly this project's target use case.
Verified facts (2026-08-14, live calls against OpenCode Go)
POST /v1/messages with Authorization: Bearer <key> → 401; with x-api-key: <key> (+ anthropic-version: 2023-06-01) → 200.
qwen3.7-plus accepts image blocks (source: {type: base64, media_type, data}) and returns content that may include type: "thinking" blocks in addition to text blocks.
- Sending
thinking: {type: "disabled"} in the body is accepted and cuts latency/cost.
Proposal
Add an optional provider.protocol (openai | anthropic) setting, in both dsh-vision-toolkit's config schema and upstream vision_client.py:
anthropic mode: POST {baseUrl}/messages with x-api-key + anthropic-version headers; map text → {type:text}, image_url (data URL or http) → {type:image, source:{type:base64,...}}; system role → top-level system; optional thinking:{type:disabled}; parse response by joining text blocks only (ignore thinking), map usage tokens.
- Keep
openai as default so nothing breaks.
Current workaround (working today)
A ~150-line local protocol-translation gateway (OpenAI /chat/completions ⇄ Go /messages) running at 127.0.0.1, pointed to by provider.baseUrl. Text + real-image calls against qwen3.7-plus both verified (200). Reference implementation: https://gist.github.com/EliteOtaku/4e55d17ca4a70052243ea3ad9064440b
Native support would let users drop the extra long-running gateway process entirely — one less moving part. Happy to send a PR if this is in scope.
Problem
dsh-vision-toolkit(and upstreamvision_client.py) hard-requires an OpenAI-compatible endpoint: it POSTs{baseUrl}/chat/completionswithimage_urlcontent blocks. But some subscriptions expose their best vision models only on the Anthropic protocol:Qwen3.7 Plus/Qwen3.7 Max/Qwen3.8 Max/MiniMax M3·M2.7·M2.5exclusively athttps://opencode.ai/zen/go/v1/messages(Anthropic Messages format), while the cheaper vision models on/chat/completions(glm-5.1 etc.) are ~3.5× more expensive per token.qwen3.7-plus≈ 21,600 requests/month within Go's included quota vs ~4,300 forglm-5.1. That's a big deal for vision-heavy workflows (UI restoration, chart/screenshot analysis) running on text-only DeepSeek agents — exactly this project's target use case.Verified facts (2026-08-14, live calls against OpenCode Go)
POST /v1/messageswithAuthorization: Bearer <key>→ 401; withx-api-key: <key>(+anthropic-version: 2023-06-01) → 200.qwen3.7-plusacceptsimageblocks (source: {type: base64, media_type, data}) and returnscontentthat may includetype: "thinking"blocks in addition totextblocks.thinking: {type: "disabled"}in the body is accepted and cuts latency/cost.Proposal
Add an optional
provider.protocol(openai|anthropic) setting, in bothdsh-vision-toolkit's config schema and upstreamvision_client.py:anthropicmode: POST{baseUrl}/messageswithx-api-key+anthropic-versionheaders; maptext→{type:text},image_url(data URL or http) →{type:image, source:{type:base64,...}}; system role → top-levelsystem; optionalthinking:{type:disabled}; parse response by joiningtextblocks only (ignorethinking), map usage tokens.openaias default so nothing breaks.Current workaround (working today)
A ~150-line local protocol-translation gateway (OpenAI
/chat/completions⇄ Go/messages) running at127.0.0.1, pointed to byprovider.baseUrl. Text + real-image calls againstqwen3.7-plusboth verified (200). Reference implementation: https://gist.github.com/EliteOtaku/4e55d17ca4a70052243ea3ad9064440bNative support would let users drop the extra long-running gateway process entirely — one less moving part. Happy to send a PR if this is in scope.