feat: 报告结构支持检索方向/来源与智能新增,并修复协助卡停轮与宿主跳转

为深度研究报告结构增加检索方向与技能来源、对话式智能新增页与详情排版;澄清中间件在 after_model 可靠结束本轮,避免弱模型出卡后继续生成;任务按钮补充 host 跳转与相关深链能力。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
董宏凯andCursor committed 2026-08-22 17:46:06 +08:00
1 parent a5a9c952e8
commit 51afebb394
67 files changed
+4511 -699

No files matched your search

@@ -23,7 +23,7 @@ import { Textarea } from "@/components/ui/textarea";
import { Switch } from "@/components/ui/switch";
import { ModelNameSelect } from "@/components/workspace/model-name-select";
import type { DocumentRewriteStyle } from "@/open-canvas/api/rewrite";
import { useReportStructures } from "@/strategy-components/api/report-structures";
import { useReportStructures, REPORT_STRUCTURE_MODE_OPTIONS, normalizeReportStructureMode, type ReportStructureMode } from "@/strategy-components/api/report-structures";
const KEEP_CURRENT_REPORT_STRUCTURE = "__keep_current_report_structure__";
const DEFAULT_REWRITE_INSTRUCTION = "统一表达风格,减少重复内容,改善段落衔接;不新增原文没有依据的事实。";
@@ -34,6 +34,7 @@ export interface DocumentRewriteDialogInput {
style: DocumentRewriteStyle;
modelName: string | null;
reportOutline: string;
structureMode: "fixed" | "adaptive";
generateImages: boolean;
maxGeneratedImages: number;
}
@@ -99,6 +100,7 @@ export function DocumentRewriteDialog({
const [style, setStyle] = useState<DocumentRewriteStyle>("formal_analysis");
const [modelName, setModelName] = useState<string | null>(null);
const [reportStructureId, setReportStructureId] = useState(KEEP_CURRENT_REPORT_STRUCTURE);
const [structureMode, setStructureMode] = useState<ReportStructureMode>("adaptive");
const [generateImages, setGenerateImages] = useState(false);
const [imageCount, setImageCount] = useState("2");
const reportStructuresQuery = useReportStructures({ status: "enabled" });
@@ -116,6 +118,7 @@ export function DocumentRewriteDialog({
setStyle("formal_analysis");
setModelName(null);
setReportStructureId(KEEP_CURRENT_REPORT_STRUCTURE);
setStructureMode("adaptive");
setGenerateImages(false);
setImageCount("2");
}, [isNewReportGeneration, open]);
@@ -130,6 +133,11 @@ export function DocumentRewriteDialog({
));
}, [initialReportStructureId, open]);
useEffect(() => {
if (!selectedReportStructure) return;
setStructureMode(selectedReportStructure.structureMode);
}, [selectedReportStructure?.id, selectedReportStructure?.structureMode]);
const selectedStyle = STYLE_OPTIONS.find((item) => item.value === style);
const canStart = instruction.trim().length > 0;
const startWith = (handler: (input: DocumentRewriteDialogInput) => void) => {
@@ -139,6 +147,7 @@ export function DocumentRewriteDialog({
style,
modelName,
reportOutline: selectedReportStructure?.content ?? "",
structureMode,
generateImages,
maxGeneratedImages: Math.min(
Math.max(Number(imageCount) || 1, 1),
@@ -179,7 +188,7 @@ export function DocumentRewriteDialog({
/>
</label>
<div className="grid gap-4 sm:grid-cols-3">
<div className="grid gap-4 sm:grid-cols-2">
<label className="grid gap-2 text-sm font-medium">
{isNewReportGeneration ? "报告风格" : "改写风格"}
<Select value={style} onValueChange={(value) => setStyle(value as DocumentRewriteStyle)}>
@@ -227,6 +236,28 @@ export function DocumentRewriteDialog({
</span>
</label>
<label className="grid gap-2 text-sm font-medium">
结构约束
<Select
value={structureMode}
onValueChange={(value) => setStructureMode(normalizeReportStructureMode(value))}
>
<SelectTrigger aria-label="结构约束">
<SelectValue />
</SelectTrigger>
<SelectContent>
{REPORT_STRUCTURE_MODE_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
<span className="text-muted-foreground text-xs">
{REPORT_STRUCTURE_MODE_OPTIONS.find((option) => option.value === structureMode)?.description}
</span>
</label>
<label className="grid gap-2 text-sm font-medium">
模型
<ModelNameSelect