Files
writer-work-flow/packages/skills/tests/test_toolbox_registry.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

86 lines
2.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.2 创作工具箱注册表(`TOOLBOX`)单测。
校验11 条齐全legacy 3 + 新 8legacy 携 legacy_route 且 spec=None新工具携 spec +
output_schema与 spec.output_schema 一致ingest 工具的 table 在白名单内;`get_tool` 解析。
"""
from __future__ import annotations
from ww_skills import TOOLBOX, get_tool
_LEGACY_KEYS = {"worldbuilding", "character", "outline"}
_NEW_KEYS = {
"brainstorm",
"book-title",
"blurb",
"name",
"golden-finger",
"glossary",
"opening",
"fine-outline",
}
_INGEST_KEYS = {"golden-finger", "glossary", "fine-outline"}
def test_toolbox_has_all_eleven_tools() -> None:
# Arrange / Act
keys = set(TOOLBOX.keys())
# Assert
assert keys == _LEGACY_KEYS | _NEW_KEYS
assert len(TOOLBOX) == 11
def test_legacy_tools_have_route_and_no_spec() -> None:
for key in _LEGACY_KEYS:
tool = TOOLBOX[key]
assert tool.spec is None, key
assert tool.output_schema is None, key
assert tool.legacy_route is not None, key
assert "{id}" in tool.legacy_route, key
def test_new_tools_carry_spec_and_matching_schema() -> None:
for key in _NEW_KEYS:
tool = TOOLBOX[key]
assert tool.spec is not None, key
assert tool.output_schema is not None, key
# 描述符的 output_schema 必须与其 spec 的 output_schema 一致(同一真类)。
assert tool.output_schema is tool.spec.output_schema, key
assert tool.legacy_route is None, key
# 每个新工具的 key 与 spec.name 一致(路由稳定)。
assert tool.key == tool.spec.name, key
def test_ingest_tools_declare_known_table() -> None:
for key, tool in TOOLBOX.items():
if key in _INGEST_KEYS:
assert tool.ingest is not None, key
else:
assert tool.ingest is None, key
assert TOOLBOX["golden-finger"].ingest is not None
assert TOOLBOX["golden-finger"].ingest.table == "world_entities"
assert TOOLBOX["glossary"].ingest is not None
assert TOOLBOX["glossary"].ingest.table == "world_entities"
assert TOOLBOX["fine-outline"].ingest is not None
assert TOOLBOX["fine-outline"].ingest.table == "outline"
def test_chapter_tools_have_chapter_no_field() -> None:
for key in ("opening", "fine-outline"):
field_names = {f.name for f in TOOLBOX[key].input_fields}
assert "chapter_no" in field_names, key
def test_every_tool_has_brief_field_where_applicable() -> None:
# 新工具均带 brief textarea声明驱动表单的统一入口
for key in _NEW_KEYS:
field_names = {f.name for f in TOOLBOX[key].input_fields}
assert "brief" in field_names, key
def test_get_tool_resolves_known_and_unknown() -> None:
assert get_tool("brainstorm") is TOOLBOX["brainstorm"]
assert get_tool("worldbuilding") is TOOLBOX["worldbuilding"]
assert get_tool("does-not-exist") is None