Skip to content

fix(moa): skip empty user messages in reference view to prevent ZAI e… - #61040

Closed
acklabsio wants to merge 1 commit into
NousResearch:mainfrom
acklabsio:fix/moa-empty-user-clean
Closed

acklabsio wants to merge 1 commit into
NousResearch:mainfrom
acklabsio:fix/moa-empty-user-clean

Conversation

@acklabsio

Copy link
Copy Markdown

…rror 1213

ZAI (glm-5.2) rejects empty/whitespace-only user content with HTTP 400 error 1213 ('The prompt parameter was not received normally'). The MoA _reference_messages() function was appending user messages unconditionally even when their content was empty — only updating last_user_content when non-empty. In conversations with empty user turns (image-only messages, whitespace, etc.), the empty content reached the reference model and caused a one-sided MoA failure (reference drops out, aggregator works with partial input).

Fix: only append user messages that have non-empty text content. This also eliminates consecutive-role alternation violations these empty messages would otherwise create.

What does this PR do?

Related Issue

Fixes #

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

How to Test

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform:

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

For New Skills

  • This skill is broadly useful to most users (if bundled) — see Contributing Guide
  • SKILL.md follows the standard format (frontmatter, trigger conditions, steps, pitfalls)
  • No external dependencies that aren't already available (prefer stdlib, curl, existing Hermes tools)
  • I've tested the skill end-to-end: hermes --toolsets skills -q "Use the X skill to do Y"

Screenshots / Logs

…rror 1213

ZAI (glm-5.2) rejects empty/whitespace-only user content with HTTP 400
error 1213 ('The prompt parameter was not received normally'). The MoA
_reference_messages() function was appending user messages unconditionally
even when their content was empty — only updating last_user_content when
non-empty. In conversations with empty user turns (image-only messages,
whitespace, etc.), the empty content reached the reference model and
caused a one-sided MoA failure (reference drops out, aggregator works
with partial input).

Fix: only append user messages that have non-empty text content. This
also eliminates consecutive-role alternation violations these empty
messages would otherwise create.
@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 P3 Low — cosmetic, nice to have duplicate This issue or pull request already exists labels Jul 8, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Duplicate of #58465 — both add an empty/whitespace-only user-turn skip to the same if role == "user" branch of _reference_messages() in agent/moa_loop.py (same code site, same base), with the same mechanism (keep empty user turns out of the MoA advisory view so strict providers stop 400ing). The only difference is the framing of the reporting provider (ZAI/glm-5.2 error 1213 here vs Kimi/Moonshot "role user must not be empty" there). #58465 is the earlier open PR (2026-07-04 vs 2026-07-08) and additionally includes a regression test, so it's canonical. Related: #58464 (issue), #56479 (open, consecutive same-role merge — a distinct facet of the same reference-view family).

@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.

Thanks for targeting a real MoA reference-view failure. The premise remains present on current main: agent/moa_loop.py:478-480 renders blank user turns.

Problems

  • agent/moa_loop.py:478-480 does not cover an advisory transcript with no nonempty user text. For a sole whitespace user turn, this branch leaves rendered empty, then the unchanged fallback at agent/moa_loop.py:521-527 returns that same whitespace string as a user message. The strict-provider failure therefore remains for that case.
  • The PR has no regression test. Existing reference-view coverage in tests/run_agent/test_moa_loop_mode.py:282-392 does not cover the empty-only fallback.

Suggested changes

  • Guard the fallback against blank strings and preserve a nonempty terminal user message when no textual user context exists.
  • Add an empty-only/whitespace-only regression case asserting no blank user content is emitted.

Automated hermes-sweeper review.

Comment thread agent/moa_loop.py
if text.strip():
last_user_content = text
rendered.append({"role": "user", "content": text})
rendered.append({"role": "user", "content": 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.

This skips blank turns only when another message renders. With a transcript containing only {"role": "user", "content": " "}, rendered stays empty and the unchanged fallback at lines 521-527 returns the whitespace string as a user message. Please harden that fallback and add an empty-only regression test.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 10, 2026
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks @alihancankara91-cloud — correct diagnosis of the same empty-user-turn class (your ZAI error-1213 report matched the Kimi/Moonshot 400 in #58464). This landed on main via #64409, which salvages the earliest submission (#58465, Jul 4) with a follow-up reconciling multimodal/image-only turns. Your report is credited in the fix's provider coverage. Closing as superseded.

@teknium1 teknium1 closed this Jul 14, 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 duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users 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.

3 participants