Repository navigation
Expand file tree
/
Copy pathmessage_types_example.rb
More file actions
executable file
·173 lines (136 loc) · 6.54 KB
/
Copy pathmessage_types_example.rb
File metadata and controls
executable file
·173 lines (136 loc) · 6.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/setup'
require 'claude_agent_sdk'
# Example: Handling all 28 SDK message types
#
# The Ruby SDK has a typed class for each message type it parses: the 28
# handled below, plus the generic SystemMessage for a system subtype it has
# no class for. This example shows a comprehensive message handler.
puts "=== Message Types Example ==="
options = ClaudeAgentSDK::ClaudeAgentOptions.new(
permission_mode: 'bypassPermissions',
allowed_tools: %w[Read Bash Grep Glob]
)
ClaudeAgentSDK.query(prompt: "List the files in the current directory", options: options) do |msg|
case msg
# --- Session lifecycle ---
when ClaudeAgentSDK::InitMessage
puts "[init] Session #{msg.session_id} started"
puts " Model: #{msg.model}, Version: #{msg.claude_code_version}"
puts " Tools: #{msg.tools&.length} available"
puts " Fast mode: #{msg.fast_mode_state}" if msg.fast_mode_state
when ClaudeAgentSDK::SessionStateChangedMessage
puts "[state] Session state: #{msg.state}" # idle, running, requires_action
# --- Core conversation ---
when ClaudeAgentSDK::AssistantMessage
msg.content.each do |block|
case block
when ClaudeAgentSDK::TextBlock
puts "[assistant] #{block.text}"
when ClaudeAgentSDK::ThinkingBlock
puts "[thinking] (#{block.thinking.length} chars)"
when ClaudeAgentSDK::ToolUseBlock
puts "[tool_use] #{block.name}(#{block.input})"
end
end
puts "[assistant] error: #{msg.error}" if msg.error
when ClaudeAgentSDK::UserMessage
content = msg.content.is_a?(String) ? msg.content : '(blocks)'
puts "[user] #{content}"
# --- Compaction ---
when ClaudeAgentSDK::CompactBoundaryMessage
meta = msg.compact_metadata
puts "[compact] #{meta&.trigger}: #{meta&.pre_tokens} tokens compacted"
puts " Preserved: #{meta.preserved_segment[:head_uuid]}..#{meta.preserved_segment[:tail_uuid]}" if meta&.preserved_segment
# --- Status updates ---
when ClaudeAgentSDK::StatusMessage
puts "[status] #{msg.status || 'clear'}"
puts " Permission mode: #{msg.permission_mode}" if msg.permission_mode
when ClaudeAgentSDK::APIRetryMessage
puts "[retry] Attempt #{msg.attempt}/#{msg.max_retries} (#{msg.error}, delay: #{msg.retry_delay_ms}ms)"
# --- Task lifecycle (subagents / background tasks) ---
when ClaudeAgentSDK::TaskStartedMessage
puts "[task:start] #{msg.task_id}: #{msg.description}"
puts " Workflow: #{msg.workflow_name}" if msg.workflow_name
when ClaudeAgentSDK::TaskProgressMessage
puts "[task:progress] #{msg.task_id}: #{msg.summary || msg.description}"
when ClaudeAgentSDK::TaskNotificationMessage
puts "[task:done] #{msg.task_id} #{msg.status}: #{msg.summary}"
when ClaudeAgentSDK::TaskUpdatedMessage
# A task can finish here without a TaskNotificationMessage: clear your
# tracking when status is in ClaudeAgentSDK::TERMINAL_TASK_STATUSES.
puts "[task:update] #{msg.task_id}: #{msg.status}" if msg.status
puts "[task:update] #{msg.task_id} moved to the background" if msg.is_backgrounded == true
when ClaudeAgentSDK::BackgroundTasksChangedMessage
# The full set of live background tasks: replace yours with it.
puts "[tasks] live background tasks: #{Array(msg.tasks).map { |t| t[:task_id] }.join(', ')}"
# --- Tool progress ---
when ClaudeAgentSDK::ToolProgressMessage
puts "[tool:progress] #{msg.tool_name} running (#{msg.elapsed_time_seconds}s)"
when ClaudeAgentSDK::ToolUseSummaryMessage
puts "[tool:summary] #{msg.summary}"
# --- Hook lifecycle ---
when ClaudeAgentSDK::HookStartedMessage
puts "[hook:start] #{msg.hook_name} (#{msg.hook_event})"
when ClaudeAgentSDK::HookProgressMessage
puts "[hook:progress] #{msg.hook_name}: #{msg.output}"
when ClaudeAgentSDK::HookResponseMessage
puts "[hook:done] #{msg.hook_name}: #{msg.outcome} (exit: #{msg.exit_code})"
# --- Auth ---
when ClaudeAgentSDK::AuthStatusMessage
puts "[auth] #{msg.is_authenticating ? 'Authenticating...' : 'Auth complete'}"
puts " Error: #{msg.error}" if msg.error
# --- Files ---
when ClaudeAgentSDK::FilesPersistedMessage
puts "[files] #{msg.files&.length || 0} persisted, #{msg.failed&.length || 0} failed"
# --- Elicitation ---
when ClaudeAgentSDK::ElicitationCompleteMessage
puts "[elicitation] #{msg.mcp_server_name}: #{msg.elicitation_id}"
# --- Local command output ---
when ClaudeAgentSDK::LocalCommandOutputMessage
puts "[local] #{msg.content}"
# --- Prompt suggestions ---
when ClaudeAgentSDK::PromptSuggestionMessage
puts "[suggestion] Next: #{msg.suggestion}"
# --- Auto-denied tool calls ---
when ClaudeAgentSDK::PermissionDeniedMessage
# Advisory only: ResultMessage#permission_denials is the authoritative list.
puts "[denied] #{msg.tool_name} (#{msg.decision_reason_type}): #{msg.message}"
# --- SessionStore mirroring (only with session_store:) ---
when ClaudeAgentSDK::MirrorErrorMessage
puts "[mirror] a transcript batch was not stored: #{msg.error}"
# --- Rate limits ---
when ClaudeAgentSDK::RateLimitEvent
info = msg.rate_limit_info
puts "[rate_limit] #{info.status} (#{info.rate_limit_type})"
# --- Conversation reset (/clear and friends) ---
when ClaudeAgentSDK::ConversationResetMessage
# Running totals on later ResultMessages restart from zero — snapshot here.
puts "[reset] new conversation #{msg.new_conversation_id} (was session #{msg.session_id})"
# --- Streaming events ---
when ClaudeAgentSDK::StreamEvent
# Only present when include_partial_messages: true
puts "[stream] event received"
# --- Final result ---
when ClaudeAgentSDK::ResultMessage
puts "\n[result] #{msg.subtype}"
puts " Duration: #{msg.duration_ms}ms (API: #{msg.duration_api_ms}ms)"
puts " Turns: #{msg.num_turns}, Cost: $#{msg.total_cost_usd}"
puts " Stop reason: #{msg.stop_reason}" if msg.stop_reason
puts " Fast mode: #{msg.fast_mode_state}" if msg.fast_mode_state
msg.model_usage&.each do |model, usage|
puts " #{model}: #{usage}"
end
if msg.permission_denials&.any?
puts " Permission denials:"
msg.permission_denials.each { |d| puts " #{d[:tool_name]}: #{d[:tool_use_id]}" }
end
puts " Errors: #{msg.errors.join(', ')}" if msg.errors&.any?
# --- A system subtype this SDK version has no class for ---
# Keep this branch after every typed subclass above: they are all
# SystemMessages, and `case` takes the first branch that matches.
when ClaudeAgentSDK::SystemMessage
puts "[system] #{msg.subtype}"
end
end