Skip to content

fix(agent-core): drop thinking-only assistant messages from projected requests - #30

Merged
mbuckaway merged 1 commit into
fork/mainfrom
fix/esc-interrupt-thinking-drop
Aug 9, 2026
Merged

fix(agent-core): drop thinking-only assistant messages from projected requests#30
mbuckaway merged 1 commit into
fork/mainfrom
fix/esc-interrupt-thinking-drop

Conversation

@mbuckaway

Copy link
Copy Markdown
Owner

Related Issue

Resolve MoonshotAI#2691 (upstream: "Pressing ESC mid-stream permanently wedges the session: next request fails with 400 Invalid assistant message: content or tool_calls must be set"). This is a port of upstream PR MoonshotAI#2689 into the fork, based on fork/main (0.34.0-MB.1.6).

Problem

Interrupting a response (ESC/stop) while the model is still thinking seals a partial assistant message that holds only an unencrypted thinking fragment. When the next request is built, the OpenAI-compatible provider base moves think parts out of content into reasoning_content, so the message serializes with neither content nor tool_calls, and the provider rejects it with:

400 Invalid assistant message: content or tool_calls must be set

The error is non-retryable and the history is rebuilt identically on every retry, so the session stays permanently wedged (observed on the webui USR-dashboard session, 2026-08-09, with deepseek-v4-flash).

What changed

The projector now treats unencrypted think parts as non-sendable content and drops a whole message when it carries nothing else:

  • packages/agent-core/src/agent/context/projector.ts (v1 engine) — new wireSendableContent helper; a message whose only parts are unencrypted thinking is dropped from the projected request.
  • packages/agent-core-v2/src/agent/contextProjector/contextProjectorService.ts (v2 engine) — same change.
  • Signed/encrypted thinking (encrypted) is preserved verbatim, and messages that carry any text, tool calls, or media keep every part intact.
  • Regression tests for the ESC-cancel scenario added to both engines; changeset included.

Commits in this PR

  • b2be09027 — fix(agent-core): drop thinking-only assistant messages from projected requests (Mark Buckaway, 2026-08-09)

Testing

  • Unit tests pass (agent-core: 4139 passed; agent-core-v2: 4967 passed)
  • Integration tests pass
  • Manual testing completed — replaying the bricked webui session's wire log through the fixed projector produces 0 empty-content assistant messages (previously 1 poisoned + 2 empty), and the patched binary was built and verified

… requests

Interrupting a response (ESC/stop) mid-thinking seals a partial assistant
message holding only an unencrypted thinking fragment. The OpenAI-compatible
base moves think parts out of `content` into `reasoning_content`, so the
message serializes with neither content nor tool_calls and the provider
rejects it with "400 Invalid assistant message: content or tool_calls must be
set" on every retry, permanently wedging the session.

The projector now treats unencrypted think parts as non-sendable content and
drops whole messages that carry nothing else (signed/encrypted thinking and
messages with real content are preserved). Applies to both the v1 (agent-core)
and v2 (agent-core-v2) engines, with regression tests for the ESC-cancel case
and a changeset.
@mbuckaway
mbuckaway merged commit 227480a into fork/main Aug 9, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pressing ESC mid-stream permanently wedges the session: next request fails with 400 Invalid assistant message: content or tool_calls must be set

1 participant