ForcePilot/backend/package/yuxi/channels/contract/dtos/inbound.py
Kris 00092c818e chore: 批量代码优化与规范完善
本次提交包含多项代码优化与规范修正:
1. 文档与注释优化:修正注释术语、补充注解与FR编号
2. 代码格式调整:统一空格、换行与缩进规范
3. 类型与接口完善:补充__all__导出、修正返回类型注解
4. 错误处理增强:新增领域错误类与校验逻辑
5. 依赖与导入调整:修复路径引用、统一时区导入
6. 协议与契约更新:完善接口文档与一致性注解
2026-07-03 19:18:13 +08:00

142 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""入站 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",
]