From 6540698bf6c03decb35a0ab824d18faa1842e7ab Mon Sep 17 00:00:00 2001 From: lhl Date: Thu, 13 Aug 2026 09:08:08 +0800 Subject: [PATCH] feat(writer): add Phase5 data models (ContentBlock/ChapterContent/GenerationContext/ChapterSpec) --- src/genesis/writer/models.py | 51 ++++++++++++++++++++++++++++++++++++ tests/test_phase5_models.py | 30 +++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/genesis/writer/models.py create mode 100644 tests/test_phase5_models.py diff --git a/src/genesis/writer/models.py b/src/genesis/writer/models.py new file mode 100644 index 0000000..a89bfa8 --- /dev/null +++ b/src/genesis/writer/models.py @@ -0,0 +1,51 @@ +"""Writer 子系统数据模型(Phase 5)。""" +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Literal + + +@dataclass +class ContentBlock: + """LLM 生成的内容块。注意:table.headers/caption、list.items/style 在渲染至 + DocxInjector.Block 时显式丢弃(renderer 中声明并测试)。""" + + block_id: str + type: Literal["paragraph", "heading", "table", "list", "note"] + level: int | None = None + text: str | None = None + caption: str | None = None + headers: list[str] | None = None + rows: list[list[str]] | None = None + items: list[str] | None = None + style: str | None = None + source_uris: list[str] = field(default_factory=list) + + +@dataclass +class ChapterContent: + chapter_id: str + version: int + title: str + blocks: list[ContentBlock] + + +@dataclass +class ChapterSpec: + """template_mapper 产出:驱动 WriterAgent 串行顺序。""" + + chapter_id: str + title: str + section_placeholder: str | None = None # 如 "{{section:db_design}}",无则 None + + +@dataclass +class GenerationContext: + chapter_id: str + title: str + template_marker: ChapterSpec + structured_source: object | None + write_rules: list[str] + design_rules: list[str] + template_styles: set[str] + prior_state: object | None = None # WriterState,避免循环 import 用 object diff --git a/tests/test_phase5_models.py b/tests/test_phase5_models.py new file mode 100644 index 0000000..f509659 --- /dev/null +++ b/tests/test_phase5_models.py @@ -0,0 +1,30 @@ +from dataclasses import FrozenInstanceError +from genesis.writer.models import ContentBlock, ChapterContent, GenerationContext, ChapterSpec + + +def test_content_block_defaults(): + b = ContentBlock(block_id="b1", type="paragraph", text="你好") + assert b.level is None + assert b.source_uris == [] + + +def test_chapter_content_holds_blocks(): + b = ContentBlock(block_id="b1", type="heading", level=2, text="标题") + c = ChapterContent(chapter_id="db_design", version=1, title="DB 设计", blocks=[b]) + assert c.blocks[0].type == "heading" + assert c.version == 1 + + +def test_generation_context_no_impact_field(): + ctx = GenerationContext( + chapter_id="db_design", title="DB 设计", + template_marker=ChapterSpec(chapter_id="db_design", title="DB 设计", section_placeholder="{{section:db_design}}"), + structured_source=None, write_rules=["规则1"], design_rules=["规则2"], + template_styles={"Heading 1"}, + ) + assert not hasattr(ctx, "impact") + + +def test_chapter_spec_placeholder_optional(): + s = ChapterSpec(chapter_id="x", title="X", section_placeholder=None) + assert s.section_placeholder is None