Skip to content

fix(zai): restore request-local prompt policy - #63622

Open
aider4ryder wants to merge 1 commit into
NousResearch:mainfrom
aider4ryder:fix/zai-prompt-policy-current-main
Open

aider4ryder wants to merge 1 commit into
NousResearch:mainfrom
aider4ryder:fix/zai-prompt-policy-current-main

Conversation

@aider4ryder

@aider4ryder aider4ryder commented Jul 13, 2026

Copy link
Copy Markdown

Summary

Restore a request-local prompt compatibility policy for direct Z.AI endpoints on current main.

This is a fresh, current-main replacement for the closed #52976 carried patch. The request assembly code has since moved into ChatCompletionsTransport, so the old commit no longer applies cleanly.

Motivation

Direct Z.AI Coding Plan requests have intermittently returned HTTP 429 with provider code 1305 when the full Hermes/Nous identity prompt is sent. The failure is not reliably deterministic—an exact failed payload can succeed later—so this change is deliberately narrow and fail-safe rather than treating every GLM model as affected.

What changed

  • Add a request-local Z.AI prompt policy that:
    • activates only for explicit Z.AI/Zhipu provider identities or the exact api.z.ai / open.bigmodel.cn hostnames;
    • does not activate from the glm-* model name alone, preserving locally hosted GLM deployments;
    • strips the known identity sentences and rewrites only the multi-word Hermes Agent / Nous Research branding phrases;
    • preserves operational identifiers such as hermes tools, ~/.hermes/, .hermes.md, HERMES_HOME, and Active Hermes profile;
    • handles string and multipart system content;
    • inserts a neutral system message if one is absent.
  • Apply the policy at the Chat Completions transport boundary.
  • Forward the resolved provider name through provider-profile transport calls, so explicit Z.AI identities remain available even without a URL-derived match.
  • Apply the same policy to the iteration-limit summary path, which intentionally bypasses the transport builder.
  • Keep cached prompts, session history, user messages, and non-Z.AI request identity unchanged.

Verification

uv run --with pytest python -m pytest tests/agent/test_zai_prompt_policy.py -q -o addopts=
9 passed

uv run --with pytest python -m pytest \
  tests/agent/test_zai_prompt_policy.py \
  tests/providers/test_transport_parity.py \
  tests/providers/test_profile_wiring.py \
  tests/agent/test_model_extra_type_guard.py \
  tests/run_agent/test_run_agent.py \
  -k 'zai_prompt_policy or transport_parity or profile_wiring or model_extra_type_guard or BuildApiKwargs or build_api_kwargs' \
  -q -o addopts=
94 passed, 381 deselected

uv run --with ruff ruff check agent/zai_prompt_policy.py agent/chat_completion_helpers.py agent/transports/chat_completions.py tests/agent/test_zai_prompt_policy.py tests/run_agent/test_run_agent.py
All checks passed!

uv run --with ty ty check agent/zai_prompt_policy.py tests/agent/test_zai_prompt_policy.py
All checks passed!

Live checks against the configured custom:z2 Z.AI endpoint:

hermes --provider custom:z2 -m glm-5.2 -z 'Reply with exactly: OK'
OK

A request-local replay of the previously failed 29k-token payload verified that the original messages remained unchanged, the outbound identity block was neutralized, and Z.AI returned HTTP 200 (finish_reason=tool_calls). No credentials or request content are included here.

Safety / scope

  • No mutation of cached prompts or persisted conversation history.
  • No model-name-only gating.
  • Exact hostname parsing for api.z.ai and open.bigmodel.cn avoids substring-host spoofing.
  • Non-target providers return the original message object unchanged.
  • Operational Hermes CLI/path/config identifiers are covered by preservation tests.

Supersedes #52976.

@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/zai ZAI provider P2 Medium — degraded but workaround exists labels Jul 13, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Fresh current-main replacement for the closed #52976 (request assembly moved into ChatCompletionsTransport), and a competing approach to OPEN #59975, which sanitizes the Z.AI/GLM system prompt at a different chokepoint. Both introduce agent/zai_prompt_policy.py — the two will collide if more than one lands. Related, not a duplicate. Flagging for a human to pick one and consolidate the shared module.

@aider4ryder
aider4ryder force-pushed the fix/zai-prompt-policy-current-main branch 5 times, most recently from 89dcd2b to 21cedc1 Compare July 13, 2026 10:50

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for moving the compatibility policy to the current request-assembly layer and preserving the cached prompt.

Problems

  • agent/zai_prompt_policy.py:60 prefixes each multipart text block independently. Since sanitize_zai_system_prompt() prepends _ZAI_SYSTEM_PREFIX for every nonempty block (agent/zai_prompt_policy.py:45-49), two text blocks produce two identity prefixes. The added multipart test exercises only one block.
  • The policy is not transport-consistent for Zhipu's supported Anthropic route: tests/run_agent/test_anthropic_third_party_oauth_guard.py:103-112 configures glm at https://open.bigmodel.cn/api/anthropic, while the iteration summary dispatches anthropic_messages via agent/chat_completion_helpers.py:1906-1914. The ordinary route remains unsanitized, but the new summary hook changes that summary request.

Suggested changes

  • Sanitize multipart branding per part but add the neutral prefix once per system message, with a multi-text-part regression test.
  • Either cover the Anthropic transport too or constrain this policy explicitly to Chat Completions, including the summary path.

Automated hermes-sweeper review.

if not isinstance(part, dict):
continue
if isinstance(part.get("text"), str):
part["text"] = sanitize_zai_system_prompt(part["text"])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sanitize_zai_system_prompt() prepends _ZAI_SYSTEM_PREFIX to every nonempty string, so a multipart system message with multiple text blocks gets the prefix repeated once per block. Preserve per-part replacement, but insert the neutral prefix once at message scope and add a two-text-part regression test.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-caching Sweeper risk: may break/degrade prompt caching or cache-key stability (invariant) sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 16, 2026
aider4ryder pushed a commit to aider4ryder/hermes-agent that referenced this pull request Jul 19, 2026
@aider4ryder
aider4ryder force-pushed the fix/zai-prompt-policy-current-main branch from 21cedc1 to 3b0d8f8 Compare July 19, 2026 10:33
RyderFreeman4Logos added a commit to RyderFreeman4Logos/hermes-agent that referenced this pull request Jul 24, 2026
RyderFreeman4Logos added a commit to RyderFreeman4Logos/hermes-agent that referenced this pull request Jul 26, 2026
ebarczynski pushed a commit to ebarczynski/hermes-agent that referenced this pull request Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists provider/zai ZAI provider sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-caching Sweeper risk: may break/degrade prompt caching or cache-key stability (invariant) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants