intelligence 1.0.0.beta05 → 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: c0a3f15cdc1061405db03b0b8039b4867b16e70458d1a896a3d7cec542870cf5
4
- data.tar.gz: 2914681b64f2295b7fbd9a4e4edb3425f53d23ec3a3dd3da0639df101a2fe31f
3
+ metadata.gz: 4831cc2ed908d140d2986d50a48db3b71f9436d8ce3c55353fc0a704ca798d07
4
+ data.tar.gz: 66e71bfca8287772c267daa06ead05b177edd64648dc52d818b8dc47ed4eaef6
5
5
  SHA512:
6
- metadata.gz: 181c33085c1c608f8d35b39332514e0a4028124e85309f4e95fddb5913b43490333298ffa8d935f3cc447d682968e04816c7d5497967d1700daa4d575dbd6425
7
- data.tar.gz: abf03a55cf8c5f1ff5d0c97bc4d6918327f240cbc1f2137338726611c447fdd32cabf2cc15ba7f0f40b6cb122d35f9e0dec092add65c10b40044f248c2535d97
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 ]
@@ -71,6 +69,7 @@ module Intelligence
71
69
  end
72
70
 
73
71
  def stream_result_chunk_attributes( context, chunk )
72
+
74
73
  context ||= {}
75
74
  buffer = context[ :buffer ] || ''
