# RAG assistant

A docs assistant that answers questions and cites the sources it used — numbered inline citations powered by kai-chat and kai-sources.

A knowledge-base assistant that grounds every answer in retrieved documents. The reply body uses `[1]`, `[2]`, `[3]` markers; `<kai-sources numbered>` renders the matching citation strip below. Ask something to see a new streamed answer with citations.

## How it works

`<kai-chat>` handles the Q&A thread. `<kai-sources>` is a **separate element** placed below it — pass the citation list as a property and set `numbered` to auto-label each chip `[1]`, `[2]`, `[3]` to match the markers in the reply text. This example keeps the row separate because the retriever, not the model, owns the citations; sources that arrive as `source` parts on a message render their own row inside the thread.

```html
<kai-chat id="chat" chat-title="Docs assistant"></kai-chat>
<kai-sources id="srcs" numbered show-favicon></kai-sources>

<script type="module">

  await customElements.whenDefined('kai-chat');

  const chat = document.getElementById('chat');
  const srcs  = document.getElementById('srcs');

  chat.messages = [];

  chat.addEventListener('kai-submit', async (e) => {
    const prompt = e.detail.value;
    const aId = crypto.randomUUID();

    // hide the previous citation strip while the new answer streams in
    srcs.sources = [];

    chat.messages = [
      ...chat.messages,
      { id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text: prompt }] },
      { id: aId, role: 'assistant', parts: [] },
    ];
    chat.loading = true;

    // stream tokens from your RAG backend
    const { reply, sources } = await fetchRagAnswer(prompt);
    let answer = '';
    for await (const token of reply) {
      answer += token;
      chat.messages = chat.messages.map((m) =>
        m.id === aId ? { ...m, parts: [{ type: 'text', text: answer }] } : m,
      );
    }

    // reveal citations once streaming finishes
    srcs.sources = sources; // [{ href, title, description }, …]
    chat.loading = false;
  });
</script>
```

**`sources` shape** — each item in the array:

| field | type | notes |
|---|---|---|
| `href` | `string` | The URL the chip links to |
| `title` | `string?` | Hover-card headline |
| `description` | `string?` | Hover-card body text |
| `label` | `string?` | Trigger label (omit when `numbered` is set) |
| `showFavicon` | `boolean?` | Per-item favicon override |

`numbered` auto-labels chips `[1]`, `[2]`, … from the merged list order, so inline markers in the reply body align without any extra logic.

## Next steps

- **[`kai-sources` reference](/components/sources/)** — `numbered`, `showFavicon`, and the declarative `<kai-source>` children path.
- **[`kai-source` reference](/components/source/)** — single citation chips and their hover-card props (`headline`, `description`).
- **[Streaming recipe](/guides/recipes/streaming/)** — parsing SSE from your RAG backend and driving the token loop.
- **[Drop-in chat](/examples/drop-in-chat/)** — the baseline streaming loop this example builds on.
