rager 0.5.0 → 0.7.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +49 -7
  3. data/lib/rager/chat/message.rb +10 -0
  4. data/lib/rager/chat/message_content.rb +7 -0
  5. data/lib/rager/chat/message_delta.rb +7 -0
  6. data/lib/rager/chat/options.rb +12 -9
  7. data/lib/rager/chat/providers/openai.rb +64 -48
  8. data/lib/rager/chat/schema.rb +3 -4
  9. data/lib/rager/config.rb +16 -20
  10. data/lib/rager/context.rb +326 -97
  11. data/lib/rager/context_options.rb +23 -0
  12. data/lib/rager/embed/options.rb +4 -3
  13. data/lib/rager/embed/providers/openai.rb +14 -6
  14. data/lib/rager/errors/credentials_error.rb +24 -0
  15. data/lib/rager/errors/dependency_error.rb +23 -0
  16. data/lib/rager/errors/http_error.rb +12 -5
  17. data/lib/rager/errors/options_error.rb +10 -5
  18. data/lib/rager/errors/parse_error.rb +9 -5
  19. data/lib/rager/errors/template_error.rb +10 -4
  20. data/lib/rager/errors/timeout_error.rb +25 -0
  21. data/lib/rager/http/adapters/async_http.rb +66 -14
  22. data/lib/rager/http/adapters/mock.rb +41 -45
  23. data/lib/rager/http/adapters/net_http.rb +144 -0
  24. data/lib/rager/http/request.rb +2 -0
  25. data/lib/rager/{image_gen → image}/options.rb +5 -4
  26. data/lib/rager/{image_gen → image}/output_format.rb +1 -1
  27. data/lib/rager/{image_gen → image}/providers/abstract.rb +4 -4
  28. data/lib/rager/{image_gen → image}/providers/replicate.rb +19 -14
  29. data/lib/rager/{logger.rb → log_strategy.rb} +2 -1
  30. data/lib/rager/{mesh_gen → mesh}/options.rb +4 -3
  31. data/lib/rager/{mesh_gen → mesh}/providers/abstract.rb +4 -4
  32. data/lib/rager/{mesh_gen → mesh}/providers/replicate.rb +20 -14
  33. data/lib/rager/operation.rb +2 -2
  34. data/lib/rager/options.rb +1 -1
  35. data/lib/rager/outcome.rb +25 -0
  36. data/lib/rager/providers.rb +61 -0
  37. data/lib/rager/rerank/{query.rb → input.rb} +8 -1
  38. data/lib/rager/rerank/options.rb +3 -2
  39. data/lib/rager/rerank/providers/abstract.rb +2 -2
  40. data/lib/rager/rerank/providers/cohere.rb +24 -15
  41. data/lib/rager/rerank/result.rb +8 -1
  42. data/lib/rager/result.rb +98 -108
  43. data/lib/rager/search/options.rb +4 -1
  44. data/lib/rager/search/providers/jina.rb +68 -0
  45. data/lib/rager/search/result.rb +9 -2
  46. data/lib/rager/template/input.rb +9 -0
  47. data/lib/rager/template/options.rb +1 -1
  48. data/lib/rager/template/providers/erb.rb +3 -3
  49. data/lib/rager/template/providers/mustache.rb +30 -0
  50. data/lib/rager/types.rb +28 -17
  51. data/lib/rager/utils/http.rb +92 -27
  52. data/lib/rager/utils/replicate.rb +40 -21
  53. data/lib/rager/utils/runtime.rb +21 -0
  54. data/lib/rager/version.rb +1 -1
  55. metadata +22 -36
  56. data/lib/rager/chat.rb +0 -35
  57. data/lib/rager/embed.rb +0 -35
  58. data/lib/rager/errors/missing_credentials_error.rb +0 -19
  59. data/lib/rager/errors/unknown_provider_error.rb +0 -17
  60. data/lib/rager/image_gen.rb +0 -31
  61. data/lib/rager/mesh_gen.rb +0 -31
  62. data/lib/rager/rerank.rb +0 -35
  63. data/lib/rager/search/providers/brave.rb +0 -59
  64. data/lib/rager/search.rb +0 -35
  65. data/lib/rager/template.rb +0 -35
