zcbot/core/external_systems/registry.py

123 lines
4.2 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.

"""外部系统 provider 注册表。
标准 OpenAPI 与 Streamable HTTP MCP 系统均通过数据库配置接入。
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from .auth import ExternalAuthError, get_auth_strategy
FACTORY_QUERY_GUIDANCE = (
"产量、良率、缺陷、库存、绩效、趋势和按日/月汇总等统计聚合查询,"
"统一先调用 BI dataset list再执行匹配的数据集。日志和业务明细列表用于"
"用户明确要求查看逐条记录、编号或追溯过程的场景。未匹配到 dataset 时,"
"先限定范围或向用户确认明细查询需求。"
)
FACTORY_RECOMMENDED_OPERATIONS = ("bi_dataset_list", "bi_dataset_exec")
@dataclass(frozen=True)
class ProviderSpec:
provider: str
title: str
connector: str
default_auth_type: str
allowed_auth_types: tuple[str, ...]
defaults: dict[str, Any]
_PROVIDERS = {
"factory_mes": ProviderSpec(
provider="factory_mes",
title="Factory MES",
connector="openapi",
default_auth_type="password_jwt",
allowed_auth_types=("password_jwt",),
defaults={
"login_path": "/api/auth/token/",
"username_field": "username",
"password_field": "password",
"token_field": "access",
"auth_header_name": "Authorization",
"auth_header_template": "Bearer {token}",
"query_guidance": FACTORY_QUERY_GUIDANCE,
"recommended_operation_ids": list(FACTORY_RECOMMENDED_OPERATIONS),
"operation_mode": "upstream_managed",
"operation_policies": {
"bi_dataset_exec": "read",
},
},
),
"generic_openapi": ProviderSpec(
provider="generic_openapi",
title="通用 OpenAPI 系统",
connector="openapi",
default_auth_type="password_jwt",
allowed_auth_types=("password_jwt", "api_key", "bearer_token"),
defaults={
"login_path": "/api/auth/token/",
"username_field": "username",
"password_field": "password",
"token_field": "access",
"auth_header_name": "Authorization",
"auth_header_template": "Bearer {token}",
"query_guidance": "",
"recommended_operation_ids": [],
"operation_mode": "query",
"operation_policies": {},
},
),
"generic_mcp": ProviderSpec(
provider="generic_mcp",
title="通用 MCP 系统",
connector="mcp",
default_auth_type="password_jwt",
allowed_auth_types=("password_jwt", "api_key", "bearer_token"),
defaults={
"login_path": "/api/auth/token/",
"username_field": "username",
"password_field": "password",
"token_field": "access",
"auth_header_name": "Authorization",
"auth_header_template": "Bearer {token}",
"query_guidance": "",
"recommended_operation_ids": [],
"operation_mode": "upstream_managed",
"operation_policies": {},
},
),
}
def get_provider(provider: str) -> ProviderSpec:
result = _PROVIDERS.get((provider or "").strip())
if result is None:
raise ValueError(f"不支持的外部系统 provider: {provider}")
return result
def provider_specs() -> tuple[ProviderSpec, ...]:
return tuple(_PROVIDERS.values())
def merged_config(provider: str, config: dict[str, Any]) -> dict[str, Any]:
spec = get_provider(provider)
result = {**spec.defaults, **(config or {})}
auth_type = str(result.get("auth_type") or spec.default_auth_type).strip()
if auth_type not in spec.allowed_auth_types:
raise ValueError(f"{spec.title} 不支持认证方式 {auth_type}")
result["auth_type"] = auth_type
return result
def credential_fields(provider: str, config: dict[str, Any]) -> list[dict[str, Any]]:
merged = merged_config(provider, config)
try:
strategy = get_auth_strategy(merged["auth_type"])
except ExternalAuthError as exc:
raise ValueError(str(exc)) from exc
return [field.as_dict() for field in strategy.credential_fields]