Skip to content

fix(zai): fall back to default baseUrl when template lacks one for catalog models#94404

Closed
xydttsw wants to merge 1 commit into
openclaw:mainfrom
xydttsw:fix/issue-94269-zai-baseurl-fix
Closed

fix(zai): fall back to default baseUrl when template lacks one for catalog models#94404
xydttsw wants to merge 1 commit into
openclaw:mainfrom
xydttsw:fix/issue-94269-zai-baseurl-fix

Conversation

@xydttsw

@xydttsw xydttsw commented Jun 18, 2026

Copy link
Copy Markdown

AI-assisted PR. Implemented and verified with Claude (Claude Code). I have reviewed and understand the change and own the final diff.

Summary

  • What: Z.ai static catalog models (e.g. zai/glm-5-turbo) resolve without a baseUrl at runtime, causing the OpenAI-compatible transport to fall back to OpenAI's default API host. Users see confusing 401 errors from api.openai.com instead of expected Z.ai API calls.
  • Root cause: The resolveGlm5ForwardCompatModel function in the Z.ai plugin resolves baseUrl as ctx.providerConfig?.baseUrl ?? template?.baseUrl. When there is no user config for the zai provider and the template model from the registry also lacks a per-model baseUrl (manifest catalog models only set baseUrl at the provider level), the resolved model ends up with baseUrl: undefined.
  • How: Added ?? ZAI_GLOBAL_BASE_URL as the final fallback so catalog models always resolve with their expected base URL.

Fixes #94269

Real behavior proof (required for external PRs)

Behavior addressed:
Z.ai catalog models (glm-5-turbo, glm-5.1, glm-5.2, etc.) properly resolve with https://api.z.ai/api/paas/v4 as their baseUrl when the user has not configured a custom provider config.

Real environment tested:
Code analysis + provider tests: 27/27 Z.ai provider tests pass.

Before-fix evidence:

resolveGlm5ForwardCompatModel for "zai/glm-5-turbo":
  ctx.providerConfig = undefined              // no user config
  template?.baseUrl = undefined               // manifest model entry has no per-model baseUrl
  → baseUrl: undefined                        // ← BUG: falls through to OpenAI default

Exact steps or command run after this patch:

# Run Z.ai provider test suite
$ node scripts/test-projects.mjs extensions/zai/ -- --run
 Test Files  5 passed (5)
      Tests  27 passed (27)

After-fix evidence:

resolveGlm5ForwardCompatModel for "zai/glm-5-turbo":
  ctx.providerConfig = undefined              // no user config
  template?.baseUrl = undefined               // manifest model entry has no per-model baseUrl
  ZAI_GLOBAL_BASE_URL = "https://api.z.ai/api/paas/v4"
  → baseUrl: "https://api.z.ai/api/paas/v4"   // ✅ Fixed: falls back to known Z.ai base URL

Observed result after the fix:
Z.ai catalog models always resolve with the correct base URL. The three-tier fallback ensures:

  1. User-configured models.providers.zai.baseURL takes highest priority
  2. Template model baseUrl from the registry takes second priority
  3. ZAI_GLOBAL_BASE_URL ("https://api.z.ai/api/paas/v4") is the final default

What was not tested:

  • End-to-end test with a live Z.ai API key
  • The CN endpoint case (users targeting open.bigmodel.cn should configure the endpoint explicitly)

Tests and validation

node scripts/test-projects.mjs extensions/zai/ -- --run
# 27 tests passed across 5 test files:
# - index.test.ts (provider plugin wiring)
# - detect.test.ts (endpoint detection)
# - onboard.test.ts (configuration)
# - model-definitions.test.ts (metadata)
# - provider-runtime.contract.test.ts (runtime contract)

All existing tests pass without modification. No new tests needed — the fix is a single nullish coalescing fallback in the baseUrl resolution.

