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

@@ -177,6 +177,16 @@
- **服务缝**`services/kimi_oauth.py`注入 `AsyncHttpClient` Protocol = `httpx.AsyncClient.post` 子集,测试零联网):`start_device_authorization(http)->DeviceAuth``poll_token(http, device_code)->TokenSet`(一次尝试,`AuthorizationPending`/`SlowDown` 异常供调用方循环)、`refresh(http, refresh_token)->TokenSet``encrypt_oauth_bundle`/`decrypt_oauth_bundle`Fernet 复用 `security/credentials` `encrypt_api_key`/`decrypt_api_key`工作在 JSON 串上`needs_refresh(token)`client_id env `KIMI_CLIENT_ID` 可覆盖默认 `17e5f671-...`device authorization **带 `scope=kimi-code`**coding entitlement实测省略 scope`api.kimi.com/coding/v1` 401故重新带上token 交换/刷新不带 scope)。
- **@frontend 行动K1.4**`pnpm gen:api` 纳入 OAuth start/disconnect/status + 3 schema连接流 = start user_code + verification_uri 轮询 `GET /jobs/{job_id}` done已连接/failed过期/拒绝status 端点查连接态档位路由到 `kimi-code:kimi-for-coding`
### C3 扩展T6.2/T6.3, 2026-06-22· 创作工具箱通用端点(独立 `routers/toolbox.py`已注册 owner @backend 状态: 稳定
- 通用生成器框架声明驱动一条执行路径——「加一个生成器」= `ww_skills.TOOLBOX` 加一份 `GeneratorTool` 声明descriptor 在代码、** DB 迁移**无需新端点snake_case**新增 3 端点 + schema @frontend 必须 `cd apps/web && pnpm gen:api`**T6 前端前置)。
- `GET /skills/toolbox` **200** `ToolboxListResponse{tools:[ToolDescriptorView{key,title,subtitle,genre?,is_legacy:bool,ingestable:bool,input_fields:[ToolInputFieldView{name,label,type,required,default?,help?}],legacy_route?:str}]}`legacy 3 + 8 key 升序)。legacy 工具worldbuilding/character/outline`is_legacy=true` `legacy_route``/projects/{id}/codex?gen=world` · `?gen=character` · `/projects/{id}/outline`供前端跳现有页面不回归既测
- `POST /projects/{project_id}/skills/{tool_key}/generate` `ToolGenerateRequest{brief:str="", chapter_no:int|None(ge1), count:int|None(1..12), kind:str|None}` **200** `ToolGeneratePreviewResponse{tool_key, output_kind:str(产物 schema 名), preview:dict(各工具 output_schema 的 model_dump)}`。**预览不入库** `spec.tier` `get_tier_gateway_builder` 建网关 `run_generator`末尾 `commit()` 仅落 ledgercontext 派发PURE `services/toolbox_context.build_toolbox_context`brief_only/with_project`build_brief_context`with_world + world_entities 硬规则卡with_outline_chapter + 指定章 outline beats**缺章/缺大纲空节拍不报错**)。未知 tool_key404legacy 工具spec=None→**404**(前端走 legacy_route项目不存在404无凭据→**503** `LLM_UNAVAILABLE`
- `POST /projects/{project_id}/skills/{tool_key}/ingest` `ToolIngestRequest{world_entities:[WorldEntityCardView], chapter_no:int|None, scenes:[OutlineSceneIngestView{idx,beat,purpose,conflict,hook}], acknowledge_conflicts:bool=false}` **201** `ToolIngestResponse{table:str, created:list[str], rejected_tables:list[str]}`。** `ingest!=None` 的工具**golden-finger/glossaryworld_entitiesfine-outlineoutline其余→**422 VALIDATION**。入库 gate仿 `POST /characters`world_entities **continuity 预检analyst 网关)** 比对待入库实体 vs 既有世界观真相源——有冲突且 `acknowledge_conflicts=false`→**409 `CONFLICT_UNRESOLVED`** + `details{conflicts:[{type,where,refs,suggestion}],conflict_count}``partition_writes(spec,{table:items})` 白名单过滤越权`rejected_tables` 审计schemaDB JSONB 形变写库rules`{"rules":[...]}`细纲场景按 idx 升序拼成该章 beats`outline_write_repo.upsert_chapter`)。outline细纲不做 continuity 预检场景是粗节拍展开非设定/角色比对 chapter_no422未知/legacy404提交边界ledger + 写侧只 flush 端点末尾一次 `commit()` 409 路径也 commit precheck usage)。
- **注册表**`packages/skills/ww_skills/toolbox_registry.py` `ww_skills` 导出`TOOLBOX:dict[str,GeneratorTool]`11 + `get_tool(key)->GeneratorTool|None`新工具的 `key==spec.name``output_schema is spec.output_schema`
- **注入缝**`services/project_deps.py``get_tier_gateway_builder``TierGatewayBuilder=Callable[[Tier],Awaitable[Gateway]]`按工具 tier 动态建网关测试经 `app.dependency_overrides[get_tier_gateway_builder]` 注返 mock 网关的 builder + `get_world_entity_write_repo`/`get_outline_write_repo`/`get_memory_repos`/`get_project_repo` fakeschema-routing fake 网关按 `req.output_schema` IdeaListResult/ContinuityReview/…)。
- **守不变量**#2spec 只声明 tier/#3预览不写库入库经 continuity gate + 白名单/#9system_prompt 进缓存前块注入材料进 input)。**无新迁移**descriptor 在代码复用 world_entities/outline )。
- **@frontend 行动**`pnpm gen:api` 纳入 `GET /skills/toolbox` + `POST .../skills/{tool_key}/generate` + `POST .../skills/{tool_key}/ingest` schema `ToolboxListResponse`/`ToolDescriptorView`/`ToolInputFieldView`/`ToolGenerateRequest`/`ToolGeneratePreviewResponse`/`ToolIngestRequest`/`ToolIngestResponse`/`OutlineSceneIngestView`工具箱落地页据 `GET /skills/toolbox` 渲染卡片栅格legacy `legacy_route` 跳页新工具据 `input_fields` 声明驱动表单 generate 预览 可入库者 ingest + 复用 409 冲突裁决)。
## C8 · Skill registry + 表权限沙箱 owner @backend 状态: 稳定T5.5, 2026-06-19M5 R3 迁入 ww_skills 包, 2026-06-19
- 来源`ARCHITECTURE.md §5.6` / `PRODUCT_SPEC §5.5`声明式 Skill = AgentSpec「声明式权限 + apply 层白名单」,**非进程沙箱**)。消费方M5 编排/生成入库层技能库 UIT5.6 C3)。
- **实现位置M5 R3 已迁移**实现现落 `packages/skills/ww_skills/{skill_registry,skill_permissions}.py``packages/skills` 已是 uv workspace member)。`ww_skills/__init__.py` **直接导出**不再是再导出 ww_core 的门面)。消费方 `from ww_skills import SkillRegistry/SqlSkillRepo/SkillRecord/SkillRepo/partition_writes/filter_reads/validate_declaration/KNOWN_TABLES`。**`ww_core.domain` 已删除这两个模块 + `__init__` 导出**不再经 ww_core.domain 暴露 skill 符号)。历史T5.5 曾因 skills workspace member 暂落 ww_core.domain decisions现已迁回