sublayer 0.2.2 → 0.2.4

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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sublayer +5 -0
  3. data/lib/sublayer/cli.rb +191 -0
  4. data/lib/sublayer/components/output_adapters/formattable.rb +31 -12
  5. data/lib/sublayer/components/output_adapters/list_of_named_strings.rb +48 -0
  6. data/lib/sublayer/components/output_adapters/named_strings.rb +33 -0
  7. data/lib/sublayer/generators/base.rb +4 -1
  8. data/lib/sublayer/templates/cli/.gitignore +14 -0
  9. data/lib/sublayer/templates/cli/Gemfile +7 -0
  10. data/lib/sublayer/templates/cli/PROJECT_NAME.gemspec +35 -0
  11. data/lib/sublayer/templates/cli/README.md +22 -0
  12. data/lib/sublayer/templates/cli/bin/PROJECT_NAME +5 -0
  13. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/actions/example_action.rb +15 -0
  14. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/agents/example_agent.rb +21 -0
  15. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/cli.rb +13 -0
  16. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/commands/base_command.rb +21 -0
  17. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/commands/example_command.rb +13 -0
  18. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/config/.keep +0 -0
  19. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/config.rb +19 -0
  20. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/generators/example_generator.rb +25 -0
  21. data/lib/sublayer/templates/cli/lib/PROJECT_NAME/version.rb +5 -0
  22. data/lib/sublayer/templates/cli/lib/project_name.rb +21 -0
  23. data/lib/sublayer/templates/cli/spec/.keep +0 -0
  24. data/lib/sublayer/templates/quick_script/README.md +16 -0
  25. data/lib/sublayer/templates/quick_script/actions/example_action.rb +11 -0
  26. data/lib/sublayer/templates/quick_script/agents/example_agent.rb +17 -0
  27. data/lib/sublayer/templates/quick_script/generators/example_generator.rb +21 -0
  28. data/lib/sublayer/templates/quick_script/project_name.rb +7 -0
  29. data/lib/sublayer/version.rb +1 -1
  30. data/lib/sublayer.rb +1 -0
  31. data/sublayer.gemspec +7 -0
  32. metadata +99 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a5a558f063c63cab9aca167a16ae3ac31300614e1a042097c544cc6361e3775
4
- data.tar.gz: 59eb567e5ccecc071e204685fbe81f8b10fee384dadd4a04ba96275b38e9235f
3
+ metadata.gz: 2238a9858f994058b23edf70f97255d6c3b20d648c7e73991c05eb7232a9ec6b
4
+ data.tar.gz: 935f154d71e8dab6ee3906f700d1f42092f33b9e15ce07c3b305817bcca8177e
5
5
  SHA512:
6
- metadata.gz: a0006db5e1aaacc819cc883ac16094d66c9e99b17b3069c19f5d43af59803ab8e032f07c900a7225b66a3ae91c14f49229742240676a74e9ce0548e5b423daeb
7
- data.tar.gz: 3072682126490797db51ba03dde2c8accaccb869f7c861338cb5a1019152701079709d26340096cc1685318119716683842ca2b15d9d37833746835dfa89b34b
6
+ metadata.gz: ae8d296c701a18a7e4dde9366f05e4ecf8a5afc964cdc336a563201049660d92345f92219bd1537517bc961e6baf74bab4b9f4652d79666cdf2041e510be2451
7
+ data.tar.gz: af8c3a33325de5e2354cc82edd73212f91e5f24bf8c70ae2fac31b58d480ea1c08c76e938e60be714a5f67871940d497b21611daf1e576d6333bb52772e1e4cd
data/bin/sublayer ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "sublayer/cli"
4
+
5
+ Sublayer::CLI.start(ARGV)
@@ -0,0 +1,191 @@
1
+ require "tty-prompt"
2
+ require "tty-progressbar"
3
+ require "tty-command"
4
+ require "tty-file"
5
+ require "fileutils"
6
+ require "yaml"
7
+ require "sublayer/version"
8
+
9
+ module Sublayer
10
+ class CLI
11
+ PLACEHOLDERS = {
12
+ "PROJECT_NAME" => { gsub: true, camelcase: false },
13
+ "ProjectName" => { gsub: true, camelcase: true },
14
+ "project_name" => { gsub: true, camelcase: false, underscore: true }
15
+ }
16
+
17
+ def self.start(args)
18
+ new.run(args)
19
+ end
20
+
21
+ def run(args)
22
+ command = args.shift
23
+
24
+ case command
25
+ when "new"
26
+ create_new_project(args.first)
27
+ when "help", nil
28
+ display_help
29
+ else
30
+ puts "Unknown command: #{command}"
31
+ display_help
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def create_new_project(project_name)
38
+ prompt = TTY::Prompt.new
39
+
40
+ project_name ||= prompt.ask("What is the name of your project?")
41
+
42
+ project_type = prompt.select("Select a project template: ", ["CLI", "Quick Script"])
43
+ ai_provider = prompt.select("Select an AI provider:", ["OpenAI", "Claude", "Gemini"])
44
+
45
+ ai_model = if ai_provider == "OpenAI"
46
+ prompt.select("Which OpenAI model would you like to use?", ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo"])
47
+ elsif ai_provider == "Claude"
48
+ prompt.select("Which Anthropic model would you like to use?", ["claude-3-5-sonnet-20240620", "claude-3-opus-20240229", "claude-3-haiku-20240307"])
49
+ elsif ai_provider == "Gemini"
50
+ prompt.select("Which Gemini model would you like to use?", ["gemini-1.5-pro-latest", "gemini-1.5-flash-latest"])
51
+ end
52
+
53
+ create_project(project_name, project_type, ai_provider, ai_model)
54
+ end
55
+
56
+ def create_project(project_name, project_type, ai_provider, ai_model)
57
+ project_path = File.join(Dir.pwd, project_name)
58
+
59
+ progress_bar = TTY::ProgressBar.new("Creating project [:bar] :percent", total: 8)
60
+
61
+ progress_bar.advance(1, log: "Creating project directory")
62
+ FileUtils.mkdir_p(project_path)
63
+
64
+ progress_bar.advance(1, log: "Copying template files")
65
+ copy_template_files(project_path, project_type)
66
+
67
+ progress_bar.advance(1, log: "Replacing placeholders")
68
+ replace_placeholders(project_path, project_name)
69
+
70
+ progress_bar.advance(1, log: "Generating configuration")
71
+ generate_config_file(project_path, project_name, project_type, ai_provider, ai_model)
72
+
73
+ progress_bar.advance(1, log: "Finalizing project")
74
+ finalize_project(project_path, project_type)
75
+
76
+ puts "\nSublayer project '#{project_name}' created successfully!"
77
+ end
78
+
79
+ def copy_template_files(project_path, project_type)
80
+ template_dir = project_type == "CLI" ? "cli" : "quick_script"
81
+ source_path = File.join(File.dirname(__FILE__), "templates", template_dir)
82
+ FileUtils.cp_r("#{source_path}/.", project_path)
83
+
84
+ FileUtils.mkdir_p(File.join(project_path, "log")) if should_add_log_folder(project_type)
85
+ end
86
+
87
+ def should_add_log_folder(project_type)
88
+ project_type == "CLI"
89
+ end
90
+
91
+ def generate_config_file(project_path, project_name, project_type, ai_provider, ai_model)
92
+ config = {
93
+ project_name: project_name,
94
+ project_type: project_type,
95
+ ai_provider: ai_provider,
96
+ ai_model: ai_model
97
+ }
98
+
99
+ TTY::File.create_file(File.join(project_path, "lib", project_name, "config", "sublayer.yml"), YAML.dump(config)) if project_type == "CLI"
100
+
101
+ if project_type == "Quick Script"
102
+ config_lines = <<~CONFIG
103
+ Sublayer.configuration.ai_provider = Sublayer::Providers::#{config[:ai_provider]}
104
+ Sublayer.configuration.ai_model = "#{config[:ai_model]}"
105
+ CONFIG
106
+ project_file = File.join(project_path, "#{project_name}.rb")
107
+ File.write(project_file, File.read(project_file) + config_lines)
108
+ end
109
+ end
110
+
111
+ def project_type_instructions(project_type)
112
+ if project_type == "CLI"
113
+ "Run your CLI application:\n ```\n ruby bin/#{File.basename(project_path)}\n ```"
114
+ else
115
+ "Start your web server:\n ```\n ruby app.rb\n ```\n Then visit http://localhost:4567 in your browser."
116
+ end
117
+ end
118
+
119
+ def replace_placeholders(project_path, project_name)
120
+ # First rename the lib/PROJECT_NAME directory to lib/project_name
121
+ FileUtils.mv(File.join(project_path, "lib", "PROJECT_NAME"), File.join(project_path, "lib", project_name.gsub("-", "_").downcase)) if File.directory?(File.join(project_path, "lib", "PROJECT_NAME"))
122
+
123
+ # Then walk through each file in the project and replace the placeholder content and filenames
124
+ Dir.glob("#{project_path}/**/*", File::FNM_DOTMATCH).each do |file_path|
125
+ next if File.directory?(file_path)
126
+ next if file_path.include?(".git/")
127
+
128
+ content = File.read(file_path)
129
+ PLACEHOLDERS.each do |placeholder, options|
130
+ replacement = if options[:camelcase]
131
+ project_name.split(/[_-]/).map(&:capitalize).join
132
+ elsif options[:underscore]
133
+ project_name.gsub("-", "_").downcase
134
+ else
135
+ project_name
136
+ end
137
+ content.gsub!(placeholder, replacement) if options[:gsub]
138
+ end
139
+
140
+ File.write(file_path, content)
141
+
142
+
143
+ if file_path.include?('PROJECT_NAME')
144
+ new_path = file_path.gsub("PROJECT_NAME", project_name.gsub("-", "_").downcase)
145
+
146
+ FileUtils.mkdir_p(File.dirname(new_path))
147
+ FileUtils.mv(file_path, new_path)
148
+ end
149
+
150
+ if file_path.include?('project_name')
151
+ new_path = file_path.gsub("project_name", project_name.gsub("-", "_").downcase)
152
+
153
+ FileUtils.mkdir_p(File.dirname(new_path))
154
+ FileUtils.mv(file_path, new_path)
155
+ end
156
+ end
157
+
158
+ # replace the sublayer version in the gemspec file with Sublayer::VERSION
159
+ if File.exist?(File.join(project_path, "#{project_name}.gemspec"))
160
+ gemspec_path = File.join(project_path, "#{project_name}.gemspec")
161
+ gemspec_content = File.read(gemspec_path)
162
+ gemspec_content.gsub!("SUBLAYER_VERSION", Sublayer::VERSION)
163
+ File.write(gemspec_path, gemspec_content)
164
+ end
165
+ end
166
+
167
+ def finalize_project(project_path, project_type)
168
+ cmd = TTY::Command.new(printer: :null)
169
+
170
+ if TTY::Prompt.new.yes?("Initialize a git repository?")
171
+ cmd.run("git init", chdir: project_path)
172
+ end
173
+
174
+ if TTY::Prompt.new.yes?("Install dependencies now?")
175
+ cmd.run("bundle install", chdir: project_path)
176
+ end
177
+
178
+ puts "To get started, run:"
179
+ puts " cd #{File.basename(project_path)}"
180
+ puts " ./bin/#{File.basename(project_path)}" if project_type == "CLI"
181
+ puts " ruby #{File.basename(project_path)}.rb" if project_type == "Quick Script"
182
+ end
183
+
184
+ def display_help
185
+ puts "Usage: sublayer [command] [arguments]"
186
+ puts "Commands:"
187
+ puts " new PROJECT_NAME Create a new Sublayer project"
188
+ puts " help Display this help message"
189
+ end
190
+ end
191
+ end
@@ -3,23 +3,42 @@ module Sublayer
3
3
  module OutputAdapters
4
4
  module Formattable
5
5
  def format_properties
6
+ build_json_schema(self.properties)
7
+ end
8
+
9
+ def build_json_schema(props)
6
10
  formatted_properties = {}
7
- self.properties.each do |prop|
8
- property = {
9
- type: prop.type,
10
- description: prop.description
11
- }
12
-
13
- property[:enum] = prop.enum if prop.respond_to?(:enum) && prop.enum
14
- property[:default] = prop.default if prop.respond_to?(:default) && !prop.default.nil?
15
- property[:minimum] = prop.minimum if prop.respond_to?(:minimum) && !prop.minimum.nil?
16
- property[:maximum] = prop.maximum if prop.respond_to?(:maximum) && !prop.maximum.nil?
17
- property[:items] = prop.items if prop.respond_to?(:items) && prop.items
18
- formatted_properties[prop.name.to_sym] = property
11
+
12
+ props.map do |prop|
13
+ formatted_property = format_property(prop)
14
+ formatted_properties[prop.name.to_sym] = formatted_property
19
15
  end
16
+
20
17
  formatted_properties
21
18
  end
22
19
 
20
+ def format_property(property)
21
+ result = {
22
+ type: property.type,
23
+ description: property.description
24
+ }
25
+
26
+ result[:enum] = property.enum if property.respond_to?(:enum) && property.enum
27
+ result[:default] = property.default if property.respond_to?(:default) && !property.default.nil?
28
+ result[:minimum] = property.minimum if property.respond_to?(:minimum) && !property.minimum.nil?
29
+ result[:maximum] = property.maximum if property.respond_to?(:maximum) && !property.maximum.nil?
30
+
31
+ case property.type
32
+ when 'array'
33
+ result[:items] = property.items.is_a?(OpenStruct) ? format_property(property.items) : property.items
34
+ when 'object'
35
+ result[:properties] = build_json_schema(property.properties) if property.properties
36
+ result[:required] = property.properties.select(&:required).map(&:name) if property.properties
37
+ end
38
+
39
+ result
40
+ end
41
+
23
42
  def format_required
24
43
  self.properties.select(&:required).map(&:name)
25
44
  end
@@ -0,0 +1,48 @@
1
+ module Sublayer
2
+ module Components
3
+ module OutputAdapters
4
+ class ListOfNamedStrings
5
+ attr_reader :name, :description, :attributes, :item_name
6
+
7
+ def initialize(options)
8
+ @name = options[:name]
9
+ @item_name = options[:item_name]
10
+ @description = options[:description]
11
+ @attributes = options[:attributes]
12
+ end
13
+
14
+ def properties
15
+ [
16
+ OpenStruct.new(
17
+ name: @name,
18
+ type: "array",
19
+ description: @description,
20
+ required: true,
21
+ items: OpenStruct.new(
22
+ type: "object",
23
+ description: "a single #{@item_name}",
24
+ name: @item_name,
25
+ properties: @attributes.map do |attribute|
26
+ OpenStruct.new(
27
+ type: "string",
28
+ name: attribute[:name],
29
+ description: attribute[:description],
30
+ required: true
31
+ )
32
+ end
33
+ )
34
+ )
35
+ ]
36
+ end
37
+
38
+ def materialize_result(raw_results)
39
+ raw_results.map do |raw_result|
40
+ OpenStruct.new(
41
+ @attributes.map { |attribute| [attribute[:name], raw_result[attribute[:name]]] }.to_h
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,33 @@
1
+ module Sublayer
2
+ module Components
3
+ module OutputAdapters
4
+ class NamedStrings
5
+ attr_reader :name, :description, :attributes
6
+
7
+ def initialize(options)
8
+ @name = options[:name]
9
+ @description = options[:description]
10
+ @attributes = options[:attributes]
11
+ end
12
+
13
+ def properties
14
+ [
15
+ OpenStruct.new(
16
+ name: @name,
17
+ type: "object",
18
+ description: @description,
19
+ required: true,
20
+ properties: @attributes.map { |attribute|
21
+ OpenStruct.new(type: "string", description: attribute[:description], required: true, name: attribute[:name])
22
+ }
23
+ )
24
+ ]
25
+ end
26
+
27
+ def materialize_result(raw_result)
28
+ OpenStruct.new( @attributes.map { |attribute| [attribute[:name], raw_result[attribute[:name]]] }.to_h)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -10,7 +10,10 @@ module Sublayer
10
10
 
11
11
  def generate
12
12
  self.class::OUTPUT_ADAPTER.load_instance_data(self) if self.class::OUTPUT_ADAPTER.respond_to?(:load_instance_data)
13
- @results = Sublayer.configuration.ai_provider.call(prompt: prompt, output_adapter: self.class::OUTPUT_ADAPTER)
13
+
14
+ raw_results = Sublayer.configuration.ai_provider.call(prompt: prompt, output_adapter: self.class::OUTPUT_ADAPTER)
15
+
16
+ @results = self.class::OUTPUT_ADAPTER.respond_to?(:materialize_result) ? self.class::OUTPUT_ADAPTER.materialize_result(raw_results) : raw_results
14
17
  end
15
18
  end
16
19
  end
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /log/
10
+
11
+ .rspec_status
12
+
13
+ .DS_Store
14
+ .DS_Store?
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem "rspec", "~> 3.10"
7
+ end
@@ -0,0 +1,35 @@
1
+ require_relative "lib/PROJECT_NAME/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "PROJECT_NAME"
5
+ spec.version = ProjectName::VERSION
6
+ spec.authors = ["Your Name"]
7
+ spec.email = ["your.email@example.com"]
8
+
9
+ spec.summary = "Summary of your project"
10
+ spec.description = "Longer description of your project"
11
+ spec.homepage = "https://github.com/yourusername/PROJECT_NAME"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = ">= 2.6.0"
14
+
15
+ spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/yourusername/PROJECT_NAME"
19
+ spec.metadata["changelog_uri"] = "https://github.com/yourusername/PROJECT_NAME/blob/master/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "bin"
29
+ spec.executables = spec.files.grep(%r{\Abin/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ # Add dependencies here
33
+ spec.add_dependency "sublayer", "~> SUBLAYER_VERSION"
34
+ spec.add_dependency "thor", "~> 1.2"
35
+ end
@@ -0,0 +1,22 @@
1
+ # ProjectName
2
+
3
+ Welcome to your new Sublayer CLI project!
4
+
5
+ ## Installation
6
+
7
+ Execute:
8
+
9
+ $ bundle install
10
+
11
+ ## Usage
12
+
13
+ To run your CLI application:
14
+
15
+ ```
16
+ $ bin/PROJECT_NAME
17
+ ```
18
+
19
+ Available commands:
20
+ - `example`: Run the example generator
21
+ - `help`: Display the help message
22
+
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/project_name"
4
+
5
+ ProjectName::CLI.start(ARGV)
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectName
4
+ module Actions
5
+ class ExampleAction < Sublayer::Actions::Base
6
+ def initialize(input:)
7
+ @input = input
8
+ end
9
+
10
+ def call
11
+ puts "Performing action with input: #{@input}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectName
4
+ module Agents
5
+ class ExampleAgent < Sublayer::Agents::Base
6
+ trigger_on_files_changed { ["example_file.txt"] }
7
+
8
+ goal_condition { @goal_reached }
9
+
10
+ check_status do
11
+ @status_checked = true
12
+ end
13
+
14
+ step do
15
+ @step_taken = true
16
+ @goal_reached = true
17
+ puts "Example agent step executed"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectName
4
+ class CLI < Thor
5
+ ProjectName::Commands.constants.reject{ |command_class| command_class == :BaseCommand }.each do |command_class|
6
+ command = ProjectName::Commands.const_get(command_class)
7
+ desc command.command_name, command.description
8
+ define_method(command.command_name) do |*args|
9
+ command.new(options).execute(*args)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module ProjectName
2
+ module Commands
3
+ class BaseCommand
4
+ def self.command_name
5
+ name.split("::").last.gsub(/Command$/, '').downcase
6
+ end
7
+
8
+ def self.description
9
+ "Description for #{command_name}"
10
+ end
11
+
12
+ def initialize(options)
13
+ @options = options
14
+ end
15
+
16
+ def execute(*args)
17
+ raise NotImplementedError, "#{self.class} must implement #execute"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module ProjectName
2
+ module Commands
3
+ class ExampleCommand < BaseCommand
4
+ def self.description
5
+ "An example command that generates a story based on the command line arguments."
6
+ end
7
+
8
+ def execute(*args)
9
+ puts ProjectName::Generators::ExampleGenerator.new(input: args.join(" ")).generate
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module ProjectName
2
+ module Config
3
+ def self.load
4
+ config_path = File.join(File.dirname(__FILE__), "config", "sublayer.yml")
5
+
6
+ if File.exist?(config_path)
7
+ config = YAML.load_file(config_path)
8
+
9
+ Sublayer.configure do |c|
10
+ c.ai_provider = Object.const_get("Sublayer::Providers::#{config[:ai_provider]}")
11
+ c.ai_model = config[:ai_model]
12
+ c.logger = Sublayer::Logging::JsonLogger.new(File.join(Dir.pwd, 'log', 'sublayer.log'))
13
+ end
14
+ else
15
+ puts "Warning: config/sublayer.yml not found. Using default configuration."
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectName
4
+ module Generators
5
+ class ExampleGenerator < Sublayer::Generators::Base
6
+ llm_output_adapter type: :single_string,
7
+ name: "generated_text",
8
+ description: "A simple generated text"
9
+
10
+ def initialize(input:)
11
+ @input = input
12
+ end
13
+
14
+ def generate
15
+ super
16
+ end
17
+
18
+ def prompt
19
+ <<-PROMPT
20
+ Generate a simple story based on this input: #{@input}
21
+ PROMPT
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProjectName
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,21 @@
1
+ require "yaml"
2
+ require "thor"
3
+ require "sublayer"
4
+ require_relative "PROJECT_NAME/version"
5
+ require_relative "PROJECT_NAME/config"
6
+
7
+ Dir[File.join(__dir__, "PROJECT_NAME", "commands", "*.rb")].each { |file| require file }
8
+ Dir[File.join(__dir__, "PROJECT_NAME", "generators", "*.rb")].each { |file| require file }
9
+ Dir[File.join(__dir__, "PROJECT_NAME", "actions", "*.rb")].each { |file| require file }
10
+ Dir[File.join(__dir__, "PROJECT_NAME", "agents", "*.rb")].each { |file| require file }
11
+
12
+ require_relative "PROJECT_NAME/cli"
13
+
14
+ module ProjectName
15
+ class Error < StandardError; end
16
+ Config.load
17
+
18
+ def self.root
19
+ File.dirname __dir__
20
+ end
21
+ end
File without changes
@@ -0,0 +1,16 @@
1
+ # ProjectName
2
+
3
+ Welcome to your new Sublayer quick script project!
4
+
5
+ There are example Agents, Generators, and Actions in the respective folders.
6
+
7
+ ## Usage
8
+
9
+ Create your own custom agents, generators, and actions and use them in
10
+ `project_name.rb`
11
+
12
+ Run your script:
13
+
14
+ ```
15
+ $ ruby project_name.rb
16
+ ```
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ExampleAction < Sublayer::Actions::Base
4
+ def initialize(input:)
5
+ @input = input
6
+ end
7
+
8
+ def call
9
+ puts "Performing action with input: #{@input}"
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ExampleAgent < Sublayer::Agents::Base
4
+ trigger_on_files_changed { ["example_file.txt"] }
5
+
6
+ goal_condition { @goal_reached }
7
+
8
+ check_status do
9
+ @status_checked = true
10
+ end
11
+
12
+ step do
13
+ @step_taken = true
14
+ @goal_reached = true
15
+ puts "Example agent step executed"
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ExampleGenerator < Sublayer::Generators::Base
4
+ llm_output_adapter type: :single_string,
5
+ name: "generated_text",
6
+ description: "A simple generated text"
7
+
8
+ def initialize(input:)
9
+ @input = input
10
+ end
11
+
12
+ def generate
13
+ super
14
+ end
15
+
16
+ def prompt
17
+ <<-PROMPT
18
+ Generate a simple story based on this input: #{@input}
19
+ PROMPT
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ require "yaml"
2
+ require "sublayer"
3
+
4
+ Dir[File.join(__dir__, "actions", "*.rb")].each { |file| require file }
5
+ Dir[File.join(__dir__, "agents", "*.rb")].each { |file| require file }
6
+ Dir[File.join(__dir__, "generators", "*.rb")].each { |file| require file }
7
+
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sublayer
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.4"
5
5
  end
data/lib/sublayer.rb CHANGED
@@ -16,6 +16,7 @@ require_relative "sublayer/version"
16
16
 
17
17
  loader = Zeitwerk::Loader.for_gem
18
18
  loader.inflector.inflect('open_ai' => 'OpenAI')
19
+ loader.inflector.inflect("cli" => "CLI")
19
20
  loader.setup
20
21
 
21
22
  module Sublayer
data/sublayer.gemspec CHANGED
@@ -29,6 +29,8 @@ Gem::Specification.new do |spec|
29
29
  end
30
30
 
31
31
  spec.require_paths = ["lib"]
32
+ spec.bindir = "bin"
33
+ spec.executables = ["sublayer"]
32
34
 
33
35
  spec.add_dependency "ruby-openai"
34
36
  spec.add_dependency "colorize"
@@ -37,6 +39,11 @@ Gem::Specification.new do |spec|
37
39
  spec.add_dependency "nokogiri", "~> 1.16.5"
38
40
  spec.add_dependency "httparty"
39
41
  spec.add_dependency "listen"
42
+ spec.add_dependency "tty-prompt", "~> 0.23"
43
+ spec.add_dependency "tty-progressbar", "~> 0.18"
44
+ spec.add_dependency "tty-command", "~> 0.10"
45
+ spec.add_dependency "tty-file", "~> 0.10"
46
+ spec.add_dependency "thor"
40
47
 
41
48
  spec.add_development_dependency "rspec", "~> 3.12"
42
49
  spec.add_development_dependency "pry", "~> 0.14"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sublayer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Werner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-12 00:00:00.000000000 Z
11
+ date: 2024-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-openai
@@ -108,6 +108,76 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: tty-prompt
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.23'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.23'
125
+ - !ruby/object:Gem::Dependency
126
+ name: tty-progressbar
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.18'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.18'
139
+ - !ruby/object:Gem::Dependency
140
+ name: tty-command
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.10'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.10'
153
+ - !ruby/object:Gem::Dependency
154
+ name: tty-file
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.10'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.10'
167
+ - !ruby/object:Gem::Dependency
168
+ name: thor
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
111
181
  - !ruby/object:Gem::Dependency
112
182
  name: rspec
113
183
  requirement: !ruby/object:Gem::Requirement
@@ -182,19 +252,24 @@ description: A DSL and framework for building AI powered applications through th
182
252
  use of Generators, Actions, Tasks, and Agents
183
253
  email:
184
254
  - scott@sublayer.com
185
- executables: []
255
+ executables:
256
+ - sublayer
186
257
  extensions: []
187
258
  extra_rdoc_files: []
188
259
  files:
189
260
  - LICENSE
190
261
  - README.md
191
262
  - Rakefile
263
+ - bin/sublayer
192
264
  - lib/sublayer.rb
193
265
  - lib/sublayer/actions/base.rb
194
266
  - lib/sublayer/agents/base.rb
267
+ - lib/sublayer/cli.rb
195
268
  - lib/sublayer/components/output_adapters.rb
196
269
  - lib/sublayer/components/output_adapters/formattable.rb
270
+ - lib/sublayer/components/output_adapters/list_of_named_strings.rb
197
271
  - lib/sublayer/components/output_adapters/list_of_strings.rb
272
+ - lib/sublayer/components/output_adapters/named_strings.rb
198
273
  - lib/sublayer/components/output_adapters/single_string.rb
199
274
  - lib/sublayer/components/output_adapters/string_selection_from_list.rb
200
275
  - lib/sublayer/generators/base.rb
@@ -206,6 +281,27 @@ files:
206
281
  - lib/sublayer/providers/gemini.rb
207
282
  - lib/sublayer/providers/open_ai.rb
208
283
  - lib/sublayer/tasks/base.rb
284
+ - lib/sublayer/templates/cli/.gitignore
285
+ - lib/sublayer/templates/cli/Gemfile
286
+ - lib/sublayer/templates/cli/PROJECT_NAME.gemspec
287
+ - lib/sublayer/templates/cli/README.md
288
+ - lib/sublayer/templates/cli/bin/PROJECT_NAME
289
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/actions/example_action.rb
290
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/agents/example_agent.rb
291
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/cli.rb
292
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/commands/base_command.rb
293
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/commands/example_command.rb
294
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/config.rb
295
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/config/.keep
296
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/generators/example_generator.rb
297
+ - lib/sublayer/templates/cli/lib/PROJECT_NAME/version.rb
298
+ - lib/sublayer/templates/cli/lib/project_name.rb
299
+ - lib/sublayer/templates/cli/spec/.keep
300
+ - lib/sublayer/templates/quick_script/README.md
301
+ - lib/sublayer/templates/quick_script/actions/example_action.rb
302
+ - lib/sublayer/templates/quick_script/agents/example_agent.rb
303
+ - lib/sublayer/templates/quick_script/generators/example_generator.rb
304
+ - lib/sublayer/templates/quick_script/project_name.rb
209
305
  - lib/sublayer/triggers/base.rb
210
306
  - lib/sublayer/triggers/file_change.rb
211
307
  - lib/sublayer/version.rb