claude_agent 0.7.12 → 0.7.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.
- checksums.yaml +4 -4
- data/.claude/rules/testing.md +51 -10
- data/.claude/settings.json +1 -0
- data/ARCHITECTURE.md +237 -0
- data/CHANGELOG.md +53 -0
- data/CLAUDE.md +2 -0
- data/README.md +46 -1
- data/Rakefile +17 -0
- data/SPEC.md +214 -125
- data/lib/claude_agent/client/commands.rb +225 -0
- data/lib/claude_agent/client.rb +4 -206
- data/lib/claude_agent/content_blocks/generic_block.rb +39 -0
- data/lib/claude_agent/content_blocks/image_content_block.rb +54 -0
- data/lib/claude_agent/content_blocks/server_tool_result_block.rb +22 -0
- data/lib/claude_agent/content_blocks/server_tool_use_block.rb +48 -0
- data/lib/claude_agent/content_blocks/text_block.rb +19 -0
- data/lib/claude_agent/content_blocks/thinking_block.rb +19 -0
- data/lib/claude_agent/content_blocks/tool_result_block.rb +25 -0
- data/lib/claude_agent/content_blocks/tool_use_block.rb +134 -0
- data/lib/claude_agent/content_blocks.rb +8 -335
- data/lib/claude_agent/control_protocol/commands.rb +304 -0
- data/lib/claude_agent/control_protocol/lifecycle.rb +116 -0
- data/lib/claude_agent/control_protocol/messaging.rb +163 -0
- data/lib/claude_agent/control_protocol/primitives.rb +168 -0
- data/lib/claude_agent/control_protocol/request_handling.rb +231 -0
- data/lib/claude_agent/control_protocol.rb +50 -882
- data/lib/claude_agent/conversation.rb +8 -1
- data/lib/claude_agent/event_handler.rb +1 -0
- data/lib/claude_agent/get_session_info.rb +86 -0
- data/lib/claude_agent/hooks.rb +23 -2
- data/lib/claude_agent/list_sessions.rb +22 -13
- data/lib/claude_agent/message_parser.rb +26 -4
- data/lib/claude_agent/messages/conversation.rb +138 -0
- data/lib/claude_agent/messages/generic.rb +39 -0
- data/lib/claude_agent/messages/hook_lifecycle.rb +158 -0
- data/lib/claude_agent/messages/result.rb +80 -0
- data/lib/claude_agent/messages/streaming.rb +84 -0
- data/lib/claude_agent/messages/system.rb +67 -0
- data/lib/claude_agent/messages/task_lifecycle.rb +240 -0
- data/lib/claude_agent/messages/tool_lifecycle.rb +95 -0
- data/lib/claude_agent/messages.rb +11 -829
- data/lib/claude_agent/options/serializer.rb +194 -0
- data/lib/claude_agent/options.rb +11 -176
- data/lib/claude_agent/query.rb +0 -2
- data/lib/claude_agent/sandbox_settings.rb +3 -0
- data/lib/claude_agent/session.rb +0 -204
- data/lib/claude_agent/session_mutations.rb +148 -0
- data/lib/claude_agent/transport/subprocess.rb +2 -2
- data/lib/claude_agent/types/mcp.rb +30 -0
- data/lib/claude_agent/types/models.rb +146 -0
- data/lib/claude_agent/types/operations.rb +38 -0
- data/lib/claude_agent/types/sessions.rb +50 -0
- data/lib/claude_agent/types/tools.rb +32 -0
- data/lib/claude_agent/types.rb +6 -264
- data/lib/claude_agent/v2_session.rb +207 -0
- data/lib/claude_agent/version.rb +1 -1
- data/lib/claude_agent.rb +37 -3
- data/sig/claude_agent.rbs +144 -13
- metadata +33 -1
|
@@ -1,835 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
super
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def type
|
|
15
|
-
:user
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Get text content if content is a string
|
|
19
|
-
# @return [String, nil]
|
|
20
|
-
def text
|
|
21
|
-
content.is_a?(String) ? content : nil
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Check if this is a replayed message
|
|
25
|
-
# @return [Boolean]
|
|
26
|
-
def replay?
|
|
27
|
-
false
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# User message replay (TypeScript SDK parity)
|
|
32
|
-
#
|
|
33
|
-
# Sent when resuming a session with existing conversation history.
|
|
34
|
-
# These messages represent replayed user messages from a previous session.
|
|
35
|
-
#
|
|
36
|
-
# @example
|
|
37
|
-
# msg = UserMessageReplay.new(
|
|
38
|
-
# content: "Hello!",
|
|
39
|
-
# uuid: "abc-123",
|
|
40
|
-
# session_id: "session-abc",
|
|
41
|
-
# is_replay: true
|
|
42
|
-
# )
|
|
43
|
-
# msg.replay? # => true
|
|
44
|
-
#
|
|
45
|
-
UserMessageReplay = Data.define(
|
|
46
|
-
:content,
|
|
47
|
-
:uuid,
|
|
48
|
-
:session_id,
|
|
49
|
-
:parent_tool_use_id,
|
|
50
|
-
:is_replay,
|
|
51
|
-
:is_synthetic,
|
|
52
|
-
:tool_use_result
|
|
53
|
-
) do
|
|
54
|
-
def initialize(
|
|
55
|
-
content:,
|
|
56
|
-
uuid: nil,
|
|
57
|
-
session_id: nil,
|
|
58
|
-
parent_tool_use_id: nil,
|
|
59
|
-
is_replay: true,
|
|
60
|
-
is_synthetic: nil,
|
|
61
|
-
tool_use_result: nil
|
|
62
|
-
)
|
|
63
|
-
super
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def type
|
|
67
|
-
:user
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Get text content if content is a string
|
|
71
|
-
# @return [String, nil]
|
|
72
|
-
def text
|
|
73
|
-
content.is_a?(String) ? content : nil
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Check if this is a replayed message
|
|
77
|
-
# @return [Boolean]
|
|
78
|
-
def replay?
|
|
79
|
-
is_replay == true
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Check if this is a synthetic message (system-generated)
|
|
83
|
-
# @return [Boolean]
|
|
84
|
-
def synthetic?
|
|
85
|
-
is_synthetic == true
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Assistant message from Claude
|
|
90
|
-
#
|
|
91
|
-
# @example
|
|
92
|
-
# msg = AssistantMessage.new(
|
|
93
|
-
# content: [TextBlock.new(text: "Hello!")],
|
|
94
|
-
# model: "claude-sonnet-4-5-20250514",
|
|
95
|
-
# uuid: "msg-123",
|
|
96
|
-
# session_id: "session-abc"
|
|
97
|
-
# )
|
|
98
|
-
#
|
|
99
|
-
AssistantMessage = Data.define(:content, :model, :uuid, :session_id, :error, :parent_tool_use_id) do
|
|
100
|
-
def initialize(content:, model:, uuid: nil, session_id: nil, error: nil, parent_tool_use_id: nil)
|
|
101
|
-
super
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def type
|
|
105
|
-
:assistant
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# Get all text content concatenated
|
|
109
|
-
# @return [String]
|
|
110
|
-
def text
|
|
111
|
-
content
|
|
112
|
-
.select { |block| block.is_a?(TextBlock) }
|
|
113
|
-
.map(&:text)
|
|
114
|
-
.join
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Get all thinking content concatenated
|
|
118
|
-
# @return [String]
|
|
119
|
-
def thinking
|
|
120
|
-
content
|
|
121
|
-
.select { |block| block.is_a?(ThinkingBlock) }
|
|
122
|
-
.map(&:thinking)
|
|
123
|
-
.join
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Get all tool use blocks
|
|
127
|
-
# @return [Array<ToolUseBlock>]
|
|
128
|
-
def tool_uses
|
|
129
|
-
content.select { |block| block.is_a?(ToolUseBlock) }
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# Check if assistant wants to use a tool
|
|
133
|
-
# @return [Boolean]
|
|
134
|
-
def has_tool_use?
|
|
135
|
-
content.any? { |block| block.is_a?(ToolUseBlock) }
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# System message (internal events)
|
|
140
|
-
#
|
|
141
|
-
# @example
|
|
142
|
-
# msg = SystemMessage.new(subtype: "init", data: {version: "2.0.0"})
|
|
143
|
-
#
|
|
144
|
-
SystemMessage = Data.define(:subtype, :data) do
|
|
145
|
-
def type
|
|
146
|
-
:system
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
# Result message (final message with usage/cost info) - TypeScript SDK parity
|
|
151
|
-
#
|
|
152
|
-
# @example Success result
|
|
153
|
-
# msg = ResultMessage.new(
|
|
154
|
-
# subtype: "success",
|
|
155
|
-
# duration_ms: 1500,
|
|
156
|
-
# duration_api_ms: 1200,
|
|
157
|
-
# is_error: false,
|
|
158
|
-
# num_turns: 3,
|
|
159
|
-
# session_id: "session-abc",
|
|
160
|
-
# total_cost_usd: 0.05,
|
|
161
|
-
# usage: {input_tokens: 100, output_tokens: 50}
|
|
162
|
-
# )
|
|
163
|
-
#
|
|
164
|
-
# @example Error result
|
|
165
|
-
# msg = ResultMessage.new(
|
|
166
|
-
# subtype: "error_max_turns",
|
|
167
|
-
# errors: ["Maximum turns exceeded"],
|
|
168
|
-
# ...
|
|
169
|
-
# )
|
|
170
|
-
#
|
|
171
|
-
ResultMessage = Data.define(
|
|
172
|
-
:subtype,
|
|
173
|
-
:duration_ms,
|
|
174
|
-
:duration_api_ms,
|
|
175
|
-
:is_error,
|
|
176
|
-
:num_turns,
|
|
177
|
-
:session_id,
|
|
178
|
-
:uuid,
|
|
179
|
-
:total_cost_usd,
|
|
180
|
-
:usage,
|
|
181
|
-
:result,
|
|
182
|
-
:structured_output,
|
|
183
|
-
:errors, # Array<String> for error subtypes
|
|
184
|
-
:permission_denials, # Array<SDKPermissionDenial>
|
|
185
|
-
:model_usage, # Hash with per-model usage breakdown
|
|
186
|
-
:stop_reason # Why the model stopped generating (TypeScript SDK parity)
|
|
187
|
-
) do
|
|
188
|
-
def initialize(
|
|
189
|
-
subtype:,
|
|
190
|
-
duration_ms:,
|
|
191
|
-
duration_api_ms:,
|
|
192
|
-
is_error:,
|
|
193
|
-
num_turns:,
|
|
194
|
-
session_id:,
|
|
195
|
-
uuid: nil,
|
|
196
|
-
total_cost_usd: nil,
|
|
197
|
-
usage: nil,
|
|
198
|
-
result: nil,
|
|
199
|
-
structured_output: nil,
|
|
200
|
-
errors: nil,
|
|
201
|
-
permission_denials: nil,
|
|
202
|
-
model_usage: nil,
|
|
203
|
-
stop_reason: nil
|
|
204
|
-
)
|
|
205
|
-
super
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def type
|
|
209
|
-
:result
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
# Check if this was an error result
|
|
213
|
-
# @return [Boolean]
|
|
214
|
-
def error?
|
|
215
|
-
is_error
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
# Check if this was a successful result
|
|
219
|
-
# @return [Boolean]
|
|
220
|
-
def success?
|
|
221
|
-
!is_error
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
# Stream event (partial message during streaming)
|
|
226
|
-
#
|
|
227
|
-
# @example
|
|
228
|
-
# event = StreamEvent.new(
|
|
229
|
-
# uuid: "evt-123",
|
|
230
|
-
# session_id: "session-abc",
|
|
231
|
-
# event: {type: "content_block_delta", delta: {type: "text_delta", text: "Hello"}}
|
|
232
|
-
# )
|
|
233
|
-
#
|
|
234
|
-
StreamEvent = Data.define(:uuid, :session_id, :event, :parent_tool_use_id) do
|
|
235
|
-
def initialize(uuid:, session_id:, event:, parent_tool_use_id: nil)
|
|
236
|
-
super
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
def type
|
|
240
|
-
:stream_event
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# Get the event type from the raw event
|
|
244
|
-
# @return [String, nil]
|
|
245
|
-
def event_type
|
|
246
|
-
event[:type]
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
# Compact boundary message (conversation compaction marker) - TypeScript SDK parity
|
|
251
|
-
#
|
|
252
|
-
# Sent when the conversation is compacted to reduce context size.
|
|
253
|
-
# Contains metadata about the compaction operation.
|
|
254
|
-
#
|
|
255
|
-
# @example
|
|
256
|
-
# msg = CompactBoundaryMessage.new(
|
|
257
|
-
# uuid: "msg-123",
|
|
258
|
-
# session_id: "session-abc",
|
|
259
|
-
# compact_metadata: { trigger: "auto", pre_tokens: 50000 }
|
|
260
|
-
# )
|
|
261
|
-
# msg.trigger # => "auto"
|
|
262
|
-
# msg.pre_tokens # => 50000
|
|
263
|
-
#
|
|
264
|
-
CompactBoundaryMessage = Data.define(:uuid, :session_id, :compact_metadata) do
|
|
265
|
-
def type
|
|
266
|
-
:compact_boundary
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
# Get the compaction trigger type
|
|
270
|
-
# @return [String] "manual" or "auto"
|
|
271
|
-
def trigger
|
|
272
|
-
compact_metadata[:trigger]
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
# Get the token count before compaction
|
|
276
|
-
# @return [Integer, nil]
|
|
277
|
-
def pre_tokens
|
|
278
|
-
compact_metadata[:pre_tokens]
|
|
279
|
-
end
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
# Status message (TypeScript SDK parity)
|
|
283
|
-
#
|
|
284
|
-
# Reports session status like 'compacting' during operations.
|
|
285
|
-
#
|
|
286
|
-
# @example
|
|
287
|
-
# msg = StatusMessage.new(
|
|
288
|
-
# uuid: "msg-123",
|
|
289
|
-
# session_id: "session-abc",
|
|
290
|
-
# status: "compacting"
|
|
291
|
-
# )
|
|
292
|
-
#
|
|
293
|
-
StatusMessage = Data.define(:uuid, :session_id, :status, :permission_mode) do
|
|
294
|
-
def initialize(uuid:, session_id:, status:, permission_mode: nil)
|
|
295
|
-
super
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
def type
|
|
299
|
-
:status
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
# Tool progress message (TypeScript SDK parity)
|
|
304
|
-
#
|
|
305
|
-
# Reports progress during long-running tool executions.
|
|
306
|
-
#
|
|
307
|
-
# @example
|
|
308
|
-
# msg = ToolProgressMessage.new(
|
|
309
|
-
# uuid: "msg-123",
|
|
310
|
-
# session_id: "session-abc",
|
|
311
|
-
# tool_use_id: "tool-456",
|
|
312
|
-
# tool_name: "Bash",
|
|
313
|
-
# elapsed_time_seconds: 5.2
|
|
314
|
-
# )
|
|
315
|
-
#
|
|
316
|
-
ToolProgressMessage = Data.define(
|
|
317
|
-
:uuid,
|
|
318
|
-
:session_id,
|
|
319
|
-
:tool_use_id,
|
|
320
|
-
:tool_name,
|
|
321
|
-
:parent_tool_use_id,
|
|
322
|
-
:elapsed_time_seconds,
|
|
323
|
-
:task_id
|
|
324
|
-
) do
|
|
325
|
-
def initialize(
|
|
326
|
-
uuid:,
|
|
327
|
-
session_id:,
|
|
328
|
-
tool_use_id:,
|
|
329
|
-
tool_name:,
|
|
330
|
-
elapsed_time_seconds:,
|
|
331
|
-
parent_tool_use_id: nil,
|
|
332
|
-
task_id: nil
|
|
333
|
-
)
|
|
334
|
-
super
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
def type
|
|
338
|
-
:tool_progress
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
# Hook response message (TypeScript SDK parity)
|
|
343
|
-
#
|
|
344
|
-
# Contains output from hook executions.
|
|
345
|
-
#
|
|
346
|
-
# @example
|
|
347
|
-
# msg = HookResponseMessage.new(
|
|
348
|
-
# uuid: "msg-123",
|
|
349
|
-
# session_id: "session-abc",
|
|
350
|
-
# hook_id: "hook-456",
|
|
351
|
-
# hook_name: "my-hook",
|
|
352
|
-
# hook_event: "PreToolUse",
|
|
353
|
-
# stdout: "Hook output",
|
|
354
|
-
# stderr: "",
|
|
355
|
-
# output: "Combined output",
|
|
356
|
-
# exit_code: 0,
|
|
357
|
-
# outcome: "success"
|
|
358
|
-
# )
|
|
359
|
-
# msg.success? # => true
|
|
360
|
-
# msg.error? # => false
|
|
361
|
-
# msg.cancelled? # => false
|
|
362
|
-
#
|
|
363
|
-
# Outcome values:
|
|
364
|
-
# - "success" - Hook completed successfully
|
|
365
|
-
# - "error" - Hook encountered an error
|
|
366
|
-
# - "cancelled" - Hook was cancelled
|
|
367
|
-
#
|
|
368
|
-
HookResponseMessage = Data.define(
|
|
369
|
-
:uuid,
|
|
370
|
-
:session_id,
|
|
371
|
-
:hook_id,
|
|
372
|
-
:hook_name,
|
|
373
|
-
:hook_event,
|
|
374
|
-
:stdout,
|
|
375
|
-
:stderr,
|
|
376
|
-
:output,
|
|
377
|
-
:exit_code,
|
|
378
|
-
:outcome
|
|
379
|
-
) do
|
|
380
|
-
def initialize(
|
|
381
|
-
uuid:,
|
|
382
|
-
session_id:,
|
|
383
|
-
hook_id: nil,
|
|
384
|
-
hook_name:,
|
|
385
|
-
hook_event:,
|
|
386
|
-
stdout: "",
|
|
387
|
-
stderr: "",
|
|
388
|
-
output: "",
|
|
389
|
-
exit_code: nil,
|
|
390
|
-
outcome: nil
|
|
391
|
-
)
|
|
392
|
-
super
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
def type
|
|
396
|
-
:hook_response
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
# Check if hook completed successfully
|
|
400
|
-
# @return [Boolean]
|
|
401
|
-
def success?
|
|
402
|
-
outcome == "success"
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
# Check if hook encountered an error
|
|
406
|
-
# @return [Boolean]
|
|
407
|
-
def error?
|
|
408
|
-
outcome == "error"
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
# Check if hook was cancelled
|
|
412
|
-
# @return [Boolean]
|
|
413
|
-
def cancelled?
|
|
414
|
-
outcome == "cancelled"
|
|
415
|
-
end
|
|
416
|
-
end
|
|
417
|
-
|
|
418
|
-
# Auth status message (TypeScript SDK parity)
|
|
419
|
-
#
|
|
420
|
-
# Reports authentication status during login flows.
|
|
421
|
-
#
|
|
422
|
-
# @example
|
|
423
|
-
# msg = AuthStatusMessage.new(
|
|
424
|
-
# uuid: "msg-123",
|
|
425
|
-
# session_id: "session-abc",
|
|
426
|
-
# is_authenticating: true,
|
|
427
|
-
# output: ["Waiting for browser..."]
|
|
428
|
-
# )
|
|
429
|
-
#
|
|
430
|
-
AuthStatusMessage = Data.define(
|
|
431
|
-
:uuid,
|
|
432
|
-
:session_id,
|
|
433
|
-
:is_authenticating,
|
|
434
|
-
:output,
|
|
435
|
-
:error
|
|
436
|
-
) do
|
|
437
|
-
def initialize(
|
|
438
|
-
uuid:,
|
|
439
|
-
session_id:,
|
|
440
|
-
is_authenticating:,
|
|
441
|
-
output: [],
|
|
442
|
-
error: nil
|
|
443
|
-
)
|
|
444
|
-
super
|
|
445
|
-
end
|
|
446
|
-
|
|
447
|
-
def type
|
|
448
|
-
:auth_status
|
|
449
|
-
end
|
|
450
|
-
end
|
|
451
|
-
|
|
452
|
-
# Task notification message (TypeScript SDK parity)
|
|
453
|
-
#
|
|
454
|
-
# Sent when a background task completes, fails, or is stopped.
|
|
455
|
-
# Used for tracking async task execution status.
|
|
456
|
-
#
|
|
457
|
-
# @example
|
|
458
|
-
# msg = TaskNotificationMessage.new(
|
|
459
|
-
# uuid: "msg-123",
|
|
460
|
-
# session_id: "session-abc",
|
|
461
|
-
# task_id: "task-456",
|
|
462
|
-
# status: "completed",
|
|
463
|
-
# output_file: "/path/to/output.txt",
|
|
464
|
-
# summary: "Task completed successfully"
|
|
465
|
-
# )
|
|
466
|
-
# msg.completed? # => true
|
|
467
|
-
# msg.failed? # => false
|
|
468
|
-
#
|
|
469
|
-
# Status values:
|
|
470
|
-
# - "completed" - Task finished successfully
|
|
471
|
-
# - "failed" - Task encountered an error
|
|
472
|
-
# - "stopped" - Task was manually stopped
|
|
473
|
-
#
|
|
474
|
-
TaskNotificationMessage = Data.define(
|
|
475
|
-
:uuid,
|
|
476
|
-
:session_id,
|
|
477
|
-
:task_id,
|
|
478
|
-
:status,
|
|
479
|
-
:output_file,
|
|
480
|
-
:summary,
|
|
481
|
-
:tool_use_id,
|
|
482
|
-
:usage
|
|
483
|
-
) do
|
|
484
|
-
def initialize(
|
|
485
|
-
uuid:,
|
|
486
|
-
session_id:,
|
|
487
|
-
task_id:,
|
|
488
|
-
status:,
|
|
489
|
-
output_file:,
|
|
490
|
-
summary:,
|
|
491
|
-
tool_use_id: nil,
|
|
492
|
-
usage: nil
|
|
493
|
-
)
|
|
494
|
-
super
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
def type
|
|
498
|
-
:task_notification
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
# Check if task completed successfully
|
|
502
|
-
# @return [Boolean]
|
|
503
|
-
def completed?
|
|
504
|
-
status == "completed"
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
# Check if task failed
|
|
508
|
-
# @return [Boolean]
|
|
509
|
-
def failed?
|
|
510
|
-
status == "failed"
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
# Check if task was stopped
|
|
514
|
-
# @return [Boolean]
|
|
515
|
-
def stopped?
|
|
516
|
-
status == "stopped"
|
|
517
|
-
end
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
# Hook started message (TypeScript SDK parity)
|
|
521
|
-
#
|
|
522
|
-
# Sent when a hook execution starts.
|
|
523
|
-
#
|
|
524
|
-
# @example
|
|
525
|
-
# msg = HookStartedMessage.new(
|
|
526
|
-
# uuid: "msg-123",
|
|
527
|
-
# session_id: "session-abc",
|
|
528
|
-
# hook_id: "hook-456",
|
|
529
|
-
# hook_name: "my-hook",
|
|
530
|
-
# hook_event: "PreToolUse"
|
|
531
|
-
# )
|
|
532
|
-
#
|
|
533
|
-
HookStartedMessage = Data.define(
|
|
534
|
-
:uuid,
|
|
535
|
-
:session_id,
|
|
536
|
-
:hook_id,
|
|
537
|
-
:hook_name,
|
|
538
|
-
:hook_event
|
|
539
|
-
) do
|
|
540
|
-
def initialize(
|
|
541
|
-
uuid:,
|
|
542
|
-
session_id:,
|
|
543
|
-
hook_id:,
|
|
544
|
-
hook_name:,
|
|
545
|
-
hook_event:
|
|
546
|
-
)
|
|
547
|
-
super
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
def type
|
|
551
|
-
:hook_started
|
|
552
|
-
end
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
# Hook progress message (TypeScript SDK parity)
|
|
556
|
-
#
|
|
557
|
-
# Reports progress during hook execution.
|
|
558
|
-
#
|
|
559
|
-
# @example
|
|
560
|
-
# msg = HookProgressMessage.new(
|
|
561
|
-
# uuid: "msg-123",
|
|
562
|
-
# session_id: "session-abc",
|
|
563
|
-
# hook_id: "hook-456",
|
|
564
|
-
# hook_name: "my-hook",
|
|
565
|
-
# hook_event: "PreToolUse",
|
|
566
|
-
# stdout: "Hook output so far...",
|
|
567
|
-
# stderr: "",
|
|
568
|
-
# output: "Combined output"
|
|
569
|
-
# )
|
|
570
|
-
#
|
|
571
|
-
HookProgressMessage = Data.define(
|
|
572
|
-
:uuid,
|
|
573
|
-
:session_id,
|
|
574
|
-
:hook_id,
|
|
575
|
-
:hook_name,
|
|
576
|
-
:hook_event,
|
|
577
|
-
:stdout,
|
|
578
|
-
:stderr,
|
|
579
|
-
:output
|
|
580
|
-
) do
|
|
581
|
-
def initialize(
|
|
582
|
-
uuid:,
|
|
583
|
-
session_id:,
|
|
584
|
-
hook_id:,
|
|
585
|
-
hook_name:,
|
|
586
|
-
hook_event:,
|
|
587
|
-
stdout: "",
|
|
588
|
-
stderr: "",
|
|
589
|
-
output: ""
|
|
590
|
-
)
|
|
591
|
-
super
|
|
592
|
-
end
|
|
593
|
-
|
|
594
|
-
def type
|
|
595
|
-
:hook_progress
|
|
596
|
-
end
|
|
597
|
-
end
|
|
598
|
-
|
|
599
|
-
# Tool use summary message (TypeScript SDK parity)
|
|
600
|
-
#
|
|
601
|
-
# Contains a summary of tool use for collapsed display.
|
|
602
|
-
#
|
|
603
|
-
# @example
|
|
604
|
-
# msg = ToolUseSummaryMessage.new(
|
|
605
|
-
# uuid: "msg-123",
|
|
606
|
-
# session_id: "session-abc",
|
|
607
|
-
# summary: "Read 3 files",
|
|
608
|
-
# preceding_tool_use_ids: ["tool-1", "tool-2", "tool-3"]
|
|
609
|
-
# )
|
|
610
|
-
#
|
|
611
|
-
ToolUseSummaryMessage = Data.define(
|
|
612
|
-
:uuid,
|
|
613
|
-
:session_id,
|
|
614
|
-
:summary,
|
|
615
|
-
:preceding_tool_use_ids
|
|
616
|
-
) do
|
|
617
|
-
def initialize(
|
|
618
|
-
uuid:,
|
|
619
|
-
session_id:,
|
|
620
|
-
summary:,
|
|
621
|
-
preceding_tool_use_ids: []
|
|
622
|
-
)
|
|
623
|
-
super
|
|
624
|
-
end
|
|
625
|
-
|
|
626
|
-
def type
|
|
627
|
-
:tool_use_summary
|
|
628
|
-
end
|
|
629
|
-
end
|
|
630
|
-
|
|
631
|
-
# Task started message (TypeScript SDK v0.2.45 parity)
|
|
632
|
-
#
|
|
633
|
-
# Sent when a new task (subagent) is started.
|
|
634
|
-
#
|
|
635
|
-
# @example
|
|
636
|
-
# msg = TaskStartedMessage.new(
|
|
637
|
-
# uuid: "msg-123",
|
|
638
|
-
# session_id: "session-abc",
|
|
639
|
-
# task_id: "task-456",
|
|
640
|
-
# tool_use_id: "tool-789",
|
|
641
|
-
# description: "Running tests",
|
|
642
|
-
# task_type: "bash"
|
|
643
|
-
# )
|
|
644
|
-
#
|
|
645
|
-
TaskStartedMessage = Data.define(
|
|
646
|
-
:uuid,
|
|
647
|
-
:session_id,
|
|
648
|
-
:task_id,
|
|
649
|
-
:tool_use_id,
|
|
650
|
-
:description,
|
|
651
|
-
:task_type
|
|
652
|
-
) do
|
|
653
|
-
def initialize(
|
|
654
|
-
uuid:,
|
|
655
|
-
session_id:,
|
|
656
|
-
task_id:,
|
|
657
|
-
tool_use_id: nil,
|
|
658
|
-
description: nil,
|
|
659
|
-
task_type: nil
|
|
660
|
-
)
|
|
661
|
-
super
|
|
662
|
-
end
|
|
663
|
-
|
|
664
|
-
def type
|
|
665
|
-
:task_started
|
|
666
|
-
end
|
|
667
|
-
end
|
|
668
|
-
|
|
669
|
-
# Task progress message (TypeScript SDK v0.2.51 parity)
|
|
670
|
-
#
|
|
671
|
-
# Reports progress during background task (subagent) execution.
|
|
672
|
-
# Contains usage information and description of what the task is doing.
|
|
673
|
-
#
|
|
674
|
-
# @example
|
|
675
|
-
# msg = TaskProgressMessage.new(
|
|
676
|
-
# uuid: "msg-123",
|
|
677
|
-
# session_id: "session-abc",
|
|
678
|
-
# task_id: "task-456",
|
|
679
|
-
# description: "Searching codebase for patterns",
|
|
680
|
-
# usage: { total_tokens: 5000, tool_uses: 3, duration_ms: 2500 }
|
|
681
|
-
# )
|
|
682
|
-
#
|
|
683
|
-
TaskProgressMessage = Data.define(
|
|
684
|
-
:uuid, :session_id, :task_id, :tool_use_id,
|
|
685
|
-
:description, :usage, :last_tool_name
|
|
686
|
-
) do
|
|
687
|
-
def initialize(
|
|
688
|
-
uuid:,
|
|
689
|
-
session_id:,
|
|
690
|
-
task_id:,
|
|
691
|
-
description:,
|
|
692
|
-
usage: nil,
|
|
693
|
-
tool_use_id: nil,
|
|
694
|
-
last_tool_name: nil
|
|
695
|
-
)
|
|
696
|
-
super
|
|
697
|
-
end
|
|
698
|
-
|
|
699
|
-
def type
|
|
700
|
-
:task_progress
|
|
701
|
-
end
|
|
702
|
-
end
|
|
703
|
-
|
|
704
|
-
# Rate limit event (TypeScript SDK v0.2.45 parity)
|
|
705
|
-
#
|
|
706
|
-
# Reports rate limit status and utilization information.
|
|
707
|
-
#
|
|
708
|
-
# @example
|
|
709
|
-
# msg = RateLimitEvent.new(
|
|
710
|
-
# uuid: "msg-123",
|
|
711
|
-
# session_id: "session-abc",
|
|
712
|
-
# rate_limit_info: {
|
|
713
|
-
# status: "allowed_warning",
|
|
714
|
-
# resetsAt: 1700000000,
|
|
715
|
-
# rateLimitType: "five_hour",
|
|
716
|
-
# utilization: 0.85,
|
|
717
|
-
# isUsingOverage: false,
|
|
718
|
-
# overageStatus: "available"
|
|
719
|
-
# }
|
|
720
|
-
# )
|
|
721
|
-
# msg.status # => "allowed_warning"
|
|
722
|
-
#
|
|
723
|
-
RateLimitEvent = Data.define(:rate_limit_info, :uuid, :session_id) do
|
|
724
|
-
def initialize(rate_limit_info:, uuid: nil, session_id: nil)
|
|
725
|
-
super
|
|
726
|
-
end
|
|
727
|
-
|
|
728
|
-
def type
|
|
729
|
-
:rate_limit_event
|
|
730
|
-
end
|
|
731
|
-
|
|
732
|
-
# Get the rate limit status
|
|
733
|
-
# @return [String, nil]
|
|
734
|
-
def status
|
|
735
|
-
rate_limit_info[:status]
|
|
736
|
-
end
|
|
737
|
-
end
|
|
738
|
-
|
|
739
|
-
# Prompt suggestion message (TypeScript SDK v0.2.47 parity)
|
|
740
|
-
#
|
|
741
|
-
# Contains a suggested prompt for the user.
|
|
742
|
-
#
|
|
743
|
-
# @example
|
|
744
|
-
# msg = PromptSuggestionMessage.new(
|
|
745
|
-
# uuid: "msg-123",
|
|
746
|
-
# session_id: "session-abc",
|
|
747
|
-
# suggestion: "Tell me about this project"
|
|
748
|
-
# )
|
|
749
|
-
#
|
|
750
|
-
PromptSuggestionMessage = Data.define(:uuid, :session_id, :suggestion) do
|
|
751
|
-
def initialize(uuid: nil, session_id: nil, suggestion:)
|
|
752
|
-
super
|
|
753
|
-
end
|
|
754
|
-
|
|
755
|
-
def type
|
|
756
|
-
:prompt_suggestion
|
|
757
|
-
end
|
|
758
|
-
end
|
|
759
|
-
|
|
760
|
-
# Files persisted event (TypeScript SDK v0.2.25 parity)
|
|
761
|
-
#
|
|
762
|
-
# Sent when files are persisted to storage during a session.
|
|
763
|
-
# Contains lists of successfully persisted files and any failures.
|
|
764
|
-
#
|
|
765
|
-
# @example
|
|
766
|
-
# msg = FilesPersistedEvent.new(
|
|
767
|
-
# uuid: "msg-123",
|
|
768
|
-
# session_id: "session-abc",
|
|
769
|
-
# files: [{ filename: "test.rb", file_id: "file-456" }],
|
|
770
|
-
# failed: [],
|
|
771
|
-
# processed_at: "2026-01-30T12:00:00Z"
|
|
772
|
-
# )
|
|
773
|
-
# msg.files.first[:filename] # => "test.rb"
|
|
774
|
-
#
|
|
775
|
-
FilesPersistedEvent = Data.define(
|
|
776
|
-
:uuid,
|
|
777
|
-
:session_id,
|
|
778
|
-
:files,
|
|
779
|
-
:failed,
|
|
780
|
-
:processed_at
|
|
781
|
-
) do
|
|
782
|
-
def initialize(
|
|
783
|
-
uuid:,
|
|
784
|
-
session_id:,
|
|
785
|
-
files: [],
|
|
786
|
-
failed: [],
|
|
787
|
-
processed_at: nil
|
|
788
|
-
)
|
|
789
|
-
super
|
|
790
|
-
end
|
|
791
|
-
|
|
792
|
-
def type
|
|
793
|
-
:files_persisted
|
|
794
|
-
end
|
|
795
|
-
end
|
|
796
|
-
|
|
797
|
-
# Generic message for unknown/future protocol types
|
|
798
|
-
#
|
|
799
|
-
# Wraps unrecognized top-level message types so they can be inspected
|
|
800
|
-
# without crashing the application. Supports dynamic field access via
|
|
801
|
-
# `[]` and `method_missing`.
|
|
802
|
-
#
|
|
803
|
-
# @example
|
|
804
|
-
# msg = GenericMessage.new(message_type: "fancy_new", raw: { data: "hello" })
|
|
805
|
-
# msg.type # => :fancy_new
|
|
806
|
-
# msg[:data] # => "hello"
|
|
807
|
-
# msg.data # => "hello"
|
|
808
|
-
# msg.to_h # => { data: "hello" }
|
|
809
|
-
#
|
|
810
|
-
GenericMessage = Data.define(:message_type, :raw) do
|
|
811
|
-
def type
|
|
812
|
-
message_type&.to_sym || :unknown
|
|
813
|
-
end
|
|
814
|
-
|
|
815
|
-
def to_h
|
|
816
|
-
raw
|
|
817
|
-
end
|
|
818
|
-
|
|
819
|
-
def [](key)
|
|
820
|
-
raw[key]
|
|
821
|
-
end
|
|
822
|
-
|
|
823
|
-
def respond_to_missing?(name, include_private = false)
|
|
824
|
-
raw.key?(name) || super
|
|
825
|
-
end
|
|
826
|
-
|
|
827
|
-
def method_missing(name, *args)
|
|
828
|
-
return raw[name] if args.empty? && raw.key?(name)
|
|
829
|
-
super
|
|
830
|
-
end
|
|
831
|
-
end
|
|
3
|
+
require_relative "messages/conversation"
|
|
4
|
+
require_relative "messages/result"
|
|
5
|
+
require_relative "messages/system"
|
|
6
|
+
require_relative "messages/streaming"
|
|
7
|
+
require_relative "messages/tool_lifecycle"
|
|
8
|
+
require_relative "messages/hook_lifecycle"
|
|
9
|
+
require_relative "messages/task_lifecycle"
|
|
10
|
+
require_relative "messages/generic"
|
|
832
11
|
|
|
12
|
+
module ClaudeAgent
|
|
833
13
|
# All message types
|
|
834
14
|
MESSAGE_TYPES = [
|
|
835
15
|
UserMessage,
|
|
@@ -852,6 +32,8 @@ module ClaudeAgent
|
|
|
852
32
|
TaskProgressMessage,
|
|
853
33
|
RateLimitEvent,
|
|
854
34
|
PromptSuggestionMessage,
|
|
35
|
+
ElicitationCompleteMessage,
|
|
36
|
+
LocalCommandOutputMessage,
|
|
855
37
|
GenericMessage
|
|
856
38
|
].freeze
|
|
857
39
|
end
|