Repository navigation
feat(providers): support BigModel's OpenAI Responses endpoint with live discovery #3641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -96,6 +96,15 @@ interface ProviderModelDiscoverySharedSpec { | |
| * Empty/invalid remainders skip that row only. | ||
| */ | ||
| stripIdPrefix?: string; | ||
| /** | ||
| * Opt-in nonstandard envelope for providers whose models API is not OpenAI-shaped: | ||
| * model rows live under this top-level key instead of `data`. Registry-only | ||
| * declaration — an undeclared provider keeps the default `data` envelope, so a | ||
| * stray `models` key on an openai-chat response still cannot pose as a catalog (#617). | ||
| */ | ||
| envelopeKey?: string; | ||
| /** Row key carrying the model id when `envelopeKey` is declared; defaults to `id`. */ | ||
| idKey?: string; | ||
| } | ||
|
|
||
| type ProviderModelDiscoveryLocation = | ||
|
|
@@ -2543,6 +2552,49 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ | |
| // yields an empty picker at runtime. | ||
| note: "Domestic BigModel Coding Plan endpoint (open.bigmodel.cn)", | ||
| }, | ||
|
|
||
| // BigModel's Coding Plan also serves the OpenAI Responses wire at /api/v1 — the same | ||
| // subscription product as the Chat Completions row above on a separate endpoint, so it | ||
| // gets its own row rather than a baseUrl override. Its models API is NOT OpenAI-shaped: | ||
| // rows arrive as `{models: [{slug, ...}]}` with the id under `slug` plus rich per-model | ||
| // metadata (context_window, supported_reasoning_levels), so the entry declares the | ||
| // envelope explicitly. An undeclared provider keeps the default `{data:[{id}]}` shape — | ||
| // a stray `models` key on an openai-chat response still cannot pose as a catalog (#617). | ||
| // Evidence (verified live 2026-09-05): POST /api/v1/responses answers the standard | ||
| // Responses object; GET /api/v1/models lists glm-5.3 / glm-5.3-flash / glm-5-turbo with | ||
| // context_window 1048576 and reasoning levels low/high/max, matching the 5.3 ladder. | ||
| { | ||
| id: "zhipu-bigmodel-responses", | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| label: "Zhipu AI — BigModel Coding Plan (Responses)", | ||
| baseUrl: "https://open.bigmodel.cn/api/v1", | ||
| adapter: "openai-responses", | ||
| authKind: "key", | ||
| dashboardUrl: "https://bigmodel.cn/console/usercenter/apikeys", | ||
| defaultModel: "glm-5.3", | ||
| models: ["glm-5.3", "glm-5.3-flash", "glm-5-turbo"], | ||
| liveModels: true, | ||
| // A user may already own a custom provider named "zhipu-bigmodel-responses" pointing | ||
| // elsewhere; without this, registry transport canonicalization would retarget it and | ||
| // send their saved key to BigModel. It also forces the exact-transport match, so a | ||
| // same-named custom row recovers no discovery policy instead of the slug envelope. | ||
| jawcodeBundle: "zai", | ||
| preserveCustomDestination: true, | ||
| // Live rows (2026-09-05): 5.3 and 5.3-flash expose low/high/max with a max default; | ||
| // 5-turbo fixes its reasoning at max internally and lists NO selectable levels, so an | ||
| // explicit [] keeps the undefined entry from falling back to the full routed ladder. | ||
|
Comment on lines
+2582
to
+2584
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Update the stale live-contract comment. The comment on Lines 2563-2565 says that all three models use Proposed comment update- // context_window 1048576 and reasoning levels low/high/max, matching the 5.3 ladder.
+ // glm-5.3 and glm-5.3-flash expose a 1,048,576-token window with low/high/max.
+ // glm-5-turbo exposes a 204,800-token window with no selectable reasoning levels.🤖 Prompt for AI Agents |
||
| modelContextWindows: { "glm-5.3": 1_048_576, "glm-5.3-flash": 1_048_576, "glm-5-turbo": 204_800 }, | ||
| modelReasoningEfforts: { | ||
| "glm-5.3": ZAI_GLM_53_REASONING_EFFORTS, | ||
| "glm-5.3-flash": ZAI_GLM_53_REASONING_EFFORTS, | ||
| "glm-5-turbo": [], | ||
|
Comment on lines
+2585
to
+2589
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n -C 12 \
'envelopeKey|idKey|context_window|supported_reasoning_levels|extractProviderModelItems' \
src/providers/model-discovery.ts tests/providers
rg -n -C 8 \
'zhipu-bigmodel-responses|glm-5-turbo|context_window|supported_reasoning_levels' \
src/providers tests/providersRepository: lidge-jun/opencodex Length of output: 50376 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- registry entry and discovery spec ---'
sed -n '2535,2610p' src/providers/registry.ts
printf '%s\n' '--- discovery result types and extraction ---'
sed -n '1,90p' src/providers/model-discovery.ts
sed -n '491,550p' src/providers/model-discovery.ts
printf '%s\n' '--- catalog mapping of discovered metadata ---'
rg -n -C 12 'catalogHintsFromModelsApiItem|context_window|supported_reasoning_levels|contextWindow|reasoningEfforts' src/codex/catalog src/codex/catalog/provider-fetch.ts src/providers/derive.tsRepository: lidge-jun/opencodex Length of output: 50376 🤖 get_repo_knowledge executed:
Length of output: 15241 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- registry target ---'
sed -n '2560,2605p' src/providers/registry.ts
printf '%s\n' '--- model API item hint mapper ---'
rg -n 'catalogHintsFromModelsApiItem|function catalogHintsFromModelsApiItem|interface ProviderModelsApiItem|type ProviderModelsApiItem|supported_reasoning_levels|context_window' src/codex/catalog/provider-fetch.ts src/codex/catalog src/providers/model-discovery.tsRepository: lidge-jun/opencodex Length of output: 10563 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '1355,1425p' src/codex/catalog/provider-fetch.ts
sed -n '1805,1865p' src/codex/catalog/provider-fetch.ts
rg -n -C 8 'applyProviderConfigHints|reasoningEfforts|contextWindow' src/providers/derive.ts src/codex/catalog/provider-fetch.ts | head -n 220Repository: lidge-jun/opencodex Length of output: 27865 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '1388,1495p' src/codex/catalog/provider-fetch.tsRepository: lidge-jun/opencodex Length of output: 5316 Preserve live model metadata during catalog mapping.
🤖 Prompt for AI Agents |
||
| }, | ||
| modelSupportsReasoningSummaries: { "glm-5.3": true, "glm-5.3-flash": true, "glm-5-turbo": true }, | ||
| // The Responses adapter replays reasoning via this provider-level flag, not the | ||
| // per-model preserveReasoningContentModels list (a Chat-path field). | ||
| preserveResponsesReasoningContent: true, | ||
| modelDiscovery: { path: "models", envelopeKey: "models", idKey: "slug" }, | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| note: "Domestic BigModel Coding Plan on the OpenAI Responses wire (open.bigmodel.cn/api/v1)", | ||
| }, | ||
| { id: "nanogpt", label: "NanoGPT", baseUrl: "https://nano-gpt.com/api/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://nano-gpt.com/api" }, | ||
| { id: "synthetic", label: "Synthetic", baseUrl: "https://api.synthetic.new/openai/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://synthetic.new" }, | ||
| // SiliconFlow publishes an OpenAI-compatible chat endpoint and a dynamic model catalog. Do not | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 50376
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 50376
🤖 get_repo_knowledge executed:
get_repo_knowledge lidge-jun/opencodex /tmp/coderabbit-repo-knowledge/lidge-jun-opencodex-7afea732/learnings /tmp/coderabbit-repo-knowledge/lidge-jun-opencodex-7afea732/conventionsLength of output: 14899
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 50376
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 6894
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 22607
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 34251
Require an exact transport match for named discovery policies.
providerMatchesRegistryTransportreturnstrueforzhipu-bigmodel-responsesbecause it is a key provider withoutpreserveCustomDestination. A same-named provider with anotherbaseUrlcan therefore receive itsmodels[].slugdiscovery policy.resolveProviderModelDiscoveryUrlthen resolvespath: "models"against the effective custom URL, so the custom endpoint can receive the wrong discovery contract. Require an exact adapter and normalizedbaseUrlmatch before selectingnamedEntry.modelDiscovery, or explicitly exclude this entry from the early-return path. Add a regression test for the mismatchedzhipu-bigmodel-responsesdestination.🤖 Prompt for AI Agents