agent99 0.0.4 → 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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/A2A_SPEC-dev.md +1829 -0
  3. data/CHANGELOG.md +31 -0
  4. data/COMMITS.md +196 -0
  5. data/DOCS.md +96 -0
  6. data/README.md +200 -78
  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/{control_actions.md → advanced-topics/control-actions.md} +2 -0
  15. data/docs/advanced-topics/model-context-protocol.md +4 -0
  16. data/docs/advanced-topics/multi-agent-processing.md +674 -0
  17. data/docs/agent-development/request-response-handling.md +512 -0
  18. data/docs/api-reference/agent99-base.md +463 -0
  19. data/docs/api-reference/message-clients.md +495 -0
  20. data/docs/api-reference/registry-client.md +470 -0
  21. data/docs/api-reference/schemas.md +518 -0
  22. data/docs/assets/css/custom.css +27 -0
  23. data/docs/assets/images/agent-lifecycle.svg +73 -0
  24. data/docs/assets/images/agent-registry-process.svg +86 -0
  25. data/docs/assets/images/agent-registry-processes.svg +114 -0
  26. data/docs/assets/images/agent-types-overview.svg +51 -0
  27. data/docs/assets/images/agent99-architecture.svg +85 -0
  28. data/docs/assets/images/agent99_logo.png +0 -0
  29. data/docs/assets/images/control-actions-state.svg +83 -0
  30. data/docs/assets/images/knowledge-graph.svg +77 -0
  31. data/docs/assets/images/message-processing-flow.svg +148 -0
  32. data/docs/assets/images/multi-agent-system.svg +66 -0
  33. data/docs/assets/images/proxy-pattern-sequence.svg +48 -0
  34. data/docs/assets/images/request-flow.svg +97 -0
  35. data/docs/assets/images/request-processing-lifecycle.svg +50 -0
  36. data/docs/assets/images/request-response-sequence.svg +39 -0
  37. data/docs/{agent_lifecycle.md → core-concepts/agent-lifecycle.md} +2 -0
  38. data/docs/core-concepts/agent-types.md +255 -0
  39. data/docs/{architecture.md → core-concepts/architecture.md} +5 -5
  40. data/docs/{what_is_an_agent.md → core-concepts/what-is-an-agent.md} +1 -1
  41. data/docs/diagrams/message-flow-sequence.svg +198 -0
  42. data/docs/diagrams/p2p-network-topology.svg +181 -0
  43. data/docs/diagrams/smart-transport-routing.svg +165 -0
  44. data/docs/diagrams/three-layer-architecture.svg +77 -0
  45. data/docs/diagrams/transport-extension-api.svg +309 -0
  46. data/docs/diagrams/transport-extension-architecture.svg +234 -0
  47. data/docs/diagrams/transport-selection-flowchart.svg +264 -0
  48. data/docs/examples/advanced-examples.md +951 -0
  49. data/docs/examples/basic-examples.md +268 -0
  50. data/docs/{agent_registry_processes.md → framework-components/agent-registry.md} +1 -1
  51. data/docs/{message_processing.md → framework-components/message-processing.md} +3 -1
  52. data/docs/getting-started/basic-example.md +306 -0
  53. data/docs/getting-started/installation.md +160 -0
  54. data/docs/getting-started/overview.md +64 -0
  55. data/docs/getting-started/quick-start.md +179 -0
  56. data/docs/index.md +97 -0
  57. data/examples/DEMO.md +148 -0
  58. data/examples/README.md +50 -0
  59. data/examples/bad_agent.rb +32 -0
  60. data/examples/registry.rb +0 -8
  61. data/examples/run_demo.rb +433 -0
  62. data/lib/agent99/amqp_message_client.rb +2 -2
  63. data/lib/agent99/base.rb +1 -1
  64. data/lib/agent99/message_processing.rb +6 -12
  65. data/lib/agent99/registry_client.rb +4 -1
  66. data/lib/agent99/version.rb +1 -1
  67. data/lib/agent99.rb +1 -1
  68. data/mkdocs.yml +195 -0
  69. data/p2p_plan.md +533 -0
  70. data/p2p_roadmap.md +299 -0
  71. data/registry_plan.md +1818 -0
  72. metadata +89 -32
  73. data/docs/README.md +0 -57
  74. data/docs/diagrams/agent_registry_processes.dot +0 -42
  75. data/docs/diagrams/agent_registry_processes.png +0 -0
  76. data/docs/diagrams/high_level_architecture.dot +0 -26
  77. data/docs/diagrams/high_level_architecture.png +0 -0
  78. data/docs/diagrams/request_flow.dot +0 -42
  79. data/docs/diagrams/request_flow.png +0 -0
  80. /data/docs/{advanced_features.md → advanced-topics/advanced-features.md} +0 -0
  81. /data/docs/{extending_the_framework.md → advanced-topics/extending-the-framework.md} +0 -0
  82. /data/docs/{custom_agent_implementation.md → agent-development/custom-agent-implementation.md} +0 -0
  83. /data/docs/{error_handling_and_logging.md → agent-development/error-handling-and-logging.md} +0 -0
  84. /data/docs/{schema_definition.md → agent-development/schema-definition.md} +0 -0
  85. /data/docs/{api_reference.md → api-reference/overview.md} +0 -0
  86. /data/docs/{agent_discovery.md → framework-components/agent-discovery.md} +0 -0
  87. /data/docs/{messaging_system.md → framework-components/messaging-system.md} +0 -0
  88. /data/docs/{breaking_change_v0.0.4.md → operations/breaking-changes.md} +0 -0
  89. /data/docs/{configuration.md → operations/configuration.md} +0 -0
  90. /data/docs/{preformance_considerations.md → operations/performance-considerations.md} +0 -0
  91. /data/docs/{security.md → operations/security.md} +0 -0
  92. /data/docs/{troubleshooting.md → operations/troubleshooting.md} +0 -0
