feat: T6.1 创作工具箱通用生成器框架地基 — 脑洞生成器 + run_generator
- schemas: Idea/IdeaListResult(脑洞生成器结构化产出,纯预览不入库) - specs: brainstorm_spec(light 档,reads=[projects] writes=[]) - orchestrator: build_brief_context(brief_only 策略)+ 通用 run_generator (据 spec.output_schema 校验 parsed,不绑定具体类型,任一声明式生成器共用) - 新增 13 测;两包 ruff/format/mypy 干净、252 passed 无回归 P1 第一波(@llm):证实「加生成器=加一份声明」。@backend T6.2/T6.3 待续。
This commit is contained in:
91
packages/core/tests/test_generator_node.py
Normal file
91
packages/core/tests/test_generator_node.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""T6 通用生成器执行器单测:`run_generator` + `build_brief_context`。
|
||||
|
||||
注入 mock 网关(产 IdeaListResult parsed),无真 LLM、无真 Postgres。通用执行器据
|
||||
`spec.output_schema` 校验 parsed(不绑定具体类型);只产结构化产物,**不写库**(纯预览,
|
||||
不变量 #3)。asyncio_mode=auto。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from fakes_orchestrator import FailingRunGateway, FakeRunGateway
|
||||
from ww_agents import Idea, IdeaListResult, brainstorm_spec
|
||||
from ww_core.orchestrator import build_brief_context, run_generator
|
||||
|
||||
PROJECT = uuid.UUID("00000000-0000-0000-0000-000000000001")
|
||||
USER = uuid.UUID("00000000-0000-0000-0000-0000000000aa")
|
||||
|
||||
_IDEAS = IdeaListResult(
|
||||
ideas=[
|
||||
Idea(premise="废柴觉醒吞噬瞳", hook="升级要付记忆", genre_fit="玄幻"),
|
||||
Idea(premise="末世种粮农场主", hook="粮食成硬通货"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# ---- run_generator:返回结构化产物,据 output_schema 校验,只读不写库 ----
|
||||
|
||||
|
||||
async def test_run_generator_returns_structured_result() -> None:
|
||||
gateway = FakeRunGateway(_IDEAS)
|
||||
|
||||
result = await run_generator(
|
||||
brainstorm_spec,
|
||||
context=build_brief_context(brief="来点逆袭流", project_context="题材:玄幻"),
|
||||
gateway=gateway,
|
||||
user_id=USER,
|
||||
project_id=PROJECT,
|
||||
)
|
||||
|
||||
assert isinstance(result, IdeaListResult)
|
||||
assert len(result.ideas) == 2
|
||||
assert result.ideas[0].premise == "废柴觉醒吞噬瞳"
|
||||
|
||||
|
||||
async def test_run_generator_passes_tier_and_schema_to_gateway() -> None:
|
||||
# 不变量 #2:只透传档位(light),不传 model;output_schema 据 spec 绑定
|
||||
gateway = FakeRunGateway(_IDEAS)
|
||||
|
||||
await run_generator(
|
||||
brainstorm_spec,
|
||||
context="x",
|
||||
gateway=gateway,
|
||||
user_id=USER,
|
||||
project_id=PROJECT,
|
||||
)
|
||||
|
||||
assert gateway.last_request is not None
|
||||
assert gateway.last_request.tier == "light"
|
||||
assert gateway.last_request.output_schema is IdeaListResult
|
||||
|
||||
|
||||
async def test_run_generator_raises_on_gateway_failure() -> None:
|
||||
# 独立生成:网关失败直接上抛(端点处理),不静默吞
|
||||
gateway = FailingRunGateway(RuntimeError("boom"))
|
||||
|
||||
with pytest.raises(RuntimeError, match="boom"):
|
||||
await run_generator(
|
||||
brainstorm_spec,
|
||||
context="x",
|
||||
gateway=gateway,
|
||||
user_id=USER,
|
||||
project_id=PROJECT,
|
||||
)
|
||||
|
||||
|
||||
# ---- build_brief_context:确定性、空需求降级占位 ----
|
||||
|
||||
|
||||
def test_build_brief_context_is_deterministic() -> None:
|
||||
a = build_brief_context(brief="逆袭", project_context="题材:玄幻")
|
||||
b = build_brief_context(brief="逆袭", project_context="题材:玄幻")
|
||||
assert a == b
|
||||
assert "题材:玄幻" in a
|
||||
assert "逆袭" in a
|
||||
|
||||
|
||||
def test_build_brief_context_empty_brief_falls_back() -> None:
|
||||
ctx = build_brief_context(brief=" ", project_context="题材:都市")
|
||||
assert "按题材自由发散" in ctx
|
||||
Reference in New Issue
Block a user