foobara-agent 0.0.11 → 0.0.14

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e0f6302247bbcc56ed93f61ec3a5d39e5041029e03b20cadea2d1dd0ebd04b6
4
- data.tar.gz: baca677e1ea555bcdc908fd2b37dc2d8b016df9888f8f7a69c8cff73774756b2
3
+ metadata.gz: dc32aeaa66ec947920e085944f7948d22d97b4fa3b39d1a4b4fbf58755ca4321
4
+ data.tar.gz: 0dc7b3d02061bf0a615ab6299ea5f607fff1d703804d5368b57a9157d4edf64a
5
5
  SHA512:
6
- metadata.gz: 350feb6d9058009889a342a5dcc4f44befed8a25be71ebc7673bf75b7ceb1f95adcec3a52d2eb53ba9301d0ef2312919a4496a53f2146423dd36c17b122856af
7
- data.tar.gz: a91ec6608bc3001f06d3c17562321d2c1a52a537372347593293d57d9d6312126f5116853c8b32b649d7c65a050bbb67bd03b2dbc50247cdc7260013b6d8f3ec
6
+ metadata.gz: e1a1d3780d7a3112cff93e7e626ec677ad558ce605e65c60f00ec3b8213b604e248ca4428311303b1902451f2bcc7d2a5f17f3725dde77bbb4725aeb10b9898d
7
+ data.tar.gz: f6113517024dc34e999fafcb3bc5ee0ec98fb63628f61725b5631e454d6edd4714933a745232e57f2a1c8f686f0d2544b481b1726cfff3e4dbbc47666bdd74c4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [0.0.14] - 2025-07-08
2
+
3
+ - Better handle serialization/pre-commit loading for various entity-depth scenarios
4
+
5
+ ## [0.0.13] - 2025-07-06
6
+
7
+ - Eliminate NotifyUser... result_type to save tokens/improve accuracy
8
+ - Choose DescribeCommand for commands with inputs that haven't been described
9
+ - Log failure output when trying to determine commands/inputs
10
+
11
+ ## [0.0.12] - 2025-07-05
12
+
13
+ - Choose DescribeCommand for commands that have inputs and haven't been described
14
+ - Log determine command/input failures when verbose
15
+
1
16
  ## [0.0.11] - 2025-07-01
2
17
 
3
18
  - Fix some bugs with result type/value mismatches
@@ -19,7 +19,6 @@ module Foobara
19
19
  io_out :duck
20
20
  io_err :duck
21
21
  agent Agent, :required
22
- context Context, :required, "The current context of the agent"
23
22
  maximum_command_calls :integer,
24
23
  :allow_nil,
25
24
  default: 25,
@@ -30,6 +29,9 @@ module Foobara
30
29
  default: "claude-3-7-sonnet-20250219",
31
30
  description: "The model to use for the LLM"
32
31
  max_llm_calls_per_minute :integer, :allow_nil
32
+ user_association_depth :symbol, :allow_nil, one_of: Foobara::AssociationDepth
33
+ result_entity_depth :symbol, :allow_nil, one_of: Foobara::AssociationDepth
34
+ pass_aggregates_to_llm :boolean, :allow_nil
33
35
  end
34
36
 
35
37
  result do
@@ -40,8 +42,10 @@ module Foobara
40
42
  depends_on ListCommands
41
43
 
42
44
  def execute
43
- simulate_describe_list_commands_command
44
- simulate_list_commands_run
45
+ unless list_commands_already_ran?
46
+ simulate_describe_list_commands_command
47
+ simulate_list_commands_run
48
+ end
45
49
  # simulate_describe_command_run_for_all_commands
46
50
 
47
51
  until mission_accomplished or given_up
@@ -51,9 +55,8 @@ module Foobara
51
55
  throttle_llm_calls_if_necessary
52
56
 
53
57
  determine_next_command_and_inputs
54
- run_next_command
55
58
 
56
- log_last_command_outcome
59
+ run_next_command
57
60
  end
58
61
 
59
62
  if given_up
@@ -68,6 +71,10 @@ module Foobara
68
71
  :final_result, :final_message, :command_response, :delayed_command_name,
69
72
  :command_calls
70
73
 
