agent99 0.0.3 → 0.0.5

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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/A2A_SPEC-dev.md +1829 -0
  3. data/CHANGELOG.md +38 -0
  4. data/COMMITS.md +196 -0
  5. data/DOCS.md +96 -0
  6. data/README.md +212 -84
  7. data/Rakefile +62 -0
  8. data/docs/AI/htm.md +215 -0
  9. data/docs/AI/htm.rb +141 -0
  10. data/docs/AI/htm_demo.db +0 -0
  11. data/docs/AI/notes_on_htm_implementation.md +1319 -0
  12. data/docs/AI/some_code.rb +692 -0
  13. data/docs/advanced-topics/a2a-protocol.md +13 -0
  14. data/docs/{advanced_features.md → advanced-topics/advanced-features.md} +9 -4
  15. data/docs/{control_actions.md → advanced-topics/control-actions.md} +2 -0
  16. data/docs/advanced-topics/model-context-protocol.md +4 -0
  17. data/docs/advanced-topics/multi-agent-processing.md +674 -0
  18. data/docs/agent-development/request-response-handling.md +512 -0
  19. data/docs/agent99_framework/central_registry.md +94 -0
  20. data/docs/agent99_framework/message_client.md +120 -0
  21. data/docs/agent99_framework/registry_client.md +119 -0
  22. data/docs/api-reference/agent99-base.md +463 -0
  23. data/docs/api-reference/message-clients.md +495 -0
  24. data/docs/{api_reference.md → api-reference/overview.md} +14 -4
  25. data/docs/api-reference/registry-client.md +470 -0
  26. data/docs/api-reference/schemas.md +518 -0
  27. data/docs/assets/css/custom.css +27 -0
  28. data/docs/assets/images/agent-lifecycle.svg +73 -0
  29. data/docs/assets/images/agent-registry-process.svg +86 -0
  30. data/docs/assets/images/agent-registry-processes.svg +114 -0
  31. data/docs/assets/images/agent-types-overview.svg +51 -0
  32. data/docs/assets/images/agent99-architecture.svg +85 -0
  33. data/docs/assets/images/agent99_logo.png +0 -0
  34. data/docs/assets/images/control-actions-state.svg +83 -0
  35. data/docs/assets/images/knowledge-graph.svg +77 -0
  36. data/docs/assets/images/message-processing-flow.svg +148 -0
  37. data/docs/assets/images/multi-agent-system.svg +66 -0
  38. data/docs/assets/images/proxy-pattern-sequence.svg +48 -0
  39. data/docs/assets/images/request-flow.svg +97 -0
  40. data/docs/assets/images/request-processing-lifecycle.svg +50 -0
  41. data/docs/assets/images/request-response-sequence.svg +39 -0
  42. data/docs/{agent_lifecycle.md → core-concepts/agent-lifecycle.md} +2 -0
  43. data/docs/core-concepts/agent-types.md +255 -0
  44. data/docs/{architecture.md → core-concepts/architecture.md} +5 -5
  45. data/docs/core-concepts/what-is-an-agent.md +293 -0
  46. data/docs/diagrams/message-flow-sequence.svg +198 -0
  47. data/docs/diagrams/p2p-network-topology.svg +181 -0
  48. data/docs/diagrams/smart-transport-routing.svg +165 -0
  49. data/docs/diagrams/three-layer-architecture.svg +77 -0
  50. data/docs/diagrams/transport-extension-api.svg +309 -0
  51. data/docs/diagrams/transport-extension-architecture.svg +234 -0
  52. data/docs/diagrams/transport-selection-flowchart.svg +264 -0
  53. data/docs/examples/advanced-examples.md +951 -0
  54. data/docs/examples/basic-examples.md +268 -0
  55. data/docs/{agent_discovery.md → framework-components/agent-discovery.md} +9 -5
  56. data/docs/{agent_registry_processes.md → framework-components/agent-registry.md} +9 -3
  57. data/docs/{message_processing.md → framework-components/message-processing.md} +3 -1
  58. data/docs/getting-started/basic-example.md +306 -0
  59. data/docs/getting-started/installation.md +160 -0
  60. data/docs/getting-started/overview.md +64 -0
  61. data/docs/getting-started/quick-start.md +179 -0
  62. data/docs/index.md +97 -0
  63. data/docs/operations/breaking-changes.md +26 -0
  64. data/examples/DEMO.md +148 -0
  65. data/examples/README.md +50 -0
  66. data/examples/agent_watcher.rb +5 -1
  67. data/examples/bad_agent.rb +32 -0
  68. data/examples/chief_agent.rb +17 -6
  69. data/examples/control.rb +16 -7
  70. data/examples/example_agent.rb +16 -3
  71. data/examples/maxwell_agent86.rb +15 -26
  72. data/examples/registry.rb +10 -9
  73. data/examples/run_demo.rb +433 -0
  74. data/lib/agent99/agent_discovery.rb +4 -0
  75. data/lib/agent99/agent_lifecycle.rb +34 -10
  76. data/lib/agent99/amqp_message_client.rb +2 -2
  77. data/lib/agent99/base.rb +6 -2
  78. data/lib/agent99/message_processing.rb +6 -10
  79. data/lib/agent99/registry_client.rb +15 -11
  80. data/lib/agent99/tcp_message_client.rb +183 -0
  81. data/lib/agent99/version.rb +1 -1
  82. data/lib/agent99.rb +1 -1
  83. data/mkdocs.yml +195 -0
  84. data/p2p_plan.md +533 -0
  85. data/p2p_roadmap.md +299 -0
  86. data/registry_plan.md +1818 -0
  87. metadata +93 -30
  88. data/docs/README.md +0 -57
  89. data/docs/diagrams/agent_registry_processes.dot +0 -42
  90. data/docs/diagrams/agent_registry_processes.png +0 -0
  91. data/docs/diagrams/high_level_architecture.dot +0 -26
  92. data/docs/diagrams/high_level_architecture.png +0 -0
  93. data/docs/diagrams/request_flow.dot +0 -42
  94. data/docs/diagrams/request_flow.png +0 -0
  95. /data/docs/{extending_the_framework.md → advanced-topics/extending-the-framework.md} +0 -0
  96. /data/docs/{custom_agent_implementation.md → agent-development/custom-agent-implementation.md} +0 -0
  97. /data/docs/{error_handling_and_logging.md → agent-development/error-handling-and-logging.md} +0 -0
  98. /data/docs/{schema_definition.md → agent-development/schema-definition.md} +0 -0
  99. /data/docs/{messaging_system.md → framework-components/messaging-system.md} +0 -0
  100. /data/docs/{configuration.md → operations/configuration.md} +0 -0
  101. /data/docs/{preformance_considerations.md → operations/performance-considerations.md} +0 -0
  102. /data/docs/{security.md → operations/security.md} +0 -0
  103. /data/docs/{troubleshooting.md → operations/troubleshooting.md} +0 -0
