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:
ruitanglin
2026-02-09 13:01:01 +08:00
4 changed files with 25 additions and 24 deletions

View File

@@ -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);