ag-ui-protocol 0.1.5 → 0.2.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.
@@ -22,15 +22,25 @@ module AgUiProtocol
22
22
  #
23
23
  # These events represent the lifecycle of tool calls made by agents.
24
24
  #
25
+ # ## Thinking Events
26
+ #
27
+ # These events represent the lifecycle of an agent's thinking steps, conveying
28
+ # intermediate reasoning to the frontend without contributing to the final message.
29
+ #
30
+ # ## Reasoning Events
31
+ #
32
+ # These events convey structured reasoning blocks emitted by an agent, including
33
+ # streaming reasoning messages and encrypted reasoning values.
34
+ #
25
35
  # ## State Management Events
26
36
  #
27
37
  # These events are used to manage agent state.
28
38
  #
29
39
  module Events
30
40
  # Valid values for the role attribute of a text message.
31
- TEXT_MESSAGE_ROLE_VALUES = ["developer", "system", "assistant", "user"].freeze
41
+ TEXT_MESSAGE_ROLE_VALUES = ["developer", "system", "assistant", "user", "reasoning"].freeze
32
42
 
33
- # The `EventType` module defines all possible event types in the system
43
+ # The `EventType` module defines all possible event types in the system.
34
44
  module EventType
35
45
  TEXT_MESSAGE_START = "TEXT_MESSAGE_START"
36
46
  TEXT_MESSAGE_CONTENT = "TEXT_MESSAGE_CONTENT"
@@ -58,10 +68,19 @@ module AgUiProtocol
58
68
  RUN_ERROR = "RUN_ERROR"
59
69
  STEP_STARTED = "STEP_STARTED"
60
70
  STEP_FINISHED = "STEP_FINISHED"
71
+ REASONING_START = "REASONING_START"
72
+ REASONING_MESSAGE_START = "REASONING_MESSAGE_START"
73
+ REASONING_MESSAGE_CONTENT = "REASONING_MESSAGE_CONTENT"
74
+ REASONING_MESSAGE_END = "REASONING_MESSAGE_END"
75
+ REASONING_MESSAGE_CHUNK = "REASONING_MESSAGE_CHUNK"
76
+ REASONING_END = "REASONING_END"
77
+ REASONING_ENCRYPTED_VALUE = "REASONING_ENCRYPTED_VALUE"
61
78
  end
62
79
 
63
- # All events inherit from the `BaseEvent` class, which provides common properties
64
- # shared across all event types.
80
+ # All event classes inherit from `BaseEvent`, which provides common properties
81
+ # shared across all event types. Value types in this module
82
+ # (RunFinishedSuccessOutcome, RunFinishedInterruptOutcome) inherit directly from
83
+ # `Model` — they are payload types referenced by events, not events themselves.
65
84
  # ```ruby
66
85
  #
67
86
  # event = AgUiProtocol::Core::Events::BaseEvent.new(
@@ -122,13 +141,16 @@ module AgUiProtocol
122
141
  attr_reader :role
123
142
 
124
143
  # @param message_id [String] Unique identifier for the message
144
+ # @param role [String] Must be one of TEXT_MESSAGE_ROLE_VALUES; defaults to "assistant"
125
145
  # @param timestamp [Time] Timestamp when the event was created
126
146
  # @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)
147
+ sig { params(message_id: String, role: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
148
+ def initialize(message_id:, role: "assistant", timestamp: nil, raw_event: nil)
149
+ raise ArgumentError, "role must be one of #{TEXT_MESSAGE_ROLE_VALUES.join(", ")}, got #{role}" unless TEXT_MESSAGE_ROLE_VALUES.include?(role)
150
+
129
151
  super(type: EventType::TEXT_MESSAGE_START, timestamp: timestamp, raw_event: raw_event)
130
152
  @message_id = message_id
131
- @role = 'assistant'
153
+ @role = role
132
154
  end
133
155
 
134
156
  sig { returns(T::Hash[Symbol, T.untyped]) }
@@ -235,18 +257,18 @@ module AgUiProtocol
235
257
  # @param delta [String] Text content chunk
236
258
  # @param timestamp [Time] Timestamp when the event was created
237
259
  # @param raw_event [Object] Original event data if this event was transformed
238
- sig do
260
+ sig do
239
261
  params(
240
262
  message_id: T.nilable(String),
241
263
  role: T.nilable(String),
242
264
  delta: T.nilable(String),
243
265
  timestamp: T.nilable(Time),
244
266
  raw_event: T.untyped,
245
- ).void
267
+ ).void
246
268
  end
247
269
  def initialize(message_id: nil, role: nil, delta: nil, timestamp: nil, raw_event: nil)
248
270
  raise ArgumentError, "role must be one of #{TEXT_MESSAGE_ROLE_VALUES.join(", ")}, got #{role}" if !role.nil? && !TEXT_MESSAGE_ROLE_VALUES.include?(role)
249
-
271
+
250
272
  super(type: EventType::TEXT_MESSAGE_CHUNK, timestamp: timestamp, raw_event: raw_event)
251
273
  @message_id = message_id
252
274
  @role = role
@@ -523,8 +545,8 @@ module AgUiProtocol
523
545
  ).void