@@ -0,0 +1,255 @@
1
+ # Agent Types
2
+
3
+ Agent99 supports three fundamental agent types, each designed for different communication patterns and use cases. Understanding these types is crucial for designing effective distributed systems.
4
+
5
+ ## Overview
6
+
7
+ ![Agent Types Overview](../assets/images/agent-types-overview.svg)
8
+
9
+ ## Server Agents
10
+
11
+ Server agents **receive and respond to requests** from other agents. They're the workhorses of the Agent99 ecosystem.
12
+
13
+ ### Characteristics
14
+
15
+ - **Reactive**: Wait for incoming requests
16
+ - **Stateless**: Each request is handled independently (by default)
17
+ - **Specialized**: Usually focus on specific capabilities
18
+ - **Discoverable**: Register their capabilities for others to find
19
+
20
+ ### Example: Server Agent
21
+
22
+ ```ruby
23
+ class WeatherAgent < Agent99::Base
24
+ def info
25
+ {
26
+ name: self.class.to_s,
27
+ type: :server, # This makes it a server agent
28
+ capabilities: ['weather', 'forecast', 'temperature']
29
+ }
30
+ end
31
+
32
+ def process_request(payload)
33
+ location = payload.dig(:location)
34
+
35
+ # Simulate weather lookup
36
+ weather_data = {
37
+ location: location,
38
+ temperature: rand(15..35),
39
+ condition: ['sunny', 'cloudy', 'rainy'].sample,
40
+ timestamp: Time.now.iso8601
41
+ }
42
+
43
+ send_response(weather_data)
44
+ end
45
+ end
46
+ ```
47
+
48
+ ### When to Use Server Agents
49
+
50
+ - **Services**: Database access, calculations, data processing
51
+ - **APIs**: Wrapping external APIs or services
52
+ - **Workers**: Background job processing
53
+ - **Specialists**: Domain-specific functionality
54
+
55
+ ## Client Agents
56
+
57
+ Client agents **make requests to other agents** and handle their responses. They're the initiators of communication.
58
+
59
+ ### Characteristics
60
+
61
+ - **Proactive**: Initiate communication
62
+ - **Discovery-aware**: Find and connect to appropriate services
63
+ - **Request-driven**: Send requests and wait for responses
64
+ - **Orchestrating**: Can coordinate multiple service calls
65
+
66
+ ### Example: Client Agent
67
+
68
+ ```ruby
69
+ class WeatherClientAgent < Agent99::Base
70
+ def info
71
+ {
72
+ name: self.class.to_s,
73
+ type: :client, # This makes it a client agent
74
+ capabilities: ['weather_requester', 'data_aggregator']
75
+ }
76
+ end
77
+
78
+ def get_weather_report(locations)
79
+ # Find weather service agents
80
+ weather_agents = discover_agents(['weather'])
81
+
82
+ if weather_agents.empty?
83
+ logger.warn "No weather agents available"
84
+ return nil
85
+ end
86
+
87
+ weather_agent = weather_agents.first
88
+ reports = []
89
+
90
+ locations.each do |location|
91
+ request = { location: location }
92
+ response = send_request(weather_agent[:name], request)
93
+ reports << response if response
94
+ end
95
+
96
+ reports
97
+ end
98
+ end
99
+ ```
100
+
101
+ ### When to Use Client Agents
102
+
103
+ - **Aggregators**: Combine data from multiple sources
104
+ - **Workflows**: Multi-step business processes
105
+ - **User Interfaces**: Frontend applications
106
+ - **Schedulers**: Time-based or event-driven tasks
107
+
108
+ ## Hybrid Agents
109
+
110
+ Hybrid agents can **both send and receive requests**. They're the most flexible but also the most complex.
111
+
112
+ ### Characteristics
113
+
114
+ - **Bidirectional**: Can act as both client and server
115
+ - **Mediating**: Often serve as intermediaries or proxies
116
+ - **Stateful**: May maintain state across interactions
117
+ - **Complex**: Handle multiple communication patterns
118
+
119
+ ### Example: Hybrid Agent
120
+
121
+ ```ruby
122
+ class WeatherProxyAgent < Agent99::Base
123
+ def initialize
124
+ super
125
+ @cache = {} # Simple caching
126
+ @stats = { requests: 0, cache_hits: 0 }
127
+ end
128
+
129
+ def info
130
+ {
131
+ name: self.class.to_s,
132
+ type: :hybrid, # This makes it a hybrid agent
133
+ capabilities: ['weather_proxy', 'caching', 'analytics']
134
+ }
135
+ end
136
+
137
+ # Server behavior: respond to weather requests
138
+ def process_request(payload)
139
+ location = payload.dig(:location)
140
+ @stats[:requests] += 1
141
+
142
+ # Check cache first
143
+ if @cache[location] && fresh_enough?(@cache[location])
144
+ @stats[:cache_hits] += 1
145
+ logger.info "Cache hit for #{location}"
146
+ send_response(@cache[location][:data])
147
+ return
148
+ end
149
+
150
+ # Cache miss - get from weather service
151
+ weather_data = fetch_weather_data(location)
152
+
153
+ if weather_data
154
+ @cache[location] = {
155
+ data: weather_data,
156
+ timestamp: Time.now
157
+ }
158
+ send_response(weather_data)
159
+ else
160
+ send_error("Weather data unavailable for #{location}")
161
+ end
162
+ end
163
+
164
+ # Client behavior: request from actual weather service
165
+ private def fetch_weather_data(location)
166
+ weather_agents = discover_agents(['weather'])
167
+ return nil if weather_agents.empty?
168
+
169
+ weather_agent = weather_agents.first
170
+ request = { location: location }
171
+ send_request(weather_agent[:name], request)
172
+ end
173
+
174
+ private def fresh_enough?(cache_entry)
175
+ Time.now - cache_entry[:timestamp] < 300 # 5 minutes
176
+ end
177
+
178
+ # Additional hybrid behavior: provide statistics
179
+ def get_statistics
180
+ {
181
+ total_requests: @stats[:requests],
182
+ cache_hits: @stats[:cache_hits],
183
+ cache_hit_rate: @stats[:requests] > 0 ? @stats[:cache_hits].to_f / @stats[:requests] : 0
184
+ }
185
+ end
186
+ end
187
+ ```
188
+
189
+ ### When to Use Hybrid Agents
190
+
191
+ - **Proxies**: Caching, load balancing, protocol translation
192
+ - **Middleware**: Authentication, logging, monitoring
193
+ - **State Managers**: Session management, workflow coordination
194
+ - **Aggregators**: Collect, process, and redistribute data
195
+
196
+ ## Agent Type Comparison
197
+
198
+ | Feature | Server | Client | Hybrid |
199
+ |---------|--------|--------|---------|
200
+ | **Receives Requests** | ✅ | ❌ | ✅ |
201
+ | **Sends Requests** | ❌ | ✅ | ✅ |
202
+ | **Complexity** | Low | Medium | High |
203
+ | **Statefulness** | Usually stateless | Can be stateful | Often stateful |
204
+ | **Use Cases** | Services, APIs | UIs, Schedulers | Proxies, Middleware |
205
+
206
+ ## Communication Patterns
207
+
208
+ ### Request-Response (Server/Client)
209
+
210
+ ![Request-Response Pattern](../assets/images/request-response-sequence.svg)
211
+
212
+ ### Proxy Pattern (Hybrid)
213
+
214
+ ![Proxy Pattern](../assets/images/proxy-pattern-sequence.svg)
215
+
216
+ ## Best Practices
217
+
218
+ ### Server Agents
219
+
220
+ 1. **Keep them focused**: One capability per agent
221
+ 2. **Make them stateless**: Each request independent
222
+ 3. **Validate inputs**: Use schemas for safety
223
+ 4. **Handle errors gracefully**: Always respond, even on error
224
+
225
+ ### Client Agents
226
+
227
+ 1. **Handle service unavailability**: Graceful degradation
228
+ 2. **Use timeouts**: Don't wait forever
229
+ 3. **Implement retries**: With exponential backoff
230
+ 4. **Cache discoveries**: Don't rediscover every time
231
+
232
+ ### Hybrid Agents
233
+
234
+ 1. **Separate concerns**: Clear distinction between client/server logic
235
+ 2. **Manage state carefully**: Consider thread safety
236
+ 3. **Monitor performance**: Track both directions
237
+ 4. **Document behavior**: Complex interactions need clear docs
238
+
239
+ ## Choosing the Right Type
240
+
241
+ Ask yourself:
242
+
243
+ - **Do I need to respond to requests?** → Server or Hybrid
244
+ - **Do I need to make requests?** → Client or Hybrid
245
+ - **Do I need both?** → Hybrid
246
+ - **Is simplicity important?** → Avoid Hybrid if possible
247
+ - **Is this a leaf service?** → Probably Server
248
+ - **Is this an orchestrator?** → Probably Client
249
+ - **Is this middleware?** → Probably Hybrid
250
+
251
+ ## Next Steps
252
+
253
+ - **[Agent Lifecycle](agent-lifecycle.md)** - How agents start, run, and stop
254
+ - **[Architecture Overview](architecture.md)** - How agents fit into the bigger picture
255
+ - **[Custom Agent Implementation](../agent-development/custom-agent-implementation.md)** - Build your own agents
@@ -10,9 +10,9 @@ Agent99 is a Ruby-based framework designed for building and managing software ag
10
10
 
