ag-ui-protocol 0.1.0

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,1024 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require_relative "types"
6
+
7
+ module AgUiProtocol
8
+ module Core
9
+ # The Agent User Interaction Protocol Ruby SDK uses a streaming event-based
10
+ # architecture. Events are the fundamental units of communication between agents
11
+ # and the frontend. This section documents the event types and their properties.
12
+ #
13
+ # ## Lifecycle Events
14
+ #
15
+ # These events represent the lifecycle of an agent run.
16
+ #
17
+ # ## Text Message Events
18
+ #
19
+ # These events represent the lifecycle of text messages in a conversation.
20
+ #
21
+ # ## Tool Call Events
22
+ #
23
+ # These events represent the lifecycle of tool calls made by agents.
24
+ #
25
+ # ## State Management Events
26
+ #
27
+ # These events are used to manage agent state.
28
+ #
29
+ module Events
30
+ # Valid values for the role attribute of a text message.
31
+ TEXT_MESSAGE_ROLE_VALUES = ["developer", "system", "assistant", "user"].freeze
32
+
33
+ # The `EventType` module defines all possible event types in the system
34
+ module EventType
35
+ TEXT_MESSAGE_START = "TEXT_MESSAGE_START"
36
+ TEXT_MESSAGE_CONTENT = "TEXT_MESSAGE_CONTENT"
37
+ TEXT_MESSAGE_END = "TEXT_MESSAGE_END"
38
+ TEXT_MESSAGE_CHUNK = "TEXT_MESSAGE_CHUNK"
39
+ THINKING_TEXT_MESSAGE_START = "THINKING_TEXT_MESSAGE_START"
40
+ THINKING_TEXT_MESSAGE_CONTENT = "THINKING_TEXT_MESSAGE_CONTENT"
41
+ THINKING_TEXT_MESSAGE_END = "THINKING_TEXT_MESSAGE_END"
42
+ TOOL_CALL_START = "TOOL_CALL_START"
43
+ TOOL_CALL_ARGS = "TOOL_CALL_ARGS"
44
+ TOOL_CALL_END = "TOOL_CALL_END"
45
+ TOOL_CALL_CHUNK = "TOOL_CALL_CHUNK"
46
+ TOOL_CALL_RESULT = "TOOL_CALL_RESULT"
47
+ THINKING_START = "THINKING_START"
48
+ THINKING_END = "THINKING_END"
49
+ STATE_SNAPSHOT = "STATE_SNAPSHOT"
50
+ STATE_DELTA = "STATE_DELTA"
51
+ MESSAGES_SNAPSHOT = "MESSAGES_SNAPSHOT"
52
+ ACTIVITY_SNAPSHOT = "ACTIVITY_SNAPSHOT"
53
+ ACTIVITY_DELTA = "ACTIVITY_DELTA"
54
+ RAW = "RAW"
55
+ CUSTOM = "CUSTOM"
56
+ RUN_STARTED = "RUN_STARTED"
57
+ RUN_FINISHED = "RUN_FINISHED"
58
+ RUN_ERROR = "RUN_ERROR"
59
+ STEP_STARTED = "STEP_STARTED"
60
+ STEP_FINISHED = "STEP_FINISHED"
61
+ end
62
+
63
+ # All events inherit from the `BaseEvent` class, which provides common properties
64
+ # shared across all event types.
65
+ # ```ruby
66
+ #
67
+ # event = AgUiProtocol::Core::Events::BaseEvent.new(
68
+ # type: AgUiProtocol::Core::Events::EventType::RAW,
69
+ # timestamp: nil,
70
+ # raw_event: nil
71
+ # )
72
+ #
73
+ # ```
74
+ class BaseEvent < AgUiProtocol::Core::Types::Model
75
+ extend T::Sig
76
+
77
+ sig { returns(String) }
78
+ attr_reader :type
79
+
80
+ sig { returns(T.nilable(Time)) }
81
+ attr_reader :timestamp
82
+
83
+ sig { returns(T.untyped) }
84
+ attr_reader :raw_event
85
+
86
+ # @param type [String] The type of event
87
+ # @param timestamp [Time] Timestamp when the event was created
88
+ # @param raw_event [Object] Original event data if this event was transformed
89
+ sig { params(type: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
90
+ def initialize(type:, timestamp: nil, raw_event: nil)
91
+ @type = type
92
+ @timestamp = timestamp
93
+ @raw_event = raw_event
94
+ end
95
+
96
+ sig { returns(T::Hash[Symbol, T.untyped]) }
97
+ def to_h
98
+ {
99
+ type: @type,
100
+ timestamp: @timestamp,
101
+ raw_event: @raw_event
102
+ }
103
+ end
104
+ end
105
+
106
+ # Signals the start of a text message.
107
+ #
108
+ # ```ruby
109
+ #
110
+ # event = AgUiProtocol::Core::Events::TextMessageStartEvent.new(
111
+ # message_id: "m1",
112
+ # )
113
+ #
114
+ # ```
115
+ # @category Text Message Events
116
+ class TextMessageStartEvent < BaseEvent
117
+
118
+ sig { returns(String) }
119
+ attr_reader :message_id
120
+
121
+ sig { returns(String) }
122
+ attr_reader :role
123
+
124
+ # @param message_id [String] Unique identifier for the message
125
+ # @param timestamp [Time] Timestamp when the event was created
126
+ # @param raw_event [Object] Original event data if this event was transformed
127
+ sig { params(message_id: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
128
+ def initialize(message_id:, timestamp: nil, raw_event: nil)
129
+ super(type: EventType::TEXT_MESSAGE_START, timestamp: timestamp, raw_event: raw_event)
130
+ @message_id = message_id
131
+ @role = 'assistant'
132
+ end
133
+
134
+ sig { returns(T::Hash[Symbol, T.untyped]) }
135
+ def to_h
136
+ super.merge(message_id: @message_id, role: @role)
137
+ end
138
+ end
139
+
140
+ # Represents a chunk of content in a streaming text message.
141
+ #
142
+ # ```ruby
143
+ #
144
+ # event = AgUiProtocol::Core::Events::TextMessageContentEvent.new(
145
+ # message_id: "m1",
146
+ # delta: "Hello, world!"
147
+ # )
148
+ #
149
+ # ```
150
+ # @category Text Message Events
151
+ class TextMessageContentEvent < BaseEvent
152
+ sig { returns(String) }
153
+ attr_reader :message_id
154
+
155
+ sig { returns(String) }
156
+ attr_reader :delta
157
+
158
+ # @param message_id [String] Matches the ID from TextMessageStartEvent
159
+ # @param delta [String] Text content chunk (non-empty)
160
+ # @param timestamp [Time] Timestamp when the event was created
161
+ # @param raw_event [Object] Original event data if this event was transformed
162
+ sig { params(message_id: String, delta: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
163
+ def initialize(message_id:, delta:, timestamp: nil, raw_event: nil)
164
+ raise ArgumentError, "delta must be non-empty" if delta.nil? || delta.empty?
165
+
166
+ super(type: EventType::TEXT_MESSAGE_CONTENT, timestamp: timestamp, raw_event: raw_event)
167
+ @message_id = message_id
168
+ @delta = delta
169
+ end
170
+
171
+ sig { returns(T::Hash[Symbol, T.untyped]) }
172
+ def to_h
173
+ super.merge(message_id: @message_id, delta: @delta)
174
+ end
175
+ end
176
+
177
+ # Signals the end of a text message.
178
+ #
179
+ # ```ruby
180
+ #
181
+ # event = AgUiProtocol::Core::Events::TextMessageEndEvent.new(message_id: "m1")
182
+ #
183
+ # ```
184
+ # @category Text Message Events
185
+ class TextMessageEndEvent < BaseEvent
186
+ sig { returns(String) }
187
+ attr_reader :message_id
188
+
189
+ # @param message_id [String] Matches the ID from TextMessageStartEvent
190
+ # @param timestamp [Time] Timestamp when the event was created
191
+ # @param raw_event [Object] Original event data if this event was transformed
192
+ sig { params(message_id: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
193
+ def initialize(message_id:, timestamp: nil, raw_event: nil)
194
+ super(type: EventType::TEXT_MESSAGE_END, timestamp: timestamp, raw_event: raw_event)
195
+ @message_id = message_id
196
+ end
197
+
198
+ sig { returns(T::Hash[Symbol, T.untyped]) }
199
+ def to_h
200
+ super.merge(message_id: @message_id)
201
+ end
202
+ end
203
+
204
+ # Convenience event for complete text messages without manually emitting `TextMessageStart`/`TextMessageEnd`.
205
+ #
206
+ # ```ruby
207
+ # event = AgUiProtocol::Core::Events::TextMessageChunkEvent.new(
208
+ # message_id: "m1",
209
+ # delta: "Hello"
210
+ # )
211
+ #
212
+ # ```
213
+ #
214
+ # Behavior:
215
+ # - Convenience: Some consumers (e.g., the JS/TS client) expand chunk events into
216
+ # the standard start/content/end sequence automatically, allowing producers to
217
+ # omit explicit start/end events when using chunks.
218
+ # - First chunk requirements: The first chunk for a given message must include
219
+ # `message_id`.
220
+ # - Streaming: Subsequent chunks with the same `message_id` correspond to content
221
+ # pieces; completion triggers an implied end in clients that perform expansion.
222
+ # @category Text Message Events
223
+ class TextMessageChunkEvent < BaseEvent
224
+ sig { returns(T.nilable(String)) }
225
+ attr_reader :message_id
226
+
227
+ sig { returns(T.nilable(String)) }
228
+ attr_reader :role
229
+
230
+ sig { returns(T.nilable(String)) }
231
+ attr_reader :delta
232
+
233
+ # @param message_id [String] required on first chunk for a message
234
+ # @param role [String] must be one of TEXT_MESSAGE_ROLE_VALUES
235
+ # @param delta [String] Text content chunk
236
+ # @param timestamp [Time] Timestamp when the event was created
237
+ # @param raw_event [Object] Original event data if this event was transformed
238
+ sig do
239
+ params(
240
+ message_id: T.nilable(String),
241
+ role: T.nilable(String),
242
+ delta: T.nilable(String),
243
+ timestamp: T.nilable(Time),
244
+ raw_event: T.untyped,
245
+ ).void
246
+ end
247
+ def initialize(message_id: nil, role: nil, delta: nil, timestamp: nil, raw_event: nil)
248
+ raise ArgumentError, "role must be one of #{TEXT_MESSAGE_ROLE_VALUES.join(", ")}, got #{role}" if !role.nil? && !TEXT_MESSAGE_ROLE_VALUES.include?(role)
249
+
250
+ super(type: EventType::TEXT_MESSAGE_CHUNK, timestamp: timestamp, raw_event: raw_event)
251
+ @message_id = message_id
252
+ @role = role
253
+ @delta = delta
254
+ end
255
+
256
+ sig { returns(T::Hash[Symbol, T.untyped]) }
257
+ def to_h
258
+ super.merge(message_id: @message_id, role: @role, delta: @delta)
259
+ end
260
+ end
261
+
262
+ # Event indicating the start of a thinking text message.
263
+ class ThinkingTextMessageStartEvent < BaseEvent
264
+ # @param timestamp [Time] Timestamp when the event was created
265
+ # @param raw_event [Object] Original event data if this event was transformed
266
+ sig { params(timestamp: T.nilable(Time), raw_event: T.untyped).void }
267
+ def initialize(timestamp: nil, raw_event: nil)
268
+ super(type: EventType::THINKING_TEXT_MESSAGE_START, timestamp: timestamp, raw_event: raw_event)
269
+ end
270
+ end
271
+
272
+ # Event indicating a piece of a thinking text message.
273
+ class ThinkingTextMessageContentEvent < BaseEvent
274
+ sig { returns(String) }
275
+ attr_reader :delta
276
+
277
+ # @param delta [String] Text content
278
+ # @param timestamp [Time] Timestamp when the event was created
279
+ # @param raw_event [Object] Original event data if this event was transformed
280
+ sig { params(delta: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
281
+ def initialize(delta:, timestamp: nil, raw_event: nil)
282
+ raise ArgumentError, "delta must be non-empty" if delta.nil? || delta.empty?
283
+
284
+ super(type: EventType::THINKING_TEXT_MESSAGE_CONTENT, timestamp: timestamp, raw_event: raw_event)
285
+ @delta = delta
286
+ end
287
+
288
+ sig { returns(T::Hash[Symbol, T.untyped]) }
289
+ def to_h
290
+ super.merge(delta: @delta)
291
+ end
292
+ end
293
+
294
+ # Event indicating the end of a thinking text message.
295
+ class ThinkingTextMessageEndEvent < BaseEvent
296
+ # @param timestamp [Time] Timestamp when the event was created
297
+ # @param raw_event [Object] Original event data if this event was transformed
298
+ sig { params(timestamp: T.nilable(Time), raw_event: T.untyped).void }
299
+ def initialize(timestamp: nil, raw_event: nil)
300
+ super(type: EventType::THINKING_TEXT_MESSAGE_END, timestamp: timestamp, raw_event: raw_event)
301
+ end
302
+ end
303
+
304
+ # Signals the start of a tool call.
305
+ #
306
+ # ```ruby
307
+ #
308
+ # event = AgUiProtocol::Core::Events::ToolCallStartEvent.new(
309
+ # tool_call_id: "tc1",
310
+ # tool_call_name: "search",
311
+ # parent_message_id: nil
312
+ # )
313
+ #
314
+ # ```
315
+ # @category Tool Call Events
316
+ class ToolCallStartEvent < BaseEvent
317
+ sig { returns(String) }
318
+ attr_reader :tool_call_id
319
+
320
+ sig { returns(String) }
321
+ attr_reader :tool_call_name
322
+
323
+ sig { returns(T.nilable(String)) }
324
+ attr_reader :parent_message_id
325
+
326
+ # @param tool_call_id [String] Unique identifier for the tool call
327
+ # @param tool_call_name [String] Name of the tool being called
328
+ # @param parent_message_id [String] ID of the parent message
329
+ # @param timestamp [Time] Timestamp when the event was created
330
+ # @param raw_event [Object] Original event data if this event was transformed
331
+ sig do
332
+ params(
333
+ tool_call_id: String,
334
+ tool_call_name: String,
335
+ parent_message_id: T.nilable(String),
336
+ timestamp: T.nilable(Time),
337
+ raw_event: T.untyped
338
+ ).void
339
+ end
340
+ def initialize(tool_call_id:, tool_call_name:, parent_message_id: nil, timestamp: nil, raw_event: nil)
341
+ super(type: EventType::TOOL_CALL_START, timestamp: timestamp, raw_event: raw_event)
342
+ @tool_call_id = tool_call_id
343
+ @tool_call_name = tool_call_name
344
+ @parent_message_id = parent_message_id
345
+ end
346
+
347
+ sig { returns(T::Hash[Symbol, T.untyped]) }
348
+ def to_h
349
+ super.merge(tool_call_id: @tool_call_id, tool_call_name: @tool_call_name, parent_message_id: @parent_message_id)
350
+ end
351
+ end
352
+
353
+ # Represents a chunk of argument data for a tool call.
354
+ #
355
+ # ```ruby
356
+ #
357
+ # event = AgUiProtocol::Core::Events::ToolCallArgsEvent.new(
358
+ # tool_call_id: "tc1",
359
+ # delta: "{\"q\":\"AG-UI\"}"
360
+ # )
361
+ #
362
+ # ```
363
+ # @category Tool Call Events
364
+ class ToolCallArgsEvent < BaseEvent
365
+ sig { returns(String) }
366
+ attr_reader :tool_call_id
367
+
368
+ sig { returns(String) }
369
+ attr_reader :delta
370
+
371
+ # @param tool_call_id [String] Matches the ID from ToolCallStartEvent
372
+ # @param delta [String] Argument data chunk
373
+ # @param timestamp [Time] Timestamp when the event was created
374
+ # @param raw_event [Object] Original event data if this event was transformed
375
+ sig { params(tool_call_id: String, delta: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
376
+ def initialize(tool_call_id:, delta:, timestamp: nil, raw_event: nil)
377
+ super(type: EventType::TOOL_CALL_ARGS, timestamp: timestamp, raw_event: raw_event)
378
+ @tool_call_id = tool_call_id
379
+ @delta = delta
380
+ end
381
+
382
+ sig { returns(T::Hash[Symbol, T.untyped]) }
383
+ def to_h
384
+ super.merge(tool_call_id: @tool_call_id, delta: @delta)
385
+ end
386
+ end
387
+
388
+ # Signals the end of a tool call.
389
+ #
390
+ # ```ruby
391
+ #
392
+ # event = AgUiProtocol::Core::Events::ToolCallEndEvent.new(tool_call_id: "tc1")
393
+ #
394
+ # ```
395
+ # @category Tool Call Events
396
+ class ToolCallEndEvent < BaseEvent
397
+ sig { returns(String) }
398
+ attr_reader :tool_call_id
399
+
400
+ # @param tool_call_id [String] Matches the ID from ToolCallStartEvent
401
+ # @param timestamp [Time] Timestamp when the event was created
402
+ # @param raw_event [Object] Original event data if this event was transformed
403
+ sig { params(tool_call_id: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
404
+ def initialize(tool_call_id:, timestamp: nil, raw_event: nil)
405
+ super(type: EventType::TOOL_CALL_END, timestamp: timestamp, raw_event: raw_event)
406
+ @tool_call_id = tool_call_id
407
+ end
408
+
409
+ sig { returns(T::Hash[Symbol, T.untyped]) }
410
+ def to_h
411
+ super.merge(tool_call_id: @tool_call_id)
412
+ end
413
+ end
414
+
415
+ # Convenience event for tool calls without manually emitting
416
+ # `ToolCallStartEvent`/`ToolCallEndEvent`.
417
+ #
418
+ # ```ruby
419
+ #
420
+ # event = AgUiProtocol::Core::Events::ToolCallChunkEvent.new(
421
+ # tool_call_id: "tc1",
422
+ # tool_call_name: "search",
423
+ # delta: "{\"q\":\"AG-UI\"}"
424
+ # )
425
+ #
426
+ # ```
427
+ #
428
+ # Behavior:
429
+ # - Convenience: Consumers may expand chunk sequences into the standard
430
+ # start/args/end triad (the JS/TS client does this automatically).
431
+ # - First chunk requirements: Include both `tool_call_id` and `tool_call_name` on
432
+ # the first chunk.
433
+ # - Streaming: Subsequent chunks with the same `tool_call_id` correspond to args
434
+ # pieces; completion triggers an implied end in clients that perform expansion.
435
+ # @category Tool Call Events
436
+ class ToolCallChunkEvent < BaseEvent
437
+ sig { returns(T.nilable(String)) }
438
+ attr_reader :tool_call_id
439
+
440
+ sig { returns(T.nilable(String)) }
441
+ attr_reader :tool_call_name
442
+
443
+ sig { returns(T.nilable(String)) }
444
+ attr_reader :parent_message_id
445
+
446
+ sig { returns(T.nilable(String)) }
447
+ attr_reader :delta
448
+
449
+ # @param tool_call_id [String] Matches the ID from ToolCallStartEvent
450
+ # @param tool_call_name [String] Name of the tool being called
451
+ # @param parent_message_id [String] ID of the parent message
452
+ # @param delta [String] Argument data chunk
453
+ # @param timestamp [Time] Timestamp when the event was created
454
+ # @param raw_event [Object] Original event data if this event was transformed
455
+ sig do
456
+ params(
457
+ tool_call_id: T.nilable(String),
458
+ tool_call_name: T.nilable(String),
459
+ parent_message_id: T.nilable(String),
460
+ delta: T.nilable(String),
461
+ timestamp: T.nilable(Time),
462
+ raw_event: T.untyped
463
+ ).void
464
+ end
465
+ def initialize(tool_call_id: nil, tool_call_name: nil, parent_message_id: nil, delta: nil, timestamp: nil, raw_event: nil)
466
+ super(type: EventType::TOOL_CALL_CHUNK, timestamp: timestamp, raw_event: raw_event)
467
+ @tool_call_id = tool_call_id
468
+ @tool_call_name = tool_call_name
469
+ @parent_message_id = parent_message_id
470
+ @delta = delta
471
+ end
472
+
473
+ sig { returns(T::Hash[Symbol, T.untyped]) }
474
+ def to_h
475
+ super.merge(
476
+ tool_call_id: @tool_call_id,
477
+ tool_call_name: @tool_call_name,
478
+ parent_message_id: @parent_message_id,
479
+ delta: @delta
480
+ )
481
+ end
482
+ end
483
+
484
+ # Provides the result of a tool call execution.
485
+ #
486
+ # ```ruby
487
+ #
488
+ # event = AgUiProtocol::Core::Events::ToolCallResultEvent.new(
489
+ # message_id: "m1",
490
+ # tool_call_id: "tc1",
491
+ # content: "ok"
492
+ # )
493
+ #
494
+ # ```
495
+ # @category Tool Call Events
496
+ class ToolCallResultEvent < BaseEvent
497
+ sig { returns(String) }
498
+ attr_reader :message_id
499
+
500
+ sig { returns(String) }
501
+ attr_reader :tool_call_id
502
+
503
+ sig { returns(String) }
504
+ attr_reader :content
505
+
506
+ sig { returns(T.nilable(String)) }
507
+ attr_reader :role
508
+
509
+ # @param message_id [String] ID of the conversation message this result belongs to
510
+ # @param tool_call_id [String] Matches the ID from the corresponding ToolCallStartEvent
511
+ # @param content [String] The actual result/output content from the tool execution
512
+ # @param role [String] Optional role identifier, typically "tool" for tool results
513
+ # @param timestamp [Time] Timestamp when the event was created
514
+ # @param raw_event [Object] Original event data if this event was transformed
515
+ sig do
516
+ params(
517
+ message_id: String,
518
+ tool_call_id: String,
519
+ content: String,
520
+ role: T.nilable(String),
521
+ timestamp: T.nilable(Time),
522
+ raw_event: T.untyped
523
+ ).void
524
+ end
525
+ def initialize(message_id:, tool_call_id:, content:, role: nil, timestamp: nil, raw_event: nil)
526
+ raise ArgumentError, "role must be tool, got #{role}" if !role.nil? && role != "tool"
527
+
528
+ super(type: EventType::TOOL_CALL_RESULT, timestamp: timestamp, raw_event: raw_event)
529
+ @message_id = message_id
530
+ @tool_call_id = tool_call_id
531
+ @content = content
532
+ @role = role
533
+ end
534
+
535
+ sig { returns(T::Hash[Symbol, T.untyped]) }
536
+ def to_h
537
+ super.merge(
538
+ message_id: @message_id,
539
+ tool_call_id: @tool_call_id,
540
+ content: @content,
541
+ role: @role
542
+ )
543
+ end
544
+ end
545
+
546
+ # Event indicating the start of a thinking step event.
547
+ #
548
+ # ```ruby
549
+ # event = AgUiProtocol::Core::Events::ThinkingStartEvent.new(title: "step")
550
+ # ```
551
+ #
552
+ # @category Thinking Events
553
+ class ThinkingStartEvent < BaseEvent
554
+ sig { returns(T.nilable(String)) }
555
+ attr_reader :title
556
+
557
+ # @param title [String] Title of the thinking step
558
+ # @param timestamp [Time] Timestamp when the event was created
559
+ # @param raw_event [Object] Original event data if this event was transformed
560
+ sig { params(title: T.nilable(String), timestamp: T.nilable(Time), raw_event: T.untyped).void }
561
+ def initialize(title: nil, timestamp: nil, raw_event: nil)
562
+ super(type: EventType::THINKING_START, timestamp: timestamp, raw_event: raw_event)
563
+ @title = title
564
+ end
565
+
566
+ sig { returns(T::Hash[Symbol, T.untyped]) }
567
+ def to_h
568
+ super.merge(title: @title)
569
+ end
570
+ end
571
+
572
+ # Event indicating the end of a thinking step event.
573
+ #
574
+ # ```ruby
575
+ # event = AgUiProtocol::Core::Events::ThinkingEndEvent.new
576
+ # ```
577
+ #
578
+ # @category Thinking Events
579
+ class ThinkingEndEvent < BaseEvent
580
+ # @param timestamp [Time] Timestamp when the event was created
581
+ # @param raw_event [Object] Original event data if this event was transformed
582
+ sig { params(timestamp: T.nilable(Time), raw_event: T.untyped).void }
583
+ def initialize(timestamp: nil, raw_event: nil)
584
+ super(type: EventType::THINKING_END, timestamp: timestamp, raw_event: raw_event)
585
+ end
586
+ end
587
+
588
+ # Provides a complete snapshot of an agent's state.
589
+ #
590
+ # ```ruby
591
+ # event = AgUiProtocol::Core::Events::StateSnapshotEvent.new(snapshot: { "a" => 1 })
592
+ # ```
593
+ #
594
+ # @category State Management Events
595
+ class StateSnapshotEvent < BaseEvent
596
+ sig { returns(T.untyped) }
597
+ attr_reader :snapshot
598
+
599
+ # @param snapshot [Object] Complete state snapshot
600
+ # @param timestamp [Time] Timestamp when the event was created
601
+ # @param raw_event [Object] Original event data if this event was transformed
602
+ sig { params(snapshot: T.untyped, timestamp: T.nilable(Time), raw_event: T.untyped).void }
603
+ def initialize(snapshot:, timestamp: nil, raw_event: nil)
604
+ super(type: EventType::STATE_SNAPSHOT, timestamp: timestamp, raw_event: raw_event)
605
+ @snapshot = snapshot
606
+ end
607
+
608
+ sig { returns(T::Hash[Symbol, T.untyped]) }
609
+ def to_h
610
+ super.merge(snapshot: @snapshot)
611
+ end
612
+ end
613
+
614
+ # Provides a partial update to an agent's state using JSON Patch.
615
+ #
616
+ # ```ruby
617
+ # event = AgUiProtocol::Core::Events::StateDeltaEvent.new(delta: [{ "op" => "replace", "path" => "/a", "value" => 2 }])
618
+ # ```
619
+ #
620
+ # @category State Management Events
621
+ class StateDeltaEvent < BaseEvent
622
+ sig { returns(T::Array[T.untyped]) }
623
+ attr_reader :delta
624
+
625
+ # @param delta [Array<Object>] Array of JSON Patch operations
626
+ # @param timestamp [Time] Timestamp when the event was created
627
+ # @param raw_event [Object] Original event data if this event was transformed
628
+ sig { params(delta: T::Array[T.untyped], timestamp: T.nilable(Time), raw_event: T.untyped).void }
629
+ def initialize(delta:, timestamp: nil, raw_event: nil)
630
+ super(type: EventType::STATE_DELTA, timestamp: timestamp, raw_event: raw_event)
631
+ @delta = delta
632
+ end
633
+
634
+ sig { returns(T::Hash[Symbol, T.untyped]) }
635
+ def to_h
636
+ super.merge(delta: @delta)
637
+ end
638
+ end
639
+
640
+ # Provides a snapshot of all messages in a conversation.
641
+ #
642
+ # ```ruby
643
+ # event = AgUiProtocol::Core::Events::MessagesSnapshotEvent.new(messages: [{ "id" => "m1", "content" => "hi" }])
644
+ # ```
645
+ #
646
+ # @category State Management Events
647
+ class MessagesSnapshotEvent < BaseEvent
648
+ sig { returns(T::Array[T.untyped]) }
649
+ attr_reader :messages
650
+
651
+ # @param messages [Array<AgUiProtocol::Core::Types::BaseMessage>] Array of message objects
652
+ # @param timestamp [Time] Timestamp when the event was created
653
+ # @param raw_event [Object] Original event data if this event was transformed
654
+ sig { params(messages: T::Array[AgUiProtocol::Core::Types::BaseMessage], timestamp: T.nilable(Time), raw_event: T.untyped).void }
655
+ def initialize(messages:, timestamp: nil, raw_event: nil)
656
+ unless messages.is_a?(Array) && messages.all? { |m| m.is_a?(AgUiProtocol::Core::Types::BaseMessage) }
657
+ raise ArgumentError, "messages must be an Array of BaseMessage"
658
+ end
659
+
660
+ super(type: EventType::MESSAGES_SNAPSHOT, timestamp: timestamp, raw_event: raw_event)
661
+ @messages = messages
662
+ end
663
+
664
+ sig { returns(T::Hash[Symbol, T.untyped]) }
665
+ def to_h
666
+ super.merge(messages: @messages)
667
+ end
668
+ end
669
+
670
+ # Delivers a complete snapshot of an activity message.
671
+ #
672
+ # ```ruby
673
+ # event = AgUiProtocol::Core::Events::ActivitySnapshotEvent.new(message_id: "m1", activity_type: "PLAN", content: { "a" => 1 })
674
+ # ```
675
+ #
676
+ # @category State Management Events
677
+ class ActivitySnapshotEvent < BaseEvent
678
+ sig { returns(String) }
679
+ attr_reader :message_id
680
+
681
+ sig { returns(String) }
682
+ attr_reader :activity_type
683
+
684
+ sig { returns(T.untyped) }
685
+ attr_reader :content
686
+
687
+ sig { returns(T::Boolean) }
688
+ attr_reader :replace
689
+
690
+ # @param message_id [String] Identifier for the target `ActivityMessage`
691
+ # @param activity_type [String] Activity discriminator such as `"PLAN"` or `"SEARCH"`
692
+ # @param content [Object] Structured payload describing the full activity state
693
+ # @param replace [Boolean] When `false`, the snapshot is ignored if a message with the same ID already exists
694
+ # @param timestamp [Time] Timestamp when the event was created
695
+ # @param raw_event [Object] Original event data if this event was transformed
696
+ sig do
697
+ params(
698
+ message_id: String,
699
+ activity_type: String,
700
+ content: T.untyped,
701
+ replace: T::Boolean,
702
+ timestamp: T.nilable(Time),
703
+ raw_event: T.untyped
704
+ ).void
705
+ end
706
+ def initialize(message_id:, activity_type:, content:, replace: true, timestamp: nil, raw_event: nil)
707
+ super(type: EventType::ACTIVITY_SNAPSHOT, timestamp: timestamp, raw_event: raw_event)
708
+ @message_id = message_id
709
+ @activity_type = activity_type
710
+ @content = content
711
+ @replace = replace
712
+ end
713
+
714
+ sig { returns(T::Hash[Symbol, T.untyped]) }
715
+ def to_h
716
+ super.merge(
717
+ message_id: @message_id,
718
+ activity_type: @activity_type,
719
+ content: @content,
720
+ replace: @replace
721
+ )
722
+ end
723
+ end
724
+
725
+ # Provides incremental updates to an activity snapshot using JSON Patch.
726
+ #
727
+ # ```ruby
728
+ # event = AgUiProtocol::Core::Events::ActivityDeltaEvent.new(message_id: "m1", activity_type: "PLAN", patch: [{ "op" => "replace", "path" => "/a", "value" => 2 }])
729
+ # ```
730
+ #
731
+ # @category State Management Events
732
+ class ActivityDeltaEvent < BaseEvent
733
+ sig { returns(String) }
734
+ attr_reader :message_id
735
+
736
+ sig { returns(String) }
737
+ attr_reader :activity_type
738
+
739
+ sig { returns(T::Array[T.untyped]) }
740
+ attr_reader :patch
741
+
742
+ # @param message_id [String] Identifier for the target `ActivityMessage`
743
+ # @param activity_type [String] Activity discriminator mirroring the most recent snapshot
744
+ # @param patch [Array<Object>] JSON Patch operations applied to the structured activity content
745
+ # @param timestamp [Time] Timestamp when the event was created
746
+ # @param raw_event [Object] Original event data if this event was transformed
747
+ sig { params(message_id: String, activity_type: String, patch: T.untyped, timestamp: T.nilable(Time), raw_event: T.untyped).void }
748
+ def initialize(message_id:, activity_type:, patch:, timestamp: nil, raw_event: nil)
749
+ super(type: EventType::ACTIVITY_DELTA, timestamp: timestamp, raw_event: raw_event)
750
+ @message_id = message_id
751
+ @activity_type = activity_type
752
+ @patch = patch
753
+ end
754
+
755
+ sig { returns(T::Hash[Symbol, T.untyped]) }
756
+ def to_h
757
+ super.merge(
758
+ message_id: @message_id,
759
+ activity_type: @activity_type,
760
+ patch: @patch
761
+ )
762
+ end
763
+ end
764
+
765
+ # Used to pass through events from external systems.
766
+ #
767
+ # ```ruby
768
+ # event = AgUiProtocol::Core::Events::RawEvent.new(event: { "type" => "my_event", "data" => { "a" => 1 } }, source: "my_source")
769
+ # ```
770
+ #
771
+ # @category Special Events
772
+ class RawEvent < BaseEvent
773
+ sig { returns(T.untyped) }
774
+ attr_reader :event
775
+
776
+ sig { returns(T.nilable(String)) }
777
+ attr_reader :source
778
+
779
+ # @param event [Object] Original event data
780
+ # @param source [String] Source of the event
781
+ # @param timestamp [Time] Timestamp when the event was created
782
+ # @param raw_event [Object] Original event data if this event was transformed
783
+ sig { params(event: T.untyped, source: T.nilable(String), timestamp: T.nilable(Time), raw_event: T.untyped).void }
784
+ def initialize(event:, source: nil, timestamp: nil, raw_event: nil)
785
+ super(type: EventType::RAW, timestamp: timestamp, raw_event: raw_event)
786
+ @event = event
787
+ @source = source
788
+ end
789
+
790
+ sig { returns(T::Hash[Symbol, T.untyped]) }
791
+ def to_h
792
+ super.merge(event: @event, source: @source)
793
+ end
794
+ end
795
+
796
+ # Used for application-specific custom events.
797
+ #
798
+ # ```ruby
799
+ # event = AgUiProtocol::Core::Events::CustomEvent.new(name: "my_event", value: { "a" => 1 })
800
+ # ```
801
+ #
802
+ # @category Special Events
803
+ class CustomEvent < BaseEvent
804
+ sig { returns(String) }
805
+ attr_reader :name
806
+
807
+ sig { returns(T.untyped) }
808
+ attr_reader :value
809
+
810
+ # @param name [String] Name of the custom event
811
+ # @param value [Object] Value of the custom event
812
+ # @param timestamp [Time] Timestamp when the event was created
813
+ # @param raw_event [Object] Original event data if this event was transformed
814
+ sig { params(name: String, value: T.untyped, timestamp: T.nilable(Time), raw_event: T.untyped).void }
815
+ def initialize(name:, value:, timestamp: nil, raw_event: nil)
816
+ super(type: EventType::CUSTOM, timestamp: timestamp, raw_event: raw_event)
817
+ @name = name
818
+ @value = value
819
+ end
820
+
821
+ sig { returns(T::Hash[Symbol, T.untyped]) }
822
+ def to_h
823
+ super.merge(name: @name, value: @value)
824
+ end
825
+ end
826
+
827
+ # Signals the start of an agent run.
828
+ #
829
+ # ```ruby
830
+ #
831
+ # input = AgUiProtocol::Core::Types::RunAgentInput.new(
832
+ # thread_id: "t1",
833
+ # run_id: "r1",
834
+ # state: {},
835
+ # messages: [],
836
+ # tools: [],
837
+ # context: [],
838
+ # forwarded_props: {}
839
+ # )
840
+ #
841
+ # event = AgUiProtocol::Core::Events::RunStartedEvent.new(
842
+ # thread_id: "t1",
843
+ # run_id: "r1",
844
+ # parent_run_id: nil,
845
+ # input: input
846
+ # )
847
+ #
848
+ # ```
849
+ # @category Lifecycle Events
850
+ class RunStartedEvent < BaseEvent
851
+ sig { returns(String) }
852
+ attr_reader :thread_id
853
+
854
+ sig { returns(String) }
855
+ attr_reader :run_id
856
+
857
+ sig { returns(T.nilable(String)) }
858
+ attr_reader :parent_run_id
859
+
860
+ sig { returns(T.nilable(T.untyped)) }
861
+ attr_reader :input
862
+
863
+ # @param thread_id [String] ID of the conversation thread
864
+ # @param run_id [String] ID of the run
865
+ # @param parent_run_id [String] Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread
866
+ # @param input [Object] The exact agent input payload sent to the agent for this run. May omit messages already in history
867
+ sig do
868
+ params(
869
+ thread_id: String,
870
+ run_id: String,
871
+ parent_run_id: T.nilable(String),
872
+ input: T.untyped,
873
+ timestamp: T.nilable(Time),
874
+ raw_event: T.untyped
875
+ ).void
876
+ end
877
+ def initialize(thread_id:, run_id:, parent_run_id: nil, input: nil, timestamp: nil, raw_event: nil)
878
+ super(type: EventType::RUN_STARTED, timestamp: timestamp, raw_event: raw_event)
879
+ @thread_id = thread_id
880
+ @run_id = run_id
881
+ @parent_run_id = parent_run_id
882
+ @input = input
883
+ end
884
+
885
+ sig { returns(T::Hash[Symbol, T.untyped]) }
886
+ def to_h
887
+ super.merge(
888
+ thread_id: @thread_id,
889
+ run_id: @run_id,
890
+ parent_run_id: @parent_run_id,
891
+ input: @input
892
+ )
893
+ end
894
+ end
895
+
896
+ # Signals the successful completion of an agent run.
897
+ #
898
+ # ```ruby
899
+ #
900
+ # event = AgUiProtocol::Core::Events::RunFinishedEvent.new(thread_id: "t1", run_id: "r1", result: { "a" => 1 })
901
+ #
902
+ # ```
903
+ #
904
+ # @category Lifecycle Events
905
+ class RunFinishedEvent < BaseEvent
906
+ sig { returns(String) }
907
+ attr_reader :thread_id
908
+
909
+ sig { returns(String) }
910
+ attr_reader :run_id
911
+
912
+ sig { returns(T.nilable(T.untyped)) }
913
+ attr_reader :result
914
+
915
+ # @param thread_id [String] ID of the conversation thread
916
+ # @param run_id [String] ID of the run
917
+ # @param result [Object] Result data from the agent run
918
+ # @param timestamp [Time] Timestamp when the event was created
919
+ # @param raw_event [Object] Original event data if this event was transformed
920
+ sig { params(thread_id: String, run_id: String, result: T.untyped, timestamp: T.nilable(Time), raw_event: T.untyped).void }
921
+ def initialize(thread_id:, run_id:, result: nil, timestamp: nil, raw_event: nil)
922
+ super(type: EventType::RUN_FINISHED, timestamp: timestamp, raw_event: raw_event)
923
+ @thread_id = thread_id
924
+ @run_id = run_id
925
+ @result = result
926
+ end
927
+
928
+ sig { returns(T::Hash[Symbol, T.untyped]) }
929
+ def to_h
930
+ super.merge(thread_id: @thread_id, run_id: @run_id, result: @result)
931
+ end
932
+ end
933
+
934
+ # Signals an error during an agent run.
935
+ #
936
+ # ```ruby
937
+ #
938
+ # event = AgUiProtocol::Core::Events::RunErrorEvent.new(message: "An error occurred", code: "RUN_ERROR")
939
+ #
940
+ # ```
941
+ #
942
+ # @category Lifecycle Events
943
+ class RunErrorEvent < BaseEvent
944
+ sig { returns(String) }
945
+ attr_reader :message
946
+
947
+ sig { returns(T.nilable(String)) }
948
+ attr_reader :code
949
+
950
+ # @param message [String] Error message
951
+ # @param code [String] Error code
952
+ # @param timestamp [Time] Timestamp when the event was created
953
+ # @param raw_event [Object] Original event data if this event was transformed
954
+ sig { params(message: String, code: T.nilable(String), timestamp: T.nilable(Time), raw_event: T.untyped).void }
955
+ def initialize(message:, code: nil, timestamp: nil, raw_event: nil)
956
+ super(type: EventType::RUN_ERROR, timestamp: timestamp, raw_event: raw_event)
957
+ @message = message
958
+ @code = code
959
+ end
960
+
961
+ sig { returns(T::Hash[Symbol, T.untyped]) }
962
+ def to_h
963
+ super.merge(message: @message, code: @code)
964
+ end
965
+ end
966
+
967
+ # Signals the start of a step within an agent run.
968
+ #
969
+ # ```ruby
970
+ #
971
+ # event = AgUiProtocol::Core::Events::StepStartedEvent.new(step_name: "s1")
972
+ #
973
+ # ```
974
+ #
975
+ # @category Lifecycle Events
976
+ class StepStartedEvent < BaseEvent
977
+ sig { returns(String) }
978
+ attr_reader :step_name
979
+
980
+ # @param step_name [String] Name of the step
981
+ # @param timestamp [Time] Timestamp when the event was created
982
+ # @param raw_event [Object] Original event data if this event was transformed
983
+ sig { params(step_name: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
984
+ def initialize(step_name:, timestamp: nil, raw_event: nil)
985
+ super(type: EventType::STEP_STARTED, timestamp: timestamp, raw_event: raw_event)
986
+ @step_name = step_name
987
+ end
988
+
989
+ sig { returns(T::Hash[Symbol, T.untyped]) }
990
+ def to_h
991
+ super.merge(step_name: @step_name)
992
+ end
993
+ end
994
+
995
+ # Signals the completion of a step within an agent run.
996
+ #
997
+ # ```ruby
998
+ #
999
+ # event = AgUiProtocol::Core::Events::StepFinishedEvent.new(step_name: "s1")
1000
+ #
1001
+ # ```
1002
+ #
1003
+ # @category Lifecycle Events
1004
+ class StepFinishedEvent < BaseEvent
1005
+ sig { returns(String) }
1006
+ attr_reader :step_name
1007
+
1008
+ # @param step_name [String] Name of the step
1009
+ # @param timestamp [Time] Timestamp when the event was created
1010
+ # @param raw_event [Object] Original event data if this event was transformed
1011
+ sig { params(step_name: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
1012
+ def initialize(step_name:, timestamp: nil, raw_event: nil)
1013
+ super(type: EventType::STEP_FINISHED, timestamp: timestamp, raw_event: raw_event)
1014
+ @step_name = step_name
1015
+ end
1016
+
1017
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1018
+ def to_h
1019
+ super.merge(step_name: @step_name)
1020
+ end
1021
+ end
1022
+ end
1023
+ end
1024
+ end