76
75
  metrics = context[ :metrics ] || {
@@ -99,20 +98,21 @@ module Intelligence
99
98
 
100
99
  data_choice_index = data_choice[ 'index' ]
101
100
  data_choice_delta = data_choice[ 'delta' ]
102
- data_choice_finish_reason = data_choice[ 'finish_reason' ]
101
+ end_reason = to_end_reason( data_choice[ 'finish_reason' ] )
103
102
 
104
103
  choices.fill( { message: {} }, choices.size, data_choice_index + 1 ) \
105
104
  if choices.size <= data_choice_index
106
105
  contents = choices[ data_choice_index ][ :message ][ :contents ] || []
107
106
 
108
- text_content = contents.first&.[]( :type ) == :text ? contents.first : nil
109
107
  if data_choice_content = data_choice_delta[ 'content' ]
108
+ text_content = contents.last&.[]( :type ) == :text ? contents.last : nil
110
109
  if text_content.nil?
111
- contents.unshift( text_content = { type: :text, text: data_choice_content } )
110
+ contents.push( text_content = { type: :text, text: data_choice_content } )
112
111
  else
113
112
  text_content[ :text ] = ( text_content[ :text ] || '' ) + data_choice_content
114
113
  end
115
114
  end
115
+
116
116
  if data_choice_tool_calls = data_choice_delta[ 'tool_calls' ]
117
117
  data_choice_tool_calls.each_with_index do | data_choice_tool_call, data_choice_tool_call_index |
118
118
  if data_choice_tool_call_function = data_choice_tool_call[ 'function' ]
@@ -121,29 +121,29 @@ module Intelligence
121
121
  data_choice_tool_name = data_choice_tool_call_function[ 'name' ]
122
122
  data_choice_tool_parameters = data_choice_tool_call_function[ 'arguments' ]
123
123
 
124
- tool_call_content_index = ( text_content.nil? ? 0 : 1 ) + data_choice_tool_index
125
- if tool_call_content_index >= contents.length
124
+ # if the data_choice_tool_id is present this indicates a new tool call.
125
+ if data_choice_tool_id
126
126
  contents.push( {
127
127
  type: :tool_call,
128
128
  tool_call_id: data_choice_tool_id,
129
129
  tool_name: data_choice_tool_name,
130
130
  tool_parameters: data_choice_tool_parameters
131
131
  } )
132
+ # otherwise the tool is being aggregated
132
133
  else
134
+ tool_call_content_index = contents.rindex do | content |
135
+ content[ :type ] == :tool_call
136
+ end
133
137
  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
138
  tool_call[ :tool_parameters ] = ( tool_call[ :tool_parameters ] || '' ) + data_choice_tool_parameters \
139
139
  if data_choice_tool_parameters
140
140
  end
141
141
  end
142
142
  end
143
143
  end
144
+
144
145
  choices[ data_choice_index ][ :message ][ :contents ] = contents
145
- choices[ data_choice_index ][ :end_reason ] ||=
146
- to_end_reason( data_choice_finish_reason )
146
+ choices[ data_choice_index ][ :end_reason ] ||= end_reason
147
147
  end
148
148
 
149
149
  if usage = data[ 'usage' ]
@@ -164,6 +164,7 @@ module Intelligence
164
164
  context[ :choices ] = choices
165
165
 
166
166
  [ context, choices.empty? ? nil : { choices: choices.dup } ]
167
+
167
168
  end
168
169
 
169
170
  def stream_result_attributes( context )
@@ -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
@@ -5,10 +5,13 @@ module Intelligence
5
5
 
6
6
  class Adapter < Generic::Adapter
7
7
 
8
- chat_request_uri "https://api.x.ai/v1/chat/completions"
9
-
8
+ DEFAULT_BASE_URI = "https://api.x.ai/v1"
9
+
10
10
  schema do
11
+
12
+ base_uri String, default: DEFAULT_BASE_URI
11
13
  key String
14
+
12
15
  chat_options do
13
16
  model String
14
17
  frequency_penalty Float, in: -2..2
@@ -31,154 +34,10 @@ module Intelligence
31
34
  top_p Float
32
35
 
33
36
  user String
37
+
34
38
  end
35
39
  end
36
40
 
37
- def chat_result_attributes( response )
38
- return nil unless response.success?
39
- response_json = JSON.parse( response.body, symbolize_names: true ) rescue nil
40
- return nil if response_json.nil? || response_json[ :choices ].nil?
41
-
42
- result = {}
43
- result[ :choices ] = []
44
-
45
- ( response_json[ :choices ] || [] ).each do | json_choice |
46
- end_reason = to_end_reason( json_choice[ :finish_reason ] )
47
- if ( json_message = json_choice[ :message ] )
48
- result_message = { role: json_message[ :role ] }
49
- if json_message[ :content ]
50
- result_message[ :contents ] = [ { type: :text, text: json_message[ :content ] } ]
51
- end
52
- if json_message[ :tool_calls ] && !json_message[ :tool_calls ].empty?
53
- result_message[ :contents ] ||= []
54
- end_reason = :tool_called if end_reason == :ended
55
- json_message[ :tool_calls ].each do | json_message_tool_call |
56
- result_message_tool_call_parameters =
57
- JSON.parse( json_message_tool_call[ :function ][ :arguments ], symbolize_names: true ) \
58
- rescue json_message_tool_call[ :function ][ :arguments ]
59
- result_message[ :contents ] << {
60
- type: :tool_call,
61
- tool_call_id: json_message_tool_call[ :id ],
62
- tool_name: json_message_tool_call[ :function ][ :name ],
63
- tool_parameters: result_message_tool_call_parameters
64
- }
65
- end
66
- end
67
- end
68
- result[ :choices ].push( { end_reason: end_reason, message: result_message } )
69
- end
70
-
71
- metrics_json = response_json[ :usage ]
72
- unless metrics_json.nil?
73
-
74
- metrics = {}
75
- metrics[ :input_tokens ] = metrics_json[ :prompt_tokens ]
76
- metrics[ :output_tokens ] = metrics_json[ :completion_tokens ]
77
- metrics = metrics.compact
78
-
79
- result[ :metrics ] = metrics unless metrics.empty?
80
-
81
- end
82
-
83
- result
84
- end
85
-
86
- def stream_result_chunk_attributes( context, chunk )
87
- context ||= {}
88
- buffer = context[ :buffer ] || ''
89
- metrics = context[ :metrics ] || {
90
- input_tokens: 0,
91
- output_tokens: 0
92
- }
93
- choices = context[ :choices ] || Array.new( 1 , { message: {} } )
94
-
95
- choices.each do | choice |
96
- choice[ :message ][ :contents ] = choice[ :message ][ :contents ]&.map do | content |
97
- { type: content[ :type ] }
98
- end
99
- end
100
-
101
- buffer += chunk
102
- while ( eol_index = buffer.index( "\n" ) )
103
- line = buffer.slice!( 0..eol_index )
104
- line = line.strip
105
- next if line.empty? || !line.start_with?( 'data:' )
106
- line = line[ 6..-1 ]
107
- next if line.end_with?( '[DONE]' )
108
-
109
- data = JSON.parse( line ) rescue nil
110
- if data.is_a?( Hash )
111
- data[ 'choices' ]&.each do | data_choice |
112
-
113
- data_choice_index = data_choice[ 'index' ]
114
- data_choice_delta = data_choice[ 'delta' ]
115
- end_reason = to_end_reason( data_choice[ 'finish_reason' ] )
116
-
117
- choices.fill( { message: {} }, choices.size, data_choice_index + 1 ) \
118
- if choices.size <= data_choice_index
119
- contents = choices[ data_choice_index ][ :message ][ :contents ] || []
120
-
121
- text_content = contents.first&.[]( :type ) == :text ? contents.first : nil
122
- if data_choice_content = data_choice_delta[ 'content' ]
123
- if text_content.nil?
124
- contents.unshift( text_content = { type: :text, text: data_choice_content } )
125
- else
126
- text_content[ :text ] = ( text_content[ :text ] || '' ) + data_choice_content
127
- end
128
- end
129
- if data_choice_tool_calls = data_choice_delta[ 'tool_calls' ]
130
- end_reason = :tool_called
131
- data_choice_tool_calls.each_with_index do | data_choice_tool_call, data_choice_tool_call_index |
132
- if data_choice_tool_call_function = data_choice_tool_call[ 'function' ]
133
- data_choice_tool_index = data_choice_tool_call[ 'index' ] || data_choice_tool_call_index
134
- data_choice_tool_id = data_choice_tool_call[ 'id' ]
135
- data_choice_tool_name = data_choice_tool_call_function[ 'name' ]
136
- data_choice_tool_parameters = data_choice_tool_call_function[ 'arguments' ]
137
-
138
- tool_call_content_index = ( text_content.nil? ? 0 : 1 ) + data_choice_tool_index
139
- if tool_call_content_index >= contents.length
140
- contents.push( {
141
- type: :tool_call,
142
- tool_call_id: data_choice_tool_id,
143
- tool_name: data_choice_tool_name,
144
- tool_parameters: data_choice_tool_parameters
145
- } )
146
- else
147
- tool_call = contents[ tool_call_content_index ]
148
- tool_call[ :tool_call_id ] = ( tool_call[ :tool_call_id ] || '' ) + data_choice_tool_id \
149
- if data_choice_tool_id
150
- tool_call[ :tool_name ] = ( tool_call[ :tool_name ] || '' ) + data_choice_tool_name \
151
- if data_choice_tool_name
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 ] ||= end_reason
160
- end
161
-
162
- if usage = data[ 'usage' ]
163
- # note: A number of providers will resend the input tokens as part of their usage
164
- # payload.
165
- metrics[ :input_tokens ] = usage[ 'prompt_tokens' ] \
166
- if usage.include?( 'prompt_tokens' )
167
- metrics[ :output_tokens ] += usage[ 'completion_tokens' ] \
168
- if usage.include?( 'completion_tokens' )
169
- end
170
-
171
- end
172
-
173
- end
174
-
175
- context[ :buffer ] = buffer
176
- context[ :metrics ] = metrics
177
- context[ :choices ] = choices
178
-
179
- [ context, choices.empty? ? nil : { choices: choices.dup } ]
180
- end
181
-
182
41
  def chat_result_error_attributes( response )
