rasti-ai 1.0.1 → 1.2.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.
@@ -1,8 +1,8 @@
1
1
  require 'minitest_helper'
2
2
 
3
- describe Rasti::AI::OpenAI::ToolSerializer do
3
+ describe Rasti::AI::ToolSerializer do
4
4
 
5
- let(:serializer) { Rasti::AI::OpenAI::ToolSerializer }
5
+ let(:serializer) { Rasti::AI::ToolSerializer }
6
6
 
7
7
  def build_tool_class(form_class=nil)
8
8
  tool_class = Minitest::Mock.new
@@ -13,15 +13,12 @@ describe Rasti::AI::OpenAI::ToolSerializer do
13
13
 
14
14
  def build_serializaton(param_name:, param_type:)
15
15
  {
16
- type: 'function',
17
- function: {
18
- name: 'call_custom_function',
19
- parameters: {
20
- type: 'object',
21
- properties: {
22
- param_name.to_sym => {
23
- type: param_type
24
- }
16
+ name: 'call_custom_function',
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ param_name.to_sym => {
21
+ type: param_type
25
22
  }
26
23
  }
27
24
  }
@@ -34,10 +31,7 @@ describe Rasti::AI::OpenAI::ToolSerializer do
34
31
  serialization = serializer.serialize tool_class
35
32
 
36
33
  expeted_serialization = {
37
- type: 'function',
38
- function: {
39
- name: 'call_custom_function'
40
- }
34
+ name: 'call_custom_function'
41
35
  }
42
36
 
43
37
  assert_equal expeted_serialization, serialization
@@ -52,11 +46,8 @@ describe Rasti::AI::OpenAI::ToolSerializer do
52
46
  serialization = serializer.serialize tool_class
53
47
 
54
48
  expeted_serialization = {
55
- type: 'function',
56
- function: {
57
- name: 'call_custom_function',
58
- description: 'Call custom function without arguments',
59
- }
49
+ name: 'call_custom_function',
50
+ description: 'Call custom function without arguments',
60
51
  }
61
52
 
62
53
  assert_equal expeted_serialization, serialization
@@ -132,7 +123,7 @@ describe Rasti::AI::OpenAI::ToolSerializer do
132
123
  serialization = serializer.serialize tool_class
133
124
 
134
125
  expeted_serialization = build_serializaton param_name: 'timestamp', param_type: 'string'
135
- expeted_serialization[:function][:parameters][:properties][:timestamp][:format] = 'date'
126
+ expeted_serialization[:inputSchema][:properties][:timestamp][:format] = 'date'
136
127
 
137
128
  assert_equal expeted_serialization, serialization
138
129
 
@@ -147,7 +138,8 @@ describe Rasti::AI::OpenAI::ToolSerializer do
147
138
  serialization = serializer.serialize tool_class
148
139
 
149
140
  expeted_serialization = build_serializaton param_name: 'option', param_type: 'string'
150
- expeted_serialization[:function][:parameters][:properties][:option][:enum] = ['option_1', 'option_2']
141
+ expeted_serialization[:inputSchema][:properties][:option][:enum] = ['option_1', 'option_2']
142
+ expeted_serialization[:inputSchema][:properties][:option][:description] = 'option_1, option_2'
151
143
 
152
144
  assert_equal expeted_serialization, serialization
153
145
 
@@ -163,7 +155,7 @@ describe Rasti::AI::OpenAI::ToolSerializer do
163
155
  serialization = serializer.serialize tool_class
164
156
 
165
157
  expeted_serialization = build_serializaton param_name: 'form', param_type: 'object'
166
- expeted_serialization[:function][:parameters][:properties][:form][:properties] = {
158
+ expeted_serialization[:inputSchema][:properties][:form][:properties] = {
167
159
  text: {type: 'string'},
168
160
  int: {type: 'integer'}
169
161
  }
@@ -183,7 +175,7 @@ describe Rasti::AI::OpenAI::ToolSerializer do
183
175
  serialization = serializer.serialize tool_class
184
176
 
185
177
  expeted_serialization = build_serializaton param_name: 'texts', param_type: 'array'
186
- expeted_serialization[:function][:parameters][:properties][:texts][:items] = {type: 'string'}
178
+ expeted_serialization[:inputSchema][:properties][:texts][:items] = {type: 'string'}
187
179
 
188
180
  assert_equal expeted_serialization, serialization
189
181
 
@@ -198,7 +190,7 @@ describe Rasti::AI::OpenAI::ToolSerializer do
198
190
  serialization = serializer.serialize tool_class
199
191
 
200
192
  expeted_serialization = build_serializaton param_name: 'numbers', param_type: 'array'
201
- expeted_serialization[:function][:parameters][:properties][:numbers][:items] = {type: 'number'}
193
+ expeted_serialization[:inputSchema][:properties][:numbers][:items] = {type: 'number'}
202
194
 
203
195
  assert_equal expeted_serialization, serialization
204
196
 
@@ -214,7 +206,7 @@ describe Rasti::AI::OpenAI::ToolSerializer do
214
206
  serialization = serializer.serialize tool_class
215
207
 
216
208
  expeted_serialization = build_serializaton param_name: 'forms', param_type: 'array'
217
- expeted_serialization[:function][:parameters][:properties][:forms][:items] = {
209
+ expeted_serialization[:inputSchema][:properties][:forms][:items] = {
218
210
  type: 'object',
219
211
  properties: {
220
212
  text: {type: 'string'},
@@ -242,11 +234,11 @@ describe Rasti::AI::OpenAI::ToolSerializer do
242
234
  serialization = serializer.serialize tool_class
243
235
 
244
236
  expeted_serialization = build_serializaton param_name: 'form', param_type: 'object'
245
- expeted_serialization[:function][:parameters][:properties] = {
237
+ expeted_serialization[:inputSchema][:properties] = {
246
238
  text: {type: 'string'},
247
239
  int: {type: 'integer'}
248
240
  }
249
- expeted_serialization[:function][:parameters][:required] = [:text]
241
+ expeted_serialization[:inputSchema][:required] = [:text]
250
242
 
251
243
  assert_equal expeted_serialization, serialization
252
244
 
@@ -264,7 +256,7 @@ describe Rasti::AI::OpenAI::ToolSerializer do
264
256
  serialization = serializer.serialize tool_class
265
257
 
266
258
  expeted_serialization = build_serializaton param_name: 'form', param_type: 'object'
267
- expeted_serialization[:function][:parameters][:properties] = {
259
+ expeted_serialization[:inputSchema][:properties] = {
268
260
  text: {
269
261
  description: 'Text param',
270
262
  type: 'string'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasti-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Naiman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-26 00:00:00.000000000 Z
11
+ date: 2025-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_require
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '12.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack-test
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: minitest
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +142,20 @@ dependencies:
128
142
  - - "~>"
129
143
  - !ruby/object:Gem::Version
130
144
  version: '0.6'
145
+ - !ruby/object:Gem::Dependency
146
+ name: minitest-extended_assertions
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '1.0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '1.0'
131
159
  - !ruby/object:Gem::Dependency
132
160
  name: simplecov
133
161
  requirement: !ruby/object:Gem::Requirement
@@ -188,24 +216,31 @@ files:
188
216
  - lib/rasti-ai.rb
189
217
  - lib/rasti/ai.rb
190
218
  - lib/rasti/ai/errors.rb
219
+ - lib/rasti/ai/mcp/client.rb
220
+ - lib/rasti/ai/mcp/errors.rb
221
+ - lib/rasti/ai/mcp/server.rb
191
222
  - lib/rasti/ai/open_ai/assistant.rb
192
223
  - lib/rasti/ai/open_ai/assistant_state.rb
193
224
  - lib/rasti/ai/open_ai/client.rb
194
225
  - lib/rasti/ai/open_ai/roles.rb
195
- - lib/rasti/ai/open_ai/tool_serializer.rb
226
+ - lib/rasti/ai/tool.rb
227
+ - lib/rasti/ai/tool_serializer.rb
196
228
  - lib/rasti/ai/version.rb
229
+ - log/.gitkeep
197
230
  - rasti-ai.gemspec
198
231
  - spec/coverage_helper.rb
232
+ - spec/mcp/client_spec.rb
233
+ - spec/mcp/server_spec.rb
199
234
  - spec/minitest_helper.rb
200
235
  - spec/open_ai/assistant_spec.rb
201
236
  - spec/open_ai/client_spec.rb
202
- - spec/open_ai/tool_serializer_spec.rb
203
237
  - spec/resources/open_ai/basic_request.json
204
238
  - spec/resources/open_ai/basic_response.json
205
239
  - spec/resources/open_ai/tool_request.json
206
240
  - spec/resources/open_ai/tool_response.json
207
241
  - spec/support/helpers/erb.rb
208
242
  - spec/support/helpers/resources.rb
243
+ - spec/tool_serializer_spec.rb
209
244
  homepage: https://github.com/gabynaiman/rasti-ai
210
245
  licenses:
211
246
  - MIT
@@ -231,13 +266,15 @@ specification_version: 4
231
266
  summary: AI for apps
232
267
  test_files:
233
268
  - spec/coverage_helper.rb
269
+ - spec/mcp/client_spec.rb
270
+ - spec/mcp/server_spec.rb
234
271
  - spec/minitest_helper.rb
235
272
  - spec/open_ai/assistant_spec.rb
236
273
  - spec/open_ai/client_spec.rb
237
- - spec/open_ai/tool_serializer_spec.rb
238
274
  - spec/resources/open_ai/basic_request.json
239
275
  - spec/resources/open_ai/basic_response.json
240
276
  - spec/resources/open_ai/tool_request.json
241
277
  - spec/resources/open_ai/tool_response.json
242
278
  - spec/support/helpers/erb.rb
243
279
  - spec/support/helpers/resources.rb
280
+ - spec/tool_serializer_spec.rb
@@ -1,111 +0,0 @@
1
- module Rasti
2
- module AI
3
- module OpenAI
4
- class ToolSerializer
5
- class << self
6
-
7
- def serialize(tool_class)
8
- {
9
- type: 'function',
10
- function: serialize_function(tool_class)
11
- }
12
-
13
- rescue => ex
14
- raise Errors::ToolSerializationError.new(tool_class), cause: ex
15
- end
16
-
17
- private
18
-
19
- def serialize_function(tool_class)
20
- serialization = {
21
- name: serialize_name(tool_class)
22
- }
23
-
24
- serialization[:description] = normalize_description(tool_class.description) if tool_class.respond_to? :description
25
-
26
- serialization[:parameters] = serialize_form(tool_class.form) if tool_class.respond_to? :form
27
-
28
- serialization
29
- end
30
-
31
- def serialize_name(tool_class)
32
- Inflecto.underscore Inflecto.demodulize(tool_class.name)
33
- end
34
-
35
- def serialize_form(form_class)
36
- serialized_attributes = form_class.attributes.each_with_object({}) do |attribute, hash|
37
- hash[attribute.name] = serialize_attribute attribute
38
- end
39
-
40
- serialization = {
41
- type: 'object',
42
- properties: serialized_attributes
43
- }
44
-
45
- required_attributes = form_class.attributes.select { |a| a.option(:required) }
46
-
47
- serialization[:required] = required_attributes.map(&:name) unless required_attributes.empty?
48
-
49
- serialization
50
- end
51
-
52
- def serialize_attribute(attribute)
53
- serialization = {}
54
-
55
- if attribute.option(:description)
56
- serialization[:description] = normalize_description attribute.option(:description)
57
- end
58
-
59
- serialization.merge! serialize_type(attribute.type)
60
-
61
- serialization
62
- end
63
-
64
- def serialize_type(type)
65
- if type == Types::String
66
- {type: 'string'}
67
-
68
- elsif type == Types::Integer
69
- {type: 'integer'}
70
-
71
- elsif type == Types::Float
72
- {type: 'number'}
73
-
74
- elsif type == Types::Boolean
75
- {type: 'boolean'}
76
-
77
- elsif type.is_a? Types::Time
78
- {
79
- type: 'string',
80
- format: 'date'
81
- }
82
-
83
- elsif type.is_a? Types::Enum
84
- {
85
- type: 'string',
86
- enum: type.values
87
- }
88
-
89
- elsif type.is_a? Types::Array
90
- {
91
- type: 'array',
92
- items: serialize_type(type.type)
93
- }
94
-
95
- elsif type.is_a? Types::Model
96
- serialize_form(type.model)
97
-
98
- else
99
- raise "Type not serializable #{type}"
100
- end
101
- end
102
-
103
- def normalize_description(description)
104
- description.split("\n").map(&:strip).join(' ').strip
105
- end
106
-
107
- end
108
- end
109
- end
110
- end
111
- end