fix: Anthropic responses with multiple text blocks lose all but the first (#1255)
* fix: concatenate all Anthropic text blocks, not just the first * test: Anthropic response parsing concatenates text blocks
This commit is contained in:
@@ -562,11 +562,18 @@ def _build_anthropic_headers(headers):
|
|||||||
return h
|
return h
|
||||||
|
|
||||||
def _parse_anthropic_response(data: dict) -> str:
|
def _parse_anthropic_response(data: dict) -> str:
|
||||||
"""Extract text from Anthropic response."""
|
"""Extract text from an Anthropic response.
|
||||||
for block in data.get("content", []):
|
|
||||||
if block.get("type") == "text":
|
The Messages API `content` is an array that can hold more than one text
|
||||||
return block.get("text", "")
|
block (e.g. text split around a tool_use block, or citation-segmented
|
||||||
return ""
|
text). Concatenate them all instead of returning only the first, which
|
||||||
|
silently dropped the rest of the reply.
|
||||||
|
"""
|
||||||
|
return "".join(
|
||||||
|
block.get("text", "")
|
||||||
|
for block in data.get("content", [])
|
||||||
|
if isinstance(block, dict) and block.get("type") == "text"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _sanitize_llm_messages(messages: List[Dict]) -> List[Dict]:
|
def _sanitize_llm_messages(messages: List[Dict]) -> List[Dict]:
|
||||||
|
|||||||
27
tests/test_anthropic_response_parse.py
Normal file
27
tests/test_anthropic_response_parse.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
"""Tests for _parse_anthropic_response (src/llm_core.py)."""
|
||||||
|
|
||||||
|
from src.llm_core import _parse_anthropic_response
|
||||||
|
|
||||||
|
|
||||||
|
def test_concatenates_multiple_text_blocks():
|
||||||
|
# Regression: only the first text block was returned, dropping the rest.
|
||||||
|
data = {"content": [
|
||||||
|
{"type": "text", "text": "Part A "},
|
||||||
|
{"type": "tool_use", "id": "t1", "name": "x", "input": {}},
|
||||||
|
{"type": "text", "text": "Part B"},
|
||||||
|
]}
|
||||||
|
assert _parse_anthropic_response(data) == "Part A Part B"
|
||||||
|
|
||||||
|
|
||||||
|
def test_skips_non_text_blocks():
|
||||||
|
data = {"content": [
|
||||||
|
{"type": "thinking", "thinking": "..."},
|
||||||
|
{"type": "text", "text": "answer"},
|
||||||
|
]}
|
||||||
|
assert _parse_anthropic_response(data) == "answer"
|
||||||
|
|
||||||
|
|
||||||
|
def test_single_block_and_empty():
|
||||||
|
assert _parse_anthropic_response({"content": [{"type": "text", "text": "hi"}]}) == "hi"
|
||||||
|
assert _parse_anthropic_response({"content": []}) == ""
|
||||||
|
assert _parse_anthropic_response({}) == ""
|
||||||
Reference in New Issue
Block a user