intelligence 0.5.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +555 -0
  3. data/intelligence.gemspec +1 -1
  4. data/lib/intelligence/adapter/base.rb +23 -3
  5. data/lib/intelligence/adapter/class_methods.rb +15 -0
  6. data/lib/intelligence/adapter/{construction_methods.rb → module_methods.rb} +8 -4
  7. data/lib/intelligence/adapter.rb +2 -2
  8. data/lib/intelligence/adapters/anthropic/adapter.rb +21 -30
  9. data/lib/intelligence/adapters/anthropic/chat_request_methods.rb +189 -0
  10. data/lib/intelligence/adapters/anthropic/{chat_methods.rb → chat_response_methods.rb} +8 -124
  11. data/lib/intelligence/adapters/cerebras.rb +17 -17
  12. data/lib/intelligence/adapters/generic/adapter.rb +1 -12
  13. data/lib/intelligence/adapters/generic/chat_methods.rb +42 -11
  14. data/lib/intelligence/adapters/generic.rb +1 -1
  15. data/lib/intelligence/adapters/google/adapter.rb +33 -35
  16. data/lib/intelligence/adapters/google/chat_request_methods.rb +233 -0
  17. data/lib/intelligence/adapters/google/{chat_methods.rb → chat_response_methods.rb} +52 -162
  18. data/lib/intelligence/adapters/groq.rb +46 -28
  19. data/lib/intelligence/adapters/hyperbolic.rb +13 -13
  20. data/lib/intelligence/adapters/legacy/adapter.rb +0 -2
  21. data/lib/intelligence/adapters/legacy/chat_methods.rb +22 -6
  22. data/lib/intelligence/adapters/mistral.rb +57 -0
  23. data/lib/intelligence/adapters/open_ai/adapter.rb +38 -45
  24. data/lib/intelligence/adapters/open_ai/chat_request_methods.rb +186 -0
  25. data/lib/intelligence/adapters/open_ai/{chat_methods.rb → chat_response_methods.rb} +60 -131
  26. data/lib/intelligence/adapters/open_ai.rb +1 -1
  27. data/lib/intelligence/adapters/open_router.rb +62 -0
  28. data/lib/intelligence/adapters/samba_nova.rb +13 -13
  29. data/lib/intelligence/adapters/together_ai.rb +21 -19
  30. data/lib/intelligence/chat_request.rb +57 -7
  31. data/lib/intelligence/chat_result.rb +4 -0
  32. data/lib/intelligence/chat_result_choice.rb +4 -2
  33. data/lib/intelligence/conversation.rb +38 -9
  34. data/lib/intelligence/message.rb +103 -20
  35. data/lib/intelligence/message_content/base.rb +3 -0
  36. data/lib/intelligence/message_content/binary.rb +6 -0
  37. data/lib/intelligence/message_content/file.rb +35 -0
  38. data/lib/intelligence/message_content/text.rb +5 -0
  39. data/lib/intelligence/message_content/tool_call.rb +12 -1
  40. data/lib/intelligence/message_content/tool_result.rb +15 -3
  41. data/lib/intelligence/message_content.rb +12 -3
  42. data/lib/intelligence/tool.rb +139 -0
  43. data/lib/intelligence/version.rb +1 -1
  44. data/lib/intelligence.rb +6 -4
  45. metadata +18 -9
@@ -1,57 +1,55 @@
1
- require_relative 'chat_methods'
1
+ require_relative 'chat_request_methods'
2
+ require_relative 'chat_response_methods'
2
3
 
3
4
  module Intelligence
4
5
  module Google
5
6
  class Adapter < Adapter::Base
6
7
 
7
- configuration do
8
+ schema do
8
9
 
9
10
  # normalized properties for all endpoints
10
- parameter :key, String, required: true
11
+ key String
11
12
 
12
- group :chat_options, as: :generationConfig do
13
+ chat_options as: :generationConfig do
13
14
 
14
15
  # normalized properties for google generative text endpoint
