// Adapted from agentui (https://github.com/ashish200729/agentui), components/agents/citations.tsx // Copyright (c) 2026 Saurabh Chauhan. MIT License, see ./LICENSE-agentui.md // 改造:去掉 favicon 抓取(控制台链接都是站内),改成可选图标槽;站内链接走 react-router 的 Link(`to`), // 外链仍新窗口打开;新增 `meta`(右侧状态文字);入场/折叠去 motion,用 Disclosure 与 tw-animate;字号/圆角换 token。 import { BookOpenText, ChevronDown, ExternalLink } from "lucide-react"; import { type ReactNode, useId, useState } from "react"; import { Link } from "react-router"; import { cn } from "~/lib/utils.ts"; import { CHEVRON_CLASS, Disclosure } from "./disclosure.tsx"; export interface CitationItem { id: string; title: ReactNode; /** 副标题(如状态、域名) */ domain?: ReactNode; /** 右侧附加信息(如状态徽章) */ meta?: ReactNode; icon?: ReactNode; /** 站内路由 */ to?: string; /** 外链 */ url?: string; } function targetId(prefix: string, id: string) { return `${prefix}-${id.replace(/[^a-zA-Z0-9_-]/g, "-")}`; } /** 行内角标:跳到同 idPrefix 的来源行 */ export function Citation({ citationId, index, idPrefix, className, }: { citationId: string; index: number; idPrefix: string; className?: string; }) { return ( {index} ); } function Row({ c, index, prefix }: { c: CitationItem; index: number; prefix: string }) { const body = ( <> {c.icon ? ( {c.icon} ) : null} {c.title} {c.domain ? {c.domain} : null} {c.meta} {index} {c.url ? : null} ); const cls = "group/citation flex min-w-0 items-center gap-2 rounded-md px-1.5 py-1 outline-none transition-colors duration-micro hover:bg-foreground/[0.04] focus-visible:ring-2 focus-visible:ring-ring"; const id = targetId(prefix, c.id); if (c.to) return ( {body} ); if (c.url) return ( {body} ); return (
{body}
); } export function CitationList({ citations, idPrefix, className, }: { citations: CitationItem[]; idPrefix?: string; className?: string; }) { const base = useId(); const prefix = idPrefix ?? `citation-${base.replace(/:/g, "")}`; return (
    {citations.map((c, i) => (
  1. ))}
); } /** 可折叠的来源列表(上游默认收起;这里给核实结果用,默认展开) */ export function Citations({ citations, title = "来源", defaultOpen = false, idPrefix, className, }: { citations: CitationItem[]; title?: ReactNode; defaultOpen?: boolean; idPrefix?: string; className?: string; }) { const id = useId(); const [open, setOpen] = useState(defaultOpen); return (
); }