intelligence 1.0.0.beta01 → 1.0.0.beta03

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02df79612b47068ee3792e78566e94160741db46f22c5ff8a97947a09872fe5f
4
- data.tar.gz: e2bf793c4bf2feb17798e0a59bdc2272cdac9e95b9cd2c31b386d973601bfcdf
3
+ metadata.gz: 77033342b73065a73acde0156a288f66fb0ef7413a939292d23886b353397fd3
4
+ data.tar.gz: 6a8c7131991c0af60d9e30c000048ae9cb7e562e7c7dbb9ca519febe486d8491
5
5
  SHA512:
6
- metadata.gz: 12bf185efa0bbd063699fc25cd33ada8729a6a95fda62ec4535319dc88b92764fb43677421cfb714f02aa766ec3e52740f018241f1632f0ea938c08543f0e62b
7
- data.tar.gz: 221871ceb024b137d2e77810ea4ef840bbe161248a72dd69c8d184af4ce176664993dbb6d3d36bc91bbb89b3c2ed8515a2692f681d7e82894c147d83e7e2bda3
6
+ metadata.gz: 65050bd8d219f8348a0fe6c5b6cbc951a8de190572c01ecdc7e947aa2fa207f4fb65ae0e6afc2658ecf1fbe50ca0fd5b58c5fcf2651cc416fb9e6aeff73c97df
7
+ data.tar.gz: 17ef75ad141fc8f25f0a62a32c1b677785340b0bd15c8f907c455a10b5d7e35532728e7f36cb62b3ccb3ebe0c835b8facd6777832dda955bb09aabae1802975b
@@ -104,7 +104,7 @@ module Intelligence
104
104
 
105
105
  tools_attributes = chat_request_tools_attributes( conversation[ :tools ] )
106
106
  result[ :tools ] = tools_attributes if tools_attributes && tools_attributes.length > 0
107
-
107
+
108
108
  JSON.generate( result )
109
109
  end
110
110
 
@@ -57,7 +57,7 @@ module Intelligence
57
57
  def chat_request_body( conversation, options = {} )
58
58
  options = @options.merge( build_options( options ) )
59
59
 
60
- gc = options[ :generationConfig ]
60
+ gc = options[ :generationConfig ]&.dup || {}
61
61
  # discard properties not part of the google generationConfig schema
62
62
  gc.delete( :model )
63
63
  gc.delete( :stream )