15
- parameter :model, String, required: true
16
- parameter :max_tokens, Integer, as: :maxOutputTokens
17
- parameter :n, Integer, as: :candidateCount
18
- parameter :temperature, Float
19
- parameter :top_k, Integer, as: :topK
20
- parameter :top_p, Float, as: :topP
21
- parameter :seed, Integer
22
- parameter :stop, String, array: true, as: :stopSequences
23
- parameter :stream, [ TrueClass, FalseClass ]
24
-
25
- parameter :frequency_penalty, Float, as: :frequencyPenalty
26
- parameter :presence_penalty, Float, as: :presencePenalty
16
+ model String
17
+ max_tokens Integer, as: :maxOutputTokens
18
+ n Integer, as: :candidateCount
19
+ temperature Float
20
+ top_k Integer, as: :topK
21
+ top_p Float, as: :topP
22
+ seed Integer
23
+ stop String, array: true, as: :stopSequences
24
+ stream [ TrueClass, FalseClass ]
25
+
26
+ frequency_penalty Float, as: :frequencyPenalty
27
+ presence_penalty Float, as: :presencePenalty
27
28
 
28
29
  # google variant of normalized properties for google generative text endpoints
29
- parameter :candidate_count, Integer, as: :candidateCount
30
- parameter :max_output_tokens, Integer, as: :maxOutputTokens
31
- parameter :stop_sequences, String, array: true, as: :stopSequences
30
+ candidate_count Integer, as: :candidateCount
31
+ max_output_tokens Integer, as: :maxOutputTokens
32
+ stop_sequences String, array: true, as: :stopSequences
32
33
 
33
34
  # google specific properties for google generative text endpoints
34
- parameter :response_mime_type, String, as: :responseMimeType
35
- parameter :response_schema, as: :responseSchema
35
+ response_mime_type String, as: :responseMimeType
36
+ response_schema as: :responseSchema
36
37
 
37
- end
38
+ # google specific tool configuration
39
+ tool_configuration as: :tool_config do
40
+ function_calling as: :function_calling_config do
41
+ mode Symbol, in: [ :auto, :any, :none ]
42
+ allowed_function_names String, array: true
43
+ end
44
+ end
38
45
 
39
- end
40
46
 
41
- attr_reader :key
42
- attr_reader :model
43
- attr_reader :stream
44
- attr_reader :chat_options
45
-
46
- def initialize( attributes = nil, &block )
47
- configuration = self.class.configure( attributes, &block ).to_h
48
- @key = configuration.delete( :key )
49
- @model = configuration[ :generationConfig ]&.delete( :model )
50
- @stream = configuration[ :generationConfig ]&.delete( :stream ) || false
51
- @chat_options = configuration[ :generationConfig ] || {}
47
+ end
48
+
52
49
  end
53
50
 
54
- include ChatMethods
51
+ include ChatRequestMethods
52
+ include ChatResponseMethods
55
53
 
56
54
  end
57
55
 
