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,268 @@
1
+ # Basic Examples
2
+
3
+ This section contains basic examples to help you get started with Agent99.
4
+
5
+ ## Simple Greeter Agent
6
+
7
+ Here's a basic server agent that responds to greeting requests:
8
+
9
+ ```ruby
10
+ require 'agent99'
11
+ require 'simple_json_schema_builder'
12
+
13
+ # Define the request schema
14
+ class GreeterRequest < SimpleJsonSchemaBuilder::Base
15
+ object do
16
+ object :header, schema: Agent99::HeaderSchema
17
+ string :name, required: true, examples: ["World"]
18
+ end
19
+ end
20
+
21
+ # Create the agent
22
+ class GreeterAgent < Agent99::Base
23
+ def info
24
+ {
25
+ name: self.class.to_s,
26
+ type: :server,
27
+ capabilities: ['greeter', 'hello_world'],
28
+ request_schema: GreeterRequest.schema
29
+ }
30
+ end
31
+
32
+ def process_request(payload)
33
+ name = payload.dig(:name) || "World"
34
+ response = { result: "Hello, #{name}!" }
35
+ send_response(response)
36
+ end
37
+ end
38
+
39
+ # Run the agent
40
+ if __FILE__ == $0
41
+ agent = GreeterAgent.new
42
+ puts "Starting Greeter Agent..."
43
+ agent.run
44
+ end
45
+ ```
46
+
47
+ ## Echo Agent
48
+
49
+ An agent that echoes back whatever message it receives:
50
+
51
+ ```ruby
52
+ require 'agent99'
53
+
54
+ class EchoAgent < Agent99::Base
55
+ def info
56
+ {
57
+ name: self.class.to_s,
58
+ type: :server,
59
+ capabilities: ['echo', 'mirror']
60
+ }
61
+ end
62
+
63
+ def process_request(payload)
64
+ logger.info "Echo agent received: #{payload}"
65
+ send_response(message: "You said: #{payload}")
66
+ end
67
+ end
68
+
69
+ # Run the agent
70
+ if __FILE__ == $0
71
+ agent = EchoAgent.new
72
+ puts "Starting Echo Agent..."
73
+ agent.run
74
+ end
75
+ ```
76
+
77
+ ## Calculator Agent
78
+
79
+ A more complex agent that performs basic arithmetic operations:
80
+
81
+ ```ruby
82
+ require 'agent99'
83
+ require 'simple_json_schema_builder'
84
+
85
+ class CalculatorRequest < SimpleJsonSchemaBuilder::Base
86
+ object do
87
+ object :header, schema: Agent99::HeaderSchema
88
+ string :operation, enum: %w[add subtract multiply divide], required: true
89
+ number :a, required: true
90
+ number :b, required: true
91
+ end
92
+ end
93
+
94
+ class CalculatorAgent < Agent99::Base
95
+ def info
96
+ {
97
+ name: self.class.to_s,
98
+ type: :server,
99
+ capabilities: ['calculator', 'math', 'arithmetic'],
100
+ request_schema: CalculatorRequest.schema
101
+ }
102
+ end
103
+
104
+ def process_request(payload)
105
+ operation = payload.dig(:operation)
106
+ a = payload.dig(:a).to_f
107
+ b = payload.dig(:b).to_f
108
+
109
+ result = case operation
110
+ when 'add'
111
+ a + b
112
+ when 'subtract'
113
+ a - b
114
+ when 'multiply'
115
+ a * b
116
+ when 'divide'
117
+ return send_error("Division by zero") if b == 0
118
+ a / b
119
+ else
120
+ return send_error("Unknown operation: #{operation}")
121
+ end
122
+
123
+ send_response(result: result, operation: operation, inputs: { a: a, b: b })
124
+ end
125
+ end
126
+
127
+ # Run the agent
128
+ if __FILE__ == $0
129
+ agent = CalculatorAgent.new
130
+ puts "Starting Calculator Agent..."
131
+ agent.run
132
+ end
133
+ ```
134
+
135
+ ## Client Agent Example
136
+
137
+ An agent that makes requests to other agents:
138
+
139
+ ```ruby
140
+ require 'agent99'
141
+
142
+ class ClientAgent < Agent99::Base
143
+ def info
144
+ {
145
+ name: self.class.to_s,
146
+ type: :client,
147
+ capabilities: ['client', 'requester']
148
+ }
149
+ end
150
+
151
+ def start
152
+ # Find available agents
153
+ agents = discover_agents(['greeter'])
154
+
155
+ if agents.any?
156
+ greeter = agents.first
157
+ logger.info "Found greeter agent: #{greeter[:name]}"
158
+
159
+ # Send a request
160
+ request = {
161
+ name: "Agent99 Client"
162
+ }
163
+
164
+ response = send_request(greeter[:name], request)
165
+ logger.info "Received response: #{response}"
166
+ else
167
+ logger.warn "No greeter agents found"
168
+ end
169
+ end
170
+ end
171
+
172
+ # Run the client
173
+ if __FILE__ == $0
174
+ client = ClientAgent.new
175
+ puts "Starting Client Agent..."
176
+
177
+ # Run once and exit
178
+ client.start
179
+ end
180
+ ```
181
+
182
+ ## Hybrid Agent Example
183
+
184
+ An agent that can both serve requests and make requests to other agents:
185
+
186
+ ```ruby
187
+ require 'agent99'
188
+
189
+ class HybridAgent < Agent99::Base
190
+ def info
191
+ {
192
+ name: self.class.to_s,
193
+ type: :hybrid,
194
+ capabilities: ['proxy', 'forwarder']
195
+ }
196
+ end
197
+
198
+ def process_request(payload)
199
+ # This agent forwards requests to other agents
200
+ target_capability = payload.dig(:forward_to)
201
+ message = payload.dig(:message)
202
+
203
+ if target_capability && message
204
+ # Find agents with the target capability
205
+ agents = discover_agents([target_capability])
206
+
207
+ if agents.any?
208
+ target_agent = agents.first
209
+
210
+ # Forward the message
211
+ response = send_request(target_agent[:name], { name: message })
212
+ send_response(forwarded_response: response, target_agent: target_agent[:name])
213
+ else
214
+ send_error("No agents found with capability: #{target_capability}")
215
+ end
216
+ else
217
+ send_error("Missing 'forward_to' or 'message' in request")
218
+ end
219
+ end
220
+ end
221
+
222
+ # Run the agent
223
+ if __FILE__ == $0
224
+ agent = HybridAgent.new
225
+ puts "Starting Hybrid Agent..."
226
+ agent.run
227
+ end
228
+ ```
229
+
230
+ ## Running the Examples
231
+
232
+ 1. **Start the Registry**:
233
+ ```bash
234
+ ruby examples/registry.rb
235
+ ```
236
+
237
+ 2. **Start a Message Broker** (NATS or RabbitMQ):
238
+ ```bash
239
+ nats-server
240
+ # OR
241
+ rabbitmq-server
242
+ ```
243
+
244
+ 3. **Run the Agents**:
245
+ ```bash
246
+ # In separate terminals
247
+ ruby greeter_agent.rb
248
+ ruby calculator_agent.rb
249
+ ruby client_agent.rb
250
+ ```
251
+
252
+ ## Testing Agent Communication
253
+
254
+ You can test agent communication using the client example or by sending HTTP requests to the registry:
255
+
256
+ ```bash
257
+ # List all registered agents
258
+ curl http://localhost:4567/agents
259
+
260
+ # Find agents by capability
261
+ curl http://localhost:4567/agents/discover/greeter
262
+ ```
263
+
264
+ ## Next Steps
265
+
266
+ - [Advanced Examples](advanced-examples.md) - More complex agent patterns
267
+ - [Schema Definition](../agent-development/schema-definition.md) - Learn about request/response schemas
268
+ - [Message Processing](../framework-components/message-processing.md) - Understand message handling
@@ -12,17 +12,21 @@ The agent discovery process involves the following steps:
12
12
  2. **Discovery**: When an agent needs to discover other agents, it queries the registry for agents with specific capabilities.
