signalwire-sdk 2.0.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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +259 -0
  4. data/bin/swaig-test +872 -0
  5. data/lib/signalwire/agent/agent_base.rb +2134 -0
  6. data/lib/signalwire/contexts/context_builder.rb +861 -0
  7. data/lib/signalwire/core/logging_config.rb +54 -0
  8. data/lib/signalwire/datamap/data_map.rb +315 -0
  9. data/lib/signalwire/logging.rb +92 -0
  10. data/lib/signalwire/pom/prompt_object_model.rb +269 -0
  11. data/lib/signalwire/pom/section.rb +202 -0
  12. data/lib/signalwire/prefabs/concierge.rb +92 -0
  13. data/lib/signalwire/prefabs/faq_bot.rb +67 -0
  14. data/lib/signalwire/prefabs/info_gatherer.rb +79 -0
  15. data/lib/signalwire/prefabs/receptionist.rb +74 -0
  16. data/lib/signalwire/prefabs/survey.rb +75 -0
  17. data/lib/signalwire/relay/action.rb +291 -0
  18. data/lib/signalwire/relay/call.rb +523 -0
  19. data/lib/signalwire/relay/client.rb +789 -0
  20. data/lib/signalwire/relay/constants.rb +124 -0
  21. data/lib/signalwire/relay/message.rb +137 -0
  22. data/lib/signalwire/relay/relay_event.rb +670 -0
  23. data/lib/signalwire/rest/http_client.rb +159 -0
  24. data/lib/signalwire/rest/namespaces/addresses.rb +19 -0
  25. data/lib/signalwire/rest/namespaces/calling.rb +179 -0
  26. data/lib/signalwire/rest/namespaces/chat.rb +18 -0
  27. data/lib/signalwire/rest/namespaces/compat.rb +229 -0
  28. data/lib/signalwire/rest/namespaces/datasphere.rb +39 -0
  29. data/lib/signalwire/rest/namespaces/fabric.rb +235 -0
  30. data/lib/signalwire/rest/namespaces/imported_numbers.rb +18 -0
  31. data/lib/signalwire/rest/namespaces/logs.rb +46 -0
  32. data/lib/signalwire/rest/namespaces/lookup.rb +18 -0
  33. data/lib/signalwire/rest/namespaces/mfa.rb +26 -0
  34. data/lib/signalwire/rest/namespaces/number_groups.rb +32 -0
  35. data/lib/signalwire/rest/namespaces/phone_numbers.rb +124 -0
  36. data/lib/signalwire/rest/namespaces/project.rb +33 -0
  37. data/lib/signalwire/rest/namespaces/pubsub.rb +18 -0
  38. data/lib/signalwire/rest/namespaces/queues.rb +28 -0
  39. data/lib/signalwire/rest/namespaces/recordings.rb +18 -0
  40. data/lib/signalwire/rest/namespaces/registry.rb +67 -0
  41. data/lib/signalwire/rest/namespaces/short_codes.rb +26 -0
  42. data/lib/signalwire/rest/namespaces/sip_profile.rb +22 -0
  43. data/lib/signalwire/rest/namespaces/verified_callers.rb +24 -0
  44. data/lib/signalwire/rest/namespaces/video.rb +129 -0
  45. data/lib/signalwire/rest/pagination.rb +89 -0
  46. data/lib/signalwire/rest/phone_call_handler.rb +56 -0
  47. data/lib/signalwire/rest/rest_client.rb +114 -0
  48. data/lib/signalwire/runtime.rb +98 -0
  49. data/lib/signalwire/security/session_manager.rb +124 -0
  50. data/lib/signalwire/security/webhook_middleware.rb +191 -0
  51. data/lib/signalwire/security/webhook_validator.rb +327 -0
  52. data/lib/signalwire/server/agent_server.rb +413 -0
  53. data/lib/signalwire/serverless/lambda_handler.rb +251 -0
  54. data/lib/signalwire/skills/builtin/api_ninjas_trivia.rb +99 -0
  55. data/lib/signalwire/skills/builtin/claude_skills.rb +92 -0
  56. data/lib/signalwire/skills/builtin/custom_skills.rb +54 -0
  57. data/lib/signalwire/skills/builtin/datasphere.rb +153 -0
  58. data/lib/signalwire/skills/builtin/datasphere_serverless.rb +107 -0
  59. data/lib/signalwire/skills/builtin/datetime.rb +97 -0
  60. data/lib/signalwire/skills/builtin/google_maps.rb +168 -0
  61. data/lib/signalwire/skills/builtin/info_gatherer.rb +189 -0
  62. data/lib/signalwire/skills/builtin/joke.rb +65 -0
  63. data/lib/signalwire/skills/builtin/math.rb +176 -0
  64. data/lib/signalwire/skills/builtin/mcp_gateway.rb +121 -0
  65. data/lib/signalwire/skills/builtin/native_vector_search.rb +116 -0
  66. data/lib/signalwire/skills/builtin/play_background_file.rb +86 -0
  67. data/lib/signalwire/skills/builtin/spider.rb +169 -0
  68. data/lib/signalwire/skills/builtin/swml_transfer.rb +118 -0
  69. data/lib/signalwire/skills/builtin/weather_api.rb +92 -0
  70. data/lib/signalwire/skills/builtin/web_search.rb +141 -0
  71. data/lib/signalwire/skills/builtin/wikipedia_search.rb +125 -0
  72. data/lib/signalwire/skills/skill_base.rb +82 -0
  73. data/lib/signalwire/skills/skill_manager.rb +97 -0
  74. data/lib/signalwire/skills/skill_registry.rb +258 -0
  75. data/lib/signalwire/swaig/function_result.rb +777 -0
  76. data/lib/signalwire/swml/document.rb +84 -0
  77. data/lib/signalwire/swml/schema.json +12250 -0
  78. data/lib/signalwire/swml/schema.rb +81 -0
  79. data/lib/signalwire/swml/service.rb +650 -0
  80. data/lib/signalwire/utils/schema_utils.rb +298 -0
  81. data/lib/signalwire/utils/serverless.rb +19 -0
  82. data/lib/signalwire/utils/url_validator.rb +138 -0
  83. data/lib/signalwire/version.rb +5 -0
  84. data/lib/signalwire.rb +114 -0
  85. metadata +225 -0
