ruby_bots 0.0.21 → 0.0.23

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: 76d6f4b77a8ef6bc0f8124475142c2fb90460e9c9f602381eca42488aea99ea3
4
- data.tar.gz: bf11eed995aec29f80a3f97f86fc1856f6c4733cdbe7d716cf705af0f9733ad4
3
+ metadata.gz: f033f968d4ac24541d10ae38913ea8752d1c6a08c538b3bab6716bcd72365e7a
4
+ data.tar.gz: c1f905d49c704475e7c96f0ab8957ac78cf422fc6fdfd38e0b15c0a2e3fe4671
5
5
  SHA512:
6
- metadata.gz: 7c052e9aad0d5de43e0ab7644b15ded54a84b1c87429a7780c455d80e93239e15a878a4d015eb9dde9383e300132d661e6e72218dff79b2ac8855117ab2aade3
7
- data.tar.gz: 7fd242669b9332dec10d886ece3145ea3b76420459b5fb532e502f3050803d90cb839e6bb5e65711e6d79dc221a6dc6e5d9b5c115e019ead934bc8a877d8fd2d
6
+ metadata.gz: b361259f543091c9a252419bcbe9d07a839b4b92249f790d58e8f09c7d421e62225d1e4f704d5dbad2932fb436f3668215c8e4f863550d2802475c00d776b46b
7
+ data.tar.gz: 011546a87f231642929daaf6a6edcd9a483da7961992958f30a0dfa8f402125c843860466c270407986c665d1a0e557a1e21652a543175374991cee1f68741b7
data/lib/ruby_bots/bot.rb CHANGED
@@ -9,7 +9,7 @@ module RubyBots
9
9
 
10
10
  private
11
11
 
12
- def run(inputs)
12
+ def run(input)
13
13
  raise NotImplementedError
14
14
  end
15
15
  end
@@ -9,13 +9,24 @@ module RubyBots
9
9
  super(name: name, description: description)
10
10
  end
11
11
 
12
+ def system_instructions
13
+ <<~PROMPT
14
+ You are an assistant designed to select a tool for a user to use. You are provided with the user's input.
15
+ Select from the following tools (name - description):
16
+ #{tools.map{|t| t.name + " - " + t.description}.join("\n")}
17
+
18
+ Return only the name of the tool that best fits the user's request.
19
+ If no tools match the user's request respond with "no tool" and nothing more.
20
+ PROMPT
21
+ end
22
+
12
23
  private
13
24
 
14
- def run(inputs)
25
+ def run(input)
15
26
  params = {
16
27
  messages: [
17
28
  { role: :system, content: system_instructions },
18
- { role: :user, content: inputs }
29
+ { role: :user, content: input }
19
30
  ]
20
31
  }.merge(default_params)
21
32
 