11
11
  ### System Components Diagram
12
12
 
13
- ![High Level Architecture](diagrams/high_level_architecture.png)
13
+ ![Agent99 Architecture](../assets/images/agent99-architecture.svg)
14
14
 
15
- The diagram above (generated from `diagrams/high_level_architecture.dot`) illustrates the key components and their interactions:
15
+ The diagram above illustrates the key components and their interactions:
16
16
 
17
17
  - **Agents**: Come in three types:
18
18
  - Client Agents: Only make requests
@@ -72,6 +72,6 @@ The framework supports three primary message types:
72
72
  ## Implementation Details
73
73
 
74
74
  For detailed implementation information, see:
75
- - [API Reference](api_reference.md) for method specifications
76
- - [Agent Lifecycle](agent_lifecycle.md) for lifecycle management
77
- - [Agent Discovery](agent_discovery.md) for discovery mechanisms
75
+ - [API Reference](../api-reference/agent99-base.md) for method specifications
76
+ - [Agent Lifecycle](agent-lifecycle.md) for lifecycle management
77
+ - [Agent Discovery](../framework-components/agent-discovery.md) for discovery mechanisms
@@ -0,0 +1,293 @@
1
+ # What is an Agent?
2
+
3
+ An agent is a self-contained piece of code designed to perform a specific function or service. Unlike general-purpose classes or modules, agents can be autonomous entities that focus on doing one thing well. They embody the Single Responsibility Principle (SRP) by design.
4
+
5
+ I will be using the Ruby programming language and the agent99 gem specifically to illustrate aspects of what I think good software agents should look like. I choose Ruby because:
6
+
7
+ - Ruby allows developers to create elegant and expressive AI applications.
8
+ - It promotes paradigm shifts, challenging the Python status quo in AI development.
9
+ - Developers who value clarity can find their niche in Ruby's design.
10
+ - Ruby's metaprogramming capabilities pave the way for creative AI solutions.
11
+ - Greater integration of Ruby-based frameworks makes them viable choices in the AI landscape.
12
+ - Ruby's object-oriented style leads to more modular and testable code.
13
+ - Ruby inspires a community that often prefers its syntax over Python's.
14
+
15
+ ## Getting Started with Agent99
16
+
17
+ The `agent99` is a Ruby gem that serves as a framework for developing and managing software agents, allowing for the execution and communication of these agents in a distributed environment. It implements a reference protocol that supports agent registration, discovery, and messaging through a centralized registry and a messaging system like AMQP or NATS. Each agent, derived from the `Agent99::Base` class, is designed to perform specific tasks as defined by its capabilities, adhering to the Single Responsibility Principle (SRP) for enhanced maintainability and testability. The framework facilitates modular agent interactions, enabling developers to build innovative applications while taking advantage of Ruby’s expressive syntax and metaprogramming features. The library emphasizes best practices in software design, including error handling and lifecycle management for robust agent operations.
18
+
19
+ To install the Agent99 gem, simply run:
20
+
21
+ ```bash
22
+ gem install agent99
23
+ ```
24
+
25
+ The [documentation](https://github.com/MadBomber/agent99/blob/main/docs/README.md) provides a comprehensive overview of the framework, but here, we will explore definitions of software agents and the Single Responsibility Principle (SRP), along with how Agent99 distinguishes itself in agent management and description.
26
+
27
+ ## What Is a Reference Implementation?
28
+
29
+ The Agent99 gem implements a protocol in Ruby that can be replicated in other programming languages. This interoperability allows software agents, given they support the Agent99 protocol, to mix and match regardless of the language they were built in.
30
+
31
+ ## Understanding Software Agents and the Single Responsibility Principle
32
+
33
+ Software agents and the Single Responsibility Principle (SRP) are crucial in contemporary software development. They decompose complex systems into manageable, autonomous components, while SRP promotes the creation of maintainable, testable, and adaptable systems. Utilizing both can boost code quality and nurture agility in development teams, particularly in AI, automation, and microservices contexts.
34
+
35
+ ## What Are Software Agents?
36
+
37
+ In simple terms, a software agent is a designated piece of code that performs a single function effectively. Within the Agent99 framework, agents are instances of subclasses derived from the **Agent99::Base** class. These instances can be running in their own separate process or groups of instances of different Agent99 instances can run within separate Threads in a single process.
38
+
39
+ Here's a simple example of an Agent99 agent class running in an independent process:
40
+
41
+ ```ruby
42
+ # File: example_agent.rb
43
+
44
+ require 'agent99'
45
+
46
+ class ExampleAgent < Agent99::Base
47
+ def info
48
+ {
49
+ name: self.class.to_s,
50
+ type: :server,
51
+ capabilities: %w[ rubber_stamp yes_man example ],
52
+ # request_schema: {}, # ExampleRequest.schema,
53
+ # response_schema: {}, # Agent99::RESPONSE.schema
54
+ # control_schema: {}, # Agent99::CONTROL.schema
55
+ # error_schema: {}, # Agent99::ERROR.schema
56
+ }
57
+ end
58
+
59
+ def receive_request
60
+ logger.info "Example agent received request: #{payload}"
61
+ send_response(status: 'success')
62
+ end
63
+ end
64
+
65
+ ExampleAgent.new.run
66
+ ```
67
+
68
+ ```base
69
+ ruby example_agent.rb
70
+ ```
71
+
72
+ Each agent subclass is responsible for specific methods that define its unique capabilities and how it handles requests. The `info` method provides a comprehensive information packet about the agent. It returns a hash containing key details that are crucial for agent registration and discovery within the system. The **:capabilities** entry in the `info` packet in an Array of Strings - synonyms - for the thing that the agent does.
73
+
74
+ For a server type agent, the only methods that are required to be defined, as in the ExampleAgent class above, are its **info** and its **receive_request** methods. Everything else from initialization, registration, message dispatching, and graceful shutdown are handled by the default methods within the **Agent99::Base** class.
75
+
76
+ More complex agents will require methods like **receive_response** and **receive_control** and potentially custom implementations of **init**, **initialize**, or **fini** may be necessary for managing state or resources.
77
+
78
+ > **RoadMap:** Currently, the Agent99 implementation defines the **capabilities** value as an `Array(String)`, with plans to enhance this functionality into descriptive unstructured text akin to defining tools for functional callbacks in LLM processing using semantic search.
79
+
80
+ ## The Single Responsibility Principle (SRP)
81
+
82
+ The Single Responsibility Principle, part of the SOLID principles of object-oriented design, asserts that a class or module should have only one reason to change. This means it should fulfill a single job or responsibility effectively.
83
+
84
+ ### Why SRP Matters
85
+
86
+ 1. **Maintainability:** Code is easier to read and modify, leading to more maintainable systems.
87
+ 2. **Testability:** Isolated responsibilities facilitate independent unit testing.
88
+ 3. **Flexibility:** Minimal impact on other parts of the system when modifying one responsibility, reducing the risk of bugs.
89
+
90
+ ### Applying SRP in Software Development
91
+
92
+ Implementing SRP involves:
93
+
94
+ - **Identifying Responsibilities:** Break down functionalities into specific tasks; each class or module should focus on a particular duty.
95
+ - **Modular Design:** Create a loosely coupled system to enhance separation of concerns.
96
+ - **Utilizing Design Patterns:** Harness design patterns like Observer, Strategy, and Factory to ensure clear interfaces and responsibilities.
97
+
98
+ ## Alignment of Agents and SRP
99
+
100
+ The notion of software agents naturally corresponds with the SRP. Each agent can be a distinct class or module that encapsulates a specific functionality. For instance:
101
+
102
+ - An order processing agent focuses solely on order management.
103
+ - A notification agent manages the sending of alerts or messages without getting involved in order processing logic.
104
+
105
+ Designing agents with SRP in mind fosters modularity and reusability, allowing changes to one agent without affecting others and supporting more robust architecture.
106
+
107
+ ## Agent99 as a Reference Framework
108
+
109
+ In its current iteration, the Agent99 Framework does not differ conceptually from other microservice architecture implementations. It enables centralized registration where agents list their capabilities for other agents or applications to discover. Agent communications occur via a distributed messaging system. The agent99 Ruby gem currently uses AMQP (via the Bunny gem and the RabbitMQ broker) and the NATS-server.
110
+
111
+ ### Agent Structure
112
+
113
+ Agents in Agent99 inherit from **Agent99::Base**, which offers core functionality through crucial modules:
114
+
115
+ - **HeaderManagement:** Handles message header processing.
116
+ - **AgentDiscovery:** Facilitates capability advertisement and discovery.
117
+ - **ControlActions:** Manages control messages.
118
+ - **AgentLifecycle:** Oversees agent startup and shutdown functionality.
119
+ - **MessageProcessing:** Manages message dispatch and handling.
120
+
121
+ Every agent must define its type (server, client, or hybrid) and capabilities. The framework supports three message types: requests, responses, and control messages.
122
+
123
+ ```ruby
124
+ class Agent99::Base
125
+ include Agent99::HeaderManagement
126
+ include Agent99::AgentDiscovery
127
+ include Agent99::ControlActions
128
+ include Agent99::AgentLifecycle
129
+ include Agent99::MessageProcessing
130
+
131
+ MESSAGE_TYPES = %w[request response control]
132
+
133
+ attr_reader :id, :capabilities, :name, :payload, :header, :logger, :queue
134
+ attr_accessor :registry_client, :message_client
135
+
136
+ ###################################################
137
+ private
138
+
139
+ def handle_error(message, error)
140
+ logger.error "#{message}: #{error.message}"
141
+ logger.debug error.backtrace.join("\n")
142
+ end
143
+
144
+ # the final rescue block
145
+ rescue StandardError => e
146
+ handle_error("Unhandled error in Agent99::Base", e)
147
+ exit(2)
148
+ end
149
+ ```
150
+
151
+ ### Centralized Registry
152
+
153
+ The registry service tracks agent availability and capabilities through a **RegistryClient**. A web-based application serves as the central registry, with a Sinatra implementation found in the `examples/registry.rb` file. Its primary function is to maintain a data store of registered agents.
154
+
155
+ It supports three core operations:
156
+
157
+ #### 1. Register
158
+
159
+ ![Central Registry Process](../assets/images/agent-registry-process.svg)
160
+
161
+ Agents register by providing their information (e.g., name and capabilities) to the registry service. Here's how registration works in practice:
162
+
163
+ ```ruby
164
+ class WeatherAgent < Agent99::Base
165
+ TYPE = :server
166
+
167
+ def capabilities
168
+ %w[get_temperature get_forecast]
169
+ end
170
+
171
+ def receive_request(message)
172
+ case message.payload[:action]
173
+ when 'get_temperature'
174
+ send_response({ temperature: 72, unit: 'F' })
175
+ when 'get_forecast'
176
+ send_response({ forecast: 'Sunny with a chance of rain' })
177
+ end
178
+ end
179
+ end
180
+
181
+ # Start the agent
182
+ WeatherAgent.new.run
183
+ ```
184
+
185
+ Upon successful registration, agents receive a universally unique ID (UUID) that identifies them in the system. The registration process is handled automatically by the Agent99 framework when you call `run`.
186
+
187
+ #### 2. Discover
188
+
189
+ Agents can query the registry to discover capabilities. The discovery operation retrieves information about agents offering specific capabilities via an HTTP GET request.
190
+
191
+ #### 3. Withdraw
192
+
193
+ When an agent needs to exit the system, it withdraws its registration using its UUID, removing it from the available agents list through an HTTP DELETE request.
194
+
195
+ ### Messaging Network
196
+
197
+ The Ruby implementation of Agent99 currently focuses on AMQP messaging systems. Messages are formatted as JSON structures that adhere to defined schemas, allowing the **MessageClient** to validate messages effortlessly.
198
+
199
+ Messages are validated against defined schemas, and invalid messages return to the sender without invoking agent-specific processes.
200
+
201
+ Message types within the framework include:
202
+
203
+ #### Request Messages
204
+
205
+ These messages are validated against an agent-defined schema and include:
206
+
207
+ - A header with routing information.
208
+ - Agent-specific elements with their types and examples.
209
+
210
+ Requests are handled by the `receive_request` handler in target agents.
211
+
212
+ Here's an example of a request message schema using the [SimpleJsonSchemaBuilder gem](https://github.com/mooktakim/simple_json_schema_builder)
213
+
214
+ ```ruby
215
+ # examples/maxwell_request.rb
216
+
217
+ require 'agent99/header_schema'
218
+
219
+ class MaxwellRequest < SimpleJsonSchemaBuilder::Base
220
+ object do
221
+ object :header, schema: Agent99::HeaderSchema
222
+
223
+ string :greeting, required: false, examples: ["Hello"]
224
+ string :name, required: true, examples: ["World"]
225
+ end
226
+ end
227
+ ```
228
+
229
+ This schema defines a `MaxwellRequest` with a header (using the `Agent99::HeaderSchema`), an optional greeting, and a required name. A valid JSON message conforming to this schema might look like:
230
+
231
+ ```json
232
+ {
233
+ "header": {
234
+ "from_uuid": "123e4567-e89b-12d3-a456-426614174000",
235
+ "to_uuid": "987e6543-e21b-12d3-a456-426614174000",
236
+ "message_id": "msg-001",
237
+ "correlation_id": "corr-001",
238
+ "timestamp": "2023-04-01T12:00:00Z"
239
+ },
240
+ "greeting": "Hello",
241
+ "name": "Agent99"
242
+ }
243
+ ```
244
+
245
+ Using such schemas ensures that messages are well-structured and contain all necessary information before being processed by agents.
246
+
247
+ Here is how the **MaxwellAgent** associates itself with its specific request schema:
248
+
249
+ ```ruby
250
+ # examples/maxwell_agent86.rb
251
+
252
+ require 'agent99'
253
+ require_relative 'maxwell_request'
254
+
255
+ class MaxwellAgent86 < Agent99::Base
256
+ def info
257
+ {
258
+ # ...
259
+ request_schema: MaxwellRequest.schema,
260
+ # ...
261
+ }
262
+ end
263
+ ```
264
+
265
+ When an agent subclass defines a **:request_schema** in its `info`, the message processing of the **Agent99::Base** validates all incoming requests against the schema. If there are errors, those errors are returned to the sender without presenting the request message to the agent's custom **receive_request** method.
266
+
267
+ #### Response Messages
268
+
269
+ Responses are routed back to the requesting agent and include:
270
+
271
+ - The original message header in reverse.
272
+ - The response payload.
273
+ - Status information.
274
+
275
+ Responses are processed by the `receive_response` method.
276
+
277
+ #### Control Messages
278
+
279
+ Control messages manage agent lifecycles and configurations and include commands such as:
280
+
281
+ - **shutdown:** Stop the agent.
282
+ - **pause/resume:** Temporarily suspend or resume operations.
283
+ - **update_config:** Modify agent configurations.
284
+ - **status:** Query agent state.
285
+ - **response:** Handle control operation results.
286
+
287
+ Messages are queued with a 60-second TTL (Time To Live) to prevent buildup from inactive agents.
288
+
289
+ ## Additional Resources
290
+
291
+ For further exploration, check out the documentation of the current Ruby implementation at [GitHub](https://github.com/MadBomber/agent99).
292
+
293
+ Contributions to this initial Ruby reference implementation are welcome! It would be exciting to see additional language implementations.