rager 0.6.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -27
  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 +6 -7
  7. data/lib/rager/chat/providers/openai.rb +49 -34
  8. data/lib/rager/chat/schema.rb +0 -2
  9. data/lib/rager/config.rb +12 -20
  10. data/lib/rager/context.rb +302 -186
  11. data/lib/rager/context_options.rb +23 -0
  12. data/lib/rager/embed/options.rb +3 -3
  13. data/lib/rager/embed/providers/openai.rb +7 -3
  14. data/lib/rager/errors/options_error.rb +1 -1
  15. data/lib/rager/http/adapters/async_http.rb +0 -2
  16. data/lib/rager/http/adapters/mock.rb +0 -2
  17. data/lib/rager/http/adapters/net_http.rb +18 -19
  18. data/lib/rager/{image_gen → image}/options.rb +4 -4
  19. data/lib/rager/{image_gen → image}/output_format.rb +1 -1
  20. data/lib/rager/{image_gen → image}/providers/abstract.rb +4 -4
  21. data/lib/rager/{image_gen → image}/providers/replicate.rb +14 -10
  22. data/lib/rager/{logger.rb → log_strategy.rb} +2 -1
  23. data/lib/rager/{mesh_gen → mesh}/options.rb +3 -3
  24. data/lib/rager/{mesh_gen → mesh}/providers/abstract.rb +4 -4
  25. data/lib/rager/{mesh_gen → mesh}/providers/replicate.rb +13 -9
  26. data/lib/rager/operation.rb +2 -2
  27. data/lib/rager/options.rb +1 -1
  28. data/lib/rager/outcome.rb +25 -0
  29. data/lib/rager/providers.rb +37 -25
  30. data/lib/rager/rerank/input.rb +20 -0
  31. data/lib/rager/rerank/options.rb +2 -2
  32. data/lib/rager/rerank/providers/abstract.rb +2 -3
  33. data/lib/rager/rerank/providers/cohere.rb +19 -13
  34. data/lib/rager/rerank/result.rb +20 -0
  35. data/lib/rager/result.rb +92 -122
  36. data/lib/rager/search/options.rb +3 -2
  37. data/lib/rager/search/providers/jina.rb +16 -15
  38. data/lib/rager/search/result.rb +21 -0
  39. data/lib/rager/template/input.rb +20 -0
  40. data/lib/rager/template/options.rb +1 -1
  41. data/lib/rager/template/providers/abstract.rb +2 -3
  42. data/lib/rager/template/providers/erb.rb +4 -5
  43. data/lib/rager/template/providers/mustache.rb +30 -0
  44. data/lib/rager/types.rb +31 -24
  45. data/lib/rager/utils/http.rb +73 -15
  46. data/lib/rager/utils/replicate.rb +28 -6
  47. data/lib/rager/utils/runtime.rb +21 -0
  48. data/lib/rager/version.rb +1 -1
  49. metadata +18 -12
  50. data/lib/rager/rerank/output.rb +0 -13
  51. data/lib/rager/search/output.rb +0 -14
data/lib/rager/result.rb CHANGED
@@ -26,7 +26,7 @@ module Rager
26
26
  sig { returns(T.nilable(Rager::Types::Output)) }
27
27
  attr_reader :output
28
28
 
29
- sig { returns(Rager::Options) }
29
+ sig { returns(Rager::Types::Options) }
30
30
  attr_reader :options
31
31
 
32
32
  sig { returns(Integer) }
@@ -35,23 +35,29 @@ module Rager
35
35
  sig { returns(Integer) }
36
36
  attr_reader :end_time
37
37
 
38
- sig { returns(T.nilable(String)) }
39
- attr_reader :name
38
+ sig { returns(Integer) }
39
+ attr_reader :attempt
40
+
41
+ sig { returns(T::Array[String]) }
42
+ attr_reader :errors
43
+
44
+ sig { returns(T::Array[String]) }
45
+ attr_reader :input_ids
40
46
 
