feat(providers): OpenAI-compatible provider seam (+ Grok/xAI, OpenRouter) - #79
Merged
Merged
Conversation
…ter) Generalize OpenAIGateway (name/base_url/stop_reason_key, defaults byte-identical to the plain OpenAI path) and add an OPENAI_COMPATIBLE registry in composition so providers speaking the OpenAI Chat Completions wire format are a data row, not a new adapter. Register xai (reference) and openrouter (single-key live path). application/loop.py unchanged; the openai.py translation is reused verbatim. Closes #71.
7 tasks
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.
Summary
Turn the OpenAI adapter into a reusable OpenAI-compatible provider seam, so any provider
speaking the OpenAI Chat Completions wire format is a data row, not a new adapter. Ships Grok
(xAI) as the reference and OpenRouter as the single-key live/recording path. Closes #71 and
unblocks #72/#73/#74/#75.
Scope
providers/openai.py,composition.py), tests, docsChanges
OpenAIGatewaygeneralized in place — newname/base_url/stop_reason_keykwargs,all defaulting to today's plain-OpenAI behavior byte-for-byte.
namemoved from a class attr toan instance attr; the
@runtime_checkableModelGatewayProtocol still matches. No new class, noinheritance.
from_wiregainedstop_reason_key: str = "openai"— compat providers reuse OpenAI'sfinish-reason table, so
stop_reason.pyneeds no per-provider row. Provider identity(
name, which keysprovider:modelpricing) is decoupled from the wire family.composition.OPENAI_COMPATIBLEregistry (name → (base_url, env_var)) + onemake_gatewaybranch that iterates it. Adding Kimi/GLM/DeepSeek is now a single row. Registered
xai(
https://api.x.ai/v1,XAI_API_KEY) andopenrouter(https://openrouter.ai/api/v1,OPENROUTER_API_KEY).application/loop.pyunchanged (load-bearing rule) — the seam is entirely at/below the port.Testing
sys.modules["openai"]and assert the capturedbase_url/api_keykwargs — no network, no key.test_openrouter_live.py,@pytest.mark.live, skipped in CI) does a two-turntool-calling exchange through OpenRouter; point it at any model with
DRYFIRE_OPENROUTER_MODEL.Quality gate
make checkpasses locallymake arch) — no new import-linter exceptionsunittest.mockoutsidetests/contracts/Scope discipline
Public contracts
provider: xai/provider: openrouterare new values of theexisting free-form
provider:field, not a schema changeDocs
docs/Progress.mdupdated (v0.4 In-Progress section; Provider: OpenAI-compatible provider seam (+ Grok/xAI reference) #71 code-complete)docs/Learnings.mdappended (compat-seam findings)Risks
pricing.yamlcarries only Anthropic rows today;the OpenAI adapter (v0.2) is already unpriced, so cost is advisory
None. Fabricating xAI/OpenRouterprices offline would violate the "never a guess" rule and make
_meta.sourcewrong. Pricing is adata-only follow-up (or user
pricing_file).Follow-ups
openai_compatible(user-suppliedbase_url).