feat(frontend): 五类交互接入 AI 对话留痕 + Workbench 抽屉入口(AC-3)

- RefinePanel/ChapterRewritePanel:结束后 append [author(意见/答复), ai(产出)];
  clarify buffer-until-concluded——澄清 Q&A(原意见→反问→答复)缓冲,随最终产出批
  一起落库同 thread;纯放弃不记。refine ai 行 meta 存 version_no+原选段(每版重锚)。
- ContinuePanel:ai-only(续写无作者输入),每候选一条 ai 气泡 meta{candidate_index}。
- GeneratorRunner:成功后 append [author(字段摘要, meta{tool_key,input_fields}),
  ai(渲染预览, meta{tool_key,output_kind})];空产物不记。lib/toolbox/aiSummary.ts 纯助手+单测。
- InlineToolbox→GeneratorRunner 透传 append+本章号;ToolboxPage 用 silent 直投项目级(chapter_no=null)。
- Workbench:挂 useAiConversation 单实例 + AiConversationDrawer + 底栏「AI 对话」入口(flag 灰度),
  三个 DRAFT-only 再接受回调(替换整章/插入正文/回填选段),成功关抽屉+toast、漂移不盲替换。
This commit is contained in:
Yaojia Wang
2026-07-09 17:27:14 +02:00
parent 59f2f60a7e
commit 33a9b7656c
10 changed files with 379 additions and 28 deletions

View File

@@ -0,0 +1,33 @@
// 工具箱生成留痕的两个纯格式化助手AI 对话记录用):
// - fieldSummary把作者填写的输入字段拼成人读摘要author 气泡 content长文进 content 不进 meta
// - renderPreviewText把结构化预览渲染成人读文本ai 气泡 content不把原始产物塞进 meta
// 确定性纯函数,无 IO供 GeneratorRunner 结束后 append 一批往复。
import type { ToolInputFieldView } from "@/lib/api/types";
import type { FieldValues, PreviewModel } from "./toolbox";
// 输入字段 → 「labelvalue」摘要跳过空值多字段用 · 连接。
export function fieldSummary(
fields: readonly ToolInputFieldView[],
values: FieldValues,
): string {
return fields
.map((f) => ({ label: f.label, value: (values[f.name] ?? "").trim() }))
.filter((entry) => entry.value.length > 0)
.map((entry) => `${entry.label}${entry.value}`)
.join(" · ");
}
// 预览模型 → 人读文本:每项 = heading + 「labelvalue」次要字段 + 正文段,项间空行分隔。
export function renderPreviewText(preview: PreviewModel): string {
return preview.items
.map((item) => {
const lines: string[] = [];
if (item.heading) lines.push(item.heading);
for (const f of item.fields) lines.push(`${f.label}${f.value}`);
if (item.body) lines.push(item.body);
return lines.join("\n");
})
.filter((block) => block.length > 0)
.join("\n\n");
}