Frameworks & Chat
ragChat() mounts a complete retrieval-augmented chat backend on Elysia — WebSocket streaming, search, ingest, sync, evaluation, and governance routes under one path. On the other side, a framework-free browser client plus matching bindings for React, Svelte, Vue, and Angular consume that surface without hand-written fetch code.
#The Chat Plugin
ragChat(config) extends the @absolutejs/ai chat plugin config — same provider, model, tools, store, and systemPrompt — with the retrieval surface. Each chat turn retrieves topK sources, streams them to the client ahead of the answer, and cites them in the response.
| Option | Type / default | Purpose |
|---|---|---|
provider | required | Factory from provider name to AI provider config — same contract as aiChat. |
path | '/rag'default | Prefix for every route and the WebSocket channel. |
collection / ragStore | RAGCollection | RAGVectorStore | Retrieval backend. A collection brings its own embedding; a bare store pairs with embedding / embeddingModel. |
topK | 6default | Sources retrieved per chat turn and per /search default. |
scoreThreshold | number | Drops sources under the threshold before answering. |
rerank / extractors | provider / registry | Reranker for retrieval and file extractors for the upload-ingest routes. |
authorizeRAGAction / resolveRAGAccessScope | hooks | Access control over mutating routes and scoped reads (see the Quality page). |
searchTraceStore, retrievalBaselineStore, ... | stores | Governance store slots — wire all fifteen at once with createRAGSQLiteGovernanceStores. |
htmx | falsedefault | true or a render config mounts the HTMX form / SSE routes alongside the JSON surface. |
staleAfterMs | 7 daysdefault | Age before an idle conversation is considered stale. |
import { Elysia } from 'elysia';
import { anthropic } from '@absolutejs/ai/anthropic';
import {
createRAGCollection,
openaiEmbeddings,
ragChat
} from '@absolutejs/rag';
import { createPostgresRAGStore } from '@absolutejs/rag-postgres';
const collection = createRAGCollection({
embedding: openaiEmbeddings({
apiKey: process.env.OPENAI_API_KEY ?? '',
defaultModel: 'text-embedding-3-small',
dimensions: 1536
}),
store: createPostgresRAGStore({ dimensions: 1536 })
});
new Elysia()
.use(
ragChat({
collection,
path: '/rag', // default
provider: () => anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }),
systemPrompt: 'Answer from the retrieved context and cite sources.',
topK: 6 // default
})
)
.listen(3000);ragPlugin is a re-export alias of ragChat — use whichever name reads better in your server file.#Server Surface
Every route lives under the configured path (default /rag). Chat itself is a WebSocket at the path root; evaluation and the opt-in HTMX surface stream over SSE. The browser client and all framework bindings target exactly these routes.
| Group | Routes | What it covers |
|---|---|---|
| Chat | WS /rag | The WebSocket chat channel: message, cancel, and branch frames; retrieval runs before each answer streams. |
| Search | POST /rag/search | Retrieval without generation; includeTrace returns the full trace. |
| Documents | GET|POST /rag/documents, GET /rag/documents/:id/chunks | List, create, inspect chunks, and DELETE /rag/documents/:id. |
| Ingest & index | POST /rag/ingest, DELETE /rag/index | Plus /rag/reindex/documents/:id, /rag/reindex/source, /rag/reseed, /rag/reset. |
| Backend | GET /rag/backends, POST /rag/backend/analyze | Backend capabilities, analyze, and POST /rag/backend/reindex-native. |
| Sync | GET|POST /rag/sync, POST /rag/sync/:id | List sync sources, run them all, or run one. |
| Evaluation | POST /rag/evaluate, POST /rag/evaluate/stream | Batch evaluation and an SSE stream of per-case results. |
| Traces | GET /rag/traces[/groups|/stats] | Trace history plus prune preview / prune / prune history. |
| Governance | /rag/compare/retrieval/* | Comparisons, baselines, promotions, lane handoffs, incidents, remediations, and policy history. |
| Status | GET /rag/status[/...], GET /rag/ops | Readiness, maintenance, release, and handoff status rollups. |
| Conversations | GET|DELETE /rag/conversations[/:id] | Stored chat history from the conversation store. |
| HTMX (opt-in) | POST /rag/message, GET /rag/sse/:conv/:msg | Form post + SSE HTML fragments; mounted only when htmx is set. |
#Browser Client
createRAGClient({ path, fetch? }) from @absolutejs/rag/client wraps the whole HTTP surface: search (with or without trace), ingest, documents, sync, status / ops, evaluation (including the SSE stream), traces, and the full governance surface — promotions, handoffs, incidents, remediations. createRAGWorkflow(path) opens the WebSocket and exposes the answer lifecycle as derived getters.
import { createRAGClient, createRAGWorkflow } from '@absolutejs/rag/client';
// Framework-free browser client : typed fetch over every route the
// plugin mounts. Pass the same path you gave ragChat.
const client = createRAGClient({ path: '/rag' });
const results = await client.search({ query: 'How do deploys work?' });
const detailed = await client.searchWithTrace({
query: 'How do deploys work?'
});
await client.ingestDocuments({
documents: [{ id: 'deploys', text: 'Deploys run on every push to main.' }]
});
const status = await client.status();
const operations = await client.ops();
await client.syncAllSources();
// WebSocket answer workflow over the same path : send a query, then
// read retrieval stage, streamed answer, sources, and citations.
const workflow = createRAGWorkflow('/rag');
workflow.query('How do deploys work?');
workflow.isRetrieving;
workflow.sources;
workflow.citations;
workflow.groundedAnswer;The client subpath also re-exports createRAGEvaluationSuite, runRAGEvaluationSuite, and buildRAGEvaluationLeaderboard so evaluation UIs need a single import, plus buildRAGMaintenanceOverview for maintenance dashboards.
#React Hooks
@absolutejs/rag/react layers hooks over the client and the streaming workflow. Every hook takes the plugin path as its first argument; useRAG(path) composes them all when you want one handle.
import { useRAG } from '@absolutejs/rag/react';
export const DocsAssistant = () => {
// One hook composes search, ingest, status, ops, documents, chunk
// preview, evaluate, index admin, and the streaming answer workflow.
const rag = useRAG('/rag');
return (
<section>
<button
onClick={() => rag.search.search({ query: 'What is hybrid search?' })}
>
Search
</button>
{rag.search.results.map((hit) => (
<article key={hit.chunkId}>
<h3>{hit.title}</h3>
<p>{hit.text}</p>
</article>
))}
<button onClick={() => rag.stream.query('Explain hybrid search')}>
Ask
</button>
{rag.stream.isRunning ? (
<p>{rag.stream.sources.length} sources retrieved...</p>
) : null}
{rag.stream.groundedAnswer ? <p>Grounded answer ready.</p> : null}
</section>
);
};#Svelte, Vue & Angular
The other bindings mirror the React surface one-for-one, adapted to each framework's reactivity model. All of them are optional peer dependencies — install only the framework you render with.
| Framework | Subpath | Entry points | State model |
|---|---|---|---|
| React | @absolutejs/rag/react | useRAG, useRAGSearch, ... | Hooks with plain state; useRAG memoizes the composite. |
| Svelte | @absolutejs/rag/svelte | createRAG, createRAGSearch, ... | Same surface as stores — subscribe in templates. |
| Vue | @absolutejs/rag/vue | useRAG, useRAGSearch, ... | Same names as React, backed by ref() / computed(). |
| Angular | @absolutejs/rag/angular | RAGClientService, RAGStreamService, RAGWorkflowService | Injectable services; connect() returns signal-based state. |
// Svelte : store-backed factories from @absolutejs/rag/svelte
import { createRAG } from '@absolutejs/rag/svelte';
const rag = createRAG('/rag');
// createRAGSearch, createRAGIngest, createRAGStream, createRAGStatus,
// createRAGOps, ... mirror the React hooks one-for-one.
// Vue : composables from @absolutejs/rag/vue with computed()/ref() state
import { useRAG } from '@absolutejs/rag/vue';
const vueRag = useRAG('/rag', { autoLoadStatus: true });
// Angular : injectable services from @absolutejs/rag/angular
import { inject } from '@angular/core';
import { RAGClientService, RAGStreamService } from '@absolutejs/rag/angular';
class DocsAssistant {
private readonly client = inject(RAGClientService);
private readonly stream = inject(RAGStreamService).connect('/rag');
async run(query: string) {
// Every RAGClientService method takes the base path first.
const hits = await this.client.search('/rag', { query });
// connect() returns Angular signals: sources(), stage(), progress()...
this.stream.query(query);
return hits;
}
}#Presentation Helpers
Two helper subpaths keep UI code framework-agnostic. @absolutejs/rag/client/ui ships the browser-safe workflow builders the bindings use internally — buildRAGAnswerWorkflowState, buildRAGStreamProgress, buildRAGGroundedAnswer, buildRAGCitationReferenceMap, buildRAGChunkGraph and its navigation helpers — so a vanilla JS app can render the same retrieval workflow.
@absolutejs/rag/ui is the wider server-side presentation layer: citations, source groups and summaries, corpus health, readiness, evaluation and grounding history rows, reranker and retrieval comparison overviews, and sync-source presentations — the building blocks for admin dashboards over the governance routes.