data/examples/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Agent99 Framework Examples - 86 and the Chief
2
2
 
3
+ FYI ... I am in the process of extracting this examples directory out into its own repository: [MadBomber/agent99_examples](https://github.com/MadBomber/agent99_examples)
4
+
3
5
  This folder contains example implementations using the Agent99 framework. The framework provides a foundation for building AI agents that can communicate with each other through a message-based system.
4
6
 
5
7
  ## Files
@@ -90,6 +92,40 @@ Note: To use the example_agent.rb, first run the AgentWatcher, then copy example
90
92
 
91
93
  ## Usage
92
94
 
95
+ There are two ways to run the Agent99 examples:
96
+
97
+ ### 🚀 Automated Demo Runner (Recommended)
98
+
99
+ The easiest way to run examples is with the comprehensive demo runner:
100
+
101
+ ```bash
102
+ ./run_demo.rb --list # List all available scenarios
103
+ ./run_demo.rb # Run default 'basic' scenario
104
+ ./run_demo.rb -s basic # Basic Maxwell/Chief interaction
105
+ ./run_demo.rb -s control # Control agent demonstration
106
+ ./run_demo.rb -s watcher # Dynamic agent loading demo
107
+ ./run_demo.rb -s security # Security demonstration (KAOS spy)
108
+ ./run_demo.rb -s all # Run multiple scenarios in sequence
109
+ ./run_demo.rb -v -s basic # Verbose output
110
+ ./run_demo.rb --help # Show all options
111
+ ```
112
+
113
+ The demo runner automatically:
114
+ - ✅ Checks dependencies (RabbitMQ, boxes command, etc.)
115
+ - 🏗️ Starts infrastructure (registry service, RabbitMQ if available)
116
+ - 🎬 Orchestrates multiple agents with proper timing
117
+ - 🧹 Handles cleanup on exit or interrupt
118
+ - 📊 Provides progress feedback and duration estimates
119
+
120
+ **Available Scenarios:**
121
+ - **basic** (~10s): Maxwell Agent86 and Chief interaction
122
+ - **control** (~15s): Control agent managing other agents
123
+ - **watcher** (~20s): Agent watcher dynamically loading new agents
124
+ - **security** (~10s): KAOS spy demonstration (educational security example)
125
+ - **all** (~60s): Run multiple scenarios in sequence
126
+
127
+ ### 📋 Manual Setup (Original Method)
128
+
93
129
  From the examples directory you will need to start three different processes. You will want to keep them all in the forgound so it would be best to start them in different terminal windows.
94
130
 
95
131
  Start the sample registry first: `./registry.rb`
@@ -104,6 +140,20 @@ But first the Chief asks the registry for the UUIDs of all agents who can handle
104
140
 
105
141
  Run the chief a few times in a roll. Some times the agent to whom the Chief issues his requests does not always respond the you would expect.
106
142
 
143
+ ### 🔧 Optional Dependencies
144
+
145
+ For the best experience, install these optional dependencies:
146
+
147
+ ```bash
148
+ # For message broker (recommended)
149
+ brew install rabbitmq-server
150
+
151
+ # For enhanced chief agent output
152
+ brew install boxes
153
+ ```
154
+
155
+ **Note:** The framework works without these dependencies using fallback implementations.
156
+
107
157
  ![Agent99 Framework Diagram](diagram.png)
108
158
 
109
159
 
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/bad_agent.rb
3
+ #
4
+ # This agent is meant to cause errors.
5
+
6
+ require_relative '../lib/agent99'
7
+
8
+ class BadAgent < Agent99::Base
9
+ # this information is made available when the agent
10
+ # registers with the central registry service. It is
11
+ # made available during the discovery process.
12
+ #
13
+ def info
14
+ {
15
+ name: self.class.to_s,
16
+ type: :server,
17
+ kapabilities: %w[ rubber_stamp yes_man example ],
18
+ # request_schema: {}, # ExampleRequest.schema,
19
+ # response_schema: {}, # Agent99::RESPONSE.schema
20
+ # control_schema: {}, # Agent99::CONTROL.schema
21
+ # error_schema: {}, # Agent99::ERROR.schema
22
+ }
23
+ end
24
+
25
+
26
+ def receive_request
27
+ logger.info "Example agent received request: #{payload}"
28
+ send_response(status: 'success')
29
+ end
30
+ end
31
+
32
+ BadAgent.new.run
data/examples/registry.rb CHANGED
@@ -28,17 +28,9 @@ end
28
28
  post '/register' do
29
29
  request.body.rewind
30
30
  request_data = JSON.parse(request.body.read, symbolize_names: true)
31
- debug_me{[
32
- :request_data
33
- ]}
34
31
  agent_name = request_data[:name]
35
32
  agent_uuid = SecureRandom.uuid
36
33
 
37
- debug_me{[
38
- :agent_name,
39
- :agent_uuid
40
- ]}
41
-
42
34
  # Ensure capabilities are lowercase
43
35
  request_data[:capabilities].map!{|c| c.downcase}
44
36
 
@@ -0,0 +1,433 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/run_demo.rb
3
+ #
4
+ # Comprehensive demo script for Agent99 framework examples
5
+ # This script orchestrates running multiple examples automatically
6
+ #
7
+
8
+ require 'optparse'
9
+ require 'fileutils'
10
+ require 'timeout'
11
+
12
+ class Agent99Demo
13
+ EXAMPLES_DIR = File.dirname(__FILE__)
14
+
15
+ # Available demo scenarios
16
+ SCENARIOS = {
17
+ 'basic' => {
18
+ description: 'Basic Maxwell Agent86 and Chief interaction',
19
+ agents: ['maxwell_agent86.rb', 'chief_agent.rb'],
20
+ duration: 10
21
+ },
22
+ 'control' => {
23
+ description: 'Control agent managing other agents',
24
+ agents: ['maxwell_agent86.rb', 'control.rb'],
25
+ duration: 15
26
+ },
27
+ 'watcher' => {
28
+ description: 'Agent watcher dynamically loading new agents',
29
+ agents: ['agent_watcher.rb'],
30
+ duration: 20,
31
+ special: :watcher_demo
32
+ },
33
+ 'security' => {
34
+ description: 'KAOS spy demonstration (security example)',
35
+ agents: ['maxwell_agent86.rb', 'kaos_spy.rb'],
36
+ duration: 10,
37
+ warning: 'This demonstrates a malicious agent for educational purposes'
38
+ },
39
+ 'all' => {
40
+ description: 'Run multiple scenarios in sequence',
41
+ agents: [],
42
+ duration: 60,
43
+ special: :run_all_scenarios
44
+ }
45
+ }
46
+
47
+ def initialize
48
+ @pids = []
49
+ @registry_pid = nil
50
+ @rabbitmq_pid = nil
51
+ @options = {
52
+ scenario: 'basic',
53
+ verbose: false,
54
+ no_cleanup: false,
55
+ list_only: false
56
+ }
57
+ setup_signal_handlers
58
+ end
59
+
60
+ def run(args = ARGV)
61
+ parse_options(args)
62
+
63
+ if @options[:list_only]
64
+ list_scenarios
65
+ return
66
+ end
67
+
68
+ puts "🚀 Starting Agent99 Demo: #{@options[:scenario]}"
69
+ puts "📁 Working directory: #{EXAMPLES_DIR}"
70
+ puts
71
+
72
+ scenario = SCENARIOS[@options[:scenario]]
73
+ unless scenario
74
+ puts "❌ Unknown scenario: #{@options[:scenario]}"
75
+ list_scenarios
76
+ exit 1
77
+ end
78
+
79
+ if scenario[:warning]
80
+ puts "⚠️ WARNING: #{scenario[:warning]}"
81
+ puts "Continue? (y/N): "
82
+ response = gets.chomp.downcase
83
+ unless response == 'y' || response == 'yes'
84
+ puts "Demo cancelled."
85
+ exit 0
86
+ end
87
+ puts
88
+ end
89
+
90
+ begin
91
+ check_dependencies
92
+ start_infrastructure
93
+
94
+ case scenario[:special]
95
+ when :run_all_scenarios
96
+ run_all_scenarios
97
+ when :watcher_demo
98
+ run_watcher_demo
99
+ else
100
+ run_scenario(scenario)
101
+ end
102
+
103
+ rescue Interrupt
104
+ puts "\n🛑 Demo interrupted by user"
105
+ rescue => e
106
+ puts "❌ Error running demo: #{e.message}"
107
+ puts e.backtrace.first(5) if @options[:verbose]
108
+ ensure
109
+ cleanup unless @options[:no_cleanup]
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ def parse_options(args)
116
+ OptionParser.new do |opts|
117
+ opts.banner = "Usage: #{$0} [options]"
118
+ opts.separator ""
119
+ opts.separator "Agent99 Framework Demo Runner"
120
+ opts.separator ""
121
+ opts.separator "Options:"
122
+
123
+ opts.on("-s", "--scenario SCENARIO", "Demo scenario to run (#{SCENARIOS.keys.join(', ')})") do |s|
124
+ @options[:scenario] = s
125
+ end
126
+
127
+ opts.on("-l", "--list", "List available scenarios") do
128
+ @options[:list_only] = true
129
+ end
130
+
131
+ opts.on("-v", "--verbose", "Verbose output") do
132
+ @options[:verbose] = true
133
+ end
134
+
135
+ opts.on("--no-cleanup", "Don't cleanup processes on exit (for debugging)") do
136
+ @options[:no_cleanup] = true
137
+ end
138
+
139
+ opts.on("-h", "--help", "Show this help") do
140
+ puts opts
141
+ exit
142
+ end
143
+
144
+ opts.separator ""
145
+ opts.separator "Examples:"
146
+ opts.separator " #{$0} -s basic # Run basic Maxwell/Chief demo"
147
+ opts.separator " #{$0} -s security # Run security demonstration"
148
+ opts.separator " #{$0} -l # List all available scenarios"
149
+ end.parse!(args)
150
+ end
151
+
152
+ def list_scenarios
153
+ puts "Available demo scenarios:"
154
+ puts
155
+ SCENARIOS.each do |name, config|
156
+ puts " #{name.ljust(12)} - #{config[:description]}"
157
+ puts "#{' ' * 17}Duration: ~#{config[:duration]}s"
158
+ puts "#{' ' * 17}Warning: #{config[:warning]}" if config[:warning]
159
+ puts
160
+ end
161
+ end
162
+
163
+ def check_dependencies
164
+ puts "🔍 Checking dependencies..."
165
+
166
+ # Check if Ruby scripts exist
167
+ required_files = %w[registry.rb]
168
+ scenario = SCENARIOS[@options[:scenario]]
169
+ required_files += scenario[:agents] if scenario[:agents]
170
+
171
+ required_files.each do |file|
172
+ path = File.join(EXAMPLES_DIR, file)
173
+ unless File.exist?(path)
174
+ puts "❌ Missing required file: #{file}"
175
+ exit 1
176
+ end
177
+ end
178
+
179
+ # Check for rabbitmq (optional warning)
180
+ begin
181
+ system("which rabbitmq-server > /dev/null 2>&1")
182
+ unless $?.success?
183
+ puts "⚠️ RabbitMQ not found. Install with: brew install rabbitmq-server"
184
+ puts " Continuing anyway - agents will use fallback message client"
185
+ end
186
+ rescue
187
+ puts "⚠️ Could not check for RabbitMQ"
188
+ end
189
+
190
+ # Check for boxes command (used by chief_agent)
191
+ begin
192
+ system("boxes --help > /dev/null 2>&1")
193
+ unless $?.success?
194
+ puts "ℹ️ 'boxes' command not found. Install with: brew install boxes"
195
+ puts " Chief agent output will be plain text"
196
+ end
197
+ rescue
198
+ end
199
+
200
+ puts "✅ Dependencies check complete"
201
+ puts
202
+ end
203
+
204
+ def start_infrastructure
205
+ puts "🏗️ Starting infrastructure..."
206
+
207
+ Dir.chdir(EXAMPLES_DIR) do
208
+ # Start RabbitMQ in background (if available)
209
+ if system("which rabbitmq-server > /dev/null 2>&1")
210
+ puts " Starting RabbitMQ server..."
211
+ @rabbitmq_pid = spawn("rabbitmq-server", out: "/dev/null", err: "/dev/null")
212
+ sleep 3 # Give RabbitMQ time to start
213
+ end
214
+
215
+ # Start registry
216
+ puts " Starting registry service on http://localhost:4567..."
217
+ @registry_pid = spawn("ruby registry.rb", out: @options[:verbose] ? $stdout : "/dev/null")
218
+ sleep 2 # Give registry time to start
219
+
220
+ # Test registry connection
221
+ begin
222
+ require 'net/http'
223
+ response = Net::HTTP.get_response(URI('http://localhost:4567/healthcheck'))
224
+ if response.code == '200'
225
+ puts "✅ Registry service started successfully"
226
+ else
227
+ raise "Registry returned status #{response.code}"
228
+ end
229
+ rescue => e
230
+ puts "❌ Failed to connect to registry: #{e.message}"
231
+ exit 1
232
+ end
233
+ end
234
+
235
+ puts
236
+ end
237
+
238
+ def run_scenario(scenario)
239
+ puts "🎬 Running scenario: #{scenario[:description]}"
240
+ puts " Duration: ~#{scenario[:duration]} seconds"
241
+ puts
242
+
243
+ Dir.chdir(EXAMPLES_DIR) do
244
+ agent_pids = []
245
+
246
+ # Start each agent
247
+ scenario[:agents].each_with_index do |agent, index|
248
+ puts " Starting agent: #{agent}"
249
+
250
+ if agent == 'chief_agent.rb'
251
+ # Chief agent runs once and exits, so we handle it specially
252
+ sleep 1 # Give other agents time to register
253
+ puts " 🎯 Running Chief Agent (one-shot)..."
254
+ system("ruby #{agent}")
255
+ else
256
+ # Regular agents run continuously
257
+ pid = spawn("ruby #{agent}",
258
+ out: @options[:verbose] ? $stdout : "/dev/null",
259
+ err: @options[:verbose] ? $stderr : "/dev/null")
260
+ agent_pids << pid
261
+ @pids << pid
262
+ sleep 1 # Stagger startup
263
+ end
264
+ end
265
+
266
+ unless scenario[:agents].include?('chief_agent.rb')
267
+ # For continuous scenarios, run for specified duration
268
+ puts " ⏱️ Running for #{scenario[:duration]} seconds..."
269
+ puts " Press Ctrl+C to stop early"
270
+ sleep scenario[:duration]
271
+ end
272
+ end
273
+
274
+ puts "✅ Scenario completed"
275
+ end
276
+
277
+ def run_watcher_demo
278
+ puts "🎬 Running Agent Watcher Demo"
279
+ puts " This demo shows dynamic agent loading"
280
+ puts
281
+
282
+ Dir.chdir(EXAMPLES_DIR) do
283
+ # Ensure agents directory exists
284
+ FileUtils.mkdir_p('agents')
285
+
286
+ # Start the agent watcher
287
+ puts " Starting Agent Watcher..."
288
+ watcher_pid = spawn("ruby agent_watcher.rb",
289
+ out: @options[:verbose] ? $stdout : "/dev/null")
290
+ @pids << watcher_pid
291
+
292
+ sleep 3
293
+
294
+ puts " 📂 Copying example_agent.rb to agents/ directory..."
295
+ FileUtils.cp('example_agent.rb', 'agents/example_agent_demo.rb')
296
+
297
+ sleep 5
298
+
299
+ puts " 📂 Adding second agent..."
300
+ # Create a simple second agent
301
+ File.write('agents/demo_agent2.rb', generate_demo_agent_code('DemoAgent2', ['demo', 'test2']))
302
+
303
+ sleep 5
304
+
305
+ puts " 📂 Adding third agent..."
306
+ File.write('agents/demo_agent3.rb', generate_demo_agent_code('DemoAgent3', ['demo', 'test3']))
307
+
308
+ puts " ⏱️ Letting agents run for 15 seconds..."
309
+ sleep 15
310
+
311
+ # Cleanup created files
312
+ FileUtils.rm_rf('agents/example_agent_demo.rb') rescue nil
313
+ FileUtils.rm_rf('agents/demo_agent2.rb') rescue nil
314
+ FileUtils.rm_rf('agents/demo_agent3.rb') rescue nil
315
+ end
316
+
317
+ puts "✅ Agent Watcher demo completed"
318
+ end
319
+
320
+ def run_all_scenarios
321
+ puts "🎬 Running All Scenarios"
322
+ puts
323
+
324
+ %w[basic control security].each do |scenario_name|
325
+ puts "=" * 60
326
+ scenario = SCENARIOS[scenario_name]
327
+
328
+ if scenario[:warning]
329
+ puts "⚠️ Skipping #{scenario_name}: #{scenario[:warning]}"
330
+ puts " Run with -s #{scenario_name} to run individually"
331
+ next
332
+ end
333
+
334
+ run_scenario(scenario)
335
+ puts
336
+
337
+ # Brief pause between scenarios
338
+ sleep 3
339
+ cleanup_agents
340
+ end
341
+
342
+ puts "=" * 60
343
+ puts "✅ All scenarios completed"
344
+ end
345
+
346
+ def generate_demo_agent_code(class_name, capabilities)
347
+ <<~RUBY
348
+ require_relative '../lib/agent99'
349
+
350
+ class #{class_name} < Agent99::Base
351
+ def info
352
+ {
353
+ name: self.class.to_s,
354
+ type: :server,
355
+ capabilities: #{capabilities.inspect}
356
+ }
357
+ end
358
+
359
+ private
360
+
361
+ def receive_request
362
+ send_response({ result: "Hello from \#{self.class.name}!" })
363
+ end
364
+ end
365
+
366
+ # Auto-start when loaded
367
+ agent = #{class_name}.new
368
+ agent.run
369
+ RUBY
370
+ end
371
+
372
+ def setup_signal_handlers
373
+ %w[INT TERM QUIT].each do |signal|
374
+ Signal.trap(signal) do
375
+ puts "\n🛑 Received #{signal} signal, cleaning up..."
376
+ cleanup
377
+ exit 0
378
+ end
379
+ end
380
+ end
381
+
382
+ def cleanup
383
+ puts "🧹 Cleaning up processes..."
384
+ cleanup_agents
385
+ cleanup_infrastructure
386
+ puts "✅ Cleanup complete"
387
+ end
388
+
389
+ def cleanup_agents
390
+ @pids.each do |pid|
391
+ begin
392
+ Process.kill('TERM', pid)
393
+ Process.wait(pid, Process::WNOHANG)
394
+ rescue Errno::ESRCH, Errno::ECHILD
395
+ # Process already terminated
396
+ rescue => e
397
+ puts "⚠️ Error terminating process #{pid}: #{e.message}" if @options[:verbose]
398
+ end
399
+ end
400
+ @pids.clear
401
+ end
402
+
403
+ def cleanup_infrastructure
404
+ if @registry_pid
405
+ begin
406
+ Process.kill('TERM', @registry_pid)
407
+ Process.wait(@registry_pid, Process::WNOHANG)
408
+ rescue Errno::ESRCH, Errno::ECHILD
409
+ rescue => e
410
+ puts "⚠️ Error terminating registry: #{e.message}" if @options[:verbose]
411
+ end
412
+ end
413
+
414
+ if @rabbitmq_pid
415
+ begin
416
+ Process.kill('TERM', @rabbitmq_pid)
417
+ Process.wait(@rabbitmq_pid, Process::WNOHANG)
418
+ rescue Errno::ESRCH, Errno::ECHILD
419
+ rescue => e
420
+ puts "⚠️ Error terminating RabbitMQ: #{e.message}" if @options[:verbose]
421
+ end
422
+
423
+ # Also try rabbitmqctl stop as backup
424
+ system("rabbitmqctl stop > /dev/null 2>&1") rescue nil
425
+ end
426
+ end
427
+ end
428
+
429
+ # Main execution
430
+ if __FILE__ == $PROGRAM_NAME
431
+ demo = Agent99Demo.new
432
+ demo.run
433
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'bunny'
4
4
  require 'json'
5
- require 'json_schema'
5
+ require 'simple_json_schema_builder'
6
6
  require 'logger'
7
7
 
8
8
  class Agent99::AmqpMessageClient
@@ -34,10 +34,10 @@ class Agent99::AmqpMessageClient
34
34
  config: CONFIG,
35
35
  logger: Logger.new($stdout))