@@ -0,0 +1,670 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module Relay
5
+ # Base event wrapper for raw signalwire.event payloads.
6
+ # Subclasses provide typed accessors for specific event types.
7
+ class RelayEvent
8
+ attr_reader :event_type, :params, :call_id, :timestamp
9
+
10
+ def initialize(event_type:, params: {}, call_id: '', timestamp: 0.0)
11
+ @event_type = event_type
12
+ @params = params
13
+ @call_id = call_id
14
+ @timestamp = timestamp
15
+ end
16
+
17
+ def self.from_payload(payload)
18
+ et = payload['event_type'] || ''
19
+ p = payload['params'] || {}
20
+ new(
21
+ event_type: et,
22
+ params: p,
23
+ call_id: p['call_id'] || '',
24
+ timestamp: p['timestamp'] || 0.0
25
+ )
26
+ end
27
+ end
28
+
29
+ # calling.call.state
30
+ class CallStateEvent < RelayEvent
31
+ attr_reader :call_state, :end_reason, :direction, :device
32
+
33
+ def self.from_payload(payload)
34
+ base = RelayEvent.from_payload(payload)
35
+ p = base.params
36
+ new(
37
+ event_type: base.event_type, params: base.params,
38
+ call_id: base.call_id, timestamp: base.timestamp,
39
+ call_state: p['call_state'] || '',
40
+ end_reason: p['end_reason'] || '',
41
+ direction: p['direction'] || '',
42
+ device: p['device'] || {}
43
+ )
44
+ end
45
+
46
+ def initialize(call_state: '', end_reason: '', direction: '', device: {}, **base)
47
+ super(**base)
48
+ @call_state = call_state
49
+ @end_reason = end_reason
50
+ @direction = direction
51
+ @device = device
52
+ end
53
+ end
54
+
55
+ # calling.call.receive
56
+ class CallReceiveEvent < RelayEvent
57
+ attr_reader :call_state, :direction, :device, :node_id, :project_id,
58
+ :context, :segment_id, :tag
59
+
60
+ def self.from_payload(payload)
61
+ base = RelayEvent.from_payload(payload)
62
+ p = base.params
63
+ new(
64
+ event_type: base.event_type, params: base.params,
65
+ call_id: base.call_id, timestamp: base.timestamp,
66
+ call_state: p['call_state'] || '',
67
+ direction: p['direction'] || '',
68
+ device: p['device'] || {},
69
+ node_id: p['node_id'] || '',
70
+ project_id: p['project_id'] || '',
71
+ context: p['context'] || p['protocol'] || '',
72
+ segment_id: p['segment_id'] || '',
73
+ tag: p['tag'] || ''
74
+ )
75
+ end
76
+
77
+ def initialize(call_state: '', direction: '', device: {}, node_id: '',
78
+ project_id: '', context: '', segment_id: '', tag: '', **base)
79
+ super(**base)
80
+ @call_state = call_state
81
+ @direction = direction
82
+ @device = device
83
+ @node_id = node_id
84
+ @project_id = project_id
85
+ @context = context
86
+ @segment_id = segment_id
87
+ @tag = tag
88
+ end
89
+ end
90
+
91
+ # calling.call.play
92
+ class PlayEvent < RelayEvent
93
+ attr_reader :control_id, :state
94
+
95
+ def self.from_payload(payload)
96
+ base = RelayEvent.from_payload(payload)
97
+ p = base.params
98
+ new(
99
+ event_type: base.event_type, params: base.params,
100
+ call_id: base.call_id, timestamp: base.timestamp,
101
+ control_id: p['control_id'] || '',
102
+ state: p['state'] || ''
103
+ )
104
+ end
105
+
106
+ def initialize(control_id: '', state: '', **base)
107
+ super(**base)
108
+ @control_id = control_id
109
+ @state = state
110
+ end
111
+ end
112
+
113
+ # calling.call.record
114
+ class RecordEvent < RelayEvent
115
+ attr_reader :control_id, :state, :url, :duration, :size, :record
116
+
117
+ def self.from_payload(payload)
118
+ base = RelayEvent.from_payload(payload)
119
+ p = base.params
120
+ rec = p['record'] || {}
121
+ new(
122
+ event_type: base.event_type, params: base.params,
123
+ call_id: base.call_id, timestamp: base.timestamp,
124
+ control_id: p['control_id'] || '',
125
+ state: p['state'] || '',
126
+ url: rec['url'] || p['url'] || '',
127
+ duration: rec['duration'] || p['duration'] || 0.0,
128
+ size: rec['size'] || p['size'] || 0,
129
+ record: rec
130
+ )
131
+ end
132
+
133
+ def initialize(control_id: '', state: '', url: '', duration: 0.0, size: 0, record: {}, **base)
134
+ super(**base)
135
+ @control_id = control_id
136
+ @state = state
137
+ @url = url
138
+ @duration = duration
139
+ @size = size
140
+ @record = record
141
+ end
142
+ end
143
+
144
+ # calling.call.collect
145
+ class CollectEvent < RelayEvent
146
+ attr_reader :control_id, :state, :result_data, :final
147
+
148
+ def self.from_payload(payload)
149
+ base = RelayEvent.from_payload(payload)
150
+ p = base.params
151
+ new(
152
+ event_type: base.event_type, params: base.params,
153
+ call_id: base.call_id, timestamp: base.timestamp,
154
+ control_id: p['control_id'] || '',
155
+ state: p['state'] || '',
156
+ result_data: p['result'] || {},
157
+ final: p['final']
158
+ )
159
+ end
160
+
161
+ def initialize(control_id: '', state: '', result_data: {}, final: nil, **base)
162
+ super(**base)
163
+ @control_id = control_id
164
+ @state = state
165
+ @result_data = result_data
166
+ @final = final
167
+ end
168
+ end
169
+
170
+ # calling.call.connect
171
+ class ConnectEvent < RelayEvent
172
+ attr_reader :connect_state, :peer
173
+
174
+ def self.from_payload(payload)
175
+ base = RelayEvent.from_payload(payload)
176
+ p = base.params
177
+ new(
178
+ event_type: base.event_type, params: base.params,
179
+ call_id: base.call_id, timestamp: base.timestamp,
180
+ connect_state: p['connect_state'] || '',
181
+ peer: p['peer'] || {}
182
+ )
183
+ end
184
+
185
+ def initialize(connect_state: '', peer: {}, **base)
186
+ super(**base)
187
+ @connect_state = connect_state
188
+ @peer = peer
189
+ end
190
+ end
191
+
192
+ # calling.call.detect
193
+ class DetectEvent < RelayEvent
194
+ attr_reader :control_id, :detect
195
+
196
+ def self.from_payload(payload)
197
+ base = RelayEvent.from_payload(payload)
198
+ p = base.params
199
+ new(
200
+ event_type: base.event_type, params: base.params,
201
+ call_id: base.call_id, timestamp: base.timestamp,
202
+ control_id: p['control_id'] || '',
203
+ detect: p['detect'] || {}
204
+ )
205
+ end
206
+
207
+ def initialize(control_id: '', detect: {}, **base)
208
+ super(**base)
209
+ @control_id = control_id
210
+ @detect = detect
211
+ end
212
+ end
213
+
214
+ # calling.call.fax
215
+ class FaxEvent < RelayEvent
216
+ attr_reader :control_id, :fax
217
+
218
+ def self.from_payload(payload)
219
+ base = RelayEvent.from_payload(payload)
220
+ p = base.params
221
+ new(
222
+ event_type: base.event_type, params: base.params,
223
+ call_id: base.call_id, timestamp: base.timestamp,
224
+ control_id: p['control_id'] || '',
225
+ fax: p['fax'] || {}
226
+ )
227
+ end
228
+
229
+ def initialize(control_id: '', fax: {}, **base)
230
+ super(**base)
231
+ @control_id = control_id
232
+ @fax = fax
233
+ end
234
+ end
235
+
236
+ # calling.call.tap
237
+ class TapEvent < RelayEvent
238
+ attr_reader :control_id, :state, :tap, :device
239
+
240
+ def self.from_payload(payload)
241
+ base = RelayEvent.from_payload(payload)
242
+ p = base.params
243
+ new(
244
+ event_type: base.event_type, params: base.params,
245
+ call_id: base.call_id, timestamp: base.timestamp,
246
+ control_id: p['control_id'] || '',
247
+ state: p['state'] || '',
248
+ tap: p['tap'] || {},
249
+ device: p['device'] || {}
250
+ )
251
+ end
252
+
253
+ def initialize(control_id: '', state: '', tap: {}, device: {}, **base)
254
+ super(**base)
255
+ @control_id = control_id
256
+ @state = state
257
+ @tap = tap
258
+ @device = device
259
+ end
260
+ end
261
+
262
+ # calling.call.stream
263
+ class StreamEvent < RelayEvent
264
+ attr_reader :control_id, :state, :url, :name
265
+
266
+ def self.from_payload(payload)
267
+ base = RelayEvent.from_payload(payload)
268
+ p = base.params
269
+ new(
270
+ event_type: base.event_type, params: base.params,
271
+ call_id: base.call_id, timestamp: base.timestamp,
272
+ control_id: p['control_id'] || '',
273
+ state: p['state'] || '',
274
+ url: p['url'] || '',
275
+ name: p['name'] || ''
276
+ )
277
+ end
278
+
279
+ def initialize(control_id: '', state: '', url: '', name: '', **base)
280
+ super(**base)
281
+ @control_id = control_id
282
+ @state = state
283
+ @url = url
284
+ @name = name
285
+ end
286
+ end
287
+
288
+ # calling.call.send_digits
289
+ class SendDigitsEvent < RelayEvent
290
+ attr_reader :control_id, :state
291
+
292
+ def self.from_payload(payload)
293
+ base = RelayEvent.from_payload(payload)
294
+ p = base.params
295
+ new(
296
+ event_type: base.event_type, params: base.params,
297
+ call_id: base.call_id, timestamp: base.timestamp,
298
+ control_id: p['control_id'] || '',
299
+ state: p['state'] || ''
300
+ )
301
+ end
302
+
303
+ def initialize(control_id: '', state: '', **base)
304
+ super(**base)
305
+ @control_id = control_id
306
+ @state = state
307
+ end
308
+ end
309
+
310
+ # calling.call.dial
311
+ class DialEvent < RelayEvent
312
+ attr_reader :tag, :dial_state, :call_data
313
+
314
+ def self.from_payload(payload)
315
+ base = RelayEvent.from_payload(payload)
316
+ p = base.params
317
+ new(
318
+ event_type: base.event_type, params: base.params,
319
+ call_id: base.call_id, timestamp: base.timestamp,
320
+ tag: p['tag'] || '',
321
+ dial_state: p['dial_state'] || '',
322
+ call_data: p['call'] || {}
323
+ )
324
+ end
325
+
326
+ def initialize(tag: '', dial_state: '', call_data: {}, **base)
327
+ super(**base)
328
+ @tag = tag
329
+ @dial_state = dial_state
330
+ @call_data = call_data
331
+ end
332
+ end
333
+
334
+ # calling.call.refer
335
+ class ReferEvent < RelayEvent
336
+ attr_reader :state, :sip_refer_to, :sip_refer_response_code,
337
+ :sip_notify_response_code
338
+
339
+ def self.from_payload(payload)
340
+ base = RelayEvent.from_payload(payload)
341
+ p = base.params
342
+ new(
343
+ event_type: base.event_type, params: base.params,
344
+ call_id: base.call_id, timestamp: base.timestamp,
345
+ state: p['state'] || '',
346
+ sip_refer_to: p['sip_refer_to'] || '',
347
+ sip_refer_response_code: p['sip_refer_response_code'] || '',
348
+ sip_notify_response_code: p['sip_notify_response_code'] || ''
349
+ )
350
+ end
351
+
352
+ def initialize(state: '', sip_refer_to: '', sip_refer_response_code: '',
353
+ sip_notify_response_code: '', **base)
354
+ super(**base)
355
+ @state = state
356
+ @sip_refer_to = sip_refer_to
357
+ @sip_refer_response_code = sip_refer_response_code
358
+ @sip_notify_response_code = sip_notify_response_code
359
+ end
360
+ end
361
+
362
+ # calling.call.denoise
363
+ class DenoiseEvent < RelayEvent
364
+ attr_reader :denoised
365
+
366
+ def self.from_payload(payload)
367
+ base = RelayEvent.from_payload(payload)
368
+ p = base.params
369
+ new(
370
+ event_type: base.event_type, params: base.params,
371
+ call_id: base.call_id, timestamp: base.timestamp,
372
+ denoised: p['denoised'] || false
373
+ )
374
+ end
375
+
376
+ def initialize(denoised: false, **base)
377
+ super(**base)
378
+ @denoised = denoised
379
+ end
380
+ end
381
+
382
+ # calling.call.pay
383
+ class PayEvent < RelayEvent
384
+ attr_reader :control_id, :state
385
+
386
+ def self.from_payload(payload)
387
+ base = RelayEvent.from_payload(payload)
388
+ p = base.params
389
+ new(
390
+ event_type: base.event_type, params: base.params,
391
+ call_id: base.call_id, timestamp: base.timestamp,
392
+ control_id: p['control_id'] || '',
393
+ state: p['state'] || ''
394
+ )
395
+ end
396
+
397
+ def initialize(control_id: '', state: '', **base)
398
+ super(**base)
399
+ @control_id = control_id
400
+ @state = state
401
+ end
402
+ end
403
+
404
+ # calling.call.queue
405
+ class QueueEvent < RelayEvent
406
+ attr_reader :control_id, :status, :queue_id, :queue_name, :position, :size
407
+
408
+ def self.from_payload(payload)
409
+ base = RelayEvent.from_payload(payload)
410
+ p = base.params
411
+ new(
412
+ event_type: base.event_type, params: base.params,
413
+ call_id: base.call_id, timestamp: base.timestamp,
414
+ control_id: p['control_id'] || '',
415
+ status: p['status'] || '',
416
+ queue_id: p['id'] || '',
417
+ queue_name: p['name'] || '',
418
+ position: p['position'] || 0,
419
+ size: p['size'] || 0
420
+ )
421
+ end
422
+
423
+ def initialize(control_id: '', status: '', queue_id: '', queue_name: '',
424
+ position: 0, size: 0, **base)
425
+ super(**base)
426
+ @control_id = control_id
427
+ @status = status
428
+ @queue_id = queue_id
429
+ @queue_name = queue_name
430
+ @position = position
431
+ @size = size
432
+ end
433
+ end
434
+
435
+ # calling.call.echo
436
+ class EchoEvent < RelayEvent
437
+ attr_reader :state
438
+
439
+ def self.from_payload(payload)
440
+ base = RelayEvent.from_payload(payload)
441
+ p = base.params
442
+ new(
443
+ event_type: base.event_type, params: base.params,
444
+ call_id: base.call_id, timestamp: base.timestamp,
445
+ state: p['state'] || ''
446
+ )
447
+ end
448
+
449
+ def initialize(state: '', **base)
450
+ super(**base)
451
+ @state = state
452
+ end
453
+ end
454
+
455
+ # calling.call.transcribe
456
+ class TranscribeEvent < RelayEvent
457
+ attr_reader :control_id, :state, :url, :recording_id, :duration, :size
458
+
459
+ def self.from_payload(payload)
460
+ base = RelayEvent.from_payload(payload)
461
+ p = base.params
462
+ new(
463
+ event_type: base.event_type, params: base.params,
464
+ call_id: base.call_id, timestamp: base.timestamp,
465
+ control_id: p['control_id'] || '',
466
+ state: p['state'] || '',
467
+ url: p['url'] || '',
468
+ recording_id: p['recording_id'] || '',
469
+ duration: p['duration'] || 0.0,
470
+ size: p['size'] || 0
471
+ )
472
+ end
473
+
474
+ def initialize(control_id: '', state: '', url: '', recording_id: '',
475
+ duration: 0.0, size: 0, **base)
476
+ super(**base)
477
+ @control_id = control_id
478
+ @state = state
479
+ @url = url
480
+ @recording_id = recording_id
481
+ @duration = duration
482
+ @size = size
483
+ end
484
+ end
485
+
486
+ # calling.call.hold
487
+ class HoldEvent < RelayEvent
488
+ attr_reader :state
489
+
490
+ def self.from_payload(payload)
491
+ base = RelayEvent.from_payload(payload)
492
+ p = base.params
493
+ new(
494
+ event_type: base.event_type, params: base.params,
495
+ call_id: base.call_id, timestamp: base.timestamp,
496
+ state: p['state'] || ''
497
+ )
498
+ end
499
+
500
+ def initialize(state: '', **base)
501
+ super(**base)
502
+ @state = state
503
+ end
504
+ end
505
+
506
+ # calling.conference
507
+ class ConferenceEvent < RelayEvent
508
+ attr_reader :conference_id, :name, :status
509
+
510
+ def self.from_payload(payload)
511
+ base = RelayEvent.from_payload(payload)
512
+ p = base.params
513
+ new(
514
+ event_type: base.event_type, params: base.params,
515
+ call_id: base.call_id, timestamp: base.timestamp,
516
+ conference_id: p['conference_id'] || '',
517
+ name: p['name'] || '',
518
+ status: p['status'] || ''
519
+ )
520
+ end
521
+
522
+ def initialize(conference_id: '', name: '', status: '', **base)
523
+ super(**base)
524
+ @conference_id = conference_id
525
+ @name = name
526
+ @status = status
527
+ end
528
+ end
529
+
530
+ # calling.error
531
+ class CallingErrorEvent < RelayEvent
532
+ attr_reader :code, :message
533
+
534
+ def self.from_payload(payload)
535
+ base = RelayEvent.from_payload(payload)
536
+ p = base.params
537
+ new(
538
+ event_type: base.event_type, params: base.params,
539
+ call_id: base.call_id, timestamp: base.timestamp,
540
+ code: p['code'] || '',
541
+ message: p['message'] || ''
542
+ )
543
+ end
544
+
545
+ def initialize(code: '', message: '', **base)
546
+ super(**base)
547
+ @code = code
548
+ @message = message
549
+ end
550
+ end
551
+
552
+ # messaging.receive
553
+ class MessageReceiveEvent < RelayEvent
554
+ attr_reader :message_id, :context, :direction, :from_number, :to_number,
555
+ :body, :media, :segments, :message_state, :tags
556
+
557
+ def self.from_payload(payload)
558
+ base = RelayEvent.from_payload(payload)
559
+ p = base.params
560
+ new(
561
+ event_type: base.event_type, params: base.params,
562
+ call_id: base.call_id, timestamp: base.timestamp,
563
+ message_id: p['message_id'] || '',
564
+ context: p['context'] || '',
565
+ direction: p['direction'] || '',
566
+ from_number: p['from_number'] || '',
567
+ to_number: p['to_number'] || '',
568
+ body: p['body'] || '',
569
+ media: p['media'] || [],
570
+ segments: p['segments'] || 0,
571
+ message_state: p['message_state'] || '',
572
+ tags: p['tags'] || []
573
+ )
574
+ end
575
+
576
+ def initialize(message_id: '', context: '', direction: '', from_number: '',
577
+ to_number: '', body: '', media: [], segments: 0,
578
+ message_state: '', tags: [], **base)
579
+ super(**base)
580
+ @message_id = message_id
581
+ @context = context
582
+ @direction = direction
583
+ @from_number = from_number
584
+ @to_number = to_number
585
+ @body = body
586
+ @media = media
587
+ @segments = segments
588
+ @message_state = message_state
589
+ @tags = tags
590
+ end
591
+ end
592
+
593
+ # messaging.state
594
+ class MessageStateEvent < RelayEvent
595
+ attr_reader :message_id, :context, :direction, :from_number, :to_number,
596
+ :body, :media, :segments, :message_state, :reason, :tags
597
+
598
+ def self.from_payload(payload)
599
+ base = RelayEvent.from_payload(payload)
600
+ p = base.params
601
+ new(
602
+ event_type: base.event_type, params: base.params,
603
+ call_id: base.call_id, timestamp: base.timestamp,
604
+ message_id: p['message_id'] || '',
605
+ context: p['context'] || '',
606
+ direction: p['direction'] || '',
607
+ from_number: p['from_number'] || '',
608
+ to_number: p['to_number'] || '',
609
+ body: p['body'] || '',
610
+ media: p['media'] || [],
611
+ segments: p['segments'] || 0,
612
+ message_state: p['message_state'] || '',
613
+ reason: p['reason'] || '',
614
+ tags: p['tags'] || []
615
+ )
616
+ end
617
+
618
+ def initialize(message_id: '', context: '', direction: '', from_number: '',
619
+ to_number: '', body: '', media: [], segments: 0,
620
+ message_state: '', reason: '', tags: [], **base)
621
+ super(**base)
622
+ @message_id = message_id
623
+ @context = context
624
+ @direction = direction
625
+ @from_number = from_number
626
+ @to_number = to_number
627
+ @body = body
628
+ @media = media
629
+ @segments = segments
630
+ @message_state = message_state
631
+ @reason = reason
632
+ @tags = tags
633
+ end
634
+ end
635
+
636
+ # Map event_type string to typed event class
637
+ EVENT_CLASS_MAP = {
638
+ 'calling.call.state' => CallStateEvent,
639
+ 'calling.call.receive' => CallReceiveEvent,
640
+ 'calling.call.play' => PlayEvent,
641
+ 'calling.call.record' => RecordEvent,
642
+ 'calling.call.collect' => CollectEvent,
643
+ 'calling.call.connect' => ConnectEvent,
644
+ 'calling.call.detect' => DetectEvent,
645
+ 'calling.call.fax' => FaxEvent,
646
+ 'calling.call.tap' => TapEvent,
647
+ 'calling.call.stream' => StreamEvent,
648
+ 'calling.call.send_digits' => SendDigitsEvent,
649
+ 'calling.call.dial' => DialEvent,
650
+ 'calling.call.refer' => ReferEvent,
651
+ 'calling.call.denoise' => DenoiseEvent,
652
+ 'calling.call.pay' => PayEvent,
653
+ 'calling.call.queue' => QueueEvent,
654
+ 'calling.call.echo' => EchoEvent,
655
+ 'calling.call.transcribe' => TranscribeEvent,
656
+ 'calling.call.hold' => HoldEvent,
657
+ 'calling.conference' => ConferenceEvent,
658
+ 'calling.error' => CallingErrorEvent,
659
+ 'messaging.receive' => MessageReceiveEvent,
660
+ 'messaging.state' => MessageStateEvent
661
+ }.freeze
662
+
663
+ # Parse a raw signalwire.event params hash into a typed event object.
664
+ def self.parse_event(payload)
665
+ event_type = payload['event_type'] || ''
666
+ klass = EVENT_CLASS_MAP[event_type] || RelayEvent
667
+ klass.from_payload(payload)
668
+ end
669
+ end
670
+ end