Conversation
Let users opt a model in/out via LLM.capability_overrides instead of only the hardcoded allow-list, which stays as the fallback. Co-authored-by: openhands <openhands@all-hands.dev>
|
📁 PR Artifacts Notice This PR contains a |
enyst
left a comment
There was a problem hiding this comment.
Thank you for the proposal. A little question, is there an issue showing that this is a problem?
On another note, I’m afraid this variable is misnamed: many other LLMs have their reasoning content sent back to them, in the SDK.
This one only means that LiteLLM doesn’t consider correctly some open LLMs as reasoning models, so we can’t recognize them together with the rest, which is why we recognize them here. Or so I recall, open to change my opinion if that’s not the case.
I think maybe we could rename it first, just so we know better… wdyt?
Thanks for the reply! Related discussion The concern applies to both self-deployed models and proxied models: they usually run behind a custom/aliased model name, and both of our recognition paths key off a known model name — which is exactly where they fall through. LiteLLM recognition: it relies on LiteLLM's model registry. A self-hosted or proxied model behind a custom name isn't in that registry — we literally get 『This model isn't mapped yet. model=qwen3.6-35b, custom_llm_provider=openai.』, so LiteLLM can't classify it (capabilities, cost, reasoning) at all. The SEND_REASONING_CONTENT_MODELS fallback: it's a substring match on the model name, so it only helps when the operator happens to name the endpoint with one of the listed substrings — which callers often can't control. That's the gap this change fills: a per-instance escape hatch (via capability_overrides) for exactly the models automatic detection and the static list cannot know about, while leaving the default (list-based) behavior untouched.
Do you have a naming you'd prefer? |
|
This PR is stale because it has been open for 40 days with no activity. Remove the stale label or leave a comment, otherwise it will be closed in 10 days. |
|
🚦 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. |
Let users opt a model in/out via LLM.capability_overrides instead of only the hardcoded allow-list, which stays as the fallback.
HUMAN:
This change makes it possible for users to control, per LLM instance, whether the SDK sends a model's full reasoning content back in the message input. Previously this was decided only by a hardcoded allow-list (SEND_REASONING_CONTENT_MODELS), so enabling a new thinking-capable model — or one served under a custom/proxy name — meant editing that list, releasing a new SDK version, and waiting for consumers to upgrade, with no way to turn it off for a model already on the list.
The fix routes send_reasoning_content through the same resolution path already used by other model capabilities, so an explicit LLM.capability_overrides value wins first, then LiteLLM metadata, and finally the hardcoded list as a fallback. It is fully backward compatible (with no override, the list behaves exactly as before) and adds no new public API or settings migration, since capability_overrides is an existing field.
AGENT:
Why
Whether the SDK sends full reasoning content back in the message input was
gated only by the hardcoded
SEND_REASONING_CONTENT_MODELSallow-list inopenhands-sdk/openhands/sdk/llm/utils/model_features.py. Adding a newthinking-capable model (or one behind a custom/proxy name) required editing the
list, releasing the SDK, and having consumers upgrade — and there was no way to
force-disable it for a listed model. This makes the behavior user-configurable
per LLM instance while keeping the list as a fallback.
Summary
send_reasoning_contentthrough the existing_resolved_boolhelper inget_features, soLLM.capability_overrides["send_reasoning_content"]takesprecedence, then LiteLLM metadata, then the hardcoded list fallback.
send_reasoning_contentas a supported key in theLLM.capability_overridesfield description.model via the override.
How to Test
Or programmatically:
Design Doc
See
.pr/design.mdfor the before/after and rationale.Type
Notes
before.
capability_overridesis an existingdict[str, bool | str]field.Jev-Fast-Audit
⚡ Jev fast audit · estimates · 0.43s · commit 4169c8c
Strongest signal: No primary concern selected.
Evidence: No primary concern to locate.
Coverage: complete supplied coverage; 4/4 hunks, 4/4 files.
All estimates and evidence