Skip to content

Commit ccdb272

Browse files
dicksontsairushilpatel0
authored andcommitted
Improve examples
Signed-off-by: Rushil Patel <[email protected]>
1 parent bd62813 commit ccdb272

File tree

4 files changed

+237
-91
lines changed

4 files changed

+237
-91
lines changed

examples/streaming_mode.py

100644100755
Lines changed: 163 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,69 @@
44
55
This file demonstrates various patterns for building applications with
66
the ClaudeSDKClient streaming interface.
7+
8+
The queries are intentionally simplistic. In reality, a query can be a more
9+
complex task that Claude SDK uses its agentic capabilities and tools (e.g. run
10+
bash commands, edit files, search the web, fetch web content) to accomplish.
11+
12+
Usage:
13+
./examples/streaming_mode.py - List the examples
14+
./examples/streaming_mode.py all - Run all examples
15+
./examples/streaming_mode.py basic_streaming - Run a specific example
716
"""
817

918
import asyncio
1019
import contextlib
20+
import sys
1121

1222
from claude_code_sdk import (
1323
AssistantMessage,
1424
ClaudeCodeOptions,
1525
ClaudeSDKClient,
1626
CLIConnectionError,
1727
ResultMessage,
28+
SystemMessage,
1829
TextBlock,
30+
UserMessage,
1931
)
2032

2133

34+
def display_message(msg):
35+
"""Standardized message display function.
36+
37+
- UserMessage: "User: <content>"
38+
- AssistantMessage: "Claude: <content>"
39+
- SystemMessage: ignored
40+
- ResultMessage: "Result ended" + cost if available
41+
"""
42+
if isinstance(msg, UserMessage):
43+
for block in msg.content:
44+
if isinstance(block, TextBlock):
45+
print(f"User: {block.text}")
46+
elif isinstance(msg, AssistantMessage):
47+
for block in msg.content:
48+
if isinstance(block, TextBlock):
49+
print(f"Claude: {block.text}")
50+
elif isinstance(msg, SystemMessage):
51+
# Ignore system messages
52+
pass
53+
elif isinstance(msg, ResultMessage):
54+
print("Result ended")
55+
56+
2257
async def example_basic_streaming():
2358
"""Basic streaming with context manager."""
2459
print("=== Basic Streaming Example ===")
2560

2661
async with ClaudeSDKClient() as client:
27-
# Send a message
28-
await client.send_message("What is 2+2?")
62+
print("User: What is 2+2?")
63+
await client.query("What is 2+2?")
2964

3065
# Receive complete response using the helper method
3166
async for msg in client.receive_response():
32-
if isinstance(msg, AssistantMessage):
33-
for block in msg.content:
34-
if isinstance(block, TextBlock):
35-
print(f"Claude: {block.text}")
36-
elif isinstance(msg, ResultMessage) and msg.total_cost_usd:
37-
print(f"Cost: ${msg.total_cost_usd:.4f}")
67+
display_message(msg)
3868

39-
print("Session ended\n")
69+
print("\n")
4070

4171

4272
async def example_multi_turn_conversation():
@@ -46,26 +76,20 @@ async def example_multi_turn_conversation():
4676
async with ClaudeSDKClient() as client:
4777
# First turn
4878
print("User: What's the capital of France?")
49-
await client.send_message("What's the capital of France?")
79+
await client.query("What's the capital of France?")
5080

5181
# Extract and print response
5282
async for msg in client.receive_response():
53-
content_blocks = getattr(msg, 'content', [])
54-
for block in content_blocks:
55-
if isinstance(block, TextBlock):
56-
print(f"{block.text}")
83+
display_message(msg)
5784

5885
# Second turn - follow-up
5986
print("\nUser: What's the population of that city?")
60-
await client.send_message("What's the population of that city?")
87+
await client.query("What's the population of that city?")
6188

6289
async for msg in client.receive_response():
63-
content_blocks = getattr(msg, 'content', [])
64-
for block in content_blocks:
65-
if isinstance(block, TextBlock):
66-
print(f"{block.text}")
90+
display_message(msg)
6791

68-
print("\nConversation ended\n")
92+
print("\n")
6993

7094

7195
async def example_concurrent_responses():
@@ -76,10 +100,7 @@ async def example_concurrent_responses():
76100
# Background task to continuously receive messages
77101
async def receive_messages():
78102
async for message in client.receive_messages():
79-
if isinstance(message, AssistantMessage):
80-
for block in message.content:
81-
if isinstance(block, TextBlock):
82-
print(f"Claude: {block.text}")
103+
display_message(message)
83104

84105
# Start receiving in background
85106
receive_task = asyncio.create_task(receive_messages())
@@ -93,7 +114,7 @@ async def receive_messages():
93114

94115
for question in questions:
95116
print(f"\nUser: {question}")
96-
await client.send_message(question)
117+
await client.query(question)
97118
await asyncio.sleep(3) # Wait between messages
98119

99120
# Give time for final responses
@@ -104,7 +125,7 @@ async def receive_messages():
104125
with contextlib.suppress(asyncio.CancelledError):
105126
await receive_task
106127

107-
print("\nSession ended\n")
128+
print("\n")
108129

109130

110131
async def example_with_interrupt():
@@ -115,7 +136,7 @@ async def example_with_interrupt():
115136
async with ClaudeSDKClient() as client:
116137
# Start a long-running task
117138
print("\nUser: Count from 1 to 100 slowly")
118-
await client.send_message(
139+
await client.query(
119140
"Count from 1 to 100 slowly, with a brief pause between each number"
120141
)
121142

@@ -132,10 +153,10 @@ async def consume_messages():
132153
if isinstance(block, TextBlock):
133154
# Print first few numbers
134155
print(f"Claude: {block.text[:50]}...")
135-
136-
# Stop when we get a result after interrupt
137-
if isinstance(message, ResultMessage) and interrupt_sent:
138-
break
156+
elif isinstance(message, ResultMessage):
157+
display_message(message)
158+
if interrupt_sent:
159+
break
139160

140161
# Start consuming messages in the background
141162
consume_task = asyncio.create_task(consume_messages())
@@ -151,24 +172,21 @@ async def consume_messages():
151172

152173
# Send new instruction after interrupt
153174
print("\nUser: Never mind, just tell me a quick joke")
154-
await client.send_message("Never mind, just tell me a quick joke")
175+
await client.query("Never mind, just tell me a quick joke")
155176

156177
# Get the joke
157178
async for msg in client.receive_response():
158-
if isinstance(msg, AssistantMessage):
159-
for block in msg.content:
160-
if isinstance(block, TextBlock):
161-
print(f"Claude: {block.text}")
179+
display_message(msg)
162180

163-
print("\nSession ended\n")
181+
print("\n")
164182

165183

166184
async def example_manual_message_handling():
167185
"""Manually handle message stream for custom logic."""
168186
print("=== Manual Message Handling Example ===")
169187

170188
async with ClaudeSDKClient() as client:
171-
await client.send_message(
189+
await client.query(
172190
"List 5 programming languages and their main use cases"
173191
)
174192

@@ -180,6 +198,7 @@ async def example_manual_message_handling():
180198
for block in message.content:
181199
if isinstance(block, TextBlock):
182200
text = block.text
201+
print(f"Claude: {text}")
183202
# Custom logic: extract language names
184203
for lang in [
185204
"Python",
@@ -193,12 +212,12 @@ async def example_manual_message_handling():
193212
if lang in text and lang not in languages_found:
194213
languages_found.append(lang)
195214
print(f"Found language: {lang}")
196-
197215
elif isinstance(message, ResultMessage):
198-
print(f"\nTotal languages mentioned: {len(languages_found)}")
216+
display_message(message)
217+
print(f"Total languages mentioned: {len(languages_found)}")
199218
break
200219

201-
print("\nSession ended\n")
220+
print("\n")
202221

203222

204223
async def example_with_options():
@@ -213,23 +232,75 @@ async def example_with_options():
213232
)
214233

215234
async with ClaudeSDKClient(options=options) as client:
216-
await client.send_message(
235+
print("User: Create a simple hello.txt file with a greeting message")
236+
await client.query(
217237
"Create a simple hello.txt file with a greeting message"
218238
)
219239

220240
tool_uses = []
221241
async for msg in client.receive_response():
222242
if isinstance(msg, AssistantMessage):
243+
display_message(msg)
223244
for block in msg.content:
224-
if isinstance(block, TextBlock):
225-
print(f"Claude: {block.text}")
226-
elif hasattr(block, "name"): # ToolUseBlock
245+
if hasattr(block, "name") and not isinstance(
246+
block, TextBlock
247+
): # ToolUseBlock
227248
tool_uses.append(getattr(block, "name", ""))
249+
else:
250+
display_message(msg)
228251

229252
if tool_uses:
230-
print(f"\nTools used: {', '.join(tool_uses)}")
253+
print(f"Tools used: {', '.join(tool_uses)}")
254+
255+
print("\n")
256+
257+
258+
async def example_async_iterable_prompt():
259+
"""Demonstrate send_message with async iterable."""
260+
print("=== Async Iterable Prompt Example ===")
261+
262+
async def create_message_stream():
263+
"""Generate a stream of messages."""
264+
print("User: Hello! I have multiple questions.")
265+
yield {
266+
"type": "user",
267+
"message": {"role": "user", "content": "Hello! I have multiple questions."},
268+
"parent_tool_use_id": None,
269+
"session_id": "qa-session",
270+
}
271+
272+
print("User: First, what's the capital of Japan?")
273+
yield {
274+
"type": "user",
275+
"message": {
276+
"role": "user",
277+
"content": "First, what's the capital of Japan?",
278+
},
279+
"parent_tool_use_id": None,
280+
"session_id": "qa-session",
281+
}
282+
283+
print("User: Second, what's 15% of 200?")
284+
yield {
285+
"type": "user",
286+
"message": {"role": "user", "content": "Second, what's 15% of 200?"},
287+
"parent_tool_use_id": None,
288+
"session_id": "qa-session",
289+
}
290+
291+
async with ClaudeSDKClient() as client:
292+
# Send async iterable of messages
293+
await client.query(create_message_stream())
294+
295+
# Receive the three responses
296+
async for msg in client.receive_response():
297+
display_message(msg)
298+
async for msg in client.receive_response():
299+
display_message(msg)
300+
async for msg in client.receive_response():
301+
display_message(msg)
231302

232-
print("\nSession ended\n")
303+
print("\n")
233304

234305

235306
async def example_error_handling():
@@ -242,7 +313,8 @@ async def example_error_handling():
242313
await client.connect()
243314

244315
# Send a message that will take time to process
245-
await client.send_message("Run a bash sleep command for 60 seconds")
316+
print("User: Run a bash sleep command for 60 seconds")
317+
await client.query("Run a bash sleep command for 60 seconds")
246318

247319
# Try to receive response with a short timeout
248320
try:
@@ -255,11 +327,13 @@ async def example_error_handling():
255327
if isinstance(block, TextBlock):
256328
print(f"Claude: {block.text[:50]}...")
257329
elif isinstance(msg, ResultMessage):
258-
print("Received complete response")
330+
display_message(msg)
259331
break
260332

261333
except asyncio.TimeoutError:
262-
print("\nResponse timeout after 10 seconds - demonstrating graceful handling")
334+
print(
335+
"\nResponse timeout after 10 seconds - demonstrating graceful handling"
336+
)
263337
print(f"Received {len(messages)} messages before timeout")
264338

265339
except CLIConnectionError as e:
@@ -272,24 +346,48 @@ async def example_error_handling():
272346
# Always disconnect
273347
await client.disconnect()
274348

275-
print("\nSession ended\n")
349+
print("\n")
276350

277351

278352
async def main():
279-
"""Run all examples."""
280-
examples = [
281-
example_basic_streaming,
282-
example_multi_turn_conversation,
283-
example_concurrent_responses,
284-
example_with_interrupt,
285-
example_manual_message_handling,
286-
example_with_options,
287-
example_error_handling,
288-
]
289-
290-
for example in examples:
291-
await example()
292-
print("-" * 50 + "\n")
353+
"""Run all examples or a specific example based on command line argument."""
354+
examples = {
355+
"basic_streaming": example_basic_streaming,
356+
"multi_turn_conversation": example_multi_turn_conversation,
357+
"concurrent_responses": example_concurrent_responses,
358+
"with_interrupt": example_with_interrupt,
359+
"manual_message_handling": example_manual_message_handling,
360+
"with_options": example_with_options,
361+
"async_iterable_prompt": example_async_iterable_prompt,
362+
"error_handling": example_error_handling,
363+
}
364+
365+
if len(sys.argv) < 2:
366+
# List available examples
367+
print("Usage: python streaming_mode.py <example_name>")
368+
print("\nAvailable examples:")
369+
print(" all - Run all examples")
370+
for name in examples:
371+
print(f" {name}")
372+
sys.exit(0)
373+
374+
example_name = sys.argv[1]
375+
376+
if example_name == "all":
377+
# Run all examples
378+
for example in examples.values():
379+
await example()
380+
print("-" * 50 + "\n")
381+
elif example_name in examples:
382+
# Run specific example
383+
await examples[example_name]()
384+
else:
385+
print(f"Error: Unknown example '{example_name}'")
386+
print("\nAvailable examples:")
387+
print(" all - Run all examples")
388+
for name in examples:
389+
print(f" {name}")
390+
sys.exit(1)
293391

294392

295393
if __name__ == "__main__":

0 commit comments

Comments
 (0)