Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 22 additions & 21 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GEM
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
base64 (0.3.0)
bigdecimal (3.2.2)
bigdecimal (3.2.3)
byebug (12.0.0)
coderay (1.1.3)
crack (1.0.0)
Expand Down Expand Up @@ -47,20 +47,21 @@ GEM
foobara-type-generator (< 2.0.0)
foobara-typescript-react-command-form-generator (< 2.0.0)
foobara-typescript-remote-command-generator (< 2.0.0)
foobara (0.1.1)
foobara (0.1.10)
bigdecimal
foobara-lru-cache (< 2.0.0)
foobara-util (< 2.0.0)
inheritable-thread-vars (< 2.0.0)
foobara-ai (1.0.2)
foobara-anthropic-api (1.0.1)
foobara-cached-command
foobara-http-api-command
foobara-anthropic-api (1.0.3)
foobara (>= 0.1.3, < 2.0.0)
foobara-cached-command (< 2.0.0)
foobara-http-api-command (< 2.0.0)
foobara-cached-command (1.0.0)
foobara (< 2.0.0)
foobara-command-generator (0.0.3)
foobara
foobara-files-generator
foobara-command-generator (0.1.0)
foobara (>= 0.1.7, < 2.0.0)
foobara-files-generator (< 2.0.0)
foobara-domain-generator (0.0.3)
foobara
foobara-files-generator
Expand All @@ -69,7 +70,7 @@ GEM
foobara-files-generator
foobara-dotenv-loader (0.0.3)
dotenv
foobara-empty-ruby-project-generator (1.0.1)
foobara-empty-ruby-project-generator (1.0.4)
extract-repo (< 2.0.0)
foobara (>= 0.1.1, < 2.0.0)
foobara-files-generator (< 2.0.0)
Expand Down Expand Up @@ -116,7 +117,7 @@ GEM
foobara-resque-scheduler-connector-generator (0.0.2)
foobara
foobara-files-generator
foobara-rubocop-rules (1.0.1)
foobara-rubocop-rules (1.0.3)
rubocop
rubocop-rspec
foobara-sh-cli-connector (1.1.0)
Expand All @@ -132,8 +133,8 @@ GEM
foobara-typescript-react-command-form-generator (1.1.0)
foobara (>= 0.1.1, < 2.0.0)
foobara-typescript-remote-command-generator (< 2.0.0)
foobara-typescript-remote-command-generator (1.1.0)
foobara (>= 0.1.1, < 2.0.0)
foobara-typescript-remote-command-generator (1.1.1)
foobara (>= 0.1.4, < 2.0.0)
foobara-files-generator (< 2.0.0)
foobara-util (1.0.2)
formatador (1.2.0)
Expand All @@ -154,7 +155,7 @@ GEM
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
hashdiff (1.2.0)
hashdiff (1.2.1)
inheritable-thread-vars (0.0.3)
io-console (0.8.1)
irb (1.15.2)
Expand All @@ -168,7 +169,7 @@ GEM
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.7.0)
lumberjack (1.4.0)
lumberjack (1.4.2)
method_source (1.1.0)
nenv (0.3.0)
notiffany (0.1.3)
Expand All @@ -182,7 +183,7 @@ GEM
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
prism (1.4.0)
prism (1.5.1)
pry (0.15.2)
coderay (~> 1.1)
method_source (~> 1.0)
Expand All @@ -205,7 +206,7 @@ GEM
regexp_parser (2.11.2)
reline (0.6.2)
io-console (~> 0.5)
rexml (3.4.1)
rexml (3.4.4)
rspec (3.13.1)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
Expand All @@ -222,7 +223,7 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.5)
rubocop (1.80.0)
rubocop (1.80.2)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
Expand All @@ -239,7 +240,7 @@ GEM
rubocop-rake (0.7.1)
lint_roller (~> 1.1)
rubocop (>= 1.72.1)
rubocop-rspec (3.6.0)
rubocop-rspec (3.7.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
ruby-prof (1.7.2)
Expand All @@ -254,9 +255,9 @@ GEM
simplecov_json_formatter (0.1.4)
stringio (3.1.7)
thor (1.4.0)
unicode-display_width (3.1.5)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)
vcr (6.3.1)
base64
webmock (3.25.1)
Expand Down
146 changes: 78 additions & 68 deletions src/foobara/agent/accomplish_goal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,32 @@ class AccomplishGoal < Foobara::Command
depends_on ListCommands

def execute
unless list_commands_already_ran?
simulate_describe_list_commands_command
simulate_list_commands_run
end
simulate_list_commands_run unless list_commands_already_ran?

until mission_accomplished? or given_up? or killed?
increment_command_calls
check_if_too_many_calls

determine_next_command_and_inputs

run_next_command
end
unless command_already_described?
choose_describe_command_command_instead
end

if given_up?
add_given_up_error
if command_inputs_valid?
run_next_command
else
increment_and_check_retry_count
end
end

add_given_up_error if given_up?

build_result
end

attr_accessor :next_command_name, :next_command_inputs, :next_command_raw_inputs, :mission_accomplished,
:given_up, :next_command_class, :next_command, :command_outcome, :timed_out,
:final_result, :final_message, :command_response, :delayed_command_name,
:command_calls, :killed
:command_calls, :killed, :retry_count, :error_outcome