@@ -0,0 +1,233 @@
1
+ require 'uri'
2
+
3
+ module Intelligence
4
+ module Google
5
+ module ChatRequestMethods
6
+
7
+ GENERATIVE_LANGUAGE_URI = "https://generativelanguage.googleapis.com/v1beta/models/"
8
+
9
+ SUPPORTED_BINARY_MEDIA_TYPES = %w[ text ]
10
+
11
+ SUPPORTED_BINARY_CONTENT_TYPES = %w[
12
+ image/png image/jpeg image/webp image/heic image/heif
13
+ audio/aac audio/flac audio/mp3 audio/m4a audio/mpeg audio/mpga audio/mp4 audio/opus
14
+ audio/pcm audio/wav audio/webm
15
+ application/pdf
16
+ ]
17
+
18
+ SUPPORTED_FILE_MEDIA_TYPES = %w[ text ]
19
+
20
+ SUPPORTED_CONTENT_TYPES = %w[
21
+ image/png image/jpeg image/webp image/heic image/heif
22
+ video/x-flv video/quicktime video/mpeg video/mpegps video/mpg video/mp4 video/webm
23
+ video/wmv video/3gpp
24
+ audio/aac audio/flac audio/mp3 audio/m4a audio/mpeg audio/mpga audio/mp4 audio/opus
25
+ audio/pcm audio/wav audio/webm
26
+ application/pdf
27
+ ]
28
+
29
+ def chat_request_uri( options )
30
+ options = @options.merge( build_options( options ) )
31
+
32
+ key = options[ :key ]
33
+ gc = options[ :generationConfig ] || {}
34
+ model = gc[ :model ]
35
+ stream = gc.key?( :stream ) ? gc[ :stream ] : false
36
+
37
+ raise ArgumentError.new( "A Google API key is required to build a Google chat request." ) \
38
+ if key.nil?
39
+ raise ArgumentError.new( "A Google model is required to build a Google chat request." ) \
40
+ if model.nil?
41
+
42
+ uri = URI( GENERATIVE_LANGUAGE_URI )
43
+ path = File.join( uri.path, model )
44
+ path += stream ? ':streamGenerateContent' : ':generateContent'
45
+ uri.path = path
46
+ query = { key: key }
47
+ query[ :alt ] = 'sse' if stream
48
+ uri.query = URI.encode_www_form( query )
49
+
50
+ uri.to_s
51
+ end
52
+
53
+ def chat_request_headers( options = {} )
54
+ { 'Content-Type' => 'application/json' }
55
+ end
56
+
57
+ def chat_request_body( conversation, options = {} )
58
+ options = @options.merge( build_options( options ) )
59
+
60
+ gc = options[ :generationConfig ]
61
+ # discard properties not part of the google generationConfig schema
62
+ gc.delete( :model )
63
+ gc.delete( :stream )
64
+
65
+ # googlify tool configuration
66
+ if tool_config = gc.delete( :tool_config )
67
+ mode = tool_config[ :function_calling_config ]&.[]( :mode )
68
+ tool_config[ :function_calling_config ][ :mode ] = mode.to_s.upcase if mode
69
+ end
70
+
71
+ result = {}
72
+ result[ :generationConfig ] = gc
73
+ result[ :tool_config ] = tool_config if tool_config
74
+
75
+ # construct the system prompt in the form of the google schema
76
+ system_instructions = to_google_system_message( conversation[ :system_message ] )
77
+ result[ :systemInstruction ] = system_instructions if system_instructions
78
+
79
+ result[ :contents ] = []
80
+ conversation[ :messages ]&.each do | message |
81
+
82
+ result_message = { role: message[ :role ] == :user ? 'user' : 'model' }
83
+ result_message_parts = []
84
+
85
+ message[ :contents ]&.each do | content |
86
+ case content[ :type ]
87
+ when :text
88
+ result_message_parts << { text: content[ :text ] }
89
+ when :binary
90
+ content_type = content[ :content_type ]
91
+ bytes = content[ :bytes ]
92
+ if content_type && bytes
93
+ mime_type = MIME::Types[ content_type ].first
94
+ if SUPPORTED_BINARY_MEDIA_TYPES.include?( mime_type&.media_type ) ||
95
+ SUPPORTED_BINARY_CONTENT_TYPES.include?( content_type )
96
+ result_message_parts << {
97
+ inline_data: {
98
+ mime_type: content_type,
99
+ data: Base64.strict_encode64( bytes )
100
+ }
101
+ }
102
+ else
103
+ raise UnsupportedContentError.new(
104
+ :google,
105
+ "does not support #{content_type} content type"
106
+ )
107
+ end
108
+ else
109
+ raise UnsupportedContentError.new(
110
+ :google,
111
+ 'requires binary content to include content type and ( packed ) bytes'
112
+ )
113
+ end
114
+ when :file
115
+ content_type = content[ :content_type ]
116
+ uri = content[ :uri ]
117
+ if content_type && uri
118
+ mime_type = MIME::Types[ content_type ].first
119
+ if SUPPORTED_FILE_MEDIA_TYPES.include?( mime_type&.media_type ) ||
120
+ SUPPORTED_FILE_CONTENT_TYPES.include?( content_type )
121
+ result_message_parts << {
122
+ file_data: {
123
+ mime_type: content_type,
124
+ file_uri: uri
125
+ }
126
+ }
127
+ else
128
+ raise UnsupportedContentError.new(
129
+ :google,
130
+ "does not support #{content_type} content type"
131
+ )
132
+ end
133
+ else
134
+ raise UnsupportedContentError.new(
135
+ :google,
136
+ 'requires file content to include content type and uri'
137
+ )
138
+ end
139
+ when :tool_call
140
+ result_message_parts << {
141
+ functionCall: {
142
+ name: content[ :tool_name ],
143
+ args: content[ :tool_parameters ]
144
+ }
145
+ }
146
+ when :tool_result
147
+ result_message_parts << {
148
+ functionResponse: {
149
+ name: content[ :tool_name ],
150
+ response: {
151
+ name: content[ :tool_name ],
152
+ content: content[ :tool_result ]
153
+ }
154
+ }
155
+ }
156
+ else
157
+ raise InvalidContentError.new( :google )
158
+ end
159
+ end
160
+
161
+ result_message[ :parts ] = result_message_parts
162
+ result[ :contents ] << result_message
163
+
164
+ end
165
+
166
+ tools_attributes = to_google_tools( conversation[ :tools ] )
167
+ result[ :tools ] = tools_attributes if tools_attributes && tools_attributes.length > 0
168
+
169
+ JSON.generate( result )
170
+ end
171
+
172
+ private
173
+
174
+ def to_google_system_message( system_message )
175
+ return nil if system_message.nil?
176
+
177
+ text = ''
178
+ system_message[ :contents ].each do | content |
179
+ text += content[ :text ] if content[ :type ] == :text
180
+ end
181
+
182
+ return nil if text.empty?
183
+
184
+ {
185
+ role: 'user',
186
+ parts: [
187
+ { text: text }
188
+ ]
189
+ }
190
+ end
191
+
192
+ def to_google_tools( tools )
193
+ properties_array_to_object = lambda do | properties |
194
+ return nil unless properties&.any?
195
+ object = {}
196
+ required = []
197
+ properties.each do | property |
198
+ name = property.delete( :name )
199
+ required << name if property.delete( :required )
200
+ if property[ :properties ]&.any?
201
+ property_properties, property_required =
202
+ properties_array_to_object.call( property[ :properties ] )
203
+ property[ :properties ] = property_properties
204
+ property[ :required ] = property_required if property_required.any?
205
+ end
206
+ object[ name ] = property
207
+ end
208
+ [ object, required.compact ]
209
+ end
210
+
211
+ return [ { function_declarations: tools&.map { | tool |
212
+ function = {
213
+ name: tool[ :name ],
214
+ description: tool[ :description ],
215
+ }
216
+ if tool[ :properties ]&.any?
217
+ properties_object, properties_required =
218
+ properties_array_to_object.call( tool[ :properties ] )
219
+ function[ :parameters ] = {
220
+ type: 'object',
221
+ properties: properties_object
222
+ }
223
+ function[ :parameters ][ :required ] = properties_required if properties_required.any?
224
+ end
225
+ function
226
+ } } ]
227
+ end
228
+
229
+ end
230
+
231
+ end
232
+
233
+ end
@@ -2,110 +2,14 @@ require 'uri'
2
2
 
