Files
writer-work-flow/apps/api/ww_api/services/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

61 lines
2.8 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.

"""创作工具箱 · context 派发PURELLM-free确定性
把 `ContextStrategy` 映射成喂给网关的注入文本。**纯函数**:给定已组装好的材料
(项目设定 / 世界观文本 / 本章节拍),同输入同输出、无 IO、无时间戳——便于单测与缓存。
IO读 projects/world_entities/outline发生在端点本模块只负责「材料 → 注入文本」的
确定性拼装,复用 `ww_core.orchestrator` 的既有 context buildersbrief / outline-chapter
与 `routers/generation` 的 `_project_context` / `_world_context` 序列化口径。
策略 → 材料:
- `brief_only` :作品设定(仅标题/题材级)+ 一句话需求;
- `with_project` :作品设定(含前提/主题)+ 一句话需求;
- `with_world` :作品设定 + world_entities 硬规则卡 + 一句话需求;
- `with_outline_chapter`:作品设定 + 指定章大纲节拍(缺章/缺大纲 → 空节拍,不报错)。
"""
from __future__ import annotations
from collections.abc import Sequence
from ww_core.orchestrator import build_brief_context, build_outline_chapter_context
from ww_skills import ContextStrategy
def build_toolbox_context(
strategy: ContextStrategy,
*,
brief: str,
project_context: str,
world_context: str = "",
chapter_no: int | None = None,
beats: Sequence[str] = (),
) -> str:
"""据注入策略组装喂网关的文本PURE确定性
`project_context` 由调用方按策略序列化brief_only 给精简设定、with_project 给完整设定);
`world_context` 仅 with_world 用(已序列化的硬规则卡);`chapter_no`/`beats` 仅
with_outline_chapter 用(缺章/缺大纲时 beats 为空,降级到空节拍而非报错)。
"""
if strategy in ("brief_only", "with_project"):
return build_brief_context(brief=brief, project_context=project_context)
if strategy == "with_world":
base = build_brief_context(brief=brief, project_context=project_context)
world_block = world_context.strip() or "(暂无世界观设定)"
return f"{base}\n\n## 世界观(硬规则供契合/校验)\n{world_block}"
if strategy == "with_outline_chapter":
# 缺章号时退回首章占位(端点对需要章号的工具会先校验,这里只做确定性兜底)。
no = chapter_no if chapter_no is not None else 1
outline_block = build_outline_chapter_context(
chapter_no=no, beats=beats, project_context=project_context
)
brief_block = brief.strip()
if brief_block:
return f"{outline_block}\n\n## 创作需求\n{brief_block}"
return outline_block
# 受限枚举不应到达此分支;保守抛错而非静默错配策略。
raise ValueError(f"unknown context strategy: {strategy!r}")