intelligence 1.0.0.beta06 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2882de87c5b4c5e0ce5c59b91ca981788b1435b4e8b68e82c592d67b5b33512e
4
- data.tar.gz: 92072e12828beec46b8d988c0b4e6ddaa9aac1d9d4cee7fbdf1d2c02cb8ccc83
3
+ metadata.gz: 4831cc2ed908d140d2986d50a48db3b71f9436d8ce3c55353fc0a704ca798d07
4
+ data.tar.gz: 66e71bfca8287772c267daa06ead05b177edd64648dc52d818b8dc47ed4eaef6
5
5
  SHA512:
6
- metadata.gz: 0a80eedb98958100ca842a66352bb43f68123285a3abc503b1a563e9161e237f7bf095541e22272ae4e73c7d738c9ad7aa23ee06d6ee76d4f7059d2c72b98041
7
- data.tar.gz: b0d7a59ade65eb893e976875d42075aacf8edfe32eada98af10de1ab39a8145913f37cb830a09498345d01cd59e1fc6e8eb511efe72e3e9976fc48c0dd2bec41
6
+ metadata.gz: 12c05f2f7115c61e94b1fd3b0b4acba5f1508abc63748032b8d003ba7d957884d0ca8bd7e4e92adbd2656cf43f0a93f8179852c86c20e26800ccfed70f1b1472
7
+ data.tar.gz: 1abef016e197f81078e32bdb18825683ff2b609d13eb407b6de20d82cc28a1750e9134c72d75c577ffebf8b2efeda8fc7ef5206eaa5cef6210784aad1dd8df2b
@@ -4,6 +4,8 @@ module Intelligence
4
4
 
5
5
  CHAT_REQUEST_URI = "https://api.anthropic.com/v1/messages"
6
6
 
7
+ SUPPORTED_CONTENT_TYPES = %w[ image/jpeg image/png image/gif image/webp application/pdf ]
8
+
7
9
  def chat_request_uri( options )
8
10
  CHAT_REQUEST_URI
9
11
  end
@@ -75,10 +77,9 @@ module Intelligence
75
77
  content_type = content[ :content_type ]
76
78
  bytes = content[ :bytes ]
77
79
  if content_type && bytes
