Repository navigation
Description
Summary
Sending a Telegram photo as the first message after a long idle period is silently dropped with Model ... doesn't support image input, even though the model does support image input. On OpenCode v2 the per-directory "location" is unloaded after ~60 minutes of inactivity and rebooted lazily on the next request; during that cold boot the providers/models list is momentarily empty, and getModelCapabilities() treats that empty snapshot as "the model has no image support".
Environment
- opencode version: 2.0.18 (CLI, managed server, bundled
@opencode/clientall 2.0.18;OPENCODE_SERVER_VERSION=v2) - OS: Linux 6.8.0-139-generic (x86_64), Ubuntu 24.04
- Node.js: v24.21.0
- opencode-telegram-bot: 0.26.0 (global npm, systemd
opencode-bot.service, server on127.0.0.1:49374) - Shell: /usr/bin/bash
- Install/channel: release (systemd,
OPENCODE_AUTO_RESTART_ENABLED=false) - Active plugins:
opencode-cmd-provider2.1.9 (providercommandcode),tps-counter@git+https://github.com/depler/opencode-tps-counter.git - Model:
commandcode/deepseek/deepseek-v4.1-flash(image-capable; see Additional Context)
Reproduction
-
Use an OpenCode v2 server with a plugin provider, and leave a location (project directory) idle for more than ~60 minutes. The server unloads it:
[server] location services evicted directory=/opt [server] location services evicted directory=/root -
Send a photo to the bot as the first message after the idle period.
-
The next request reboots the location lazily; models register a few seconds later:
[server] location services booted directory=/root durationMs=1271 [server] event provider.updated directory=/root -
The bot's capability lookup lands inside that cold window.
Expected Behavior
The photo should be forwarded. When the providers list is not yet populated, the bot should either retry briefly (as the server-ready wait does) until the model list is non-empty, or not treat unknown capabilities as "image unsupported". Silently dropping the attachment is the worst outcome.
Actual Behavior
The photo is silently dropped. The bot logs a warning and skips the attachment:
[WARN] [ModelCapabilities] Providers list has no models; not caching commandcode/deepseek/deepseek-v4.1-flash
[WARN] [Bot] Model commandcode/deepseek/deepseek-v4.1-flash doesn't support image input
Sending the exact same photo again a moment later succeeds, so the model and the bot's mapping are fine — only the first, cold-location attempt fails.
Additional Context
Root cause
dist/app/services/model-capabilities-service.js→getModelCapabilities()returnsnullwhen every provider has zero models. It deliberately does not cache that ("not caching"), but it still returnsnullto the caller.supportsInput(capabilities, "image")returnsfalsefornull, soprepareTelegramPhotos()indist/bot/handlers/prompt.jslogs "doesn't support image input" and drops the photo.
Cold-location timeline (server log is MSK = UTC+3)
19:20:22.193 location services evicted directory=/opt
19:20:22.438 location services evicted directory=/root
19:21:02.915 location services booted directory=/opt durationMs=256
19:21:04.386 location services booted directory=/root durationMs=1271
19:21:04.396 [Bot] Providers list has no models; not caching commandcode/deepseek/deepseek-v4.1-flash
19:21:04.397 [Bot] Model commandcode/deepseek/deepseek-v4.1-flash doesn't support image input
19:21:07.828 provider.updated directory=/root (models registered only here)
The capability request arrived 10 ms after the /root location finished booting but ~3.4 s before the plugin registered its models, so /api/model was still empty.
The model is image-capable
- Plugin catalog (
[email protected]):"deepseek/deepseek-v4.1-flash": ["text", "image"]. - Live
GET /api/model:"capabilities": { "tools": true, "input": ["text","image"], "output": ["text"] }. - Running the bot's own
toV1Providersmapper over the live response yieldscapabilities.input.image === true.
Notes
- OpenCode v2 unloads a location after ~60 minutes of inactivity (sweep every 1 minute). This is a normal lifecycle, not a crash or a server restart, so a startup readiness wait does not cover it.
- Workaround without a bot change: send the photo a second time (the first attempt warms the location and the empty result is not cached), or send any text message before the photo after a long idle.
- Related: [Bug]: Models from plugin providers vanish after restart until the 10-minute catalog cache expires #255 (catalog cached from a partial snapshot after restart) — same class of "empty/partial provider snapshot treated as authoritative", but a different code path (
getModelCapabilitiesvs the model catalog cache).
Activity
depler commentedon Sep 27, 2026
Cross-link: the upstream server-side cause is tracked in anomalyco/opencode#51701 (empty
/api/model//api/providerwhile a Location reboots after the 60-minute idle eviction; same class as anomalyco/opencode#36117).Client-side this bot issue is the observable impact:
getModelCapabilities()gets an empty providers list, returnsnull, andsupportsInput(null, "image")drops the attachment. Fixing the bot to retry on an empty list would make it resilient to this regardless of the server fix.grinev commentedon Sep 28, 2026
Fixed in https://github.com/grinev/opencode-telegram-bot/releases/tag/v0.26.1