traia-iatp 0.1.1__py3-none-any.whl
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.
Potentially problematic release.
This version of traia-iatp might be problematic. Click here for more details.
- traia_iatp/README.md +368 -0
- traia_iatp/__init__.py +30 -0
- traia_iatp/cli/__init__.py +5 -0
- traia_iatp/cli/main.py +483 -0
- traia_iatp/client/__init__.py +10 -0
- traia_iatp/client/a2a_client.py +274 -0
- traia_iatp/client/crewai_a2a_tools.py +335 -0
- traia_iatp/client/grpc_a2a_tools.py +349 -0
- traia_iatp/client/root_path_a2a_client.py +1 -0
- traia_iatp/core/__init__.py +43 -0
- traia_iatp/core/models.py +161 -0
- traia_iatp/mcp/__init__.py +15 -0
- traia_iatp/mcp/client.py +201 -0
- traia_iatp/mcp/mcp_agent_template.py +422 -0
- traia_iatp/mcp/templates/Dockerfile.j2 +56 -0
- traia_iatp/mcp/templates/README.md.j2 +212 -0
- traia_iatp/mcp/templates/cursor-rules.md.j2 +326 -0
- traia_iatp/mcp/templates/deployment_params.json.j2 +20 -0
- traia_iatp/mcp/templates/docker-compose.yml.j2 +23 -0
- traia_iatp/mcp/templates/dockerignore.j2 +47 -0
- traia_iatp/mcp/templates/gitignore.j2 +77 -0
- traia_iatp/mcp/templates/mcp_health_check.py.j2 +150 -0
- traia_iatp/mcp/templates/pyproject.toml.j2 +26 -0
- traia_iatp/mcp/templates/run_local_docker.sh.j2 +94 -0
- traia_iatp/mcp/templates/server.py.j2 +240 -0
- traia_iatp/mcp/traia_mcp_adapter.py +381 -0
- traia_iatp/preview_diagrams.html +181 -0
- traia_iatp/registry/__init__.py +26 -0
- traia_iatp/registry/atlas_search_indexes.json +280 -0
- traia_iatp/registry/embeddings.py +298 -0
- traia_iatp/registry/iatp_search_api.py +839 -0
- traia_iatp/registry/mongodb_registry.py +771 -0
- traia_iatp/registry/readmes/ATLAS_SEARCH_INDEXES.md +252 -0
- traia_iatp/registry/readmes/ATLAS_SEARCH_SETUP.md +134 -0
- traia_iatp/registry/readmes/AUTHENTICATION_UPDATE.md +124 -0
- traia_iatp/registry/readmes/EMBEDDINGS_SETUP.md +172 -0
- traia_iatp/registry/readmes/IATP_SEARCH_API_GUIDE.md +257 -0
- traia_iatp/registry/readmes/MONGODB_X509_AUTH.md +208 -0
- traia_iatp/registry/readmes/README.md +251 -0
- traia_iatp/registry/readmes/REFACTORING_SUMMARY.md +191 -0
- traia_iatp/server/__init__.py +15 -0
- traia_iatp/server/a2a_server.py +215 -0
- traia_iatp/server/example_template_usage.py +72 -0
- traia_iatp/server/iatp_server_agent_generator.py +237 -0
- traia_iatp/server/iatp_server_template_generator.py +235 -0
- traia_iatp/server/templates/Dockerfile.j2 +49 -0
- traia_iatp/server/templates/README.md +137 -0
- traia_iatp/server/templates/README.md.j2 +425 -0
- traia_iatp/server/templates/__init__.py +1 -0
- traia_iatp/server/templates/__main__.py.j2 +450 -0
- traia_iatp/server/templates/agent.py.j2 +80 -0
- traia_iatp/server/templates/agent_config.json.j2 +22 -0
- traia_iatp/server/templates/agent_executor.py.j2 +264 -0
- traia_iatp/server/templates/docker-compose.yml.j2 +23 -0
- traia_iatp/server/templates/env.example.j2 +67 -0
- traia_iatp/server/templates/gitignore.j2 +78 -0
- traia_iatp/server/templates/grpc_server.py.j2 +218 -0
- traia_iatp/server/templates/pyproject.toml.j2 +76 -0
- traia_iatp/server/templates/run_local_docker.sh.j2 +103 -0
- traia_iatp/server/templates/server.py.j2 +190 -0
- traia_iatp/special_agencies/__init__.py +4 -0
- traia_iatp/special_agencies/registry_search_agency.py +392 -0
- traia_iatp/utils/__init__.py +10 -0
- traia_iatp/utils/docker_utils.py +251 -0
- traia_iatp/utils/general.py +64 -0
- traia_iatp/utils/iatp_utils.py +126 -0
- traia_iatp-0.1.1.dist-info/METADATA +414 -0
- traia_iatp-0.1.1.dist-info/RECORD +72 -0
- traia_iatp-0.1.1.dist-info/WHEEL +5 -0
- traia_iatp-0.1.1.dist-info/entry_points.txt +2 -0
- traia_iatp-0.1.1.dist-info/licenses/LICENSE +21 -0
- traia_iatp-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Registry and Search API Refactoring Summary
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This refactoring separates the concerns between registry management (write operations) and search/query operations (read operations) to eliminate duplication and improve maintainability.
|
|
6
|
+
|
|
7
|
+
## Changes Made
|
|
8
|
+
|
|
9
|
+
### 1. `mongodb_registry.py` - Write Operations Only
|
|
10
|
+
|
|
11
|
+
**Removed Methods:**
|
|
12
|
+
- `query_agents()` - Moved to search API
|
|
13
|
+
- `atlas_search()` - Moved to search API
|
|
14
|
+
- `vector_search()` - Moved to search API
|
|
15
|
+
- `vector_search_text()` - Moved to search API
|
|
16
|
+
- `query_mcp_servers()` - Moved to search API
|
|
17
|
+
- `atlas_search()` (MCP) - Moved to search API
|
|
18
|
+
- `vector_search()` (MCP) - Moved to search API
|
|
19
|
+
- `vector_search_text()` (MCP) - Moved to search API
|
|
20
|
+
|
|
21
|
+
**Kept Methods:**
|
|
22
|
+
- `add_utility_agent()` - Registry management
|
|
23
|
+
- `update_health_status()` - Registry management
|
|
24
|
+
- `update_agent_base_url()` - Registry management
|
|
25
|
+
- `add_tags()` - Registry management
|
|
26
|
+
- `remove_agent()` - Registry management
|
|
27
|
+
- `update_utility_agent()` - Registry management
|
|
28
|
+
- `get_statistics()` - Registry statistics (read but specific to registry)
|
|
29
|
+
- `add_mcp_server()` - Registry management
|
|
30
|
+
- `get_mcp_server()` - Simple lookup (kept for backward compatibility)
|
|
31
|
+
|
|
32
|
+
**Updated Documentation:**
|
|
33
|
+
- Updated module docstring to clarify write-only purpose
|
|
34
|
+
- Updated class docstrings to indicate write operations only
|
|
35
|
+
- Added references to `iatp_search_api.py` for search operations
|
|
36
|
+
|
|
37
|
+
### 2. `iatp_search_api.py` - Search and Query Operations
|
|
38
|
+
|
|
39
|
+
**Existing Methods (Unchanged):**
|
|
40
|
+
- `find_utility_agent()` - Search by name, capability, tag, or query
|
|
41
|
+
- `list_utility_agents()` - List agents with filters
|
|
42
|
+
- `search_utility_agents()` - Vector search for agents
|
|
43
|
+
- `find_mcp_server()` - Search MCP servers
|
|
44
|
+
- `list_mcp_servers()` - List MCP servers
|
|
45
|
+
- `search_mcp_servers()` - Vector search for MCP servers
|
|
46
|
+
- `get_mcp_server()` - Get MCP server by name
|
|
47
|
+
|
|
48
|
+
**Features:**
|
|
49
|
+
- Atlas Search integration
|
|
50
|
+
- Vector search with embeddings
|
|
51
|
+
- Fallback to Atlas Search when vector search fails
|
|
52
|
+
- Read-only operations (no MongoDB write access needed)
|
|
53
|
+
- Cached connections for better performance
|
|
54
|
+
|
|
55
|
+
### 3. Updated Test Files
|
|
56
|
+
|
|
57
|
+
**`test_discovery_and_usage.py`:**
|
|
58
|
+
- Updated imports to use `iatp_search_api` instead of `mongodb_registry`
|
|
59
|
+
- Modified `discover_hyperliquid_agent()` to use `search_utility_agents()`
|
|
60
|
+
- Updated `create_tools_from_discovered_agent()` to work with `UtilityAgentInfo` structure
|
|
61
|
+
- Removed registry connection management
|
|
62
|
+
|
|
63
|
+
**`test_refactoring.py`:**
|
|
64
|
+
- New test script to verify refactoring works correctly
|
|
65
|
+
- Tests registry write operations
|
|
66
|
+
- Tests search API operations
|
|
67
|
+
- Tests discovery test imports
|
|
68
|
+
|
|
69
|
+
## Benefits
|
|
70
|
+
|
|
71
|
+
### 1. Clear Separation of Concerns
|
|
72
|
+
- **Registry**: Handles data persistence and lifecycle management
|
|
73
|
+
- **Search API**: Handles discovery and querying
|
|
74
|
+
|
|
75
|
+
### 2. Reduced Duplication
|
|
76
|
+
- Eliminated duplicate search methods between files
|
|
77
|
+
- Single source of truth for search logic
|
|
78
|
+
|
|
79
|
+
### 3. Better Performance
|
|
80
|
+
- Search API uses read-only connections
|
|
81
|
+
- Cached connections for repeated queries
|
|
82
|
+
- Optimized for search operations
|
|
83
|
+
|
|
84
|
+
### 4. Improved Maintainability
|
|
85
|
+
- Easier to modify search logic in one place
|
|
86
|
+
- Clearer responsibilities for each module
|
|
87
|
+
- Better testability
|
|
88
|
+
|
|
89
|
+
### 5. Enhanced Security
|
|
90
|
+
- Search API can use read-only credentials
|
|
91
|
+
- Registry operations require write permissions
|
|
92
|
+
- Reduced attack surface
|
|
93
|
+
|
|
94
|
+
## Usage Examples
|
|
95
|
+
|
|
96
|
+
### Registry Operations (Write)
|
|
97
|
+
```python
|
|
98
|
+
from iatp.registry.mongodb_registry import UtilityAgentRegistry
|
|
99
|
+
|
|
100
|
+
# Add new agent
|
|
101
|
+
registry = UtilityAgentRegistry()
|
|
102
|
+
await registry.add_utility_agent(agent, tags=["trading", "hyperliquid"])
|
|
103
|
+
|
|
104
|
+
# Update agent
|
|
105
|
+
await registry.update_health_status(agent_id, is_healthy=True)
|
|
106
|
+
await registry.update_agent_base_url(agent_id, new_url)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Search Operations (Read)
|
|
110
|
+
```python
|
|
111
|
+
from iatp.registry.iatp_search_api import search_utility_agents, find_utility_agent
|
|
112
|
+
|
|
113
|
+
# Search for agents
|
|
114
|
+
agents = await search_utility_agents("hyperliquid trading", limit=5)
|
|
115
|
+
|
|
116
|
+
# Find specific agent
|
|
117
|
+
agent = find_utility_agent(capability="market_data")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Discovery Test
|
|
121
|
+
```python
|
|
122
|
+
# The discovery test now uses the search API
|
|
123
|
+
from iatp.registry.iatp_search_api import search_utility_agents
|
|
124
|
+
|
|
125
|
+
# Search for Hyperliquid agent
|
|
126
|
+
search_results = await search_utility_agents(
|
|
127
|
+
query="hyperliquid trading",
|
|
128
|
+
limit=5,
|
|
129
|
+
active_only=True
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Migration Guide
|
|
134
|
+
|
|
135
|
+
### For Existing Code
|
|
136
|
+
|
|
137
|
+
1. **If using registry for search/query:**
|
|
138
|
+
```python
|
|
139
|
+
# OLD
|
|
140
|
+
from iatp.registry.mongodb_registry import UtilityAgentRegistry
|
|
141
|
+
registry = UtilityAgentRegistry()
|
|
142
|
+
agents = await registry.query_agents(query="trading")
|
|
143
|
+
|
|
144
|
+
# NEW
|
|
145
|
+
from iatp.registry.iatp_search_api import search_utility_agents
|
|
146
|
+
agents = await search_utility_agents("trading")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
2. **If using registry for write operations:**
|
|
150
|
+
```python
|
|
151
|
+
# No changes needed - these methods are still available
|
|
152
|
+
from iatp.registry.mongodb_registry import UtilityAgentRegistry
|
|
153
|
+
registry = UtilityAgentRegistry()
|
|
154
|
+
await registry.add_utility_agent(agent)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Environment Variables
|
|
158
|
+
|
|
159
|
+
No changes to environment variables are required. Both modules use the same authentication methods:
|
|
160
|
+
- `MONGODB_CONNECTION_STRING`
|
|
161
|
+
- `MONGODB_USER` + `MONGODB_PASSWORD`
|
|
162
|
+
- `MONGODB_X509_CERT_FILE`
|
|
163
|
+
|
|
164
|
+
## Testing
|
|
165
|
+
|
|
166
|
+
Run the refactoring test to verify everything works:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
cd traia-centralized-backend
|
|
170
|
+
python test_refactoring.py
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
This will test:
|
|
174
|
+
- Registry write operations
|
|
175
|
+
- Search API operations
|
|
176
|
+
- Discovery test imports
|
|
177
|
+
|
|
178
|
+
## Future Improvements
|
|
179
|
+
|
|
180
|
+
1. **Connection Pooling**: Implement connection pooling for better performance
|
|
181
|
+
2. **Caching**: Add Redis caching for frequently accessed data
|
|
182
|
+
3. **Rate Limiting**: Add rate limiting for search operations
|
|
183
|
+
4. **Metrics**: Add metrics collection for search performance
|
|
184
|
+
5. **API Versioning**: Consider API versioning for future changes
|
|
185
|
+
|
|
186
|
+
## Backward Compatibility
|
|
187
|
+
|
|
188
|
+
- All existing registry write operations remain unchanged
|
|
189
|
+
- Search operations now use the dedicated search API
|
|
190
|
+
- No breaking changes to existing functionality
|
|
191
|
+
- Clear migration path provided
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""IATP server module for creating A2A servers from utility agents."""
|
|
2
|
+
|
|
3
|
+
from .a2a_server import (
|
|
4
|
+
UtilityAgencyExecutor,
|
|
5
|
+
create_a2a_server,
|
|
6
|
+
create_and_start_a2a_server
|
|
7
|
+
)
|
|
8
|
+
from .iatp_server_agent_generator import IATPServerAgentGenerator
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"UtilityAgencyExecutor",
|
|
12
|
+
"IATPServerAgentGenerator",
|
|
13
|
+
"create_a2a_server",
|
|
14
|
+
"create_and_start_a2a_server",
|
|
15
|
+
]
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""A2A server implementation for utility agencies using the official a2a-sdk."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Dict, Any, Optional, List
|
|
6
|
+
from a2a.server.apps import A2AStarletteApplication
|
|
7
|
+
from a2a.server.agent_execution import AgentExecutor, RequestContext
|
|
8
|
+
from a2a.server.events.event_queue import EventQueue
|
|
9
|
+
from a2a.server.tasks import InMemoryTaskStore
|
|
10
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
11
|
+
from a2a.types import AgentCard, AgentSkill, AgentCapabilities
|
|
12
|
+
from a2a.utils import new_agent_text_message, new_text_artifact
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
import uvicorn
|
|
15
|
+
|
|
16
|
+
from ..core.models import UtilityAgent
|
|
17
|
+
from .iatp_server_agent_generator import IATPServerAgentGenerator
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UtilityAgencyExecutor(AgentExecutor):
|
|
23
|
+
"""Agent executor that wraps a utility agency and executes tasks via CrewAI."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, agency: UtilityAgent, agency_generator: IATPServerAgentGenerator):
|
|
26
|
+
self.agency = agency
|
|
27
|
+
self.agency_generator = agency_generator
|
|
28
|
+
self._crew = None
|
|
29
|
+
|
|
30
|
+
async def _get_crew(self):
|
|
31
|
+
"""Lazily build the crew from agency config."""
|
|
32
|
+
if self._crew is None:
|
|
33
|
+
self._crew = await self.agency_generator.build_crew_from_agency(self.agency)
|
|
34
|
+
return self._crew
|
|
35
|
+
|
|
36
|
+
async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
|
|
37
|
+
"""Execute a task using the utility agency crew."""
|
|
38
|
+
try:
|
|
39
|
+
# Get the user's request from context
|
|
40
|
+
user_message = context.get_last_user_message()
|
|
41
|
+
if not user_message:
|
|
42
|
+
event_queue.enqueue_event(
|
|
43
|
+
new_agent_text_message("No user message provided")
|
|
44
|
+
)
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
# Extract text from message parts
|
|
48
|
+
user_text = ""
|
|
49
|
+
for part in user_message.parts:
|
|
50
|
+
if hasattr(part, 'text'):
|
|
51
|
+
user_text += part.text
|
|
52
|
+
|
|
53
|
+
if not user_text:
|
|
54
|
+
event_queue.enqueue_event(
|
|
55
|
+
new_agent_text_message("No text content in user message")
|
|
56
|
+
)
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
# Build crew and execute
|
|
60
|
+
crew = await self._get_crew()
|
|
61
|
+
|
|
62
|
+
# Run the crew with the request
|
|
63
|
+
result = crew.kickoff(inputs={"request": user_text})
|
|
64
|
+
|
|
65
|
+
# Send the result as agent message
|
|
66
|
+
event_queue.enqueue_event(
|
|
67
|
+
new_agent_text_message(str(result))
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
logger.error(f"Error executing task: {e}")
|
|
72
|
+
event_queue.enqueue_event(
|
|
73
|
+
new_agent_text_message(f"Error processing request: {str(e)}")
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class MCPToolExecutor(AgentExecutor):
|
|
78
|
+
"""Agent executor for individual MCP tool execution."""
|
|
79
|
+
|
|
80
|
+
def __init__(self, agency: UtilityAgent, tool_name: str):
|
|
81
|
+
self.agency = agency
|
|
82
|
+
self.tool_name = tool_name
|
|
83
|
+
|
|
84
|
+
async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
|
|
85
|
+
"""Execute a specific MCP tool."""
|
|
86
|
+
try:
|
|
87
|
+
from ..mcp.client import MCPClient
|
|
88
|
+
|
|
89
|
+
# Get tool arguments from context
|
|
90
|
+
user_message = context.get_last_user_message()
|
|
91
|
+
if not user_message:
|
|
92
|
+
event_queue.enqueue_event(
|
|
93
|
+
new_agent_text_message("No arguments provided")
|
|
94
|
+
)
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
# Extract arguments (assuming they're passed as JSON in text)
|
|
98
|
+
import json
|
|
99
|
+
arguments = {}
|
|
100
|
+
for part in user_message.parts:
|
|
101
|
+
if hasattr(part, 'text'):
|
|
102
|
+
try:
|
|
103
|
+
arguments = json.loads(part.text)
|
|
104
|
+
except:
|
|
105
|
+
arguments = {"query": part.text} # Fallback to simple text
|
|
106
|
+
|
|
107
|
+
# Connect to MCP server and execute tool
|
|
108
|
+
mcp_client = MCPClient(self.agency.mcp_server)
|
|
109
|
+
await mcp_client.connect()
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
result = await mcp_client.call_tool(self.tool_name, arguments)
|
|
113
|
+
event_queue.enqueue_event(
|
|
114
|
+
new_agent_text_message(str(result))
|
|
115
|
+
)
|
|
116
|
+
finally:
|
|
117
|
+
await mcp_client.disconnect()
|
|
118
|
+
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.error(f"Error executing MCP tool {self.tool_name}: {e}")
|
|
121
|
+
event_queue.enqueue_event(
|
|
122
|
+
new_agent_text_message(f"Error executing tool: {str(e)}")
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def create_a2a_server(
|
|
127
|
+
agency: UtilityAgent,
|
|
128
|
+
agency_generator: IATPServerAgentGenerator,
|
|
129
|
+
host: str = "0.0.0.0",
|
|
130
|
+
port: int = 8000
|
|
131
|
+
) -> A2AStarletteApplication:
|
|
132
|
+
"""Create an A2A server for a utility agency."""
|
|
133
|
+
|
|
134
|
+
# Create skills from agency capabilities
|
|
135
|
+
skills = []
|
|
136
|
+
|
|
137
|
+
# Add main processing skill
|
|
138
|
+
main_skill = AgentSkill(
|
|
139
|
+
id="process_request",
|
|
140
|
+
name=f"Process request using {agency.name}",
|
|
141
|
+
description=f"Process a request using {agency.name} capabilities. {agency.description}",
|
|
142
|
+
examples=[
|
|
143
|
+
f"Help me with {cap}" for cap in agency.mcp_server.capabilities[:2]
|
|
144
|
+
] if agency.mcp_server.capabilities else ["Process this request for me"]
|
|
145
|
+
)
|
|
146
|
+
skills.append(main_skill)
|
|
147
|
+
|
|
148
|
+
# Add individual MCP tool skills
|
|
149
|
+
for capability in agency.mcp_server.capabilities:
|
|
150
|
+
skill = AgentSkill(
|
|
151
|
+
id=f"mcp_{capability}",
|
|
152
|
+
name=f"Execute {capability}",
|
|
153
|
+
description=f"Execute {capability} tool on MCP server",
|
|
154
|
+
examples=[f"Run {capability} with these parameters"]
|
|
155
|
+
)
|
|
156
|
+
skills.append(skill)
|
|
157
|
+
|
|
158
|
+
# Create capabilities
|
|
159
|
+
capabilities = AgentCapabilities(
|
|
160
|
+
streaming=False, # Not implementing streaming for now
|
|
161
|
+
pushNotifications=False, # Not implementing push notifications
|
|
162
|
+
stateTransitionHistory=False
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Create agent card
|
|
166
|
+
agent_card = AgentCard(
|
|
167
|
+
name=agency.name.replace(" ", "_").lower(),
|
|
168
|
+
description=agency.description,
|
|
169
|
+
url=f"http://{host}:{port}",
|
|
170
|
+
version="1.0.0",
|
|
171
|
+
capabilities=capabilities,
|
|
172
|
+
skills=skills,
|
|
173
|
+
# TODO: Add authentication when AgentAuthentication is available
|
|
174
|
+
# authentication=AgentAuthentication(schemes=["Bearer"]) if agency.auth_type else None
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Create executor mapping
|
|
178
|
+
executors = {
|
|
179
|
+
"process_request": UtilityAgencyExecutor(agency, agency_generator)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Add MCP tool executors
|
|
183
|
+
for capability in agency.mcp_server.capabilities:
|
|
184
|
+
executors[f"mcp_{capability}"] = MCPToolExecutor(agency, capability)
|
|
185
|
+
|
|
186
|
+
# Create task store and request handler
|
|
187
|
+
task_store = InMemoryTaskStore()
|
|
188
|
+
request_handler = DefaultRequestHandler(
|
|
189
|
+
agent_card=agent_card,
|
|
190
|
+
executors=executors,
|
|
191
|
+
task_store=task_store
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Create the A2A application
|
|
195
|
+
app = A2AStarletteApplication(
|
|
196
|
+
agent_card=agent_card,
|
|
197
|
+
request_handler=request_handler
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return app
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
async def create_and_start_a2a_server(
|
|
204
|
+
agency: UtilityAgent,
|
|
205
|
+
agency_generator: IATPServerAgentGenerator,
|
|
206
|
+
host: str = "0.0.0.0",
|
|
207
|
+
port: int = 8000
|
|
208
|
+
):
|
|
209
|
+
"""Create and start an A2A server for a utility agency."""
|
|
210
|
+
app = create_a2a_server(agency, agency_generator, host, port)
|
|
211
|
+
|
|
212
|
+
logger.info(f"Starting A2A server for {agency.name} on {host}:{port}")
|
|
213
|
+
config = uvicorn.Config(app, host=host, port=port, log_level="info")
|
|
214
|
+
server = uvicorn.Server(config)
|
|
215
|
+
await server.serve()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Example usage of the utility agent template generator.
|
|
2
|
+
|
|
3
|
+
This script demonstrates how to generate a utility agent from an MCP server.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from ..core.models import MCPServer, MCPServerType
|
|
8
|
+
from .iatp_server_agent_generator import IATPServerAgentGenerator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
"""Example of generating a utility agent."""
|
|
13
|
+
|
|
14
|
+
# Create an MCP server specification
|
|
15
|
+
mcp_server = MCPServer(
|
|
16
|
+
id="hyperliquid-mcp-001",
|
|
17
|
+
name="hyperliquid-mcp",
|
|
18
|
+
url="http://localhost:3000/mcp",
|
|
19
|
+
server_type=MCPServerType.STREAMABLE_HTTP,
|
|
20
|
+
description="Implements comprehensive trading tools for Hyperliquid L1",
|
|
21
|
+
capabilities=[
|
|
22
|
+
"market_data",
|
|
23
|
+
"place_order",
|
|
24
|
+
"cancel_order",
|
|
25
|
+
"get_positions",
|
|
26
|
+
"get_account_info"
|
|
27
|
+
],
|
|
28
|
+
metadata={
|
|
29
|
+
"version": "1.0.0",
|
|
30
|
+
"author": "Traia"
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Create the generator
|
|
35
|
+
generator = IATPServerAgentGenerator(
|
|
36
|
+
output_base_dir=Path("generated_agents")
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Generate the utility agent
|
|
40
|
+
agent = generator.generate_agent(
|
|
41
|
+
mcp_server=mcp_server,
|
|
42
|
+
agent_name="Hyperliquid Trading",
|
|
43
|
+
agent_id="hyperliquid-mcp-traia-utility-agent",
|
|
44
|
+
agent_description="A utility agent that exposes Hyperliquid trading capabilities via A2A protocol",
|
|
45
|
+
expose_individual_tools=False, # Just expose one main skill
|
|
46
|
+
auth_required=False,
|
|
47
|
+
use_simple_server=True, # Use the simplified server template
|
|
48
|
+
skill_examples=[
|
|
49
|
+
"Get current market data for ETH-USD",
|
|
50
|
+
"Place a limit order to buy 1 ETH at $3000",
|
|
51
|
+
"Show my current positions",
|
|
52
|
+
"Cancel order with ID 12345",
|
|
53
|
+
"Get my account balance and margin"
|
|
54
|
+
]
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
print(f"Generated utility agent: {agent.name}")
|
|
58
|
+
print(f"ID: {agent.id}")
|
|
59
|
+
print(f"Status: {agent.status}")
|
|
60
|
+
print(f"Code path: {agent.code_path}")
|
|
61
|
+
print(f"Capabilities: {agent.capabilities}")
|
|
62
|
+
|
|
63
|
+
# The generated agent can now be:
|
|
64
|
+
# 1. Pushed to GitHub using push_agency_to_repo
|
|
65
|
+
# 2. Deployed to Cloud Run using cloudrun_deployer
|
|
66
|
+
# 3. Registered in MongoDB for discovery
|
|
67
|
+
|
|
68
|
+
return agent
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if __name__ == "__main__":
|
|
72
|
+
main()
|