Skip to content

feat(providers): add SCX.ai as a JSON-configured OpenAI-compatible provider - #34752

Open
bhuvan2134686 wants to merge 5 commits into
BerriAI:litellm_internal_stagingfrom
SouthernCrossAI:litellm_scx_ai_provider
Open

feat(providers): add SCX.ai as a JSON-configured OpenAI-compatible provider#34752
bhuvan2134686 wants to merge 5 commits into
BerriAI:litellm_internal_stagingfrom
SouthernCrossAI:litellm_scx_ai_provider

Conversation

@bhuvan2134686

@bhuvan2134686 bhuvan2134686 commented Jul 27, 2026

Copy link
Copy Markdown

TLDR

Problem this solves:

  • SCX.ai has no first class support in LiteLLM, so callers have to route through openai/ with a custom api_base and lose provider naming, cost tracking, the endpoint support matrix and the Add Model entry in the dashboard
  • SCX.ai caps temperature at 1.0 and takes max_tokens rather than max_completion_tokens, so requests that pass either straight through get rejected upstream

How it solves it:

  • Registers scx-ai through the JSON provider registry in litellm/llms/openai_like/providers.json, expressing the temperature ceiling as a constraint and mapping max_completion_tokens to max_tokens, so no Python transformation module is needed
  • Adds the five chat models to the cost map, the provider to the endpoint support matrix, and the provider to both the dashboard display metadata and the create-fields metadata that populates the Add Model dropdown

Relevant issues

N/A, this adds a new OpenAI-compatible provider

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to 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 on localhost:4000 against the real SCX.ai API, no mocks, started with

LITELLM_LOCAL_MODEL_COST_MAP=True python litellm/proxy/proxy_cli.py --config scx_config.yaml --port 4000
model_list:
  - model_name: scx-gpt-oss-120b
    litellm_params:
      model: scx-ai/gpt-oss-120b
      api_key: os.environ/SCX_API_KEY
  - model_name: scx-gemma-4
    litellm_params:
      model: scx-ai/gemma-4-31B-it
      api_key: os.environ/SCX_API_KEY
  - model_name: scx-llama-4-maverick
    litellm_params:
      model: scx-ai/Llama-4-Maverick-17B-128E-Instruct
      api_key: os.environ/SCX_API_KEY
  - model_name: scx-minimax-m2.7
    litellm_params:
      model: scx-ai/MiniMax-M2.7
      api_key: os.environ/SCX_API_KEY
  - model_name: scx-qwen3-32b
    litellm_params:
      model: scx-ai/Qwen3-32B
      api_key: os.environ/SCX_API_KEY

general_settings:
  master_key: sk-1234

Every model answers and cost tracking resolves from the new price map entries

$ for m in scx-gpt-oss-120b scx-gemma-4 scx-llama-4-maverick scx-minimax-m2.7 scx-qwen3-32b; do
    curl -sS -D /tmp/h_$m.txt http://localhost:4000/v1/chat/completions \
      -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
      -d "{\"model\":\"$m\",\"messages\":[{\"role\":\"user\",\"content\":\"Reply with exactly: hello from SCX\"}],\"max_tokens\":1024}" \
      | jq -c "{m:\"$m\", content: .choices[0].message.content, pt: .usage.prompt_tokens, ct: .usage.completion_tokens}"
    grep -i "^x-litellm-response-cost:" /tmp/h_$m.txt
  done

{"m":"scx-gpt-oss-120b","content":"hello from SCX","pt":89,"ct":44}
x-litellm-response-cost: 3.9330000000000005e-05
{"m":"scx-gemma-4","content":"hello from SCX","pt":35,"ct":4}
x-litellm-response-cost: 1.414e-05
{"m":"scx-llama-4-maverick","content":"hello from SCX","pt":18,"ct":4}
x-litellm-response-cost: 1.602e-05
{"m":"scx-minimax-m2.7","content":"\n\nhello from SCX","pt":46,"ct":126}
x-litellm-response-cost: 0.00024762
{"m":"scx-qwen3-32b","content":"\n\nhello from SCX","pt":16,"ct":393}
x-litellm-response-cost: 0.00034767

The gemma-4 figure checks out by hand against the committed rates, 35 prompt tokens at $0.30 per million plus 4 completion tokens at $0.91 per million is $1.414e-05

Tool calling round trips

