RAG Knowledge Base
Pro4 variants: overview dashboard, source management, ingestion pipeline and health monitoring — with index stats, sync progress, pipeline stages, an alert list, and opt-in file upload that adds and indexes new sources.
import { SvRagKnowledgeBaseComponent } from '@styloviz-pro/rag-knowledge-base';Demo & usage
Basic usage
ProUsage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
Pipeline & health
ProSources with file upload
ProThe chunk inspector, sized for your own model
ProWhen to use
- Managing a retrieval-augmented knowledge base: sources, ingestion, index health.
- RAG-powered products that need source and pipeline visibility.
- For displaying retrieved chunks in chat, use the AI Chat tool-call chips.
Async states
- loading
- error
- retry
Item identity & owned state
- Restorable state
- syncingIds
Bind these to put a saved view back — the open sections, the hidden columns, the selected rows — and read their
Changeevents to store what the user does.
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
| loading | boolean | false | True while the data is being fetched. |
| error | SvDataError | string | null | null | Load failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`. |
| variant | RagKbVariant | 'overview' | View: overview, sources, ingestion pipeline or health. |
| uploadable | boolean | false | Show a file-upload dropzone in the sources view. |
| accept | string | '.pdf,.txt,.md,.docx,.csv' | Accepted file types for the upload input. |
| stats | KbStats | null | null | Corpus-level counts. |
| sources | readonly KbSource[] | [] | The connected sources. Uploads and sync progress are transient local state layered over this — the array you pass is never mutated, and supplying a new one discards the local layer, because your list is the truth. SET `audience` ON EACH SOURCE — the groups that can retrieve it. Every row in the overview and sources views shows it, and one left unset reads as "Everyone" and is counted in the roll-up, because an undeclared audience is exactly as open as the assistant is. |
| simulate | boolean | false | Simulate indexing after an upload, ramping a new source to ready. **Off by default.** `sourceAdded` fires and you supply the updated `sources` — an operator watching a progress bar that tracks a timer rather than an indexer is the most consequential thing this component can get wrong. Set it explicitly to `true` in a showcase. |
| pipelineRun | PipelineRun | null | null | The most recent indexing run. |
| pastRuns | typeof PAST_RUNS | PAST_RUNS | Earlier runs. |
| alerts | readonly KbAlert[] | [] | Health alerts. Resolutions are layered locally and reported as an output. |
| chunks | readonly SvKbChunk[] | [] | The chunks the `chunks` variant inspects. Raw chunks with their document offsets — the shape an index export already has. The overlap, the gaps and the token estimates are computed here because none of them are stored anywhere. |
| hits | readonly SvRetrievalHit[] | [] | The hits the `retrieval` variant lays out. |
| query | string | '' | The query those hits answered, shown above them. |
| maxSources | number | 200 | How many sources either list renders at once. `0` = no ceiling. A SOURCE LIST IS SHORT UNTIL A CONNECTOR ENUMERATES. One Confluence space is one row; one Google Drive connector is one row per shared folder, and a large tenant's Drive has thousands. The component cannot tell those apart — they are the same shape of data — so the ceiling is what stops the second case rendering as a page that never paints. |
| syncingIds | ReadonlySet<string> (two-way) | new Set() | Ids of the sources currently syncing (two-way). A `model` (audit item X-6) because a sync outlives the click that started it: `syncTriggered` tells the host a sync was asked for, and this is how the host says which ones are still running — after a route change, or for a job that was already in flight when the panel mounted. |
| minChunkTokens | number | SV_CHUNK_MIN_TOKENS | Below this many tokens a chunk is too small to answer anything. |
| maxChunkTokens | number | SV_CHUNK_MAX_TOKENS | The target ceiling past which a chunk crowds the context window. A retrieval-budget choice, not a fact: five chunks at 512 tokens is most of a small context window and a rounding error in a large one. |
| embedTokenLimit | number | SV_EMBED_TOKEN_LIMIT | The embedding model's HARD input limit. THE DEFAULT IS A FACT ABOUT ONE MODEL. 8,192 is `text-embedding-3`; it is 512 on a BERT-family encoder and far higher on some 2026 models. Past the real limit the embedding call does not fail — it truncates, embeds the head and returns a perfectly ordinary vector, so the tail is present, searchable-looking and unreachable. A default that is too high for the deployment hides exactly that, which is why this is an input and not a constant. |
| spreadFlatPct | number | SV_SPREAD_FLAT_PCT | Spread, as a share of the top score, under which the set is called flat. A STATEMENT ABOUT ONE RETRIEVER'S SCORE DISTRIBUTION. Cosine similarities that all land between 0.78 and 0.83 are flat at five per cent by definition; BM25 scores running from 40 to 2 are never flat at all. The default is reasoned for a normalised vector score and is not a fact about anyone else's. |
| marginDecisive | number | SV_MARGIN_DECISIVE | Share of the spread the first step must take for the set to be decisive. A SHARE, so `0`–`1`. Passing `50` for "half" would demand a first step fifty times the whole spread — no result set can reach it, so every query would read `contested`, permanently and silently. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| retry | void | The host should re-run the failed load. |
| sourceAdded | KbSource | Emitted for each file added via upload (as a new knowledge source). |
| sourceSelect | string | Emitted with the id of the source the user selects. |
| syncTriggered | string | Emitted with the id of the source the user re-syncs. |
| alertResolved | string | Emitted with the id of an alert the user resolves. |
| syncingIdsChange | ReadonlySet<string> | Emits the new `syncingIds` whenever it changes — the output half of `[(syncingIds)]`. |
Wire it to your API
This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.
Template
ProBound to the names this component actually exposes.
Host class
ProDrive the three async inputs from your own fetch.
- This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `sources`, `loading` and `error`.
- Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.
Full walkthrough: Connecting to a backend.
Customization & theming
- Who can retrieve a source is on **every row**, not only in the expanded panel: a compact audience chip (Everyone, or the group names) in the overview Source Health strip and on each collapsed row in the sources view, with a roll-up of how many sources are open to everyone. The full sentence stays in the expanded detail.
- `KbSource.audience` lists the groups that can retrieve a source, and every row says who that is. An **undeclared audience reads as everyone** and says so — reading silence as 'restricted' would make an unmigrated index look safer than it is, which is the one direction this surface must never round. A roll-up counts the sources open to everyone, because a reviewer scanning forty rows will not notice the one without a lock.
- `status: 'deleting'` with `KbSource.deletion` — chunks remaining, embeddings remaining, and **whether it can still be retrieved**. Deletion is a lag, not an event: until the chunks and the embeddings go, the retriever can still return the thing somebody asked to have removed, and a panel that says 'deleted' the moment the button is pressed is making a compliance claim it cannot support. The source stays listed while it happens rather than vanishing from a panel whose answers keep arriving. The retrievability sentence renders as real emphasis from `svDeletionParts()` (structured runs, no Markdown, no `innerHTML`); `svDeletionLabel()` is the same notice as plain text.
- The retrievability sentence is never omitted while it is true, including when both counts have reached zero — that is the dangerous middle, where nothing is left to delete and answers are still arriving. The counts are reassuring because they go down, and a reader watching them fall will assume the job is done long before it is.
- Redaction, from the pack-wide policy (`X-2`): a chunk preview is masked BEFORE it is truncated. The other order leaves a half-secret whenever the preview boundary falls inside one — `sk-live-abcde…` is not a redaction, it is a shorter version of the key.
- Every content set is an input defaulting to the bundled sample — `stats`, `sources`, `pipelineRun`, `pastRuns` and `alerts`. Uploads and sync progress are transient local state layered over `sources`; supplying a new list discards that layer, because your data is the truth. Alert resolutions are layered the same way and reported through `alertResolved`.
- `simulate` is off by default, so `sourceAdded` fires on upload and you supply the updated `sources`. Set it to true only in a showcase — a progress bar that tracks a timer instead of an indexer is worse than none.
- Overview, sources, pipeline and health views.
- Index stats and sync progress.
- Pipeline stage visualization.
- Set `uploadable` (sources view) for a drag-and-drop upload zone that adds files as new sources; constrain types with `accept` and listen to `sourceAdded`. An added source is marked as not yet persisted until your `sources` list contains it.
- Also emits `sourceSelect` and `syncTriggered` with the source id.
- The retrieval panel's two confidence lines are inputs too: `[spreadFlatPct]` (5) and `[marginDecisive]` (0.5), from the still-exported `SV_SPREAD_FLAT_PCT` and `SV_MARGIN_DECISIVE`. Both describe one retriever's score distribution — cosine similarities between 0.78 and 0.83 are flat at five per cent by definition, and BM25 scores from 40 to 2 are never flat at all. `[marginDecisive]` is a SHARE of the spread, so it lives in 0–1; a figure above 1 is refused with a dev warning rather than making every query read "contested" for ever.
- The chunk inspector's three token limits are inputs: `[minChunkTokens]` (48), `[maxChunkTokens]` (512) and `[embedTokenLimit]` (8192), defaulting to the exported `SV_CHUNK_MIN_TOKENS`, `SV_CHUNK_MAX_TOKENS` and `SV_EMBED_TOKEN_LIMIT`, which are still exported — `svChunkRows` and `svChunkFlagLabel` take them as an optional last argument. A target ceiling above the embedding limit is clamped down (it would let a chunk be reported healthy AND truncated at embed time), a floor at or above the ceiling is clamped below it, and each `SvChunkRow` carries the limits it was judged against so the wording can never quote a threshold that had nothing to do with the flag.
Best practices
- Do: Show sync progress and index stats so stale sources are obvious.
- Do: Use the health variant to surface ingestion failures with actionable alerts.
- Do: Set `[embedTokenLimit]` to your embedding model's real input limit. The 8,192 default is `text-embedding-3`; on a smaller encoder a chunk can be reported healthy while its tail is dropped at embed time — content that is present, searchable-looking and unreachable, which is the worst failure mode in a retrieval system.
- Don't: Don't set `[maxChunkTokens]` above `[embedTokenLimit]`. A target ceiling above the hard limit is the one combination that re-creates the defect the flag exists for; the component clamps it down and says so once in a dev warning.
- Tip: Group sources by status (synced, syncing, failed) for quick triage.
Accessibility
- Status and progress conveyed as text.
- The upload zone is a real `<label>`-wrapped file input — keyboard-focusable and screen-reader labelled.
- Alerts use appropriate roles.
- A flagged chunk states the limit it breached in words — in the badge tooltip and in the row's accessible name — and both quote the limits THAT ROW was judged against rather than whatever the inputs currently say, so a re-render cannot put a fresh threshold into a sentence explaining an old verdict.
Feedback on RAG Knowledge Base
Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.