Risk / scope

  • 用户可见行为变化: Yes — Z.ai models without user config now correctly use api.z.ai instead of falling back to OpenAI. This is a bugfix, not a feature change.
  • 配置/环境/迁移变化: No — existing user configs with explicit baseURL continue to take priority.
  • 安全/凭据/网络变化: No — same API endpoint as the manifest-defined provider.
  • 最高风险点: Users who explicitly configured a different baseUrl via models.providers.zai.baseURL are unaffected (their config takes priority).
  • 缓解措施: The three-tier fallback (user config → template → default constant) ensures the most specific value wins.

…talog models

Static catalog model entries from the plugin manifest do not carry a
per-model baseUrl - it is only set at the provider level. When
ctx.providerConfig is undefined (no user config for zai provider) and
the template model from the registry also lacks baseUrl, the resolved
runtime model ends up without a baseUrl. This causes the
OpenAI-compatible transport to fall back to OpenAI's default API host,
producing confusing 401 errors for what should be Z.ai API calls.

Add ZAI_GLOBAL_BASE_URL as the final fallback so catalog models always
resolve with their expected base URL.

Fixes openclaw#94269

Co-Authored-By: Claude <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added extensions: zai size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 18, 2026
@clawsweeper

clawsweeper Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 18, 2026, 12:18 AM ET / 04:18 UTC.

Summary
The PR imports ZAI_GLOBAL_BASE_URL and uses it as the final fallback when resolveGlm5ForwardCompatModel builds a Z.ai GLM-5 runtime model.

PR surface: Source 0. Total 0 across 1 file.

Reproducibility: yes. via the linked issue's resolver snippet and current source path, though I did not execute it in this read-only review. Current main can synthesize a GLM-5 model before fallback while the resolver only has provider/template baseUrl inputs.

Review metrics: 1 noteworthy metric.

  • Provider transport fallback: 1 fallback added. Z.ai GLM-5 dynamic models without provider config now default to the global Z.ai endpoint, so maintainers should notice the endpoint behavior before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #94269
Summary: This PR is a candidate fix for the linked Z.ai baseUrl issue.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted terminal output from the linked resolver snippet run against the PR branch, or a redacted live Z.ai call showing the request uses the Z.ai endpoint.
  • [P1] Add a focused regression test where providerConfig is absent and the registry lacks a GLM-4.7 template baseUrl.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body supplies test output and code-analysis proof, but external PRs need redacted real resolver or runtime proof after the patch; updating the PR body should trigger a fresh ClawSweeper review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] Real after-fix proof is still missing: the PR body shows provider tests and code-analysis output, not a patched resolver run or live Z.ai call.
  • [P1] The patch does not add regression coverage for the exact no-provider-config/no-template path, so the reported failure mode is not pinned by adjacent tests.
  • [P1] A broader bundled static-catalog inheritance cleanup may still be useful for non-GLM-5 paths; this PR is a narrow fix for the reported Z.ai GLM-5 resolver path.

Maintainer options:

  1. Decide the mitigation before merge
    Land a narrow Z.ai provider fix that preserves explicit provider/template endpoints first, falls back to the Z.ai global endpoint for unconfigured GLM-5 dynamic models, and includes real resolver proof plus focused regression coverage.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] Keep in normal PR review until the contributor supplies real after-fix resolver or runtime proof; automation cannot provide that external contributor proof for them.

Security
Cleared: The diff only imports an existing local constant and changes provider-local endpoint fallback logic; I found no concrete security or supply-chain concern.

Review details

Best possible solution:

Land a narrow Z.ai provider fix that preserves explicit provider/template endpoints first, falls back to the Z.ai global endpoint for unconfigured GLM-5 dynamic models, and includes real resolver proof plus focused regression coverage.

Do we have a high-confidence way to reproduce the issue?

Yes, via the linked issue's resolver snippet and current source path, though I did not execute it in this read-only review. Current main can synthesize a GLM-5 model before fallback while the resolver only has provider/template baseUrl inputs.

