Skip to content

Commit 0ae5c32

Browse files
authored
Add UUID to UserMessage response type to improve devX for rewind (#418)
1 parent f834ba9 commit 0ae5c32

File tree

4 files changed

+28
-4
lines changed

4 files changed

+28
-4
lines changed

src/claude_agent_sdk/_internal/message_parser.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def parse_message(data: dict[str, Any]) -> Message:
4848
case "user":
4949
try:
5050
parent_tool_use_id = data.get("parent_tool_use_id")
51+
uuid = data.get("uuid")
5152
if isinstance(data["message"]["content"], list):
5253
user_content_blocks: list[ContentBlock] = []
5354
for block in data["message"]["content"]:
@@ -74,10 +75,12 @@ def parse_message(data: dict[str, Any]) -> Message:
7475
)
7576
return UserMessage(
7677
content=user_content_blocks,
78+
uuid=uuid,
7779
parent_tool_use_id=parent_tool_use_id,
7880
)
7981
return UserMessage(
8082
content=data["message"]["content"],
83+
uuid=uuid,
8184
parent_tool_use_id=parent_tool_use_id,
8285
)
8386
except KeyError as e:

src/claude_agent_sdk/client.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,20 +264,25 @@ async def set_model(self, model: str | None = None) -> None:
264264
async def rewind_files(self, user_message_id: str) -> None:
265265
"""Rewind tracked files to their state at a specific user message.
266266
267-
Requires file checkpointing to be enabled via the `enable_file_checkpointing` option
268-
when creating the ClaudeSDKClient.
267+
Requires:
268+
- `enable_file_checkpointing=True` to track file changes
269+
- `extra_args={"replay-user-messages": None}` to receive UserMessage
270+
objects with `uuid` in the response stream
269271
270272
Args:
271273
user_message_id: UUID of the user message to rewind to. This should be
272274
the `uuid` field from a `UserMessage` received during the conversation.
273275
274276
Example:
275277
```python
276-
options = ClaudeAgentOptions(enable_file_checkpointing=True)
278+
options = ClaudeAgentOptions(
279+
enable_file_checkpointing=True,
280+
extra_args={"replay-user-messages": None},
281+
)
277282
async with ClaudeSDKClient(options) as client:
278283
await client.query("Make some changes to my files")
279284
async for msg in client.receive_response():
280-
if isinstance(msg, UserMessage):
285+
if isinstance(msg, UserMessage) and msg.uuid:
281286
checkpoint_id = msg.uuid # Save this for later
282287
283288
# Later, rewind to that point

src/claude_agent_sdk/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ class UserMessage:
562562
"""User message."""
563563

564564
content: str | list[ContentBlock]
565+
uuid: str | None = None
565566
parent_tool_use_id: str | None = None
566567

567568

tests/test_message_parser.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ def test_parse_valid_user_message(self):
3131
assert isinstance(message.content[0], TextBlock)
3232
assert message.content[0].text == "Hello"
3333

34+
def test_parse_user_message_with_uuid(self):
35+
"""Test parsing a user message with uuid field (issue #414).
36+
37+
The uuid field is needed for file checkpointing with rewind_files().
38+
"""
39+
data = {
40+
"type": "user",
41+
"uuid": "msg-abc123-def456",
42+
"message": {"content": [{"type": "text", "text": "Hello"}]},
43+
}
44+
message = parse_message(data)
45+
assert isinstance(message, UserMessage)
46+
assert message.uuid == "msg-abc123-def456"
47+
assert len(message.content) == 1
48+
3449
def test_parse_user_message_with_tool_use(self):
3550
"""Test parsing a user message with tool_use block."""
3651
data = {

0 commit comments

Comments
 (0)