本次提交包含多项代码优化与规范修正: 1. 文档与注释优化:修正注释术语、补充注解与FR编号 2. 代码格式调整:统一空格、换行与缩进规范 3. 类型与接口完善:补充__all__导出、修正返回类型注解 4. 错误处理增强:新增领域错误类与校验逻辑 5. 依赖与导入调整:修复路径引用、统一时区导入 6. 协议与契约更新:完善接口文档与一致性注解
181 lines
6.1 KiB
Python
181 lines
6.1 KiB
Python
"""流式 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
|