36
36
  @config = config
37
+ @logger = logger
37
38
  @connection = create_amqp_connection
38
39
  @channel = @connection.create_channel
39
40
  @exchange = @channel.default_exchange
40
- @logger = logger
41
41
  end
42
42
 
43
43
  def setup(agent_id:, logger:)
data/lib/agent99/base.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'logger'
4
4
  require 'json'
5
- require 'json_schema'
5
+ require 'simple_json_schema_builder'
6
6
 
7
7
  require_relative 'timestamp'
8
8
  require_relative 'registry_client'
@@ -128,19 +128,13 @@ module Agent99::MessageProcessing
128
128
  # @return [Array] An array of validation errors, empty if validation succeeds
129
129
  #
130
130
  def validate_schema
131
- return unless info[:request_schema]
132
-
133
- schema = JsonSchema.parse!(info[:request_schema])
134
- schema.expand_references!
135
- validator = JsonSchema::Validator.new(schema)
136
-
137
- validator.validate(@payload)
138
- []
139
-
140
- rescue JsonSchema::ValidationError => e
131
+ # TODO: Implement proper JSON schema validation
132
+ # For now, skip validation to avoid JsonSchema dependency issues
133
+ return []
134
+ rescue => e
141
135
  handle_error("Validation error", e)
142
- send_response(type: 'error', errors: e.messages)
143
- e.messages
136
+ send_response(type: 'error', errors: [e.message])
137
+ [e.message]
144
138
  end
145
139
 
146
140
 
@@ -13,7 +13,8 @@ class Agent99::RegistryClient
13
13
  )
14
14
  @base_url = base_url
15
15
  @logger = logger
16
- @http_client = Net::HTTP.new(URI.parse(base_url).host, URI.parse(base_url).port)
16
+ uri = URI.parse(base_url)
17
+ @http_client = Net::HTTP.new(uri.host, uri.port)
17
18
  end
18
19
 
19
20
  def register(info:)
@@ -58,10 +59,12 @@ class Agent99::RegistryClient
58
59
 
59
60
  rescue JSON::ParserError => e
60
61
  logger.error "JSON parsing error: #{e.message}"
62
+ logger.debug "Response body that failed parsing: #{response&.body}"
61
63
  nil
62
64
 
63
65
  rescue StandardError => e
64
66
  logger.error "Request error: #{e.message}"
67
+ logger.debug "Error details: #{e.class} - #{e.backtrace&.first(5)}"
65
68
  nil
66
69
  end
67
70
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Agent99
4
- VERSION = "0.0.4"
4
+ VERSION = "0.0.5"
5
5
 
6
6
  def self.version = VERSION
7
7
  end
data/lib/agent99.rb CHANGED
@@ -4,7 +4,7 @@ require 'debug_me'
4
4
  include DebugMe
5
5
 
6
6
  require 'json'
7
- require 'json_schema'
7
+ require 'simple_json_schema_builder'
8
8
  require 'securerandom'
9
9
 
10
10
  module Agent99; end # Establish a namespace