41
47
  sig { returns(T.nilable(String)) }
42
- attr_reader :context_name
48
+ attr_reader :name
43
49
 
44
50
  sig { returns(T::Array[String]) }
45
51
  attr_reader :tags
46
52
 
47
- sig { returns(T::Array[String]) }
48
- attr_reader :input_ids
53
+ sig { returns(T.nilable(String)) }
54
+ attr_reader :context_name
49
55
 
50
56
  sig { returns(T::Array[String]) }
51
- attr_reader :errors
57
+ attr_reader :context_tags
52
58
 
53
- sig { returns(Integer) }
54
- attr_reader :attempt
59
+ sig { returns(T.untyped) }
60
+ attr_reader :transform
55
61
 
56
62
  sig do
57
63
  params(
@@ -60,33 +66,20 @@ module Rager
60
66
  operation: Rager::Operation,
61
67
  input: Rager::Types::Input,
62
68
  output: T.nilable(Rager::Types::Output),
63
- options: Rager::Options,
69
+ options: Rager::Types::Options,
64
70
  start_time: Integer,
65
71
  end_time: Integer,
72
+ attempt: Integer,
73
+ errors: T::Array[String],
74
+ input_ids: T::Array[String],
66
75
  name: T.nilable(String),
67
- context_name: T.nilable(String),
68
76
  tags: T::Array[String],
69
- input_ids: T::Array[String],
70
- errors: T::Array[String],
71
- attempt: Integer
77
+ context_name: T.nilable(String),
78
+ context_tags: T::Array[String],
79
+ transform: T.untyped
72
80
  ).void
73
81
  end
74
- def initialize(
75
- id:,
76
- context_id:,
77
- operation:,
78
- input:,
79
- output:,
80
- options:,
81
- start_time:,
82
- end_time:,
83
- name: nil,
84
- context_name: nil,
85
- tags: [],
86
- input_ids: [],
87
- errors: [],
88
- attempt: 0
89
- )
82
+ def initialize(id:, context_id:, operation:, input:, output:, options:, start_time:, end_time:, attempt: 0, errors: [], input_ids: [], name: nil, tags: [], context_name: nil, context_tags: [], transform: nil)
90
83
  @id = id
91
84
  @context_id = context_id
92
85
  @operation = operation
@@ -95,12 +88,14 @@ module Rager
95
88
  @options = options
96
89
  @start_time = start_time
97
90
  @end_time = end_time
98
- @name = T.let(name, T.nilable(String))
99
- @context_name = T.let(context_name, T.nilable(String))
100
- @tags = T.let(tags, T::Array[String])
101
- @input_ids = T.let(input_ids, T::Array[String])
102
- @errors = T.let(errors, T::Array[String])
103
91
  @attempt = attempt
92
+ @errors = T.let(errors, T::Array[String])
93
+ @input_ids = T.let(input_ids, T::Array[String])
94
+ @name = name
95
+ @tags = tags
96
+ @context_name = context_name
97
+ @context_tags = T.let(context_tags, T::Array[String])
98
+ @transform = transform
104
99
 
105
100
  @stream = T.let(nil, T.nilable(Rager::Types::Stream))
106
101
  @buffer = T.let([], Rager::Types::Buffer)
@@ -118,7 +113,7 @@ module Rager
118
113
  end
119
114
 
120
115
  sig { returns(Rager::Types::Output) }
121
- def out
116
+ def stream
122
117
  return T.must(@output) unless stream?
123
118
  return @buffer.each if @consumed
124
119
 
@@ -138,123 +133,98 @@ module Rager
138
133
  @stream
139
134
  end
140
135
 
141
- sig { returns(Rager::Types::NonStreamOutput) }
142
- def mat
143
- return T.cast(@output, Rager::Types::NonStreamOutput) unless stream?
136
+ sig { returns(T.untyped) }
137
+ def value
138
+ return @transform if @transform
144
139
 
