feat(providers): add AI Token King (aitokenking) OpenAI-compatible provider with pricing - #39732
feat(providers): add AI Token King (aitokenking) OpenAI-compatible provider with pricing#39732firekou wants to merge 3 commits into
Conversation
…ovider with pricing AI Token King (api.aitokenking.com.tw) is an OpenAI-compatible LLM gateway that resells 48 chat models from Anthropic, OpenAI, Google, Qwen, DeepSeek, Zhipu, Moonshot, MiniMax and ByteDance under one API key. Users could already point LiteLLM at it via `openai/<model>` + `api_base`, but with two problems this PR fixes: 1. Cost tracking silently reported 0.0. Router registers every deployment with `register_model`, so an unmapped gateway model gets a zero-cost entry and `response_cost` reads as "free" instead of "unknown". 2. The only workaround — registering the gateway's prices under `openai/<model>` — shadows the vendor entries already in the map (13 of the 48 ids collide, e.g. `gpt-5.5`, `claude-sonnet-5`), changing the cost reported for real OpenAI/Anthropic calls in the same process. Adding `aitokenking` as a JSON-configured provider gives the gateway its own namespace, so `aitokenking/qwen3.7-max` resolves the base URL, strips the prefix before sending, and prices from `aitokenking/*` without touching any vendor entry. Changes: - providers.json: `aitokenking` (chat completions only; base URL overridable via AITOKENKING_API_BASE) - LlmProviders enum, openai_compatible_providers, openai_compatible_endpoints - provider_endpoints_support.json entry - model_prices_and_context_window.json (+ backup): 48 chat models keyed `aitokenking/<id>` — input/output cost and max_input_tokens only. Fields the gateway does not publish (max_output_tokens, cache tiers, capability flags) are deliberately omitted rather than guessed. The gateway's 61 image/video models are excluded because it publishes no per-token price for them; an entry with cost 0 would read as free. - tests: provider resolution, URL autodetection, Router config, price-map shape, no vendor-entry shadowing, completion_cost resolves to a non-zero value for a prefixed model. Prices measured 2026-08-23 from the gateway's read-only /models endpoint; the unit (USD per 1M tokens) was cross-checked against two vendors' public list prices. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DBBj5ym47x1LmSxurSxbKH
Greptile SummaryThis PR registers AI Token King as a declarative OpenAI-compatible chat provider and adds provider-scoped pricing for 48 models
Confidence Score: 4/5The provider wiring appears correct, but the repository’s explicit comment and meaningful-test requirements must be satisfied before merging No production behavior defect was established, but the new tests do not exercise the advertised completion and Router response-cost flow, and several added comments violate repository guidance Files Needing Attention: litellm/constants.py; tests/test_litellm/llms/openai_like/test_aitokenking_provider.py
|
| Filename | Overview |
|---|---|
| litellm/llms/openai_like/providers.json | Adds a consistent declarative chat-provider configuration with default URL, credential variables, and token-limit parameter mapping |
| litellm/constants.py | Registers the provider slug and API base correctly, but adds a redundant source-code comment prohibited by repository guidance |
| litellm/types/utils.py | Adds the provider to the central LlmProviders enum |
| model_prices_and_context_window.json | Adds 48 provider-prefixed chat pricing records with positive input and output costs |
| litellm/model_prices_and_context_window_backup.json | Keeps the backup model-price catalog synchronized with the primary catalog |
| provider_endpoints_support.json | Declares chat-completions as the provider’s only supported endpoint family |
| tests/test_litellm/llms/openai_like/test_aitokenking_provider.py | Covers registration and isolated pricing arithmetic but omits the required functional completion and Router accounting regression path |
Reviews (1): Last reviewed commit: "feat(providers): add AI Token King (aito..." | Re-trigger Greptile
| "docker_model_runner", | ||
| "ragflow", | ||
| "pinstripes", # Pinstripes - JSON-configured provider | ||
| "aitokenking", # AI Token King - JSON-configured provider |
There was a problem hiding this comment.
These comments restate straightforward code, violating the directive to reserve comments for complex logic, tooling, or follow-up work. Remove before merging
Context Used: CLAUDE.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!
| def test_aitokenking_router_config(self): | ||
| from litellm import Router | ||
|
|
||
| router = Router( | ||
| model_list=[ | ||
| { | ||
| "model_name": "atk-chat", | ||
| "litellm_params": { | ||
| "model": "aitokenking/qwen3.7-max", | ||
| "api_key": "test-key", | ||
| }, | ||
| } | ||
| ] | ||
| ) | ||
|
|
||
| assert len(router.model_list) == 1 | ||
| assert router.model_list[0]["model_name"] == "atk-chat" |
There was a problem hiding this comment.
This only checks stored Router configuration, violating the requirement for functional tests. Exercise request dispatch and response-cost integration before merging
Context Used: CLAUDE.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!
| }, | ||
| "aitokenking": { | ||
| "base_url": "https://api.aitokenking.com.tw/api/v1", | ||
| "api_key_env": "AITOKENKING_API_KEY", |
There was a problem hiding this comment.
Medium: Provider key can be sent to a caller-controlled host
The generic JSON-provider resolver accepts the request's api_base but still falls back to this environment key when api_key is omitted. An authenticated caller can submit model: "aitokenking/..." with api_base: "https://attacker.example" and capture AITOKENKING_API_KEY from the resulting Authorization header. Require an explicit caller-supplied key whenever the base URL differs from the configured provider host, or reject such overrides before resolving the environment credential.
PR overviewThis pull request adds AI Token King as an OpenAI-compatible provider, including its provider configuration and pricing information. One security issue remains open: an authenticated caller can override the provider base URL and cause the configured AI Token King API key to be sent to a caller-controlled host. This creates a direct credential-exfiltration path when the environment credential is configured, and no issues have yet been addressed. Open issues (1)
Fixed/addressed: 0 · PR risk: 7/10 |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Review feedback: the comment restated the code. The neighbouring JSON-configured entries carry the same trailing comment, but the repo guideline is to reserve comments for non-obvious logic, so the new line drops it rather than adding one more instance.
… config Review feedback: the Router test only asserted the stored model list, which proves nothing about what happens when a request is actually routed. Replaces it with two functional tests through Router.acompletion, following the pattern already used by the neighbouring cognition provider tests: - the routed request resolves to the gateway base URL and the response model is the bare id, so the `aitokenking/` prefix selects the provider without reaching the wire; - the routed response is costed from the aitokenking price-map entry and is non-zero. This is the regression the price map exists to prevent: Router registers every deployment, so an unmapped gateway model reports 0.0, which reads as "free" rather than "unknown". Verified the cost assertion actually catches that regression: with the `aitokenking/qwen3.7-max` entry temporarily renamed the test fails, and it passes again once restored.
TLDR
Problem this solves:
response_cost = 0.0from Router (unmapped models)openai/<model>pricing) overwrites 13 real vendor price entriesHow it solves it:
aitokenkingas a JSON-configured OpenAI-compatible provideraitokenking/*, no vendor entry touchedUser Flow
Before: a developer routing through the gateway sees zero spend on every call
model: openai/qwen3.7-max,api_base: https://api.aitokenking.com.tw/api/v1and their gateway keyrouter.completion(...); the response comes back fine with real token usageresponse_costis0.0, so their spend dashboard shows $0 even though the gateway billed themmodel: aitokenking/qwen3.7-maxinstead, LiteLLM rejects it withLLM Provider NOT providedAfter: the same developer gets real spend with a one-line model string
model: aitokenking/qwen3.7-maxand their gateway key; noapi_baseneededhttps://api.aitokenking.com.tw/api/v1/chat/completionswith theaitokenking/prefix stripped and the key inAuthorizationresponse_costis computed fromaitokenking/qwen3.7-maxin the price map (100k in + 100k out → $1.00)gpt-5.5,claude-sonnet-5etc. used elsewhere in the same process are unchangedRelevant issues
None filed; this PR is the report.
Notes for reviewers
litellm/llms/openai_like/README.md): no Python logic added. URL autodetection reuses the existingJSONProviderRegistry.get_by_base_urlfallback.max_input_tokens,source).max_output_tokens, cache tiers and capability flags are omitted on purpose rather than guessed. The gateway's 61 image/video models are excluded because it publishes no per-token price for them; an entry with cost 0 would read as "free"./modelsendpoint; unit (USD per 1M tokens) cross-checked against Anthropic's public list prices for two models.Pre-Submission checklist
tests/test_litellm/llms/openai_like/test_aitokenking_provider.py(10 passed),tests/test_litellm/llms/openai_like/test_pinstripes_provider.py,tests/test_litellm/test_model_prices_schema.py(38 passed total);tests/code_coverage_tests/check_provider_folders_documented.pypassesScreenshots / Proof of Fix
Opened as a draft because the run below uses a local OpenAI-compatible mock server (fixed 100k/100k usage) rather than the live gateway. A live-gateway run will be added before marking ready for review.
Shared setup: a local mock at
http://127.0.0.1:<port>/v1that answers/chat/completionswithusage: {prompt_tokens: 100000, completion_tokens: 100000};LITELLM_LOCAL_MODEL_COST_MAP=Trueso the price map is read from the checkout.Before (4990f06)
litellm.completion(model="aitokenking/qwen3.7-max", api_base=<mock>, api_key="test")→
BadRequestError: LLM Provider NOT providedRouter(model_list=[{model: "openai/qwen3.7-max", api_base: <mock>}]).completion(...)(today's workaround)→
200,response_cost = 0.0Router(model_list=[{model: "aitokenking/qwen3.7-max", api_base: <mock>}]).completion(...)→
BadRequestError: LLM Provider NOT providedAfter (cc5c94f)
litellm.completion(model="aitokenking/qwen3.7-max", api_base=<mock>, api_key="test")→
200, model sent to gateway:qwen3.7-max,response_cost = 1.0Router(model_list=[{model: "openai/qwen3.7-max", api_base: <mock>}]).completion(...)(unchanged, still the old behaviour)→
200,response_cost = 0.0Router(model_list=[{model: "aitokenking/qwen3.7-max", api_base: <mock>}]).completion(...)→
200, model sent to gateway:qwen3.7-max,response_cost = 1.0(100k in + 100k out @ $2.5/$7.5 per 1M)Type
🆕 New Feature
Caveats (if any)
Low
/v1/chat/completionsis declared; the gateway's other endpoints are not claimed until verifieddocs/providers/aitokenkingreferenced inprovider_endpoints_support.jsonstill needs to be added in the docs repo/modelsendpoint is the source to refresh fromFinal Attestation
🤖 Generated with Claude Code