foobara-agent 0.0.5 → 0.0.6

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: 88347fd73d897f4a3f05eb2dcec999c5afddcec625cecc79a44a1a803394b352
4
- data.tar.gz: '016936d6acc4e2497aa8e8853d058653d201d3d7d5c2c77090128b728f8833fe'
3
+ metadata.gz: 121474f4e61c1b3a5eebc883794bef41159d48ecc05eba44165bd8d79111c426
4
+ data.tar.gz: 50bc4c4aea5bd447f17cf39712b7a86295e4f45708602398f72a61af2f221881
5
5
  SHA512:
6
- metadata.gz: 5672d6bd7930969b566d6dce04314062116593cd2df5c06d718916d83938deb91af64765a85752f7b5c8119d0fce32a56099907b252da636f0408fb3109bf38c
7
- data.tar.gz: 71b2c350e024aca9d86c1f5f2bfd3d83726784ab028c6d7b6e0010a88512c1a06351cfbb298478fc1e5f6b5126367e9bca5d417040b9d493153fe7d142b20faa
6
+ metadata.gz: e0cbf20f7fc287bd4a3be5caed0572de59475493ae4bed80d755b5284ead25fa697b455959ca323891bb20f0bfb57a5a01f1e62f335faacc6c99c220821920f3
7
+ data.tar.gz: cf85ac42b6ab4a9f8efddd35e533afd32f664b9a9ec8bba17f77abf424a5499e64ba6ad576b54bb24c03dadb5e6bc1c2fe54a502bd505f30caaeeb15e002d655
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.0.6] - 2025-06-19
2
+
3
+ - Do not run next command with pre-cast inputs
4
+ - Make result_data and message_to_user required (probably unwise for message_to_user?)
5
+ - Simulate ListCommands and DescribeCommand being at start
6
+ - Add a verbose flag for debugging help
7
+ - Give each AccomplishGoal its own command call count
8
+ - Convert entities to their aggregates as input and primary keys as output
9
+
1
10
  ## [0.0.5] - 2025-05-30
2
11
 
3
12
  - Don't require agents to have a name
@@ -1,7 +1,6 @@
1
1
  require_relative "list_commands"
2
2
 
3
3
  module Foobara
4
- # TODO: should agent maybe be a command connector? It feels a bit more like a command connector.
5
4
  class Agent < CommandConnector
6
5
  class AccomplishGoal < Foobara::Command
7
6
  possible_error :gave_up, context: { reason: :string }, message: "Gave up."
@@ -14,6 +13,9 @@ module Foobara
14
13
  # TODO: we should be able to specify a subclass as a type
15
14
  command_classes [Class], "Commands that can be ran to accomplish the goal"
16
15
  final_result_type :duck, "Specifies how the result of the goal is to be structured"
16
+ verbose :boolean, default: false
17
+ io_out :duck
18
+ io_err :duck
17
19
  existing_command_connector CommandConnector, :allow_nil,
18
20
  "A connector containing already-connected commands for the agent to use"
19
21
  current_context Context, :allow_nil, "The current context of the agent"
@@ -62,8 +64,13 @@ module Foobara
62
64
  connect_agent_commands
63
65
  end
64
66
 
67
+ simulate_list_commands_run
68
+ simulate_describe_command_run_for_all_commands
69
+
65
70
  until mission_accomplished or given_up
71
+ increment_command_calls
66
72
  check_if_too_many_calls
73
+
67
74
  if choose_next_command_and_next_inputs_separately?
68
75
  determine_next_command_then_inputs_separately
69
76
  else
@@ -95,7 +102,8 @@ module Foobara
95
102
 
96
103
  attr_accessor :context, :next_command_name, :next_command_inputs, :mission_accomplished, :given_up,
97
104
  :next_command_class, :next_command, :command_outcome, :timed_out,
98
- :final_result, :final_message, :command_response, :delayed_command_name
105
+ :final_result, :final_message, :command_response, :delayed_command_name,
106
+ :command_calls
99
107
  attr_writer :command_connector
100
108
 
101
109
  def agent_name
@@ -107,6 +115,32 @@ module Foobara
107
115
  self.context = current_context || Context.new(command_log: [])
108
116
  end
109
117
 