74
+ def list_commands_already_ran?
75
+ context.command_log.any? { |log_entry| log_entry.command_name =~ /\bListCommands\z/ }
76
+ end
77
+
71
78
  def simulate_list_commands_run
72
79
  self.next_command_name = ListCommands.full_command_name
73
80
  self.next_command_raw_inputs = nil
@@ -75,7 +82,6 @@ module Foobara
75
82
  fetch_next_command_class
76
83
 
77
84
  run_next_command
78
- log_last_command_outcome
79
85
  end
80
86
 
81
87
  def simulate_describe_list_commands_command
@@ -85,7 +91,6 @@ module Foobara
85
91
  fetch_next_command_class
86
92
 
87
93
  run_next_command
88
- log_last_command_outcome
89
94
  end
90
95
 
91
96
  def simulate_describe_command(command_name = next_command_name)
@@ -100,7 +105,6 @@ module Foobara
100
105
  fetch_next_command_class
101
106
 
102
107
  run_next_command
103
- log_last_command_outcome
104
108
 
105
109
  self.next_command_name = old_next_command_name
106
110
  self.next_command_inputs = old_next_command_inputs
@@ -114,7 +118,7 @@ module Foobara
114
118
  return if context.command_log.size > 1
115
119
 
116
120
  ListCommands.run!(command_connector: agent)[:user_provided_commands].each do |full_command_name|
117
- next if described_commands.include?(full_command_name)
121
+ next if command_described?(full_command_name)
118
122
 
119
123
  self.next_command_name = DescribeCommand.full_command_name
120
124
  self.next_command_inputs = { command_name: full_command_name }
@@ -122,7 +126,6 @@ module Foobara
122
126
  fetch_next_command_class
123
127
 
124
128
  run_next_command
125
- log_last_command_outcome
126
129
  end
127
130
  # :nocov:
128
131
  end
@@ -145,11 +148,10 @@ module Foobara
145
148
 
146
149
  compact_command_log
147
150
 
148
- inputs_for_determine = {
149
- context:,
150
- llm_model:
151
- }
152
-
151
+ inputs_for_determine = { agent:, llm_model: }
152
+ unless pass_aggregates_to_llm.nil?
153
+ inputs_for_determine[:pass_aggregates_to_llm] = pass_aggregates_to_llm
154
+ end
153
155
  determine_command = DetermineNextCommandNameAndInputs.new(inputs_for_determine)
154
156
 
155
157
  outcome = begin
@@ -171,10 +173,17 @@ module Foobara
171
173
  if outcome.success?
172
174
  fetch_next_command_class
173
175
 
176
+ if need_to_describe_next_command?
177
+ simulate_describe_command
178
+ return determine_next_command_and_inputs(retries, outcome)
179
+ end
180
+
174
181
  if next_command_has_inputs?
175
182
  outcome = validate_next_command_inputs
176
183
 
177
184
  unless outcome.success?