183
42
  error_type, error_description = to_error_response( response.status )
184
43
  error = error_type
@@ -1,3 +1,3 @@
1
1
  module Intelligence
2
- VERSION = "1.0.0.beta05"
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.beta05
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-07 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,7 +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
137
  - lib/intelligence/adapters/generic.rb
139
138
  - lib/intelligence/adapters/generic/adapter.rb
140
139
  - lib/intelligence/adapters/generic/chat_request_methods.rb
@@ -1,44 +0,0 @@
1
- require_relative 'generic/adapter'
2
-
3
- module Intelligence
4
- module Deepseek
5
- class Adapter < Generic::Adapter
6
-
7
- chat_request_uri 'https://api.deepseek.com/v1/chat/completions'
8
-
9
- schema do
10
- key String
11
- chat_options do
12
- frequency_penalty Float
13
- logprobs [ TrueClass, FalseClass ]
14
- max_tokens Integer
15
- model String
16
- presence_penalty Float, in: [ -2..2 ]
17
- response_format do
18
- # 'text' and 'json_object' are the only supported types; you must also instruct
19
- # the model to output json
20
- type Symbol, in: [ :text, :json_object ]
21
- end
22
- stop String, array: true
23
- stream [ TrueClass, FalseClass ]
24
- stream_options do
25
- include_usage [ TrueClass, FalseClass ]
26
- end
27
- temperature Float, in: [ 0..2 ]
28
- tool array: true, as: :tools, &Tool.schema
29
- tool_choice do
30
- # one of 'auto', 'none' or 'function'
31
- type Symbol, in: [ :auto, :none, :required ]
32
- # the function parameters is required if you specify a type of 'function'
33
- function do
34
- name String
35
- end
36
- end
37
- top_logprobs Integer
38
- top_p Float
39
- end
40
- end
41
-
42
- end
43
- end
44
- end