mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-22 13:44:46 +08:00
fix(citations): render external links as badges during streaming
During streaming when citations are still loading (isLoadingCitations=true), all external links should be rendered as badges since we don't know yet which links are citations. After streaming completes, only links in citationMap are rendered as badges. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -77,25 +77,43 @@ export function MessageListItem({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom link component that handles citations and external links
|
* Custom link component that handles citations and external links
|
||||||
* Only links that are in citationMap are rendered as CitationLink badges
|
* - During streaming (isLoadingCitations=true): all external links render as badges
|
||||||
* Other links (project URLs, regular links) are rendered as plain links
|
* - After streaming: only links in citationMap render as badges
|
||||||
|
* - Human messages and non-citation links render as plain links
|
||||||
*/
|
*/
|
||||||
function MessageLink({
|
function MessageLink({
|
||||||
href,
|
href,
|
||||||
children,
|
children,
|
||||||
citationMap,
|
citationMap,
|
||||||
isHuman,
|
isHuman,
|
||||||
|
isLoadingCitations,
|
||||||
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {
|
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {
|
||||||
citationMap: Map<string, Citation>;
|
citationMap: Map<string, Citation>;
|
||||||
isHuman: boolean;
|
isHuman: boolean;
|
||||||
|
isLoadingCitations: boolean;
|
||||||
}) {
|
}) {
|
||||||
if (!href) return <span>{children}</span>;
|
if (!href) return <span>{children}</span>;
|
||||||
|
|
||||||
const citation = citationMap.get(href);
|
// 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Only render as CitationLink badge if it's a citation (in citationMap)
|
const citation = citationMap.get(href);
|
||||||
// This ensures project URLs and regular links are not rendered as badges
|
const isExternalLink = href.startsWith("http://") || href.startsWith("https://");
|
||||||
if (citation && !isHuman) {
|
|
||||||
|
// 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)) {
|
||||||
return (
|
return (
|
||||||
<CitationLink citation={citation} href={href}>
|
<CitationLink citation={citation} href={href}>
|
||||||
{children}
|
{children}
|
||||||
@@ -103,7 +121,7 @@ function MessageLink({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All other links (including project URLs) render as plain links
|
// Non-citation links render as plain links
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
href={href}
|
href={href}
|
||||||
@@ -202,12 +220,12 @@ function MessageContent_({
|
|||||||
// Shared markdown components
|
// Shared markdown components
|
||||||
const markdownComponents = useMemo(() => ({
|
const markdownComponents = useMemo(() => ({
|
||||||
a: (props: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
|
a: (props: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
|
||||||
<MessageLink {...props} citationMap={citationMap} isHuman={isHuman} />
|
<MessageLink {...props} citationMap={citationMap} isHuman={isHuman} isLoadingCitations={isLoadingCitations} />
|
||||||
),
|
),
|
||||||
img: (props: React.ImgHTMLAttributes<HTMLImageElement>) => (
|
img: (props: React.ImgHTMLAttributes<HTMLImageElement>) => (
|
||||||
<MessageImage {...props} threadId={thread_id} maxWidth={isHuman ? "full" : "90%"} />
|
<MessageImage {...props} threadId={thread_id} maxWidth={isHuman ? "full" : "90%"} />
|
||||||
),
|
),
|
||||||
}), [citationMap, thread_id, isHuman]);
|
}), [citationMap, thread_id, isHuman, isLoadingCitations]);
|
||||||
|
|
||||||
// Render message response
|
// Render message response
|
||||||
// Human messages use humanMessagePlugins (no autolink) to prevent URL bleeding into adjacent text
|
// Human messages use humanMessagePlugins (no autolink) to prevent URL bleeding into adjacent text
|
||||||
|
|||||||
Reference in New Issue
Block a user