Conversation
Add glm-5.3 as the newest zai entry in _PROVIDER_MODELS and a matching zai/glm-5.3 entry in _FALLBACK_MODELS, and bump the Z.AI onboarding default_model from glm-5.1 to glm-5.3 (Z.ai's current flagship; legacy GLM-5.2/5.1 requests are routed to GLM-5.3 per docs.z.ai). Reasoning gating needs no change: _zai_glm_classification() treats GLM >= 5.2 as effort-ladder capable, so glm-5.3 is already covered and pinned by tests/test_zai_reasoning_effort_gating.py. New regression coverage in tests/test_glm_5_3_catalog.py: catalog presence, newest-first ordering, fallback entry, onboarding default, full reasoning_effort ladder, and the get_available_models() payload.
|
| Filename | Overview |
|---|---|
| api/config.py | Adds consistent GLM-5.3 entries to the Z.AI provider and fallback model catalogs. |
| tests/test_glm_5_3_catalog.py | Adds comprehensive catalog regression coverage and now restores _cfg_fingerprint alongside the other configuration state. |
Reviews (3): Last reviewed commit: "fix: keep Z.AI onboarding default at glm..." | Re-trigger Greptile
Review follow-up (nesquena#7017): the isolation fixture snapshot restored cfg, _cfg_mtime, and _cfg_path but left _cfg_fingerprint pointing at the temporary config loaded by the payload test. api/config.py uses that fingerprint to distinguish in-memory overrides from changed files (config.py:371), so a stale value could make later same-process tests skip reloading a changed config. Snapshot and restore it like the rest.
nesquena-hermes
left a comment
There was a problem hiding this comment.
Capability-truth gate: adding GLM-5.3 to the catalog is correct, but making it the default_model is a ship-blocker until the direct Z.AI API serves it
Thanks for this — I verified GLM-5.3 against Z.ai's first-party docs and it's a real, current flagship (docs.z.ai/guides/llm/glm-5.3: 1M context, 128K output, "Z.ai's latest flagship model"). Adding it to the _PROVIDER_MODELS["zai"] catalog (newest-first, ahead of GLM-5.2) is the right call and I'd happily ship that part.
The blocker is one line: default_model: "glm-5.1" → "glm-5.3".
Why that's risky
Hermes' zai provider connects via the direct endpoint https://api.z.ai/api/paas/v4 (see api/routes.py:1828 and the agent's PROVIDER_REGISTRY["zai"].inference_base_url = https://api.z.ai/api/paas/v4). But Z.ai's own GLM-5.3 API guide page currently states, verbatim:
The GLM-5.3 API is coming soon. GLM-5.3 is now available to all GLM Coding Plan users…
That is: GLM-5.3 is live only via the Coding Plan subscription (a different endpoint/auth), and the standalone direct API that our zai provider actually calls is "coming soon." The auto-route note ("requests for GLM-5.2/5.1 are routed to GLM-5.3") is also under the Coding-Plan section, not the direct API.
So if we make glm-5.3 the default, a brand-new user onboarding to Z.AI with a direct-API key gets a model that the direct endpoint doesn't serve yet → their very first message fails with a model-not-found. That's a fresh-onboarding regression.
To unblock — either:
- Confirm the direct API already serves it: paste a successful raw completion against
https://api.z.ai/api/paas/v4/chat/completionswith"model": "glm-5.3"(a 200 with a real completion, not a Coding-Plan/ZCode call). If it works today, I'll ship the whole PR as-is. - Or split it: keep
default_modelat its current value and just addglm-5.3to the catalog (opt-in selection). It'll work the moment the direct API ships GLM-5.3, with zero onboarding risk in the meantime — and update the onboarding-default test accordingly.
Everything else (catalog entry, label, newest-first ordering, fallback entry, the test file) looks correct. This is purely about not defaulting new direct-API users onto a model Z.ai itself lists as "API coming soon." Happy to re-gate as soon as either path is in.
…GLM-5.3 Review follow-up (nesquena#7017): GLM-5.3 is live on Z.ai's Coding Plan endpoint only; the direct api.z.ai endpoint the zai provider uses still lists the GLM-5.3 API as coming soon. Defaulting new direct-API users onto glm-5.3 would fail their first message, so the catalog addition stays (opt-in) and the default stays glm-5.1. Bump the default in a follow-up once the direct endpoint serves GLM-5.3.
|
Resolved via option 2 in 2ca8e89: the Z.AI onboarding |
Addressed via option 2 — catalog-only add, default_model unchanged, protective test added. Re-gated clean; the sole local test failure is a proven installed-core environment artifact (details in comment).
🔬 Re-gate — converged on the fix-spec, SAFE TO SHIP (queued for maintainer merge)Thanks @rh-id — the re-push took option 2 from my earlier review exactly: glm-5.3 is added to the catalog ( Gate results (head
Change is capability-truthful, opt-in, additive, no onboarding regression, with a protective default-lock test. Dismissing my earlier changes-request and queuing (Release-manager overnight re-gate — queued for maintainer merge, not autonomously tagged.) |
…xperimental) (#7090) * feat: add GLM-5.3 to Z.AI model list Add glm-5.3 as the newest zai entry in _PROVIDER_MODELS and a matching zai/glm-5.3 entry in _FALLBACK_MODELS, and bump the Z.AI onboarding default_model from glm-5.1 to glm-5.3 (Z.ai's current flagship; legacy GLM-5.2/5.1 requests are routed to GLM-5.3 per docs.z.ai). Reasoning gating needs no change: _zai_glm_classification() treats GLM >= 5.2 as effort-ladder capable, so glm-5.3 is already covered and pinned by tests/test_zai_reasoning_effort_gating.py. New regression coverage in tests/test_glm_5_3_catalog.py: catalog presence, newest-first ordering, fallback entry, onboarding default, full reasoning_effort ladder, and the get_available_models() payload. * test: restore _cfg_fingerprint in catalog test fixture Review follow-up (#7017): the isolation fixture snapshot restored cfg, _cfg_mtime, and _cfg_path but left _cfg_fingerprint pointing at the temporary config loaded by the payload test. api/config.py uses that fingerprint to distinguish in-memory overrides from changed files (config.py:371), so a stale value could make later same-process tests skip reloading a changed config. Snapshot and restore it like the rest. * fix: keep Z.AI onboarding default at glm-5.1 until direct API serves GLM-5.3 Review follow-up (#7017): GLM-5.3 is live on Z.ai's Coding Plan endpoint only; the direct api.z.ai endpoint the zai provider uses still lists the GLM-5.3 API as coming soon. Defaulting new direct-API users onto glm-5.3 would fail their first message, so the catalog addition stays (opt-in) and the default stays glm-5.1. Bump the default in a follow-up once the direct endpoint serves GLM-5.3. * fix(docker): probe the configured state dir before /workspace for UID/GID (#7027) UID/GID auto-detection probed /workspace before the configured HERMES_WEBUI_STATE_DIR. In a stock single-container image none of the priority-1 candidates exist, but /workspace does — owned by the image's build-time 1024:1024. Detection therefore returned the image's own owner, which carries no information about the host, while the one directory whose owner *is* the host UID by definition — the state-dir bind mount — was never probed. With a host-owned state mount and no explicit WANTED_UID the container remapped to 1024, failed its own state-dir writability check, and restart-looped. The log line made this expensive to debug: 1024 is also the fallback default, so "Auto-detected workspace UID: 1024" read as if detection had found nothing. - probe ${HERMES_WEBUI_STATE_DIR:-/app/data} first, for both UID and GID - keep /workspace as a lower-priority signal (unchanged for setups that actually bind-mount it), and keep the hermes-home probes from #668 - stop treating an explicitly supplied 1024 as "unset": the sentinel and a valid UID were the same number, so an operator who deliberately ran as 1024 got it overwritten by detection. The explicit/detected origin is persisted next to the value because `su` drops the environment when the script re-enters as the runtime user, so the second pass would otherwise see an explicit choice as a detected one. Tests: tests/test_7027_state_dir_uid_probe.py runs the real resolution block under bash with `stat` stubbed, covering the non-1024 state mount, the explicit 1024 override (including across the privilege drop), and the pre-existing /workspace + hermes-home fallback paths. A new state-dir-uid job in the Docker smoke workflow boots a real container on a host-owned state mount and gates on /health. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Release batch B: Docker UID fix + GLM-5.3 catalog (experimental) Two independently gate-passed contributor PRs, rebased fresh onto master and re-gated as a combined stage (Codex SAFE TO SHIP; full suite green except the 8 pre-existing approval-test failures that fail identically on clean origin/master — CI green on the same commit; tracked separately for a fix). - #7027 (@jorgejiro) probe configured state-dir before /workspace for Docker UID/GID; persist explicit marker so a supplied 1024 survives root->su re-entry (fixes the single-container restart loop) (#7034) - #7017 (@rh-id) add GLM-5.3 to the Z.AI model list (onboarding default stays glm-5.1) Co-authored-by: jorgejiro <jorgejiro@users.noreply.github.com> Co-authored-by: rh-id <rh-id@users.noreply.github.com> --------- Co-authored-by: Ruby Hartono <58564005+rh-id@users.noreply.github.com> Co-authored-by: Jorge <jorgejiro@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: n <a@n> Co-authored-by: jorgejiro <jorgejiro@users.noreply.github.com> Co-authored-by: rh-id <rh-id@users.noreply.github.com>
…xperimental) (nesquena#7090) * feat: add GLM-5.3 to Z.AI model list Add glm-5.3 as the newest zai entry in _PROVIDER_MODELS and a matching zai/glm-5.3 entry in _FALLBACK_MODELS, and bump the Z.AI onboarding default_model from glm-5.1 to glm-5.3 (Z.ai's current flagship; legacy GLM-5.2/5.1 requests are routed to GLM-5.3 per docs.z.ai). Reasoning gating needs no change: _zai_glm_classification() treats GLM >= 5.2 as effort-ladder capable, so glm-5.3 is already covered and pinned by tests/test_zai_reasoning_effort_gating.py. New regression coverage in tests/test_glm_5_3_catalog.py: catalog presence, newest-first ordering, fallback entry, onboarding default, full reasoning_effort ladder, and the get_available_models() payload. * test: restore _cfg_fingerprint in catalog test fixture Review follow-up (nesquena#7017): the isolation fixture snapshot restored cfg, _cfg_mtime, and _cfg_path but left _cfg_fingerprint pointing at the temporary config loaded by the payload test. api/config.py uses that fingerprint to distinguish in-memory overrides from changed files (config.py:371), so a stale value could make later same-process tests skip reloading a changed config. Snapshot and restore it like the rest. * fix: keep Z.AI onboarding default at glm-5.1 until direct API serves GLM-5.3 Review follow-up (nesquena#7017): GLM-5.3 is live on Z.ai's Coding Plan endpoint only; the direct api.z.ai endpoint the zai provider uses still lists the GLM-5.3 API as coming soon. Defaulting new direct-API users onto glm-5.3 would fail their first message, so the catalog addition stays (opt-in) and the default stays glm-5.1. Bump the default in a follow-up once the direct endpoint serves GLM-5.3. * fix(docker): probe the configured state dir before /workspace for UID/GID (nesquena#7027) UID/GID auto-detection probed /workspace before the configured HERMES_WEBUI_STATE_DIR. In a stock single-container image none of the priority-1 candidates exist, but /workspace does — owned by the image's build-time 1024:1024. Detection therefore returned the image's own owner, which carries no information about the host, while the one directory whose owner *is* the host UID by definition — the state-dir bind mount — was never probed. With a host-owned state mount and no explicit WANTED_UID the container remapped to 1024, failed its own state-dir writability check, and restart-looped. The log line made this expensive to debug: 1024 is also the fallback default, so "Auto-detected workspace UID: 1024" read as if detection had found nothing. - probe ${HERMES_WEBUI_STATE_DIR:-/app/data} first, for both UID and GID - keep /workspace as a lower-priority signal (unchanged for setups that actually bind-mount it), and keep the hermes-home probes from nesquena#668 - stop treating an explicitly supplied 1024 as "unset": the sentinel and a valid UID were the same number, so an operator who deliberately ran as 1024 got it overwritten by detection. The explicit/detected origin is persisted next to the value because `su` drops the environment when the script re-enters as the runtime user, so the second pass would otherwise see an explicit choice as a detected one. Tests: tests/test_7027_state_dir_uid_probe.py runs the real resolution block under bash with `stat` stubbed, covering the non-1024 state mount, the explicit 1024 override (including across the privilege drop), and the pre-existing /workspace + hermes-home fallback paths. A new state-dir-uid job in the Docker smoke workflow boots a real container on a host-owned state mount and gates on /health. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Release batch B: Docker UID fix + GLM-5.3 catalog (experimental) Two independently gate-passed contributor PRs, rebased fresh onto master and re-gated as a combined stage (Codex SAFE TO SHIP; full suite green except the 8 pre-existing approval-test failures that fail identically on clean origin/master — CI green on the same commit; tracked separately for a fix). - nesquena#7027 (@jorgejiro) probe configured state-dir before /workspace for Docker UID/GID; persist explicit marker so a supplied 1024 survives root->su re-entry (fixes the single-container restart loop) (nesquena#7034) - nesquena#7017 (@rh-id) add GLM-5.3 to the Z.AI model list (onboarding default stays glm-5.1) Co-authored-by: jorgejiro <jorgejiro@users.noreply.github.com> Co-authored-by: rh-id <rh-id@users.noreply.github.com> --------- Co-authored-by: Ruby Hartono <58564005+rh-id@users.noreply.github.com> Co-authored-by: Jorge <jorgejiro@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: n <a@n> Co-authored-by: jorgejiro <jorgejiro@users.noreply.github.com> Co-authored-by: rh-id <rh-id@users.noreply.github.com>
Thinking Path
_PROVIDER_MODELSinapi/config.py; the newest cataloged Z.AI (GLM) model is GLM-5.2.api.z.aiendpoint thezaiprovider uses still lists the GLM-5.3 API as "coming soon". So: catalog the model for opt-in selection, but do not default new direct-API users onto it.(major, minor) >= (5, 2)→ fullreasoning_effortladder), soglm-5.3is already handled correctly — no gating change needed.What Changed
api/config.py:glm-5.3added as the firstzaientry in_PROVIDER_MODELS, plus a matchingzai/glm-5.3entry in_FALLBACK_MODELS(both lists are newest-first).api/onboarding.py: unchanged — the Z.AIdefault_modeldeliberately staysglm-5.1until the direct API serves GLM-5.3 (per review; see Risks / Follow-ups). The wizard'smodelslist derives from_PROVIDER_MODELS, so GLM-5.3 is selectable there as an opt-in.tests/test_glm_5_3_catalog.py: new regression file (8 tests) — catalog presence + label, newest-first ordering, fallback entry + ordering, the onboarding default staying atglm-5.1(pinned with rationale), GLM-5.3 present in the wizard's selectable list, fullreasoning_effortladder, and an endpoint-level check thatglm-5.3reaches theget_available_models()payload (the builder behindGET /api/models).tests/test_custom_providers_in_panel.py: untouched relative tomaster(the onboarding-default assertion still pinsglm-5.1).Why It Matters
Verification
All runs through the repo
.venv(Python 3.12, created by./scripts/test.sh); all fixtures usetmp_path— no real~/.hermesstate touched.masterthe new catalog tests fail (catalog missing, fallback missing, ordering, wizard list missing GLM-5.3); after the change all 8 pass.api/config.pycatalog hunk stashed it fails withglm-5.3 missing from zai group models; got ['glm-5.2', …]; restored, it passes. Its fixture config deliberately setsdefault: glm-5.2, so the assertion proves catalog propagation, not config echo..venv):tests/test_glm_5_3_catalog.py+tests/test_custom_providers_in_panel.py+tests/test_byok_model_dropdown.py+tests/test_zai_reasoning_effort_gating.py+tests/test_model_resolver.py→ 190 passed.E9,F,B) on touched files: clean.glm-5.3forward-compat intests/test_zai_reasoning_effort_gating.py— unchanged and passing.cfg,_cfg_mtime,_cfg_path, and_cfg_fingerprint(Greptile follow-up addressed in 1dab4f2).Risks / Follow-ups
default_modeltoglm-5.3in a one-line follow-up PR and update thetest_zai_onboarding_default_stays_glm_5_1_until_direct_api_serves_glm_5_3pin. The gate: a raw200completion againsthttps://api.z.ai/api/paas/v4/chat/completionswith"model": "glm-5.3"./api/modelscache auto-invalidates via the_PROVIDER_MODELShash in_models_cache_catalog_fingerprint()(Invalidate persisted models cache when catalog sources change #2443), so no cache-version bump is needed.opencode-zen/opencode-gostatic catalogs also list GLM models, but they are independently synced platform snapshots — left untouched because GLM-5.3 availability on those platforms is unverified.tests/test_byok_model_dropdown.pybeforetests/test_custom_providers_in_panel.pyin the same process makes the latter'stest_custom_provider_with_modelsfail (custom:glmcode missing) — reproducible onmasterwithout these changes (config-path state leaks between the files). The new test file does not add to that problem.glm-5.3(no API key used; the id follows the repo's established lowercase convention). No browser session was run — the payload-level test stands in for picker UI evidence.Contract Routing
Task type: static model-catalog addition (opt-in model; onboarding default intentionally unchanged).
Touched areas:
api/config.pycatalog, tests.Relevant public docs:
AGENTS.md,CONTRIBUTING.md,docs/CONTRACTS.md(no subsystem contract pins provider model lists).Scope boundaries: no runtime/streaming/UI-flow changes; onboarding default and aggregator catalogs untouched.
Evidence: fail-before/pass-after tests + endpoint-level payload assertion.
Not contract-affecting.
Release note
Model Used