145
- if !@consumed
146
- T.cast(out, Rager::Types::Stream).each { |_| }
147
- end
140
+ return T.cast(@output, Rager::Types::NonStreamOutput) unless stream?
148
141
 
149
- parts = {}
142
+ T.cast(stream, Rager::Types::Stream).each { |_| } unless @consumed
150
143
 
151
- @buffer.each do |message_delta|
152
- parts[message_delta.index] =
153
- (parts[message_delta.index] || "") + message_delta.content
154
- end
155
-
156
- parts
157
- .sort_by { |index, _| index }
158
- .map { |_, content| content }
144
+ @buffer
145
+ .group_by(&:index)
146
+ .transform_values { |deltas| deltas.map(&:content).join }
147
+ .sort
148
+ .map(&:last)
159
149
  .then { |parts| (parts.length == 1) ? parts.first : parts }
160
150
  end
161
151
 
162
152
  sig do
163
- returns(
164
- T.any(
165
- String,
166
- T::Hash[String, T.untyped],
167
- T::Array[T.untyped]
168
- )
169
- )
170
- end
171
- def serialize_input
172
- case @input
173
- when String
174
- @input
175
- when Hash
176
- @input.transform_keys(&:to_s)
177
- when Array
178
- @input.map do |item|
179
- if !item.is_a?(String)
180
- item.serialize
181
- else
182
- item
183
- end
184
- end
185
- else
186
- @input.to_s
187
- end
153
+ params(
154
+ block: T.proc.params(
155
+ value: Rager::Types::NonStreamOutput
156
+ ).returns(T.untyped)
157
+ ).returns(Rager::Result)
188
158
  end
159
+ def let(&block)
160
+ transform = yield(value)
189
161
 
190
- sig { returns(T.nilable(Rager::Types::NonStreamOutput)) }
191
- def serialize_output
192
- return nil unless success?
193
- return @consumed ? mat : "[STREAM]" if stream?
194
- T.cast(@output, Rager::Types::NonStreamOutput)
162
+ Result.new(
163
+ id: @id,
164
+ context_id: @context_id,
165
+ operation: @operation,
166
+ input: @input,
167
+ output: @output,
168
+ options: @options,
169
+ start_time: @start_time,
170
+ end_time: @end_time,
171
+ attempt: @attempt,
172
+ errors: @errors,
173
+ input_ids: @input_ids,
174
+ name: @name,
175
+ tags: @tags,
176
+ context_name: @context_name,
177
+ context_tags: @context_tags,
178
+ transform: transform
179
+ )
195
180
  end
196
181
 
197
- sig { returns(T::Hash[String, T.untyped]) }
182
+ sig { returns(T::Hash[Symbol, T.untyped]) }
198
183
  def to_h
199
184
  {
200
- id: @id,
201
185
  version: "1",
202
186
  data: {
187
+ id: @id,
203
188
  context_id: @context_id,
204
189
  operation: @operation.serialize,
205
- input: {input: serialize_input},
206
- output: {output: serialize_output},
190
+ input: @input,
191
+ output: display_output,
207
192
  options: @options.serialize_safe,
208
193
  start_time: @start_time,
209
194
  end_time: @end_time,
195
+ attempt: @attempt,
196
+ errors: @errors,
197
+ input_ids: @input_ids,
210
198
  name: @name,
211
- context_name: @context_name,
212
199
  tags: @tags,
213
- input_ids: @input_ids,
214
- errors: @errors,
215
- attempt: @attempt
200
+ context_name: @context_name,
201
+ context_tags: @context_tags
216
202
  }
217
203
  }
218
204
  end
219
205
 
206
+ sig { returns(String) }
207
+ def to_json
208
+ to_h.to_json
209
+ end
210
+
220
211
  sig { void }
221
212
  def log
