Files
taiji-AI-PAD/services/mcp-server/app/agent_manager_client.py
T

1041 lines
32 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
AI Agent Manager API 客户端
封装对 AI Agent Manager 服务的 HTTP 调用
适配 Agent Manager 实际接口(基于 agent-manager接口文档.md)
"""
import os
import httpx
import structlog
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field
from enum import Enum
logger = structlog.get_logger(__name__)
# 从环境变量获取 Agent Manager URL
AGENT_MANAGER_URL = os.getenv("AGENT_MANAGER_URL", "http://localhost:8000")
class AgentStatus(str, Enum):
"""Agent Pod 状态"""
PENDING = "Pending"
RUNNING = "Running"
SUCCEEDED = "Succeeded"
FAILED = "Failed"
UNKNOWN = "Unknown"
@dataclass
class AgentConfig:
"""
Agent 资源配置
适配 Agent Manager POST /agents 接口的 config 参数
"""
user_id: Optional[str] = None # 用户标识,用于多租户管理
cpu_request: Optional[str] = "100m"
cpu_limit: Optional[str] = "500m"
memory_request: Optional[str] = "128Mi"
memory_limit: Optional[str] = "512Mi"
def to_dict(self) -> Dict[str, Any]:
"""转换为 API 请求格式"""
result = {}
if self.user_id:
result["user_id"] = self.user_id
if self.cpu_request:
result["cpu_request"] = self.cpu_request
if self.cpu_limit:
result["cpu_limit"] = self.cpu_limit
if self.memory_request:
result["memory_request"] = self.memory_request
if self.memory_limit:
result["memory_limit"] = self.memory_limit
return result
@dataclass
class TemplateInfo:
"""
模板信息
适配 Agent Manager GET /templates 接口响应
"""
template: str
port: Optional[int] = None
env_info: Dict[str, Any] = field(default_factory=dict)
template_type: Optional[str] = None # platform 或 custom
@dataclass
class AgentCreateResult:
"""
Agent 创建结果
适配 Agent Manager POST /agents 接口响应
"""
name: str
namespace: str
status: str
created_at: str
template: str
service_port: Optional[int] = None
access_info: Optional[Dict[str, Any]] = None
# 新增字段(适配实际接口响应)
pod_id: Optional[str] = None
pod_ip: Optional[str] = None
host_ip: Optional[str] = None
node_name: Optional[str] = None
owner_info: Optional[Dict[str, Any]] = None
@dataclass
class AgentStatusResult:
"""
Agent 状态结果
适配 Agent Manager GET /agents/{name}/status 接口响应
"""
name: str
namespace: str
status: str
created_at: Optional[str] = None
pod_ip: Optional[str] = None
node_name: Optional[str] = None
labels: Optional[Dict[str, str]] = None
# 兼容旧字段
template: Optional[str] = None
endpoints: Optional[Dict[str, str]] = None
@dataclass
class AgentMetricsResult:
"""
Agent 资源使用结果
适配 Agent Manager GET /agents/{name}/metrics 接口响应
Agent Manager 实际返回格式:
{
"name": "alice-echo",
"namespace": "ai-agents",
"requests": {
"cpu": "100m",
"memory": "128Mi"
},
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"usage": {
"cpu": "14502n",
"memory": "8704Ki"
},
"timestamp": "2026-01-06T05:01:04Z",
"metrics_available": null
}
字段说明:
- requests/limits: 资源配额(从 Pod spec 获取)
- usage: 实时资源使用(从 metrics-server 获取,需要集群安装 metrics-server)
- timestamp: metrics 数据的时间戳(ISO 8601 格式)
- metrics_available: metrics-server 是否可用
CPU 单位说明:
- n (nanocores): 1 核 = 1,000,000,000n
- m (millicores): 1 核 = 1,000m
- 例如: 14502n = 0.014502m ≈ 0.000014 核
内存单位说明:
- Ki (Kibibytes): 1024 字节
- Mi (Mebibytes): 1024 KiB
- 例如: 8704Ki ≈ 8.5 MiB
"""
name: str
namespace: str = "ai-agents"
requests: Dict[str, str] = field(default_factory=dict)
limits: Dict[str, str] = field(default_factory=dict)
# 新增:实时资源使用(从 metrics-server 获取)
usage: Optional[Dict[str, str]] = None
# 新增:metrics 数据时间戳
timestamp: Optional[str] = None
# 新增:metrics-server 是否可用
metrics_available: Optional[bool] = None
# 兼容旧格式
resources: Dict[str, Any] = field(default_factory=dict)
@staticmethod
def _parse_cpu_to_millicores(cpu_str: str) -> float:
"""
将 CPU 字符串转换为毫核(millicores)
支持的单位:
- n (nanocores): 1m = 1,000,000n
- m (millicores): 直接使用
- 无单位: 视为核数,乘以 1000
Args:
cpu_str: CPU 字符串,如 "100m", "14502n", "0.5"
Returns:
毫核数(float)
"""
if not cpu_str or cpu_str == "0":
return 0.0
cpu_str = str(cpu_str).strip()
try:
if cpu_str.endswith("n"):
# nanocores -> millicores: 1m = 1,000,000n
return float(cpu_str[:-1]) / 1_000_000
elif cpu_str.endswith("m"):
# millicores
return float(cpu_str[:-1])
else:
# 核数 -> millicores
return float(cpu_str) * 1000
except ValueError:
return 0.0
@staticmethod
def _parse_memory_to_mb(mem_str: str) -> float:
"""
将内存字符串转换为 MB
支持的单位:
- Ki (Kibibytes): 1 MiB = 1024 KiB
- Mi (Mebibytes): 直接使用
- Gi (Gibibytes): 1 GiB = 1024 MiB
- K (Kilobytes): 1 MB = 1000 KB
- M (Megabytes): 直接使用
- G (Gigabytes): 1 GB = 1000 MB
- 无单位: 视为字节
Args:
mem_str: 内存字符串,如 "128Mi", "8704Ki", "1Gi"
Returns:
MB 数(float)
"""
if not mem_str or mem_str == "0":
return 0.0
mem_str = str(mem_str).strip()
try:
# 二进制单位(IEC)
if mem_str.endswith("Ki"):
return float(mem_str[:-2]) / 1024
elif mem_str.endswith("Mi"):
return float(mem_str[:-2])
elif mem_str.endswith("Gi"):
return float(mem_str[:-2]) * 1024
elif mem_str.endswith("Ti"):
return float(mem_str[:-2]) * 1024 * 1024
# 十进制单位(SI)
elif mem_str.endswith("K"):
return float(mem_str[:-1]) / 1000
elif mem_str.endswith("M"):
return float(mem_str[:-1])
elif mem_str.endswith("G"):
return float(mem_str[:-1]) * 1000
elif mem_str.endswith("T"):
return float(mem_str[:-1]) * 1000 * 1000
else:
# 字节 -> MB
return float(mem_str) / (1024 * 1024)
except ValueError:
return 0.0
@property
def cpu_request(self) -> str:
"""获取 CPU 请求量(如 '100m')"""
return self.requests.get("cpu", "0")
@property
def memory_request(self) -> str:
"""获取内存请求量(如 '128Mi')"""
return self.requests.get("memory", "0")
@property
def cpu_limit(self) -> str:
"""获取 CPU 限制(如 '500m')"""
return self.limits.get("cpu", "0")
@property
def memory_limit(self) -> str:
"""获取内存限制(如 '512Mi')"""
return self.limits.get("memory", "0")
@property
def cpu_usage_current(self) -> str:
"""获取当前 CPU 使用量(如 '14502n')"""
if self.usage:
return self.usage.get("cpu", "0")
return "0"
@property
def memory_usage_current(self) -> str:
"""获取当前内存使用量(如 '8704Ki')"""
if self.usage:
return self.usage.get("memory", "0")
return "0"
# 兼容旧的 cpu_usage/memory_usage 属性名(使用 limits 作为显示值)
@property
def cpu_usage(self) -> str:
"""获取 CPU 限制(兼容旧属性名)"""
return self.cpu_limit
@property
def memory_usage(self) -> str:
"""获取内存限制(兼容旧属性名)"""
return self.memory_limit
@property
def available(self) -> bool:
"""是否可用(基于是否有 limits 配置)"""
return bool(self.limits.get("cpu") or self.limits.get("memory"))
@property
def has_realtime_metrics(self) -> bool:
"""是否有实时 metrics 数据"""
return self.usage is not None and bool(self.usage)
@property
def cpu_limit_millicores(self) -> float:
"""获取 CPU 限制(毫核,如 500m -> 500.0)"""
return self._parse_cpu_to_millicores(self.cpu_limit)
@property
def cpu_request_millicores(self) -> float:
"""获取 CPU 请求量(毫核)"""
return self._parse_cpu_to_millicores(self.cpu_request)
@property
def cpu_usage_current_millicores(self) -> float:
"""获取当前 CPU 使用量(毫核)"""
return self._parse_cpu_to_millicores(self.cpu_usage_current)
@property
def memory_limit_mb(self) -> float:
"""获取内存限制(MB)"""
return self._parse_memory_to_mb(self.memory_limit)
@property
def memory_request_mb(self) -> float:
"""获取内存请求量(MB)"""
return self._parse_memory_to_mb(self.memory_request)
@property
def memory_usage_current_mb(self) -> float:
"""获取当前内存使用量(MB)"""
return self._parse_memory_to_mb(self.memory_usage_current)
@property
def cpu_utilization_percent(self) -> Optional[float]:
"""
获取 CPU 使用率(相对于 limit 的百分比)
Returns:
使用率百分比,如果没有实时数据则返回 None
"""
if not self.has_realtime_metrics:
return None
limit = self.cpu_limit_millicores
if limit <= 0:
return None
usage = self.cpu_usage_current_millicores
return (usage / limit) * 100
@property
def memory_utilization_percent(self) -> Optional[float]:
"""
获取内存使用率(相对于 limit 的百分比)
Returns:
使用率百分比,如果没有实时数据则返回 None
"""
if not self.has_realtime_metrics:
return None
limit = self.memory_limit_mb
if limit <= 0:
return None
usage = self.memory_usage_current_mb
return (usage / limit) * 100
# 兼容旧属性名
@property
def cpu_usage_millicores(self) -> float:
"""获取 CPU 限制(毫核,兼容旧属性名)"""
return self.cpu_limit_millicores
@property
def memory_usage_mb(self) -> float:
"""获取内存限制(MB,兼容旧属性名)"""
return self.memory_limit_mb
@dataclass
class AgentListResult:
"""
Agent 列表结果
适配 Agent Manager GET /agents 接口响应
"""
agents: List[Dict[str, Any]]
count: int
class AgentManagerError(Exception):
"""Agent Manager API 错误"""
def __init__(self, message: str, status_code: int = 500, detail: Any = None):
self.message = message
self.status_code = status_code
self.detail = detail
super().__init__(message)
class AgentManagerClient:
"""
AI Agent Manager API 客户端
适配 Agent Manager 实际接口:
- POST /agents - 创建 Agent
- GET /agents - 获取所有 Agent
- GET /agents/{name}/status - 获取 Agent 状态
- GET /agents/{name}/metrics - 获取资源使用情况
- DELETE /agents/{name} - 删除 Agent
- GET /templates - 获取所有模板
- GET /templates/platform - 获取平台模板
- GET /templates/custom - 获取自定义模板
- GET /templates/{name} - 获取模板详情
- GET / - 健康检查
"""
def __init__(self, base_url: Optional[str] = None, timeout: float = 30.0):
"""
初始化客户端
Args:
base_url: API 基础 URL,默认从环境变量获取
timeout: 请求超时时间(秒)
"""
self.base_url = (base_url or AGENT_MANAGER_URL).rstrip("/")
self.timeout = timeout
self._client: Optional[httpx.AsyncClient] = None
async def _get_client(self) -> httpx.AsyncClient:
"""获取或创建 HTTP 客户端"""
if self._client is None or self._client.is_closed:
self._client = httpx.AsyncClient(
base_url=self.base_url,
timeout=self.timeout,
headers={"Content-Type": "application/json"}
)
return self._client
async def close(self):
"""关闭客户端"""
if self._client and not self._client.is_closed:
await self._client.aclose()
self._client = None
async def _request(
self,
method: str,
path: str,
json: Optional[Dict] = None,
params: Optional[Dict] = None
) -> Dict[str, Any]:
"""
发送 HTTP 请求
Args:
method: HTTP 方法
path: API 路径
json: 请求体
params: 查询参数
Returns:
响应 JSON
Raises:
AgentManagerError: API 调用失败
"""
client = await self._get_client()
try:
response = await client.request(
method=method,
url=path,
json=json,
params=params
)
if response.status_code >= 400:
try:
detail = response.json()
except Exception:
detail = response.text
logger.error(
"agent_manager_api_error",
method=method,
path=path,
status_code=response.status_code,
detail=detail
)
raise AgentManagerError(
message=f"API 调用失败: {response.status_code}",
status_code=response.status_code,
detail=detail
)
return response.json()
except httpx.RequestError as e:
logger.error(
"agent_manager_connection_error",
method=method,
path=path,
error=str(e)
)
raise AgentManagerError(
message=f"连接 Agent Manager 失败: {str(e)}",
status_code=503,
detail={"error": "connection_error", "message": str(e)}
)
# ==================== 健康检查 ====================
async def health_check(self) -> Dict[str, Any]:
"""
检查 Agent Manager 服务状态
调用: GET /
Returns:
服务状态信息,包含:
- service: 服务名称
- version: 版本
- status: 状态
"""
return await self._request("GET", "/")
# ==================== 模板管理 ====================
async def list_templates(self) -> List[TemplateInfo]:
"""
获取所有可用模板
调用: GET /templates
Returns:
模板列表
"""
data = await self._request("GET", "/templates")
templates = []
for t in data.get("templates", []):
templates.append(TemplateInfo(
template=t["template"],
port=t.get("port"),
env_info=t.get("env_info", {})
))
return templates
async def list_platform_templates(self) -> List[TemplateInfo]:
"""
获取所有平台 Agent 模板
调用: GET /templates/platform
平台 Agent 模板是预定义的、由平台管理的 Agent 类型。
Returns:
平台模板列表
"""
data = await self._request("GET", "/templates/platform")
templates = []
for t in data.get("templates", []):
templates.append(TemplateInfo(
template=t["template"],
port=t.get("port"),
env_info=t.get("env_info", {}),
template_type="platform"
))
return templates
async def list_custom_templates(self) -> List[TemplateInfo]:
"""
获取所有自定义 Agent 模板
调用: GET /templates/custom
自定义 Agent 模板需要用户配置环境变量(如 API Key)。
Returns:
自定义模板列表,每个模板的 env_info 包含:
- required: 必需的环境变量
- optional: 可选的环境变量
"""
data = await self._request("GET", "/templates/custom")
templates = []
for t in data.get("templates", []):
templates.append(TemplateInfo(
template=t["template"],
port=t.get("port"),
env_info=t.get("env_info", {}),
template_type="custom"
))
return templates
async def get_template(self, template_name: str) -> TemplateInfo:
"""
获取模板详情
调用: GET /templates/{template_name}
Args:
template_name: 模板名称
Returns:
模板信息
"""
data = await self._request("GET", f"/templates/{template_name}")
return TemplateInfo(
template=data["template"],
port=data.get("port"),
env_info=data.get("env_info", {})
)
# ==================== Agent 管理 ====================
async def create_agent(
self,
name: str,
template: str,
config: Optional[AgentConfig] = None,
env: Optional[Dict[str, str]] = None
) -> AgentCreateResult:
"""
创建 Agent Pod
调用: POST /agents
这是统一的 Agent 创建接口,适用于平台 Agent 和自定义 Agent。
Args:
name: Agent 名称(1-63 字符,小写字母、数字、连字符)
template: 模板类型(如 echo_agent, mysql_agent)
config: 资源配置(包含 user_id, cpu, memory 等)
env: 环境变量(自定义 Agent 需要,如 API Key)
Returns:
创建结果
Example:
# 创建平台 Agent
result = await client.create_agent(
name="alice-echo",
template="echo_agent",
config=AgentConfig(user_id="alice")
)
# 创建自定义 Agent
result = await client.create_agent(
name="my-mysql-agent",
template="mysql_agent",
config=AgentConfig(user_id="alice"),
env={
"MYSQL_HOST": "mysql.example.com",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "password",
"MYSQL_DATABASE": "mydb",
"OPENAI_API_KEY": "sk-..."
}
)
"""
payload: Dict[str, Any] = {
"name": name,
"template": template
}
if config:
payload["config"] = config.to_dict()
if env:
payload["env"] = env
logger.info(
"creating_agent",
name=name,
template=template,
config=config.to_dict() if config else None,
has_env=bool(env)
)
data = await self._request("POST", "/agents", json=payload)
return AgentCreateResult(
name=data["name"],
namespace=data["namespace"],
status=data["status"],
created_at=data["created_at"],
template=data["template"],
service_port=data.get("service_port"),
access_info=data.get("access_info"),
pod_id=data.get("pod_id"),
pod_ip=data.get("pod_ip"),
host_ip=data.get("host_ip"),
node_name=data.get("node_name"),
owner_info=data.get("owner_info")
)
async def create_platform_agent(
self,
name: str,
template: str,
user_id: str,
config: Optional[AgentConfig] = None
) -> AgentCreateResult:
"""
创建平台 Agent 实例
这是 create_agent 的便捷方法,用于创建平台 Agent。
平台 Agent 使用平台预定义的镜像,用户无需配置环境变量。
Args:
name: Agent 实例名称
template: 平台模板名称(如 echo_agent, jina_search_agent)
user_id: 用户 ID(用于资源隔离和计费)
config: 资源配置(可选,使用模板默认值)
Returns:
创建结果
"""
if config is None:
config = AgentConfig(user_id=user_id)
else:
config.user_id = user_id
logger.info(
"creating_platform_agent",
name=name,
template=template,
user_id=user_id
)
return await self.create_agent(
name=name,
template=template,
config=config
)
async def create_custom_agent(
self,
name: str,
template: str,
user_id: str,
env_vars: Dict[str, str],
config: Optional[AgentConfig] = None
) -> AgentCreateResult:
"""
创建自定义 Agent 实例
这是 create_agent 的便捷方法,用于创建自定义 Agent。
自定义 Agent 需要用户提供环境变量(如 API Key、数据库连接信息)。
Args:
name: Agent 实例名称
template: 自定义模板名称(如 mysql_agent, postgresql_agent)
user_id: 用户 ID
env_vars: 环境变量(必须,包含 API Key 等敏感信息)
config: 资源配置(可选)
Returns:
创建结果
Example:
result = await client.create_custom_agent(
name="my-mysql-agent",
template="mysql_agent",
user_id="alice",
env_vars={
"MYSQL_HOST": "mysql.example.com",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "password",
"MYSQL_DATABASE": "mydb",
"OPENAI_API_KEY": "sk-..."
}
)
"""
if config is None:
config = AgentConfig(user_id=user_id)
else:
config.user_id = user_id
logger.info(
"creating_custom_agent",
name=name,
template=template,
user_id=user_id,
env_keys=list(env_vars.keys()) if env_vars else []
)
return await self.create_agent(
name=name,
template=template,
config=config,
env=env_vars
)
async def delete_agent(self, agent_name: str) -> Dict[str, Any]:
"""
删除 Agent Pod
调用: DELETE /agents/{agent_name}
Args:
agent_name: Agent 名称
Returns:
删除结果,包含 message 字段
"""
logger.info("deleting_agent", name=agent_name)
return await self._request("DELETE", f"/agents/{agent_name}")
async def get_agent_status(self, agent_name: str) -> AgentStatusResult:
"""
获取 Agent 状态
调用: GET /agents/{agent_name}/status
Args:
agent_name: Agent 名称
Returns:
Agent 状态信息
"""
data = await self._request("GET", f"/agents/{agent_name}/status")
return AgentStatusResult(
name=data["name"],
namespace=data["namespace"],
status=data["status"],
created_at=data.get("created_at"),
pod_ip=data.get("pod_ip"),
node_name=data.get("node_name"),
labels=data.get("labels"),
# 从 labels 中提取 template
template=data.get("labels", {}).get("template") if data.get("labels") else None
)
async def get_agent_metrics(self, agent_name: str) -> AgentMetricsResult:
"""
获取 Agent 资源使用情况
调用: GET /agents/{agent_name}/metrics
Agent Manager 返回格式:
{
"name": "alice-echo",
"namespace": "ai-agents",
"requests": {
"cpu": "100m",
"memory": "128Mi"
},
"limits": {
"cpu": "500m",
"memory": "512Mi"
},
"usage": {
"cpu": "14502n",
"memory": "8704Ki"
},
"timestamp": "2026-01-06T05:01:04Z",
"metrics_available": null
}
Args:
agent_name: Agent 名称
Returns:
资源使用信息,可通过属性访问:
配额信息:
- metrics.cpu_limit: CPU 限制字符串(如 "500m")
- metrics.memory_limit: 内存限制字符串(如 "512Mi")
- metrics.cpu_request: CPU 请求字符串(如 "100m")
- metrics.memory_request: 内存请求字符串(如 "128Mi")
- metrics.cpu_limit_millicores: CPU 限制(毫核)
- metrics.memory_limit_mb: 内存限制(MB)
实时使用(需要 metrics-server):
- metrics.usage: 实时资源使用字典
- metrics.cpu_usage_current: 当前 CPU 使用字符串(如 "14502n")
- metrics.memory_usage_current: 当前内存使用字符串(如 "8704Ki")
- metrics.cpu_usage_current_millicores: 当前 CPU 使用(毫核)
- metrics.memory_usage_current_mb: 当前内存使用(MB)
- metrics.cpu_utilization_percent: CPU 使用率百分比
- metrics.memory_utilization_percent: 内存使用率百分比
- metrics.has_realtime_metrics: 是否有实时数据
- metrics.timestamp: metrics 数据时间戳
- metrics.metrics_available: metrics-server 是否可用
兼容属性:
- metrics.available: 是否可用(基于 limits)
"""
data = await self._request("GET", f"/agents/{agent_name}/metrics")
return AgentMetricsResult(
name=data.get("name", agent_name),
namespace=data.get("namespace", "ai-agents"),
requests=data.get("requests", {}),
limits=data.get("limits", {}),
usage=data.get("usage"), # 新增:实时资源使用
timestamp=data.get("timestamp"), # 新增:metrics 时间戳
metrics_available=data.get("metrics_available"), # 新增:metrics-server 可用性
resources=data.get("resources", {}) # 兼容旧格式
)
async def list_agents(self, template: Optional[str] = None) -> AgentListResult:
"""
列出所有 Agent
调用: GET /agents
Args:
template: 按模板类型过滤(可选)
Returns:
Agent 列表结果
"""
params = {}
if template:
params["template"] = template
data = await self._request("GET", "/agents", params=params)
return AgentListResult(
agents=data.get("agents", []),
count=data.get("count", 0)
)
# ==================== 未实现的接口(Agent Manager 尚未提供)====================
# 以下方法调用的接口在 Agent Manager 中尚未实现
# 保留方法签名以便后续扩展,但调用时会抛出 NotImplementedError
async def scale_agent(
self,
agent_name: str,
replicas: Optional[int] = None,
cpu_request: Optional[str] = None,
cpu_limit: Optional[str] = None,
memory_request: Optional[str] = None,
memory_limit: Optional[str] = None
) -> Dict[str, Any]:
"""
扩缩容 Agent(待实现)
预期调用: PATCH /agents/{agent_name}/scale
注意: Agent Manager 尚未实现此接口
"""
raise NotImplementedError(
"Agent Manager 尚未实现 PATCH /agents/{name}/scale 接口"
)
async def get_agent_logs(
self,
agent_name: str,
tail_lines: int = 100,
since_seconds: Optional[int] = None
) -> str:
"""
获取 Agent 日志(待实现)
预期调用: GET /agents/{agent_name}/logs
注意: Agent Manager 尚未实现此接口
"""
raise NotImplementedError(
"Agent Manager 尚未实现 GET /agents/{name}/logs 接口"
)
async def restart_agent(self, agent_name: str) -> Dict[str, Any]:
"""
重启 Agent(待实现)
预期调用: POST /agents/{agent_name}/restart
注意: Agent Manager 尚未实现此接口
"""
raise NotImplementedError(
"Agent Manager 尚未实现 POST /agents/{name}/restart 接口"
)
async def get_resource_stats(self) -> Dict[str, Any]:
"""
获取资源统计(待实现)
预期调用: GET /resources/stats
注意: Agent Manager 尚未实现此接口
"""
raise NotImplementedError(
"Agent Manager 尚未实现 GET /resources/stats 接口"
)
async def get_user_resources(self, user_id: str) -> Dict[str, Any]:
"""
获取用户资源使用统计(待实现)
预期调用: GET /resources/stats/by-user/{user_id}
注意: Agent Manager 尚未实现此接口
"""
raise NotImplementedError(
"Agent Manager 尚未实现 GET /resources/stats/by-user/{user_id} 接口"
)
async def get_channel_resources(self, channel_id: str) -> Dict[str, Any]:
"""
获取渠道资源使用统计(待实现)
预期调用: GET /resources/stats/by-channel/{channel_id}
注意: Agent Manager 尚未实现此接口
"""
raise NotImplementedError(
"Agent Manager 尚未实现 GET /resources/stats/by-channel/{channel_id} 接口"
)
# 全局客户端实例
_agent_manager_client: Optional[AgentManagerClient] = None
def get_agent_manager_client() -> AgentManagerClient:
"""获取全局 Agent Manager 客户端实例"""
global _agent_manager_client
if _agent_manager_client is None:
_agent_manager_client = AgentManagerClient()
return _agent_manager_client
async def close_agent_manager_client():
"""关闭全局客户端"""
global _agent_manager_client
if _agent_manager_client:
await _agent_manager_client.close()
_agent_manager_client = None