新增16个AI技能:包含图像生成、视频剪辑、数据分析、智能查询等功能模块

This commit is contained in:
hmo
2026-02-13 20:18:38 +08:00
parent 456cd45de4
commit 8200a17176
154 changed files with 14585 additions and 1 deletions

View File

@@ -0,0 +1,189 @@
# UniAgent - 统一智能体协议适配层
"Connect Any Agent, Any Protocol"
一套 API 调用所有 Agent 协议ANP/MCP/A2A/AITP/LMOS/Agent Protocol
## 一键部署
```bash
# 1. 运行安装脚本
./setup.sh
# 2. 开始使用
python scripts/uni_cli.py list
```
## 使用方式
### 调用 Agent
```bash
# Agent ID 格式: <name>@<protocol>
# ANP - 去中心化 Agent 网络
python scripts/uni_cli.py call amap@anp maps_weather '{"city":"北京"}'
python scripts/uni_cli.py call amap@anp maps_text_search '{"keywords":"咖啡厅","city":"上海"}'
# MCP - LLM 工具调用 (需配置)
python scripts/uni_cli.py call filesystem@mcp read_file '{"path":"/tmp/a.txt"}'
# A2A - Google Agent 协作 (需配置)
python scripts/uni_cli.py call assistant@a2a tasks/send '{"message":{"role":"user","content":"hello"}}'
# AITP - NEAR 交互交易 (需配置)
python scripts/uni_cli.py call shop@aitp message '{"content":"我要买咖啡"}'
# Agent Protocol - REST API (需配置)
python scripts/uni_cli.py call autogpt@ap create_task '{"input":"写一个hello world"}'
# LMOS - 企业级 Agent (需配置)
python scripts/uni_cli.py call sales@lmos invoke '{"capability":"sales","input":{}}'
```
### 查看 Agent 方法
```bash
python scripts/uni_cli.py methods amap@anp
```
### 发现 Agent
```bash
python scripts/uni_cli.py discover weather
```
### 列出已注册 Agent
```bash
python scripts/uni_cli.py list
```
## 支持的协议
| 协议 | 状态 | 说明 |
|------|------|------|
| **ANP** | ✅ 已实现 | Agent Network Protocol - 去中心化身份 + Agent 网络 |
| **MCP** | ✅ 已实现 | Model Context Protocol - LLM 工具调用 |
| **A2A** | ✅ 已实现 | Agent-to-Agent - Google 的 Agent 间协作协议 |
| **AITP** | ✅ 已实现 | Agent Interaction & Transaction - 交互 + 交易 |
| **Agent Protocol** | ✅ 已实现 | AI Engineer Foundation REST API 标准 |
| **LMOS** | ✅ 已实现 | Language Model OS - Eclipse 企业级 Agent 平台 |
## 内置 ANP Agent
| ID | 名称 | 功能 |
|----|------|------|
| amap@anp | 高德地图 | 地点搜索、路线规划、天气查询 |
| kuaidi@anp | 快递查询 | 快递单号追踪 |
| hotel@anp | 酒店预订 | 搜索酒店、查询房价 |
| juhe@anp | 聚合查询 | 多种生活服务 |
| navigation@anp | Agent导航 | 发现更多 Agent |
## 添加自定义 Agent
编辑 `config/agents.yaml`:
```yaml
agents:
# ANP Agent
- id: my_agent
protocol: anp
name: 我的 Agent
ad_url: https://example.com/ad.json
# MCP Server
- id: filesystem
protocol: mcp
name: 文件系统
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
# A2A Agent
- id: assistant
protocol: a2a
name: AI Assistant
endpoint: https://example.com/.well-known/agent.json
auth:
type: api_key
api_key: "${A2A_API_KEY}"
# AITP Agent
- id: shop
protocol: aitp
name: NEAR Shop
endpoint: https://shop.near.ai/api
wallet:
type: near
account_id: "${NEAR_ACCOUNT_ID}"
# Agent Protocol
- id: autogpt
protocol: agent_protocol # 或 ap
name: AutoGPT
endpoint: http://localhost:8000
# LMOS Agent
- id: sales
protocol: lmos
name: 销售 Agent
endpoint: http://sales.internal:8080
```
## 架构设计
```
┌─────────────────────────────────────────────────────────┐
│ UniAgent │
│ 统一调用接口 │
├─────────────────────────────────────────────────────────┤
│ call(agent_id, method, params) -> result │
└────────────────────────┬────────────────────────────────┘
┌──────────┴──────────┐
│ Protocol Router │
└──────────┬──────────┘
┌─────────┬───────────┼───────────┬─────────┬─────────┐
▼ ▼ ▼ ▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ ANP │ │ MCP │ │ A2A │ │ AITP │ │ AP │ │ LMOS │
└──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘
```
## 目录结构
```
uni-agent/
├── README.md
├── SKILL.md # AI 助手技能描述
├── setup.sh # 一键安装
├── requirements.txt
├── config/
│ ├── agents.yaml # Agent 注册表
│ └── .gitignore
├── adapters/
│ ├── __init__.py # 适配器注册
│ ├── base.py # 适配器基类
│ ├── anp.py # ANP 适配器
│ ├── mcp.py # MCP 适配器
│ ├── a2a.py # A2A 适配器
│ ├── aitp.py # AITP 适配器
│ ├── agent_protocol.py # Agent Protocol 适配器
│ └── lmos.py # LMOS 适配器
└── scripts/
└── uni_cli.py # CLI 工具
```
## 扩展新协议
1. 创建 `adapters/new_protocol.py`
2. 继承 `ProtocolAdapter` 基类
3. 实现 `connect``call``discover``close` 方法
4.`adapters/__init__.py` 注册
详见 [SKILL.md](SKILL.md)
## License
MIT

View File

@@ -0,0 +1,279 @@
---
name: uni-agent
description: 统一智能体协议适配层。一套 API 调用所有 Agent 协议ANP/MCP/A2A/AITP 等)。当用户需要调用 Agent、跨协议通信、连接工具时触发此技能。
---
# UniAgent - 统一智能体协议适配层
"Connect Any Agent, Any Protocol"
## 设计理念
### 问题
当前 Agent 协议生态割裂:
- **MCP**Anthropic 的工具调用协议
- **A2A**Google 的 Agent 间协作协议
- **ANP**:去中心化身份 + Agent 网络协议
- **AITP**NEAR 的交互交易协议
- ...
开发者需要为每个协议学习不同的 SDK、实现不同的调用逻辑。
### 解决方案
UniAgent 提供统一抽象层,一套 API 适配所有协议:
```python
from uni_agent import UniAgent
agent = UniAgent()
# 调用 ANP Agent
agent.call("amap@anp", "maps_weather", {"city": "北京"})
# 调用 MCP Server
agent.call("filesystem@mcp", "read_file", {"path": "/tmp/a.txt"})
# 调用 A2A Agent
agent.call("assistant@a2a", "chat", {"message": "hello"})
# 调用 AITP Agent带支付
agent.call("shop@aitp", "purchase", {"item": "coffee", "amount": 10})
```
## 架构设计
```
┌─────────────────────────────────────────────────────────┐
│ UniAgent │
│ 统一调用接口 │
├─────────────────────────────────────────────────────────┤
│ call(agent_id, method, params) -> result │
│ discover(capability) -> List[Agent] │
│ connect(agent_id) -> Connection │
└────────────────────────┬────────────────────────────────┘
┌──────────┴──────────┐
│ Protocol Router │
│ 协议路由 & 适配 │
└──────────┬──────────┘
┌─────────┬───────────┼───────────┬─────────┐
▼ ▼ ▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ ANP │ │ MCP │ │ A2A │ │ AITP │ │ ... │
│Adapter│ │Adapter│ │Adapter│ │Adapter│ │Adapter│
└──────┘ └──────┘ └──────┘ └──────┘ └──────┘
```
## 核心概念
### 1. Agent ID 格式
```
<agent_name>@<protocol>
示例:
- amap@anp # ANP 协议的高德地图 Agent
- filesystem@mcp # MCP 协议的文件系统 Server
- gemini@a2a # A2A 协议的 Gemini Agent
- shop@aitp # AITP 协议的商店 Agent
```
### 2. 统一调用接口
```python
result = agent.call(
agent_id="amap@anp", # Agent 标识
method="maps_weather", # 方法名
params={"city": "北京"}, # 参数
timeout=30 # 可选超时
)
```
### 3. 能力发现
```python
# 发现所有能提供天气服务的 Agent
agents = agent.discover("weather")
# 返回: [
# {"id": "amap@anp", "protocol": "anp", "methods": [...]},
# {"id": "weather@mcp", "protocol": "mcp", "methods": [...]}
# ]
```
### 4. 协议适配器接口
```python
class ProtocolAdapter(ABC):
"""协议适配器基类"""
@abstractmethod
def connect(self, agent_config: dict) -> Connection:
"""建立连接"""
pass
@abstractmethod
def call(self, connection: Connection, method: str, params: dict) -> dict:
"""调用方法"""
pass
@abstractmethod
def discover(self, capability: str) -> List[AgentInfo]:
"""发现 Agent"""
pass
@abstractmethod
def close(self, connection: Connection):
"""关闭连接"""
pass
```
## 支持的协议
| 协议 | 状态 | 适配器 | 说明 |
|------|------|--------|------|
| ANP | ✅ 已实现 | `adapters/anp.py` | 去中心化身份 + Agent 网络 |
| MCP | ✅ 已实现 | `adapters/mcp.py` | LLM 工具调用 |
| A2A | ✅ 已实现 | `adapters/a2a.py` | Agent 间协作 |
| AITP | ✅ 已实现 | `adapters/aitp.py` | 交互 + 交易 |
| Agent Protocol | ✅ 已实现 | `adapters/agent_protocol.py` | REST API |
| LMOS | ✅ 已实现 | `adapters/lmos.py` | 企业级平台 |
## 使用方式
### CLI 调用
```bash
# 调用 ANP Agent
python scripts/uni_cli.py call amap@anp maps_weather '{"city":"北京"}'
# 调用 MCP Server
python scripts/uni_cli.py call filesystem@mcp read_file '{"path":"/tmp/a.txt"}'
# 发现 Agent
python scripts/uni_cli.py discover weather
# 列出已注册 Agent
python scripts/uni_cli.py list
```
### Python SDK
```python
from uni_agent import UniAgent
# 初始化
agent = UniAgent(config_path="config/agents.yaml")
# 调用
result = agent.call("amap@anp", "maps_weather", {"city": "北京"})
print(result)
# 批量调用
results = agent.batch_call([
("amap@anp", "maps_weather", {"city": "北京"}),
("amap@anp", "maps_weather", {"city": "上海"}),
])
```
## 配置文件
### config/agents.yaml
```yaml
agents:
# ANP Agents
- id: amap
protocol: anp
ad_url: https://agent-connect.ai/mcp/agents/amap/ad.json
- id: hotel
protocol: anp
ad_url: https://agent-connect.ai/agents/hotel-assistant/ad.json
# MCP Servers
- id: filesystem
protocol: mcp
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
- id: github
protocol: mcp
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_TOKEN: "${GITHUB_TOKEN}"
# A2A Agents
- id: assistant
protocol: a2a
endpoint: https://example.com/.well-known/agent.json
```
### config/identity.yaml
```yaml
# 身份配置(跨协议通用)
identity:
# ANP DID 身份
anp:
did_document: config/did.json
private_key: config/private-key.pem
# A2A 认证
a2a:
auth_type: oauth2
client_id: "${A2A_CLIENT_ID}"
client_secret: "${A2A_CLIENT_SECRET}"
```
## 目录结构
```
uni-agent/
├── SKILL.md # 本文件
├── README.md # 使用文档
├── setup.sh # 一键安装
├── requirements.txt # Python 依赖
├── config/
│ ├── agents.yaml # Agent 注册表
│ ├── identity.yaml # 身份配置
│ └── .gitignore
├── adapters/
│ ├── __init__.py
│ ├── base.py # 适配器基类
│ ├── anp.py # ANP 适配器
│ ├── mcp.py # MCP 适配器
│ ├── a2a.py # A2A 适配器
│ └── aitp.py # AITP 适配器
├── scripts/
│ └── uni_cli.py # CLI 工具
└── docs/
├── architecture.md # 架构文档
└── adapters.md # 适配器开发指南
```
## 扩展新协议
1. 创建适配器文件 `adapters/new_protocol.py`
2. 继承 `ProtocolAdapter` 基类
3. 实现 `connect``call``discover``close` 方法
4.`adapters/__init__.py` 注册
```python
# adapters/new_protocol.py
from .base import ProtocolAdapter
class NewProtocolAdapter(ProtocolAdapter):
protocol_name = "new_protocol"
def connect(self, agent_config):
# 实现连接逻辑
pass
def call(self, connection, method, params):
# 实现调用逻辑
pass
# ...
```
## 依赖
```bash
pip install anp aiohttp mcp pyyaml
```