524
546
  end
525
547
  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
-
548
+ raise ArgumentError, "role must be \"tool\", got #{role.inspect}" if !role.nil? && role != "tool"
549
+
528
550
  super(type: EventType::TOOL_CALL_RESULT, timestamp: timestamp, raw_event: raw_event)
529
551
  @message_id = message_id
530
552
  @tool_call_id = tool_call_id
@@ -607,7 +629,8 @@ module AgUiProtocol
607
629
 
608
630
  sig { returns(T::Hash[Symbol, T.untyped]) }
609
631
  def to_h
610
- super.merge(snapshot: @snapshot)
632
+ # `snapshot` is the agent's user-defined state object — preserve keys verbatim.
633
+ super.merge(snapshot: @snapshot.nil? ? nil : AgUiProtocol::Util::Opaque.new(@snapshot))
611
634
  end
612
635
  end
613
636
 
@@ -633,14 +656,19 @@ module AgUiProtocol
633
656
 
634
657
  sig { returns(T::Hash[Symbol, T.untyped]) }
635
658
  def to_h
636
- super.merge(delta: @delta)
659
+ # `delta` is an array of JSON Patch ops; each op's `value` may carry
660
+ # arbitrary user-defined keys (RFC 6902). Preserve the array
661
+ # contents verbatim on the wire.
662
+ super.merge(delta: @delta.nil? ? nil : AgUiProtocol::Util::Opaque.new(@delta))
637
663
  end
638
664
  end
639
665
 
640
666
  # Provides a snapshot of all messages in a conversation.
641
667
  #
642
668
  # ```ruby
643
- # event = AgUiProtocol::Core::Events::MessagesSnapshotEvent.new(messages: [{ "id" => "m1", "content" => "hi" }])
669
+ # event = AgUiProtocol::Core::Events::MessagesSnapshotEvent.new(
670
+ # messages: [AgUiProtocol::Core::Types::UserMessage.new(id: "m1", content: "hi")]
671
+ # )
644
672
  # ```
645
673
  #
646
674
  # @category State Management Events
@@ -648,13 +676,13 @@ module AgUiProtocol
648
676
  sig { returns(T::Array[T.untyped]) }
649
677
  attr_reader :messages
650
678
 
651
- # @param messages [Array<AgUiProtocol::Core::Types::BaseMessage>] Array of message objects
679
+ # @param messages [Array<AgUiProtocol::Core::Types::BaseMessage, AgUiProtocol::Core::Types::ActivityMessage>] Array of message objects. Accepts both BaseMessage subclasses and ActivityMessage for parity with RunAgentInput.
652
680
  # @param timestamp [Time] Timestamp when the event was created
653
681
  # @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 }
682
+ sig { params(messages: T::Array[T.any(AgUiProtocol::Core::Types::BaseMessage, AgUiProtocol::Core::Types::ActivityMessage)], timestamp: T.nilable(Time), raw_event: T.untyped).void }
655
683
  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"
684
+ unless messages.is_a?(Array) && messages.all? { |m| m.is_a?(AgUiProtocol::Core::Types::BaseMessage) || m.is_a?(AgUiProtocol::Core::Types::ActivityMessage) }
685
+ raise ArgumentError, "messages must be an Array of BaseMessage or ActivityMessage"
658
686
  end
659
687
 
660
688
  super(type: EventType::MESSAGES_SNAPSHOT, timestamp: timestamp, raw_event: raw_event)
@@ -789,7 +817,8 @@ module AgUiProtocol
789
817
 
790
818
  sig { returns(T::Hash[Symbol, T.untyped]) }
791
819
  def to_h
792
- super.merge(event: @event, source: @source)
820
+ # `event` is the raw upstream event payload — preserve keys verbatim.
821
+ super.merge(event: @event.nil? ? nil : AgUiProtocol::Util::Opaque.new(@event), source: @source)
793
822
  end
