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
data/lib/lluminary/task.rb
CHANGED
@@ -1,20 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "ostruct"
|
3
|
+
require "json"
|
3
4
|
require_relative "schema"
|
4
5
|
require_relative "validation_error"
|
5
|
-
require_relative "
|
6
|
-
|
6
|
+
require_relative "models/base"
|
7
|
+
require_relative "models/openai/gpt35_turbo"
|
8
|
+
require_relative "models/bedrock/anthropic_claude_instant_v1"
|
7
9
|
|
8
10
|
module Lluminary
|
9
11
|
# Base class for all Lluminary tasks.
|
10
12
|
# Provides the core functionality for defining and running LLM-powered tasks.
|
11
|
-
#
|
12
|
-
# @example Creating a custom task
|
13
|
-
# class MyTask < Lluminary::Task
|
14
|
-
# def run
|
15
|
-
# # Task implementation
|
16
|
-
# end
|
17
|
-
# end
|
18
13
|
class Task
|
19
14
|
class << self
|
20
15
|
def input_schema(&block)
|
@@ -43,11 +38,7 @@ module Lluminary
|
|
43
38
|
raise ArgumentError, "Unknown provider: #{provider_name}"
|
44
39
|
end
|
45
40
|
|
46
|
-
|
47
|
-
global_config = Lluminary.config.provider_config(provider_name)
|
48
|
-
merged_config = global_config.merge(config)
|
49
|
-
|
50
|
-
@provider = provider_class.new(**merged_config)
|
41
|
+
@provider = provider_class.new(**config)
|
51
42
|
end
|
52
43
|
|
53
44
|
def call(input = {})
|
@@ -122,11 +113,11 @@ module Lluminary
|
|
122
113
|
end
|
123
114
|
|
124
115
|
def prompt
|
125
|
-
|
126
|
-
|
116
|
+
@prompt ||= self.class.provider.model.format_prompt(self)
|
117
|
+
end
|
127
118
|
|
128
|
-
|
129
|
-
|
119
|
+
def task_prompt
|
120
|
+
raise NotImplementedError, "Subclasses must implement task_prompt"
|
130
121
|
end
|
131
122
|
|
132
123
|
private
|
@@ -172,7 +163,7 @@ module Lluminary
|
|
172
163
|
# Validate after merging
|
173
164
|
@output.valid?
|
174
165
|
|
175
|
-
|
166
|
+
prompt
|
176
167
|
end
|
177
168
|
|
178
169
|
def define_input_methods
|
@@ -181,68 +172,11 @@ module Lluminary
|
|
181
172
|
end
|
182
173
|
end
|
183
174
|
|
184
|
-
def task_prompt
|
185
|
-
raise NotImplementedError, "Subclasses must implement task_prompt"
|
186
|
-
end
|
187
|
-
|
188
|
-
def json_schema_example
|
189
|
-
return "{}" if fields.empty?
|
190
|
-
|
191
|
-
<<~SCHEMA.chomp
|
192
|
-
You must respond with ONLY a valid JSON object. Do not include any other text, explanations, or formatting.
|
193
|
-
The JSON object must contain the following fields:
|
194
|
-
|
195
|
-
#{generate_field_descriptions}
|
196
|
-
|
197
|
-
Your response must be ONLY this JSON object:
|
198
|
-
#{example_json}
|
199
|
-
SCHEMA
|
200
|
-
end
|
201
|
-
|
202
|
-
def fields
|
203
|
-
@fields ||= self.class.output_fields
|
204
|
-
end
|
205
|
-
|
206
|
-
def generate_field_descriptions
|
207
|
-
fields
|
208
|
-
.map do |name, field|
|
209
|
-
# Get validations for this field
|
210
|
-
validations =
|
211
|
-
self
|
212
|
-
.class
|
213
|
-
.instance_variable_get(:@output_schema)
|
214
|
-
&.validations_for(name) || []
|
215
|
-
field_with_validations = field.merge(validations: validations)
|
216
|
-
FieldDescription.new(name, field_with_validations).to_schema_s
|
217
|
-
end
|
218
|
-
.join("\n\n")
|
219
|
-
end
|
220
|
-
|
221
|
-
def example_json
|
222
|
-
json =
|
223
|
-
fields.each_with_object({}) do |(name, field), hash|
|
224
|
-
hash[name] = case field[:type]
|
225
|
-
when :string
|
226
|
-
"your #{name} here"
|
227
|
-
when :integer
|
228
|
-
0
|
229
|
-
when :datetime
|
230
|
-
"2024-01-01T12:00:00+00:00"
|
231
|
-
when :boolean
|
232
|
-
true
|
233
|
-
when :float
|
234
|
-
0.0
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
JSON.pretty_generate(json)
|
239
|
-
end
|
240
|
-
|
241
175
|
def to_result
|
242
176
|
Result.new(
|
243
177
|
raw_response: @output&.raw_response,
|
244
178
|
output: @parsed_response,
|
245
|
-
prompt:
|
179
|
+
prompt: prompt
|
246
180
|
)
|
247
181
|
end
|
248
182
|
end
|
data/lib/lluminary.rb
CHANGED
@@ -3,8 +3,10 @@
|
|
3
3
|
require_relative "lluminary/version"
|
4
4
|
require_relative "lluminary/result"
|
5
5
|
require_relative "lluminary/task"
|
6
|
-
|
7
|
-
|
6
|
+
# automatically require all providers
|
7
|
+
Dir[File.join(__dir__, "lluminary/providers/*.rb")].each { |file| require file }
|
8
|
+
# automatically require all models
|
9
|
+
Dir[File.join(__dir__, "lluminary/models/**/*.rb")].each { |file| require file }
|
8
10
|
require_relative "lluminary/config"
|
9
11
|
|
10
12
|
# Lluminary is a framework for building and running LLM-powered tasks.
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
require_relative "../../examples/meal_suggester"
|
4
|
+
|
5
|
+
RSpec.describe MealSuggester do
|
6
|
+
let(:valid_ingredients) { %w[eggs bread butter] }
|
7
|
+
let(:valid_count) { 3 }
|
8
|
+
let(:valid_params) do
|
9
|
+
{ ingredients: valid_ingredients, suggestions_count: valid_count }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "input validation" do
|
13
|
+
it "accepts valid parameters" do
|
14
|
+
expect { described_class.call!(**valid_params) }.not_to raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it "requires ingredients to be present" do
|
18
|
+
expect do
|
19
|
+
described_class.call!(ingredients: [], suggestions_count: valid_count)
|
20
|
+
end.to raise_error(Lluminary::ValidationError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "requires suggestions_count to be present" do
|
24
|
+
expect do
|
25
|
+
described_class.call!(
|
26
|
+
ingredients: valid_ingredients,
|
27
|
+
suggestions_count: nil
|
28
|
+
)
|
29
|
+
end.to raise_error(Lluminary::ValidationError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "output validation" do
|
34
|
+
let(:result) { described_class.call(**valid_params) }
|
35
|
+
|
36
|
+
it "returns an array of meal suggestions" do
|
37
|
+
expect(result.output.meal_suggestions).to be_an(Array)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns the requested number of suggestions" do
|
41
|
+
expect(result.output.meal_suggestions.length).to eq(valid_count)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns string suggestions" do
|
45
|
+
expect(result.output.meal_suggestions).to all(be_a(String))
|
46
|
+
end
|
47
|
+
|
48
|
+
it "returns non-empty suggestions" do
|
49
|
+
expect(result.output.meal_suggestions).to all(be_present)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "prompt generation" do
|
54
|
+
let(:result) { described_class.call(**valid_params) }
|
55
|
+
|
56
|
+
it "includes the ingredients in the prompt" do
|
57
|
+
expect(result.prompt).to include(valid_ingredients.inspect)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "includes the suggestions count in the prompt" do
|
61
|
+
expect(result.prompt).to include(valid_count.to_s)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|