118
+ def simulate_list_commands_run
119
+ return unless context.command_log.empty?
120
+
121
+ self.next_command_name = ListCommands.full_command_name
122
+ self.next_command_inputs = nil
123
+ fetch_next_command_class
124
+
125
+ run_next_command
126
+ log_last_command_outcome
127
+ end
128
+
129
+ def simulate_describe_command_run_for_all_commands
130
+ return if context.command_log.size > 1
131
+
132
+ ListCommands.run!(command_connector:)[:user_provided_commands].each do |full_command_name|
133
+ next if described_commands.include?(full_command_name)
134
+
135
+ self.next_command_name = DescribeCommand.full_command_name
136
+ self.next_command_inputs = { command_name: full_command_name }
137
+ fetch_next_command_class
138
+
139
+ run_next_command
140
+ log_last_command_outcome
141
+ end
142
+ end
143
+
110
144
  def command_connector_passed_in?
111
145
  existing_command_connector
112
146
  end
@@ -120,7 +154,9 @@ module Foobara
120
154
  def build_command_connector
121
155
  self.command_connector ||= Agent.new(
122
156
  current_accomplish_goal_command: self,
123
- llm_model:
157
+ llm_model:,
158
+ verbose:,
159
+ io_out:
124
160
  )
125
161
  end
126
162
 
@@ -139,13 +175,6 @@ module Foobara
139
175
  end
140
176
 
141
177
  def determine_next_command_and_inputs(retries = 2)