data/lib/rager/context.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "securerandom"
5
+
5
6
  require "sorbet-runtime"
6
7
 
7
8
  module Rager
@@ -14,128 +15,297 @@ module Rager
14
15
  sig { returns(T.nilable(String)) }
15
16
  attr_reader :name
16
17
 
17
- sig { params(id: T.nilable(String), name: T.nilable(String)).void }
18
- def initialize(id: nil, name: nil)
18
+ sig { returns(T::Array[String]) }
19
+ attr_reader :tags
20
+
21
+ sig { returns(Integer) }
22
+ attr_reader :max_retries
23
+
24
+ sig { returns(Numeric) }
25
+ attr_reader :backoff
26
+
27
+ sig {
28
+ params(
29
+ id: T.nilable(String),
30
+ name: T.nilable(String),
31
+ tags: T::Array[String],
32
+ max_retries: T.nilable(Integer),
33
+ backoff: T.nilable(Numeric)
34
+ ).void
35
+ }
36
+ def initialize(id: nil, name: nil, tags: [], max_retries: nil, backoff: nil)
19
37
  @id = T.let(id || SecureRandom.uuid, String)
20
38
  @name = T.let(name, T.nilable(String))
39
+ @tags = T.let(tags, T::Array[String])
40
+ @max_retries = T.let(max_retries || 0, Integer)
41
+ @backoff = T.let(backoff || 1.0, Numeric)
42
+ end
43
+
44
+ sig do
45
+ params(
46
+ max_retries: T.nilable(Integer),
47
+ backoff: T.nilable(Numeric)
48
+ ).returns(Rager::Context)
49
+ end
50
+ def with_options(max_retries: nil, backoff: nil)
51
+ Context.new(
52
+ id: @id,
53
+ name: @name,
54
+ tags: @tags,
55
+ max_retries: max_retries || @max_retries,
56
+ backoff: backoff || @backoff
57
+ )
21
58
  end
22
59
 
23
60
  sig do
24
61
  params(
25
- messages: T.any(String, Rager::Types::ChatInput),
62
+ messages: T.any(String, Rager::Types::ChatInput, Rager::Result),
26
63
  kwargs: T.untyped
27
64
  ).returns(Rager::Result)
28
65
  end
29
66
  def chat(messages, **kwargs)
30
- if messages.is_a?(String)
31
- messages = [
67
+ context_options = Rager::ContextOptions.new(**Rager::ContextOptions.extract_kwargs(kwargs))
68
+ options = Rager::Chat::Options.new(**kwargs)
69
+ options.validate
70
+
71
+ normalized_input, input_ids = normalize(messages, context_options.input_ids)
72
+
73
+ if normalized_input.is_a?(String)
74
+ normalized_input = [
32
75
  Rager::Chat::Message.new(
33
76
  role: Rager::Chat::MessageRole::User,
34
- content: messages
77
+ content: normalized_input
35
78
  )
36
79
  ]
37
80
  end
38
81
 
39
82
  execute(
40
- Rager::Operation::Chat,
41
- Rager::Chat::Options,
42
- kwargs,
43
- messages
44
- ) { |options| Chat.chat(messages, options) }
83
+ operation: Rager::Operation::Chat,
84
+ input: normalized_input,
85
+ options: options,
86
+ context_options: context_options,
87
+ input_ids: input_ids
88
+ ) do |input, opts|
89
+ Rager::Providers
90
+ .get_provider(Rager::Operation::Chat, opts.provider, opts)
91
+ .chat(input, opts)
92
+ end
45
93
  end
46
94
 
47
95
  sig do
48
96
  params(
49
- text: T.any(String, Rager::Types::EmbedInput),
97
+ text: T.any(String, Rager::Types::EmbedInput, Rager::Result),
50
98
  kwargs: T.untyped
51
99
  ).returns(Rager::Result)