def list_commands_already_ran?
context.command_log.any? { |log_entry| log_entry.command_name =~ /\bListCommands\z/ }
Expand Down Expand Up @@ -123,32 +124,9 @@ def simulate_describe_command_run_for_all_commands
# :nocov:
end

RETRY_COUNT = 3

def determine_next_command_and_inputs(retries = RETRY_COUNT, error_outcome = nil)
def determine_next_command_and_inputs
return if killed

if verbose? && retries != RETRY_COUNT
# :nocov:
(io_err || $stderr).puts " !!! Retrying to determine next command and inputs. Retries left: #{retries}"
# :nocov:
end

if retries == 0
# TODO: test this path by irreparably breaking the needed commands
# :nocov:
self.next_command_name = GiveUp.full_command_name
self.next_command_inputs = {
message_to_user: "While trying to choose the next command and inputs, " \
"I've ran into an error several times that I couldn't figure out how to get past. " \
"The last error looked like this:\n#{error_outcome.errors_hash}"
}
self.next_command_raw_inputs = next_command_inputs

return
# :nocov:
end

compact_command_log

inputs_for_determine = { agent:, llm_model: }
Expand All @@ -175,33 +153,6 @@ def determine_next_command_and_inputs(retries = RETRY_COUNT, error_outcome = nil

if outcome.success?
fetch_next_command_class

if need_to_describe_next_command?
simulate_describe_command
return determine_next_command_and_inputs(retries, outcome)
end

if next_command_has_inputs?
outcome = validate_next_command_inputs

unless outcome.success?
# TODO: test this path
# :nocov:
log_command_outcome(
command_name: next_command_name,
inputs: next_command_inputs,
outcome:
)

simulate_describe_command

determine_next_command_and_inputs(retries - 1, outcome)
# :nocov:
end
else
self.next_command_inputs = {}
self.next_command_raw_inputs = next_command_inputs
end
else
log_command_outcome(
command_name: next_command_name,
Expand All @@ -210,7 +161,9 @@ def determine_next_command_and_inputs(retries = RETRY_COUNT, error_outcome = nil
result: nil
)

determine_next_command_and_inputs(retries - 1, outcome)
self.error_outcome = outcome
increment_and_check_retry_count
determine_next_command_and_inputs
end
else
log_command_outcome(
Expand All @@ -220,7 +173,9 @@ def determine_next_command_and_inputs(retries = RETRY_COUNT, error_outcome = nil
result: outcome.result || determine_command.raw_result
)

determine_next_command_and_inputs(retries - 1, outcome)
self.error_outcome = outcome
increment_and_check_retry_count
determine_next_command_and_inputs
end
end

Expand Down Expand Up @@ -248,14 +203,41 @@ def validate_next_command_name
end

def validate_next_command_inputs
inputs_type = next_command_class.inputs_type
if next_command_has_inputs?
inputs_type = next_command_class.inputs_type

outcome = NestedTransactionable.with_needed_transactions_for_type(inputs_type) do
inputs = next_command_inputs.nil? ? {} : next_command_inputs
inputs_type.process_value(inputs)
end

valid = outcome.success?
self.command_inputs_valid = valid

NestedTransactionable.with_needed_transactions_for_type(inputs_type) do
inputs = next_command_inputs.nil? ? {} : next_command_inputs
inputs_type.process_value(inputs)
if valid
self.next_command_inputs = outcome.result
# Do we really need this raw inputs variable?
self.next_command_raw_inputs = next_command_inputs
else # TODO: test this path
# :nocov:
log_command_outcome(
command_name: next_command_name,
inputs: next_command_inputs,
outcome:
)
# :nocov:
end
else
self.command_inputs_valid = true
self.next_command_inputs = {}
self.next_command_raw_inputs = next_command_inputs
end
end

def command_inputs_valid?
command_inputs_valid
end

def command_name_type
@command_name_type ||= Agent.foobara_type_from_declaration(:string, one_of: all_command_classes)
end
Expand All @@ -274,6 +256,9 @@ def next_command_has_inputs?
end

def run_next_command
increment_command_calls
reset_retry_count

log_command_code(command_name: next_command_name, inputs: next_command_inputs)

self.command_response = agent.run(
Expand Down Expand Up @@ -348,6 +333,31 @@ def compact_command_log
context.command_log = new_log
end

MAX_RETRY_COUNT = 3

def increment_and_check_retry_count
self.retry_count ||= 0
self.retry_count += 1

if retry_count > MAX_RETRY_COUNT
# TODO: test this path by irreparably breaking the needed commands
# :nocov:
self.next_command_name = GiveUp.full_command_name
self.next_command_inputs = {
message_to_user: "While trying to choose the next command and inputs, " \
"I've ran into an error several times that I couldn't figure out how to get past. " \
"The last error looked like this:\n#{error_outcome.errors_hash}"
}
self.next_command_raw_inputs = next_command_inputs
# :nocov:
elsif verbose?
# :nocov:
(io_err || $stderr).puts " !!! Retrying to determine next command and inputs. " \
"Retries left: #{RETRY_COUNT - retry_count}"
# :nocov:
end
end

def increment_command_calls
self.command_calls ||= -1
self.command_calls += 1
Expand Down
Loading