intelligence 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/intelligence.gemspec +47 -0
  4. data/lib/intelligence/adapter/base.rb +7 -0
  5. data/lib/intelligence/adapter/construction_methods.rb +37 -0
  6. data/lib/intelligence/adapter.rb +8 -0
  7. data/lib/intelligence/adapter_error.rb +8 -0
  8. data/lib/intelligence/adapters/anthropic/adapter.rb +59 -0
  9. data/lib/intelligence/adapters/anthropic/chat_methods.rb +358 -0
  10. data/lib/intelligence/adapters/anthropic.rb +2 -0
  11. data/lib/intelligence/adapters/cerebras.rb +35 -0
  12. data/lib/intelligence/adapters/generic/adapter.rb +21 -0
  13. data/lib/intelligence/adapters/generic/chat_methods.rb +331 -0
  14. data/lib/intelligence/adapters/generic.rb +2 -0
  15. data/lib/intelligence/adapters/google/adapter.rb +60 -0
  16. data/lib/intelligence/adapters/google/chat_methods.rb +346 -0
  17. data/lib/intelligence/adapters/google.rb +2 -0
  18. data/lib/intelligence/adapters/groq.rb +51 -0
  19. data/lib/intelligence/adapters/hyperbolic.rb +55 -0
  20. data/lib/intelligence/adapters/legacy/adapter.rb +13 -0
  21. data/lib/intelligence/adapters/legacy/chat_methods.rb +37 -0
  22. data/lib/intelligence/adapters/open_ai/adapter.rb +75 -0
  23. data/lib/intelligence/adapters/open_ai/chat_methods.rb +314 -0
  24. data/lib/intelligence/adapters/open_ai.rb +2 -0
  25. data/lib/intelligence/adapters/samba_nova.rb +64 -0
  26. data/lib/intelligence/adapters/together_ai.rb +46 -0
  27. data/lib/intelligence/chat_error_result.rb +11 -0
  28. data/lib/intelligence/chat_metrics.rb +32 -0
  29. data/lib/intelligence/chat_request.rb +117 -0
  30. data/lib/intelligence/chat_result.rb +32 -0
  31. data/lib/intelligence/chat_result_choice.rb +26 -0
  32. data/lib/intelligence/conversation.rb +48 -0
  33. data/lib/intelligence/error.rb +3 -0
  34. data/lib/intelligence/error_result.rb +24 -0
  35. data/lib/intelligence/invalid_content_error.rb +3 -0
  36. data/lib/intelligence/message.rb +53 -0
  37. data/lib/intelligence/message_content/base.rb +18 -0
  38. data/lib/intelligence/message_content/binary.rb +24 -0
  39. data/lib/intelligence/message_content/text.rb +17 -0
  40. data/lib/intelligence/message_content/tool_call.rb +20 -0
  41. data/lib/intelligence/message_content/tool_result.rb +20 -0
  42. data/lib/intelligence/message_content.rb +16 -0
  43. data/lib/intelligence/unsupported_content_error.rb +3 -0
  44. data/lib/intelligence/version.rb +3 -0
  45. data/lib/intelligence.rb +24 -0
  46. metadata +181 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 694776aeafc7552879d8b9d5358907e62c90a6fc5a1219081ee1d1a4cb5ddeef