52
100
  end
53
101
  def embed(text, **kwargs)
54
- if text.is_a?(String)
55
- text = [text]
56
- end
102
+ context_options = Rager::ContextOptions.new(**Rager::ContextOptions.extract_kwargs(kwargs))
103
+ options = Rager::Embed::Options.new(**kwargs)
104
+ options.validate
105
+
106
+ normalized_input, input_ids = normalize(text, context_options.input_ids)
107
+
108
+ normalized_input = [normalized_input] if normalized_input.is_a?(String)
57
109
 
58
110
  execute(
59
- Rager::Operation::Embed,
60
- Rager::Embed::Options,
61
- kwargs,
62
- text
63
- ) { |options| Embed.embed(text, options) }
111
+ operation: Rager::Operation::Embed,
112
+ input: normalized_input,
113
+ options: options,
114
+ context_options: context_options,
115
+ input_ids: input_ids
116
+ ) do |input, opts|
117
+ Rager::Providers
118
+ .get_provider(Rager::Operation::Embed, opts.provider, opts)
119
+ .embed(input, opts)
120
+ end
64
121
  end
65
122
 
66
123
  sig do
67
124
  params(
68
- prompt: Rager::Types::ImageGenInput,
125
+ prompt: T.any(Rager::Types::ImageInput, Rager::Result),
69
126
  kwargs: T.untyped
70
127
  ).returns(Rager::Result)
71
128
  end
72
- def image_gen(prompt, **kwargs)
129
+ def image(prompt, **kwargs)
130
+ context_options = Rager::ContextOptions.new(**Rager::ContextOptions.extract_kwargs(kwargs))
131
+ options = Rager::Image::Options.new(**kwargs)
132
+ options.validate
133
+
134
+ normalized_input, input_ids = normalize(prompt, context_options.input_ids)
135
+
73
136
  execute(
74
- Rager::Operation::ImageGen,
75
- Rager::ImageGen::Options,
76
- kwargs,
77
- prompt
78
- ) { |options| ImageGen.image_gen(prompt, options) }
137
+ operation: Rager::Operation::Image,
138
+ input: normalized_input,
139
+ options: options,
140
+ context_options: context_options,
141
+ input_ids: input_ids
142
+ ) do |input, opts|
143
+ Rager::Providers
144
+ .get_provider(Rager::Operation::Image, opts.provider, opts)
145
+ .image(input, opts)
146
+ end
79
147
  end
80
148
 
81
149
  sig do
82
150
  params(
83
- prompt: Rager::Types::MeshGenInput,
151
+ prompt: T.any(Rager::Types::MeshInput, Rager::Result),
84
152
  kwargs: T.untyped
85
153
  ).returns(Rager::Result)
86
154
  end
87
- def mesh_gen(prompt, **kwargs)
155
+ def mesh(prompt, **kwargs)
156
+ context_options = Rager::ContextOptions.new(**Rager::ContextOptions.extract_kwargs(kwargs))
157
+ options = Rager::Mesh::Options.new(**kwargs)
158
+ options.validate
159
+
160
+ normalized_input, input_ids = normalize(prompt, context_options.input_ids)
161
+
88
162
  execute(
89
- Rager::Operation::MeshGen,
90
- Rager::MeshGen::Options,
91
- kwargs,
92
- prompt
93
- ) { |options| MeshGen.mesh_gen(prompt, options) }
163
+ operation: Rager::Operation::Mesh,
164
+ input: normalized_input,
165
+ options: options,
166
+ context_options: context_options,
167
+ input_ids: input_ids
168
+ ) do |input, opts|
169
+ Rager::Providers
170
+ .get_provider(Rager::Operation::Mesh, opts.provider, opts)
171
+ .mesh(input, opts)
172
+ end
94
173
  end
95
174
 
96
175
  sig do
