omniai 2.5.0 → 2.6.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 +4 -4
- data/README.md +114 -39
- data/lib/omniai/chat/message.rb +7 -1
- data/lib/omniai/chat/response.rb +2 -0
- data/lib/omniai/chat.rb +1 -1
- data/lib/omniai/schema/array.rb +96 -0
- data/lib/omniai/schema/format.rb +71 -0
- data/lib/omniai/schema/object.rb +96 -0
- data/lib/omniai/schema/scalar.rb +118 -0
- data/lib/omniai/schema.rb +165 -0
- data/lib/omniai/tool.rb +5 -5
- data/lib/omniai/version.rb +1 -1
- metadata +7 -6
- data/lib/omniai/tool/array.rb +0 -74
- data/lib/omniai/tool/object.rb +0 -62
- data/lib/omniai/tool/parameters.rb +0 -23
- data/lib/omniai/tool/property.rb +0 -151
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b8a243fb8313c7c1fe3a483cdac33892f1b764cac19c38465a880e3f8a790f0
|
4
|
+
data.tar.gz: b24f59696a3befee77cde24b8fd25b88331b3664a327e8e207d9f57a08abb524
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 985aafb6c64874122c77c172ba7dccc1a371a982855b33add51c3371d872db7008391a28382aa7442d640a2f76df1e3ca95426428fb7cd3b12a177d69ed3605e
|
7
|
+
data.tar.gz: 42edecdd416fdc53562ea82caf09b94886e761ea2858c28db76dc4e909dd4da87835fe152bbebf3cc87a64a72eded21706c60ba13beba2293fa5470f11e822bd
|
data/README.md
CHANGED
@@ -88,34 +88,62 @@ require 'omniai/google'
|
|
88
88
|
|
89
89
|
client = OmniAI::Google::Client.new
|
90
90
|
|
91
|
-
class
|
92
|
-
description "Lookup the weather for a
|
91
|
+
class WeatherTool < OmniAI::Tool
|
92
|
+
description "Lookup the weather for a lat / lng."
|
93
93
|
|
94
|
-
parameter :
|
94
|
+
parameter :lat, :number, description: "The latitude of the location."
|
95
|
+
parameter :lng, :number, description: "The longitude of the location."
|
95
96
|
parameter :unit, :string, enum: %w[Celsius Fahrenheit], description: "The unit of measurement."
|
97
|
+
required %i[lat lng]
|
98
|
+
|
99
|
+
# @param lat [Float]
|
100
|
+
# @param lng [Float]
|
101
|
+
# @param unit [String] "Celsius" or "Fahrenheit"
|
102
|
+
#
|
103
|
+
# @return [String] e.g. "20° Celsius at lat=43.7 lng=-79.4"
|
104
|
+
def execute(lat:, lng:, unit: "Celsius")
|
105
|
+
puts "[weather] lat=#{lat} lng=#{lng} unit=#{unit}"
|
106
|
+
"#{rand(20..50)}° #{unit} at lat=#{lat} lng=#{lng}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class GeocodeTool < OmniAI::Tool
|
111
|
+
description "Lookup the latitude and longitude of a location."
|
112
|
+
|
113
|
+
parameter :location, :string, description: "The location to geocode."
|
96
114
|
required %i[location]
|
97
115
|
|
98
|
-
# @param location [String]
|
99
|
-
#
|
100
|
-
# @return [String
|
101
|
-
def execute(location
|
102
|
-
puts "[
|
103
|
-
|
116
|
+
# @param location [String] "Toronto, Canada"
|
117
|
+
#
|
118
|
+
# @return [Hash] { lat: Float, lng: Float, location: String }
|
119
|
+
def execute(location:)
|
120
|
+
puts "[geocode] location=#{location}"
|
121
|
+
|
122
|
+
{
|
123
|
+
lat: rand(-90.0..+90.0),
|
124
|
+
lng: rand(-180.0..+180.0),
|
125
|
+
location:,
|
126
|
+
}
|
104
127
|
end
|
105
128
|
end
|
106
129
|
|
107
|
-
|
130
|
+
tools = [
|
131
|
+
WeatherTool.new,
|
132
|
+
GeocodeTool.new,
|
133
|
+
]
|
134
|
+
|
135
|
+
client.chat(stream: $stdout, tools:) do |prompt|
|
108
136
|
prompt.system "You are an expert in weather."
|
109
137
|
prompt.user 'What is the weather in "London" in Celsius and "Madrid" in Fahrenheit?'
|
110
138
|
end
|
111
139
|
```
|
112
140
|
|
113
141
|
```
|
114
|
-
[
|
115
|
-
[weather]
|
116
|
-
|
142
|
+
[geocode] location=London
|
143
|
+
[weather] lat=... lng=... unit=Celsius
|
144
|
+
[geocode] location=Madrid
|
145
|
+
[weather] lat=... lng=... unit=Fahrenheit
|
117
146
|
|
118
|
-
```
|
119
147
|
The weather is 24° Celsius in London and 42° Fahrenheit in Madrid.
|
120
148
|
```
|
121
149
|
|
@@ -146,19 +174,57 @@ loop do
|
|
146
174
|
end
|
147
175
|
```
|
148
176
|
|
149
|
-
|
150
|
-
Type 'exit' or 'quit' to leave.
|
177
|
+
### Example #6 [Chat w/ Schema](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_schema)
|
151
178
|
|
152
|
-
|
153
|
-
|
154
|
-
|
179
|
+
```ruby
|
180
|
+
format = OmniAI::Schema.format(name: "Contact", schema: OmniAI::Schema.object(
|
181
|
+
description: "A contact with a name, relationship, and addresses.",
|
182
|
+
properties: {
|
183
|
+
name: OmniAI::Schema.string,
|
184
|
+
relationship: OmniAI::Schema.string(enum: %w[friend family]),
|
185
|
+
addresses: OmniAI::Schema.array(
|
186
|
+
items: OmniAI::Schema.object(
|
187
|
+
title: "Address",
|
188
|
+
description: "An address with street, city, state, and zip code.",
|
189
|
+
properties: {
|
190
|
+
street: OmniAI::Schema.string,
|
191
|
+
city: OmniAI::Schema.string,
|
192
|
+
state: OmniAI::Schema.string,
|
193
|
+
zip: OmniAI::Schema.string,
|
194
|
+
},
|
195
|
+
required: %i[street city state zip]
|
196
|
+
)
|
197
|
+
),
|
198
|
+
},
|
199
|
+
required: %i[name]
|
200
|
+
))
|
201
|
+
|
202
|
+
response = client.chat(format:) do |prompt|
|
203
|
+
prompt.user <<~TEXT
|
204
|
+
Parse the following contact:
|
205
|
+
|
206
|
+
NAME: George Harrison
|
207
|
+
RELATIONSHIP: friend
|
208
|
+
HOME: 123 Main St, Springfield, IL, 12345
|
209
|
+
WORK: 456 Elm St, Springfield, IL, 12345
|
210
|
+
TEXT
|
211
|
+
end
|
212
|
+
|
213
|
+
puts format.parse(response.text)
|
214
|
+
```
|
155
215
|
|
156
|
-
|
157
|
-
|
158
|
-
|
216
|
+
```
|
217
|
+
{
|
218
|
+
name: "George Harrison",
|
219
|
+
relationship: "friend",
|
220
|
+
addresses: [
|
221
|
+
{ street: "123 Main St", city: "Springfield", state: "IL", zip: "12345" },
|
222
|
+
{ street: "456 Elm St", city: "Springfield", state: "IL", zip: "12345" },
|
223
|
+
]
|
224
|
+
}
|
159
225
|
```
|
160
226
|
|
161
|
-
### Example #
|
227
|
+
### Example #7: [Chat w/ CLI](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_cli)
|
162
228
|
|
163
229
|
The `OmniAI` gem also ships with a CLI to simplify quick tests.
|
164
230
|
|
@@ -178,7 +244,7 @@ omniai chat --provider="google" --model="gemini-2.0-flash" "Who are you?"
|
|
178
244
|
I am a large language model, trained by Google.
|
179
245
|
```
|
180
246
|
|
181
|
-
### Example #
|
247
|
+
### Example #8: [Text-to-Speech](https://github.com/ksylvest/omniai/blob/main/examples/text_to_speech)
|
182
248
|
|
183
249
|
This example demonstrates using `OmniAI` with **OpenAI** to convert text to speech and save it to a file.
|
184
250
|
|
@@ -194,7 +260,7 @@ File.open(File.join(__dir__, 'audio.wav'), 'wb') do |file|
|
|
194
260
|
end
|
195
261
|
```
|
196
262
|
|
197
|
-
### Example #
|
263
|
+
### Example #9: [Speech-to-Text](https://github.com/ksylvest/omniai/blob/main/examples/speech_to_text)
|
198
264
|
|
199
265
|
This example demonstrates using `OmniAI` with **OpenAI** to convert speech to text.
|
200
266
|
|
@@ -209,7 +275,7 @@ File.open(File.join(__dir__, 'audio.wav'), 'rb') do |file|
|
|
209
275
|
end
|
210
276
|
```
|
211
277
|
|
212
|
-
### Example #
|
278
|
+
### Example #10: [Embeddings](https://github.com/ksylvest/omniai/blob/main/examples/embeddings)
|
213
279
|
|
214
280
|
This example demonstrates using `OmniAI` with **Mistral** to generate embeddings for a dataset. It defines a set of entries (e.g. "George is a teacher." or "Ringo is a doctor.") and then compares the embeddings generated from a query (e.g. "What does George do?" or "Who is a doctor?") to rank the entries by relevance.
|
215
281
|
|
@@ -426,19 +492,28 @@ client.chat('Tell me a story', stream: $stdout)
|
|
426
492
|
A chat can also be initialized with tools:
|
427
493
|
|
428
494
|
```ruby
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
description:
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
)
|
441
|
-
|
495
|
+
class WeatherTool
|
496
|
+
description "Lookup the weather at a location in either Celsius for Fahrenheit."
|
497
|
+
|
498
|
+
parameter :location, :string, description: "The location to find the weather."
|
499
|
+
parameter :unit, :string, enum: %w[Celsius Fahrenheit], description: "The unit of measurement."
|
500
|
+
required %i[location]
|
501
|
+
|
502
|
+
# @param location [String]
|
503
|
+
# @param unit [String] "Celsius" or "Fahrenheit"
|
504
|
+
#
|
505
|
+
# @return [Hash]
|
506
|
+
def execute(location:, unit: "Celsius")
|
507
|
+
puts "[weather] location=#{locaiton} unit=#{unit}"
|
508
|
+
|
509
|
+
{
|
510
|
+
temperature: "#{rand(20..50)}°",
|
511
|
+
humidty: rand(0..100),
|
512
|
+
}
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
client.chat('What is the weather in "London" in Celsius and "Paris" in Fahrenheit?', tools: [WeatherTool.new])
|
442
517
|
```
|
443
518
|
|
444
519
|
### Transcribe
|
data/lib/omniai/chat/message.rb
CHANGED
@@ -103,7 +103,13 @@ module OmniAI
|
|
103
103
|
serializer = context&.serializer(:message)
|
104
104
|
return serializer.call(self, context:) if serializer
|
105
105
|
|
106
|
-
content =
|
106
|
+
content =
|
107
|
+
case @content
|
108
|
+
when Array then @content.map { |content| content.serialize(context:) }
|
109
|
+
when Content then @content.serialize(context:)
|
110
|
+
else @content
|
111
|
+
end
|
112
|
+
|
107
113
|
tool_calls = @tool_call_list&.serialize(context:)
|
108
114
|
|
109
115
|
{ role: @role, content:, tool_calls: }.compact
|
data/lib/omniai/chat/response.rb
CHANGED
@@ -29,6 +29,8 @@ module OmniAI
|
|
29
29
|
|
30
30
|
# @param data [Hash]
|
31
31
|
# @param context [OmniAI::Context] optional
|
32
|
+
#
|
33
|
+
# @return [OmniAI::Chat::Response]
|
32
34
|
def self.deserialize(data, context: nil)
|
33
35
|
deserialize = context&.deserializer(:response)
|
34
36
|
return deserialize.call(data, context:) if deserialize
|
data/lib/omniai/chat.rb
CHANGED
@@ -65,7 +65,7 @@ module OmniAI
|
|
65
65
|
# @param temperature [Float, nil] optional
|
66
66
|
# @param stream [Proc, IO, nil] optional
|
67
67
|
# @param tools [Array<OmniAI::Tool>] optional
|
68
|
-
# @param format [
|
68
|
+
# @param format [:json, :text, OmniAI::Schema::Object, nil] optional
|
69
69
|
#
|
70
70
|
# @yield [prompt] optional
|
71
71
|
# @yieldparam prompt [OmniAI::Chat::Prompt]
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
module Schema
|
5
|
+
# @example
|
6
|
+
# array = OmniAI::Tool::Array.deserialize({
|
7
|
+
# description: "A list of people.",
|
8
|
+
# items: {
|
9
|
+
# properties: {
|
10
|
+
# name: { type: "string" },
|
11
|
+
# },
|
12
|
+
# required: ["name"],
|
13
|
+
# },
|
14
|
+
# min_items: 1,
|
15
|
+
# max_items: 5,
|
16
|
+
# })
|
17
|
+
# array.serialize # => { type: "array", items: { ... }, minItems: 1, maxItems: 5 }
|
18
|
+
# array.parse([{ "name" => "Ringo Starr" }]) # => [{ name: "Ringo Star" }]
|
19
|
+
class Array
|
20
|
+
TYPE = "array"
|
21
|
+
|
22
|
+
# @!attribute [rw] items
|
23
|
+
# @return [OmniAI::Schema::Object, OmniAI::Schema::Array, OmniAI::Schema::Scalar]
|
24
|
+
attr_accessor :items
|
25
|
+
|
26
|
+
# @!attribute [rw] max_items
|
27
|
+
# @return [Integer, nil]
|
28
|
+
attr_accessor :max_items
|
29
|
+
|
30
|
+
# @!attribute [rw] min_items
|
31
|
+
# @return [Integer, nil]
|
32
|
+
attr_accessor :min_items
|
33
|
+
|
34
|
+
# @!attribute [rw] description
|
35
|
+
# @return [String, nil]
|
36
|
+
attr_accessor :description
|
37
|
+
|
38
|
+
# @example
|
39
|
+
# array = OmniAI::Schema::Array.deserialize({
|
40
|
+
# type: "array",
|
41
|
+
# items: { type: "string" },
|
42
|
+
# minItems: 1,
|
43
|
+
# maxItems: 5,
|
44
|
+
# description: "A list of strings."
|
45
|
+
# }) # => OmniAI::Schema::Array
|
46
|
+
#
|
47
|
+
# @param data [Hash]
|
48
|
+
#
|
49
|
+
# @return [OmniAI::Schema::Array]
|
50
|
+
def self.deserialize(data)
|
51
|
+
new(
|
52
|
+
items: OmniAI::Schema.deserialize(data["items"] || data[:items]),
|
53
|
+
max_items: data[:maxItems] || data["maxItems"],
|
54
|
+
min_items: data[:minItems] || data["minItems"],
|
55
|
+
description: data[:description] || data["description"]
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param items [OmniAI::Schema::Object, OmniAI::Schema::Array, OmniAI::Schema::Scalar] required
|
60
|
+
# @param min_items [Integer] optional
|
61
|
+
# @param max_items [Integer] optional
|
62
|
+
# @param description [String] optional
|
63
|
+
def initialize(items:, min_items: nil, max_items: nil, description: nil)
|
64
|
+
super()
|
65
|
+
@items = items
|
66
|
+
@min_items = min_items
|
67
|
+
@max_items = max_items
|
68
|
+
@description = description
|
69
|
+
end
|
70
|
+
|
71
|
+
# @example
|
72
|
+
# array.serialize # => { type: "array", items: { type: "string" } }
|
73
|
+
#
|
74
|
+
# @return [Hash]
|
75
|
+
def serialize
|
76
|
+
{
|
77
|
+
type: TYPE,
|
78
|
+
description: @description,
|
79
|
+
items: @items.serialize,
|
80
|
+
maxItems: @max_items,
|
81
|
+
minItems: @min_items,
|
82
|
+
}.compact
|
83
|
+
end
|
84
|
+
|
85
|
+
# @example
|
86
|
+
# array.parse(["1", "2", "3"]) # => [1, 2, 3]
|
87
|
+
#
|
88
|
+
# @param data [Array]
|
89
|
+
#
|
90
|
+
# @return [Array]
|
91
|
+
def parse(data)
|
92
|
+
data.map { |arg| @items.parse(arg) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
module Schema
|
5
|
+
# @example
|
6
|
+
# format = OmniAI::Schema::Format.deserialize({
|
7
|
+
# name: "example",
|
8
|
+
# schema: {
|
9
|
+
# type: "object",
|
10
|
+
# properties: {
|
11
|
+
# name: { type: "string" },
|
12
|
+
# },
|
13
|
+
# required: ["name"],
|
14
|
+
# }
|
15
|
+
# })
|
16
|
+
# format.serialize # => { name: "example", schema: { ... } }
|
17
|
+
class Format
|
18
|
+
# @!attribute [rw] name
|
19
|
+
# @return [String]
|
20
|
+
attr_accessor :name
|
21
|
+
|
22
|
+
# @!attribute [rw] schema
|
23
|
+
# @return [OmniAI::Schema::Object]
|
24
|
+
attr_accessor :schema
|
25
|
+
|
26
|
+
# @example
|
27
|
+
# array = OmniAI::Schema::Format.deserialize({
|
28
|
+
# name: "Contact",
|
29
|
+
# schema: { ... },
|
30
|
+
# }) # => OmniAI::Schema::Format
|
31
|
+
#
|
32
|
+
# @param data [Hash]
|
33
|
+
#
|
34
|
+
# @return [OmniAI::Schema::Format]
|
35
|
+
def self.deserialize(data)
|
36
|
+
name = data["name"] || data[:name]
|
37
|
+
schema = OmniAI::Schema.deserialize(data["schema"] || data[:schema])
|
38
|
+
|
39
|
+
new(name:, schema:)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param name [String]
|
43
|
+
# @param schema [OmniAI::Schema::Object]
|
44
|
+
def initialize(name:, schema:)
|
45
|
+
@name = name
|
46
|
+
@schema = schema
|
47
|
+
end
|
48
|
+
|
49
|
+
# @example
|
50
|
+
# format.serialize # => { name: "...", schema: { ... } }
|
51
|
+
#
|
52
|
+
# @return [Hash]
|
53
|
+
def serialize
|
54
|
+
{
|
55
|
+
name:,
|
56
|
+
schema: schema.serialize,
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
# @example
|
61
|
+
# format.parse("{ "name": "Ringo Starr" }"") # => { name: "Ringo Starr" }
|
62
|
+
#
|
63
|
+
# @param text [String]
|
64
|
+
#
|
65
|
+
# @return [Hash]
|
66
|
+
def parse(text)
|
67
|
+
schema.parse(JSON.parse(text))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
module Schema
|
5
|
+
# @example
|
6
|
+
# schema = OmniAI::Schema::Object.deserialize({
|
7
|
+
# type: "object",
|
8
|
+
# properties: {
|
9
|
+
# name: { type: "string" }
|
10
|
+
# },
|
11
|
+
# required: ["name"],
|
12
|
+
# })
|
13
|
+
# schema.serialize #=> { type: "object", properties: { ... }, required: %i[name] }
|
14
|
+
# schema.parse({ "name" => "John Doe" }) #=> { name: "John Doe" }
|
15
|
+
class Object
|
16
|
+
TYPE = "object"
|
17
|
+
|
18
|
+
# @!attribute [rw] properties
|
19
|
+
# @return [Hash]
|
20
|
+
attr_accessor :properties
|
21
|
+
|
22
|
+
# @!attribute [rw] required
|
23
|
+
# @return [Array<String>]
|
24
|
+
attr_accessor :required
|
25
|
+
|
26
|
+
# @!attribute [rw] title
|
27
|
+
# @return [String, nil]
|
28
|
+
attr_accessor :title
|
29
|
+
|
30
|
+
# @!attribute [rw] description
|
31
|
+
# @return [String, nil]
|
32
|
+
attr_accessor :description
|
33
|
+
|
34
|
+
# @example
|
35
|
+
# OmniAI::Schema::Object.deserialize({
|
36
|
+
# type: "object",
|
37
|
+
# properties: {
|
38
|
+
# name: { type: "string" }
|
39
|
+
# },
|
40
|
+
# required: ["name"],
|
41
|
+
# }) # => OmniAI::Schema::Object
|
42
|
+
#
|
43
|
+
# @param data [Hash]
|
44
|
+
#
|
45
|
+
# @return [OmniAI::Schema::Object]
|
46
|
+
def self.deserialize(data)
|
47
|
+
title = data["title"] || data[:title]
|
48
|
+
description = data["description"] || data[:description]
|
49
|
+
properties = (data["properties"] || data[:properties]).transform_values { |i| OmniAI::Schema.deserialize(i) }
|
50
|
+
required = data["required"] || data[:required] || []
|
51
|
+
|
52
|
+
new(title:, description:, properties:, required:)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param title [String] optional
|
56
|
+
# @param description [String] optional
|
57
|
+
# @param properties [Hash] optional
|
58
|
+
# @param required [Array<String>] optional
|
59
|
+
def initialize(title: nil, description: nil, properties: {}, required: [])
|
60
|
+
super()
|
61
|
+
@title = title
|
62
|
+
@description = description
|
63
|
+
@properties = properties
|
64
|
+
@required = required
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Hash]
|
68
|
+
def serialize
|
69
|
+
{
|
70
|
+
type: TYPE,
|
71
|
+
title: @title,
|
72
|
+
description: @description,
|
73
|
+
properties: @properties.transform_values(&:serialize),
|
74
|
+
required: @required,
|
75
|
+
}.compact
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param name [Symbol]
|
79
|
+
def property(name, ...)
|
80
|
+
@properties[name] = OmniAI::Schema::Scalar.build(...)
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param data [Hash]
|
84
|
+
#
|
85
|
+
# @return [Hash]
|
86
|
+
def parse(data)
|
87
|
+
result = {}
|
88
|
+
@properties.each do |name, property|
|
89
|
+
value = data[String(name)]
|
90
|
+
result[name.intern] = property.parse(value) unless value.nil?
|
91
|
+
end
|
92
|
+
result
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
module Schema
|
5
|
+
# @example
|
6
|
+
# scalar = OmniAI::Schema::Scalar.deserialize({ type: "string" })
|
7
|
+
# scalar.serialize #=> { type: "string" }
|
8
|
+
# scalar.parse("Hello World") #=> "Hello World"
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# scalar = OmniAI::Schema::Scalar.deserialize({ type: "integer" })
|
12
|
+
# scalar.serialize #=> { type: "integer" }
|
13
|
+
# scalar.parse("123") #=> 123
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# scalar = OmniAI::Schema::Scalar.deserialize({ type: "number" })
|
17
|
+
# scalar.serialize #=> { type: "number" }
|
18
|
+
# scalar.parse("123.45") #=> 123.45
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# scalar = OmniAI::Schema::Scalar.deserialize({ type: "boolean" })
|
22
|
+
# scalar.serialize #=> { type: "boolean" }
|
23
|
+
# scalar.parse(true) #=> true
|
24
|
+
# scalar.parse(false) #=> false
|
25
|
+
class Scalar
|
26
|
+
module Type
|
27
|
+
BOOLEAN = "boolean"
|
28
|
+
INTEGER = "integer"
|
29
|
+
STRING = "string"
|
30
|
+
NUMBER = "number"
|
31
|
+
end
|
32
|
+
|
33
|
+
# @!attribute [rw] type
|
34
|
+
# @return [String]
|
35
|
+
attr_accessor :type
|
36
|
+
|
37
|
+
# @!attribute [rw] description
|
38
|
+
# @return [String, nil]
|
39
|
+
attr_accessor :description
|
40
|
+
|
41
|
+
# @!attribute [rw] enum
|
42
|
+
# @return [Array<String>, nil]
|
43
|
+
attr_accessor :enum
|
44
|
+
|
45
|
+
# @example
|
46
|
+
# property = OmniAI::Schema::Scalar.deserialize({
|
47
|
+
# type: "string",
|
48
|
+
# description: "A predefined color.",
|
49
|
+
# enum: %w[red organge yellow green blue indigo violet],
|
50
|
+
# })
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# property = OmniAI::Schema::Scalar.deserialize({
|
54
|
+
# type: "integer",
|
55
|
+
# })
|
56
|
+
#
|
57
|
+
# @example
|
58
|
+
# property = OmniAI::Schema::Scalar.deserialize({
|
59
|
+
# type: "number",
|
60
|
+
# })
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
# property = OmniAI::Schema::Scalar.deserialize({
|
64
|
+
# type: "boolean",
|
65
|
+
# })
|
66
|
+
#
|
67
|
+
# @param data [Hash]
|
68
|
+
#
|
69
|
+
# @return [OmniAI::Schema::Scalar]
|
70
|
+
def self.deserialize(data)
|
71
|
+
type = data["type"] || data[:type] || Type::STRING
|
72
|
+
description = data["description"] || data[:description]
|
73
|
+
enum = data["enum"] || data[:enum]
|
74
|
+
|
75
|
+
new(type:, description:, enum:)
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param type [String] required - the type of the property
|
79
|
+
# @param description [String] optional - a description of the property
|
80
|
+
# @param enum [Array] optional - the possible values of the property
|
81
|
+
#
|
82
|
+
# @return [OmniAI::Schema::Scalar]
|
83
|
+
def initialize(type:, description: nil, enum: nil)
|
84
|
+
super()
|
85
|
+
@type = type
|
86
|
+
@description = description
|
87
|
+
@enum = enum
|
88
|
+
end
|
89
|
+
|
90
|
+
# @example
|
91
|
+
# property.serialize #=> { type: "string" }
|
92
|
+
#
|
93
|
+
# @return [Hash]
|
94
|
+
def serialize
|
95
|
+
{
|
96
|
+
type: @type,
|
97
|
+
description: @description,
|
98
|
+
enum: @enum,
|
99
|
+
}.compact
|
100
|
+
end
|
101
|
+
|
102
|
+
# @example
|
103
|
+
# property.parse("123") #=> 123
|
104
|
+
#
|
105
|
+
# @param value [String, Integer, Float, Boolean, Object]
|
106
|
+
#
|
107
|
+
# @return [String, Integer, Float, Boolean, Object]
|
108
|
+
def parse(value)
|
109
|
+
case @type
|
110
|
+
when Type::INTEGER then Integer(value)
|
111
|
+
when Type::STRING then String(value)
|
112
|
+
when Type::NUMBER then Float(value)
|
113
|
+
else value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
# @example
|
5
|
+
# format = OmniAI::Schema.format(name: "Contact", schema: OmniAI::Schema.object(
|
6
|
+
# description: "A contact with a name, relationship, and addresses.",
|
7
|
+
# properties: {
|
8
|
+
# name: OmniAI::Schema.string,
|
9
|
+
# relationship: OmniAI::Schema.string(enum: %w[friend family]),
|
10
|
+
# addresses: OmniAI::Schema.array(
|
11
|
+
# items: OmniAI::Schema.object(
|
12
|
+
# title: "Address",
|
13
|
+
# description: "An address with street, city, state, and zip code.",
|
14
|
+
# properties: {
|
15
|
+
# street: OmniAI::Schema.string,
|
16
|
+
# city: OmniAI::Schema.string,
|
17
|
+
# state: OmniAI::Schema.string,
|
18
|
+
# zip: OmniAI::Schema.string,
|
19
|
+
# },
|
20
|
+
# required: %i[street city state zip]
|
21
|
+
# )
|
22
|
+
# ),
|
23
|
+
# },
|
24
|
+
# required: %i[name]
|
25
|
+
# ))
|
26
|
+
module Schema
|
27
|
+
# @example
|
28
|
+
# OmniAI::Schema.deserialize({
|
29
|
+
# type: 'object',
|
30
|
+
# title: 'Person',
|
31
|
+
# properties: { name: { type: 'string' } },
|
32
|
+
# required: %i[name],
|
33
|
+
# }) # => OmniAI::Schema::Object
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# OmniAI::Schema.deserialize({
|
37
|
+
# type: 'array',
|
38
|
+
# items: { type: 'string' },
|
39
|
+
# }) # => OmniAI::Schema::Array
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# OmniAI::Schema.deserialize({
|
43
|
+
# type: 'string',
|
44
|
+
# description: '...',
|
45
|
+
# enum: ['...', ],
|
46
|
+
# }) # => OmniAI::Schema::Scalar
|
47
|
+
#
|
48
|
+
# @param data [OmniAI::Schema::Object, OmniAI::Schema::Array, OmniAI::Schema::Scalar]
|
49
|
+
def self.deserialize(data)
|
50
|
+
case data["type"] || data[:type]
|
51
|
+
when OmniAI::Schema::Array::TYPE then OmniAI::Schema::Array.deserialize(data)
|
52
|
+
when OmniAI::Schema::Object::TYPE then OmniAI::Schema::Object.deserialize(data)
|
53
|
+
else OmniAI::Schema::Scalar.deserialize(data)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param kind [Symbol]
|
58
|
+
#
|
59
|
+
# @return [OmniAI::Schema::Object, OmniAI::Schema::Array, OmniAI::Schema::Scalar]
|
60
|
+
def self.build(kind, **args)
|
61
|
+
case kind
|
62
|
+
when :array then array(**args)
|
63
|
+
when :object then object(**args)
|
64
|
+
when :boolean then boolean(**args)
|
65
|
+
when :integer then integer(**args)
|
66
|
+
when :number then number(**args)
|
67
|
+
when :string then string(**args)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# @example
|
72
|
+
# property = OmniAI::Schema.array(
|
73
|
+
# items: OmniAI::Schema.string(description: 'The name of the person.'),
|
74
|
+
# description: 'A list of names.'
|
75
|
+
# min_items: 1,
|
76
|
+
# max_items: 5,
|
77
|
+
# )
|
78
|
+
#
|
79
|
+
# @param items [OmniAI::Schema::Scalar] required - the items in the array
|
80
|
+
# @param min_items [Integer] optional - the minimum number of items
|
81
|
+
# @param max_items [Integer] optional - the maximum number of items
|
82
|
+
# @param description [String] optional - a description of the array
|
83
|
+
#
|
84
|
+
# @return [OmniAI::Schema::Array]
|
85
|
+
def self.array(items:, min_items: nil, max_items: nil, description: nil)
|
86
|
+
OmniAI::Schema::Array.new(items:, description:, min_items:, max_items:)
|
87
|
+
end
|
88
|
+
|
89
|
+
# @example
|
90
|
+
# property = OmniAI::Schema.object(
|
91
|
+
# properties: {
|
92
|
+
# name: OmniAI::Schema.string(description: 'The name of the person.'),
|
93
|
+
# age: OmniAI::Schema.integer(description: 'The age of the person.'),
|
94
|
+
# employed: OmniAI::Schema.boolean(description: 'Is the person employed?'),
|
95
|
+
# },
|
96
|
+
# description: 'A person.'
|
97
|
+
# required: %i[name]
|
98
|
+
# )
|
99
|
+
#
|
100
|
+
# @param title [String] optional - the title of the object
|
101
|
+
# @param properties [Hash<String, OmniAI::Schema::Scalar>] required - the properties of the object
|
102
|
+
# @param required [Array<Symbol>] optional - the required properties
|
103
|
+
# @param description [String] optional - a description of the object
|
104
|
+
#
|
105
|
+
# @return [OmniAI::Schema::Array]
|
106
|
+
def self.object(title: nil, properties: {}, required: [], description: nil)
|
107
|
+
OmniAI::Schema::Object.new(title:, properties:, required:, description:)
|
108
|
+
end
|
109
|
+
|
110
|
+
# @example
|
111
|
+
# OmniAI::Schema.boolean(description: "Is the person employed?") #=> OmniAI::Schema::Scalar
|
112
|
+
#
|
113
|
+
# @param description [String] optional - a description of the property
|
114
|
+
# @param enum [Array<Boolean>] optional - the possible values of the property
|
115
|
+
#
|
116
|
+
# @return [OmniAI::Schema::Scalar]
|
117
|
+
def self.boolean(description: nil, enum: nil)
|
118
|
+
OmniAI::Schema::Scalar.new(type: OmniAI::Schema::Scalar::Type::BOOLEAN, description:, enum:)
|
119
|
+
end
|
120
|
+
|
121
|
+
# @example
|
122
|
+
# OmniAI::Schema.integer(description: "The age of the person") #=> OmniAI::Schema::Scalar
|
123
|
+
#
|
124
|
+
# @param description [String] optional - a description of the property
|
125
|
+
# @param enum [Array<Integer>] optinoal - the possible values of the property
|
126
|
+
#
|
127
|
+
# @return [OmniAI::Schema::Scalar]
|
128
|
+
def self.integer(description: nil, enum: nil)
|
129
|
+
OmniAI::Schema::Scalar.new(type: OmniAI::Schema::Scalar::Type::INTEGER, description:, enum:)
|
130
|
+
end
|
131
|
+
|
132
|
+
# @example
|
133
|
+
# OmniAI::Schema.string(description: "The name of the person.") #=> OmniAI::Schema::Scalar
|
134
|
+
#
|
135
|
+
# @param description [String] optional - a description of the property
|
136
|
+
# @param enum [Array<String>] optional - the possible values of the property
|
137
|
+
#
|
138
|
+
# @return [OmniAI::Schema::Scalar]
|
139
|
+
def self.string(description: nil, enum: nil)
|
140
|
+
OmniAI::Schema::Scalar.new(type: OmniAI::Schema::Scalar::Type::STRING, description:, enum:)
|
141
|
+
end
|
142
|
+
|
143
|
+
# @example
|
144
|
+
# OmniAI::Schema.number(description: "The current temperature.") #=> OmniAI::Schema::Scalar
|
145
|
+
#
|
146
|
+
# @param description [String] optional - a description of the property
|
147
|
+
# @param enum [Array<Number>] optional - the possible values of the property
|
148
|
+
#
|
149
|
+
# @return [OmniAI::Schema::Scalar]
|
150
|
+
def self.number(description: nil, enum: nil)
|
151
|
+
OmniAI::Schema::Scalar.new(type: OmniAI::Schema::Scalar::Type::NUMBER, description:, enum:)
|
152
|
+
end
|
153
|
+
|
154
|
+
# @example
|
155
|
+
# OmniAI::Schema.format(name: "Contact", schema: OmniAI::Schema.object(...)) #=> OmniAI::Schema::Format
|
156
|
+
#
|
157
|
+
# @param name [String] required
|
158
|
+
# @param schema [OmniAI::Schema::Object] required
|
159
|
+
#
|
160
|
+
# @return [OmniAI::Schema::Format]
|
161
|
+
def self.format(name:, schema:)
|
162
|
+
OmniAI::Schema::Format.new(name:, schema:)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
data/lib/omniai/tool.rb
CHANGED
@@ -25,15 +25,15 @@ module OmniAI
|
|
25
25
|
@description = description
|
26
26
|
end
|
27
27
|
|
28
|
-
# @return [OmniAI::
|
28
|
+
# @return [OmniAI::Schema::Object]
|
29
29
|
def parameters
|
30
|
-
@parameters ||=
|
30
|
+
@parameters ||= OmniAI::Schema::Object.new
|
31
31
|
end
|
32
32
|
|
33
33
|
# @param name [Symbol]
|
34
34
|
# @param kind [Symbol]
|
35
35
|
def parameter(name, kind, **)
|
36
|
-
parameters.properties[name] =
|
36
|
+
parameters.properties[name] = OmniAI::Schema.build(kind, **)
|
37
37
|
end
|
38
38
|
|
39
39
|
# @param names [Array<Symbol>]
|
@@ -118,7 +118,7 @@ module OmniAI
|
|
118
118
|
function: {
|
119
119
|
name: @name,
|
120
120
|
description: @description,
|
121
|
-
parameters: @parameters.is_a?(
|
121
|
+
parameters: @parameters.is_a?(Schema::Object) ? @parameters.serialize : @parameters,
|
122
122
|
}.compact,
|
123
123
|
}
|
124
124
|
end
|
@@ -134,7 +134,7 @@ module OmniAI
|
|
134
134
|
# @param args [Hash]
|
135
135
|
# @return [String]
|
136
136
|
def call(args = {})
|
137
|
-
@function.call(**(@parameters.is_a?(
|
137
|
+
@function.call(**(@parameters.is_a?(Schema::Object) ? @parameters.parse(args) : args))
|
138
138
|
end
|
139
139
|
end
|
140
140
|
end
|
data/lib/omniai/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Sylvestre
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-05-08 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: event_stream_parser
|
@@ -119,13 +119,14 @@ files:
|
|
119
119
|
- lib/omniai/mcp/server.rb
|
120
120
|
- lib/omniai/mcp/transport/base.rb
|
121
121
|
- lib/omniai/mcp/transport/stdio.rb
|
122
|
+
- lib/omniai/schema.rb
|
123
|
+
- lib/omniai/schema/array.rb
|
124
|
+
- lib/omniai/schema/format.rb
|
125
|
+
- lib/omniai/schema/object.rb
|
126
|
+
- lib/omniai/schema/scalar.rb
|
122
127
|
- lib/omniai/speak.rb
|
123
128
|
- lib/omniai/ssl_error.rb
|
124
129
|
- lib/omniai/tool.rb
|
125
|
-
- lib/omniai/tool/array.rb
|
126
|
-
- lib/omniai/tool/object.rb
|
127
|
-
- lib/omniai/tool/parameters.rb
|
128
|
-
- lib/omniai/tool/property.rb
|
129
130
|
- lib/omniai/transcribe.rb
|
130
131
|
- lib/omniai/transcribe/transcription.rb
|
131
132
|
- lib/omniai/version.rb
|
data/lib/omniai/tool/array.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OmniAI
|
4
|
-
class Tool
|
5
|
-
# Represents a schema object.
|
6
|
-
#
|
7
|
-
# @example
|
8
|
-
# array = OmniAI::Tool::Array.new(
|
9
|
-
# description: 'A list of people.',
|
10
|
-
# items: OmniAI::Tool::Object.new(
|
11
|
-
# properties: {
|
12
|
-
# name: OmniAI::Tool::Property.string(description: 'The name of the person.'),
|
13
|
-
# age: OmniAI::Tool::Property.integer(description: 'The age of the person.'),
|
14
|
-
# },
|
15
|
-
# required: %i[name]
|
16
|
-
# ),
|
17
|
-
# min_items: 1,
|
18
|
-
# max_items: 5,
|
19
|
-
# })
|
20
|
-
class Array
|
21
|
-
TYPE = "array"
|
22
|
-
|
23
|
-
# @!attribute [rw] items
|
24
|
-
# @return [OmniAI::Tool::Object, OmniAI::Tool::Array, OmniAI::Tool::Property]
|
25
|
-
attr_accessor :items
|
26
|
-
|
27
|
-
# @!attribute [rw] max_items
|
28
|
-
# @return [Integer, nil]
|
29
|
-
attr_accessor :max_items
|
30
|
-
|
31
|
-
# @!attribute [rw] min_items
|
32
|
-
# @return [Integer, nil]
|
33
|
-
attr_accessor :min_items
|
34
|
-
|
35
|
-
# @!attribute [rw] description
|
36
|
-
# @return [String, nil]
|
37
|
-
attr_accessor :description
|
38
|
-
|
39
|
-
# @param items [OmniAI::Tool::Object, OmniAI::Tool::Array, OmniAI::Tool::Property] required
|
40
|
-
# @param max_items [Integer] optional
|
41
|
-
# @param min_items [Integer] optional
|
42
|
-
# @param description [String] optional
|
43
|
-
def initialize(items:, max_items: nil, min_items: nil, description: nil)
|
44
|
-
@items = items
|
45
|
-
@description = description
|
46
|
-
@max_items = max_items
|
47
|
-
@min_items = min_items
|
48
|
-
end
|
49
|
-
|
50
|
-
# @example
|
51
|
-
# array.serialize # => { type: 'array', items: { type: 'string' } }
|
52
|
-
#
|
53
|
-
# @return [Hash]
|
54
|
-
def serialize
|
55
|
-
{
|
56
|
-
type: TYPE,
|
57
|
-
description: @description,
|
58
|
-
items: @items.serialize,
|
59
|
-
maxItems: @max_items,
|
60
|
-
minItems: @min_items,
|
61
|
-
}.compact
|
62
|
-
end
|
63
|
-
|
64
|
-
# @example
|
65
|
-
# array.parse(['1', '2', '3']) # => [1, 2, 3]
|
66
|
-
# @param args [Array]
|
67
|
-
#
|
68
|
-
# @return [Array]
|
69
|
-
def parse(args)
|
70
|
-
args.map { |arg| @items.parse(arg) }
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
data/lib/omniai/tool/object.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OmniAI
|
4
|
-
class Tool
|
5
|
-
# Represents a schema object.
|
6
|
-
#
|
7
|
-
# @example
|
8
|
-
# object = OmniAI::Tool::Object.new(
|
9
|
-
# properties: {
|
10
|
-
# name: OmniAI::Tool::Property.string(description: 'The name of the person.'),
|
11
|
-
# age: OmniAI::Tool::Property.integer(description: 'The age of the person.'),
|
12
|
-
# },
|
13
|
-
# required: %i[name]
|
14
|
-
# })
|
15
|
-
class Object
|
16
|
-
TYPE = "object"
|
17
|
-
|
18
|
-
# @!attribute [rw] properties
|
19
|
-
# @return [Hash]
|
20
|
-
attr_accessor :properties
|
21
|
-
|
22
|
-
# @!attribute [rw] required
|
23
|
-
# @return [Array<String>]
|
24
|
-
attr_accessor :required
|
25
|
-
|
26
|
-
# @!attribute [rw] description
|
27
|
-
# @return [String, nil]
|
28
|
-
attr_accessor :description
|
29
|
-
|
30
|
-
# @param properties [Hash]
|
31
|
-
# @param required [Array<String>]
|
32
|
-
# @return [OmniAI::Tool::Parameters]
|
33
|
-
def initialize(properties: {}, required: [], description: nil)
|
34
|
-
@properties = properties
|
35
|
-
@required = required
|
36
|
-
@description = description
|
37
|
-
end
|
38
|
-
|
39
|
-
# @return [Hash]
|
40
|
-
def serialize
|
41
|
-
{
|
42
|
-
type: TYPE,
|
43
|
-
description: @description,
|
44
|
-
properties: @properties.transform_values(&:serialize),
|
45
|
-
required: @required,
|
46
|
-
}.compact
|
47
|
-
end
|
48
|
-
|
49
|
-
# @param args [Hash]
|
50
|
-
#
|
51
|
-
# @return [Hash]
|
52
|
-
def parse(args)
|
53
|
-
result = {}
|
54
|
-
@properties.each do |name, property|
|
55
|
-
value = args[String(name)]
|
56
|
-
result[name.intern] = property.parse(value) unless value.nil?
|
57
|
-
end
|
58
|
-
result
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OmniAI
|
4
|
-
class Tool
|
5
|
-
# Parameters are used to define the arguments for a tool.
|
6
|
-
#
|
7
|
-
# @example
|
8
|
-
# parameters = OmniAI::Tool::Parameters.new(properties: {
|
9
|
-
# people: OmniAI::Tool::Parameters.array(
|
10
|
-
# items: OmniAI::Tool::Parameters.object(
|
11
|
-
# properties: {
|
12
|
-
# name: OmniAI::Tool::Parameters.string(description: 'The name of the person.'),
|
13
|
-
# age: OmniAI::Tool::Parameters.integer(description: 'The age of the person.'),
|
14
|
-
# employed: OmniAI::Tool::Parameters.boolean(description: 'Is the person employed?'),
|
15
|
-
# }
|
16
|
-
# n: OmniAI::Tool::Parameters.integer(description: 'The nth number to calculate.')
|
17
|
-
# required: %i[n]
|
18
|
-
# })
|
19
|
-
# tool = OmniAI::Tool.new(fibonacci, parameters: parameters)
|
20
|
-
class Parameters < Object
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/lib/omniai/tool/property.rb
DELETED
@@ -1,151 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OmniAI
|
4
|
-
class Tool
|
5
|
-
# A property used for a tool parameter.
|
6
|
-
#
|
7
|
-
# @example
|
8
|
-
# OmniAI::Tool::Property.array(description: '...', items: ...)
|
9
|
-
# OmniAI::Tool::Property.object(description: '...', properties: { ... }, required: %i[...])
|
10
|
-
# OmniAI::Tool::Property.string(description: '...')
|
11
|
-
# OmniAI::Tool::Property.integer(description: '...')
|
12
|
-
# OmniAI::Tool::Property.number(description: '...')
|
13
|
-
# OmniAI::Tool::Property.boolean(description: '...')
|
14
|
-
class Property
|
15
|
-
module Type
|
16
|
-
BOOLEAN = "boolean"
|
17
|
-
INTEGER = "integer"
|
18
|
-
STRING = "string"
|
19
|
-
NUMBER = "number"
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [String]
|
23
|
-
attr_reader :type
|
24
|
-
|
25
|
-
# @return [String, nil]
|
26
|
-
attr_reader :description
|
27
|
-
|
28
|
-
# @return [Array<String>, nil]
|
29
|
-
attr_reader :enum
|
30
|
-
|
31
|
-
# @param kind [Symbol]
|
32
|
-
# @return [OmniAI::Tool::Property]
|
33
|
-
def self.build(kind, **args)
|
34
|
-
case kind
|
35
|
-
when :array then array(**args)
|
36
|
-
when :object then object(**args)
|
37
|
-
when :boolean then boolean(**args)
|
38
|
-
when :integer then integer(**args)
|
39
|
-
when :string then string(**args)
|
40
|
-
when :number then number(**args)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# @example
|
45
|
-
# property = OmniAI::Tool::Property.array(
|
46
|
-
# items: OmniAI::Tool::Property.string(description: 'The name of the person.'),
|
47
|
-
# description: 'A list of names.'
|
48
|
-
# min_items: 1,
|
49
|
-
# max_items: 5,
|
50
|
-
# )
|
51
|
-
#
|
52
|
-
# @param items [OmniAI::Tool::Property] required - the items in the array
|
53
|
-
# @param min_items [Integer] optional - the minimum number of items
|
54
|
-
# @param max_items [Integer] optional - the maximum number of items
|
55
|
-
# @param description [String] optional - a description of the array
|
56
|
-
#
|
57
|
-
# @return [OmniAI::Tool::Array]
|
58
|
-
def self.array(items:, min_items: nil, max_items: nil, description: nil)
|
59
|
-
OmniAI::Tool::Array.new(items:, description:, min_items:, max_items:)
|
60
|
-
end
|
61
|
-
|
62
|
-
# @example
|
63
|
-
# property = OmniAI::Tool::Property.object(
|
64
|
-
# properties: {
|
65
|
-
# name: OmniAI::Tool::Property.string(description: 'The name of the person.'),
|
66
|
-
# age: OmniAI::Tool::Property.integer(description: 'The age of the person.'),
|
67
|
-
# employed: OmniAI::Tool::Property.boolean(description: 'Is the person employed?'),
|
68
|
-
# },
|
69
|
-
# description: 'A person.'
|
70
|
-
# required: %i[name]
|
71
|
-
# )
|
72
|
-
#
|
73
|
-
# @param properties [Hash<String, OmniAI::Tool::Property>] required - the properties of the object
|
74
|
-
# @param required [Array<Symbol>] optional - the required properties
|
75
|
-
# @param description [String] optional - a description of the object
|
76
|
-
#
|
77
|
-
# @return [OmniAI::Tool::Array]
|
78
|
-
def self.object(properties: {}, required: [], description: nil)
|
79
|
-
OmniAI::Tool::Object.new(properties:, required:, description:)
|
80
|
-
end
|
81
|
-
|
82
|
-
# @param description [String] optional - a description of the property
|
83
|
-
# @param enum [Array<Boolean>] optional - the possible values of the property
|
84
|
-
#
|
85
|
-
# @return [OmniAI::Tool::Property]
|
86
|
-
def self.boolean(description: nil, enum: nil)
|
87
|
-
new(type: Type::BOOLEAN, description:, enum:)
|
88
|
-
end
|
89
|
-
|
90
|
-
# @param description [String] optional - a description of the property
|
91
|
-
# @param enum [Array<Integer>] optinoal - the possible values of the property
|
92
|
-
#
|
93
|
-
# @return [OmniAI::Tool::Property]
|
94
|
-
def self.integer(description: nil, enum: nil)
|
95
|
-
new(type: Type::INTEGER, description:, enum:)
|
96
|
-
end
|
97
|
-
|
98
|
-
# @param description [String] optional - a description of the property
|
99
|
-
# @param enum [Array<String>] optional - the possible values of the property
|
100
|
-
#
|
101
|
-
# @return [OmniAI::Tool::Property]
|
102
|
-
def self.string(description: nil, enum: nil)
|
103
|
-
new(type: Type::STRING, description:, enum:)
|
104
|
-
end
|
105
|
-
|
106
|
-
# @param description [String] optional - a description of the property
|
107
|
-
# @param enum [Array<Number>] optional - the possible values of the property
|
108
|
-
#
|
109
|
-
# @return [OmniAI::Tool::Property]
|
110
|
-
def self.number(description: nil, enum: nil)
|
111
|
-
new(type: Type::NUMBER, description:, enum:)
|
112
|
-
end
|
113
|
-
|
114
|
-
# @param type [String] required - the type of the property
|
115
|
-
# @param description [String] optional - a description of the property
|
116
|
-
# @param enum [Array] optional - the possible values of the property
|
117
|
-
#
|
118
|
-
# @return [OmniAI::Tool::Property]
|
119
|
-
def initialize(type:, description: nil, enum: nil)
|
120
|
-
@type = type
|
121
|
-
@description = description
|
122
|
-
@enum = enum
|
123
|
-
end
|
124
|
-
|
125
|
-
# @example
|
126
|
-
# property.serialize #=> { type: 'string' }
|
127
|
-
#
|
128
|
-
# @return [Hash]
|
129
|
-
def serialize
|
130
|
-
{
|
131
|
-
type: @type,
|
132
|
-
description: @description,
|
133
|
-
enum: @enum,
|
134
|
-
}.compact
|
135
|
-
end
|
136
|
-
|
137
|
-
# @example
|
138
|
-
# property.parse('123') #=> 123
|
139
|
-
#
|
140
|
-
# @return [String, Integer, Float, Boolean, Object]
|
141
|
-
def parse(value)
|
142
|
-
case @type
|
143
|
-
when Type::INTEGER then Integer(value)
|
144
|
-
when Type::STRING then String(value)
|
145
|
-
when Type::NUMBER then Float(value)
|
146
|
-
else value
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|