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.
- checksums.yaml +4 -4
- data/A2A_SPEC-dev.md +1829 -0
- data/CHANGELOG.md +31 -0
- data/COMMITS.md +196 -0
- data/DOCS.md +96 -0
- data/README.md +200 -78
- data/Rakefile +62 -0
- data/docs/AI/htm.md +215 -0
- data/docs/AI/htm.rb +141 -0
- data/docs/AI/htm_demo.db +0 -0
- data/docs/AI/notes_on_htm_implementation.md +1319 -0
- data/docs/AI/some_code.rb +692 -0
- data/docs/advanced-topics/a2a-protocol.md +13 -0
- data/docs/{control_actions.md → advanced-topics/control-actions.md} +2 -0
- data/docs/advanced-topics/model-context-protocol.md +4 -0
- data/docs/advanced-topics/multi-agent-processing.md +674 -0
- data/docs/agent-development/request-response-handling.md +512 -0
- data/docs/api-reference/agent99-base.md +463 -0
- data/docs/api-reference/message-clients.md +495 -0
- data/docs/api-reference/registry-client.md +470 -0
- data/docs/api-reference/schemas.md +518 -0
- data/docs/assets/css/custom.css +27 -0
- data/docs/assets/images/agent-lifecycle.svg +73 -0
- data/docs/assets/images/agent-registry-process.svg +86 -0
- data/docs/assets/images/agent-registry-processes.svg +114 -0
- data/docs/assets/images/agent-types-overview.svg +51 -0
- data/docs/assets/images/agent99-architecture.svg +85 -0
- data/docs/assets/images/agent99_logo.png +0 -0
- data/docs/assets/images/control-actions-state.svg +83 -0
- data/docs/assets/images/knowledge-graph.svg +77 -0
- data/docs/assets/images/message-processing-flow.svg +148 -0
- data/docs/assets/images/multi-agent-system.svg +66 -0
- data/docs/assets/images/proxy-pattern-sequence.svg +48 -0
- data/docs/assets/images/request-flow.svg +97 -0
- data/docs/assets/images/request-processing-lifecycle.svg +50 -0
- data/docs/assets/images/request-response-sequence.svg +39 -0
- data/docs/{agent_lifecycle.md → core-concepts/agent-lifecycle.md} +2 -0
- data/docs/core-concepts/agent-types.md +255 -0
- data/docs/{architecture.md → core-concepts/architecture.md} +5 -5
- data/docs/{what_is_an_agent.md → core-concepts/what-is-an-agent.md} +1 -1
- data/docs/diagrams/message-flow-sequence.svg +198 -0
- data/docs/diagrams/p2p-network-topology.svg +181 -0
- data/docs/diagrams/smart-transport-routing.svg +165 -0
- data/docs/diagrams/three-layer-architecture.svg +77 -0
- data/docs/diagrams/transport-extension-api.svg +309 -0
- data/docs/diagrams/transport-extension-architecture.svg +234 -0
- data/docs/diagrams/transport-selection-flowchart.svg +264 -0
- data/docs/examples/advanced-examples.md +951 -0
- data/docs/examples/basic-examples.md +268 -0
- data/docs/{agent_registry_processes.md → framework-components/agent-registry.md} +1 -1
- data/docs/{message_processing.md → framework-components/message-processing.md} +3 -1
- data/docs/getting-started/basic-example.md +306 -0
- data/docs/getting-started/installation.md +160 -0
- data/docs/getting-started/overview.md +64 -0
- data/docs/getting-started/quick-start.md +179 -0
- data/docs/index.md +97 -0
- data/examples/DEMO.md +148 -0
- data/examples/README.md +50 -0
- data/examples/bad_agent.rb +32 -0
- data/examples/registry.rb +0 -8
- data/examples/run_demo.rb +433 -0
- data/lib/agent99/amqp_message_client.rb +2 -2
- data/lib/agent99/base.rb +1 -1
- data/lib/agent99/message_processing.rb +6 -12
- data/lib/agent99/registry_client.rb +4 -1
- data/lib/agent99/version.rb +1 -1
- data/lib/agent99.rb +1 -1
- data/mkdocs.yml +195 -0
- data/p2p_plan.md +533 -0
- data/p2p_roadmap.md +299 -0
- data/registry_plan.md +1818 -0
- metadata +89 -32
- data/docs/README.md +0 -57
- data/docs/diagrams/agent_registry_processes.dot +0 -42
- data/docs/diagrams/agent_registry_processes.png +0 -0
- data/docs/diagrams/high_level_architecture.dot +0 -26
- data/docs/diagrams/high_level_architecture.png +0 -0
- data/docs/diagrams/request_flow.dot +0 -42
- data/docs/diagrams/request_flow.png +0 -0
- /data/docs/{advanced_features.md → advanced-topics/advanced-features.md} +0 -0
- /data/docs/{extending_the_framework.md → advanced-topics/extending-the-framework.md} +0 -0
- /data/docs/{custom_agent_implementation.md → agent-development/custom-agent-implementation.md} +0 -0
- /data/docs/{error_handling_and_logging.md → agent-development/error-handling-and-logging.md} +0 -0
- /data/docs/{schema_definition.md → agent-development/schema-definition.md} +0 -0
- /data/docs/{api_reference.md → api-reference/overview.md} +0 -0
- /data/docs/{agent_discovery.md → framework-components/agent-discovery.md} +0 -0
- /data/docs/{messaging_system.md → framework-components/messaging-system.md} +0 -0
- /data/docs/{breaking_change_v0.0.4.md → operations/breaking-changes.md} +0 -0
- /data/docs/{configuration.md → operations/configuration.md} +0 -0
- /data/docs/{preformance_considerations.md → operations/performance-considerations.md} +0 -0
- /data/docs/{security.md → operations/security.md} +0 -0
- /data/docs/{troubleshooting.md → operations/troubleshooting.md} +0 -0
@@ -0,0 +1,463 @@
|
|
1
|
+
# Agent99::Base
|
2
|
+
|
3
|
+
The `Agent99::Base` class is the foundation of all agents in the Agent99 framework. It provides core functionality for agent lifecycle, messaging, discovery, and error handling.
|
4
|
+
|
5
|
+
## Class Overview
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class Agent99::Base
|
9
|
+
include Agent99::HeaderManagement
|
10
|
+
include Agent99::AgentDiscovery
|
11
|
+
include Agent99::ControlActions
|
12
|
+
include Agent99::AgentLifecycle
|
13
|
+
include Agent99::MessageProcessing
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
## Instance Methods
|
18
|
+
|
19
|
+
### Core Lifecycle
|
20
|
+
|
21
|
+
#### `#run`
|
22
|
+
|
23
|
+
Starts the agent and begins listening for messages.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
def run
|
27
|
+
```
|
28
|
+
|
29
|
+
**Example:**
|
30
|
+
```ruby
|
31
|
+
agent = MyAgent.new
|
32
|
+
agent.run # Blocks until shutdown
|
33
|
+
```
|
34
|
+
|
35
|
+
#### `#shutdown`
|
36
|
+
|
37
|
+
Gracefully shuts down the agent.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
def shutdown
|
41
|
+
```
|
42
|
+
|
43
|
+
**Example:**
|
44
|
+
```ruby
|
45
|
+
agent.shutdown
|
46
|
+
```
|
47
|
+
|
48
|
+
#### `#info`
|
49
|
+
|
50
|
+
Abstract method that must be implemented by subclasses. Returns agent metadata.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
def info
|
54
|
+
# Must return hash with:
|
55
|
+
# - :name (String)
|
56
|
+
# - :type (Symbol: :server, :client, or :hybrid)
|
57
|
+
# - :capabilities (Array of Strings)
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
**Example:**
|
62
|
+
```ruby
|
63
|
+
def info
|
64
|
+
{
|
65
|
+
name: self.class.to_s,
|
66
|
+
type: :server,
|
67
|
+
capabilities: ['calculator', 'math']
|
68
|
+
}
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
### Message Processing
|
73
|
+
|
74
|
+
#### `#process_request(payload)`
|
75
|
+
|
76
|
+
Abstract method for handling incoming requests. Only called for server and hybrid agents.
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
def process_request(payload)
|
80
|
+
# Process the payload and call send_response or send_error
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
**Parameters:**
|
85
|
+
- `payload` (Hash) - The request data
|
86
|
+
|
87
|
+
**Example:**
|
88
|
+
```ruby
|
89
|
+
def process_request(payload)
|
90
|
+
name = payload.dig(:name) || "World"
|
91
|
+
send_response(message: "Hello, #{name}!")
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
#### `#send_response(data)`
|
96
|
+
|
97
|
+
Sends a successful response back to the requester.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
def send_response(data)
|
101
|
+
```
|
102
|
+
|
103
|
+
**Parameters:**
|
104
|
+
- `data` (Hash) - Response data
|
105
|
+
|
106
|
+
**Example:**
|
107
|
+
```ruby
|
108
|
+
send_response(
|
109
|
+
result: 42,
|
110
|
+
status: "success",
|
111
|
+
timestamp: Time.now.iso8601
|
112
|
+
)
|
113
|
+
```
|
114
|
+
|
115
|
+
#### `#send_error(message, code = nil, details = nil)`
|
116
|
+
|
117
|
+
Sends an error response back to the requester.
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
def send_error(message, code = nil, details = nil)
|
121
|
+
```
|
122
|
+
|
123
|
+
**Parameters:**
|
124
|
+
- `message` (String) - Error message
|
125
|
+
- `code` (String, optional) - Error code
|
126
|
+
- `details` (Hash, optional) - Additional error details
|
127
|
+
|
128
|
+
**Example:**
|
129
|
+
```ruby
|
130
|
+
send_error(
|
131
|
+
"Invalid input data",
|
132
|
+
"VALIDATION_ERROR",
|
133
|
+
{ field: "email", expected: "valid email address" }
|
134
|
+
)
|
135
|
+
```
|
136
|
+
|
137
|
+
#### `#send_request(agent_name, payload, options = {})`
|
138
|
+
|
139
|
+
Sends a request to another agent. Only available for client and hybrid agents.
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
def send_request(agent_name, payload, options = {})
|
143
|
+
```
|
144
|
+
|
145
|
+
**Parameters:**
|
146
|
+
- `agent_name` (String) - Target agent name
|
147
|
+
- `payload` (Hash) - Request data
|
148
|
+
- `options` (Hash, optional) - Request options (timeout, etc.)
|
149
|
+
|
150
|
+
**Returns:** Response hash or nil if failed
|
151
|
+
|
152
|
+
**Example:**
|
153
|
+
```ruby
|
154
|
+
response = send_request(
|
155
|
+
"CalculatorAgent",
|
156
|
+
{ operation: "add", a: 5, b: 3 },
|
157
|
+
{ timeout: 30 }
|
158
|
+
)
|
159
|
+
```
|
160
|
+
|
161
|
+
### Agent Discovery
|
162
|
+
|
163
|
+
#### `#discover_agents(capabilities = [])`
|
164
|
+
|
165
|
+
Finds agents that match the specified capabilities.
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
def discover_agents(capabilities = [])
|
169
|
+
```
|
170
|
+
|
171
|
+
**Parameters:**
|
172
|
+
- `capabilities` (Array) - List of required capabilities
|
173
|
+
|
174
|
+
**Returns:** Array of agent info hashes
|
175
|
+
|
176
|
+
**Example:**
|
177
|
+
```ruby
|
178
|
+
calculators = discover_agents(['calculator'])
|
179
|
+
weather_agents = discover_agents(['weather', 'forecast'])
|
180
|
+
```
|
181
|
+
|
182
|
+
#### `#register_agent`
|
183
|
+
|
184
|
+
Registers this agent with the registry.
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
def register_agent
|
188
|
+
```
|
189
|
+
|
190
|
+
**Example:**
|
191
|
+
```ruby
|
192
|
+
register_agent
|
193
|
+
```
|
194
|
+
|
195
|
+
#### `#unregister_agent`
|
196
|
+
|
197
|
+
Removes this agent from the registry.
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
def unregister_agent
|
201
|
+
```
|
202
|
+
|
203
|
+
### Header Management
|
204
|
+
|
205
|
+
#### `#header_value(key)`
|
206
|
+
|
207
|
+
Gets a header value from the current request.
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
def header_value(key)
|
211
|
+
```
|
212
|
+
|
213
|
+
**Parameters:**
|
214
|
+
- `key` (String) - Header key
|
215
|
+
|
216
|
+
**Returns:** Header value or nil
|
217
|
+
|
218
|
+
**Example:**
|
219
|
+
```ruby
|
220
|
+
user_id = header_value('user_id')
|
221
|
+
correlation_id = header_value('correlation_id')
|
222
|
+
```
|
223
|
+
|
224
|
+
#### `#set_header(key, value)`
|
225
|
+
|
226
|
+
Sets a header value for the current response.
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
def set_header(key, value)
|
230
|
+
```
|
231
|
+
|
232
|
+
**Parameters:**
|
233
|
+
- `key` (String) - Header key
|
234
|
+
- `value` (String) - Header value
|
235
|
+
|
236
|
+
**Example:**
|
237
|
+
```ruby
|
238
|
+
set_header('processing_time', '150ms')
|
239
|
+
set_header('cache_status', 'hit')
|
240
|
+
```
|
241
|
+
|
242
|
+
### Control Actions
|
243
|
+
|
244
|
+
#### `#pause`
|
245
|
+
|
246
|
+
Pauses the agent (stops processing new requests).
|
247
|
+
|
248
|
+
```ruby
|
249
|
+
def pause
|
250
|
+
```
|
251
|
+
|
252
|
+
#### `#resume`
|
253
|
+
|
254
|
+
Resumes the agent after being paused.
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
def resume
|
258
|
+
```
|
259
|
+
|
260
|
+
#### `#status`
|
261
|
+
|
262
|
+
Returns the current agent status.
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
def status
|
266
|
+
```
|
267
|
+
|
268
|
+
**Returns:** Symbol (`:running`, `:paused`, `:stopped`)
|
269
|
+
|
270
|
+
### Configuration
|
271
|
+
|
272
|
+
#### `#logger`
|
273
|
+
|
274
|
+
Returns the logger instance for this agent.
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
def logger
|
278
|
+
```
|
279
|
+
|
280
|
+
**Example:**
|
281
|
+
```ruby
|
282
|
+
logger.info "Processing request"
|
283
|
+
logger.error "Something went wrong: #{error.message}"
|
284
|
+
```
|
285
|
+
|
286
|
+
#### `#config`
|
287
|
+
|
288
|
+
Returns the configuration hash for this agent.
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
def config
|
292
|
+
```
|
293
|
+
|
294
|
+
**Example:**
|
295
|
+
```ruby
|
296
|
+
timeout = config[:timeout] || 30
|
297
|
+
registry_url = config[:registry_url]
|
298
|
+
```
|
299
|
+
|
300
|
+
## Class Methods
|
301
|
+
|
302
|
+
### `Agent99::Base.create(type:, **options)`
|
303
|
+
|
304
|
+
Factory method for creating agents.
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
Agent99::Base.create(type: :server, name: 'TestAgent')
|
308
|
+
```
|
309
|
+
|
310
|
+
**Parameters:**
|
311
|
+
- `type` (Symbol) - Agent type (`:server`, `:client`, `:hybrid`)
|
312
|
+
- `options` (Hash) - Configuration options
|
313
|
+
|
314
|
+
## Configuration Options
|
315
|
+
|
316
|
+
When creating agents, you can pass configuration options:
|
317
|
+
|
318
|
+
```ruby
|
319
|
+
class MyAgent < Agent99::Base
|
320
|
+
def initialize(options = {})
|
321
|
+
super(options)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
agent = MyAgent.new(
|
326
|
+
registry_url: 'http://localhost:4567',
|
327
|
+
message_client: 'nats',
|
328
|
+
timeout: 30,
|
329
|
+
log_level: :info
|
330
|
+
)
|
331
|
+
```
|
332
|
+
|
333
|
+
### Available Options
|
334
|
+
|
335
|
+
| Option | Type | Default | Description |
|
336
|
+
|--------|------|---------|-------------|
|
337
|
+
| `registry_url` | String | `http://localhost:4567` | Registry service URL |
|
338
|
+
| `message_client` | String | `nats` | Message broker type (`nats`, `amqp`, `tcp`) |
|
339
|
+
| `timeout` | Integer | 30 | Default request timeout (seconds) |
|
340
|
+
| `log_level` | Symbol | `:info` | Logging level |
|
341
|
+
| `retry_attempts` | Integer | 3 | Request retry attempts |
|
342
|
+
| `retry_delay` | Integer | 1 | Delay between retries (seconds) |
|
343
|
+
|
344
|
+
## Examples
|
345
|
+
|
346
|
+
### Simple Server Agent
|
347
|
+
|
348
|
+
```ruby
|
349
|
+
class GreeterAgent < Agent99::Base
|
350
|
+
def info
|
351
|
+
{
|
352
|
+
name: self.class.to_s,
|
353
|
+
type: :server,
|
354
|
+
capabilities: ['greeting', 'hello']
|
355
|
+
}
|
356
|
+
end
|
357
|
+
|
358
|
+
def process_request(payload)
|
359
|
+
name = payload.dig(:name) || "World"
|
360
|
+
logger.info "Greeting #{name}"
|
361
|
+
|
362
|
+
send_response(
|
363
|
+
message: "Hello, #{name}!",
|
364
|
+
timestamp: Time.now.iso8601
|
365
|
+
)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
```
|
369
|
+
|
370
|
+
### Client Agent with Error Handling
|
371
|
+
|
372
|
+
```ruby
|
373
|
+
class ClientAgent < Agent99::Base
|
374
|
+
def info
|
375
|
+
{
|
376
|
+
name: self.class.to_s,
|
377
|
+
type: :client,
|
378
|
+
capabilities: ['client_operations']
|
379
|
+
}
|
380
|
+
end
|
381
|
+
|
382
|
+
def make_greeting_request(name)
|
383
|
+
greeters = discover_agents(['greeting'])
|
384
|
+
|
385
|
+
if greeters.empty?
|
386
|
+
logger.warn "No greeting agents available"
|
387
|
+
return nil
|
388
|
+
end
|
389
|
+
|
390
|
+
begin
|
391
|
+
response = send_request(
|
392
|
+
greeters.first[:name],
|
393
|
+
{ name: name },
|
394
|
+
{ timeout: 10 }
|
395
|
+
)
|
396
|
+
|
397
|
+
logger.info "Received: #{response[:message]}"
|
398
|
+
response
|
399
|
+
rescue => e
|
400
|
+
logger.error "Request failed: #{e.message}"
|
401
|
+
nil
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
```
|
406
|
+
|
407
|
+
### Hybrid Agent with State
|
408
|
+
|
409
|
+
```ruby
|
410
|
+
class StatefulAgent < Agent99::Base
|
411
|
+
def initialize(options = {})
|
412
|
+
super(options)
|
413
|
+
@request_count = 0
|
414
|
+
@mutex = Mutex.new
|
415
|
+
end
|
416
|
+
|
417
|
+
def info
|
418
|
+
{
|
419
|
+
name: self.class.to_s,
|
420
|
+
type: :hybrid,
|
421
|
+
capabilities: ['stateful', 'counter']
|
422
|
+
}
|
423
|
+
end
|
424
|
+
|
425
|
+
def process_request(payload)
|
426
|
+
@mutex.synchronize do
|
427
|
+
@request_count += 1
|
428
|
+
|
429
|
+
if payload[:operation] == 'get_count'
|
430
|
+
send_response(count: @request_count)
|
431
|
+
elsif payload[:operation] == 'reset_count'
|
432
|
+
@request_count = 0
|
433
|
+
send_response(count: 0, status: 'reset')
|
434
|
+
else
|
435
|
+
send_error('Unknown operation', 'INVALID_OPERATION')
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
```
|
441
|
+
|
442
|
+
## Thread Safety
|
443
|
+
|
444
|
+
The `Agent99::Base` class is designed to be thread-safe for concurrent request processing. However:
|
445
|
+
|
446
|
+
- **Subclass implementations** should ensure thread safety in their `process_request` methods
|
447
|
+
- **Shared state** should be protected with mutexes or other synchronization primitives
|
448
|
+
- **Instance variables** may be accessed concurrently during request processing
|
449
|
+
|
450
|
+
## Error Handling
|
451
|
+
|
452
|
+
The base class provides automatic error handling for:
|
453
|
+
|
454
|
+
- **Network failures** during agent registration and discovery
|
455
|
+
- **Message broker disconnections** with automatic retry
|
456
|
+
- **Invalid message formats** with appropriate error responses
|
457
|
+
- **Unhandled exceptions** in `process_request` (converted to error responses)
|
458
|
+
|
459
|
+
## Next Steps
|
460
|
+
|
461
|
+
- **[Registry Client](registry-client.md)** - Registry service API
|
462
|
+
- **[Message Clients](message-clients.md)** - Message broker clients
|
463
|
+
- **[Schemas](schemas.md)** - Schema validation system
|