13
13
  3. **Response**: The registry responds with a list of available agents, allowing them to interact based on their capabilities.
14
14
 
15
- ### Declaring Capabilities
15
+ ### Declaring Capabilities in the Info Method
16
16
 
17
- Each agent must implement the `capabilities` method to declare its capabilities as an array of strings:
17
+ Each agent must implement the `info` method to declare its capabilities as an array of strings:
18
18
 
19
19
  ```ruby
20
- def capabilities
21
- ['process_image', 'face_detection']
20
+ def info
21
+ {
22
+ # ...
23
+ capabilities: ['process_image', 'face_detection'],
24
+ # ...
25
+ }
22
26
  end
23
27
  ```
24
28
 
25
- **Note**: The discovery mechanism is based on an exact match (case insensitive) between the requested capability and the entries in the agent's capabilities array. For example, if an agent declares its capabilities as mentioned above, a discovery request for `'FACE_DETECTION'` will successfully match.
29
+ **Note**: The discovery mechanism is based on an exact match (case insensitive) between the requested capability and the entries in the agent's capabilities array in its information packet. For example, if an agent declares its capabilities as mentioned above, a discovery request for `'FACE_DETECTION'` will successfully match.
26
30
 
27
31
  ### Discovery API
28
32
 
@@ -38,8 +38,14 @@ end
38
38
  # Define the new Agent ....