78
- mime_type = MIME::Types[ content_type ].first
79
- if mime_type&.media_type == 'image'
80
+ if SUPPORTED_CONTENT_TYPES.include?( content_type )
80
81
  result_message_content << {
81
- type: 'image',
82
+ type: content_type == 'application/pdf' ? 'document' : 'image',
82
83
  source: {
83
84
  type: 'base64',
84
85
  media_type: content_type,
@@ -97,6 +98,30 @@ module Intelligence
97
98
  'requires file content to include content type and (packed) bytes'
98
99
  )
99
100
  end
101
+ when :file
102
+ content_type = content[ :content_type ]
103
+ uri = content[ :uri ]
104
+ if content_type && uri
105
+ if SUPPORTED_CONTENT_TYPES.include?( content_type )
106
+ result_message_content << {
107
+ type: content_type == 'application/pdf' ? 'document' : 'image',
108
+ source: {
109
+ type: 'url',
110
+ url: uri
111
+ }
112
+ }
113
+ else
114
+ raise UnsupportedContentError.new(
115
+ :anthropic,
116
+ "only supports content of type #{SUPPORTED_CONTENT_TYPES.join( ', ' )}"
117
+ )
118
+ end
119
+ else
120
+ raise UnsupportedContentError.new(
121
+ :anthropic,
122
+ 'requires file content to include content type and uri'
123
+ )
124
+ end
100
125
  when :tool_call
101
126
  result_message_content << {
102
127
  type: 'tool_use',
@@ -111,7 +136,7 @@ module Intelligence
111
136
  content: content[ :tool_result ]
112
137
  }
113
138
  else
114
- raise InvalidContentError.new( :anthropic )
139
+ raise UnsupportedContentError.new( :anthropic )
115
140
  end
116
141
  end
117
142
 
@@ -9,8 +9,8 @@ module Intelligence
9
9
 
10
10
  result = {}
11
11
  result[ :choices ] = []
12
-
13
12
  ( response_json[ :choices ] || [] ).each do | json_choice |
13
+ end_reason = to_end_reason( json_choice[ :finish_reason ] )
14
14
  if ( json_message = json_choice[ :message ] )
15
15
  result_message = { role: json_message[ :role ] }
16
16
  if json_message[ :content ]
@@ -18,6 +18,7 @@ module Intelligence
18
18
  end
19
19
  if json_message[ :tool_calls ] && !json_message[ :tool_calls ].empty?
20
20
  result_message[ :contents ] ||= []
21
+ end_reason = :tool_called if end_reason == :ended
21
22
  json_message[ :tool_calls ].each do | json_message_tool_call |
22
23
  result_message_tool_call_parameters =
23
24
  JSON.parse( json_message_tool_call[ :function ][ :arguments ], symbolize_names: true ) \
@@ -31,10 +32,7 @@ module Intelligence
31
32
  end
32
33
  end
33
34
  end
34
- result[ :choices ].push( {
35
- end_reason: to_end_reason( json_choice[ :finish_reason ] ),
36
- message: result_message
37
- } )
35
+ result[ :choices ].push( { end_reason: end_reason, message: result_message } )
38
36
  end
39
37
 
40
38
  metrics_json = response_json[ :usage ]
@@ -35,6 +35,11 @@ module Intelligence
35
35
  response_mime_type String, as: :responseMimeType
36
36
  response_schema as: :responseSchema
37
37
 
38
+ # google specific thinking properies
39
+ thinking as: :thinkingConfig, default: {} do
40
+ budget as: :thinkingBudget, default: 0
41
+ end
42
+
38
43
  # google specific tool configuration
39
44
  tool array: true, as: :tools, &Tool.schema
40
45
  tool_configuration as: :tool_config do
@@ -44,8 +49,8 @@ module Intelligence
44
49
  end
45
50
  end
46
51
 
47
- # build-in tools are called 'abilities' in Intelligence so as not to conflic with the
48
- # caller defined tools
52
+ # build-in tools are called 'abilities' in Intelligence so as not to conflic
53
+ # with the caller defined tools
49
54
  abilities do
50
55
  # this appears to be a ( now ) legacy argument and is no longer supported
51
56
  # with the 2.0 models
@@ -4,30 +4,31 @@ module Intelligence
4
4
  module Mistral
5
5
  class Adapter < Generic::Adapter
6
6
 
7
- chat_request_uri "https://api.mistral.ai/v1/chat/completions"
7
+ DEFAULT_BASE_URI = "https://api.mistral.ai/v1"
8
8
 
9
9
  schema do
10
- key String
10
+ base_uri String, default: DEFAULT_BASE_URI
11
+ key String
11
12
  chat_options do
12
- model String
13
- temperature Float
14
- top_p Float
15
- max_tokens Integer
16
- min_tokens Integer
17
- seed Integer, as: :random_seed
18
- stop String, array: true
19
- stream [ TrueClass, FalseClass ]
13
+ model String
14
+ temperature Float
15
+ top_p Float
16
+ max_tokens Integer
17
+ min_tokens Integer
18
+ seed Integer, as: :random_seed
19
+ stop String, array: true
20
+ stream [ TrueClass, FalseClass ]
20
21
 
21
- random_seed Integer
22
+ random_seed Integer
22
23
  response_format do
23
- type String
24
+ type String
24
25
  end
25
26
 
26
- tool array: true, as: :tools, &Tool.schema
27
+ tool array: true, as: :tools, &Tool.schema
27
28
  tool_choice do
28
- type String
29
+ type String
29
30
  function do
30
- name String
31
+ name String
31
32
  end
32
33
  end
33
34
  end
@@ -38,55 +38,6 @@ module Intelligence
38
38
  end
39
39
  end
40
40
 
41
- def chat_result_attributes( response )
42
- return nil unless response.success?
43
- response_json = JSON.parse( response.body, symbolize_names: true ) rescue nil
44
- return nil if response_json.nil? || response_json[ :choices ].nil?
45
-
46
- result = {}
47
- result[ :choices ] = []
48
-
49
- ( response_json[ :choices ] || [] ).each do | json_choice |
50
- end_reason = to_end_reason( json_choice[ :finish_reason ] )
51
- if ( json_message = json_choice[ :message ] )
52
- result_message = { role: json_message[ :role ] }
53
- if json_message[ :content ]
54
- result_message[ :contents ] = [ { type: :text, text: json_message[ :content ] } ]
55
- end
56
- if json_message[ :tool_calls ] && !json_message[ :tool_calls ].empty?
57
- result_message[ :contents ] ||= []
58
- end_reason = :tool_called if end_reason == :ended
59
- json_message[ :tool_calls ].each do | json_message_tool_call |
60
- result_message_tool_call_parameters =
61
- JSON.parse( json_message_tool_call[ :function ][ :arguments ], symbolize_names: true ) \
62
- rescue json_message_tool_call[ :function ][ :arguments ]
63
- result_message[ :contents ] << {
64
- type: :tool_call,
65
- tool_call_id: json_message_tool_call[ :id ],
66
- tool_name: json_message_tool_call[ :function ][ :name ],
67
- tool_parameters: result_message_tool_call_parameters
68
- }
69
- end
70
- end
71
- end
72
- result[ :choices ].push( { end_reason: end_reason, message: result_message } )
73
- end
74
-
75
- metrics_json = response_json[ :usage ]
76
- unless metrics_json.nil?
77
-
78
- metrics = {}
79
- metrics[ :input_tokens ] = metrics_json[ :prompt_tokens ]
80
- metrics[ :output_tokens ] = metrics_json[ :completion_tokens ]
81
- metrics = metrics.compact
82
-
83
- result[ :metrics ] = metrics unless metrics.empty?
84
-
85
- end
86
-
87
- result
88
- end
89
-
90
41
  def chat_result_error_attributes( response )
91
42
  error_type, error_description = to_error_response( response.status )
92
43
  error = error_type
@@ -1,3 +1,3 @@
1
1
  module Intelligence
2
- VERSION = "1.0.0.beta06"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: intelligence
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta06
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kristoph Cichocki-Romanov
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-06-08 00:00:00.000000000 Z
10
+ date: 2025-06-19 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: faraday
@@ -134,10 +134,6 @@ files:
134
134
  - lib/intelligence/adapters/anthropic/chat_request_methods.rb
135
135
  - lib/intelligence/adapters/anthropic/chat_response_methods.rb
136
136
  - lib/intelligence/adapters/cerebras.rb
137
- - lib/intelligence/adapters/deepseek.rb
138
- - lib/intelligence/adapters/deepseek/adapter.rb
139
- - lib/intelligence/adapters/deepseek/chat_request_methods.rb
140
- - lib/intelligence/adapters/deepseek/chat_response_methods.rb
141
137
  - lib/intelligence/adapters/generic.rb
142
138
  - lib/intelligence/adapters/generic/adapter.rb
143
139
  - lib/intelligence/adapters/generic/chat_request_methods.rb
@@ -173,7 +169,6 @@ files:
173
169
  - lib/intelligence/message_content/binary.rb
174
170
  - lib/intelligence/message_content/file.rb
175
171
  - lib/intelligence/message_content/text.rb
176
- - lib/intelligence/message_content/thought.rb
177
172
  - lib/intelligence/message_content/tool_call.rb
178
173
  - lib/intelligence/message_content/tool_result.rb
179
174
  - lib/intelligence/tool.rb
@@ -1,47 +0,0 @@
1
- require_relative '../../adapter'
2
- require_relative 'chat_request_methods'
3
- require_relative 'chat_response_methods'
4
-
5
- module Intelligence
6
- module Deepseek
7
- class Adapter < Adapter::Base
8
- include ChatRequestMethods
9
- include ChatResponseMethods
10
-
11
- chat_request_uri 'https://api.deepseek.com/v1/chat/completions'
12
-
13
- schema do
14
- key String
15
- chat_options do
16
- frequency_penalty Float
17
- logprobs [ TrueClass, FalseClass ]
18
- max_tokens Integer
19
- model String
20
- presence_penalty Float, in: [ -2..2 ]
21
- response_format do
22
- # 'text' and 'json_object' are the only supported types; you must also instruct
23
- # the model to output json
24
- type Symbol, in: [ :text, :json_object ]
25
- end
26
- stop String, array: true
27
- stream [ TrueClass, FalseClass ]
28
- stream_options do
29
- include_usage [ TrueClass, FalseClass ]
30
- end
31
- temperature Float, in: [ 0..2 ]
32
- tool array: true, as: :tools, &Tool.schema
33
- tool_choice do
34
- # one of 'auto', 'none' or 'function'
35
- type Symbol, in: [ :auto, :none, :required ]
36
- # the function parameters is required if you specify a type of 'function'
37
- function do
38
- name String
39
- end
40
- end
41
- top_logprobs Integer
42
- top_p Float
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,233 +0,0 @@
1
- module Intelligence
2
- module Deepseek
3
- module ChatRequestMethods
4
-
5
- module ClassMethods
6
- def chat_request_uri( uri = nil )
7
- if uri
8
- @chat_request_uri = uri
9
- else
10
- @chat_request_uri
11
- end
12
- end
13
- end
14
-
15
- CHAT_COMPLETIONS_PATH = 'chat/completions'
16
-
17
- def self.included( base )
18
- base.extend( ClassMethods )
19
- end
20
-
21
- def chat_request_uri( options = nil )
22
- options = merge_options( @options, build_options( options ) )
23
- self.class.chat_request_uri || begin
24
- base_uri = options[ :base_uri ]
25
- if base_uri
26
- # because URI join is dumb
27
- base_uri += '/' unless base_uri.end_with?( '/' )
28
- URI.join( base_uri, CHAT_COMPLETIONS_PATH )
29
- else
30
- nil
31
- end
32
- end
33
- end
34
-
35
- def chat_request_headers( options = nil )
36
- options = merge_options( @options, build_options( options ) )
37
- result = { 'Content-Type': 'application/json' }
38
-
39
- key = options[ :key ]
40
- result[ 'Authorization' ] = "Bearer #{key}" if key
41
-
42
- result
43
- end
44
-
45
- def chat_request_body( conversation, options = nil )
46
- tools = options.delete( :tools ) || []
47
-
48
- options = merge_options( @options, build_options( options ) )
49
-
50
- result = options[ :chat_options ]
51
- result[ :messages ] = []
52
-
53
- system_message = chat_request_system_message_attributes( conversation[ :system_message ] )
54
- result[ :messages ] << system_message if system_message
55
-
56
- conversation[ :messages ]&.each do | message |
57
- return nil unless message[ :contents ]&.any?
58
-
59
- result_message = { role: message[ :role ] }
60
- result_message_content = []
61
-
62
- message_contents = message[ :contents ]
63
-
64
- # tool calls in the open ai api are not content
65
- tool_calls, message_contents = message_contents.partition do | content |
66
- content[ :type ] == :tool_call
67
- end
68
-
69
- # tool results in the open ai api are not content
70
- tool_results, message_contents = message_contents.partition do | content |
71
- content[ :type ] == :tool_result
72
- end
73
-
74
- # many vendor api's, especially when hosting text only models, will only accept a single
75
- # text content item; if the content is only text this will coalece multiple text content
76
- # items into a single content item
77
- unless message_contents.any? { | c | c[ :type ] != :text }
78
- result_message_content = message_contents.map { | c | c[ :text ] || '' }.join( "\n" )
79
- else
80
- message_contents&.each do | content |
81
- result_message_content << chat_request_message_content_attributes( content )
82
- end
83
- end
84
-
85
- if tool_calls.any?
86
- result_message[ :tool_calls ] = tool_calls.map { | tool_call |
87
- {
88
- id: tool_call[ :tool_call_id ],
89
- type: 'function',
90
- function: {
91
- name: tool_call[ :tool_name ],
92
- arguments: JSON.generate( tool_call[ :tool_parameters ] || {} )
93
- }
94
- }
95
- }
96
- end
97
-
98
- result_message[ :content ] = result_message_content
99
- unless result_message_content.empty? && tool_calls.empty?
100
- result[ :messages ] << result_message
101
- end
102
-
103
- if tool_results.any?
104
- result[ :messages ].concat( tool_results.map { | tool_result |
105
- {
106
- role: :tool,
107
- tool_call_id: tool_result[ :tool_call_id ],
108
- content: tool_result[ :tool_result ]
109
- }
110
- } )
111
- end
112
- end
113
-
114
- tools_attributes = chat_request_tools_attributes(
115
- ( result[ :tools ] || [] ).concat( tools )
116
- )
117
- result[ :tools ] = tools_attributes if tools_attributes && tools_attributes.length > 0
118
-
119
- JSON.generate( result )
120
- end
121
-
122
- def chat_request_message_content_attributes( content )
123
- case content[ :type ]
124
- when :text
125
- { type: 'text', text: content[ :text ] }
126
- when :binary
127
- content_type = content[ :content_type ]
128
- bytes = content[ :bytes ]
129
- if content_type && bytes
130
- mime_type = MIME::Types[ content_type ].first
131
- if mime_type&.media_type == 'image'
132
- {
133
- type: 'image_url',
134
- image_url: {
135
- url: "data:#{content_type};base64,#{Base64.strict_encode64( bytes )}".freeze
136
- }
137
- }
138
- else
139
- raise UnsupportedContentError.new(
140
- :generic,
141
- 'only support content of type image/*'
142
- )
143
- end
144
- else
145
- raise UnsupportedContentError.new(
146
- :generic,
147
- 'requires binary content to include content type and ( packed ) bytes'
148
- )
149
- end
150
- when :file
151
- content_type = content[ :content_type ]
152
- uri = content[ :uri ]
153
- if content_type && uri
154
- mime_type = MIME::Types[ content_type ].first
155
- if mime_type&.media_type == 'image'
156
- {
157
- type: 'image_url',
158
- image_url: { url: uri }
159
- }
160
- else
161
- raise UnsupportedContentError.new(
162
- :generic,
163
- 'only support content of type image/*'
164
- )
165
- end
166
- else
167
- raise UnsupportedContentError.new(
168
- :generic,
169
- 'requires binary content to include content type and ( packed ) bytes'
170
- )
171
- end
172
- end
173
- end
174
-
175
- def chat_request_system_message_attributes( system_message )
176
- return nil if system_message.nil?
177
-
178
- result = ''
179
- system_message[ :contents ].each do | content |
180
- result += content[ :text ] if content[ :type ] == :text
181
- end
182
-
183
- result.empty? ? nil : { role: 'system', content: result } if system_message
184
- end
185
-
186
- def chat_request_tools_attributes( tools )
187
- properties_array_to_object = lambda do | properties |
188
- return nil unless properties&.any?
189
- object = {}
190
- required = []
191
- properties.each do | property |
192
- name = property.delete( :name )
193
- required << name if property.delete( :required )
194
- if property[ :properties ]&.any?
195
- property_properties, property_required =
196
- properties_array_to_object.call( property[ :properties ] )
197
- property[ :properties ] = property_properties
198
- property[ :required ] = property_required if property_required.any?
199
- end
200
- object[ name ] = property
201
- end
202
- [ object, required.compact ]
203
- end
204
-
205
- tools&.map do | tool |
206
- function = {
207
- type: 'function',
208
- function: {
209
- type: 'object',
210
- name: tool[ :name ],
211
- description: tool[ :description ],
212
- }
213
- }
214
-
215
- if tool[ :properties ]&.any?
216
- properties_object, properties_required =
217
- properties_array_to_object.call( tool[ :properties ] )
218
- function[ :function ][ :parameters ] = {
219
- type: 'object',
220
- properties: properties_object
221
- }
222
- function[ :function ][ :parameters ][ :required ] = properties_required \
223
- if properties_required.any?
224
- else
225
- # function[ :function ][ :parameters ] = {}
226
- end
227
- function
228
- end
229
- end
230
-
231
- end
232
- end
233
- end
@@ -1,248 +0,0 @@
1
- module Intelligence
2
- module Deepseek
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
-
89
- buffer += chunk
90
- while ( eol_index = buffer.index( "\n" ) )
91
- line = buffer.slice!( 0..eol_index )
92
- line = line.strip
93
- next if line.empty? || !line.start_with?( 'data:' )
94
- line = line[ 6..-1 ]
95
- next if line.end_with?( '[DONE]' )
96
-
97
- data = JSON.parse( line ) rescue nil
98
- if data.is_a?( Hash )
99
- data[ 'choices' ]&.each do | data_choice |
100
-
101
- data_choice_index = data_choice[ 'index' ]
102
- data_choice_delta = data_choice[ 'delta' ]
103
- data_choice_finish_reason = data_choice[ 'finish_reason' ]
104
-
105
- choices.fill( { message: {} }, choices.size, data_choice_index + 1 ) \
106
- if choices.size <= data_choice_index
107
- contents = choices[ data_choice_index ][ :message ][ :contents ] || []
108
-
109
- # this deepseek response doesn't place reasoning in a separate index ( presumably
110
- # because they are simply detecting the thought tag in the first text )
111
-
112
- if data_choice_content = data_choice_delta[ 'reasoning_content' ]
113
- thought_content = contents.find { | content | content[ :type ] == :thought }
114
- if thought_content.nil?
115
- thought_content = { type: :thought, text: data_choice_content }
116
- contents << thought_content
117
- else
118
- thought_content[ :text ] = ( thought_content[ :text ] || '' ) + data_choice_content
119
- end
120
- end
121
-
122
- if data_choice_content = data_choice_delta[ 'content' ]
123
- text_content = contents.find { | content | content[ :type ] == :text }
124
- if text_content.nil?
125
- text_content = { type: :text, text: data_choice_content }
126
- contents << text_content
127
- else
128
- text_content[ :text ] = ( text_content[ :text ] || '' ) + data_choice_content
129
- end
130
- end
131
-
132
- if data_choice_tool_calls = data_choice_delta[ 'tool_calls' ]
133
- data_choice_tool_calls.each_with_index do | data_choice_tool_call, data_choice_tool_call_index |
134
- if data_choice_tool_call_function = data_choice_tool_call[ 'function' ]
135
- data_choice_tool_index = data_choice_tool_call[ 'index' ] || data_choice_tool_call_index
136
- data_choice_tool_id = data_choice_tool_call[ 'id' ]
137
- data_choice_tool_name = data_choice_tool_call_function[ 'name' ]
138
- data_choice_tool_parameters = data_choice_tool_call_function[ 'arguments' ]
139
-
140
- if data_choice_tool_id
141
- contents.push( {
142
- type: :tool_call,
143
- tool_call_id: data_choice_tool_id,
144
- tool_name: data_choice_tool_name,
145
- tool_parameters: data_choice_tool_parameters
146
- } )
147
- else
148
- tool_call_content_index = contents.rindex do | content |
149
- content[ :type ] == :tool_call
150
- end
151
- tool_call = contents[ tool_call_content_index ]
152
- tool_call[ :tool_parameters ] = ( tool_call[ :tool_parameters ] || '' ) + data_choice_tool_parameters \
153
- if data_choice_tool_parameters
154
- end
155
- end
156
- end
157
- end
158
- choices[ data_choice_index ][ :message ][ :contents ] = contents
159
- choices[ data_choice_index ][ :end_reason ] ||=
160
- to_end_reason( data_choice_finish_reason )
161
- end
162
-
163
- if usage = data[ 'usage' ]
164
- # note: A number of providers will resend the input tokens as part of their usage
165
- # payload.
166
- metrics[ :input_tokens ] = usage[ 'prompt_tokens' ] \
167
- if usage.include?( 'prompt_tokens' )
168
- metrics[ :output_tokens ] += usage[ 'completion_tokens' ] \
169
- if usage.include?( 'completion_tokens' )
170
- end
171
-
172
- end
173
-
174
- end
175
-
176
- context[ :buffer ] = buffer
177
- context[ :metrics ] = metrics
178
- context[ :choices ] = choices
179
-
180
- [ context, choices.empty? ? nil : { choices: choices.dup } ]
181
- end
182
-
183
- def stream_result_attributes( context )
184
- choices = context[ :choices ]
185
- metrics = context[ :metrics ]
186
-
187
- choices = choices.map do | choice |
188
- { end_reason: choice[ :end_reason ] }
189
- end
190
-
191
- { choices: choices, metrics: context[ :metrics ] }
192
- end
193
-
194
- alias_method :stream_result_error_attributes, :chat_result_error_attributes
195
-
196
- def to_end_reason( finish_reason )
197
- case finish_reason
198
- when 'stop'
199
- :ended
200
- when 'length'
201
- :token_limit_exceeded
202
- when 'tool_calls'
203
- :tool_called
204
- when 'content_filter'
205
- :filtered
206
- else
207
- nil
208
- end
209
- end
210
-
211
- def to_error_response( status )
212
- case status
213
- when 400
214
- [ :invalid_request_error,
215
- "There was an issue with the format or content of your request." ]
216
- when 401
217
- [ :authentication_error,
218
- "There's an issue with your API key." ]
219
- when 403
220
- [ :permission_error,
221
- "Your API key does not have permission to use the specified resource." ]
222
- when 404
223
- [ :not_found_error,
224
- "The requested resource was not found." ]
225
- when 413
226
- [ :request_too_large,
227
- "Request exceeds the maximum allowed number of bytes." ]
228
- when 422
229
- [ :invalid_request_error,
230
- "There was an issue with the format or content of your request." ]
231
- when 429
232
- [ :rate_limit_error,
233
- "Your account has hit a rate limit." ]
234
- when 500, 502, 503
235
- [ :api_error,
236
- "An unexpected error has occurred internal to the providers systems." ]
237
- when 529
238
- [ :overloaded_error,
239
- "The providers server is temporarily overloaded." ]
240
- else
241
- [ :unknown_error, "
242
- An unknown error occurred." ]
243
- end
244
- end
245
-
246
- end
247
- end
248
- end
@@ -1 +0,0 @@
1
- require_relative 'deepseek/adapter'
@@ -1,30 +0,0 @@
1
- module Intelligence
2
- module MessageContent
3
-
4
- class Thought < Base
5
-
6
- schema do
7
- text String, required: true
8
- end
9
-
10
- attr_reader :text
11
-
12
- def valid?
13
- true
14
- end
15
-
16
- def merge( other )
17
- other_text = other.text
18
- text = @text
19
- text = ( @text || '' ) + other_text if other_text
20
-
21
- self.class.new( text: text )
22
- end
23
-
24
- def to_h
25
- { type: :text, text: text }
26
- end
27
- end
28
-
29
- end
30
- end