Skip to content

Fix custom provider API mode detection for OpenAI-compatible endpoints - #9155

Open
luoxiao6645 wants to merge 1 commit into
NousResearch:mainfrom
luoxiao6645:fix/custom-provider-openai-messages-9064
Open

Fix custom provider API mode detection for OpenAI-compatible endpoints#9155
luoxiao6645 wants to merge 1 commit into
NousResearch:mainfrom
luoxiao6645:fix/custom-provider-openai-messages-9064

Conversation

@luoxiao6645

@luoxiao6645 luoxiao6645 commented Apr 13, 2026

Copy link
Copy Markdown

Summary

  • Prevent stale model.api_mode from leaking into custom and explicit API-key provider runtimes
  • Tighten direct OpenAI detection so only the api.openai.com host is treated as native OpenAI, not proxy URLs that merely contain it in the path
  • Align main-agent runtime resolution, provider fallback helpers, and auxiliary clients on the same API-mode detection rules

Fixes #9064

Problem

Custom OpenAI-compatible endpoints could be misclassified as codex_responses instead of chat_completions.

That caused Hermes to send Responses-style payloads to chat-completions backends, which broke request validation and produced errors such as:

Key: 'GptVParam.Messages' Error:Field validation for 'Messages' failed on the 'required' tag

Fix

  • Add provider-family guards before honoring persisted model.api_mode
  • Replace broad api.openai.com substring checks with hostname-based detection
  • Keep proxy URLs that only include api.openai.com in the path on the chat_completions path
  • Apply the same detection logic across runtime provider resolution, main agent request routing, fallback helpers, and auxiliary clients

Regression Coverage

  • Stale api_mode does not leak into custom endpoints
  • Stale api_mode does not leak into explicit API-key providers
  • Proxy URLs containing api.openai.com in the path are not treated as native OpenAI
  • Auxiliary client wrapping and token-param selection follow the corrected detection logic

Validation

venv\Scripts\python -m pytest -n 0 tests\agent\test_auxiliary_client.py
venv\Scripts\python -m pytest -n 0 tests\hermes_cli\test_runtime_provider_resolution.py
venv\Scripts\python -m pytest -n 0 tests\run_agent\test_strict_api_validation.py
venv\Scripts\python -m pytest -n 0 tests\agent\test_minimax_provider.p

@luoxiao6645
luoxiao6645 force-pushed the fix/custom-provider-openai-messages-9064 branch from f2c0741 to d124690 Compare April 17, 2026 10:07
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/config Config system, migrations, profiles labels Apr 27, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed cross-path analysis. The linked plain-custom failure is already covered on current main by 0e4c879a3 (hermes_cli/runtime_provider.py:136-155), but there is still a narrow hostname-hardening gap worth salvaging.

Problems

  • hermes_cli/providers.py:551 still uses a broad "api.openai.com" in url_lower check for known providers. This reaches live model-switch setup through agent/agent_runtime_helpers.py:1752-1756.
  • The added proxy test uses "totally-unknown", so it exercises the already hostname-safe unknown-provider branch (hermes_cli/providers.py:559-568), not the known-provider branch this PR changes.
  • Current main already centralizes hostname parsing in utils.base_url_hostname() (hermes_cli/runtime_provider.py:117); the PR's duplicated local helpers should not be carried forward.

Suggested changes

  • Salvage the remaining providers.py branch with base_url_hostname(base_url) == "api.openai.com".
  • Add the regression using a known provider and a proxy path containing api.openai.com.

Automated hermes-sweeper review.

result = determine_api_mode("deepseek")
assert result == "chat_completions"

def test_proxy_path_containing_openai_does_not_force_responses(self):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This uses an unknown provider, which already takes the hostname-safe fallback branch. Please exercise a known provider (for example openrouter) so the test covers the get_provider(provider) is not None branch that still has the substring check on current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 'GptVParam.Messages' Error:Field validation for 'Messages' failed on the 'required' tag

3 participants