39
39
 
40
40
  class MyAgent < Agent99::Base
41
- REQUEST_SCHEMA = MyAgentRequest.schema
42
- def capabilities = %w[ greeter hello_world ]
41
+ def info
42
+ {
43
+ # ...
44
+ request_schema: MyAgentRequest.schema
45
+ capabilities: %w[ greeter hello_world ],
46
+ # ...
47
+ }
48
+ end
43
49
  end
44
50
 
45
51
  # You may create multiple instances of the agent if needed
@@ -60,7 +66,7 @@ my_agent.id
60
66
 
61
67
  The image below shows how the `Agent99::Base` class uses dependency injection in its constructor method to bring in an instance of the `RegristryClient` class to provide an interface to the centralized regristery service.
62
68
 
63
- ![Agent Register, Discover and Withdraw Processes](diagrams/agent_registry_processes.png)
69
+ ![Agent Register, Discover and Withdraw Processes](../assets/images/agent-registry-processes.svg)
64
70
 
65
71
  The above image also show the other services provided via the RegistryClient class.
66
72
 
@@ -31,6 +31,8 @@ and validation rules.
31
31
 
32
32
  ### Message Processing Flow
33
33
 
34
+ ![Message Processing Flow](../assets/images/message-processing-flow.svg)
35
+
34
36
  #### Request Processing
35
37
  1. Message arrives and is validated against schema
36
38
  2. If validation passes:
@@ -42,7 +44,7 @@ and validation rules.
42
44
  - Error is logged
43
45
  - Request is not processed further
44
46
 
45
- ![Request Message Processing Flow](diagrams/request_flow.png)
47
+ ![Request Message Processing Flow](../assets/images/request-flow.svg)
46
48
 
47
49
  #### Response Processing
48
50
  1. Response message is received