185
+ # TODO: test this path
186
+ # :nocov:
178
187
  log_command_outcome(
179
188
  command_name: next_command_name,
180
189
  inputs: next_command_inputs,
@@ -184,6 +193,7 @@ module Foobara
184
193
  simulate_describe_command
185
194
 
186
195
  determine_next_command_and_inputs(retries - 1, outcome)
196
+ # :nocov:
187
197
  end
188
198
  else
189
199
  self.next_command_inputs = {}
@@ -260,23 +270,7 @@ module Foobara
260
270
  end
261
271
 
262
272
  def run_next_command
263
- if verbose?
264
- args = if next_command_inputs.nil? || next_command_inputs.empty?
265
- ""
266
- else
267
- s = next_command_inputs.to_s
268
-
269
- if s =~ /\A\{(.*)}\z/
270
- "(#{::Regexp.last_match(1)})"
271
- else
272
- # :nocov:
273
- raise "Unexpected next_command_inputs: #{next_command_inputs}"
274
- # :nocov:
275
- end
276
- end
277
-
278
- (io_out || $stdout).puts "#{next_command_name}.run#{args}"
279
- end
273
+ log_command_code(command_name: next_command_name, inputs: next_command_inputs)
280
274
 
281
275
  self.command_response = agent.run(
282
276
  full_command_name: next_command_name,
@@ -286,19 +280,7 @@ module Foobara
286
280
 
287
281
  self.command_outcome = command_response.outcome
288
282
 
289
- if verbose?
290
- unless command_outcome.success?
291
- # :nocov:
292
- (io_err || $stderr).puts(
293
- "Command #{command_response.command.class.full_command_name} failed #{command_outcome.errors_hash}"
294
- )
295
- # :nocov:
296
- end
297
- end
298
- end
299
-
300
- def log_last_command_outcome
301
- log_command_outcome(command: command_response.command)
283
+ log_command_outcome(command: command_response.command, log_command_code: false)
302
284
  end
303
285
 
304
286
  def compact_command_log
@@ -337,13 +319,14 @@ module Foobara
337
319
  next unless last_success
338
320
 
339
321
  failure_indexes.each do |failure_index|
322
+ # TODO: test this path
323
+ # :nocov:
340
324
  if failure_index < last_success
341
325
  indexes_to_delete << failure_index
342
326
  else
343
- # :nocov:
344
327
  break
345
- # :nocov:
346
328
  end
329
+ # :nocov:
347
330
  end
348
331
  end
349
332
 
@@ -377,7 +360,12 @@ module Foobara
377
360
  end
378
361
  end
379
362
 
380
- def log_command_outcome(command: nil, command_name: nil, inputs: nil, outcome: nil, result: nil)
363
+ def log_command_outcome(command: nil,
364
+ command_name: nil,
365
+ inputs: nil,
366
+ outcome: nil,
367
+ result: nil,
368
+ log_command_code: true)
381
369
  if command
382
370
  command_name ||= command.class.full_command_name
383
371
  inputs ||= command.raw_inputs
@@ -405,6 +393,43 @@ module Foobara
405
393
  )
406
394
 
407
395
  context.command_log << log_entry
396
+
397
+ if verbose?
398
+ if log_command_code
399
+ # TODO: test this code path hmmm
400
+ # :nocov:
401
+ self.log_command_code(command_name:, inputs:)
402
+ # :nocov:
403
+ end
404
+
405
+ unless log_entry.success?
406
+ # :nocov:
407
+ (io_err || $stderr).puts(
408
+ "Command #{log_entry.command_name} failed:\n#{log_entry.errors_hash}"
409
+ )
410
+ # :nocov:
411
+ end
412
+ end
413
+ end
414
+
415
+ def log_command_code(command_name:, inputs:)
416
+ if verbose?
417
+ args = if next_command_inputs.nil? || next_command_inputs.empty?
418
+ ""
419
+ else
420
+ s = next_command_inputs.to_s
421
+
422
+ if s =~ /\A\{(.*)}\z/
423
+ "(#{::Regexp.last_match(1)})"
424
+ else
425
+ # :nocov:
426
+ raise "Unexpected next_command_inputs: #{next_command_inputs}"
427
+ # :nocov:
428
+ end
429
+ end
430
+
431
+ (io_out || $stdout).puts "#{next_command_name}.run#{args}"
432
+ end
408
433
  end
409
434
 
410
435
  # TODO: these are awkwardly called from outside. Come up with a better solution.
@@ -442,6 +467,20 @@ module Foobara
442
467
  verbose
443
468
  end
444
469
 
470
+ def need_to_describe_next_command?
471
+ return false if command_described?(next_command_name)
472
+ return false if next_command_name == DescribeCommand.full_command_name
473
+ return true if next_command_has_inputs?
474
+
475
+ # check if inputs were unexpectedly given for a command that doesn't need them,
476
+ # in which case we should describe it
477
+ next_command_inputs && !next_command_inputs.empty?
478
+ end
479
+
480
+ def command_described?(command_name)
481
+ described_commands.include?(command_name)
482
+ end
483
+
445
484
  def llm_call_timestamps
446
485
  @llm_call_timestamps ||= []
447
486
  end
@@ -487,6 +526,10 @@ module Foobara
487
526
  sleep seconds
488
527
  end
489
528
  end
529
+
530
+ def context
531
+ agent.context
532
+ end
490
533
  end
491
534
  end
492
535
  end
@@ -2,9 +2,12 @@ require "foobara/llm_backed_command"
2
2
 
3
3
  module Foobara
4
4
  class Agent < CommandConnector
5
+ # TODO: just move this back to DetermineNextCommandAndInputs since it's now the only base class
5
6
  class DetermineBase < Foobara::LlmBackedCommand
6
7
  inputs do
7
- context Context, :required, "Context of the progress towards the goal so far"
8
+ pass_aggregates_to_llm :boolean, :allow_nil, "Should we send aggregates to the LLM or " \
9
+ "require it to fetch what it needs?"
10
+ agent Agent, :required
8
11
  llm_model :string,
9
12
  one_of: Foobara::Ai::AnswerBot::Types::ModelEnum,
10
13
  default: "claude-3-7-sonnet-20250219",
@@ -12,7 +15,11 @@ module Foobara
12
15
  end
13
16
 
14
17
  def association_depth
15
- Foobara::JsonSchemaGenerator::AssociationDepth::ATOM
18
+ if pass_aggregates_to_llm
19
+ Foobara::AssociationDepth::AGGREGATE
20
+ else
21
+ Foobara::AssociationDepth::ATOM
22
+ end
16
23
  end
17
24
 
18
25
  def build_messages
@@ -49,34 +56,13 @@ module Foobara
49
56
  p
50
57
  end
51
58
 
52
- def llm_instructions
53
- return @llm_instructions if defined?(@llm_instructions)
54
-
55
- description = self.class.description
56
-
57
- instructions = "You are the implementation of a command called #{self.class.scoped_full_name}"
58
-
59
- instructions += if description && !description.empty?
60
- " which has the following description:\n\n#{self.class.description}\n\n"
61
- else
62
- # :nocov:
63
- ". "
64
- # :nocov:
65
- end
66
-
67
- instructions += "You are working towards accomplishing the following goal:\n\n#{goal}\n\n"
68
- instructions += "Your response should match the following JSON schema: \n\n#{self.class.result_json_schema}\n\n"
69
- instructions += "You can get more details about the result schema for a specific command by " \
70
- "choosing the DescribeCommand command. " \
71
- "You will reply with nothing more than the JSON you've generated so that the calling code " \
72
- "can successfully parse your answer."
73
-
74
- @llm_instructions = instructions
75
- end
76
-
77
59
  def goal
78
60
  context.current_goal
79
61
  end
62
+
63
+ def context
64
+ agent.context
65
+ end
80
66
  end
81
67
  end
82
68
  end
@@ -3,6 +3,44 @@ require_relative "determine_base"
3
3
  module Foobara
4
4
  class Agent < CommandConnector
5
5
  class DetermineNextCommandNameAndInputs < DetermineBase
6
+ class << self
7
+ def llm_instructions(assistant_association_depth, goal)
8
+ key = [assistant_association_depth, goal]
9
+
10
+ @llm_instructions_cache ||= {}
11
+
12
+ if @llm_instructions_cache.key?(key)
13
+ @llm_instructions_cache[key]
14
+ else
15
+ @llm_instructions_cache[key] = build_llm_instructions(assistant_association_depth, goal)
16
+ end
17
+ end
18
+
19
+ def build_llm_instructions(assistant_association_depth, goal)
20
+ instructions = "You are the implementation of a command called #{scoped_full_name}"
21
+
22
+ instructions += if description && !description.empty?
23
+ " which has the following description:\n\n#{description}\n\n"
24
+ else
25
+ # :nocov:
26
+ ". "
27
+ # :nocov:
28
+ end
29
+
30
+ result_schema = result_json_schema(assistant_association_depth)
31
+
32
+ instructions += "You are working towards accomplishing the following goal:\n\n#{goal}\n\n"
33
+ instructions += "Your response of which command to run next should match the following JSON schema:"
34
+ instructions += "\n\n#{result_schema}\n\n"
35
+ instructions += "You can get more details about the inputs and result schemas for a specific command by " \
36
+ "choosing the DescribeCommand command. " \
37
+ "You will reply with nothing more than the JSON you've generated so that the calling code " \
38
+ "can successfully parse your answer."
39
+
40
+ instructions
41
+ end
42
+ end
43
+
6
44
  description "Returns the name of the next command to run and its inputs given the progress " \
7
45
  "towards accomplishing the current goal. " \
8
46
  "If the goal has been accomplished it will choose the " \
@@ -12,6 +50,10 @@ module Foobara
12
50
  command :string, :required
13
51
  inputs :attributes, :allow_nil
14
52
  end
53
+
54
+ def determine_llm_instructions
55
+ self.llm_instructions = self.class.llm_instructions(computed_user_association_depth, goal)
56
+ end
15
57
  end
16
58
  end
17
59
  end
@@ -1,15 +1,18 @@
1
1
  module Foobara
2
2
  class Agent < CommandConnector
3
+ # NOTE: we intentionally don't use a result type here
4
+ # to reduce tokens the LLM has to deal with when this command is described
3
5
  class NotifyUserThatCurrentGoalHasBeenAccomplished < Foobara::Command
4
6
  extend Concerns::SubclassCacheable
5
7
 
6
8
  class << self
7
- attr_accessor :command_class, :returns_message_to_user, :returns_result_data, :result_is_attributes
9
+ attr_accessor :command_class, :returns_message_to_user, :returns_result_data, :result_is_attributes,
10
+ :built_result_type
8
11
 
9
- def for(agent_id: nil, result_type: nil, include_message_to_user_in_result: true)
12
+ def for(agent_id: nil, result_type: nil, include_message_to_user_in_result: true, result_entity_depth: nil)
10
13
  agent_id ||= "Anon#{SecureRandom.hex(2)}"
11
14
 
12
- cached_subclass([result_type, agent_id, include_message_to_user_in_result]) do
15
+ cached_subclass([agent_id]) do
13
16
  command_name = "Foobara::Agent::#{agent_id}::NotifyUserThatCurrentGoalHasBeenAccomplished"
14
17
  klass = Util.make_class_p(command_name, self)
15
18
 
@@ -20,39 +23,40 @@ module Foobara
20
23
 
21
24
  if result_type
22
25
  klass.returns_result_data = true
26
+ unless result_type.is_a?(Types::Type)
27
+ result_type = Domain.current.foobara_type_from_declaration(result_type)
28
+ end
29
+
30
+ domain = result_type.created_in_namespace.foobara_domain
23
31
 
24
32
  # TODO: fix this... agent backed command sets these via its own result type.
25
33
  # check if message_to_user is already here and also search/fix result_data to be result for consistency.
26
34
  if include_message_to_user_in_result
27
35
  klass.returns_message_to_user = true
28
36
 
29
- klass.result do
37
+ klass.built_result_type = domain.foobara_type_from_declaration do
30
38
  result result_type, :required
31
39
  message_to_user :string, :required, "Message to the user about what was done"
32
40
  end
33
41
 
34
- klass.add_inputs klass.result_type
42
+ klass.add_inputs klass.built_result_type
35
43
 
36
44
  klass.description "Notifies the user that the current goal has been accomplished and returns a final " \
37
45
  "result formatted according to the " \
38
46
  "result schema and a message to the user. " \
39
47
  "The user might issue a new goal."
40
48
  else
41
- unless result_type.is_a?(Types::Type)
42
- result_type = Domain.current.foobara_type_from_declaration(result_type)
43
- end
44
-
45
49
  if result_type.extends?(BuiltinTypes[:attributes])
50
+ klass.built_result_type = result_type
46
51
  klass.result_is_attributes = true
47
52
  klass.add_inputs result_type
48
53
  else
49
- klass.add_inputs do
54
+ klass.built_result_type = domain.foobara_type_from_declaration do
50
55
  result result_type, :required
51
56
  end
57
+ klass.add_inputs klass.built_result_type
52
58
  end
53
59
 
54
- klass.result result_type
55
-
56
60
  klass.description "Notifies the user that the current goal has been accomplished and returns a final " \
57
61
  "result formatted according to the " \
58
62
  "result schema. " \
@@ -65,10 +69,6 @@ module Foobara
65
69
  message_to_user :string, :required, "Message to the user about what was done"
66
70
  end
67
71
 
68
- klass.result do
69
- message_to_user :string, :required, "Message to the user about what was done"
70
- end
71
-
72
72
  klass.description "Notifies the user that the current goal has been accomplished and results in a " \
73
73
  "message to the user. " \
74
74
  "The user might issue a new goal."
@@ -80,9 +80,46 @@ module Foobara
80
80
  # :nocov:
81
81
  end
82
82
 
83
+ apply_result_data_transformer(klass, result_entity_depth)
84
+
83
85
  klass
84
86
  end
85
87
  end
88
+
89
+ def result_data_transformer(result_entity_depth)
90
+ if result_entity_depth
91
+ case result_entity_depth
92
+ when AssociationDepth::AGGREGATE
93
+ CommandConnectors::Transformers::LoadAggregatesTransformer
94
+ when AssociationDepth::ATOM
95
+ CommandConnectors::Transformers::LoadAtomsTransformer
96
+ else
97
+ # :nocov:
98
+ raise "Unsupported result entity depth: #{result_entity_depth}"
99
+ # :nocov:
100
+ end&.instance
101
+ end
102
+ end
103
+
104
+ def apply_result_data_transformer(command_klass, result_entity_depth)
105
+ transformer = result_data_transformer(result_entity_depth)
106
+ return unless transformer
107
+
108
+ inputs_type = command_klass.inputs_type
109
+ return unless inputs_type
110
+
111
+ if inputs_type.extends?(BuiltinTypes[:detached_entity]) ||
112
+ DetachedEntity.contains_associations?(inputs_type)
113
+ command_klass.before_commit_transaction do |command:, **|
114
+ # TODO: why can't we just pass in the command??
115
+ built_result = command.built_result
116
+
117
+ if built_result
118
+ transformer.process_value!(built_result)
119
+ end
120
+ end
121
+ end
122
+ end
86
123
  end
87
124
 
88
125
  description "Ends the session giving a final result formatted according to the " \
@@ -96,7 +133,7 @@ module Foobara
96
133
  build_result
97
134
  mark_mission_accomplished
98
135
 
99
- built_result
136
+ nil
100
137
  end
101
138
 
102
139
  attr_accessor :built_result
@@ -116,7 +153,7 @@ module Foobara
116
153
  inputs.slice(:result, :message_to_user)
117
154
  elsif returns_result_data?
118
155
  if result_is_attributes?
119
- inputs.slice(*self.class.result_type.element_types.keys)
156
+ inputs.slice(*self.class.built_result_type.element_types.keys)
120
157
  else
121
158
  inputs[:result]
122
159
  end
@@ -11,6 +11,17 @@ module Foobara
11
11
  errors_hash :duck, "Errors that occurred during the command"
12
12
  end
13
13
  end
14
+
15
+ def success?
16
+ outcome[:success]
17
+ end
18
+
19
+ def errors_hash
20
+ # TODO: test this path
21
+ # :nocov:
22
+ outcome[:errors_hash]
23
+ # :nocov:
24
+ end
14
25
  end
15
26
  end
16
27
  end
data/src/foobara/agent.rb CHANGED
@@ -23,7 +23,9 @@ module Foobara
23
23
  :verbose,
24
24
  :io_out,
25
25
  :io_err,
26
- :max_llm_calls_per_minute
26
+ :max_llm_calls_per_minute,
27
+ :pass_aggregates_to_llm,
28
+ :result_entity_depth
27
29
 
28
30
  def initialize(
29
31
  context: nil,
@@ -36,6 +38,8 @@ module Foobara
36
38
  io_out: nil,
37
39
  io_err: nil,
38
40
  max_llm_calls_per_minute: nil,
41
+ result_entity_depth: AssociationDepth::AGGREGATE,
42
+ pass_aggregates_to_llm: nil,
39
43
  **opts
40
44
  )
41
45
  # TODO: shouldn't have to pass command_log here since it has a default, debug that
@@ -48,25 +52,22 @@ module Foobara
48
52
  self.io_out = io_out
49
53
  self.io_err = io_err
50
54
  self.max_llm_calls_per_minute = max_llm_calls_per_minute
55
+ self.result_entity_depth = result_entity_depth
56
+ self.pass_aggregates_to_llm = pass_aggregates_to_llm
51
57
 
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
+ pre_commit_transformer = if pass_aggregates_to_llm
59
+ CommandConnectors::Transformers::LoadAggregatesPreCommitTransformer
60
+ else
61
+ CommandConnectors::Transformers::LoadAtomsPreCommitTransformer
62
+ end
58
63
 
59
- unless opts.key?(:default_pre_commit_transformers)
60
- opts = opts.merge(
61
- default_pre_commit_transformers: Foobara::CommandConnectors::Transformers::LoadAtomsPreCommitTransformer
62
- )
63
- end
64
+ opts = opts.merge(default_pre_commit_transformers: [
65
+ *opts[:default_pre_commit_transformers],
66
+ pre_commit_transformer
67
+ ].uniq)
64
68
 
65
69
  super(**opts)
66
70
 
67
- # TODO: this should work now, switch to this approach
68
- # add_default_inputs_transformer EntityToPrimaryKeyInputsTransformer
69
-
70
71
  # TODO: push this convenience method up into base class?
71
72
  command_classes&.each do |command_class|
72
73
  connect(command_class)
@@ -140,42 +141,7 @@ module Foobara
140
141
  state_machine.perform_transition!(:accomplish_goal)
141
142
 
142
143
  begin
143
- inputs = {
144
- goal:,
145
- final_result_type: self.result_type,
146
- context:,
147
- agent: self
148
- }
149
-
150
- llm_model ||= self.llm_model
151
-
152
- if llm_model
153
- inputs[:llm_model] = llm_model
154
- end
155
-
156
- unless maximum_call_count.nil?
157
- inputs[:maximum_command_calls] = maximum_call_count
158
- end
159
-
160
- if verbose
161
- inputs[:verbose] = verbose
162
- end
163
-
164
- if io_out
165
- inputs[:io_out] = io_out
166
- end
167
-
168
- if io_err
169
- inputs[:io_err] = io_err
170
- end
171
-
172
- if include_message_to_user_in_result || include_message_to_user_in_result == false
173
- inputs[:include_message_to_user_in_result] = include_message_to_user_in_result
174
- end
175
-
176
- if max_llm_calls_per_minute && max_llm_calls_per_minute > 0
177
- inputs[:max_llm_calls_per_minute] = max_llm_calls_per_minute
178
- end
144
+ inputs = accomplish_goal_inputs(goal, result_type:, maximum_call_count:, llm_model:)
179
145
 
180
146
  self.current_accomplish_goal_command = AccomplishGoal.new(inputs)
181
147
 
@@ -196,6 +162,57 @@ module Foobara
196
162
  end
197
163
  end
198
164
 
165
+ def accomplish_goal_inputs(goal,
166
+ result_type: nil,
167
+ maximum_call_count: nil,
168
+ llm_model: nil)
169
+ inputs = {
170
+ goal:,
171
+ final_result_type: self.result_type,
172
+ agent: self
173
+ }
174
+
175
+ llm_model ||= self.llm_model
176
+
177
+ if llm_model
178
+ inputs[:llm_model] = llm_model
179
+ end
180
+
181
+ unless maximum_call_count.nil?
182
+ inputs[:maximum_command_calls] = maximum_call_count
183
+ end
184
+
185
+ if verbose
186
+ inputs[:verbose] = verbose
187
+ end
188
+
189
+ if io_out
190
+ inputs[:io_out] = io_out
191
+ end
192
+
193
+ if io_err
194
+ inputs[:io_err] = io_err
195
+ end
196
+
197
+ if include_message_to_user_in_result || include_message_to_user_in_result == false
198
+ inputs[:include_message_to_user_in_result] = include_message_to_user_in_result
199
+ end
200
+
201
+ if max_llm_calls_per_minute && max_llm_calls_per_minute > 0
202
+ inputs[:max_llm_calls_per_minute] = max_llm_calls_per_minute
203
+ end
204
+
205
+ if result_entity_depth
206
+ inputs[:result_entity_depth] = result_entity_depth
207
+ end
208
+
209
+ unless pass_aggregates_to_llm.nil?
210
+ inputs[:pass_aggregates_to_llm] = pass_aggregates_to_llm
211
+ end
212
+
213
+ inputs
214
+ end
215
+
199
216
  def set_context_goal(goal)
200
217
  if context
201
218
  context.set_new_goal(goal)
@@ -232,7 +249,8 @@ module Foobara
232
249
  result_type:,
233
250
  agent_id: agent_name,
234
251
  # TODO: Support changing this flag when the goal changes
235
- include_message_to_user_in_result:
252
+ include_message_to_user_in_result:,
253
+ result_entity_depth:
236
254
  )
237
255
  else
238
256
  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.11
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.0.1
32
+ version: 1.0.0
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 0.0.1
39
+ version: 1.0.0
40
40
  email:
41
41
  - azimux@gmail.com
42
42
  executables: []