View File

@@ -0,0 +1,60 @@
"""
UniAgent 协议适配器
支持的协议:
- ANP: Agent Network Protocol (去中心化身份 + Agent 网络)
- MCP: Model Context Protocol (LLM 工具调用)
- A2A: Agent-to-Agent (Google Agent 间协作)
- AITP: Agent Interaction & Transaction Protocol (交互 + 交易)
- Agent Protocol: 统一 REST API
- LMOS: Language Model OS (企业级 Agent 平台)
"""
from .base import ProtocolAdapter, Connection, AgentInfo
from .anp import ANPAdapter
from .mcp import MCPAdapter
from .a2a import A2AAdapter
from .aitp import AITPAdapter
from .agent_protocol import AgentProtocolAdapter
from .lmos import LMOSAdapter
ADAPTERS = {
"anp": ANPAdapter,
"mcp": MCPAdapter,
"a2a": A2AAdapter,
"aitp": AITPAdapter,
"agent_protocol": AgentProtocolAdapter,
"ap": AgentProtocolAdapter,
"lmos": LMOSAdapter,
}
def get_adapter(protocol: str) -> ProtocolAdapter:
"""获取协议适配器"""
adapter_class = ADAPTERS.get(protocol)
if not adapter_class:
raise ValueError(f"不支持的协议: {protocol},可用协议: {list(ADAPTERS.keys())}")
return adapter_class()
def register_adapter(protocol: str, adapter_class: type):
"""注册新的协议适配器"""
ADAPTERS[protocol] = adapter_class
def list_protocols() -> list:
"""列出所有支持的协议"""
return list(set(ADAPTERS.keys()))
__all__ = [
"ProtocolAdapter",
"Connection",
"AgentInfo",
"ANPAdapter",
"MCPAdapter",
"A2AAdapter",
"AITPAdapter",
"AgentProtocolAdapter",
"LMOSAdapter",
"get_adapter",
"register_adapter",
"list_protocols",
"ADAPTERS",
]

View File

@@ -0,0 +1,225 @@
"""
A2A (Agent-to-Agent) 适配器
Google 提出的 Agent 间协作协议
参考: https://github.com/google/a2a
"""
import json
import uuid
from pathlib import Path
from typing import Any, Dict, List, Optional
import aiohttp
from .base import ProtocolAdapter, Connection, AgentInfo
class A2AAdapter(ProtocolAdapter):
"""A2A 协议适配器"""
protocol_name = "a2a"
def __init__(self, config_dir: Optional[Path] = None):
self.config_dir = config_dir or Path(__file__).parent.parent / "config"
self._agent_cards: Dict[str, dict] = {}
async def _fetch_agent_card(self, endpoint: str) -> dict:
"""获取 Agent Card"""
if endpoint in self._agent_cards:
return self._agent_cards[endpoint]
agent_json_url = endpoint.rstrip("/")
if not agent_json_url.endswith("agent.json"):
agent_json_url = f"{agent_json_url}/.well-known/agent.json"
async with aiohttp.ClientSession() as session:
async with session.get(agent_json_url, timeout=aiohttp.ClientTimeout(total=15)) as resp:
if resp.status == 200:
card = await resp.json()
self._agent_cards[endpoint] = card
return card
raise Exception(f"获取 Agent Card 失败: HTTP {resp.status}")
async def connect(self, agent_config: dict) -> Connection:
"""建立连接"""
endpoint = agent_config.get("endpoint")
if not endpoint:
raise ValueError("A2A Agent 配置必须包含 endpoint")
agent_card = await self._fetch_agent_card(endpoint)
rpc_url = None
if "url" in agent_card:
rpc_url = agent_card["url"]
elif "capabilities" in agent_card:
caps = agent_card.get("capabilities", {})
if "streaming" in caps:
rpc_url = caps.get("streaming", {}).get("streamingUrl")
if not rpc_url:
rpc_url = endpoint.rstrip("/") + "/rpc"
return Connection(
agent_id=agent_config.get("id", ""),
protocol=self.protocol_name,
endpoint=rpc_url,
session=None,
metadata={
"agent_card": agent_card,
"original_endpoint": endpoint,
"auth": agent_config.get("auth", {}),
}
)
async def call(
self,
connection: Connection,
method: str,
params: dict,
timeout: float = 30.0
) -> dict:
"""调用 A2A Agent 方法"""
rpc_url = connection.endpoint
auth_config = connection.metadata.get("auth", {})
headers = {
"Content-Type": "application/json",
}
if auth_config.get("type") == "api_key":
headers["Authorization"] = f"Bearer {auth_config.get('api_key', '')}"
elif auth_config.get("type") == "oauth2":
token = await self._get_oauth_token(auth_config)
headers["Authorization"] = f"Bearer {token}"
task_id = str(uuid.uuid4())
if method == "tasks/send":
payload = {
"jsonrpc": "2.0",
"id": task_id,
"method": "tasks/send",
"params": {
"id": task_id,
"message": params.get("message", {}),
}
}
elif method == "tasks/get":
payload = {
"jsonrpc": "2.0",
"id": task_id,
"method": "tasks/get",
"params": {
"id": params.get("task_id", task_id),
}
}
else:
payload = {
"jsonrpc": "2.0",
"id": task_id,
"method": method,
"params": params,
}
async with aiohttp.ClientSession() as session:
async with session.post(
rpc_url,
json=payload,
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status == 200:
result = await resp.json()
return {
"success": True,
"result": result.get("result", result),
"task_id": task_id,
}
else:
error_text = await resp.text()
return {
"success": False,
"error": f"HTTP {resp.status}: {error_text}",
}
async def _get_oauth_token(self, auth_config: dict) -> str:
"""获取 OAuth2 令牌"""
token_url = auth_config.get("token_url")
client_id = auth_config.get("client_id")
client_secret = auth_config.get("client_secret")
if not all([token_url, client_id, client_secret]):
raise ValueError("OAuth2 配置不完整")
async with aiohttp.ClientSession() as session:
async with session.post(
token_url,
data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret,
}
) as resp:
if resp.status == 200:
result = await resp.json()
return result.get("access_token", "")
raise Exception(f"获取 OAuth2 令牌失败: HTTP {resp.status}")
async def discover(self, capability: str = "") -> List[AgentInfo]:
"""发现 Agent"""
agents_file = self.config_dir / "agents.yaml"
if not agents_file.exists():
return []
import yaml
with open(agents_file) as f:
config = yaml.safe_load(f)
agents = []
for agent in config.get("agents", []):
if agent.get("protocol") != "a2a":
continue
if capability and capability.lower() not in agent.get("id", "").lower():
continue
agents.append(AgentInfo(
id=f"{agent['id']}@a2a",
protocol="a2a",
name=agent.get("name", agent["id"]),
endpoint=agent.get("endpoint", ""),
metadata=agent
))
return agents
async def close(self, connection: Connection):
"""关闭连接"""
pass
async def get_methods(self, connection: Connection) -> List[dict]:
"""获取 Agent 支持的方法(从 Agent Card 的 skills"""
agent_card = connection.metadata.get("agent_card", {})
skills = agent_card.get("skills", [])
methods = []
for skill in skills:
methods.append({
"name": skill.get("id", skill.get("name", "unknown")),
"description": skill.get("description", ""),
"inputSchema": skill.get("inputSchema", {}),
"outputSchema": skill.get("outputSchema", {}),
})
methods.extend([
{"name": "tasks/send", "description": "发送任务消息"},
{"name": "tasks/get", "description": "获取任务状态"},
{"name": "tasks/cancel", "description": "取消任务"},
])
return methods
def validate_config(self, agent_config: dict) -> bool:
"""验证配置"""
return "endpoint" in agent_config

View File

