diff --git a/agent/anthropic_adapter.py b/agent/anthropic_adapter.py index fd7596e7e3bf..ca86c3ebe266 100644 --- a/agent/anthropic_adapter.py +++ b/agent/anthropic_adapter.py @@ -2427,7 +2427,10 @@ def _ensure_leading_user_turn(result: List[Dict[str, Any]]) -> None: (convert_messages_to_converse). """ if result and result[0].get("role") != "user": - result.insert(0, {"role": "user", "content": [{"type": "text", "text": " "}]}) + # ponytail: some Anthropic-compatible endpoints (e.g. zenmux) reject a + # whitespace-only text block with HTTP 400 "text content blocks must + # contain non-whitespace text"; use a minimal non-blank placeholder. + result.insert(0, {"role": "user", "content": [{"type": "text", "text": "."}]}) def convert_messages_to_anthropic( diff --git a/tests/agent/test_anthropic_adapter.py b/tests/agent/test_anthropic_adapter.py index ae99f950f739..c2166522edf4 100644 --- a/tests/agent/test_anthropic_adapter.py +++ b/tests/agent/test_anthropic_adapter.py @@ -1394,7 +1394,9 @@ def test_leading_assistant_after_compaction_gets_user_turn_prepended(self): assert system == "You are helpful." assert result[0]["role"] == "user" - assert result[0]["content"] == [{"type": "text", "text": " "}] + # Placeholder text must be non-whitespace: strict Anthropic-compatible + # endpoints (zenmux) 400 on whitespace-only text blocks. + assert result[0]["content"][0]["text"].strip() assert result[1]["role"] == "assistant" assert any( m["role"] == "assistant" and "Context compaction summary" in str(m["content"]) @@ -1418,7 +1420,7 @@ def test_double_compaction_no_system_in_messages_leads_with_user(self): assert system is None assert result[0]["role"] == "user" - assert result[0]["content"] == [{"type": "text", "text": " "}] + assert result[0]["content"][0]["text"].strip() assert result[1]["role"] == "assistant" assert "Context compaction summary" in str(result[1]["content"])