diff --git a/web/src/app/chat/components/research-block.tsx b/web/src/app/chat/components/research-block.tsx
index 52779fd..4897d6a 100644
--- a/web/src/app/chat/components/research-block.tsx
+++ b/web/src/app/chat/components/research-block.tsx
@@ -1,7 +1,7 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
-import { Check, Copy, Headphones, Pencil, Undo2, X } from "lucide-react";
+import { Check, Copy, Headphones, Pencil, Undo2, X, Download } from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { ScrollContainer } from "~/components/deer-flow/scroll-container";
@@ -64,6 +64,33 @@ export function ResearchBlock({
}, 1000);
}, [reportId]);
+ // Download report as markdown
+ const handleDownload = useCallback(() => {
+ if (!reportId) {
+ return;
+ }
+ const report = useStore.getState().messages.get(reportId);
+ if (!report) {
+ return;
+ }
+ const now = new Date();
+ const pad = (n: number) => n.toString().padStart(2, '0');
+ const timestamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
+ const filename = `research-report-${timestamp}.md`;
+ const blob = new Blob([report.content], { type: 'text/markdown' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ document.body.appendChild(a);
+ a.click();
+ setTimeout(() => {
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ }, 0);
+ }, [reportId]);
+
+
const handleEdit = useCallback(() => {
setEditing((editing) => !editing);
}, []);
@@ -113,6 +140,16 @@ export function ResearchBlock({
{copied ? : }
+
+
+
>
)}