"""截断检测 DTO。 定义上下文截断检测的不可变值对象,包括截断候选与截断结果。所有 DTO 均为 ``dataclass(frozen=True)``,仅依赖标准库,用于上下文长度超限时的截断 检测与降级策略决策。 """ from __future__ import annotations from dataclasses import dataclass from yuxi.channels.contract.errors import ValidationError @dataclass(frozen=True) class TruncationCandidate: """截断候选。 描述一个待截断的文本片段,包括文本内容、来源与长度,用于截断策略的 优先级排序。 字段: text: 文本内容。 source: 来源(system_prompt | context_remark | user_message | ...)。 length: 文本长度。 """ text: str source: str length: int def __post_init__(self) -> None: """校验 text / source 非空与 length 非负。 ``text`` 与 ``source`` 必须非空,``length`` 必须非负,在构造时即 抛出 ``ValidationError``,避免空文本或负长度破坏截断策略排序(INV-8)。 """ if not self.text: raise ValidationError("text", "must not be empty") if not self.source: raise ValidationError("source", "must not be empty") if self.length < 0: raise ValidationError("length", "must not be negative") @dataclass(frozen=True) class TruncationResult: """截断结果。 描述截断检测的结果,包括是否发生截断、缺失内容与是否降级到持久化查询。 检测到截断时携带补全文本与长度信息(FR-28)。 字段: is_truncated: 是否发生截断。 missing_content: 缺失内容(未截断时为 None)。 fallback_to_persistent: 是否降级到持久化查询(默认 False)。 completed_text: 补全后的文本(补全失败时为原始截断文本,未截断时为 None)。 original_length: 原始截断文本长度(未截断时为 None)。 completed_length: 补全后文本长度(未截断时为 None)。 """ is_truncated: bool missing_content: str | None = None fallback_to_persistent: bool = False completed_text: str | None = None original_length: int | None = None completed_length: int | None = None