222
- return unless Rager.config.logger_type
223
-
224
- json = to_h.to_json
225
-
226
- logger = Rager.config.logger
227
-
228
- case Rager.config.logger_type
229
- when Rager::Logger::Stdout
230
- success? ? logger.info(json) : logger.error(json)
231
- when Rager::Logger::Remote
232
- http_adapter = Rager.config.http_adapter
233
- url = Rager.config.url
234
- api_key = Rager.config.api_key
235
-
236
- unless url && api_key
237
- raise Rager::Errors::CredentialsError.new("Rager Cloud", details: "Missing url or api_key for remote logging")
238
- end
239
-
240
- headers = {
241
- "Content-Type" => "application/json",
242
- "Authorization" => "Bearer #{api_key}"
243
- }
213
+ Rager::Utils::Http.log_remote(
214
+ "results",
215
+ to_json,
216
+ !success?
217
+ )
218
+ end
244
219
 
245
- request = Rager::Http::Request.new(
246
- url: url,
247
- verb: Rager::Http::Verb::Post,
248
- headers: headers,
249
- body: json
250
- )
220
+ private
251
221
 
252
- response = http_adapter.make_request(request)
222
+ sig { returns(T.nilable(Rager::Types::NonStreamOutput)) }
223
+ def display_output
224
+ return nil unless success?
225
+ return @consumed ? value : "[STREAM]" if stream?
253
226
 
254
- unless response.success?
255
- logger.error("Failed to log to remote server: #{response.status} #{response.body}")
256
- end
257
- end
227
+ T.cast(@output, Rager::Types::NonStreamOutput)
258
228
  end
259
229
  end
260
230
  end
@@ -9,9 +9,10 @@ module Rager
9
9
  extend T::Sig
10
10
  include Rager::Options
11
11
 
12
- const :provider, String, default: "jina"
13
- const :max_length, T.nilable(Integer)
12
+ const :provider, Symbol, default: :jina
14
13
  const :n, T.nilable(Integer)
14
+ const :pagination, T.nilable(Integer)
15
+ const :max_length, T.nilable(Integer)
15
16
  const :api_key, T.nilable(String)
16
17
  const :timeout, T.nilable(Numeric)
17
18
  end
@@ -22,18 +22,21 @@ module Rager
22
22
  api_key = options.api_key || ENV["JINA_API_KEY"]
23
23
  raise Rager::Errors::CredentialsError.new("Jina", env_var: ["JINA_API_KEY"]) if api_key.nil?
24
24
 
25
- params = {"q" => query}
25
+ base_url = "https://s.jina.ai"
26
+ url = "#{base_url}/?#{URI.encode_www_form({"q" => query})}"
27
+ pagination = options.pagination
28
+ url = "#{url}&page=#{pagination}" if pagination && pagination > 1
26
29
 
27
30
  headers = {
28
31
  "Accept" => "application/json",
29
32
  "X-Return-Format" => "markdown"
30
- }
31
-
32
- headers["Authorization"] = "Bearer #{api_key}" if api_key
33
+ }.tap do |h|
34
+ h["Authorization"] = "Bearer #{api_key}" if api_key
35
+ end
33
36
 
34
37
  request = Rager::Http::Request.new(
35
38
  verb: Rager::Http::Verb::Get,
36
- url: "https://s.jina.ai/?#{URI.encode_www_form(params)}",
39
+ url: url,
37
40
  headers: headers,
38
41
  timeout: options.timeout || Rager.config.timeout
39
42
  )
@@ -48,18 +51,16 @@ module Rager
48
51
 
49
52
  search_results = search_results.first(options.n) if options.n
50
53
 
51
- urls = search_results.map { |r| r["url"] }
52
- titles = search_results.map { |r| r["title"] }
53
- contents = search_results.map { |r|
54
+ search_results.map do |r|
54
55
  content = r["content"] || r["description"]
55
- options.max_length ? content&.slice(0, options.max_length) : content
56
- }
56
+ content = content&.slice(0, options.max_length) if options.max_length
57
57
 