3
3
  module Intelligence
4
4
  module Google
5
- module ChatMethods
5
+ module ChatResponseMethods
6
6
 
7
- GENERATIVE_LANGUAGE_URI = "https://generativelanguage.googleapis.com/v1beta/models/"
8
-
9
- def chat_request_uri( options )
10
-
11
- options = options.nil? || options.empty? ? {} : self.class.configure( options )
12
-
13
- key = options[ :key ] || self.key
14
-
15
- gc = options[ :generationConfig ] || {}
16
- model = gc[ :model ] || self.model
17
- stream = gc.key?( :stream ) ? gc[ :stream ] : self.stream
18
-
19
- raise ArgumentError.new( "A Google API key is required to build a Google chat request." ) \
20
- if self.key.nil?
21
- raise ArgumentError.new( "A Google model is required to build a Google chat request." ) \
22
- if model.nil?
23
-
24
- uri = URI( GENERATIVE_LANGUAGE_URI )
25
- path = File.join( uri.path, model )
26
- path += stream ? ':streamGenerateContent' : ':generateContent'
27
- uri.path = path
28
- query = { key: self.key }
29
- query[ :alt ] = 'sse' if stream
30
- uri.query = URI.encode_www_form( query )
31
-
32
- uri.to_s
33
-
34
- end
35
-
36
- def chat_request_headers( options = {} )
37
- { 'Content-Type' => 'application/json' }
38
- end
39
-
40
- def chat_request_body( conversation, options = {} )
41
-
42
- result = {}
43
- result[ :generationConfig ] = self.chat_options
44
-
45
- options = options.nil? || options.empty? ? {} : self.class.configure( options )
46
- result = result.merge( options )
47
-
48
- # discard properties not part of the google endpoint schema
49
- result[ :generationConfig ].delete( :model )
50
- result[ :generationConfig ].delete( :stream )
51
-
52
- # construct the system prompt in the form of the google schema
53
- system_instructions = translate_system_message( conversation[ :system_message ] )
54
- result[ :systemInstruction ] = system_instructions if system_instructions
55
-
56
- result[ :contents ] = []
57
- conversation[ :messages ]&.each do | message |
58
-
59
- result_message = { role: message[ :role ] == :user ? 'user' : 'model' }
60
- result_message_parts = []
61
-
62
- message[ :contents ]&.each do | content |
63
- case content[ :type ]
64
- when :text
65
- result_message_parts << { text: content[ :text ] }
66
- when :binary
67
- content_type = content[ :content_type ]
68
- bytes = content[ :bytes ]
69
- if content_type && bytes
70
- unless MIME::Types[ content_type ].empty?
71
- # TODO: verify the specific google supported MIME types
72
- result_message_parts << {
73
- inline_data: {
74
- mime_type: content_type,
75
- data: Base64.strict_encode64( bytes )
76
- }
77
- }
78
- else
79
- raise UnsupportedContentError.new(
80
- :google,
81
- 'only support recognized mime types'
82
- )
83
- end
84
- else
85
- raise UnsupportedContentError.new(
86
- :google,
87
- 'requires binary content to include content type and ( packed ) bytes'
88
- )
89
- end
90
- end
91
- end
92
-
93
- result_message[ :parts ] = result_message_parts
94
- result[ :contents ] << result_message
95
-
96
- end
97
-
98
- JSON.generate( result )
99
-
100
- end
101
-
102
- def chat_result_attributes( response )
7
+ def chat_result_attributes( response )
103
8
 