$ curl -sS http://localhost:4000/v1/chat/completions \
    -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
    -d '{"model":"scx-gemma-4","messages":[{"role":"user","content":"What is the weather in Sydney? Use the tool."}],"tools":[{"type":"function","function":{"name":"get_weather","description":"Get the weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}],"max_tokens":128}' \
    | jq -c '.choices[0].message.tool_calls[0].function'

{"arguments":"{\"city\":\"Sydney\"}","name":"get_weather"}

A temperature above the provider ceiling is clamped by the constraint rather than sent upstream and rejected

$ curl -sS http://localhost:4000/v1/chat/completions \
    -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
    -d '{"model":"scx-gemma-4","messages":[{"role":"user","content":"say ok"}],"temperature":1.7,"max_tokens":16}' \
    | jq -c '{content: .choices[0].message.content, error: .error.message}'

{"content":"ok","error":null}

Streaming

$ curl -sS -N http://localhost:4000/v1/chat/completions \
    -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
    -d '{"model":"scx-gemma-4","messages":[{"role":"user","content":"Count 1 to 3."}],"stream":true,"max_tokens":64}' | head -3

data: {"id":"76dfe914-c080-4c13-bbf3-d84ada45aef8","created":1785136143,"model":"scx-gemma-4","object":"chat.completion.chunk","system_fingerprint":"fastcoe","choices":[{"index":0,"delta":{"content":"1","role":"assistant"}}]}

data: {"id":"76dfe914-c080-4c13-bbf3-d84ada45aef8","created":1785136143,"model":"scx-gemma-4","object":"chat.completion.chunk","system_fingerprint":"fastcoe","choices":[{"index":0,"delta":{"content":", 2, 3"}}]}

Health check

$ curl -sS "http://localhost:4000/health?model=scx-gemma-4" -H "Authorization: Bearer sk-1234" \
    | jq -c '{healthy: (.healthy_endpoints|length), unhealthy: (.unhealthy_endpoints|length)}'

{"healthy":1,"unhealthy":0}

The metadata the Add Model form renders now includes the provider, which is what makes it selectable in the dropdown

$ curl -sS http://localhost:4000/public/providers/fields | jq -c '.[] | select(.litellm_provider=="scx-ai")'

{"provider":"SCX_AI","provider_display_name":"SCX.ai","litellm_provider":"scx-ai","credential_fields":[{"key":"api_base","label":"API Base","placeholder":"https://api.scx.ai/v1","tooltip":null,"required":false,"field_type":"text","options":null,"default_value":null},{"key":"api_key","label":"API Key","placeholder":null,"tooltip":null,"required":true,"field_type":"password","options":null,"default_value":null}],"default_model_placeholder":"scx-ai/gpt-oss-120b"}

With that proxy running and npm run dev in ui/litellm-dashboard, go to http://localhost:3000/ui/?page=llm-playground, open Models and Endpoints, then Add Model, and pick SCX.ai from the Provider dropdown; it renders with the SCX logo, asks for an API key and offers the api base override

Type

New Feature

Changes

The provider is registered as JSON config rather than a Python module, since the SCX.ai API is OpenAI compatible and needs no custom authentication, transformation or streaming logic. The entry in providers.json carries the base URL, the SCX_API_KEY environment variable, the SCX_API_BASE override, the max_completion_tokens to max_tokens mapping and a temperature_max constraint of 1.0

Beyond that, scx-ai goes into LlmProviders, into openai_compatible_providers and openai_compatible_endpoints, into the https://api.scx.ai/v1 autodetection branch in get_llm_provider_logic.py so an api base alone resolves the provider, and into the endpoint support matrix along with the packaged backup copy the proxy serves from /public/endpoints. Five chat models land in the cost map with published USD rates, context limits and capability flags, MiniMax-M2.7 also carrying the published cached input rate; those flags are what let tools and reasoning_effort through, since LiteLLM derives support for both from the cost map

On the dashboard side the provider needs two things, the display metadata and logo in provider_info_helpers.tsx, and an entry in provider_create_fields.json, which is the static metadata the Add Model form renders from /public/providers/fields. Without the second one the display mapping is unreachable and the provider cannot be picked, so both are included

Tests live in tests/test_litellm/llms/openai_like/test_scx_ai_provider.py and cover provider registration, the JSON config values, model prefix resolution, api base override and endpoint autodetection, the temperature clamp in both the clamped and unclamped direction, the parameter mapping, router configuration, that every listed model is present in both the root and backup cost maps with matching metadata, and that the create-fields entry the dropdown depends on exists with the right key, display name and credential fields. The dashboard test in provider_info_helpers.test.tsx asserts SCX.ai resolves from both the slug and the enum key, since the Add Model dropdown passes the enum key while the backend passes the slug

