claude_code 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,336 @@
1
+ # Rails + Sidekiq streaming example for Ruby Claude Code SDK
2
+ # This shows how to use the SDK in a Rails background job with real-time streaming
3
+
4
+ require 'sidekiq'
5
+ require 'action_cable'
6
+ require_relative '../lib/claude_code'
7
+
8
+ # Sidekiq job for streaming Claude responses
9
+ class ClaudeStreamingJob
10
+ include Sidekiq::Job
11
+
12
+ # Job to process a Claude query with streaming updates
13
+ def perform(user_id, query_id, prompt, options_hash = {})
14
+ # Parse options
15
+ options = build_claude_options(options_hash)
16
+
17
+ # Set up streaming
18
+ channel_name = "claude_stream_#{user_id}_#{query_id}"
19
+
20
+ begin
21
+ # Broadcast start
22
+ ActionCable.server.broadcast(channel_name, {
23
+ type: 'start',
24
+ query_id: query_id,
25
+ timestamp: Time.current
26
+ })
27
+
28
+ message_count = 0
29
+
30
+ # Stream Claude responses
31
+ ClaudeCode.query(
32
+ prompt: prompt,
33
+ options: options,
34
+ cli_path: claude_cli_path
35
+ ).each do |message|
36
+ message_count += 1
37
+
38
+ # Broadcast each message as it arrives
39
+ broadcast_data = {
40
+ type: 'message',
41
+ query_id: query_id,
42
+ message_index: message_count,
43
+ timestamp: Time.current
44
+ }
45
+
46
+ case message
47
+ when ClaudeCode::SystemMessage
48
+ broadcast_data.merge!(
49
+ message_type: 'system',
50
+ subtype: message.subtype,
51
+ data: message.data
52
+ )
53
+
54
+ when ClaudeCode::AssistantMessage
55
+ # Process content blocks
56
+ content_blocks = message.content.map do |block|
57
+ case block
58
+ when ClaudeCode::TextBlock
59
+ { type: 'text', text: block.text }
60
+ when ClaudeCode::ToolUseBlock
61
+ {
62
+ type: 'tool_use',
63
+ id: block.id,
64
+ name: block.name,
65
+ input: block.input
66
+ }
67
+ when ClaudeCode::ToolResultBlock
68
+ {
69
+ type: 'tool_result',
70
+ tool_use_id: block.tool_use_id,
71
+ content: block.content,
72
+ is_error: block.is_error
73
+ }
74
+ end
75
+ end
76
+
77
+ broadcast_data.merge!(
78
+ message_type: 'assistant',
79
+ content: content_blocks
80
+ )
81
+
82
+ when ClaudeCode::ResultMessage
83
+ broadcast_data.merge!(
84
+ message_type: 'result',
85
+ subtype: message.subtype,
86
+ duration_ms: message.duration_ms,
87
+ duration_api_ms: message.duration_api_ms,
88
+ is_error: message.is_error,
89
+ num_turns: message.num_turns,
90
+ session_id: message.session_id,
91
+ total_cost_usd: message.total_cost_usd,
92
+ usage: message.usage,
93
+ result: message.result
94
+ )
95
+ end
96
+
97
+ # Broadcast to WebSocket
98
+ ActionCable.server.broadcast(channel_name, broadcast_data)
99
+
100
+ # Optional: Save to database for persistence
101
+ save_message_to_db(user_id, query_id, message_count, broadcast_data)
102
+ end
103
+
104
+ # Broadcast completion
105
+ ActionCable.server.broadcast(channel_name, {
106
+ type: 'complete',
107
+ query_id: query_id,
108
+ total_messages: message_count,
109
+ timestamp: Time.current
110
+ })
111
+
112
+ rescue => e
113
+ # Broadcast error
114
+ ActionCable.server.broadcast(channel_name, {
115
+ type: 'error',
116
+ query_id: query_id,
117
+ error: e.message,
118
+ timestamp: Time.current
119
+ })
120
+
121
+ # Log error
122
+ Rails.logger.error "Claude streaming job failed: #{e.message}"
123
+ Rails.logger.error e.backtrace.join("\n")
124
+
125
+ raise e # Re-raise for Sidekiq retry logic
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ def build_claude_options(options_hash)
132
+ ClaudeCode::ClaudeCodeOptions.new(
133
+ model: options_hash['model'],
134
+ max_turns: options_hash['max_turns'] || 1,
135
+ system_prompt: options_hash['system_prompt'],
136
+ allowed_tools: options_hash['allowed_tools'] || [],
137
+ mcp_servers: build_mcp_servers(options_hash['mcp_servers'] || {}),
138
+ permission_mode: options_hash['permission_mode']
139
+ )
140
+ end
141
+
142
+ def build_mcp_servers(mcp_config)
143
+ return {} if mcp_config.empty?
144
+
145
+ servers = {}
146
+ mcp_config.each do |name, config|
147
+ servers.merge!(ClaudeCode.add_mcp_server(name, config))
148
+ end
149
+ servers
150
+ end
151
+
152
+ def claude_cli_path
153
+ # Try environment variable first, then common paths
154
+ ENV['CLAUDE_CLI_PATH'] ||
155
+ Rails.application.config.claude_cli_path ||
156
+ '/usr/local/bin/claude'
157
+ end
158
+
159
+ def save_message_to_db(user_id, query_id, message_index, data)
160
+ # Example: Save to database for persistence/replay
161
+ # ClaudeMessage.create!(
162
+ # user_id: user_id,
163
+ # query_id: query_id,
164
+ # message_index: message_index,
165
+ # message_type: data[:message_type],
166
+ # content: data,
167
+ # timestamp: data[:timestamp]
168
+ # )
169
+ end
170
+ end
171
+
172
+ # ActionCable channel for real-time streaming
173
+ class ClaudeStreamChannel < ApplicationCable::Channel
174
+ def subscribed
175
+ stream_from "claude_stream_#{params[:user_id]}_#{params[:query_id]}"
176
+ end
177
+
178
+ def unsubscribed
179
+ # Cleanup when channel is unsubscribed
180
+ end
181
+ end
182
+
183
+ # Controller example
184
+ class ClaudeController < ApplicationController
185
+ def create_stream_query
186
+ query_id = SecureRandom.uuid
187
+
188
+ # Validate and sanitize input
189
+ prompt = params[:prompt]
190
+ options = {
191
+ 'model' => params[:model],
192
+ 'max_turns' => params[:max_turns]&.to_i,
193
+ 'system_prompt' => params[:system_prompt],
194
+ 'allowed_tools' => params[:allowed_tools] || [],
195
+ 'mcp_servers' => params[:mcp_servers] || {}
196
+ }
197
+
198
+ # Start background job
199
+ ClaudeStreamingJob.perform_async(
200
+ current_user.id,
201
+ query_id,
202
+ prompt,
203
+ options
204
+ )
205
+
206
+ render json: {
207
+ query_id: query_id,
208
+ channel: "claude_stream_#{current_user.id}_#{query_id}",
209
+ status: 'started'
210
+ }
211
+ end
212
+ end
213
+
214
+ # Frontend JavaScript example (with ActionCable)
215
+ FRONTEND_EXAMPLE = <<~JAVASCRIPT
216
+ // Connect to the streaming channel
217
+ const subscription = App.cable.subscriptions.create(
218
+ {
219
+ channel: "ClaudeStreamChannel",
220
+ user_id: currentUserId,
221
+ query_id: queryId
222
+ },
223
+ {
224
+ received(data) {
225
+ switch(data.type) {
226
+ case 'start':
227
+ console.log('Claude query started:', data.query_id);
228
+ showLoadingIndicator();
229
+ break;
230
+
231
+ case 'message':
232
+ handleClaudeMessage(data);
233
+ break;
234
+
235
+ case 'complete':
236
+ console.log('Claude query completed');
237
+ hideLoadingIndicator();
238
+ break;
239
+
240
+ case 'error':
241
+ console.error('Claude query failed:', data.error);
242
+ showError(data.error);
243
+ break;
244
+ }
245
+ }
246
+ }
247
+ );
248
+
249
+ function handleClaudeMessage(data) {
250
+ switch(data.message_type) {
251
+ case 'system':
252
+ console.log('System message:', data.subtype);
253
+ break;
254
+
255
+ case 'assistant':
256
+ data.content.forEach(block => {
257
+ if (block.type === 'text') {
258
+ appendText(block.text);
259
+ } else if (block.type === 'tool_use') {
260
+ showToolUsage(block.name, block.input);
261
+ }
262
+ });
263
+ break;
264
+
265
+ case 'result':
266
+ showFinalResult(data);
267
+ break;
268
+ }
269
+ }
270
+
271
+ // Start a Claude query
272
+ function startClaudeQuery(prompt, options = {}) {
273
+ fetch('/claude/stream_query', {
274
+ method: 'POST',
275
+ headers: {
276
+ 'Content-Type': 'application/json',
277
+ 'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
278
+ },
279
+ body: JSON.stringify({
280
+ prompt: prompt,
281
+ model: options.model,
282
+ max_turns: options.maxTurns,
283
+ system_prompt: options.systemPrompt,
284
+ allowed_tools: options.allowedTools,
285
+ mcp_servers: options.mcpServers
286
+ })
287
+ })
288
+ .then(response => response.json())
289
+ .then(data => {
290
+ console.log('Query started with ID:', data.query_id);
291
+ });
292
+ }
293
+ JAVASCRIPT
294
+
295
+ # Usage example in Rails console or initializer
296
+ RAILS_USAGE_EXAMPLE = <<~RUBY
297
+ # In Rails console:
298
+
299
+ # Start a simple streaming query
300
+ ClaudeStreamingJob.perform_async(
301
+ 1, # user_id
302
+ SecureRandom.uuid, # query_id
303
+ "Explain Ruby on Rails", # prompt
304
+ { 'model' => 'sonnet', 'max_turns' => 1 }
305
+ )
306
+
307
+ # Start an MCP-enabled streaming query
308
+ ClaudeStreamingJob.perform_async(
309
+ 1,
310
+ SecureRandom.uuid,
311
+ "Use the about tool to describe yourself",
312
+ {
313
+ 'model' => 'sonnet',
314
+ 'max_turns' => 1,
315
+ 'allowed_tools' => ['mcp__ninja__about'],
316
+ 'mcp_servers' => {
317
+ 'ninja' => 'https://mcp-creator-ninja-v1-4-0.mcp.soy/'
318
+ }
319
+ }
320
+ )
321
+ RUBY
322
+
323
+ puts "Rails + Sidekiq + ActionCable streaming example loaded!"
324
+ puts
325
+ puts "Key components:"
326
+ puts "• ClaudeStreamingJob - Sidekiq background job"
327
+ puts "• ClaudeStreamChannel - ActionCable channel"
328
+ puts "• Real-time WebSocket streaming to frontend"
329
+ puts "• Error handling and retry logic"
330
+ puts "• MCP server support"
331
+ puts
332
+ puts "Usage examples:"
333
+ puts RAILS_USAGE_EXAMPLE
334
+ puts
335
+ puts "Frontend JavaScript:"
336
+ puts FRONTEND_EXAMPLE
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env ruby
2
+ # Streaming examples for Ruby Claude Code SDK
3
+
4
+ require_relative '../lib/claude_code'
5
+
6
+ def streaming_example
7
+ claude_path = "/Users/admin/.claude/local/claude"
8
+
9
+ puts "=== Streaming Messages Example ==="
10
+ puts "Watch messages arrive in real-time!"
11
+ puts
12
+
13
+ options = ClaudeCode::ClaudeCodeOptions.new(
14
+ model: "sonnet",
15
+ max_turns: 1,
16
+ system_prompt: "You are helpful. Provide detailed explanations."
17
+ )
18
+
19
+ start_time = Time.now
20
+ message_count = 0
21
+
22
+ ClaudeCode.query(
23
+ prompt: "Explain how Ruby blocks work and give some examples",
24
+ options: options,
25
+ cli_path: claude_path
26
+ ).each_with_index do |message, index|
27
+ timestamp = Time.now - start_time
28
+ message_count += 1
29
+
30
+ puts "[#{format('%.3f', timestamp)}s] Message #{message_count}:"
31
+
32
+ case message
33
+ when ClaudeCode::SystemMessage
34
+ puts " šŸ”§ SYSTEM: #{message.subtype}"
35
+ if message.subtype == "init"
36
+ puts " Session: #{message.data['session_id']}"
37
+ puts " Model: #{message.data['model']}"
38
+ puts " Tools: #{message.data['tools'].length} available"
39
+ puts " MCP Servers: #{message.data['mcp_servers'].length}"
40
+ end
41
+
42
+ when ClaudeCode::UserMessage
43
+ puts " šŸ‘¤ USER: #{message.content[0, 50]}..."
44
+
45
+ when ClaudeCode::AssistantMessage
46
+ puts " šŸ¤– ASSISTANT:"
47
+ message.content.each do |block|
48
+ case block
49
+ when ClaudeCode::TextBlock
50
+ # Stream text in chunks to show real-time effect
51
+ text = block.text
52
+ if text.length > 100
53
+ puts " šŸ’¬ #{text[0, 100]}..."
54
+ puts " (#{text.length} total characters)"
55
+ else
56
+ puts " šŸ’¬ #{text}"
57
+ end
58
+
59
+ when ClaudeCode::ToolUseBlock
60
+ puts " šŸ”§ TOOL: #{block.name}"
61
+ puts " Input: #{block.input}"
62
+
63
+ when ClaudeCode::ToolResultBlock
64
+ puts " šŸ“¤ RESULT: #{block.content}"
65
+ end
66
+ end
67
+
68
+ when ClaudeCode::ResultMessage
69
+ puts " āœ… RESULT: #{message.subtype}"
70
+ puts " Duration: #{message.duration_ms}ms (API: #{message.duration_api_ms}ms)"
71
+ puts " Turns: #{message.num_turns}"
72
+ puts " Cost: $#{format('%.6f', message.total_cost_usd)}" if message.total_cost_usd
73
+ puts " Session: #{message.session_id}"
74
+ if message.result
75
+ puts " Final: #{message.result[0, 100]}..."
76
+ end
77
+ end
78
+
79
+ puts
80
+ $stdout.flush # Ensure immediate output
81
+ end
82
+
83
+ total_time = Time.now - start_time
84
+ puts "šŸ Streaming completed in #{format('%.3f', total_time)}s with #{message_count} messages"
85
+ end
86
+
87
+ def streaming_mcp_example
88
+ puts "\n" + "="*60 + "\n"
89
+ puts "=== Streaming MCP Example ==="
90
+ puts
91
+
92
+ start_time = Time.now
93
+
94
+ ClaudeCode.quick_mcp_query(
95
+ "Use the about tool and then explain what you learned about this MCP server",
96
+ server_name: "ninja",
97
+ server_url: "https://mcp-creator-ninja-v1-4-0.mcp.soy/",
98
+ tools: "about",
99
+ max_turns: 1
100
+ ).each_with_index do |message, index|
101
+ timestamp = Time.now - start_time
102
+
103
+ case message
104
+ when ClaudeCode::SystemMessage
105
+ puts "[#{format('%.3f', timestamp)}s] šŸ”§ System init - MCP servers: #{message.data['mcp_servers'].length}"
106
+
107
+ when ClaudeCode::AssistantMessage
108
+ puts "[#{format('%.3f', timestamp)}s] šŸ¤– Assistant response:"
109
+ message.content.each do |block|
110
+ case block
111
+ when ClaudeCode::TextBlock
112
+ puts " šŸ’¬ #{block.text}"
113
+ when ClaudeCode::ToolUseBlock
114
+ puts " šŸ”§ Using tool: #{block.name}"
115
+ puts " šŸ“„ Input: #{block.input}"
116
+ when ClaudeCode::ToolResultBlock
117
+ puts " šŸ“¤ Tool result received"
118
+ end
119
+ end
120
+
121
+ when ClaudeCode::ResultMessage
122
+ puts "[#{format('%.3f', timestamp)}s] āœ… Final result - Cost: $#{format('%.6f', message.total_cost_usd || 0)}"
123
+ end
124
+
125
+ $stdout.flush
126
+ end
127
+ end
128
+
129
+ def simple_streaming_examples
130
+ puts "\n" + "="*60 + "\n"
131
+ puts "=== Simple Streaming Examples ==="
132
+ puts
133
+
134
+ # Example 1: Default streaming output
135
+ puts "1. Default streaming (auto-formatted):"
136
+ ClaudeCode.stream_query(
137
+ prompt: "Count from 1 to 3 and explain each number",
138
+ options: ClaudeCode::ClaudeCodeOptions.new(
139
+ model: "sonnet",
140
+ max_turns: 1
141
+ ),
142
+ cli_path: "/Users/admin/.claude/local/claude"
143
+ )
144
+
145
+ puts "\n" + "="*50 + "\n"
146
+
147
+ # Example 2: Custom streaming with block
148
+ puts "2. Custom streaming with timestamps:"
149
+ start_time = Time.now
150
+
151
+ ClaudeCode.stream_query(
152
+ prompt: "What is Ruby?",
153
+ options: ClaudeCode::ClaudeCodeOptions.new(max_turns: 1),
154
+ cli_path: "/Users/admin/.claude/local/claude"
155
+ ) do |message, index|
156
+ timestamp = Time.now - start_time
157
+
158
+ case message
159
+ when ClaudeCode::AssistantMessage
160
+ message.content.each do |block|
161
+ if block.is_a?(ClaudeCode::TextBlock)
162
+ puts "[#{format('%.2f', timestamp)}s] #{block.text}"
163
+ end
164
+ end
165
+ when ClaudeCode::ResultMessage
166
+ puts "[#{format('%.2f', timestamp)}s] šŸ’° $#{format('%.6f', message.total_cost_usd || 0)}"
167
+ end
168
+ end
169
+ end
170
+
171
+ def show_streaming_benefits
172
+ puts "=== Benefits of Streaming ==="
173
+ puts
174
+ puts "āœ… Real-time feedback - see messages as they arrive"
175
+ puts "āœ… Lower memory usage - process messages one by one"
176
+ puts "āœ… Better user experience - immediate response indication"
177
+ puts "āœ… Early error detection - catch issues quickly"
178
+ puts "āœ… Progress tracking - monitor long-running operations"
179
+ puts
180
+ puts "Perfect for:"
181
+ puts "• Interactive applications"
182
+ puts "• Long-running code generation"
183
+ puts "• Tool-heavy workflows"
184
+ puts "• Real-time monitoring"
185
+ puts
186
+ puts "="*60
187
+ puts
188
+ end
189
+
190
+ if __FILE__ == $0
191
+ show_streaming_benefits
192
+ streaming_example
193
+ streaming_mcp_example
194
+ simple_streaming_examples
195
+ end
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/claude_code'
5
+
6
+ # Example: Streaming JSON input for multi-turn conversations
7
+
8
+ puts "=== Streaming JSON Input Example ==="
9
+
10
+ # Set your API key
11
+ # ENV['ANTHROPIC_API_KEY'] = 'your-api-key-here'
12
+
13
+ puts "\n1. Multi-turn conversation using JSONL messages..."
14
+
15
+ # Create multiple user messages for a conversation
16
+ messages = [
17
+ ClaudeCode::JSONLHelpers.create_user_message("Hello! I'm working on a Ruby project."),
18
+ ClaudeCode::JSONLHelpers.create_user_message("Can you help me understand how modules work?"),
19
+ ClaudeCode::JSONLHelpers.create_user_message("Show me a practical example of a module.")
20
+ ]
21
+
22
+ puts "Sending #{messages.length} messages via streaming JSON input..."
23
+
24
+ begin
25
+ ClaudeCode.stream_json_query(messages) do |message|
26
+ case message
27
+ when ClaudeCode::SystemMessage
28
+ if message.subtype == 'init'
29
+ puts "šŸ”§ Session started: #{message.data['session_id']}"
30
+ puts "šŸ¤– Model: #{message.data['model']}"
31
+ end
32
+ when ClaudeCode::AssistantMessage
33
+ message.content.each do |block|
34
+ case block
35
+ when ClaudeCode::TextBlock
36
+ puts "šŸ’¬ #{block.text}"
37
+ when ClaudeCode::ToolUseBlock
38
+ puts "šŸ”§ Tool: #{block.name}"
39
+ puts "šŸ“„ Input: #{block.input}"
40
+ when ClaudeCode::ToolResultBlock
41
+ puts "šŸ“¤ Result: #{block.content}"
42
+ end
43
+ end
44
+ when ClaudeCode::ResultMessage
45
+ puts "\nāœ… Conversation completed!"
46
+ puts "šŸ“Š Duration: #{message.duration_ms}ms"
47
+ puts "šŸ’° Cost: $#{format('%.6f', message.total_cost_usd || 0)}"
48
+ puts "šŸ”„ Turns: #{message.num_turns}"
49
+ end
50
+ end
51
+ rescue ClaudeCode::CLINotFoundError => e
52
+ puts "āŒ Claude CLI not found: #{e.message}"
53
+ rescue ClaudeCode::ProcessError => e
54
+ puts "āŒ Process error: #{e.message}"
55
+ rescue StandardError => e
56
+ puts "āŒ Unexpected error: #{e.message}"
57
+ end
58
+
59
+ puts "\n2. Interactive conversation with streaming JSON..."
60
+
61
+ # Create a more complex conversation with different message types
62
+ conversation_messages = ClaudeCode::JSONLHelpers.create_conversation(
63
+ "I need help with a Ruby script",
64
+ "The script should read a CSV file and process the data",
65
+ "Can you show me how to handle errors when reading the file?"
66
+ )
67
+
68
+ puts "Starting interactive conversation..."
69
+
70
+ ClaudeCode.stream_json_query(conversation_messages) do |message|
71
+ case message
72
+ when ClaudeCode::AssistantMessage
73
+ message.content.each do |block|
74
+ if block.is_a?(ClaudeCode::TextBlock)
75
+ # Print text content with a slight delay to simulate real-time streaming
76
+ puts "šŸ¤– #{block.text}"
77
+ sleep(0.1) if block.text.length > 100 # Slight delay for longer responses
78
+ end
79
+ end
80
+ when ClaudeCode::ResultMessage
81
+ puts "\nšŸ“‹ Final Session: #{message.session_id}"
82
+ puts "šŸ’° Total Cost: $#{format('%.6f', message.total_cost_usd || 0)}"
83
+ end
84
+ end
85
+
86
+ puts "\n3. Custom JSONL format example..."
87
+
88
+ # Manually create JSONL format messages
89
+ custom_messages = [
90
+ {
91
+ 'type' => 'user',
92
+ 'message' => {
93
+ 'role' => 'user',
94
+ 'content' => [
95
+ {
96
+ 'type' => 'text',
97
+ 'text' => 'Explain Ruby metaprogramming in simple terms'
98
+ }
99
+ ]
100
+ }
101
+ },
102
+ {
103
+ 'type' => 'user',
104
+ 'message' => {
105
+ 'role' => 'user',
106
+ 'content' => [
107
+ {
108
+ 'type' => 'text',
109
+ 'text' => 'Give me a practical example I can try'
110
+ }
111
+ ]
112
+ }
113
+ }
114
+ ]
115
+
116
+ puts "Using custom JSONL messages..."
117
+
118
+ ClaudeCode.stream_json_query(custom_messages) do |message|
119
+ if message.is_a?(ClaudeCode::AssistantMessage)
120
+ message.content.each do |block|
121
+ if block.is_a?(ClaudeCode::TextBlock)
122
+ puts "šŸŽ“ #{block.text}"
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ puts "\n4. Streaming JSON with options..."
129
+
130
+ # Use streaming JSON with specific options
131
+ options = ClaudeCode::ClaudeCodeOptions.new(
132
+ model: 'claude-3-haiku', # Use faster model for quick responses
133
+ max_turns: 5,
134
+ system_prompt: 'You are a Ruby programming tutor. Keep responses concise and practical.'
135
+ )
136
+
137
+ tutorial_messages = ClaudeCode::JSONLHelpers.create_conversation(
138
+ "Teach me about Ruby blocks",
139
+ "Show me different ways to use blocks",
140
+ "What's the difference between blocks and procs?"
141
+ )
142
+
143
+ puts "Tutorial conversation with custom options..."
144
+
145
+ ClaudeCode.stream_json_query(tutorial_messages, options: options) do |message|
146
+ case message
147
+ when ClaudeCode::AssistantMessage
148
+ message.content.each do |block|
149
+ if block.is_a?(ClaudeCode::TextBlock)
150
+ puts "šŸ‘Øā€šŸ« #{block.text}"
151
+ end
152
+ end
153
+ when ClaudeCode::ResultMessage
154
+ puts "\nšŸ“š Tutorial completed - Cost: $#{format('%.6f', message.total_cost_usd || 0)}"
155
+ end
156
+ end
157
+
158
+ puts "\nāœ… Streaming JSON input examples completed!"
159
+ puts "\nKey features demonstrated:"
160
+ puts "- Multi-turn conversations via JSONL"
161
+ puts "- Real-time streaming responses"
162
+ puts "- Custom message creation with JSONLHelpers"
163
+ puts "- Manual JSONL format for advanced usage"
164
+ puts "- Integration with ClaudeCodeOptions"
165
+ puts "- Error handling for streaming conversations"
166
+
167
+ puts "\nšŸ’” Use streaming JSON input when you need:"
168
+ puts "- Multiple conversation turns without restarting the CLI"
169
+ puts "- Interactive conversations with guidance during processing"
170
+ puts "- Complex multi-step conversations"
171
+ puts "- Efficient batch processing of conversation turns"
data/hello.txt ADDED
@@ -0,0 +1 @@
1
+ Hello, World!