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>
This commit is contained in:
Yaojia Wang
2026-06-22 20:37:55 +02:00
parent 1f1afa37b6
commit f43ccd293f
46 changed files with 4848 additions and 12 deletions

View File

@@ -487,6 +487,68 @@ export interface paths {
patch?: never;
trace?: never;
};
"/skills/toolbox": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* List Toolbox
* @description 创作工具箱全量描述符legacy + 新工具;前端据此渲染卡片栅格 + 表单 + 路由)。
*/
get: operations["list_toolbox_skills_toolbox_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/projects/{project_id}/skills/{tool_key}/generate": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Generate With Tool
* @description 通用生成(结构化预览,不入库)。未知/ legacy 工具→404项目不存在→404无凭据→503。
*/
post: operations["generate_with_tool_projects__project_id__skills__tool_key__generate_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/projects/{project_id}/skills/{tool_key}/ingest": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Ingest With Tool
* @description 通用入库(仅可入库工具):过 continuity 预检 + 白名单 → 写 ingest.table。
*
* 未知/legacy 工具→404不可入库工具→422有冲突且未确认→409越权写表丢弃+审计。
*/
post: operations["ingest_with_tool_projects__project_id__skills__tool_key__ingest_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/settings/providers": {
parameters: {
query?: never;
@@ -1216,6 +1278,31 @@ export interface components {
/** Chapters */
chapters?: components["schemas"]["OutlineChapterView"][];
};
/**
* OutlineSceneIngestView
* @description 细纲入库的单章场景行(贴 ww_agents.Scene落 outline 表)。
*/
OutlineSceneIngestView: {
/** Idx */
idx: number;
/** Beat */
beat: string;
/**
* Purpose
* @default
*/
purpose: string;
/**
* Conflict
* @default
*/
conflict: string;
/**
* Hook
* @default
*/
hook: string;
};
/**
* ProjectCreateRequest
* @description POST /projects立项向导字段owner_id 由后端补 stub不入参
@@ -1568,6 +1655,175 @@ export interface components {
/** Fallback */
fallback?: string[];
};
/**
* ToolDescriptorView
* @description 单个生成器卡片描述符视图(前端据此渲染卡片栅格 + 输入表单)。
*/
ToolDescriptorView: {
/**
* Key
* @description 路由用稳定标识brainstorm / book-title ...
*/
key: string;
/** Title */
title: string;
/** Subtitle */
subtitle: string;
/** Genre */
genre?: string | null;
/**
* Is Legacy
* @description legacy 工具spec=None→ 前端走 legacy_route 跳现有页面
*/
is_legacy: boolean;
/**
* Ingestable
* @description 是否可入库(声明了 ingest 目标)
*/
ingestable: boolean;
/** Input Fields */
input_fields?: components["schemas"]["ToolInputFieldView"][];
/**
* Legacy Route
* @description legacy 工具指向的现有页面路径(含 {id} 占位)
*/
legacy_route?: string | null;
};
/**
* ToolGeneratePreviewResponse
* @description 通用生成预览:结构化产物(不持久化;仅记 ledger
*
* `output_kind` = 该工具产物的 schema 名(如 IdeaListResult供前端按类型选预览渲染器
* `preview` = 解析后的结构化产物(按各工具 output_schema 的形,键名见 ww_agents.schemas
*/
ToolGeneratePreviewResponse: {
/** Tool Key */
tool_key: string;
/**
* Output Kind
* @description 产物 schema 名(前端按此选预览渲染器)
*/
output_kind: string;
/**
* Preview
* @description 结构化产物(各工具 output_schema 的 model_dump不入库
*/
preview?: {
[key: string]: unknown;
};
};
/**
* ToolGenerateRequest
* @description 通用生成请求(覆盖全部工具的可选入参;按工具 input_fields 取用snake_case
*/
ToolGenerateRequest: {
/**
* Brief
* @description 一句话需求/方向(可空,空则按题材发散)
* @default
*/
brief: string;
/**
* Chapter No
* @description 按章展开类工具的章号(开篇/细纲)
*/
chapter_no?: number | null;
/**
* Count
* @description 生成数量(部分工具可用)
*/
count?: number | null;
/**
* Kind
* @description 命名对象类别等(部分工具可用)
*/
kind?: string | null;
};
/**
* ToolIngestRequest
* @description 通用入库请求:待持久化的产物 + 冲突确认。
*
* 仅声明了 `ingest` 的工具可用。按入库表取用对应字段:
* - world_entities金手指/词条)→ `world_entities`(贴 WorldEntityCardViewtype/name/rules
* - outline细纲→ `chapter_no` + `scenes`(贴 OutlineSceneIngestView
* `acknowledge_conflicts`:作者已查看并接受 continuity 预检冲突时置 true 放行(仿 accept gate
*/
ToolIngestRequest: {
/**
* World Entities
* @description world_entities 入库项(金手指/词条)
*/
world_entities?: components["schemas"]["WorldEntityCardView"][];
/**
* Chapter No
* @description outline 入库的目标章号(细纲)
*/
chapter_no?: number | null;
/**
* Scenes
* @description outline 入库的场景行(细纲)
*/
scenes?: components["schemas"]["OutlineSceneIngestView"][];
/**
* Acknowledge Conflicts
* @description 作者已知悉并接受 continuity 冲突 → 放行入库
* @default false
*/
acknowledge_conflicts: boolean;
};
/**
* ToolIngestResponse
* @description 通用入库结果201写入项标识 + 被白名单丢弃的越权表(审计)。
*/
ToolIngestResponse: {
/**
* Table
* @description 入库目标表
*/
table: string;
/**
* Created
* @description 写入项的标识(实体名 / 场景索引),按入参顺序
*/
created?: string[];
/**
* Rejected Tables
* @description 被权限白名单丢弃的越权写表名(审计;正常为空)
*/
rejected_tables?: string[];
};
/**
* ToolInputFieldView
* @description 单个声明式表单字段视图(贴 ww_skills.InputField
*/
ToolInputFieldView: {
/** Name */
name: string;
/** Label */
label: string;
/**
* Type
* @description 控件类型text / textarea / number / select 等
*/
type: string;
/**
* Required
* @default true
*/
required: boolean;
/** Default */
default?: string | null;
/** Help */
help?: string | null;
};
/**
* ToolboxListResponse
* @description GET /skills/toolbox创作工具箱全量描述符legacy + 新工具)。
*/
ToolboxListResponse: {
/** Tools */
tools?: components["schemas"]["ToolDescriptorView"][];
};
/** ValidationError */
ValidationError: {
/** Location */
@@ -2681,6 +2937,143 @@ export interface operations {
};
};
};
list_toolbox_skills_toolbox_get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ToolboxListResponse"];
};
};
};
};
generate_with_tool_projects__project_id__skills__tool_key__generate_post: {
parameters: {
query?: never;
header?: never;
path: {
project_id: string;
tool_key: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["ToolGenerateRequest"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ToolGeneratePreviewResponse"];
};
};
/** @description 工具或项目不存在 / legacy 工具无通用执行 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description 工具不支持该操作(如不可入库) */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description LLM 不可用 */
503: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
};
};
ingest_with_tool_projects__project_id__skills__tool_key__ingest_post: {
parameters: {
query?: never;
header?: never;
path: {
project_id: string;
tool_key: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["ToolIngestRequest"];
};
};
responses: {
/** @description Successful Response */
201: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ToolIngestResponse"];
};
};
/** @description 工具或项目不存在 / legacy 工具无通用执行 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description 存在未裁决 continuity 冲突 */
409: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description 工具不支持该操作(如不可入库) */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description LLM 不可用 */
503: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
};
};
list_providers_settings_providers_get: {
parameters: {
query?: never;