ForcePilot/backend/package/yuxi/channels/contract/plugin/manifest.py

251 lines
10 KiB
Python
Raw Normal View History

"""插件元数据。
定义插件清单相关的枚举不可变值对象包括失败策略凭证策略插件依赖
资源配额配置字段渠道清单与插件清单所有 DTO 均为 ``dataclass(frozen=True)``
集合字段使用 tuple仅依赖标准库与契约层内部类型用于插件注册依赖解析
资源配额声明与能力边界声明
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from enum import StrEnum
from typing import Any
from yuxi.channels.contract.dtos.capability import ChannelCapabilities
from yuxi.channels.contract.dtos.channel import ChannelType
from yuxi.channels.contract.dtos.config import ConfigField
from yuxi.channels.contract.dtos.plugin import EnvVar
class FailurePolicy(StrEnum):
"""失败策略。
标识插件失败时的处理策略用于宿主决定降级熔断或隔离继承
``str, Enum`` 以支持 JSON 序列化与字符串比较
取值
DEGRADE: 降级走降级路径保留部分能力
CIRCUIT_BREAK: 熔断打开熔断器暂时停止调用
ISOLATE: 隔离隔离插件阻止其继续运行
"""
DEGRADE = "degrade"
CIRCUIT_BREAK = "circuit_break"
ISOLATE = "isolate"
class CredentialType(StrEnum):
"""凭证类型。
标识渠道插件凭证的获取形态用于 ``WizardService.finalize`` 分支选择
``CredentialService`` acquire 方法INV-3 契约显式化
取值
STATIC: 纯静态凭证 app_id/app_secret通过 ``acquireByManual``
落库
DYNAMIC: 纯动态凭证 iLink bot_token通过 ``acquireByQrLogin``
/ ``acquireByOAuth`` 落库
HYBRID: 混合策略如飞书 app_id/app_secret 静态 + user_access_token
动态静态部分 ``acquireByManual``动态部分可跳过skippable
"""
STATIC = "static"
DYNAMIC = "dynamic"
HYBRID = "hybrid"
class AcquireMethod(StrEnum):
"""凭证获取方法。
标识 ``CredentialService`` 应调用的具体 acquire 方法
``CredentialType`` 配合指导凭证落库流程
取值
MANUAL: 手动录入对应 ``acquireByManual``
QR_LOGIN: 扫码登录对应 ``acquireByQrLogin``
OAUTH: OAuth 授权对应 ``acquireByOAuth``
WEBHOOK_VERIFY: Webhook 验证对应 ``acquireByWebhookVerify``
"""
MANUAL = "manual"
QR_LOGIN = "qr_login"
OAUTH = "oauth"
WEBHOOK_VERIFY = "webhook_verify"
@dataclass(frozen=True)
class PluginDependency:
"""插件依赖。
描述插件对其他插件的依赖关系包括插件 ID 与版本范围用于插件加载
前的依赖解析
字段
plugin_id: 依赖的插件 ID
version_range: 语义化版本范围表达式SemVer range
"""
plugin_id: str
version_range: str
@dataclass(frozen=True)
class ResourceQuota:
"""资源配额。
描述插件的资源配额限制包括 CPU内存连接数与每秒调用数用于
宿主对插件施加资源边界FR-32 / §8.5
字段
max_cpu: CPU 上限 "500m"可选
max_memory: 内存上限 "512Mi"可选
max_connections: 最大连接数可选
max_calls_per_sec: 每秒最大调用数可选
"""
max_cpu: str | None = None
max_memory: str | None = None
max_connections: int | None = None
max_calls_per_sec: int | None = None
@dataclass(frozen=True)
class CredentialStrategy:
"""凭证获取策略。
声明渠道插件的凭证获取策略指导 ``WizardService.finalize`` 分支调用
``CredentialService`` 的何种 acquire 方法将凭证落库INV-3 契约显式化
缺失该声明时``None`` ``type=static`` / ``acquire_method=manual``
兜底
字段
type: 凭证类型static/dynamic/hybrid
acquire_method: 凭证获取方法manual/qr_login/oauth/webhook_verify
required_fields: 必需凭证字段名清单对应 ``config_schema`` 中的字段
optional_fields: 可选凭证字段名清单
supports_rotation: 是否支持凭证轮换
supports_revocation: 是否支持凭证撤销
"""
type: CredentialType
acquire_method: AcquireMethod
required_fields: tuple[str, ...]
optional_fields: tuple[str, ...] = ()
supports_rotation: bool = False
supports_revocation: bool = False
@dataclass(frozen=True)
class ChannelManifest:
"""渠道清单。
描述渠道插件的元数据包括标识版本渠道类型提供的能力配置 schema
入口模块依赖生命周期兼容性失败策略资源配额与能力边界声明
用于插件注册与装配
字段
id: 全局唯一标识 com.yuxi.channels.feishu
name: 人类可读名称
version: 语义化版本
channel_type: 渠道类型
provides: 提供的能力列表
entry_module: 插件入口模块路径
capabilities: 渠道能力集合静态声明必填
config_schema: 配置项 schema必填
capability_requirements: 能力运行时依赖声明默认空每项为
``(能力字段名, (所需配置字段名清单))`` 元组保持 frozen dataclass
可哈希用于能力查询页判断"声明支持""实际可用"之间的差距
depends: 依赖的其他插件默认空
lifecycle: 支持的生命周期钩子默认 init/start/stop/unload
compatibility: 兼容性信息可选
failure_policy: 失败策略默认 DEGRADE
resource_quota: 资源配额可选
accessible_ports: 可访问的端口列表默认空
injectable_pipelines: 可注入的管道列表默认空
skills: 提供的技能列表默认空
env_vars: 环境变量声明默认空
critical: 是否为关键渠道默认 False关键渠道失败时宿主标记为
``unhealthy``非关键渠道失败标记为 ``degraded``FR-31 / FR-35
requires_dm_pairing: 是否要求 DM 安全配对审批默认 True声明
``False`` 的渠道如已通过宿主认证体系跳过 DM 配对审批直接放行
FR-31插件未注册时框架回退为 ``True``fail-closed
requires_outbound_delivery: 是否要求出站投递默认 True声明 ``False``
的渠道无需实现 ``OutboundAdapter``框架跳过出站投递阶段FR-31
credential_strategy: 凭证获取策略默认 ``None`` 表示无动态凭证
``type=static`` / ``acquire_method=manual`` 兜底声明该策略后
``WizardService.finalize`` 据此分支调用 ``CredentialService``
acquire 方法完成凭证落库INV-3 契约显式化
max_message_length: 单条消息最大文本长度FR19-P0-5 渠道级内容
长度校验默认 4096出站管道据此对超长内容做截断或分片
决策未声明的渠道沿用默认值本字段为配置型参数非能力
声明故置于 manifest 顶层而非 ``capabilities``
supports_credential_cloning: 是否允许在账户克隆时复制凭据字段
默认 FalseACC-CLONE声明为 False ``include_credentials=True``
的克隆请求将被 handler 拒绝``RuleViolationError``fail-closed
防止凭据经克隆路径泄露本字段为安全策略声明非能力声明
故置于 manifest 顶层而非 ``capabilities``
icon: 渠道展示图标名lucide 图标库的 kebab-case 名称
``"message-square"``供前端卡片视图筛选下拉标签等场景
渲染渠道图标缺失时前端回退默认图标本字段为纯展示元数据
非能力声明非业务规则由插件作者根据渠道视觉特征选择
框架层不做取值校验
"""
id: str
name: str
version: str
channel_type: ChannelType
provides: tuple[str, ...]
entry_module: str
capabilities: ChannelCapabilities
config_schema: tuple[ConfigField, ...]
capability_requirements: tuple[tuple[str, tuple[str, ...]], ...] = ()
depends: tuple[PluginDependency, ...] = ()
lifecycle: tuple[str, ...] = ("init", "start", "stop", "unload")
compatibility: dict[str, Any] | None = None
failure_policy: FailurePolicy = FailurePolicy.DEGRADE
resource_quota: ResourceQuota | None = None
accessible_ports: tuple[str, ...] = ()
injectable_pipelines: tuple[str, ...] = ()
skills: tuple[str, ...] = ()
env_vars: tuple[EnvVar, ...] = ()
critical: bool = False
requires_dm_pairing: bool = True
requires_outbound_delivery: bool = True
credential_strategy: CredentialStrategy | None = None
max_message_length: int = 4096
supports_credential_cloning: bool = False
icon: str | None = None
@dataclass(frozen=True)
class PluginManifest:
"""插件清单。
描述插件注册到宿主的完整清单包括渠道清单与插件提供的扩展点适配器
阶段事件订阅配置源 ``CHANNEL_ENTRY`` 返回给宿主
字段
manifest: 渠道清单
adapters: 提供的适配器类型列表默认空
stages: 提供的管道阶段列表默认空
event_subscriptions: 订阅的事件类型列表默认空
config_sources: 配置源列表默认空
installed_at: 文件级安装时间PLG-INSTALL 端点写入默认 None
表示未通过文件级安装流程注册
install_source: 安装来源标识如文件路径URL包名默认 None
install_version: 安装时的版本号可能与 manifest.version 不同
如安装后未升级默认 None
"""
manifest: ChannelManifest
adapters: tuple[str, ...] = ()
stages: tuple[str, ...] = ()
event_subscriptions: tuple[str, ...] = ()
config_sources: tuple[str, ...] = ()
installed_at: datetime | None = None
install_source: str | None = None
install_version: str | None = None