mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-02 22:02:13 +08:00
Merge upstream/experimental and resolve conflicts; citations + path_utils + mode-hover
## 冲突解决 (Resolve conflicts) - input-box.tsx: 保留 ModeHoverGuide 包裹的模式选择器(PR #26 的 mode-hover-guide) - message-group.tsx: 保留 getCleanContent / hasCitationsBlock / useParsedCitations - message-list-item.tsx: 保留 useParsedCitations,移除重复的 MessageLink(使用 CitationAwareLink) - artifact-file-detail.tsx: 保留 CitationAwareLink、useParsedCitations、contentWithoutCitationsFromParsed - artifacts.py: 保留 path_utils 与 _extract_citation_urls + remove_citations_block 精简实现 - citations/index.ts: 保留并补充 contentWithoutCitationsFromParsed 导出 - en-US.ts: 保留 Ultra 模式描述 "Reasoning, planning and execution with subagents..." - zh-CN.ts: 保留「超级」标签,描述保留「思考、计划并执行,可调用子代理分工协作...」 ## PR #26 代码改动汇总 ### 1. Citations(引用) - lead_agent prompt: 增加 Web search 与子代理合成时的 citation 提示 - general_purpose: 子代理 system prompt 增加 <citations_format> 说明 - frontend utils: 新增 contentWithoutCitationsFromParsed,removeAllCitations 基于单次解析 - frontend artifact: 使用 contentWithoutCitationsFromParsed(parsed) 避免对同一内容解析两次 - backend artifacts: _extract_citation_urls + remove_citations_block,json 提到顶部 ### 2. path_utils(路径解析) - 新增 backend/src/gateway/path_utils.py:resolve_thread_virtual_path,防 path traversal - artifacts.py / skills.py:删除内联路径解析,统一使用 path_utils ### 3. Mode hover guide - input-box: 模式选择器外包 ModeHoverGuide,悬停展示模式说明 ### 4. i18n - en: ultraModeDescription 与 zh: ultraMode / ultraModeDescription 与上游对齐并保留 PR 文案 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -34,7 +34,11 @@ import { CodeEditor } from "@/components/workspace/code-editor";
|
||||
import { useArtifactContent } from "@/core/artifacts/hooks";
|
||||
import { urlOfArtifact } from "@/core/artifacts/utils";
|
||||
import type { Citation } from "@/core/citations";
|
||||
import { removeAllCitations, useParsedCitations } from "@/core/citations";
|
||||
import {
|
||||
contentWithoutCitationsFromParsed,
|
||||
removeAllCitations,
|
||||
useParsedCitations,
|
||||
} from "@/core/citations";
|
||||
import { useI18n } from "@/core/i18n/hooks";
|
||||
import { installSkill } from "@/core/skills/api";
|
||||
import { streamdownPlugins } from "@/core/streamdown";
|
||||
@@ -96,12 +100,10 @@ export function ArtifactFileDetail({
|
||||
);
|
||||
const cleanContent =
|
||||
language === "markdown" && content ? parsed.cleanContent : (content ?? "");
|
||||
const contentWithoutCitations = useMemo(() => {
|
||||
if (language === "markdown" && content) {
|
||||
return removeAllCitations(content);
|
||||
}
|
||||
return content;
|
||||
}, [content, language]);
|
||||
const contentWithoutCitations =
|
||||
language === "markdown" && content
|
||||
? contentWithoutCitationsFromParsed(parsed)
|
||||
: (content ?? "");
|
||||
|
||||
const [viewMode, setViewMode] = useState<"code" | "preview">("code");
|
||||
const [isInstalling, setIsInstalling] = useState(false);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export {
|
||||
contentWithoutCitationsFromParsed,
|
||||
extractDomainFromUrl,
|
||||
getCleanContent,
|
||||
hasCitationsBlock,
|
||||
|
||||
@@ -185,27 +185,25 @@ export function isCitationsBlockIncomplete(content: string): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove ALL citations from content, including:
|
||||
* - <citations> blocks
|
||||
* - [cite-N] references (and their converted markdown links)
|
||||
*
|
||||
* Uses parseCitations once, then strips citation links from cleanContent.
|
||||
* Used for copy/download to produce content without any citation references.
|
||||
*
|
||||
* @param content - The raw content that may contain citations
|
||||
* @returns Content with all citations completely removed
|
||||
* Strip citation markdown links from already-cleaned content (from parseCitations).
|
||||
* Use when you already have ParseCitationsResult to avoid parsing twice.
|
||||
*/
|
||||
export function removeAllCitations(content: string): string {
|
||||
if (!content) return content;
|
||||
|
||||
const parsed = parseCitations(content);
|
||||
export function contentWithoutCitationsFromParsed(
|
||||
parsed: ParseCitationsResult,
|
||||
): string {
|
||||
const citationUrls = new Set(parsed.citations.map((c) => c.url));
|
||||
|
||||
// Remove markdown links that point to citation URLs; keep non-citation links
|
||||
const withoutLinks = parsed.cleanContent.replace(
|
||||
/\[([^\]]+)\]\(([^)]+)\)/g,
|
||||
(fullMatch, _text, url) => (citationUrls.has(url) ? "" : fullMatch),
|
||||
);
|
||||
|
||||
return withoutLinks.replace(/\n{3,}/g, "\n\n").trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove ALL citations from content (blocks, [cite-N], and citation links).
|
||||
* Used for copy/download. For display you typically use parseCitations/useParsedCitations.
|
||||
*/
|
||||
export function removeAllCitations(content: string): string {
|
||||
if (!content) return content;
|
||||
return contentWithoutCitationsFromParsed(parseCitations(content));
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export const zhCN: Translations = {
|
||||
reasoningModeDescription: "思考后再行动,在时间与准确性之间取得平衡",
|
||||
proMode: "Pro",
|
||||
proModeDescription: "思考、计划再执行,获得更精准的结果,可能需要更多时间",
|
||||
ultraMode: "Ultra",
|
||||
ultraMode: "超级",
|
||||
ultraModeDescription:
|
||||
"思考、计划并执行,可调用子代理分工协作,适合复杂多步骤任务,能力最强",
|
||||
searchModels: "搜索模型...",
|
||||
|
||||
Reference in New Issue
Block a user