feat(ux): T4-b 后端 — draft 端点接收本章指令 directive 直通 assemble(volatile)
assemble/_build_volatile 加 directive 参数(仅入 volatile,守缓存前缀不变量 #9);stream_draft 加可选 body {directive} 透传;不持久化、无迁移;directive 长度入 log 不记原文。新 DraftStreamRequest schema + 重生成 TS 客户端。后端门禁绿: ruff/mypy/pytest。契约记 memory/contracts.md。
This commit is contained in:
@@ -293,6 +293,18 @@ async def test_assemble_override_recent_n_limits_digests() -> None:
|
||||
assert "实体1" not in names
|
||||
|
||||
|
||||
async def test_assemble_directive_in_volatile_not_stable() -> None:
|
||||
repos = build_repos(
|
||||
characters=[char("林动", role="主角")],
|
||||
spec=ProjectSpecView(title="书"),
|
||||
)
|
||||
ctx = await assemble(repos, PROJECT, 1, directive="多写战斗")
|
||||
assert "本章指令" in ctx.volatile
|
||||
assert "多写战斗" in ctx.volatile
|
||||
assert "多写战斗" not in ctx.stable_core
|
||||
assert "本章指令" not in ctx.stable_core
|
||||
|
||||
|
||||
# ---- render_cards ----
|
||||
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ def _build_volatile(
|
||||
foreshadows: list[ForeshadowView],
|
||||
digests: list[DigestView],
|
||||
beats: dict[str, Any],
|
||||
directive: str | None = None,
|
||||
) -> str:
|
||||
fore_lines = [
|
||||
f"【伏笔】{f.code} {f.title} [{f.status}]"
|
||||
@@ -113,6 +114,8 @@ def _build_volatile(
|
||||
f"第{d.chapter_no}章:{_ser(d.facts)}" for d in sorted(digests, key=lambda d: d.chapter_no)
|
||||
]
|
||||
sections = [
|
||||
# 作者本章指令领衔——易变的每章输入,只入 volatile(断点后),守缓存前缀不变量 #9。
|
||||
_section("本章指令", directive.strip()) if directive and directive.strip() else None,
|
||||
# 写章指令始终在场——保证 volatile(断点后的 input)永不为空(修空 prompt 400)。
|
||||
_section("写作指令", f"请创作第 {chapter_no} 章的正文。"),
|
||||
_section("本章注入卡片", cards),
|
||||
@@ -130,11 +133,15 @@ async def assemble(
|
||||
recent_k: int = RECENT_DIGEST_COUNT,
|
||||
*,
|
||||
override: InjectionOverride | None = None,
|
||||
directive: str | None = None,
|
||||
) -> AssembledContext:
|
||||
"""组装本章 prompt 上下文(确定性、可缓存)。
|
||||
|
||||
`override`(B0 可控版作者覆盖)也是确定性输入:pin 强制纳入 / excluded 强制剔除 /
|
||||
recent_n 覆盖近况回看章数。draft 与注入读端点传同一覆盖,故「看到的=写章用的」(不变量 #6)。
|
||||
|
||||
`directive`(T4-b 本章指令)是临时的每章输入——只入 volatile(断点后),绝不污染
|
||||
stable_core 缓存前缀(不变量 #9);不持久化。
|
||||
"""
|
||||
# recent_n 覆盖优先于默认 recent_k;非正值视为未设(守住至少回看若干章)。
|
||||
effective_k = override.recent_n if (override and override.recent_n) else recent_k
|
||||
@@ -171,6 +178,8 @@ async def assemble(
|
||||
|
||||
stable_core = _build_stable(spec, world_entities, main_characters, style, rules)
|
||||
cards = render_cards(selection, characters, world_entities)
|
||||
volatile = _build_volatile(chapter_no, cards, foreshadows, recent_digests, outline.beats)
|
||||
volatile = _build_volatile(
|
||||
chapter_no, cards, foreshadows, recent_digests, outline.beats, directive
|
||||
)
|
||||
|
||||
return AssembledContext(stable_core=stable_core, volatile=volatile, selection=selection)
|
||||
|
||||
Reference in New Issue
Block a user