agent99 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -1
- data/README.md +34 -26
- data/docs/README.md +57 -0
- data/docs/advanced_features.md +115 -0
- data/docs/agent99_framework/central_registry.md +94 -0
- data/docs/agent99_framework/message_client.md +120 -0
- data/docs/agent99_framework/registry_client.md +119 -0
- data/docs/agent_discovery.md +66 -0
- data/docs/agent_lifecycle.md +137 -0
- data/docs/agent_registry_processes.md +108 -0
- data/docs/api_reference.md +146 -0
- data/docs/architecture.md +77 -0
- data/docs/breaking_change_v0.0.4.md +26 -0
- data/docs/configuration.md +17 -0
- data/docs/control_actions.md +179 -0
- data/docs/custom_agent_implementation.md +30 -0
- data/docs/diagrams/agent_registry_processes.dot +42 -0
- data/docs/diagrams/agent_registry_processes.png +0 -0
- data/docs/diagrams/high_level_architecture.dot +26 -0
- data/docs/diagrams/high_level_architecture.png +0 -0
- data/docs/diagrams/request_flow.dot +42 -0
- data/docs/diagrams/request_flow.png +0 -0
- data/docs/error_handling_and_logging.md +13 -0
- data/docs/extending_the_framework.md +11 -0
- data/docs/message_processing.md +165 -0
- data/docs/messaging_system.md +129 -0
- data/docs/preformance_considerations.md +9 -0
- data/docs/schema_definition.md +78 -0
- data/docs/security.md +9 -0
- data/docs/troubleshooting.md +11 -0
- data/docs/what_is_an_agent.md +293 -0
- data/examples/README.md +43 -0
- data/examples/agent_watcher.rb +106 -0
- data/examples/agents/.keep +0 -0
- data/examples/chief_agent.rb +17 -6
- data/examples/control.rb +16 -7
- data/examples/example_agent.rb +39 -0
- data/examples/kaos_spy.rb +63 -0
- data/examples/maxwell_agent86.rb +15 -26
- data/examples/registry.rb +24 -13
- data/lib/agent99/agent_discovery.rb +4 -0
- data/lib/agent99/agent_lifecycle.rb +34 -10
- data/lib/agent99/base.rb +5 -1
- data/lib/agent99/header_schema.rb +5 -0
- data/lib/agent99/message_processing.rb +3 -1
- data/lib/agent99/registry_client.rb +12 -11
- data/lib/agent99/tcp_message_client.rb +183 -0
- data/lib/agent99/version.rb +1 -1
- metadata +50 -3
- data/docs/todo.md +0 -66
@@ -0,0 +1,66 @@
|
|
1
|
+
# Agent99 Framework
|
2
|
+
|
3
|
+
## Agent Discovery
|
4
|
+
|
5
|
+
Agents within the Agent99 Framework can efficiently discover one another based on their declared capabilities. This feature fosters dynamic interactions that enhance the collaborative functionality of the agents.
|
6
|
+
|
7
|
+
### Overview
|
8
|
+
|
9
|
+
The agent discovery process involves the following steps:
|
10
|
+
|
11
|
+
1. **Registration**: Agents register their capabilities with a central registry upon startup.
|
12
|
+
2. **Discovery**: When an agent needs to discover other agents, it queries the registry for agents with specific capabilities.
|
13
|
+
3. **Response**: The registry responds with a list of available agents, allowing them to interact based on their capabilities.
|
14
|
+
|
15
|
+
### Declaring Capabilities in the Info Method
|
16
|
+
|
17
|
+
Each agent must implement the `info` method to declare its capabilities as an array of strings:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
def info
|
21
|
+
{
|
22
|
+
# ...
|
23
|
+
capabilities: ['process_image', 'face_detection'],
|
24
|
+
# ...
|
25
|
+
}
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
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.
|
30
|
+
|
31
|
+
### Discovery API
|
32
|
+
|
33
|
+
To find other agents, use the `discover_agent` method. Here are some usage examples:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# Find a single agent with a specific capability
|
37
|
+
agent = discover_agent(capability: 'face_detection')
|
38
|
+
|
39
|
+
# Find multiple agents
|
40
|
+
agents = discover_agent(capability: 'process_image', how_many: 3)
|
41
|
+
|
42
|
+
# Find all agents with a specific capability
|
43
|
+
all_agents = discover_agent(capability: 'process_image', all: true)
|
44
|
+
```
|
45
|
+
|
46
|
+
### Important Note on Capabilities
|
47
|
+
|
48
|
+
- **Single Capability**: A seeking agent can only request one kind of capability at a time.
|
49
|
+
- **Semantics-Based Capabilities**: The development roadmap includes enhancements towards semantic-based capabilities that could allow for more complex interactions between agents in the future. This would be a change from the current Array of Strings to a single String that is a description of the services the agent provides. This would be consistent with the way in which LLMs currently find Tools for augmented generation.
|
50
|
+
|
51
|
+
### Registry Configuration
|
52
|
+
|
53
|
+
The registry client comes with default settings, which you can override as needed:
|
54
|
+
|
55
|
+
- **URL**: Default is `http://localhost:4567` (you can override this using the `REGISTRY_BASE_URL` environment variable).
|
56
|
+
- **Interface**: Supports a standard HTTP REST interface.
|
57
|
+
- **Reconnection**: Automatic reconnection handling is provided to ensure reliable communication.
|
58
|
+
|
59
|
+
### Best Practices
|
60
|
+
|
61
|
+
1. **Check Discovery Success**: Always verify if agent discovery succeeded before attempting to establish communication with the discovered agent.
|
62
|
+
2. **Use Specific Capability Names**: This ensures that the correct agents are matched during the discovery process, avoiding ambiguity.
|
63
|
+
3. **Implement Multiple Capabilities**: Consider declaring multiple capabilities per agent to enhance its versatility and improve interaction possibilities.
|
64
|
+
|
65
|
+
With these guidelines, you can effectively implement and utilize the agent discovery feature within the Agent99 Framework, ensuring robust and dynamic interactions among agents based on their declared capabilities.
|
66
|
+
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# Agent99 Framework
|
2
|
+
|
3
|
+
## Agent Lifecycle
|
4
|
+
|
5
|
+
The lifecycle of an agent within Agent99 consists of several key stages that are managed through dedicated lifecycle methods. Understanding these stages and their corresponding methods is crucial for proper agent implementation.
|
6
|
+
|
7
|
+
### Lifecycle Stages
|
8
|
+
|
9
|
+
1. **Creation**: An agent is instantiated through the `Agent99::Base` class.
|
10
|
+
2. **Initialization**: The agent sets up resources and establishes connections.
|
11
|
+
3. **Running**: The agent processes messages and performs its designated tasks.
|
12
|
+
4. **Shutdown**: The agent performs cleanup and gracefully terminates.
|
13
|
+
|
14
|
+
### Core Lifecycle Methods
|
15
|
+
|
16
|
+
#### The `init` Method
|
17
|
+
|
18
|
+
The `init` method is called automatically after the agent has been registered but before it starts processing messages. Its primary purpose is to perform any additional setup required for the agent following the default initialization provided by the `Agent99::Base` class. This may include:
|
19
|
+
|
20
|
+
- Setting up initial state
|
21
|
+
- Establishing connections to other agents or resources
|
22
|
+
- Discovering dependencies or agents to communicate with
|
23
|
+
- Sending initial messages to specific agents
|
24
|
+
|
25
|
+
Here’s an example implementation:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
def init
|
29
|
+
@state = initialize_state
|
30
|
+
@resources = setup_resources
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
#### Custom Initialization
|
35
|
+
|
36
|
+
Agents can choose to either use the default behavior provided by the `Agent99::Base` class or implement their own `initialize` method to customize the `logger`, `message_client`, and `registry_client` attributes. For instance:
|
37
|
+
|
38
|
+
1. **Using Defaults**: If you do not define an `initialize` method in your agent class, it will inherit the defaults:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class MyAgent < Agent99::Base
|
42
|
+
# Inherits default logger, message_client, and registry_client
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
2. **Customizing Initialization**: If you need custom initialization, you can ignore the `init` method and override the `initialize` method:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
class MyCustomAgent < Agent99::Base
|
50
|
+
def initialize(
|
51
|
+
registry_client: CustomRegistryClient.new,
|
52
|
+
message_client: CustomMessageClient.new,
|
53
|
+
logger: Logger.new('custom_agent.log')
|
54
|
+
)
|
55
|
+
super # Registers the Agent and setups its message queue
|
56
|
+
|
57
|
+
# Additional state or resource initialization required
|
58
|
+
# by the new agent
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
In this case, the custom agent not need the `init` method to perform any additional setup.
|
64
|
+
|
65
|
+
#### The `fini` Method
|
66
|
+
|
67
|
+
The `fini` method is setup to be invoked when the `exit` method is called within `initialize` method by the `on_exit { fini }` hook.
|
68
|
+
|
69
|
+
The `fini` method ensures proper cleanup during agent shutdown:
|
70
|
+
|
71
|
+
The default `fini` method does:
|
72
|
+
- Withdrawing from the registry
|
73
|
+
- Closing message queue connections
|
74
|
+
|
75
|
+
If your agent requires additional cleanup or state presistence you should implement a custom `fini` method to do things like:
|
76
|
+
- Cleaning up resources
|
77
|
+
- Saving state (if required)
|
78
|
+
- Releasing system resources
|
79
|
+
|
80
|
+
Example implementation:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
def fini
|
84
|
+
save_state if @state
|
85
|
+
cleanup_resources
|
86
|
+
deregister_from_registry
|
87
|
+
|
88
|
+
super # Always call super last for proper framework cleanup
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
### Best Practices
|
93
|
+
|
94
|
+
1. **Proper Method Ordering**:
|
95
|
+
- Always call `super` first in `initialize`.
|
96
|
+
- Always call `super` last in `fini`.
|
97
|
+
- This order ensures proper framework initialization and cleanup.
|
98
|
+
|
99
|
+
2. **Resource Management**:
|
100
|
+
- Initialize all resources in `init` or `initialize`.
|
101
|
+
- Clean up all resources in `fini`.
|
102
|
+
- Handle cleanup idempotently.
|
103
|
+
|
104
|
+
3. **Error Handling**:
|
105
|
+
- Implement robust error handling in all methods.
|
106
|
+
- Ensure `fini` can handle partial initialization states.
|
107
|
+
- Log all significant lifecycle events.
|
108
|
+
|
109
|
+
4. **State Management**:
|
110
|
+
- Initialize state clearly.
|
111
|
+
- Save or cleanup state properly in `fini`.
|
112
|
+
- Consider persistence needs.
|
113
|
+
|
114
|
+
### Important Considerations
|
115
|
+
|
116
|
+
- Agents can be implemented as stand-alone processes.
|
117
|
+
- When an agent is implemented within the context of a larger application process, the agent should be "run" within its own thread.
|
118
|
+
```ruby
|
119
|
+
begin
|
120
|
+
my_agent = MyAgent.new
|
121
|
+
Thread.new { my_agent.run }
|
122
|
+
end
|
123
|
+
```
|
124
|
+
- Agents handle only one request message at a time.
|
125
|
+
- The `fini` method is called automatically during graceful shutdowns.
|
126
|
+
|
127
|
+
### Framework Integration
|
128
|
+
|
129
|
+
The Agent99 framework automatically manages the lifecycle of agents:
|
130
|
+
|
131
|
+
1. Calls `init` (if present) after agent creation.
|
132
|
+
2. Monitors agent health during operation.
|
133
|
+
3. Calls `fini` during shutdown (`on_exit {fini}`).
|
134
|
+
4. Handles cleanup if initialization fails.
|
135
|
+
|
136
|
+
This automated lifecycle management ensures reliable agent operation within the framework.
|
137
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# Agent99 Framework
|
2
|
+
|
3
|
+
## Agent Registry Processes
|
4
|
+
|
5
|
+
In the Agent99 framework, an instance of the `Agent99::RegistryClient` class is responsible for registering agent capabilities with a centralized registry. `examples/registry.rb` is a Sinatra web-app example of what a centralized regristry service should be.
|
6
|
+
|
7
|
+
The registration process is transparent to a new instance of an `Agent99::Base` class.
|
8
|
+
|
9
|
+
First thing: start the registry.rb Sinatra app and the peer-to-peer messaging network. The default is the `AmqpMessageClient` class.
|
10
|
+
|
11
|
+
If you do not have the RabbitMQ server installed on your Macthen then grab it using `brew install rabbitmq-server` and while you are installing software do `brew install boxes` as well since the `chief_agent.rb` example uses that little CLI tool to highlight some text in the terminal.
|
12
|
+
|
13
|
+
```bash
|
14
|
+
git clone ssh://git@github.com/MadBomber/agent99
|
15
|
+
brew install rabbitmq-server boxes
|
16
|
+
gem install agent99
|
17
|
+
|
18
|
+
cd agent99/examples
|
19
|
+
./start_rabbitmq_and_registry.sh
|
20
|
+
```
|
21
|
+
|
22
|
+
Now go into `irb` in a different terminal window and try this code ...
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
require 'agent99'
|
26
|
+
|
27
|
+
# Define the Schema for the Agent's request payload
|
28
|
+
|
29
|
+
class MyAgentRequest < SimpleJsonSchemaBuilder::Base
|
30
|
+
object do
|
31
|
+
object :header, schema: Agent99::HeaderSchema
|
32
|
+
|
33
|
+
string :greeting, required: false, examples: ["Hello"]
|
34
|
+
string :name, required: true, examples: ["World"]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Define the new Agent ....
|
39
|
+
|
40
|
+
class MyAgent < Agent99::Base
|
41
|
+
def info
|
42
|
+
{
|
43
|
+
# ...
|
44
|
+
request_schema: MyAgentRequest.schema
|
45
|
+
capabilities: %w[ greeter hello_world ],
|
46
|
+
# ...
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# You may create multiple instances of the agent if needed
|
52
|
+
|
53
|
+
my_agent = MyAgent.new
|
54
|
+
|
55
|
+
I, [2024-12-07T14:42:08.140286 #36471] INFO -- : Registered Agent MyAgent with ID: 9e735449-582f-46e2-8f11-371e584d0f08
|
56
|
+
I, [2024-12-07T14:42:08.141978 #36471] INFO -- : Created queue for agent_id: 9e735449-582f-46e2-8f11-371e584d0f08
|
57
|
+
#=>
|
58
|
+
#<MyAgent:0x000000011d4d2e48
|
59
|
+
...
|
60
|
+
|
61
|
+
# The agent as an ID and an address in the peer-to-peer network
|
62
|
+
|
63
|
+
my_agent.id
|
64
|
+
#=> "9e735449-582f-46e2-8f11-371e584d0f08"
|
65
|
+
```
|
66
|
+
|
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.
|
68
|
+
|
69
|
+

|
70
|
+
|
71
|
+
The above image also show the other services provided via the RegistryClient class.
|
72
|
+
|
73
|
+
The example centralized regristry service provides three processes:
|
74
|
+
|
75
|
+
1. Registration Process:
|
76
|
+
- MyAgent initializes the RegistryClient
|
77
|
+
- RegistryClient sends a POST request to the Central Registry
|
78
|
+
- Central Registry responds with a UUID
|
79
|
+
- RegistryClient returns the UUID to MyAgent
|
80
|
+
2. Discovery Process:
|
81
|
+
- MyAgent requests discovery of agents with a specific capability
|
82
|
+
- RegistryClient sends a GET request to the Central Registry
|
83
|
+
- Central Registry responds with matching agents
|
84
|
+
- RegistryClient returns the matching agents to MyAgent
|
85
|
+
3. Withdrawal Process:
|
86
|
+
- MyAgent requests withdrawal using its UUID
|
87
|
+
- RegistryClient sends a DELETE request to the Central Registry
|
88
|
+
- Central Registry responds with a 204 No Content
|
89
|
+
- RegistryClient confirms the withdrawal to MyAgent
|
90
|
+
|
91
|
+
Like the register process, the withdraw process is also transparent. Its executed on any exit via the public method `fini` in the base class' `on_exit {...}` handler. Calling `exit` for any reason within your agent class will withdraw it from the central registry and remove its message queue from peer-to-peer messaging network.
|
92
|
+
|
93
|
+
The discover process is primary business logic for your agent class. You must call the `@registry_client.discover(capability: "whatever")` method directly within the agents process.
|
94
|
+
|
95
|
+
For example suppose your agent needs to work with other agents that provide the "pne", "twp" and "three" services. That is 3 outside agents. You can do this in the `init` method for you agent.
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
class MyAgent < Agent99::Base
|
99
|
+
def init
|
100
|
+
@agnet_1 = discover_agent(capability: 'one')
|
101
|
+
@agnet_2 = discover_agent(capability: 'two')
|
102
|
+
@agnet_3 = discover_agent(capability: 'three')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
`discover_agent` is the `Agent99::Base` method that links to the registry client's instance to do the discovery via the central registry. Other parameters to `discover_agent` allow's you agent to specify `how_many` agents having the specify capability you want returned. The default is 1. If you want all the agents capable of providing the requested service use the `all: true` parameter with the `discover_agent` method.
|
108
|
+
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# Agent99 Framework API Reference
|
2
|
+
|
3
|
+
## Agent Implementation Requirements
|
4
|
+
|
5
|
+
When creating a new agent by subclassing `Agent99::Base`, you must implement certain methods and may optionally override others.
|
6
|
+
|
7
|
+
### Required Methods
|
8
|
+
|
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
|
+
```ruby
|
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
|
+
}
|
22
|
+
end
|
23
|
+
```
|
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
|
+
|
27
|
+
#### `receive_request`
|
28
|
+
Handles incoming request messages. Must be implemented if the agent accepts requests.
|
29
|
+
```ruby
|
30
|
+
def receive_request
|
31
|
+
# Process the request message in @payload
|
32
|
+
# Access message data via @payload[:data]
|
33
|
+
# Send response using send_response(response_data)
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
### Optional Methods
|
38
|
+
|
39
|
+
#### `init`
|
40
|
+
Called after registration but before message processing begins. Use for additional setup.
|
41
|
+
```ruby
|
42
|
+
def init
|
43
|
+
@state = initialize_state
|
44
|
+
@resources = setup_resources
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
#### `fini`
|
49
|
+
Called during shutdown. Override to add custom cleanup.
|
50
|
+
```ruby
|
51
|
+
def fini
|
52
|
+
cleanup_resources
|
53
|
+
save_state if @state
|
54
|
+
super # Always call super last
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
#### `receive_response`
|
59
|
+
Handles incoming response messages. Override if the agent processes responses.
|
60
|
+
```ruby
|
61
|
+
def receive_response
|
62
|
+
# Process the response message in @payload
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
## Message Client Interface
|
67
|
+
|
68
|
+
To implement a custom message client, create a class that implements these methods:
|
69
|
+
|
70
|
+
### Required Methods
|
71
|
+
|
72
|
+
#### `initialize(logger: Logger.new($stdout))`
|
73
|
+
Sets up the messaging connection.
|
74
|
+
|
75
|
+
#### `setup(agent_id:, logger:)`
|
76
|
+
Initializes message queues/topics for the agent.
|
77
|
+
- Returns: queue/topic identifier
|
78
|
+
|
79
|
+
#### `listen_for_messages(queue, request_handler:, response_handler:, control_handler:)`
|
80
|
+
Starts listening for messages.
|
81
|
+
- `queue`: Queue/topic to listen on
|
82
|
+
- `request_handler`: Lambda for handling requests
|
83
|
+
- `response_handler`: Lambda for handling responses
|
84
|
+
- `control_handler`: Lambda for handling control messages
|
85
|
+
|
86
|
+
#### `publish(message)`
|
87
|
+
Publishes a message.
|
88
|
+
- `message`: Hash containing the message with :header and payload
|
89
|
+
- Returns: Hash with :success and optional :error
|
90
|
+
|
91
|
+
#### `delete_queue(queue_name)`
|
92
|
+
Cleans up agent's message queue/topic.
|
93
|
+
|
94
|
+
## Registry Client Interface
|
95
|
+
|
96
|
+
To implement a custom registry client, create a class that implements these methods:
|
97
|
+
|
98
|
+
### Required Methods
|
99
|
+
|
100
|
+
#### `initialize(base_url: ENV.fetch('REGISTRY_BASE_URL', 'http://localhost:4567'), logger: Logger.new($stdout))`
|
101
|
+
Sets up the registry connection.
|
102
|
+
|
103
|
+
#### `register(name:, capabilities:)`
|
104
|
+
Registers an agent with the registry.
|
105
|
+
- Returns: UUID string for the agent
|
106
|
+
|
107
|
+
#### `withdraw(id)`
|
108
|
+
Removes an agent from the registry.
|
109
|
+
|
110
|
+
## Base Class Public Methods
|
111
|
+
|
112
|
+
The `Agent99::Base` class provides these public methods:
|
113
|
+
|
114
|
+
#### `run`
|
115
|
+
Starts the agent's message processing loop.
|
116
|
+
|
117
|
+
#### `discover_agent(capability:, how_many: 1, all: false)`
|
118
|
+
Finds other agents by capability.
|
119
|
+
- Returns: Array of agent information hashes
|
120
|
+
|
121
|
+
#### `send_response(response)`
|
122
|
+
Sends a response message.
|
123
|
+
- `response`: Hash containing the response data
|
124
|
+
|
125
|
+
## Message Types
|
126
|
+
|
127
|
+
Messages in Agent99 must include a `:header` with:
|
128
|
+
- `:type`: One of "request", "response", or "control"
|
129
|
+
- `:to_uuid`: Destination agent's UUID
|
130
|
+
- `:from_uuid`: Sending agent's UUID
|
131
|
+
- `:event_uuid`: UUID to link request to response
|
132
|
+
- `:timestamp`: Integer (`Agent99::Timestamp.new.to_i`)
|
133
|
+
|
134
|
+
Example request message structure:
|
135
|
+
```ruby
|
136
|
+
{
|
137
|
+
header: {
|
138
|
+
type: 'request',
|
139
|
+
to_uuid: ,
|
140
|
+
from_uuid: ,
|
141
|
+
event_uuid: ,
|
142
|
+
timestamp: ,
|
143
|
+
},
|
144
|
+
# agent specific parameters
|
145
|
+
}
|
146
|
+
```
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Agent99 Framework Architecture
|
2
|
+
|
3
|
+
## High-Level Architecture Overview
|
4
|
+
|
5
|
+
Agent99 is a Ruby-based framework designed for building and managing software agents in a distributed system environment. The architecture follows a service-oriented approach with three main components:
|
6
|
+
|
7
|
+
1. **Agents**: Independent services that can register, discover, and communicate with each other
|
8
|
+
2. **Registry Service**: Central registration and discovery system
|
9
|
+
3. **Message Broker**: Communication backbone (supports AMQP or NATS)
|
10
|
+
|
11
|
+
### System Components Diagram
|
12
|
+
|
13
|
+

|
14
|
+
|
15
|
+
The diagram above (generated from `diagrams/high_level_architecture.dot`) illustrates the key components and their interactions:
|
16
|
+
|
17
|
+
- **Agents**: Come in three types:
|
18
|
+
- Client Agents: Only make requests
|
19
|
+
- Server Agents: Only respond to requests
|
20
|
+
- Hybrid Agents: Both make and respond to requests
|
21
|
+
|
22
|
+
- **Registry Service**:
|
23
|
+
- Maintains agent registrations
|
24
|
+
- Handles capability-based discovery
|
25
|
+
- Issues unique UUIDs to agents
|
26
|
+
|
27
|
+
- **Message Broker**:
|
28
|
+
- Supports both AMQP and NATS protocols
|
29
|
+
- Handles message routing between agents
|
30
|
+
- Provides reliable message delivery
|
31
|
+
|
32
|
+
### Communication Patterns
|
33
|
+
|
34
|
+
1. **Registration Flow**:
|
35
|
+
- New agent instantiated
|
36
|
+
- Agent registers with Registry Service
|
37
|
+
- Receives unique UUID for identification
|
38
|
+
- Sets up message queue/topic
|
39
|
+
|
40
|
+
2. **Discovery Flow**:
|
41
|
+
- Agent queries Registry for specific capabilities
|
42
|
+
- Registry returns matching agent information
|
43
|
+
- Requesting agent caches discovery results
|
44
|
+
|
45
|
+
3. **Messaging Flow**:
|
46
|
+
- Agent creates message with recipient UUID
|
47
|
+
- Message routed through Message Broker
|
48
|
+
- Recipient processes message based on type:
|
49
|
+
- Requests: Handled by receive_request
|
50
|
+
- Responses: Handled by receive_response
|
51
|
+
- Control: Handled by control handlers
|
52
|
+
|
53
|
+
### Message Types
|
54
|
+
|
55
|
+
The framework supports three primary message types:
|
56
|
+
|
57
|
+
1. **Request Messages**:
|
58
|
+
- Used to request services from other agents
|
59
|
+
- Must include capability requirements
|
60
|
+
- Can contain arbitrary payload data
|
61
|
+
|
62
|
+
2. **Response Messages**:
|
63
|
+
- Sent in reply to requests
|
64
|
+
- Include original request reference
|
65
|
+
- Contain result data or error information
|
66
|
+
|
67
|
+
3. **Control Messages**:
|
68
|
+
- System-level communication
|
69
|
+
- Handle agent lifecycle events
|
70
|
+
- Support configuration updates
|
71
|
+
|
72
|
+
## Implementation Details
|
73
|
+
|
74
|
+
For detailed implementation information, see:
|
75
|
+
- [API Reference](api_reference.md) for method specifications
|
76
|
+
- [Agent Lifecycle](agent_lifecycle.md) for lifecycle management
|
77
|
+
- [Agent Discovery](agent_discovery.md) for discovery mechanisms
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# v0.0.4 is a Breaking Change
|
2
|
+
|
3
|
+
## Before
|
4
|
+
|
5
|
+
Each agent was required to implement a `capabilities` method that returned an Array of Strings in which the elements of the array were essentially synonyms describing the thing that the agent does. The roadmap calls for this capabilities structure to become an unstructured String in which semmantic search will be used for discovery rather than exact matches.
|
6
|
+
|
7
|
+
## After
|
8
|
+
|
9
|
+
The **capabilities** is now just one of several within a Hash collection returned by a new method named `info` representing the agent's information packet. The entire packet will be returned by the central regristry when the agent is discovered.
|
10
|
+
|
11
|
+
The capabilities element of this new `info` hash still has the same requirement of being an Array of Strings with a promiss of becoming more later as the system becomes more sophisticated.
|
12
|
+
|
13
|
+
The required elements of the `info` Hash are:
|
14
|
+
|
15
|
+
- **name** -- automaticall derived from the class name of the agent.
|
16
|
+
- **type** -- one of server, client or hybrid.
|
17
|
+
- **capabilities** -- An Array of Strings
|
18
|
+
- **request_schema** -- is required when the type is server
|
19
|
+
|
20
|
+
The keys to the `info` Hash are Symbols.
|
21
|
+
|
22
|
+
### Modivation
|
23
|
+
|
24
|
+
The goal is to be able to mix and match multiple agents created by different developers in different languages within the context of the protocols and APIs of the Agent99 Framework. To that end it seems reasonable that agents would have a need to share more than just their capabilitieis. For example, their JSON schema for their request, response and control messages might also be something worth sharing.
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Agent99 Framework
|
2
|
+
|
3
|
+
## Configuration
|
4
|
+
|
5
|
+
Agents can be configured using environment variables. Key configuration options include:
|
6
|
+
|
7
|
+
- `REGISTRY_BASE_URL`: Specifies the URL of the agent registry service (default: 'http://localhost:4567').
|
8
|
+
|
9
|
+
|
10
|
+
### Environment Variables
|
11
|
+
|
12
|
+
To set an environment variable, use the following command in your terminal before running your application:
|
13
|
+
|
14
|
+
```bash
|
15
|
+
export REGISTRY_BASE_URL=http://my-registry-url
|
16
|
+
```
|
17
|
+
|