fix(citations): only citation links in citationMap render as badges

Revert streaming logic - only links that are actually in citationMap
should render as badges. This prevents project URLs and other regular
links from being incorrectly rendered as citation badges.

During streaming, links may initially appear as plain links until the
citations block is fully parsed, then they will update to badge style.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
LofiSu
2026-02-06 16:10:29 +08:00
parent e7ea0fc551
commit 582bfaee39

View File

@@ -77,43 +77,24 @@ export function MessageListItem({
/**
* Custom link component that handles citations and external links
* - During streaming (isLoadingCitations=true): all external links render as badges
* - After streaming: only links in citationMap render as badges
* - Human messages and non-citation links render as plain links
* Only links in citationMap are rendered as CitationLink badges
* Other links (project URLs, regular links) are rendered as plain links
*/
function MessageLink({
href,
children,
citationMap,
isHuman,
isLoadingCitations,
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {
citationMap: Map<string, Citation>;
isHuman: boolean;
isLoadingCitations: boolean;
}) {
if (!href) return <span>{children}</span>;
// Human messages always render as plain links
if (isHuman) {
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="text-primary underline underline-offset-2 hover:no-underline"
>
{children}
</a>
);
}
const citation = citationMap.get(href);
const isExternalLink = href.startsWith("http://") || href.startsWith("https://");
// During streaming: render all external links as badges (citations not yet fully loaded)
// After streaming: only render links in citationMap as badges
if (citation || (isLoadingCitations && isExternalLink)) {
// Only render as CitationLink badge if it's a citation (in citationMap) and not human message
if (citation && !isHuman) {
return (
<CitationLink citation={citation} href={href}>
{children}
@@ -121,7 +102,7 @@ function MessageLink({
);
}
// Non-citation links render as plain links
// All other links render as plain links
return (
<a
href={href}
@@ -220,12 +201,12 @@ function MessageContent_({
// Shared markdown components
const markdownComponents = useMemo(() => ({
a: (props: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
<MessageLink {...props} citationMap={citationMap} isHuman={isHuman} isLoadingCitations={isLoadingCitations} />
<MessageLink {...props} citationMap={citationMap} isHuman={isHuman} />
),
img: (props: React.ImgHTMLAttributes<HTMLImageElement>) => (
<MessageImage {...props} threadId={thread_id} maxWidth={isHuman ? "full" : "90%"} />
),
}), [citationMap, thread_id, isHuman, isLoadingCitations]);
}), [citationMap, thread_id, isHuman]);
// Render message response
// Human messages use humanMessagePlugins (no autolink) to prevent URL bleeding into adjacent text