lluminary 0.1.2 → 0.1.3
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/lib/lluminary/config.rb +1 -6
- data/lib/lluminary/models/base.rb +235 -0
- data/lib/lluminary/models/bedrock/amazon_nova_pro_v1.rb +19 -0
- data/lib/lluminary/models/bedrock/anthropic_claude_instant_v1.rb +17 -0
- data/lib/lluminary/models/bedrock/base.rb +29 -0
- data/lib/lluminary/models/openai/gpt35_turbo.rb +20 -0
- data/lib/lluminary/providers/base.rb +15 -2
- data/lib/lluminary/providers/bedrock.rb +25 -7
- data/lib/lluminary/providers/openai.rb +14 -4
- data/lib/lluminary/providers/test.rb +6 -0
- data/lib/lluminary/schema.rb +51 -0
- data/lib/lluminary/schema_model.rb +54 -0
- data/lib/lluminary/task.rb +11 -77
- data/lib/lluminary.rb +4 -2
- data/spec/examples/meal_suggester_spec.rb +64 -0
- data/spec/lluminary/models/base_spec.rb +581 -0
- data/spec/lluminary/models/bedrock/amazon_nova_pro_v1_spec.rb +30 -0
- data/spec/lluminary/models/bedrock/anthropic_claude_instant_v1_spec.rb +21 -0
- data/spec/lluminary/models/openai/gpt35_turbo_spec.rb +22 -0
- data/spec/lluminary/providers/bedrock_spec.rb +39 -0
- data/spec/lluminary/providers/openai_spec.rb +32 -0
- data/spec/lluminary/providers/test_spec.rb +25 -0
- data/spec/lluminary/schema_model_spec.rb +77 -0
- data/spec/lluminary/schema_spec.rb +146 -0
- data/spec/lluminary/task_spec.rb +18 -550
- data/spec/spec_helper.rb +1 -0
- metadata +44 -9
- data/lib/lluminary/field_description.rb +0 -153
- data/spec/lluminary/field_description_spec.rb +0 -34
- data/spec/lluminary/providers/base_spec.rb +0 -20
@@ -11,6 +11,38 @@ RSpec.describe Lluminary::Providers::OpenAI do
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
describe "#models" do
|
15
|
+
let(:mock_models_response) do
|
16
|
+
{
|
17
|
+
"object" => "list",
|
18
|
+
"data" => [
|
19
|
+
{
|
20
|
+
"id" => "gpt-4",
|
21
|
+
"object" => "model",
|
22
|
+
"created" => 1_687_882_411,
|
23
|
+
"owned_by" => "openai"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"id" => "gpt-3.5-turbo",
|
27
|
+
"object" => "model",
|
28
|
+
"created" => 1_677_610_602,
|
29
|
+
"owned_by" => "openai"
|
30
|
+
}
|
31
|
+
]
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
before do
|
36
|
+
allow_any_instance_of(OpenAI::Client).to receive(:models).and_return(
|
37
|
+
double("ModelsClient", list: mock_models_response)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns an array of model IDs as strings" do
|
42
|
+
expect(provider.models).to eq(%w[gpt-4 gpt-3.5-turbo])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
14
46
|
describe "#call" do
|
15
47
|
let(:prompt) { "Test prompt" }
|
16
48
|
let(:task) { "Test task" }
|
@@ -10,6 +10,31 @@ RSpec.describe Lluminary::Providers::Test do
|
|
10
10
|
end
|
11
11
|
let(:task) { double("Task", class: task_class) }
|
12
12
|
|
13
|
+
describe "#initialize" do
|
14
|
+
it "accepts configuration options" do
|
15
|
+
config = { api_key: "test_key", model: "test_model" }
|
16
|
+
provider = described_class.new(**config)
|
17
|
+
expect(provider.config).to eq(config)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "merges default provider configuration with instance configuration" do
|
21
|
+
# Set up default provider configuration
|
22
|
+
Lluminary.configure do |config|
|
23
|
+
config.provider(:test, api_key: "global_key", model: "global_model")
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create provider with instance-specific config
|
27
|
+
provider = described_class.new(model: "instance_model", temperature: 0.7)
|
28
|
+
|
29
|
+
# Should merge default and instance config, with instance taking precedence
|
30
|
+
expect(provider.config).to eq(
|
31
|
+
api_key: "global_key",
|
32
|
+
model: "instance_model",
|
33
|
+
temperature: 0.7
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
13
38
|
describe "#call" do
|
14
39
|
it "returns a hash with raw and parsed response" do
|
15
40
|
response = provider.call(prompt, task)
|
@@ -91,5 +91,82 @@ RSpec.describe Lluminary::SchemaModel do
|
|
91
91
|
instance = model_class.new(name: "John", age: 30)
|
92
92
|
expect(instance.attributes).to eq({ "name" => "John", "age" => 30 })
|
93
93
|
end
|
94
|
+
|
95
|
+
it "validates array types" do
|
96
|
+
fields = {
|
97
|
+
items: {
|
98
|
+
type: :array,
|
99
|
+
element_type: {
|
100
|
+
type: :string,
|
101
|
+
description: nil
|
102
|
+
},
|
103
|
+
description: "A list of strings"
|
104
|
+
}
|
105
|
+
}
|
106
|
+
model_class = described_class.build(fields: fields, validations: [])
|
107
|
+
|
108
|
+
# Test that nil is allowed
|
109
|
+
instance = model_class.new(items: nil)
|
110
|
+
expect(instance.valid?).to be true
|
111
|
+
|
112
|
+
# Test valid array of strings
|
113
|
+
instance = model_class.new(items: %w[one two])
|
114
|
+
expect(instance.valid?).to be true
|
115
|
+
|
116
|
+
# Test invalid array (not an array)
|
117
|
+
instance = model_class.new(items: "not an array")
|
118
|
+
expect(instance.valid?).to be false
|
119
|
+
expect(instance.errors.full_messages).to include("Items must be an Array")
|
120
|
+
|
121
|
+
# Test invalid array elements
|
122
|
+
instance = model_class.new(items: ["one", 2, "three"])
|
123
|
+
expect(instance.valid?).to be false
|
124
|
+
expect(instance.errors.full_messages).to include(
|
125
|
+
"Items[1] must be a String"
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "validates nested array types" do
|
130
|
+
fields = {
|
131
|
+
matrix: {
|
132
|
+
type: :array,
|
133
|
+
element_type: {
|
134
|
+
type: :array,
|
135
|
+
element_type: {
|
136
|
+
type: :integer,
|
137
|
+
description: nil
|
138
|
+
},
|
139
|
+
description: nil
|
140
|
+
},
|
141
|
+
description: "A matrix of integers"
|
142
|
+
}
|
143
|
+
}
|
144
|
+
model_class = described_class.build(fields: fields, validations: [])
|
145
|
+
|
146
|
+
# Test valid nested arrays
|
147
|
+
instance = model_class.new(matrix: [[1, 2], [3, 4]])
|
148
|
+
expect(instance.valid?).to be true
|
149
|
+
|
150
|
+
# Test invalid outer array
|
151
|
+
instance = model_class.new(matrix: "not an array")
|
152
|
+
expect(instance.valid?).to be false
|
153
|
+
expect(instance.errors.full_messages).to include(
|
154
|
+
"Matrix must be an Array"
|
155
|
+
)
|
156
|
+
|
157
|
+
# Test invalid inner array
|
158
|
+
instance = model_class.new(matrix: ["not an array"])
|
159
|
+
expect(instance.valid?).to be false
|
160
|
+
expect(instance.errors.full_messages).to include(
|
161
|
+
"Matrix[0] must be an Array"
|
162
|
+
)
|
163
|
+
|
164
|
+
# Test invalid inner array elements
|
165
|
+
instance = model_class.new(matrix: [[1, "2"], [3, 4]])
|
166
|
+
expect(instance.valid?).to be false
|
167
|
+
expect(instance.errors.full_messages).to include(
|
168
|
+
"Matrix[0][1] must be an Integer"
|
169
|
+
)
|
170
|
+
end
|
94
171
|
end
|
95
172
|
end
|
@@ -96,6 +96,152 @@ RSpec.describe Lluminary::Schema do
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
describe "#array" do
|
100
|
+
it "adds an untyped array field to the schema" do
|
101
|
+
schema.array(:items)
|
102
|
+
expect(schema.fields).to eq({ items: { type: :array, description: nil } })
|
103
|
+
end
|
104
|
+
|
105
|
+
it "adds an untyped array field with description" do
|
106
|
+
schema.array(:items, description: "A list of items")
|
107
|
+
expect(schema.fields).to eq(
|
108
|
+
{ items: { type: :array, description: "A list of items" } }
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "requires a name for the array field" do
|
113
|
+
expect { schema.array }.to raise_error(ArgumentError)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "accepts array type without a name" do
|
117
|
+
schema.array(:items) { array { string } }
|
118
|
+
expect(schema.fields).to eq(
|
119
|
+
{
|
120
|
+
items: {
|
121
|
+
type: :array,
|
122
|
+
element_type: {
|
123
|
+
type: :array,
|
124
|
+
element_type: {
|
125
|
+
type: :string,
|
126
|
+
description: nil
|
127
|
+
},
|
128
|
+
description: nil
|
129
|
+
},
|
130
|
+
description: nil
|
131
|
+
}
|
132
|
+
}
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "accepts string type without a name" do
|
137
|
+
schema.array(:items) { string }
|
138
|
+
expect(schema.fields).to eq(
|
139
|
+
{
|
140
|
+
items: {
|
141
|
+
type: :array,
|
142
|
+
element_type: {
|
143
|
+
type: :string,
|
144
|
+
description: nil
|
145
|
+
},
|
146
|
+
description: nil
|
147
|
+
}
|
148
|
+
}
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "accepts integer type without a name" do
|
153
|
+
schema.array(:items) { integer }
|
154
|
+
expect(schema.fields).to eq(
|
155
|
+
{
|
156
|
+
items: {
|
157
|
+
type: :array,
|
158
|
+
element_type: {
|
159
|
+
type: :integer,
|
160
|
+
description: nil
|
161
|
+
},
|
162
|
+
description: nil
|
163
|
+
}
|
164
|
+
}
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "accepts boolean type without a name" do
|
169
|
+
schema.array(:items) { boolean }
|
170
|
+
expect(schema.fields).to eq(
|
171
|
+
{
|
172
|
+
items: {
|
173
|
+
type: :array,
|
174
|
+
element_type: {
|
175
|
+
type: :boolean,
|
176
|
+
description: nil
|
177
|
+
},
|
178
|
+
description: nil
|
179
|
+
}
|
180
|
+
}
|
181
|
+
)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "accepts float type without a name" do
|
185
|
+
schema.array(:items) { float }
|
186
|
+
expect(schema.fields).to eq(
|
187
|
+
{
|
188
|
+
items: {
|
189
|
+
type: :array,
|
190
|
+
element_type: {
|
191
|
+
type: :float,
|
192
|
+
description: nil
|
193
|
+
},
|
194
|
+
description: nil
|
195
|
+
}
|
196
|
+
}
|
197
|
+
)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "accepts datetime type without a name" do
|
201
|
+
schema.array(:items) { datetime }
|
202
|
+
expect(schema.fields).to eq(
|
203
|
+
{
|
204
|
+
items: {
|
205
|
+
type: :array,
|
206
|
+
element_type: {
|
207
|
+
type: :datetime,
|
208
|
+
description: nil
|
209
|
+
},
|
210
|
+
description: nil
|
211
|
+
}
|
212
|
+
}
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "validates array elements" do
|
217
|
+
schema.array(:numbers) { integer }
|
218
|
+
errors = schema.validate(numbers: [1, "2", 3])
|
219
|
+
expect(errors).to contain_exactly("Numbers[1] must be an Integer")
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe "primitive types" do
|
224
|
+
it "requires a name for string fields" do
|
225
|
+
expect { schema.string }.to raise_error(ArgumentError)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "requires a name for integer fields" do
|
229
|
+
expect { schema.integer }.to raise_error(ArgumentError)
|
230
|
+
end
|
231
|
+
|
232
|
+
it "requires a name for boolean fields" do
|
233
|
+
expect { schema.boolean }.to raise_error(ArgumentError)
|
234
|
+
end
|
235
|
+
|
236
|
+
it "requires a name for float fields" do
|
237
|
+
expect { schema.float }.to raise_error(ArgumentError)
|
238
|
+
end
|
239
|
+
|
240
|
+
it "requires a name for datetime fields" do
|
241
|
+
expect { schema.datetime }.to raise_error(ArgumentError)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
99
245
|
describe "#fields" do
|
100
246
|
it "returns the fields hash" do
|
101
247
|
schema.string(:name)
|