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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +259 -0
- data/bin/swaig-test +872 -0
- data/lib/signalwire/agent/agent_base.rb +2134 -0
- data/lib/signalwire/contexts/context_builder.rb +861 -0
- data/lib/signalwire/core/logging_config.rb +54 -0
- data/lib/signalwire/datamap/data_map.rb +315 -0
- data/lib/signalwire/logging.rb +92 -0
- data/lib/signalwire/pom/prompt_object_model.rb +269 -0
- data/lib/signalwire/pom/section.rb +202 -0
- data/lib/signalwire/prefabs/concierge.rb +92 -0
- data/lib/signalwire/prefabs/faq_bot.rb +67 -0
- data/lib/signalwire/prefabs/info_gatherer.rb +79 -0
- data/lib/signalwire/prefabs/receptionist.rb +74 -0
- data/lib/signalwire/prefabs/survey.rb +75 -0
- data/lib/signalwire/relay/action.rb +291 -0
- data/lib/signalwire/relay/call.rb +523 -0
- data/lib/signalwire/relay/client.rb +789 -0
- data/lib/signalwire/relay/constants.rb +124 -0
- data/lib/signalwire/relay/message.rb +137 -0
- data/lib/signalwire/relay/relay_event.rb +670 -0
- data/lib/signalwire/rest/http_client.rb +159 -0
- data/lib/signalwire/rest/namespaces/addresses.rb +19 -0
- data/lib/signalwire/rest/namespaces/calling.rb +179 -0
- data/lib/signalwire/rest/namespaces/chat.rb +18 -0
- data/lib/signalwire/rest/namespaces/compat.rb +229 -0
- data/lib/signalwire/rest/namespaces/datasphere.rb +39 -0
- data/lib/signalwire/rest/namespaces/fabric.rb +235 -0
- data/lib/signalwire/rest/namespaces/imported_numbers.rb +18 -0
- data/lib/signalwire/rest/namespaces/logs.rb +46 -0
- data/lib/signalwire/rest/namespaces/lookup.rb +18 -0
- data/lib/signalwire/rest/namespaces/mfa.rb +26 -0
- data/lib/signalwire/rest/namespaces/number_groups.rb +32 -0
- data/lib/signalwire/rest/namespaces/phone_numbers.rb +124 -0
- data/lib/signalwire/rest/namespaces/project.rb +33 -0
- data/lib/signalwire/rest/namespaces/pubsub.rb +18 -0
- data/lib/signalwire/rest/namespaces/queues.rb +28 -0
- data/lib/signalwire/rest/namespaces/recordings.rb +18 -0
- data/lib/signalwire/rest/namespaces/registry.rb +67 -0
- data/lib/signalwire/rest/namespaces/short_codes.rb +26 -0
- data/lib/signalwire/rest/namespaces/sip_profile.rb +22 -0
- data/lib/signalwire/rest/namespaces/verified_callers.rb +24 -0
- data/lib/signalwire/rest/namespaces/video.rb +129 -0
- data/lib/signalwire/rest/pagination.rb +89 -0
- data/lib/signalwire/rest/phone_call_handler.rb +56 -0
- data/lib/signalwire/rest/rest_client.rb +114 -0
- data/lib/signalwire/runtime.rb +98 -0
- data/lib/signalwire/security/session_manager.rb +124 -0
- data/lib/signalwire/security/webhook_middleware.rb +191 -0
- data/lib/signalwire/security/webhook_validator.rb +327 -0
- data/lib/signalwire/server/agent_server.rb +413 -0
- data/lib/signalwire/serverless/lambda_handler.rb +251 -0
- data/lib/signalwire/skills/builtin/api_ninjas_trivia.rb +99 -0
- data/lib/signalwire/skills/builtin/claude_skills.rb +92 -0
- data/lib/signalwire/skills/builtin/custom_skills.rb +54 -0
- data/lib/signalwire/skills/builtin/datasphere.rb +153 -0
- data/lib/signalwire/skills/builtin/datasphere_serverless.rb +107 -0
- data/lib/signalwire/skills/builtin/datetime.rb +97 -0
- data/lib/signalwire/skills/builtin/google_maps.rb +168 -0
- data/lib/signalwire/skills/builtin/info_gatherer.rb +189 -0
- data/lib/signalwire/skills/builtin/joke.rb +65 -0
- data/lib/signalwire/skills/builtin/math.rb +176 -0
- data/lib/signalwire/skills/builtin/mcp_gateway.rb +121 -0
- data/lib/signalwire/skills/builtin/native_vector_search.rb +116 -0
- data/lib/signalwire/skills/builtin/play_background_file.rb +86 -0
- data/lib/signalwire/skills/builtin/spider.rb +169 -0
- data/lib/signalwire/skills/builtin/swml_transfer.rb +118 -0
- data/lib/signalwire/skills/builtin/weather_api.rb +92 -0
- data/lib/signalwire/skills/builtin/web_search.rb +141 -0
- data/lib/signalwire/skills/builtin/wikipedia_search.rb +125 -0
- data/lib/signalwire/skills/skill_base.rb +82 -0
- data/lib/signalwire/skills/skill_manager.rb +97 -0
- data/lib/signalwire/skills/skill_registry.rb +258 -0
- data/lib/signalwire/swaig/function_result.rb +777 -0
- data/lib/signalwire/swml/document.rb +84 -0
- data/lib/signalwire/swml/schema.json +12250 -0
- data/lib/signalwire/swml/schema.rb +81 -0
- data/lib/signalwire/swml/service.rb +650 -0
- data/lib/signalwire/utils/schema_utils.rb +298 -0
- data/lib/signalwire/utils/serverless.rb +19 -0
- data/lib/signalwire/utils/url_validator.rb +138 -0
- data/lib/signalwire/version.rb +5 -0
- data/lib/signalwire.rb +114 -0
- 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
|