riffer 0.40.0 → 0.41.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 +4 -4
- data/.agents/providers.md +10 -1
- data/.agents/rbs-inline.md +2 -2
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +11 -0
- data/README.md +20 -24
- data/docs/AGENTS.md +0 -11
- data/docs/CONFIGURATION.md +105 -21
- data/docs/SERIALIZATION.md +4 -3
- data/docs/providers/AMAZON_BEDROCK.md +14 -8
- data/docs/providers/ANTHROPIC.md +9 -7
- data/docs/providers/AZURE_OPENAI.md +12 -12
- data/docs/providers/CUSTOM_PROVIDERS.md +32 -16
- data/docs/providers/GEMINI.md +28 -5
- data/docs/providers/OPENAI.md +21 -5
- data/docs/providers/OPENROUTER.md +11 -6
- data/docs/providers/PROVIDERS.md +16 -1
- data/lib/riffer/agent/config.rb +0 -6
- data/lib/riffer/agent/serializer.rb +0 -2
- data/lib/riffer/agent.rb +1 -9
- data/lib/riffer/config.rb +6 -6
- data/lib/riffer/evals/judge.rb +3 -5
- data/lib/riffer/providers/amazon_bedrock.rb +31 -19
- data/lib/riffer/providers/anthropic.rb +19 -8
- data/lib/riffer/providers/azure_open_ai.rb +19 -11
- data/lib/riffer/providers/base.rb +28 -0
- data/lib/riffer/providers/gemini/client.rb +120 -0
- data/lib/riffer/providers/gemini.rb +13 -62
- data/lib/riffer/providers/mock.rb +5 -4
- data/lib/riffer/providers/open_ai.rb +23 -8
- data/lib/riffer/providers/open_router.rb +23 -9
- data/lib/riffer/version.rb +1 -1
- data/sig/_private/riffer/providers/amazon_bedrock.rbs +4 -2
- data/sig/_private/riffer/providers/anthropic.rbs +4 -2
- data/sig/_private/riffer/providers/gemini.rbs +7 -0
- data/sig/_private/riffer/providers/open_ai.rbs +4 -2
- data/sig/_private/riffer/providers/open_router.rbs +4 -2
- data/sig/generated/riffer/agent/config.rbs +1 -5
- data/sig/generated/riffer/agent.rbs +0 -6
- data/sig/generated/riffer/config.rbs +25 -15
- data/sig/generated/riffer/evals/judge.rbs +2 -4
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +13 -2
- data/sig/generated/riffer/providers/anthropic.rbs +13 -2
- data/sig/generated/riffer/providers/azure_open_ai.rbs +14 -4
- data/sig/generated/riffer/providers/base.rbs +20 -0
- data/sig/generated/riffer/providers/gemini/client.rbs +65 -0
- data/sig/generated/riffer/providers/gemini.rbs +7 -23
- data/sig/generated/riffer/providers/mock.rbs +4 -3
- data/sig/generated/riffer/providers/open_ai.rbs +13 -2
- data/sig/generated/riffer/providers/open_router.rbs +16 -3
- metadata +4 -1
|
@@ -2,20 +2,11 @@
|
|
|
2
2
|
# rbs_inline: enabled
|
|
3
3
|
|
|
4
4
|
require "json"
|
|
5
|
-
require "net/http"
|
|
6
5
|
require "securerandom"
|
|
7
|
-
require "uri"
|
|
8
6
|
|
|
9
7
|
# Google Gemini provider for Gemini models via the Gemini REST API.
|
|
10
8
|
class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
11
|
-
# @rbs @api_key: String?
|
|
12
|
-
# @rbs @open_timeout: Integer
|
|
13
|
-
# @rbs @read_timeout: Integer
|
|
14
|
-
|
|
15
|
-
BASE_URI = URI("https://generativelanguage.googleapis.com") #: URI::Generic
|
|
16
9
|
VALID_MODEL_PATTERN = /\A[a-zA-Z0-9._-]+\z/ #: Regexp
|
|
17
|
-
DEFAULT_OPEN_TIMEOUT = 10 #: Integer
|
|
18
|
-
DEFAULT_READ_TIMEOUT = 60 #: Integer
|
|
19
10
|
|
|
20
11
|
FINISH_REASONS = {
|
|
21
12
|
"STOP" => :stop,
|
|
@@ -36,17 +27,19 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
36
27
|
"gcp.gemini"
|
|
37
28
|
end
|
|
38
29
|
|
|
30
|
+
private
|
|
31
|
+
|
|
39
32
|
#--
|
|
40
|
-
#: (
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
api_key ||= Riffer.config.gemini.api_key
|
|
44
|
-
@api_key = api_key
|
|
45
|
-
@open_timeout = open_timeout || Riffer.config.gemini.open_timeout || DEFAULT_OPEN_TIMEOUT
|
|
46
|
-
@read_timeout = read_timeout || Riffer.config.gemini.read_timeout || DEFAULT_READ_TIMEOUT
|
|
33
|
+
#: () -> untyped
|
|
34
|
+
def global_client
|
|
35
|
+
Riffer.config.gemini.client
|
|
47
36
|
end
|
|
48
37
|
|
|
49
|
-
|
|
38
|
+
#--
|
|
39
|
+
#: () -> untyped
|
|
40
|
+
def build_client
|
|
41
|
+
Riffer::Providers::Gemini::Client.new(**{ api_key: Riffer.config.gemini.api_key }.compact)
|
|
42
|
+
end
|
|
50
43
|
|
|
51
44
|
#--
|
|
52
45
|
#: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -89,9 +82,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
89
82
|
def execute_generate(params)
|
|
90
83
|
model = params[:model]
|
|
91
84
|
body = params.except(:model)
|
|
92
|
-
|
|
93
|
-
handle_api_error!(response) unless response.is_a?(Net::HTTPSuccess)
|
|
94
|
-
JSON.parse(response.body, symbolize_names: true)
|
|
85
|
+
client.post(api_path(model, "generateContent"), body)
|
|
95
86
|
end
|
|
96
87
|
|
|
97
88
|
#--
|
|
@@ -171,13 +162,6 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
171
162
|
model = params[:model]
|
|
172
163
|
body = params.except(:model)
|
|
173
164
|
|
|
174
|
-
uri = URI("#{BASE_URI}/#{api_path(model, 'streamGenerateContent')}?alt=sse")
|
|
175
|
-
host = uri.hostname #: String
|
|
176
|
-
request = Net::HTTP::Post.new(uri)
|
|
177
|
-
request["Content-Type"] = "application/json"
|
|
178
|
-
request["x-goog-api-key"] = @api_key
|
|
179
|
-
request.body = body.to_json
|
|
180
|
-
|
|
181
165
|
full_text = +""
|
|
182
166
|
buffer = +""
|
|
183
167
|
raw_finish_reason = nil #: String?
|
|
@@ -224,17 +208,8 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
224
208
|
end
|
|
225
209
|
end
|
|
226
210
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
handle_api_error!(response) unless response.is_a?(Net::HTTPSuccess)
|
|
230
|
-
|
|
231
|
-
begin
|
|
232
|
-
response.read_body { |chunk| process_chunk.call(chunk) }
|
|
233
|
-
rescue IOError
|
|
234
|
-
process_chunk.call(response.body)
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
end
|
|
211
|
+
path = "#{api_path(model, 'streamGenerateContent')}?alt=sse"
|
|
212
|
+
client.post_stream(path, body) { |chunk| process_chunk.call(chunk) }
|
|
238
213
|
|
|
239
214
|
yielder << Riffer::StreamEvents::TextDone.new(full_text) unless full_text.empty?
|
|
240
215
|
yield_finish_reason(yielder, build_finish_reason(raw_finish_reason, tool_calls: saw_function_call))
|
|
@@ -325,18 +300,6 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
325
300
|
args.is_a?(String) ? args : args.to_json
|
|
326
301
|
end
|
|
327
302
|
|
|
328
|
-
#--
|
|
329
|
-
#: (String, Hash[Symbol, untyped]) -> Net::HTTPResponse
|
|
330
|
-
def post_request(path, body)
|
|
331
|
-
uri = URI("#{BASE_URI}/#{path}")
|
|
332
|
-
host = uri.hostname #: String
|
|
333
|
-
request = Net::HTTP::Post.new(uri)
|
|
334
|
-
request["Content-Type"] = "application/json"
|
|
335
|
-
request["x-goog-api-key"] = @api_key
|
|
336
|
-
request.body = body.to_json
|
|
337
|
-
Net::HTTP.start(host, uri.port, use_ssl: true, open_timeout: @open_timeout, read_timeout: @read_timeout) { |http| http.request(request) }
|
|
338
|
-
end
|
|
339
|
-
|
|
340
303
|
#--
|
|
341
304
|
#: (String, String) -> String
|
|
342
305
|
def api_path(model, method)
|
|
@@ -370,16 +333,4 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
370
333
|
|
|
371
334
|
schema
|
|
372
335
|
end
|
|
373
|
-
|
|
374
|
-
#--
|
|
375
|
-
#: (Net::HTTPResponse) -> void
|
|
376
|
-
def handle_api_error!(response)
|
|
377
|
-
body = begin
|
|
378
|
-
JSON.parse(response.body, symbolize_names: true)
|
|
379
|
-
rescue JSON::ParserError
|
|
380
|
-
{ message: response.body }
|
|
381
|
-
end
|
|
382
|
-
error_message = body.dig(:error, :message) || body[:message] || response.body
|
|
383
|
-
raise Riffer::Error, "Gemini API error (#{response.code}): #{error_message}"
|
|
384
|
-
end
|
|
385
336
|
end
|
|
@@ -28,7 +28,8 @@ class Riffer::Providers::Mock < Riffer::Providers::Base
|
|
|
28
28
|
attr_reader :calls #: Array[Hash[Symbol, untyped]]
|
|
29
29
|
|
|
30
30
|
# +responses:+ pre-configures canned responses (same shape as
|
|
31
|
-
# +#stub_response+)
|
|
31
|
+
# +#stub_response+) for standalone use; agent tests queue responses on
|
|
32
|
+
# <tt>agent.provider</tt> via +#stub_response+ instead.
|
|
32
33
|
#
|
|
33
34
|
# Riffer::Providers::Mock.new(responses: [
|
|
34
35
|
# {content: "", tool_calls: [{name: "tool_a", arguments: "{}"}]},
|
|
@@ -36,10 +37,10 @@ class Riffer::Providers::Mock < Riffer::Providers::Base
|
|
|
36
37
|
# ])
|
|
37
38
|
#
|
|
38
39
|
#--
|
|
39
|
-
#: (
|
|
40
|
-
def initialize(
|
|
40
|
+
#: (?responses: Array[Hash[Symbol, untyped]]) -> void
|
|
41
|
+
def initialize(responses: [])
|
|
41
42
|
super()
|
|
42
|
-
@responses =
|
|
43
|
+
@responses = responses.map { |r| normalize_response(r) }
|
|
43
44
|
@current_index = 0
|
|
44
45
|
@calls = []
|
|
45
46
|
@stubbed_responses = []
|
|
@@ -13,17 +13,32 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
#--
|
|
16
|
-
#: (
|
|
17
|
-
def initialize
|
|
18
|
-
super
|
|
16
|
+
#: () -> void
|
|
17
|
+
def initialize
|
|
18
|
+
super
|
|
19
19
|
depends_on "openai"
|
|
20
|
-
|
|
21
|
-
api_key = options.fetch(:api_key, Riffer.config.openai.api_key)
|
|
22
|
-
@client = ::OpenAI::Client.new(api_key: api_key, **options.except(:api_key))
|
|
23
20
|
end
|
|
24
21
|
|
|
25
22
|
private
|
|
26
23
|
|
|
24
|
+
#--
|
|
25
|
+
#: () -> untyped
|
|
26
|
+
def global_client
|
|
27
|
+
Riffer.config.openai.client
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Compacted so an unset value stays absent: the SDK reads +OPENAI_API_KEY+ /
|
|
31
|
+
# +OPENAI_BASE_URL+ only for a missing argument, and an explicit nil would
|
|
32
|
+
# suppress that fallback.
|
|
33
|
+
#--
|
|
34
|
+
#: () -> untyped
|
|
35
|
+
def build_client
|
|
36
|
+
::OpenAI::Client.new(**{
|
|
37
|
+
api_key: Riffer.config.openai.api_key,
|
|
38
|
+
base_url: Riffer.config.openai.base_url,
|
|
39
|
+
}.compact)
|
|
40
|
+
end
|
|
41
|
+
|
|
27
42
|
#--
|
|
28
43
|
#: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
29
44
|
def build_request_params(messages, model, options)
|
|
@@ -81,7 +96,7 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
|
|
|
81
96
|
#--
|
|
82
97
|
#: (Hash[Symbol, untyped]) -> untyped
|
|
83
98
|
def execute_generate(params)
|
|
84
|
-
|
|
99
|
+
client.responses.create(params)
|
|
85
100
|
end
|
|
86
101
|
|
|
87
102
|
#--
|
|
@@ -190,7 +205,7 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
|
|
|
190
205
|
tool_info: {},
|
|
191
206
|
} #: Hash[Symbol, untyped]
|
|
192
207
|
|
|
193
|
-
stream =
|
|
208
|
+
stream = client.responses.stream(params)
|
|
194
209
|
begin
|
|
195
210
|
stream.each do |event|
|
|
196
211
|
case event.type
|
|
@@ -5,7 +5,7 @@ require "json"
|
|
|
5
5
|
|
|
6
6
|
# OpenRouter provider (https://openrouter.ai). Requires the +openai+ gem —
|
|
7
7
|
# OpenRouter exposes an OpenAI-compatible endpoint, so this reuses the OpenAI
|
|
8
|
-
# SDK with a +base_url+ override. +api_key+
|
|
8
|
+
# SDK with a +base_url+ override. +api_key+ resolves from config, then
|
|
9
9
|
# +OPENROUTER_API_KEY+.
|
|
10
10
|
class Riffer::Providers::OpenRouter < Riffer::Providers::Base
|
|
11
11
|
BASE_URL = "https://openrouter.ai/api/v1" #: String
|
|
@@ -27,17 +27,31 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
#--
|
|
30
|
-
#: (
|
|
31
|
-
def initialize
|
|
32
|
-
super
|
|
30
|
+
#: () -> void
|
|
31
|
+
def initialize
|
|
32
|
+
super
|
|
33
33
|
depends_on "openai"
|
|
34
|
+
end
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
private
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
#--
|
|
39
|
+
#: () -> untyped
|
|
40
|
+
def global_client
|
|
41
|
+
Riffer.config.openrouter.client
|
|
38
42
|
end
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
# Deliberately not compacted: this borrows the OpenAI SDK to talk to a
|
|
45
|
+
# different vendor, so omitting an unset +api_key+ would let the SDK fall
|
|
46
|
+
# back to +OPENAI_API_KEY+ and send an OpenAI credential to OpenRouter.
|
|
47
|
+
# Passing nil raises in the SDK instead. +OPENROUTER_API_KEY+ is read here
|
|
48
|
+
# rather than left to the SDK for the same reason.
|
|
49
|
+
#--
|
|
50
|
+
#: () -> untyped
|
|
51
|
+
def build_client
|
|
52
|
+
api_key = Riffer.config.openrouter.api_key || ENV.fetch("OPENROUTER_API_KEY", nil)
|
|
53
|
+
::OpenAI::Client.new(api_key: api_key, base_url: BASE_URL)
|
|
54
|
+
end
|
|
41
55
|
|
|
42
56
|
#--
|
|
43
57
|
#: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -84,7 +98,7 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
|
|
|
84
98
|
#--
|
|
85
99
|
#: (Hash[Symbol, untyped]) -> untyped
|
|
86
100
|
def execute_generate(params)
|
|
87
|
-
|
|
101
|
+
client.chat.completions.create(**params)
|
|
88
102
|
end
|
|
89
103
|
|
|
90
104
|
#--
|
|
@@ -174,7 +188,7 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
|
|
|
174
188
|
# events. We want raw ChatCompletionChunk objects with
|
|
175
189
|
# +choices.first.delta+ so we can map deltas to Riffer::StreamEvents
|
|
176
190
|
# ourselves.
|
|
177
|
-
stream =
|
|
191
|
+
stream = client.chat.completions.stream_raw(**stream_params)
|
|
178
192
|
begin
|
|
179
193
|
stream.each do |chunk|
|
|
180
194
|
handle_stream_chunk(chunk, state: state, yielder: yielder)
|
data/lib/riffer/version.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::AmazonBedrock
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::Aws::BedrockRuntime::Client
|
|
4
6
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::Anthropic
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::Anthropic::Client
|
|
4
6
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::OpenAI
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::OpenAI::Client
|
|
4
6
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::OpenRouter
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::OpenAI::Client
|
|
4
6
|
end
|
|
@@ -15,9 +15,6 @@ class Riffer::Agent::Config
|
|
|
15
15
|
# The configured instructions.
|
|
16
16
|
attr_reader instructions: (String | Proc)?
|
|
17
17
|
|
|
18
|
-
# Options passed to the provider client.
|
|
19
|
-
attr_accessor provider_options: Hash[Symbol, untyped]
|
|
20
|
-
|
|
21
18
|
# Options passed to generate_text/stream_text.
|
|
22
19
|
attr_accessor model_options: Hash[Symbol, untyped]
|
|
23
20
|
|
|
@@ -49,7 +46,6 @@ class Riffer::Agent::Config
|
|
|
49
46
|
# ?identifier: String?,
|
|
50
47
|
# ?model: (String | Proc)?,
|
|
51
48
|
# ?instructions: (String | Proc)?,
|
|
52
|
-
# ?provider_options: Hash[Symbol, untyped],
|
|
53
49
|
# ?model_options: Hash[Symbol, untyped],
|
|
54
50
|
# ?structured_output: Riffer::Params?,
|
|
55
51
|
# ?max_steps: Numeric?,
|
|
@@ -59,7 +55,7 @@ class Riffer::Agent::Config
|
|
|
59
55
|
# ?skills_config: Riffer::Skills::Config?,
|
|
60
56
|
# ?guardrails: Hash[Symbol, Array[Hash[Symbol, untyped]]]
|
|
61
57
|
# ) -> void
|
|
62
|
-
def initialize: (?identifier: String?, ?model: (String | Proc)?, ?instructions: (String | Proc)?, ?
|
|
58
|
+
def initialize: (?identifier: String?, ?model: (String | Proc)?, ?instructions: (String | Proc)?, ?model_options: Hash[Symbol, untyped], ?structured_output: Riffer::Params?, ?max_steps: Numeric?, ?tools_config: (Array[singleton(Riffer::Tool)] | Proc)?, ?mcp_configs: Array[Hash[Symbol, untyped]], ?tool_runtime: singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc, ?skills_config: Riffer::Skills::Config?, ?guardrails: Hash[Symbol, Array[Hash[Symbol, untyped]]]) -> void
|
|
63
59
|
|
|
64
60
|
# Sets +identifier+, coercing the value to String.
|
|
65
61
|
# --
|
|
@@ -45,12 +45,6 @@ class Riffer::Agent
|
|
|
45
45
|
# : (?(String | Proc)?) -> (String | Proc)?
|
|
46
46
|
def self.instructions: (?(String | Proc)?) -> (String | Proc)?
|
|
47
47
|
|
|
48
|
-
# Gets or sets provider options passed to the provider client.
|
|
49
|
-
#
|
|
50
|
-
# --
|
|
51
|
-
# : (?Hash[Symbol, untyped]?) -> Hash[Symbol, untyped]
|
|
52
|
-
def self.provider_options: (?Hash[Symbol, untyped]?) -> Hash[Symbol, untyped]
|
|
53
|
-
|
|
54
48
|
# Gets or sets model options passed to generate_text/stream_text.
|
|
55
49
|
#
|
|
56
50
|
# --
|
|
@@ -7,15 +7,19 @@ class Riffer::Config
|
|
|
7
7
|
|
|
8
8
|
attr_accessor region(): untyped
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
attr_accessor client(): untyped
|
|
11
|
+
|
|
12
|
+
def self.new: (?untyped api_token, ?untyped region, ?untyped client) -> instance
|
|
13
|
+
| (?api_token: untyped, ?region: untyped, ?client: untyped) -> instance
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
class Anthropic < Struct[untyped]
|
|
15
17
|
attr_accessor api_key(): untyped
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
attr_accessor client(): untyped
|
|
20
|
+
|
|
21
|
+
def self.new: (?untyped api_key, ?untyped client) -> instance
|
|
22
|
+
| (?api_key: untyped, ?client: untyped) -> instance
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
class AzureOpenAI < Struct[untyped]
|
|
@@ -23,33 +27,39 @@ class Riffer::Config
|
|
|
23
27
|
|
|
24
28
|
attr_accessor endpoint(): untyped
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
attr_accessor client(): untyped
|
|
31
|
+
|
|
32
|
+
def self.new: (?untyped api_key, ?untyped endpoint, ?untyped client) -> instance
|
|
33
|
+
| (?api_key: untyped, ?endpoint: untyped, ?client: untyped) -> instance
|
|
28
34
|
end
|
|
29
35
|
|
|
30
36
|
class Gemini < Struct[untyped]
|
|
31
37
|
attr_accessor api_key(): untyped
|
|
32
38
|
|
|
33
|
-
attr_accessor
|
|
34
|
-
|
|
35
|
-
attr_accessor read_timeout(): untyped
|
|
39
|
+
attr_accessor client(): untyped
|
|
36
40
|
|
|
37
|
-
def self.new: (?untyped api_key, ?untyped
|
|
38
|
-
| (?api_key: untyped, ?
|
|
41
|
+
def self.new: (?untyped api_key, ?untyped client) -> instance
|
|
42
|
+
| (?api_key: untyped, ?client: untyped) -> instance
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
class OpenAI < Struct[untyped]
|
|
42
46
|
attr_accessor api_key(): untyped
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
attr_accessor base_url(): untyped
|
|
49
|
+
|
|
50
|
+
attr_accessor client(): untyped
|
|
51
|
+
|
|
52
|
+
def self.new: (?untyped api_key, ?untyped base_url, ?untyped client) -> instance
|
|
53
|
+
| (?api_key: untyped, ?base_url: untyped, ?client: untyped) -> instance
|
|
46
54
|
end
|
|
47
55
|
|
|
48
56
|
class OpenRouter < Struct[untyped]
|
|
49
57
|
attr_accessor api_key(): untyped
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
attr_accessor client(): untyped
|
|
60
|
+
|
|
61
|
+
def self.new: (?untyped api_key, ?untyped client) -> instance
|
|
62
|
+
| (?api_key: untyped, ?client: untyped) -> instance
|
|
53
63
|
end
|
|
54
64
|
|
|
55
65
|
class Evals < Struct[untyped]
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
# Executes LLM-as-judge evaluations, using tool calling internally to get
|
|
4
4
|
# structured output from the judge model.
|
|
5
5
|
class Riffer::Evals::Judge
|
|
6
|
-
@provider_options: Hash[Symbol, untyped]
|
|
7
|
-
|
|
8
6
|
@provider_instance: Riffer::Providers::Base?
|
|
9
7
|
|
|
10
8
|
@provider_name: String?
|
|
@@ -23,8 +21,8 @@ class Riffer::Evals::Judge
|
|
|
23
21
|
|
|
24
22
|
# Raises Riffer::ArgumentError unless +model+ is "provider/model" format.
|
|
25
23
|
# --
|
|
26
|
-
# : (model: String
|
|
27
|
-
def initialize: (model: String
|
|
24
|
+
# : (model: String) -> void
|
|
25
|
+
def initialize: (model: String) -> void
|
|
28
26
|
|
|
29
27
|
# Evaluates an input/output pair using the configured LLM.
|
|
30
28
|
# --
|
|
@@ -21,11 +21,22 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
21
21
|
def self.semconv_provider_name: () -> String
|
|
22
22
|
|
|
23
23
|
# --
|
|
24
|
-
# : (
|
|
25
|
-
def initialize: (
|
|
24
|
+
# : () -> void
|
|
25
|
+
def initialize: () -> void
|
|
26
26
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
|
+
# --
|
|
30
|
+
# : () -> untyped
|
|
31
|
+
def global_client: () -> untyped
|
|
32
|
+
|
|
33
|
+
# Compacted so an unset region stays absent: the AWS SDK resolves +AWS_REGION+
|
|
34
|
+
# and the shared config only for a missing argument, and raises
|
|
35
|
+
# +Aws::Errors::MissingRegionError+ on an explicit nil.
|
|
36
|
+
# --
|
|
37
|
+
# : () -> untyped
|
|
38
|
+
def build_client: () -> untyped
|
|
39
|
+
|
|
29
40
|
# --
|
|
30
41
|
# : (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
31
42
|
def build_request_params: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -19,11 +19,22 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
19
19
|
def self.semconv_provider_name: () -> String
|
|
20
20
|
|
|
21
21
|
# --
|
|
22
|
-
# : (
|
|
23
|
-
def initialize: (
|
|
22
|
+
# : () -> void
|
|
23
|
+
def initialize: () -> void
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
|
+
# --
|
|
28
|
+
# : () -> untyped
|
|
29
|
+
def global_client: () -> untyped
|
|
30
|
+
|
|
31
|
+
# Compacted for the same reason as the other providers: never hand an SDK an
|
|
32
|
+
# explicit nil credential, so its own +ANTHROPIC_API_KEY+ resolution stays
|
|
33
|
+
# reachable regardless of how that SDK distinguishes nil from absent.
|
|
34
|
+
# --
|
|
35
|
+
# : () -> untyped
|
|
36
|
+
def build_client: () -> untyped
|
|
37
|
+
|
|
27
38
|
# --
|
|
28
39
|
# : (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
29
40
|
def build_request_params: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
# Generated from lib/riffer/providers/azure_open_ai.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
# Azure OpenAI provider for GPT models hosted on Azure. Requires the +openai+
|
|
4
|
-
# gem. Credentials resolve from
|
|
5
|
-
# +
|
|
4
|
+
# gem. Credentials resolve from config, then +AZURE_OPENAI_API_KEY+ /
|
|
5
|
+
# +AZURE_OPENAI_ENDPOINT+.
|
|
6
6
|
class Riffer::Providers::AzureOpenAI < Riffer::Providers::OpenAI
|
|
7
7
|
# The GenAI semconv well-known provider name.
|
|
8
8
|
# --
|
|
9
9
|
# : () -> String
|
|
10
10
|
def self.semconv_provider_name: () -> String
|
|
11
11
|
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# --
|
|
15
|
+
# : () -> untyped
|
|
16
|
+
def global_client: () -> untyped
|
|
17
|
+
|
|
18
|
+
# Deliberately not compacted: this borrows the OpenAI SDK to talk to Azure, so
|
|
19
|
+
# omitting an unset argument would let the SDK fall back to +OPENAI_API_KEY+
|
|
20
|
+
# and +OPENAI_BASE_URL+ — sending Azure traffic, and an OpenAI credential, to
|
|
21
|
+
# whatever those name. Passing nil raises in the SDK instead.
|
|
12
22
|
# --
|
|
13
|
-
# : (
|
|
14
|
-
def
|
|
23
|
+
# : () -> untyped
|
|
24
|
+
def build_client: () -> untyped
|
|
15
25
|
end
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
# +extract_token_usage+, +extract_content+, +extract_tool_calls+) and the base
|
|
6
6
|
# class orchestrates them.
|
|
7
7
|
class Riffer::Providers::Base
|
|
8
|
+
@client: untyped
|
|
9
|
+
|
|
8
10
|
@current_model: String?
|
|
9
11
|
|
|
10
12
|
@current_tools: Array[singleton(Riffer::Tool)]
|
|
@@ -42,6 +44,24 @@ class Riffer::Providers::Base
|
|
|
42
44
|
# : (String) -> true
|
|
43
45
|
def depends_on: (String) -> true
|
|
44
46
|
|
|
47
|
+
# Returns the client for the current LLM call. A configured client wins,
|
|
48
|
+
# resolved on every call so a Proc can vary the client by process or
|
|
49
|
+
# credential lifetime; otherwise the provider builds one from the configured
|
|
50
|
+
# credentials, memoized for the life of the provider.
|
|
51
|
+
# --
|
|
52
|
+
# : () -> untyped
|
|
53
|
+
def client: () -> untyped
|
|
54
|
+
|
|
55
|
+
# Returns the consumer-configured client for this provider; nil when none is
|
|
56
|
+
# configured, and for providers that take no configuration at all.
|
|
57
|
+
# --
|
|
58
|
+
# : () -> untyped
|
|
59
|
+
def global_client: () -> untyped
|
|
60
|
+
|
|
61
|
+
# --
|
|
62
|
+
# : () -> untyped
|
|
63
|
+
def build_client: () -> untyped
|
|
64
|
+
|
|
45
65
|
# --
|
|
46
66
|
# : (String) -> String
|
|
47
67
|
def encode_tool_name: (String) -> String
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Generated from lib/riffer/providers/gemini/client.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
# HTTP transport for the Gemini REST API. Riffer builds one from the
|
|
4
|
+
# configured +api_key+ by default; construct your own to tune the HTTP knobs
|
|
5
|
+
# and assign it to <tt>Riffer.config.gemini.client</tt>. Any object
|
|
6
|
+
# implementing +post+ and +post_stream+ with these contracts works there —
|
|
7
|
+
# the class is a default implementation, not a required base.
|
|
8
|
+
#
|
|
9
|
+
# Riffer.configure do |config|
|
|
10
|
+
# config.gemini.client = Riffer::Providers::Gemini::Client.new(
|
|
11
|
+
# api_key: ENV["GEMINI_API_KEY"],
|
|
12
|
+
# read_timeout: 120
|
|
13
|
+
# )
|
|
14
|
+
# end
|
|
15
|
+
class Riffer::Providers::Gemini::Client
|
|
16
|
+
@proxy_port: Integer?
|
|
17
|
+
|
|
18
|
+
@proxy_address: String?
|
|
19
|
+
|
|
20
|
+
@write_timeout: Integer?
|
|
21
|
+
|
|
22
|
+
@read_timeout: Integer
|
|
23
|
+
|
|
24
|
+
@open_timeout: Integer
|
|
25
|
+
|
|
26
|
+
@base_url: String
|
|
27
|
+
|
|
28
|
+
@api_key: String?
|
|
29
|
+
|
|
30
|
+
DEFAULT_BASE_URL: String
|
|
31
|
+
|
|
32
|
+
DEFAULT_OPEN_TIMEOUT: Integer
|
|
33
|
+
|
|
34
|
+
DEFAULT_READ_TIMEOUT: Integer
|
|
35
|
+
|
|
36
|
+
# : (?api_key: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer?, ?proxy_address: String?, ?proxy_port: Integer?) -> void
|
|
37
|
+
def initialize: (?api_key: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer?, ?proxy_address: String?, ?proxy_port: Integer?) -> void
|
|
38
|
+
|
|
39
|
+
# POSTs a JSON body to an API path and returns the parsed response hash.
|
|
40
|
+
# Raises Riffer::Error when the API responds with a non-success status.
|
|
41
|
+
# --
|
|
42
|
+
# : (String, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
43
|
+
def post: (String, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
44
|
+
|
|
45
|
+
# POSTs a JSON body to an API path, yielding raw response body chunks as
|
|
46
|
+
# they arrive. Raises Riffer::Error when the API responds with a
|
|
47
|
+
# non-success status.
|
|
48
|
+
# --
|
|
49
|
+
# : (String, Hash[Symbol, untyped]) { (String) -> void } -> void
|
|
50
|
+
def post_stream: (String, Hash[Symbol, untyped]) { (String) -> void } -> void
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# --
|
|
55
|
+
# : (URI::Generic, Hash[Symbol, untyped]) -> Net::HTTP::Post
|
|
56
|
+
def build_request: (URI::Generic, Hash[Symbol, untyped]) -> Net::HTTP::Post
|
|
57
|
+
|
|
58
|
+
# --
|
|
59
|
+
# : [R] (URI::Generic) { (Net::HTTP) -> R } -> R
|
|
60
|
+
def start_http: [R] (URI::Generic) { (Net::HTTP) -> R } -> R
|
|
61
|
+
|
|
62
|
+
# --
|
|
63
|
+
# : (Net::HTTPResponse) -> void
|
|
64
|
+
def handle_api_error!: (Net::HTTPResponse) -> void
|
|
65
|
+
end
|