104
9
  return nil unless response.success?
105
10
 
106
11
  response_json = JSON.parse( response.body, symbolize_names: true ) rescue nil
107
- return nil \
108
- if response_json.nil? || response_json[ :candidates ].nil?
12
+ return nil if response_json.nil? || response_json[ :candidates ].nil?
109
13
 
110
14
  result = {}
111
15
  result[ :choices ] = []
@@ -120,13 +24,21 @@ module Intelligence
120
24
  response_content = response_choice[ :content ]
121
25
  if response_content
122
26
  role = ( response_content[ :role ] == 'model' ) ? 'assistant' : 'user'
123
-
124
27
  contents = []
125
28
  response_content[ :parts ]&.each do | response_content_part |
126
29
  if response_content_part.key?( :text )
127
30
  contents.push( {
128
31
  type: 'text', text: response_content_part[ :text ]
129
32
  } )
33
+ elsif function_call = response_content_part[ :functionCall ]
34
+ contents.push( {
35
+ type: :tool_call,
36
+ tool_name: function_call[ :name ],
37
+ tool_parameters: function_call[ :args ]
38
+ } )
39
+ # google does not indicate there is tool call in the stop reason so
40
+ # we will synthesize this end reason
41
+ end_reason = :tool_called if end_reason == :ended
130
42
  end
131
43
  end
132
44
  end
@@ -178,7 +90,6 @@ module Intelligence
178
90
  end
179
91
 
180
92
  def stream_result_chunk_attributes( context, chunk )
181
- #---------------------------------------------------
182
93
 
183
94
  context ||= {}
184
95
  buffer = context[ :buffer ] || ''
@@ -257,7 +168,6 @@ module Intelligence
257
168
  end
258
169
 
259
170
  def stream_result_attributes( context )
260
- #--------------------------------------
261
171
 
262
172
  choices = context[ :choices ]
263
173
  metrics = context[ :metrics ]
@@ -272,71 +182,51 @@ module Intelligence
272
182
 
273
183
  alias_method :stream_result_error_attributes, :chat_result_error_attributes
274
184
 
275
- private; def translate_system_message( system_message )
276
- # -----------------------------------------------------
277
-
278
- return nil if system_message.nil?
279
-
280
- text = ''
281
- system_message[ :contents ].each do | content |
282
- text += content[ :text ] if content[ :type ] == :text
283
- end
284
-
285
- return nil if text.empty?
286
-
287
- {
288
- role: 'user',
289
- parts: [
290
- { text: text }
291
- ]
292
- }
293
-
294
- end
295
-
296
- private; def translate_finish_reason( finish_reason )
297
- # ---------------------------------------------------
185
+ private
186
+
187
+ def translate_finish_reason( finish_reason )
298
188
  case finish_reason
