agent99 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/README.md +46 -2
  4. data/docs/README.md +57 -0
  5. data/docs/advanced_features.md +110 -0
  6. data/docs/agent_discovery.md +62 -0
  7. data/docs/agent_lifecycle.md +137 -0
  8. data/docs/agent_registry_processes.md +102 -0
  9. data/docs/api_reference.md +136 -0
  10. data/docs/architecture.md +77 -0
  11. data/docs/configuration.md +17 -0
  12. data/docs/control_actions.md +179 -0
  13. data/docs/custom_agent_implementation.md +30 -0
  14. data/docs/diagrams/agent_registry_processes.dot +42 -0
  15. data/docs/diagrams/agent_registry_processes.png +0 -0
  16. data/docs/diagrams/high_level_architecture.dot +26 -0
  17. data/docs/diagrams/high_level_architecture.png +0 -0
  18. data/docs/diagrams/request_flow.dot +42 -0
  19. data/docs/diagrams/request_flow.png +0 -0
  20. data/docs/error_handling_and_logging.md +13 -0
  21. data/docs/extending_the_framework.md +11 -0
  22. data/docs/message_processing.md +165 -0
  23. data/docs/messaging_system.md +129 -0
  24. data/docs/preformance_considerations.md +9 -0
  25. data/docs/schema_definition.md +78 -0
  26. data/docs/security.md +9 -0
  27. data/docs/troubleshooting.md +11 -0
  28. data/examples/README.md +65 -35
  29. data/examples/agent_watcher.rb +102 -0
  30. data/examples/agents/.keep +0 -0
  31. data/examples/chief_agent.rb +96 -0
  32. data/examples/control.rb +136 -0
  33. data/examples/diagram.dot +22 -0
  34. data/examples/diagram.png +0 -0
  35. data/examples/example_agent.rb +26 -0
  36. data/examples/kaos_spy.rb +63 -0
  37. data/examples/{hello_world.rb → maxwell_agent86.rb} +38 -18
  38. data/examples/{hello_world_request.rb → maxwell_request.rb} +2 -2
  39. data/examples/registry.rb +8 -7
  40. data/examples/start_rabbitmq_and_registry.sh +29 -0
  41. data/lib/agent99/agent_lifecycle.rb +14 -15
  42. data/lib/agent99/amqp_message_client.rb +41 -10
  43. data/lib/agent99/base.rb +6 -8
  44. data/lib/agent99/control_actions.rb +80 -47
  45. data/lib/agent99/header_management.rb +6 -4
  46. data/lib/agent99/header_schema.rb +5 -0
  47. data/lib/agent99/message_processing.rb +21 -13
  48. data/lib/agent99/registry_client.rb +8 -0
  49. data/lib/agent99/version.rb +1 -1
  50. data/lib/agent99.rb +4 -0
  51. metadata +41 -11
  52. data/docs/todo.md +0 -66
  53. data/examples/hello_world_client.rb +0 -70
  54. data/examples/start_agents.sh +0 -20
data/lib/agent99/base.rb CHANGED
@@ -36,14 +36,6 @@ class Agent99::Base
36
36
  include Agent99::MessageProcessing
37
37
 
38
38
  MESSAGE_TYPES = %w[request response control]
39
-
40
- CONTROL_HANDLERS = {
41
- 'shutdown' => :handle_shutdown,
42
- 'pause' => :handle_pause,
43
- 'resume' => :handle_resume,
44
- 'update_config' => :handle_update_config,
45
- 'status' => :handle_status_request
46
- }
47
39
 
48
40
  attr_reader :id, :capabilities, :name, :payload, :header, :logger, :queue
49
41
  attr_accessor :registry_client, :message_client
@@ -56,6 +48,12 @@ class Agent99::Base
56
48
  logger.error "#{message}: #{error.message}"
57
49
  logger.debug error.backtrace.join("\n")
58
50
  end
51
+
52
+
53
+ # the final rescue block
54
+ rescue StandardError => e
55
+ handle_error("Unhandled error in Agent99::Base", e)
56
+ exit(2)
59
57
  end
60
58
 
61
59
 
@@ -1,56 +1,89 @@
1
1
  # lib/agent99/control_actions.rb
2
2
 
3
3
 
