fix(anthropic): strip trailing assistant messages to prevent prefill error

Anthropic does not support assistant-message prefill and returns a 400
error when the conversation ends with an assistant turn. This commonly
happens when heartbeat/system messages accumulate trailing assistant
replies in the session history.

The _merge_consecutive method already handles same-role merging but did
not strip trailing assistant messages. The base provider's
_enforce_role_alternation (used by OpenAI-compat) does strip them, but
AnthropicProvider uses its own _merge_consecutive instead.

Add a trailing-assistant stripping loop to _merge_consecutive, matching
the behavior already present in _enforce_role_alternation.

Includes 7 new tests covering merge + strip behavior.
This commit is contained in:
hussein1362
2026-04-21 01:32:32 +08:00
committed by Xubin Ren
parent 00de55072d
commit 2f02342083
2 changed files with 78 additions and 1 deletions
+12 -1
View File
@@ -247,7 +247,12 @@ class AnthropicProvider(LLMProvider):
@staticmethod
def _merge_consecutive(msgs: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""Anthropic requires alternating user/assistant roles."""
"""Anthropic requires alternating user/assistant roles.
Also strips trailing assistant messages since Anthropic does not
support assistant-message prefill and will reject the request with
a 400 error if the conversation ends with an assistant turn.
"""
merged: list[dict[str, Any]] = []
for msg in msgs:
if merged and merged[-1]["role"] == msg["role"]:
@@ -262,6 +267,12 @@ class AnthropicProvider(LLMProvider):
merged[-1]["content"] = prev_c
else:
merged.append(msg)
# Drop trailing assistant messages to avoid Anthropic's
# "does not support assistant message prefill" 400 error.
while merged and merged[-1].get("role") == "assistant":
merged.pop()
return merged
# ------------------------------------------------------------------