97
176
  params(
98
- query: Rager::Types::RerankInput,
177
+ query: T.any(String, Rager::Result),
178
+ documents: T.any(T::Array[String], Rager::Result),
99
179
  kwargs: T.untyped
100
180
  ).returns(Rager::Result)
101
181
  end
102
- def rerank(query, **kwargs)
182
+ def rerank(query, documents, **kwargs)
183
+ context_options = Rager::ContextOptions.new(**Rager::ContextOptions.extract_kwargs(kwargs))
184
+ options = Rager::Rerank::Options.new(**kwargs)
185
+ options.validate
186
+
187
+ normalized_query, input_ids = normalize(query, context_options.input_ids)
188
+ normalized_documents, input_ids = normalize(documents, input_ids)
189
+
190
+ rerank_input = Rager::Rerank::Input.new(
191
+ query: normalized_query,
192
+ documents: normalized_documents
193
+ )
194
+
103
195
  execute(
104
- Rager::Operation::Rerank,
105
- Rager::Rerank::Options,
106
- kwargs,
107
- query
108
- ) { |options| Rager::Rerank.rerank(query, options) }
196
+ operation: Rager::Operation::Rerank,
197
+ input: rerank_input,
198
+ options: options,
199
+ context_options: context_options,
200
+ input_ids: input_ids
201
+ ) do |input, opts|
202
+ Rager::Providers
203
+ .get_provider(Rager::Operation::Rerank, opts.provider, opts)
204
+ .rerank(input, opts)
205
+ end
109
206
  end
110
207
 
111
208
  sig do
112
209
  params(
113
- query: Rager::Types::SearchInput,
210
+ query: T.any(Rager::Types::SearchInput, Rager::Result),
114
211
  kwargs: T.untyped
115
212
  ).returns(Rager::Result)
116
213
  end
117
214
  def search(query, **kwargs)
215
+ context_options = Rager::ContextOptions.new(**Rager::ContextOptions.extract_kwargs(kwargs))
216
+ options = Rager::Search::Options.new(**kwargs)
217
+ options.validate
218
+
219
+ normalized_input, input_ids = normalize(query, context_options.input_ids)
220
+
118
221
  execute(
119
- Rager::Operation::Search,
120
- Rager::Search::Options,
121
- kwargs,
122
- query
123
- ) { |options| Search.search(query, options) }
222
+ operation: Rager::Operation::Search,
223
+ input: normalized_input,
224
+ options: options,
225
+ context_options: context_options,
226
+ input_ids: input_ids
227
+ ) do |input, opts|
228
+ Rager::Providers
229
+ .get_provider(Rager::Operation::Search, opts.provider, opts)
230
+ .search(input, opts)
231
+ end
124
232
  end
125
233
 
126
234
  sig do
127
235
  params(
128
- input: Rager::Types::TemplateInput,
236
+ template: T.any(String, Rager::Result),
237
+ variables: T.any(T::Hash[Symbol, T.untyped], Rager::Result),
129
238
  kwargs: T.untyped
130
239
  ).returns(Rager::Result)
131
240
  end
