Citations
An answer whose claims link to the sources behind them.
≈ 862 tokens per use (tool 382 · guidance 209 · typical payload 271)How token costs are estimated
Example: Citations
What water temperature should I use for matcha?
Use water at 70–80°C, well below boiling Brew Guide +1. Hotter water pulls out bitter compounds and dulls the colour Tea Atlas.
If you don't have a thermometer, boil the water and let it rest for about 3 minutes Home Cook. Whisk in a quick zigzag rather than circles to get a fine foam Brew Guide.
When to use
- Your answer relies on facts from web pages or documents you retrieved.
- The user asked where something comes from, or the claims are worth checking.
When not to use
- You have no retrieved sources. Never cite from memory or invent a source.
- The answer is your own reasoning, opinion or a calculation.
- Casual conversation where sources add nothing.
How it works
The agent writes ordinary text and marks each claim with the number of its source:
{
"text": "Use water at **70–80°C** [1][2]. Hotter water tastes bitter [2].",
"sources": [{ "title": "…", "url": "https://…" }, { "title": "…", "url": "https://…" }]
}- Each marker becomes a chip. It shows the site name, with "+1" when the chip covers several sources, or a number when
markeris"number". - Hovering or focusing a chip opens a preview of each source behind it: title, publisher, date and the supporting quote.
- The sources list starts open, one line per source: its number, title and publisher with the date. Quotes live in the chip preview, not the list. Clicking a chip scrolls to its source and highlights it.
- Missing sources are flagged. A marker that points to a source that wasn't provided shows a dashed ? instead of disappearing.
- The text can be streamed. Chips for sources that haven't arrived yet show a placeholder, and a marker that's still being written is hidden.
Text supports paragraphs (separated by a blank line), - list items and **bold**.
Safety
- Only
http:andhttps:URLs become links. Anything else, such asjavascript:, renders as plain text. - External links open in a new tab with
rel="noopener noreferrer nofollow". - No favicons are fetched. The list toggle shows letter badges, so rendering an answer doesn't call third-party servers.
How the agent should use it
- Only cite pages you actually retrieved in this conversation, with their exact URLs.
- Put each marker right after the claim it supports, and only cite a source for claims it really supports.
- Quotes must be verbatim. If you can't quote it, leave
quoteout. - Prefer primary and recent sources, and drop sources you didn't use.
Installation
npx shadcn@latest add https://your-site.com/r/citations.json
Usage
Citations are display-only. Nothing is sent back, so the tool can return immediately:
import { tool } from "ai"
import { citationsTool } from "@/components/genui/citations.schema"
const tools = {
[citationsTool.name]: tool({
description: citationsTool.description,
inputSchema: citationsTool.inputSchema,
execute: async () => ({ shown: true }),
}),
}import { Citations } from "@/components/genui/citations"
function ToolPart({ part }) {
if (part.type !== "tool-answer_with_sources") return null
return (
<Citations
{...part.input}
status={part.state === "input-streaming" ? "streaming" : "ready"}
/>
)
}With LangGraph
Push it from a graph node with ui.push({ name: "answer_with_sources", props: { toolCallId, ...args } }, { message }), and render the thread's UI messages with the Renderer.
Schema
| Prop | Type | Notes |
|---|---|---|
text | string | The answer, with [n] markers |
sources | Source[] | 1–20. [n] refers to the nth source |
marker | "domain" | "number" | Default domain |
display | "inline" | "sources" | Host prop. sources shows only the sources list, for hosts that render the answer text themselves. Default inline |
Source
| Field | Type | Notes |
|---|---|---|
title | string | Data-bound |
url | string | Data-bound. http(s) only |
publisher | string? | Display name. Defaults to the domain |
quote | string? | Data-bound. The verbatim supporting passage, up to 300 characters |
published | string? | ISO date |
Host props: status (streaming or ready) and className.