fix(acp): skip detect_provider_for_model when input had explicit provider prefix - #59197
Conversation
WhatsApp Web.js uses LID format (digits@lid) for certain contact IDs, but _parse_target_ref() only recognizes E.164 phone number format. Add a regex and branch for WhatsApp LID IDs so send_message works without requiring a home_channel. Closes NousResearch#59136
…ider prefix _resolve_model_selection re-runs detect_provider_for_model() when the resolved provider equals the current provider, even when parse_model_input already resolved an explicit provider:model prefix. For models that newly appear in OpenRouter's catalog, this overwrites the correct provider with openrouter, causing 'No LLM provider configured' errors. Track whether raw_model had an explicit provider prefix and only run the fallback when it didn't. Closes NousResearch#59089
Duplicate of #59092 — both fix #59089 by skipping |
AmirF194
left a comment
There was a problem hiding this comment.
Thanks for the clear writeup, the root cause here is spot on and the failing case is real. I ran it both ways and confirmed the explicit anthropic:claude-sonnet-5 path returns openrouter before your change and anthropic after, so the fix does what it says for the reported input.
My concern is that ":" in raw_model is a looser test than the one parse_model_input actually uses to decide a prefix is a provider. It only treats a colon as a provider delimiter when the left side is a known provider name. So a bare model name that carries a colon variant tag (the OpenRouter :free / :beta / :thinking suffixes) now counts as "had explicit provider" and skips detection, even though the user never named a provider. Concretely, _resolve_model_selection("poolside/laguna-m.1:free", "anthropic") routes to openrouter on main but stays on anthropic with this change, and that id is literally in the catalog (model_ids() ships three :free ids right now). That is the same "No LLM provider configured" failure you are fixing, just reached from the other direction, and it is hittable from the /model text path.
Your own issue points at the clean version of the guard: parse_model_input already knows whether it matched a real provider prefix (colon > 0 and provider_part in _KNOWN_PROVIDER_NAMES). Reusing that (return a flag, or recompute the same condition) skips detection only when there was a genuine explicit provider and avoids the variant-tag regression.
Two smaller things. Could you add a regression test in tests/acp/test_server.py? The existing test_set_session_model_accepts_provider_prefixed_choice stubs detect_provider_for_model to None, so it passes on the buggy code too and would not have caught this (I ran that file in a clean 3.11 container, 80 passed, and confirmed neither the fix nor the new regression is exercised). A case where detection returns a different provider and the explicit prefix wins, plus one for a bare :free slug that should still route, would lock both directions down. And the WhatsApp LID commit (tools/send_message_tool.py) looks unrelated to ACP routing and is not in the PR description, so I would pull it into its own PR to keep this one reviewable, especially since \d+@lid already matches the existing _WHATSAPP_JID_RE.
|
Revisei o feedback e ajustei a branch.\n\nMudanças aplicadas:\n- troquei o guard para só pular quando houver prefixo de provider realmente reconhecido (mesma condição semântica do parser, evitando regressão com slugs /)\n- removi da PR a alteração não relacionada de WhatsApp LID\n- adicionei regressões para os dois sentidos: prefixo explícito vence detecção divergente, e slug bare com continua roteando via detecção\n\nValidação:\n- ........................................................................ [ 90%] |
|
Revisei o feedback e ajustei a branch. Mudanças aplicadas:
Validação:
|
|
Reopening — this was closed in error by the automated stale-PR check, which only inspected GitHub's |
|
Re-closing: this was mistakenly reopened citing the stale-close automation bug (that bug affects #59194/#59189, which is a separate issue), but this PR's actual close reason was different and still valid — it is a duplicate of #59092 (opened earlier, same fix for #59089). Leaving one open note for whoever picks up #59092: this branch's follow-up commit narrowed the guard to only skip |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused ACP regression coverage. Current main still parses the requested model and then reruns provider detection when the parsed provider equals the current provider (acp_adapter/server.py:654-658); the proposed recognized-prefix guard follows the parser's own delimiter rule (hermes_cli/models.py:1801-1816) and protects the shared resolver used by both ACP model-switch paths.
Problems
- The diff still includes unrelated WhatsApp code.
_WHATSAPP_LID_REis added intools/send_message_tool.py:51, but parsing consults_WHATSAPP_JID_REattools/send_message_tool.py:594; existing coverage already verifiesdigits@lidthrough that regex (tests/tools/test_send_message_target_parse.py:42-46).
Suggested changes
- Remove the
tools/send_message_tool.pyhunk so this ACP fix remains scoped and independently salvageable.
This is an automated hermes-sweeper review.
| r"^\s*[-\w]+@(?:g\.us|s\.whatsapp\.net|lid|broadcast|newsletter)\s*$", | ||
| re.IGNORECASE, | ||
| ) | ||
| _WHATSAPP_LID_RE = re.compile(r"^\s*(\d+@lid)\s*$") |
There was a problem hiding this comment.
This declaration is unused: _parse_target_ref() only checks _WHATSAPP_JID_RE, which already accepts digits@lid. Please drop this unrelated WhatsApp residue from the ACP-routing PR.
|
Re-closing (again) — this PR is a duplicate of #59092 (opened earlier for the same #59089 root cause). This was already confirmed in my 2026-07-15T06:34Z close comment above; something reopened it again without any new information. #59092 remains open and is the canonical fix to review/merge; teknium1's 23:32 sweeper review here also asked to drop the unrelated WhatsApp LID hunk, which is moot once this closes in favor of #59092. Leaving closed. |
Summary
_resolve_model_selectionre-runsdetect_provider_for_model()when the resolved provider equals the current provider, even whenparse_model_inputalready resolved an explicitprovider:modelprefix. For models that newly appear in OpenRouter's catalog (or any model known to multiple providers), this overwrites the correct provider with a detected one, causing "No LLM provider configured" errors.Root cause
In
acp_adapter/server.py,_resolve_model_selection:parse_model_input(raw_model, current_provider)which correctly resolvesopenrouter:anthropic/claude-sonnet-4.5→("openrouter", "anthropic/claude-sonnet-4.5").if target_provider == current_provider. If the current session provider happens to also beopenrouter, it enters the branch.detect_provider_for_model(new_model, current_provider), which detectsanthropic/claude-sonnet-4.5as belonging to theanthropicprovider and overwritestarget_providerfromopenrouter→anthropic.The fix skips the
detect_provider_for_modelfallback whenraw_modelcontained an explicit:(provider prefix), sinceparse_model_inputhas already handled that case correctly.Changes
acp_adapter/server.py—_resolve_model_selection: add_had_explicit_providerguardTesting
The fix is minimal and targeted: it only changes the condition under which
detect_provider_for_modelis called, and only for inputs where the user explicitly specified a provider prefix.Closes #59089