132
- def template(input, **kwargs)
241
+ def template(template, variables, **kwargs)
242
+ context_options = Rager::ContextOptions.new(**Rager::ContextOptions.extract_kwargs(kwargs))
243
+ options = Rager::Template::Options.new(**kwargs)
244
+ options.validate
245
+
246
+ normalized_template, input_ids = normalize(template, context_options.input_ids)
247
+ normalized_variables, input_ids = normalize(variables, input_ids)
248
+
249
+ template_input = Rager::Template::Input.new(
250
+ template: normalized_template,
251
+ variables: normalized_variables
252
+ )
253
+
133
254
  execute(
134
- Rager::Operation::Template,
135
- Rager::Template::Options,
136
- kwargs,
137
- input
138
- ) { |options| Template.template(input, options) }
255
+ operation: Rager::Operation::Template,
256
+ input: template_input,
257
+ options: options,
258
+ context_options: context_options,
259
+ input_ids: input_ids
260
+ ) do |input, opts|
261
+ Rager::Providers
262
+ .get_provider(Rager::Operation::Template, opts.provider, opts)
263
+ .template(input, opts)
264
+ end
265
+ end
266
+
267
+ sig do
268
+ params(
269
+ value: Float,
270
+ feedback: T.nilable(String),
271
+ tags: T::Array[String]
272
+ ).void
273
+ end
274
+ def outcome(value, feedback: nil, tags: [])
275
+ Rager::Utils::Http.log_remote(
276
+ "outcomes",
277
+ {
278
+ version: "1",
279
+ data: Rager::Outcome.new(
280
+ context_id: @id,
281
+ value: value,
282
+ feedback: feedback,
283
+ tags: tags
284
+ )
285
+ }.to_json
286
+ )
287
+ end
288
+
289
+ sig { returns(T::Hash[Symbol, T.untyped]) }
290
+ def to_h
291
+ {
292
+ id: @id,
293
+ name: @name,
294
+ tags: @tags,
295
+ max_retries: @max_retries,
296
+ backoff: @backoff
297
+ }
298
+ end
299
+
300
+ sig { params(hash: T::Hash[Symbol, T.untyped], max_retries: T.nilable(Integer), backoff: T.nilable(Float)).returns(Rager::Context) }
301
+ def self.from_h(hash, max_retries: nil, backoff: nil)
302
+ new(
303
+ id: hash[:id],
304
+ name: hash[:name],
305
+ tags: hash[:tags],
306
+ max_retries: max_retries || hash[:max_retries],
307
+ backoff: backoff || hash[:backoff]
308
+ )
139
309
  end
140
310
 
141
311
  private
@@ -143,55 +313,114 @@ module Rager
143
313
  sig do
144
314
  params(
145
315
  operation: Rager::Operation,
146
- options_struct: T::Class[Rager::Options],
147
- kwargs: T.untyped,
148
316
  input: Rager::Types::Input,
149
- block: T.proc.params(options: T.untyped).returns(T.untyped)
317
+ options: Rager::Types::Options,
318
+ context_options: Rager::ContextOptions,
319
+ input_ids: T::Array[String],
320
+ block: T.proc.params(
321
+ input: Rager::Types::Input,
322
+ options: Rager::Types::Options
323
+ ).returns(Rager::Types::Output)
150
324
  ).returns(Rager::Result)
151
325
  end
152
- def execute(operation, options_struct, kwargs, input, &block)
153
- name = kwargs.delete(:name)
154
- iids = kwargs.delete(:iids)
155
-
156
- options = options_struct.new(**kwargs)
157
- options.validate
158
-
326
+ def execute(operation:, input:, options:, context_options:, input_ids:, &block)
159
327
  start_time = Time.now
328
+ attempt = 0
329
+ errors = []
330
+ last_error = nil
160
331
 
161
332
  begin
