foobara-agent 0.0.14 → 0.0.17
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 +4 -4
- data/CHANGELOG.md +14 -0
- data/src/foobara/agent/accomplish_goal.rb +14 -5
- data/src/foobara/agent/determine_base.rb +10 -2
- data/src/foobara/agent/determine_next_command_name_and_inputs.rb +19 -5
- data/src/foobara/agent/types/context.rb +6 -4
- data/src/foobara/agent/types/goal.rb +18 -0
- data/src/foobara/agent.rb +30 -8
- metadata +20 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 786fe4f10e3355da241847e573ff5d80abfb174d5afdedc0cb936d0a08b583ab
|
4
|
+
data.tar.gz: f6ae8472f81c4a7ba98f8daa6dd9998118d3d0dbf0728d5710b0d1b0575264ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4f150fb79b86ea3e02413bbd2d08e186f08888dd462fd722037d7741d65f7ccfc04d080ac751abcf04cbd2ba3455c240a3a0695699b3b01fd9e3d5ffba96948
|
7
|
+
data.tar.gz: 759813642a132a0f874506af6d5692f820fc62893e76e14bc759b33ebd353541917ad72b8589efa74141dee0fa8866638dd188e8860d7af4a9a412c69c344571
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.0.17] - 2025-07-10
|
2
|
+
|
3
|
+
- Prefix verbose output with the agent name if there is one
|
4
|
+
|
5
|
+
## [0.0.16] - 2025-07-09
|
6
|
+
|
7
|
+
- Tell the llm about previous goals
|
8
|
+
- Allow agents to be nameless
|
9
|
+
- Improve support for killing a running agent
|
10
|
+
|
11
|
+
## [0.0.15] - 2025-07-09
|
12
|
+
|
13
|
+
- Make use of Ai.default_llm_model
|
14
|
+
|
1
15
|
## [0.0.14] - 2025-07-08
|
2
16
|
|
3
17
|
- Better handle serialization/pre-commit loading for various entity-depth scenarios
|
@@ -25,8 +25,8 @@ module Foobara
|
|
25
25
|
description: "Maximum number of commands to run before giving up"
|
26
26
|
llm_model :string,
|
27
27
|
:allow_nil,
|
28
|
-
one_of:
|
29
|
-
default:
|
28
|
+
one_of: Ai::AnswerBot::Types::ModelEnum,
|
29
|
+
default: Ai.default_llm_model,
|
30
30
|
description: "The model to use for the LLM"
|
31
31
|
max_llm_calls_per_minute :integer, :allow_nil
|
32
32
|
user_association_depth :symbol, :allow_nil, one_of: Foobara::AssociationDepth
|
@@ -48,7 +48,7 @@ module Foobara
|
|
48
48
|
end
|
49
49
|
# simulate_describe_command_run_for_all_commands
|
50
50
|
|
51
|
-
until mission_accomplished or given_up
|
51
|
+
until mission_accomplished or given_up or killed
|
52
52
|
increment_command_calls
|
53
53
|
check_if_too_many_calls
|
54
54
|
|
@@ -69,7 +69,7 @@ module Foobara
|
|
69
69
|
attr_accessor :next_command_name, :next_command_inputs, :next_command_raw_inputs, :mission_accomplished,
|
70
70
|
:given_up, :next_command_class, :next_command, :command_outcome, :timed_out,
|
71
71
|
:final_result, :final_message, :command_response, :delayed_command_name,
|
72
|
-
:command_calls
|
72
|
+
:command_calls, :killed
|
73
73
|
|
74
74
|
def list_commands_already_ran?
|
75
75
|
context.command_log.any? { |log_entry| log_entry.command_name =~ /\bListCommands\z/ }
|
@@ -131,6 +131,8 @@ module Foobara
|
|
131
131
|
end
|
132
132
|
|
133
133
|
def determine_next_command_and_inputs(retries = 3, error_outcome = nil)
|
134
|
+
return if killed
|
135
|
+
|
134
136
|
if retries == 0
|
135
137
|
# TODO: test this path by irreparably breaking the needed commands
|
136
138
|
# :nocov:
|
@@ -428,7 +430,10 @@ module Foobara
|
|
428
430
|
end
|
429
431
|
end
|
430
432
|
|
431
|
-
|
433
|
+
agent_name = agent.agent_name
|
434
|
+
prefix = agent_name && !agent_name.empty? ? "#{agent_name}: " : ""
|
435
|
+
|
436
|
+
(io_out || $stdout).puts "#{prefix}#{next_command_name}.run#{args}"
|
432
437
|
end
|
433
438
|
end
|
434
439
|
|
@@ -439,6 +444,10 @@ module Foobara
|
|
439
444
|
self.final_message = message
|
440
445
|
end
|
441
446
|
|
447
|
+
def kill!
|
448
|
+
self.killed = true
|
449
|
+
end
|
450
|
+
|
442
451
|
def give_up!(message)
|
443
452
|
self.given_up = true
|
444
453
|
self.final_message = message
|
@@ -10,7 +10,7 @@ module Foobara
|
|
10
10
|
agent Agent, :required
|
11
11
|
llm_model :string,
|
12
12
|
one_of: Foobara::Ai::AnswerBot::Types::ModelEnum,
|
13
|
-
default:
|
13
|
+
default: Ai.default_llm_model,
|
14
14
|
description: "The model to use for the LLM"
|
15
15
|
end
|
16
16
|
|
@@ -57,7 +57,15 @@ module Foobara
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def goal
|
60
|
-
context.current_goal
|
60
|
+
context.current_goal.text
|
61
|
+
end
|
62
|
+
|
63
|
+
def previous_goal_and_status_pairs
|
64
|
+
if context.previous_goals && !context.previous_goals.empty?
|
65
|
+
context.previous_goals.map do |previous_goal|
|
66
|
+
[previous_goal.text, previous_goal.state]
|
67
|
+
end
|
68
|
+
end
|
61
69
|
end
|
62
70
|
|
63
71
|
def context
|
@@ -4,19 +4,19 @@ module Foobara
|
|
4
4
|
class Agent < CommandConnector
|
5
5
|
class DetermineNextCommandNameAndInputs < DetermineBase
|
6
6
|
class << self
|
7
|
-
def llm_instructions(assistant_association_depth, goal)
|
8
|
-
key = [assistant_association_depth, goal]
|
7
|
+
def llm_instructions(assistant_association_depth, goal, previous_goals = nil)
|
8
|
+
key = [assistant_association_depth, goal, previous_goals]
|
9
9
|
|
10
10
|
@llm_instructions_cache ||= {}
|
11
11
|
|
12
12
|
if @llm_instructions_cache.key?(key)
|
13
13
|
@llm_instructions_cache[key]
|
14
14
|
else
|
15
|
-
@llm_instructions_cache[key] = build_llm_instructions(assistant_association_depth, goal)
|
15
|
+
@llm_instructions_cache[key] = build_llm_instructions(assistant_association_depth, goal, previous_goals)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def build_llm_instructions(assistant_association_depth, goal)
|
19
|
+
def build_llm_instructions(assistant_association_depth, goal, previous_goals)
|
20
20
|
instructions = "You are the implementation of a command called #{scoped_full_name}"
|
21
21
|
|
22
22
|
instructions += if description && !description.empty?
|
@@ -29,7 +29,17 @@ module Foobara
|
|
29
29
|
|
30
30
|
result_schema = result_json_schema(assistant_association_depth)
|
31
31
|
|
32
|
+
if previous_goals && !previous_goals.empty?
|
33
|
+
instructions += "You have previously accomplished the following goals:\n\n"
|
34
|
+
|
35
|
+
previous_goals.each.with_index do |(previous_goal, state), index|
|
36
|
+
instructions += "previous goal #{index + 1}: #{previous_goal}\n"
|
37
|
+
instructions += "status of goal #{index + 1}: #{state}\n\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
32
41
|
instructions += "You are working towards accomplishing the following goal:\n\n#{goal}\n\n"
|
42
|
+
|
33
43
|
instructions += "Your response of which command to run next should match the following JSON schema:"
|
34
44
|
instructions += "\n\n#{result_schema}\n\n"
|
35
45
|
instructions += "You can get more details about the inputs and result schemas for a specific command by " \
|
@@ -52,7 +62,11 @@ module Foobara
|
|
52
62
|
end
|
53
63
|
|
54
64
|
def determine_llm_instructions
|
55
|
-
self.llm_instructions = self.class.llm_instructions(
|
65
|
+
self.llm_instructions = self.class.llm_instructions(
|
66
|
+
computed_user_association_depth,
|
67
|
+
goal,
|
68
|
+
previous_goal_and_status_pairs
|
69
|
+
)
|
56
70
|
end
|
57
71
|
end
|
58
72
|
end
|
@@ -1,15 +1,17 @@
|
|
1
|
+
require_relative "goal"
|
2
|
+
|
1
3
|
module Foobara
|
2
4
|
class Agent < CommandConnector
|
3
5
|
class Context < Foobara::Model
|
4
6
|
class << self
|
5
7
|
def for(goal)
|
6
|
-
new(command_log: [], current_goal: goal)
|
8
|
+
new(command_log: [], current_goal: Goal.new(text: goal))
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
12
|
attributes do
|
11
|
-
current_goal
|
12
|
-
previous_goals [
|
13
|
+
current_goal Goal, :required, "The current goal the agent needs to accomplish"
|
14
|
+
previous_goals [Goal]
|
13
15
|
# TODO: why doesn't this default of [] work as expected on newly created models?
|
14
16
|
command_log [CommandLogEntry], default: [],
|
15
17
|
description: "Log of all commands run so far and their outcomes"
|
@@ -18,7 +20,7 @@ module Foobara
|
|
18
20
|
def set_new_goal(goal)
|
19
21
|
self.previous_goals ||= []
|
20
22
|
previous_goals << current_goal
|
21
|
-
self.current_goal = goal
|
23
|
+
self.current_goal = Goal.new(text: goal)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Foobara
|
2
|
+
class Agent < CommandConnector
|
3
|
+
class Goal < Foobara::Model
|
4
|
+
module States
|
5
|
+
ACCOMPLISHED = :accomplished
|
6
|
+
KILLED = :killed
|
7
|
+
FAILED = :failed
|
8
|
+
ERROR = :error
|
9
|
+
GAVE_UP = :gave_up
|
10
|
+
end
|
11
|
+
|
12
|
+
attributes do
|
13
|
+
text :string, :required
|
14
|
+
state :symbol, :allow_nil, one_of: States
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/src/foobara/agent.rb
CHANGED
@@ -15,6 +15,7 @@ module Foobara
|
|
15
15
|
|
16
16
|
attr_accessor :context,
|
17
17
|
:agent_name,
|
18
|
+
:agent_id,
|
18
19
|
:llm_model,
|
19
20
|
:current_accomplish_goal_command,
|
20
21
|
:result_type,
|
@@ -44,8 +45,11 @@ module Foobara
|
|
44
45
|
)
|
45
46
|
# TODO: shouldn't have to pass command_log here since it has a default, debug that
|
46
47
|
self.context = context
|
47
|
-
|
48
|
-
|
48
|
+
if agent_name
|
49
|
+
self.agent_name = agent_name
|
50
|
+
end
|
51
|
+
self.agent_id = agent_name || "Anon#{SecureRandom.hex(2)}"
|
52
|
+
self.llm_model = llm_model || Ai.default_llm_model
|
49
53
|
self.result_type = result_type
|
50
54
|
self.include_message_to_user_in_result = include_message_to_user_in_result
|
51
55
|
self.verbose = verbose
|
@@ -105,11 +109,16 @@ module Foobara
|
|
105
109
|
end
|
106
110
|
|
107
111
|
def kill!
|
108
|
-
|
112
|
+
current_accomplish_goal_command&.kill!
|
113
|
+
state_machine.perform_transition!(:kill) do
|
114
|
+
if context
|
115
|
+
context.current_goal.state = Goal::States::KILLED
|
116
|
+
end
|
117
|
+
end
|
109
118
|
end
|
110
119
|
|
111
120
|
def killed?
|
112
|
-
state_machine.current_state ==
|
121
|
+
state_machine.current_state == Goal::States::KILLED
|
113
122
|
end
|
114
123
|
|
115
124
|
def accomplish_goal(
|
@@ -149,14 +158,27 @@ module Foobara
|
|
149
158
|
transition = if outcome.success?
|
150
159
|
:goal_accomplished
|
151
160
|
else
|
152
|
-
:
|
161
|
+
:goal_failed
|
153
162
|
end
|
154
163
|
|
155
|
-
|
164
|
+
unless killed?
|
165
|
+
state_machine.perform_transition!(transition) do
|
166
|
+
context.current_goal.state = if outcome.success?
|
167
|
+
Goal::States::ACCOMPLISHED
|
168
|
+
else
|
169
|
+
Goal::States::FAILED
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
156
173
|
end
|
157
174
|
rescue
|
158
175
|
# :nocov:
|
159
|
-
|
176
|
+
unless killed?
|
177
|
+
state_machine.perform_transition!(:goal_errored) do
|
178
|
+
context.current_goal.state = Goal::States::ERROR
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
160
182
|
raise
|
161
183
|
# :nocov:
|
162
184
|
end
|
@@ -247,7 +269,7 @@ module Foobara
|
|
247
269
|
# TODO: Support changing the final result type when the goal changes
|
248
270
|
NotifyUserThatCurrentGoalHasBeenAccomplished.for(
|
249
271
|
result_type:,
|
250
|
-
agent_id
|
272
|
+
agent_id:,
|
251
273
|
# TODO: Support changing this flag when the goal changes
|
252
274
|
include_message_to_user_in_result:,
|
253
275
|
result_entity_depth:
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara-agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
@@ -13,30 +13,42 @@ dependencies:
|
|
13
13
|
name: foobara
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- - "
|
16
|
+
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 0.0.
|
18
|
+
version: 0.0.136
|
19
|
+
- - "<"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.0.0
|
19
22
|
type: :runtime
|
20
23
|
prerelease: false
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
22
25
|
requirements:
|
23
|
-
- - "
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 0.0.136
|
29
|
+
- - "<"
|
24
30
|
- !ruby/object:Gem::Version
|
25
|
-
version: 0.0
|
31
|
+
version: 2.0.0
|
26
32
|
- !ruby/object:Gem::Dependency
|
27
33
|
name: foobara-llm-backed-command
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
29
35
|
requirements:
|
30
|
-
- - "
|
36
|
+
- - ">="
|
31
37
|
- !ruby/object:Gem::Version
|
32
38
|
version: 1.0.0
|
39
|
+
- - "<"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.0.0
|
33
42
|
type: :runtime
|
34
43
|
prerelease: false
|
35
44
|
version_requirements: !ruby/object:Gem::Requirement
|
36
45
|
requirements:
|
37
|
-
- - "
|
46
|
+
- - ">="
|
38
47
|
- !ruby/object:Gem::Version
|
39
48
|
version: 1.0.0
|
49
|
+
- - "<"
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 2.0.0
|
40
52
|
email:
|
41
53
|
- azimux@gmail.com
|
42
54
|
executables: []
|
@@ -61,6 +73,7 @@ files:
|
|
61
73
|
- src/foobara/agent/notify_user_that_current_goal_has_been_accomplished.rb
|
62
74
|
- src/foobara/agent/types/command_log_entry.rb
|
63
75
|
- src/foobara/agent/types/context.rb
|
76
|
+
- src/foobara/agent/types/goal.rb
|
64
77
|
homepage: https://github.com/foobara/agent
|
65
78
|
licenses:
|
66
79
|
- MPL-2.0
|