@@ -0,0 +1,211 @@
"""
Agent Protocol 适配器
AI Engineer Foundation 提出的 Agent 统一 REST API
参考: https://agentprotocol.ai
"""
import json
import uuid
from pathlib import Path
from typing import Any, Dict, List, Optional
import aiohttp
from .base import ProtocolAdapter, Connection, AgentInfo
class AgentProtocolAdapter(ProtocolAdapter):
"""Agent Protocol 适配器"""
protocol_name = "agent_protocol"
def __init__(self, config_dir: Optional[Path] = None):
self.config_dir = config_dir or Path(__file__).parent.parent / "config"
self._tasks: Dict[str, dict] = {}
async def connect(self, agent_config: dict) -> Connection:
"""建立连接"""
endpoint = agent_config.get("endpoint")
if not endpoint:
raise ValueError("Agent Protocol 配置必须包含 endpoint")
endpoint = endpoint.rstrip("/")
if not endpoint.endswith("/ap/v1"):
endpoint = f"{endpoint}/ap/v1"
return Connection(
agent_id=agent_config.get("id", ""),
protocol=self.protocol_name,
endpoint=endpoint,
session=None,
metadata=agent_config
)
async def call(
self,
connection: Connection,
method: str,
params: dict,
timeout: float = 30.0
) -> dict:
"""调用 Agent Protocol API"""
endpoint = connection.endpoint
headers = {
"Content-Type": "application/json",
}
api_key = connection.metadata.get("api_key")
if api_key:
headers["Authorization"] = f"Bearer {api_key}"
if method == "create_task":
async with aiohttp.ClientSession() as session:
async with session.post(
f"{endpoint}/agent/tasks",
json={"input": params.get("input", "")},
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status in [200, 201]:
result = await resp.json()
task_id = result.get("task_id")
self._tasks[task_id] = result
return {"success": True, "result": result, "task_id": task_id}
else:
return {"success": False, "error": f"HTTP {resp.status}"}
elif method == "execute_step":
task_id = params.get("task_id")
if not task_id:
return {"success": False, "error": "缺少 task_id"}
async with aiohttp.ClientSession() as session:
async with session.post(
f"{endpoint}/agent/tasks/{task_id}/steps",
json={"input": params.get("input", "")},
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status in [200, 201]:
result = await resp.json()
return {"success": True, "result": result}
else:
return {"success": False, "error": f"HTTP {resp.status}"}
elif method == "get_task":
task_id = params.get("task_id")
if not task_id:
return {"success": False, "error": "缺少 task_id"}
async with aiohttp.ClientSession() as session:
async with session.get(
f"{endpoint}/agent/tasks/{task_id}",
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status == 200:
result = await resp.json()
return {"success": True, "result": result}
else:
return {"success": False, "error": f"HTTP {resp.status}"}
elif method == "list_tasks":
async with aiohttp.ClientSession() as session:
async with session.get(
f"{endpoint}/agent/tasks",
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status == 200:
result = await resp.json()
return {"success": True, "result": result}
else:
return {"success": False, "error": f"HTTP {resp.status}"}
elif method == "get_artifacts":
task_id = params.get("task_id")
if not task_id:
return {"success": False, "error": "缺少 task_id"}
async with aiohttp.ClientSession() as session:
async with session.get(
f"{endpoint}/agent/tasks/{task_id}/artifacts",
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status == 200:
result = await resp.json()
return {"success": True, "result": result}
else:
return {"success": False, "error": f"HTTP {resp.status}"}
else:
return {"success": False, "error": f"未知方法: {method}"}
async def discover(self, capability: str = "") -> List[AgentInfo]:
"""发现 Agent"""
agents_file = self.config_dir / "agents.yaml"
if not agents_file.exists():
return []
import yaml
with open(agents_file) as f:
config = yaml.safe_load(f)
agents = []
for agent in config.get("agents", []):
if agent.get("protocol") != "agent_protocol":
continue
if capability and capability.lower() not in agent.get("id", "").lower():
continue
agents.append(AgentInfo(
id=f"{agent['id']}@agent_protocol",
protocol="agent_protocol",
name=agent.get("name", agent["id"]),
endpoint=agent.get("endpoint", ""),
metadata=agent
))
return agents
async def close(self, connection: Connection):
"""关闭连接"""
pass
async def get_methods(self, connection: Connection) -> List[dict]:
"""获取支持的方法"""
return [
{
"name": "create_task",
"description": "创建新任务",
"inputSchema": {"input": "string"},
},
{
"name": "execute_step",
"description": "执行任务步骤",
"inputSchema": {"task_id": "string", "input": "string"},
},
{
"name": "get_task",
"description": "获取任务状态",
"inputSchema": {"task_id": "string"},
},
{
"name": "list_tasks",
"description": "列出所有任务",
"inputSchema": {},
},
{
"name": "get_artifacts",
"description": "获取任务产物",
"inputSchema": {"task_id": "string"},
},
]
def validate_config(self, agent_config: dict) -> bool:
"""验证配置"""
return "endpoint" in agent_config

View File

@@ -0,0 +1,217 @@
"""
AITP (Agent Interaction & Transaction Protocol) 适配器
NEAR 基金会提出的 Agent 交互与交易协议
参考: https://aitp.dev
"""
import json
import uuid
from pathlib import Path
from typing import Any, Dict, List, Optional
import aiohttp
from .base import ProtocolAdapter, Connection, AgentInfo
class AITPAdapter(ProtocolAdapter):
"""AITP 协议适配器"""
protocol_name = "aitp"
def __init__(self, config_dir: Optional[Path] = None):
self.config_dir = config_dir or Path(__file__).parent.parent / "config"
self._threads: Dict[str, dict] = {}
async def connect(self, agent_config: dict) -> Connection:
"""建立连接 - 创建 Thread"""
endpoint = agent_config.get("endpoint")
if not endpoint:
raise ValueError("AITP Agent 配置必须包含 endpoint")
thread_id = str(uuid.uuid4())
self._threads[thread_id] = {
"id": thread_id,
"messages": [],
"status": "open",
}
return Connection(
agent_id=agent_config.get("id", ""),
protocol=self.protocol_name,
endpoint=endpoint,
session=thread_id,
metadata={
"thread_id": thread_id,
"wallet": agent_config.get("wallet", {}),
}
)
async def call(
self,
connection: Connection,
method: str,
params: dict,
timeout: float = 30.0
) -> dict:
"""调用 AITP Agent"""
endpoint = connection.endpoint
thread_id = connection.session
wallet_config = connection.metadata.get("wallet", {})
headers = {
"Content-Type": "application/json",
}
if method == "message":
payload = {
"thread_id": thread_id,
"message": {
"role": "user",
"content": params.get("content", ""),
"parts": params.get("parts", []),
}
}
elif method == "payment":
payload = {
"thread_id": thread_id,
"capability": "aitp-01",
"payment_request": {
"amount": params.get("amount"),
"currency": params.get("currency", "NEAR"),
"recipient": params.get("recipient"),
"memo": params.get("memo", ""),
}
}
if wallet_config.get("type") == "near":
payload["wallet"] = {
"type": "near",
"account_id": wallet_config.get("account_id"),
}
elif method == "decision":
payload = {
"thread_id": thread_id,
"capability": "aitp-02",
"decision_request": {
"question": params.get("question"),
"options": params.get("options", []),
"allow_custom": params.get("allow_custom", False),
}
}
elif method == "data_request":
payload = {
"thread_id": thread_id,
"capability": "aitp-03",
"data_request": {
"schema": params.get("schema", {}),
"description": params.get("description", ""),
}
}
else:
payload = {
"thread_id": thread_id,
"method": method,
"params": params,
}
async with aiohttp.ClientSession() as session:
async with session.post(
f"{endpoint}/threads/{thread_id}/messages",
json=payload,
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status == 200:
result = await resp.json()
if thread_id in self._threads:
self._threads[thread_id]["messages"].append(payload)
self._threads[thread_id]["messages"].append(result)
return {
"success": True,
"result": result,
"thread_id": thread_id,
}
else:
error_text = await resp.text()
return {
"success": False,
"error": f"HTTP {resp.status}: {error_text}",
}
async def discover(self, capability: str = "") -> List[AgentInfo]:
"""发现 Agent"""
agents_file = self.config_dir / "agents.yaml"
if not agents_file.exists():
return []
import yaml
with open(agents_file) as f:
config = yaml.safe_load(f)
agents = []
for agent in config.get("agents", []):
if agent.get("protocol") != "aitp":
continue
if capability and capability.lower() not in agent.get("id", "").lower():
continue
agents.append(AgentInfo(
id=f"{agent['id']}@aitp",
protocol="aitp",
name=agent.get("name", agent["id"]),
endpoint=agent.get("endpoint", ""),
metadata=agent
))
return agents
async def close(self, connection: Connection):
"""关闭连接 - 关闭 Thread"""
thread_id = connection.session
if thread_id in self._threads:
self._threads[thread_id]["status"] = "closed"
async def get_methods(self, connection: Connection) -> List[dict]:
"""获取支持的方法AITP 能力)"""
return [
{
"name": "message",
"description": "发送对话消息",
"inputSchema": {"content": "string"},
},
{
"name": "payment",
"description": "AITP-01: 发起支付请求",
"inputSchema": {
"amount": "number",
"currency": "string",
"recipient": "string",
},
},
{
"name": "decision",
"description": "AITP-02: 请求用户决策",
"inputSchema": {
"question": "string",
"options": "array",
},
},
{
"name": "data_request",
"description": "AITP-03: 请求结构化数据",
"inputSchema": {
"schema": "object",
"description": "string",
},
},
]
def validate_config(self, agent_config: dict) -> bool:
"""验证配置"""
return "endpoint" in agent_config

View File

@@ -0,0 +1,191 @@
"""
ANP (Agent Network Protocol) 适配器
"""
import json
from pathlib import Path
from typing import Any, Dict, List, Optional
import aiohttp
from .base import ProtocolAdapter, Connection, AgentInfo
try:
from anp.anp_crawler import ANPCrawler
HAS_ANP = True
except ImportError:
HAS_ANP = False
class ANPAdapter(ProtocolAdapter):
"""ANP 协议适配器"""
protocol_name = "anp"
def __init__(self, config_dir: Optional[Path] = None):
self.config_dir = config_dir or Path(__file__).parent.parent / "config"
self._crawler = None
self._ad_cache: Dict[str, dict] = {}
self._endpoint_cache: Dict[str, str] = {}
def _get_crawler(self) -> "ANPCrawler":
"""获取 ANP Crawler 实例"""
if not HAS_ANP:
raise ImportError("请安装 anp 库: pip install anp")
if self._crawler is None:
did_path = self.config_dir / "did.json"
key_path = self.config_dir / "private-key.pem"
if did_path.exists() and key_path.exists():
self._crawler = ANPCrawler(
did_document_path=str(did_path),
private_key_path=str(key_path)
)
else:
raise FileNotFoundError(
f"DID 配置文件不存在: {did_path}{key_path}\n"
"请运行 setup.sh 生成本地身份"
)
return self._crawler
async def _fetch_ad(self, ad_url: str) -> dict:
"""获取 Agent Description 文档"""
if ad_url in self._ad_cache:
return self._ad_cache[ad_url]
async with aiohttp.ClientSession() as session:
async with session.get(ad_url, timeout=aiohttp.ClientTimeout(total=15)) as resp:
if resp.status == 200:
ad = await resp.json()
self._ad_cache[ad_url] = ad
return ad
raise Exception(f"获取 AD 失败: HTTP {resp.status}")
async def _get_endpoint(self, ad_url: str) -> str:
"""从 AD 获取 RPC 端点"""
if ad_url in self._endpoint_cache:
return self._endpoint_cache[ad_url]
ad = await self._fetch_ad(ad_url)
interfaces = ad.get("interfaces", [])
if not interfaces:
raise ValueError(f"AD 中没有定义接口: {ad_url}")
interface_url = interfaces[0].get("url")
if not interface_url:
raise ValueError(f"接口 URL 为空: {ad_url}")
async with aiohttp.ClientSession() as session:
async with session.get(interface_url, timeout=aiohttp.ClientTimeout(total=15)) as resp:
if resp.status == 200:
interface_doc = await resp.json()
servers = interface_doc.get("servers", [])
if servers:
endpoint = servers[0].get("url")
self._endpoint_cache[ad_url] = endpoint
return endpoint
raise ValueError(f"无法获取 RPC 端点: {ad_url}")
async def connect(self, agent_config: dict) -> Connection:
"""建立连接"""
ad_url = agent_config.get("ad_url")
if not ad_url:
raise ValueError("ANP Agent 配置必须包含 ad_url")
ad = await self._fetch_ad(ad_url)
endpoint = await self._get_endpoint(ad_url)
return Connection(
agent_id=agent_config.get("id", ""),
protocol=self.protocol_name,
endpoint=endpoint,
session=self._get_crawler(),
metadata={
"ad_url": ad_url,
"ad": ad,
"name": ad.get("name", ""),
}
)
async def call(
self,
connection: Connection,
method: str,
params: dict,
timeout: float = 30.0
) -> dict:
"""调用 Agent 方法"""
crawler = connection.session
endpoint = connection.endpoint
result = await crawler.execute_json_rpc(
endpoint=endpoint,
method=method,
params=params
)
return result
async def discover(self, capability: str = "") -> List[AgentInfo]:
"""发现 Agent从本地配置"""
agents_file = self.config_dir / "agents.yaml"
if not agents_file.exists():
return []
import yaml
with open(agents_file) as f:
config = yaml.safe_load(f)
agents = []
for agent in config.get("agents", []):
if agent.get("protocol") != "anp":
continue
if capability and capability.lower() not in agent.get("id", "").lower():
continue
agents.append(AgentInfo(
id=f"{agent['id']}@anp",
protocol="anp",
name=agent.get("name", agent["id"]),
endpoint=agent.get("ad_url", ""),
metadata=agent
))
return agents
async def close(self, connection: Connection):
"""关闭连接"""
pass
async def get_methods(self, connection: Connection) -> List[dict]:
"""获取 Agent 支持的方法"""
ad_url = connection.metadata.get("ad_url")
if not ad_url:
return []
ad = await self._fetch_ad(ad_url)
interfaces = ad.get("interfaces", [])
if not interfaces:
return []
interface_url = interfaces[0].get("url")
if not interface_url:
return []
async with aiohttp.ClientSession() as session:
async with session.get(interface_url, timeout=aiohttp.ClientTimeout(total=15)) as resp:
if resp.status == 200:
interface_doc = await resp.json()
return interface_doc.get("methods", [])
return []
def validate_config(self, agent_config: dict) -> bool:
"""验证配置"""
return "ad_url" in agent_config

View File

@@ -0,0 +1,120 @@
"""
协议适配器基类
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional
@dataclass
class AgentInfo:
"""Agent 信息"""
id: str
protocol: str
name: str = ""
description: str = ""
methods: List[str] = field(default_factory=list)
endpoint: str = ""
metadata: Dict[str, Any] = field(default_factory=dict)
@dataclass
class Connection:
"""连接对象"""
agent_id: str
protocol: str
endpoint: str = ""
session: Any = None
metadata: Dict[str, Any] = field(default_factory=dict)
def is_active(self) -> bool:
return self.session is not None
class ProtocolAdapter(ABC):
"""协议适配器基类"""
protocol_name: str = "base"
@abstractmethod
async def connect(self, agent_config: dict) -> Connection:
"""
建立与 Agent 的连接
Args:
agent_config: Agent 配置信息
Returns:
Connection 对象
"""
pass
@abstractmethod
async def call(
self,
connection: Connection,
method: str,
params: dict,
timeout: float = 30.0
) -> dict:
"""
调用 Agent 方法
Args:
connection: 连接对象
method: 方法名
params: 参数
timeout: 超时时间(秒)
Returns:
调用结果
"""
pass
@abstractmethod
async def discover(self, capability: str = "") -> List[AgentInfo]:
"""
发现 Agent
Args:
capability: 能力关键词(可选)
Returns:
Agent 信息列表
"""
pass
@abstractmethod
async def close(self, connection: Connection):
"""
关闭连接
Args:
connection: 连接对象
"""
pass
async def get_methods(self, connection: Connection) -> List[dict]:
"""
获取 Agent 支持的方法列表
Args:
connection: 连接对象
Returns:
方法列表
"""
return []
def validate_config(self, agent_config: dict) -> bool:
"""
验证 Agent 配置
Args:
agent_config: Agent 配置
Returns:
是否有效
"""
return True

View File

@@ -0,0 +1,215 @@
"""
LMOS (Language Model Operating System) 适配器
Eclipse 基金会孵化的企业级多 Agent 平台
参考: https://eclipse.dev/lmos/
"""
import json
import uuid
from pathlib import Path
from typing import Any, Dict, List, Optional
import aiohttp
from .base import ProtocolAdapter, Connection, AgentInfo
class LMOSAdapter(ProtocolAdapter):
"""LMOS 协议适配器"""
protocol_name = "lmos"
def __init__(self, config_dir: Optional[Path] = None):
self.config_dir = config_dir or Path(__file__).parent.parent / "config"
self._registry_cache: Dict[str, List[dict]] = {}
async def _discover_via_mdns(self) -> List[dict]:
"""通过 mDNS 发现本地 Agent简化实现"""
return []
async def _query_registry(self, registry_url: str, capability: str = "") -> List[dict]:
"""查询 Agent 注册中心"""
if registry_url in self._registry_cache:
return self._registry_cache[registry_url]
async with aiohttp.ClientSession() as session:
params = {}
if capability:
params["capability"] = capability
async with session.get(
f"{registry_url}/agents",
params=params,
timeout=aiohttp.ClientTimeout(total=15)
) as resp:
if resp.status == 200:
result = await resp.json()
agents = result.get("agents", [])
self._registry_cache[registry_url] = agents
return agents
return []
async def connect(self, agent_config: dict) -> Connection:
"""建立连接"""
endpoint = agent_config.get("endpoint")
registry_url = agent_config.get("registry_url")
if not endpoint and not registry_url:
raise ValueError("LMOS Agent 配置必须包含 endpoint 或 registry_url")
if registry_url and not endpoint:
agent_id = agent_config.get("id")
agents = await self._query_registry(registry_url)
for agent in agents:
if agent.get("id") == agent_id:
endpoint = agent.get("endpoint")
break
if not endpoint:
raise ValueError(f"在注册中心未找到 Agent: {agent_id}")
return Connection(
agent_id=agent_config.get("id", ""),
protocol=self.protocol_name,
endpoint=endpoint,
session=None,
metadata={
"registry_url": registry_url,
"group": agent_config.get("group"),
}
)
async def call(
self,
connection: Connection,
method: str,
params: dict,
timeout: float = 30.0
) -> dict:
"""调用 LMOS Agent"""
endpoint = connection.endpoint
headers = {
"Content-Type": "application/json",
}
if method == "invoke":
payload = {
"capability": params.get("capability"),
"input": params.get("input", {}),
"context": params.get("context", {}),
}
elif method == "route":
payload = {
"query": params.get("query"),
"context": params.get("context", {}),
}
elif method == "describe":
async with aiohttp.ClientSession() as session:
async with session.get(
f"{endpoint}/capabilities",
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status == 200:
result = await resp.json()
return {"success": True, "result": result}
else:
return {"success": False, "error": f"HTTP {resp.status}"}
else:
payload = {
"method": method,
"params": params,
}
async with aiohttp.ClientSession() as session:
async with session.post(
f"{endpoint}/invoke",
json=payload,
headers=headers,
timeout=aiohttp.ClientTimeout(total=timeout)
) as resp:
if resp.status == 200:
result = await resp.json()
return {"success": True, "result": result}
else:
error_text = await resp.text()
return {"success": False, "error": f"HTTP {resp.status}: {error_text}"}
async def discover(self, capability: str = "") -> List[AgentInfo]:
"""发现 Agent"""
agents_file = self.config_dir / "agents.yaml"
if not agents_file.exists():
return []
import yaml
with open(agents_file) as f:
config = yaml.safe_load(f)
all_agents = []
for agent in config.get("agents", []):
if agent.get("protocol") != "lmos":
continue
if capability and capability.lower() not in agent.get("id", "").lower():
continue
all_agents.append(AgentInfo(
id=f"{agent['id']}@lmos",
protocol="lmos",
name=agent.get("name", agent["id"]),
endpoint=agent.get("endpoint", ""),
metadata=agent
))
for agent in config.get("agents", []):
if agent.get("protocol") != "lmos":
continue
registry_url = agent.get("registry_url")
if registry_url:
try:
remote_agents = await self._query_registry(registry_url, capability)
for ra in remote_agents:
all_agents.append(AgentInfo(
id=f"{ra['id']}@lmos",
protocol="lmos",
name=ra.get("name", ra["id"]),
endpoint=ra.get("endpoint", ""),
metadata=ra
))
except Exception:
pass
return all_agents
async def close(self, connection: Connection):
"""关闭连接"""
pass
async def get_methods(self, connection: Connection) -> List[dict]:
"""获取支持的方法"""
result = await self.call(connection, "describe", {})
if result.get("success"):
capabilities = result.get("result", {}).get("capabilities", [])
return [
{
"name": cap.get("id", cap.get("name")),
"description": cap.get("description", ""),
"inputSchema": cap.get("inputSchema", {}),
}
for cap in capabilities
]
return [
{"name": "invoke", "description": "调用 Agent 能力"},
{"name": "route", "description": "智能路由到最佳 Agent"},
{"name": "describe", "description": "获取 Agent 能力描述"},
]
def validate_config(self, agent_config: dict) -> bool:
"""验证配置"""
return "endpoint" in agent_config or "registry_url" in agent_config

View File

@@ -0,0 +1,159 @@
"""
MCP (Model Context Protocol) 适配器
"""
import asyncio
import json
import os
import subprocess
from pathlib import Path
from typing import Any, Dict, List, Optional
from .base import ProtocolAdapter, Connection, AgentInfo
try:
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
HAS_MCP = True
except ImportError:
HAS_MCP = False
class MCPAdapter(ProtocolAdapter):
"""MCP 协议适配器"""
protocol_name = "mcp"
def __init__(self, config_dir: Optional[Path] = None):
self.config_dir = config_dir or Path(__file__).parent.parent / "config"
self._sessions: Dict[str, Any] = {}
async def connect(self, agent_config: dict) -> Connection:
"""建立连接"""
if not HAS_MCP:
raise ImportError("请安装 mcp 库: pip install mcp")
command = agent_config.get("command")
args = agent_config.get("args", [])
env = agent_config.get("env", {})
if not command:
raise ValueError("MCP Agent 配置必须包含 command")
full_env = os.environ.copy()
for k, v in env.items():
if v.startswith("${") and v.endswith("}"):
env_var = v[2:-1]
full_env[k] = os.environ.get(env_var, "")
else:
full_env[k] = v
server_params = StdioServerParameters(
command=command,
args=args,
env=full_env
)
read, write = await stdio_client(server_params).__aenter__()
session = ClientSession(read, write)
await session.__aenter__()
await session.initialize()
agent_id = agent_config.get("id", "")
self._sessions[agent_id] = {
"session": session,
"read": read,
"write": write,
}
return Connection(
agent_id=agent_id,
protocol=self.protocol_name,
endpoint=f"{command} {' '.join(args)}",
session=session,
metadata=agent_config
)
async def call(
self,
connection: Connection,
method: str,
params: dict,
timeout: float = 30.0
) -> dict:
"""调用 MCP 工具"""
session: ClientSession = connection.session
result = await asyncio.wait_for(
session.call_tool(method, params),
timeout=timeout
)
if hasattr(result, "content"):
content = result.content
if isinstance(content, list) and len(content) > 0:
first = content[0]
if hasattr(first, "text"):
return {"success": True, "result": first.text}
return {"success": True, "result": str(first)}
return {"success": True, "result": content}
return {"success": True, "result": result}
async def discover(self, capability: str = "") -> List[AgentInfo]:
"""发现 Agent从本地配置"""
agents_file = self.config_dir / "agents.yaml"
if not agents_file.exists():
return []
import yaml
with open(agents_file) as f:
config = yaml.safe_load(f)
agents = []
for agent in config.get("agents", []):
if agent.get("protocol") != "mcp":
continue
if capability and capability.lower() not in agent.get("id", "").lower():
continue
agents.append(AgentInfo(
id=f"{agent['id']}@mcp",
protocol="mcp",
name=agent.get("name", agent["id"]),
endpoint=f"{agent.get('command', '')} {' '.join(agent.get('args', []))}",
metadata=agent
))
return agents
async def close(self, connection: Connection):
"""关闭连接"""
agent_id = connection.agent_id
if agent_id in self._sessions:
session_info = self._sessions.pop(agent_id)
session = session_info.get("session")
if session:
await session.__aexit__(None, None, None)
async def get_methods(self, connection: Connection) -> List[dict]:
"""获取 MCP Server 支持的工具"""
session: ClientSession = connection.session
result = await session.list_tools()
tools = []
if hasattr(result, "tools"):
for tool in result.tools:
tools.append({
"name": tool.name,
"description": getattr(tool, "description", ""),
"inputSchema": getattr(tool, "inputSchema", {}),
})
return tools
def validate_config(self, agent_config: dict) -> bool:
"""验证配置"""
return "command" in agent_config

View File

@@ -0,0 +1,121 @@
# UniAgent 配置文件
# Agent 注册表
agents:
# ==================== ANP Agents ====================
- id: amap
protocol: anp
name: 高德地图
ad_url: https://agent-connect.ai/mcp/agents/amap/ad.json
description: 地点搜索、路线规划、天气查询、周边搜索
- id: kuaidi
protocol: anp
name: 快递查询
ad_url: https://agent-connect.ai/mcp/agents/kuaidi/ad.json
description: 快递单号追踪
- id: hotel
protocol: anp
name: 酒店预订
ad_url: https://agent-connect.ai/agents/hotel-assistant/ad.json
description: 搜索酒店、查询房价
- id: juhe
protocol: anp
name: 聚合查询
ad_url: https://agent-connect.ai/mcp/agents/juhe/ad.json
description: 多种生活服务查询
- id: navigation
protocol: anp
name: Agent导航
ad_url: https://agent-search.ai/agents/navigation/ad.json
description: 发现更多 ANP Agent
# ==================== MCP Servers ====================
# - id: filesystem
# protocol: mcp
# name: 文件系统
# command: npx
# args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
# description: 文件读写操作
# - id: github
# protocol: mcp
# name: GitHub
# command: npx
# args: ["-y", "@modelcontextprotocol/server-github"]
# env:
# GITHUB_TOKEN: "${GITHUB_TOKEN}"
# description: GitHub 仓库操作
# - id: sqlite
# protocol: mcp
# name: SQLite
# command: npx
# args: ["-y", "@modelcontextprotocol/server-sqlite", "/tmp/test.db"]
# description: SQLite 数据库操作
# ==================== A2A Agents ====================
# Google Agent-to-Agent 协议
# - id: gemini_assistant
# protocol: a2a
# name: Gemini Assistant
# endpoint: https://example.com/.well-known/agent.json
# auth:
# type: api_key
# api_key: "${A2A_API_KEY}"
# - id: vertexai_agent
# protocol: a2a
# name: VertexAI Agent
# endpoint: https://your-project.cloudfunctions.net/agent
# auth:
# type: oauth2
# token_url: https://oauth2.googleapis.com/token
# client_id: "${GOOGLE_CLIENT_ID}"
# client_secret: "${GOOGLE_CLIENT_SECRET}"
# ==================== AITP Agents ====================
# NEAR Agent Interaction & Transaction Protocol
# - id: near_shop
# protocol: aitp
# name: NEAR Shop
# endpoint: https://example.near.ai/api
# wallet:
# type: near
# account_id: "${NEAR_ACCOUNT_ID}"
# - id: payment_agent
# protocol: aitp
# name: Payment Agent
# endpoint: https://pay.example.com/aitp
# description: 支持 NEAR/ETH 支付的 Agent
# ==================== Agent Protocol ====================
# AI Engineer Foundation REST API 标准
# - id: autogpt
# protocol: agent_protocol
# name: AutoGPT
# endpoint: http://localhost:8000
# api_key: "${AUTOGPT_API_KEY}"
# - id: smol_developer
# protocol: ap
# name: Smol Developer
# endpoint: http://localhost:8080
# ==================== LMOS Agents ====================
# Eclipse 企业级 Agent 平台
# - id: customer_service
# protocol: lmos
# name: 客服 Agent
# registry_url: http://lmos-registry.internal:8080
# group: customer-agents
# - id: sales_agent
# protocol: lmos
# name: 销售 Agent
# endpoint: http://sales-agent.internal:8080
# description: 处理销售咨询

View File

@@ -0,0 +1,14 @@
# UniAgent 依赖
# 核心
pyyaml>=6.0
aiohttp>=3.8.0
# ANP 协议
anp>=0.1.0
# MCP 协议 (可选)
# mcp>=0.1.0
# A2A 协议 (待实现)
# google-a2a>=0.1.0

View File

@@ -0,0 +1,282 @@
#!/usr/bin/env python3
"""
UniAgent 适配器测试脚本
测试所有协议适配器的基本功能
"""
import asyncio
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from adapters import get_adapter, ADAPTERS, list_protocols
class TestResult:
def __init__(self, protocol: str):
self.protocol = protocol
self.passed = 0
self.failed = 0
self.skipped = 0
self.errors = []
def pass_(self, msg: str):
self.passed += 1
print(f"{msg}")
def fail(self, msg: str, error: str = ""):
self.failed += 1
self.errors.append(f"{msg}: {error}")
print(f"{msg}: {error[:100]}")
def skip(self, msg: str):
self.skipped += 1
print(f" ⏭️ {msg} (跳过)")
def summary(self) -> str:
status = "" if self.failed == 0 else ""
return f"{status} {self.protocol}: {self.passed} passed, {self.failed} failed, {self.skipped} skipped"
async def test_anp() -> TestResult:
"""测试 ANP 适配器"""
result = TestResult("ANP")
print("\n[ANP] 测试 Agent Network Protocol...\n")
try:
adapter = get_adapter("anp")
result.pass_("获取适配器")
except Exception as e:
result.fail("获取适配器", str(e))
return result
agent_config = {
"id": "amap",
"protocol": "anp",
"ad_url": "https://agent-connect.ai/mcp/agents/amap/ad.json"
}
try:
connection = await adapter.connect(agent_config)
result.pass_(f"建立连接: {connection.endpoint[:50]}...")
except Exception as e:
result.fail("建立连接", str(e))
return result
try:
methods = await adapter.get_methods(connection)
result.pass_(f"获取方法列表: {len(methods)} 个方法")
except Exception as e:
result.fail("获取方法列表", str(e))
try:
res = await adapter.call(connection, "maps_weather", {"city": "北京"})
if res.get("success") or res.get("result"):
city = res.get("result", {}).get("city", "")
result.pass_(f"调用 maps_weather: {city}")
else:
result.fail("调用 maps_weather", str(res))
except Exception as e:
result.fail("调用 maps_weather", str(e))
try:
res = await adapter.call(connection, "maps_text_search", {"keywords": "咖啡厅", "city": "上海"})
if res.get("success") or res.get("result"):
pois = res.get("result", {}).get("pois", [])
result.pass_(f"调用 maps_text_search: 找到 {len(pois)} 个结果")
else:
result.fail("调用 maps_text_search", str(res))
except Exception as e:
result.fail("调用 maps_text_search", str(e))
try:
agents = await adapter.discover()
result.pass_(f"发现 Agent: {len(agents)}")
except Exception as e:
result.fail("发现 Agent", str(e))
try:
await adapter.close(connection)
result.pass_("关闭连接")
except Exception as e:
result.fail("关闭连接", str(e))
return result
async def test_mcp() -> TestResult:
"""测试 MCP 适配器"""
result = TestResult("MCP")
print("\n[MCP] 测试 Model Context Protocol...\n")
try:
adapter = get_adapter("mcp")
result.pass_("获取适配器")
except Exception as e:
result.fail("获取适配器", str(e))
return result
result.skip("MCP 需要本地 npx 环境,跳过实际连接测试")
result.skip("如需测试,请配置 config/agents.yaml 中的 MCP Server")
return result
async def test_a2a() -> TestResult:
"""测试 A2A 适配器"""
result = TestResult("A2A")
print("\n[A2A] 测试 Agent-to-Agent Protocol...\n")
try:
adapter = get_adapter("a2a")
result.pass_("获取适配器")
except Exception as e:
result.fail("获取适配器", str(e))
return result
result.skip("A2A 需要配置 Agent endpoint跳过实际连接测试")
result.skip("如需测试,请配置 config/agents.yaml 中的 A2A Agent")
try:
agents = await adapter.discover()
result.pass_(f"发现 Agent: {len(agents)} 个 (本地配置)")
except Exception as e:
result.fail("发现 Agent", str(e))
return result
async def test_aitp() -> TestResult:
"""测试 AITP 适配器"""
result = TestResult("AITP")
print("\n[AITP] 测试 Agent Interaction & Transaction Protocol...\n")
try:
adapter = get_adapter("aitp")
result.pass_("获取适配器")
except Exception as e:
result.fail("获取适配器", str(e))
return result
result.skip("AITP 需要配置 NEAR 钱包和 endpoint跳过实际连接测试")
result.skip("如需测试,请配置 config/agents.yaml 中的 AITP Agent")
try:
agents = await adapter.discover()
result.pass_(f"发现 Agent: {len(agents)} 个 (本地配置)")
except Exception as e:
result.fail("发现 Agent", str(e))
try:
methods = [
{"name": "message", "desc": "发送消息"},
{"name": "payment", "desc": "发起支付"},
{"name": "decision", "desc": "请求决策"},
]
result.pass_(f"支持方法: {', '.join([m['name'] for m in methods])}")
except Exception as e:
result.fail("检查方法", str(e))
return result
async def test_agent_protocol() -> TestResult:
"""测试 Agent Protocol 适配器"""
result = TestResult("Agent Protocol")
print("\n[AP] 测试 Agent Protocol...\n")
try:
adapter = get_adapter("agent_protocol")
result.pass_("获取适配器 (agent_protocol)")
except Exception as e:
result.fail("获取适配器", str(e))
return result
try:
adapter2 = get_adapter("ap")
result.pass_("获取适配器 (别名 ap)")
except Exception as e:
result.fail("获取适配器别名", str(e))
result.skip("Agent Protocol 需要运行中的 Agent 服务,跳过实际连接测试")
result.skip("如需测试,请启动 AutoGPT 或其他兼容服务")
try:
agents = await adapter.discover()
result.pass_(f"发现 Agent: {len(agents)} 个 (本地配置)")
except Exception as e:
result.fail("发现 Agent", str(e))
return result
async def test_lmos() -> TestResult:
"""测试 LMOS 适配器"""
result = TestResult("LMOS")
print("\n[LMOS] 测试 Language Model Operating System...\n")
try:
adapter = get_adapter("lmos")
result.pass_("获取适配器")
except Exception as e:
result.fail("获取适配器", str(e))
return result
result.skip("LMOS 需要配置注册中心或 Agent endpoint跳过实际连接测试")
result.skip("如需测试,请配置 config/agents.yaml 中的 LMOS Agent")
try:
agents = await adapter.discover()
result.pass_(f"发现 Agent: {len(agents)} 个 (本地配置)")
except Exception as e:
result.fail("发现 Agent", str(e))
return result
async def main():
print("=" * 60)
print(" UniAgent 适配器测试")
print("=" * 60)
print(f"\n支持的协议: {list_protocols()}\n")
results = []
results.append(await test_anp())
results.append(await test_mcp())
results.append(await test_a2a())
results.append(await test_aitp())
results.append(await test_agent_protocol())
results.append(await test_lmos())
print("\n" + "=" * 60)
print(" 测试汇总")
print("=" * 60 + "\n")
total_passed = 0
total_failed = 0
total_skipped = 0
for r in results:
print(r.summary())
total_passed += r.passed
total_failed += r.failed
total_skipped += r.skipped
print(f"\n总计: {total_passed} passed, {total_failed} failed, {total_skipped} skipped")
if total_failed > 0:
print("\n失败详情:")
for r in results:
for err in r.errors:
print(f" - [{r.protocol}] {err}")
sys.exit(1)
else:
print("\n🎉 所有测试通过!")
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,368 @@
#!/usr/bin/env python3
"""
UniAgent 完整测试脚本
启动测试服务器,测试所有协议的真实交互
"""
import asyncio
import json
import subprocess
import sys
import time
import signal
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from adapters import get_adapter
SERVERS = {}
def start_server(name: str, script: str, port: int) -> subprocess.Popen:
"""启动测试服务器"""
script_path = Path(__file__).parent.parent / "test_servers" / script
proc = subprocess.Popen(
[sys.executable, str(script_path)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
time.sleep(0.5)
if proc.poll() is not None:
stderr = proc.stderr.read().decode()
print(f"{name} 启动失败: {stderr}")
return None
print(f"{name} 启动成功 (port {port})")
return proc
def stop_servers():
"""停止所有服务器"""
for name, proc in SERVERS.items():
if proc and proc.poll() is None:
proc.terminate()
proc.wait(timeout=2)
async def test_anp():
"""测试 ANP 适配器"""
print("\n" + "=" * 50)
print("[ANP] Agent Network Protocol")
print("=" * 50)
adapter = get_adapter("anp")
config = {
"id": "amap",
"protocol": "anp",
"ad_url": "https://agent-connect.ai/mcp/agents/amap/ad.json"
}
try:
conn = await adapter.connect(config)
print(f"✅ 连接成功: {conn.endpoint[:50]}...")
result = await adapter.call(conn, "maps_weather", {"city": "北京"})
city = result.get("result", {}).get("city", "")
print(f"✅ maps_weather: {city}")
result = await adapter.call(conn, "maps_text_search", {"keywords": "咖啡厅", "city": "上海"})
pois = result.get("result", {}).get("pois", [])
print(f"✅ maps_text_search: 找到 {len(pois)} 个结果")
await adapter.close(conn)
print(f"✅ 关闭连接")
return True
except Exception as e:
print(f"❌ 测试失败: {e}")
return False
async def test_a2a():
"""测试 A2A 适配器"""
print("\n" + "=" * 50)
print("[A2A] Agent-to-Agent Protocol")
print("=" * 50)
adapter = get_adapter("a2a")
config = {
"id": "test_agent",
"protocol": "a2a",
"endpoint": "http://localhost:8100"
}
try:
conn = await adapter.connect(config)
print(f"✅ 连接成功")
methods = await adapter.get_methods(conn)
print(f"✅ 获取方法: {len(methods)} 个 (包含 skills)")
result = await adapter.call(conn, "tasks/send", {
"message": {
"role": "user",
"parts": [{"type": "text", "text": "Hello A2A!"}]
}
})
if result.get("success"):
task = result.get("result", {})
history = task.get("history", [])
if len(history) >= 2:
response = history[-1].get("parts", [{}])[0].get("text", "")
print(f"✅ tasks/send: {response}")
else:
print(f"✅ tasks/send: 任务已创建")
else:
print(f"❌ tasks/send 失败: {result}")
return False
await adapter.close(conn)
print(f"✅ 关闭连接")
return True
except Exception as e:
print(f"❌ 测试失败: {e}")
return False
async def test_aitp():
"""测试 AITP 适配器"""
print("\n" + "=" * 50)
print("[AITP] Agent Interaction & Transaction Protocol")
print("=" * 50)
adapter = get_adapter("aitp")
config = {
"id": "test_shop",
"protocol": "aitp",
"endpoint": "http://localhost:8101"
}
try:
conn = await adapter.connect(config)
print(f"✅ 连接成功 (Thread: {conn.session[:8]}...)")
result = await adapter.call(conn, "message", {"content": "Hello AITP!"})
if result.get("success"):
response = result.get("result", {}).get("content", "")
print(f"✅ message: {response}")
else:
print(f"❌ message 失败")
return False
result = await adapter.call(conn, "payment", {
"amount": 10,
"currency": "NEAR",
"recipient": "shop.near"
})
if result.get("success"):
payment = result.get("result", {}).get("payment_response", {})
status = payment.get("status", "")
tx_id = payment.get("transaction_id", "")[:8]
print(f"✅ payment: {status} (tx: {tx_id}...)")
else:
print(f"❌ payment 失败")
return False
result = await adapter.call(conn, "decision", {
"question": "选择颜色",
"options": ["红色", "蓝色", "绿色"]
})
if result.get("success"):
decision = result.get("result", {}).get("decision_response", {})
selected = decision.get("selected", "")
print(f"✅ decision: 选择了 {selected}")
else:
print(f"❌ decision 失败")
return False
await adapter.close(conn)
print(f"✅ 关闭连接")
return True
except Exception as e:
print(f"❌ 测试失败: {e}")
return False
async def test_agent_protocol():
"""测试 Agent Protocol 适配器"""
print("\n" + "=" * 50)
print("[AP] Agent Protocol")
print("=" * 50)
adapter = get_adapter("agent_protocol")
config = {
"id": "test_agent",
"protocol": "agent_protocol",
"endpoint": "http://localhost:8102"
}
try:
conn = await adapter.connect(config)
print(f"✅ 连接成功")
result = await adapter.call(conn, "create_task", {"input": "Hello Agent Protocol!"})
if result.get("success"):
task_id = result.get("task_id", "")
print(f"✅ create_task: {task_id[:8]}...")
else:
print(f"❌ create_task 失败")
return False
result = await adapter.call(conn, "execute_step", {
"task_id": task_id,
"input": "Process this"
})
if result.get("success"):
step = result.get("result", {})
output = step.get("output", "")
print(f"✅ execute_step: {output}")
else:
print(f"❌ execute_step 失败")
return False
result = await adapter.call(conn, "get_task", {"task_id": task_id})
if result.get("success"):
task = result.get("result", {})
status = task.get("status", "")
print(f"✅ get_task: status={status}")
else:
print(f"❌ get_task 失败")
return False
result = await adapter.call(conn, "get_artifacts", {"task_id": task_id})
if result.get("success"):
artifacts = result.get("result", {}).get("artifacts", [])
print(f"✅ get_artifacts: {len(artifacts)} 个产物")
else:
print(f"❌ get_artifacts 失败")
return False
await adapter.close(conn)
print(f"✅ 关闭连接")
return True
except Exception as e:
print(f"❌ 测试失败: {e}")
return False
async def test_lmos():
"""测试 LMOS 适配器"""
print("\n" + "=" * 50)
print("[LMOS] Language Model Operating System")
print("=" * 50)
adapter = get_adapter("lmos")
config = {
"id": "calculator",
"protocol": "lmos",
"endpoint": "http://localhost:8103/agents/calculator"
}
try:
conn = await adapter.connect(config)
print(f"✅ 连接成功")
result = await adapter.call(conn, "invoke", {
"capability": "add",
"input": {"a": 10, "b": 20}
})
if result.get("success"):
output = result.get("result", {}).get("output", {})
calc_result = output.get("result", "")
print(f"✅ invoke add(10, 20): {calc_result}")
else:
print(f"❌ invoke add 失败")
return False
result = await adapter.call(conn, "invoke", {
"capability": "multiply",
"input": {"a": 6, "b": 7}
})
if result.get("success"):
output = result.get("result", {}).get("output", {})
calc_result = output.get("result", "")
print(f"✅ invoke multiply(6, 7): {calc_result}")
else:
print(f"❌ invoke multiply 失败")
return False
greeter_config = {
"id": "greeter",
"protocol": "lmos",
"endpoint": "http://localhost:8103/agents/greeter"
}
conn2 = await adapter.connect(greeter_config)
result = await adapter.call(conn2, "invoke", {
"capability": "greet",
"input": {"name": "test_user"}
})
if result.get("success"):
output = result.get("result", {}).get("output", {})
greeting = output.get("greeting", "")
print(f"✅ invoke greet: {greeting}")
else:
print(f"❌ invoke greet 失败")
return False
await adapter.close(conn)
await adapter.close(conn2)
print(f"✅ 关闭连接")
return True
except Exception as e:
print(f"❌ 测试失败: {e}")
return False
async def main():
print("=" * 60)
print(" UniAgent 完整交互测试")
print("=" * 60)
print("\n[1] 启动测试服务器...")
SERVERS["A2A"] = start_server("A2A Server", "a2a_server.py", 8100)
SERVERS["AITP"] = start_server("AITP Server", "aitp_server.py", 8101)
SERVERS["AP"] = start_server("Agent Protocol Server", "agent_protocol_server.py", 8102)
SERVERS["LMOS"] = start_server("LMOS Server", "lmos_server.py", 8103)
time.sleep(1)
print("\n[2] 开始测试...")
results = {}
try:
results["ANP"] = await test_anp()
results["A2A"] = await test_a2a()
results["AITP"] = await test_aitp()
results["Agent Protocol"] = await test_agent_protocol()
results["LMOS"] = await test_lmos()
finally:
print("\n[3] 停止测试服务器...")
stop_servers()
print(" ✅ 所有服务器已停止")
print("\n" + "=" * 60)
print(" 测试汇总")
print("=" * 60)
all_passed = True
for name, passed in results.items():
status = "" if passed else ""
print(f" {status} {name}")
if not passed:
all_passed = False
print()
if all_passed:
print("🎉 所有协议测试通过!")
else:
print("⚠️ 部分测试失败")
sys.exit(1)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
stop_servers()
print("\n测试中断")

View File

@@ -0,0 +1,257 @@
#!/usr/bin/env python3
"""
UniAgent CLI - 统一智能体协议调用工具
用法:
# 调用 Agent
python uni_cli.py call amap@anp maps_weather '{"city":"北京"}'
python uni_cli.py call filesystem@mcp read_file '{"path":"/tmp/a.txt"}'
# 发现 Agent
python uni_cli.py discover weather
# 列出已注册 Agent
python uni_cli.py list
# 查看 Agent 方法
python uni_cli.py methods amap@anp
"""
import asyncio
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
import yaml
from adapters import get_adapter, ADAPTERS
CONFIG_DIR = Path(__file__).parent.parent / "config"
def load_agents_config():
"""加载 Agent 配置"""
agents_file = CONFIG_DIR / "agents.yaml"
if not agents_file.exists():
return {"agents": []}
with open(agents_file) as f:
return yaml.safe_load(f) or {"agents": []}
def parse_agent_id(agent_id: str) -> tuple:
"""解析 Agent ID返回 (name, protocol)"""
if "@" not in agent_id:
return agent_id, "anp"
parts = agent_id.rsplit("@", 1)
return parts[0], parts[1]
def get_agent_config(agent_name: str, protocol: str) -> dict:
"""获取 Agent 配置"""
config = load_agents_config()
for agent in config.get("agents", []):
if agent.get("id") == agent_name and agent.get("protocol") == protocol:
return agent
raise ValueError(f"未找到 Agent: {agent_name}@{protocol}")
async def call_agent(agent_id: str, method: str, params: dict):
"""调用 Agent"""
agent_name, protocol = parse_agent_id(agent_id)
print(f"协议: {protocol}")
print(f"Agent: {agent_name}")
print(f"方法: {method}")
print(f"参数: {json.dumps(params, ensure_ascii=False)}")
print()
agent_config = get_agent_config(agent_name, protocol)
adapter = get_adapter(protocol)
connection = await adapter.connect(agent_config)
try:
result = await adapter.call(connection, method, params)
print("=== 结果 ===")
print(json.dumps(result, indent=2, ensure_ascii=False))
finally:
await adapter.close(connection)
async def discover_agents(capability: str = ""):
"""发现 Agent"""
print(f"搜索能力: {capability or '全部'}\n")
all_agents = []
for protocol, adapter_class in ADAPTERS.items():
adapter = adapter_class()
agents = await adapter.discover(capability)
all_agents.extend(agents)
if not all_agents:
print("未找到匹配的 Agent")
return
print(f"找到 {len(all_agents)} 个 Agent:\n")
for agent in all_agents:
print(f" {agent.id}")
print(f" 名称: {agent.name}")
print(f" 协议: {agent.protocol}")
if agent.endpoint:
print(f" 端点: {agent.endpoint[:60]}...")
print()
async def list_agents():
"""列出所有已注册 Agent"""
config = load_agents_config()
agents = config.get("agents", [])
if not agents:
print("暂无已注册的 Agent")
print("请编辑 config/agents.yaml 添加 Agent")
return
print(f"\n已注册的 Agent ({len(agents)} 个):\n")
by_protocol = {}
for agent in agents:
protocol = agent.get("protocol", "unknown")
if protocol not in by_protocol:
by_protocol[protocol] = []
by_protocol[protocol].append(agent)
for protocol, protocol_agents in by_protocol.items():
print(f"[{protocol.upper()}]")
for agent in protocol_agents:
agent_id = f"{agent['id']}@{protocol}"
name = agent.get("name", agent["id"])
print(f" {agent_id}: {name}")
print()
async def show_methods(agent_id: str):
"""显示 Agent 支持的方法"""
agent_name, protocol = parse_agent_id(agent_id)
print(f"获取 {agent_name}@{protocol} 的方法列表...\n")
agent_config = get_agent_config(agent_name, protocol)
adapter = get_adapter(protocol)
connection = await adapter.connect(agent_config)
try:
methods = await adapter.get_methods(connection)
if not methods:
print("未获取到方法列表")
return
print(f"可用方法 ({len(methods)} 个):\n")
for m in methods[:30]:
name = m.get("name", "unknown")
desc = m.get("description", "")[:50]
print(f" - {name}: {desc}")
if len(methods) > 30:
print(f" ... 还有 {len(methods) - 30} 个方法")
finally:
await adapter.close(connection)
def show_help():
print("""
UniAgent - 统一智能体协议调用工具
用法:
python uni_cli.py <命令> [参数...]
命令:
call <agent_id> <method> <params> 调用 Agent 方法
discover [capability] 发现 Agent
list 列出已注册 Agent
methods <agent_id> 查看 Agent 方法
Agent ID 格式:
<name>@<protocol>
示例:
- amap@anp ANP 协议的高德地图
- filesystem@mcp MCP 协议的文件系统
支持的协议:
- anp ANP (Agent Network Protocol) - 去中心化 Agent 网络
- mcp MCP (Model Context Protocol) - LLM 工具调用
- a2a A2A (Agent-to-Agent) - Google Agent 协作
- aitp AITP (Agent Interaction & Transaction) - 交互交易
- agent_protocol Agent Protocol - REST API 标准 (别名: ap)
- lmos LMOS (Language Model OS) - 企业级 Agent 平台
示例:
# ANP - 查天气
python uni_cli.py call amap@anp maps_weather '{"city":"北京"}'
# MCP - 读文件
python uni_cli.py call filesystem@mcp read_file '{"path":"/tmp/a.txt"}'
# A2A - 发送任务
python uni_cli.py call assistant@a2a tasks/send '{"message":{"content":"hello"}}'
# AITP - 对话
python uni_cli.py call shop@aitp message '{"content":"我要买咖啡"}'
# Agent Protocol - 创建任务
python uni_cli.py call autogpt@ap create_task '{"input":"写代码"}'
# 发现 Agent
python uni_cli.py discover weather
""")
async def main():
if len(sys.argv) < 2:
show_help()
return
cmd = sys.argv[1]
if cmd in ["help", "-h", "--help"]:
show_help()
elif cmd == "call":
if len(sys.argv) < 5:
print("用法: python uni_cli.py call <agent_id> <method> '<params_json>'")
return
agent_id = sys.argv[2]
method = sys.argv[3]
params = json.loads(sys.argv[4])
await call_agent(agent_id, method, params)
elif cmd == "discover":
capability = sys.argv[2] if len(sys.argv) > 2 else ""
await discover_agents(capability)
elif cmd == "list":
await list_agents()
elif cmd == "methods":
if len(sys.argv) < 3:
print("用法: python uni_cli.py methods <agent_id>")
return
await show_methods(sys.argv[2])
else:
print(f"未知命令: {cmd}")
show_help()
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,107 @@
#!/bin/bash
#
# UniAgent 一键安装脚本
#
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$SCRIPT_DIR/config"
echo "=========================================="
echo " UniAgent - 统一智能体协议适配层"
echo " Connect Any Agent, Any Protocol"
echo "=========================================="
echo ""
# 1. 检查 Python
echo "[1/4] 检查 Python 环境..."
if ! command -v python3 &> /dev/null; then
echo "❌ 未找到 Python3请先安装 Python 3.8+"
exit 1
fi
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
echo "✅ Python $PYTHON_VERSION"
# 2. 安装依赖
echo ""
echo "[2/4] 安装 Python 依赖..."
pip3 install -q pyyaml aiohttp anp --break-system-packages 2>/dev/null || pip3 install -q pyyaml aiohttp anp --user 2>/dev/null || pip3 install -q pyyaml aiohttp anp
echo "✅ 依赖安装完成"
# 3. 检查/生成 DID 身份(用于 ANP
echo ""
echo "[3/4] 配置 DID 身份 (ANP 协议)..."
if [ -f "$CONFIG_DIR/did.json" ] && [ -f "$CONFIG_DIR/private-key.pem" ]; then
echo "✅ 已存在 DID 身份,跳过生成"
DID_ID=$(python3 -c "import json; print(json.load(open('$CONFIG_DIR/did.json'))['id'])" 2>/dev/null || echo "unknown")
echo " DID: $DID_ID"
else
echo "⚙️ 生成本地临时身份..."
# 生成 secp256k1 私钥
openssl ecparam -name secp256k1 -genkey -noout -out "$CONFIG_DIR/private-key.pem" 2>/dev/null
# 生成随机 ID
RANDOM_ID=$(openssl rand -hex 8)
# 创建 DID 文档
cat > "$CONFIG_DIR/did.json" << EOF
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1-2019/v1"
],
"id": "did:wba:local:user:$RANDOM_ID",
"verificationMethod": [
{
"id": "did:wba:local:user:$RANDOM_ID#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:wba:local:user:$RANDOM_ID"
}
],
"authentication": [
"did:wba:local:user:$RANDOM_ID#key-1"
]
}
EOF
echo "✅ 本地身份生成完成"
echo " DID: did:wba:local:user:$RANDOM_ID"
fi
# 4. 验证安装
echo ""
echo "[4/4] 验证安装..."
cd "$SCRIPT_DIR"
if python3 scripts/uni_cli.py list &> /dev/null; then
echo "✅ 安装成功!"
else
echo "⚠️ 安装可能有问题,请检查错误信息"
fi
echo ""
echo "=========================================="
echo " 安装完成!"
echo "=========================================="
echo ""
echo "支持的协议:"
echo " - ANP (Agent Network Protocol) ✅ 已实现"
echo " - MCP (Model Context Protocol) ✅ 已实现"
echo " - A2A (Agent-to-Agent) ✅ 已实现"
echo " - AITP (Agent Interaction & Tx) ✅ 已实现"
echo " - AP (Agent Protocol) ✅ 已实现"
echo " - LMOS (Eclipse LMOS) ✅ 已实现"
echo ""
echo "快速开始:"
echo ""
echo " # 列出已注册 Agent"
echo " python scripts/uni_cli.py list"
echo ""
echo " # 调用 ANP Agent 查天气"
echo " python scripts/uni_cli.py call amap@anp maps_weather '{\"city\":\"北京\"}'"
echo ""
echo " # 查看 Agent 方法"
echo " python scripts/uni_cli.py methods amap@anp"
echo ""

View File

@@ -0,0 +1,165 @@
#!/usr/bin/env python3
"""
A2A 测试服务器 - 简单的 Echo Agent
HTTP 服务,提供 Agent Card 和 JSON-RPC 端点
"""
import json
import uuid
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse
PORT = 8100
class A2AHandler(BaseHTTPRequestHandler):
tasks = {}
def log_message(self, format, *args):
pass
def send_json(self, data: dict, status: int = 200):
body = json.dumps(data, ensure_ascii=False).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", len(body))
self.end_headers()
self.wfile.write(body)
def do_GET(self):
path = urlparse(self.path).path
if path == "/.well-known/agent.json":
self.send_json({
"name": "Test A2A Agent",
"description": "A simple echo agent for testing",
"url": f"http://localhost:{PORT}/rpc",
"version": "1.0.0",
"capabilities": {
"streaming": False,
"pushNotifications": False
},
"skills": [
{
"id": "echo",
"name": "Echo",
"description": "Echo back the message",
"inputSchema": {
"type": "object",
"properties": {
"message": {"type": "string"}
}
}
},
{
"id": "greet",
"name": "Greet",
"description": "Greet the user",
"inputSchema": {
"type": "object",
"properties": {
"name": {"type": "string"}
}
}
}
],
"authentication": {
"schemes": ["none"]
}
})
else:
self.send_json({"error": "Not found"}, 404)
def do_POST(self):
path = urlparse(self.path).path
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
try:
request = json.loads(body)
except json.JSONDecodeError:
self.send_json({"error": "Invalid JSON"}, 400)
return
if path == "/rpc":
self.handle_rpc(request)
else:
self.send_json({"error": "Not found"}, 404)
def handle_rpc(self, request: dict):
method = request.get("method", "")
params = request.get("params", {})
req_id = request.get("id", str(uuid.uuid4()))
if method == "tasks/send":
task_id = params.get("id", str(uuid.uuid4()))
message = params.get("message", {})
content = message.get("parts", [{}])[0].get("text", "") if "parts" in message else message.get("content", "")
response_text = f"Echo: {content}"
A2AHandler.tasks[task_id] = {
"id": task_id,
"status": {"state": "completed"},
"history": [
message,
{"role": "agent", "parts": [{"type": "text", "text": response_text}]}
]
}
self.send_json({
"jsonrpc": "2.0",
"id": req_id,
"result": A2AHandler.tasks[task_id]
})
elif method == "tasks/get":
task_id = params.get("id", "")
if task_id in A2AHandler.tasks:
self.send_json({
"jsonrpc": "2.0",
"id": req_id,
"result": A2AHandler.tasks[task_id]
})
else:
self.send_json({
"jsonrpc": "2.0",
"id": req_id,
"error": {"code": -32000, "message": "Task not found"}
})
elif method == "tasks/cancel":
task_id = params.get("id", "")
if task_id in A2AHandler.tasks:
A2AHandler.tasks[task_id]["status"]["state"] = "canceled"
self.send_json({
"jsonrpc": "2.0",
"id": req_id,
"result": {"success": True}
})
else:
self.send_json({
"jsonrpc": "2.0",
"id": req_id,
"error": {"code": -32000, "message": "Task not found"}
})
else:
self.send_json({
"jsonrpc": "2.0",
"id": req_id,
"error": {"code": -32601, "message": f"Unknown method: {method}"}
})
def main():
server = HTTPServer(("localhost", PORT), A2AHandler)
print(f"A2A Test Server running on http://localhost:{PORT}")
print(f"Agent Card: http://localhost:{PORT}/.well-known/agent.json")
server.serve_forever()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,146 @@
#!/usr/bin/env python3
"""
Agent Protocol 测试服务器
REST API 标准实现
"""
import json
import uuid
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse
from datetime import datetime
PORT = 8102
class APHandler(BaseHTTPRequestHandler):
tasks = {}
def log_message(self, format, *args):
pass
def send_json(self, data: dict, status: int = 200):
body = json.dumps(data, ensure_ascii=False).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", len(body))
self.end_headers()
self.wfile.write(body)
def do_GET(self):
path = urlparse(self.path).path
if path == "/" or path == "/ap/v1":
self.send_json({
"name": "Test Agent Protocol Server",
"version": "1.0.0",
"protocol_version": "v1"
})
elif path == "/ap/v1/agent/tasks":
self.send_json({
"tasks": list(APHandler.tasks.values())
})
elif path.startswith("/ap/v1/agent/tasks/"):
parts = path.split("/")
task_id = parts[5] if len(parts) > 5 else ""
if "/artifacts" in path:
if task_id in APHandler.tasks:
self.send_json({
"artifacts": APHandler.tasks[task_id].get("artifacts", [])
})
else:
self.send_json({"error": "Task not found"}, 404)
elif "/steps" in path:
if task_id in APHandler.tasks:
self.send_json({
"steps": APHandler.tasks[task_id].get("steps", [])
})
else:
self.send_json({"error": "Task not found"}, 404)
else:
if task_id in APHandler.tasks:
self.send_json(APHandler.tasks[task_id])
else:
self.send_json({"error": "Task not found"}, 404)
else:
self.send_json({"error": "Not found"}, 404)
def do_POST(self):
path = urlparse(self.path).path
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
try:
request = json.loads(body) if body else {}
except json.JSONDecodeError:
self.send_json({"error": "Invalid JSON"}, 400)
return
if path == "/ap/v1/agent/tasks":
task_id = str(uuid.uuid4())
task_input = request.get("input", "")
APHandler.tasks[task_id] = {
"task_id": task_id,
"input": task_input,
"status": "running",
"steps": [],
"artifacts": [],
"created_at": datetime.now().isoformat()
}
self.send_json(APHandler.tasks[task_id], 201)
elif path.startswith("/ap/v1/agent/tasks/") and path.endswith("/steps"):
parts = path.split("/")
task_id = parts[5]
if task_id not in APHandler.tasks:
self.send_json({"error": "Task not found"}, 404)
return
step_input = request.get("input", "")
step_id = str(uuid.uuid4())
step = {
"step_id": step_id,
"input": step_input,
"output": f"Processed: {step_input}" if step_input else "Step executed",
"status": "completed",
"is_last": True,
"created_at": datetime.now().isoformat()
}
APHandler.tasks[task_id]["steps"].append(step)
APHandler.tasks[task_id]["status"] = "completed"
APHandler.tasks[task_id]["artifacts"].append({
"artifact_id": str(uuid.uuid4()),
"file_name": "output.txt",
"relative_path": "/output.txt",
"content": step["output"]
})
self.send_json(step, 201)
else:
self.send_json({"error": "Not found"}, 404)
def main():
server = HTTPServer(("localhost", PORT), APHandler)
print(f"Agent Protocol Test Server running on http://localhost:{PORT}")
print(f"API Base: http://localhost:{PORT}/ap/v1")
server.serve_forever()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,160 @@
#!/usr/bin/env python3
"""
AITP 测试服务器 - 模拟交互与交易
HTTP 服务,支持 Thread 会话
"""
import json
import uuid
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse
from datetime import datetime
PORT = 8101
class AITPHandler(BaseHTTPRequestHandler):
threads = {}
def log_message(self, format, *args):
pass
def send_json(self, data: dict, status: int = 200):
body = json.dumps(data, ensure_ascii=False).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", len(body))
self.end_headers()
self.wfile.write(body)
def do_GET(self):
path = urlparse(self.path).path
if path == "/":
self.send_json({
"name": "Test AITP Agent",
"description": "A simple AITP agent for testing",
"version": "1.0.0",
"capabilities": ["aitp-01", "aitp-02", "aitp-03"]
})
elif path.startswith("/threads/"):
parts = path.split("/")
if len(parts) >= 3:
thread_id = parts[2]
if thread_id in AITPHandler.threads:
self.send_json(AITPHandler.threads[thread_id])
else:
self.send_json({"error": "Thread not found"}, 404)
else:
self.send_json({"error": "Not found"}, 404)
def do_POST(self):
path = urlparse(self.path).path
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
try:
request = json.loads(body)
except json.JSONDecodeError:
self.send_json({"error": "Invalid JSON"}, 400)
return
if path == "/threads":
thread_id = str(uuid.uuid4())
AITPHandler.threads[thread_id] = {
"id": thread_id,
"status": "open",
"messages": [],
"created_at": datetime.now().isoformat()
}
self.send_json({"thread_id": thread_id})
elif path.startswith("/threads/") and path.endswith("/messages"):
parts = path.split("/")
thread_id = parts[2]
if thread_id not in AITPHandler.threads:
AITPHandler.threads[thread_id] = {
"id": thread_id,
"status": "open",
"messages": [],
"created_at": datetime.now().isoformat()
}
thread = AITPHandler.threads[thread_id]
if "capability" in request:
capability = request.get("capability")
if capability == "aitp-01":
payment_req = request.get("payment_request", {})
response = {
"role": "agent",
"capability": "aitp-01",
"payment_response": {
"status": "approved",
"transaction_id": str(uuid.uuid4()),
"amount": payment_req.get("amount"),
"currency": payment_req.get("currency", "NEAR"),
"timestamp": datetime.now().isoformat()
}
}
elif capability == "aitp-02":
decision_req = request.get("decision_request", {})
response = {
"role": "agent",
"capability": "aitp-02",
"decision_response": {
"question": decision_req.get("question"),
"selected": decision_req.get("options", ["Yes"])[0] if decision_req.get("options") else "Yes"
}
}
elif capability == "aitp-03":
data_req = request.get("data_request", {})
response = {
"role": "agent",
"capability": "aitp-03",
"data_response": {
"schema": data_req.get("schema", {}),
"data": {"sample": "test_data", "timestamp": datetime.now().isoformat()}
}
}
else:
response = {
"role": "agent",
"error": f"Unknown capability: {capability}"
}
else:
message = request.get("message", {})
content = message.get("content", "")
response = {
"role": "agent",
"content": f"AITP Echo: {content}",
"timestamp": datetime.now().isoformat()
}
thread["messages"].append(request)
thread["messages"].append(response)
self.send_json(response)
else:
self.send_json({"error": "Not found"}, 404)
def main():
server = HTTPServer(("localhost", PORT), AITPHandler)
print(f"AITP Test Server running on http://localhost:{PORT}")
server.serve_forever()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,169 @@
#!/usr/bin/env python3
"""
LMOS 测试服务器 - 模拟企业级 Agent 平台
包含注册中心和 Agent 能力调用
"""
import json
import uuid
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
from datetime import datetime
PORT = 8103
MOCK_AGENTS = [
{
"id": "calculator",
"name": "Calculator Agent",
"description": "Performs calculations",
"endpoint": f"http://localhost:{PORT}/agents/calculator",
"capabilities": [
{"id": "add", "description": "Add two numbers"},
{"id": "multiply", "description": "Multiply two numbers"}
]
},
{
"id": "greeter",
"name": "Greeter Agent",
"description": "Greets users",
"endpoint": f"http://localhost:{PORT}/agents/greeter",
"capabilities": [
{"id": "greet", "description": "Greet a user by name"}
]
}
]
class LMOSHandler(BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
def send_json(self, data: dict, status: int = 200):
body = json.dumps(data, ensure_ascii=False).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", len(body))
self.end_headers()
self.wfile.write(body)
def do_GET(self):
parsed = urlparse(self.path)
path = parsed.path
query = parse_qs(parsed.query)
if path == "/":
self.send_json({
"name": "Test LMOS Registry",
"version": "1.0.0",
"agents": len(MOCK_AGENTS)
})
elif path == "/agents":
capability = query.get("capability", [None])[0]
if capability:
filtered = [
a for a in MOCK_AGENTS
if any(c["id"] == capability for c in a["capabilities"])
]
self.send_json({"agents": filtered})
else:
self.send_json({"agents": MOCK_AGENTS})
elif path.startswith("/agents/") and path.endswith("/capabilities"):
agent_id = path.split("/")[2]
agent = next((a for a in MOCK_AGENTS if a["id"] == agent_id), None)
if agent:
self.send_json({"capabilities": agent["capabilities"]})
else:
self.send_json({"error": "Agent not found"}, 404)
else:
self.send_json({"error": "Not found"}, 404)
def do_POST(self):
parsed = urlparse(self.path)
path = parsed.path
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
try:
request = json.loads(body) if body else {}
except json.JSONDecodeError:
self.send_json({"error": "Invalid JSON"}, 400)
return
if path.startswith("/agents/") and path.endswith("/invoke"):
agent_id = path.split("/")[2]
agent = next((a for a in MOCK_AGENTS if a["id"] == agent_id), None)
if not agent:
self.send_json({"error": "Agent not found"}, 404)
return
capability = request.get("capability", "")
input_data = request.get("input", {})
if agent_id == "calculator":
if capability == "add":
a = input_data.get("a", 0)
b = input_data.get("b", 0)
result = {"result": a + b}
elif capability == "multiply":
a = input_data.get("a", 0)
b = input_data.get("b", 0)
result = {"result": a * b}
else:
result = {"error": f"Unknown capability: {capability}"}
elif agent_id == "greeter":
if capability == "greet":
name = input_data.get("name", "World")
result = {"greeting": f"Hello, {name}!"}
else:
result = {"error": f"Unknown capability: {capability}"}
else:
result = {"error": "Unknown agent"}
self.send_json({
"agent_id": agent_id,
"capability": capability,
"output": result,
"timestamp": datetime.now().isoformat()
})
elif path == "/route":
query_text = request.get("query", "")
if "add" in query_text.lower() or "calculate" in query_text.lower():
best_agent = MOCK_AGENTS[0]
elif "greet" in query_text.lower() or "hello" in query_text.lower():
best_agent = MOCK_AGENTS[1]
else:
best_agent = MOCK_AGENTS[0]
self.send_json({
"recommended_agent": best_agent,
"confidence": 0.85,
"alternatives": [a for a in MOCK_AGENTS if a["id"] != best_agent["id"]]
})
else:
self.send_json({"error": "Not found"}, 404)
def main():
server = HTTPServer(("localhost", PORT), LMOSHandler)
print(f"LMOS Test Server running on http://localhost:{PORT}")
print(f"Registry: http://localhost:{PORT}/agents")
server.serve_forever()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,161 @@
#!/usr/bin/env python3
"""
MCP 测试服务器 - 简单的 Echo + 计算器
通过 stdio 通信
"""
import json
import sys
from datetime import datetime
def send_response(id: str, result: dict):
"""发送 JSON-RPC 响应"""
response = {
"jsonrpc": "2.0",
"id": id,
"result": result
}
msg = json.dumps(response)
sys.stdout.write(f"Content-Length: {len(msg)}\r\n\r\n{msg}")
sys.stdout.flush()
def send_error(id: str, code: int, message: str):
"""发送错误响应"""
response = {
"jsonrpc": "2.0",
"id": id,
"error": {"code": code, "message": message}
}
msg = json.dumps(response)
sys.stdout.write(f"Content-Length: {len(msg)}\r\n\r\n{msg}")
sys.stdout.flush()
def handle_request(request: dict):
"""处理请求"""
method = request.get("method", "")
params = request.get("params", {})
req_id = request.get("id", "0")
if method == "initialize":
send_response(req_id, {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {"listChanged": True}
},
"serverInfo": {
"name": "test-mcp-server",
"version": "1.0.0"
}
})
elif method == "notifications/initialized":
pass
elif method == "tools/list":
send_response(req_id, {
"tools": [
{
"name": "echo",
"description": "返回输入的消息",
"inputSchema": {
"type": "object",
"properties": {
"message": {"type": "string", "description": "要返回的消息"}
},
"required": ["message"]
}
},
{
"name": "add",
"description": "两数相加",
"inputSchema": {
"type": "object",
"properties": {
"a": {"type": "number"},
"b": {"type": "number"}
},
"required": ["a", "b"]
}
},
{
"name": "get_time",
"description": "获取当前时间",
"inputSchema": {"type": "object", "properties": {}}
}
]
})
elif method == "tools/call":
tool_name = params.get("name", "")
tool_args = params.get("arguments", {})
if tool_name == "echo":
msg = tool_args.get("message", "")
send_response(req_id, {
"content": [{"type": "text", "text": f"Echo: {msg}"}]
})
elif tool_name == "add":
a = tool_args.get("a", 0)
b = tool_args.get("b", 0)
send_response(req_id, {
"content": [{"type": "text", "text": str(a + b)}]
})
elif tool_name == "get_time":
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
send_response(req_id, {
"content": [{"type": "text", "text": now}]
})
else:
send_error(req_id, -32601, f"Unknown tool: {tool_name}")
else:
send_error(req_id, -32601, f"Unknown method: {method}")
def main():
"""主循环 - 读取 stdin处理请求"""
buffer = ""
while True:
try:
line = sys.stdin.readline()
if not line:
break
buffer += line
if "Content-Length:" in buffer:
parts = buffer.split("\r\n\r\n", 1)
if len(parts) == 2:
header, body = parts
length = int(header.split(":")[1].strip())
while len(body) < length:
body += sys.stdin.read(length - len(body))
request = json.loads(body[:length])
handle_request(request)
buffer = body[length:]
elif buffer.strip().startswith("{"):
try:
request = json.loads(buffer.strip())
handle_request(request)
buffer = ""
except json.JSONDecodeError:
pass
except Exception as e:
sys.stderr.write(f"Error: {e}\n")
sys.stderr.flush()
if __name__ == "__main__":
main()