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,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module Relay
5
+ # Protocol version sent during signalwire.connect
6
+ PROTOCOL_VERSION = { 'major' => 2, 'minor' => 0, 'revision' => 0 }.freeze
7
+ AGENT_STRING = 'signalwire-agents-ruby/1.0'
8
+
9
+ # JSON-RPC methods
10
+ METHOD_SIGNALWIRE_CONNECT = 'signalwire.connect'
11
+ METHOD_SIGNALWIRE_EVENT = 'signalwire.event'
12
+ METHOD_SIGNALWIRE_PING = 'signalwire.ping'
13
+ METHOD_SIGNALWIRE_DISCONNECT = 'signalwire.disconnect'
14
+ METHOD_SIGNALWIRE_RECEIVE = 'signalwire.receive'
15
+ METHOD_SIGNALWIRE_UNRECEIVE = 'signalwire.unreceive'
16
+
17
+ # Authorization state event
18
+ EVENT_AUTHORIZATION_STATE = 'signalwire.authorization.state'
19
+
20
+ # Call states
21
+ CALL_STATE_CREATED = 'created'
22
+ CALL_STATE_RINGING = 'ringing'
23
+ CALL_STATE_ANSWERED = 'answered'
24
+ CALL_STATE_ENDING = 'ending'
25
+ CALL_STATE_ENDED = 'ended'
26
+
27
+ CALL_STATES = [
28
+ CALL_STATE_CREATED,
29
+ CALL_STATE_RINGING,
30
+ CALL_STATE_ANSWERED,
31
+ CALL_STATE_ENDING,
32
+ CALL_STATE_ENDED
33
+ ].freeze
34
+
35
+ # End reasons
36
+ END_REASON_HANGUP = 'hangup'
37
+ END_REASON_CANCEL = 'cancel'
38
+ END_REASON_BUSY = 'busy'
39
+ END_REASON_NO_ANSWER = 'noAnswer'
40
+ END_REASON_DECLINE = 'decline'
41
+ END_REASON_ERROR = 'error'
42
+ END_REASON_ABANDONED = 'abandoned'
43
+ END_REASON_MAX_DURATION = 'max_duration'
44
+ END_REASON_NOT_FOUND = 'not_found'
45
+
46
+ # Connect states
47
+ CONNECT_STATE_CONNECTING = 'connecting'
48
+ CONNECT_STATE_CONNECTED = 'connected'
49
+ CONNECT_STATE_DISCONNECTED = 'disconnected'
50
+ CONNECT_STATE_FAILED = 'failed'
51
+
52
+ # Event types — calling
53
+ EVENT_CALL_STATE = 'calling.call.state'
54
+ EVENT_CALL_RECEIVE = 'calling.call.receive'
55
+ EVENT_CALL_CONNECT = 'calling.call.connect'
56
+ EVENT_CALL_PLAY = 'calling.call.play'
57
+ EVENT_CALL_COLLECT = 'calling.call.collect'
58
+ EVENT_CALL_RECORD = 'calling.call.record'
59
+ EVENT_CALL_DETECT = 'calling.call.detect'
60
+ EVENT_CALL_FAX = 'calling.call.fax'
61
+ EVENT_CALL_TAP = 'calling.call.tap'
62
+ EVENT_CALL_SEND_DIGITS = 'calling.call.send_digits'
63
+ EVENT_CALL_DIAL = 'calling.call.dial'
64
+ EVENT_CALL_REFER = 'calling.call.refer'
65
+ EVENT_CALL_DENOISE = 'calling.call.denoise'
66
+ EVENT_CALL_PAY = 'calling.call.pay'
67
+ EVENT_CALL_QUEUE = 'calling.call.queue'
68
+ EVENT_CALL_STREAM = 'calling.call.stream'
69
+ EVENT_CALL_ECHO = 'calling.call.echo'
70
+ EVENT_CALL_TRANSCRIBE = 'calling.call.transcribe'
71
+ EVENT_CONFERENCE = 'calling.conference'
72
+ EVENT_CALLING_ERROR = 'calling.error'
73
+
74
+ # Messaging event types
75
+ EVENT_MESSAGING_RECEIVE = 'messaging.receive'
76
+ EVENT_MESSAGING_STATE = 'messaging.state'
77
+
78
+ # Message states
79
+ MESSAGE_STATE_QUEUED = 'queued'
80
+ MESSAGE_STATE_INITIATED = 'initiated'
81
+ MESSAGE_STATE_SENT = 'sent'
82
+ MESSAGE_STATE_DELIVERED = 'delivered'
83
+ MESSAGE_STATE_UNDELIVERED = 'undelivered'
84
+ MESSAGE_STATE_FAILED = 'failed'
85
+ MESSAGE_STATE_RECEIVED = 'received'
86
+
87
+ MESSAGE_TERMINAL_STATES = [
88
+ MESSAGE_STATE_DELIVERED,
89
+ MESSAGE_STATE_UNDELIVERED,
90
+ MESSAGE_STATE_FAILED
91
+ ].freeze
92
+
93
+ # Play states
94
+ PLAY_STATE_PLAYING = 'playing'
95
+ PLAY_STATE_PAUSED = 'paused'
96
+ PLAY_STATE_FINISHED = 'finished'
97
+ PLAY_STATE_ERROR = 'error'
98
+
99
+ # Record states
100
+ RECORD_STATE_RECORDING = 'recording'
101
+ RECORD_STATE_PAUSED = 'paused'
102
+ RECORD_STATE_FINISHED = 'finished'
103
+ RECORD_STATE_NO_INPUT = 'no_input'
104
+
105
+ # Detect types
106
+ DETECT_TYPE_MACHINE = 'machine'
107
+ DETECT_TYPE_FAX = 'fax'
108
+ DETECT_TYPE_DIGIT = 'digit'
109
+
110
+ # Join room states
111
+ ROOM_STATE_JOINING = 'joining'
112
+ ROOM_STATE_JOIN = 'join'
113
+ ROOM_STATE_LEAVING = 'leaving'
114
+ ROOM_STATE_LEAVE = 'leave'
115
+
116
+ # Reconnect settings
117
+ RECONNECT_MIN_DELAY = 1.0
118
+ RECONNECT_MAX_DELAY = 30.0
119
+ RECONNECT_BACKOFF_FACTOR = 2.0
120
+
121
+ # Default host
122
+ DEFAULT_RELAY_HOST = 'relay.signalwire.com'
123
+ end
124
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module Relay
5
+ # Represents a single SMS/MMS message.
6
+ #
7
+ # For outbound messages, use message.wait to block until a terminal state
8
+ # (delivered, undelivered, failed) is reached.
9
+ class Message
10
+ attr_reader :message_id, :context, :direction, :from_number, :to_number,
11
+ :body, :media, :segments, :tags, :reason
12
+ attr_accessor :state
13
+
14
+ def initialize(message_id: '', context: '', direction: '', from_number: '',
15
+ to_number: '', body: '', media: nil, segments: 0,
16
+ state: '', reason: '', tags: nil)
17
+ @message_id = message_id
18
+ @context = context
19
+ @direction = direction
20
+ @from_number = from_number
21
+ @to_number = to_number
22
+ @body = body
23
+ @media = media || []
24
+ @segments = segments
25
+ @state = state
26
+ @reason = reason
27
+ @tags = tags || []
28
+
29
+ # Completion tracking
30
+ @mutex = Mutex.new
31
+ @condition = ConditionVariable.new
32
+ @done = false
33
+ @result = nil
34
+ @on_completed = nil
35
+ @listeners = []
36
+ end
37
+
38
+ # Set the on_completed callback.
39
+ def on_completed(&block)
40
+ @on_completed = block
41
+ end
42
+
43
+ # Set the on_completed callback from options.
44
+ def _set_on_completed(callback)
45
+ @on_completed = callback
46
+ end
47
+
48
+ # Register an event listener for state changes.
49
+ def on_event(&handler)
50
+ @listeners << handler
51
+ end
52
+
53
+ def done?
54
+ @done
55
+ end
56
+
57
+ alias_method :is_done?, :done?
58
+
59
+ def result
60
+ @result
61
+ end
62
+
63
+ # Wait for the message to reach a terminal state.
64
+ # Raises ActionTimeoutError if timeout exceeded.
65
+ def wait(timeout: nil)
66
+ @mutex.synchronize do
67
+ return @result if @done
68
+
69
+ if timeout
70
+ deadline = Time.now + timeout
71
+ while !@done
72
+ remaining = deadline - Time.now
73
+ if remaining <= 0
74
+ raise ActionTimeoutError, "Message #{@message_id} timed out after #{timeout}s"
75
+ end
76
+ @condition.wait(@mutex, remaining)
77
+ end
78
+ else
79
+ @condition.wait(@mutex) until @done
80
+ end
81
+ @result
82
+ end
83
+ end
84
+
85
+ # Handle a messaging.state event for this message.
86
+ def _dispatch_event(payload)
87
+ event_params = payload['params'] || {}
88
+ new_state = event_params['message_state'] || ''
89
+
90
+ @state = new_state unless new_state.empty?
91
+ @reason = event_params['reason'] if event_params.key?('reason')
92
+
93
+ event = Relay.parse_event(payload)
94
+
95
+ # Notify listeners
96
+ @listeners.each do |handler|
97
+ begin
98
+ handler.call(event)
99
+ rescue => e
100
+ $stderr.puts "[RELAY] Error in message event handler for #{@message_id}: #{e.message}"
101
+ end
102
+ end
103
+
104
+ # Check terminal state
105
+ _resolve(event) if MESSAGE_TERMINAL_STATES.include?(new_state)
106
+ end
107
+
108
+ def to_s
109
+ "Message(id=#{@message_id}, direction=#{@direction}, " \
110
+ "state=#{@state}, from=#{@from_number}, to=#{@to_number})"
111
+ end
112
+
113
+ def inspect
114
+ to_s
115
+ end
116
+
117
+ private
118
+
119
+ def _resolve(event)
120
+ @mutex.synchronize do
121
+ return if @done
122
+
123
+ @result = event
124
+ @done = true
125
+ @condition.broadcast
126
+ end
127
+ if @on_completed
128
+ begin
129
+ @on_completed.call(event)
130
+ rescue => e
131
+ $stderr.puts "[RELAY] Error in on_completed callback for message #{@message_id}: #{e.message}"
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end