@@ -0,0 +1,132 @@
1
+ module RubyBots
2
+ class OpenAIReactBot < OpenAIBot
3
+ attr_accessor :tools
4
+
5
+ DEFAULT_DESCRIPTION = "This bot will use the ReAct framework to determine the appropriate response. It is powered by OpenAI and the ReAct framework."
6
+
7
+ DEFAULT_TOOLS = [
8
+ RubyBots::Tool.new(name:"search", description:"Search the web for information. Input should be the string to search for."),
9
+ RubyBots::Tool.new(name:"calculate", description:"Solve math problems. Input should be a mathematical expression with no additional details or context."),
10
+ ]
11
+
12
+ def initialize(name: "OpenAI ReAct bot", description: DEFAULT_DESCRIPTION, tools: DEFAULT_TOOLS)
13
+ @tools = tools
14
+ super(name: name, description: description)
15
+ end
16
+
17
+ def examples
18
+ [ EXAMPLE_ONE, EXAMPLE_TWO, EXAMPLE_THREE ]
19
+ end
20
+
21
+
22
+ EXAMPLE_ONE = <<~EXAMPLE
23
+ User: What is the current temperature in the city Julia Roberts was born in?
24
+ Thought: I need to know where Julia Roberts was born.
25
+ Action: search[Julia Roberts birthplace]
26
+ Observation: Smyrna, Georgia
27
+ Thought: I need to know the current temperature in Smyrna, Georgia.
28
+ Action: search[current temperature Smyrna, Georgia]
29
+ Observation: 72 degrees Fahrenheit
30
+ Thought: I need to tell the user the current temperature in the city Julia Roberts was born in.
31
+ Answer: 72 degrees Fahrenheit
32
+ EXAMPLE
33
+
34
+ EXAMPLE_TWO = <<~EXAMPLE
35
+ User: What is the square of the age of Albert Einstein at his death?
36
+ Thought: I need to know the age of Albert Einstein at his death.
37
+ Action: search[Albert Einstein age at death]
38
+ Observation: 76 years old
39
+ Thought: I need to know the square of 76.
40
+ Action: calculate[76^2]
41
+ Observation: 5776
42
+ Thought: I need to tell the user the square of the age of Albert Einstein at his death.
43
+ Answer: 5776
44
+ EXAMPLE
45
+
46
+ EXAMPLE_THREE = <<~EXAMPLE
47
+ User: What is half of the amount of years that have passed since the year the first airplane flew?
48
+ Thought: I need to know the year the first airplane flew.
49
+ Action: search[first airplane flight year]
50
+ Observation: 1903
51
+ Thought: I need to know the current year.
52
+ Action: search[current year]
53
+ Observation: 2023
54
+ Thought: I need to know the amount of years that have passed since 1903.
55
+ Action: calculate[2023 - 1903]
56
+ Observation: 120
57
+ Thought: I need to know half of 120.
58
+ Action: calculate[120 / 2]
59
+ Observation: 60
60
+ Thought: I need to tell the user half of the amount of years that have passed since the year the first airplane flew.
61
+ Answer: 60
62
+ EXAMPLE
63
+
64
+ def system_instructions
65
+ <<~PROMPT
66
+ You are an assistant designed to provide solutions for a user. You are provided with the user's input.
67
+ You run in a loop of thought, action, observation, and reflection until you have a solution for the user.
68
+ You can utilize the following actions to gather more information (name - description):
69
+ #{ tools.map{ |t| t.name + " - " + t.description }.join("\n") }
70
+
71
+ You should begin by providing a thought and an action with the necessary input for the action. The action will be
72
+ executed externally, and then you will be called again with the observation returned from the action.
73
+
74
+ You should then begin the loop again and provide a thought and action.
75
+
76
+ If you have a solution for the user, return the solution instead of a new action.
77
+ The final answer should only answer the question without additional information about reasoning or process.
78
+
79
+ Examples:
80
+ #{ examples.join("\n\n") }
81
+ PROMPT
82
+ end
83
+
84
+ private
85
+
86
+ def run(input)
87
+ params = {
88
+ messages: [
89
+ { role: :system, content: system_instructions },
90
+ { role: :user, content: input }
91
+ ]
92
+ }.merge(default_params)
93
+
94
+ response = client.chat(parameters: params)
95
+ response = response.dig("choices", 0, "message", "content")
96
+
97
+ while !is_answer?(response)
98
+ params[:messages] << { role: :assistant, content: response }
99
+
100
+ observation = get_observation_from_action(response)
101
+
102
+ params[:messages] << { role: :assistant, content: "Observation: #{observation}" }
103
+
104
+ response = client.chat(parameters: params)
105
+
106
+ response = response.dig("choices", 0, "message", "content")
107
+ end
108
+
109
+ get_answer_from_response(response)
110
+ end
111
+
112
+ def is_answer?(input)
113
+ input.match(/Answer: /)
114
+ end
115
+
116
+ def get_observation_from_action(response)
117
+ t = response.match(/Action: ([\s\S]*)/)[1]
118
+ tool_name = t.match(/([a-zA-Z\-\_]*)\[([\s\S]*)\]/)[1]
119
+ tool_input = t.match(/([a-zA-Z\-\_]*)\[([\s\S]*)\]/)[2]
120
+
121
+ notify_observers(:action, tool_name, tool_input)
122
+
123
+ tool = tools.find{|t| t.name == tool_name}
124
+
125
+ tool.response(tool_input)
126
+ end
127
+
128
+ def get_answer_from_response(response)
129
+ response.match(/Answer: ([\s\S]*)/)[1]
130
+ end
131
+ end
132
+ end
@@ -8,12 +8,12 @@ module RubyBots
8
8
 
9
9
  private
10
10
 
11
- def run(inputs)
11
+ def run(input)
12
12
  tools.each do |tool|
13
- inputs = tool.run(inputs)
13
+ input = tool.run(input)
14
14
  end
15
15
 
16
- inputs
16
+ input
17
17
  end
18
18
  end
19
19
  end
@@ -19,11 +19,11 @@ module RubyBots
19
19
 
20
20
  private
21
21
 
