fix(sdk): resolve custom OpenAI-compatible endpoints when model id lacks a recognized provider prefix - #4579
Open
asiqur-rahman wants to merge 2 commits into
Open
Conversation
…cks a recognized provider prefix LLMProvider.from_model() only ever calls LiteLLM's get_llm_provider() with custom_llm_provider=None. When api_base points at a custom endpoint (a self-hosted server such as LM Studio, or a third-party router) and the model id's first "/" segment isn't a LiteLLM-recognized provider name (e.g. "auto/coding"), that call raises instead of falling back to the custom base. from_model() swallows the exception and returns name=None, so as_litellm_call_kwargs() omits custom_llm_provider entirely -- the later, unguarded litellm.completion() call then hits the same resolution failure and raises "LLM Provider NOT provided" to the user. Retry once with custom_llm_provider="openai" when api_base is set and the first attempt didn't resolve a provider. A caller-supplied api_base already implies an OpenAI-compatible endpoint, and LiteLLM only strips a *recognized* provider prefix, so an unrecognized one like "auto/" reaches the endpoint unchanged -- confirmed with a live litellm.get_llm_provider() call against the exact repro (model="auto/coding") before writing the fix. Fixes OpenHands#4247 Credit to @moorsecopers99, whose prior PR OpenHands/OpenHands#14043 diagnosed this exact class of bug (LM Studio namespaced model ids) and validated the same auto-prefix approach against the pre-split monorepo settings router. That PR went stale before review and doesn't apply to the current repo layout; this reimplements the fix at the SDK's LiteLLM boundary (LLMProvider.from_model) instead of an app-server-specific code path, so it applies uniformly to every consumer (CLI, agent-server, SaaS) per this repo's "prefer interfaces over special cases" principle.
asiqur-rahman
marked this pull request as ready for review
August 22, 2026 11:55
Collaborator
|
🚦 CI is currently failing on this PR's latest commit. Please fix the failing checks before OpenHands reviews it - this is re-checked automatically once you push a new commit. (A maintainer can also request This is an automated check - no AI was used to generate this comment. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
HUMAN:
My own OpenAI-compatible endpoint kept throwing this error until I traced it to how LiteLLM resolves the provider prefix.
AGENT:
Why
LLMProvider.from_model()only ever calls LiteLLM'sget_llm_provider()withcustom_llm_provider=None. Whenapi_basepoints at a custom endpoint (aself-hosted server such as LM Studio, or a third-party OpenAI-compatible
router) and the model id's first
/segment isn't a LiteLLM-recognizedprovider name (e.g.
auto/coding,qwen/qwen3-coder-30b-a3b-instruct), thatcall raises instead of falling back to the custom base.
from_model()swallows the exception and returns
name=None, soas_litellm_call_kwargs()omits
custom_llm_providerentirely — the later, unguardedlitellm.completion()call then hits the same resolution failure and raisesto the user:
This reproduces with a real personal OpenAI-compatible router (Custom Model
auto/coding, a liveapi_base) and matches the exact symptom in the linkedissue and in prior reports (#11608, #11632, #14323 in
OpenHands/OpenHands).Summary
LLMProvider.from_model()retries once withcustom_llm_provider="openai"when
api_baseis set and the first attempt doesn't resolve a provider. Acaller-supplied
api_basealready implies an OpenAI-compatible endpoint,and LiteLLM only strips a recognized provider prefix, so an unrecognized
one (
auto/,qwen/, etc.) reaches the endpoint unchanged.api_base, behavior is unchanged — there's no custom endpoint toinfer, so an unresolved model id stays unresolved exactly as before.
tests/sdk/llm/test_litellm_provider.pycovering the fix and the no-
api_basenon-regression case.Issue Number
Fixes #4247
How to Test
Reproduced and verified live against the real
litellmpackage (not mocked),via
uv run pythonin this repo:Automated:
Video/Screenshots
N/A — backend-only correctness fix, no visual surface.
Type
Notes
Credit to @moorsecopers99, whose prior PR
OpenHands/OpenHands#14043diagnosedthis exact class of bug (LM Studio namespaced model ids hitting the same
LiteLLM provider-resolution failure) and validated the same auto-prefix
approach — that PR went stale before review and targeted the pre-split
monorepo's app-server settings router, which no longer exists in this repo
layout. This reimplements the fix at the SDK's LiteLLM boundary
(
LLMProvider.from_model) instead of an app-server-specific code path, perthis repo's "prefer interfaces over special cases" principle in
CONTRIBUTING.md— it applies uniformly to every consumer (CLI, agent-server,SaaS) rather than only wherever a settings endpoint happens to intercept it.