58
- Rager::Search::Output.new(
59
- urls: urls,
60
- titles: titles,
61
- contents: contents
62
- )
58
+ Rager::Search::Result.new(
59
+ url: r["url"],
60
+ title: r["title"],
61
+ content: content
62
+ )
63
+ end
63
64
  end
64
65
  end
65
66
  end
@@ -0,0 +1,21 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Search
8
+ class Result < T::Struct
9
+ extend T::Sig
10
+
11
+ const :url, String
12
+ const :title, String
13
+ const :content, String
14
+
15
+ sig { params(options: T.untyped).returns(String) }
16
+ def to_json(options = nil)
17
+ serialize.to_json(options)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Rager
7
+ module Template
8
+ class Input < T::Struct
9
+ extend T::Sig
10
+
11
+ const :template, String
12
+ const :variables, T::Hash[Symbol, T.untyped]
13
+
14
+ sig { params(options: T.untyped).returns(String) }
15
+ def to_json(options = nil)
16
+ serialize.to_json(options)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -7,7 +7,7 @@ module Rager
7
7
  include Rager::Options
8
8
  extend T::Sig
9
9
 
10
- const :provider, String, default: "erb"
10
+ const :provider, Symbol, default: :erb
11
11
  end
12
12
  end
13
13
  end
@@ -14,12 +14,11 @@ module Rager
14
14
 
15
15
  sig do
16
16
  abstract.params(
17
- template: String,
18
- variables: T::Hash[Symbol, T.untyped],
17
+ input: Rager::Template::Input,
19
18
  options: Rager::Template::Options
20
19
  ).returns(Rager::Types::TemplateOutput)
21
20
  end
22
- def template(template, variables, options)
21
+ def template(input, options)
23
22
  end
24
23
  end
25
24
  end
@@ -11,15 +11,14 @@ module Rager
11
11
 
12
12
  sig do
13
13
  override.params(
14
- template: String,
15
- variables: T::Hash[Symbol, T.untyped],
14
+ input: Rager::Template::Input,
16
15
  options: Rager::Template::Options
17
16
  ).returns(Rager::Types::TemplateOutput)
18
17
  end
19
- def template(template, variables, options)
20
- ERB.new(template).result_with_hash(variables)
18
+ def template(input, options)
19
+ ERB.new(input.template).result_with_hash(input.variables)
21
20
  rescue SyntaxError, NameError => e
22
- raise Rager::Errors::TemplateError.new(template, variables, details: e.message)
21
+ raise Rager::Errors::TemplateError.new(input.template, input.variables, details: e.message)
23
22
  end
24
23
  end
25
24
  end
@@ -0,0 +1,30 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Rager
5
+ module Template
6
+ module Providers
7
+ class Mustache < Rager::Template::Providers::Abstract
8
+ extend T::Sig
9
+
10
+ sig do
11
+ override.params(
12
+ input: Rager::Template::Input,
13
+ options: Rager::Template::Options
14
+ ).returns(Rager::Types::TemplateOutput)
15
+ end
16
+ def template(input, options)
17
+ begin
18
+ require "mustache"
19
+ rescue LoadError
20
+ raise Rager::Errors::DependencyError.new("mustache", details: "Please install the mustache gem to use mustache templates")
21
+ end
22
+
23
+ ::Mustache.render(input.template, input.variables)
24
+ rescue ::Mustache::Parser::SyntaxError, ::Mustache::ContextMiss => e
25
+ raise Rager::Errors::TemplateError.new(input.template, input.variables, details: e.message)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/rager/types.rb CHANGED
@@ -1,71 +1,78 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative "rerank/output"
5
- require_relative "search/output"
6
-
7
4
  module Rager
8
5
  module Types
9
6
  extend T::Sig
10
7
 
11
8
  ChatInput = T.type_alias { T::Array[Rager::Chat::Message] }
12
9
  EmbedInput = T.type_alias { T::Array[String] }