22
- def run(inputs)
22
+ def run(input)
23
23
  params = {
24
24
  messages: [
25
25
  { role: :system, content: system_instructions },
26
- { role: :user, content: inputs }
26
+ { role: :user, content: input }
27
27
  ]
28
28
  }.merge(default_params)
29
29
 
@@ -32,7 +32,7 @@ module RubyBots
32
32
  response_text = response.dig("choices", 0, "message", "content")
33
33
  selected_tool = tools.find{|t| t.name == response_text}
34
34
  if selected_tool
35
- selected_tool.response(inputs)
35
+ selected_tool.response(input)
36
36
  else
37
37
  response_text
38
38
  end
@@ -48,7 +48,7 @@ module RubyBots
48
48
 
49
49
  private
50
50
 
51
- def run(inputs)
51
+ def run(input)
52
52
  raise NotImplementedError
53
53
  end
54
54
 
@@ -25,11 +25,11 @@ module RubyBots
25
25
 
26
26
  private
27
27
 
28
- def run(inputs)
28
+ def run(input)
29
29
  params = {
30
30
  messages: [
31
31
  { role: :system, content: system_instructions },
32
- { role: :user, content: inputs }
32
+ { role: :user, content: input }
33
33
  ]
34
34
  }.merge(default_params)
35
35
 
@@ -0,0 +1,24 @@
1
+ require 'cgi'
2
+ require 'uri'
3
+ require 'net/http'
4
+
5
+ module RubyBots
6
+ class WolframTool < Tool
7
+ # This tool requires an App ID key from Wolfram Alpha.
8
+ # add it to your environment variables as WOLFRAM_APP_ID
9
+
10
+ DEFAULT_DESCRIPTION = "This tool will use the Wolfram Alpha API to answer questions."
11
+
12
+ def initialize(name: "Wolfram tool", description: DEFAULT_DESCRIPTION)
13
+ super(name: name, description: description)
14
+ end
15
+
16
+ private
17
+
18
+ def run(input)
19
+ uri = URI("http://api.wolframalpha.com/v1/simple?appid=#{ENV['WOLFRAM_APPID']}&i=#{CGI.escape(input)}")
20
+ resp = Net::HTTP.get_response(uri)
21
+ resp.body
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module RubyBots
2
- VERSION = "0.0.21".freeze
2
+ VERSION = "0.0.23".freeze
3
3
  end
data/lib/ruby_bots.rb CHANGED
@@ -13,6 +13,7 @@ module RubyBots
13
13
  attr_accessor :openai_api_key
14
14
  def initialize()
15
15
  @openai_api_key = ENV["OPENAI_ACCESS_TOKEN"]
16
+ @wolfram_app_id = ENV["WOLFRAM_APPID"]
16
17
  end
17
18
  end
18
19
 
@@ -29,9 +30,10 @@ module RubyBots
29
30
  class InvalidOutputError < Error; end
30
31
  end
31
32
 
32
- require "ruby_bots/tool"
33
- require "ruby_bots/bot"
34
- require "ruby_bots/tools/openai_tool.rb"
35
- require "ruby_bots/bots/openai_bot.rb"
36
- require "ruby_bots/bots/pipeline_bot.rb"
37
- require "ruby_bots/bots/router_bot.rb"
33
+ require_relative "ruby_bots/tool"
34
+ require_relative "ruby_bots/bot"
35
+ require_relative "ruby_bots/tools/openai_tool.rb"
36
+ require_relative "ruby_bots/bots/openai_bot.rb"
37
+ require_relative "ruby_bots/bots/pipeline_bot.rb"
38
+ require_relative "ruby_bots/bots/router_bot.rb"
39
+ require_relative "ruby_bots/bots/openai_react_bot.rb"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_bots
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.21
4
+ version: 0.0.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Paulson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-03 00:00:00.000000000 Z
11
+ date: 2023-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: debug
@@ -91,10 +91,12 @@ files:
91
91
  - lib/ruby_bots.rb
92
92
  - lib/ruby_bots/bot.rb
93
93
  - lib/ruby_bots/bots/openai_bot.rb
94
+ - lib/ruby_bots/bots/openai_react_bot.rb
94
95
  - lib/ruby_bots/bots/pipeline_bot.rb
95
96
  - lib/ruby_bots/bots/router_bot.rb
96
97
  - lib/ruby_bots/tool.rb
97
98
  - lib/ruby_bots/tools/openai_tool.rb
99
+ - lib/ruby_bots/tools/wolfram_tool.rb
98
100
  - lib/ruby_bots/version.rb
99
101
  homepage: https://github.com/aha-app/ruby_bots
100
102
  licenses: