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,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
@@ -32,4 +32,8 @@ module Agent99::AgentDiscovery
32
32
 
33
33
  all ? result : result.sample(how_many)
34
34
  end
35
+
36
+ def add_agent(agent_info)
37
+ @agents[agent_info[:uuid]] = agent_info
38
+ end
35
39
  end
@@ -11,16 +11,19 @@ module Agent99::AgentLifecycle
11
11
  def initialize(registry_client: Agent99::RegistryClient.new,
12
12
  message_client: Agent99::AmqpMessageClient.new,
13
13
  logger: Logger.new($stdout))
14
- @payload = nil
15
- @name = self.class.name
16
- @capabilities = capabilities
17
- @id = nil
18
- @registry_client = registry_client
19
- @message_client = message_client
20
- @logger = logger
14
+ @agents = {}
15
+ @payload = nil
16
+ @name = self.class.name
17
+ @capabilities = capabilities
18
+ @id = nil
19
+ @registry_client = registry_client
20
+ @message_client = message_client
21
+ @logger = logger
22
+
23
+ validate_info_keys
21
24
 
22
25
  @registry_client.logger = logger
23
- register
26
+ register(info)
24
27
 
25
28
  @queue = message_client.setup(agent_id: id, logger:)
26
29
 
@@ -29,12 +32,33 @@ module Agent99::AgentLifecycle
29
32
  setup_signal_handlers
30
33
  end
31
34
 
35
+
36
+ def validate_info_keys
37
+ required_keys = [:name, :capabilities]
38
+ if respond_to? :info
39
+ missing_keys = required_keys - info.keys
40
+ unless missing_keys.empty?
41
+ logger.error <<~MESSAGE
42
+ This agent's info method is missing
43
+ #{1 == missing_keys.size ? 'a required key' : 'some required keys'}:
44
+ #{missing_keys}
45
+ MESSAGE
46
+ .split("\n").join
47
+ exit(1)
48
+ end
49
+ else
50
+ logger.error "An agent must implement the info method"
51
+ exit(1)
52
+ end
53
+ end
54
+
55
+
32
56
  # Registers the agent with the registry service.
33
57
  #
34
58
  # @raise [StandardError] If registration fails
35
59
  #
36
- def register
37
- @id = registry_client.register(name:, capabilities:)
60
+ def register(agent_info)
61
+ @id = registry_client.register(info: agent_info)
38
62
  logger.info "Registered Agent #{name} with ID: #{id}"
39
63
  rescue StandardError => e
40
64
  handle_error("Error during registration", e)
@@ -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'
@@ -37,7 +37,11 @@ class Agent99::Base
37
37
 
38
38
  MESSAGE_TYPES = %w[request response control]
39
39
 
40
- attr_reader :id, :capabilities, :name, :payload, :header, :logger, :queue
40
+ attr_reader :id, :capabilities, :name
41
+ attr_reader :payload, :header, :queue
42
+ attr_reader :logger
43
+ attr_reader :agents
44
+
41
45
  attr_accessor :registry_client, :message_client
42
46
 
43
47
 
@@ -128,17 +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
- schema = JsonSchema.parse!(self.class::REQUEST_SCHEMA)
132
- schema.expand_references!
133
- validator = JsonSchema::Validator.new(schema)
134
-
135
- validator.validate(@payload)
136
- []
137
-
138
- 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
139
135
  handle_error("Validation error", e)
140
- send_response(type: 'error', errors: e.messages)
141
- e.messages
136
+ send_response(type: 'error', errors: [e.message])
137
+ [e.message]
142
138
  end
143
139
 
144
140
 
@@ -8,17 +8,19 @@ class Agent99::RegistryClient
8
8
  attr_accessor :logger
9
9
 
10
10
  def initialize(
11
- base_url: ENV.fetch('REGISTRY_BASE_URL', 'http://localhost:4567'),
11
+ base_url: ENV.fetch('AGENT99_REGISTRY_URL', 'http://localhost:4567'),
12
12
  logger: Logger.new($stdout)
13
13
  )
14
- @base_url = base_url
15
- @logger = logger
16
- @http_client = Net::HTTP.new(URI.parse(base_url).host, URI.parse(base_url).port)
14
+ @base_url = base_url
15
+ @logger = logger
16
+ uri = URI.parse(base_url)
17
+ @http_client = Net::HTTP.new(uri.host, uri.port)
17
18
  end
18
19
 
19
- def register(name:, capabilities:)
20
- request = create_request(:post, "/register", { name: name, capabilities: capabilities })
21
- @id = send_request(request)
20
+ def register(info:)
21
+ payload = info
22
+ request = create_request(:post, "/register", payload)
23
+ @id = send_request(request)
22
24
  end
23
25
 
24
26
  def withdraw(id)
@@ -37,16 +39,16 @@ class Agent99::RegistryClient
37
39
 
38
40
 
39
41
  def fetch_all_agents
40
- request = create_request(:get, "/")
41
- response = send_request(request)
42
+ request = create_request(:get, "/")
43
+ response = send_request(request)
42
44
  end
43
45
 
44
46
  ################################################
45
47
  private
46
48
 
47
49
  def create_request(method, path, body = nil)
48
- request = Object.const_get("Net::HTTP::#{method.capitalize}").new(path, { "Content-Type" => "application/json" })
49
- request.body = body.to_json if body
50
+ request = Object.const_get("Net::HTTP::#{method.capitalize}").new(path, { "Content-Type" => "application/json" })
51
+ request.body = body.to_json if body
50
52
  request
51
53
  end
52
54
 
@@ -57,10 +59,12 @@ class Agent99::RegistryClient
57
59
 
58
60
  rescue JSON::ParserError => e
59
61
  logger.error "JSON parsing error: #{e.message}"
62
+ logger.debug "Response body that failed parsing: #{response&.body}"
60
63
  nil
61
64
 
62
65
  rescue StandardError => e
63
66
  logger.error "Request error: #{e.message}"
67
+ logger.debug "Error details: #{e.class} - #{e.backtrace&.first(5)}"
64
68
  nil
65
69
  end
66
70