I work at SCX.ai

QA runbook

Export SCX_API_KEY, start the proxy with the config above, then run the curl commands in the proof section. All five deployments should answer with non zero cost headers, the tool call should come back as a get_weather call, the temperature 1.7 request should succeed rather than error, /health should report the deployment healthy, and /public/providers/fields should include the scx-ai entry

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@CLAassistant

CLAassistant commented Jul 27, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds SCX.ai as a JSON-configured OpenAI-compatible provider

  • Registers provider resolution, request constraints, endpoint support, model pricing, and capability metadata
  • Adds dashboard provider metadata, credential fields, logo mappings, and provider integration tests

Confidence Score: 4/5

The PR appears safe to merge, with only a misleading Add Model placeholder remaining

Selecting SCX.ai now works, but the model field falls back to the generic gpt-3.5-turbo placeholder instead of showing the SCX model identifier declared in provider metadata

Files Needing Attention: ui/litellm-dashboard/src/components/provider_info_helpers.tsx

Important Files Changed

Filename Overview
litellm/llms/openai_like/providers.json Registers SCX.ai chat completions with its base URL, environment variables, token mapping, and temperature ceiling
litellm/proxy/public_endpoints/provider_create_fields.json Adds the SCX.ai provider and credential metadata required by the Add Model dropdown
ui/litellm-dashboard/src/components/provider_info_helpers.tsx Adds SCX.ai display and logo mappings
model_prices_and_context_window.json Adds pricing, context limits, and capabilities for five SCX.ai chat models
tests/test_litellm/llms/openai_like/test_scx_ai_provider.py Covers provider registration, parameter transformation, model metadata synchronization, and dashboard selection metadata

Reviews (2): Last reviewed commit: "fix(ui): make SCX.ai selectable in the A..." | Re-trigger Greptile

@@ -260,6 +262,7 @@ export const provider_map: Record<string, string> = {
SageMaker: "sagemaker_chat",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 SCX missing from provider options

When an operator opens the Add Model provider dropdown, the form renders only entries returned by /public/providers/fields, whose static provider_create_fields.json data has no SCX.ai entry, so these new display mappings remain unreachable and SCX.ai cannot be selected

Knowledge Base Used: Admin dashboard (ui/litellm-dashboard)

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@bhuvan2134686

Copy link
Copy Markdown
Author

Good catch on the Add Model dropdown, the display mapping on its own was not enough. The provider is now in litellm/proxy/public_endpoints/provider_create_fields.json with a required API key and an optional api base, so /public/providers/fields returns it and the form can render it, plus a test in test_scx_ai_provider.py that fails if the entry ever goes missing

Verified against the live proxy

$ curl -sS http://localhost:4000/public/providers/fields | jq -c '.[] | select(.litellm_provider=="scx-ai")'

{"provider":"SCX_AI","provider_display_name":"SCX.ai","litellm_provider":"scx-ai","credential_fields":[{"key":"api_base","label":"API Base","placeholder":"https://api.scx.ai/v1","tooltip":null,"required":false,"field_type":"text","options":null,"default_value":null},{"key":"api_key","label":"API Key","placeholder":null,"tooltip":null,"required":true,"field_type":"password","options":null,"default_value":null}],"default_model_placeholder":"scx-ai/gpt-oss-120b"}

The same push adds the five chat models to the cost map with published rates and capability flags, which restores cost tracking and lets tools through, since supports_function_calling is derived from there. Tool calls now round trip against the live API

$ curl -sS http://localhost:4000/v1/chat/completions -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
    -d '{"model":"scx-gemma-4","messages":[{"role":"user","content":"What is the weather in Sydney? Use the tool."}],"tools":[{"type":"function","function":{"name":"get_weather","description":"Get the weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}],"max_tokens":128}' \
    | jq -c '.choices[0].message.tool_calls[0].function'

{"arguments":"{\"city\":\"Sydney\"}","name":"get_weather"}

The PR description is updated with the full run

@greptileai

@codspeed-hq

codspeed-hq Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing SouthernCrossAI:litellm_scx_ai_provider (b8e2848) with litellm_internal_staging (2412326)

Open in CodSpeed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants