"""管理员消息 DTO。 定义管理员消息发送的命令与结果值对象,包括管理员发送命令与发送结果。 所有 DTO 均为 ``dataclass(frozen=True)``,仅依赖标准库与契约层内部类型, 用于管理员向目标会话或用户批量发送消息并聚合失败与跳过详情。集合字段 使用 tuple 以保证 frozen dataclass 的不可变语义。 """ from __future__ import annotations from dataclasses import dataclass from yuxi.channels.contract.dtos.common import ( FailureDetail, MessageContent, Operator, SkipDetail, ) from yuxi.channels.contract.errors import ValidationError @dataclass(frozen=True) class AdminSendCmd: """管理员发送命令。 由管理员消息端口方法引用,描述管理员向目标会话或用户发送消息的请求, 携带目标、内容、会话策略、幂等键与操作人,支持复用 / 新建 / 临时 三种会话策略。 字段: target: 目标会话或用户。 content: 消息内容。 conversation_policy: 会话策略(reuse | reuse-or-create | new)。 idempotency_key: 幂等键。 operator: 操作人(审计用)。 """ target: str content: MessageContent conversation_policy: str idempotency_key: str operator: Operator def __post_init__(self) -> None: """校验必填字段非空(FR-19)。 ``target`` 与 ``idempotency_key`` 必须非空,在构造时即抛出 ``ValidationError``,adapter 不再做该校验(INV-8)。 ``conversation_policy`` 的合法值校验由 ``AdminMessageService`` 统一执行(``_CONVERSATION_POLICIES``),DTO 层不重复校验,避免 与 service 层默认值回退(``or _DEFAULT_CONVERSATION_POLICY``) 冲突。 """ if not self.target: raise ValidationError("target", "must not be empty") if not self.idempotency_key: raise ValidationError("idempotency_key", "must not be empty") @dataclass(frozen=True) class AdminSendResult: """管理员发送结果。 描述管理员批量发送消息的执行结果,聚合成功消息 ID、失败详情与跳过 详情,用于结果汇报与重试策略决策。集合字段使用 tuple 以保证不可变。 字段: message_ids: 成功发送的消息 ID 列表。 failures: 失败详情列表(默认空 tuple)。 skipped: 跳过详情列表(默认空 tuple)。 """ message_ids: tuple[str, ...] failures: tuple[FailureDetail, ...] = () skipped: tuple[SkipDetail, ...] = ()