intelligence 0.7.1 → 1.0.0.beta01
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/README.md +80 -59
- data/intelligence.gemspec +1 -0
- data/lib/intelligence/adapters/anthropic/chat_response_methods.rb +5 -12
- data/lib/intelligence/adapters/cerebras.rb +2 -2
- data/lib/intelligence/adapters/generic/adapter.rb +4 -2
- data/lib/intelligence/adapters/generic/chat_request_methods.rb +221 -0
- data/lib/intelligence/adapters/generic/chat_response_methods.rb +234 -0
- data/lib/intelligence/adapters/google/adapter.rb +13 -0
- data/lib/intelligence/adapters/google/chat_request_methods.rb +22 -8
- data/lib/intelligence/adapters/groq.rb +2 -21
- data/lib/intelligence/adapters/hyperbolic.rb +0 -26
- data/lib/intelligence/adapters/mistral.rb +3 -24
- data/lib/intelligence/adapters/open_ai/adapter.rb +47 -23
- data/lib/intelligence/adapters/open_ai/chat_request_methods.rb +1 -1
- data/lib/intelligence/adapters/open_ai/chat_response_methods.rb +38 -42
- data/lib/intelligence/adapters/samba_nova.rb +3 -5
- data/lib/intelligence/adapters/together_ai.rb +4 -4
- data/lib/intelligence/message.rb +1 -1
- data/lib/intelligence/message_content/text.rb +8 -0
- data/lib/intelligence/message_content/tool_call.rb +53 -1
- data/lib/intelligence/version.rb +1 -1
- data/lib/intelligence.rb +1 -0
- metadata +18 -5
- data/lib/intelligence/adapters/generic/chat_methods.rb +0 -362
- data/lib/intelligence/adapters/legacy/adapter.rb +0 -11
- data/lib/intelligence/adapters/legacy/chat_methods.rb +0 -53
@@ -0,0 +1,234 @@
|
|
1
|
+
module Intelligence
|
2
|
+
module Generic
|
3
|
+
module ChatResponseMethods
|
4
|
+
|
5
|
+
def chat_result_attributes( response )
|
6
|
+
return nil unless response.success?
|
7
|
+
response_json = JSON.parse( response.body, symbolize_names: true ) rescue nil
|
8
|
+
return nil if response_json.nil? || response_json[ :choices ].nil?
|
9
|
+
|
10
|
+
result = {}
|
11
|
+
result[ :choices ] = []
|
12
|
+
|
13
|
+
( response_json[ :choices ] || [] ).each do | json_choice |
|
14
|
+
if ( json_message = json_choice[ :message ] )
|
15
|
+
result_message = { role: json_message[ :role ] }
|
16
|
+
if json_message[ :content ]
|
17
|
+
result_message[ :contents ] = [ { type: :text, text: json_message[ :content ] } ]
|
18
|
+
end
|
19
|
+
if json_message[ :tool_calls ] && !json_message[ :tool_calls ].empty?
|
20
|
+
result_message[ :contents ] ||= []
|
21
|
+
json_message[ :tool_calls ].each do | json_message_tool_call |
|
22
|
+
result_message_tool_call_parameters =
|
23
|
+
JSON.parse( json_message_tool_call[ :function ][ :arguments ], symbolize_names: true ) \
|
24
|
+
rescue json_message_tool_call[ :function ][ :arguments ]
|
25
|
+
result_message[ :contents ] << {
|
26
|
+
type: :tool_call,
|
27
|
+
tool_call_id: json_message_tool_call[ :id ],
|
28
|
+
tool_name: json_message_tool_call[ :function ][ :name ],
|
29
|
+
tool_parameters: result_message_tool_call_parameters
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
result[ :choices ].push( {
|
35
|
+
end_reason: to_end_reason( json_choice[ :finish_reason ] ),
|
36
|
+
message: result_message
|
37
|
+
} )
|
38
|
+
end
|
39
|
+
|
40
|
+
metrics_json = response_json[ :usage ]
|
41
|
+
unless metrics_json.nil?
|
42
|
+
|
43
|
+
metrics = {}
|
44
|
+
metrics[ :input_tokens ] = metrics_json[ :prompt_tokens ]
|
45
|
+
metrics[ :output_tokens ] = metrics_json[ :completion_tokens ]
|
46
|
+
metrics = metrics.compact
|
47
|
+
|
48
|
+
result[ :metrics ] = metrics unless metrics.empty?
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
def chat_result_error_attributes( response )
|
56
|
+
error_type, error_description = to_error_response( response.status )
|
57
|
+
error = error_type
|
58
|
+
|
59
|
+
parsed_body = JSON.parse( response.body, symbolize_names: true ) rescue nil
|
60
|
+
if parsed_body && parsed_body.respond_to?( :[] )
|
61
|
+
if parsed_body[ :error ].respond_to?( :[] )
|
62
|
+
error = parsed_body[ :error ][ :code ] || error_type
|
63
|
+
error_description = parsed_body[ :error ][ :message ] || error_description
|
64
|
+
elsif parsed_body[ :object ] == 'error'
|
65
|
+
error = parsed_body[ :type ] || error_type
|
66
|
+
error_description = parsed_body[ :detail ] || parsed_body[ :message ]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
{ error_type: error_type.to_s, error: error.to_s, error_description: error_description }
|
71
|
+
end
|
72
|
+
|
73
|
+
def stream_result_chunk_attributes( context, chunk )
|
74
|
+
context ||= {}
|
75
|
+
buffer = context[ :buffer ] || ''
|
76
|
+
metrics = context[ :metrics ] || {
|
77
|
+
input_tokens: 0,
|
78
|
+
output_tokens: 0
|
79
|
+
}
|
80
|
+
choices = context[ :choices ] || Array.new( 1 , { message: {} } )
|
81
|
+
|
82
|
+
choices.each do | choice |
|
83
|
+
choice[ :message ][ :contents ] = choice[ :message ][ :contents ]&.map do | content |
|
84
|
+
{ type: content[ :type ] }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
buffer += chunk
|
89
|
+
while ( eol_index = buffer.index( "\n" ) )
|
90
|
+
line = buffer.slice!( 0..eol_index )
|
91
|
+
line = line.strip
|
92
|
+
next if line.empty? || !line.start_with?( 'data:' )
|
93
|
+
line = line[ 6..-1 ]
|
94
|
+
next if line.end_with?( '[DONE]' )
|
95
|
+
|
96
|
+
data = JSON.parse( line ) rescue nil
|
97
|
+
if data.is_a?( Hash )
|
98
|
+
data[ 'choices' ]&.each do | data_choice |
|
99
|
+
|
100
|
+
data_choice_index = data_choice[ 'index' ]
|
101
|
+
data_choice_delta = data_choice[ 'delta' ]
|
102
|
+
data_choice_finish_reason = data_choice[ 'finish_reason' ]
|
103
|
+
|
104
|
+
choices.fill( { message: {} }, choices.size, data_choice_index + 1 ) \
|
105
|
+
if choices.size <= data_choice_index
|
106
|
+
contents = choices[ data_choice_index ][ :message ][ :contents ] || []
|
107
|
+
|
108
|
+
text_content = contents.first&.[]( :type ) == :text ? contents.first : nil
|
109
|
+
if data_choice_content = data_choice_delta[ 'content' ]
|
110
|
+
if text_content.nil?
|
111
|
+
contents.unshift( text_content = { type: :text, text: data_choice_content } )
|
112
|
+
else
|
113
|
+
text_content[ :text ] = ( text_content[ :text ] || '' ) + data_choice_content
|
114
|
+
end
|
115
|
+
end
|
116
|
+
if data_choice_tool_calls = data_choice_delta[ 'tool_calls' ]
|
117
|
+
data_choice_tool_calls.each_with_index do | data_choice_tool_call, data_choice_tool_call_index |
|
118
|
+
if data_choice_tool_call_function = data_choice_tool_call[ 'function' ]
|
119
|
+
data_choice_tool_index = data_choice_tool_call[ 'index' ] || data_choice_tool_call_index
|
120
|
+
data_choice_tool_id = data_choice_tool_call[ 'id' ]
|
121
|
+
data_choice_tool_name = data_choice_tool_call_function[ 'name' ]
|
122
|
+
data_choice_tool_parameters = data_choice_tool_call_function[ 'arguments' ]
|
123
|
+
|
124
|
+
tool_call_content_index = ( text_content.nil? ? 0 : 1 ) + data_choice_tool_index
|
125
|
+
if tool_call_content_index >= contents.length
|
126
|
+
contents.push( {
|
127
|
+
type: :tool_call,
|
128
|
+
tool_call_id: data_choice_tool_id,
|
129
|
+
tool_name: data_choice_tool_name,
|
130
|
+
tool_parameters: data_choice_tool_parameters
|
131
|
+
} )
|
132
|
+
else
|
133
|
+
tool_call = contents[ tool_call_content_index ]
|
134
|
+
tool_call[ :tool_call_id ] = ( tool_call[ :tool_call_id ] || '' ) + data_choice_tool_id \
|
135
|
+
if data_choice_tool_id
|
136
|
+
tool_call[ :tool_name ] = ( tool_call[ :tool_name ] || '' ) + data_choice_tool_name \
|
137
|
+
if data_choice_tool_name
|
138
|
+
tool_call[ :tool_parameters ] = ( tool_call[ :tool_parameters ] || '' ) + data_choice_tool_parameters \
|
139
|
+
if data_choice_tool_parameters
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
choices[ data_choice_index ][ :message ][ :contents ] = contents
|
145
|
+
choices[ data_choice_index ][ :end_reason ] ||=
|
146
|
+
to_end_reason( data_choice_finish_reason )
|
147
|
+
end
|
148
|
+
|
149
|
+
if usage = data[ 'usage' ]
|
150
|
+
# note: A number of providers will resend the input tokens as part of their usage
|
151
|
+
# payload.
|
152
|
+
metrics[ :input_tokens ] = usage[ 'prompt_tokens' ] \
|
153
|
+
if usage.include?( 'prompt_tokens' )
|
154
|
+
metrics[ :output_tokens ] += usage[ 'completion_tokens' ] \
|
155
|
+
if usage.include?( 'completion_tokens' )
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
context[ :buffer ] = buffer
|
163
|
+
context[ :metrics ] = metrics
|
164
|
+
context[ :choices ] = choices
|
165
|
+
|
166
|
+
[ context, choices.empty? ? nil : { choices: choices.dup } ]
|
167
|
+
end
|
168
|
+
|
169
|
+
def stream_result_attributes( context )
|
170
|
+
choices = context[ :choices ]
|
171
|
+
metrics = context[ :metrics ]
|
172
|
+
|
173
|
+
choices = choices.map do | choice |
|
174
|
+
{ end_reason: choice[ :end_reason ] }
|
175
|
+
end
|
176
|
+
|
177
|
+
{ choices: choices, metrics: context[ :metrics ] }
|
178
|
+
end
|
179
|
+
|
180
|
+
alias_method :stream_result_error_attributes, :chat_result_error_attributes
|
181
|
+
|
182
|
+
def to_end_reason( finish_reason )
|
183
|
+
case finish_reason
|
184
|
+
when 'stop'
|
185
|
+
:ended
|
186
|
+
when 'length'
|
187
|
+
:token_limit_exceeded
|
188
|
+
when 'tool_calls'
|
189
|
+
:tool_called
|
190
|
+
when 'content_filter'
|
191
|
+
:filtered
|
192
|
+
else
|
193
|
+
nil
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def to_error_response( status )
|
198
|
+
case status
|
199
|
+
when 400
|
200
|
+
[ :invalid_request_error,
|
201
|
+
"There was an issue with the format or content of your request." ]
|
202
|
+
when 401
|
203
|
+
[ :authentication_error,
|
204
|
+
"There's an issue with your API key." ]
|
205
|
+
when 403
|
206
|
+
[ :permission_error,
|
207
|
+
"Your API key does not have permission to use the specified resource." ]
|
208
|
+
when 404
|
209
|
+
[ :not_found_error,
|
210
|
+
"The requested resource was not found." ]
|
211
|
+
when 413
|
212
|
+
[ :request_too_large,
|
213
|
+
"Request exceeds the maximum allowed number of bytes." ]
|
214
|
+
when 422
|
215
|
+
[ :invalid_request_error,
|
216
|
+
"There was an issue with the format or content of your request." ]
|
217
|
+
when 429
|
218
|
+
[ :rate_limit_error,
|
219
|
+
"Your account has hit a rate limit." ]
|
220
|
+
when 500, 502, 503
|
221
|
+
[ :api_error,
|
222
|
+
"An unexpected error has occurred internal to the providers systems." ]
|
223
|
+
when 529
|
224
|
+
[ :overloaded_error,
|
225
|
+
"The providers server is temporarily overloaded." ]
|
226
|
+
else
|
227
|
+
[ :unknown_error, "
|
228
|
+
An unknown error occurred." ]
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -35,6 +35,19 @@ module Intelligence
|
|
35
35
|
response_mime_type String, as: :responseMimeType
|
36
36
|
response_schema as: :responseSchema
|
37
37
|
|
38
|
+
# google tools setup
|
39
|
+
tools do
|
40
|
+
google_search as: :google_search_retrieval do
|
41
|
+
dynamic_retrieval as: :dynamic_retrieval_config, default: {} do
|
42
|
+
mode String, default: 'MODE_DYNAMIC'
|
43
|
+
threshold Float, as: :dynamic_threshold, in: 0..1, default: 0.3
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
code_execution do
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
38
51
|
# google specific tool configuration
|
39
52
|
tool_configuration as: :tool_config do
|
40
53
|
function_calling as: :function_calling_config do
|
@@ -61,16 +61,33 @@ module Intelligence
|
|
61
61
|
# discard properties not part of the google generationConfig schema
|
62
62
|
gc.delete( :model )
|
63
63
|
gc.delete( :stream )
|
64
|
-
|
64
|
+
|
65
|
+
# googlify tools
|
66
|
+
tools = gc.delete( :tools )
|
67
|
+
if tools&.any?
|
68
|
+
tools = tools.then do | tools_object |
|
69
|
+
tools_array ||= []
|
70
|
+
tools_object.each { | key, value | tools_array << { key => value } }
|
71
|
+
tools_array
|
72
|
+
end
|
73
|
+
end
|
74
|
+
tool_functions = to_google_tools( conversation[ :tools ] )
|
75
|
+
if tool_functions&.any?
|
76
|
+
tools ||= {}
|
77
|
+
tools[ :function_declarations ] ||= []
|
78
|
+
tools[ :function_declarations ].concat( tool_functions )
|
79
|
+
end
|
80
|
+
|
65
81
|
# googlify tool configuration
|
66
82
|
if tool_config = gc.delete( :tool_config )
|
67
83
|
mode = tool_config[ :function_calling_config ]&.[]( :mode )
|
68
84
|
tool_config[ :function_calling_config ][ :mode ] = mode.to_s.upcase if mode
|
69
85
|
end
|
70
|
-
|
86
|
+
|
71
87
|
result = {}
|
72
88
|
result[ :generationConfig ] = gc
|
73
|
-
result[ :
|
89
|
+
result[ :tools ] = tools if tools
|
90
|
+
result[ :tool_config ] = tool_config if tools && tool_config
|
74
91
|
|
75
92
|
# construct the system prompt in the form of the google schema
|
76
93
|
system_instructions = to_google_system_message( conversation[ :system_message ] )
|
@@ -163,9 +180,6 @@ module Intelligence
|
|
163
180
|
|
164
181
|
end
|
165
182
|
|
166
|
-
tools_attributes = to_google_tools( conversation[ :tools ] )
|
167
|
-
result[ :tools ] = tools_attributes if tools_attributes && tools_attributes.length > 0
|
168
|
-
|
169
183
|
JSON.generate( result )
|
170
184
|
end
|
171
185
|
|
@@ -208,7 +222,7 @@ module Intelligence
|
|
208
222
|
[ object, required.compact ]
|
209
223
|
end
|
210
224
|
|
211
|
-
return
|
225
|
+
return tools&.map { | tool |
|
212
226
|
function = {
|
213
227
|
name: tool[ :name ],
|
214
228
|
description: tool[ :description ],
|
@@ -223,7 +237,7 @@ module Intelligence
|
|
223
237
|
function[ :parameters ][ :required ] = properties_required if properties_required.any?
|
224
238
|
end
|
225
239
|
function
|
226
|
-
}
|
240
|
+
}
|
227
241
|
end
|
228
242
|
|
229
243
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'generic/adapter'
|
2
2
|
|
3
3
|
module Intelligence
|
4
4
|
module Groq
|
5
5
|
|
6
|
-
class Adapter <
|
6
|
+
class Adapter < Generic::Adapter
|
7
7
|
|
8
8
|
chat_request_uri 'https://api.groq.com/openai/v1/chat/completions'
|
9
9
|
|
@@ -44,25 +44,6 @@ module Intelligence
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
alias chat_request_generic_message_attributes chat_request_message_attributes
|
48
|
-
|
49
|
-
# groq models only support the legacy Open AI message schema for the assistant
|
50
|
-
# messages while supporting the modern message schema for user messages
|
51
|
-
def chat_request_message_attributes( message )
|
52
|
-
role = message[ :role ]&.to_sym
|
53
|
-
case role
|
54
|
-
when :user
|
55
|
-
chat_request_generic_message_attributes( message )
|
56
|
-
when :assistant
|
57
|
-
chat_request_legacy_message_attributes( message )
|
58
|
-
else
|
59
|
-
raise UnsupportedContentError.new(
|
60
|
-
:mistral,
|
61
|
-
'only supports user and assistant message roles'
|
62
|
-
)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
47
|
end
|
67
48
|
|
68
49
|
end
|
@@ -23,32 +23,6 @@ module Intelligence
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def chat_result_error_attributes( response )
|
27
|
-
|
28
|
-
error_type, error_description = translate_error_response_status( response.status )
|
29
|
-
result = {
|
30
|
-
error_type: error_type.to_s,
|
31
|
-
error_description: error_description
|
32
|
-
}
|
33
|
-
parsed_body = JSON.parse( response.body, symbolize_names: true ) rescue nil
|
34
|
-
if parsed_body && parsed_body.respond_to?( :include? )
|
35
|
-
if parsed_body.include?( :error )
|
36
|
-
result = {
|
37
|
-
error_type: error_type.to_s,
|
38
|
-
error: parsed_body[ :error ][ :code ] || error_type.to_s,
|
39
|
-
error_description: parsed_body[ :error ][ :message ] || error_description
|
40
|
-
}
|
41
|
-
elsif parsed_body.include?( :detail )
|
42
|
-
result[ :error_description ] = parsed_body[ :detail ]
|
43
|
-
elsif parsed_body[ :object ] == 'error'
|
44
|
-
result[ :error_description ] = parsed_body[ :message ]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
result
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
26
|
end
|
53
27
|
|
54
28
|
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'generic/adapter'
|
2
2
|
|
3
3
|
module Intelligence
|
4
4
|
module Mistral
|
5
|
-
|
6
|
-
class Adapter < Legacy::Adapter
|
5
|
+
class Adapter < Generic::Adapter
|
7
6
|
|
8
7
|
chat_request_uri "https://api.mistral.ai/v1/chat/completions"
|
9
8
|
|
@@ -31,27 +30,7 @@ module Intelligence
|
|
31
30
|
end
|
32
31
|
end
|
33
32
|
end
|
34
|
-
|
35
|
-
alias chat_request_generic_message_attributes chat_request_message_attributes
|
36
|
-
|
37
|
-
# mistral vision models only support the legacy Open AI message schema for the assistant
|
38
|
-
# messages while supporting the modern message schema for user messages :facepalm:
|
39
|
-
def chat_request_message_attributes( message )
|
40
|
-
role = message[ :role ]&.to_sym
|
41
|
-
case role
|
42
|
-
when :user
|
43
|
-
chat_request_generic_message_attributes( message )
|
44
|
-
when :assistant
|
45
|
-
chat_request_legacy_message_attributes( message )
|
46
|
-
else
|
47
|
-
raise UnsupportedContentError.new(
|
48
|
-
:mistral,
|
49
|
-
'only supports user and assistant message roles'
|
50
|
-
)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
33
|
+
|
54
34
|
end
|
55
|
-
|
56
35
|
end
|
57
36
|
end
|
@@ -18,43 +18,67 @@ module Intelligence
|
|
18
18
|
chat_options do
|
19
19
|
|
20
20
|
# normalized properties for openai generative text endpoint
|
21
|
-
model
|
22
|
-
n
|
23
|
-
max_tokens
|
24
|
-
temperature
|
25
|
-
top_p
|
26
|
-
seed
|
27
|
-
stop
|
28
|
-
stream
|
21
|
+
model String, requried: true
|
22
|
+
n Integer
|
23
|
+
max_tokens Integer, as: :max_completion_tokens
|
24
|
+
temperature Float
|
25
|
+
top_p Float
|
26
|
+
seed Integer
|
27
|
+
stop String, array: true
|
28
|
+
stream [ TrueClass, FalseClass ]
|
29
29
|
|
30
|
-
frequency_penalty
|
31
|
-
presence_penalty
|
30
|
+
frequency_penalty Float
|
31
|
+
presence_penalty Float
|
32
32
|
|
33
33
|
# openai variant of normalized properties for openai generative text endpoints
|
34
|
-
max_completion_tokens
|
34
|
+
max_completion_tokens Integer
|
35
35
|
|
36
36
|
# openai properties for openai generative text endpoint
|
37
37
|
audio do
|
38
|
-
voice
|
39
|
-
format
|
38
|
+
voice String
|
39
|
+
format String
|
40
40
|
end
|
41
41
|
logit_bias
|
42
|
-
logprobs
|
43
|
-
|
44
|
-
|
45
|
-
parallel_tool_calls [ TrueClass, FalseClass ]
|
42
|
+
logprobs [ TrueClass, FalseClass ]
|
43
|
+
top_logprobs Integer
|
44
|
+
modalities String, array: true
|
46
45
|
response_format do
|
47
46
|
# 'text' and 'json_schema' are the only supported types
|
48
|
-
type
|
47
|
+
type Symbol, in: [ :text, :json_schema ]
|
49
48
|
json_schema
|
50
49
|
end
|
51
|
-
service_tier
|
50
|
+
service_tier String
|
52
51
|
stream_options do
|
53
|
-
include_usage
|
52
|
+
include_usage [ TrueClass, FalseClass ]
|
54
53
|
end
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
user
|
55
|
+
|
56
|
+
# open ai tool configuration; this allows you to enable build in tools ( currently
|
57
|
+
# that's just 'code_interpreter' )
|
58
|
+
#
|
59
|
+
# tool :code_interpreter
|
60
|
+
#
|
61
|
+
#tool array: true, as: :tools, arguments: :type
|
62
|
+
# type Symbol
|
63
|
+
#end
|
64
|
+
|
65
|
+
# open ai tool choice configuration
|
66
|
+
#
|
67
|
+
# `tool_choice :none`
|
68
|
+
# or
|
69
|
+
# ```
|
70
|
+
# tool_choice :function do
|
71
|
+
# function :my_function
|
72
|
+
# end
|
73
|
+
# ```
|
74
|
+
tool_choice arguments: :type do
|
75
|
+
type Symbol, in: [ :none, :auto, :required ]
|
76
|
+
function arguments: :name do
|
77
|
+
name Symbol
|
78
|
+
end
|
79
|
+
end
|
80
|
+
# the parallel_tool_calls parameter is only allowed when 'tools' are specified
|
81
|
+
parallel_tool_calls [ TrueClass, FalseClass ]
|
58
82
|
|
59
83
|
end
|
60
84
|
|
@@ -85,31 +85,21 @@ module Intelligence
|
|
85
85
|
|
86
86
|
choices.each do | choice |
|
87
87
|
choice[ :message ][ :contents ] = choice[ :message ][ :contents ]&.map do | content |
|
88
|
-
|
89
|
-
when :text
|
90
|
-
content[ :text ] = ''
|
91
|
-
when :tool_call
|
92
|
-
content[ :tool_parameters ] = ''
|
93
|
-
else
|
94
|
-
content.clear
|
95
|
-
end
|
96
|
-
content
|
88
|
+
{ type: content[ :type ] }
|
97
89
|
end
|
98
90
|
end
|
99
91
|
|
100
92
|
buffer += chunk
|
101
93
|
while ( eol_index = buffer.index( "\n" ) )
|
102
|
-
|
103
94
|
line = buffer.slice!( 0..eol_index )
|
104
95
|
line = line.strip
|
105
96
|
next if line.empty? || !line.start_with?( 'data:' )
|
106
97
|
line = line[ 6..-1 ]
|
107
98
|
|
108
99
|
next if line.end_with?( '[DONE]' )
|
109
|
-
data = JSON.parse( line )
|
100
|
+
data = JSON.parse( line ) rescue nil
|
110
101
|
|
111
102
|
if data.is_a?( Hash )
|
112
|
-
|
113
103
|
data[ 'choices' ]&.each do | data_choice |
|
114
104
|
|
115
105
|
data_choice_index = data_choice[ 'index' ]
|
@@ -119,39 +109,45 @@ module Intelligence
|
|
119
109
|
choices.fill( { message: {} }, choices.size, data_choice_index + 1 ) \
|
120
110
|
if choices.size <= data_choice_index
|
121
111
|
contents = choices[ data_choice_index ][ :message ][ :contents ] || []
|
122
|
-
|
123
|
-
|
124
|
-
if data_choice_delta
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
last_content[ :type ] = :text
|
130
|
-
last_content[ :text ] = data_choice_content
|
131
|
-
elsif last_content[ :type ] == :text
|
132
|
-
last_content[ :text ] = ( last_content[ :text ] || '' ) + data_choice_content
|
133
|
-
end
|
134
|
-
elsif data_choice_delta.include?( 'function_call' )
|
135
|
-
data_choice_tool_call = data_choice_delta[ 'function_call' ]
|
136
|
-
data_choice_tool_name = data_choice_tool_call[ 'name' ]
|
137
|
-
data_choice_tool_parameters = data_choice_tool_call[ 'arguments' ]
|
138
|
-
if last_content.nil? || last_content[ :type ] == :text
|
139
|
-
contents.push( {
|
140
|
-
type: :tool_call,
|
141
|
-
tool_name: data_choice_tool_name,
|
142
|
-
tool_parameters: data_choice_tool_parameters
|
143
|
-
} )
|
144
|
-
elsif last_content[ :type ].nil?
|
145
|
-
last_content[ :type ] = :tool_call
|
146
|
-
last_content[ :tool_name ] = data_choice_tool_name if data_choice_tool_name.present?
|
147
|
-
last_content[ :tool_parameters ] = tool_parameters
|
148
|
-
elsif last_content[ :type ] == :tool_call
|
149
|
-
last_content[ :tool_parameters ] =
|
150
|
-
( last_content[ :tool_parameters ] || '' ) + data_choice_tool_parameters
|
112
|
+
|
113
|
+
text_content = contents.first&.[]( :type ) == :text ? contents.first : nil
|
114
|
+
if data_choice_content = data_choice_delta[ 'content' ]
|
115
|
+
if text_content.nil?
|
116
|
+
contents.unshift( text_content = { type: :text, text: data_choice_content } )
|
117
|
+
else
|
118
|
+
text_content[ :text ] = ( text_content[ :text ] || '' ) + data_choice_content
|
151
119
|
end
|
120
|
+
end
|
121
|
+
if data_choice_tool_calls = data_choice_delta[ 'tool_calls' ]
|
122
|
+
data_choice_tool_calls.each do | data_choice_tool_call |
|
123
|
+
if data_choice_tool_call_function = data_choice_tool_call[ 'function' ]
|
124
|
+
data_choice_tool_index = data_choice_tool_call[ 'index' ]
|
125
|
+
data_choice_tool_id = data_choice_tool_call[ 'id' ]
|
126
|
+
data_choice_tool_name = data_choice_tool_call_function[ 'name' ]
|
127
|
+
data_choice_tool_parameters = data_choice_tool_call_function[ 'arguments' ]
|
128
|
+
|
129
|
+
tool_call_content_index = ( text_content.nil? ? 0 : 1 ) + data_choice_tool_index
|
130
|
+
if tool_call_content_index >= contents.length
|
131
|
+
contents.push( {
|
132
|
+
type: :tool_call,
|
133
|
+
tool_call_id: data_choice_tool_id,
|
134
|
+
tool_name: data_choice_tool_name,
|
135
|
+
tool_parameters: data_choice_tool_parameters
|
136
|
+
} )
|
137
|
+
else
|
138
|
+
tool_call = contents[ tool_call_content_index ]
|
139
|
+
tool_call[ :tool_call_id ] = ( tool_call[ :tool_call_id ] || '' ) + data_choice_tool_id \
|
140
|
+
if data_choice_tool_id
|
141
|
+
tool_call[ :tool_name ] = ( tool_call[ :tool_name ] || '' ) + data_choice_tool_name \
|
142
|
+
if data_choice_tool_name
|
143
|
+
tool_call[ :tool_parameters ] = ( tool_call[ :tool_parameters ] || '' ) + data_choice_tool_parameters \
|
144
|
+
if data_choice_tool_parameters
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
152
148
|
end
|
153
149
|
choices[ data_choice_index ][ :message ][ :contents ] = contents
|
154
|
-
choices[ data_choice_index ][ :end_reason ]
|
150
|
+
choices[ data_choice_index ][ :end_reason ] ||=
|
155
151
|
translate_end_result( data_choice_finish_reason )
|
156
152
|
end
|
157
153
|
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'generic/adapter'
|
2
2
|
|
3
3
|
module Intelligence
|
4
4
|
module SambaNova
|
5
5
|
|
6
|
-
class Adapter <
|
6
|
+
class Adapter < Generic::Adapter
|
7
7
|
|
8
8
|
chat_request_uri "https://api.sambanova.ai/v1/chat/completions"
|
9
9
|
|
@@ -35,8 +35,7 @@ module Intelligence
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def chat_result_error_attributes( response )
|
38
|
-
|
39
|
-
error_type, error_description = translate_error_response_status( response.status )
|
38
|
+
error_type, error_description = to_error_response( response.status )
|
40
39
|
result = {
|
41
40
|
error_type: error_type.to_s,
|
42
41
|
error_description: error_description
|
@@ -55,7 +54,6 @@ module Intelligence
|
|
55
54
|
end
|
56
55
|
|
57
56
|
result
|
58
|
-
|
59
57
|
end
|
60
58
|
|
61
59
|
end
|