riffer 0.27.2 → 0.29.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/architecture.md +18 -11
- data/.agents/code-style.md +1 -1
- data/.agents/rbs-inline.md +2 -2
- data/.agents/testing.md +9 -5
- data/.release-please-manifest.json +1 -1
- data/AGENTS.md +17 -10
- data/CHANGELOG.md +31 -0
- data/README.md +17 -18
- data/Steepfile +7 -1
- data/docs/03_AGENTS.md +34 -3
- data/docs/04_AGENT_LIFECYCLE.md +134 -86
- data/docs/05_AGENT_LOOP.md +2 -2
- data/docs/06_TOOLS.md +9 -4
- data/docs/07_TOOL_ADVANCED.md +23 -19
- data/docs/08_MESSAGES.md +28 -31
- data/docs/09_STREAM_EVENTS.md +1 -1
- data/docs/10_CONFIGURATION.md +25 -15
- data/docs/providers/01_PROVIDERS.md +6 -0
- data/docs/providers/06_MOCK_PROVIDER.md +2 -1
- data/docs/providers/07_CUSTOM_PROVIDERS.md +4 -4
- data/docs/providers/08_GEMINI.md +2 -2
- data/docs/providers/09_OPENROUTER.md +242 -0
- data/lib/riffer/agent/config.rb +173 -0
- data/lib/riffer/agent/context.rb +125 -0
- data/lib/riffer/agent/response.rb +11 -2
- data/lib/riffer/agent/run.rb +308 -0
- data/lib/riffer/agent/session/repair.rb +112 -0
- data/lib/riffer/agent/session.rb +268 -0
- data/lib/riffer/{structured_output → agent/structured_output}/result.rb +1 -1
- data/lib/riffer/{structured_output.rb → agent/structured_output.rb} +4 -4
- data/lib/riffer/agent.rb +246 -684
- data/lib/riffer/config.rb +56 -7
- data/lib/riffer/evals/evaluator.rb +13 -3
- data/lib/riffer/evals/judge.rb +2 -2
- data/lib/riffer/evals/run_result.rb +2 -1
- data/lib/riffer/evals/scenario_result.rb +2 -1
- data/lib/riffer/guardrails/runner.rb +3 -2
- data/lib/riffer/helpers/call_or_value.rb +16 -0
- data/lib/riffer/helpers.rb +0 -1
- data/lib/riffer/mcp/authenticated_tool.rb +4 -0
- data/lib/riffer/mcp/client.rb +1 -1
- data/lib/riffer/mcp/registration.rb +2 -3
- data/lib/riffer/mcp/registry.rb +3 -1
- data/lib/riffer/mcp/tool_factory.rb +5 -0
- data/lib/riffer/messages/assistant.rb +9 -3
- data/lib/riffer/messages/base.rb +22 -0
- data/lib/riffer/messages/converter.rb +6 -6
- data/lib/riffer/{file_part.rb → messages/file_part.rb} +5 -5
- data/lib/riffer/messages/tool.rb +1 -1
- data/lib/riffer/messages/user.rb +4 -4
- data/lib/riffer/{boolean.rb → params/boolean.rb} +3 -3
- data/lib/riffer/{param.rb → params/param.rb} +6 -6
- data/lib/riffer/params.rb +27 -21
- data/lib/riffer/providers/amazon_bedrock.rb +19 -20
- data/lib/riffer/providers/anthropic.rb +27 -28
- data/lib/riffer/providers/base.rb +10 -9
- data/lib/riffer/providers/gemini.rb +15 -12
- data/lib/riffer/providers/mock.rb +41 -13
- data/lib/riffer/providers/open_ai.rb +24 -22
- data/lib/riffer/providers/open_router.rb +318 -0
- data/lib/riffer/providers/repository.rb +1 -0
- data/lib/riffer/{token_usage.rb → providers/token_usage.rb} +4 -4
- data/lib/riffer/providers.rb +1 -0
- data/lib/riffer/runner/fibers.rb +4 -3
- data/lib/riffer/runner/sequential.rb +1 -1
- data/lib/riffer/runner/threaded.rb +1 -1
- data/lib/riffer/runner.rb +1 -1
- data/lib/riffer/skills/activate_tool.rb +4 -3
- data/lib/riffer/skills/config.rb +1 -1
- data/lib/riffer/skills/context.rb +3 -3
- data/lib/riffer/skills/filesystem_backend.rb +7 -5
- data/lib/riffer/skills/markdown_adapter.rb +1 -1
- data/lib/riffer/skills/xml_adapter.rb +1 -1
- data/lib/riffer/stream_events/interrupt.rb +10 -3
- data/lib/riffer/stream_events/token_usage_done.rb +2 -2
- data/lib/riffer/stream_events/web_search_status.rb +1 -1
- data/lib/riffer/tool.rb +3 -3
- data/lib/riffer/{tool_runtime → tools/runtime}/fibers.rb +2 -2
- data/lib/riffer/{tool_runtime → tools/runtime}/inline.rb +1 -1
- data/lib/riffer/{tool_runtime → tools/runtime}/threaded.rb +2 -2
- data/lib/riffer/{tool_runtime.rb → tools/runtime.rb} +21 -15
- data/lib/riffer/{toolable.rb → tools/toolable.rb} +12 -9
- data/lib/riffer/version.rb +1 -1
- data/lib/riffer.rb +2 -1
- data/sig/generated/riffer/agent/config.rbs +119 -0
- data/sig/generated/riffer/agent/context.rbs +91 -0
- data/sig/generated/riffer/agent/response.rbs +10 -2
- data/sig/generated/riffer/agent/run.rbs +144 -0
- data/sig/generated/riffer/agent/session/repair.rbs +51 -0
- data/sig/generated/riffer/agent/session.rbs +145 -0
- data/sig/generated/riffer/{structured_output → agent/structured_output}/result.rbs +2 -2
- data/sig/generated/riffer/{structured_output.rbs → agent/structured_output.rbs} +6 -6
- data/sig/generated/riffer/agent.rbs +154 -225
- data/sig/generated/riffer/config.rbs +50 -5
- data/sig/generated/riffer/evals/judge.rbs +2 -2
- data/sig/generated/riffer/helpers/call_or_value.rbs +9 -0
- data/sig/generated/riffer/helpers.rbs +0 -1
- data/sig/generated/riffer/messages/assistant.rbs +7 -3
- data/sig/generated/riffer/messages/base.rbs +18 -0
- data/sig/generated/riffer/messages/converter.rbs +4 -4
- data/sig/generated/riffer/{file_part.rbs → messages/file_part.rbs} +5 -5
- data/sig/generated/riffer/messages/user.rbs +4 -4
- data/sig/generated/riffer/params/boolean.rbs +10 -0
- data/sig/generated/riffer/{param.rbs → params/param.rbs} +3 -3
- data/sig/generated/riffer/params.rbs +15 -15
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +22 -22
- data/sig/generated/riffer/providers/anthropic.rbs +4 -4
- data/sig/generated/riffer/providers/base.rbs +10 -10
- data/sig/generated/riffer/providers/gemini.rbs +4 -4
- data/sig/generated/riffer/providers/mock.rbs +25 -5
- data/sig/generated/riffer/providers/open_ai.rbs +4 -4
- data/sig/generated/riffer/providers/open_router.rbs +85 -0
- data/sig/generated/riffer/{token_usage.rbs → providers/token_usage.rbs} +5 -5
- data/sig/generated/riffer/providers.rbs +1 -0
- data/sig/generated/riffer/runner/fibers.rbs +2 -2
- data/sig/generated/riffer/runner/sequential.rbs +2 -2
- data/sig/generated/riffer/runner/threaded.rbs +2 -2
- data/sig/generated/riffer/runner.rbs +2 -2
- data/sig/generated/riffer/skills/activate_tool.rbs +4 -3
- data/sig/generated/riffer/skills/config.rbs +1 -1
- data/sig/generated/riffer/skills/context.rbs +2 -2
- data/sig/generated/riffer/stream_events/interrupt.rbs +7 -2
- data/sig/generated/riffer/stream_events/token_usage_done.rbs +3 -3
- data/sig/generated/riffer/tool.rbs +5 -5
- data/sig/generated/riffer/{tool_runtime → tools/runtime}/fibers.rbs +3 -3
- data/sig/generated/riffer/{tool_runtime → tools/runtime}/inline.rbs +2 -2
- data/sig/generated/riffer/{tool_runtime → tools/runtime}/threaded.rbs +3 -3
- data/sig/generated/riffer/{tool_runtime.rbs → tools/runtime.rbs} +19 -13
- data/sig/generated/riffer/{toolable.rbs → tools/toolable.rbs} +6 -6
- data/sig/stubs/agent_ivars.rbs +7 -0
- data/sig/stubs/async.rbs +24 -0
- data/sig/stubs/aws-sdk-core/seahorse_request_context.rbs +7 -0
- data/sig/stubs/aws-sdk-core/static_token_provider.rbs +5 -0
- data/sig/stubs/extend_self.rbs +11 -0
- data/sig/stubs/lib_ivars.rbs +101 -0
- data/sig/stubs/mcp_sdk.rbs +22 -0
- data/sig/stubs/provider_ivars.rbs +36 -0
- data/sig/stubs/provider_sdk_methods.rbs +50 -0
- data/sig/stubs/zeitwerk.rbs +12 -0
- metadata +54 -33
- data/lib/riffer/core.rb +0 -28
- data/lib/riffer/helpers/validations.rb +0 -18
- data/sig/generated/riffer/boolean.rbs +0 -10
- data/sig/generated/riffer/core.rbs +0 -19
- data/sig/generated/riffer/helpers/validations.rbs +0 -12
data/lib/riffer/params.rb
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# end
|
|
13
13
|
#
|
|
14
14
|
class Riffer::Params
|
|
15
|
-
attr_reader :parameters #: Array[Riffer::Param]
|
|
15
|
+
attr_reader :parameters #: Array[Riffer::Params::Param]
|
|
16
16
|
|
|
17
17
|
#--
|
|
18
18
|
#: () -> void
|
|
@@ -23,10 +23,10 @@ class Riffer::Params
|
|
|
23
23
|
# Defines a required parameter.
|
|
24
24
|
#
|
|
25
25
|
#--
|
|
26
|
-
#: (Symbol, Class, ?description: String?, ?enum: Array[untyped]?, ?of: Class?) ?{ () -> void } -> void
|
|
26
|
+
#: (Symbol, Class, ?description: String?, ?enum: Array[untyped]?, ?of: Class?) ?{ (Riffer::Params) [self: Riffer::Params] -> void } -> void
|
|
27
27
|
def required(name, type, description: nil, enum: nil, of: nil, &block)
|
|
28
28
|
nested = build_nested(type, of, &block)
|
|
29
|
-
@parameters << Riffer::Param.new(
|
|
29
|
+
@parameters << Riffer::Params::Param.new(
|
|
30
30
|
name: name,
|
|
31
31
|
type: type,
|
|
32
32
|
required: true,
|
|
@@ -40,10 +40,10 @@ class Riffer::Params
|
|
|
40
40
|
# Defines an optional parameter.
|
|
41
41
|
#
|
|
42
42
|
#--
|
|
43
|
-
#: (Symbol, Class, ?description: String?, ?enum: Array[untyped]?, ?default: untyped, ?of: Class?) ?{ () -> void } -> void
|
|
43
|
+
#: (Symbol, Class, ?description: String?, ?enum: Array[untyped]?, ?default: untyped, ?of: Class?) ?{ (Riffer::Params) [self: Riffer::Params] -> void } -> void
|
|
44
44
|
def optional(name, type, description: nil, enum: nil, default: nil, of: nil, &block)
|
|
45
45
|
nested = build_nested(type, of, &block)
|
|
46
|
-
@parameters << Riffer::Param.new(
|
|
46
|
+
@parameters << Riffer::Params::Param.new(
|
|
47
47
|
name: name,
|
|
48
48
|
type: type,
|
|
49
49
|
required: false,
|
|
@@ -62,8 +62,8 @@ class Riffer::Params
|
|
|
62
62
|
#--
|
|
63
63
|
#: (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
64
64
|
def validate(arguments)
|
|
65
|
-
validated = {}
|
|
66
|
-
errors = []
|
|
65
|
+
validated = {} #: Hash[Symbol, untyped]
|
|
66
|
+
errors = [] #: Array[String]
|
|
67
67
|
|
|
68
68
|
@parameters.each do |param|
|
|
69
69
|
value = arguments[param.name]
|
|
@@ -107,8 +107,8 @@ class Riffer::Params
|
|
|
107
107
|
#--
|
|
108
108
|
#: (?strict: bool) -> Hash[Symbol, untyped]
|
|
109
109
|
def to_json_schema(strict: false)
|
|
110
|
-
properties = {}
|
|
111
|
-
required_params = []
|
|
110
|
+
properties = {} #: Hash[String, untyped]
|
|
111
|
+
required_params = [] #: Array[String]
|
|
112
112
|
|
|
113
113
|
@parameters.each do |param|
|
|
114
114
|
properties[param.name.to_s] = param.to_json_schema(strict: strict)
|
|
@@ -126,7 +126,7 @@ class Riffer::Params
|
|
|
126
126
|
private
|
|
127
127
|
|
|
128
128
|
#--
|
|
129
|
-
#: (Class, Class?) ?{ () -> void } -> Riffer::Params?
|
|
129
|
+
#: (Class, Class?) ?{ (Riffer::Params) [self: Riffer::Params] -> void } -> Riffer::Params?
|
|
130
130
|
def build_nested(type, of, &block)
|
|
131
131
|
if of && block
|
|
132
132
|
raise Riffer::ArgumentError, "cannot use both of: and a block"
|
|
@@ -136,9 +136,9 @@ class Riffer::Params
|
|
|
136
136
|
unless type == Array
|
|
137
137
|
raise Riffer::ArgumentError, "of: can only be used with Array type, got #{type}"
|
|
138
138
|
end
|
|
139
|
-
unless Riffer::Param::PRIMITIVE_TYPES.include?(of)
|
|
139
|
+
unless Riffer::Params::Param::PRIMITIVE_TYPES.include?(of)
|
|
140
140
|
raise Riffer::ArgumentError,
|
|
141
|
-
"of: must be a primitive type (#{Riffer::Param::PRIMITIVE_TYPES.map(&:name).join(", ")}), got #{of}"
|
|
141
|
+
"of: must be a primitive type (#{Riffer::Params::Param::PRIMITIVE_TYPES.map(&:name).join(", ")}), got #{of}"
|
|
142
142
|
end
|
|
143
143
|
return nil
|
|
144
144
|
end
|
|
@@ -154,7 +154,7 @@ class Riffer::Params
|
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
#--
|
|
157
|
-
#: (Riffer::Param, untyped, Array[String]) -> untyped
|
|
157
|
+
#: (Riffer::Params::Param, untyped, Array[String]) -> untyped
|
|
158
158
|
def validate_nested(param, value, errors)
|
|
159
159
|
if param.type == Hash && param.nested_params
|
|
160
160
|
validate_nested_hash(param, value, errors)
|
|
@@ -169,9 +169,11 @@ class Riffer::Params
|
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
#--
|
|
172
|
-
#: (Riffer::Param, Hash[Symbol, untyped], Array[String]) -> Hash[Symbol, untyped]
|
|
172
|
+
#: (Riffer::Params::Param, Hash[Symbol, untyped], Array[String]) -> Hash[Symbol, untyped]
|
|
173
173
|
def validate_nested_hash(param, value, errors)
|
|
174
|
-
param.nested_params
|
|
174
|
+
nested = param.nested_params
|
|
175
|
+
return value unless nested
|
|
176
|
+
nested.validate(value)
|
|
175
177
|
rescue Riffer::ValidationError => e
|
|
176
178
|
e.message.split("; ").each do |msg|
|
|
177
179
|
errors << "#{param.name}.#{msg}"
|
|
@@ -180,14 +182,16 @@ class Riffer::Params
|
|
|
180
182
|
end
|
|
181
183
|
|
|
182
184
|
#--
|
|
183
|
-
#: (Riffer::Param, Array[untyped], Array[String]) -> Array[untyped]
|
|
185
|
+
#: (Riffer::Params::Param, Array[untyped], Array[String]) -> Array[untyped]
|
|
184
186
|
def validate_nested_array_of_objects(param, value, errors)
|
|
187
|
+
nested = param.nested_params
|
|
188
|
+
return value unless nested
|
|
185
189
|
value.map.with_index do |item, i|
|
|
186
190
|
unless item.is_a?(Hash)
|
|
187
191
|
errors << "#{param.name}[#{i}] must be an object"
|
|
188
192
|
next item
|
|
189
193
|
end
|
|
190
|
-
|
|
194
|
+
nested.validate(item)
|
|
191
195
|
rescue Riffer::ValidationError => e
|
|
192
196
|
e.message.split("; ").each do |msg|
|
|
193
197
|
errors << "#{param.name}[#{i}].#{msg}"
|
|
@@ -197,14 +201,16 @@ class Riffer::Params
|
|
|
197
201
|
end
|
|
198
202
|
|
|
199
203
|
#--
|
|
200
|
-
#: (Riffer::Param, Array[untyped], Array[String]) -> void
|
|
204
|
+
#: (Riffer::Params::Param, Array[untyped], Array[String]) -> void
|
|
201
205
|
def validate_typed_array(param, value, errors)
|
|
202
|
-
|
|
206
|
+
item_type = param.item_type
|
|
207
|
+
return unless item_type
|
|
208
|
+
type_name = Riffer::Params::Param::TYPE_MAPPINGS[item_type]
|
|
203
209
|
value.each_with_index do |item, i|
|
|
204
|
-
valid = if
|
|
210
|
+
valid = if item_type == Riffer::Params::Boolean || item_type == TrueClass || item_type == FalseClass
|
|
205
211
|
item == true || item == false
|
|
206
212
|
else
|
|
207
|
-
item.is_a?(
|
|
213
|
+
item.is_a?(item_type)
|
|
208
214
|
end
|
|
209
215
|
errors << "#{param.name}[#{i}] must be a #{type_name}" unless valid
|
|
210
216
|
end
|
|
@@ -63,7 +63,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
63
63
|
system: partitioned_messages[:system],
|
|
64
64
|
messages: partitioned_messages[:conversation],
|
|
65
65
|
**options.except(:tools, :structured_output)
|
|
66
|
-
}
|
|
66
|
+
} #: Hash[Symbol, untyped]
|
|
67
67
|
|
|
68
68
|
if tools && !tools.empty?
|
|
69
69
|
params[:tool_config] = {
|
|
@@ -92,18 +92,17 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
#--
|
|
95
|
-
#: (Hash[Symbol, untyped]) -> Aws::BedrockRuntime::
|
|
95
|
+
#: (Hash[Symbol, untyped]) -> Aws::BedrockRuntime::Client::_ConverseResponseSuccess
|
|
96
96
|
def execute_generate(params)
|
|
97
97
|
@client.converse(**params)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
#--
|
|
101
|
-
#: (Aws::BedrockRuntime::
|
|
101
|
+
#: (Aws::BedrockRuntime::Client::_ConverseResponseSuccess) -> Riffer::Providers::TokenUsage?
|
|
102
102
|
def extract_token_usage(response)
|
|
103
103
|
usage = response.usage
|
|
104
|
-
return nil unless usage
|
|
105
104
|
|
|
106
|
-
Riffer::TokenUsage.new(
|
|
105
|
+
Riffer::Providers::TokenUsage.new(
|
|
107
106
|
input_tokens: usage.input_tokens,
|
|
108
107
|
output_tokens: usage.output_tokens,
|
|
109
108
|
cache_creation_tokens: usage.cache_write_input_tokens,
|
|
@@ -112,7 +111,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
112
111
|
end
|
|
113
112
|
|
|
114
113
|
#--
|
|
115
|
-
#: (Aws::BedrockRuntime::
|
|
114
|
+
#: (Aws::BedrockRuntime::Client::_ConverseResponseSuccess) -> String
|
|
116
115
|
def extract_content(response)
|
|
117
116
|
content_blocks = response.output&.message&.content
|
|
118
117
|
return "" if content_blocks.nil? || content_blocks.empty?
|
|
@@ -127,12 +126,12 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
127
126
|
end
|
|
128
127
|
|
|
129
128
|
#--
|
|
130
|
-
#: (Aws::BedrockRuntime::
|
|
129
|
+
#: (Aws::BedrockRuntime::Client::_ConverseResponseSuccess) -> Array[Riffer::Messages::Assistant::ToolCall]
|
|
131
130
|
def extract_tool_calls(response)
|
|
132
131
|
content_blocks = response.output&.message&.content
|
|
133
132
|
return [] if content_blocks.nil? || content_blocks.empty?
|
|
134
133
|
|
|
135
|
-
tool_calls = []
|
|
134
|
+
tool_calls = [] #: Array[Riffer::Messages::Assistant::ToolCall]
|
|
136
135
|
|
|
137
136
|
content_blocks.each do |block|
|
|
138
137
|
if block.respond_to?(:tool_use) && block.tool_use
|
|
@@ -153,7 +152,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
153
152
|
current_state = {
|
|
154
153
|
text: nil,
|
|
155
154
|
tool_call: nil
|
|
156
|
-
}
|
|
155
|
+
} #: Hash[Symbol, untyped]
|
|
157
156
|
|
|
158
157
|
@client.converse_stream(**params) do |stream|
|
|
159
158
|
stream.on_event do |event|
|
|
@@ -196,7 +195,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
196
195
|
end
|
|
197
196
|
|
|
198
197
|
#--
|
|
199
|
-
#: (Aws::BedrockRuntime::Types::ContentBlockStartEvent, state: Hash[Symbol, untyped], yielder: Enumerator
|
|
198
|
+
#: (Aws::BedrockRuntime::Types::ContentBlockStartEvent, state: Hash[Symbol, untyped], yielder: Enumerator::Yielder) -> void
|
|
200
199
|
def handle_content_block_start_tool_use(event, state:, yielder:)
|
|
201
200
|
state[:tool_call] = {
|
|
202
201
|
id: event.start.tool_use.tool_use_id,
|
|
@@ -206,7 +205,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
206
205
|
end
|
|
207
206
|
|
|
208
207
|
#--
|
|
209
|
-
#: (Aws::BedrockRuntime::Types::ContentBlockDeltaEvent, state: Hash[Symbol, untyped], yielder: Enumerator
|
|
208
|
+
#: (Aws::BedrockRuntime::Types::ContentBlockDeltaEvent, state: Hash[Symbol, untyped], yielder: Enumerator::Yielder) -> void
|
|
210
209
|
def handle_content_block_delta_text_delta(event, state:, yielder:)
|
|
211
210
|
delta_text = event.delta.text
|
|
212
211
|
state[:text] ||= ""
|
|
@@ -215,7 +214,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
215
214
|
end
|
|
216
215
|
|
|
217
216
|
#--
|
|
218
|
-
#: (Aws::BedrockRuntime::Types::ContentBlockDeltaEvent, state: Hash[Symbol, untyped], yielder: Enumerator
|
|
217
|
+
#: (Aws::BedrockRuntime::Types::ContentBlockDeltaEvent, state: Hash[Symbol, untyped], yielder: Enumerator::Yielder) -> void
|
|
219
218
|
def handle_content_block_delta_tool_use(event, state:, yielder:)
|
|
220
219
|
input_delta = event.delta.tool_use.input
|
|
221
220
|
|
|
@@ -229,14 +228,14 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
229
228
|
end
|
|
230
229
|
|
|
231
230
|
#--
|
|
232
|
-
#: (Aws::BedrockRuntime::Types::ContentBlockStopEvent, state: Hash[Symbol, untyped], yielder: Enumerator
|
|
231
|
+
#: (Aws::BedrockRuntime::Types::ContentBlockStopEvent, state: Hash[Symbol, untyped], yielder: Enumerator::Yielder) -> void
|
|
233
232
|
def handle_content_block_stop_text_delta(_event, state:, yielder:)
|
|
234
233
|
yielder << Riffer::StreamEvents::TextDone.new(state[:text])
|
|
235
234
|
state[:text] = nil
|
|
236
235
|
end
|
|
237
236
|
|
|
238
237
|
#--
|
|
239
|
-
#: (Aws::BedrockRuntime::Types::ContentBlockStopEvent, state: Hash[Symbol, untyped], yielder: Enumerator
|
|
238
|
+
#: (Aws::BedrockRuntime::Types::ContentBlockStopEvent, state: Hash[Symbol, untyped], yielder: Enumerator::Yielder) -> void
|
|
240
239
|
def handle_content_block_stop_tool_use(_event, state:, yielder:)
|
|
241
240
|
tool_call = state[:tool_call]
|
|
242
241
|
yielder << Riffer::StreamEvents::ToolCallDone.new(
|
|
@@ -249,10 +248,10 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
249
248
|
end
|
|
250
249
|
|
|
251
250
|
#--
|
|
252
|
-
#: (Aws::BedrockRuntime::Types::ConverseStreamMetadataEvent, state: Hash[Symbol, untyped], yielder: Enumerator
|
|
251
|
+
#: (Aws::BedrockRuntime::Types::ConverseStreamMetadataEvent, state: Hash[Symbol, untyped], yielder: Enumerator::Yielder) -> void
|
|
253
252
|
def handle_metadata_usage(event, state:, yielder:)
|
|
254
253
|
yielder << Riffer::StreamEvents::TokenUsageDone.new(
|
|
255
|
-
token_usage: Riffer::TokenUsage.new(
|
|
254
|
+
token_usage: Riffer::Providers::TokenUsage.new(
|
|
256
255
|
input_tokens: event.usage.input_tokens,
|
|
257
256
|
output_tokens: event.usage.output_tokens,
|
|
258
257
|
cache_creation_tokens: event.usage.cache_write_input_tokens,
|
|
@@ -264,8 +263,8 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
264
263
|
#--
|
|
265
264
|
#: (Array[Riffer::Messages::Base]) -> Hash[Symbol, untyped]
|
|
266
265
|
def partition_messages(messages)
|
|
267
|
-
system_prompts = []
|
|
268
|
-
conversation_messages = []
|
|
266
|
+
system_prompts = [] #: Array[Hash[Symbol, untyped]]
|
|
267
|
+
conversation_messages = [] #: Array[Hash[Symbol, untyped]]
|
|
269
268
|
|
|
270
269
|
messages.each do |message|
|
|
271
270
|
case message
|
|
@@ -291,7 +290,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
291
290
|
#--
|
|
292
291
|
#: (Riffer::Messages::Assistant) -> Hash[Symbol, untyped]
|
|
293
292
|
def convert_assistant_to_bedrock_format(message)
|
|
294
|
-
content = []
|
|
293
|
+
content = [] #: Array[Hash[Symbol, untyped]]
|
|
295
294
|
content << {text: message.content} if message.content && !message.content.empty?
|
|
296
295
|
|
|
297
296
|
message.tool_calls.each do |tc|
|
|
@@ -326,7 +325,7 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
326
325
|
end
|
|
327
326
|
|
|
328
327
|
#--
|
|
329
|
-
#: (Riffer::FilePart) -> Hash[Symbol, untyped]
|
|
328
|
+
#: (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
|
|
330
329
|
def convert_file_part_to_bedrock_format(file)
|
|
331
330
|
format = bedrock_format(file.media_type)
|
|
332
331
|
|
|
@@ -26,7 +26,7 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
26
26
|
|
|
27
27
|
api_key ||= Riffer.config.anthropic.api_key
|
|
28
28
|
|
|
29
|
-
@client = Anthropic::Client.new(api_key: api_key, **options)
|
|
29
|
+
@client = ::Anthropic::Client.new(api_key: api_key, **options)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
private
|
|
@@ -46,11 +46,11 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
46
46
|
messages: partitioned_messages[:conversation],
|
|
47
47
|
max_tokens: max_tokens,
|
|
48
48
|
**options.except(:tools, :max_tokens, :structured_output, :web_search)
|
|
49
|
-
}
|
|
49
|
+
} #: Hash[Symbol, untyped]
|
|
50
50
|
|
|
51
51
|
params[:system] = partitioned_messages[:system] if partitioned_messages[:system]
|
|
52
52
|
|
|
53
|
-
anthropic_tools = []
|
|
53
|
+
anthropic_tools = [] #: Array[Hash[Symbol, untyped]]
|
|
54
54
|
anthropic_tools.concat(tools.map { |t| convert_tool_to_anthropic_format(t) }) if tools && !tools.empty?
|
|
55
55
|
|
|
56
56
|
if web_search
|
|
@@ -83,12 +83,11 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
#--
|
|
86
|
-
#: (Anthropic::Models::Message) -> Riffer::TokenUsage?
|
|
86
|
+
#: (Anthropic::Models::Message) -> Riffer::Providers::TokenUsage?
|
|
87
87
|
def extract_token_usage(response)
|
|
88
88
|
usage = response.usage
|
|
89
|
-
return nil unless usage
|
|
90
89
|
|
|
91
|
-
Riffer::TokenUsage.new(
|
|
90
|
+
Riffer::Providers::TokenUsage.new(
|
|
92
91
|
input_tokens: usage.input_tokens,
|
|
93
92
|
output_tokens: usage.output_tokens,
|
|
94
93
|
cache_creation_tokens: usage.cache_creation_input_tokens,
|
|
@@ -105,7 +104,7 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
105
104
|
text_content = ""
|
|
106
105
|
|
|
107
106
|
content_blocks.each do |block|
|
|
108
|
-
text_content = block.text if block.
|
|
107
|
+
text_content = block.text if block.is_a?(::Anthropic::Models::TextBlock)
|
|
109
108
|
end
|
|
110
109
|
|
|
111
110
|
text_content
|
|
@@ -117,10 +116,10 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
117
116
|
content_blocks = response.content
|
|
118
117
|
return [] if content_blocks.nil? || content_blocks.empty?
|
|
119
118
|
|
|
120
|
-
tool_calls = []
|
|
119
|
+
tool_calls = [] #: Array[Riffer::Messages::Assistant::ToolCall]
|
|
121
120
|
|
|
122
121
|
content_blocks.each do |block|
|
|
123
|
-
if block.
|
|
122
|
+
if block.is_a?(::Anthropic::Models::ToolUseBlock)
|
|
124
123
|
tool_calls << Riffer::Messages::Assistant::ToolCall.new(
|
|
125
124
|
call_id: block.id,
|
|
126
125
|
name: decode_tool_name(block.name, tools: @current_tools),
|
|
@@ -142,7 +141,7 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
142
141
|
web_search_index: nil,
|
|
143
142
|
web_search_json: nil,
|
|
144
143
|
web_search_query: nil
|
|
145
|
-
}
|
|
144
|
+
} #: Hash[Symbol, untyped]
|
|
146
145
|
|
|
147
146
|
# Workaround for anthropics/anthropic-sdk-ruby#182: force identity
|
|
148
147
|
# encoding so Net::HTTP/Zlib doesn't buffer SSE chunks until EOF.
|
|
@@ -154,24 +153,24 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
154
153
|
begin
|
|
155
154
|
stream.each do |event|
|
|
156
155
|
case event
|
|
157
|
-
when Anthropic::Models::RawContentBlockStartEvent
|
|
156
|
+
when ::Anthropic::Models::RawContentBlockStartEvent
|
|
158
157
|
handle_raw_content_block_start(event, state: current_state)
|
|
159
|
-
when Anthropic::Models::RawContentBlockDeltaEvent
|
|
158
|
+
when ::Anthropic::Models::RawContentBlockDeltaEvent
|
|
160
159
|
handle_raw_content_block_delta(event, state: current_state)
|
|
161
|
-
when Anthropic::Streaming::TextEvent
|
|
160
|
+
when ::Anthropic::Helpers::Streaming::TextEvent
|
|
162
161
|
handle_text_event(event, state: current_state, yielder: yielder)
|
|
163
|
-
when Anthropic::Streaming::ThinkingEvent
|
|
162
|
+
when ::Anthropic::Helpers::Streaming::ThinkingEvent
|
|
164
163
|
handle_thinking_event(event, state: current_state, yielder: yielder)
|
|
165
|
-
when Anthropic::Streaming::InputJsonEvent
|
|
164
|
+
when ::Anthropic::Helpers::Streaming::InputJsonEvent
|
|
166
165
|
handle_input_json_event(event, state: current_state, yielder: yielder)
|
|
167
|
-
when Anthropic::Streaming::ContentBlockStopEvent
|
|
168
|
-
|
|
169
|
-
handle_content_block_stop_text(event, state: current_state, yielder: yielder) if
|
|
170
|
-
handle_content_block_stop_tool_use(event, state: current_state, yielder: yielder) if
|
|
171
|
-
handle_content_block_stop_thinking(event, state: current_state, yielder: yielder) if
|
|
172
|
-
handle_content_block_stop_server_tool_use(event, state: current_state, yielder: yielder) if
|
|
173
|
-
handle_content_block_stop_web_search_result(event, state: current_state, yielder: yielder) if
|
|
174
|
-
when Anthropic::Streaming::MessageStopEvent
|
|
166
|
+
when ::Anthropic::Helpers::Streaming::ContentBlockStopEvent
|
|
167
|
+
block = event.content_block
|
|
168
|
+
handle_content_block_stop_text(event, state: current_state, yielder: yielder) if block.is_a?(::Anthropic::Models::TextBlock) && current_state[:text]
|
|
169
|
+
handle_content_block_stop_tool_use(event, state: current_state, yielder: yielder) if block.is_a?(::Anthropic::Models::ToolUseBlock)
|
|
170
|
+
handle_content_block_stop_thinking(event, state: current_state, yielder: yielder) if block.is_a?(::Anthropic::Models::ThinkingBlock) && current_state[:reasoning]
|
|
171
|
+
handle_content_block_stop_server_tool_use(event, state: current_state, yielder: yielder) if block.is_a?(::Anthropic::Models::ServerToolUseBlock)
|
|
172
|
+
handle_content_block_stop_web_search_result(event, state: current_state, yielder: yielder) if block.is_a?(::Anthropic::Models::WebSearchToolResultBlock)
|
|
173
|
+
when ::Anthropic::Helpers::Streaming::MessageStopEvent
|
|
175
174
|
handle_message_stop(event, accumulated_message: stream.accumulated_message, yielder: yielder)
|
|
176
175
|
end
|
|
177
176
|
end
|
|
@@ -292,7 +291,7 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
292
291
|
return unless usage
|
|
293
292
|
|
|
294
293
|
yielder << Riffer::StreamEvents::TokenUsageDone.new(
|
|
295
|
-
token_usage: Riffer::TokenUsage.new(
|
|
294
|
+
token_usage: Riffer::Providers::TokenUsage.new(
|
|
296
295
|
input_tokens: usage.input_tokens,
|
|
297
296
|
output_tokens: usage.output_tokens,
|
|
298
297
|
cache_creation_tokens: usage.cache_creation_input_tokens,
|
|
@@ -304,8 +303,8 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
304
303
|
#--
|
|
305
304
|
#: (Array[Riffer::Messages::Base]) -> Hash[Symbol, untyped]
|
|
306
305
|
def partition_messages(messages)
|
|
307
|
-
system_prompts = []
|
|
308
|
-
conversation_messages = []
|
|
306
|
+
system_prompts = [] #: Array[Hash[Symbol, untyped]]
|
|
307
|
+
conversation_messages = [] #: Array[Hash[Symbol, untyped]]
|
|
309
308
|
|
|
310
309
|
messages.each do |message|
|
|
311
310
|
case message
|
|
@@ -342,7 +341,7 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
342
341
|
#--
|
|
343
342
|
#: (Riffer::Messages::Assistant) -> Hash[Symbol, untyped]
|
|
344
343
|
def convert_assistant_to_anthropic_format(message)
|
|
345
|
-
content = []
|
|
344
|
+
content = [] #: Array[Hash[Symbol, untyped]]
|
|
346
345
|
content << {type: "text", text: message.content} if message.content && !message.content.empty?
|
|
347
346
|
|
|
348
347
|
message.tool_calls.each do |tc|
|
|
@@ -358,7 +357,7 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
358
357
|
end
|
|
359
358
|
|
|
360
359
|
#--
|
|
361
|
-
#: (Riffer::FilePart) -> Hash[Symbol, untyped]
|
|
360
|
+
#: (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
|
|
362
361
|
def convert_file_part_to_anthropic_format(file)
|
|
363
362
|
type = file.image? ? "image" : "document"
|
|
364
363
|
|
|
@@ -39,10 +39,10 @@ class Riffer::Providers::Base
|
|
|
39
39
|
# Generates text using the provider.
|
|
40
40
|
#
|
|
41
41
|
#--
|
|
42
|
-
#: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::FilePart]?, **untyped) -> Riffer::Messages::Assistant
|
|
42
|
+
#: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, **untyped) -> Riffer::Messages::Assistant
|
|
43
43
|
def generate_text(prompt: nil, system: nil, messages: nil, model: nil, files: nil, **options)
|
|
44
44
|
validate_input!(prompt: prompt, system: system, messages: messages)
|
|
45
|
-
@current_tools = options[:tools] || []
|
|
45
|
+
@current_tools = options[:tools] || [] #: Array[singleton(Riffer::Tool)]
|
|
46
46
|
messages = normalize_messages(prompt: prompt, system: system, messages: messages, files: files)
|
|
47
47
|
validate_normalized_messages!(messages)
|
|
48
48
|
messages = merge_consecutive_messages(messages)
|
|
@@ -65,10 +65,10 @@ class Riffer::Providers::Base
|
|
|
65
65
|
# Streams text from the provider.
|
|
66
66
|
#
|
|
67
67
|
#--
|
|
68
|
-
#: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::FilePart]?, **untyped) -> Enumerator[Riffer::StreamEvents::Base, void]
|
|
68
|
+
#: (?prompt: String?, ?system: String?, ?messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?model: String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, **untyped) -> Enumerator[Riffer::StreamEvents::Base, void]
|
|
69
69
|
def stream_text(prompt: nil, system: nil, messages: nil, model: nil, files: nil, **options)
|
|
70
70
|
validate_input!(prompt: prompt, system: system, messages: messages)
|
|
71
|
-
@current_tools = options[:tools] || []
|
|
71
|
+
@current_tools = options[:tools] || [] #: Array[singleton(Riffer::Tool)]
|
|
72
72
|
messages = normalize_messages(prompt: prompt, system: system, messages: messages, files: files)
|
|
73
73
|
validate_normalized_messages!(messages)
|
|
74
74
|
messages = merge_consecutive_messages(messages)
|
|
@@ -87,7 +87,7 @@ class Riffer::Providers::Base
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
#--
|
|
90
|
-
#: (String, tools: Array[Riffer::Tool]) -> String
|
|
90
|
+
#: (String, tools: Array[singleton(Riffer::Tool)]) -> String
|
|
91
91
|
def decode_tool_name(wire_name, tools:)
|
|
92
92
|
tool = tools.find { |t| encode_tool_name(t.name) == wire_name }
|
|
93
93
|
tool ? tool.name : wire_name
|
|
@@ -112,7 +112,7 @@ class Riffer::Providers::Base
|
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
#--
|
|
115
|
-
#: (untyped) -> Riffer::TokenUsage?
|
|
115
|
+
#: (untyped) -> Riffer::Providers::TokenUsage?
|
|
116
116
|
def extract_token_usage(response)
|
|
117
117
|
raise NotImplementedError, "Subclasses must implement #extract_token_usage"
|
|
118
118
|
end
|
|
@@ -166,7 +166,7 @@ class Riffer::Providers::Base
|
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
#--
|
|
169
|
-
#: (prompt: String?, system: String?, messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?files: Array[Hash[Symbol, untyped] | Riffer::FilePart]?) -> Array[Riffer::Messages::Base]
|
|
169
|
+
#: (prompt: String?, system: String?, messages: Array[Hash[Symbol, untyped] | Riffer::Messages::Base]?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?) -> Array[Riffer::Messages::Base]
|
|
170
170
|
def normalize_messages(prompt:, system:, messages:, files: nil)
|
|
171
171
|
if messages && files && !files.empty?
|
|
172
172
|
raise Riffer::ArgumentError, "cannot provide both files and messages; attach files to individual messages instead"
|
|
@@ -176,10 +176,11 @@ class Riffer::Providers::Base
|
|
|
176
176
|
return messages.map { |msg| convert_to_message_object(msg) }
|
|
177
177
|
end
|
|
178
178
|
|
|
179
|
-
result = []
|
|
179
|
+
result = [] #: Array[Riffer::Messages::Base]
|
|
180
180
|
result << Riffer::Messages::System.new(system) if system
|
|
181
181
|
file_parts = (files || []).map { |f| convert_to_file_part(f) }
|
|
182
|
-
|
|
182
|
+
prompt_text = prompt #: String
|
|
183
|
+
result << Riffer::Messages::User.new(prompt_text, files: file_parts)
|
|
183
184
|
result
|
|
184
185
|
end
|
|
185
186
|
|
|
@@ -36,7 +36,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
36
36
|
params = {
|
|
37
37
|
model: model,
|
|
38
38
|
contents: partitioned[:contents]
|
|
39
|
-
}
|
|
39
|
+
} #: Hash[Symbol, untyped]
|
|
40
40
|
|
|
41
41
|
params[:systemInstruction] = partitioned[:system_instruction] if partitioned[:system_instruction]
|
|
42
42
|
|
|
@@ -96,12 +96,12 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
#--
|
|
99
|
-
#: (Hash[Symbol, untyped]) -> Riffer::TokenUsage?
|
|
99
|
+
#: (Hash[Symbol, untyped]) -> Riffer::Providers::TokenUsage?
|
|
100
100
|
def extract_token_usage(response)
|
|
101
101
|
usage = response[:usageMetadata]
|
|
102
102
|
return nil unless usage
|
|
103
103
|
|
|
104
|
-
Riffer::TokenUsage.new(
|
|
104
|
+
Riffer::Providers::TokenUsage.new(
|
|
105
105
|
input_tokens: usage[:promptTokenCount] || 0,
|
|
106
106
|
output_tokens: usage[:candidatesTokenCount] || 0
|
|
107
107
|
)
|
|
@@ -114,6 +114,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
114
114
|
body = params.except(:model)
|
|
115
115
|
|
|
116
116
|
uri = URI("#{BASE_URI}/#{api_path(model, "streamGenerateContent")}?alt=sse")
|
|
117
|
+
host = uri.hostname #: String
|
|
117
118
|
request = Net::HTTP::Post.new(uri)
|
|
118
119
|
request["Content-Type"] = "application/json"
|
|
119
120
|
request["x-goog-api-key"] = @api_key
|
|
@@ -126,7 +127,8 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
126
127
|
buffer << chunk
|
|
127
128
|
|
|
128
129
|
while (match = buffer.match(/\r?\n\r?\n/))
|
|
129
|
-
|
|
130
|
+
match_end = match.end(0) #: Integer
|
|
131
|
+
frame = buffer.slice!(0, match_end).to_s.strip
|
|
130
132
|
next unless frame.start_with?("data: ")
|
|
131
133
|
|
|
132
134
|
json_str = frame.delete_prefix("data: ").strip
|
|
@@ -155,7 +157,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
155
157
|
usage = parsed[:usageMetadata]
|
|
156
158
|
if usage && usage[:candidatesTokenCount]
|
|
157
159
|
yielder << Riffer::StreamEvents::TokenUsageDone.new(
|
|
158
|
-
token_usage: Riffer::TokenUsage.new(
|
|
160
|
+
token_usage: Riffer::Providers::TokenUsage.new(
|
|
159
161
|
input_tokens: usage[:promptTokenCount] || 0,
|
|
160
162
|
output_tokens: usage[:candidatesTokenCount] || 0
|
|
161
163
|
)
|
|
@@ -164,7 +166,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
164
166
|
end
|
|
165
167
|
end
|
|
166
168
|
|
|
167
|
-
Net::HTTP.start(
|
|
169
|
+
Net::HTTP.start(host, uri.port, use_ssl: true, open_timeout: @open_timeout, read_timeout: @read_timeout) do |http|
|
|
168
170
|
http.request(request) do |response|
|
|
169
171
|
handle_api_error!(response) unless response.is_a?(Net::HTTPSuccess)
|
|
170
172
|
|
|
@@ -182,8 +184,8 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
182
184
|
#--
|
|
183
185
|
#: (Array[Riffer::Messages::Base]) -> Hash[Symbol, untyped]
|
|
184
186
|
def partition_messages(messages)
|
|
185
|
-
system_parts = []
|
|
186
|
-
contents = []
|
|
187
|
+
system_parts = [] #: Array[Hash[Symbol, untyped]]
|
|
188
|
+
contents = [] #: Array[Hash[Symbol, untyped]]
|
|
187
189
|
|
|
188
190
|
messages.each do |message|
|
|
189
191
|
case message
|
|
@@ -212,7 +214,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
212
214
|
end
|
|
213
215
|
end
|
|
214
216
|
|
|
215
|
-
result = {contents: contents}
|
|
217
|
+
result = {contents: contents} #: Hash[Symbol, untyped]
|
|
216
218
|
result[:system_instruction] = {parts: system_parts} unless system_parts.empty?
|
|
217
219
|
result
|
|
218
220
|
end
|
|
@@ -220,7 +222,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
220
222
|
#--
|
|
221
223
|
#: (Riffer::Messages::Assistant) -> Hash[Symbol, untyped]
|
|
222
224
|
def convert_assistant_to_gemini_format(message)
|
|
223
|
-
parts = []
|
|
225
|
+
parts = [] #: Array[Hash[Symbol, untyped]]
|
|
224
226
|
parts << {text: message.content} if message.content && !message.content.empty?
|
|
225
227
|
|
|
226
228
|
message.tool_calls.each do |tc|
|
|
@@ -236,7 +238,7 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
236
238
|
end
|
|
237
239
|
|
|
238
240
|
#--
|
|
239
|
-
#: (Riffer::FilePart) -> Hash[Symbol, untyped]
|
|
241
|
+
#: (Riffer::Messages::FilePart) -> Hash[Symbol, untyped]
|
|
240
242
|
def convert_file_part_to_gemini_format(file)
|
|
241
243
|
if file.url?
|
|
242
244
|
raise Riffer::ArgumentError,
|
|
@@ -268,11 +270,12 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
268
270
|
#: (String, Hash[Symbol, untyped]) -> Net::HTTPResponse
|
|
269
271
|
def post_request(path, body)
|
|
270
272
|
uri = URI("#{BASE_URI}/#{path}")
|
|
273
|
+
host = uri.hostname #: String
|
|
271
274
|
request = Net::HTTP::Post.new(uri)
|
|
272
275
|
request["Content-Type"] = "application/json"
|
|
273
276
|
request["x-goog-api-key"] = @api_key
|
|
274
277
|
request.body = body.to_json
|
|
275
|
-
Net::HTTP.start(
|
|
278
|
+
Net::HTTP.start(host, uri.port, use_ssl: true, open_timeout: @open_timeout, read_timeout: @read_timeout) { |http| http.request(request) }
|
|
276
279
|
end
|
|
277
280
|
|
|
278
281
|
#--
|