Knowledge base
A retrieval assistant where the user picks which knowledge base to query. Choosing a scope in <kai-scope-picker> filters the <kai-conversations> sidebar, retitles the <kai-chat> thread, and grounds answers in <kai-sources> drawn from that scope. Switch the dropdown, then ask — the citations change with it.
How it works
Section titled “How it works”Four web components share one piece of state — the active scope:
<kai-scope-picker>emitskai-scope-changewith the chosenfilters.undefinedfilters mean “all knowledge”.<kai-conversations>re-renders with only the threads tagged for that scope.<kai-chat>drives the thread; itskai-submithandler fetches a scoped answer.<kai-sources numbered>shows the citations behind that answer — a separate element below the chat.
<kai-resizable> wraps the sidebar and main pane so the user can drag the split.
Wire the scope to the data
Section titled “Wire the scope to the data”The picker offers tags; map each tag to a knowledge base, then refresh the dependent elements when it changes.
<kai-resizable orientation="horizontal"> <kai-resizable-item size="28%" min="220px" max="360px"> <kai-scope-picker id="scope"></kai-scope-picker> <kai-conversations id="threads"></kai-conversations> </kai-resizable-item> <kai-resizable-item> <kai-chat id="chat"></kai-chat> <kai-sources id="srcs" numbered show-favicon></kai-sources> </kai-resizable-item></kai-resizable>
<script type="module"> import '@kitn.ai/ui/elements';
const scope = document.getElementById('scope'); const threads = document.getElementById('threads'); const chat = document.getElementById('chat'); const srcs = document.getElementById('srcs');
// Offer the knowledge bases as scope tags. scope.availableTags = ['Product Docs', 'API Reference', 'Engineering Wiki']; scope.currentLabel = 'All knowledge';
let activeScope = 'all';
// Seed every thread; filter the list to the active scope. const ALL_THREADS = await fetchThreads(); const showThreads = () => threads.conversations = activeScope === 'all' ? ALL_THREADS : ALL_THREADS.filter((t) => t.scope.filters?.tags?.includes(activeScope)); showThreads();
// Scope change → refilter threads, reset the thread, clear stale citations. scope.addEventListener('kai-scope-change', (e) => { activeScope = e.detail.filters?.tags?.[0] ?? 'all'; showThreads(); chat.messages = []; srcs.sources = []; });
// Ask → stream a scoped answer, then reveal its citations. chat.addEventListener('kai-submit', async (e) => { const aId = crypto.randomUUID(); srcs.sources = []; chat.messages = [ ...chat.messages, { id: crypto.randomUUID(), role: 'user', content: e.detail.value }, { id: aId, role: 'assistant', content: '' }, ]; chat.loading = true;
const { reply, sources } = await fetchAnswer(e.detail.value, activeScope); for await (const token of reply) { chat.messages = chat.messages.map((m) => m.id === aId ? { ...m, content: m.content + token } : m, ); }
srcs.sources = sources; // citations from the active scope chat.loading = false; });</script>The scope payload
Section titled “The scope payload”kai-scope-change carries the same SearchFilters your retrieval backend already understands:
| field | type | notes |
|---|---|---|
tags | string[]? | The knowledge bases / labels to query |
authors | string[]? | Restrict to specific authors |
contentType | 'transcript' | 'markdown'? | Restrict by document type |
dateRange | { from, to }? | Restrict by date |
filters is undefined when the user clears the scope (the picker’s reset item) — treat that as “search everything”.
Next steps
Section titled “Next steps”kai-scope-pickerreference —availableAuthors,availableTags,currentLabel, and thekai-scope-changeevent.kai-conversationsreference — grouping,activeId, and thekai-conversation-selectevent.- RAG assistant — the single-scope version this example builds on, with numbered inline citations.
- Resizable split layout — the sidebar + main-pane layout used here.