fix(setup): unbreak custom-openai-compatible probe for GLM-style URLs#81
Merged
Conversation
2 tasks
6704ba0 to
da8c935
Compare
2 tasks
Users pasting vendor docs URLs like https://open.bigmodel.cn/api/paas/v4/chat/completions into the Custom (OpenAI Compatible) base URL field hit /chat/completions/chat/completions and got the generic "API Key 无效或网络不可达" error. Two root causes: 1. Base URL kept the /chat/completions suffix; probe appended another. 2. Custom provider has no preset models, so probe fell back to gpt-4o-mini which non-OpenAI endpoints reject as unknown model — still returning false on otherwise-valid keys. - Add normalizeOpenAiCompatibleBaseUrl() in providerCatalog; strip trailing /chat/completions and /completions suffixes. - Apply normalization in testApiKey + setApiKey so both probe and persisted config use a clean base. - Add GET /models fallback probe after chat/completions probes fail, so we confirm auth without needing a valid model id. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Custom providers (GLM, self-hosted OAI-compatible endpoints) previously had no way to discover models — users had to type model IDs manually. Both the frontend UI gate and the backend SSRF gate blocked catalog loading outright. - supportsProviderCatalog(): return true for custom-openai-compatible once a baseUrl is configured. "刷新模型列表" now appears on the card. - assertSafeProviderCatalogBaseUrl() (web + backend): accept user-supplied http(s) endpoints for custom, but block loopback / RFC1918 / link-local ranges so a custom provider cannot be used to SSRF cloud metadata (169.254.169.254) or internal services. The existing SSRF regression test is updated to assert the narrower guard still protects against the original payload. - Verified live against GLM (bigmodel.cn): 7 models returned (glm-4.5, glm-4.5-air, glm-4.6, glm-4.7, glm-5, glm-5-turbo, glm-5.1), visible as quick picks in the UI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
da8c935 to
99892f1
Compare
2 tasks
This was referenced Apr 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two commits on this branch fix and complete the
custom-openai-compatibleprovider flow so users can onboard GLM-style endpoints:.../chat/completionsURLs to a true base, and add aGET /modelsfallback probe so auth verification succeeds even when the endpoint's model catalog doesn't match our hard-coded fallback list.169.254.169.254) remain blocked.User report this fixes: pasting
https://open.bigmodel.cn/api/paas/v4/chat/completionsinto Custom (OpenAI Compatible) returned the genericAPI Key 无效或网络不可达error.Why
This is a rc.1 regression blocking GLM (and any OpenAI-compatible endpoint whose model catalog doesn't overlap with OpenAI's) from onboarding through the Custom provider path. Two overlapping root causes:
/chat/completionssuffix; the probe appended another, hitting/chat/completions/chat/completionsand returning 404.custom-openai-compatiblehas no preset models, so the probe fell back togpt-4o-mini— which non-OpenAI endpoints reject as an unknown model, still returningfalseon otherwise-valid keys.Even after (1)+(2) were fixed, users had no way to discover the endpoint's real models — the frontend
supportsProviderCatalogand backendassertSafeProviderCatalogBaseUrlboth rejected custom providers outright. The backend block specifically was guarding against SSRF to cloud metadata — a legitimate concern for multi-tenant deploys that doesn't match ClawMaster's single-user local-web / desktop model. Narrowing the guard to "block private ranges only" preserves the SSRF protection while unblocking real-world use.Changes
providerCatalog.ts(web) — newnormalizeOpenAiCompatibleBaseUrl(); strips trailing/chat/completionsand/completions(case-insensitive, URL-API based).providerCatalog.ts(web) +providerCatalogService.ts(backend) —assertSafeProviderCatalogBaseUrlnow accepts user-supplied http(s) endpoints forcustom-openai-compatiblebut rejects loopback / RFC1918 / link-local / IPv6 private / IPv4-mapped-IPv6 ranges. Existing SSRF regression test updated to assert the narrower message still protects against169.254.169.254.providerCatalog.ts(web) —supportsProviderCatalog('custom-openai-compatible', provider)returns true onceprovider.baseUrlis set.setup/adapters.ts— normalize baseUrl in bothtestApiKey(probe endpoint) andsetApiKey(persisted config). AddGET /modelsfallback probe after all/chat/completionsprobes fail — confirms auth without needing a known model id.Test plan
pnpm --filter web test— 568/568 passtsc --noEmitcleanERR_DLOPEN_FAILEDnative-binding failures in this env for sqlite-dependent memory tests)https://open.bigmodel.cn/api/paas/v4/chat/completions+ GLM key into Custom (OpenAI Compatible) via dev-browser E2E — dialog closed successfully, stored baseUrl normalized to.../v4, key persisted masked.POST /api/models/catalogwithhttp://169.254.169.254/...returns 400 with "loopback, private, or link-local".Target branch
release/0.3.0— rc.1 regression fix + direct UX completion. Pure bug-fix + SSRF guard refinement, no new features or new providers.🤖 Generated with Claude Code