"""能力 DTO。 定义渠道能力相关的不可变值对象,包括渠道能力集合与能力探测结果。 所有 DTO 均为 ``dataclass(frozen=True)``,仅依赖标准库,用于渠道 能力声明、探测与降级决策。 """ from __future__ import annotations from dataclasses import dataclass from enum import StrEnum from yuxi.channels.contract.dtos.channel import ChannelType from yuxi.channels.contract.dtos.config import ConfigField from yuxi.channels.contract.errors import ValidationError @dataclass(frozen=True) class ChannelCapabilities: """渠道能力集合。 描述渠道支持的能力集合,全部为 ``bool`` 类型的能力声明字段,用于 适配器能力声明与降级决策。 字段(按语义分组): 基础消息能力: rich_message: 是否支持富消息(默认 False)。 streaming: 是否支持流式输出(默认 False)。 typing_indicator: 是否支持输入指示(默认 False)。由出站 适配器承载,不在加载期校验范围,运行时由 ``CapabilityVerifier`` 证明。 message_edit: 是否支持消息编辑(默认 False)。 message_recall: 是否支持消息撤回(默认 False)。 消息操作子能力(任一为 True 时要求 ``message_ops_adapters`` 非空): supports_reaction: 是否支持表情反应(默认 False,FR-12)。 supports_pin: 是否支持置顶(默认 False,FR-12)。 supports_card_update: 是否支持投递完成后的卡片刷新 (``MessageOpsAdapter.updateCard``,默认 False,FR-12)。 **不** 涵盖流式输出过程中的渐进式卡片更新,后者由 ``supports_card_update_streaming`` 声明。 supports_card_update_streaming: 是否支持流式输出过程中的 渐进式卡片更新(``StreamingAdapter.updateFullCard`` / ``updatePartialCard``,默认 False)。声明为 True 时要求 ``streaming_adapters`` 非空。 媒体能力(FR-43): supports_image_inbound: 是否支持入站图片(默认 False)。 supports_video_inbound: 是否支持入站视频(默认 False)。 supports_image_outbound: 是否支持出站图片(默认 False)。 supports_video_outbound: 是否支持出站视频(默认 False)。 扩展能力: mention: 是否支持提及(默认 False)。 command: 是否支持命令(默认 False,FR-15)。 directory: 是否支持目录查询(默认 False,FR-14)。 doctor: 是否支持配置诊断与自动修复(默认 False,FR-17)。 whitelist: 是否支持白名单管理(默认 False,FR-18)。 wizard: 是否支持配置向导(默认 False,FR-16)。声明为 True 时要求 ``wizard_adapters`` 非空。 tools: 是否支持工具能力(默认 False,FR-12 工具暴露)。 声明为 True 时要求 ``tools_adapters`` 非空。 status: 是否支持状态分类(默认 False)。声明为 True 时要求 ``status_adapters`` 非空;未声明的渠道默认将所有事件 分类为 MESSAGE。 probeable: 是否支持连接探测(默认 False,FR-17 探测)。 声明为 True 时要求 ``probeable_adapters`` 非空。 identity_resolver: 是否支持身份解析适配器(默认 False)。 由 ``IdentityResolverPort`` 承载,不在加载期校验范围, 运行时由 ``CapabilityVerifier`` 证明。 生命周期与协作能力: lifecycle: 是否实现账户生命周期适配器(默认 False,AL-01)。 supports_qr_login: 是否支持扫码登录(默认 False,QR-02)。 agent_collaboration: 是否支持多 Agent 协作(默认 False, FR-AgentCollab)。声明为 True 时要求 ``mention_adapters`` 非空(FR-21 契约一致性)。 """ # 基础消息能力 rich_message: bool = False streaming: bool = False typing_indicator: bool = False message_edit: bool = False message_recall: bool = False # 消息操作子能力 supports_reaction: bool = False supports_pin: bool = False supports_card_update: bool = False supports_card_update_streaming: bool = False # 媒体能力(FR-43) supports_image_inbound: bool = False supports_video_inbound: bool = False supports_image_outbound: bool = False supports_video_outbound: bool = False # 扩展能力 mention: bool = False command: bool = False directory: bool = False doctor: bool = False whitelist: bool = False wizard: bool = False tools: bool = False status: bool = False probeable: bool = False identity_resolver: bool = False # 生命周期与协作能力 lifecycle: bool = False supports_qr_login: bool = False agent_collaboration: bool = False class RuntimeAvailability(StrEnum): """能力运行时可用性状态。 用于能力查询页区分"声明支持"与"实际可用": available: 声明支持且依赖配置已满足。 unavailable: 声明支持但依赖配置缺失,实际不可用。 unknown: 声明支持但无法判断运行时状态(无依赖声明、依赖账户级配置 或未实现检测)。 unsupported: 声明不支持。 """ AVAILABLE = "available" UNAVAILABLE = "unavailable" UNKNOWN = "unknown" UNSUPPORTED = "unsupported" @dataclass(frozen=True) class CapabilityAvailabilityDetail: """单项能力运行时可用性详情。 补充 ``runtime_availability`` 的状态码,提供可解释的运行时推导结果, 供前端 tooltip 与详情面板展示缺失项与原因。 字段: status: 运行时可用性状态。 missing_config_keys: 缺失或未有效配置的配置键清单。 missing_adapters: 缺失的适配器类型清单(如 directory/wizard)。 reason: 人类可读的原因说明(可选)。 """ status: RuntimeAvailability missing_config_keys: tuple[str, ...] = () missing_adapters: tuple[str, ...] = () reason: str | None = None @dataclass(frozen=True) class ChannelCapabilityProfile: """渠道能力画像。 聚合单个渠道的能力声明、运行时可用性、插件元数据与配置 schema, 供能力查询页矩阵/详情/对比视图一次性消费。 字段: channel_type: 渠道类型。 display_name: 渠道显示名。 plugin_id: 插件 ID。 plugin_version: 插件版本。 plugin_state: 插件当前状态(如 started / paused / stopped)。 is_loaded: 是否已加载。 max_message_length: 单条消息最大长度。 capabilities: 静态能力声明集合。 runtime_availability: 运行时可用性映射,键为能力字段名, 值为 ``RuntimeAvailability``。 availability_details: 运行时可用性详情映射,键为能力字段名, 值为 ``CapabilityAvailabilityDetail``,解释状态原因与缺失项。 config_schema: 配置字段 schema 摘要。 """ channel_type: ChannelType display_name: str plugin_id: str plugin_version: str plugin_state: str is_loaded: bool max_message_length: int capabilities: ChannelCapabilities runtime_availability: dict[str, RuntimeAvailability] availability_details: dict[str, CapabilityAvailabilityDetail] config_schema: tuple[ConfigField, ...] @dataclass(frozen=True) class CapabilityResult: """能力探测结果。 描述单项能力的探测结果,包括声明层、证明层与降级标记,用于能力 探测流程的决策与审计。 字段: capability: 能力名称。 declared: 声明层是否支持。 proven: 证明层是否验证通过(默认 False)。 degraded: 是否降级(默认 False)。 """ capability: str declared: bool proven: bool = False degraded: bool = False def __post_init__(self) -> None: """校验 capability 非空。 ``capability`` 必须非空,在构造时即抛出 ``ValidationError``, 避免空能力名称传播到探测决策(INV-8)。 """ if not self.capability: raise ValidationError("capability", "must not be empty")