@@ -611,11 +619,11 @@ export function MessageList({
/>
)}
+ files={files}
+ threadId={threadId}
+ onOpenArtifact={onOpenArtifact}
+ onDownloadArtifact={onDownloadArtifact}
+ />
,
);
}
@@ -726,11 +735,15 @@ export function MessageList({
message.type === "ai" &&
(hasToolCalls(message) ? true : !hasContent(message)),
);
+ const processingAi = [...group.messages]
+ .reverse()
+ .find((message) => message.type === "ai");
return (
);
- })}
- {documentRewriteItems.map((item) => (
-
- ))}
- {thread.isLoading &&
}
+ })}
+ {documentRewriteItems.map((item) => (
+
+ ))}
+ {thread.isLoading &&
}
diff --git a/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx b/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx
index 7499cc54..586be7ea 100644
--- a/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx
+++ b/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx
@@ -14,7 +14,7 @@ import {
SidebarMenuItem,
} from "@/components/ui/sidebar";
import { useI18n } from "@/core/i18n/hooks";
-import { BookOpen, BotIcon, BrainIcon, ListChecks, MessageSquarePlus, MessagesSquare, PenLine, Plus, SparklesIcon, Telescope, Users } from "lucide-react";
+import { BookOpen, BotIcon, BrainIcon, FileSearch, ListChecks, MessageSquarePlus, MessagesSquare, PenLine, Plus, SparklesIcon, Telescope, Users } from "lucide-react";
import { KnowledgeRagToggle } from "./knowledge-rag-toggle";
import { SidebarCollapseButton } from "./workspace-header";
@@ -100,6 +100,13 @@ export const WORKSPACE_COMPACT_NAV_ITEMS: WorkspaceCompactNavItem[] = [
path: "/page/workspace/deep-research",
match: (pathname) => pathname.startsWith("/page/workspace/deep-research"),
},
+ {
+ id: "workspace-enterprise-research",
+ label: "企业深度研究",
+ icon: FileSearch,
+ path: "/page/workspace/enterprise-research",
+ match: (pathname) => pathname.startsWith("/page/workspace/enterprise-research"),
+ },
{
id: "workspace-roundtable-planning",
label: "多智能体规划",
diff --git a/frontend-web/src/core/agents/types.ts b/frontend-web/src/core/agents/types.ts
index 06718d76..70d82a8e 100644
--- a/frontend-web/src/core/agents/types.ts
+++ b/frontend-web/src/core/agents/types.ts
@@ -62,8 +62,6 @@ export interface Agent {
* (名称 + SKILL.md 路径 + 必须先 read_file 的硬指令) 拼进本轮任务以补偿弱模型。
* 与业务链条同名开关取 OR。null/false = 关 (默认)。 */
seat_skill_directive?: boolean | null;
- /** 岗位职责。会商智能体配置面板展示在常用问题上方。空/缺省 = 未填写。 */
- job_responsibilities?: string | null;
/** DeerFlow LLMWiki mapping ids this agent allows conversations to select. */
llmwiki_knowledge_base_ids?: string[] | null;
tags?: Tag[];
@@ -101,8 +99,6 @@ export interface CreateAgentRequest {
template_name?: string | null;
/** 会商席位「技能识别强化」开关;缺省/false = 关。 */
seat_skill_directive?: boolean | null;
- /** 岗位职责;缺省/空 = 未填写。 */
- job_responsibilities?: string | null;
llmwiki_knowledge_base_ids?: string[] | null;
}
@@ -121,7 +117,5 @@ export interface UpdateAgentRequest {
template_name?: string | null;
/** 会商席位「技能识别强化」开关;缺省/false = 关。 */
seat_skill_directive?: boolean | null;
- /** 岗位职责;传空字符串表示清除。 */
- job_responsibilities?: string | null;
llmwiki_knowledge_base_ids?: string[] | null;
}
diff --git a/frontend-web/src/core/page-layout/sidebar-menu.ts b/frontend-web/src/core/page-layout/sidebar-menu.ts
index 8f87e2be..fa4cdc8a 100644
--- a/frontend-web/src/core/page-layout/sidebar-menu.ts
+++ b/frontend-web/src/core/page-layout/sidebar-menu.ts
@@ -19,6 +19,7 @@ import {
ClipboardList,
Database,
FileBox,
+ FileSearch,
FileText,
Gauge,
Grid3X3,
@@ -99,6 +100,12 @@ export const sidebarMenuItems: MenuItem[] = [
icon: Telescope,
path: "/page/strategy/qa/deep-research",
},
+ {
+ id: "qa-enterprise-research",
+ label: "企业深度研究",
+ icon: FileSearch,
+ path: "/page/strategy/qa/enterprise-research",
+ },
],
},
{
diff --git a/frontend-web/src/eightbf-roundtable/components/EightBfStep1Workspace.tsx b/frontend-web/src/eightbf-roundtable/components/EightBfStep1Workspace.tsx
index 5d4423a0..62d06b13 100644
--- a/frontend-web/src/eightbf-roundtable/components/EightBfStep1Workspace.tsx
+++ b/frontend-web/src/eightbf-roundtable/components/EightBfStep1Workspace.tsx
@@ -417,6 +417,7 @@ function EightBfAgentWorkspace({
showRecentChats={false}
avatarSrc={agentConfigLogo}
positionName={positionNameById(selectedSeat?.position_id)}
+ jobResponsibilities={selectedSeat?.job_responsibilities ?? ""}
skillsIcon={

}
skillsTitle="技能列表"
showCommonQuestions
@@ -502,10 +503,12 @@ function EightBfAgentRow({
}) {
const name = agent?.name || seat.name || "未命名智能体";
const description = agent?.description || seat.description || "智能体助手";
- const avatarText = Array.from(name.trim() || "?")[0]?.toUpperCase() || "?";
+ const avatarText = firstAgentAvatarChar(name);
return (
);
}
diff --git a/frontend-web/src/eightbf-roundtable/styles/step1.css b/frontend-web/src/eightbf-roundtable/styles/step1.css
index d3bab280..9dc22caf 100644
--- a/frontend-web/src/eightbf-roundtable/styles/step1.css
+++ b/frontend-web/src/eightbf-roundtable/styles/step1.css
@@ -300,6 +300,11 @@
font-size: 16px;
font-weight: 700;
}
+.eightbf-roundtable .eightbf-roundtable__agent-selector-avatar img {
+ width: 22px;
+ height: 22px;
+ object-fit: contain;
+}
.eightbf-roundtable .eightbf-roundtable__agent-selector-main {
display: flex;
min-width: 0;
diff --git a/frontend-web/src/pages/EnterpriseResearchPage.tsx b/frontend-web/src/pages/EnterpriseResearchPage.tsx
new file mode 100644
index 00000000..9c2118bb
--- /dev/null
+++ b/frontend-web/src/pages/EnterpriseResearchPage.tsx
@@ -0,0 +1,734 @@
+import { type FormEvent, useEffect, useMemo, useRef, useState } from "react";
+import {
+ AlertCircle,
+ BookOpenCheck,
+ CheckCircle2,
+ ChevronRight,
+ ClipboardList,
+ Database,
+ Download,
+ ExternalLink,
+ FileSearch,
+ FileText,
+ Loader2,
+ Play,
+ Plus,
+ Search,
+ Send,
+ ShieldCheck,
+ Square,
+ Sparkles,
+ WandSparkles,
+} from "lucide-react";
+import { toast } from "sonner";
+
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
+import { Checkbox } from "@/components/ui/checkbox";
+import { Input } from "@/components/ui/input";
+import { ModelNameSelect } from "@/components/workspace/model-name-select";
+import { DownloadWordButton } from "@/components/workspace/messages/download-word-button";
+import { DocumentRewriteDiffDialog } from "@/components/workspace/messages/document-rewrite-diff-dialog";
+import { ScrollArea } from "@/components/ui/scroll-area";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Textarea } from "@/components/ui/textarea";
+import { cn } from "@/lib/utils";
+import { openKnowledgeSource } from "@/core/llmwiki/source-links";
+import MarkdownRenderer from "@/strategy-components/MarkdownRenderer";
+import {
+ type LlmWikiSearchResult,
+ useLlmWikiKnowledgeBases,
+ useLlmWikiRuntime,
+} from "@/strategy-components/api/llmwiki";
+import {
+ type EnterpriseResearchTask,
+ type EnterpriseResearchTaskStatus,
+ type EnterpriseResearchReportEvent,
+ type EnterpriseResearchReportJob,
+ collectEnterpriseResearchTask,
+ cancelEnterpriseResearchReportJob,
+ createEnterpriseResearchAiPlan,
+ createEnterpriseResearchTask,
+ createEnterpriseResearchPlanDraft,
+ createEnterpriseResearchReportJob,
+ listEnterpriseResearchTasks,
+ listEnterpriseResearchReportJobs,
+ restoreEnterpriseResearchReportVersion,
+ streamEnterpriseResearchReportJob,
+ updateEnterpriseResearchPlan,
+} from "@/strategy-components/api/enterprise-research";
+
+type TemplateId = "topic" | "event" | "policy";
+type TaskStatus = EnterpriseResearchTaskStatus;
+
+type ResearchTemplate = {
+ id: TemplateId;
+ name: string;
+ description: string;
+ stages: string[];
+ buildQueries: (subject: string, focus: string) => string[];
+};
+
+const TEMPLATES: ResearchTemplate[] = [
+ {
+ id: "topic",
+ name: "通用议题研究",
+ description: "先梳理事实与背景,再归纳关键分歧、影响与待验证问题。",
+ stages: ["界定研究问题", "检索内部证据", "归纳观点与分歧", "形成研究任务包"],
+ buildQueries: (subject, focus) => [subject, `${subject} 背景 关键事实`, focus ? `${subject} ${focus}` : `${subject} 影响 风险 机会`],
+ },
+ {
+ id: "event",
+ name: "事件影响评估",
+ description: "适用于突发事件、舆情事件或专项行动的影响研判。",
+ stages: ["还原事件时间线", "识别相关主体", "评估影响传导", "输出风险与跟踪项"],
+ buildQueries: (subject, focus) => [
+ `${subject} 时间线 经过`,
+ `${subject} 相关主体 公开表态`,
+ focus ? `${subject} ${focus} 影响 风险` : `${subject} 影响 风险 应对`,
+ ],
+ },
+ {
+ id: "policy",
+ name: "政策与行业研究",
+ description: "适用于政策、产业、市场等需比较变化与传导机制的主题。",
+ stages: ["明确政策或产业边界", "对比历史与现状", "拆解传导机制", "沉淀研判与建议"],
+ buildQueries: (subject, focus) => [
+ `${subject} 政策 现状`,
+ `${subject} 发展趋势 数据`,
+ focus ? `${subject} ${focus} 行业影响` : `${subject} 影响 挑战 机遇`,
+ ],
+ },
+];
+
+const STATUS_META: Record