Skip to content

fix(setup): unbreak custom-openai-compatible probe for GLM-style URLs#81

Merged
webup merged 2 commits into
release/0.3.0from
fix/custom-compatible-probe
Apr 23, 2026
Merged

fix(setup): unbreak custom-openai-compatible probe for GLM-style URLs#81
webup merged 2 commits into
release/0.3.0from
fix/custom-compatible-probe

Conversation

@webup
Copy link
Copy Markdown
Contributor

@webup webup commented Apr 23, 2026

What

Two commits on this branch fix and complete the custom-openai-compatible provider flow so users can onboard GLM-style endpoints:

  1. fix(setup): unbreak custom-openai-compatible probe for GLM-style URLs — normalize pasted .../chat/completions URLs to a true base, and add a GET /models fallback probe so auth verification succeeds even when the endpoint's model catalog doesn't match our hard-coded fallback list.
  2. feat(setup): live /models catalog for custom-openai-compatible — surface the "刷新模型列表" (Refresh Models) button on the custom card once a baseUrl is configured, and narrow the backend SSRF gate from "block all custom" to "block loopback/RFC1918/link-local" so public endpoints (bigmodel.cn, dashscope, self-hosted vLLM on a public host) work while instance-metadata payloads (169.254.169.254) remain blocked.

User report this fixes: pasting https://open.bigmodel.cn/api/paas/v4/chat/completions into Custom (OpenAI Compatible) returned the generic API 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:

  1. Pasted base URL kept the /chat/completions suffix; the probe appended another, hitting /chat/completions/chat/completions and returning 404.
  2. custom-openai-compatible has no preset models, so the probe fell back to gpt-4o-mini — which non-OpenAI endpoints reject as an unknown model, still returning false on otherwise-valid keys.

Even after (1)+(2) were fixed, users had no way to discover the endpoint's real models — the frontend supportsProviderCatalog and backend assertSafeProviderCatalogBaseUrl both 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) — new normalizeOpenAiCompatibleBaseUrl(); strips trailing /chat/completions and /completions (case-insensitive, URL-API based).
  • providerCatalog.ts (web) + providerCatalogService.ts (backend) — assertSafeProviderCatalogBaseUrl now accepts user-supplied http(s) endpoints for custom-openai-compatible but rejects loopback / RFC1918 / link-local / IPv6 private / IPv4-mapped-IPv6 ranges. Existing SSRF regression test updated to assert the narrower message still protects against 169.254.169.254.
  • providerCatalog.ts (web) — supportsProviderCatalog('custom-openai-compatible', provider) returns true once provider.baseUrl is set.
  • setup/adapters.ts — normalize baseUrl in both testApiKey (probe endpoint) and setApiKey (persisted config). Add GET /models fallback probe after all /chat/completions probes fail — confirms auth without needing a known model id.
  • Tests: 15 unit + 4 adapter-integration + 1 ModelsPage update. Backend SSRF regression preserved.

Test plan

  • pnpm --filter web test — 568/568 pass
  • tsc --noEmit clean
  • Targeted backend catalog tests 12/12 pass (unrelated pre-existing ERR_DLOPEN_FAILED native-binding failures in this env for sqlite-dependent memory tests)
  • Manual: pasted 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.
  • Manual: clicked "刷新模型列表" on the custom card — loaded 7 GLM models (glm-4.5, glm-4.5-air, glm-4.6, glm-4.7, glm-5, glm-5-turbo, glm-5.1) from bigmodel.cn.
  • Manual: verified backend still rejects SSRF payload — POST /api/models/catalog with http://169.254.169.254/... returns 400 with "loopback, private, or link-local".
  • Verify existing providers (SiliconFlow, DeepSeek, ERNIE, Ollama) still probe correctly via regression run.

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

webup and others added 2 commits April 23, 2026 18:21
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>
@webup webup force-pushed the fix/custom-compatible-probe branch from da8c935 to 99892f1 Compare April 23, 2026 10:21
@webup webup merged commit 43978dd into release/0.3.0 Apr 23, 2026
13 checks passed
@webup webup deleted the fix/custom-compatible-probe branch April 23, 2026 11:09
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.

1 participant