ForcePilot/backend/package/yuxi/channels/contract/dtos/outbound.py

332 lines
10 KiB
Python
Raw Normal View History

"""出站 DTO。
定义出站管道的富消息与最终输出值对象包括富消息按钮富消息选项
富消息富消息字段出站负载格式化消息可信消息与最终消息
所有 DTO 均为 ``dataclass(frozen=True)``仅依赖标准库与契约层内部
类型用于出站消息的格式化可信注入与最终投递集合字段使用 tuple
以保证 frozen dataclass 的不可变语义
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from yuxi.channels.contract.dtos.common import Attachment, MessageFormat
from yuxi.channels.contract.errors import ValidationError
@dataclass(frozen=True)
class RichMessageButton:
"""富消息按钮。
描述富消息中的可点击按钮由适配器按渠道协议渲染为对应交互元素
字段
label: 按钮显示文本
action: 按钮动作标识
value: 按钮动作携带的值可选
"""
label: str
action: str
value: str | None = None
@dataclass(frozen=True)
class RichMessageOption:
"""富消息选项。
描述富消息中的可选项用于下拉 / 列表类交互组件
字段
label: 选项显示文本
value: 选项值
"""
label: str
value: str
@dataclass(frozen=True)
class RichMessageSelect:
"""富消息下拉选择器组件。
字段
name: 表单字段名
label: 显示标签
options: 可选项列表
placeholder: 占位文本可选
default_value: 默认值可选
"""
name: str
label: str
options: tuple[RichMessageOption, ...]
placeholder: str | None = None
default_value: str | None = None
@dataclass(frozen=True)
class RichMessageDatePicker:
"""富消息日期选择器组件。
字段
name: 表单字段名
label: 显示标签
placeholder: 占位文本可选
default_value: 默认日期ISO 格式可选
min_date: 最小可选日期ISO 格式可选
max_date: 最大可选日期ISO 格式可选
"""
name: str
label: str
placeholder: str | None = None
default_value: str | None = None
min_date: str | None = None
max_date: str | None = None
@dataclass(frozen=True)
class RichMessageCheckbox:
"""富消息复选框组件。
字段
name: 表单字段名
label: 显示标签
options: 可选项列表
default_values: 默认选中值列表
"""
name: str
label: str
options: tuple[RichMessageOption, ...]
default_values: tuple[str, ...] = ()
@dataclass(frozen=True)
class RichMessageInput:
"""富消息输入框组件。
字段
name: 表单字段名
label: 显示标签
placeholder: 占位文本可选
default_value: 默认值可选
max_length: 最大输入长度可选
input_type: 输入类型text/number/email 默认 text
"""
name: str
label: str
placeholder: str | None = None
default_value: str | None = None
max_length: int | None = None
input_type: str = "text"
@dataclass(frozen=True)
class RichMessage:
"""富消息。
描述结构化的富消息内容包括标题正文描述图片视频与交互元素
按钮 / 选项由适配器按渠道协议渲染集合字段使用 tuple
保证不可变
字段
text: 正文文本
title: 标题可选
description: 描述可选
image_url: 图片 URL可选向后兼容
video_url: 视频 URL可选FR-50
attachments: 多附件列表承载多图文件等FR-50
buttons: 按钮列表默认空 tuple
options: 选项列表默认空 tuple
metadata: 渠道侧元数据可选
selects: 下拉选择器组件列表
date_pickers: 日期选择器组件列表
checkboxes: 复选框组件列表
inputs: 输入框组件列表
"""
text: str
title: str | None = None
description: str | None = None
image_url: str | None = None
video_url: str | None = None
attachments: tuple[Attachment, ...] = ()
buttons: tuple[RichMessageButton, ...] = ()
options: tuple[RichMessageOption, ...] = ()
metadata: dict[str, Any] | None = None
selects: tuple[RichMessageSelect, ...] = ()
date_pickers: tuple[RichMessageDatePicker, ...] = ()
checkboxes: tuple[RichMessageCheckbox, ...] = ()
inputs: tuple[RichMessageInput, ...] = ()
@dataclass(frozen=True)
class RichMessageFields:
"""富消息字段。
包装富消息与其回退格式用于出站负载携带富消息渲染信息当渠道
不支持富消息时按回退格式渲染
字段
rich_message: 富消息内容
fallback_format: 回退格式默认 MARKDOWN
"""
rich_message: RichMessage
fallback_format: MessageFormat = MessageFormat.MARKDOWN
@dataclass(frozen=True)
class OutboundPayload:
"""出站负载。
描述出站管道的统一负载关联 Agent 运行 ID携带流式分块可选的
富消息字段与附件列表用于驱动出站消息的格式化与投递
字段
agent_run_id: 关联的 Agent 运行 ID
stream_chunks: 流式分块列表默认空 tuple
rich_message_fields: 富消息字段可选
attachments: 附件列表默认空 tupleFR-51
"""
agent_run_id: str | None = None
stream_chunks: tuple[str, ...] = ()
rich_message_fields: RichMessageFields | None = None
attachments: tuple[Attachment, ...] = ()
@dataclass(frozen=True)
class FormattedMessage:
"""格式化消息。
描述经格式化后的消息内容携带文本格式可选的富消息与附件列表
用于适配器按渠道协议渲染最终消息
字段
content: 消息文本内容
format: 消息格式默认 TEXT
rich_message: 渲染后的渠道原生富消息对象可选
RichMessageAdapter.renderRichMessage 产生类型由具体适配器
决定
attachments: 附件列表默认空 tupleFR-51
"""
content: str
format: MessageFormat = MessageFormat.TEXT
rich_message: Any = None
attachments: tuple[Attachment, ...] = ()
@dataclass(frozen=True)
class TrustedMessage:
"""可信消息。
描述经服务端强制注入发送者身份与所有者标记的消息用于可信注入
边界FR-25确保渠道侧无法伪造发送者
字段
content: 消息文本内容
sender_id: 发送者 ID服务端强制注入
is_owner: 是否为会话所有者服务端强制注入默认 False
rich_message: 渲染后的渠道原生富消息对象可选
FormattedMessage 透传FR-08
"""
content: str
sender_id: str
is_owner: bool = False
rich_message: Any = None
def __post_init__(self) -> None:
"""校验必填字段非空。
``content`` ``sender_id`` 必须非空在构造时即抛出
``ValidationError``避免空消息内容或空发送者身份传播到渠道
适配器INV-8
"""
if not self.content:
raise ValidationError("content", "must not be empty")
if not self.sender_id:
raise ValidationError("sender_id", "must not be empty")
@dataclass(frozen=True)
class FinalMessage:
"""最终消息。
描述出站管道最终投递至渠道适配器的消息携带文本发送者 ID
可选前缀前缀用于所有者标记等场景
字段
content: 消息文本内容
sender_id: 发送者 ID
prefix: 前缀可选如所有者标记
rich_message: 渲染后的渠道原生富消息对象可选
TrustedMessage 透传FR-08
"""
content: str
sender_id: str
prefix: str | None = None
rich_message: Any = None
def __post_init__(self) -> None:
"""校验必填字段非空。
``content`` ``sender_id`` 必须非空在构造时即抛出
``ValidationError``避免空消息内容或空发送者身份投递到渠道
INV-8
"""
if not self.content:
raise ValidationError("content", "must not be empty")
if not self.sender_id:
raise ValidationError("sender_id", "must not be empty")
@dataclass(frozen=True)
class BatchSendItem:
"""批量发送单条结果。
描述 ``OutboundAdapter.batchSendMessages`` 单条投递结果
``MultiPartReceipt`` 区别``MultiPartReceipt`` 描述**同一条**逻辑
消息拆分为多个分片的回执``BatchSendItem`` 描述**同一负载**投递到
多个 peer 的逐条结果
字段
peer_id: 接收目标 ID
channel_msg_id: 渠道侧消息 ID成功时非空失败时为空字符串
success: 是否投递成功
error: 失败时的错误信息可选成功时为 ``None``
"""
peer_id: str
channel_msg_id: str
success: bool
error: str | None = None
@dataclass(frozen=True)
class BatchSendResult:
"""批量发送结果。
描述 ``OutboundAdapter.batchSendMessages`` 的聚合结果包含逐条结果
与汇总统计集合字段使用 tuple 以保证 frozen dataclass 的不可变语义
字段
total: 总投递目标数
succeeded: 成功的目标 ID 元组
failed: 失败条目元组含目标 ID 与错误信息
items: 逐条结果元组含成功与失败
"""
total: int
succeeded: tuple[str, ...]
failed: tuple[BatchSendItem, ...]
items: tuple[BatchSendItem, ...]