162
- output = yield(options)
163
-
164
- Result.new(
165
- id: SecureRandom.uuid,
166
- context_id: @id,
167
- operation: operation,
168
- input: input,
169
- output: output,
170
- options: options,
171
- start_time: start_time.to_i,
172
- end_time: Time.now.to_i,
173
- name: name,
174
- context_name: @name,
175
- iids: iids,
176
- error: nil
177
- ).tap(&:log)
178
- rescue => e
179
- Result.new(
180
- id: SecureRandom.uuid,
181
- context_id: @id,
182
- operation: operation,
183
- input: input,
184
- output: nil,
185
- options: options,
186
- start_time: start_time.to_i,
187
- end_time: Time.now.to_i,
188
- name: name,
189
- context_name: @name,
190
- iids: iids,
191
- error: e.message
192
- ).tap(&:log)
193
-
194
- raise e
333
+ output = yield(input, options)
334
+ rescue Rager::Errors::HttpError => e
335
+ errors << e.message
336
+ last_error = e
337
+ attempt += 1
338
+
339
+ if attempt <= @max_retries
340
+ jitter = @backoff * rand(0.0..1.0)
341
+ delay = @backoff * (2**(attempt - 1)) + jitter
342
+ Rager.config.logger.warn("Retrying in #{delay.round(2)}s after failure #{attempt}/#{@max_retries}: #{e.message}")
343
+
344
+ Rager::Utils::Runtime.sleep(delay)
345
+
346
+ retry
347
+ else
348
+ output = nil
349
+ end
350
+ end
351
+
352
+ result = Result.new(
353
+ id: SecureRandom.uuid,
354
+ context_id: @id,
355
+ operation: operation,
356
+ input: input,
357
+ output: output,
358
+ options: options,
359
+ start_time: start_time.to_i,
360
+ end_time: Time.now.to_i,
361
+ attempt: attempt,
362
+ errors: errors,
363
+ input_ids: input_ids.uniq,
364
+ name: context_options.name,
365
+ tags: context_options.tags,
366
+ context_name: @name,
367
+ context_tags: @tags
368
+ ).tap(&:log)
369
+
370
+ raise last_error if last_error
371
+
372
+ result
373
+ end
374
+
375
+ sig {
376
+ params(
377
+ input: T.untyped,
378
+ ids: T.nilable(T::Array[String])
379
+ ).returns([T.untyped, T::Array[String]])
380
+ }
381
+ def normalize(input, ids = nil)
382
+ collected_ids = (ids || []).to_set
383
+ visited = Set.new
384
+
385
+ normalized_input = normalize_item(input, collected_ids, visited)
386
+ [normalized_input, collected_ids.to_a]
387
+ end
388
+
389
+ sig {
390
+ params(
391
+ item: T.untyped,
392
+ collected_ids: T::Set[String],
393
+ visited: T::Set[Integer]
394
+ ).returns(T.untyped)
395
+ }
396
+ def normalize_item(item, collected_ids, visited)
397
+ case item
398
+ when Rager::Result
399
+ collected_ids.add(item.id)
400
+ normalize_item(item.value, collected_ids, visited)
401
+ when Array
402
+ object_id = item.object_id
403
+ return item if visited.include?(object_id)
404
+ visited.add(object_id)
405
+
406
+ item.map { |i| normalize_item(i, collected_ids, visited) }
407
+ when Hash
408
+ object_id = item.object_id
409
+ return item if visited.include?(object_id)
410
+ visited.add(object_id)
411
+
412
+ item.transform_values { |value| normalize_item(value, collected_ids, visited) }
413
+ when T::Struct
414
+ object_id = item.object_id
415
+ return item if visited.include?(object_id)
416
+ visited.add(object_id)
417
+
418
+ transformed_props = item.class.props.each_key.each_with_object({}) do |prop_name, acc|
419
+ acc[prop_name] = normalize_item(item.send(prop_name), collected_ids, visited)
420
+ end
421
+ item.class.new(transformed_props)
422
+ else
423
+ item
195
424
  end
196
425
  end
197
426
  end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ class ContextOptions < T::Struct