142
- if context.command_log.empty?
143
- self.next_command_name = ListCommands.full_command_name
144
- self.next_command_inputs = nil
145
- fetch_next_command_class
146
- return
147
- end
148
-
149
178
  inputs_for_determine = {
150
179
  goal:,
151
180
  context:,
@@ -250,15 +279,9 @@ module Foobara
250
279
  def validate_next_command_inputs
251
280
  inputs_type = next_command_class.inputs_type
252
281
 
253
- outcome = NestedTransactionable.with_needed_transactions_for_type(inputs_type) do
282
+ NestedTransactionable.with_needed_transactions_for_type(inputs_type) do
254
283
  inputs_type.process_value(next_command_inputs)
255
284
  end
256
-
257
- if outcome.success?
258
- self.next_command_inputs = outcome.result
259
- end
260
-
261
- outcome
262
285
  end
263
286
 
264
287
  def command_name_type
@@ -266,9 +289,7 @@ module Foobara
266
289
  end
267
290
 
268
291
  def determine_next_command_name(retries = 2)
269
- self.next_command_name = if context.command_log.empty?
270
- ListCommands.full_command_name
271
- elsif delayed_command_name
292
+ self.next_command_name = if delayed_command_name
272
293
  name = delayed_command_name
273
294
  self.delayed_command_name = nil
274
295
  name
@@ -392,6 +413,10 @@ module Foobara
392
413
  end
393
414
 
394
415
  def run_next_command
416
+ if verbose?
417
+ (io_out || $stdout).puts "Running #{next_command_name} with #{next_command_inputs}"
418
+ end
419
+
395
420
  self.command_response = command_connector.run(
396
421
  full_command_name: next_command_name,
397
422
  inputs: next_command_inputs,
@@ -399,14 +424,31 @@ module Foobara
399
424
  )
400
425
 
401
426
  self.command_outcome = command_response.outcome
427
+
428
+ if verbose?
429
+ if command_outcome.success?
430
+ (io_out || $stdout).puts "Command #{command_response.command.class.full_command_name} succeeded"
431
+ else
432
+ # :nocov:
433
+ (io_err || $stderr).puts(
434
+ "Command #{command_response.command.class.full_command_name} failed #{command_outcome.errors_hash}"
435
+ )
436
+ # :nocov:
437
+ end
438
+ end
402
439
  end
403
440
 
404
441
  def log_last_command_outcome
405
442
  log_command_outcome(command: command_response.command)
406
443
  end
407
444
 
445
+ def increment_command_calls
446
+ self.command_calls ||= -1
447
+ self.command_calls += 1
448
+ end
449
+
408
450
  def check_if_too_many_calls
409
- if context.command_log.size > maximum_command_calls
451
+ if command_calls > maximum_command_calls
410
452
  add_runtime_error(
411
453
  :too_many_command_calls,
412
454
  "Too many command calls. " \
@@ -485,6 +527,10 @@ module Foobara
485
527
  def choose_next_command_and_next_inputs_separately?
486
528
  choose_next_command_and_next_inputs_separately
487
529
  end
530
+
531
+ def verbose?
532
+ verbose
533
+ end
488
534
  end
489
535
  end
490
536
  end
@@ -18,17 +18,17 @@ module Foobara
18
18
 
19
19
  inputs do
20
20
  command_connector CommandConnector, :required, "Connector to notify user through"
21
- message_to_user :string, "Optional message to the user"
21
+ message_to_user :string, :required, "Message to the user about what was done"
22
22
  end
23
23
 
24
24
  if result_type
25
25
  add_inputs do
26
- result_data result_type
26
+ result_data result_type, :required
27
27
  end
28
28
 
29
29
  klass.result do
30
- message_to_user :string
31
- result_data result_type
30
+ message_to_user :string, :required
31
+ result_data result_type, :required
32
32
  end
33
33
  klass.description "Notifies the user that the current goal has been accomplished and returns a final " \
34
34
  "result formatted according to the " \
@@ -57,7 +57,7 @@ module Foobara
57
57
  inputs do
58
58
  # TODO: Are we still not able to uses classes as foobara types??
59
59
  command_connector :duck, :required, "Connector to end"
60
- message_to_user :string, "Optional message to the user"
60
+ message_to_user :string, :required, "Message to the user about what was done"
61
61
  result_data :duck, "The final result of the work if relevant/expected"
62
62
  end
63
63
 
data/src/foobara/agent.rb CHANGED
@@ -18,7 +18,10 @@ module Foobara
18
18
  :llm_model,
19
19
  :current_accomplish_goal_command,
20
20
  :result_type,
21
- :agent_commands_connected
21
+ :agent_commands_connected,
22
+ :verbose,
23
+ :io_out,
24
+ :io_err
22
25
 
23
26
  def initialize(
24
27
  context: nil,
@@ -27,6 +30,9 @@ module Foobara
27
30
  llm_model: nil,
28
31
  result_type: nil,
29
32
  current_accomplish_goal_command: nil,
33
+ verbose: false,
34
+ io_out: nil,
35
+ io_err: nil,
30
36
  **opts
31
37
  )
32
38
  # TODO: shouldn't have to pass command_log here since it has a default, debug that
@@ -35,16 +41,22 @@ module Foobara
35
41
  self.llm_model = llm_model
36
42
  self.result_type = result_type
37
43
  self.current_accomplish_goal_command = current_accomplish_goal_command
44
+ self.verbose = verbose
45
+ self.io_out = io_out
46
+ self.io_err = io_err
38
47
 
39
48
  unless opts.key?(:default_serializers)
40
49
  opts = opts.merge(default_serializers: [
41
50
  Foobara::CommandConnectors::Serializers::ErrorsSerializer,
42
- Foobara::CommandConnectors::Serializers::AtomicSerializer
51
+ Foobara::CommandConnectors::Serializers::AggregateSerializer
43
52
  ])
44
53
  end
45
54
 
46
55
  super(**opts)
47
56
 
57
+ # TODO: this should work now, switch to this approach
58
+ # add_default_inputs_transformer EntityToPrimaryKeyInputsTransformer
59
+
48
60
  build_initial_context
49
61
 
50
62
  # TODO: push this convenience method up into base class?
@@ -53,6 +65,20 @@ module Foobara
53
65
  end
54
66
  end
55
67
 
68
+ def connect(*args, **opts)
69
+ args, opts = desugarize_connect_args(args, opts)
70
+
71
+ inputs_transformers = opts[:inputs_transformers] || []
72
+ inputs_transformers = Util.array(inputs_transformers)
73
+ inputs_transformers << CommandConnectors::Transformers::EntityToPrimaryKeyInputsTransformer
74
+
75
+ unless opts.key?(:aggregate_entities)
76
+ opts = opts.merge(aggregate_entities: true)
77
+ end
78
+
79
+ super(*args, **opts.merge(inputs_transformers:))
80
+ end
81
+
56
82
  def run(*args, **)
57
83
  if args.first.is_a?(::String)
58
84
  accomplish_goal(*args, **)
@@ -123,6 +149,18 @@ module Foobara
123
149
  inputs[:maximum_command_calls] = maximum_call_count
124
150
  end
125
151
 
152
+ if verbose
153
+ inputs[:verbose] = verbose
154
+ end
155
+
156
+ if io_out
157
+ inputs[:io_out] = io_out
158
+ end
159
+
160
+ if io_err
161
+ inputs[:io_err] = io_err
162
+ end
163
+
126
164
  self.current_accomplish_goal_command = AccomplishGoal.new(inputs)
127
165
 
128
166
  current_accomplish_goal_command.run.tap do |outcome|
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.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
@@ -85,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
85
  - !ruby/object:Gem::Version
86
86
  version: '0'
87
87
  requirements: []
88
- rubygems_version: 3.6.7
88
+ rubygems_version: 3.6.9
89
89
  specification_version: 4
90
90
  summary: An agent that uses whatever Foobara commands you wish to accomplish goals
91
91
  of your choosing!