sublayer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8254634ae1c2de3daa2f3a1fddf102df81ee82e79e345c1ef4a9256ea35553e2
4
- data.tar.gz: 7a2eb512a983ae642858af5c395d3651b69449359204975be9468b30736c6c40
3
+ metadata.gz: c0266ca3b856c768f521cf65a907ebe9d411f5420f83bfb62455912075253820
4
+ data.tar.gz: 1b32e201baa8f26e8caa3a124b4ebe9aeeb652b31745ec0fe6b06ab0cee57da2
5
5
  SHA512:
6
- metadata.gz: ea8183fce2be4f378a581d079a124df8c82b03165186575b6152576e76ca26fd93a925df6a108d1e348bdd393a71206d3e79ce832b000c9607224c9ea5fc46df
7
- data.tar.gz: a52f4942386fabe647fe97ee060747fa02e6f93c1261a33336bb14012383907419ad92e385c7fe4973df313dad8cc818f772063c8637ca81e318ba0b273430bb
6
+ metadata.gz: 417a853211fb739887936804948c5758d3880431b2b8252df5e3fc58beb6464f44d6f3e1efb0945b0e72a4f80b7135eec8b9813fbffbe9a6cfbe0c4a1d4bf63a
7
+ data.tar.gz: 4ee873c4e5edbe289211320573847cd58273b959e001ad3db8fadf68fdedc0bdc9e957b103573c3d31080acc69886dd58d0146906122192bd75fce1e24724d49
data/README.md CHANGED
@@ -14,12 +14,18 @@ for new features and bug fixes.
14
14
 
15
15
  To maintain stability in your application, we recommend pinning the version of
16
16
  Sublayer in your Gemfile to a specific minor version. For example, to pin to
17
- version 0.1.x, you would add the following line to your Gemfile:
17
+ version 0.2.x, you would add the following line to your Gemfile:
18
18
 
19
19
  ```ruby
20
- gem 'sublayer', '~> 0.1'
20
+ gem 'sublayer', '~> 0.2'
21
21
  ```
22
22
 
23
+ ## Notes on 0.2
24
+
25
+ New default model update: gpt 4 turbo -> gpt 4o
26
+
27
+ Gemini: Updates include the use of beta API function calling features. Experimental and unstable.
28
+
23
29
  ## Installation
24
30
 
25
31
  Install the gem by running the following commands:
@@ -29,12 +35,12 @@ Install the gem by running the following commands:
29
35
  Or add this line to your application's Gemfile:
30
36
 
31
37
  ```ruby
32
- gem 'sublayer', '~> 0.1'
38
+ gem 'sublayer', '~> 0.2'
33
39
  ```
34
40
 
35
41
  ## Choose your AI Model
36
42
 