299
- when 'STOP'
300
- :ended
301
- when 'MAX_TOKENS'
302
- :token_limit_exceeded
303
- when 'SAFETY', 'RECITATION', 'BLOCKLIST', 'PROHIBITED_CONTENT', 'SPII'
304
- :filtered
305
- else
306
- nil
189
+ when 'STOP'
190
+ :ended
191
+ when 'MAX_TOKENS'
192
+ :token_limit_exceeded
193
+ when 'SAFETY', 'RECITATION', 'BLOCKLIST', 'PROHIBITED_CONTENT', 'SPII'
194
+ :filtered
195
+ else
196
+ nil
307
197
  end
308
198
  end
309
199
 
310
- private; def translate_error_response_status( status )
200
+ def translate_error_response_status( status )
311
201
  case status
312
- when 400
313
- [ :invalid_request_error,
314
- "There was an issue with the format or content of your request." ]
315
- when 403
316
- [ :permission_error,
317
- "Your API key does not have permission to use the specified resource." ]
318
- when 404
319
- [ :not_found_error,
320
- "The requested resource was not found." ]
321
- when 413
322
- [ :request_too_large,
323
- "Request exceeds the maximum allowed number of bytes." ]
324
- when 422
325
- [ :invalid_request_error,
326
- "There was an issue with the format or content of your request." ]
327
- when 429
328
- [ :rate_limit_error,
329
- "Your account has hit a rate limit." ]
330
- when 500, 502, 503
331
- [ :api_error,
332
- "An unexpected error has occurred internal to the providers systems." ]
333
- when 529
334
- [ :overloaded_error,
335
- "The providers server is temporarily overloaded." ]
336
- else
337
- [ :unknown_error, "
338
- An unknown error occurred." ]
339
- end
202
+ when 400
203
+ [ :invalid_request_error,
204
+ "There was an issue with the format or content of your request." ]
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
340
230
  end
341
231
 
342
232
  end
@@ -7,41 +7,59 @@ module Intelligence
7
7
 
8
8
  chat_request_uri 'https://api.groq.com/openai/v1/chat/completions'
9
9
 
10
- configuration do
11
- parameter :key, String, required: true
12
- group :chat_options do
13
- parameter :frequency_penalty, Float
14
- parameter :logit_bias
15
- parameter :logprobs, [ TrueClass, FalseClass ]
16
- parameter :max_tokens, Integer
17
- parameter :model, String
18
- parameter :n, Integer
19
- # the parallel_tool_calls parameter is only allowed when 'tools' are specified
20
- parameter :parallel_tool_calls, [ TrueClass, FalseClass ]
21
- parameter :presence_penalty, Float
22
- group :response_format do
10
+ schema do
11
+ key String
12
+ chat_options do
13
+ frequency_penalty Float
14
+ logit_bias
15
+ logprobs [ TrueClass, FalseClass ]
16
+ max_tokens Integer
17
+ model String
18
+ # the parallel_tool_calls is only allowed when 'tools' are specified
19
+ parallel_tool_calls [ TrueClass, FalseClass ]
20
+ presence_penalty Float
21
+ response_format do
23
22
  # 'text' and 'json_object' are the only supported types; you must also instruct
24
23
  # the model to output json
25
- parameter :type, String
24
+ type Symbol, in: [ :text, :json_object ]
26
25
  end
27
- parameter :seed, Integer
28
- parameter :stop, String, array: true
29
- parameter :stream, [ TrueClass, FalseClass ]
30
- group :stream_options do
31
- parameter :include_usage, [ TrueClass, FalseClass ]
26
+ seed Integer
27
+ stop String, array: true
28
+ stream [ TrueClass, FalseClass ]
29
+ stream_options do
30
+ include_usage [ TrueClass, FalseClass ]
32
31
  end
33
- parameter :temperature, Float
34
- group :tool_choice do
32
+ temperature Float
33
+ tool_choice do
35
34
  # one of 'auto', 'none' or 'function'
36
- parameter :type, String
37
- # the function group is required if you specify a type of 'function'
38
- group :function do
39
- parameter :name, String
35
+ type Symbol, in: [ :auto, :none, :function ]
36
+ # the function parameters is required if you specify a type of 'function'
37
+ function do
38
+ name String
40
39
  end
41
40
  end
42
- parameter :top_logprobs, Integer
43
- parameter :top_p, Float
44
- parameter :user, String
41
+ top_logprobs Integer
42
+ top_p Float
43
+ user String
44
+ end
45
+ end
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
+ )
45
63
  end
46
64
  end
47
65