react_ai 0.0.2

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: 3aacc461fe13509ef3fa146423501596363d0c548a5311fd1af303ffff16d0af
4
+ data.tar.gz: 43ebb709bb580d16eb020669b9937653e16cdd45e4d23d66acd9e1606c8d6ca4
5
+ SHA512:
6
+ metadata.gz: 71931954621b173c64bc230f78d0aad183804aea0635f3ffe60c3110d5247ed35265f4fa966be5dc3fb211534fbb1265b87d5d33386c0471ba670c6e7df491ae
7
+ data.tar.gz: 83cc6afbefd787d7b1552cd2e8bcc3e5dd4825f1d27a07eeb234dac0da0f045a8f73c9feaa4dc3f3b0b4a55a93046fc7b406857c4edbbfac73591bec097db8dd
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+
2
+
3
+ ## [0.0.2] - 2024-01-08
4
+ - Add the ability to search wikipedia as a tool.
5
+
6
+ ## [0.0.1] - 2023-11-24
7
+
8
+ - Add an implmentation of ReAct that implements the calculator tool in a naive way.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in react_ai.gemspec
6
+ gemspec
7
+
8
+ gem "rake"
9
+ gem "minitest"
10
+ gem "standard"
data/Gemfile.lock ADDED
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ react_ai (0.0.2)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ base64 (0.1.1)
11
+ json (2.6.3)
12
+ language_server-protocol (3.17.0.3)
13
+ lint_roller (1.1.0)
14
+ minitest (5.20.0)
15
+ parallel (1.23.0)
16
+ parser (3.2.2.4)
17
+ ast (~> 2.4.1)
18
+ racc
19
+ racc (1.7.1)
20
+ rainbow (3.1.1)
21
+ rake (13.1.0)
22
+ regexp_parser (2.8.2)
23
+ rexml (3.2.6)
24
+ rubocop (1.56.4)
25
+ base64 (~> 0.1.1)
26
+ json (~> 2.3)
27
+ language_server-protocol (>= 3.17.0)
28
+ parallel (~> 1.10)
29
+ parser (>= 3.2.2.3)
30
+ rainbow (>= 2.2.2, < 4.0)
31
+ regexp_parser (>= 1.8, < 3.0)
32
+ rexml (>= 3.2.5, < 4.0)
33
+ rubocop-ast (>= 1.28.1, < 2.0)
34
+ ruby-progressbar (~> 1.7)
35
+ unicode-display_width (>= 2.4.0, < 3.0)
36
+ rubocop-ast (1.29.0)
37
+ parser (>= 3.2.1.0)
38
+ rubocop-performance (1.19.1)
39
+ rubocop (>= 1.7.0, < 2.0)
40
+ rubocop-ast (>= 0.4.0)
41
+ ruby-progressbar (1.13.0)
42
+ standard (1.31.2)
43
+ language_server-protocol (~> 3.17.0.2)
44
+ lint_roller (~> 1.0)
45
+ rubocop (~> 1.56.4)
46
+ standard-custom (~> 1.0.0)
47
+ standard-performance (~> 1.2)
48
+ standard-custom (1.0.2)
49
+ lint_roller (~> 1.0)
50
+ rubocop (~> 1.50)
51
+ standard-performance (1.2.1)
52
+ lint_roller (~> 1.1)
53
+ rubocop-performance (~> 1.19.1)
54
+ unicode-display_width (2.5.0)
55
+
56
+ PLATFORMS
57
+ x86_64-darwin-21
58
+
59
+ DEPENDENCIES
60
+ minitest
61
+ rake
62
+ react_ai!
63
+ standard
64
+
65
+ BUNDLED WITH
66
+ 2.3.26
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # ReactAi
2
+
3
+ Welcome to ```react_ai``` a gemified version of [my attempt to recreate the ReAct pattern in Ruby](https://github.com/thedayisntgray/Ruby-ReAct-Agent) with added features.
4
+
5
+ ## Purpose
6
+
7
+ The [ReAct pattern](https://arxiv.org/abs/2210.03629) is a technique used to circumvent the limitation LLMs have of only being able to respond past the date they were trained. We do this by prompting our LLM to use tools that we can define for it. Another advantage of using tools is that we can reduce hallucinations and therefore improve accuracy of LLM responses.
8
+
9
+ ## Features
10
+
11
+ ### Tools
12
+ - Calculator
13
+ - Wikipedia
14
+
15
+ ### CLI
16
+ - A simple CLI tool to test prompts
17
+
18
+ ## Installation
19
+
20
+ Install the gem and add to the application's Gemfile by executing:
21
+
22
+ $ bundle add react_ai
23
+
24
+ If bundler is not being used to manage dependencies, install the gem by executing:
25
+
26
+ $ gem install react_ai
27
+
28
+ Create a ```.env``` file in the root directory and add your open-ai key and your're ready to go!🔥
29
+
30
+ ```
31
+ OPEN_AI_KEY='your open ai key'
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ You can use this gem via the commmand line after it is installed by typing:
37
+
38
+ ```./exe/react_ai "Some prompt for our LLM!"```
39
+
40
+ Here's an example of what a user prompt and subsequent response might look like:
41
+
42
+
43
+ https://github.com/thedayisntgray/react_ai/assets/4859128/bbc6cba8-914b-4d6a-9a45-77e819acaec2
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/thedayisntgray/react_ai.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/test_*.rb"]
10
+ end
11
+
12
+ require "standard/rake"
13
+
14
+ task default: %i[test standard]
data/exe/react_ai ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift("#{__dir__}/../lib")
4
+
5
+ require "react_ai"
6
+
7
+ ReactAi::Cli.new(ARGV).run
@@ -0,0 +1,12 @@
1
+ module ReactAi
2
+ class Cli
3
+ def initialize(argv)
4
+ @argv = argv
5
+ end
6
+
7
+ def run
8
+ input = @argv.join(" ")
9
+ puts ReactAi::Agent.new.query(input, 5)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactAi
4
+ VERSION = "0.0.2"
5
+ end
data/lib/react_ai.rb ADDED
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv/load"
4
+ require "openai"
5
+ require_relative "react_ai/cli"
6
+ require_relative "react_ai/version"
7
+
8
+ module ReactAi
9
+ class Error < StandardError; end
10
+
11
+ class Agent
12
+ def initialize(agent_prompt: "You run in a loop of Thought, Action, PAUSE, Observation.
13
+ At the end of the loop you output an Answer
14
+ Use Thought to describe your thoughts about the question you have been asked.
15
+ Use Action to run one of the actions available to you - then return PAUSE.
16
+ Observation will be the result of running those actions.
17
+
18
+ Your available actions are:
19
+
20
+ calculate:
21
+ e.g. calculate: 4 * 7 / 3
22
+ Runs a calculation and returns the number - uses Ruby so be sure to use floating point syntax if necessary
23
+
24
+ wikipedia:
25
+ e.g. wikipedia: Ruby On Rails
26
+ Returns a summary from searching Wikipedia
27
+
28
+ Always look things up on Wikipedia if you have the opportunity to do so.
29
+
30
+ Example session:
31
+
32
+ Question: What is the capital of France?
33
+ Thought: I should look up France on Wikipedia
34
+ Action: wikipedia: France
35
+ PAUSE
36
+
37
+ You will be called again with this:
38
+
39
+ Observation: France is a country. The capital is Paris.
40
+
41
+ You then output:
42
+
43
+ Answer: The capital of France is Paris")
44
+ @client = OpenAI::Client.new(access_token: ENV["OPEN_AI_KEY"])
45
+ @messages = []
46
+
47
+ @known_actions = [
48
+ "wikipedia",
49
+ "calculate"
50
+ ]
51
+
52
+ unless agent_prompt.nil?
53
+ @messages << {"role" => "system", "content" => agent_prompt}
54
+ end
55
+ end
56
+
57
+ def query(question, max_iterations)
58
+ next_prompt = question
59
+ max_iterations.times do |i|
60
+ result = execute(next_prompt)
61
+ print result
62
+ actions = result.split("\n").map { |a| /^Action: (\w+): (.*)$/.match(a) }.compact.first
63
+
64
+ if actions
65
+ tool = actions[1]
66
+ action_input = actions[2]
67
+
68
+ unless @known_actions.include?(tool)
69
+ raise "Unknown Action: #{tool}"
70
+ end
71
+ puts " -- running #{tool} #{action_input}"
72
+ observation = send(tool, action_input)
73
+ puts "Observation: #{observation}"
74
+ next_prompt = "Observation: #{observation}"
75
+
76
+ else
77
+ return # standard:disable Lint/NonLocalExitFromIterator
78
+ end
79
+ end
80
+ end
81
+
82
+ def calculate(expr)
83
+ # consider integrating dentaku instead of using eval() which is unsafe
84
+ # https://github.com/rubysolo/dentaku
85
+ eval(expr)
86
+ end
87
+
88
+ def wikipedia(query)
89
+ uri = URI("https://en.wikipedia.org/w/api.php")
90
+ params = {action: "query", list: "search", srsearch: query, format: "json"}
91
+ uri.query = URI.encode_www_form(params)
92
+ res = Net::HTTP.get_response(uri)
93
+ JSON.parse(res.body)["query"]["search"][0]["snippet"]
94
+ end
95
+
96
+ def execute(question)
97
+ @messages << {"role" => "user", "content" => question}
98
+ response = @client.chat(
99
+ parameters: {
100
+ model: "gpt-3.5-turbo",
101
+ messages: @messages
102
+ }
103
+ )
104
+
105
+ result = response.dig("choices").first.dig("message").dig("content")
106
+ @messages << {"role" => "assistant", "content" => result}
107
+ result
108
+ end
109
+ end
110
+ end
data/react_ai.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/react_ai/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "react_ai"
7
+ spec.version = ReactAi::VERSION
8
+ spec.authors = ["Landon Gray"]
9
+ spec.email = ["thedayisntgray@gmail.com"]
10
+
11
+ spec.summary = "ReAct is an llm prompting pattern that enables an LLM to take actions such as searching the web or using a calculator."
12
+ spec.homepage = "https://github.com/thedayisntgray/react_ai"
13
+ spec.required_ruby_version = ">= 2.6.0"
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = spec.homepage
17
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
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
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ # Uncomment to register a new dependency of your gem
31
+ # spec.add_dependency "example-gem", "~> 1.0"
32
+
33
+ # For more information and examples about making a new gem, check out our
34
+ # guide at: https://bundler.io/guides/creating_gem.html
35
+ end
data/sig/react_ai.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module ReactAi
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: react_ai
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Landon Gray
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - thedayisntgray@gmail.com
16
+ executables:
17
+ - react_ai
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rspec"
22
+ - CHANGELOG.md
23
+ - Gemfile
24
+ - Gemfile.lock
25
+ - README.md
26
+ - Rakefile
27
+ - exe/react_ai
28
+ - lib/react_ai.rb
29
+ - lib/react_ai/cli.rb
30
+ - lib/react_ai/version.rb
31
+ - react_ai.gemspec
32
+ - sig/react_ai.rbs
33
+ homepage: https://github.com/thedayisntgray/react_ai
34
+ licenses: []
35
+ metadata:
36
+ homepage_uri: https://github.com/thedayisntgray/react_ai
37
+ source_code_uri: https://github.com/thedayisntgray/react_ai
38
+ changelog_uri: https://github.com/thedayisntgray/react_ai/blob/main/CHANGELOG.md
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.6.0
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.3.7
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: ReAct is an llm prompting pattern that enables an LLM to take actions such
58
+ as searching the web or using a calculator.
59
+ test_files: []