Conversation
Adds an orcarouter: provider to the pipeline LLM provider registry (opencontractserver/pipeline/llm_providers/orcarouter_provider.py) mirroring the OpenAI provider pattern. OrcaRouter is an OpenAI-compatible model routing gateway; model specs like orcarouter:orcarouter/auto reuse the existing pydantic-ai OpenAI client path. pydantic-ai has no native orcarouter: prefix, so opencontractserver/llms/model_factory.py now always constructs a concrete OpenAI-compatible model for this provider instead of returning a bare spec string (which would raise 'Unknown model'). DB-configured credentials win; otherwise ORCAROUTER_API_KEY and the default endpoint https://api.orcarouter.ai/v1 are used. Docs: model-spec table + API-keys section in docs/architecture/llms/README.md, ORCAROUTER_API_KEY in the production sample env. Changelog fragment added. Signed-off-by: XiaoHuo888-hue <jinhao.song@myflashcloud.com>
- Never pass api_key=None to OpenAIProvider for OrcaRouter: the OpenAI client would fall back to OPENAI_API_KEY and send the install's OpenAI secret to the third-party gateway. Use an inert placeholder + warning. - Extract _is_valid_base_url() so the base_url scheme check lives in one place for every provider; move OrcaRouter construction to its own helper. - Warn when a routed model belongs to a Responses-API-only family. - Offer only orcarouter/auto in the picker, with a conservative 64K context-window entry (fixes test_every_supported_model_has_a_context_window). - Update docs/test script provider counts and the changelog fragment.
ReviewSolid, well-scoped PR — carries the OrcaRouter provider forward from #2275 and closes the two real blockers (API-key leak to Findings1. (Low/Medium) The module's "construction failure always degrades safely" invariant doesn't hold for OrcaRouter 2. (Low, consistency nit) 3. (Nit) Hardcoded Other notes
None of the findings above block merging — they're narrow edge cases in the failure path, not the happy path this PR is shipping. The CLA/authorship question flagged in the PR description is a maintainer decision, not a code issue. |
…ing an unresolvable spec
|
Addressed in
On the context-window note: yes, that's intended. Only the Generated by Claude Code |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…dels listing
Replaces the hardcoded orcarouter/auto MODEL_CONTEXT_WINDOWS entry. Agent
builds fetch GET {base_url}/models (TTL-cached, short timeout, no redirects,
never raises) and get_context_window_for_model serves orcarouter: specs from
that cache without I/O, falling back to ORCAROUTER_FALLBACK_CONTEXT_WINDOW.
…ad of module globals
ReviewSolid PR — this carries over the OrcaRouter provider from #2275 and fixes real problems in it (the One correctness concern I'd like addressed before merge, plus a couple of smaller notes. Correctness:
|
…riginal prefix stripping
|
Addressed in
Generated by Claude Code |
Summary
Carries the OrcaRouter provider from fork PR #2275 (original commit cherry-picked with its authorship intact) and fixes the blockers and smaller items from the maintainer review on that PR. The fork PR could not get CI beyond
CLAAssistant: fork workflows need approval, and the CLA check fails because the commit email isn't linked to a GitHub account.Note: #2275's CLA is still unsigned. This PR includes the contributor's original commit, so a maintainer needs to decide whether that's acceptable before merging.
Changes
opencontractserver/llms/model_factory.py::_construct_orcarouter_modelnever passesapi_key=NonetoOpenAIProvider. When it did, the OpenAI client fell back toOPENAI_API_KEYand sent the install's OpenAI secret toapi.orcarouter.ai. With no key configured it now sends an inert placeholder (ORCAROUTER_API_KEY_PLACEHOLDER) and logs a static warning.opencontractserver/llms/orcarouter_context.pyfetches OrcaRouter'sGET {base_url}/modelswhen the agent model is built and reads each model'scontext_length,context_windowormax_context_length. The fetch is TTL-cached, has a 3s timeout, doesn't follow redirects, and never raises (including onhttpx.InvalidURL).get_context_window_for_modelservesorcarouter:specs from that cache with no I/O, and falls back toORCAROUTER_FALLBACK_CONTEXT_WINDOW(64K) until a listing is available.supported_modelsis cut down to("orcarouter/auto",). The eight speculativevendor/modelnames had no verified windows. Specific routed models can still be typed as a spec.orcarouter:spec, which pydantic-ai can't resolve.base_urlscheme check is now one helper,_is_valid_base_url().openai/gpt-5.6-luna).ORCAROUTER_PROVIDER_KEY,ORCAROUTER_API_KEY_ENV_VARandORCAROUTER_API_KEY_PLACEHOLDERare in the provider module. The fallback window, cache TTL, fetch timeout and response keys are inconstants/context_guardrails.py.docs/architecture/llms/README.md, the provider count indocs/test_scripts/llm_runtime_config.md, and the changelog fragment.Test plan
opencontractserver/tests/test_orcarouter_context.py. Unit tests drive the fetch through a realhttpx.Clientoverhttpx.MockTransport. They cover parsing, sending the key only to/models, no redirects, TTL reuse and refetch, HTTP, network, malformed-URL and non-JSON failures, and fallback. An integration test builds an agent model and then checks the window lookup.test_llm_model_factory.pycovers the key-leak regression, DB-wins precedence, invalidbase_urlfallback, the Responses-family warning, build failures surfacing, the refresh being invoked with the resolved endpoint, and_is_valid_base_url.pre-commitreports no failures on the changed files. CI, including the full backendpytest, is green.Checklist
pre-commit runpasses on the changed files (black, isort, flake8, mypy)changelog.d/pydantic-ai-slim[openai]andhttpxContributor License Agreement
By submitting this pull request, you agree to license your contribution under the project's Contributor License Agreement.