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,495 @@
1
+ # Message Clients API
2
+
3
+ Agent99 supports multiple message broker clients for different messaging protocols. This document covers the APIs and configuration for each supported client type.
4
+
5
+ ## Overview
6
+
7
+ Agent99 currently supports three message client types:
8
+
9
+ - **NATS** - High-performance, cloud-native messaging (recommended)
10
+ - **AMQP** - Advanced Message Queuing Protocol via RabbitMQ
11
+ - **TCP** - Simple TCP-based messaging for testing
12
+
13
+ ## Client Selection
14
+
15
+ The message client is automatically selected based on configuration:
16
+
17
+ ```ruby
18
+ # Environment variable
19
+ ENV['AGENT99_MESSAGE_CLIENT'] = 'nats' # or 'amqp', 'tcp'
20
+
21
+ # Or via agent initialization
22
+ agent = MyAgent.new(message_client: 'nats')
23
+ ```
24
+
25
+ ## NATS Client
26
+
27
+ ### Configuration
28
+
29
+ ```ruby
30
+ # Environment variables
31
+ ENV['NATS_URL'] = 'nats://localhost:4222'
32
+ ENV['NATS_USERNAME'] = 'agent99' # optional
33
+ ENV['NATS_PASSWORD'] = 'secret' # optional
34
+
35
+ # Or programmatically
36
+ nats_config = {
37
+ servers: ['nats://localhost:4222'],
38
+ username: 'agent99',
39
+ password: 'secret',
40
+ timeout: 30,
41
+ reconnect_attempts: 10
42
+ }
43
+
44
+ client = Agent99::MessageClients::NatsClient.new(nats_config)
45
+ ```
46
+
47
+ ### Connection Options
48
+
49
+ | Option | Type | Default | Description |
50
+ |--------|------|---------|-------------|
51
+ | `servers` | Array | `['nats://localhost:4222']` | NATS server URLs |
52
+ | `username` | String | `nil` | Authentication username |
53
+ | `password` | String | `nil` | Authentication password |
54
+ | `timeout` | Integer | 30 | Connection timeout (seconds) |
55
+ | `reconnect_attempts` | Integer | 10 | Reconnection attempts |
56
+ | `max_reconnect_attempts` | Integer | -1 | Max reconnection attempts (-1 = unlimited) |
57
+
58
+ ### Usage Example
59
+
60
+ ```ruby
61
+ class NatsAgent < Agent99::Base
62
+ def initialize
63
+ super(message_client: 'nats')
64
+ end
65
+
66
+ def info
67
+ {
68
+ name: self.class.to_s,
69
+ type: :server,
70
+ capabilities: ['nats_example']
71
+ }
72
+ end
73
+
74
+ def process_request(payload)
75
+ # NATS-specific features can be accessed via client
76
+ subject = current_message_subject
77
+ reply_to = current_reply_subject
78
+
79
+ logger.info "Received on subject: #{subject}"
80
+
81
+ send_response(
82
+ message: "Processed via NATS",
83
+ subject: subject,
84
+ timestamp: Time.now.iso8601
85
+ )
86
+ end
87
+ end
88
+ ```
89
+
90
+ ## AMQP Client (RabbitMQ)
91
+
92
+ ### Configuration
93
+
94
+ ```ruby
95
+ # Environment variables
96
+ ENV['RABBITMQ_URL'] = 'amqp://localhost:5672'
97
+ ENV['RABBITMQ_USERNAME'] = 'guest' # optional
98
+ ENV['RABBITMQ_PASSWORD'] = 'guest' # optional
99
+
100
+ # Or programmatically
101
+ amqp_config = {
102
+ url: 'amqp://localhost:5672',
103
+ username: 'agent99',
104
+ password: 'secret',
105
+ vhost: '/',
106
+ timeout: 30,
107
+ heartbeat: 30
108
+ }
109
+
110
+ client = Agent99::MessageClients::AmqpClient.new(amqp_config)
111
+ ```
112
+
113
+ ### Connection Options
114
+
115
+ | Option | Type | Default | Description |
116
+ |--------|------|---------|-------------|
117
+ | `url` | String | `amqp://localhost:5672` | RabbitMQ connection URL |
118
+ | `username` | String | `guest` | Authentication username |
119
+ | `password` | String | `guest` | Authentication password |
120
+ | `vhost` | String | `/` | Virtual host |
121
+ | `timeout` | Integer | 30 | Connection timeout (seconds) |
122
+ | `heartbeat` | Integer | 30 | Heartbeat interval (seconds) |
123
+ | `exchange` | String | `agent99` | Default exchange name |
124
+ | `exchange_type` | String | `topic` | Exchange type |
125
+
126
+ ### Exchange and Routing
127
+
128
+ ```ruby
129
+ class AmqpAgent < Agent99::Base
130
+ def initialize
131
+ super(
132
+ message_client: 'amqp',
133
+ exchange: 'agent99.services',
134
+ routing_key: 'services.calculator'
135
+ )
136
+ end
137
+
138
+ def process_request(payload)
139
+ # AMQP-specific features
140
+ routing_key = current_routing_key
141
+ exchange = current_exchange
142
+
143
+ logger.info "Message from: #{routing_key} on #{exchange}"
144
+
145
+ # Can publish to specific routing keys
146
+ publish_to_routing_key('notifications.processed', {
147
+ agent: info[:name],
148
+ processed_at: Time.now.iso8601
149
+ })
150
+
151
+ send_response(
152
+ message: "Processed via AMQP",
153
+ routing_key: routing_key
154
+ )
155
+ end
156
+ end
157
+ ```
158
+
159
+ ## TCP Client
160
+
161
+ ### Configuration
162
+
163
+ The TCP client is primarily for testing and simple setups:
164
+
165
+ ```ruby
166
+ # Environment variables
167
+ ENV['TCP_HOST'] = 'localhost'
168
+ ENV['TCP_PORT'] = '9999'
169
+
170
+ # Or programmatically
171
+ tcp_config = {
172
+ host: 'localhost',
173
+ port: 9999,
174
+ timeout: 30
175
+ }
176
+
177
+ client = Agent99::MessageClients::TcpClient.new(tcp_config)
178
+ ```
179
+
180
+ ### Usage Example
181
+
182
+ ```ruby
183
+ class TcpAgent < Agent99::Base
184
+ def initialize
185
+ super(message_client: 'tcp')
186
+ end
187
+
188
+ def process_request(payload)
189
+ client_address = current_client_address
190
+
191
+ logger.info "Request from: #{client_address}"
192
+
193
+ send_response(
194
+ message: "Processed via TCP",
195
+ client: client_address
196
+ )
197
+ end
198
+ end
199
+ ```
200
+
201
+ ## Message Client API
202
+
203
+ ### Common Interface
204
+
205
+ All message clients implement a common interface:
206
+
207
+ ```ruby
208
+ class MessageClientBase
209
+ def initialize(config = {})
210
+ # Initialize connection with config
211
+ end
212
+
213
+ def connect
214
+ # Establish connection to message broker
215
+ end
216
+
217
+ def disconnect
218
+ # Close connection
219
+ end
220
+
221
+ def subscribe(subject, &block)
222
+ # Subscribe to messages on subject/queue
223
+ end
224
+
225
+ def publish(subject, message, options = {})
226
+ # Publish message to subject/exchange
227
+ end
228
+
229
+ def request(subject, message, options = {})
230
+ # Send request and wait for response
231
+ end
232
+
233
+ def connected?
234
+ # Check connection status
235
+ end
236
+ end
237
+ ```
238
+
239
+ ### Connection Management
240
+
241
+ ```ruby
242
+ # Check connection status
243
+ if client.connected?
244
+ logger.info "Connected to message broker"
245
+ else
246
+ logger.warn "Not connected, attempting reconnect..."
247
+ client.connect
248
+ end
249
+
250
+ # Graceful shutdown
251
+ Signal.trap('TERM') do
252
+ logger.info "Shutting down..."
253
+ client.disconnect
254
+ exit
255
+ end
256
+ ```
257
+
258
+ ### Error Handling
259
+
260
+ ```ruby
261
+ begin
262
+ response = client.request('service.calculate', payload, timeout: 10)
263
+ rescue Agent99::MessageClient::TimeoutError
264
+ logger.error "Request timed out"
265
+ rescue Agent99::MessageClient::ConnectionError => e
266
+ logger.error "Connection failed: #{e.message}"
267
+ # Attempt reconnection
268
+ client.connect
269
+ rescue Agent99::MessageClient::Error => e
270
+ logger.error "Message client error: #{e.message}"
271
+ end
272
+ ```
273
+
274
+ ## Advanced Features
275
+
276
+ ### Message Filtering
277
+
278
+ ```ruby
279
+ # NATS subject filtering
280
+ client.subscribe('services.calculator.*') do |message|
281
+ # Receives: services.calculator.add, services.calculator.multiply, etc.
282
+ end
283
+
284
+ # AMQP routing key patterns
285
+ client.subscribe('services.#') do |message|
286
+ # Receives all messages starting with 'services.'
287
+ end
288
+ ```
289
+
290
+ ### Message Persistence
291
+
292
+ ```ruby
293
+ # AMQP persistent messages
294
+ client.publish('important.task', payload, persistent: true)
295
+
296
+ # NATS with JetStream persistence (if available)
297
+ client.publish('stream.data', payload, stream: 'EVENTS')
298
+ ```
299
+
300
+ ### Load Balancing
301
+
302
+ ```ruby
303
+ # NATS queue groups for load balancing
304
+ client.subscribe('work.queue', queue: 'workers') do |message|
305
+ # Multiple subscribers share the work
306
+ end
307
+
308
+ # AMQP work queues
309
+ client.subscribe('task.queue', durable: true, ack: true) do |message|
310
+ process_task(message)
311
+ message.ack # Acknowledge completion
312
+ end
313
+ ```
314
+
315
+ ## Performance Considerations
316
+
317
+ ### Connection Pooling
318
+
319
+ ```ruby
320
+ class PooledMessageClient
321
+ def initialize(config = {})
322
+ @pool_size = config[:pool_size] || 10
323
+ @pool = ConnectionPool.new(size: @pool_size) do
324
+ Agent99::MessageClients::NatsClient.new(config)
325
+ end
326
+ end
327
+
328
+ def with_connection(&block)
329
+ @pool.with(&block)
330
+ end
331
+ end
332
+ ```
333
+
334
+ ### Batching
335
+
336
+ ```ruby
337
+ # Batch messages for better performance
338
+ messages = []
339
+ (1..100).each do |i|
340
+ messages << { id: i, data: "message #{i}" }
341
+ end
342
+
343
+ # Send in batches
344
+ messages.each_slice(10) do |batch|
345
+ batch.each { |msg| client.publish('batch.data', msg) }
346
+ sleep(0.1) # Rate limiting
347
+ end
348
+ ```
349
+
350
+ ### Monitoring
351
+
352
+ ```ruby
353
+ class MonitoredClient
354
+ def initialize(base_client)
355
+ @client = base_client
356
+ @metrics = {
357
+ messages_sent: 0,
358
+ messages_received: 0,
359
+ errors: 0
360
+ }
361
+ end
362
+
363
+ def publish(subject, message, options = {})
364
+ start_time = Time.now
365
+
366
+ begin
367
+ @client.publish(subject, message, options)
368
+ @metrics[:messages_sent] += 1
369
+ rescue => e
370
+ @metrics[:errors] += 1
371
+ raise
372
+ ensure
373
+ duration = Time.now - start_time
374
+ logger.debug "Published to #{subject} in #{duration}s"
375
+ end
376
+ end
377
+
378
+ def stats
379
+ @metrics.dup
380
+ end
381
+ end
382
+ ```
383
+
384
+ ## Testing Message Clients
385
+
386
+ ### Mock Client for Testing
387
+
388
+ ```ruby
389
+ class MockMessageClient
390
+ def initialize
391
+ @messages = []
392
+ @subscriptions = {}
393
+ end
394
+
395
+ def publish(subject, message, options = {})
396
+ @messages << {
397
+ subject: subject,
398
+ message: message,
399
+ options: options,
400
+ timestamp: Time.now
401
+ }
402
+
403
+ # Trigger subscriptions
404
+ @subscriptions[subject]&.each { |block| block.call(message) }
405
+ end
406
+
407
+ def subscribe(subject, &block)
408
+ @subscriptions[subject] ||= []
409
+ @subscriptions[subject] << block
410
+ end
411
+
412
+ def published_messages
413
+ @messages
414
+ end
415
+
416
+ def clear_messages
417
+ @messages.clear
418
+ end
419
+ end
420
+ ```
421
+
422
+ ### Integration Testing
423
+
424
+ ```ruby
425
+ require 'minitest/autorun'
426
+
427
+ class TestMessageClientIntegration < Minitest::Test
428
+ def setup
429
+ @client = Agent99::MessageClients::NatsClient.new
430
+ @client.connect
431
+ end
432
+
433
+ def teardown
434
+ @client.disconnect
435
+ end
436
+
437
+ def test_request_response
438
+ # Start a responder
439
+ response_thread = Thread.new do
440
+ @client.subscribe('test.echo') do |message|
441
+ @client.publish(message.reply, { echo: message.data })
442
+ end
443
+ end
444
+
445
+ # Send request
446
+ response = @client.request('test.echo', { text: 'hello' })
447
+
448
+ assert_equal 'hello', response[:echo][:text]
449
+
450
+ response_thread.kill
451
+ end
452
+ end
453
+ ```
454
+
455
+ ## Configuration Examples
456
+
457
+ ### Production NATS Cluster
458
+
459
+ ```yaml
460
+ # config/nats.yml
461
+ production:
462
+ servers:
463
+ - nats://nats1.example.com:4222
464
+ - nats://nats2.example.com:4222
465
+ - nats://nats3.example.com:4222
466
+ username: <%= ENV['NATS_USERNAME'] %>
467
+ password: <%= ENV['NATS_PASSWORD'] %>
468
+ tls:
469
+ cert_file: /etc/ssl/certs/client.crt
470
+ key_file: /etc/ssl/private/client.key
471
+ ca_file: /etc/ssl/certs/ca.crt
472
+ ```
473
+
474
+ ### Production RabbitMQ
475
+
476
+ ```yaml
477
+ # config/rabbitmq.yml
478
+ production:
479
+ url: <%= ENV['RABBITMQ_URL'] %>
480
+ heartbeat: 30
481
+ connection_timeout: 10
482
+ read_timeout: 30
483
+ write_timeout: 30
484
+ ssl:
485
+ enabled: true
486
+ verify: true
487
+ cert_path: /etc/ssl/certs/client.pem
488
+ key_path: /etc/ssl/private/client.key
489
+ ```
490
+
491
+ ## Next Steps
492
+
493
+ - **[Agent99::Base](agent99-base.md)** - Core agent class reference
494
+ - **[Registry Client](registry-client.md)** - Registry service API
495
+ - **[Configuration](../operations/configuration.md)** - Detailed configuration options
@@ -6,14 +6,24 @@ When creating a new agent by subclassing `Agent99::Base`, you must implement cer
6
6
 
7
7
  ### Required Methods
8
8
 
9
- #### `capabilities`
10
- Returns an array of strings describing the agent's capabilities.
9
+ #### `info`
10
+ 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.
11
11
  ```ruby
12
- def capabilities
13
- ['process_image', 'face_detection']
12
+ def info
13
+ {
14
+ name: self.class.to_s,
15
+ type: :server,
16
+ capabilities: %w[ greeter hello_world hello-world hello],
17
+ request_schema: MaxwellRequest.schema,
18
+ # response_schema: {}, # Agent99::RESPONSE.schema
19
+ # control_schema: {}, # Agent99::CONTROL.schema
20
+ # error_schema: {}, # Agent99::ERROR.schema
21
+ }
14
22
  end
15
23
  ```
16
24
 
25
+ Entries for **:name** and **:capabilities** are required. Other entries are optional. This entire info packet is stored by the central registry and provided to other agents on a discover "hit" so that the inquiring agents know all the target agent is willing to tell them.
26
+
17
27
  #### `receive_request`
18
28
  Handles incoming request messages. Must be implemented if the agent accepts requests.
19
29
  ```ruby