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

181 lines
6.1 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)``,仅依赖标准库与契约层内部类型,用于
流式输出的分块投递、结果同步与能力声明FR-13
"""
from __future__ import annotations
from dataclasses import dataclass
from enum import StrEnum
from yuxi.channels.contract.errors import ValidationError
class ChunkMode(StrEnum):
"""分块模式。
标识流式输出的分块模式,用于适配器按模式渲染分块。继承
``str, Enum`` 以支持 JSON 序列化与字符串比较。
取值:
NONE: 无流式(走完整消息)。
TEXT: 文本追加模式。
BLOCK: 块模式(每分块作为新消息块)。
FULL_UPDATE: 卡片整体更新。
PARTIAL_UPDATE: 卡片局部更新。
"""
NONE = "none"
TEXT = "text"
BLOCK = "block"
FULL_UPDATE = "full_update" # 卡片整体更新
PARTIAL_UPDATE = "partial_update" # 卡片局部更新
class RenderStrategy(StrEnum):
"""卡片渲染策略。
继承 ``str, Enum`` 以支持 JSON 序列化。用于 ``updatePartialCard``
方法声明局部更新的渲染策略。
取值:
APPEND: 追加到现有内容。
REPLACE: 替换现有内容。
MERGE: 合并到现有内容。
"""
APPEND = "append" # 追加到现有内容
REPLACE = "replace" # 替换现有内容
MERGE = "merge" # 合并到现有内容
@dataclass(frozen=True)
class StreamChunk:
"""流式分块。
描述流式输出的单个分块,包括内容、序号与是否末块标记,用于
适配器按序投递分块。
字段:
content: 分块内容。
sequence: 序号。
is_final: 是否末块(默认 False
"""
content: str
sequence: int
is_final: bool = False
def __post_init__(self) -> None:
"""校验 content 非空与 sequence 非负。
``content`` 必须非空,``sequence`` 必须非负,在构造时即抛出
``ValidationError``避免空分块或负序号破坏流式分块顺序INV-8
"""
if not self.content:
raise ValidationError("content", "must not be empty")
if self.sequence < 0:
raise ValidationError("sequence", "must not be negative")
@dataclass(frozen=True)
class ChunkResult:
"""分块结果。
描述单个分块投递的结果,包括分块本身、是否成功与可选错误信息,
用于流式投递的状态同步与错误处理。
字段:
chunk: 流式分块。
success: 是否成功。
error: 错误信息(可选)。
"""
chunk: StreamChunk
success: bool
error: str | None = None
@dataclass(frozen=True)
class StreamingCompleted:
"""流式完成结果。
描述流式输出完成后的汇总结果,包括总分块数与耗时(毫秒),用于
流式投递的统计与审计。
字段:
total_chunks: 总分块数。
duration_ms: 耗时(毫秒)。
"""
total_chunks: int
duration_ms: int
def __post_init__(self) -> None:
"""校验 total_chunks 为正整数与 duration_ms 非负。
``total_chunks`` 必须为正整数,``duration_ms`` 必须非负,在构造时
即抛出 ``ValidationError``避免非正分块数或负耗时导致统计失真INV-8
"""
if self.total_chunks <= 0:
raise ValidationError("total_chunks", "must be a positive integer")
if self.duration_ms < 0:
raise ValidationError("duration_ms", "must not be negative")
@dataclass(frozen=True)
class StreamingCapability:
"""流式能力。
描述渠道的流式能力声明,包括是否支持流式、是否支持输入指示、
分块模式、最小分块间隔与最大分块长度,用于 FR-13 流式能力协商
与降级决策。
字段:
supports_streaming: 是否支持流式(默认 False
supports_typing_indicator: 是否支持输入指示(默认 False
chunk_mode: 分块模式(默认 NONE
min_chunk_interval_ms: 最小分块间隔(毫秒,默认 0
max_chunk_length: 最大分块长度(默认 0
"""
supports_streaming: bool = False
supports_typing_indicator: bool = False
chunk_mode: ChunkMode = ChunkMode.NONE
min_chunk_interval_ms: int = 0
max_chunk_length: int = 0
@dataclass(frozen=True)
class StreamingConfig:
"""流式配置。
描述流式管道的运行时配置,由 ConfigPort.getStreamingConfig 读取,
用于控制流式管道是否激活、输入指示开关、最小分块间隔与 TTL 安全阀
FR-13
字段:
streaming_enabled: 是否启用流式管道(默认 False。启用时
``delivery_mode`` 设为 ``streaming``,激活 stream-chunk /
truncation-check 等流式阶段。
enable_typing: 是否启用输入指示(默认 True。typing-indicator 阶段
据此决定是否调用 ``startTypingIndicator`` / ``stopTypingIndicator``
FR-13。关闭时跳过输入指示动画不影响流式分块投递。
min_chunk_interval_ms: 最小分块间隔(毫秒,默认 200。stream-chunk
阶段据此在分批发送之间强制等待避免对渠道侧造成压力AC-22
streaming_ttl_ms: 流式 TTL 安全阀(毫秒,默认 60000。stream-chunk
阶段累计耗时超过该值时停止发送分块,由 typing-stop 阶段强制
结束流式会话并记录告警日志AC-62
typing_ttl_ms: 输入指示 TTL毫秒默认 10000。插件可据此控制
输入指示动画的刷新周期避免动画超时停留FR-13
"""
streaming_enabled: bool = False
enable_typing: bool = True
min_chunk_interval_ms: int = 200
streaming_ttl_ms: int = 60000
typing_ttl_ms: int = 10000