Files
writer-work-flow/apps/api/tests/test_toolbox_context.py
Yaojia Wang a5351320a2 feat(skills): Scope B A2 — 4 竞品生成器注册表+上下文分派+端点接线
注册表 TOOLBOX +4 entry(continue/expand/de-ai/teardown,全 preview-only writes=[]);
ContextStrategy +with_prior_chapter/text_input;ToolGenerateRequest +text 字段。
toolbox_context 分派新策略(续写→build_continuation_context、原文→build_text_input_context);
路由续写经 chapter_repo 读最新 accepted/draft 正文注入 builder(core 不 import apps/api,仿 accept_op)。
预览仅 commit ledger 不写业务表(#3);只声明 tier(#2);system_prompt 进缓存前缀(#9)。
单测:4 生成器 generate 预览 + 续写读前文/草稿路由 + 扩写/降AI text 路由 + 拆书结构化;
更新 registry/strategy 计数测试(15 工具 / 6 策略)。门禁绿:ruff/format/mypy 196 files/pytest 168(api)+32(skills)。
2026-06-23 19:10:35 +02:00

123 lines
3.9 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_with_prior_chapter_injects_prior_text_and_beats() -> None:
text = build_toolbox_context(
"with_prior_chapter",
brief="续写下文",
project_context="标题:测试",
prior_text="他推开门,看见了那道身影。",
beats=["主角揭穿阴谋"],
)
assert "前文正文" in text
assert "他推开门" in text
assert "主角揭穿阴谋" in text
def test_with_prior_chapter_empty_prior_degrades() -> None:
text = build_toolbox_context(
"with_prior_chapter", brief="", project_context="标题:测试", prior_text=""
)
# 无前文 → 降级占位(不报错),交由 system_prompt 处理。
assert "暂无前文" in text
def test_text_input_injects_source_text() -> None:
text = build_toolbox_context(
"text_input",
brief="加强环境描写",
project_context="标题:测试",
text="原始的一段正文。",
)
assert "## 原文" in text
assert "原始的一段正文" in text
assert "加强环境描写" in text
def test_text_input_empty_text_degrades() -> None:
text = build_toolbox_context("text_input", brief="", project_context="标题:测试", 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]