foobara-agent 0.0.6 → 0.0.7
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 +4 -0
- data/src/foobara/agent/accomplish_goal.rb +11 -70
- data/src/foobara/agent/notify_user_that_current_goal_has_been_accomplished.rb +48 -34
- data/src/foobara/agent.rb +31 -19
- metadata +1 -2
- data/src/foobara/agent/list_types.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 968399c2d338c8f069712d0ad9437b928fe48bc7356e88fd86b9ff6fb7ae235f
|
4
|
+
data.tar.gz: 8483b856faf2f559985550cc631764121797f88963c0baf428b7f16646bd8b59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79be2912847cb407d1ad65166313c8b799b981a2b0da6f8c8e3f8132049c1eb67ec56a9307fdf887f8e659299883f0da4517762abc885fdf8b69949f869f54de
|
7
|
+
data.tar.gz: 169c02a8070d5feb4d307b41ff757294ca5a2e3b810ac0766cece386a357db2cf85075ae9ecb1f5ee2e0b1ec92c855eb202ee4166102a88341b8e5b4268eeb92
|
data/CHANGELOG.md
CHANGED
@@ -8,16 +8,14 @@ module Foobara
|
|
8
8
|
context: { maximum_command_calls: :integer }
|
9
9
|
|
10
10
|
inputs do
|
11
|
-
agent_name :string, "Name of the agent"
|
12
11
|
goal :string, :required, "What do you want the agent to attempt to accomplish?"
|
13
12
|
# TODO: we should be able to specify a subclass as a type
|
14
|
-
command_classes [Class], "Commands that can be ran to accomplish the goal"
|
15
13
|
final_result_type :duck, "Specifies how the result of the goal is to be structured"
|
14
|
+
include_message_to_user_in_result :boolean, default: true
|
16
15
|
verbose :boolean, default: false
|
17
16
|
io_out :duck
|
18
17
|
io_err :duck
|
19
|
-
|
20
|
-
"A connector containing already-connected commands for the agent to use"
|
18
|
+
agent Agent, :required
|
21
19
|
current_context Context, :allow_nil, "The current context of the agent"
|
22
20
|
maximum_command_calls :integer,
|
23
21
|
:allow_nil,
|
@@ -44,7 +42,7 @@ module Foobara
|
|
44
42
|
end
|
45
43
|
|
46
44
|
result do
|
47
|
-
message_to_user :string, :
|
45
|
+
message_to_user :string, :allow_nil, "Message to the user about successfully accomplishing the goal"
|
48
46
|
result_data :duck, "Optional result data to return to the user if final_result_type was given"
|
49
47
|
end
|
50
48
|
|
@@ -53,17 +51,6 @@ module Foobara
|
|
53
51
|
def execute
|
54
52
|
build_initial_context_if_necessary
|
55
53
|
|
56
|
-
if command_connector_passed_in?
|
57
|
-
set_accomplished_goal_command
|
58
|
-
else
|
59
|
-
build_command_connector
|
60
|
-
connect_user_provided_commands
|
61
|
-
end
|
62
|
-
|
63
|
-
unless agent_commands_connected?
|
64
|
-
connect_agent_commands
|
65
|
-
end
|
66
|
-
|
67
54
|
simulate_list_commands_run
|
68
55
|
simulate_describe_command_run_for_all_commands
|
69
56
|
|
@@ -88,27 +75,10 @@ module Foobara
|
|
88
75
|
build_result
|
89
76
|
end
|
90
77
|
|
91
|
-
def agent_commands_connected?
|
92
|
-
command_connector.agent_commands_connected?
|
93
|
-
end
|
94
|
-
|
95
|
-
def validate
|
96
|
-
validate_either_command_classes_or_connector_given
|
97
|
-
end
|
98
|
-
|
99
|
-
def validate_either_command_classes_or_connector_given
|
100
|
-
# TODO: implement this!
|
101
|
-
end
|
102
|
-
|
103
78
|
attr_accessor :context, :next_command_name, :next_command_inputs, :mission_accomplished, :given_up,
|
104
79
|
:next_command_class, :next_command, :command_outcome, :timed_out,
|
105
80
|
:final_result, :final_message, :command_response, :delayed_command_name,
|
106
81
|
:command_calls
|
107
|
-
attr_writer :command_connector
|
108
|
-
|
109
|
-
def agent_name
|
110
|
-
@agent_name ||= inputs[:agent_name] || "Anon#{SecureRandom.hex(2)}"
|
111
|
-
end
|
112
82
|
|
113
83
|
def build_initial_context_if_necessary
|
114
84
|
# TODO: shouldn't have to pass command_log here since it has a default, debug that
|
@@ -129,7 +99,7 @@ module Foobara
|
|
129
99
|
def simulate_describe_command_run_for_all_commands
|
130
100
|
return if context.command_log.size > 1
|
131
101
|
|
132
|
-
ListCommands.run!(command_connector:)[:user_provided_commands].each do |full_command_name|
|
102
|
+
ListCommands.run!(command_connector: agent)[:user_provided_commands].each do |full_command_name|
|
133
103
|
next if described_commands.include?(full_command_name)
|
134
104
|
|
135
105
|
self.next_command_name = DescribeCommand.full_command_name
|
@@ -141,39 +111,6 @@ module Foobara
|
|
141
111
|
end
|
142
112
|
end
|
143
113
|
|
144
|
-
def command_connector_passed_in?
|
145
|
-
existing_command_connector
|
146
|
-
end
|
147
|
-
|
148
|
-
def command_connector
|
149
|
-
@command_connector ||= existing_command_connector
|
150
|
-
end
|
151
|
-
|
152
|
-
# Do we really want to support calling AccomplishGoal outside the context of an Agent?
|
153
|
-
# If not, just delete this awkward coupling
|
154
|
-
def build_command_connector
|
155
|
-
self.command_connector ||= Agent.new(
|
156
|
-
current_accomplish_goal_command: self,
|
157
|
-
llm_model:,
|
158
|
-
verbose:,
|
159
|
-
io_out:
|
160
|
-
)
|
161
|
-
end
|
162
|
-
|
163
|
-
def set_accomplished_goal_command
|
164
|
-
command_connector.current_accomplish_goal_command = self
|
165
|
-
end
|
166
|
-
|
167
|
-
def connect_agent_commands
|
168
|
-
command_connector.connect_agent_commands(final_result_type:, agent_name:)
|
169
|
-
end
|
170
|
-
|
171
|
-
def connect_user_provided_commands
|
172
|
-
command_classes.each do |command_class|
|
173
|
-
command_connector.connect(command_class)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
114
|
def determine_next_command_and_inputs(retries = 2)
|
178
115
|
inputs_for_determine = {
|
179
116
|
goal:,
|
@@ -348,11 +285,11 @@ module Foobara
|
|
348
285
|
end
|
349
286
|
|
350
287
|
def all_command_classes
|
351
|
-
@all_command_classes ||= run_subcommand!(ListCommands, command_connector:).values.flatten
|
288
|
+
@all_command_classes ||= run_subcommand!(ListCommands, command_connector: agent).values.flatten
|
352
289
|
end
|
353
290
|
|
354
291
|
def fetch_next_command_class
|
355
|
-
self.next_command_class =
|
292
|
+
self.next_command_class = agent.transformed_command_from_name(next_command_name)
|
356
293
|
end
|
357
294
|
|
358
295
|
def determine_next_command_inputs(retries = 2)
|
@@ -417,7 +354,7 @@ module Foobara
|
|
417
354
|
(io_out || $stdout).puts "Running #{next_command_name} with #{next_command_inputs}"
|
418
355
|
end
|
419
356
|
|
420
|
-
self.command_response =
|
357
|
+
self.command_response = agent.run(
|
421
358
|
full_command_name: next_command_name,
|
422
359
|
inputs: next_command_inputs,
|
423
360
|
action: "run"
|
@@ -528,6 +465,10 @@ module Foobara
|
|
528
465
|
choose_next_command_and_next_inputs_separately
|
529
466
|
end
|
530
467
|
|
468
|
+
def agent_name
|
469
|
+
agent.agent_name
|
470
|
+
end
|
471
|
+
|
531
472
|
def verbose?
|
532
473
|
verbose
|
533
474
|
end
|
@@ -6,8 +6,10 @@ module Foobara
|
|
6
6
|
class << self
|
7
7
|
attr_accessor :command_class
|
8
8
|
|
9
|
-
def for(result_type
|
10
|
-
|
9
|
+
def for(agent_id: nil, result_type: nil, include_message_to_user_in_result: true)
|
10
|
+
agent_id ||= "Anon#{SecureRandom.hex(2)}"
|
11
|
+
|
12
|
+
cached_subclass([result_type, agent_id, include_message_to_user_in_result]) do
|
11
13
|
command_name = "Foobara::Agent::#{agent_id}::NotifyUserThatCurrentGoalHasBeenAccomplished"
|
12
14
|
klass = Util.make_class_p(command_name, self)
|
13
15
|
|
@@ -16,32 +18,50 @@ module Foobara
|
|
16
18
|
"result schema and an optional message to the user. " \
|
17
19
|
"The user might issue a new goal."
|
18
20
|
|
19
|
-
inputs do
|
20
|
-
command_connector CommandConnector, :required, "Connector to notify user through"
|
21
|
-
message_to_user :string, :required, "Message to the user about what was done"
|
22
|
-
end
|
23
|
-
|
24
21
|
if result_type
|
25
|
-
|
26
|
-
|
22
|
+
if include_message_to_user_in_result
|
23
|
+
klass.add_inputs do
|
24
|
+
result result_type, :required
|
25
|
+
message_to_user :string, :required, "Message to the user about what was done"
|
26
|
+
end
|
27
|
+
|
28
|
+
klass.result do
|
29
|
+
result result_type, :required
|
30
|
+
message_to_user :string, :required, "Message to the user about what was done"
|
31
|
+
end
|
32
|
+
|
33
|
+
klass.description "Notifies the user that the current goal has been accomplished and returns a final " \
|
34
|
+
"result formatted according to the " \
|
35
|
+
"result schema and a message to the user. " \
|
36
|
+
"The user might issue a new goal."
|
37
|
+
else
|
38
|
+
klass.add_inputs do
|
39
|
+
result result_type, :required
|
40
|
+
end
|
41
|
+
|
42
|
+
klass.result result_type
|
43
|
+
|
44
|
+
klass.description "Notifies the user that the current goal has been accomplished and returns a final " \
|
45
|
+
"result formatted according to the " \
|
46
|
+
"result schema. " \
|
47
|
+
"The user might issue a new goal."
|
48
|
+
end
|
49
|
+
elsif include_message_to_user_in_result
|
50
|
+
klass.add_inputs do
|
51
|
+
message_to_user :string, :required, "Message to the user about what was done"
|
27
52
|
end
|
28
53
|
|
29
54
|
klass.result do
|
30
|
-
message_to_user :string, :required
|
31
|
-
result_data result_type, :required
|
55
|
+
message_to_user :string, :required, "Message to the user about what was done"
|
32
56
|
end
|
33
|
-
klass.description "Notifies the user that the current goal has been accomplished and returns a final " \
|
34
|
-
"result formatted according to the " \
|
35
|
-
"result schema if relevant and an optional message to the user. " \
|
36
|
-
"The user might issue a new goal."
|
37
57
|
|
58
|
+
klass.description "Notifies the user that the current goal has been accomplished and results in a " \
|
59
|
+
"message to the user. " \
|
60
|
+
"The user might issue a new goal."
|
38
61
|
else
|
39
|
-
#
|
62
|
+
# This should be unreachable actually
|
40
63
|
# :nocov:
|
41
|
-
klass.description "Notifies the user that the current goal has been accomplished
|
42
|
-
"returns a final " \
|
43
|
-
"result formatted according to the " \
|
44
|
-
"result schema and an optional message to the user. " \
|
64
|
+
klass.description "Notifies the user that the current goal has been accomplished. " \
|
45
65
|
"The user might issue a new goal."
|
46
66
|
# :nocov:
|
47
67
|
end
|
@@ -55,10 +75,7 @@ module Foobara
|
|
55
75
|
"result schema if relevant and an optional message to the user."
|
56
76
|
|
57
77
|
inputs do
|
58
|
-
|
59
|
-
command_connector :duck, :required, "Connector to end"
|
60
|
-
message_to_user :string, :required, "Message to the user about what was done"
|
61
|
-
result_data :duck, "The final result of the work if relevant/expected"
|
78
|
+
command_connector CommandConnector, :required, "Connector to notify user through"
|
62
79
|
end
|
63
80
|
|
64
81
|
def execute
|
@@ -68,21 +85,18 @@ module Foobara
|
|
68
85
|
end
|
69
86
|
|
70
87
|
def mark_mission_accomplished
|
71
|
-
|
72
|
-
inputs[:result_data]
|
73
|
-
end
|
74
|
-
|
75
|
-
command_connector.mark_mission_accomplished(data, message_to_user)
|
88
|
+
command_connector.mark_mission_accomplished(inputs[:result], inputs[:message_to_user])
|
76
89
|
end
|
77
90
|
|
78
91
|
def parsed_result
|
79
|
-
|
92
|
+
inputs_type = self.class.inputs_type
|
93
|
+
element_types = inputs_type.element_types
|
80
94
|
|
81
|
-
if
|
82
|
-
|
95
|
+
if element_types.key?(:message_to_user)
|
96
|
+
inputs.slice(:result, :message_to_user)
|
97
|
+
elsif element_types.key?(:result)
|
98
|
+
inputs[:result]
|
83
99
|
end
|
84
|
-
|
85
|
-
h
|
86
100
|
end
|
87
101
|
end
|
88
102
|
end
|
data/src/foobara/agent.rb
CHANGED
@@ -18,6 +18,7 @@ module Foobara
|
|
18
18
|
:llm_model,
|
19
19
|
:current_accomplish_goal_command,
|
20
20
|
:result_type,
|
21
|
+
:include_message_to_user_in_result,
|
21
22
|
:agent_commands_connected,
|
22
23
|
:verbose,
|
23
24
|
:io_out,
|
@@ -29,7 +30,7 @@ module Foobara
|
|
29
30
|
command_classes: nil,
|
30
31
|
llm_model: nil,
|
31
32
|
result_type: nil,
|
32
|
-
|
33
|
+
include_message_to_user_in_result: true,
|
33
34
|
verbose: false,
|
34
35
|
io_out: nil,
|
35
36
|
io_err: nil,
|
@@ -37,10 +38,10 @@ module Foobara
|
|
37
38
|
)
|
38
39
|
# TODO: shouldn't have to pass command_log here since it has a default, debug that
|
39
40
|
self.context = context
|
40
|
-
self.agent_name = agent_name
|
41
|
+
self.agent_name = agent_name || "Anon#{SecureRandom.hex(2)}"
|
41
42
|
self.llm_model = llm_model
|
42
43
|
self.result_type = result_type
|
43
|
-
self.
|
44
|
+
self.include_message_to_user_in_result = include_message_to_user_in_result
|
44
45
|
self.verbose = verbose
|
45
46
|
self.io_out = io_out
|
46
47
|
self.io_err = io_err
|
@@ -107,7 +108,8 @@ module Foobara
|
|
107
108
|
goal,
|
108
109
|
result_type: nil,
|
109
110
|
choose_next_command_and_next_inputs_separately: nil,
|
110
|
-
maximum_call_count: nil
|
111
|
+
maximum_call_count: nil,
|
112
|
+
llm_model: nil
|
111
113
|
)
|
112
114
|
if result_type && self.result_type != result_type
|
113
115
|
if self.result_type
|
@@ -123,6 +125,10 @@ module Foobara
|
|
123
125
|
end
|
124
126
|
end
|
125
127
|
|
128
|
+
unless agent_commands_connected?
|
129
|
+
connect_agent_commands
|
130
|
+
end
|
131
|
+
|
126
132
|
state_machine.perform_transition!(:accomplish_goal)
|
127
133
|
|
128
134
|
begin
|
@@ -130,12 +136,10 @@ module Foobara
|
|
130
136
|
goal:,
|
131
137
|
final_result_type: self.result_type,
|
132
138
|
current_context: context,
|
133
|
-
|
139
|
+
agent: self
|
134
140
|
}
|
135
141
|
|
136
|
-
|
137
|
-
inputs[:agent_name] = agent_name
|
138
|
-
end
|
142
|
+
llm_model ||= self.llm_model
|
139
143
|
|
140
144
|
if llm_model
|
141
145
|
inputs[:llm_model] = llm_model
|
@@ -161,14 +165,20 @@ module Foobara
|
|
161
165
|
inputs[:io_err] = io_err
|
162
166
|
end
|
163
167
|
|
168
|
+
if include_message_to_user_in_result || include_message_to_user_in_result == false
|
169
|
+
inputs[:include_message_to_user_in_result] = include_message_to_user_in_result
|
170
|
+
end
|
171
|
+
|
164
172
|
self.current_accomplish_goal_command = AccomplishGoal.new(inputs)
|
165
173
|
|
166
174
|
current_accomplish_goal_command.run.tap do |outcome|
|
167
|
-
if outcome.success?
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
175
|
+
transition = if outcome.success?
|
176
|
+
:goal_accomplished
|
177
|
+
else
|
178
|
+
:goal_errored
|
179
|
+
end
|
180
|
+
|
181
|
+
state_machine.perform_transition!(transition)
|
172
182
|
end
|
173
183
|
rescue
|
174
184
|
# :nocov:
|
@@ -197,19 +207,21 @@ module Foobara
|
|
197
207
|
agent_commands_connected
|
198
208
|
end
|
199
209
|
|
200
|
-
def connect_agent_commands
|
210
|
+
def connect_agent_commands
|
201
211
|
command_classes = [
|
202
212
|
DescribeCommand,
|
203
213
|
DescribeType,
|
204
214
|
GiveUp,
|
205
|
-
ListCommands
|
206
|
-
ListTypes
|
215
|
+
ListCommands
|
207
216
|
]
|
208
217
|
|
209
|
-
command_classes << if
|
218
|
+
command_classes << if result_type || include_message_to_user_in_result
|
219
|
+
# TODO: Support changing the final result type when the goal changes
|
210
220
|
NotifyUserThatCurrentGoalHasBeenAccomplished.for(
|
211
|
-
result_type
|
212
|
-
agent_id: agent_name
|
221
|
+
result_type:,
|
222
|
+
agent_id: agent_name,
|
223
|
+
# TODO: Support changing this flag when the goal changes
|
224
|
+
include_message_to_user_in_result:
|
213
225
|
)
|
214
226
|
else
|
215
227
|
NotifyUserThatCurrentGoalHasBeenAccomplished
|
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.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
@@ -59,7 +59,6 @@ files:
|
|
59
59
|
- src/foobara/agent/determine_next_command_name_and_inputs.rb
|
60
60
|
- src/foobara/agent/give_up.rb
|
61
61
|
- src/foobara/agent/list_commands.rb
|
62
|
-
- src/foobara/agent/list_types.rb
|
63
62
|
- src/foobara/agent/notify_user_that_current_goal_has_been_accomplished.rb
|
64
63
|
- src/foobara/agent/types/command_log_entry.rb
|
65
64
|
- src/foobara/agent/types/context.rb
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Foobara
|
2
|
-
class Agent < CommandConnector
|
3
|
-
class ListTypes < Foobara::Command
|
4
|
-
inputs do
|
5
|
-
command_connector :duck, :required, "Connector to fetch types from"
|
6
|
-
end
|
7
|
-
|
8
|
-
result [:string]
|
9
|
-
|
10
|
-
def execute
|
11
|
-
construct_type_list
|
12
|
-
|
13
|
-
type_list
|
14
|
-
end
|
15
|
-
|
16
|
-
attr_accessor :type_list
|
17
|
-
|
18
|
-
def construct_type_list
|
19
|
-
self.type_list = command_connector.all_exposed_type_names
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|