Repository navigation
feat(providers): add Umans AI as an OpenAI-compatible provider - #44400
jcraftsman wants to merge 4 commits into
Conversation
|
| "scx-ai", | ||
| "prism", | ||
| "sail", | ||
| "umans-ai", |
There was a problem hiding this comment.
Unsupported audio reaches Umans
Adding umans-ai to openai_compatible_providers also adds it to the audio-transcription provider set. An audio-transcription call for an Umans model is then sent to Umans /v1/audio/transcriptions, even though this PR marks transcription unsupported. Keeping transcription dispatch separate would avoid sending audio to an unsupported endpoint.
Knowledge Base Used: Provider adapters and capabilities
There was a problem hiding this comment.
Every JSON provider in openai_compatible_providers shares this, so a Umans-only exclusion would be inconsistent. Umans answers transcription requests with a 404
There was a problem hiding this comment.
That’s fair context. The important distinction is that provider_endpoints_support.json is metadata and does not gate SDK dispatch: because OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS is derived directly from openai_compatible_providers, an Umans transcription call is still classified as supported and makes a network request to /v1/audio/transcriptions; the upstream 404 is not a LiteLLM-side fast-fail.
However, this is shared behavior for all JSON-configured OpenAI-compatible providers, and adding a one-off exclusion here would be inconsistent and require a broader refactor of the derived provider sets. I’m withdrawing this as a blocking issue; the current implementation is reasonable given the existing architecture.
Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.
There was a problem hiding this comment.
That’s fair. Since openai_compatible_providers is also used for transcription dispatch for every JSON-configured OpenAI-compatible provider, excluding only umans-ai would be inconsistent; the upstream 404 is the established behavior for unsupported operations. I’m withdrawing this finding—no Umans-specific change is needed here.
Merging this PR will not alter performance
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
4a95581 to
4b04d3c
Compare
| return json.load(f) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize(("model", "input_cost", "output_cost", "cache_read_cost"), UMANS_PRICING) |
There was a problem hiding this comment.
Vendor prices pinned in tests These assertions pin seven vendor prices. The test guide requires an invariant or a dated source beside outside facts; satisfy that requirement before merging.
Context Used: AGENTS.md (source)
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!
There was a problem hiding this comment.
Replaced the pinned prices with invariants: main and backup agree, every entry is priced, the default model is priced, and billing uses map rates
|
|
||
|
|
||
| UMANS_PRICING: Final = ( | ||
| # model, then USD per token for input, output and cache read (app.umans.ai/pricing) |
There was a problem hiding this comment.
Disallowed explanatory comment This comment only labels tuple fields and the price source. Repository guidance prohibits such source comments; remove it before merging.
| # model, then USD per token for input, output and cache read (app.umans.ai/pricing) |
Context Used: AGENTS.md (source)
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!
There was a problem hiding this comment.
Removed. The pricing tuple and its comment are gone, and the new invariant tests carry no explanatory comments
e5bd038 to
0e2ed9a
Compare
0e2ed9a to
d3ab5d0
Compare
4b0151b to
c543fad
Compare
Adds cost map entries (main and bundled backup) for the six public Umans AI models at the rates on app.umans.ai/pricing, so proxy spend and budgets count Umans usage. Adds streaming tests for chat completions, Responses and Anthropic Messages.
Adds the umans-ai/umans-glm-5.3 cost map entry (main and bundled backup) at the rates on app.umans.ai/pricing and covers it in the pricing test.
…d prices Replaces literal vendor prices with checks LiteLLM owns: main and backup agree, every entry is a priced chat model, the Add Model default model is priced, and billing (cache reads included) uses the cost map rates. Marks test locals Final and types the SSE helpers as read-only mappings.
c543fad to
b7a1177
Compare
TLDR
Problem this solves:
openai/plusapi_basefor every Umans modelHow it solves it:
umans-aias a JSON-configured OpenAI-compatible providerhttps://api.code.umans.ai/v1User Flow
Before: a proxy admin who adds a Umans AI model gets a provider error and no working deployment
model: umans-ai/umans-deepseek-v4-flash-0731with their Umans AI 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 Umans AI on all three endpoints
model: umans-ai/umans-deepseek-v4-flash-0731withUMANS_AI_API_KEYto the proxy config and start the proxy/v1/responses, and/v1/messagesare forwarded tohttps://api.code.umans.ai/v1Pre-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 modelumans-flash->umans-ai/umans-deepseek-v4-flash-0731,UMANS_AI_API_KEY=sk-not-a-real-key. The proof uses a placeholder key, so success here means the request reachesapi.code.umans.aiand comes back with Umans AI's own401 authentication_errorinstead of litellm failing to resolve the providerProxy config:
Run with
DATABASE_URL/DIRECT_URLunset,UMANS_AI_API_KEY=sk-not-a-real-keyexported:The proxy appends a generic routing note to each error message below, trimmed here for readability
Before (b024950)
On
main,umans-ai/umans-deepseek-v4-flash-0731resolves no provider. The router logsLLM Provider NOT provided. Pass in the LLM provider you are trying to callat boot and the deployment is never created, so every route returns "no healthy deployments"Chat completions
{"error":{"message":"litellm.BadRequestError: You passed in model=umans-flash. There are no healthy deployments for this model","type":"invalid_request_error","param":null,"code":"400"}}Responses
{"error":{"message":"litellm.BadRequestError: You passed in model=umans-flash. There are no healthy deployments for this model","type":"invalid_request_error","param":null,"code":"400"}}Messages
{"type":"error","error":{"type":"invalid_request_error","message":"litellm.BadRequestError: You passed in model=umans-flash. There are no healthy deployments for this model"}}Add Model form lists Umans AI
After (a8c58cc)
Each endpoint reaches
https://api.code.umans.ai/v1/<path>and returns Umans AI's own401 authentication_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: Umans-aiException - Invalid API key","type":"authentication_error","param":null,"code":"401"}}Responses
{"error":{"message":"litellm.AuthenticationError: AuthenticationError: Umans-aiException - {\"error\":{\"type\":\"authentication_error\",\"message\":\"Invalid API key\"}}","type":"authentication_error","param":null,"code":"401"}}Messages
{"type":"error","error":{"type":"authentication_error","message":"litellm.AuthenticationError: AuthenticationError: Umans-aiException - {\"error\":{\"type\":\"authentication_error\",\"message\":\"Invalid API key\"}}"}}Add Model form lists Umans AI
{ "provider": "UMANS_AI", "provider_display_name": "Umans AI", "litellm_provider": "umans-ai", "credential_fields": [ {"key": "api_base", "label": "API Base", "placeholder": "https://api.code.umans.ai/v1", "required": false, "field_type": "text"}, {"key": "api_key", "label": "API Key", "placeholder": null, "required": true, "field_type": "password"} ], "default_model_placeholder": "umans-ai/umans-deepseek-v4-flash-0731" }Unit tests:
tests/unit/llms/openai_like/test_umans_ai_provider.pycovers env and explicit credential resolution, the Add Model form entry, the endpoint matrix, respx-captured chat, Responses, and Messages requests in both non-streaming and streaming mode, and cost map invariants: main matches backup, every entry is a priced chat model, the Add Model default model is priced, and billing with cache reads uses the map rates (13 tests). Also passing locally: all oftests/unit/llms/openai_like/(232 tests),test_aaamodel_prices_and_context_window_json_is_valid, plustests/unit/litellm_core_utils/test_get_llm_provider_logic.pyandtest_exception_mapping_utils.py(1,276 tests). Mutation checks: changingbase_urlto/v2turns 7 tests red, and changing one price in the backup map turns both cost map tests redType
🆕 New Feature
Caveats (if any)
Medium
Low
docs/providers/umans_ainot included hereFinal Attestation