"""T6 脑洞生成器契约测试:spec + schema(创作工具箱通用框架首个最简生成器)。 契约测试——构造符合 schema 的 mock 响应,校验字段、tier、读写权限。 brainstorm:`{ideas:[{premise,hook,genre_fit}]}`(轻量档,reads=projects,writes=[] 纯预览)。 不联网、无 DB。 """ from __future__ import annotations import pytest from pydantic import ValidationError from ww_agents import ( AgentSpec, Idea, IdeaListResult, brainstorm_spec, ) # ---- IdeaListResult schema ---- def test_idea_list_parses_mock_response() -> None: # Arrange:模拟网关 instructor 校验后的结构化脑洞产出 mock = { "ideas": [ { "premise": "废柴觉醒可吞噬规则的瞳术", "hook": "每次升级都要付出一段记忆为代价", "genre_fit": "玄幻·热血", }, {"premise": "末世里唯一能种粮的农场主", "hook": "粮食成了最硬的通货"}, ] } # Act result = IdeaListResult.model_validate(mock) # Assert assert len(result.ideas) == 2 assert result.ideas[0].premise == "废柴觉醒可吞噬规则的瞳术" assert result.ideas[0].hook == "每次升级都要付出一段记忆为代价" assert result.ideas[0].genre_fit == "玄幻·热血" assert result.ideas[1].genre_fit is None # 可缺 def test_idea_list_defaults_to_empty() -> None: assert IdeaListResult().ideas == [] def test_idea_requires_premise_and_hook() -> None: with pytest.raises(ValidationError): Idea.model_validate({"premise": "只有前提没有钩子"}) # ---- brainstorm_spec 声明 ---- def test_brainstorm_spec_is_light_tier() -> None: # 不变量 #2:脑洞发散用轻量档,只声明 tier assert brainstorm_spec.tier == "light" assert brainstorm_spec.name == "brainstorm" def test_brainstorm_spec_reads_projects_writes_nothing() -> None: # 纯预览:读作品设定、不写任何业务表(不变量 #3) assert brainstorm_spec.reads == ("projects",) assert brainstorm_spec.writes == () def test_brainstorm_spec_output_schema() -> None: assert brainstorm_spec.output_schema is IdeaListResult def test_brainstorm_spec_prompt_documents_diversification() -> None: # 一次多条须逐条差异化——system_prompt 必须强调 assert "差异化" in brainstorm_spec.system_prompt def test_brainstorm_spec_is_agent_spec_and_immutable() -> None: assert isinstance(brainstorm_spec, AgentSpec) with pytest.raises(ValidationError): brainstorm_spec.tier = "writer"