retell-sdk-unofficial 0.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/lib/retell/sdk/unofficial/agent.rb +73 -0
- data/lib/retell/sdk/unofficial/agent_list.rb +11 -0
- data/lib/retell/sdk/unofficial/api/agent.rb +348 -0
- data/lib/retell/sdk/unofficial/api/call.rb +212 -0
- data/lib/retell/sdk/unofficial/api/concurrency.rb +28 -0
- data/lib/retell/sdk/unofficial/api/phone_number.rb +179 -0
- data/lib/retell/sdk/unofficial/api/retell_llm.rb +254 -0
- data/lib/retell/sdk/unofficial/api/voice.rb +50 -0
- data/lib/retell/sdk/unofficial/base.rb +81 -0
- data/lib/retell/sdk/unofficial/base_call.rb +40 -0
- data/lib/retell/sdk/unofficial/base_list.rb +52 -0
- data/lib/retell/sdk/unofficial/call.rb +18 -0
- data/lib/retell/sdk/unofficial/call_list.rb +14 -0
- data/lib/retell/sdk/unofficial/client.rb +285 -0
- data/lib/retell/sdk/unofficial/concurrency.rb +17 -0
- data/lib/retell/sdk/unofficial/phone_call.rb +22 -0
- data/lib/retell/sdk/unofficial/phone_number.rb +62 -0
- data/lib/retell/sdk/unofficial/phone_number_list.rb +11 -0
- data/lib/retell/sdk/unofficial/retell_llm.rb +59 -0
- data/lib/retell/sdk/unofficial/retell_llm_list.rb +11 -0
- data/lib/retell/sdk/unofficial/version.rb +7 -0
- data/lib/retell/sdk/unofficial/voice.rb +25 -0
- data/lib/retell/sdk/unofficial/voice_list.rb +11 -0
- data/lib/retell/sdk/unofficial/web_call.rb +20 -0
- data/lib/retell/sdk/unofficial.rb +33 -0
- metadata +142 -0
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require_relative 'api/agent'
|
5
|
+
require_relative 'api/call'
|
6
|
+
require_relative 'api/retell_llm'
|
7
|
+
require_relative 'api/phone_number'
|
8
|
+
require_relative 'api/voice'
|
9
|
+
require_relative 'api/concurrency'
|
10
|
+
|
11
|
+
module Retell
|
12
|
+
module SDK
|
13
|
+
module Unofficial
|
14
|
+
class Client
|
15
|
+
DEFAULT_BASE_URL = 'https://api.retellai.com'.freeze
|
16
|
+
DEFAULT_TIMEOUT = 60
|
17
|
+
|
18
|
+
def initialize(api_key:, base_url: nil, timeout: DEFAULT_TIMEOUT)
|
19
|
+
@api_key = api_key
|
20
|
+
@base_url = base_url || DEFAULT_BASE_URL
|
21
|
+
@timeout = timeout
|
22
|
+
end
|
23
|
+
|
24
|
+
def agent
|
25
|
+
@agent ||= Retell::SDK::Unofficial::API::Agent.new(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def call
|
29
|
+
@call ||= Retell::SDK::Unofficial::API::Call.new(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
def retell_llm
|
33
|
+
@retell_llm ||= Retell::SDK::Unofficial::API::RetellLLM.new(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def phone_number
|
37
|
+
@phone_number ||= Retell::SDK::Unofficial::API::PhoneNumber.new(self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def voice
|
41
|
+
@voice ||= Retell::SDK::Unofficial::API::Voice.new(self)
|
42
|
+
end
|
43
|
+
|
44
|
+
def concurrency
|
45
|
+
@concurrency ||= Retell::SDK::Unofficial::API::Concurrency.new(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
def agents
|
49
|
+
agent.list
|
50
|
+
end
|
51
|
+
|
52
|
+
def calls(**params)
|
53
|
+
call.list(**params)
|
54
|
+
end
|
55
|
+
|
56
|
+
def retell_llms
|
57
|
+
retell_llm.list
|
58
|
+
end
|
59
|
+
|
60
|
+
def phone_numbers
|
61
|
+
phone_number.list
|
62
|
+
end
|
63
|
+
|
64
|
+
def voices
|
65
|
+
voice.list
|
66
|
+
end
|
67
|
+
|
68
|
+
def request(method, path, params = {}, **options)
|
69
|
+
url = "#{@base_url}#{path}"
|
70
|
+
|
71
|
+
http_options = {
|
72
|
+
headers: headers.merge(options[:headers] || {}),
|
73
|
+
format: :json,
|
74
|
+
timeout: options[:timeout] || @timeout
|
75
|
+
}
|
76
|
+
|
77
|
+
body_params = options[:body] || {}
|
78
|
+
|
79
|
+
if [:get, :delete].include?(method)
|
80
|
+
options[:query] = options[:query].merge(params)
|
81
|
+
else
|
82
|
+
options[:body] = options[:body].merge(params)
|
83
|
+
end
|
84
|
+
|
85
|
+
http_options[:query] = options[:query] unless options[:query].empty?
|
86
|
+
|
87
|
+
if [:post, :patch].include?(method)
|
88
|
+
http_options[:body] = options[:body].to_json
|
89
|
+
elsif !body_params.empty?
|
90
|
+
http_options[:body] = body_params.to_json
|
91
|
+
end
|
92
|
+
|
93
|
+
begin
|
94
|
+
response = HTTParty.send(
|
95
|
+
method,
|
96
|
+
url,
|
97
|
+
http_options
|
98
|
+
)
|
99
|
+
rescue Net::OpenTimeout, Net::ReadTimeout, Timeout::Error, Errno::ETIMEDOUT => e
|
100
|
+
raise APITimeoutError.new(http_options)
|
101
|
+
end
|
102
|
+
|
103
|
+
handle_response(response)
|
104
|
+
end
|
105
|
+
|
106
|
+
def get(path, params = {}, **options)
|
107
|
+
request(:get, path, params, **options)
|
108
|
+
end
|
109
|
+
|
110
|
+
def post(path, params = {}, **options)
|
111
|
+
request(:post, path, params, **options)
|
112
|
+
end
|
113
|
+
|
114
|
+
def patch(path, params = {}, **options)
|
115
|
+
request(:patch, path, params, **options)
|
116
|
+
end
|
117
|
+
|
118
|
+
def delete(path, params = {}, **options)
|
119
|
+
request(:delete, path, params, **options)
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
123
|
+
def make_request_options(extra_headers: nil, extra_query: nil, extra_body: nil, timeout: nil)
|
124
|
+
options = {}
|
125
|
+
options[:headers] = extra_headers || {}
|
126
|
+
options[:query] = extra_query || {}
|
127
|
+
options[:body] = extra_body || {}
|
128
|
+
options[:timeout] = timeout if timeout
|
129
|
+
options
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def headers
|
135
|
+
{
|
136
|
+
'Authorization' => "Bearer #{@api_key}",
|
137
|
+
'Content-Type' => 'application/json',
|
138
|
+
'Accept' => 'application/json'
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
142
|
+
def handle_response(response)
|
143
|
+
case response.code
|
144
|
+
when 204
|
145
|
+
return nil
|
146
|
+
when 200..299
|
147
|
+
parse_response(response)
|
148
|
+
when 400..499
|
149
|
+
raise Retell::SDK::Unofficial::Error.new(response.code, "Client error: #{response.body}")
|
150
|
+
when 500..599
|
151
|
+
raise Retell::SDK::Unofficial::Error.new(response.code, "Server error: #{response.body}")
|
152
|
+
else
|
153
|
+
raise Retell::SDK::Unofficial::Error.new(response.code, "Unknown error: #{response.body}")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def parse_response(response)
|
158
|
+
data = response.parsed_response
|
159
|
+
if data.is_a?(Array)
|
160
|
+
parse_array_response(data)
|
161
|
+
elsif data.is_a?(Hash)
|
162
|
+
parse_single_response(data)
|
163
|
+
else
|
164
|
+
raise Retell::SDK::Unofficial::Error, "Unexpected data format: #{data.class}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def parse_array_response(data)
|
169
|
+
type_key = data.first&.keys&.find { |key|
|
170
|
+
key.end_with?('_id') || key == 'phone_number'
|
171
|
+
}&.gsub('_id', '')
|
172
|
+
|
173
|
+
return unknown_response_error('array') unless type_key
|
174
|
+
|
175
|
+
list_class = "Retell::SDK::Unofficial::#{process_type_key(type_key)}List"
|
176
|
+
item_class = "Retell::SDK::Unofficial::#{process_type_key(type_key)}"
|
177
|
+
|
178
|
+
items = data.map { |item_data| constantize_item_class(item_class).new(
|
179
|
+
self,
|
180
|
+
**process_data(item_data, type_key)
|
181
|
+
)}
|
182
|
+
raw_response = { "#{type_key}s".to_sym => items }
|
183
|
+
|
184
|
+
constantize_list_class(list_class).new(**raw_response)
|
185
|
+
end
|
186
|
+
|
187
|
+
def parse_single_response(data)
|
188
|
+
type_key = data.keys.find { |key|
|
189
|
+
key.end_with?('_id') || key == 'phone_number' || key == 'concurrency_limit'
|
190
|
+
}&.gsub('_id', '')
|
191
|
+
|
192
|
+
return unknown_response_error('single object') unless type_key
|
193
|
+
|
194
|
+
response_class = "Retell::SDK::Unofficial::#{process_type_key(type_key)}"
|
195
|
+
processed_data = process_data(data, type_key)
|
196
|
+
|
197
|
+
constantize_item_class(response_class).new(self, **processed_data)
|
198
|
+
end
|
199
|
+
|
200
|
+
# yes, same as constantize_list_class - to circumvent type checking issues
|
201
|
+
def constantize_item_class(class_name)
|
202
|
+
class_name.split('::').inject(Object) { |mod, class_name| mod.const_get(class_name) }
|
203
|
+
end
|
204
|
+
|
205
|
+
# yes, same as constantize_item_class - Ruby type checking isn't where it should be
|
206
|
+
def constantize_list_class(class_name)
|
207
|
+
class_name.split('::').inject(Object) { |mod, class_name| mod.const_get(class_name) }
|
208
|
+
end
|
209
|
+
|
210
|
+
def process_type_key(type_key)
|
211
|
+
case type_key
|
212
|
+
when 'llm'
|
213
|
+
'RetellLLM'
|
214
|
+
when 'concurrency_limit'
|
215
|
+
'Concurrency'
|
216
|
+
when 'phone_number'
|
217
|
+
'PhoneNumber'
|
218
|
+
else
|
219
|
+
type_key.capitalize
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def process_data(data, type_key)
|
224
|
+
case data
|
225
|
+
when Hash
|
226
|
+
data.map do |key, value|
|
227
|
+
processed_value = process_data(value, type_key)
|
228
|
+
[
|
229
|
+
key.to_sym,
|
230
|
+
convert_to_float(processed_value, type_key, key.to_sym)
|
231
|
+
]
|
232
|
+
end.to_h
|
233
|
+
when Array
|
234
|
+
data.map { |item| process_data(item, type_key) }
|
235
|
+
else
|
236
|
+
data
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def convert_to_float(value, type_key, field_name)
|
241
|
+
if value.is_a?(Integer) && float_fields(type_key).include?(field_name)
|
242
|
+
value.to_f
|
243
|
+
else
|
244
|
+
value
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def float_fields(type_key)
|
249
|
+
case type_key
|
250
|
+
when 'agent'
|
251
|
+
[:ambient_sound_volume, :backchannel_frequency, :interruption_sensitivity, :responsiveness, :voice_speed, :voice_temperature, :volume]
|
252
|
+
when 'llm'
|
253
|
+
[:model_temperature]
|
254
|
+
else
|
255
|
+
[]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def unknown_response_error(type)
|
260
|
+
raise Retell::SDK::Unofficial::Error, "Unknown response type for #{type} data"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
class Error < StandardError
|
265
|
+
attr_reader :code, :message
|
266
|
+
|
267
|
+
def initialize(code, message)
|
268
|
+
@code = code
|
269
|
+
@message = message
|
270
|
+
super("#{code}: #{message}")
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
class APITimeoutError < Error
|
276
|
+
attr_reader :request
|
277
|
+
|
278
|
+
def initialize(request)
|
279
|
+
@request = request
|
280
|
+
super(500, "API request timed out")
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Retell
|
2
|
+
module SDK
|
3
|
+
module Unofficial
|
4
|
+
class Concurrency < Base
|
5
|
+
@attributes = [
|
6
|
+
:current_concurrency, :concurrency_limit
|
7
|
+
]
|
8
|
+
|
9
|
+
attr_reader *@attributes
|
10
|
+
|
11
|
+
def retrieve
|
12
|
+
@client.concurrency.retrieve()
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Retell
|
2
|
+
module SDK
|
3
|
+
module Unofficial
|
4
|
+
class PhoneCall < BaseCall
|
5
|
+
@attributes = [:from_number, :to_number, :direction] + BaseCall.attributes
|
6
|
+
|
7
|
+
attr_reader *@attributes
|
8
|
+
|
9
|
+
def initialize(client, raw_response)
|
10
|
+
super(client, raw_response)
|
11
|
+
@from_number = raw_response[:from_number]
|
12
|
+
@to_number = raw_response[:to_number]
|
13
|
+
@direction = raw_response[:direction]
|
14
|
+
end
|
15
|
+
|
16
|
+
def retrieve
|
17
|
+
@client.call.retrieve(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Retell
|
2
|
+
module SDK
|
3
|
+
module Unofficial
|
4
|
+
class PhoneNumber < Base
|
5
|
+
@attributes = [
|
6
|
+
:phone_number, :phone_number_pretty, :inbound_agent_id, :outbound_agent_id,
|
7
|
+
:area_code, :nickname, :last_modification_timestamp
|
8
|
+
]
|
9
|
+
|
10
|
+
@writeable_attributes = [
|
11
|
+
:inbound_agent_id, :outbound_agent_id, :nickname
|
12
|
+
]
|
13
|
+
|
14
|
+
attr_reader *@attributes
|
15
|
+
|
16
|
+
@writeable_attributes.each do |attr|
|
17
|
+
define_method("#{attr}=") do |value|
|
18
|
+
self[attr] = value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def inbound_agent
|
23
|
+
inbound_agent_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def inbound_agent=(value)
|
27
|
+
self[:inbound_agent_id] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def outbound_agent
|
31
|
+
outbound_agent_id
|
32
|
+
end
|
33
|
+
|
34
|
+
def outbound_agent=(value)
|
35
|
+
self[:outbound_agent_id] = value
|
36
|
+
end
|
37
|
+
|
38
|
+
def retrieve
|
39
|
+
@client.phone_number.retrieve(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def update(**params)
|
43
|
+
update_params = @changed_attributes.merge(params)
|
44
|
+
|
45
|
+
if update_params.any?
|
46
|
+
updated_phone_number = @client.phone_number.update(self, **update_params)
|
47
|
+
self.class.attributes.each do |attr|
|
48
|
+
instance_variable_set("@#{attr}", updated_phone_number.send(attr))
|
49
|
+
end
|
50
|
+
@changed_attributes.clear
|
51
|
+
end
|
52
|
+
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete
|
57
|
+
@client.phone_number.delete(self)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Retell
|
2
|
+
module SDK
|
3
|
+
module Unofficial
|
4
|
+
class RetellLLM < Base
|
5
|
+
@attributes = [
|
6
|
+
:last_modification_timestamp, :llm_id, :llm_websocket_url, :begin_message,
|
7
|
+
:general_prompt, :general_tools, :inbound_dynamic_variables_webhook_url,
|
8
|
+
:model, :model_temperature, :starting_state, :states
|
9
|
+
]
|
10
|
+
|
11
|
+
@writeable_attributes = [
|
12
|
+
:begin_message,:general_prompt, :general_tools, :inbound_dynamic_variables_webhook_url, :model, :model_temperature, :states, :starting_state
|
13
|
+
]
|
14
|
+
|
15
|
+
attr_reader *@attributes
|
16
|
+
|
17
|
+
def id
|
18
|
+
llm_id
|
19
|
+
end
|
20
|
+
|
21
|
+
def websocket_url
|
22
|
+
llm_websocket_url
|
23
|
+
end
|
24
|
+
|
25
|
+
def url
|
26
|
+
llm_websocket_url
|
27
|
+
end
|
28
|
+
|
29
|
+
@writeable_attributes.each do |attr|
|
30
|
+
define_method("#{attr}=") do |value|
|
31
|
+
self[attr] = value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def retrieve
|
36
|
+
@client.retell_llm.retrieve(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(**params)
|
40
|
+
update_params = @changed_attributes.merge(params)
|
41
|
+
|
42
|
+
if update_params.any?
|
43
|
+
updated_retell_llm = @client.retell_llm.update(self, **update_params)
|
44
|
+
self.class.attributes.each do |attr|
|
45
|
+
instance_variable_set("@#{attr}", updated_retell_llm.send(attr))
|
46
|
+
end
|
47
|
+
@changed_attributes.clear
|
48
|
+
end
|
49
|
+
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def delete
|
54
|
+
@client.retell_llm.delete(self)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Retell
|
2
|
+
module SDK
|
3
|
+
module Unofficial
|
4
|
+
class Voice < Base
|
5
|
+
@attributes = [
|
6
|
+
:voice_id, :voice_name, :provider, :accent, :gender, :age, :preview_audio_url
|
7
|
+
]
|
8
|
+
|
9
|
+
attr_reader *@attributes
|
10
|
+
|
11
|
+
def retrieve
|
12
|
+
@client.voice.retrieve(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def id
|
16
|
+
voice_id
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
voice_name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Retell
|
2
|
+
module SDK
|
3
|
+
module Unofficial
|
4
|
+
class WebCall < BaseCall
|
5
|
+
@attributes = [:access_token] + BaseCall.attributes
|
6
|
+
|
7
|
+
attr_reader *@attributes
|
8
|
+
|
9
|
+
def initialize(client, raw_response)
|
10
|
+
super(client, raw_response)
|
11
|
+
@access_token = raw_response[:access_token]
|
12
|
+
end
|
13
|
+
|
14
|
+
def retrieve
|
15
|
+
@client.call.retrieve(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'unofficial/client'
|
2
|
+
require_relative 'unofficial/api/agent'
|
3
|
+
require_relative 'unofficial/api/call'
|
4
|
+
require_relative 'unofficial/api/retell_llm'
|
5
|
+
require_relative 'unofficial/api/phone_number'
|
6
|
+
require_relative 'unofficial/api/voice'
|
7
|
+
require_relative 'unofficial/api/concurrency'
|
8
|
+
require_relative 'unofficial/base'
|
9
|
+
require_relative 'unofficial/base_list'
|
10
|
+
require_relative 'unofficial/agent'
|
11
|
+
require_relative 'unofficial/agent_list'
|
12
|
+
require_relative 'unofficial/call'
|
13
|
+
require_relative 'unofficial/base_call'
|
14
|
+
require_relative 'unofficial/web_call'
|
15
|
+
require_relative 'unofficial/phone_call'
|
16
|
+
require_relative 'unofficial/call_list'
|
17
|
+
require_relative 'unofficial/retell_llm'
|
18
|
+
require_relative 'unofficial/retell_llm_list'
|
19
|
+
require_relative 'unofficial/phone_number'
|
20
|
+
require_relative 'unofficial/phone_number_list'
|
21
|
+
require_relative 'unofficial/voice'
|
22
|
+
require_relative 'unofficial/voice_list'
|
23
|
+
require_relative 'unofficial/concurrency'
|
24
|
+
|
25
|
+
module Retell
|
26
|
+
module SDK
|
27
|
+
module Unofficial
|
28
|
+
def self.new(api_key:, base_url: nil)
|
29
|
+
Client.new(base_url: base_url, api_key: api_key)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|