anthropics / anthropics/claude-agent-sdk-python

parse_message silently drops newer CLI wire fields (ttft_ms, terminal_reason, stop_details, …) with no escape hatch

Đang mở
#1,026 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
bug enhancement
Ngôn ngữ chính
Python
Star
8.1k
Fork
1.3k
Merge trung bình
2 ngày 31 phút
Pull request đã merge (30 ngày)
1

Mô tả

## Summary

The Claude Code CLI (2.1.150) emits several stream-json fields that `parse_message` neither reads nor retains — they vanish from the typed messages with no way to recover them. Unlike `SystemMessage` (which keeps the raw frame as `.data`), `AssistantMessage` and `ResultMessage` don't retain the original frame, so SDK consumers cannot access these fields at all without bypassing the SDK and re-parsing the wire themselves.

Verified identical on **claude-agent-sdk 0.2.87 and 0.2.95** (latest).

## Dropped fields observed on the wire

| Wire field | Example recorded value | Notes |
|---|---|---|
| `result.ttft_ms` | `2806` | time-to-first-token — a metric consumers chart |
| `result.terminal_reason` | `"completed"` | |
| `result.fast_mode_state` | `"off"` | |
| `assistant message.content[].caller` | `{"type": "direct"}` | per content block |
| `assistant message.stop_details` | observed `null` | emitted, unmodeled |
| `assistant message.diagnostics` | observed `null` | emitted, unmodeled |
| `assistant message.context_management` | observed `null` | emitted, unmodeled |
| `assistant request_id` | `"req_…"` | top-level frame key |

## Repro

```python
from claude_agent_sdk._internal.message_parser import parse_message

frame = { # verbatim CLI stream-json (trimmed)
"type": "result", "subtype": "success", "duration_ms": 8127,
"duration_api_ms": 7903, "is_error": False, "num_turns": 4,
"session_id": "s", "total_cost_usd": 0.02, "usage": {},
"ttft_ms": 2806, "terminal_reason": "completed", "fast_mode_state": "off",
}
msg = parse_message(frame)
assert not hasattr(msg, "ttft_ms") # gone
assert "terminal_reason" not in str(msg) # gone, and not recoverable
```

## Suggested fix (either works)

1. Model the fields on the dataclasses (`ResultMessage.ttft_ms`, etc.), or
2. Retain the raw frame on every message type (the `SystemMessage.data` pattern) as a forward-compatible escape hatch, so new CLI fields are reachable before they're modeled.

## How this was found

Mechanically, by a record/replay drift detector ([claude-agent-cassette](https://github.com/oneryalcin/claude-agent-cassette)): it runs `parse_message` over an access-tracking view of recorded frames and reports any key the parser neither reads nor retains. Happy to re-run it against a branch if useful.

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.