hermes-agent/tests/agent
Teknium c769be344a
fix(agent): recover from providers rejecting list-type tool content (#27344) (#30259)
Some providers (Xiaomi MiMo, some Alibaba endpoints, a long tail of
OpenAI-compatible servers) follow the OpenAI spec strictly and require
tool message `content` to be a string — they reject our list-type
content (text + image_url parts) with HTTP 400 'text is not set' /
'tool message content must be a string'.

Instead of an allowlist of known-good providers (maintenance burden,
guaranteed to miss aggregators like OpenRouter where the underlying
model determines support, not the aggregator name), this lands a
reactive recovery:

1. New `FailoverReason.multimodal_tool_content_unsupported` with a
   small pattern list covering the common 400 wordings.
2. `AIAgent._try_strip_image_parts_from_tool_messages` walks the API
   message list, downgrades any `role:tool` message whose content is
   list-with-image to a plain text summary (preserves text parts) in
   place, AND records the active (provider, model) in a session-scoped
   `_no_list_tool_content_models` set.
3. `_tool_result_content_for_active_model` short-circuits to a text
   summary when (provider, model) is in the cache — so after the first
   400 + retry, subsequent screenshots in the same session skip the
   round trip entirely.
4. Retry hook in `agent.conversation_loop` mirrors the existing
   `image_too_large` recovery: detect the reason, run the helper,
   retry once, fall through to the normal error path if no list-type
   tool content was actually present.

Cache is transient (per-session) by design — next session retries in
case the provider added support, no persistent state to maintain.

Fixes #27344. Closes #27351 (allowlist approach superseded by reactive
recovery).
2026-05-21 23:40:16 -07:00
..
lsp fix(lint): skip per-file shell linter when LSP will handle the file (#29054) 2026-05-20 01:46:40 -05:00
transports fix(xai): restore encrypted reasoning replay across turns 2026-05-20 23:12:45 -07:00
__init__.py
test_anthropic_adapter.py feat(azure-foundry): add Microsoft Entra ID auth 2026-05-18 10:14:38 -07:00
test_anthropic_keychain.py
test_anthropic_oauth_pkce.py
test_arcee_trinity_overrides.py
test_async_utils.py
test_auxiliary_client.py test: use subprocesses for each test file (#29016) 2026-05-21 16:40:04 +05:30
test_auxiliary_client_anthropic_custom.py
test_auxiliary_client_azure_foundry.py feat(azure-foundry): add Microsoft Entra ID auth 2026-05-18 10:14:38 -07:00
test_auxiliary_config_bridge.py
test_auxiliary_main_first.py chore: ruff auto-fix PLR6201 resweep — tuple → set in membership tests (#27355) 2026-05-17 02:29:41 -07:00
test_auxiliary_named_custom_providers.py
test_auxiliary_transport_autodetect.py
test_azure_identity_adapter.py feat(azure-foundry): add Microsoft Entra ID auth 2026-05-18 10:14:38 -07:00
test_bedrock_1m_context.py feat(azure-foundry): add Microsoft Entra ID auth 2026-05-18 10:14:38 -07:00
test_bedrock_adapter.py
test_bedrock_integration.py
test_codex_cloudflare_headers.py
test_compress_focus.py
test_compressor_historical_media.py Port from Kilo-Org/kilocode#9434: strip historical media after compression (#27189) 2026-05-16 17:18:25 -07:00
test_compressor_image_tokens.py
test_context_compressor.py fix(compress): make abort-on-summary-failure opt-in via config flag (#28117) 2026-05-18 10:28:20 -07:00
test_context_compressor_summary_continuity.py
test_context_engine.py
test_context_references.py
test_copilot_acp_client.py
test_copilot_acp_deprecation.py
test_credential_pool.py fix(codex-oauth): quarantine terminal refresh errors so dead tokens are not replayed across sessions 2026-05-18 10:31:40 -07:00
test_credential_pool_routing.py
test_crossloop_client_cache.py
test_curator.py
test_curator_activity.py
test_curator_backup.py
test_curator_classification.py
test_curator_reports.py
test_custom_provider_extra_body.py fix(custom): pass custom provider extra body 2026-05-21 07:48:53 -07:00
test_deepseek_anthropic_thinking.py chore: ruff auto-fix PLR6201 resweep — tuple → set in membership tests (#27355) 2026-05-17 02:29:41 -07:00
test_direct_provider_url_detection.py
test_display.py
test_display_emoji.py
test_error_classifier.py fix(agent): recover from providers rejecting list-type tool content (#27344) (#30259) 2026-05-21 23:40:16 -07:00
test_external_skills.py
test_external_skills_dirs_cache.py
test_gemini_cloudcode.py
test_gemini_fast_fallback.py fix: wrap _pool_may_recover_from_rate_limit call through run_agent namespace 2026-05-18 20:04:57 -07:00
test_gemini_free_tier_gate.py
test_gemini_native_adapter.py
test_gemini_schema.py
test_i18n.py
test_image_gen_registry.py
test_image_routing.py fix(agent): consult supports_vision override in auto-mode routing 2026-05-20 23:27:10 -07:00
test_insights.py
test_kimi_coding_anthropic_thinking.py
test_local_stream_timeout.py
test_markdown_tables.py
test_memory_provider.py fix(agent): widen toolset gate to context engine tools (#5544 sibling) 2026-05-21 23:18:37 -07:00
test_memory_session_switch.py
test_memory_user_id.py
test_minimax_auxiliary_url.py
test_minimax_provider.py
test_model_metadata.py fix(metadata): qwen3.6-plus has a 1M context window (#27008) 2026-05-17 02:31:18 -07:00
test_model_metadata_local_ctx.py
test_model_metadata_ssl.py
test_models_dev.py
test_moonshot_schema.py fix(moonshot): strip $ref siblings and collapse tuple items in tool schemas (#27104) 2026-05-16 13:02:19 -07:00
test_nous_rate_guard.py
test_onboarding.py
test_openrouter_response_cache.py
test_plugin_llm.py
test_portal_tags.py
test_prompt_builder.py fix(agent): add qwen and deepseek to TOOL_USE_ENFORCEMENT_MODELS 2026-05-18 20:06:49 -07:00
test_prompt_caching.py
test_proxy_and_url_validation.py
test_rate_limit_tracker.py
test_redact.py fix(security): redact xAI (Grok) API keys in logs 2026-05-18 10:21:22 -07:00
test_shell_hooks.py fix(security): restore type safety and extract constant in shell hook block handler 2026-05-17 02:31:18 -07:00
test_shell_hooks_consent.py
test_skill_bundles.py feat(skills): add skill bundles — alias /<name> loads multiple skills (#28373) 2026-05-18 21:38:05 -07:00
test_skill_commands.py test: use subprocesses for each test file (#29016) 2026-05-21 16:40:04 +05:30
test_skill_commands_reload.py
test_skill_utils.py fix(skills): load Linux-tagged skills on Termux (android sys.platform) 2026-05-21 19:08:38 -07:00
test_streaming_context_scrubber.py 🐛 fix(memory): require newline after context tag 2026-05-18 10:53:08 -07:00
test_subagent_progress.py
test_subagent_stop_hook.py
test_subdirectory_hints.py
test_system_prompt_restore.py perf(prompt-cache): date-only timestamp + loud gateway-DB roundtrip logging 2026-05-17 23:20:37 -07:00
test_think_scrubber.py
test_title_generator.py
test_tool_guardrails.py fix: add recovery hints to loop guard warnings 2026-05-19 00:12:12 -07:00
test_tool_result_classification.py
test_unsupported_parameter_retry.py
test_unsupported_temperature_retry.py
test_usage_pricing.py
test_video_gen_registry.py
test_vision_resolved_args.py