@@ -0,0 +1,196 @@
1
+ require_relative 'generic/adapter'
2
+
3
+ module Intelligence
4
+ module XAi
5
+
6
+ class Adapter < Generic::Adapter
7
+
8
+ chat_request_uri "https://api.x.ai/v1/chat/completions"
9
+
10
+ schema do
11
+ key String
12
+ chat_options do
13
+ model String
14
+ frequency_penalty Float, in: -2..2
15
+ logit_bias Hash
16
+ logprobs [ TrueClass, FalseClass ]
17
+ max_tokens Integer
18
+ n Integer
19
+ presence_penalty Float, in: -2..2
20
+ response_format
21
+ seed Integer
22
+ stop String, array: true
23
+ stream [ TrueClass, FalseClass ]
24
+ stream_options
25
+ temperature Float, in: 0..2
26
+ tool_choice
27
+ top_logprobs Integer, in: 0..20
28
+ top_p Float
29
+ user String
30
+ end
31
+ end
32
+
33
+ def chat_result_attributes( response )
34
+ return nil unless response.success?
35
+ response_json = JSON.parse( response.body, symbolize_names: true ) rescue nil
36
+ return nil if response_json.nil? || response_json[ :choices ].nil?
37
+
38
+ result = {}
39
+ result[ :choices ] = []
40
+
41
+ ( response_json[ :choices ] || [] ).each do | json_choice |
42
+ end_reason = to_end_reason( json_choice[ :finish_reason ] )
43
+ if ( json_message = json_choice[ :message ] )
44
+ result_message = { role: json_message[ :role ] }
45
+ if json_message[ :content ]
46
+ result_message[ :contents ] = [ { type: :text, text: json_message[ :content ] } ]
47
+ end
48
+ if json_message[ :tool_calls ] && !json_message[ :tool_calls ].empty?
49
+ result_message[ :contents ] ||= []
50
+ end_reason = :tool_called if end_reason == :ended
51
+ json_message[ :tool_calls ].each do | json_message_tool_call |
52
+ result_message_tool_call_parameters =
53
+ JSON.parse( json_message_tool_call[ :function ][ :arguments ], symbolize_names: true ) \
54
+ rescue json_message_tool_call[ :function ][ :arguments ]
55
+ result_message[ :contents ] << {
56
+ type: :tool_call,
57
+ tool_call_id: json_message_tool_call[ :id ],
58
+ tool_name: json_message_tool_call[ :function ][ :name ],
59
+ tool_parameters: result_message_tool_call_parameters
60
+ }
61
+ end
62
+ end
63
+ end
64
+ result[ :choices ].push( { end_reason: end_reason, message: result_message } )
65
+ end
66
+
67
+ metrics_json = response_json[ :usage ]
68
+ unless metrics_json.nil?
69
+
70
+ metrics = {}
71
+ metrics[ :input_tokens ] = metrics_json[ :prompt_tokens ]
72
+ metrics[ :output_tokens ] = metrics_json[ :completion_tokens ]
73
+ metrics = metrics.compact
74
+
75
+ result[ :metrics ] = metrics unless metrics.empty?
76
+
77
+ end
78
+
79
+ result
80
+ end
81
+
82
+ def stream_result_chunk_attributes( context, chunk )
83
+ context ||= {}
84
+ buffer = context[ :buffer ] || ''
85
+ metrics = context[ :metrics ] || {
86
+ input_tokens: 0,
87
+ output_tokens: 0
88
+ }
89
+ choices = context[ :choices ] || Array.new( 1 , { message: {} } )
90
+
91
+ choices.each do | choice |
92
+ choice[ :message ][ :contents ] = choice[ :message ][ :contents ]&.map do | content |
93
+ { type: content[ :type ] }
94
+ end
95
+ end
96
+
97
+ buffer += chunk
98
+ while ( eol_index = buffer.index( "\n" ) )
99
+ line = buffer.slice!( 0..eol_index )
100
+ line = line.strip
101
+ next if line.empty? || !line.start_with?( 'data:' )
102
+ line = line[ 6..-1 ]
103
+ next if line.end_with?( '[DONE]' )
104
+
105
+ data = JSON.parse( line ) rescue nil
106
+ if data.is_a?( Hash )
107
+ data[ 'choices' ]&.each do | data_choice |
108
+
109
+ data_choice_index = data_choice[ 'index' ]
110
+ data_choice_delta = data_choice[ 'delta' ]
111
+ end_reason = to_end_reason( data_choice[ 'finish_reason' ] )
112
+
113
+ choices.fill( { message: {} }, choices.size, data_choice_index + 1 ) \
114
+ if choices.size <= data_choice_index
115
+ contents = choices[ data_choice_index ][ :message ][ :contents ] || []
116
+
117
+ text_content = contents.first&.[]( :type ) == :text ? contents.first : nil
118
+ if data_choice_content = data_choice_delta[ 'content' ]
119
+ if text_content.nil?
120
+ contents.unshift( text_content = { type: :text, text: data_choice_content } )
121
+ else
122
+ text_content[ :text ] = ( text_content[ :text ] || '' ) + data_choice_content
123
+ end
124
+ end
125
+ if data_choice_tool_calls = data_choice_delta[ 'tool_calls' ]
126
+ end_reason = :tool_called
127
+ data_choice_tool_calls.each_with_index do | data_choice_tool_call, data_choice_tool_call_index |
128
+ if data_choice_tool_call_function = data_choice_tool_call[ 'function' ]
129
+ data_choice_tool_index = data_choice_tool_call[ 'index' ] || data_choice_tool_call_index
130
+ data_choice_tool_id = data_choice_tool_call[ 'id' ]
131
+ data_choice_tool_name = data_choice_tool_call_function[ 'name' ]
132
+ data_choice_tool_parameters = data_choice_tool_call_function[ 'arguments' ]
133
+
134
+ tool_call_content_index = ( text_content.nil? ? 0 : 1 ) + data_choice_tool_index
135
+ if tool_call_content_index >= contents.length
136
+ contents.push( {
137
+ type: :tool_call,
138
+ tool_call_id: data_choice_tool_id,
139
+ tool_name: data_choice_tool_name,
140
+ tool_parameters: data_choice_tool_parameters
141
+ } )
142
+ else
143
+ tool_call = contents[ tool_call_content_index ]
144
+ tool_call[ :tool_call_id ] = ( tool_call[ :tool_call_id ] || '' ) + data_choice_tool_id \
145
+ if data_choice_tool_id
146
+ tool_call[ :tool_name ] = ( tool_call[ :tool_name ] || '' ) + data_choice_tool_name \
147
+ if data_choice_tool_name
148
+ tool_call[ :tool_parameters ] = ( tool_call[ :tool_parameters ] || '' ) + data_choice_tool_parameters \
149
+ if data_choice_tool_parameters
150
+ end
151
+ end
152
+ end
153
+ end
154
+ choices[ data_choice_index ][ :message ][ :contents ] = contents
155
+ choices[ data_choice_index ][ :end_reason ] ||= end_reason
156
+ end
157
+
158
+ if usage = data[ 'usage' ]
159
+ # note: A number of providers will resend the input tokens as part of their usage
160
+ # payload.
161
+ metrics[ :input_tokens ] = usage[ 'prompt_tokens' ] \
162
+ if usage.include?( 'prompt_tokens' )
163
+ metrics[ :output_tokens ] += usage[ 'completion_tokens' ] \
164
+ if usage.include?( 'completion_tokens' )
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+
171
+ context[ :buffer ] = buffer
172
+ context[ :metrics ] = metrics
173
+ context[ :choices ] = choices
174
+
175
+ [ context, choices.empty? ? nil : { choices: choices.dup } ]
176
+ end
177
+
178
+ def chat_result_error_attributes( response )
179
+ error_type, error_description = to_error_response( response.status )
180
+ error = error_type
181
+
182
+ parsed_body = JSON.parse( response.body, symbolize_names: true ) rescue nil
183
+ if parsed_body && parsed_body.respond_to?( :[] )
184
+ error = parsed_body[ :code ] || error_type
185
+ error_description = parsed_body[ :error ] || error_description
186
+ end
187
+
188
+ { error_type: error_type.to_s, error: error.to_s, error_description: error_description }
189
+ end
190
+
191
+ alias_method :stream_result_error_attributes, :chat_result_error_attributes
192
+
193
+ end
194
+
195
+ end
196
+ end
@@ -1,3 +1,3 @@
1
1
  module Intelligence
2
- VERSION = "1.0.0.beta01"
2
+ VERSION = "1.0.0.beta03"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: intelligence
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta01
4
+ version: 1.0.0.beta03
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kristoph Cichocki-Romanov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-01 00:00:00.000000000 Z
11
+ date: 2024-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -153,6 +153,7 @@ files:
153
153
  - lib/intelligence/adapters/open_router.rb
154
154
  - lib/intelligence/adapters/samba_nova.rb
155
155
  - lib/intelligence/adapters/together_ai.rb
156
+ - lib/intelligence/adapters/x_ai.rb
156
157
  - lib/intelligence/chat_error_result.rb
157
158
  - lib/intelligence/chat_metrics.rb
158
159
  - lib/intelligence/chat_request.rb