4
- module Agent99::ControlActions
5
-
6
-
7
- ################################################
8
- private
9
-
10
- # Handles the shutdown control message.
11
- #
12
- def handle_shutdown
13
- logger.info "Received shutdown command. Initiating graceful shutdown..."
14
- send_control_response("Shutting down")
15
- fini
16
- exit(0)
17
- end
4
+ module Agent99
5
+ CONTROL_HANDLERS = {
6
+ 'shutdown' => :handle_shutdown,
7
+ 'pause' => :handle_pause,
8
+ 'resume' => :handle_resume,
9
+ 'update_config' => :handle_update_config,
10
+ 'status' => :handle_status_request,
11
+ 'response' => :handle_control_response,
12
+ }
18
13
 
19
- # Handles the pause control message.
20
- #
21
- def handle_pause
22
- @paused = true
23
- logger.info "Agent paused"
24
- send_control_response("Paused")
25
- end
14
+ module ControlActions
26
15
 
27
- # Handles the resume control message.
28
- #
29
- def handle_resume
30
- @paused = false
31
- logger.info "Agent resumed"
32
- send_control_response("Resumed")
33
- end
34
16
 
35
- # Handles the update_config control message.
36
- #
37
- def handle_update_config
38
- new_config = payload[:config]
39
- @config = new_config
40
- logger.info "Configuration updated: #{@config}"
41
- send_control_response("Configuration updated")
42
- end
17
+ ################################################
18
+ private
19
+
20
+ def handle_control_response
21
+ logger.info "Received control response: #{payload}"
22
+ response_type = payload.dig(:data, :type)
23
+ response_data = payload[:data]
24
+
25
+ case response_type
26
+ when 'status'
27
+ logger.info "Status update from agent: #{response_data}"
28
+ when 'error'
29
+ logger.error "Error from agent: #{response_data[:error]}"
30
+ else
31
+ logger.info "Generic control response: #{payload[:message]}"
32
+ end
33
+ end
34
+
35
+
36
+ # Handles the shutdown control message.
37
+ #
38
+ def handle_shutdown
39
+ logger.info "Received shutdown command. Initiating graceful shutdown..."
40
+ send_control_response("Shutting down")
41
+ fini
42
+ exit(0)
43
+ end
44
+
43
45
 
44
- # Handles the status request control message.
45
- #
46
- def handle_status_request
47
- status = {
48
- id: @id,
49
- name: @name,
50
- paused: @paused,
51
- config: @config,
52
- uptime: (Time.now - @start_time).to_i
53
- }
54
- send_control_response("Status", status)
46
+ # Handles the pause control message.
47
+ #
48
+ def handle_pause
49
+ @paused = true
50
+ logger.info "Agent paused"
51
+ send_control_response("Paused")
52
+ end
53
+
54
+
55
+ # Handles the resume control message.
56
+ #
57
+ def handle_resume
58
+ @paused = false
59
+ logger.info "Agent resumed"
60
+ send_control_response("Resumed")
61
+ end
62
+
63
+
64
+ # Handles the update_config control message.
65
+ #
66
+ def handle_update_config
67
+ new_config = payload[:config]
68
+ @config = new_config
69
+ logger.info "Configuration updated: #{@config}"
70
+ send_control_response("Configuration updated")
71
+ end
72
+
73
+
74
+ # Handles the status request control message.
75
+ #
76
+ def handle_status_request
77
+ status = {
78
+ type: 'status',
79
+ id: @id,
80
+ name: @name,
81
+ paused: @paused,
82
+ config: @config,
83
+ uptime: (Time.now - @start_time).to_i
84
+ }
85
+ send_control_response(status)
86
+ end
55
87
  end
56
88
  end
89
+
@@ -4,7 +4,7 @@ module Agent99::HeaderManagement
4
4
 
5
5
 
6
6
  ################################################
7
- private
7
+ # private
8
8
 
9
9
  def header = @payload[:header]
10
10
  def to_uuid = header[:to_uuid]
@@ -14,9 +14,11 @@ module Agent99::HeaderManagement
14
14
  def type = header[:type]
15
15
 
16
16
  def return_address
