Repository navigation
Conversation
Add alibaba_token_plan/ for Alibaba Cloud Model Studio's Token Plan subscription: chat completions, Anthropic Messages and Responses through the plan's OpenAI- and Anthropic-compatible endpoints, plus image generation and editing, speech, transcription, 16 kHz realtime audio and HappyHorse video through its native endpoints. Registers the 21 plan models, endpoint metadata and Admin UI provider fields.
…slation Leave request validation to Alibaba instead of re-encoding its limits: drop the video model allow-list and parameter enumerations, the transcription format list, per-model image-edit rules, speech response branches the plan never returns, the realtime field-by-field rejections, and the gateway URL normalisation. One rule now maps the OpenAI-compatible api_base to every native endpoint, and image generation reuses the DashScope configuration like the QwenCloud route.
|
Merging this PR will not alter performance
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Reject realtime audio, sent through input_audio_buffer.append or as input_audio content in conversation.item.create, until the session has declared 16 kHz PCM16 input. Text-only and partial session updates stay allowed, and undeclared OpenAI-default 24 kHz audio is no longer forwarded as 16 kHz. Replace the recursive realtime event and image-reference helpers with explicit iterative mappings, register the chat config class directly, and make the provider test directories packages.
|
@greptileai Please re-review the updated provider branch at 57a7049, including the realtime audio validation fix and clarified credential guard |
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 2 · PR risk: 0/10 |
|
bugbot run |
|
@mateo-berri ready for review: Greptile 5/5, Veria clean, required checks green; documentation checks wait on docs PR BerriAI/litellm-docs#2085 |
…_plan # Conflicts: # litellm/litellm_core_utils/get_llm_provider_logic.py # litellm/model_prices_and_context_window_backup.json # model_prices_and_context_window.json # tests/unit/litellm_core_utils/test_realtime_streaming.py # tests/unit/proxy/public_endpoints/test_public_endpoints.py
Main now gates every lint and type rule on its merge-base count, only injects response.create when a transcript guardrail suppressed VAD (BerriAI#43791), and reads AsyncHTTPHandler.timeout on every post. Remove the Token Plan additions over those ceilings, assert the realtime relay no longer sends response.create, and build the TTS test handler through its public client setter.
Main now asserts every tests/unit/llms provider directory is claimed by a shard, so list alibaba_token_plan beside its alphabetical neighbours.
Token Plan only returns a plain transcript, so srt, vtt and verbose_json were silently answered as plain text. Accept json and text, and raise UnsupportedParamsError for anything else unless drop_params is set, matching the Vertex transcription config.
…ken Plan video Native extra_body input was spread after the top-level prompt, so a nested input.prompt could replace the text prompt guardrails had checked. Spread native input first and set the prompt last.
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit e40d8af. Configure here.
TLDR
Problem this solves:
How it solves it:
alibaba_token_plan/and 21 subscription modelsDocs: BerriAI/litellm-docs#2085
User Flow
Before: Token Plan is missing from Add Model and requests fail
Alibabachat.jsonreturns HTTP 400Invalid model name passedAfter: the same page offers Token Plan and its models
Alibabachat.jsonreturns HTTP 200 withpongRelevant issues
Relates to #36150, where the QwenCloud docs note that Token Plan endpoints were not yet mapped
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)Validation at
e40d8af8f2, after merging main:make checkand 629 focused tests passed. Earlier at5eae427b48, 1,103 focused tests and the recursion detector passed. Nine regression cases fail with thedbc41e65d9adapter and pass with the fixScreenshots / Proof of Fix
Current tip is
e40d8af8f2336fd9070ddb188c694fe539c57158. The 16 kHz realtime voice/tool proof ran at6538becb9eon 2026-10-10; the later commits only change CI sharding, transcription format validation and video prompt precedence. Earlier voice/tool verification ran at5eae427b48on 2026-10-05. API/UI captures remain at45d050e1c1, Terminal panes at6ac150fc7b, and rechecks at57a704962fanddbc41e65d9. Before remains at original merge base02f61c9c420b9aa9de10ff673098ad7132b78f5bThe proof appendix holds commands, payloads, realtime client code, fixtures and supporting captures. Successful calls hit the real Token Plan API
Start the proxy with
LITELLM_LOCAL_MODEL_COST_MAP=true, the Token Plan key and a random master key in its environment. In a second shell:Interactive Claude Code uses
ANTHROPIC_BASE_URL=http://localhost:4000,ANTHROPIC_AUTH_TOKEN=$LITELLM_MASTER_KEY,ANTHROPIC_MODEL=alibaba_token_plan/qwen3.8-maxandANTHROPIC_DEFAULT_HAIKU_MODEL=alibaba_token_plan/qwen3.8-flash. The appendix supplies the greeting fixtureBefore (02f61c9)
Admin UI provider selection
AlibabaClaude Code
Start interactive Claude Code with the shared settings and ask it to read the greeting fixture, reproduce the whitespace failures, edit only
greeting.py, then rerunpython3 -m unittest -vHTTP 400
anthropic_messages: Invalid model name passed in model=alibaba_token_plan/qwen3.8-max, before any tool call. The separate baseline proxy was stopped afterwardChat completions
post chat/completions @chat.json,post chat/completions @chat-stream.jsonandpost chat/completions @auto-tools.jsonInvalid model name passed, namingqwen3.8-max,qwen3.8-flashandautorespectivelyMessages
post messages @messages.jsonandpost messages @messages-stream.jsonanthropic_messages: Invalid model name passedResponses
post responses @responses.json/responses: Invalid model name passed in model=alibaba_token_plan/deepseek-v4-proImages
post images/generations @image-request.jsonandpost images/generations @image-b64.jsonInvalid model name passedforqwen-image-3.0-procurl -sS "$B/v1/images/edits" -H "$AUTH" -F model=alibaba_token_plan/wan2.7-image-pro -F 'image[]=@cube.png' -F 'image[]=@generated.png' -F 'prompt=Put both cubes side by side and make them blue' -F size=1024x1024Invalid model name passedforwan2.7-image-pro; this run used valid copied PNG fixturesSpeech and transcription
post audio/speech @speech.json, thencurl -sS "$B/v1/audio/transcriptions" -H "$AUTH" -F model=alibaba_token_plan/qwen-audio-3.0-asr-flash -F file=@speech.mp3 -F language=enwith a valid copied MP3 fixtureInvalid model name passed, naming the TTS and ASR models respectivelyRealtime
python realtime.pyagainstws://localhost:4000/v1/realtime?model=alibaba_token_plan/qwen-audio-3.0-realtime-pluserrorevent:_arealtime: Invalid model name passed in model=alibaba_token_plan/qwen-audio-3.0-realtime-plusVideo
post videos @video-request.json, requesting one three-second 480P, 16:9 clip/videos: Invalid model name passed in model=alibaba_token_plan/happyhorse-1.1-t2vModel list
curl -sS "$B/v1/models" -H "$AUTH" | jq '[.data[].id | select(startswith("alibaba_token_plan/"))] | length'0After (6538bec)
Admin UI provider selection
45d050e1c1: open http://localhost:3000/models-and-endpoints, choose Add Model, and search Provider forAlibabaClaude Code
At
6ac150fc7b: start the same interactive task. Read, Edit andpython3 -m unittest -vwere pre-approved for this After runClaude reads both files and runs the tests to reproduce the bug
It reproduces two failures, changes only
greeting.pyto usename.strip(), then reportsRan 3 testsandOKSupporting Before transcript, After transcript and proxy logs retain their original revisions
Chat completions
45d050e1c1: runpost chat/completions @chat.json{"model":"alibaba_token_plan/qwen3.8-max","content":"pong","total_tokens":91}post chat/completions @chat-stream.jsonandpost chat/completions @auto-tools.json1, 2, 3, 4, 5and[DONE]; auto returnsget_weatherwith{"city":"Paris"}andfinish_reason: tool_calls57a704962frerun:post chat/completions '{"model":"alibaba_token_plan/qwen3.8-max","messages":[{"role":"user","content":"Reply with exactly: pong"}]}'{"model":"alibaba_token_plan/qwen3.8-max","content":"pong","total_tokens":91}dbc41e65d9rerun: repeat step 5{"model":"alibaba_token_plan/qwen3.8-max","content":"pong","total_tokens":96}Messages
45d050e1c1: runpost messages @messages.jsonandpost messages @messages-stream.json{"model":"alibaba_token_plan/glm-5.3","stop_reason":"end_turn","text":["pong"]}message_start, 38content_block_deltaevents andmessage_stopResponses
45d050e1c1: runpost responses @responses.json{"status":"completed","text":["pong"]}Images
45d050e1c1: runpost images/generations @image-request.json > image-result.json, thencurl -sS -o generated.png "$(jq -r '.data[0].url' image-result.json)"1024 x 1024post images/generations @image-b64.jsonAlibaba Token Plan image generation only returns image URLs; use response_format='url'1024 x 1024PNGSpeech and transcription
45d050e1c1: runpost audio/speech @speech.json > speech.mp3, then the same transcription command from Before with this MP3audio/mpeg, 57,211 bytes{"text":"Your build finished without errors at nine fifteen. ","usage":{"type":"duration","seconds":3.0},"duration":3.0}Realtime
45d050e1c1: run the samepython realtime.py, which sends 16 kHz PCM16, then performs aget_weathertool round-tripWhat is the capital of France? Answer in one short sentence.Reply:The capital of France is Paris.Audio: 103,680 bytes, 2.16 seconds at 24 kHz; statuscompleted6538becb9e, after merging fix(realtime): only inject response.create when a transcript guardrail suppressed VAD auto-response #43791, the same voice turn with a regenerated recording of the same question repliesThe capital of France is Paris., 157,440 bytes, 3.28 seconds at 24 kHz,completed, witherror events: []. NoCannot create response while another response is in progressevent appears, and the weather tool turn also completesget_weather {"city":"Paris"}. Final answer:The weather in Paris is 18°C with light rain.Statuscompleted57a704962frerun: connect tows://localhost:4000/v1/realtime?model=alibaba_token_plan/qwen-audio-3.0-realtime-pluswith the shared Authorization header and sendsession.updatewithaudio.input.format={"type":"audio/pcm","rate":16000}, then an instructions-only update and the same voice/tool turnsThe capital of France is Paris., 111,360 bytes, 2.32 seconds at 24 kHz,completed, no errors.get_weather({"city":"Paris"})and its final reply complete{"type":"session.update","session":{"instructions":"Answer briefly."}}, then either{"type":"input_audio_buffer.append","audio":"AAAAAA=="}or{"type":"conversation.item.create","item":{"type":"message","role":"user","content":[{"type":"input_audio","audio":"AAAAAA=="}]}}1006{"type":"session.update","session":{"type":"realtime","audio":{"input":{"format":{"type":"audio/pcm","rate":24000}}}}}dbc41e65d9rerun: repeat steps 5-10completed, no errors. Weather tool/reply:completed. All three rejected sessions: client code1006, no close frame5eae427b48, repeat the declared 16 kHz voice/tool requests from step 5The capital of France is Paris., 111,360 bytes at 24 kHz,completed. Tool reply:The weather in Paris is 18°C with light rain.,completed. No error eventsVideo
45d050e1c1: runpost videos @video-request.json > video-result.json; saveVIDEO_ID=$(jq -r '.id' video-result.json)queued; pollingcurl -sS "$B/v1/videos/$VIDEO_ID" -H "$AUTH"ends withcompleted,seconds: "3",video_resolution: "480p"curl -sS "$B/v1/videos/$VIDEO_ID/content" -H "$AUTH" -o t2v.mp4848x480, 3.041667 seconds, plus AAC audio. Only one video was generatedModel list
45d050e1c1: run the same GET and jq command from Before21, both at45d050e1c1and in the earlier6ac150fc7bsmoke57a704962frerun returned HTTP 200,21dbc41e65d9rerun of the same GET/jq: HTTP 200,21Type
New Feature
Caveats
Medium
Transcription guardrails are not supported on Token Plan realtime; sessions requesting them reject audio
Audio is rejected until the session declares 16 kHz input; declaring 24 kHz closes the session
Invalid chat keys return HTTP 401 typed as
BadRequestErrorLow
Documentation CI depends on docs(providers): add Alibaba Cloud Token Plan litellm-docs#2085 merging
Earlier
rust-wheelfailed upstream at 45 MB, now raised to 48 MBSpend shows $0 because the subscription bills credits
Images return URLs;
b64_jsonfails unlessdrop_paramsis enabledTranscription returns
jsonortext;srt,vttandverbose_jsonfail unlessdrop_paramsis enabledAlibaba's terms limit Token Plan to interactive coding tools
Image-to-video and reference-to-video were not rerun in this proof
Final Attestation
Note
Medium Risk
Large new provider surface (realtime WebSocket translation, signed media downloads, provider routing) touches core HTTP/TTS paths; mistakes could mis-route credentials or break unrelated TTS async handling.
Overview
Adds a first-class
alibaba_token_planprovider for Alibaba Cloud Token Plan subscriptions, wired through LiteLLM’s provider registry, proxy credential fields, dashboard “Add Model” UI, model catalog, and CI unit-test shard.Routing uses dedicated
ALIBABA_TOKEN_PLAN_API_KEY/API_BASEresolution (with a special case so JSON openai-like config does not swallow the provider). Chat builds on DashScope translation; multimodal paths add native transforms for Anthropic/messages, transcription, TTS (URL fetch via newasync_transform_text_to_speech_response), image gen/edit, realtime (OpenAI event shaping, 16 kHz PCM guardrails), and async video create/poll/download. 21 subscription models and endpoint capability metadata are registered; README lists the provider.Reviewed by Cursor Bugbot for commit e40d8af. Bugbot is set up for automated code reviews on this repo. Configure here.