8
+ extend T::Sig
9
+
10
+ const :input_ids, T::Array[String], default: []
11
+ const :tags, T::Array[T.untyped], default: []
12
+ const :name, T.nilable(String)
13
+
14
+ sig { params(kwargs: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
15
+ def self.extract_kwargs(kwargs)
16
+ {
17
+ input_ids: kwargs.delete(:input_ids),
18
+ tags: kwargs.delete(:tags),
19
+ name: kwargs.delete(:name)
20
+ }.compact
21
+ end
22
+ end
23
+ end
@@ -9,11 +9,12 @@ module Rager
9
9
  extend T::Sig
10
10
  include Rager::Options
11
11
 
12
- const :provider, String, default: "openai"
13
- const :url, T.nilable(String)
12
+ const :provider, Symbol, default: :openai
14
13
  const :model, T.nilable(String)
15
- const :api_key, T.nilable(String)
16
14
  const :seed, T.nilable(Integer)
15
+ const :url, T.nilable(String)
16
+ const :api_key, T.nilable(String)
17
+ const :timeout, T.nilable(Numeric)
17
18
  end
18
19
  end
19
20
  end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "json"
5
+
5
6
  require "sorbet-runtime"
6
7
 
7
8
  module Rager
@@ -18,10 +19,16 @@ module Rager
18
19
  end
19
20
  def embed(text, options)
20
21
  api_key = options.api_key || ENV["OPENAI_API_KEY"]
21
- raise Rager::Errors::MissingCredentialsError.new("OpenAI", "OPENAI_API_KEY") if api_key.nil?
22
+ raise Rager::Errors::CredentialsError.new("OpenAI", env_var: ["OPENAI_API_KEY"]) if api_key.nil?
23
+
24
+ base_url = options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1"
25
+ url = "#{base_url}/embeddings"
22
26
 
23
- headers = {"Content-Type" => "application/json"}
24
- headers["Authorization"] = "Bearer #{api_key}" if api_key
27
+ headers = {
28
+ "Content-Type" => "application/json"
29
+ }.tap do |h|
30
+ h["Authorization"] = "Bearer #{api_key}" if api_key
31
+ end
25
32
 
26
33
  body = {
27
34
  model: options.model || "text-embedding-3-large",
@@ -30,15 +37,16 @@ module Rager
30
37
 
31
38
  request = Rager::Http::Request.new(
32
39
  verb: Rager::Http::Verb::Post,
33
- url: options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1/embeddings",
40
+ url: url,
34
41
  headers: headers,
35
- body: body.to_json
42
+ body: body.to_json,
43
+ timeout: options.timeout || Rager.config.timeout
36
44
  )
37
45
 
38
46
  response = Rager.config.http_adapter.make_request(request)
39
47
  response_body = T.cast(T.must(response.body), String)
40
48
 
41
- raise Rager::Errors::HttpError.new(Rager.config.http_adapter, response.status, response_body) if response.status != 200
49
+ raise Rager::Errors::HttpError.new(Rager.config.http_adapter, request.url, response.status, body: response_body) if response.status != 200
42
50
 
43
51
  parsed_response = JSON.parse(response_body)
44
52
  parsed_response["data"].map { |item| item["embedding"] }
@@ -0,0 +1,24 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Errors
8
+ class CredentialsError < Rager::Error
9
+ extend T::Sig
10
+
11
+ sig { params(provider: String, env_var: T::Array[String], details: T.nilable(String)).void }
12
+ def initialize(provider, env_var: [], details: nil)
13
+ error_data = {
14
+ type: "credentials",
15
+ provider: provider,
16
+ env_var: env_var,
17
+ details: details
18
+ }
19
+
20
+ super(error_data.to_json)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Errors
8
+ class DependencyError < Rager::Error
9
+ extend T::Sig
10
+
11
+ sig { params(dependency: String, details: T.nilable(String)).void }
12
+ def initialize(dependency, details: nil)
13
+ error_data = {
14
+ type: "dependency",
15
+ dependency: dependency,
16
+ details: details
17
+ }
18
+
19
+ super(error_data.to_json)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -8,11 +8,18 @@ module Rager
8
8
  class HttpError < Rager::Error
9
9
  extend T::Sig
10
10
 
11
- sig { params(adapter: Rager::Http::Adapters::Abstract, status: Integer, body: T.nilable(String)).void }
12
- def initialize(adapter, status, body)
13
- message = "HTTP Error #{status} using #{adapter.class.name}"
14
- message += ": #{body}" if body
15
- super(message)
11
+ sig { params(adapter: Rager::Http::Adapters::Abstract, url: T.nilable(String), status: Integer, body: T.nilable(String), details: T.nilable(String)).void }
12
+ def initialize(adapter, url, status, body: nil, details: nil)
13
+ error_data = {
14
+ type: "http",
15
+ adapter: adapter.class.name,
16
+ url: url,
17
+ status: status,
18
+ body: body,
19
+ details: details
20
+ }
21
+
22
+ super(error_data.to_json)
16
23
  end
17
24
  end
18
25
  end