17
- header.merge(
18
- to_uuid: from_uuid,
19
- from_uuid: to_uuid,
17
+ return_address = payload[:header].dup
18
+
19
+ return_address.merge(
20
+ to_uuid: return_address[:from_uuid],
21
+ from_uuid: return_address[:to_uuid],
20
22
  timestamp: Agent99::Timestamp.new.to_i,
21
23
  type: 'response'
22
24
  )
@@ -13,3 +13,8 @@ class Agent99::HeaderSchema < SimpleJsonSchemaBuilder::Base
13
13
  integer :timestamp, required: true, examples: [Agent99::Timestamp.new.to_i]
14
14
  end
15
15
  end
16
+
17
+ __END__
18
+
19
+ string :type, required: true, enum: %w[request response control]
20
+
@@ -16,14 +16,15 @@ module Agent99::MessageProcessing
16
16
  #
17
17
  def dispatcher
18
18
  @start_time = Time.now
19
- @paused = false
20
- @config = {}
19
+ @paused = false
20
+ @config = {}
21
+
21
22
 
22
23
  message_client.listen_for_messages(
23
24
  queue,
24
- request_handler: ->(message) { process_request(message) unless paused? },
25
+ request_handler: ->(message) { process_request(message) unless paused? },
25
26
  response_handler: ->(message) { process_response(message) unless paused? },
26
- control_handler: ->(message) { process_control(message) }
27
+ control_handler: ->(message) { process_control(message) }
27
28
  )
28
29
  end
29
30
 
@@ -33,8 +34,8 @@ module Agent99::MessageProcessing
33
34
  # @param message [Hash] The incoming message
34
35
  #
35
36
  def process_request(message)
36
- @payload = message
37
- @header = payload[:header]
37
+ @payload = message
38
+ @header = payload[:header]
38
39
  return unless validate_schema.empty?
39
40
  receive_request
40
41
  end
@@ -54,11 +55,14 @@ module Agent99::MessageProcessing
54
55
  #
55
56
  def process_control(message)
56
57
  @payload = message
57
- receive_control
58
+ if payload[:action] == 'response'
59
+ receive_response
60
+ else
61
+ receive_control
62
+ end
58
63
  end
59
64
 
60
65
 
61
-
62
66
  # Handles incoming request messages (to be overridden by subclasses).
63
67
  #
64
68
  def receive_request
@@ -78,8 +82,9 @@ module Agent99::MessageProcessing
78
82
  # @raise [StandardError] If there's an error processing the control message
79
83
  #
80
84
  def receive_control
81
- action = payload[:action]
82
- handler = CONTROL_HANDLERS[action]
85
+
86
+ action = payload[:action]
87
+ handler = Agent99::CONTROL_HANDLERS[action]
83
88
 
84
89
  if handler
85
90
  send(handler)
@@ -89,7 +94,7 @@ module Agent99::MessageProcessing
89
94
 
90
95
  rescue StandardError => e
91
96
  logger.error "Error processing control message: #{e.message}"
92
- send_control_response("Error", { error: e.message })
97
+ send_control_response({ error: e.message })
93
98
  end
94
99
 
95
100
 
@@ -108,15 +113,16 @@ module Agent99::MessageProcessing
108
113
  # @param message [String] The response message
109
114
  # @param data [Hash, nil] Additional data to include in the response
110
115
  #
111
- def send_control_response(message, data = nil)
116
+ def send_control_response(data)
112
117
  response = {
113
118
  header: return_address.merge(type: 'control'),
114
- message: message,
119
+ action: 'response',
115
120
  data: data
116
121
  }
117
122
  @message_client.publish(response)
118
123
  end
119
124
 
125
+
120
126
  # Validates the incoming message against the defined schema.
121
127
  #
122
128
  # @return [Array] An array of validation errors, empty if validation succeeds
@@ -135,6 +141,7 @@ module Agent99::MessageProcessing
135
141
  e.messages
136
142
  end
137
143
 
144
+
138
145
  # Retrieves a field from the payload or returns a default value.
139
146
  #
140
147
  # @param field [Symbol] The field to retrieve
@@ -144,6 +151,7 @@ module Agent99::MessageProcessing
144
151
  payload[field] || default(field)
145
152
  end
146
153
 
154
+
147
155
  # Returns the default value for a field from the schema.
148
156
  #
149
157
  # @param field [Symbol] The field to get the default for
@@ -35,6 +35,12 @@ class Agent99::RegistryClient
35
35
  send_request(request)
36
36
  end
37
37
 
38
+
39
+ def fetch_all_agents
40
+ request = create_request(:get, "/")
41
+ response = send_request(request)
42
+ end
43
+
38
44
  ################################################
39
45
  private
40
46
 
@@ -48,9 +54,11 @@ class Agent99::RegistryClient
48
54
  response = @http_client.request(request)
49
55
 
50
56
  handle_response(response)
57
+
51
58
  rescue JSON::ParserError => e
52
59
  logger.error "JSON parsing error: #{e.message}"
53
60
  nil
61
+
54
62
  rescue StandardError => e
55
63
  logger.error "Request error: #{e.message}"
56
64
  nil
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Agent99
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.3"
5
5
 
6
6
  def self.version = VERSION
7
7
  end
data/lib/agent99.rb CHANGED
@@ -3,6 +3,10 @@
3
3
  require 'debug_me'
4
4
  include DebugMe
5
5
 
6
+ require 'json'
7
+ require 'json_schema'
8
+ require 'securerandom'
9
+
6
10
  module Agent99; end # Establish a namespace
7
11
 
8
12
  require_relative 'agent99/base'
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agent99
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-05 00:00:00.000000000 Z
11
+ date: 2024-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ai_client
14
+ name: bunny
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bunny
28
+ name: nats-pure
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: nats-pure
42
+ name: simple_json_schema_builder
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: simple_json_schema_builder
56
+ name: sinatra
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -152,13 +152,43 @@ files:
152
152
  - LICENSE
153
153
  - README.md
154
154
  - Rakefile
155
- - docs/todo.md
155
+ - docs/README.md
156
+ - docs/advanced_features.md
157
+ - docs/agent_discovery.md
158
+ - docs/agent_lifecycle.md
159
+ - docs/agent_registry_processes.md
160
+ - docs/api_reference.md
161
+ - docs/architecture.md
162
+ - docs/configuration.md
163
+ - docs/control_actions.md
164
+ - docs/custom_agent_implementation.md
165
+ - docs/diagrams/agent_registry_processes.dot
166
+ - docs/diagrams/agent_registry_processes.png
167
+ - docs/diagrams/high_level_architecture.dot
168
+ - docs/diagrams/high_level_architecture.png
169
+ - docs/diagrams/request_flow.dot
170
+ - docs/diagrams/request_flow.png
171
+ - docs/error_handling_and_logging.md
172
+ - docs/extending_the_framework.md
173
+ - docs/message_processing.md
174
+ - docs/messaging_system.md
175
+ - docs/preformance_considerations.md
176
+ - docs/schema_definition.md
177
+ - docs/security.md
178
+ - docs/troubleshooting.md
156
179
  - examples/README.md
157
- - examples/hello_world.rb
158
- - examples/hello_world_client.rb
159
- - examples/hello_world_request.rb
180
+ - examples/agent_watcher.rb
181
+ - examples/agents/.keep
182
+ - examples/chief_agent.rb
183
+ - examples/control.rb
184
+ - examples/diagram.dot
185
+ - examples/diagram.png
186
+ - examples/example_agent.rb
187
+ - examples/kaos_spy.rb
188
+ - examples/maxwell_agent86.rb
189
+ - examples/maxwell_request.rb
160
190
  - examples/registry.rb
161
- - examples/start_agents.sh
191
+ - examples/start_rabbitmq_and_registry.sh
162
192
  - lib/agent99.rb
163
193
  - lib/agent99/.irbrc
164
194
  - lib/agent99/agent_discovery.rb
data/docs/todo.md DELETED
@@ -1,66 +0,0 @@
1
- # Documentation
2
-
3
- TODO: Lets get some more detailed documentation underway that can be linked to from the main README.md file.
4
-
5
- Here are some key areas that should be covered in comprehensive documentation files:
6
-
7
- 1. Architecture Overview:
8
- - Explain the overall structure of the AiAgent framework
9
- - Describe the roles of different components (Base, MessageClient, RegistryClient, etc.)
10
- - Illustrate how agents communicate and interact within the system
11
-
12
- 2. Agent Lifecycle:
13
- - Detail the process of creating, initializing, running, and shutting down an agent
14
- - Explain the registration and withdrawal process with the registry service
15
-
16
- 3. Message Processing:
17
- - Describe the different types of messages (request, response, control)
18
- - Explain how messages are routed and processed
19
- - Detail the schema validation process for incoming messages
20
-
21
- 4. Agent Discovery:
22
- - Explain how agents can discover other agents based on capabilities
23
- - Describe the process of querying the registry for available agents
24
-
25
- 5. Control Actions:
26
- - List and explain all available control actions (shutdown, pause, resume, etc.)
27
- - Describe how to implement custom control actions
28
-
29
- 6. Configuration:
30
- - Detail all configuration options available for agents
31
- - Explain how to use environment variables for configuration
32
-
33
- 7. Error Handling and Logging:
34
- - Describe the error handling mechanisms in place
35
- - Explain how to configure and use the logging system effectively
36
-
37
- 8. Messaging Systems:
38
- - Provide details on both AMQP and NATS messaging systems
39
- - Explain how to switch between different messaging backends
40
-
41
- 9. Custom Agent Implementation:
42
- - Provide a step-by-step guide on creating a custom agent
43
- - Explain how to define capabilities, handle requests, and send responses
44
-
45
- 10. Schema Definition:
46
- - Explain how to define and use request and response schemas
47
- - Provide examples of complex schema definitions
48
-
49
- 11. Performance Considerations:
50
- - Discuss any performance optimizations in the framework
51
- - Provide guidelines for writing efficient agents
52
-
53
- 12. Security:
54
- - Explain any security measures in place (if any)
55
- - Provide best practices for securing agent communications
56
-
57
- 13. Extending the Framework:
58
- - Describe how to add new features or modify existing functionality
59
- - Explain the plugin system (if one exists)
60
-
61
- 14. Troubleshooting:
62
- - Provide a list of common issues and their solutions
63
- - Explain how to debug agents effectively
64
-
65
- 15. API Reference:
66
- - Provide a comprehensive API reference for all public methods and classes
@@ -1,70 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # examples/hello_world_client.rb
3
-
4
- require 'json'
5
- require 'json_schema'
6
- require 'securerandom'
7
- require_relative '../lib/agent99'
8
-
9
- class HelloWorldClient < Agent99::Base
10
- def init
11
- send_request
12
- end
13
-
14
- def send_request
15
- to_uuid = discover_agent(capability: 'greeter', how_many: 1).first[:uuid]
16
-
17
- request = build_request(
18
- to_uuid:,
19
- greeting: 'Hey',
20
- name: 'MadBomber'
21
- )
22
-
23
- result = @message_client.publish(request)
24
- logger.info "Sent request: #{request.inspect}; status? #{result.inspect}"
25
- end
26
-
27
- def build_request(
28
- to_uuid:,
29
- greeting: 'Hello',
30
- name: 'World'
31
- )
32
-
33
- {
34
- header: {
35
- type: 'request',
36
- from_uuid: @id,
37
- to_uuid:,
38
- event_uuid: SecureRandom.uuid,
39
- timestamp: Agent99::Timestamp.new.to_i
40
- },
41
- greeting:,
42
- name:
43
- }
44
- end
45
-
46
-
47
- def receive_response
48
- logger.info "Received response: #{payload.inspect}"
49
- result = payload[:result]
50
-
51
- puts
52
- puts `echo "#{result}" | boxes -d info`
53
- puts
54
-
55
- exit(0)
56
- end
57
-
58
- #####################################################
59
- private
60
-
61
- def capabilities
62
- ['hello_world_client']
63
- end
64
- end
65
-
66
-
67
- # Example usage
68
- client = HelloWorldClient.new
69
- client.run
70
-
@@ -1,20 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Start the registry server
4
- echo "Starting registry server..."
5
- # Assuming the registry server is a separate process, replace with actual command
6
- # e.g., ruby registry_server.rb &
7
- # Replace 'registry_server_command' with the actual command to start your registry server
8
- # Example: ruby registry_server.rb &
9
- ./registry.rb &
10
-
11
- # Start the HelloWorld agent
12
- echo "Starting HelloWorld agent..."
13
- ./hello_world.rb &
14
-
15
- # Start the HelloWorldClient agent
16
- echo "Starting HelloWorldClient agent..."
17
- ./hello_world_client.rb &
18
-
19
- # Wait for all background processes to finish
20
- wait