roast-ai 0.1.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 +7 -0
- data/.claude/settings.json +12 -0
- data/.github/workflows/ci.yaml +29 -0
- data/.github/workflows/cla.yml +22 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.rubocop.yml +12 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +0 -0
- data/CLAUDE.md +31 -0
- data/CODE_OF_CONDUCT.md +133 -0
- data/CONTRIBUTING.md +35 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +194 -0
- data/LICENSE.md +21 -0
- data/README.md +27 -0
- data/Rakefile +24 -0
- data/bin/console +11 -0
- data/examples/grading/analyze_coverage/prompt.md +52 -0
- data/examples/grading/calculate_final_grade.rb +67 -0
- data/examples/grading/format_result.rb +48 -0
- data/examples/grading/generate_grades/prompt.md +105 -0
- data/examples/grading/generate_recommendations/output.txt +17 -0
- data/examples/grading/generate_recommendations/prompt.md +60 -0
- data/examples/grading/run_coverage.rb +47 -0
- data/examples/grading/verify_mocks_and_stubs/prompt.md +12 -0
- data/examples/grading/verify_test_helpers/prompt.md +53 -0
- data/examples/grading/workflow.md +8 -0
- data/examples/grading/workflow.rb.md +6 -0
- data/examples/grading/workflow.ts+tsx.md +6 -0
- data/examples/grading/workflow.yml +46 -0
- data/exe/roast +17 -0
- data/lib/roast/helpers/function_caching_interceptor.rb +27 -0
- data/lib/roast/helpers/logger.rb +104 -0
- data/lib/roast/helpers/minitest_coverage_runner.rb +244 -0
- data/lib/roast/helpers/path_resolver.rb +148 -0
- data/lib/roast/helpers/prompt_loader.rb +97 -0
- data/lib/roast/helpers.rb +12 -0
- data/lib/roast/tools/cmd.rb +72 -0
- data/lib/roast/tools/grep.rb +43 -0
- data/lib/roast/tools/read_file.rb +49 -0
- data/lib/roast/tools/search_file.rb +51 -0
- data/lib/roast/tools/write_file.rb +60 -0
- data/lib/roast/tools.rb +50 -0
- data/lib/roast/version.rb +5 -0
- data/lib/roast/workflow/base_step.rb +94 -0
- data/lib/roast/workflow/base_workflow.rb +79 -0
- data/lib/roast/workflow/configuration.rb +117 -0
- data/lib/roast/workflow/configuration_parser.rb +92 -0
- data/lib/roast/workflow/validator.rb +37 -0
- data/lib/roast/workflow/workflow_executor.rb +119 -0
- data/lib/roast/workflow.rb +13 -0
- data/lib/roast.rb +40 -0
- data/roast.gemspec +44 -0
- data/schema/workflow.json +92 -0
- data/shipit.rubygems.yml +0 -0
- metadata +171 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Roast
|
4
|
+
module Workflow
|
5
|
+
# Handles the execution of workflow steps, including orchestration and threading
|
6
|
+
class WorkflowExecutor
|
7
|
+
DEFAULT_MODEL = "anthropic:claude-3-7-sonnet"
|
8
|
+
|
9
|
+
attr_reader :workflow, :config_hash, :context_path
|
10
|
+
|
11
|
+
def initialize(workflow, config_hash, context_path)
|
12
|
+
@workflow = workflow
|
13
|
+
@config_hash = config_hash
|
14
|
+
@context_path = context_path
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_steps(steps)
|
18
|
+
steps.each do |step|
|
19
|
+
case step
|
20
|
+
when Hash
|
21
|
+
execute_hash_step(step)
|
22
|
+
when Array
|
23
|
+
execute_parallel_steps(step)
|
24
|
+
when String
|
25
|
+
execute_string_step(step)
|
26
|
+
else
|
27
|
+
raise "Unknown step type: #{step.inspect}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute_step(name)
|
33
|
+
$stderr.puts "Executing: #{name}"
|
34
|
+
return strip_and_execute(name) if name.starts_with?("%") || name.starts_with?("$(")
|
35
|
+
|
36
|
+
return glob(name) if name.include?("*")
|
37
|
+
|
38
|
+
step_object = find_and_load_step(name)
|
39
|
+
result = step_object.call
|
40
|
+
|
41
|
+
workflow.output[name] = result
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def execute_hash_step(step)
|
48
|
+
# execute a command and store the output in a variable
|
49
|
+
name, command = step.to_a.flatten
|
50
|
+
if command.is_a?(Hash)
|
51
|
+
execute_steps([command])
|
52
|
+
else
|
53
|
+
workflow.output[name] = execute_step(command)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute_parallel_steps(steps)
|
58
|
+
# run steps in parallel, don't proceed until all are done
|
59
|
+
steps.map do |sub_step|
|
60
|
+
Thread.new { execute_steps([sub_step]) }
|
61
|
+
end.each(&:join)
|
62
|
+
end
|
63
|
+
|
64
|
+
def execute_string_step(step)
|
65
|
+
execute_step(step)
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_and_load_step(step_name)
|
69
|
+
# First check for a ruby file with the step name
|
70
|
+
rb_file_path = File.join(context_path, "#{step_name}.rb")
|
71
|
+
if File.file?(rb_file_path)
|
72
|
+
return load_ruby_step(rb_file_path, step_name)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check in shared directory for ruby file
|
76
|
+
shared_rb_path = File.expand_path(File.join(context_path, "..", "shared", "#{step_name}.rb"))
|
77
|
+
if File.file?(shared_rb_path)
|
78
|
+
return load_ruby_step(shared_rb_path, step_name, File.dirname(shared_rb_path))
|
79
|
+
end
|
80
|
+
|
81
|
+
# Continue with existing directory check logic
|
82
|
+
step_path = File.join(context_path, step_name)
|
83
|
+
step_path = File.expand_path(File.join(context_path, "..", "shared", step_name)) unless File.directory?(step_path)
|
84
|
+
raise "Step directory or file not found: #{step_path}" unless File.directory?(step_path)
|
85
|
+
|
86
|
+
setup_step(Roast::Workflow::BaseStep, step_name, step_path)
|
87
|
+
end
|
88
|
+
|
89
|
+
def glob(name)
|
90
|
+
Dir.glob(name).join("\n")
|
91
|
+
end
|
92
|
+
|
93
|
+
def load_ruby_step(file_path, step_name, context_path = File.dirname(file_path))
|
94
|
+
$stderr.puts "Requiring step file: #{file_path}"
|
95
|
+
require file_path
|
96
|
+
step_class = step_name.classify.constantize
|
97
|
+
setup_step(step_class, step_name, context_path)
|
98
|
+
end
|
99
|
+
|
100
|
+
def setup_step(step_class, step_name, context_path)
|
101
|
+
step_class.new(workflow, name: step_name, context_path: context_path).tap do |step|
|
102
|
+
step_config = config_hash[step_name]
|
103
|
+
if step_config.present?
|
104
|
+
step.model = step_config["model"] || DEFAULT_MODEL
|
105
|
+
step.print_response = step_config["print_response"] if step_config["print_response"].present?
|
106
|
+
step.loop = step_config["loop"] if step_config["loop"].present?
|
107
|
+
step.json = step_config["json"] if step_config["json"].present?
|
108
|
+
step.params = step_config["params"] if step_config["params"].present?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def strip_and_execute(step)
|
114
|
+
command = step.gsub("%", "")
|
115
|
+
%x(#{command})
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "roast/workflow/base_step"
|
4
|
+
require "roast/workflow/base_workflow"
|
5
|
+
require "roast/workflow/configuration"
|
6
|
+
require "roast/workflow/workflow_executor"
|
7
|
+
require "roast/workflow/configuration_parser"
|
8
|
+
require "roast/workflow/validator"
|
9
|
+
|
10
|
+
module Roast
|
11
|
+
module Workflow
|
12
|
+
end
|
13
|
+
end
|
data/lib/roast.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "raix"
|
4
|
+
require "thor"
|
5
|
+
require "roast/version"
|
6
|
+
require "roast/tools"
|
7
|
+
require "roast/helpers"
|
8
|
+
require "roast/workflow"
|
9
|
+
|
10
|
+
module Roast
|
11
|
+
ROOT = File.expand_path("../..", __FILE__)
|
12
|
+
|
13
|
+
class CLI < Thor
|
14
|
+
desc "execute [WORKFLOW_CONFIGURATION_FILE] [FILES...]", "Run a configured workflow"
|
15
|
+
option :concise, type: :boolean, aliases: "-c", desc: "Optional flag for use in output templates"
|
16
|
+
option :output, type: :string, aliases: "-o", desc: "Save results to a file"
|
17
|
+
option :verbose, type: :boolean, aliases: "-v", desc: "Show output from all steps as they are executed"
|
18
|
+
option :target, type: :string, aliases: "-t", desc: "Override target files. Can be file path, glob pattern, or $(shell command)"
|
19
|
+
option :subject, type: :string, aliases: "-s", desc: "Subject file to analyze"
|
20
|
+
def execute(*paths)
|
21
|
+
raise Thor::Error, "Workflow configuration file is required" if paths.empty?
|
22
|
+
|
23
|
+
workflow_path, *files = paths
|
24
|
+
expanded_workflow_path = File.expand_path(workflow_path)
|
25
|
+
raise Thor::Error, "Expected a Roast workflow configuration file, got directory: #{expanded_workflow_path}" if File.directory?(expanded_workflow_path)
|
26
|
+
|
27
|
+
if options[:subject] && !File.exist?(options[:subject])
|
28
|
+
raise Thor::Error, "Subject file does not exist: #{options[:subject]}"
|
29
|
+
end
|
30
|
+
|
31
|
+
Roast::Workflow::ConfigurationParser.new(expanded_workflow_path, files, options.transform_keys(&:to_sym)).begin!
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
def exit_on_failure?
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/roast.gemspec
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "roast/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "roast-ai"
|
9
|
+
spec.version = Roast::VERSION
|
10
|
+
spec.authors = ["Shopify"]
|
11
|
+
spec.email = ["opensource@shopify.com"]
|
12
|
+
|
13
|
+
spec.summary = "A framework for executing structured AI workflows in Ruby"
|
14
|
+
spec.description = "Roast is a Ruby library for running structured AI workflows along with many building blocks for creating and executing them"
|
15
|
+
spec.homepage = "https://github.com/Shopify/roast"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
22
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
23
|
+
spec.metadata["source_code_uri"] = "https://github.com/Shopify/roast"
|
24
|
+
spec.metadata["changelog_uri"] = "https://github.com/Shopify/roast/blob/main/CHANGELOG.md"
|
25
|
+
else
|
26
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
27
|
+
"public gem pushes."
|
28
|
+
end
|
29
|
+
|
30
|
+
# Specify which files should be added to the gem when it is released.
|
31
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
32
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
33
|
+
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
34
|
+
end
|
35
|
+
spec.bindir = "exe"
|
36
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
37
|
+
spec.require_paths = ["lib"]
|
38
|
+
|
39
|
+
spec.add_dependency("activesupport", "~> 8.0")
|
40
|
+
spec.add_dependency("faraday-retry")
|
41
|
+
spec.add_dependency("json-schema")
|
42
|
+
spec.add_dependency("raix", "0.8.3")
|
43
|
+
spec.add_dependency("thor", "~> 1.3")
|
44
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
{
|
2
|
+
"type": "object",
|
3
|
+
"required": ["name", "tools", "steps"],
|
4
|
+
"properties": {
|
5
|
+
"name": {
|
6
|
+
"type": "string"
|
7
|
+
},
|
8
|
+
"tools": {
|
9
|
+
"type": "array",
|
10
|
+
"items": {
|
11
|
+
"type": "string"
|
12
|
+
}
|
13
|
+
},
|
14
|
+
"inputs": {
|
15
|
+
"type": "array",
|
16
|
+
"items": {
|
17
|
+
"oneOf": [
|
18
|
+
{
|
19
|
+
"type": "string"
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"type": "object",
|
23
|
+
"additionalProperties": {
|
24
|
+
"type": "string"
|
25
|
+
},
|
26
|
+
"minProperties": 1,
|
27
|
+
"maxProperties": 1
|
28
|
+
}
|
29
|
+
]
|
30
|
+
}
|
31
|
+
},
|
32
|
+
"steps": {
|
33
|
+
"type": "array",
|
34
|
+
"items": {
|
35
|
+
"oneOf": [
|
36
|
+
{
|
37
|
+
"type": "string"
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"type": "array",
|
41
|
+
"items": {
|
42
|
+
"oneOf": [
|
43
|
+
{
|
44
|
+
"type": "string"
|
45
|
+
},
|
46
|
+
{
|
47
|
+
"type": "object",
|
48
|
+
"properties": {
|
49
|
+
"steps": {
|
50
|
+
"type": "array",
|
51
|
+
"items": {
|
52
|
+
"type": "string"
|
53
|
+
}
|
54
|
+
}
|
55
|
+
},
|
56
|
+
"required": ["steps"]
|
57
|
+
}
|
58
|
+
]
|
59
|
+
}
|
60
|
+
},
|
61
|
+
{
|
62
|
+
"type": "object",
|
63
|
+
"properties": {
|
64
|
+
"proceed?": {
|
65
|
+
"type": "object",
|
66
|
+
"properties": {
|
67
|
+
"true": {
|
68
|
+
"$ref": "#/properties/steps"
|
69
|
+
},
|
70
|
+
"false": {
|
71
|
+
"$ref": "#/properties/steps"
|
72
|
+
}
|
73
|
+
},
|
74
|
+
"required": ["true", "false"]
|
75
|
+
}
|
76
|
+
},
|
77
|
+
"required": ["proceed?"]
|
78
|
+
}
|
79
|
+
]
|
80
|
+
}
|
81
|
+
},
|
82
|
+
"proceed?": {
|
83
|
+
"type": "object",
|
84
|
+
"properties": {
|
85
|
+
"label": {
|
86
|
+
"type": "string"
|
87
|
+
}
|
88
|
+
},
|
89
|
+
"required": ["label"]
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
data/shipit.rubygems.yml
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roast-ai
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shopify
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: activesupport
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '8.0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '8.0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: faraday-retry
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: json-schema
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: raix
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - '='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.8.3
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.8.3
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: thor
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.3'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '1.3'
|
82
|
+
description: Roast is a Ruby library for running structured AI workflows along with
|
83
|
+
many building blocks for creating and executing them
|
84
|
+
email:
|
85
|
+
- opensource@shopify.com
|
86
|
+
executables:
|
87
|
+
- roast
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".claude/settings.json"
|
92
|
+
- ".github/workflows/ci.yaml"
|
93
|
+
- ".github/workflows/cla.yml"
|
94
|
+
- ".gitignore"
|
95
|
+
- ".rspec"
|
96
|
+
- ".rubocop.yml"
|
97
|
+
- ".ruby-version"
|
98
|
+
- CHANGELOG.md
|
99
|
+
- CLAUDE.md
|
100
|
+
- CODE_OF_CONDUCT.md
|
101
|
+
- CONTRIBUTING.md
|
102
|
+
- Gemfile
|
103
|
+
- Gemfile.lock
|
104
|
+
- LICENSE.md
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/console
|
108
|
+
- examples/grading/analyze_coverage/prompt.md
|
109
|
+
- examples/grading/calculate_final_grade.rb
|
110
|
+
- examples/grading/format_result.rb
|
111
|
+
- examples/grading/generate_grades/prompt.md
|
112
|
+
- examples/grading/generate_recommendations/output.txt
|
113
|
+
- examples/grading/generate_recommendations/prompt.md
|
114
|
+
- examples/grading/run_coverage.rb
|
115
|
+
- examples/grading/verify_mocks_and_stubs/prompt.md
|
116
|
+
- examples/grading/verify_test_helpers/prompt.md
|
117
|
+
- examples/grading/workflow.md
|
118
|
+
- examples/grading/workflow.rb.md
|
119
|
+
- examples/grading/workflow.ts+tsx.md
|
120
|
+
- examples/grading/workflow.yml
|
121
|
+
- exe/roast
|
122
|
+
- lib/roast.rb
|
123
|
+
- lib/roast/helpers.rb
|
124
|
+
- lib/roast/helpers/function_caching_interceptor.rb
|
125
|
+
- lib/roast/helpers/logger.rb
|
126
|
+
- lib/roast/helpers/minitest_coverage_runner.rb
|
127
|
+
- lib/roast/helpers/path_resolver.rb
|
128
|
+
- lib/roast/helpers/prompt_loader.rb
|
129
|
+
- lib/roast/tools.rb
|
130
|
+
- lib/roast/tools/cmd.rb
|
131
|
+
- lib/roast/tools/grep.rb
|
132
|
+
- lib/roast/tools/read_file.rb
|
133
|
+
- lib/roast/tools/search_file.rb
|
134
|
+
- lib/roast/tools/write_file.rb
|
135
|
+
- lib/roast/version.rb
|
136
|
+
- lib/roast/workflow.rb
|
137
|
+
- lib/roast/workflow/base_step.rb
|
138
|
+
- lib/roast/workflow/base_workflow.rb
|
139
|
+
- lib/roast/workflow/configuration.rb
|
140
|
+
- lib/roast/workflow/configuration_parser.rb
|
141
|
+
- lib/roast/workflow/validator.rb
|
142
|
+
- lib/roast/workflow/workflow_executor.rb
|
143
|
+
- roast.gemspec
|
144
|
+
- schema/workflow.json
|
145
|
+
- shipit.rubygems.yml
|
146
|
+
homepage: https://github.com/Shopify/roast
|
147
|
+
licenses:
|
148
|
+
- MIT
|
149
|
+
metadata:
|
150
|
+
allowed_push_host: https://rubygems.org
|
151
|
+
homepage_uri: https://github.com/Shopify/roast
|
152
|
+
source_code_uri: https://github.com/Shopify/roast
|
153
|
+
changelog_uri: https://github.com/Shopify/roast/blob/main/CHANGELOG.md
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
requirements: []
|
168
|
+
rubygems_version: 3.6.8
|
169
|
+
specification_version: 4
|
170
|
+
summary: A framework for executing structured AI workflows in Ruby
|
171
|
+
test_files: []
|