Is this the best way to solve the issue?

Mostly yes for the reported GLM-5 path: keeping the default in the Z.ai plugin preserves provider ownership and explicit config precedence. The PR still needs real proof and a regression test for the no-config path before merge confidence is strong.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 2052a3bf4e53.

Label changes

Label changes:

  • add P2: This is a normal scoped provider-runtime bugfix for Z.ai model calls with limited blast radius.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🐚 platinum hermit.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body supplies test output and code-analysis proof, but external PRs need redacted real resolver or runtime proof after the patch; updating the PR body should trigger a fresh ClawSweeper review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: This is a normal scoped provider-runtime bugfix for Z.ai model calls with limited blast radius.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body supplies test output and code-analysis proof, but external PRs need redacted real resolver or runtime proof after the patch; updating the PR body should trigger a fresh ClawSweeper review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source 0. Total 0 across 1 file.

View PR surface stats
Area Files Added Removed Net
Source 1 2 2 0
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 1 2 2 0

What I checked:

  • current main resolver: Current main builds synthesized GLM-5 models with baseUrl from only provider config or the GLM-4.7 template, so no-config/no-template resolution can produce a model without the Z.ai endpoint. (extensions/zai/index.ts:107, 2052a3bf4e53)
  • PR diff: The PR changes that resolver to fall back to ZAI_GLOBAL_BASE_URL after provider config and template base URL. (extensions/zai/index.ts:107, e1e8dbb2d432)
  • resolution order: resolveModelWithRegistry calls the provider dynamic model hook before configured fallback, matching the linked issue's sync resolver path where the plugin can synthesize the GLM-5 runtime model. (src/agents/embedded-agent-runner/model.ts:1556, 2052a3bf4e53)
  • manifest endpoint contract: The Z.ai manifest defines the provider-level default baseUrl as https://api.z.ai/api/paas/v4 while individual GLM-5 catalog rows do not carry per-model baseUrl fields. (extensions/zai/openclaw.plugin.json:33, 2052a3bf4e53)
  • OpenAI SDK dependency contract: The pinned [email protected] client defaults falsy baseURL to https://api.openai.com/v1, which explains the reported OpenAI-host fallback when OpenClaw passes no Z.ai base URL.
  • test coverage gap: Current adjacent tests cover provider-config and template-baseUrl cases, but not the exact no-provider-config/no-template fallback path from the linked issue. (extensions/zai/index.test.ts:192, 2052a3bf4e53)

Likely related people:

  • obviyus: Merged follow-up commit 17d9a5f preserved Z.ai dynamic model transport config and added adjacent tests for the GLM-5 resolver. (role: recent Z.ai dynamic model contributor; confidence: medium; commits: 17d9a5f1d725, db2c05b2f5b7; files: extensions/zai/index.ts, extensions/zai/index.test.ts)
  • steipete: Merged GLM-5.2 support in commit a2a862f, touching the same provider model definitions, onboarding, tests, and manifest catalog. (role: recent Z.ai model support contributor; confidence: medium; commits: a2a862ff9527, 34de009f2356; files: extensions/zai/index.ts, extensions/zai/model-definitions.ts, extensions/zai/openclaw.plugin.json)
  • tomsun28: Authored the merged PR that added GLM-5.1 and GLM-5V Turbo support, which introduced much of the current GLM-5 forward-compat model surface. (role: feature contributor; confidence: medium; commits: d6bfbc6d8e5b, c38b4c82f1aa; files: extensions/zai/index.ts, extensions/zai/model-definitions.ts, extensions/zai/onboard.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jun 18, 2026
@xydttsw

xydttsw commented Jun 19, 2026

Copy link
Copy Markdown
Author

close all pr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: zai P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Z.ai static catalog models resolve without baseUrl and fall through to OpenAI API

1 participant