Repository navigation
refactor(llm): consolidate OpenAI-compatible providers onto one base (#11517) - #11747
Merged
Merged
Conversation
…11517) One OpenAICompatibleProvider now owns the request-building, response-mapping, tool-call parsing, streaming, and model-listing flow shared by the five providers speaking the OpenAI chat-completions dialect. Each concrete provider is a thin subclass carrying only its genuine deltas: - openai: SSOT key fallback chain, optional base_url, reasoning-effort mapping (#9017), prompt-cache payload normalisation (#7368) - groq: groq SDK client, historical omission of top_p - custom_openai: mandatory base_url, permissive api_key default, per-instance provider naming - openrouter: gateway base URL default, api_kwargs penalty forwarding, empty static model fallback - nous: HF token chain, HF inference base URL, 2048 default max_tokens, api_kwargs penalty forwarding, NOUS_MODELS fallback Drift bugs fixed by the shared flow (#10582-class divergence): - openrouter/nous accessed .role/.content on dict messages (AttributeError on every call); nous passed nonexistent model_name=/provider_name= kwargs to LLMResponse (TypeError violating the must-not-raise contract) - openrouter/nous gain tool wiring, finish_reason/processing_time/ request_id/total_tokens population, and reasoning_content capture - streaming now builds the same payload as non-streaming (top_p/stop/tools were silently dropped from openai/groq streams) and raises on error instead of yielding error text into the output stream (openrouter/nous) Breaker seam untouched: circuit-breaker accounting stays in BaseProvider._guarded_completion (GH#11488); _chat_completion_impl still returns errors via LLMResponse.error. Module paths, class names, provider ids, and registry/adapter construction sites are unchanged.
Contributor
✅ SSOT Configuration Compliance: Passing🎉 No hardcoded values detected that have SSOT config equivalents! |
This was referenced Jul 15, 2026
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.
Closes #11517
Thinking Path
Five near-identical OpenAI-compatible providers each hand-rolled request-building, response-mapping, tool-call parsing, and streaming — and had drifted. New
OpenAICompatibleProvider(BaseProvider)owns the shared flow; each provider is a thin subclass carrying only its genuine deltas. Module paths, class names, andprovider_nameids are unchanged (config compatibility), so registry/adapters/re-exports needed zero changes.What Changed
llm_shared/providers/openai_compatible.py(283 lines) replaces ~750 lines of duplicated flow acrossopenai.py,groq.py,custom_openai.py,openrouter.py,nous_portal.py(net −381).Verification
BaseProvider._guarded_completion;_chat_completion_implreturns viaLLMResponse.error;TestNoMethodLevelBreakerguard passes (repo rule: method-level breaker decorators are inert).llm_shared.providers) — the real-load runs are the stricter verification.Model Used
Claude Fable 5 (subagent: general-purpose)