@@ -0,0 +1,306 @@
1
+ # Basic Example: Building a Calculator Service
2
+
3
+ This detailed example walks you through creating a complete calculator service using Agent99, demonstrating key concepts like schema validation, error handling, and agent discovery.
4
+
5
+ ## What We'll Build
6
+
7
+ A distributed calculator system with:
8
+ - **Calculator Agent**: Performs arithmetic operations
9
+ - **Client Agent**: Sends calculation requests
10
+ - **Request/Response Schemas**: Validates input and output
11
+ - **Error Handling**: Graceful error management
12
+
13
+ ## Step 1: Define the Request Schema
14
+
15
+ Create `calculator_schemas.rb`:
16
+
17
+ ```ruby
18
+ require 'simple_json_schema_builder'
19
+
20
+ # Request schema for calculator operations
21
+ class CalculatorRequest < SimpleJsonSchemaBuilder::Base
22
+ object do
23
+ object :header, schema: Agent99::HeaderSchema
24
+ string :operation, enum: %w[add subtract multiply divide], required: true,
25
+ description: "The arithmetic operation to perform"
26
+ number :a, required: true, description: "First operand"
27
+ number :b, required: true, description: "Second operand"
28
+ end
29
+ end
30
+
31
+ # Response schema for calculator results
32
+ class CalculatorResponse < SimpleJsonSchemaBuilder::Base
33
+ object do
34
+ object :header, schema: Agent99::HeaderSchema
35
+ number :result, required: true, description: "The calculation result"
36
+ string :operation, required: true, description: "The operation performed"
37
+ object :operands do
38
+ number :a, required: true
39
+ number :b, required: true
40
+ end
41
+ string :timestamp, required: true, description: "When the calculation was performed"
42
+ end
43
+ end
44
+ ```
45
+
46
+ ## Step 2: Create the Calculator Agent
47
+
48
+ Create `calculator_agent.rb`:
49
+
50
+ ```ruby
51
+ require 'agent99'
52
+ require_relative 'calculator_schemas'
53
+
54
+ class CalculatorAgent < Agent99::Base
55
+ def info
56
+ {
57
+ name: self.class.to_s,
58
+ type: :server,
59
+ capabilities: ['calculator', 'math', 'arithmetic'],
60
+ description: 'Performs basic arithmetic operations',
61
+ request_schema: CalculatorRequest.schema,
62
+ response_schema: CalculatorResponse.schema
63
+ }
64
+ end
65
+
66
+ def process_request(payload)
67
+ logger.info "Received calculation request: #{payload}"
68
+
69
+ # Extract and validate inputs
70
+ operation = payload.dig(:operation)
71
+ a = payload.dig(:a).to_f
72
+ b = payload.dig(:b).to_f
73
+
74
+ # Perform calculation
75
+ result = perform_calculation(operation, a, b)
76
+
77
+ if result.is_a?(Hash) && result[:error]
78
+ # Send error response
79
+ send_error(result[:error], result[:code] || 'CALCULATION_ERROR')
80
+ else
81
+ # Send successful response
82
+ response = {
83
+ result: result,
84
+ operation: operation,
85
+ operands: { a: a, b: b },
86
+ timestamp: Time.now.iso8601
87
+ }
88
+
89
+ send_response(response)
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def perform_calculation(operation, a, b)
96
+ case operation
97
+ when 'add'
98
+ a + b
99
+ when 'subtract'
100
+ a - b
101
+ when 'multiply'
102
+ a * b
103
+ when 'divide'
104
+ return { error: "Division by zero is not allowed", code: 'DIVISION_BY_ZERO' } if b == 0
105
+ a / b
106
+ else
107
+ { error: "Unknown operation: #{operation}", code: 'INVALID_OPERATION' }
108
+ end
109
+ end
110
+ end
111
+
112
+ # Run the agent if this file is executed directly
113
+ if __FILE__ == $0
114
+ puts "🧮 Starting Calculator Agent..."
115
+ agent = CalculatorAgent.new
116
+
117
+ # Handle graceful shutdown
118
+ trap('INT') do
119
+ puts "\n👋 Shutting down Calculator Agent..."
120
+ agent.shutdown
121
+ exit
122
+ end
123
+
124
+ agent.run
125
+ end
126
+ ```
127
+
128
+ ## Step 3: Create a Client Agent
129
+
130
+ Create `calculator_client.rb`:
131
+
132
+ ```ruby
133
+ require 'agent99'
134
+
135
+ class CalculatorClient < Agent99::Base
136
+ def info
137
+ {
138
+ name: self.class.to_s,
139
+ type: :client,
140
+ capabilities: ['calculator_client', 'testing']
141
+ }
142
+ end
143
+
144
+ def perform_calculations
145
+ # Find calculator agents
146
+ calculators = discover_agents(['calculator'])
147
+
148
+ if calculators.empty?
149
+ puts "❌ No calculator agents found!"
150
+ return
151
+ end
152
+
153
+ calculator = calculators.first
154
+ puts "🎯 Found calculator: #{calculator[:name]}"
155
+
156
+ # Test calculations
157
+ test_cases = [
158
+ { operation: 'add', a: 10, b: 5, expected: 15 },
159
+ { operation: 'subtract', a: 10, b: 3, expected: 7 },
160
+ { operation: 'multiply', a: 4, b: 7, expected: 28 },
161
+ { operation: 'divide', a: 20, b: 4, expected: 5 },
162
+ { operation: 'divide', a: 10, b: 0, expected: 'ERROR' } # This should error
163
+ ]
164
+
165
+ test_cases.each_with_index do |test_case, index|
166
+ puts "\n📋 Test #{index + 1}: #{test_case[:a]} #{test_case[:operation]} #{test_case[:b]}"
167
+
168
+ begin
169
+ response = send_request(calculator[:name], test_case.reject { |k, _| k == :expected })
170
+
171
+ if response[:error]
172
+ puts "⚠️ Error: #{response[:error]} (#{response[:code]})"
173
+ puts "✅ Expected error!" if test_case[:expected] == 'ERROR'
174
+ else
175
+ result = response[:result]
176
+ puts "📊 Result: #{result}"
177
+
178
+ if test_case[:expected] != 'ERROR'
179
+ if (result - test_case[:expected]).abs < 0.001 # Handle floating point comparison
180
+ puts "✅ Test passed!"
181
+ else
182
+ puts "❌ Test failed! Expected #{test_case[:expected]}, got #{result}"
183
+ end
184
+ end
185
+ end
186
+ rescue => e
187
+ puts "💥 Request failed: #{e.message}"
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ # Run the client if this file is executed directly
194
+ if __FILE__ == $0
195
+ puts "📱 Starting Calculator Client..."
196
+ client = CalculatorClient.new
197
+ client.perform_calculations
198
+ end
199
+ ```
200
+
201
+ ## Step 4: Run the Complete Example
202
+
203
+ ### Terminal 1: Start the Registry
204
+ ```bash
205
+ # From the agent99 repository
206
+ ruby examples/registry.rb
207
+ ```
208
+
209
+ ### Terminal 2: Start NATS (or RabbitMQ)
210
+ ```bash
211
+ nats-server
212
+ ```
213
+
214
+ ### Terminal 3: Start the Calculator Agent
215
+ ```bash
216
+ ruby calculator_agent.rb
217
+ ```
218
+
219
+ Expected output:
220
+ ```
221
+ 🧮 Starting Calculator Agent...
222
+ INFO -- Agent CalculatorAgent registered successfully
223
+ INFO -- Agent listening for messages...
224
+ ```
225
+
226
+ ### Terminal 4: Run the Client
227
+ ```bash
228
+ ruby calculator_client.rb
229
+ ```
230
+
231
+ Expected output:
232
+ ```
233
+ 📱 Starting Calculator Client...
234
+ 🎯 Found calculator: CalculatorAgent
235
+
236
+ 📋 Test 1: 10 add 5
237
+ 📊 Result: 15.0
238
+ ✅ Test passed!
239
+
240
+ 📋 Test 2: 10 subtract 3
241
+ 📊 Result: 7.0
242
+ ✅ Test passed!
243
+
244
+ 📋 Test 3: 4 multiply 7
245
+ 📊 Result: 28.0
246
+ ✅ Test passed!
247
+
248
+ 📋 Test 4: 20 divide 4
249
+ 📊 Result: 5.0
250
+ ✅ Test passed!
251
+
252
+ 📋 Test 5: 10 divide 0
253
+ ⚠️ Error: Division by zero is not allowed (DIVISION_BY_ZERO)
254
+ ✅ Expected error!
255
+ ```
256
+
257
+ ## Step 5: Explore the Registry
258
+
259
+ While everything is running, visit http://localhost:4567/agents in your browser to see registered agents, or use curl:
260
+
261
+ ```bash
262
+ # List all agents
263
+ curl http://localhost:4567/agents | jq
264
+
265
+ # Find calculator agents
266
+ curl http://localhost:4567/agents/discover/calculator | jq
267
+ ```
268
+
269
+ ## Key Concepts Demonstrated
270
+
271
+ ### 🏗️ **Agent Architecture**
272
+ - **Server Agent**: Waits for and processes requests
273
+ - **Client Agent**: Discovers and communicates with other agents
274
+ - **Registry**: Central discovery service
275
+
276
+ ### 📝 **Schema Validation**
277
+ - **Request Schema**: Validates incoming requests
278
+ - **Response Schema**: Defines response structure
279
+ - **Type Safety**: Ensures data integrity
280
+
281
+ ### 🛡️ **Error Handling**
282
+ - **Validation Errors**: Invalid input handling
283
+ - **Business Logic Errors**: Division by zero, invalid operations
284
+ - **Network Errors**: Communication failures
285
+
286
+ ### 🔍 **Agent Discovery**
287
+ - **Capability-based**: Find agents by what they can do
288
+ - **Dynamic**: Agents can join and leave at runtime
289
+ - **Fault-tolerant**: Graceful handling of missing agents
290
+
291
+ ## What's Next?
292
+
293
+ - **[Core Concepts](../core-concepts/what-is-an-agent.md)** - Deep dive into agent theory
294
+ - **[Schema Definition](../agent-development/schema-definition.md)** - Advanced schema patterns
295
+ - **[Advanced Examples](../examples/advanced-examples.md)** - Complex multi-agent scenarios
296
+ - **[Error Handling](../agent-development/error-handling-and-logging.md)** - Comprehensive error strategies
297
+
298
+ ## Exercises
299
+
300
+ Try extending this example:
301
+
302
+ 1. **Add more operations**: power, square root, factorial
303
+ 2. **Add validation**: check for reasonable input ranges
304
+ 3. **Add persistence**: log all calculations to a file
305
+ 4. **Add monitoring**: track success/failure rates
306
+ 5. **Add authentication**: require API keys for requests