4
+ data.tar.gz: 380f5cd13200750f65938fd4e92c21218af8c2b57af0614bfe16f714ba296e68
5
+ SHA512:
6
+ metadata.gz: f2ca65b2a4e3a202bc1b331f7965da9e76a8ccd2ec83f7c5c273c94137fb1e0131226ecf3bf2aed6d50e262933d26c0024b3a5052edda28c39768c766b508e29
7
+ data.tar.gz: c6694ffa62ddd9eb766f42fb9cc073195a01e11e0d34cd346588b3923266c14f794d1711e1766888369874e27ce4ac696de0513055af8e27149a778611ce0cb2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Endless International
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,47 @@
1
+ require_relative 'lib/intelligence/version'
2
+
3
+ Gem::Specification.new do | spec |
4
+
5
+ spec.name = 'intelligence'
6
+ spec.version = Intelligence::VERSION
7
+ spec.authors = [ 'Kristoph Cichocki-Romanov' ]
8
+ spec.email = [ 'rubygems.org@kristoph.net' ]
9
+
10
+ spec.summary = <<~TEXT.gsub( "\n", " " ).strip
11
+ A Ruby gem for seamlessly and uniformly interacting with large languge and vision model (LLM)
12
+ API's served by numerous services, including those of OpenAI, Anthropic, Google and others.
13
+ TEXT
14
+ spec.description = <<~TEXT.gsub( "\n", " " ).strip
15
+ Intelligence is a lightweight yet powerful Ruby gem that allows you to seamlessly and uniformly
16
+ interact with large language and vision models (LLM) API's of numerous vendors, including
17
+ OpenAI, Anthropic, Google, Cerebras, Groq, Hyperbolic, Samba Nova and Together AI. It can be
18
+ trivially expanded to other OpenAI conformant API providers as well as self hosted models.
19
+
20
+ Intelligence supports text models in streaming and non-streaming mode, vision models, and
21
+ tool use.
22
+
23
+ Intelligence has minimal dependencies and does not require the vendors ( often bloated )
24
+ SDK's.
25
+ TEXT
26
+
27
+ spec.license = 'MIT'
28
+ spec.homepage = 'https://github.com/EndlessInternational/intelligence'
29
+ spec.metadata = {
30
+ 'source_code_uri' => 'https://github.com/EndlessInternational/intelligence',
31
+ 'bug_tracker_uri' => 'https://github.com/EndlessInternational/intelligence/issues',
32
+ # 'documentation_uri' => 'https://github.com/EndlessInternational/intelligence/wiki'
33
+ }
34
+
35
+ spec.required_ruby_version = '>= 3.0'
36
+ spec.files = Dir[ "lib/**/*.rb", "LICENSE", "README.md", "intelligence.gemspec" ]
37
+ spec.require_paths = [ "lib" ]
38
+
39
+ spec.add_runtime_dependency 'faraday', '~> 2.7'
40
+ spec.add_runtime_dependency 'adaptiveconfiguration', '~> 1.0.0.beta01'
41
+ spec.add_runtime_dependency 'mime-types', '~> 3.6'
42
+
43
+ spec.add_development_dependency 'rspec', '~> 3.4'
44
+ spec.add_development_dependency 'debug', '~> 1.9'
45
+ spec.add_development_dependency 'vcr', '~> 6.3'
46
+
47
+ end
@@ -0,0 +1,7 @@
1
+ module Intelligence
2
+ module Adapter
3
+ class Base
4
+ extend AdaptiveConfiguration::Configurable
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ module Intelligence
2
+ module Adapter
3
+ module ConstructionMethods
4
+
5
+ def []( adapter_type )
6
+
7
+ raise ArgumentError.new( "An adapter type is required but nil was given." ) \
8
+ if adapter_type.nil?
9
+
10
+ class_name = adapter_type.to_s.split( '_' ).map( &:capitalize ).join
11
+ class_name += "::Adapter"
12
+
13
+ adapter_class = Intelligence.const_get( class_name ) rescue nil
14
+ if adapter_class.nil?
15
+ adapter_file = File.expand_path( "../../adapters/#{adapter_type}", __FILE__ )
16
+ unless require adapter_file
17
+ raise ArgumentError.new(
18
+ "The Intelligence adapter file #{adapter_file} is missing or does not define #{class_name}."
19
+ )
20
+ end
21
+ adapter_class = Intelligence.const_get( class_name ) rescue nil
22
+ end
23
+
24
+ raise ArgumentError.new( "An unknown Intelligence adapter #{adapter_type} was configured." ) \
25
+ if adapter_class.nil?
26
+
27
+ adapter_class
28
+
29
+ end
30
+
31
+ def build( adapter_type, attributes, &block )
32
+ self.[]( adapter_type ).new( attributes, &block )
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'adapter/construction_methods'
2
+ require_relative 'adapter/base'
3
+
4
+ module Intelligence
5
+ module Adapter
6
+ extend ConstructionMethods
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Intelligence
2
+ class AdapterError < Error;
3
+ def initialize( adapter_type, text )
4
+ adapter_class_name = adapter_type.to_s.split( '_' ).map( &:capitalize ).join
5
+ super( "The #{adapter_class_name} #{text}." )
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,59 @@
1
+ require_relative 'chat_methods'
2
+
3
+ module Intelligence
4
+ module Anthropic
5
+ class Adapter < Adapter::Base
6
+
7
+ configuration do
8
+
9
+ # normalized properties for all endpoints
10
+ parameter :key, required: true
11
+
12
+ # anthropic specific properties for all endpoints
13
+ parameter :version, String, required: true, default: '2023-06-01'
14
+
15
+ group :chat_options do
16
+
17
+ # normalized properties for anthropic generative text endpoint
18
+ parameter :model, String, required: true
19
+ parameter :max_tokens, Integer, required: true
20
+ parameter :temperature, Float
21
+ parameter :top_k, Integer
22
+ parameter :top_p, Float
23
+ parameter :stop, String, array: true, as: :stop_sequences
24
+ parameter :stream, [ TrueClass, FalseClass ]
25
+
26
+ # anthropic variant of normalized properties for anthropic generative text endpoints
27
+ parameter :stop_sequences, String, array: true
28
+
29
+ # anthropic specific properties for anthropic generative text endpoints
30
+ parameter :tool_choice do
31
+ parameter :type, String
32
+ # the name parameter should only be set if type = 'tool'
33
+ parameter :name, String
34
+ end
35
+ group :metadata do
36
+ parameter :user_id, String
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ attr_reader :key
44
+ attr_reader :version
45
+ attr_reader :chat_options
46
+
47
+ def initialize( attributes = nil, &block )
48
+ configuration = self.class.configure( attributes, &block )
49
+ @key = configuration[ :key ]
50
+ @version = configuration[ :version ]
51
+ @chat_options = configuration[ :chat_options ] || {}
52
+ end
53
+
54
+ include ChatMethods
55
+
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,358 @@
1
+ require 'base64'
2
+
3
+ module Intelligence
4
+ module Anthropic
5
+ module ChatMethods
6
+
7
+ CHAT_REQUEST_URI = "https://api.anthropic.com/v1/messages"
8
+
9
+ def chat_request_uri( options )
10
+ CHAT_REQUEST_URI
11
+ end
12
+
13
+ def chat_request_headers( options = {} )
14
+ result = {}
15
+
16
+ key = options[ :key ] || self.key
17
+ version = options[ :version ] || self.version || "2023-06-01"
18
+
19
+ raise ArgumentError.new(
20
+ "An Anthropic key is required to build an Anthropic chat request."
21
+ ) if key.nil?
22
+
23
+ result[ 'content-type' ] = 'application/json'
24
+ result[ 'x-api-key' ] = "#{key}"
25
+ result[ 'anthropic-version' ] = version unless version.nil?
26
+
27
+ result
28
+ end
29
+
30
+ def chat_request_body( conversation, options = {} )
31
+ options = self.class.configure( options ) unless options.empty?
32
+ result = self.chat_options.merge( options ).compact
33
+
34
+ system_message = translate_system_message( conversation[ :system_message ] )
35
+ result[ :system ] = system_message unless system_message.nil?
36
+ result[ :messages ] = []
37
+
38
+ messages = conversation[ :messages ]
39
+ length = messages&.length || 0
40
+ index = 0; while index < length
41
+
42
+ message = messages[ index ]
43
+ unless message.nil?
44
+
45
+ # The Anthropic API will not accept a sequence of messages where the role of two
46
+ # sequentian messages is the same.
47
+ #
48
+ # The purpose of this code is to identify such occurences and coalece them such
49
+ # that the first message in the sequence aggregates the contents of all subsequent
50
+ # messages with the same role.
51
+ look_ahead_index = index + 1; while look_ahead_index < length
52
+ ahead_message = messages[ look_ahead_index ]
53
+ unless ahead_message.nil?
54
+ if ahead_message[ :role ] == message[ :role ]
55
+ message[ :contents ] =
56
+ ( message[ :contents ] || [] ) +
57
+ ( ahead_message[ :contents ] || [] )
58
+ messages[ look_ahead_index ] = nil
59
+ look_ahead_index += 1
60
+ else
61
+ break
62
+ end
63
+ end
64
+ end
65
+
66
+ result_message = { role: message[ :role ] }
67
+ result_message_content = []
68
+
69
+ message[ :contents ]&.each do | content |
70
+ case content[ :type ]
71
+ when :text
72
+ result_message_content << { type: 'text', text: content[ :text ] }
73
+ when :binary
74
+ content_type = content[ :content_type ]
75
+ bytes = content[ :bytes ]
76
+ if content_type && bytes
77
+ mime_type = MIME::Types[ content_type ].first
78
+ if mime_type&.media_type == 'image'
79
+ result_message_content << {
80
+ type: 'image',
81
+ source: {
82
+ type: 'base64',
83
+ media_type: content_type,
84
+ data: Base64.strict_encode64( bytes )
85
+ }
86
+ }
87
+ else
88
+ raise UnsupportedContentError.new(
89
+ :anthropic,
90
+ 'only support content of type image/*'
91
+ )
92
+ end
93
+ else
94
+ raise InvalidContentError.new( :anthropic )
95
+ end
96
+ end
97
+ end
98
+
99
+ result_message[ :content ] = result_message_content
100
+ result[ :messages ] << result_message
101
+
102
+ end
103
+
104
+ index += 1
105
+
106
+ end
107
+
108
+ JSON.generate( result )
109
+ end
110
+
111
+ def chat_result_attributes( response )
112
+ return nil unless response.success?
113
+
114
+ response_json = JSON.parse( response.body, symbolize_names: true ) rescue nil
115
+ return nil if response_json.nil?
116
+
117
+ result = {}
118
+
119
+ result_choice = {
120
+ end_reason: translate_end_result( response_json[ :stop_reason ] ),
121
+ end_sequence: response_json[ :stop_sequence ],
122
+ }
123
+
124
+ if response_json[ :content ] &&
125
+ response_json[ :content ].is_a?( Array ) &&
126
+ !response_json[ :content ].empty?
127
+
128
+ result_content = []
129
+ response_json[ :content ].each do | content |
130
+ if content[ :type ] == 'text'
131
+ result_content.push( { type: 'text', text: content[ :text ] } )
132
+ end
133
+ end
134
+
135
+ unless result_content.empty?
136
+ result_choice[ :message ] = {
137
+ role: response_json[ :role ] || 'assistant',
138
+ contents: result_content
139
+ }
140
+ end
141
+
142
+ end
143
+
144
+ result[ :choices ] = [ result_choice ]
145
+
146
+ metrics_json = response_json[ :usage ]
147
+ unless metrics_json.nil?
148
+
149
+ result_metrics = {}
150
+ result_metrics[ :input_tokens ] = metrics_json[ :input_tokens ]
151
+ result_metrics[ :output_tokens ] = metrics_json[ :output_tokens ]
152
+ result_metrics = result_metrics.compact
153
+
154
+ result[ :metrics ] = result_metrics unless result_metrics.empty?
155
+
156
+ end
157
+
158
+ result
159
+ end
160
+
161
+ def chat_result_error_attributes( response )
162
+ error_type, error_description = translate_response_status( response.status )
163
+ parsed_body = JSON.parse( response.body, symbolize_names: true ) rescue nil
164
+ if parsed_body && parsed_body.respond_to?( :include? ) && parsed_body.include?( :error )
165
+ result = {
166
+ error_type: error_type.to_s,
167
+ error: parsed_body[ :error ][ :type ],
168
+ error_description: parsed_body[ :error ][ :message ] || error_description
169
+ }
170
+ elsif
171
+ result = {
172
+ error_type: error_type.to_s,
173
+ error_description: error_description
174
+ }
175
+ end
176
+ result
177
+ end
178
+
179
+ def stream_result_chunk_attributes( context, chunk )
180
+ context ||= {}
181
+
182
+ buffer = context[ :buffer ] || ''
183
+ contents = context[ :contents ] || []
184
+ end_reason = context[ :end_reason ]
185
+ end_sequence = context[ :end_sequence ]
186
+ metrics = context[ :metrics ] || {
187
+ input_tokens: 0,
188
+ output_tokens: 0
189
+ }
190
+
191
+ contents.each do | content |
192
+ case content[ :type ]
193
+ when :text
194
+ content[ :text ] = ''
195
+ when :tool_call
196
+ content[ :tool_parameters ] = ''
197
+ else
198
+ content.clear
199
+ end
200
+ end
201
+
202
+ buffer += chunk
203
+ while ( eol_index = buffer.index( "\n" ) )
204
+
205
+ line = buffer.slice!( 0..eol_index )
206
+ line = line.strip
207
+ next if line.empty? || !line.start_with?( 'data:' )
208
+
209
+ line = line[ 6..-1 ]
210
+ data = JSON.parse( line )
211
+
212
+ case data[ 'type' ]
213
+ when 'message_start'
214
+ metrics[ :input_tokens ] += data[ 'message' ]&.[]( 'usage' )&.[]( 'input_tokens' ) || 0
215
+ metrics[ :output_tokens ] += data[ 'message' ]&.[]( 'usage' )&.[]( 'output_tokens' ) || 0
216
+ when 'content_block_start'
217
+ index = data[ 'index' ]
218
+ contents.fill( {}, contents.size, index + 1 ) if contents.size <= index
219
+ if content_block = data[ 'content_block' ]
220
+ if content_block[ 'type' ] == 'text'
221
+ contents[ index ] = {
222
+ type: :text,
223
+ text: content_block[ 'text' ] || ''
224
+ }
225
+ elsif content_block[ 'type' ] == 'tool_use'
226
+ contents[ index ] = {
227
+ type: :tool_call,
228
+ tool_name: content_block[ 'name' ],
229
+ tool_call_id: content_block[ 'id' ],
230
+ tool_parameters: ''
231
+ }
232
+ end
233
+ end
234
+ when 'content_block_delta'
235
+ index = data[ 'index' ]
236
+ contents.fill( {}, contents.size, index + 1 ) if contents.size <= index
237
+ if delta = data[ 'delta' ]
238
+ if delta[ 'type' ] == 'text_delta'
239
+ contents[ index ][ :type ] = :text
240
+ contents[ index ][ :text ] = ( contents[ index ][ :text ] || '' ) + delta[ 'text' ]
241
+ elsif delta[ 'type' ] == 'input_json_delta'
242
+ contents[ index ][ :type ] = :tool_call
243
+ contents[ index ][ :tool_parameters ] =
244
+ ( contents[ index ][ :tool_parameters ] || '' ) + delta[ 'input_json_delta' ]
245
+ end
246
+ end
247
+ when 'message_delta'
248
+ if delta = data[ 'delta' ]
249
+ end_reason = delta[ 'stop_reason' ]
250
+ end_sequence = delta[ 'stop_sequence' ]
251
+ end
252
+ metrics[ :output_tokens ] += data[ 'usage' ]&.[]( 'output_tokens' ) || 0
253
+ when 'message_stop'
254
+
255
+ end
256
+ end
257
+
258
+ context = {
259
+ buffer: buffer,
260
+ contents: contents,
261
+ end_reason: end_reason,
262
+ end_sequence: end_sequence,
263
+ metrics: metrics
264
+ }
265
+ choices = [ {
266
+ end_reason: translate_end_result( end_reason ),
267
+ end_sequence: end_sequence,
268
+ message: {
269
+ contents: contents.dup
270
+ }
271
+ }
272
+ ]
273
+
274
+ [ context, ( choices.empty? ? nil : { choices: choices } ) ]
275
+ end
276
+
277
+ def stream_result_attributes( context )
278
+ {
279
+ choices: [ {
280
+ end_reason: translate_end_result( context[ :end_reason ] ),
281
+ end_sequence: context[ :end_sequence ],
282
+ } ],
283
+ metrics: context[ :metrics ]
284
+ }
285
+ end
286
+
287
+ alias_method :stream_result_error_attributes, :chat_result_error_attributes
288
+
289
+ private
290
+
291
+ def translate_system_message( system_message )
292
+
293
+ return nil if system_message.nil?
294
+
295
+ # note: the current version of the anthropic api simply takes a string as the
296
+ # system message but the beta version requires an array of objects akin
297
+ # to message contents.
298
+
299
+ result = ''
300
+ system_message[ :contents ].each do | content |
301
+ result += content[ :text ] if content[ :type ] == :text
302
+ end
303
+
304
+ result.empty? ? nil : result
305
+
306
+ end
307
+
308
+ def translate_end_result( end_result )
309
+ case end_result
310
+ when 'end_turn'
311
+ :ended
312
+ when 'max_tokens'
313
+ :token_limit_exceeded
314
+ when 'stop_sequence'
315
+ :end_sequence_encountered
316
+ when 'tool_use'
317
+ :tool_called
318
+ else
319
+ # if the result has already been translated, this simply returns it
320
+ end_result
321
+ end
322
+ end
323
+
324
+ def translate_response_status( status )
325
+ case status
326
+ when 400
327
+ [ :invalid_request_error,
328
+ "There was an issue with the format or content of your request." ]
329
+ when 401
330
+ [ :authentication_error,
331
+ "There's an issue with your API key." ]
332
+ when 403
333
+ [ :permission_error,
334
+ "Your API key does not have permission to use the specified resource." ]
335
+ when 404
336
+ [ :not_found_error,
337
+ "The requested resource was not found." ]
338
+ when 413
339
+ [ :request_too_large,
340
+ "Request exceeds the maximum allowed number of bytes." ]
341
+ when 429
342
+ [ :rate_limit_error,
343
+ "Your account has hit a rate limit." ]
344
+ when 500
345
+ [ :api_error,
346
+ "An unexpected error has occurred internal to Anthropic's systems." ]
347
+ when 529
348
+ [ :overloaded_error,
349
+ "Anthropic's API is temporarily overloaded." ]
350
+ else
351
+ [ :unknown_error, "
352
+ An unknown error occurred." ]
353
+ end
354
+ end
355
+
356
+ end
357
+ end
358
+ end
@@ -0,0 +1,2 @@
1
+ require_relative '../adapter'
2
+ require_relative 'anthropic/adapter'
@@ -0,0 +1,35 @@
1
+ require_relative 'legacy/adapter'
2
+
3
+ module Intelligence
4
+ module Cerebras
5
+
6
+ class Adapter < Legacy::Adapter
7
+
8
+ chat_request_uri "https://api.cerebras.ai/v1/chat/completions"
9
+
10
+ configuration do
11
+ parameter :key, required: true
12
+ group :chat_options do
13
+ parameter :model, String, required: true
14
+ parameter :max_tokens, Integer, required: true
15
+ parameter :response_format do
16
+ parameter :type, String, default: 'json_schema'
17
+ parameter :json_schema
18
+ end
19
+ parameter :seed, Integer
20
+ parameter :stop, array: true
21
+ parameter :stream, [ TrueClass, FalseClass ]
22
+ parameter :temperature, Float
23
+ parameter :top_p, Float
24
+ parameter :tool_choice do
25
+ parameter :type, String
26
+ parameter :mame, String
27
+ end
28
+ parameter :user
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../../adapter'
2
+ require_relative 'chat_methods'
3
+
4
+ module Intelligence
5
+ module Generic
6
+ class Adapter < Adapter::Base
7
+
8
+ attr_reader :key
9
+ attr_reader :chat_options
10
+
11
+ def initialize( attributes = nil, &block )
12
+ configuration = self.class.configure( attributes, &block )
13
+ @key = configuration[ :key ]
14
+ @chat_options = configuration[ :chat_options ] || {}
15
+ end
16
+
17
+ include ChatMethods
18
+
19
+ end
20
+ end
21
+ end