agent99 0.0.1
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 +7 -0
- data/.envrc +3 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +21 -0
- data/README.md +99 -0
- data/Rakefile +8 -0
- data/docs/todo.md +66 -0
- data/examples/README.md +79 -0
- data/examples/hello_world.rb +97 -0
- data/examples/hello_world_client.rb +70 -0
- data/examples/hello_world_request.rb +12 -0
- data/examples/registry.rb +81 -0
- data/examples/start_agents.sh +20 -0
- data/lib/agent99/.irbrc +5 -0
- data/lib/agent99/agent_discovery.rb +35 -0
- data/lib/agent99/agent_lifecycle.rb +87 -0
- data/lib/agent99/amqp_message_client.rb +117 -0
- data/lib/agent99/base.rb +61 -0
- data/lib/agent99/control_actions.rb +56 -0
- data/lib/agent99/header_management.rb +24 -0
- data/lib/agent99/header_schema.rb +15 -0
- data/lib/agent99/message_processing.rb +155 -0
- data/lib/agent99/nats_message_client.rb +101 -0
- data/lib/agent99/registry_client.rb +73 -0
- data/lib/agent99/timestamp.rb +36 -0
- data/lib/agent99/version.rb +7 -0
- data/lib/agent99.rb +19 -0
- data/sig/ai_agent.rbs +4 -0
- metadata +205 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 827e521c4a6580cfe954cf07cf04f1a822c00b9ed6eebf75598d925aeb555626
|
4
|
+
data.tar.gz: 1b3e9b499610b9b3853757432fd4e3e39acab8fb70e29feb94eae1d22f6097aa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ce549f64fb88cd2f152e7af27b9724dbfedfda0f6255033ea1773dda7eaf89dd71a6b622667d023b3093ae1eca72ae3a55e7bd6b1f538e3035fe889ab52ac7c4
|
7
|
+
data.tar.gz: 959b0c9c342738bb9ee75f2dd82a4caaa825a13656f6d12dba2a11434857c08f11d746c1754f03ce1902f9e4ced1f3b7e1067ab1cdbe39c054250b23592ae94f
|
data/.envrc
ADDED
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Dewayne VanHoozer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Agent99 Framework (AFW)
|
2
|
+
|
3
|
+
**Under Development** Initial release has no AI components - its just a generic client-server / request-response micro-services system using a peer-to-peer messaging broker and a centralized agent registry.
|
4
|
+
|
5
|
+
Agent99 is a Ruby-based framework for building and managing AI agents in a distributed system. It provides a robust foundation for creating intelligent agents that can communicate, discover each other, and perform various tasks.
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
- Agent Lifecycle Management: Easy setup and teardown of agents
|
10
|
+
- Message Processing: Handle requests, responses, and control messages
|
11
|
+
- Agent Discovery: Find other agents based on capabilities
|
12
|
+
- Flexible Communication: Support for both AMQP and NATS messaging systems
|
13
|
+
- Registry Integration: Register and discover agents through a central registry
|
14
|
+
- Error Handling and Logging: Built-in error management and logging capabilities
|
15
|
+
- Control Actions: Pause, resume, update configuration, and request status of agents
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'agent99'
|
23
|
+
```
|
24
|
+
|
25
|
+
And then execute:
|
26
|
+
|
27
|
+
```
|
28
|
+
$ bundle install
|
29
|
+
```
|
30
|
+
|
31
|
+
Or install it yourself as:
|
32
|
+
|
33
|
+
```
|
34
|
+
$ gem install agent99
|
35
|
+
```
|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
Here's a basic example of how to create an AI agent:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'agent99'
|
43
|
+
|
44
|
+
class MyAgentRequest < SimpleJsonSchemaBuilder::Base
|
45
|
+
object do
|
46
|
+
object :header, schema: Agent99::HeaderSchema
|
47
|
+
|
48
|
+
# Define your agents parameters ....
|
49
|
+
string :greeting, required: false, examples: ["Hello"]
|
50
|
+
string :name, required: true, examples: ["World"]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class MyAgent < Agent99::Base
|
55
|
+
REQUEST_SCHEMA = MyAgentRequest.schema
|
56
|
+
|
57
|
+
def capabilities
|
58
|
+
['text_processing', 'sentiment_analysis']
|
59
|
+
# TODO: make up mind on keyword or unstructured text
|
60
|
+
end
|
61
|
+
|
62
|
+
def receive_request
|
63
|
+
# Handle the validated incoming requests
|
64
|
+
response = { result: "Processed request" }
|
65
|
+
|
66
|
+
# Not every request needs a response
|
67
|
+
send_response(response)
|
68
|
+
end
|
69
|
+
|
70
|
+
def receive_response
|
71
|
+
# You sent a request to another agent
|
72
|
+
# now handle the response.
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
agent = MyAgent.new
|
77
|
+
agent.run
|
78
|
+
```
|
79
|
+
|
80
|
+
## Configuration
|
81
|
+
|
82
|
+
The framework can be configured through environment variables:
|
83
|
+
|
84
|
+
- `REGISTRY_BASE_URL`: URL of the agent registry service (default: 'http://localhost:4567') See the default registry service in the examples folder.
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/MadBomber/agent99.
|
89
|
+
|
90
|
+
## Short-term Roadmap
|
91
|
+
|
92
|
+
- In the example registry, replace the Array(Hash) datastore with sqlite3 with a vector table to support discovery using semantic search.
|
93
|
+
- Treat the agent like a Tool w/r/t RAG for prompts.
|
94
|
+
- Add AgentRequest schema to agent's info in the registry.
|
95
|
+
- Add AgentResponse schema to define the `result` element in the response JSON payload
|
96
|
+
|
97
|
+
## License
|
98
|
+
|
99
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/docs/todo.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Documentation
|
2
|
+
|
3
|
+
TODO: Lets get some more detailed documentation underway that can be linked to from the main README.md file.
|
4
|
+
|
5
|
+
Here are some key areas that should be covered in comprehensive documentation files:
|
6
|
+
|
7
|
+
1. Architecture Overview:
|
8
|
+
- Explain the overall structure of the AiAgent framework
|
9
|
+
- Describe the roles of different components (Base, MessageClient, RegistryClient, etc.)
|
10
|
+
- Illustrate how agents communicate and interact within the system
|
11
|
+
|
12
|
+
2. Agent Lifecycle:
|
13
|
+
- Detail the process of creating, initializing, running, and shutting down an agent
|
14
|
+
- Explain the registration and withdrawal process with the registry service
|
15
|
+
|
16
|
+
3. Message Processing:
|
17
|
+
- Describe the different types of messages (request, response, control)
|
18
|
+
- Explain how messages are routed and processed
|
19
|
+
- Detail the schema validation process for incoming messages
|
20
|
+
|
21
|
+
4. Agent Discovery:
|
22
|
+
- Explain how agents can discover other agents based on capabilities
|
23
|
+
- Describe the process of querying the registry for available agents
|
24
|
+
|
25
|
+
5. Control Actions:
|
26
|
+
- List and explain all available control actions (shutdown, pause, resume, etc.)
|
27
|
+
- Describe how to implement custom control actions
|
28
|
+
|
29
|
+
6. Configuration:
|
30
|
+
- Detail all configuration options available for agents
|
31
|
+
- Explain how to use environment variables for configuration
|
32
|
+
|
33
|
+
7. Error Handling and Logging:
|
34
|
+
- Describe the error handling mechanisms in place
|
35
|
+
- Explain how to configure and use the logging system effectively
|
36
|
+
|
37
|
+
8. Messaging Systems:
|
38
|
+
- Provide details on both AMQP and NATS messaging systems
|
39
|
+
- Explain how to switch between different messaging backends
|
40
|
+
|
41
|
+
9. Custom Agent Implementation:
|
42
|
+
- Provide a step-by-step guide on creating a custom agent
|
43
|
+
- Explain how to define capabilities, handle requests, and send responses
|
44
|
+
|
45
|
+
10. Schema Definition:
|
46
|
+
- Explain how to define and use request and response schemas
|
47
|
+
- Provide examples of complex schema definitions
|
48
|
+
|
49
|
+
11. Performance Considerations:
|
50
|
+
- Discuss any performance optimizations in the framework
|
51
|
+
- Provide guidelines for writing efficient agents
|
52
|
+
|
53
|
+
12. Security:
|
54
|
+
- Explain any security measures in place (if any)
|
55
|
+
- Provide best practices for securing agent communications
|
56
|
+
|
57
|
+
13. Extending the Framework:
|
58
|
+
- Describe how to add new features or modify existing functionality
|
59
|
+
- Explain the plugin system (if one exists)
|
60
|
+
|
61
|
+
14. Troubleshooting:
|
62
|
+
- Provide a list of common issues and their solutions
|
63
|
+
- Explain how to debug agents effectively
|
64
|
+
|
65
|
+
15. API Reference:
|
66
|
+
- Provide a comprehensive API reference for all public methods and classes
|
data/examples/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Agent99 Framework Examples
|
2
|
+
|
3
|
+
- TODO
|
4
|
+
- Review and edit
|
5
|
+
- Add instructions for brew install rabbitmq nats-server boxes
|
6
|
+
- review example agents to see code can be tightened
|
7
|
+
|
8
|
+
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.
|
9
|
+
|
10
|
+
## Files
|
11
|
+
|
12
|
+
### 1. hello_world.rb
|
13
|
+
|
14
|
+
This file demonstrates a basic AI agent implementation using the Agent99 framework.
|
15
|
+
|
16
|
+
- Class: `HelloWorld < Agent99::Base`
|
17
|
+
- Functionality: Responds to "hello world" requests
|
18
|
+
- Key methods:
|
19
|
+
- `receive_request`: Handles incoming requests
|
20
|
+
- `validate_request`: Validates the request against a schema
|
21
|
+
- `process`: Generates the response
|
22
|
+
|
23
|
+
### 2. hello_world_client.rb
|
24
|
+
|
25
|
+
This file shows how to create a client that interacts with the HelloWorld agent.
|
26
|
+
|
27
|
+
- Class: `HelloWorldClient < Agent99::Base`
|
28
|
+
- Functionality: Sends a request to a HelloWorld agent and processes the response
|
29
|
+
- Key methods:
|
30
|
+
- `init`: Initiates the request sending process
|
31
|
+
- `send_request`: Builds and sends the request
|
32
|
+
- `receive_response`: Handles the response from the HelloWorld agent
|
33
|
+
|
34
|
+
### 3. hello_world_request.rb
|
35
|
+
|
36
|
+
This file defines the schema for HelloWorld requests using SimpleJsonSchemaBuilder.
|
37
|
+
|
38
|
+
- Class: `HelloWorldRequest < SimpleJsonSchemaBuilder::Base`
|
39
|
+
- Defines the structure of a valid HelloWorld request
|
40
|
+
|
41
|
+
### 4. registry.rb
|
42
|
+
|
43
|
+
This file implements a simple registry service for AI agents using Sinatra.
|
44
|
+
|
45
|
+
- Functionality: Allows agents to register, discover other agents, and withdraw from the registry
|
46
|
+
- Endpoints:
|
47
|
+
- GET `/healthcheck`: Returns the number of registered agents
|
48
|
+
- POST `/register`: Registers a new agent
|
49
|
+
- GET `/discover`: Discovers agents by capability
|
50
|
+
- DELETE `/withdraw/:uuid`: Withdraws an agent from the registry
|
51
|
+
- GET `/`: Lists all registered agents
|
52
|
+
|
53
|
+
## Usage
|
54
|
+
|
55
|
+
1. Start the registry service:
|
56
|
+
```
|
57
|
+
ruby registry.rb
|
58
|
+
```
|
59
|
+
|
60
|
+
2. Run the HelloWorld agent:
|
61
|
+
```
|
62
|
+
ruby hello_world.rb
|
63
|
+
```
|
64
|
+
|
65
|
+
3. Run the HelloWorld client:
|
66
|
+
```
|
67
|
+
ruby hello_world_client.rb
|
68
|
+
```
|
69
|
+
|
70
|
+
## Dependencies
|
71
|
+
|
72
|
+
- Ruby 3.3+
|
73
|
+
- Gems: json, json_schema, sinatra, bunny, securerandom
|
74
|
+
|
75
|
+
## Notes
|
76
|
+
|
77
|
+
- The framework uses modern Ruby 3.3 syntax, especially for hashes and method signatures with named parameters.
|
78
|
+
- The examples demonstrate basic usage of the Agent99 framework, including request/response handling, validation, and agent discovery.
|
79
|
+
- The registry service uses an in-memory store (AGENT_REGISTRY) for simplicity, but it's recommended to use a more robust solution like SQLite for production use.
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/hello_world.rb
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
require 'json_schema'
|
6
|
+
|
7
|
+
require_relative '../lib/agent99'
|
8
|
+
require_relative 'hello_world_request'
|
9
|
+
|
10
|
+
class HelloWorld < Agent99::Base
|
11
|
+
REQUEST_SCHEMA = HelloWorldRequest.schema
|
12
|
+
# RESPONSE_SCHEMA = Agent99::RESPONSE.schema
|
13
|
+
# ERROR_SCHEMA = Agent99::ERROR.schema
|
14
|
+
|
15
|
+
# The request is in @payload
|
16
|
+
def receive_request
|
17
|
+
send_response( validate_request || process )
|
18
|
+
end
|
19
|
+
|
20
|
+
# This method validates the incoming request and returns any errors found
|
21
|
+
# or nil if there are no errors.
|
22
|
+
# It allows for returning an array of errors.
|
23
|
+
#
|
24
|
+
# TODO: consider a 4th message type of error
|
25
|
+
#
|
26
|
+
def validate_request
|
27
|
+
responses = []
|
28
|
+
|
29
|
+
# Check if the ID matches
|
30
|
+
unless id == to_uuid
|
31
|
+
logger.error <<~ERROR
|
32
|
+
#{name} received someone else's request
|
33
|
+
id: #{id} timestamp: #{timestamp}
|
34
|
+
to_uuid: #{to_uuid}
|
35
|
+
from_uuid: #{from_uuid}
|
36
|
+
event_uuid:#{event_uuid}
|
37
|
+
ERROR
|
38
|
+
responses << {
|
39
|
+
error: "Incorrect message queue for header",
|
40
|
+
details: {
|
41
|
+
id: id,
|
42
|
+
header: header
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Validate the incoming request body against the schema
|
48
|
+
validation_errors = validate_schema
|
49
|
+
unless validation_errors.empty?
|
50
|
+
logger.error "Validation errors: #{validation_errors}"
|
51
|
+
responses << {
|
52
|
+
error: "Invalid request",
|
53
|
+
details: validation_errors
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
responses.empty? ? nil : responses
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the response value
|
61
|
+
# All response message have the same schema in that
|
62
|
+
# they have a header (all messages have headers) and
|
63
|
+
# a result element that is a String. Could it be
|
64
|
+
# a JSON string, sure but then we would need a
|
65
|
+
# RESPONSE_SCHEMA constant for the class.
|
66
|
+
def process
|
67
|
+
{
|
68
|
+
result: get(:greeting) + ' ' + get(:name)
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# As a server type, HelloWorld should never receive
|
74
|
+
# a response message.
|
75
|
+
def receive_response(response)
|
76
|
+
loger.warn("Unexpected response type message: response.inspect")
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# NOTE: what I'm thinking about here is similar to the
|
82
|
+
# prompt tool (aka function) callback facility
|
83
|
+
# where descriptive text is used to describe
|
84
|
+
# what the tool does.
|
85
|
+
#
|
86
|
+
# TODO: scale this idea back to just keywords
|
87
|
+
# until the registry program gets more
|
88
|
+
# stuff added to its discovery process.
|
89
|
+
#
|
90
|
+
def capabilities
|
91
|
+
%w[ greeter hello_world hello-world hello]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Example usage
|
96
|
+
agent = HelloWorld.new
|
97
|
+
agent.run # Starts listening for messages
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/hello_world_client.rb
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
require 'json_schema'
|
6
|
+
require 'securerandom'
|
7
|
+
require_relative '../lib/agent99'
|
8
|
+
|
9
|
+
class HelloWorldClient < Agent99::Base
|
10
|
+
def init
|
11
|
+
send_request
|
12
|
+
end
|
13
|
+
|
14
|
+
def send_request
|
15
|
+
to_uuid = discover_agent(capability: 'greeter', how_many: 1).first[:uuid]
|
16
|
+
|
17
|
+
request = build_request(
|
18
|
+
to_uuid:,
|
19
|
+
greeting: 'Hey',
|
20
|
+
name: 'MadBomber'
|
21
|
+
)
|
22
|
+
|
23
|
+
result = @message_client.publish(request)
|
24
|
+
logger.info "Sent request: #{request.inspect}; status? #{result.inspect}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_request(
|
28
|
+
to_uuid:,
|
29
|
+
greeting: 'Hello',
|
30
|
+
name: 'World'
|
31
|
+
)
|
32
|
+
|
33
|
+
{
|
34
|
+
header: {
|
35
|
+
type: 'request',
|
36
|
+
from_uuid: @id,
|
37
|
+
to_uuid:,
|
38
|
+
event_uuid: SecureRandom.uuid,
|
39
|
+
timestamp: Agent99::Timestamp.new.to_i
|
40
|
+
},
|
41
|
+
greeting:,
|
42
|
+
name:
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def receive_response
|
48
|
+
logger.info "Received response: #{payload.inspect}"
|
49
|
+
result = payload[:result]
|
50
|
+
|
51
|
+
puts
|
52
|
+
puts `echo "#{result}" | boxes -d info`
|
53
|
+
puts
|
54
|
+
|
55
|
+
exit(0)
|
56
|
+
end
|
57
|
+
|
58
|
+
#####################################################
|
59
|
+
private
|
60
|
+
|
61
|
+
def capabilities
|
62
|
+
['hello_world_client']
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Example usage
|
68
|
+
client = HelloWorldClient.new
|
69
|
+
client.run
|
70
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# examples/hello_world_request.rb
|
2
|
+
|
3
|
+
require_relative '../lib/agent99/header_schema'
|
4
|
+
|
5
|
+
class HelloWorldRequest < SimpleJsonSchemaBuilder::Base
|
6
|
+
object do
|
7
|
+
object :header, schema: Agent99::HeaderSchema
|
8
|
+
|
9
|
+
string :greeting, required: false, examples: ["Hello"]
|
10
|
+
string :name, required: true, examples: ["World"]
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/registry.rb
|
3
|
+
|
4
|
+
require 'debug_me'
|
5
|
+
include DebugMe
|
6
|
+
|
7
|
+
require 'sinatra'
|
8
|
+
require 'json'
|
9
|
+
require 'bunny'
|
10
|
+
require 'securerandom'
|
11
|
+
|
12
|
+
# In-memory registry to store agent capabilities
|
13
|
+
# Array(Hash)
|
14
|
+
# TODO: change this data store to a sqlite database
|
15
|
+
# maybe with a vector search capability.
|
16
|
+
#
|
17
|
+
AGENT_REGISTRY = []
|
18
|
+
|
19
|
+
# Health check endpoint
|
20
|
+
get '/healthcheck' do
|
21
|
+
content_type :json
|
22
|
+
{ agent_count: AGENT_REGISTRY.size }.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
# Endpoint to register an agent
|
26
|
+
post '/register' do
|
27
|
+
request.body.rewind
|
28
|
+
agent_info = JSON.parse(request.body.read, symbolize_names: true)
|
29
|
+
|
30
|
+
agent_name = agent_info[:name]
|
31
|
+
capabilities = agent_info[:capabilities]
|
32
|
+
|
33
|
+
agent_uuid = SecureRandom.uuid
|
34
|
+
|
35
|
+
AGENT_REGISTRY << agent_info.merge({uuid: agent_uuid})
|
36
|
+
|
37
|
+
status 201
|
38
|
+
content_type :json
|
39
|
+
{ uuid: agent_uuid }.to_json
|
40
|
+
end
|
41
|
+
|
42
|
+
# Endpoint to discover agents by capability
|
43
|
+
# TODO: This is a simple keyword matcher. Looking
|
44
|
+
# => for a semantic match process.
|
45
|
+
get '/discover' do
|
46
|
+
capability = params['capability']
|
47
|
+
|
48
|
+
matching_agents = AGENT_REGISTRY.select do |agent|
|
49
|
+
agent[:capabilities].include?(capability)
|
50
|
+
end
|
51
|
+
|
52
|
+
content_type :json
|
53
|
+
matching_agents.to_json
|
54
|
+
end
|
55
|
+
|
56
|
+
# Withdraw an agent from the registry
|
57
|
+
delete '/withdraw/:uuid' do
|
58
|
+
uuid = params['uuid']
|
59
|
+
how_many = AGENT_REGISTRY.size
|
60
|
+
|
61
|
+
AGENT_REGISTRY.delete_if { |agent_info| agent_info[:uuid] == uuid }
|
62
|
+
|
63
|
+
if AGENT_REGISTRY.size == how_many
|
64
|
+
status 404 # Not Found
|
65
|
+
content_type :json
|
66
|
+
{ error: "Agent with UUID #{uuid} not found." }.to_json
|
67
|
+
else
|
68
|
+
status 204 # No Content
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Display all registered agents
|
73
|
+
get '/' do
|
74
|
+
content_type :json
|
75
|
+
AGENT_REGISTRY.to_json
|
76
|
+
end
|
77
|
+
|
78
|
+
# Start the Sinatra server
|
79
|
+
if __FILE__ == $PROGRAM_NAME
|
80
|
+
Sinatra::Application.run!
|
81
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Start the registry server
|
4
|
+
echo "Starting registry server..."
|
5
|
+
# Assuming the registry server is a separate process, replace with actual command
|
6
|
+
# e.g., ruby registry_server.rb &
|
7
|
+
# Replace 'registry_server_command' with the actual command to start your registry server
|
8
|
+
# Example: ruby registry_server.rb &
|
9
|
+
./registry.rb &
|
10
|
+
|
11
|
+
# Start the HelloWorld agent
|
12
|
+
echo "Starting HelloWorld agent..."
|
13
|
+
./hello_world.rb &
|
14
|
+
|
15
|
+
# Start the HelloWorldClient agent
|
16
|
+
echo "Starting HelloWorldClient agent..."
|
17
|
+
./hello_world_client.rb &
|
18
|
+
|
19
|
+
# Wait for all background processes to finish
|
20
|
+
wait
|
data/lib/agent99/.irbrc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# lib/agent99/agent_discovery.rb
|
2
|
+
|
3
|
+
module Agent99::AgentDiscovery
|
4
|
+
|
5
|
+
# Returns the agent's capabilities (to be overridden by subclasses).
|
6
|
+
#
|
7
|
+
# @return [Array<String>] The agent's capabilities
|
8
|
+
#
|
9
|
+
def capabilities
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
################################################
|
15
|
+
private
|
16
|
+
|
17
|
+
# Discovers other agents with a specific capability.
|
18
|
+
#
|
19
|
+
# @param capability [String] The capability to search for
|
20
|
+
# @param how_many [Integer] The number of agents to return
|
21
|
+
# @param all [Boolean] Whether to return all matching agents
|
22
|
+
# @return [Array<Hash>] The discovered agents
|
23
|
+
# @raise [RuntimeError] If no agents are found
|
24
|
+
#
|
25
|
+
def discover_agent(capability:, how_many: 1, all: false)
|
26
|
+
result = @registry_client.discover(capability:)
|
27
|
+
|
28
|
+
if result.empty?
|
29
|
+
logger.error "No agents found for capability: #{capability}"
|
30
|
+
raise "No agents available"
|
31
|
+
end
|
32
|
+
|
33
|
+
all ? result : result.sample(how_many)
|
34
|
+
end
|
35
|
+
end
|