regent 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: feb467916a88bf9123800575b64736a5d91c6f5b7c85180cac9a221d5da74cb7
4
- data.tar.gz: f5de9f6dbab7639d2eb66e77ce612eb5d7e60882ceea0277ece05768a04d81d8
3
+ metadata.gz: 2a6ab1feb1aafc91509881b72df5b6e7212a9588345ae39576afee47bfb1c614
4
+ data.tar.gz: 8a4275e5a82653c736539ef8c5650e1a7e11ac1c231be7561470fafd9943e54c
5
5
  SHA512:
6
- metadata.gz: d6e665134c70908195e3e666427e7ade9349ee39a92c245c6c6ee8afa12e7c1a0347d621cad6f11cacf93f499546fe549f674a0f4c6adb20c1370230660fa81d
7
- data.tar.gz: 59436f79df401f5b7b69bb4d1b8bf96d94b2657ff0a75b9616bfa059301fabe3465795ddbfbefbfdd6d429dcc721b5738d4871dc06862470ae28083dfd196b31
6
+ metadata.gz: 5dbaa9f8c0ed4d6ded4e164436062c2a919c2fe42a81da97d993785f6298963a34241cdf01900fb7d3a24eee1bd2f23844cab1764c1e1507d455793a4e85a60b
7
+ data.tar.gz: ad7d51c9fbd2c6751974d4cf8591f59c673b3ddf420cf6ce22d7fd60e4f62d1b7e028cc5647c3ac13867bf4f5a4c3ea0a275c9f34c1c9bd13ec62c09a3cc9854
data/README.md CHANGED
@@ -1,24 +1,64 @@
1
+
2
+ ![regent_light](https://github.com/user-attachments/assets/62564dac-b8d7-4dc0-9b63-64c6841b5872)
3
+
1
4
  # Regent
5
+ **Regent** is library for building AI agents with Ruby.
6
+
7
+ > [!WARNING]
8
+ > Regent is currently an experiment intended to explore patterns for building easily traceable and debuggable AI agents of different architectures. It is not yet intended to be used in production and is currently in development.
2
9
 
3
- TODO: Delete this and the text below, and describe your gem
10
+ ## Showcase
11
+ A basic Regnt Agent extended with a `price_tool` that allows for retrieving cryptocurrency prices from coingecko.com.
4
12
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/regent`. To experiment with that code, run `bin/console` for an interactive prompt.
13
+ ![screencast 2024-12-25 21-53-47](https://github.com/user-attachments/assets/4e65b731-bbd7-4732-b157-b705d35a7824)
6
14
 
7
- ## Installation
8
15
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
16
+ ## Install
10
17
 
11
- Install the gem and add to the application's Gemfile by executing:
18
+ ```bash
19
+ gem install regent
20
+ ```
12
21
 
13
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
22
+ or add regent to the Gemfile:
14
23
 
15
- If bundler is not being used to manage dependencies, install the gem by executing:
24
+ ```ruby
25
+ gem 'regent'
26
+ ```
16
27
 
17
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
28
+ and run
29
+
30
+ ```bash
31
+ bundle install
32
+ ```
18
33
 
19
34
  ## Usage
35
+ In order to operate an agent needs access to LLM (large language model). Regent relies on the [Langchainrb](https://github.com/patterns-ai-core/langchainrb) library to interact with LLMs. Let's create an instance of OapnAI LLM:
36
+ ```ruby
37
+ llm = Langchain::LLM::OpenAI(api_key: ENV["OPENAI_KEY"])
38
+ ```
39
+
40
+ Agents are effective when they have tools that enable them to get new information:
41
+
42
+ ```ruby
43
+ class WeatherTool < Regent::Tool
44
+ def call(location)
45
+ # implementation of a call to weather API
46
+ end
47
+ end
48
+
49
+ weather_tool = WeatherTool.new(name: "weather_tool", description: "Get the weather in a given location")
50
+ ```
51
+
52
+ Next, let's instantiate an agent passing LLM and a set of tools:
53
+
54
+ ```ruby
55
+ agent = Regent::Agent.new(llm: llm, tools: [weather_tool])
56
+ ```
20
57
 
21
- TODO: Write usage instructions here
58
+ Simply run an execute function, passing your query as an argument
59
+ ``` ruby
60
+ agent.execute("What is the weather in London today?")
61
+ ```
22
62
 
23
63
  ## Development
24
64
 
@@ -28,8 +68,8 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
28
68
 
29
69
  ## Contributing
30
70
 
31
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/regent. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/regent/blob/main/CODE_OF_CONDUCT.md).
71
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alchaplinsky/regent. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/alchaplinsky/regent/blob/main/CODE_OF_CONDUCT.md).
32
72
 
33
73
  ## Code of Conduct
34
74
 
35
- Everyone interacting in the Regent project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/regent/blob/main/CODE_OF_CONDUCT.md).
75
+ Everyone interacting in the Regent project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/alchaplinsky/regent/blob/main/CODE_OF_CONDUCT.md).
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ class Agent
5
+ include Concerns::Identifiable
6
+
7
+ DEFAULT_MAX_ITERATIONS = 10
8
+
9
+ def initialize(llm:, tools: [], **options)
10
+ super()
11
+
12
+ @llm = llm
13
+ @sessions = []
14
+ @tools = tools.is_a?(Toolchain) ? tools : Toolchain.new(Array(tools))
15
+ @max_iterations = options[:max_iterations] || DEFAULT_MAX_ITERATIONS
16
+ end
17
+
18
+ attr_reader :sessions, :llm, :tools
19
+
20
+ def execute(task)
21
+ raise ArgumentError, "Task cannot be empty" if task.to_s.strip.empty?
22
+
23
+ start_session
24
+ react.reason(task)
25
+ ensure
26
+ complete_session
27
+ end
28
+
29
+ def running?
30
+ session&.active? || false
31
+ end
32
+
33
+ def session
34
+ @sessions.last
35
+ end
36
+
37
+ private
38
+
39
+ def start_session
40
+ complete_session
41
+ @sessions << Session.new
42
+ session.start
43
+ end
44
+
45
+ def complete_session
46
+ session&.complete if running?
47
+ end
48
+
49
+ def react
50
+ Regent::Engine::React.new(llm, tools, session, @max_iterations)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module Regent
3
+ module Concerns
4
+ module Durationable
5
+ def duration
6
+ return 0 unless @start_time
7
+
8
+ (@end_time || Time.now) - @start_time
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ module Concerns
5
+ module Identifiable
6
+ def self.included(base)
7
+ base.class_eval do
8
+ attr_reader :id
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def generate_id
15
+ @id = SecureRandom.uuid
16
+ end
17
+
18
+ def initialize(*)
19
+ generate_id
20
+ super
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ module Engine
5
+ class React
6
+ module PromptTemplate
7
+ def self.system_prompt(tool_names)
8
+ <<~PROMPT
9
+ You are assisstant reasoning step-by-step to solve complex problems.
10
+ Your reasoning process happens in a loop of Though, Action, Observation.
11
+ Thought - a description of your thoughts about the question.
12
+ Action - pick a an action from available tools. If there are no tools that can help return an Answer saying you are not able to help..
13
+ Observation - is the result of running a tool.
14
+
15
+ ## Available tools:
16
+ #{tool_names}
17
+
18
+ ## Example session
19
+ Question: What is the weather in London today?
20
+ Thought: I need to get the wether in London
21
+ Action: weather_tool | "London"
22
+ PAUSE
23
+
24
+ You will have a response with Observation:
25
+ Observation: It is 32 degress and Sunny
26
+
27
+ ... (this Thought/Action/Observation can repeat N times)
28
+
29
+ Thought: I know the final answer
30
+ Answer: It is 32 degress and Sunny in London
31
+ PROMPT
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ module Engine
5
+ class React
6
+ SEQUENCES = {
7
+ answer: "Answer:",
8
+ action: "Action:",
9
+ observation: "Observation:",
10
+ stop: "PAUSE"
11
+ }.freeze
12
+
13
+ def initialize(llm, toolchain, session, max_iterations)
14
+ @llm = llm
15
+ @toolchain = toolchain
16
+ @session = session
17
+ @max_iterations = max_iterations
18
+ end
19
+
20
+ attr_reader :llm, :toolchain, :session, :max_iterations
21
+
22
+ def reason(task)
23
+ initialize_session(task)
24
+
25
+ max_iterations.times do |i|
26
+ content = get_llm_response
27
+ session.add_message({role: :assistant, content: content })
28
+ return extract_answer(content) if answer_present?(content)
29
+
30
+ if action_present?(content)
31
+ tool, argument = parse_action(content)
32
+ return unless tool
33
+
34
+ process_tool_execution(tool, argument)
35
+ end
36
+ end
37
+
38
+ error_answer("Max iterations reached without finding an answer.")
39
+ end
40
+
41
+ private
42
+
43
+ def initialize_session(task)
44
+ session.add_message({role: :system, content: Regent::Engine::React::PromptTemplate.system_prompt(toolchain.to_s)})
45
+ session.add_message({role: :user, content: task})
46
+ session.exec(Span::Type::INPUT, message: task) { task }
47
+ end
48
+
49
+ def get_llm_response
50
+ session.exec(Span::Type::LLM_CALL, type: llm.defaults[:chat_model], message: session.messages.last[:content]) do
51
+ result = llm.chat(messages: session.messages, params: { stop: [SEQUENCES[:stop]] })
52
+
53
+ # Relying on Langchain Response interface to get token counts and chat completion
54
+ session.current_span.set_meta("#{result.prompt_tokens} → #{result.completion_tokens} tokens")
55
+ result.chat_completion
56
+ end
57
+ end
58
+
59
+ def extract_answer(content)
60
+ answer = content.split(SEQUENCES[:answer])[1]&.strip
61
+ success_answer(answer)
62
+ end
63
+
64
+ def parse_action(content)
65
+ sanitized_content = content.gsub(SEQUENCES[:stop], "")
66
+ lookup_tool(sanitized_content)
67
+ end
68
+
69
+ def process_tool_execution(tool, argument)
70
+ result = session.exec(Span::Type::TOOL_EXECUTION, { type: tool.name, message: argument }) do
71
+ tool.call(argument)
72
+ end
73
+
74
+ session.add_message({ role: :user, content: "#{SEQUENCES[:observation]} #{result}" })
75
+ end
76
+
77
+ def answer_present?(content)
78
+ content.include?(SEQUENCES[:answer])
79
+ end
80
+
81
+ def action_present?(content)
82
+ content.include?(SEQUENCES[:action])
83
+ end
84
+
85
+ def success_answer(content)
86
+ session.exec(Span::Type::ANSWER, type: :success, message: content, duration: session.duration.round(2)) { content }
87
+ end
88
+
89
+ def error_answer(content)
90
+ session.exec(Span::Type::ANSWER, type: :failure, message: content, duration: session.duration.round(2)) { content }
91
+ end
92
+
93
+ def lookup_tool(content)
94
+ tool_name, argument = parse_tool_signature(content)
95
+ tool = toolchain.find(tool_name)
96
+
97
+ unless tool
98
+ session.exec(Span::Type::ANSWER, type: :failure, message: "No matching tool found for: #{tool_name}")
99
+ return [nil, nil]
100
+ end
101
+
102
+ [tool, argument]
103
+ end
104
+
105
+ def parse_tool_signature(content)
106
+ action = content.split(SEQUENCES[:action])[1]&.strip
107
+ return [nil, nil] unless action
108
+
109
+ parts = action.split('|', 2).map(&:strip)
110
+ tool_name = parts[0]
111
+ argument = parts[1].gsub('"', '')
112
+
113
+ # Handle cases where argument is nil, empty, or only whitespace
114
+ argument = nil if argument.nil? || argument.empty?
115
+
116
+ [tool_name, argument]
117
+ rescue
118
+ [nil, nil]
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ class Logger
5
+ COLORS = %i[dim green yellow red blue cyan clear].freeze
6
+
7
+ def initialize
8
+ @pastel = Pastel.new
9
+ @spinner = build_spinner(spinner_symbol)
10
+ @nested_spinner = build_spinner("#{dim(" ├──")}#{spinner_symbol}")
11
+ end
12
+
13
+ attr_reader :spinner, :nested_spinner
14
+
15
+ def info(label:, message:, duration: nil, type: nil, meta: nil, top_level: false)
16
+ current_spinner = top_level ? spinner : nested_spinner
17
+
18
+ current_spinner.update(title: format_message(label, message, duration, type, meta))
19
+ current_spinner
20
+ end
21
+
22
+ def start(**args)
23
+ info(**args).auto_spin
24
+ end
25
+
26
+ def success(**args)
27
+ info(**args).success
28
+ end
29
+
30
+ def error(**args)
31
+ info(**args).error
32
+ end
33
+
34
+ private
35
+
36
+ def format_message(label, message, duration, type, meta)
37
+ parts = []
38
+ parts << "#{dim("[")}#{cyan(label)}"
39
+ parts << "#{dim(" ❯")} #{yellow(type)}" if type
40
+ parts << dim("]")
41
+ parts << dim("[#{meta}]") if meta
42
+ parts << dim("[#{duration.round(2)}s]") if duration
43
+ parts << dim(":")
44
+ parts << clear(" #{message}")
45
+
46
+ parts.join
47
+ end
48
+
49
+ def spinner_symbol
50
+ "#{dim("[")}#{green(":spinner")}#{dim("]")}"
51
+ end
52
+
53
+ def build_spinner(spinner_format)
54
+ TTY::Spinner.new("#{spinner_format} :title", format: :dots)
55
+ end
56
+
57
+ COLORS.each do |color|
58
+ define_method(color) do |message|
59
+ @pastel.send(color, message)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ class Session
5
+ include Concerns::Identifiable
6
+ include Concerns::Durationable
7
+
8
+ class SessionError < StandardError; end
9
+ class InactiveSessionError < SessionError; end
10
+ class AlreadyStartedError < SessionError; end
11
+
12
+ def initialize
13
+ super()
14
+
15
+ @spans = []
16
+ @messages = []
17
+ @start_time = nil
18
+ @end_time = nil
19
+ end
20
+
21
+ attr_reader :id, :spans, :messages, :start_time, :end_time
22
+
23
+ # Starts the session
24
+ # @raise [AlreadyStartedError] if session is already started
25
+ # @return [void]
26
+ def start
27
+ raise AlreadyStartedError, "Session already started" if @start_time
28
+
29
+ @start_time = Time.now.freeze
30
+ end
31
+
32
+ # Executes a new span in the session
33
+ # @param type [Symbol, String] The type of span
34
+ # @param options [Hash] Options for the span
35
+ # @raise [InactiveSessionError] if session is not active
36
+ # @return [String] The output of the span
37
+ def exec(type, options = {}, &block)
38
+ raise InactiveSessionError, "Cannot execute span in inactive session" unless active?
39
+
40
+ @spans << Span.new(type: type, arguments: options)
41
+ current_span.run(&block)
42
+ end
43
+
44
+ # Replays the session
45
+ # @return [String] The result of the session
46
+ def replay
47
+ spans.each { |span| span.replay }
48
+ result
49
+ end
50
+
51
+ # Completes the session and returns the result
52
+ # @return [Object] The result of the last span
53
+ # @raise [InactiveSessionError] if session is not active
54
+ # @return [String] The result of the last span
55
+ def complete
56
+ raise InactiveSessionError, "Cannot complete inactive session" unless active?
57
+
58
+ @end_time = Time.now.freeze
59
+ result
60
+ end
61
+
62
+ # @return [Span, nil] The current span or nil if no spans exist
63
+ def current_span
64
+ @spans.last
65
+ end
66
+
67
+ # @return [String, nil] The output of the current span or nil if no spans exist
68
+ def result
69
+ current_span&.output
70
+ end
71
+
72
+ # @return [Boolean] Whether the session is currently active
73
+ def active?
74
+ start_time && end_time.nil?
75
+ end
76
+
77
+ # Adds a message to the session
78
+ # @param message [String] The message to add
79
+ # @raise [ArgumentError] if message is nil or empty
80
+ def add_message(message)
81
+ raise ArgumentError, "Message cannot be nil or empty" if message.nil? || message.empty?
82
+
83
+ @messages << message
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ class Span
5
+ include Concerns::Identifiable
6
+ include Concerns::Durationable
7
+
8
+ module Type
9
+ INPUT = 'INPUT'.freeze
10
+ LLM_CALL = 'LLM'.freeze
11
+ TOOL_EXECUTION = 'TOOL'.freeze
12
+ MEMORY_ACCESS = 'MEMO'.freeze
13
+ ANSWER = 'ANSWER'.freeze
14
+
15
+ def self.all
16
+ constants.map { |c| const_get(c) }
17
+ end
18
+
19
+ def self.valid?(type)
20
+ all.include?(type)
21
+ end
22
+ end
23
+
24
+ # @param type [String] The type of span (must be one of Type.all)
25
+ # @param arguments [Hash] Arguments for the span
26
+ # @param logger [Logger] Logger instance
27
+ def initialize(type:, arguments:, logger: Logger.new)
28
+ super()
29
+
30
+ validate_type!(type)
31
+
32
+ @logger = logger
33
+ @type = type
34
+ @arguments = arguments
35
+ @meta = nil
36
+ @output = nil
37
+ end
38
+
39
+ attr_reader :name, :arguments, :output, :type, :start_time, :end_time
40
+
41
+ # @raise [ArgumentError] if block is not given
42
+ # @return [String] The output of the span
43
+ def run
44
+ @output = log_operation do
45
+ yield
46
+ rescue StandardError => e
47
+ logger.error(label: type, message: e.message, **arguments)
48
+ raise
49
+ end
50
+ end
51
+
52
+ # @return [String] The output of the span
53
+ def replay
54
+ log_operation(live: false) { @output }
55
+ end
56
+
57
+ # @return [Boolean] Whether the span is currently running
58
+ def running?
59
+ @start_time && @end_time.nil?
60
+ end
61
+
62
+ # @return [Boolean] Whether the span is completed
63
+ def completed?
64
+ @start_time && @end_time
65
+ end
66
+
67
+ # @param value [String] The meta value to set
68
+ def set_meta(value)
69
+ @meta = value.freeze
70
+ end
71
+
72
+ private
73
+
74
+ attr_reader :logger, :meta
75
+
76
+ def validate_type!(type)
77
+ raise InvalidSpanType, "Invalid span type: #{type}" unless Type.valid?(type)
78
+ end
79
+
80
+ def log_operation(live: true, &block)
81
+ @start_time = live ? Time.now.freeze : @start_time
82
+ logger.start(label: type, **arguments)
83
+
84
+ result = yield
85
+
86
+ @end_time = live ? Time.now.freeze : @end_time
87
+ logger.success(label: type, **({ duration: duration.round(2), meta: meta }.merge(arguments)))
88
+
89
+ result
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ class Tool
5
+ def initialize(name:, description:)
6
+ @name = name
7
+ @description = description
8
+ end
9
+
10
+ attr_reader :name, :description
11
+
12
+ def call(argument)
13
+ raise NotImplementedError, "Tool #{name} has not implemented the execute method"
14
+ end
15
+
16
+ def to_s
17
+ "#{name} - #{description}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Regent
4
+ class Toolchain
5
+ def initialize(tools)
6
+ @tools = tools
7
+ end
8
+
9
+ attr_reader :tools
10
+
11
+ def find(name)
12
+ tools.find { |tool| tool.name.downcase == name.downcase }
13
+ end
14
+
15
+ def to_s
16
+ tools.map(&:to_s).join("\n")
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Regent
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/regent.rb CHANGED
@@ -1,8 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "regent/version"
3
+ require 'securerandom'
4
+ require 'pastel'
5
+ require 'tty-spinner'
6
+ require 'zeitwerk'
4
7
 
5
8
  module Regent
6
9
  class Error < StandardError; end
7
10
  # Your code goes here...
11
+
12
+ loader = Zeitwerk::Loader.for_gem
13
+ loader.setup
8
14
  end
metadata CHANGED
@@ -1,15 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: regent
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
  - Alex Chaplinsky
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-18 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2024-12-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: zeitwerk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby-openai
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 7.3.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 7.3.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: langchainrb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.19.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.19.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: tty-spinner
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.9.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: pastel
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.8.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.8.0
13
83
  description: Write a longer description or delete this line.
14
84
  email:
15
85
  - alchaplinsky@gmail.com
@@ -24,6 +94,16 @@ files:
24
94
  - README.md
25
95
  - Rakefile
26
96
  - lib/regent.rb
97
+ - lib/regent/agent.rb
98
+ - lib/regent/concerns/durationable.rb
99
+ - lib/regent/concerns/identifiable.rb
100
+ - lib/regent/engine/react.rb
101
+ - lib/regent/engine/react/prompt_template.rb
102
+ - lib/regent/logger.rb
103
+ - lib/regent/session.rb
104
+ - lib/regent/span.rb
105
+ - lib/regent/tool.rb
106
+ - lib/regent/toolchain.rb
27
107
  - lib/regent/version.rb
28
108
  - sig/regent.rbs
29
109
  homepage: https://github.com/alchaplinsky/regent