Files
writer-work-flow/apps/api/tests/test_toolbox_context.py
Yaojia Wang f43ccd293f feat(toolbox): T6 创作工具箱通用生成器框架 — 8 新生成器 + 声明驱动落地页 + P2 收尾
通用执行路径驱动全部生成器("加生成器=加一份声明"):
- @llm: ww_agents +7 输出 schema + 7 spec(book-title/blurb/name/golden-finger/
  glossary/opening/fine-outline,只声明 tier)+ build_outline_chapter_context
- @backend: ww_skills GeneratorTool 描述符 + TOOLBOX(11) + get_tool;3 通用端点
  GET /skills/toolbox · POST .../skills/{tool_key}/generate(预览不写库,仅记账) ·
  POST .../ingest(复用 continuity 409 + partition_writes 白名单);纯 context 派发
- @frontend: 工具箱落地页 RSC + 声明驱动 GeneratorRunner + lib/toolbox 纯函数
  + LeftNav「工具箱」+ ⌘K nav-toolbox/action-gen-*;legacy 3 跳现页
- @qa: tests/test_t6_toolbox_e2e.py 5 用例真 pg + mock 网关零 token,无端点 bug
- P2 收尾: 限流→decisions.md 记延后(单用户原型);noopener/Committable 早已修

守不变量 #2(只声明 tier)/#3(预览不写库,入库经验收 gate)/#9(缓存前缀)。无 DB 迁移。
门禁绿: 后端 ruff/format/mypy 195/alembic 无漂移/pytest 583;前端 lint/tsc/vitest 279/build。
spec 回写 PRODUCT_SPEC §7 + ARCHITECTURE §7.2 端点表。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:37:55 +02:00

85 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""T6.3 创作工具箱 context 派发纯函数单测LLM-free确定性
每种策略的注入文本形状 + with_outline_chapter 缺节拍降级(空 beats 不报错)。
"""
from __future__ import annotations
import pytest
from ww_api.services.toolbox_context import build_toolbox_context
def test_brief_only_includes_setting_and_brief() -> None:
text = build_toolbox_context(
"brief_only", brief="爽文脑洞", project_context="标题:测试\n题材:玄幻"
)
assert "## 作品设定" in text
assert "标题:测试" in text
assert "## 创作需求" in text
assert "爽文脑洞" in text
def test_brief_only_empty_brief_degrades() -> None:
text = build_toolbox_context("brief_only", brief="", project_context="标题:测试")
# 空 brief → 降级占位(由 system_prompt 的「自由发散」纪律处理)。
assert "自由发散" in text
def test_with_project_uses_brief_context() -> None:
text = build_toolbox_context(
"with_project", brief="多版简介", project_context="标题:测试\n前提:废柴逆袭"
)
assert "前提:废柴逆袭" in text
assert "多版简介" in text
def test_with_world_injects_world_block() -> None:
text = build_toolbox_context(
"with_world",
brief="取个名字",
project_context="标题:测试",
world_context="- [力量体系] 灵脉:灵力守恒",
)
assert "## 世界观" in text
assert "灵脉" in text
assert "取个名字" in text
def test_with_world_empty_world_degrades() -> None:
text = build_toolbox_context(
"with_world", brief="x", project_context="标题:测试", world_context=""
)
assert "暂无世界观设定" in text
def test_with_outline_chapter_injects_beats() -> None:
text = build_toolbox_context(
"with_outline_chapter",
brief="展开细纲",
project_context="标题:测试",
chapter_no=3,
beats=["主角觉醒", "初遇反派"],
)
assert "第 3 章大纲节拍" in text
assert "主角觉醒" in text
assert "初遇反派" in text
assert "展开细纲" in text
def test_with_outline_chapter_missing_beats_does_not_error() -> None:
# 缺章/缺大纲 → 空节拍占位,不报错(预览降级)。
text = build_toolbox_context(
"with_outline_chapter",
brief="",
project_context="标题:测试",
chapter_no=99,
beats=[],
)
assert "第 99 章大纲节拍" in text
assert "暂无大纲节拍" in text
def test_unknown_strategy_raises() -> None:
with pytest.raises(ValueError):
build_toolbox_context("nope", brief="x", project_context="y") # type: ignore[arg-type]