13
- ImageGenInput = T.type_alias { String }
14
- MeshGenInput = T.type_alias { String }
15
- RerankInput = T.type_alias { {query: String, documents: T.any(T::Array[String], T::Array[T::Hash[Symbol, String]])} }
10
+ ImageInput = T.type_alias { String }
11
+ MeshInput = T.type_alias { String }
12
+ RerankInput = T.type_alias { Rager::Rerank::Input }
16
13
  SearchInput = T.type_alias { String }
17
- TemplateInput = T.type_alias { {template: String, variables: T::Hash[Symbol, T.untyped]} }
14
+ TemplateInput = T.type_alias { Rager::Template::Input }
18
15
  Input = T.type_alias {
19
16
  T.any(
20
17
  ChatInput,
21
18
  EmbedInput,
22
- ImageGenInput,
23
- MeshGenInput,
19
+ ImageInput,
20
+ MeshInput,
24
21
  RerankInput,
25
22
  SearchInput,
26
- TemplateInput,
27
- Rager::Result
23
+ TemplateInput
28
24
  )
29
25
  }
30
26
 
31
- ChatStream = T.type_alias { T::Enumerator[Rager::Chat::MessageDelta] }
32
- Stream = T.type_alias { ChatStream }
27
+ ChatStreamOutput = T.type_alias { T::Enumerator[Rager::Chat::MessageDelta] }
28
+ Stream = T.type_alias { ChatStreamOutput }
33
29
 
34
30
  ChatBuffer = T.type_alias { T::Array[Rager::Chat::MessageDelta] }
35
31
  Buffer = T.type_alias { ChatBuffer }
36
32
 
37
- ChatNonStream = T.type_alias { T.any(String, T::Array[String]) }
33
+ ChatNonStreamOutput = T.type_alias { T.any(String, T::Array[String]) }
38
34
 
39
- ChatOutput = T.type_alias { T.any(ChatNonStream, ChatStream) }
35
+ ChatOutput = T.type_alias { T.any(ChatNonStreamOutput, ChatStreamOutput) }
40
36
  EmbedOutput = T.type_alias { T::Array[T::Array[Float]] }
41
- ImageGenOutput = T.type_alias { String }
42
- MeshGenOutput = T.type_alias { String }
43
- RerankOutput = T.type_alias { Rager::Rerank::Output }
44
- SearchOutput = T.type_alias { Rager::Search::Output }
37
+ ImageOutput = T.type_alias { String }
38
+ MeshOutput = T.type_alias { String }
39
+ RerankOutput = T.type_alias { T::Array[Rager::Rerank::Result] }
40
+ SearchOutput = T.type_alias { T::Array[Rager::Search::Result] }
45
41
  TemplateOutput = T.type_alias { String }
46
42
  Output = T.type_alias {
47
43
  T.any(
48
44
  ChatOutput,
49
45
  EmbedOutput,
50
- ImageGenOutput,
51
- MeshGenOutput,
46
+ ImageOutput,
47
+ MeshOutput,
52
48
  RerankOutput,
53
49
  SearchOutput,
54
50
  TemplateOutput
55
51
  )
56
52
  }
57
53
 
58
- ChatNonStreamOutput = T.type_alias { ChatNonStream }
59
54
  NonStreamOutput = T.type_alias {
60
55
  T.any(
61
56
  ChatNonStreamOutput,
62
57
  EmbedOutput,
63
- ImageGenOutput,
64
- MeshGenOutput,
58
+ ImageOutput,
59
+ MeshOutput,
65
60
  RerankOutput,
66
61
  SearchOutput,
67
62
  TemplateOutput
68
63
  )
69
64
  }
65
+
66
+ Options = T.type_alias {
67
+ T.any(
68
+ Rager::Chat::Options,
69
+ Rager::Embed::Options,
70
+ Rager::Image::Options,
71
+ Rager::Mesh::Options,
72
+ Rager::Rerank::Options,
73
+ Rager::Search::Options,
74
+ Rager::Template::Options
75
+ )
76
+ }
70
77
  end
71
78
  end