foobara-agent 0.0.7 → 0.0.8
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 +9 -1
- data/lib/foobara/agent.rb +0 -1
- data/src/foobara/agent/accomplish_goal.rb +136 -58
- data/src/foobara/agent/determine_inputs_for_next_command.rb +8 -1
- data/src/foobara/agent/determine_next_command.rb +21 -36
- data/src/foobara/agent/determine_next_command_name_and_inputs.rb +4 -1
- data/src/foobara/agent.rb +23 -10
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12e8facdeb95a000d81ec0ba8a133affa1ea66e470115e978bdc81f05bc51855
|
4
|
+
data.tar.gz: 294064df166d152c037db13263863b8ccfe32f064a78e77f6f5fe59af0be3829
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c7fcaf044ba9bc821dcc42f9b0fb44b412fb42f9ef77dd4b7f3ed13cb8293cdb60d448d136e4e0567d104ecb022a00accfd05dbcf955e38185884d34e59668e
|
7
|
+
data.tar.gz: 380d9ae749b6a942b4e33b112f5aae35fd9600fa9ffcaf462fc0a35122354aae0658378190a4b9db3c0d65d2a12c9d49305b1d03a2881ce504d6d268cf039255
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
## [0.0.8] - 2025-06-27
|
2
|
+
|
3
|
+
- Improve what is logged and its formatting when verbose
|
4
|
+
- Improve/experiment with what is stored in the command log
|
5
|
+
- Experiment with Atoms instead of Aggregates
|
6
|
+
- Add max_llm_calls_per_minute option
|
7
|
+
|
1
8
|
## [0.0.7] - 2025-06-23
|
2
9
|
|
3
|
-
-
|
10
|
+
- Improvements to result type handling
|
11
|
+
- Eliminate DescribeType command
|
4
12
|
|
5
13
|
## [0.0.6] - 2025-06-19
|
6
14
|
|
data/lib/foobara/agent.rb
CHANGED
@@ -3,6 +3,9 @@ require_relative "list_commands"
|
|
3
3
|
module Foobara
|
4
4
|
class Agent < CommandConnector
|
5
5
|
class AccomplishGoal < Foobara::Command
|
6
|
+
# Using a const here so we can stub it in the test suite to speed things up
|
7
|
+
SECONDS_PER_MINUTE = 60
|
8
|
+
|
6
9
|
possible_error :gave_up, context: { reason: :string }, message: "Gave up."
|
7
10
|
possible_error :too_many_command_calls,
|
8
11
|
context: { maximum_command_calls: :integer }
|
@@ -26,19 +29,13 @@ module Foobara
|
|
26
29
|
one_of: Foobara::Ai::AnswerBot::Types::ModelEnum,
|
27
30
|
default: "claude-3-7-sonnet-20250219",
|
28
31
|
description: "The model to use for the LLM"
|
29
|
-
log_successful_determine_command_and_inputs_outcomes(
|
30
|
-
:boolean,
|
31
|
-
default: true,
|
32
|
-
description: "You can experiment with turning this off " \
|
33
|
-
"if you want to see what happens if we don't log " \
|
34
|
-
"successful command/input selection outcomes"
|
35
|
-
)
|
36
32
|
choose_next_command_and_next_inputs_separately :boolean,
|
37
33
|
default: false,
|
38
34
|
description:
|
39
35
|
"By default, asks for next command and inputs together. " \
|
40
36
|
"You can experiment with getting the separately " \
|
41
37
|
"with this flag if you wish."
|
38
|
+
max_llm_calls_per_minute :integer, :allow_nil
|
42
39
|
end
|
43
40
|
|
44
41
|
result do
|
@@ -51,13 +48,16 @@ module Foobara
|
|
51
48
|
def execute
|
52
49
|
build_initial_context_if_necessary
|
53
50
|
|
51
|
+
simulate_describe_list_commands_command
|
54
52
|
simulate_list_commands_run
|
55
|
-
simulate_describe_command_run_for_all_commands
|
53
|
+
# simulate_describe_command_run_for_all_commands
|
56
54
|
|
57
55
|
until mission_accomplished or given_up
|
58
56
|
increment_command_calls
|
59
57
|
check_if_too_many_calls
|
60
58
|
|
59
|
+
throttle_llm_calls_if_necessary
|
60
|
+
|
61
61
|
if choose_next_command_and_next_inputs_separately?
|
62
62
|
determine_next_command_then_inputs_separately
|
63
63
|
else
|
@@ -75,8 +75,8 @@ module Foobara
|
|
75
75
|
build_result
|
76
76
|
end
|
77
77
|
|
78
|
-
attr_accessor :context, :next_command_name, :next_command_inputs, :
|
79
|
-
:next_command_class, :next_command, :command_outcome, :timed_out,
|
78
|
+
attr_accessor :context, :next_command_name, :next_command_inputs, :next_command_raw_inputs, :mission_accomplished,
|
79
|
+
:given_up, :next_command_class, :next_command, :command_outcome, :timed_out,
|
80
80
|
:final_result, :final_message, :command_response, :delayed_command_name,
|
81
81
|
:command_calls
|
82
82
|
|
@@ -86,9 +86,8 @@ module Foobara
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def simulate_list_commands_run
|
89
|
-
return unless context.command_log.empty?
|
90
|
-
|
91
89
|
self.next_command_name = ListCommands.full_command_name
|
90
|
+
self.next_command_raw_inputs = nil
|
92
91
|
self.next_command_inputs = nil
|
93
92
|
fetch_next_command_class
|
94
93
|
|
@@ -96,7 +95,19 @@ module Foobara
|
|
96
95
|
log_last_command_outcome
|
97
96
|
end
|
98
97
|
|
98
|
+
def simulate_describe_list_commands_command
|
99
|
+
self.next_command_name = DescribeCommand.full_command_name
|
100
|
+
self.next_command_inputs = { command_name: ListCommands.full_command_name }
|
101
|
+
self.next_command_raw_inputs = next_command_inputs
|
102
|
+
fetch_next_command_class
|
103
|
+
|
104
|
+
run_next_command
|
105
|
+
log_last_command_outcome
|
106
|
+
end
|
107
|
+
|
99
108
|
def simulate_describe_command_run_for_all_commands
|
109
|
+
# TODO: currently not using this code path. Unclear if it is worth it.
|
110
|
+
# :nocov:
|
100
111
|
return if context.command_log.size > 1
|
101
112
|
|
102
113
|
ListCommands.run!(command_connector: agent)[:user_provided_commands].each do |full_command_name|
|
@@ -104,24 +115,26 @@ module Foobara
|
|
104
115
|
|
105
116
|
self.next_command_name = DescribeCommand.full_command_name
|
106
117
|
self.next_command_inputs = { command_name: full_command_name }
|
118
|
+
self.next_command_raw_inputs = next_command_inputs
|
107
119
|
fetch_next_command_class
|
108
120
|
|
109
121
|
run_next_command
|
110
122
|
log_last_command_outcome
|
111
123
|
end
|
124
|
+
# :nocov:
|
112
125
|
end
|
113
126
|
|
114
127
|
def determine_next_command_and_inputs(retries = 2)
|
115
128
|
inputs_for_determine = {
|
116
129
|
goal:,
|
117
130
|
context:,
|
118
|
-
llm_model
|
119
|
-
command_class_names: all_command_classes
|
131
|
+
llm_model:
|
120
132
|
}
|
121
133
|
|
122
134
|
determine_command = DetermineNextCommandNameAndInputs.new(inputs_for_determine)
|
123
135
|
|
124
136
|
outcome = begin
|
137
|
+
record_llm_call_timestamp
|
125
138
|
determine_command.run
|
126
139
|
rescue CommandPatternImplementation::Concerns::Result::CouldNotProcessResult => e
|
127
140
|
# :nocov:
|
@@ -132,6 +145,7 @@ module Foobara
|
|
132
145
|
if outcome.success?
|
133
146
|
self.next_command_name = outcome.result[:command_name]
|
134
147
|
self.next_command_inputs = outcome.result[:inputs]
|
148
|
+
self.next_command_raw_inputs = next_command_inputs
|
135
149
|
|
136
150
|
outcome = validate_next_command_name
|
137
151
|
|
@@ -141,32 +155,25 @@ module Foobara
|
|
141
155
|
if next_command_has_inputs?
|
142
156
|
outcome = validate_next_command_inputs
|
143
157
|
|
144
|
-
|
145
|
-
if log_successful_determine_command_and_inputs_outcomes?
|
146
|
-
log_command_outcome(
|
147
|
-
command: determine_command,
|
148
|
-
inputs: determine_command.inputs.except(:context)
|
149
|
-
)
|
150
|
-
end
|
151
|
-
else
|
158
|
+
unless outcome.success?
|
152
159
|
log_command_outcome(
|
153
|
-
|
154
|
-
inputs:
|
155
|
-
outcome
|
156
|
-
result: outcome.result || determine_command.raw_result
|
160
|
+
command_name: next_command_name,
|
161
|
+
inputs: next_command_inputs,
|
162
|
+
outcome:
|
157
163
|
)
|
158
164
|
|
159
165
|
determine_next_command_inputs
|
160
166
|
end
|
161
167
|
else
|
162
168
|
self.next_command_inputs = {}
|
169
|
+
self.next_command_raw_inputs = next_command_inputs
|
163
170
|
end
|
164
171
|
else
|
165
172
|
log_command_outcome(
|
166
|
-
|
167
|
-
inputs:
|
173
|
+
command_name: next_command_name,
|
174
|
+
inputs: next_command_inputs,
|
168
175
|
outcome:,
|
169
|
-
result:
|
176
|
+
result: nil
|
170
177
|
)
|
171
178
|
|
172
179
|
if retries > 0
|
@@ -204,10 +211,23 @@ module Foobara
|
|
204
211
|
end
|
205
212
|
|
206
213
|
def validate_next_command_name
|
214
|
+
if next_command_name.is_a?(::String)
|
215
|
+
command_class = agent.transformed_command_from_name(next_command_name)
|
216
|
+
|
217
|
+
if command_class
|
218
|
+
self.next_command_name = command_class.full_command_name
|
219
|
+
|
220
|
+
return Outcome.success(next_command_name)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
207
224
|
outcome = command_name_type.process_value(next_command_name)
|
208
225
|
|
209
226
|
if outcome.success?
|
227
|
+
# TODO: figure out a way to hit this path in the test suite
|
228
|
+
# :nocov:
|
210
229
|
self.next_command_name = outcome.result
|
230
|
+
# :nocov:
|
211
231
|
end
|
212
232
|
|
213
233
|
outcome
|
@@ -231,17 +251,14 @@ module Foobara
|
|
231
251
|
self.delayed_command_name = nil
|
232
252
|
name
|
233
253
|
else
|
234
|
-
command_class = DetermineNextCommand.for(
|
235
|
-
command_class_names: all_command_classes, agent_id: agent_name
|
236
|
-
)
|
237
|
-
|
238
254
|
inputs = { goal:, context: }
|
239
255
|
if llm_model
|
240
256
|
inputs[:llm_model] = llm_model
|
241
257
|
end
|
242
258
|
|
243
|
-
command =
|
259
|
+
command = DetermineNextCommand.new(inputs)
|
244
260
|
outcome = begin
|
261
|
+
record_llm_call_timestamp
|
245
262
|
command.run
|
246
263
|
rescue CommandPatternImplementation::Concerns::Result::CouldNotProcessResult => e
|
247
264
|
# :nocov:
|
@@ -250,12 +267,24 @@ module Foobara
|
|
250
267
|
end
|
251
268
|
|
252
269
|
if outcome.success?
|
253
|
-
|
270
|
+
self.next_command_name = outcome.result
|
271
|
+
|
272
|
+
outcome = validate_next_command_name
|
273
|
+
|
274
|
+
unless outcome.success?
|
275
|
+
# TODO: figure out a way to hit this path in the test suite or delete it
|
276
|
+
# :nocov:
|
254
277
|
log_command_outcome(
|
255
278
|
command:,
|
256
279
|
inputs: command.inputs.except(:context),
|
257
|
-
outcome
|
280
|
+
outcome:,
|
281
|
+
result: outcome.result || command.raw_result
|
258
282
|
)
|
283
|
+
|
284
|
+
if retries > 0
|
285
|
+
return determine_next_command_name(retries - 1)
|
286
|
+
end
|
287
|
+
# :nocov:
|
259
288
|
end
|
260
289
|
else
|
261
290
|
# TODO: either figure out a way to hit this path in the test suite or delete it
|
@@ -303,6 +332,7 @@ module Foobara
|
|
303
332
|
|
304
333
|
command = command_class.new(inputs)
|
305
334
|
outcome = begin
|
335
|
+
record_llm_call_timestamp
|
306
336
|
command.run
|
307
337
|
rescue CommandPatternImplementation::Concerns::Result::CouldNotProcessResult => e
|
308
338
|
# :nocov:
|
@@ -310,23 +340,15 @@ module Foobara
|
|
310
340
|
# :nocov:
|
311
341
|
end
|
312
342
|
|
313
|
-
|
314
|
-
if log_successful_determine_command_and_inputs_outcomes?
|
315
|
-
log_command_outcome(
|
316
|
-
command:,
|
317
|
-
inputs: command.inputs.except(:context),
|
318
|
-
outcome:
|
319
|
-
)
|
320
|
-
end
|
321
|
-
else
|
343
|
+
unless outcome.success?
|
322
344
|
# TODO: either figure out a way to hit this path in the test suite or delete it
|
323
345
|
# :nocov:
|
324
346
|
log_command_outcome(
|
325
|
-
|
326
|
-
inputs: command.
|
327
|
-
outcome
|
328
|
-
result: outcome.result || command.raw_result
|
347
|
+
command_name: next_command_name,
|
348
|
+
inputs: command.raw_result,
|
349
|
+
outcome:
|
329
350
|
)
|
351
|
+
|
330
352
|
if retries > 0
|
331
353
|
return determine_next_command_inputs(retries - 1)
|
332
354
|
end
|
@@ -351,7 +373,20 @@ module Foobara
|
|
351
373
|
|
352
374
|
def run_next_command
|
353
375
|
if verbose?
|
354
|
-
|
376
|
+
args = if next_command_inputs.nil? || next_command_inputs.empty?
|
377
|
+
""
|
378
|
+
else
|
379
|
+
s = next_command_inputs.to_s
|
380
|
+
|
381
|
+
if s =~ /\A\{(.*)}\z/
|
382
|
+
"(#{::Regexp.last_match(1)})"
|
383
|
+
else
|
384
|
+
# :nocov:
|
385
|
+
raise "Unexpected next_command_inputs: #{next_command_inputs}"
|
386
|
+
# :nocov:
|
387
|
+
end
|
388
|
+
end
|
389
|
+
(io_out || $stdout).puts "#{next_command_name}.run#{args}"
|
355
390
|
end
|
356
391
|
|
357
392
|
self.command_response = agent.run(
|
@@ -363,9 +398,7 @@ module Foobara
|
|
363
398
|
self.command_outcome = command_response.outcome
|
364
399
|
|
365
400
|
if verbose?
|
366
|
-
|
367
|
-
(io_out || $stdout).puts "Command #{command_response.command.class.full_command_name} succeeded"
|
368
|
-
else
|
401
|
+
unless command_outcome.success?
|
369
402
|
# :nocov:
|
370
403
|
(io_err || $stderr).puts(
|
371
404
|
"Command #{command_response.command.class.full_command_name} failed #{command_outcome.errors_hash}"
|
@@ -398,8 +431,11 @@ module Foobara
|
|
398
431
|
def log_command_outcome(command: nil, command_name: nil, inputs: nil, outcome: nil, result: nil)
|
399
432
|
if command
|
400
433
|
command_name ||= command.class.full_command_name
|
401
|
-
inputs ||= command.
|
434
|
+
inputs ||= command.raw_inputs
|
402
435
|
outcome ||= command.outcome
|
436
|
+
end
|
437
|
+
|
438
|
+
if outcome
|
403
439
|
result ||= outcome.result
|
404
440
|
end
|
405
441
|
|
@@ -457,10 +493,6 @@ module Foobara
|
|
457
493
|
type.extends_type?(BuiltinTypes[:attributes]) && type.element_types.empty?
|
458
494
|
end
|
459
495
|
|
460
|
-
def log_successful_determine_command_and_inputs_outcomes?
|
461
|
-
log_successful_determine_command_and_inputs_outcomes
|
462
|
-
end
|
463
|
-
|
464
496
|
def choose_next_command_and_next_inputs_separately?
|
465
497
|
choose_next_command_and_next_inputs_separately
|
466
498
|
end
|
@@ -472,6 +504,52 @@ module Foobara
|
|
472
504
|
def verbose?
|
473
505
|
verbose
|
474
506
|
end
|
507
|
+
|
508
|
+
def llm_call_timestamps
|
509
|
+
@llm_call_timestamps ||= []
|
510
|
+
end
|
511
|
+
|
512
|
+
attr_writer :llm_call_timestamps
|
513
|
+
|
514
|
+
def record_llm_call_timestamp
|
515
|
+
llm_call_timestamps.unshift(Time.now)
|
516
|
+
end
|
517
|
+
|
518
|
+
def llm_calls_in_last_minute
|
519
|
+
llm_call_timestamps.select { |t| t > (Time.now - 60) }
|
520
|
+
end
|
521
|
+
|
522
|
+
def llm_call_count_in_last_minute
|
523
|
+
llm_calls_in_last_minute.size
|
524
|
+
end
|
525
|
+
|
526
|
+
def time_until_llm_call_count_in_last_minute_changes
|
527
|
+
calls = llm_calls_in_last_minute
|
528
|
+
|
529
|
+
first_to_expire = calls.first
|
530
|
+
|
531
|
+
if first_to_expire
|
532
|
+
(first_to_expire + SECONDS_PER_MINUTE) - Time.now
|
533
|
+
else
|
534
|
+
# TODO: figure out how to test this code path
|
535
|
+
# :nocov:
|
536
|
+
0
|
537
|
+
# :nocov:
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
def throttle_llm_calls_if_necessary
|
542
|
+
return unless max_llm_calls_per_minute && max_llm_calls_per_minute > 0
|
543
|
+
|
544
|
+
if llm_call_count_in_last_minute >= max_llm_calls_per_minute
|
545
|
+
seconds = time_until_llm_call_count_in_last_minute_changes
|
546
|
+
if verbose?
|
547
|
+
(io_out || $stdout).puts "Sleeping for #{seconds} seconds to avoid LLM calls per minute limit"
|
548
|
+
end
|
549
|
+
|
550
|
+
sleep seconds
|
551
|
+
end
|
552
|
+
end
|
475
553
|
end
|
476
554
|
end
|
477
555
|
end
|
@@ -26,13 +26,20 @@ module Foobara
|
|
26
26
|
end
|
27
27
|
|
28
28
|
if command_class.inputs_type
|
29
|
-
|
29
|
+
transformer = CommandConnectors::Transformers::EntityToPrimaryKeyInputsTransformer.new(
|
30
|
+
to: command_class.inputs_type
|
31
|
+
)
|
32
|
+
klass.result transformer.from_type
|
30
33
|
end
|
31
34
|
|
32
35
|
klass
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
39
|
+
|
40
|
+
def association_depth
|
41
|
+
Foobara::JsonSchemaGenerator::AssociationDepth::ATOM
|
42
|
+
end
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
@@ -3,45 +3,30 @@ require "foobara/llm_backed_command"
|
|
3
3
|
module Foobara
|
4
4
|
class Agent < CommandConnector
|
5
5
|
class DetermineNextCommand < Foobara::LlmBackedCommand
|
6
|
-
|
6
|
+
description "Accepts the current goal, which might already be accomplished, " \
|
7
|
+
"and context of the work " \
|
8
|
+
"so far and returns the name of " \
|
9
|
+
"the next command to run to make progress towards " \
|
10
|
+
"accomplishing the goal. If the goal has already been accomplished then choose the " \
|
11
|
+
"NotifyUserThatCurrentGoalHasBeenAccomplished command."
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
"so far and returns the name of " \
|
18
|
-
"the next command to run to make progress towards " \
|
19
|
-
"accomplishing the goal. If the goal has already been accomplished then choose the " \
|
20
|
-
"NotifyUserThatCurrentGoalHasBeenAccomplished command."
|
21
|
-
|
22
|
-
klass.inputs do
|
23
|
-
goal :string, :required, "The current goal to accomplish. If the goal has already been accomplished " \
|
24
|
-
"by the previous command runs then choose " \
|
25
|
-
"NotifyUserThatCurrentGoalHasBeenAccomplished to stop the loop."
|
26
|
-
context Context, :required, "Context of progress so far"
|
27
|
-
llm_model :string,
|
28
|
-
one_of: Foobara::Ai::AnswerBot::Types::ModelEnum,
|
29
|
-
default: "claude-3-7-sonnet-20250219",
|
30
|
-
description: "The model to use for the LLM"
|
31
|
-
end
|
32
|
-
|
33
|
-
klass.result :string,
|
34
|
-
one_of: command_class_names,
|
35
|
-
description: "Name of the next command to run to make progress " \
|
36
|
-
"towards accomplishing the mission"
|
37
|
-
|
38
|
-
klass
|
39
|
-
end
|
40
|
-
end
|
13
|
+
inputs do
|
14
|
+
goal :string, :required, "The current goal to accomplish. If the goal has already been accomplished " \
|
15
|
+
"by the previous command runs then choose " \
|
16
|
+
"NotifyUserThatCurrentGoalHasBeenAccomplished to stop the loop."
|
17
|
+
context Context, :required, "Context of progress so far"
|
18
|
+
llm_model :string,
|
19
|
+
one_of: Foobara::Ai::AnswerBot::Types::ModelEnum,
|
20
|
+
default: "claude-3-7-sonnet-20250219",
|
21
|
+
description: "The model to use for the LLM"
|
41
22
|
end
|
42
23
|
|
43
|
-
|
44
|
-
|
24
|
+
result :string,
|
25
|
+
description: "Name of the next command to run to make progress " \
|
26
|
+
"towards accomplishing the mission"
|
27
|
+
def association_depth
|
28
|
+
Foobara::JsonSchemaGenerator::AssociationDepth::ATOM
|
29
|
+
end
|
45
30
|
end
|
46
31
|
end
|
47
32
|
end
|
@@ -14,7 +14,6 @@ module Foobara
|
|
14
14
|
"by the previous command runs then choose " \
|
15
15
|
"NotifyUserThatCurrentGoalHasBeenAccomplished to stop the loop."
|
16
16
|
context Context, :required, "Context of the progress towards the goal so far"
|
17
|
-
command_class_names [:string], :required
|
18
17
|
llm_model :string,
|
19
18
|
one_of: Foobara::Ai::AnswerBot::Types::ModelEnum,
|
20
19
|
default: "claude-3-7-sonnet-20250219",
|
@@ -25,6 +24,10 @@ module Foobara
|
|
25
24
|
command_name :string, :required
|
26
25
|
inputs :attributes, :allow_nil
|
27
26
|
end
|
27
|
+
|
28
|
+
def association_depth
|
29
|
+
Foobara::JsonSchemaGenerator::AssociationDepth::ATOM
|
30
|
+
end
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
data/src/foobara/agent.rb
CHANGED
@@ -22,7 +22,8 @@ module Foobara
|
|
22
22
|
:agent_commands_connected,
|
23
23
|
:verbose,
|
24
24
|
:io_out,
|
25
|
-
:io_err
|
25
|
+
:io_err,
|
26
|
+
:max_llm_calls_per_minute
|
26
27
|
|
27
28
|
def initialize(
|
28
29
|
context: nil,
|
@@ -34,6 +35,7 @@ module Foobara
|
|
34
35
|
verbose: false,
|
35
36
|
io_out: nil,
|
36
37
|
io_err: nil,
|
38
|
+
max_llm_calls_per_minute: nil,
|
37
39
|
**opts
|
38
40
|
)
|
39
41
|
# TODO: shouldn't have to pass command_log here since it has a default, debug that
|
@@ -45,12 +47,19 @@ module Foobara
|
|
45
47
|
self.verbose = verbose
|
46
48
|
self.io_out = io_out
|
47
49
|
self.io_err = io_err
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
self.max_llm_calls_per_minute = max_llm_calls_per_minute
|
51
|
+
|
52
|
+
# unless opts.key?(:default_serializers)
|
53
|
+
# opts = opts.merge(default_serializers: [
|
54
|
+
# Foobara::CommandConnectors::Serializers::ErrorsSerializer,
|
55
|
+
# Foobara::CommandConnectors::Serializers::AggregateSerializer
|
56
|
+
# ])
|
57
|
+
# end
|
58
|
+
|
59
|
+
unless opts.key?(:default_pre_commit_transformers)
|
60
|
+
opts = opts.merge(
|
61
|
+
default_pre_commit_transformers: Foobara::CommandConnectors::Transformers::LoadAtomsPreCommitTransformer
|
62
|
+
)
|
54
63
|
end
|
55
64
|
|
56
65
|
super(**opts)
|
@@ -73,9 +82,9 @@ module Foobara
|
|
73
82
|
inputs_transformers = Util.array(inputs_transformers)
|
74
83
|
inputs_transformers << CommandConnectors::Transformers::EntityToPrimaryKeyInputsTransformer
|
75
84
|
|
76
|
-
unless opts.key?(:aggregate_entities)
|
77
|
-
|
78
|
-
end
|
85
|
+
# unless opts.key?(:aggregate_entities)
|
86
|
+
# opts = opts.merge(aggregate_entities: true)
|
87
|
+
# end
|
79
88
|
|
80
89
|
super(*args, **opts.merge(inputs_transformers:))
|
81
90
|
end
|
@@ -169,6 +178,10 @@ module Foobara
|
|
169
178
|
inputs[:include_message_to_user_in_result] = include_message_to_user_in_result
|
170
179
|
end
|
171
180
|
|
181
|
+
if max_llm_calls_per_minute && max_llm_calls_per_minute > 0
|
182
|
+
inputs[:max_llm_calls_per_minute] = max_llm_calls_per_minute
|
183
|
+
end
|
184
|
+
|
172
185
|
self.current_accomplish_goal_command = AccomplishGoal.new(inputs)
|
173
186
|
|
174
187
|
current_accomplish_goal_command.run.tap do |outcome|
|