"""人工创作命令的共同外壳;作者身份从接入取得,不接受客户端自报。""" from datetime import datetime from typing import Any, Literal from pydantic import BaseModel, ConfigDict, Field, StrictInt from muse.作品规划.接口 import ( 作品错误, 探索选择, 档案保存, 档案结构, 节点目录保存, 规划保存, 规划定位, ) from muse.元数据.接口 import 字段变更 from muse.共享.调用身份 import 内容用途, 调用身份 from muse.故事世界.接口 import ( 事实字段提案请求, 事实定位, 事实提案请求, 事实结构, 叙事窗口, 正文依据, 知情记录, ) from muse.正文写作.接口 import 候选定位, 正文草稿, 段落 class 创作命令(BaseModel): model_config = ConfigDict(extra="forbid") command_id: str = Field(min_length=1) class 档案保存请求(创作命令): work_id: str = Field(min_length=1) expected_revision: int = Field(ge=0) content: dict = Field(default_factory=dict) schema_binding: 档案结构 changes: list[字段变更] = Field(default_factory=list) def 业务请求(self) -> 档案保存: return 档案保存( self.work_id, self.expected_revision, self.content, self.schema_binding, tuple(self.changes), ) class 新增章节请求(创作命令): work_id: str = Field(min_length=1) chapter_id: str = Field(min_length=1) title: str expected_directory_revision: int = Field(ge=0) class 重排章节请求(创作命令): work_id: str = Field(min_length=1) chapter_ids: list[str] expected_directory_revision: int = Field(ge=0) class 人工保存请求(创作命令): chapter_id: str = Field(min_length=1) branch_id: str = "main" expected_revision: int = Field(ge=0) document: 正文草稿 class 回退正文请求(创作命令): chapter_id: str = Field(min_length=1) branch_id: str = "main" expected_revision: int = Field(ge=0) restore_from: int = Field(ge=1) class 章后重建请求(创作命令): """作者明确重建章后派生;配置ID 缺省时使用部署声明的抽取配置。""" work_id: str = Field(min_length=1) branch_id: str = "main" config_id: str | None = Field(default=None, min_length=1) class 候选修改请求(创作命令): candidate_id: str = Field(min_length=1) expected_candidate_revision: int = Field(ge=1) expected_candidate_hash: str = Field(min_length=1) document: 正文草稿 | None = None selected_changes: list[str] = Field(default_factory=list) class 候选审阅请求(BaseModel): model_config = ConfigDict(extra="forbid") candidate_id: str = Field(min_length=1) candidate_revision: int = Field(ge=1) candidate_hash: str = Field(min_length=1) target_ref: str = Field(min_length=1) expected_revision: int = Field(ge=0) def 定位(self) -> 候选定位: return 候选定位( self.candidate_id, self.candidate_revision, self.candidate_hash, self.target_ref, self.expected_revision, ) class 候选决定请求(候选审阅请求, 创作命令): action: Literal["adopt", "reject", "defer"] author_review_id: str = Field(min_length=1) review_hash: str = Field(min_length=1) approved_changes: list[str] = Field(default_factory=list) class 候选差异结果(BaseModel): change_id: str start: int end: int before: list[段落] after: list[段落] before_text: str after_text: str class 候选检查结果(BaseModel): format: str format_version: int quality: str class 正文候选结果(BaseModel): document_hash: str | None = None candidate_id: str revision: int candidate_hash: str document_id: str chapter_id: str branch_id: str origin: str base_revision: int current_document_revision: int document: 正文草稿 visible_text: str checks: 候选检查结果 decision: Literal["undecided", "adopt", "reject", "defer"] stale: bool changes: list[候选差异结果] class 正文候选摘要(BaseModel): candidate_id: str revision: int candidate_hash: str document_id: str chapter_id: str branch_id: str origin: str base_revision: int current_document_revision: int decision: Literal["undecided", "adopt", "reject", "defer"] stale: bool class 正文候选摘要页(BaseModel): items: list[正文候选摘要] next_cursor: str | None class 作品表单结果(BaseModel): work_id: str revision: int content: dict[str, Any] schema_binding: 档案结构 visible_schema: dict[str, Any] editable_schema: dict[str, Any] visible_projection_version: str class 作品概要(BaseModel): work_id: str revision: int content: dict[str, Any] class 正式回执结果(BaseModel): receipt_id: str command_id: str target_ref: str action: str author_review_id: str | None basis: dict[str, Any] results: list[dict[str, Any]] impact_ids: list[str] # S01 回执固定带变更标记;HTTP 合同与 CLI 必须同形。 did_change: bool = True no_change: bool = False class 章节条目(BaseModel): chapter_id: str title: str position: int class 目录结果(BaseModel): work_id: str revision: int chapters: list[章节条目] class 节点目录请求(创作命令): directory: 节点目录保存 class 节点条目(BaseModel): node_id: str kind: Literal["volume", "chapter", "scene"] title: str parent_id: str | None position: int class 节点目录结果(BaseModel): work_id: str revision: int nodes: list[节点条目] class 正文读取结果(BaseModel): work_id: str document_id: str chapter_id: str branch_id: str revision: int state: Literal["saved", "unsaved"] document: 正文草稿 visible_text: str document_hash: str visible_text_hash: str class 正文历史结果(BaseModel): revision: int document_hash: str visible_text_hash: str restored_from: int | None created_at: datetime class 候选审阅结果(BaseModel): review_id: str review_hash: str snapshot: dict[str, Any] candidate: 正文候选结果 before: 正文读取结果 class 候选进度结果(BaseModel): candidate_id: str revision: int decision: str stale: bool class 章节进度结果(BaseModel): chapter_id: str title: str position: int document_revision: int document_hash: str visible_characters: int candidates: list[候选进度结果] class 任务进度结果(BaseModel): task_id: str state: str event_cursor: int class 作品进度结果(BaseModel): work_id: str directory_revision: int total_chapters: int saved_chapters: int undecided_candidates: int chapters: list[章节进度结果] tasks: list[任务进度结果] def 创作身份(作者: str, 配置) -> 调用身份: # 人工命令不是S02后台任务,不编造数据库中不存在的task_id。 return 调用身份(作者, None, 配置.运行用途, 内容用途.规划) def 核对路径(路径身份: str, 请求身份: str) -> None: if 路径身份 != 请求身份: raise 作品错误("SCOPE_DENIED", "请求目标与访问路径不一致") class 事实创建请求(创作命令): proposal: 事实提案请求 | 事实字段提案请求 = Field(union_mode="left_to_right") class 事实审阅请求(BaseModel): model_config = ConfigDict(extra="forbid") proposal_id: str proposal_revision: int = Field(ge=1) proposal_hash: str target_ref: str expected_revision: int = Field(ge=0) def 定位(self) -> 事实定位: return 事实定位( self.proposal_id, self.proposal_revision, self.proposal_hash, self.target_ref, self.expected_revision, ) class 事实决定请求(事实审阅请求, 创作命令): action: Literal["adopt", "reject", "defer"] author_review_id: str review_hash: str approved_changes: list[str] = Field(default_factory=list) class 事实来源版本(BaseModel): chapter_id: str branch_id: str revision: int document_hash: str class 世界事实结果(BaseModel): object_id: str type_id: str revision: int system_revision: int content: dict[str, Any] effective_from: str | None knowledge_mode: str independent: bool content_hash: str projection_version: str schema_binding: dict[str, Any] sources: list[事实来源版本] planned_window: dict[str, str] | None = None class 事实省略原因(BaseModel): object_id: str reason: str class 世界查询结果(BaseModel): work_id: str directory_revision: int system_revision: int facts: list[世界事实结果] beliefs: list[世界事实结果] plans: list[世界事实结果] omitted: list[事实省略原因] class 事实提案结果(BaseModel): proposal_id: str revision: int proposal_hash: str work_id: str object_id: str expected_revision: int schema_binding: 事实结构 = Field(alias="schema") content: dict[str, Any] independent: bool sources: list[dict[str, Any]] effective_from: str | None knowledge_mode: str known_to: list[知情记录] planned_window: dict[str, str] | None decision: str class 事实审阅结果(BaseModel): review_id: str review_hash: str snapshot: dict[str, Any] proposal: 事实提案结果 class 实体编辑上下文(BaseModel): sources: list[正文依据] independent: bool knowledge_mode: Literal["fact", "belief", "plan", "setting"] effective_from: str | None known_to: list[知情记录] reader_visible: bool planned_window: 叙事窗口 | None class 实体表单结果(BaseModel): work_id: str object_id: str type_id: str revision: int schema_binding: 事实结构 content: dict[str, Any] visible_schema: dict[str, Any] editable_schema: dict[str, Any] visible_projection_version: str source_current: bool context: 实体编辑上下文 class 探索保存请求(BaseModel): model_config = ConfigDict(extra="forbid") draft_id: str title: str content: str expected_hash: str | None class 探索检查请求(BaseModel): model_config = ConfigDict(extra="forbid") expected_hash: str class 探索稿概要(BaseModel): draft_id: str title: str revision: int draft_hash: str class 探索稿结果(探索稿概要): content: str class 交付格式问题(BaseModel): code: str message: str class 探索检查结果(BaseModel): draft_id: str draft_hash: str valid: bool problems: list[交付格式问题] setting_count: int contract_version: str class 探索选定请求(创作命令): selection: 探索选择 class 已选探索稿(BaseModel): work_id: str revision: int snapshot: 探索稿结果 selected_by: str selected_at: str class 探索选定状态(BaseModel): work_id: str revision: int selection: 已选探索稿 | None class 规划候选请求(创作命令): request: 规划保存 class 规划生成请求(规划候选请求): instruction: str = Field(min_length=1) config_id: str = Field(min_length=1) budget: dict[str, StrictInt] | None = None class 规划任务结果(BaseModel): task_id: str class 规划编辑请求(创作命令): candidate: 规划定位 changes: list[字段变更] class 规划决定请求(创作命令): candidate: 规划定位 action: Literal["adopt", "reject", "defer"] author_review_id: str review_hash: str approved_changes: list[str] class 规划候选结果(BaseModel): candidate_id: str origin: Literal["author", "model"] = "author" model_source: dict[str, str] | None = None plan_id: str revision: int candidate_hash: str work_id: str chapter_id: str | None node_id: str | None = None expected_revision: int schema_binding: 档案结构 content: dict[str, Any] decision: str visible_schema: dict[str, Any] editable_schema: dict[str, Any] class 规划结果(BaseModel): plan_id: str work_id: str chapter_id: str | None node_id: str | None = None type_id: str revision: int content: dict[str, Any] schema_binding: dict[str, Any] source_dependencies: list[dict[str, str]] class 规划审阅结果(BaseModel): review_id: str review_hash: str snapshot: dict[str, Any] candidate: 规划候选结果 before: 规划结果 | None class 规划表单结果(BaseModel): work_id: str chapter_id: str | None node_id: str | None = None plan_id: str revision: int schema_binding: 档案结构 content: dict[str, Any] visible_schema: dict[str, Any] editable_schema: dict[str, Any] class 实体保存请求(创作命令): object_id: str = Field(min_length=1) expected_revision: int = Field(ge=0) schema_id: str = Field(min_length=1) schema_version: int = Field(ge=1) content: dict sources: list[dict] = [] independent: bool = True knowledge_mode: Literal["fact", "belief", "plan", "setting"] = "setting" effective_from: str | None = None known_to: list[dict] = [] planned_window: dict | None = None instance_family: Literal["entity", "relation"] = "entity"