sublayer 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 49d6bc9e7a56b5f5b7cb47aa3c46bfd5c30fe7ff5927b7b391fe370d70b8e4e3
4
+ data.tar.gz: e54f5e28724f4c8fb8af83b13bd7a71de005266511b275540955376d91a2b6a9
5
+ SHA512:
6
+ metadata.gz: df71cd627df49a5b76a631810137fb639e5c936a2a9f2516ccc90ede301428ea00f6fce79045b37539ff89a02f3bca1b69f4fd53816f91c1cd9aee153760d482
7
+ data.tar.gz: 694f971637fd0609b6a0b07f3a178d7f3b51d42820b51a4e282c360a39b806541f8534976caa320a065e345b02f32069865da9e88de10ae31000d1697cc52dec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Sublayer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # Sublayer
2
+
3
+ A model-agnostic Ruby Generative AI DSL and framework. Provides base classes for
4
+ building Generators, Actions, Tasks, and Agents that can be used to build AI
5
+ powered applications in Ruby.
6
+
7
+ ## Installation
8
+
9
+ Install the gem by running the following commands:
10
+
11
+ $ bundle
12
+ $ gem build sublayer.gemspec
13
+ $ gem install sublayer-0.0.1.gem
14
+
15
+ ## Choose your AI Model
16
+
17
+ Sublayer is model-agnostic and can be used with any AI model. Below are the
18
+
19
+ ### OpenAI (Default)
20
+
21
+ Expects you to have an OpenAI API key set in the `OPENAI_API_KEY` environment variable.
22
+
23
+ Visit [OpenAI](https://openai.com/product) to get an API key.
24
+
25
+ Usage:
26
+ ```ruby
27
+ Sublayer.configuration.ai_provider = Sublayer::Providers::OpenAI
28
+ Sublayer.configuration.ai_model = "gpt-4-turbo-preview"
29
+ ```
30
+
31
+ ### Gemini
32
+
33
+ Expects you to have a Gemini API key set in the `GEMINI_API_KEY` environment variable.
34
+
35
+ Visit [Google AI Studio](https://ai.google.dev/) to get an API key.
36
+
37
+ Usage:
38
+ ```ruby
39
+ Sublayer.configuration.ai_provider = Sublayer::Providers::Gemini
40
+ Sublayer.configuration.ai_model = "gemini-pro"
41
+ ```
42
+
43
+ ### Claude
44
+
45
+ Expect you to have a Claude API key set in the `ANTHROPIC_API_KEY` environment variable.
46
+
47
+ Visit [Anthropic](https://anthropic.com/) to get an API key.
48
+
49
+
50
+ Usage:
51
+ ```ruby
52
+ Sublayer.configuration.ai_provider = Sublayer::Providers::Claude
53
+ Sublayer.configuration.ai_model ="claude-3-opus-20240229"
54
+ ```
55
+
56
+ ### Groq
57
+
58
+ Expects you to have a Groq API key set in the `GROQ_API_KEY` environment variable.
59
+
60
+ Visit [Groq Console](https://console.groq.com/) to get an API key.
61
+
62
+ Usage:
63
+ ```ruby
64
+ Sublayer.configuration.ai_provider = Sublayer::Providers::Groq
65
+ Sublayer.configuration.ai_model = "mixtral-8x7b-32768"
66
+ ```
67
+
68
+ ### Local
69
+
70
+ Support for running a local model and serving an API on https://localhost:8080
71
+
72
+ The simplest way to do this is to download
73
+ [llamafile](https://github.com/Mozilla-Ocho/llamafile) and download one of the
74
+ server llamafiles they provide. We've also tested with [this Mixtral
75
+ model](https://huggingface.co/NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO-GGUF) from
76
+ [Nous
77
+ Research](https://nousresearch.com/).
78
+
79
+ ```ruby
80
+ Sublayer.configuration.ai_provider = Sublayer::Providers::Local
81
+ Sublayer.configuration.ai_model = "LLaMA_CPP"
82
+ ```
83
+
84
+ ## Concepts
85
+
86
+ ### Generators
87
+
88
+ Generators are responsible for generating specific outputs based on input data.
89
+ They focus on a single generation task and do not perform any actions or complex
90
+ decision-making. Generators are the building blocks of the Sublayer framework.
91
+
92
+ Examples (in the /examples/ directory):
93
+ - CodeFromDescriptionGenerator: Generates code based on a description and the
94
+ technologies used.
95
+ - DescriptionFromCodeGenerator: Generates a description of the code passed in to
96
+ it.
97
+ - CodeFromBlueprintGenerator: Generates code based on a blueprint, a blueprint
98
+ description, and a description of the desired code.
99
+
100
+
101
+ ### Actions (Coming Soon)
102
+
103
+ Actions are responsible for performing specific operations to get inputs for a
104
+ Generator or based on the generated output from a Generator. They encapsulate a
105
+ single action and do not involve complex decision-making. Actions are the
106
+ executable units that bring the generated inputs to life.
107
+
108
+ Examples:
109
+ - SaveToFileAction: Saves generated output to a file.
110
+ - RunCommandLineCommandAction: Runs a generated command line command.
111
+
112
+ ### Tasks (Coming Soon)
113
+
114
+ Tasks combine Generators and Actions to accomplish a specific goal. They involve
115
+ a sequence of generation and action steps that may include basic decision-making
116
+ and flow control. Tasks are the high-level building blocks that define the
117
+ desired outcome.
118
+
119
+ Examples:
120
+ - ModifyFileContentsTask: Generates new file contents based on the existing
121
+ contents and a set of rules, and then saves the new contents to the file.
122
+
123
+ ### Agents (Coming Soon)
124
+
125
+ Agents are high-level entities that coordinate and orchestrate multiple Tasks to
126
+ achieve a broader goal. They involve complex decision-making, monitoring, and
127
+ adaptation based on the outcomes of the Tasks. Agents are the intelligent
128
+ supervisors that manage the overall workflow.
129
+
130
+ Examples:
131
+ - CustomerSupportAgent: Handles customer support inquiries by using various
132
+ Tasks such as understanding the customer's issue, generating appropriate
133
+ responses, and performing actions like sending emails or creating support
134
+ tickets.
135
+
136
+ ## Usage Examples
137
+
138
+ There are sample Generators in the /examples/ directory that demonstrate how to
139
+ build generators using the Sublayer framework. Alternatively below are links to
140
+ open source projects that are using generators in different ways:
141
+
142
+ - [Blueprints](https://blueprints.sublayer.com) - An open source AI code
143
+ assistant that allows you to capture patterns in your codebase to use as a
144
+ base for generating new code.
145
+
146
+ - [Clag](https://github.com/sublayerapp/clag) - A ruby gem that generates
147
+ command line commands from a simple description right in your terminal.
148
+
149
+ ## Development
150
+
151
+ TBD
152
+
153
+ ## Contributing
154
+
155
+ TBD
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,30 @@
1
+ class CodeFromBlueprintGenerator < Sublayer::Generators::Base
2
+ llm_output_adapter type: :single_string,
3
+ name: "generated_code",
4
+ description: "The generated code for the description"
5
+
6
+ def initialize(blueprint_description:, blueprint_code:, description:)
7
+ @blueprint_description = blueprint_description
8
+ @blueprint_code = blueprint_code
9
+ @description = description
10
+ end
11
+
12
+ def generate
13
+ super
14
+ end
15
+
16
+ def prompt
17
+ <<-PROMPT
18
+ You are an expert programmer and are great at looking at and understanding existing patterns and applying them to new situations.
19
+
20
+ The blueprint we're working with is: #{@blueprint_description}.
21
+ The code for that blueprint is:
22
+ #{@blueprint_code}
23
+
24
+ You need to use the blueprint above and modify it so that it satisfied the following description:
25
+ #{@description}
26
+
27
+ Take a deep breath and think step by step before you start coding.
28
+ PROMPT
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ class CodeFromDescriptionGenerator < Sublayer::Generators::Base
2
+ llm_output_adapter type: :single_string,
3
+ name: "generated_code",
4
+ description: "The generated code in the requested language"
5
+
6
+ def initialize(description:, technologies:)
7
+ @description = description
8
+ @technologies = technologies
9
+ end
10
+
11
+ def generate
12
+ super
13
+ end
14
+
15
+ def prompt
16
+ <<-PROMPT
17
+ You are an expert programmer in #{@technologies.join(", ")}.
18
+
19
+ You are tasked with writing code using the following technologies: #{@technologies.join(", ")}.
20
+
21
+ The description of the task is #{@description}
22
+
23
+ Take a deep breath and think step by step before you start coding.
24
+ PROMPT
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ class DescriptionFromCodeGenerator < Sublayer::Generators::Base
2
+ llm_output_adapter type: :single_string,
3
+ name: "code_description",
4
+ description: "A description of what the code in the file does"
5
+
6
+ def initialize(code:)
7
+ @code = code
8
+ end
9
+
10
+ def generate
11
+ super
12
+ end
13
+
14
+ def prompt
15
+ <<-PROMPT
16
+ You are an experienced software engineer. Below is a chunk of code:
17
+
18
+ #{@code}
19
+
20
+ Please read the code carefully and provide a high-level description of what this code does, including its purpose, functionalities, and any noteworthy details.
21
+ PROMPT
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ class InvalidToValidJsonGenerator < Sublayer::Generators::Base
2
+ llm_output_adapter type: :single_string,
3
+ name: "valid_json",
4
+ description: "The valid JSON string"
5
+
6
+ def initialize(invalid_json:)
7
+ @invalid_json = invalid_json
8
+ end
9
+
10
+ def generate
11
+ super
12
+ end
13
+
14
+ def prompt
15
+ <<-PROMPT
16
+ You are an expert in JSON parsing.
17
+
18
+ The given string is not a valid JSON: #{@invalid_json}
19
+
20
+ Please fix this and produce a valid JSON.
21
+ PROMPT
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ module Sublayer
2
+ module Components
3
+ module OutputAdapters
4
+ class SingleString
5
+ attr_reader :name
6
+
7
+ def initialize(options)
8
+ @name = options[:name]
9
+ @description = options[:description]
10
+ end
11
+
12
+ def to_hash
13
+ {
14
+ name: @name,
15
+ description: @description,
16
+ parameters: {
17
+ type: "object",
18
+ properties: {
19
+ @name => {
20
+ type: "string",
21
+ description: @description
22
+ }
23
+ }
24
+ }
25
+ }
26
+ end
27
+
28
+ def to_xml
29
+ <<-XML
30
+ <tool_description>
31
+ <tool_name>#{@name}</tool_name>
32
+ <tool_description>#{@description}</tool_description>
33
+ <parameters>
34
+ <name>#{@name}</name>
35
+ <type>string</type>
36
+ <description>#{@description}</description>
37
+ </parameters>
38
+ </tool_description>
39
+ XML
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ module Sublayer
2
+ module Components
3
+ module OutputAdapters
4
+ attr_reader :name
5
+
6
+ def self.create(options)
7
+ ("Sublayer::Components::OutputAdapters::"+options[:type].to_s.camelize).constantize.new(options)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require "pry"
2
+ module Sublayer
3
+ module Generators
4
+ class Base
5
+ attr_reader :results
6
+
7
+ def self.llm_output_adapter(options)
8
+ output_adapter = Sublayer::Components::OutputAdapters.create(options)
9
+ const_set(:OUTPUT_ADAPTER, output_adapter)
10
+ end
11
+
12
+ def generate
13
+ @results = Sublayer.configuration.ai_provider.call(prompt: prompt, output_adapter: self.class::OUTPUT_ADAPTER)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,55 @@
1
+ # Sublayer.configuration.ai_provider = Sublayer::Providers::Claude
2
+ # Sublayer.configuration.ai_model ="claude-3-opus-20240229"
3
+
4
+ module Sublayer
5
+ module Providers
6
+ class Claude
7
+ def self.call(prompt:, output_adapter:)
8
+ system_prompt = <<-PROMPT
9
+ In this environment you have access to a set of tools you can use to answer the user's question.
10
+
11
+ You may call them like this:
12
+ <function_calls>
13
+ <invoke>
14
+ <tool_name>$TOOL_NAME</tool_name>
15
+ <parameters>
16
+ <$PARAMETER_NAME>$PARAMETER_VALUE</$PARAMETER_NAME>
17
+ ...
18
+ </parameters>
19
+ </invoke>
20
+ </function_calls>
21
+
22
+ Here are the tools available:
23
+ <tools>
24
+ #{output_adapter.to_xml}
25
+ </tools>
26
+
27
+ Respond only with valid xml. The entire response should be wrapped in a <response> tag. Any additional information not inside a tool call should go in a <scratch> tag.
28
+ PROMPT
29
+
30
+ response = HTTParty.post(
31
+ "https://api.anthropic.com/v1/messages",
32
+ headers: {
33
+ "x-api-key": ENV["ANTHROPIC_API_KEY"],
34
+ "anthropic-version": "2023-06-01",
35
+ "content-type": "application/json"
36
+ },
37
+ body: {
38
+ model: Sublayer.configuration.ai_model,
39
+ max_tokens: 4096,
40
+ system: system_prompt,
41
+ messages: [ { "role": "user", "content": prompt }]
42
+ }.to_json
43
+ )
44
+ raise "Error generating with Claude, error: #{response.body}" unless response.code == 200
45
+
46
+ text_containing_xml = JSON.parse(response.body).dig("content", 0, "text")
47
+ xml = text_containing_xml.match(/\<response\>(.*?)\<\/response\>/m).to_s
48
+ response_xml = ::Nokogiri::XML(xml)
49
+ function_output = response_xml.at_xpath("//response/function_calls/invoke/parameters/#{output_adapter.name}").children.to_s
50
+
51
+ return function_output
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,26 @@
1
+ # Sublayer.configuration.ai_provider = Sublayer::Providers::Gemini
2
+ # Sublayer.configuration.ai_model = "gemini-pro"
3
+
4
+ module Sublayer
5
+ module Providers
6
+ class Gemini
7
+ def self.call(prompt:, output_adapter:)
8
+ response = HTTParty.post(
9
+ "https://generativelanguage.googleapis.com/v1beta/models/#{Sublayer.configuration.ai_model}:generateContent?key=#{ENV['GEMINI_API_KEY']}",
10
+ body: {
11
+ tools: { function_declarations: [output_adapter.to_hash] },
12
+ contents: { role: "user", parts: { text: prompt } }
13
+ }.to_json,
14
+ headers: {
15
+ "Content-Type" => "application/json"
16
+ })
17
+
18
+ part = response.dig('candidates', 0, 'content', 'parts', 0)
19
+ raise "No function called" unless part['functionCall']
20
+
21
+ args = part['functionCall']['args']
22
+ args[output_adapter.name]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,53 @@
1
+ # Sublayer.configuration.ai_provider = Sublayer::Providers::Groq
2
+ # Sublayer.configuration.ai_model = "mixtral-8x7b-32768"
3
+
4
+ module Sublayer
5
+ module Providers
6
+ class Groq
7
+ def self.call(prompt:, output_adapter:)
8
+ system_prompt = <<-PROMPT
9
+ In this environment you have access to a set of tools you can use to answer the user's question.
10
+
11
+ You may call them like this:
12
+ <function_calls>
13
+ <invoke>
14
+ <tool_name>$TOOL_NAME</tool_name>
15
+ <parameters>
16
+ <#{output_adapter.name}>value</#{output_adapter.name}>
17
+ ...
18
+ </parameters>
19
+ </invoke>
20
+ </function_calls>
21
+
22
+ Here are the tools available:
23
+ <tools>
24
+ #{output_adapter.to_xml}
25
+ </tools>
26
+
27
+ Respond only with valid xml.
28
+ The entire response should be wrapped in a <response> tag.
29
+ Any additional information not inside a tool call should go in a <scratch> tag.
30
+ PROMPT
31
+
32
+ response = HTTParty.post(
33
+ "https://api.groq.com/openai/v1/chat/completions",
34
+ headers: {
35
+ "Authorization": "Bearer #{ENV["GROQ_API_KEY"]}",
36
+ "Content-Type": "application/json"
37
+ },
38
+ body: {
39
+ "messages": [{"role": "user", "content": "#{system_prompt}\n#{prompt}"}],
40
+ "model": Sublayer.configuration.ai_model
41
+ }.to_json
42
+ )
43
+
44
+ text_containing_xml = JSON.parse(response.body).dig("choices", 0, "message", "content")
45
+ xml = text_containing_xml.match(/\<response\>(.*?)\<\/response\>/m).to_s
46
+ response_xml = ::Nokogiri::XML(xml)
47
+ function_output = response_xml.at_xpath("//response/function_calls/invoke/parameters/command").children.to_s
48
+
49
+ return function_output
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,56 @@
1
+ # Sublayer.configuration.ai_provider = Sublayer::Providers::Local
2
+ # Sublayer.configuration.ai_model = "LLaMA_CPP"
3
+
4
+ module Sublayer
5
+ module Providers
6
+ class Local
7
+ def initialize(prompt:, output_adapter:)
8
+ system_prompt = <<-PROMPT
9
+ In this environment you have access to a set of tools you can use to answer the user's question.
10
+
11
+ You may call them like this:
12
+ <function_calls>
13
+ <invoke>
14
+ <tool_name>$TOOL_NAME</tool_name>
15
+ <parameters>
16
+ <#{output_adapter.name}>value</#{output_adapter.name}>
17
+ ...
18
+ </parameters>
19
+ </invoke>
20
+ </function_calls>
21
+
22
+ Here are the tools available:
23
+ <tools>
24
+ #{output_adapter.to_xml}
25
+ </tools>
26
+
27
+ Respond only with valid xml.
28
+ The entire response should be wrapped in a <response> tag.
29
+ Any additional information not inside a tool call should go in a <scratch> tag.
30
+ PROMPT
31
+
32
+ response = HTTParty.post(
33
+ "http://localhost:8080/v1/chat/completions",
34
+ headers: {
35
+ "Authorization": "Bearer no-key",
36
+ "Content-Type": "application/json"
37
+ },
38
+ body: {
39
+ "model": Sublayer.configuration.ai_model,
40
+ "messages": [
41
+ { "role": "system", "content": system_prompt },
42
+ { "role": "user", "content": prompt }
43
+ ]
44
+ }.to_json
45
+ )
46
+
47
+ text_containing_xml = JSON.parse(response.body).dig("choices", 0, "message", "content")
48
+ xml = text_containing_xml.match(/\<response\>(.*?)\<\/response\>/m).to_s
49
+ response_xml = ::Nokogiri::XML(xml)
50
+ function_output = response_xml.at_xpath("//parameters/#{output_adapter.name}").children.to_s
51
+
52
+ return function_output
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,34 @@
1
+ # Sublayer.configuration.ai_provider = Sublayer::Providers::OpenAI
2
+ # Sublayer.configuration.ai_model = "gpt-4-turbo-preview"
3
+
4
+ module Sublayer
5
+ module Providers
6
+ class OpenAI
7
+ def self.call(prompt:, output_adapter:)
8
+ client = ::OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
9
+
10
+ response = client.chat(
11
+ parameters: {
12
+ model: Sublayer.configuration.ai_model,
13
+ messages: [
14
+ {
15
+ "role": "user",
16
+ "content": prompt
17
+ }
18
+ ],
19
+ function_call: { name: output_adapter.name },
20
+ functions: [
21
+ output_adapter.to_hash
22
+ ]
23
+ })
24
+
25
+ message = response.dig("choices", 0, "message")
26
+ raise "No function called" unless message["function_call"]
27
+
28
+ function_name = message.dig("function_call", output_adapter.name)
29
+ args_from_llm = message.dig("function_call", "arguments")
30
+ JSON.parse(args_from_llm)[output_adapter.name]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sublayer
4
+ VERSION = "0.0.1"
5
+ end
data/lib/sublayer.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeitwerk"
4
+ require 'active_support'
5
+ require 'active_support/core_ext/hash/indifferent_access'
6
+ require 'active_support/inflector'
7
+ require 'ostruct'
8
+ require "httparty"
9
+ require "openai"
10
+ require "nokogiri"
11
+ require_relative "sublayer/version"
12
+
13
+ loader = Zeitwerk::Loader.for_gem
14
+ loader.inflector.inflect('open_ai' => 'OpenAI')
15
+ loader.setup
16
+
17
+ module Sublayer
18
+ class Error < StandardError; end
19
+
20
+ def self.configuration
21
+ @configuration ||= OpenStruct.new(
22
+ ai_provider: Sublayer::Providers::OpenAI,
23
+ ai_model: "gpt-4-turbo-preview"
24
+ )
25
+ end
26
+
27
+ def self.configure
28
+ yield(configuration) if block_given?
29
+ end
30
+ end
data/sublayer.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/sublayer/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "sublayer"
7
+ spec.version = Sublayer::VERSION
8
+ spec.authors = ["Scott Werner"]
9
+ spec.email = ["scott@sublayer.com"]
10
+ spec.license = "MIT"
11
+
12
+ spec.summary = "A model-agnostic Ruby GenerativeAI DSL and Framework"
13
+ spec.description = "A DSL and framework for building AI powered applications through the use of Generators, Actions, Tasks, and Agents"
14
+ spec.homepage = "https://www.sublayer.com"
15
+ spec.required_ruby_version = ">= 2.6.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(__dir__) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (File.expand_path(f) == __FILE__) ||
24
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
25
+ end
26
+ end
27
+
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "ruby-openai"
31
+ spec.add_dependency "colorize"
32
+ spec.add_dependency "activesupport"
33
+ spec.add_dependency "zeitwerk"
34
+ spec.add_dependency "nokogiri"
35
+ spec.add_dependency "httparty"
36
+
37
+ spec.add_development_dependency "rspec", "~> 3.12"
38
+ spec.add_development_dependency "pry", " ~> 0.14"
39
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sublayer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Scott Werner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-03-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-openai
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: zeitwerk
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: nokogiri
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: httparty
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.12'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.12'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.14'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.14'
125
+ description: A DSL and framework for building AI powered applications through the
126
+ use of Generators, Actions, Tasks, and Agents
127
+ email:
128
+ - scott@sublayer.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - LICENSE
134
+ - README.md
135
+ - Rakefile
136
+ - examples/code_from_blueprint_generator.rb
137
+ - examples/code_from_description_generator.rb
138
+ - examples/description_from_code_generator.rb
139
+ - examples/invalid_to_valid_json_generator.rb
140
+ - lib/sublayer.rb
141
+ - lib/sublayer/components/output_adapters.rb
142
+ - lib/sublayer/components/output_adapters/single_string.rb
143
+ - lib/sublayer/generators/base.rb
144
+ - lib/sublayer/providers/claude.rb
145
+ - lib/sublayer/providers/gemini.rb
146
+ - lib/sublayer/providers/groq.rb
147
+ - lib/sublayer/providers/local.rb
148
+ - lib/sublayer/providers/open_ai.rb
149
+ - lib/sublayer/version.rb
150
+ - sublayer.gemspec
151
+ homepage: https://www.sublayer.com
152
+ licenses:
153
+ - MIT
154
+ metadata:
155
+ homepage_uri: https://www.sublayer.com
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: 2.6.0
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubygems_version: 3.3.26
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: A model-agnostic Ruby GenerativeAI DSL and Framework
175
+ test_files: []