"""人格 API schema。""" from typing import Any from pydantic import BaseModel, ConfigDict, Field class PersonalityResponse(BaseModel): model_config = ConfigDict( json_schema_extra={ "examples": [ { "id": "personality_9b5f5b7e413442d0a2f9e61a2f4d7df5", "character_id": "character_ec83d55746c54e47ab6f98d683032626", "version": 1, "identity_profile": "魂镜默认人物,面向本地 MVP 联调。", "role_destiny": "帮助用户验证对话、记忆和运行时链路。", "personality_seed": "稳定、简洁、可靠。", "traits": {"tone": "calm", "helpfulness": 0.9}, "expression_style": "使用简洁中文回答,必要时列出验证步骤。", "values": {"accuracy": "high", "privacy": "high"}, "relationship_pattern": "以协作者方式与用户互动。", "emotion_baseline": {"mood": "neutral"}, "reason": "初始化默认人格。", "evidence_ids": [], "created_by": "system", "created_at": "2026-06-19T09:00:00.000000Z", } ] } ) id: str = Field(description="人格版本 ID。") character_id: str = Field(description="所属人物 ID。") version: int = Field(description="人格版本号。") identity_profile: str = Field(description="身份画像。") role_destiny: str = Field(description="角色定位与使命。") personality_seed: str = Field(description="人格种子。") traits: dict[str, Any] = Field(description="人格特质。") expression_style: str = Field(description="表达风格。") values: dict[str, Any] = Field(description="价值偏好。") relationship_pattern: str = Field(description="关系模式。") emotion_baseline: dict[str, Any] = Field(description="情绪基线。") reason: str = Field(description="版本创建原因。") evidence_ids: list[str] = Field(description="证据 ID 列表。") created_by: str = Field(description="创建者。") created_at: str = Field(description="创建时间,UTC ISO 8601 字符串。") # 允许人工提议覆盖的人格字段(None 表示不改)。dict 字段落库为 JSON 文本。 _PERSONALITY_STRING_FIELDS = ( "identity_profile", "role_destiny", "personality_seed", "expression_style", "relationship_pattern", ) _PERSONALITY_JSON_FIELDS = ("traits", "values", "emotion_baseline") class PersonalityProposalFields(BaseModel): """人格字段覆盖建议;仅列允许编辑字段,未传(None)表示不改。""" identity_profile: str | None = None role_destiny: str | None = None personality_seed: str | None = None traits: dict[str, Any] | None = None expression_style: str | None = None values: dict[str, Any] | None = None relationship_pattern: str | None = None emotion_baseline: dict[str, Any] | None = None def has_any(self) -> bool: """是否至少覆盖一个字段。""" return any( getattr(self, f) is not None for f in _PERSONALITY_STRING_FIELDS + _PERSONALITY_JSON_FIELDS ) class ProposePersonalityUpdateRequest(BaseModel): """提交人格修改建议(api-spec §11);建议进入 pending 待审核。""" character_id: str | None = Field(default=None, description="人物 ID,省略取当前激活人物。") fields: PersonalityProposalFields = Field(description="需变更的人格字段覆盖。") reason: str = Field(min_length=1, description="修改原因,必填留痕。") class PersonalityProposalResponse(BaseModel): """人格修改建议响应(api-spec §11)。""" proposal_id: str = Field(description="建议 ID。") character_id: str = Field(description="所属人物 ID。") status: str = Field(description="建议状态,见契约字典 §10.6 candidate.status。") reason: str = Field(description="修改原因。") fields: dict[str, Any] = Field(description="实际覆盖的字段集合。") resulting_version_id: str | None = Field( default=None, description="审核通过后生成的人格版本 ID。" ) reviewed_at: str | None = Field(default=None, description="审核时间。") created_at: str = Field(description="创建时间,UTC ISO 8601 字符串。")