clag 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/clag.gemspec +1 -0
- data/exe/clag +1 -3
- data/lib/clag/commands/generate.rb +1 -1
- data/lib/clag/generators/command_line_command_generator.rb +29 -0
- data/lib/clag/version.rb +1 -1
- data/lib/clag.rb +19 -1
- metadata +17 -23
- data/vendor/gems/sublayer/.gitignore +0 -16
- data/vendor/gems/sublayer/Gemfile +0 -6
- data/vendor/gems/sublayer/LICENSE +0 -21
- data/vendor/gems/sublayer/README.md +0 -52
- data/vendor/gems/sublayer/Rakefile +0 -8
- data/vendor/gems/sublayer/lib/sublayer/agents/generate_code_given_description_agent.rb +0 -35
- data/vendor/gems/sublayer/lib/sublayer/agents/generate_command_agent.rb +0 -37
- data/vendor/gems/sublayer/lib/sublayer/agents/json_fixing_agent.rb +0 -32
- data/vendor/gems/sublayer/lib/sublayer/agents/modify_file_contents_agent.rb +0 -38
- data/vendor/gems/sublayer/lib/sublayer/agents/save_file_contents_agent.rb +0 -18
- data/vendor/gems/sublayer/lib/sublayer/capabilities/human_assistance.rb +0 -23
- data/vendor/gems/sublayer/lib/sublayer/capabilities/llm_assistance.rb +0 -253
- data/vendor/gems/sublayer/lib/sublayer/components/output_function.rb +0 -22
- data/vendor/gems/sublayer/lib/sublayer/components/output_function_formats/list_of_objects.rb +0 -30
- data/vendor/gems/sublayer/lib/sublayer/components/output_function_formats/single_string.rb +0 -40
- data/vendor/gems/sublayer/lib/sublayer/enhancements/json.rb +0 -9
- data/vendor/gems/sublayer/lib/sublayer/version.rb +0 -5
- data/vendor/gems/sublayer/lib/sublayer.rb +0 -47
- data/vendor/gems/sublayer/spec/components/output_function_spec.rb +0 -73
- data/vendor/gems/sublayer/spec/spec_helper.rb +0 -15
- data/vendor/gems/sublayer/sublayer.gemspec +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f27cc2c8372c73257a2455613a3f5db566301ce249dc5e0b8d6812a16795f1ea
|
4
|
+
data.tar.gz: 2886e0b99f0d5443c66bc19087a96584674927e320de67eea79115a9f734015d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1efa37ed3818cb1b5778e76c5eaccebbb732529cafe66da308964abf3be10047fec073b232e0134b41188b748090752b95d7d542b6d82bb6cd3bc2c841be29fe
|
7
|
+
data.tar.gz: 40619d05e7bd9fc2c3f17aa42f615914d2e2f8fb569304ebaf04f04bdfaa056a844a3dceb489d39769faa14c104de927319b0ecb3b28ae938f6bbfabea40374d
|
data/clag.gemspec
CHANGED
data/exe/clag
CHANGED
@@ -8,10 +8,8 @@ unshift_path = ->(path) {
|
|
8
8
|
$LOAD_PATH.unshift(p) unless $LOAD_PATH.include?(p)
|
9
9
|
}
|
10
10
|
unshift_path.call('lib')
|
11
|
-
require 'bundler/setup'
|
12
|
-
|
13
|
-
unshift_path.call('vendor/gems/sublayer/lib')
|
14
11
|
|
12
|
+
require 'bundler/setup'
|
15
13
|
require 'clag'
|
16
14
|
|
17
15
|
exit(Clag::ErrorHandler.call do
|
@@ -17,7 +17,7 @@ module Clag
|
|
17
17
|
return
|
18
18
|
end
|
19
19
|
|
20
|
-
results =
|
20
|
+
results = Clag::CommandLineCommandGenerator.new(description: input).generate
|
21
21
|
|
22
22
|
if results == 'unknown'
|
23
23
|
puts CLI::UI.fmt("{{yellow:Unable to generate command. Please try again or provide more information.}}")
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Clag
|
2
|
+
class CommandLineCommandGenerator < Sublayer::Generators::Base
|
3
|
+
llm_output_adapter type: :single_string,
|
4
|
+
name: "command",
|
5
|
+
description: "The command line command for the user to run or 'unknown'"
|
6
|
+
|
7
|
+
def initialize(description:)
|
8
|
+
@description = description
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def prompt
|
16
|
+
<<-PROMPT
|
17
|
+
You are an expert in command line operations.
|
18
|
+
|
19
|
+
You are tasked with finding or crafting a command line command to achieve the following:
|
20
|
+
|
21
|
+
#{@description}
|
22
|
+
|
23
|
+
Considering best practices, what should be run on the command line to achieve this.
|
24
|
+
|
25
|
+
If no command is possible, respond with 'unknown'
|
26
|
+
PROMPT
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/clag/version.rb
CHANGED
data/lib/clag.rb
CHANGED
@@ -11,7 +11,7 @@ module Clag
|
|
11
11
|
|
12
12
|
autoload(:EntryPoint, 'clag/entry_point')
|
13
13
|
autoload(:Commands, 'clag/commands')
|
14
|
-
|
14
|
+
load 'clag/generators/command_line_command_generator.rb'
|
15
15
|
|
16
16
|
Config = CLI::Kit::Config.new(tool_name: TOOL_NAME)
|
17
17
|
Command = CLI::Kit::BaseCommand
|
@@ -23,4 +23,22 @@ module Clag
|
|
23
23
|
)
|
24
24
|
|
25
25
|
ErrorHandler = CLI::Kit::ErrorHandler.new(log_file: LOG_FILE)
|
26
|
+
|
27
|
+
case ENV["CLAG_LLM"]
|
28
|
+
when "gemini"
|
29
|
+
Sublayer.configuration.ai_provider = Sublayer::Providers::Gemini
|
30
|
+
Sublayer.configuration.ai_model = "gemini-pro"
|
31
|
+
when "claude"
|
32
|
+
Sublayer.configuration.ai_provider = Sublayer::Providers::Claude
|
33
|
+
Sublayer.configuration.ai_model ="claude-3-opus-20240229"
|
34
|
+
when "groq"
|
35
|
+
Sublayer.configuration.ai_provider = Sublayer::Providers::Groq
|
36
|
+
Sublayer.configuration.ai_model = "mixtral-8x7b-32768"
|
37
|
+
when "local"
|
38
|
+
Sublayer.configuration.ai_provider = Sublayer::Providers::Local
|
39
|
+
Sublayer.configuration.ai_model = "LLaMA_CPP"
|
40
|
+
else
|
41
|
+
Sublayer.configuration.ai_provider = Sublayer::Providers::OpenAI
|
42
|
+
Sublayer.configuration.ai_model = "gpt-4-turbo-preview"
|
43
|
+
end
|
26
44
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Werner
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cli-kit
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: sublayer
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: rake
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,30 +172,10 @@ files:
|
|
158
172
|
- lib/clag/commands/generate.rb
|
159
173
|
- lib/clag/commands/help.rb
|
160
174
|
- lib/clag/entry_point.rb
|
175
|
+
- lib/clag/generators/command_line_command_generator.rb
|
161
176
|
- lib/clag/version.rb
|
162
177
|
- test/example_test.rb
|
163
178
|
- test/test_helper.rb
|
164
|
-
- vendor/gems/sublayer/.gitignore
|
165
|
-
- vendor/gems/sublayer/Gemfile
|
166
|
-
- vendor/gems/sublayer/LICENSE
|
167
|
-
- vendor/gems/sublayer/README.md
|
168
|
-
- vendor/gems/sublayer/Rakefile
|
169
|
-
- vendor/gems/sublayer/lib/sublayer.rb
|
170
|
-
- vendor/gems/sublayer/lib/sublayer/agents/generate_code_given_description_agent.rb
|
171
|
-
- vendor/gems/sublayer/lib/sublayer/agents/generate_command_agent.rb
|
172
|
-
- vendor/gems/sublayer/lib/sublayer/agents/json_fixing_agent.rb
|
173
|
-
- vendor/gems/sublayer/lib/sublayer/agents/modify_file_contents_agent.rb
|
174
|
-
- vendor/gems/sublayer/lib/sublayer/agents/save_file_contents_agent.rb
|
175
|
-
- vendor/gems/sublayer/lib/sublayer/capabilities/human_assistance.rb
|
176
|
-
- vendor/gems/sublayer/lib/sublayer/capabilities/llm_assistance.rb
|
177
|
-
- vendor/gems/sublayer/lib/sublayer/components/output_function.rb
|
178
|
-
- vendor/gems/sublayer/lib/sublayer/components/output_function_formats/list_of_objects.rb
|
179
|
-
- vendor/gems/sublayer/lib/sublayer/components/output_function_formats/single_string.rb
|
180
|
-
- vendor/gems/sublayer/lib/sublayer/enhancements/json.rb
|
181
|
-
- vendor/gems/sublayer/lib/sublayer/version.rb
|
182
|
-
- vendor/gems/sublayer/spec/components/output_function_spec.rb
|
183
|
-
- vendor/gems/sublayer/spec/spec_helper.rb
|
184
|
-
- vendor/gems/sublayer/sublayer.gemspec
|
185
179
|
homepage: https://github.com/sublayerapp/clag
|
186
180
|
licenses:
|
187
181
|
- MIT
|
@@ -1,21 +0,0 @@
|
|
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.
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# Sublayer
|
2
|
-
|
3
|
-
An AI agent framework
|
4
|
-
|
5
|
-
## Installation
|
6
|
-
|
7
|
-
Install the gem by running the following commands:
|
8
|
-
|
9
|
-
$ bundle
|
10
|
-
$ gem build sublayer.gemspec
|
11
|
-
$ gem install sublayer-0.0.1.gem
|
12
|
-
|
13
|
-
Your OpenAI API key needs to be accessible in your environment at OPENAI\_API\_KEY
|
14
|
-
|
15
|
-
Your default editor for your environment is also used.
|
16
|
-
|
17
|
-
## Usage
|
18
|
-
|
19
|
-
### * Interactive CLI
|
20
|
-
|
21
|
-
You can use the gem by running the command `sublayer` in any project directory.
|
22
|
-
This will open an interactive shell where all file operations are run relative
|
23
|
-
to that root project directory.
|
24
|
-
|
25
|
-
In the interactive shell, you're able to create new agents specific to your
|
26
|
-
project, generate code, modify existing files, and save the resulting code from
|
27
|
-
those agent commands.
|
28
|
-
|
29
|
-
### * Simple TDD Pair (experimental / dangerous)
|
30
|
-
|
31
|
-
**Warning:** This will generate code from GPT4 and run it as called from your
|
32
|
-
tests. Use at your own risk.
|
33
|
-
|
34
|
-
Usage: `sublayer_simple_tdd_pair "TEST_RUN_COMMAND" "FILE_UNDER_TEST"`
|
35
|
-
|
36
|
-
This command will run the TEST_RUN_COMMAND, send the test output, the tests, and
|
37
|
-
the FILE\_UNDER\_TEST to GPT4 and will attempt to edit FILE\_UNDER\_TEST and
|
38
|
-
rerun the tests until they pass.
|
39
|
-
|
40
|
-
To do use it like in [this
|
41
|
-
loom](https://www.loom.com/share/6970b51856b04a91b792f14e848e9b6d) you'll need
|
42
|
-
to install entr: `brew install entr`
|
43
|
-
|
44
|
-
The command I'm running there is: `ls ./day3/*.rb | entr sublayer_simple_tdd_pair "rspec ./day3/santa_spec.rb" "./day3/santa.rb"`
|
45
|
-
|
46
|
-
## Development
|
47
|
-
|
48
|
-
TBD
|
49
|
-
|
50
|
-
## Contributing
|
51
|
-
|
52
|
-
TBD
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Agents
|
3
|
-
class GenerateCodeGivenDescriptionAgent
|
4
|
-
include Sublayer::Capabilities::LLMAssistance
|
5
|
-
include Sublayer::Capabilities::HumanAssistance
|
6
|
-
|
7
|
-
attr_reader :description, :technologies, :results
|
8
|
-
|
9
|
-
llm_result_format type: :single_string,
|
10
|
-
name: "generated_code",
|
11
|
-
description: "The generated code in the requested language"
|
12
|
-
|
13
|
-
def initialize(description:, technologies:)
|
14
|
-
@description = description
|
15
|
-
@technologies = technologies
|
16
|
-
end
|
17
|
-
|
18
|
-
def execute
|
19
|
-
@results = human_assistance_with(llm_generate)
|
20
|
-
end
|
21
|
-
|
22
|
-
def prompt
|
23
|
-
<<-PROMPT
|
24
|
-
You are an expert programmer in #{technologies.join(", ")}.
|
25
|
-
|
26
|
-
You are tasked with writing code using the following technologies: #{technologies.join(", ")}.
|
27
|
-
|
28
|
-
The description of the task is #{description}
|
29
|
-
|
30
|
-
Take a deep breath and think step by step before you start coding.
|
31
|
-
PROMPT
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Agents
|
3
|
-
class GenerateCommandLineCommandAgent
|
4
|
-
include Sublayer::Capabilities::LLMAssistance
|
5
|
-
include Sublayer::Capabilities::HumanAssistance
|
6
|
-
|
7
|
-
attr_reader :description, :results
|
8
|
-
|
9
|
-
llm_result_format type: :single_string,
|
10
|
-
name: "command",
|
11
|
-
description: "The command line command for the user to run or 'unknown'"
|
12
|
-
|
13
|
-
def initialize(description:)
|
14
|
-
@description = description
|
15
|
-
end
|
16
|
-
|
17
|
-
def execute
|
18
|
-
@results = llm_generate
|
19
|
-
end
|
20
|
-
|
21
|
-
def prompt
|
22
|
-
<<-PROMPT
|
23
|
-
You are an expert in command line operations.
|
24
|
-
|
25
|
-
You are tasked with finding or crafting a command line command to achieve the following:
|
26
|
-
|
27
|
-
#{description}
|
28
|
-
|
29
|
-
Considering best practices, what should be run on the command line to achieve this.
|
30
|
-
|
31
|
-
If no command is possible, respond with 'unknown'
|
32
|
-
|
33
|
-
PROMPT
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Agents
|
3
|
-
class JSONFixingAgent
|
4
|
-
include Sublayer::Capabilities::LLMAssistance
|
5
|
-
include Sublayer::Capabilities::HumanAssistance
|
6
|
-
|
7
|
-
attr_reader :invalid_json, :results
|
8
|
-
|
9
|
-
llm_result_format type: :single_string,
|
10
|
-
name: "valid_json",
|
11
|
-
description: "The valid JSON string"
|
12
|
-
|
13
|
-
def initialize(invalid_json:)
|
14
|
-
@invalid_json = invalid_json
|
15
|
-
end
|
16
|
-
|
17
|
-
def execute
|
18
|
-
@results = llm_generate
|
19
|
-
end
|
20
|
-
|
21
|
-
def prompt
|
22
|
-
<<-PROMPT
|
23
|
-
You are an expert in JSON parsing.
|
24
|
-
|
25
|
-
The given string is not a valid JSON: #{invalid_json}
|
26
|
-
|
27
|
-
Please fix this and produce a valid JSON.
|
28
|
-
PROMPT
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Agents
|
3
|
-
class ModifyFileContentsAgent
|
4
|
-
include Sublayer::Capabilities::LLMAssistance
|
5
|
-
include Sublayer::Capabilities::HumanAssistance
|
6
|
-
|
7
|
-
attr_reader :file_path, :description, :technologies, :results
|
8
|
-
|
9
|
-
llm_result_format type: :single_string,
|
10
|
-
name: "modified_file_contents",
|
11
|
-
description: "The modified file contents"
|
12
|
-
|
13
|
-
def initialize(file_path:, description:, technologies:)
|
14
|
-
@file_path = file_path
|
15
|
-
@description = description
|
16
|
-
@technologies = technologies
|
17
|
-
end
|
18
|
-
|
19
|
-
def execute
|
20
|
-
@results = human_assistance_with(llm_generate)
|
21
|
-
end
|
22
|
-
|
23
|
-
def prompt
|
24
|
-
<<-PROMPT
|
25
|
-
You are an expert programmer in #{technologies.join(", ")}.
|
26
|
-
|
27
|
-
Here are the original file contents:
|
28
|
-
|
29
|
-
#{File.read(@file_path)}
|
30
|
-
|
31
|
-
The description of the changes to make is: #{description}
|
32
|
-
|
33
|
-
Please make the necessary changes to this file.
|
34
|
-
PROMPT
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Agents
|
3
|
-
class SaveFileContentsAgent
|
4
|
-
attr_reader :file_contents, :file_path
|
5
|
-
|
6
|
-
def initialize(file_contents:, file_path:)
|
7
|
-
@file_contents = file_contents
|
8
|
-
@file_path = file_path
|
9
|
-
end
|
10
|
-
|
11
|
-
def execute
|
12
|
-
File.open(file_path, "w") do |file|
|
13
|
-
file.write(file_contents)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require "tempfile"
|
2
|
-
|
3
|
-
module Sublayer
|
4
|
-
module Capabilities
|
5
|
-
module HumanAssistance
|
6
|
-
def human_assistance_with(string_to_assist_with)
|
7
|
-
tempfile = Tempfile.new("some_tempfile_to_assist_with")
|
8
|
-
tempfile.write(string_to_assist_with)
|
9
|
-
tempfile.close
|
10
|
-
|
11
|
-
system("$EDITOR #{tempfile.path}")
|
12
|
-
|
13
|
-
tempfile.open
|
14
|
-
results = tempfile.read
|
15
|
-
|
16
|
-
tempfile.close
|
17
|
-
tempfile.unlink
|
18
|
-
|
19
|
-
results.chomp
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,253 +0,0 @@
|
|
1
|
-
require "openai"
|
2
|
-
require "pry"
|
3
|
-
require "httparty"
|
4
|
-
require "nokogiri"
|
5
|
-
|
6
|
-
module Sublayer
|
7
|
-
module Capabilities
|
8
|
-
module LLMAssistance
|
9
|
-
def self.included(base)
|
10
|
-
base.extend(ClassMethods)
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
def llm_result_format(type:, name:, description:)
|
15
|
-
output_function = Sublayer::Components::OutputFunction.create(type: type, name: name, description: description)
|
16
|
-
const_set(:OUTPUT_FUNCTION, output_function)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def llm_generate
|
21
|
-
case ENV["CLAG_LLM"]
|
22
|
-
when "gemini"
|
23
|
-
generate_with_gemini
|
24
|
-
when "claude"
|
25
|
-
generate_with_claude
|
26
|
-
when "groq"
|
27
|
-
generate_with_groq
|
28
|
-
when "local"
|
29
|
-
generate_with_local_model
|
30
|
-
else
|
31
|
-
generate_with_openai
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def generate_with_local_model
|
38
|
-
system_prompt = <<-PROMPT
|
39
|
-
In this environment you have access to a set of tools you can use to answer the user's question.
|
40
|
-
|
41
|
-
You may call them like this:
|
42
|
-
<function_calls>
|
43
|
-
<invoke>
|
44
|
-
<tool_name>$TOOL_NAME</tool_name>
|
45
|
-
<parameters>
|
46
|
-
<command>value</command>
|
47
|
-
...
|
48
|
-
</parameters>
|
49
|
-
</invoke>
|
50
|
-
</function_calls>
|
51
|
-
|
52
|
-
Here are the tools available:
|
53
|
-
<tools>
|
54
|
-
#{self.class::OUTPUT_FUNCTION.to_xml}
|
55
|
-
</tools>
|
56
|
-
|
57
|
-
Respond only with valid xml.
|
58
|
-
The entire response should be wrapped in a <response> tag.
|
59
|
-
Any additional information not inside a tool call should go in a <scratch> tag.
|
60
|
-
PROMPT
|
61
|
-
|
62
|
-
response = HTTParty.post(
|
63
|
-
"http://localhost:8080/v1/chat/completions",
|
64
|
-
headers: {
|
65
|
-
"Authorization": "Bearer no-key",
|
66
|
-
"Content-Type": "application/json"
|
67
|
-
},
|
68
|
-
body: {
|
69
|
-
"model": "LLaMA_CPP",
|
70
|
-
"messages": [
|
71
|
-
{ "role": "system", "content": system_prompt },
|
72
|
-
{ "role": "user", "content": prompt }
|
73
|
-
]
|
74
|
-
}.to_json
|
75
|
-
)
|
76
|
-
|
77
|
-
text_containing_xml = JSON.parse(response.body).dig("choices", 0, "message", "content")
|
78
|
-
xml = text_containing_xml.match(/\<response\>(.*?)\<\/response\>/m).to_s
|
79
|
-
response_xml = Nokogiri::XML(xml)
|
80
|
-
function_output = response_xml.at_xpath("//parameters/command").children.to_s
|
81
|
-
|
82
|
-
return function_output
|
83
|
-
end
|
84
|
-
|
85
|
-
def generate_with_groq
|
86
|
-
system_prompt = <<-PROMPT
|
87
|
-
In this environment you have access to a set of tools you can use to answer the user's question.
|
88
|
-
|
89
|
-
You may call them like this:
|
90
|
-
<function_calls>
|
91
|
-
<invoke>
|
92
|
-
<tool_name>$TOOL_NAME</tool_name>
|
93
|
-
<parameters>
|
94
|
-
<command>value</command>
|
95
|
-
...
|
96
|
-
</parameters>
|
97
|
-
</invoke>
|
98
|
-
</function_calls>
|
99
|
-
|
100
|
-
Here are the tools available:
|
101
|
-
<tools>
|
102
|
-
#{self.class::OUTPUT_FUNCTION.to_xml}
|
103
|
-
</tools>
|
104
|
-
|
105
|
-
Respond only with valid xml.
|
106
|
-
The entire response should be wrapped in a <response> tag.
|
107
|
-
Any additional information not inside a tool call should go in a <scratch> tag.
|
108
|
-
PROMPT
|
109
|
-
|
110
|
-
response = HTTParty.post(
|
111
|
-
"https://api.groq.com/openai/v1/chat/completions",
|
112
|
-
headers: {
|
113
|
-
"Authorization": "Bearer #{ENV["GROQ_API_KEY"]}",
|
114
|
-
"Content-Type": "application/json"
|
115
|
-
},
|
116
|
-
body: {
|
117
|
-
"messages": [{"role": "user", "content": "#{system_prompt}\n#{prompt}"}],
|
118
|
-
"model": "mixtral-8x7b-32768"
|
119
|
-
}.to_json
|
120
|
-
)
|
121
|
-
|
122
|
-
text_containing_xml = JSON.parse(response.body).dig("choices", 0, "message", "content")
|
123
|
-
xml = text_containing_xml.match(/\<response\>(.*?)\<\/response\>/m).to_s
|
124
|
-
response_xml = Nokogiri::XML(xml)
|
125
|
-
function_output = response_xml.at_xpath("//response/function_calls/invoke/parameters/command").children.to_s
|
126
|
-
|
127
|
-
return function_output
|
128
|
-
end
|
129
|
-
|
130
|
-
def generate_with_claude
|
131
|
-
system_prompt = <<-PROMPT
|
132
|
-
In this environment you have access to a set of tools you can use to answer the user's question.
|
133
|
-
|
134
|
-
You may call them like this:
|
135
|
-
<function_calls>
|
136
|
-
<invoke>
|
137
|
-
<tool_name>$TOOL_NAME</tool_name>
|
138
|
-
<parameters>
|
139
|
-
<$PARAMETER_NAME>$PARAMETER_VALUE</$PARAMETER_NAME>
|
140
|
-
...
|
141
|
-
</parameters>
|
142
|
-
</invoke>
|
143
|
-
</function_calls>
|
144
|
-
|
145
|
-
Here are the tools available:
|
146
|
-
<tools>
|
147
|
-
#{self.class::OUTPUT_FUNCTION.to_xml}
|
148
|
-
</tools>
|
149
|
-
|
150
|
-
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.
|
151
|
-
PROMPT
|
152
|
-
|
153
|
-
response = HTTParty.post(
|
154
|
-
"https://api.anthropic.com/v1/messages",
|
155
|
-
headers: {
|
156
|
-
"x-api-key": ENV["ANTHROPIC_API_KEY"],
|
157
|
-
"anthropic-version": "2023-06-01",
|
158
|
-
"content-type": "application/json"
|
159
|
-
},
|
160
|
-
body: {
|
161
|
-
model: "claude-3-opus-20240229",
|
162
|
-
max_tokens: 1337,
|
163
|
-
system: system_prompt,
|
164
|
-
messages: [
|
165
|
-
{ "role": "user", "content": prompt }
|
166
|
-
]
|
167
|
-
}.to_json
|
168
|
-
)
|
169
|
-
|
170
|
-
# raise an error if the response is not a 200
|
171
|
-
raise "Error generating with Claude, error: #{response.body}" unless response.code == 200
|
172
|
-
|
173
|
-
text_containing_xml = JSON.parse(response.body).dig("content", 0, "text")
|
174
|
-
|
175
|
-
# Extract the xml from the respons contained in <response> tags the content of the string looksl ike this:
|
176
|
-
xml = text_containing_xml.match(/\<response\>(.*?)\<\/response\>/m).to_s
|
177
|
-
|
178
|
-
# Parse the xml and extract the response
|
179
|
-
response_xml = Nokogiri::XML(xml)
|
180
|
-
|
181
|
-
# Extract the response from the xml
|
182
|
-
function_output = response_xml.at_xpath("//response/function_calls/invoke/parameters/command").children.to_s
|
183
|
-
|
184
|
-
return function_output
|
185
|
-
end
|
186
|
-
|
187
|
-
def generate_with_gemini
|
188
|
-
gemini_prompt = adapt_prompt_for_gemini
|
189
|
-
|
190
|
-
response = HTTParty.post("https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=#{ENV['GEMINI_API_KEY']}", body: gemini_prompt.to_json, headers: { 'Content-Type' => 'application/json' })
|
191
|
-
|
192
|
-
function_output = extract_function_output_from_gemini_response(response)
|
193
|
-
|
194
|
-
return function_output
|
195
|
-
end
|
196
|
-
|
197
|
-
def adapt_prompt_for_gemini
|
198
|
-
return({ tools: { function_declarations: [ self.class::OUTPUT_FUNCTION.to_hash ] }, contents: { role: "user", parts: { text: prompt } } })
|
199
|
-
end
|
200
|
-
|
201
|
-
def extract_function_output_from_gemini_response(response)
|
202
|
-
candidates = response.dig('candidates')
|
203
|
-
if candidates && candidates.size > 0
|
204
|
-
content = candidates[0].dig('content')
|
205
|
-
if content && content['parts'] && content['parts'].size > 0
|
206
|
-
part = content['parts'][0]
|
207
|
-
|
208
|
-
# Check if the part contains a function call
|
209
|
-
if part.key?('functionCall')
|
210
|
-
function_name = part['functionCall']['name']
|
211
|
-
args = part['functionCall']['args']
|
212
|
-
|
213
|
-
# Assuming the agent expects a single string parameter:
|
214
|
-
if args && args.key?(self.class::OUTPUT_FUNCTION.name)
|
215
|
-
return args[self.class::OUTPUT_FUNCTION.name]
|
216
|
-
end
|
217
|
-
else
|
218
|
-
# If it's not a function call, check for a direct string response
|
219
|
-
return part['text'] if part.key?('text')
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def generate_with_openai
|
226
|
-
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
|
227
|
-
|
228
|
-
response = client.chat(
|
229
|
-
parameters: {
|
230
|
-
model: "gpt-4-turbo-preview",
|
231
|
-
messages: [
|
232
|
-
{
|
233
|
-
"role": "user",
|
234
|
-
"content": prompt
|
235
|
-
}
|
236
|
-
],
|
237
|
-
function_call: { name: self.class::OUTPUT_FUNCTION.name },
|
238
|
-
functions: [
|
239
|
-
self.class::OUTPUT_FUNCTION.to_hash
|
240
|
-
]
|
241
|
-
}
|
242
|
-
)
|
243
|
-
|
244
|
-
message = response.dig("choices", 0, "message")
|
245
|
-
raise "No function called" unless message["function_call"]
|
246
|
-
|
247
|
-
function_name = message.dig("function_call", self.class::OUTPUT_FUNCTION.name)
|
248
|
-
args_from_llm = message.dig("function_call", "arguments")
|
249
|
-
JSON.parse(args_from_llm)[self.class::OUTPUT_FUNCTION.name]
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Components
|
3
|
-
class OutputFunction
|
4
|
-
include Sublayer::Components
|
5
|
-
|
6
|
-
attr_reader :name
|
7
|
-
|
8
|
-
def self.create(options)
|
9
|
-
("Sublayer::Components::"+options[:type].to_s.camelize).constantize.new(options)
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_hash
|
13
|
-
# Raise not implemented error
|
14
|
-
raise NotImplementedError
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_xml
|
18
|
-
raise NotImplementedError
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
data/vendor/gems/sublayer/lib/sublayer/components/output_function_formats/list_of_objects.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Components
|
3
|
-
class ListOfObjects < OutputFunction
|
4
|
-
def initialize(options)
|
5
|
-
@name = options[:name]
|
6
|
-
@description = options[:description]
|
7
|
-
@structure = options[:structure]
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_hash
|
11
|
-
{
|
12
|
-
name: @name,
|
13
|
-
description: @description,
|
14
|
-
parameters: {
|
15
|
-
type: "object",
|
16
|
-
properties: {
|
17
|
-
@name.to_sym => {
|
18
|
-
type: "array",
|
19
|
-
items: {
|
20
|
-
type: "object",
|
21
|
-
properties: @structure.transform_values { |desc| { type: "string", description: desc.capitalize } }
|
22
|
-
}
|
23
|
-
}
|
24
|
-
}
|
25
|
-
}
|
26
|
-
}
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Sublayer
|
2
|
-
module Components
|
3
|
-
class SingleString < OutputFunction
|
4
|
-
def initialize(options)
|
5
|
-
@name = options[:name]
|
6
|
-
@description = options[:description]
|
7
|
-
end
|
8
|
-
|
9
|
-
def to_hash
|
10
|
-
{
|
11
|
-
name: @name,
|
12
|
-
description: @description,
|
13
|
-
parameters: {
|
14
|
-
type: "object",
|
15
|
-
properties: {
|
16
|
-
@name => {
|
17
|
-
type: "string",
|
18
|
-
description: @description
|
19
|
-
}
|
20
|
-
}
|
21
|
-
}
|
22
|
-
}
|
23
|
-
end
|
24
|
-
|
25
|
-
def to_xml
|
26
|
-
<<-XML
|
27
|
-
<tool_description>
|
28
|
-
<tool_name>#{@name}</tool_name>
|
29
|
-
<tool_description>#{@description}</tool_description>
|
30
|
-
<parameters>
|
31
|
-
<name>#{@name}</name>
|
32
|
-
<type>string</type>
|
33
|
-
<description>#{@description}</description>
|
34
|
-
</parameters>
|
35
|
-
</tool_description>
|
36
|
-
XML
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support'
|
4
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
5
|
-
require 'active_support/inflector'
|
6
|
-
require_relative "sublayer/version"
|
7
|
-
|
8
|
-
if !File.directory?(File.join(Dir.pwd, ".sublayer", "agents"))
|
9
|
-
Dir.mkdir(File.join(Dir.pwd, ".sublayer"))
|
10
|
-
Dir.mkdir(File.join(Dir.pwd, ".sublayer", "agents"))
|
11
|
-
end
|
12
|
-
|
13
|
-
# List of directories to load files from
|
14
|
-
LOAD_PATHS = [
|
15
|
-
File.join(__dir__, 'sublayer', 'components'),
|
16
|
-
File.join(__dir__, 'sublayer', 'components', 'output_function_formats'),
|
17
|
-
File.join(__dir__, 'sublayer', 'capabilities'),
|
18
|
-
File.join(__dir__, 'sublayer', 'agents'),
|
19
|
-
File.join(Dir.pwd, '.sublayer', 'agents')
|
20
|
-
]
|
21
|
-
|
22
|
-
|
23
|
-
# Load files from each directory in the list
|
24
|
-
LOAD_PATHS.each do |load_path|
|
25
|
-
Dir.glob(File.join(load_path, '*.rb')).each do |file|
|
26
|
-
require_relative file
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
require_relative "sublayer/enhancements/json.rb"
|
31
|
-
|
32
|
-
module Sublayer
|
33
|
-
class Error < StandardError; end
|
34
|
-
|
35
|
-
# Defines a method to reload all the agents
|
36
|
-
def self.reload_agents
|
37
|
-
LOAD_PATHS.each do |load_path|
|
38
|
-
Dir.glob(File.join(load_path, '*.rb')) do |file|
|
39
|
-
load file
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.cwd
|
45
|
-
Dir.pwd
|
46
|
-
end
|
47
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
RSpec.describe Sublayer::Components::OutputFunction do
|
4
|
-
describe "#to_hash" do
|
5
|
-
context "type: :single_string" do
|
6
|
-
it "formats the hash output correctly" do
|
7
|
-
output_function = Sublayer::Components::OutputFunction.create(type: :single_string, name: "modified_file_contents", description: "The modified file contents")
|
8
|
-
expect(output_function.to_hash).to eq(
|
9
|
-
{
|
10
|
-
name: "modified_file_contents",
|
11
|
-
description: "The modified file contents",
|
12
|
-
parameters: {
|
13
|
-
type: "object",
|
14
|
-
properties: {
|
15
|
-
"modified_file_contents" => {
|
16
|
-
type: "string",
|
17
|
-
description: "The modified file contents"
|
18
|
-
}
|
19
|
-
}
|
20
|
-
}
|
21
|
-
}
|
22
|
-
)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "type: :list_of_objects" do
|
27
|
-
it "formats the hash output correctly" do
|
28
|
-
output_function = Sublayer::Components::OutputFunction.create(
|
29
|
-
type: :list_of_objects,
|
30
|
-
name: "retrieved_steps",
|
31
|
-
description: "The retrieved steps for performing the given coding task",
|
32
|
-
structure: {
|
33
|
-
category: "The category of the step",
|
34
|
-
command: "The command to run on the command line",
|
35
|
-
description: "The description of what the command is for"
|
36
|
-
}
|
37
|
-
)
|
38
|
-
|
39
|
-
expect(output_function.to_hash).to eq(
|
40
|
-
{
|
41
|
-
name: "retrieved_steps",
|
42
|
-
description: "The retrieved steps for performing the given coding task",
|
43
|
-
parameters: {
|
44
|
-
type: "object",
|
45
|
-
properties: {
|
46
|
-
retrieved_steps: {
|
47
|
-
type: "array",
|
48
|
-
items: {
|
49
|
-
type: "object",
|
50
|
-
properties: {
|
51
|
-
category: {
|
52
|
-
type: "string",
|
53
|
-
description: "The category of the step"
|
54
|
-
},
|
55
|
-
command: {
|
56
|
-
type: "string",
|
57
|
-
description: "The command to run on the command line"
|
58
|
-
},
|
59
|
-
description: {
|
60
|
-
type: "string",
|
61
|
-
description: "The description of what the command is for"
|
62
|
-
}
|
63
|
-
}
|
64
|
-
}
|
65
|
-
}
|
66
|
-
}
|
67
|
-
}
|
68
|
-
}
|
69
|
-
)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "sublayer"
|
4
|
-
|
5
|
-
RSpec.configure do |config|
|
6
|
-
# Enable flags like --only-failures and --next-failure
|
7
|
-
config.example_status_persistence_file_path = ".rspec_status"
|
8
|
-
|
9
|
-
# Disable RSpec exposing methods globally on `Module` and `main`
|
10
|
-
config.disable_monkey_patching!
|
11
|
-
|
12
|
-
config.expect_with :rspec do |c|
|
13
|
-
c.syntax = :expect
|
14
|
-
end
|
15
|
-
end
|
@@ -1,38 +0,0 @@
|
|
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 ruby library for interacting with and orchestrating AI agents"
|
13
|
-
spec.description = "A command line framework for building, generating, and orchestrating AI 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.executables << "sublayer"
|
29
|
-
spec.executables << "sublayer_simple_tdd_pair"
|
30
|
-
spec.require_paths = ["lib"]
|
31
|
-
|
32
|
-
spec.add_dependency "ruby-openai"
|
33
|
-
spec.add_dependency "colorize"
|
34
|
-
spec.add_dependency "activesupport"
|
35
|
-
|
36
|
-
spec.add_development_dependency "rspec", "~> 3.12"
|
37
|
-
spec.add_development_dependency "pry", " ~> 0.14"
|
38
|
-
end
|