Fixes the persistent 429 (code 1305 "overloaded") error when using Hermes Agent with zai/glm-5.2 (Z.AI Coding Plan).
This is not ordinary rate limiting. Swapping API keys, changing endpoints, or shrinking request size all fail because two independent triggers are at work:
| Layer | Trigger | Symptom |
|---|---|---|
| System Prompt content filter | The product name "Hermes Agent" appears in the prompt |
Server returns 429/1305 disguised as "overloaded" |
| Client fingerprint detection | Request headers don't match the real ZCode Desktop client | Cloudflare edge 1010 / silent throttling |
Both gates must be bypassed simultaneously for stable API access.
At the final assembly boundary in build_system_prompt(), when the provider is zai and the model is glm-5.2, every occurrence of "Hermes Agent" in the assembled prompt is rewritten to "ZCode".
Key design: The rewrite happens on the in-memory prompt after assembly. Nothing on disk is touched — docs, skills, memories, and stored sessions all remain byte-identical. The substitution exists only in the text sent to the API.
build_zcode_headers() generates a set of HTTP headers that match the real ZCode Desktop 3.1.8 client:
| Header | Value | Lifecycle |
|---|---|---|
User-Agent |
ZCode/<ver> ai-sdk/anthropic/3.0.81 |
Static |
X-ZCode-App-Version |
<ver> (overridable via ZCODE_APP_VERSION env var) |
Static |
X-ZCode-Agent |
glm |
Static |
x-zcode-trace-id |
Random hex | Fresh per request |
x-request-id |
Random hex | Fresh per request |
x-session-id |
sess_<24hex> |
Process-stable |
x-query-id |
Random hex | Fresh per request |
HTTP-Referer |
https://zcode.z.ai |
Static |
X-Title |
Z Code |
Static |
In run_agent.py, these headers are injected when the provider is zai or the base URL matches api.z.ai / open.bigmodel.cn.
Fingerprint source: Reverse-engineered from ZCode Desktop 3.1.8 (Electron), bundled obfuscated code at resources/glm/zcode.cjs, functions eao() / rao().
| File | Change |
|---|---|
agent/auxiliary_client.py |
New build_zcode_headers() function + uuid import |
agent/system_prompt.py |
Brand-word replacement logic in build_system_prompt() |
run_agent.py |
New zai branch in _apply_client_headers_for_base_url() |
tests/agent/test_system_prompt.py |
New TestZaiSystemPromptRewrite test class (2 cases) |
tests/run_agent/test_provider_attribution_headers.py |
New fingerprint assertion test |
5 files, +127/-1 (including tests). The package-lock.json diff is unrelated and excluded.
- Hermes Agent v0.17.0+ installed at
~/.hermes/hermes-agent - A
zaiprovider configured (GLM Coding Plan API key) gitand a working Python venv insidehermes-agent/- No uncommitted changes to the 5 target files (see below)
1 — Clone this repo
git clone https://github.com/moreoronce/hermes-zcode-glm-patch.git /tmp/zcode-patch2 — Check for conflicts
Before applying, verify the target files have no uncommitted local changes:
cd ~/.hermes/hermes-agent
git status --short -- agent/auxiliary_client.py agent/system_prompt.py run_agent.py \
tests/agent/test_system_prompt.py tests/run_agent/test_provider_attribution_headers.pyIf anything shows up, git stash or commit first.
3 — Back up (safety net)
git tag pre-zcode-patchIf something goes wrong later: git reset --hard pre-zcode-patch rolls everything back in one command.
4 — Apply the patch
git apply --check /tmp/zcode-patch/patches/zcode-glm-patch.diff # dry-run first
git apply /tmp/zcode-patch/patches/zcode-glm-patch.diff # apply for realIf --check reports conflicts, the upstream code has diverged. See Upstream Sync Notes below, or fall back to manual installation.
5 — Verify
source venv/bin/activate
python -m pytest tests/agent/test_system_prompt.py::TestZaiSystemPromptRewrite \
tests/run_agent/test_provider_attribution_headers.py::test_zai_base_url_applies_zcode_client_fingerprint -vAll 3 tests should pass. Then restart Hermes (TUI / gateway / desktop app) so the new headers take effect — existing in-flight clients won't hot-reload the change.
6 — Confirm the fix
Start a new session and send any message. In the gateway log or dashboard, verify the request to api.z.ai carries User-Agent: ZCode/3.1.8 ... and X-ZCode-App-Version: 3.1.8. The 429/1305 errors should be gone.
If git apply fails due to upstream divergence, apply each section of patches/zcode-glm-patch.diff by hand:
agent/auxiliary_client.py— addimport uuidto the top imports; add the_ZCODE_APP_VERSION/_ZCODE_SESSION_IDconstants and thebuild_zcode_headers()function (follow the diff hunk@@ ... @@markers to find insertion points).agent/system_prompt.py— inbuild_system_prompt(), after thejoined = ...line and before the truncation-warning loop, insert thezai+glm-5.2brand-rewrite block.run_agent.py— in_apply_client_headers_for_base_url(), add thebuild_zcode_headersimport and theelif provider == "zai"branch.- Test files — add the test cases from the diff.
If you are an AI agent (e.g. another Hermes instance, Claude Code, Cursor) reading this repo to apply the patch on behalf of a user, see INSTALL-AGENT.md for a machine-readable install protocol.
The version is hardcoded as 3.1.8 but can be overridden without editing code:
# In ~/.hermes/.env or your shell profile:
export ZCODE_APP_VERSION=3.2.0To change the default, edit the fallback in agent/auxiliary_client.py:
_ZCODE_APP_VERSION = os.environ.get("ZCODE_APP_VERSION", "3.1.8") # ← change thisAfter merging Hermes upstream updates, re-check:
auxiliary_client.pyandrun_agent.pyare high-churn files — watch the_create_openai_client()wrapper and header branch logic for conflicts.system_prompt.pyupstream rarely changes the assembly boundary, but verify.- ZCode version defaults to
3.1.8; override at runtime withZCODE_APP_VERSION=3.2.0without code changes.
Current compatibility snapshot: rebased against Hermes Agent upstream 44ddc552f with the targeted verification suite passing (23 passed).
- Hermes Agent — Nous Research
- Root-cause analysis: Deep Router — Hermes Agent 优化:解决GLM-5.2模型429(1305 overloaded)
MIT