Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/claude_agent_sdk/_internal/message_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def parse_message(data: dict[str, Any]) -> Message | None:
is_error=data["is_error"],
num_turns=data["num_turns"],
session_id=data["session_id"],
stop_reason=data.get("stop_reason"),
total_cost_usd=data.get("total_cost_usd"),
usage=data.get("usage"),
result=data.get("result"),
Expand Down
1 change: 1 addition & 0 deletions src/claude_agent_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ class ResultMessage:
is_error: bool
num_turns: int
session_id: str
stop_reason: str | None = None
total_cost_usd: float | None = None
usage: dict[str, Any] | None = None
result: str | None = None
Expand Down
39 changes: 39 additions & 0 deletions tests/test_message_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,45 @@ def test_parse_valid_result_message(self):
message = parse_message(data)
assert isinstance(message, ResultMessage)
assert message.subtype == "success"
assert message.stop_reason is None

def test_parse_result_message_with_stop_reason(self):
"""Test parsing a result message with stop_reason field.

The stop_reason field mirrors the Anthropic API's stop_reason on the
final assistant turn (e.g., "end_turn", "max_tokens", "tool_use").
"""
data = {
"type": "result",
"subtype": "success",
"duration_ms": 1000,
"duration_api_ms": 500,
"is_error": False,
"num_turns": 2,
"session_id": "session_123",
"stop_reason": "end_turn",
"result": "Done",
}
message = parse_message(data)
assert isinstance(message, ResultMessage)
assert message.stop_reason == "end_turn"
assert message.result == "Done"

def test_parse_result_message_with_null_stop_reason(self):
"""Test parsing a result message with explicit null stop_reason."""
data = {
"type": "result",
"subtype": "error_max_turns",
"duration_ms": 1000,
"duration_api_ms": 500,
"is_error": True,
"num_turns": 10,
"session_id": "session_123",
"stop_reason": None,
}
message = parse_message(data)
assert isinstance(message, ResultMessage)
assert message.stop_reason is None

def test_parse_invalid_data_type(self):
"""Test that non-dict data raises MessageParseError."""
Expand Down