"""需求理解的输出协议,描述用户诉求,不包含前端执行动作。""" from typing import Literal, Self from pydantic import Field, model_validator from .base import ExtensibleModel, JsonObject, NonBlankString Intent = Literal["create_screen", "modify_screen", "qa", "unclear"] TargetScope = Literal["nodes", "canvas", "screen", "unresolved"] class RequirementChange(ExtensibleModel): """一项需求变更。目标范围显式声明,避免空 ID 被理解成修改整个大屏。""" target_scope: TargetScope = Field( description="nodes=已有节点;canvas=画布属性;screen=整体或新增内容;unresolved=目标待确认" ) target_ids: list[NonBlankString] = Field( default_factory=list, description="已有节点的 ID;新增组件不能虚构 ID" ) target_description: NonBlankString | None = Field( default=None, description="目标的自然语言描述,例如右侧区域、用户所说的那个图" ) operation: NonBlankString = Field( description="需求操作,例如 move、resize、add、delete、restyle;允许后续扩展" ) parameters: JsonObject = Field( default_factory=dict, description="需求参数,例如 delta_x=50;保留用户要求的单位与相对变化语义", ) @model_validator(mode="after") def validate_target(self) -> Self: if len(self.target_ids) != len(set(self.target_ids)): raise ValueError("target_ids 不能包含重复 ID") if self.target_scope == "nodes": if not self.target_ids: raise ValueError("nodes 范围必须提供 target_ids") elif self.target_ids: raise ValueError("只有 nodes 范围可以提供 target_ids") if self.target_scope == "unresolved" and self.target_description is None: raise ValueError("目标待确认时必须提供 target_description") return self class Requirement(ExtensibleModel): intent: Intent goal: NonBlankString = Field(description="忠实概括用户目标,不能擅自扩大修改范围") changes: list[RequirementChange] = Field(default_factory=list) needs_clarification: bool clarification_question: NonBlankString | None = None assumptions: list[NonBlankString] = Field( default_factory=list, description="非阻塞信息采用的默认假设,不可用来猜测删除目标", ) constraints: list[NonBlankString] = Field( default_factory=list, description="用户明确提出的约束,例如只修改右侧、保留其他组件", ) @model_validator(mode="after") def validate_consistency(self) -> Self: if self.needs_clarification != (self.clarification_question is not None): raise ValueError("需要澄清时必须提供问题,不需要澄清时问题应为 null") if self.intent == "unclear" and not self.needs_clarification: raise ValueError("意图不明确时必须澄清") if any(change.target_scope == "unresolved" for change in self.changes): if not self.needs_clarification: raise ValueError("存在待确认目标时必须澄清") if self.intent == "qa" and self.changes: raise ValueError("纯问答需求不应包含大屏变更") return self