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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/rules/testing.md +51 -10
  3. data/.claude/settings.json +1 -0
  4. data/ARCHITECTURE.md +237 -0
  5. data/CHANGELOG.md +53 -0
  6. data/CLAUDE.md +2 -0
  7. data/README.md +46 -1
  8. data/Rakefile +17 -0
  9. data/SPEC.md +214 -125
  10. data/lib/claude_agent/client/commands.rb +225 -0
  11. data/lib/claude_agent/client.rb +4 -206
  12. data/lib/claude_agent/content_blocks/generic_block.rb +39 -0
  13. data/lib/claude_agent/content_blocks/image_content_block.rb +54 -0
  14. data/lib/claude_agent/content_blocks/server_tool_result_block.rb +22 -0
  15. data/lib/claude_agent/content_blocks/server_tool_use_block.rb +48 -0
  16. data/lib/claude_agent/content_blocks/text_block.rb +19 -0
  17. data/lib/claude_agent/content_blocks/thinking_block.rb +19 -0
  18. data/lib/claude_agent/content_blocks/tool_result_block.rb +25 -0
  19. data/lib/claude_agent/content_blocks/tool_use_block.rb +134 -0
  20. data/lib/claude_agent/content_blocks.rb +8 -335
  21. data/lib/claude_agent/control_protocol/commands.rb +304 -0
  22. data/lib/claude_agent/control_protocol/lifecycle.rb +116 -0
  23. data/lib/claude_agent/control_protocol/messaging.rb +163 -0
  24. data/lib/claude_agent/control_protocol/primitives.rb +168 -0
  25. data/lib/claude_agent/control_protocol/request_handling.rb +231 -0
  26. data/lib/claude_agent/control_protocol.rb +50 -882
  27. data/lib/claude_agent/conversation.rb +8 -1
  28. data/lib/claude_agent/event_handler.rb +1 -0
  29. data/lib/claude_agent/get_session_info.rb +86 -0
  30. data/lib/claude_agent/hooks.rb +23 -2
  31. data/lib/claude_agent/list_sessions.rb +22 -13
  32. data/lib/claude_agent/message_parser.rb +26 -4
  33. data/lib/claude_agent/messages/conversation.rb +138 -0
  34. data/lib/claude_agent/messages/generic.rb +39 -0
  35. data/lib/claude_agent/messages/hook_lifecycle.rb +158 -0
  36. data/lib/claude_agent/messages/result.rb +80 -0
  37. data/lib/claude_agent/messages/streaming.rb +84 -0
  38. data/lib/claude_agent/messages/system.rb +67 -0
  39. data/lib/claude_agent/messages/task_lifecycle.rb +240 -0
  40. data/lib/claude_agent/messages/tool_lifecycle.rb +95 -0
  41. data/lib/claude_agent/messages.rb +11 -829
  42. data/lib/claude_agent/options/serializer.rb +194 -0
  43. data/lib/claude_agent/options.rb +11 -176
  44. data/lib/claude_agent/query.rb +0 -2
  45. data/lib/claude_agent/sandbox_settings.rb +3 -0
  46. data/lib/claude_agent/session.rb +0 -204
  47. data/lib/claude_agent/session_mutations.rb +148 -0
  48. data/lib/claude_agent/transport/subprocess.rb +2 -2
  49. data/lib/claude_agent/types/mcp.rb +30 -0
  50. data/lib/claude_agent/types/models.rb +146 -0
  51. data/lib/claude_agent/types/operations.rb +38 -0
  52. data/lib/claude_agent/types/sessions.rb +50 -0
  53. data/lib/claude_agent/types/tools.rb +32 -0
  54. data/lib/claude_agent/types.rb +6 -264
  55. data/lib/claude_agent/v2_session.rb +207 -0
  56. data/lib/claude_agent/version.rb +1 -1
  57. data/lib/claude_agent.rb +37 -3
  58. data/sig/claude_agent.rbs +144 -13
  59. metadata +33 -1
@@ -1,835 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ClaudeAgent
4
- # User message sent to Claude
5
- #
6
- # @example
7
- # msg = UserMessage.new(content: "Hello!", uuid: "abc-123", session_id: "session-abc")
8
- #
9
- UserMessage = Data.define(:content, :uuid, :session_id, :parent_tool_use_id) do
10
- def initialize(content:, uuid: nil, session_id: nil, parent_tool_use_id: nil)
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