本次提交包含多项代码优化与规范修正: 1. 文档与注释优化:修正注释术语、补充注解与FR编号 2. 代码格式调整:统一空格、换行与缩进规范 3. 类型与接口完善:补充__all__导出、修正返回类型注解 4. 错误处理增强:新增领域错误类与校验逻辑 5. 依赖与导入调整:修复路径引用、统一时区导入 6. 协议与契约更新:完善接口文档与一致性注解
142 lines
5.3 KiB
Python
142 lines
5.3 KiB
Python
"""入站 DTO。
|
||
|
||
定义入站管道入口的命令与结果值对象,包括入站消息命令与入站结果。所有
|
||
DTO 均为 ``dataclass(frozen=True)``,仅依赖标准库与契约层内部类型,用于
|
||
渠道适配器向核心层传递原始事件并返回 ACK 决策。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass, field
|
||
from typing import Any, Literal
|
||
|
||
from yuxi.channels.contract.dtos.channel import ChannelType
|
||
from yuxi.channels.contract.dtos.command import CommandResponse
|
||
from yuxi.channels.contract.dtos.common import RawEvent
|
||
from yuxi.channels.contract.errors import ValidationError
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class InboundMessageCmd:
|
||
"""入站消息命令(FR-01)。
|
||
|
||
由入站端口方法引用,封装渠道适配器接收到的原始事件,携带渠道类型、
|
||
账户 ID、原始事件与可选追踪 ID,作为入站管道的统一输入。
|
||
|
||
字段:
|
||
channel_type: 渠道类型。
|
||
account_id: 渠道账户 ID。
|
||
raw_event: 原始事件。
|
||
trace_id: 追踪 ID(可选)。
|
||
"""
|
||
|
||
channel_type: ChannelType
|
||
account_id: str
|
||
raw_event: RawEvent
|
||
trace_id: str | None = None
|
||
|
||
def __post_init__(self) -> None:
|
||
"""校验必填字段非空。
|
||
|
||
``account_id`` 必须非空,在构造时即抛出 ``ValidationError``,
|
||
adapter 不再做该校验(INV-8)。
|
||
"""
|
||
if not self.account_id:
|
||
raise ValidationError("account_id", "must not be empty")
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class InboundResult:
|
||
"""入站结果(FR-24)。
|
||
|
||
描述入站管道处理后的 ACK 决策与后续 Agent 运行信息,用于适配器按
|
||
决策向渠道侧返回确认或保持静默。
|
||
|
||
字段:
|
||
ack_decision: ACK 决策(ack | nack | pending)。
|
||
agent_run_id: 关联的 Agent 运行 ID(可选)。
|
||
is_silent: 是否静默处理(默认 False)。
|
||
error: NACK 错误消息(FR-24 显式 NACK,与 ACK 互斥,仅
|
||
``ack_decision="nack"`` 时填充)。
|
||
command_response: 命令响应(FR-15)。命令命中且需回显时由
|
||
command-check 阶段填充,供 reply 阶段向渠道侧回送命令响应内容;
|
||
非命令路径或静默命令为 None。
|
||
error_code: 错误码(用例服务捕获异常时填充,默认空字符串)。
|
||
trace_id: 追踪 ID(用例服务捕获异常时填充,默认空字符串)。
|
||
raw_response: 渠道侧契约回包(可选)。用于 Webhook 配置验证等
|
||
需要向渠道侧返回特定格式响应的场景(如飞书 challenge 握手),
|
||
由 ``InboundAdapter.extractWebhookResponse`` 填充。非 None 时
|
||
Router 直接将其作为 HTTP 响应体返回,跳过标准 ``{"success":...}``
|
||
包装,确保渠道平台能正确解析握手回包。
|
||
"""
|
||
|
||
ack_decision: Literal["ack", "nack", "pending"]
|
||
agent_run_id: str | None = None
|
||
is_silent: bool = False
|
||
error: str | None = None
|
||
command_response: CommandResponse | None = None
|
||
error_code: str = ""
|
||
trace_id: str = ""
|
||
raw_response: dict[str, Any] | None = None
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class ReceiveInboundCmd:
|
||
"""Webhook 入站接收命令(FR-01)。
|
||
|
||
供 ``InboundMessagePort.receiveWebhook`` 调用,封装 webhook 路由解析
|
||
后的原始事件负载与请求头。与 ``InboundMessageCmd`` 的差异:不要求
|
||
``account_id``,账户身份解析下沉入站管道,由 webhook 适配器仅传递
|
||
渠道类型、原始事件字符串与请求头(FR-01)。
|
||
|
||
字段:
|
||
channel_type: 渠道类型。
|
||
raw_event: 原始事件负载字符串(webhook body 原文)。
|
||
headers: 请求头(含签名、时间戳等,默认空 dict)。
|
||
trace_id: 链路追踪 ID(可选,由 Router 从 ContextVar 注入,
|
||
确保全链路 trace_id 一致;缺省时由用例服务生成新值)。
|
||
"""
|
||
|
||
channel_type: ChannelType
|
||
raw_event: str
|
||
headers: dict[str, str] = field(default_factory=dict)
|
||
trace_id: str | None = None
|
||
|
||
def __post_init__(self) -> None:
|
||
"""校验必填字段非空。
|
||
|
||
``channel_type`` 不可为 ``None``,``raw_event`` 必须为非空字符串;
|
||
违规抛 ``ValidationError``,与同文件 ``InboundMessageCmd`` 风格一致
|
||
(INV-7 异常协议一致性)。
|
||
"""
|
||
if self.channel_type is None:
|
||
raise ValidationError("channel_type", "must not be None")
|
||
if not self.raw_event:
|
||
raise ValidationError("raw_event", "must be a non-empty string")
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class SignatureVerifyResult:
|
||
"""Webhook 签名校验结果(WHK-09)。
|
||
|
||
由 ``InboundAdapter.verifySignature`` 返回,携带校验结论与失败原因,
|
||
供 Router 与入站管道 signature-verify 阶段消费。``reason`` 在校验通过
|
||
时为 ``None``,失败时填充可读原因(如 ``"timestamp out of window"``
|
||
/ ``"signature mismatch"``),辅助接入调试与日志排查。
|
||
|
||
字段:
|
||
valid: 签名校验是否通过。
|
||
reason: 校验失败原因(通过时为 ``None``)。
|
||
"""
|
||
|
||
valid: bool
|
||
reason: str | None = None
|
||
|
||
|
||
__all__ = [
|
||
"InboundMessageCmd",
|
||
"InboundResult",
|
||
"ReceiveInboundCmd",
|
||
"SignatureVerifyResult",
|
||
]
|