""" Tool Registry models for Mid Platform. [AC-IDMP-19] Tool Registry 治理模型 Reference: spec/intent-driven-mid-platform/openapi.provider.yaml """ import uuid from dataclasses import dataclass, field from datetime import datetime from enum import Enum from typing import Any from sqlalchemy import JSON, Column from sqlmodel import Field, Index, SQLModel class ToolStatus(str, Enum): """工具状态""" ENABLED = "enabled" DISABLED = "disabled" DEPRECATED = "deprecated" class ToolAuthType(str, Enum): """工具鉴权类型""" NONE = "none" API_KEY = "api_key" OAUTH = "oauth" CUSTOM = "custom" @dataclass class ToolAuthConfig: """ [AC-IDMP-19] 工具鉴权配置 """ auth_type: ToolAuthType = ToolAuthType.NONE required_scopes: list[str] = field(default_factory=list) api_key_header: str | None = None oauth_url: str | None = None custom_validator: str | None = None def to_dict(self) -> dict[str, Any]: result = {"auth_type": self.auth_type.value} if self.required_scopes: result["required_scopes"] = self.required_scopes if self.api_key_header: result["api_key_header"] = self.api_key_header if self.oauth_url: result["oauth_url"] = self.oauth_url if self.custom_validator: result["custom_validator"] = self.custom_validator return result @classmethod def from_dict(cls, data: dict[str, Any]) -> "ToolAuthConfig": return cls( auth_type=ToolAuthType(data.get("auth_type", "none")), required_scopes=data.get("required_scopes", []), api_key_header=data.get("api_key_header"), oauth_url=data.get("oauth_url"), custom_validator=data.get("custom_validator"), ) @dataclass class ToolTimeoutPolicy: """ [AC-IDMP-19] 工具超时策略 Reference: openapi.provider.yaml - TimeoutProfile """ per_tool_timeout_ms: int = 30000 end_to_end_timeout_ms: int = 120000 retry_count: int = 0 retry_delay_ms: int = 100 def to_dict(self) -> dict[str, Any]: return { "per_tool_timeout_ms": self.per_tool_timeout_ms, "end_to_end_timeout_ms": self.end_to_end_timeout_ms, "retry_count": self.retry_count, "retry_delay_ms": self.retry_delay_ms, } @classmethod def from_dict(cls, data: dict[str, Any]) -> "ToolTimeoutPolicy": return cls( per_tool_timeout_ms=data.get("per_tool_timeout_ms", 30000), end_to_end_timeout_ms=data.get("end_to_end_timeout_ms", 120000), retry_count=data.get("retry_count", 0), retry_delay_ms=data.get("retry_delay_ms", 100), ) @dataclass class ToolDefinition: """ [AC-IDMP-19] 工具定义(内存模型) 包含: - name: 工具名称 - type: 工具类型 (internal | mcp) - version: 版本号 - timeout_policy: 超时策略 - auth_config: 鉴权配置 - is_enabled: 启停状态 """ name: str type: str = "internal" version: str = "1.0.0" description: str | None = None timeout_policy: ToolTimeoutPolicy = field(default_factory=ToolTimeoutPolicy) auth_config: ToolAuthConfig = field(default_factory=ToolAuthConfig) is_enabled: bool = True metadata: dict[str, Any] = field(default_factory=dict) created_at: datetime = field(default_factory=datetime.utcnow) updated_at: datetime = field(default_factory=datetime.utcnow) def to_dict(self) -> dict[str, Any]: return { "name": self.name, "type": self.type, "version": self.version, "description": self.description, "timeout_policy": self.timeout_policy.to_dict(), "auth_config": self.auth_config.to_dict(), "is_enabled": self.is_enabled, "metadata": self.metadata, "created_at": self.created_at.isoformat(), "updated_at": self.updated_at.isoformat(), } @classmethod def from_dict(cls, data: dict[str, Any]) -> "ToolDefinition": return cls( name=data["name"], type=data.get("type", "internal"), version=data.get("version", "1.0.0"), description=data.get("description"), timeout_policy=ToolTimeoutPolicy.from_dict(data.get("timeout_policy", {})), auth_config=ToolAuthConfig.from_dict(data.get("auth_config", {})), is_enabled=data.get("is_enabled", True), metadata=data.get("metadata", {}), created_at=datetime.fromisoformat(data["created_at"]) if data.get("created_at") else datetime.utcnow(), updated_at=datetime.fromisoformat(data["updated_at"]) if data.get("updated_at") else datetime.utcnow(), ) class ToolRegistryEntity(SQLModel, table=True): """ [AC-IDMP-19] 工具注册表数据库实体 支持动态配置更新 """ __tablename__ = "tool_registry" __table_args__ = ( Index("ix_tool_registry_tenant_name", "tenant_id", "name", unique=True), Index("ix_tool_registry_tenant_enabled", "tenant_id", "is_enabled"), ) id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) tenant_id: str = Field(..., description="租户ID", index=True) name: str = Field(..., description="工具名称", max_length=128) type: str = Field(default="internal", description="工具类型: internal | mcp") version: str = Field(default="1.0.0", description="版本号", max_length=32) description: str | None = Field(default=None, description="工具描述") timeout_policy: dict[str, Any] | None = Field( default=None, sa_column=Column("timeout_policy", JSON, nullable=True), description="超时策略配置" ) auth_config: dict[str, Any] | None = Field( default=None, sa_column=Column("auth_config", JSON, nullable=True), description="鉴权配置" ) is_enabled: bool = Field(default=True, description="是否启用") metadata_: dict[str, Any] | None = Field( default=None, sa_column=Column("metadata", JSON, nullable=True), description="扩展元数据" ) created_at: datetime = Field(default_factory=datetime.utcnow, description="创建时间") updated_at: datetime = Field(default_factory=datetime.utcnow, description="更新时间") def to_definition(self) -> ToolDefinition: """转换为内存模型""" return ToolDefinition( name=self.name, type=self.type, version=self.version, description=self.description, timeout_policy=ToolTimeoutPolicy.from_dict(self.timeout_policy or {}), auth_config=ToolAuthConfig.from_dict(self.auth_config or {}), is_enabled=self.is_enabled, metadata=self.metadata_ or {}, created_at=self.created_at, updated_at=self.updated_at, ) class ToolRegistryCreate(SQLModel): """创建工具注册请求""" name: str = Field(..., max_length=128) type: str = "internal" version: str = "1.0.0" description: str | None = None timeout_policy: dict[str, Any] | None = None auth_config: dict[str, Any] | None = None is_enabled: bool = True metadata_: dict[str, Any] | None = None class ToolRegistryUpdate(SQLModel): """更新工具注册请求""" type: str | None = None version: str | None = None description: str | None = None timeout_policy: dict[str, Any] | None = None auth_config: dict[str, Any] | None = None is_enabled: bool | None = None metadata_: dict[str, Any] | None = None