Repository navigation
feat(providers): add Cortecs as an OpenAI-compatible provider - #43872
Conversation
Co-authored-by: markoarnauto <7702545+markoarnauto@users.noreply.github.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
|
|
|
| "cortecs": { | ||
| "base_url": "https://api.cortecs.ai/v1", | ||
| "api_key_env": "CORTECS_API_KEY", | ||
| "api_base_env": "CORTECS_API_BASE", | ||
| "supported_endpoints": ["/v1/chat/completions", "/v1/responses", "/v1/messages"] | ||
| }, | ||
| "pinstripes": { |
There was a problem hiding this comment.
Cortecs usage records zero spend
If a Cortecs deployment has no custom pricing, a successful call to cortecs/gpt-6-sol has no matching provider-specific cost entry. Cost calculation returns no cost, and the proxy records $0 spend despite reported token usage. Key and team budgets based on accumulated spend therefore cannot cap this usage. Add pricing or require explicit pricing for billable Cortecs deployments.
| monkeypatch.setattr(litellm, "disable_aiohttp_transport", True) | ||
| monkeypatch.setattr(litellm, "in_memory_llm_clients_cache", LLMClientCache()) | ||
| with respx.mock() as upstream: | ||
| route: Final = upstream.post("https://api.cortecs.ai/v1/messages").respond( | ||
| 200, |
There was a problem hiding this comment.
Streaming routes lack test coverage
The new request tests cover only non-streaming calls, although Cortecs is registered for chat completions, Responses, and Messages. A broken streaming URL, transport, or event parser on any of these routes would pass this suite. Please add mocked streaming tests for the advertised endpoints.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…ject_key_prefix * upstream/main: (62 commits) fix(guardrails): scan Responses API input in Azure Prompt Shield (BerriAI#43786) feat(lens): investigate sampled traces and retain batch results (BerriAI#43942) fix(proxy): restore pre-config-wins handling of pass-through endpoints (BerriAI#43962) fix(cost-map): raise baseten DeepSeek-V4.1-Flash max output to 262144 (BerriAI#43916) chore(cost-map): add deprecation date for anthropic claude-sonnet-4-5 (BerriAI#43898) chore(cost-map): add fireworks inkling priority prices from the prices api (BerriAI#43949) feat(guardrails): honor litellm_params.timeout in every HTTP guardrail (BerriAI#43134) test(e2e): typed per-test metadata for the e2e suite (BerriAI#42044) fix(caching): write the response-cache SET to Redis at once instead of on the post-call batch (BerriAI#43973) feat(ui): filter tags by name and description on the Tag Management page (BerriAI#42949) feat(providers): add Cortecs as an OpenAI-compatible provider (BerriAI#43872) feat(e2e): record each e2e test's steps, starting with ProxyClient (BerriAI#42393) test(ci): repair stale tests and move retired OpenAI text-completion fixtures (BerriAI#43958) feat(proxy): record in spend logs whether a request used a client-forwarded Anthropic OAuth token (BerriAI#43063) fix(azure_storage): keep the DataLakeServiceClient alive until its TTL elapses (BerriAI#43082) chore(deps): bump gitpython and tornado, extend diskcache osv ignore to Nov 1 (BerriAI#43961) fix(guardrails): treat an unknown straiker api_version as unset instead of skipping the guardrail (BerriAI#43956) fix(azure_storage): name Data Lake objects without base64 padding or slashes (BerriAI#43914) fix(grayswan): send request conversation and tool calls to post-call monitor (BerriAI#43770) chore(cost-map): sync openrouter prices from the models API (BerriAI#43950) ...
TLDR
Problem this solves:
How it solves it:
cortecsas a JSON-configured OpenAI-compatible providerhttps://api.cortecs.ai/v1User Flow
Before: a proxy admin who adds a Cortecs model gets a provider error and no working deployment
model: cortecs/gpt-6-solwith their Cortecs key to the proxy config and start the proxyLLM Provider NOT providedfor that model at boot/v1/responses,/v1/messages) returns 400 "no healthy deployments"After: the same config serves Cortecs on all three endpoints
model: cortecs/gpt-6-solwithCORTECS_API_KEYto the proxy config and start the proxy/v1/responses, and/v1/messagesare forwarded tohttps://api.cortecs.ai/v1Relevant issues
Supersedes #26971 and #24801 by @markoarnauto, credited as co-author
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/unit/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Live proxy (
litellm.proxy.proxy_cli, DB-free,master_key=sk-1234) with one modelcortecs-gpt->cortecs/gpt-6-sol,CORTECS_API_KEY=sk-not-a-real-key. No real Cortecs key exists, so success here means the request reachesapi.cortecs.aiand comes back with Cortecs's own401 auth_errorinstead of litellm failing to resolve the provider.Proxy config (
/home/ubuntu/cortecs_proxy_config.yaml):Run with
DATABASE_URL/DIRECT_URLunset,CORTECS_API_KEY=sk-not-a-real-keyexported:Before (9dda4d8)
On
main,cortecs/gpt-6-solresolves no provider. The router logslitellm.BadRequestError: LLM Provider NOT provided. ... You passed model=cortecs/gpt-6-solat boot and the deployment is never created, so every route returns "no healthy deployments". (Proxy run from a git worktree at this sha solitellmimports the main checkout.)Chat completions
{"error":{"message":"litellm.BadRequestError: You passed in model=cortecs-gpt. There are no healthy deployments for this model\n\nLiteLLM: model group 'cortecs-gpt' failed with the error above. No fallback was attempted.","type":"invalid_request_error","param":null,"code":"400"}}Responses
{"error":{"message":"litellm.BadRequestError: You passed in model=cortecs-gpt. There are no healthy deployments for this model\n\nLiteLLM: model group 'cortecs-gpt' failed with the error above. No fallback was attempted.","type":"invalid_request_error","param":null,"code":"400"}}Messages
{"type":"error","error":{"type":"invalid_request_error","message":"litellm.BadRequestError: You passed in model=cortecs-gpt. There are no healthy deployments for this model\n\nLiteLLM: model group 'cortecs-gpt' failed with the error above. No fallback was attempted."}}After (a84b627)
Each endpoint reaches
https://api.cortecs.ai/v1/<path>and returns Cortecs's own401 auth_error, which is the response a customer would see with a bad key. (Each capture used a freshly restarted proxy, since the first 401 puts the deployment in router cooldown.)Chat completions
{"error":{"message":"litellm.AuthenticationError: AuthenticationError: CortecsException - Unauthorized\n\nLiteLLM: model group 'cortecs-gpt' failed with the error above. No fallback was attempted.","type":"authentication_error","param":null,"code":"401"}}Responses
{"error":{"message":"litellm.AuthenticationError: AuthenticationError: CortecsException - {\"error\":{\"message\":\"Unauthorized\",\"type\":\"auth_error\",\"param\":\"None\",\"code\":\"401\"}}\n\nLiteLLM: model group 'cortecs-gpt' failed with the error above. No fallback was attempted.","type":"authentication_error","param":null,"code":"401"}}Messages
{"type":"error","error":{"type":"authentication_error","message":"litellm.AuthenticationError: AuthenticationError: CortecsException - {\"error\":{\"message\":\"Unauthorized\",\"type\":\"auth_error\",\"param\":\"None\",\"code\":\"401\"}}\n\nLiteLLM: model group 'cortecs-gpt' failed with the error above. No fallback was attempted."}}Add Model form lists Cortecs
{ "provider": "CORTECS", "provider_display_name": "Cortecs", "litellm_provider": "cortecs", "credential_fields": [ {"key": "api_base", "label": "API Base", "placeholder": "https://api.cortecs.ai/v1", "required": false, "field_type": "text"}, {"key": "api_key", "label": "API Key", "placeholder": null, "required": true, "field_type": "password"} ], "default_model_placeholder": "cortecs/gpt-6-sol" }Unit tests:
tests/unit/llms/openai_like/test_cortecs_provider.pycovers env and explicit credential resolution, the Add Model form entry, the endpoint matrix, and respx-captured chat, Responses, and Messages requests. Mutation check: changingbase_urlto/v2turns 4 tests red, and dropping/v1/responsesfromsupported_endpointsturns the Responses test redType
🆕 New Feature
Caveats (if any)
Medium
Low
embedding()todaydocs/providers/cortecslands in a separate litellm-docs PRFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/5f14fda38083472abc8ac2d183c1e19a
Open in Devin Desktop: https://app.devin.ai/desktop/session/5f14fda38083472abc8ac2d183c1e19a?variant=devin
Requested by: @krrish-berri-2