anthropics / anthropics/claude-agent-sdk-python
parse_message silently drops newer CLI wire fields (ttft_ms, terminal_reason, stop_details, …) with no escape hatch
- 主要言語
- Python
- スター
- 8.1k
- フォーク
- 1.3k
- 平均マージ
- 2日 31分
- マージ済み PR(30日)
- 1
説明
## 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.
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
評価
この issue はまだ評価されていません。