signalwire_agents 1.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.
- checksums.yaml +7 -0
- data/README.md +79 -0
- data/bin/swaig-test +310 -0
- data/lib/signalwire_agents/agent/agent_base.rb +1171 -0
- data/lib/signalwire_agents/contexts/context_builder.rb +622 -0
- data/lib/signalwire_agents/datamap/data_map.rb +279 -0
- data/lib/signalwire_agents/logging.rb +92 -0
- data/lib/signalwire_agents/prefabs/concierge.rb +92 -0
- data/lib/signalwire_agents/prefabs/faq_bot.rb +67 -0
- data/lib/signalwire_agents/prefabs/info_gatherer.rb +79 -0
- data/lib/signalwire_agents/prefabs/receptionist.rb +74 -0
- data/lib/signalwire_agents/prefabs/survey.rb +75 -0
- data/lib/signalwire_agents/relay/action.rb +291 -0
- data/lib/signalwire_agents/relay/call.rb +523 -0
- data/lib/signalwire_agents/relay/client.rb +671 -0
- data/lib/signalwire_agents/relay/constants.rb +124 -0
- data/lib/signalwire_agents/relay/message.rb +137 -0
- data/lib/signalwire_agents/relay/relay_event.rb +670 -0
- data/lib/signalwire_agents/rest/http_client.rb +147 -0
- data/lib/signalwire_agents/rest/namespaces/addresses.rb +19 -0
- data/lib/signalwire_agents/rest/namespaces/calling.rb +179 -0
- data/lib/signalwire_agents/rest/namespaces/chat.rb +18 -0
- data/lib/signalwire_agents/rest/namespaces/compat.rb +229 -0
- data/lib/signalwire_agents/rest/namespaces/datasphere.rb +39 -0
- data/lib/signalwire_agents/rest/namespaces/fabric.rb +175 -0
- data/lib/signalwire_agents/rest/namespaces/imported_numbers.rb +18 -0
- data/lib/signalwire_agents/rest/namespaces/logs.rb +46 -0
- data/lib/signalwire_agents/rest/namespaces/lookup.rb +18 -0
- data/lib/signalwire_agents/rest/namespaces/mfa.rb +26 -0
- data/lib/signalwire_agents/rest/namespaces/number_groups.rb +32 -0
- data/lib/signalwire_agents/rest/namespaces/phone_numbers.rb +20 -0
- data/lib/signalwire_agents/rest/namespaces/project.rb +33 -0
- data/lib/signalwire_agents/rest/namespaces/pubsub.rb +18 -0
- data/lib/signalwire_agents/rest/namespaces/queues.rb +28 -0
- data/lib/signalwire_agents/rest/namespaces/recordings.rb +18 -0
- data/lib/signalwire_agents/rest/namespaces/registry.rb +67 -0
- data/lib/signalwire_agents/rest/namespaces/short_codes.rb +26 -0
- data/lib/signalwire_agents/rest/namespaces/sip_profile.rb +22 -0
- data/lib/signalwire_agents/rest/namespaces/verified_callers.rb +24 -0
- data/lib/signalwire_agents/rest/namespaces/video.rb +129 -0
- data/lib/signalwire_agents/rest/signalwire_client.rb +110 -0
- data/lib/signalwire_agents/security/session_manager.rb +124 -0
- data/lib/signalwire_agents/server/agent_server.rb +260 -0
- data/lib/signalwire_agents/skills/builtin/api_ninjas_trivia.rb +91 -0
- data/lib/signalwire_agents/skills/builtin/claude_skills.rb +92 -0
- data/lib/signalwire_agents/skills/builtin/custom_skills.rb +54 -0
- data/lib/signalwire_agents/skills/builtin/datasphere.rb +141 -0
- data/lib/signalwire_agents/skills/builtin/datasphere_serverless.rb +107 -0
- data/lib/signalwire_agents/skills/builtin/datetime.rb +97 -0
- data/lib/signalwire_agents/skills/builtin/google_maps.rb +168 -0
- data/lib/signalwire_agents/skills/builtin/info_gatherer.rb +189 -0
- data/lib/signalwire_agents/skills/builtin/joke.rb +65 -0
- data/lib/signalwire_agents/skills/builtin/math.rb +176 -0
- data/lib/signalwire_agents/skills/builtin/mcp_gateway.rb +121 -0
- data/lib/signalwire_agents/skills/builtin/native_vector_search.rb +116 -0
- data/lib/signalwire_agents/skills/builtin/play_background_file.rb +86 -0
- data/lib/signalwire_agents/skills/builtin/spider.rb +142 -0
- data/lib/signalwire_agents/skills/builtin/swml_transfer.rb +118 -0
- data/lib/signalwire_agents/skills/builtin/weather_api.rb +85 -0
- data/lib/signalwire_agents/skills/builtin/web_search.rb +123 -0
- data/lib/signalwire_agents/skills/builtin/wikipedia_search.rb +109 -0
- data/lib/signalwire_agents/skills/skill_base.rb +58 -0
- data/lib/signalwire_agents/skills/skill_manager.rb +85 -0
- data/lib/signalwire_agents/skills/skill_registry.rb +76 -0
- data/lib/signalwire_agents/swaig/function_result.rb +777 -0
- data/lib/signalwire_agents/swml/document.rb +84 -0
- data/lib/signalwire_agents/swml/schema.json +12250 -0
- data/lib/signalwire_agents/swml/schema.rb +81 -0
- data/lib/signalwire_agents/swml/service.rb +304 -0
- data/lib/signalwire_agents/version.rb +5 -0
- data/lib/signalwire_agents.rb +19 -0
- metadata +212 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SignalWireAgents
|
|
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 SignalWireAgents
|
|
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
|