anthropics / anthropics/claude-agent-sdk-python

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

Offen
#1,026 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug enhancement
Vorherrschende Sprache
Python
Sterne
8.1k
Forks
1.3k
Ø Merge
2 T. 31 Min.
Gemergte PRs (30 T.)
1

Beschreibung

## 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.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.