794
823
  end
795
824
 
@@ -820,7 +849,8 @@ module AgUiProtocol
820
849
 
821
850
  sig { returns(T::Hash[Symbol, T.untyped]) }
822
851
  def to_h
823
- super.merge(name: @name, value: @value)
852
+ # `value` is an application-specific payload — preserve keys verbatim.
853
+ super.merge(name: @name, value: @value.nil? ? nil : AgUiProtocol::Util::Opaque.new(@value))
824
854
  end
825
855
  end
826
856
 
@@ -864,6 +894,8 @@ module AgUiProtocol
864
894
  # @param run_id [String] ID of the run
865
895
  # @param parent_run_id [String] Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread
866
896
  # @param input [Object] The exact agent input payload sent to the agent for this run. May omit messages already in history
897
+ # @param timestamp [Time, nil] Timestamp when the event was created
898
+ # @param raw_event [Object, nil] Original event data if this event was transformed
867
899
  sig do
868
900
  params(
869
901
  thread_id: String,
@@ -893,7 +925,74 @@ module AgUiProtocol
893
925
  end
894
926
  end
895
927
 
896
- # Signals the successful completion of an agent run.
928
+ # Represents a successful outcome for a run.
929
+ #
930
+ # The `type` discriminator is enforced — only "success" is accepted (or nil for default).
931
+ # The optional `type:` kwarg exists to support round-trip deserialization from `to_h`
932
+ # output (which emits `type: "success"`); supplying any other value raises ArgumentError.
933
+ #
934
+ # ```ruby
935
+ # outcome = AgUiProtocol::Core::Events::RunFinishedSuccessOutcome.new
936
+ # ```
937
+ class RunFinishedSuccessOutcome < AgUiProtocol::Core::Types::Model
938
+ sig { returns(String) }
939
+ attr_reader :type
940
+
941
+ # @param type [String, nil] Optional. Must be "success" if provided. Always stored as "success"; the kwarg exists to support round-trip deserialization from `to_h` output.
942
+ sig { params(type: T.nilable(String)).void }
943
+ def initialize(type: nil)
944
+ if !type.nil? && type != "success"
945
+ raise ArgumentError, "RunFinishedSuccessOutcome.type must be \"success\""
946
+ end
947
+
948
+ @type = "success"
949
+ end
950
+
951
+ sig { returns(T::Hash[Symbol, T.untyped]) }
952
+ def to_h
953
+ { type: @type }
954
+ end
955
+ end
956
+
957
+ # Represents an interrupt outcome for a run.
958
+ #
959
+ # ```ruby
960
+ # outcome = AgUiProtocol::Core::Events::RunFinishedInterruptOutcome.new(
961
+ # interrupts: [
962
+ # AgUiProtocol::Core::Types::Interrupt.new(id: "int_1", reason: "input_required")
963
+ # ]
964
+ # )
965
+ # ```
966
+ class RunFinishedInterruptOutcome < AgUiProtocol::Core::Types::Model
967
+ sig { returns(String) }
968
+ attr_reader :type
969
+
970
+ sig { returns(T::Array[AgUiProtocol::Core::Types::Interrupt]) }
971
+ attr_reader :interrupts
972
+
973
+ # @param interrupts [Array<AgUiProtocol::Core::Types::Interrupt>] List of interrupts
974
+ # @param type [String, nil] Optional. Must be "interrupt" if provided. Always stored as "interrupt"; the kwarg exists to support round-trip deserialization from `to_h` output.
975
+ sig { params(interrupts: T::Array[AgUiProtocol::Core::Types::Interrupt], type: T.nilable(String)).void }
976
+ def initialize(interrupts:, type: nil)
977
+ unless interrupts.is_a?(Array) && interrupts.all? { |i| i.is_a?(AgUiProtocol::Core::Types::Interrupt) }
978
+ raise ArgumentError, "interrupts must be an Array of Interrupt"
979
+ end
980
+
981
+ if !type.nil? && type != "interrupt"
982
+ raise ArgumentError, "RunFinishedInterruptOutcome.type must be \"interrupt\""
983
+ end
984
+
985
+ @type = "interrupt"
986
+ @interrupts = interrupts
987
+ end
988
+
989
+ sig { returns(T::Hash[Symbol, T.untyped]) }
990
+ def to_h
991
+ { type: @type, interrupts: @interrupts }
992
+ end
993
+ end
994
+
995
+ # Signals the completion of an agent run. The `outcome` field discriminates between success and interrupt: provide either a `RunFinishedSuccessOutcome` or `RunFinishedInterruptOutcome` (or use the legacy `result` field; the two are mutually exclusive).
897
996
  #
898
997
  # ```ruby
899
998
  #
@@ -912,22 +1011,41 @@ module AgUiProtocol
912
1011
  sig { returns(T.untyped) }
913
1012
  attr_reader :result
914
1013
 
1014
+ sig { returns(T.nilable(T.any(RunFinishedSuccessOutcome, RunFinishedInterruptOutcome))) }
1015
+ attr_reader :outcome
1016
+
915
1017
  # @param thread_id [String] ID of the conversation thread
916
1018
  # @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)
1019
+ # @param result [Object] Result data from the agent run. Mutually exclusive with `outcome`.
1020
+ # @param outcome [RunFinishedSuccessOutcome, RunFinishedInterruptOutcome] Outcome of the run. Mutually exclusive with `result`.
1021
+ # @param timestamp [Time] Timestamp when the event was created
1022
+ # @param raw_event [Object] Original event data if this event was transformed
1023
+ # @raise [ArgumentError] when both `result` and `outcome` are non-nil. Callers must choose one.
1024
+ sig do
1025
+ params(
1026
+ thread_id: String,
1027
+ run_id: String,
1028
+ result: T.untyped,
1029
+ outcome: T.nilable(T.any(RunFinishedSuccessOutcome, RunFinishedInterruptOutcome)),
1030
+ timestamp: T.nilable(Time),
1031
+ raw_event: T.untyped
1032
+ ).void
1033
+ end
1034
+ def initialize(thread_id:, run_id:, result: nil, outcome: nil, timestamp: nil, raw_event: nil)
1035
+ if !result.nil? && !outcome.nil?
1036
+ raise ArgumentError, "result and outcome are mutually exclusive; provide one or the other, not both"
1037
+ end
1038
+
922
1039
  super(type: EventType::RUN_FINISHED, timestamp: timestamp, raw_event: raw_event)
923
1040
  @thread_id = thread_id
924
1041
  @run_id = run_id
925
1042
  @result = result
1043
+ @outcome = outcome
926
1044
  end
927
1045
 
928
1046
  sig { returns(T::Hash[Symbol, T.untyped]) }
929
1047
  def to_h
930
- super.merge(thread_id: @thread_id, run_id: @run_id, result: @result)
1048
+ super.merge(thread_id: @thread_id, run_id: @run_id, result: @result, outcome: @outcome)
931
1049
  end
932
1050
  end
933
1051
 
@@ -1019,6 +1137,245 @@ module AgUiProtocol
1019
1137
  super.merge(step_name: @step_name)
1020
1138
  end
1021
1139
  end
1140
+
1141
+ # Signals the start of a reasoning block.
1142
+ #
1143
+ # ```ruby
1144
+ # event = AgUiProtocol::Core::Events::ReasoningStartEvent.new(message_id: "reason_1")
1145
+ # ```
1146
+ #
1147
+ # @category Reasoning Events
1148
+ class ReasoningStartEvent < BaseEvent
1149
+ sig { returns(String) }
1150
+ attr_reader :message_id
1151
+
1152
+ # @param message_id [String] Unique identifier for the reasoning message
1153
+ # @param timestamp [Time] Timestamp when the event was created
1154
+ # @param raw_event [Object] Original event data if this event was transformed
1155
+ sig { params(message_id: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
1156
+ def initialize(message_id:, timestamp: nil, raw_event: nil)
1157
+ super(type: EventType::REASONING_START, timestamp: timestamp, raw_event: raw_event)
1158
+ @message_id = message_id
1159
+ end
1160
+
1161
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1162
+ def to_h
1163
+ super.merge(message_id: @message_id)
1164
+ end
1165
+ end
1166
+
1167
+ # Signals the start of a reasoning message within a reasoning block.
1168
+ #
1169
+ # The `role` is always "reasoning" (enforced). The optional `role:` kwarg exists
1170
+ # to support round-trip deserialization from `to_h` output (which emits
1171
+ # `role: "reasoning"`); supplying any other value raises ArgumentError.
1172
+ #
1173
+ # ```ruby
1174
+ # event = AgUiProtocol::Core::Events::ReasoningMessageStartEvent.new(message_id: "reason_msg_1")
1175
+ # ```
1176
+ #
1177
+ # @category Reasoning Events
1178
+ class ReasoningMessageStartEvent < BaseEvent
1179
+ sig { returns(String) }
1180
+ attr_reader :message_id
1181
+
1182
+ sig { returns(String) }
1183
+ attr_reader :role
1184
+
1185
+ # @param message_id [String] Unique identifier
1186
+ # @param role [String, nil] Optional. Must be "reasoning" if provided. Always stored as "reasoning"; the kwarg exists to support round-trip deserialization from `to_h` output.
1187
+ # @param timestamp [Time] Timestamp when the event was created
1188
+ # @param raw_event [Object] Original event data if this event was transformed
1189
+ sig { params(message_id: String, role: T.nilable(String), timestamp: T.nilable(Time), raw_event: T.untyped).void }
1190
+ def initialize(message_id:, role: nil, timestamp: nil, raw_event: nil)
1191
+ if !role.nil? && role != "reasoning"
1192
+ raise ArgumentError, "ReasoningMessageStartEvent.role must be \"reasoning\""
1193
+ end
1194
+
1195
+ super(type: EventType::REASONING_MESSAGE_START, timestamp: timestamp, raw_event: raw_event)
1196
+ @message_id = message_id
1197
+ # Role is always "reasoning" for ReasoningMessageStartEvent.
1198
+ @role = "reasoning"
1199
+ end
1200
+
1201
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1202
+ def to_h
1203
+ super.merge(message_id: @message_id, role: @role)
1204
+ end
1205
+ end
1206
+
1207
+ # Represents a chunk of content in a streaming reasoning message.
1208
+ #
1209
+ # ```ruby
1210
+ # event = AgUiProtocol::Core::Events::ReasoningMessageContentEvent.new(message_id: "reason_msg_1", delta: "step 1...")
1211
+ # ```
1212
+ #
1213
+ # @category Reasoning Events
1214
+ class ReasoningMessageContentEvent < BaseEvent
1215
+ sig { returns(String) }
1216
+ attr_reader :message_id
1217
+
1218
+ sig { returns(String) }
1219
+ attr_reader :delta
1220
+
1221
+ # @param message_id [String] Matches the ID from ReasoningMessageStartEvent
1222
+ # @param delta [String] Reasoning content chunk
1223
+ # @param timestamp [Time] Timestamp when the event was created
1224
+ # @param raw_event [Object] Original event data if this event was transformed
1225
+ sig { params(message_id: String, delta: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
1226
+ def initialize(message_id:, delta:, timestamp: nil, raw_event: nil)
1227
+ super(type: EventType::REASONING_MESSAGE_CONTENT, timestamp: timestamp, raw_event: raw_event)
1228
+ @message_id = message_id
1229
+ @delta = delta
1230
+ end
1231
+
1232
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1233
+ def to_h
1234
+ super.merge(message_id: @message_id, delta: @delta)
1235
+ end
1236
+ end
1237
+
1238
+ # Signals the end of a reasoning message.
1239
+ #
1240
+ # ```ruby
1241
+ # event = AgUiProtocol::Core::Events::ReasoningMessageEndEvent.new(message_id: "reason_msg_1")
1242
+ # ```
1243
+ #
1244
+ # @category Reasoning Events
1245
+ class ReasoningMessageEndEvent < BaseEvent
1246
+ sig { returns(String) }
1247
+ attr_reader :message_id
1248
+
1249
+ # @param message_id [String] Matches the ID from ReasoningMessageStartEvent
1250
+ # @param timestamp [Time] Timestamp when the event was created
1251
+ # @param raw_event [Object] Original event data if this event was transformed
1252
+ sig { params(message_id: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
1253
+ def initialize(message_id:, timestamp: nil, raw_event: nil)
1254
+ super(type: EventType::REASONING_MESSAGE_END, timestamp: timestamp, raw_event: raw_event)
1255
+ @message_id = message_id
1256
+ end
1257
+
1258
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1259
+ def to_h
1260
+ super.merge(message_id: @message_id)
1261
+ end
1262
+ end
1263
+
1264
+ # Convenience event for reasoning messages without manually emitting start/end.
1265
+ #
1266
+ # ```ruby
1267
+ # event = AgUiProtocol::Core::Events::ReasoningMessageChunkEvent.new(
1268
+ # message_id: "reason_msg_1",
1269
+ # delta: "step 1..."
1270
+ # )
1271
+ # ```
1272
+ #
1273
+ # @category Reasoning Events
1274
+ class ReasoningMessageChunkEvent < BaseEvent
1275
+ sig { returns(T.nilable(String)) }
1276
+ attr_reader :message_id
1277
+
1278
+ sig { returns(T.nilable(String)) }
1279
+ attr_reader :delta
1280
+
1281
+ # @param message_id [String] Optional on first chunk
1282
+ # @param delta [String] Optional reasoning content chunk
1283
+ # @param timestamp [Time] Timestamp when the event was created
1284
+ # @param raw_event [Object] Original event data if this event was transformed
1285
+ sig do
1286
+ params(
1287
+ message_id: T.nilable(String),
1288
+ delta: T.nilable(String),
1289
+ timestamp: T.nilable(Time),
1290
+ raw_event: T.untyped
1291
+ ).void
1292
+ end
1293
+ def initialize(message_id: nil, delta: nil, timestamp: nil, raw_event: nil)
1294
+ super(type: EventType::REASONING_MESSAGE_CHUNK, timestamp: timestamp, raw_event: raw_event)
1295
+ @message_id = message_id
1296
+ @delta = delta
1297
+ end
1298
+
1299
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1300
+ def to_h
1301
+ super.merge(message_id: @message_id, delta: @delta)
1302
+ end
1303
+ end
1304
+
1305
+ # Signals the end of a reasoning block.
1306
+ #
1307
+ # ```ruby
1308
+ # event = AgUiProtocol::Core::Events::ReasoningEndEvent.new(message_id: "reason_1")
1309
+ # ```
1310
+ #
1311
+ # @category Reasoning Events
1312
+ class ReasoningEndEvent < BaseEvent
1313
+ sig { returns(String) }
1314
+ attr_reader :message_id
1315
+
1316
+ # @param message_id [String] Matches the ID from ReasoningStartEvent
1317
+ # @param timestamp [Time] Timestamp when the event was created
1318
+ # @param raw_event [Object] Original event data if this event was transformed
1319
+ sig { params(message_id: String, timestamp: T.nilable(Time), raw_event: T.untyped).void }
1320
+ def initialize(message_id:, timestamp: nil, raw_event: nil)
1321
+ super(type: EventType::REASONING_END, timestamp: timestamp, raw_event: raw_event)
1322
+ @message_id = message_id
1323
+ end
1324
+
1325
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1326
+ def to_h
1327
+ super.merge(message_id: @message_id)
1328
+ end
1329
+ end
1330
+
1331
+ # Event containing an encrypted value within a reasoning block.
1332
+ #
1333
+ # ```ruby
1334
+ # event = AgUiProtocol::Core::Events::ReasoningEncryptedValueEvent.new(
1335
+ # subtype: "tool-call",
1336
+ # entity_id: "tc_1",
1337
+ # encrypted_value: "encrypted..."
1338
+ # )
1339
+ # ```
1340
+ #
1341
+ # @category Reasoning Events
1342
+ class ReasoningEncryptedValueEvent < BaseEvent
1343
+ sig { returns(String) }
1344
+ attr_reader :subtype
1345
+
1346
+ sig { returns(String) }
1347
+ attr_reader :entity_id
1348
+
1349
+ sig { returns(String) }
1350
+ attr_reader :encrypted_value
1351
+
1352
+ # @param subtype [String] free-form string; protocol values are "tool-call" or "message" but not enforced by this SDK
1353
+ # @param entity_id [String] ID of the entity being encrypted
1354
+ # @param encrypted_value [String] The encrypted value
1355
+ # @param timestamp [Time] Timestamp when the event was created
1356
+ # @param raw_event [Object] Original event data if this event was transformed
1357
+ sig do
1358
+ params(
1359
+ subtype: String,
1360
+ entity_id: String,
1361
+ encrypted_value: String,
1362
+ timestamp: T.nilable(Time),
1363
+ raw_event: T.untyped
1364
+ ).void
1365
+ end
1366
+ def initialize(subtype:, entity_id:, encrypted_value:, timestamp: nil, raw_event: nil)
1367
+ super(type: EventType::REASONING_ENCRYPTED_VALUE, timestamp: timestamp, raw_event: raw_event)
1368
+ @subtype = subtype
1369
+ @entity_id = entity_id
1370
+ @encrypted_value = encrypted_value
1371
+ end
1372
+
1373
+ sig { returns(T::Hash[Symbol, T.untyped]) }
1374
+ def to_h
1375
+ super.merge(subtype: @subtype, entity_id: @entity_id, encrypted_value: @encrypted_value)
1376
+ end
1377
+ end
1378
+
1022
1379
  end
1023
1380
  end
1024
1381
  end