nas-runbooks/hermes-nyora/mimo-400-param-incorrect-vi...

3.9 KiB
Raw Blame History

mimo-v2.5 — HTTP 400 « Param Incorrect » (text is not set) sur screenshots browser_vision

Date : 2026-07-09 · Instance : hermes-nyora · Tags : nyora, mimo, opencode, xiaomi, vision, browser_vision, 400

Symptôme

Depuis le 08/07 ~21:30, appels mimo-v2.5 en échec récurrent (3 sessions, 6 appels) :

WARNING agent.conversation_loop: API call failed (attempt 1/3)
error_type=BadRequestError provider=opencode-go model=mimo-v2.5
summary=HTTP 400: Error from provider (Xiaomi): Param Incorrect

Détail complet dans le log : 'param': 'text is not set'. Chaque échec déclenche un fallback silencieux vers deepseek-v4-flash (la réponse arrive, mais pas par mimo). deepseek ne présente jamais le problème sur la même stack.

Cause racine (reproduite par appel direct opencode.ai/zen/go/v1)

  1. mimo-v2.5 est vision-capable : les images dans les messages user (photos Telegram) passent et sont bien décrites. Ce n'est PAS un problème d'image utilisateur, ni de tools, ni de streaming, ni de thinking.
  2. Xiaomi rejette le contenu de type liste dans les messages role: tool (multipart [{type:text},{type:image_url}], ce que produit browser_vision pour ses screenshots) → 400 « Param Incorrect », param `text` is not set.
  3. hermes-agent connaît ce bug (issue upstream #27344) et a un recovery dédié (_try_strip_image_parts_from_tool_messages + classifier multimodal_tool_content_unsupported), mais le pattern du classifier est "text is not set" SANS backticks alors que l'API renvoie désormais `text` AVEC backticks → pattern raté → 400 générique → fallback.

Repro minimale (SDK openai, clé OPENCODE_GO_API_KEY du container) : un message role:tool avec content liste contenant un part image → 400 systématique. Le même contenu en message user → OK.

Fix appliqué (config-only, aucune modif d'image Docker)

Plugin utilisateur (mécanisme officiel $HERMES_HOME/plugins/model-providers/, last-writer-wins sur les profils bundled) :

/volume1/docker/hermes-platform/hermes-nyora/data/plugins/model-providers/opencode-go-vision-fix/__init__.py

from providers import get_provider_profile
_profile = get_provider_profile("opencode-go")
if _profile is not None:
    _profile.supports_vision_tool_messages = False

Effet : _tool_result_content_for_active_model convertit préemptivement les résultats d'outils multimodaux en résumé texte (_multimodal_text_summary) avant l'envoi à Xiaomi. La vision native des images user reste active. Ownership 1026:100, puis docker restart hermes-agent-nyora.

Vérification (2026-07-09 ~07:00 UTC)

  • Process frais : supports_vision_tool_messages=False, cap max_tokens mimo-v2.5-pro conservé, tool result screenshot → str sans image_url.
  • E2E via api_server (port 8642, clé API_SERVER_KEY) : scénario exact en échec la veille (navigation + browser_vision + description) → réponse correcte, 3 appels model=mimo-v2.5, zéro 400, zéro fallback.

Impact sur le comparatif mimo vs deepseek

Les stats du pilote (05→08/07) ne sont PAS faussées : zéro occurrence dans agent.log.1 (04/07→08/07 20:42) ; les 6 × 400 datent du 08/07 21:3522:05, après le verdict, déclenchées par un nouveau pattern d'usage (sessions browser avec screenshots). Le « 1 erreur / 591 appels » de mimo tient. Nuance : les tours en 400 ont été servis par deepseek via fallback (3 tours, négligeable).

Pièges / à savoir

  • Les request_dump_*.json ne sont écrits que sur max_retries_exhausted — un 400 récupéré par fallback ne laisse PAS de dump. Chercher dans data/logs/agent.log (Param Incorrect, Fallback activated).
  • curl/urllib directs sur opencode.ai → 403 Cloudflare 1010 (User-Agent) ; utiliser le SDK openai du venv du container.
  • À retirer si l'image upstream corrige le pattern du classifier (backticks) ou si Xiaomi accepte le contenu liste dans les messages tool.