37
- Sublayer is model-agnostic and can be used with any AI model. Below are the
43
+ Sublayer is model-agnostic and can be used with any AI model. Below are the supported LLM Providers. Check out our [docs](https://docs.sublayer.com) to add your own custom Provider.
38
44
 
39
45
  ### OpenAI (Default)
40
46
 
@@ -45,10 +51,12 @@ Visit [OpenAI](https://openai.com/product) to get an API key.
45
51
  Usage:
46
52
  ```ruby
47
53
  Sublayer.configuration.ai_provider = Sublayer::Providers::OpenAI
48
- Sublayer.configuration.ai_model = "gpt-4-turbo-preview"
54
+ Sublayer.configuration.ai_model = "gpt-4o"
49
55
  ```
50
56
 
51
- ### Gemini
57
+ ### Gemini [UNSTABLE]
58
+
59
+ (Gemini's function calling API is in beta. Not recommended for production use.)
52
60
 
53
61
  Expects you to have a Gemini API key set in the `GEMINI_API_KEY` environment variable.
54
62
 
@@ -57,7 +65,7 @@ Visit [Google AI Studio](https://ai.google.dev/) to get an API key.
57
65
  Usage:
58
66
  ```ruby
59
67
  Sublayer.configuration.ai_provider = Sublayer::Providers::Gemini
60
- Sublayer.configuration.ai_model = "gemini-pro"
68
+ Sublayer.configuration.ai_model = "gemini-1.5-pro"
61
69
  ```
62
70
 
63
71
  ### Claude
@@ -70,7 +78,7 @@ Visit [Anthropic](https://anthropic.com/) to get an API key.
70
78
  Usage:
71
79
  ```ruby
72
80
  Sublayer.configuration.ai_provider = Sublayer::Providers::Claude
73
- Sublayer.configuration.ai_model ="claude-3-opus-20240229"
81
+ Sublayer.configuration.ai_model ="claude-3-5-sonnet-20240620"
74
82
  ```
75
83
 
76
84
  ## Concepts
@@ -81,49 +89,46 @@ Generators are responsible for generating specific outputs based on input data.
81
89
  They focus on a single generation task and do not perform any actions or complex
82
90
  decision-making. Generators are the building blocks of the Sublayer framework.
83
91
 
84
- Examples (in the `/lib/sublayer/generators/examples` directory):
85
- - `CodeFromDescriptionGenerator`: Generates code based on a description and the
86
- technologies used.
87
- - `DescriptionFromCodeGenerator`: Generates a description of the code passed in to
88
- it.
89
- - `CodeFromBlueprintGenerator`: Generates code based on a blueprint, a blueprint
90
- description, and a description of the desired code.
92
+ Examples (in the `/spec/generators/examples` directory):
93
+ - [CodeFromDescriptionGenerator](https://github.com/sublayerapp/sublayer/blob/main/spec/generators/examples/code_from_description_generator.rb):
94
+ Generates code based on a description and the technologies used.
95
+ - [DescriptionFromCodeGenerator](https://github.com/sublayerapp/sublayer/blob/main/spec/generators/description_from_code_generator_spec.rb):
96
+ Generates a description of the code passed in to it.
97
+ - [CodeFromBlueprintGenerator](https://github.com/sublayerapp/sublayer/blob/main/spec/generators/examples/code_from_blueprint_generator.rb):
98
+ Generates code based on a blueprint, a blueprint description, and a description of the desired code.
91
99
 
92
100
 
93
- ### Actions (Coming Soon)
101
+ ### Actions
94
102
 
95
- Actions are responsible for performing specific operations to get inputs for a
96
- Generator or based on the generated output from a Generator. They encapsulate a
97
- single action and do not involve complex decision-making. Actions are the
98
- executable units that bring the generated inputs to life.
103
+ Actions perform specific operations to either get inputs for a Generator or use
104
+ the generated output from a Generator. Actions do not involve complex decision making.
99
105
 
100
106
  Examples:
101
- - SaveToFileAction: Saves generated output to a file.
102
- - RunCommandLineCommandAction: Runs a generated command line command.
107
+ - [WriteFileAction](https://github.com/sublayerapp/tddbot/blob/43297c5da9445bd6c8882d5e3876cff5fc6b2650/lib/tddbot/sublayer/actions/write_file_action.rb):
108
+ Saves generated output to a file.
109
+ - [RunTestCommandAction](https://github.com/sublayerapp/tddbot/blob/43297c5da9445bd6c8882d5e3876cff5fc6b2650/lib/tddbot/sublayer/actions/run_test_command_action.rb):
110
+ Runs a generated command line command.
103
111
 
104
- ### Tasks (Coming Soon)
112
+ ### Agents
105
113
 
106
- Tasks combine Generators and Actions to accomplish a specific goal. They involve
107
- a sequence of generation and action steps that may include basic decision-making
108
- and flow control. Tasks are the high-level building blocks that define the
109
- desired outcome.
114
+ Sublayer Agents are autonomous entities designed to perform specific
115
+ tasks or monitor systems.
110
116
 
111
117
  Examples:
112
- - ModifyFileContentsTask: Generates new file contents based on the existing
113
- contents and a set of rules, and then saves the new contents to the file.
118
+ - [RSpecAgent](https://github.com/sublayerapp/sublayer/blob/main/spec/agents/examples/rspec_agent.rb):
119
+ Runs tests whenever a file is changed. If the tests fail the code is changed
120
+ by the agent to pass the tests.
114
121
 
115
- ### Agents (Coming Soon)
122
+ ### Triggers
116
123
 
117
- Agents are high-level entities that coordinate and orchestrate multiple Tasks to
118
- achieve a broader goal. They involve complex decision-making, monitoring, and
119
- adaptation based on the outcomes of the Tasks. Agents are the intelligent
120
- supervisors that manage the overall workflow.
124
+ Sublayer Triggers are used in agents. Triggers decide when an agent is activated
125
+ and performs its task
121
126
 
122
127
  Examples:
123
- - CustomerSupportAgent: Handles customer support inquiries by using various
124
- Tasks such as understanding the customer's issue, generating appropriate
125
- responses, and performing actions like sending emails or creating support
126
- tickets.
128
+ - [FileChange](https://github.com/sublayerapp/sublayer/blob/main/lib/sublayer/triggers/file_change.rb):
129
+ This built in sublayer trigger, listens for file changes
130
+ - [TimeInterval](https://docs.sublayer.com/docs/guides/build-a-custom-trigger)
131
+ This custom trigger tutorial shows how to create your own trigger, this one activates on a time interval
127
132
 
128
133
  ## Usage Examples
129
134
 
@@ -0,0 +1,29 @@
1
+ module Sublayer
2
+ module Components
3
+ module OutputAdapters
4
+ module Formattable
5
+ def format_properties
6
+ 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
19
+ end
20
+ formatted_properties
21
+ end
22
+
23
+ def format_required
24
+ self.properties.select(&:required).map(&:name)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ module Sublayer
2
+ module Components
3
+ module OutputAdapters
4
+ class ListOfStrings
5
+ attr_reader :name, :description
6
+
7
+ def initialize(options)
8
+ @name = options[:name]
9
+ @description = options[:description]
10
+ end
11
+
12
+ def properties
13
+ [
14
+ OpenStruct.new(
15
+ name: @name,
16
+ type: 'array',
17
+ description: @description,
18
+ required: true,
19
+ items: {
20
+ type: 'string'
21
+ }
22
+ )
23
+ ]
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -18,6 +18,9 @@ module Sublayer
18
18
  else
19
19
  raise "Output adapter must be specified with :class or :type"
20
20
  end
21
+
22
+ options[:name] = options[:name].to_s if options[:name].is_a?(Symbol)
23
+
21
24
  klass.new(options)
22
25
  end
23
26
  end
@@ -4,7 +4,7 @@ module Sublayer
4
4
  attr_reader :results
5
5
 
6
6
  def self.llm_output_adapter(options)
7
- output_adapter = Sublayer::Components::OutputAdapters.create(options)
7
+ output_adapter = Sublayer::Components::OutputAdapters.create(options).extend(Sublayer::Components::OutputAdapters::Formattable)
8
8
  const_set(:OUTPUT_ADAPTER, output_adapter)
9
9
  end
10
10
 
@@ -1,5 +1,5 @@
1
1
  # Sublayer.configuration.ai_provider = Sublayer::Providers::Claude
2
- # Sublayer.configuration.ai_model ="claude-3-opus-20240229"
2
+ # Sublayer.configuration.ai_model ="claude-3-5-sonnet-20240620"
3
3
 
4
4
  module Sublayer
5
5
  module Providers
@@ -22,8 +22,8 @@ module Sublayer
22
22
  description: output_adapter.description,
23
23
  input_schema: {
24
24
  type: "object",
25
- properties: format_properties(output_adapter),
26
- required: output_adapter.properties.select(&:required).map(&:name)
25
+ properties: output_adapter.format_properties,
26
+ required: output_adapter.format_required
27
27
  }
28
28
  }
29
29
  ],
@@ -35,20 +35,6 @@ module Sublayer
35
35
  function_input = JSON.parse(response.body).dig("content").find {|content| content['type'] == 'tool_use'}.dig("input")
36
36
  function_input[output_adapter.name]
37
37
  end
38
-
39
- private
40
- def self.format_properties(output_adapter)
41
- output_adapter.properties.each_with_object({}) do |property, hash|
42
- hash[property.name] = {
43
- type: property.type,
44
- description: property.description
45
- }
46
-
47
- if property.enum
48
- hash[property.name][:enum] = property.enum
49
- end
50
- end
51
- end
52
38
  end
53
39
  end
54
40
  end
@@ -1,44 +1,41 @@
1
+ # *UNSTABLE* Gemini function calling API is in beta.
2
+ # Provider is not recommended until API update.
3
+
1
4
  # Sublayer.configuration.ai_provider = Sublayer::Providers::Gemini
2
- # Sublayer.configuration.ai_model = "gemini-pro"
5
+ # Sublayer.configuration.ai_model = "gemini-1.5-pro"
3
6
 
4
7
  module Sublayer
5
8
  module Providers
6
9
  class Gemini
7
10
  def self.call(prompt:, output_adapter:)
8
- system_prompt = <<-PROMPT
9
- You have access to a set of tools to answer the prompt.
10
-
11
- You may call tools like this:
12
- <tool_calls>
13
- <tool_call>
14
- <tool_name>$TOOL_NAME</tool_name>
15
- <parameters>
16
- <$PARAMETER_NAME>$VALUE</$PARAMETER_NAME>
17
- ...
18
- </parameters>
19
- </tool_call>
20
- </tool_calls>
21
-
22
- Here are the tools available:
23
- <tools>
24
- <tool_description>
25
- <tool_name>#{output_adapter.name}</tool_name>
26
- <tool_description>#{output_adapter.description}</tool_description>
27
- <parameters>
28
- #{format_properties(output_adapter)}
29
- </parameters>
30
- </tool_description>
31
- </tools>
32
-
33
- Respond only with valid xml.
34
- The entire response should be wrapped in a <response> tag.
35
- Your response should call a tool inside a <tool_calls> tag.
36
- PROMPT
37
-
38
11
  response = HTTParty.post(
39
12
  "https://generativelanguage.googleapis.com/v1beta/models/#{Sublayer.configuration.ai_model}:generateContent?key=#{ENV['GEMINI_API_KEY']}",
40
13
  body: {
41
- contents: { role: "user", parts: { text: "#{system_prompt}\n#{prompt}" } }
14
+ contents: {
15
+ role: "user",
16
+ parts: {
17
+ text: "#{prompt}"
18
+ },
19
+ },
20
+ tools: {
21
+ functionDeclarations: [
22
+ {
23
+ name: output_adapter.name,
24
+ description: output_adapter.description,
25
+ parameters: {
26
+ type: "OBJECT",
27
+ properties: output_adapter.format_properties,
28
+ required: output_adapter.format_required
29
+ }
30
+ }
31
+ ]
32
+ },
33
+ tool_config: {
34
+ function_calling_config: {
35
+ mode: "ANY",
36
+ allowed_function_names: [output_adapter.name]
37
+ }
38
+ }
42
39
  }.to_json,
43
40
  headers: {
44
41
  "Content-Type" => "application/json"
@@ -47,22 +44,7 @@ module Sublayer
47
44
 
48
45
  raise "Error generating with Gemini, error: #{response.body}" unless response.success?
49
46
 
50
- text_containing_xml = response.dig('candidates', 0, 'content', 'parts', 0, 'text')
51
- tool_output = Nokogiri::HTML.parse(text_containing_xml.match(/\<#{output_adapter.name}\>(.*?)\<\/#{output_adapter.name}\>/m)[1]).text
52
-
53
- raise "Gemini did not format response, error: #{response.body}" unless tool_output
54
- return tool_output
55
- end
56
-
57
- private
58
- def self.format_properties(output_adapter)
59
- output_adapter.properties.each_with_object("") do |property, xml|
60
- xml << "<name>#{property.name}</name>"
61
- xml << "<type>#{property.type}</type>"
62
- xml << "<description>#{property.description}</description>"
63
- xml << "<required>#{property.required}</required>"
64
- xml << "<enum>#{property.enum}</enum>" if property.enum
65
- end
47
+ argument = response.dig("candidates", 0, "content", "parts", 0, "functionCall", "args", output_adapter.name)
66
48
  end
67
49
  end
68
50
  end
@@ -1,5 +1,5 @@
1
1
  # Sublayer.configuration.ai_provider = Sublayer::Providers::OpenAI
2
- # Sublayer.configuration.ai_model = "gpt-4-turbo-preview"
2
+ # Sublayer.configuration.ai_model = "gpt-4o"
3
3
 
4
4
  module Sublayer
5
5
  module Providers
@@ -25,9 +25,9 @@ module Sublayer
25
25
  description: output_adapter.description,
26
26
  parameters: {
27
27
  type: "object",
28
- properties: OpenAI.format_properties(output_adapter)
28
+ properties: output_adapter.format_properties
29
29
  },
30
- required: [output_adapter.properties.select(&:required).map(&:name)]
30
+ required: output_adapter.format_required
31
31
  }
32
32
  }
33
33
  ]
@@ -41,20 +41,6 @@ module Sublayer
41
41
  function_body = message.dig("tool_calls", 0, "function", "arguments")
42
42
  JSON.parse(function_body)[output_adapter.name]
43
43
  end
44
-
45
- private
46
- def self.format_properties(output_adapter)
47
- output_adapter.properties.each_with_object({}) do |property, hash|
48
- hash[property.name] = {
49
- type: property.type,
50
- description: property.description
51
- }
52
-
53
- if property.enum
54
- hash[property.name][:enum] = property.enum
55
- end
56
- end
57
- end
58
44
  end
59
45
  end
60
46
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sublayer
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/sublayer.rb CHANGED
@@ -22,7 +22,7 @@ module Sublayer
22
22
  def self.configuration
23
23
  @configuration ||= OpenStruct.new(
24
24
  ai_provider: Sublayer::Providers::OpenAI,
25
- ai_model: "gpt-4-turbo-preview"
25
+ ai_model: "gpt-4o"
26
26
  )
27
27
  end
28
28
 
data/sublayer.gemspec CHANGED
@@ -41,6 +41,6 @@ Gem::Specification.new do |spec|
41
41
  spec.add_development_dependency "rspec", "~> 3.12"
42
42
  spec.add_development_dependency "pry", "~> 0.14"
43
43
  spec.add_development_dependency "vcr", "~> 6.0"
44
- spec.add_development_dependency "webmock", "~> 3.0"
44
+ spec.add_development_dependency "webmock", "~> 3"
45
45
  spec.add_development_dependency "clag"
46
46
  end
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.1.0
4
+ version: 0.2.0
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-07-11 00:00:00.000000000 Z
11
+ date: 2024-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-openai
@@ -156,14 +156,14 @@ dependencies:
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '3.0'
159
+ version: '3'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '3.0'
166
+ version: '3'
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: clag
169
169
  requirement: !ruby/object:Gem::Requirement
@@ -193,6 +193,8 @@ files:
193
193
  - lib/sublayer/actions/base.rb
194
194
  - lib/sublayer/agents/base.rb
195
195
  - lib/sublayer/components/output_adapters.rb
196
+ - lib/sublayer/components/output_adapters/formattable.rb
197
+ - lib/sublayer/components/output_adapters/list_of_strings.rb
196
198
  - lib/sublayer/components/output_adapters/single_string.rb
197
199
  - lib/sublayer/components/output_adapters/string_selection_from_list.rb
198
200
  - lib/sublayer/generators/base.rb
@@ -227,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
229
  - !ruby/object:Gem::Version
228
230
  version: '0'
229
231
  requirements: []
230
- rubygems_version: 3.3.26
232
+ rubygems_version: 3.5.3
231
233
  signing_key:
232
234
  specification_version: 4
233
235
  summary: A model-agnostic Ruby GenerativeAI DSL and Framework