RAG Pipeline

Deskly reuses the base template's upload → chunk → embed → retrieve pipeline unchanged, with one addition: retrieval is scoped per bot, not per account.

Scoping

The documents table has a nullable bot_id column. A document uploaded against a specific bot (from /dashboard/bots/[botId]) is only ever retrieved for that bot's conversations — a visitor talking to Bot A never sees content uploaded to Bot B, even if both bots belong to the same account.

Existing per-account documents from the base template's dashboard chat feature have no bot_id and are unaffected; they continue to work exactly as before for that (non-widget) feature.

What happens on each widget message

In /api/widget/chat/route.ts, once the bot and rate limits are resolved:

const { data: botDocuments } = await supabase
  .from("documents")
  .select("id")
  .eq("bot_id", bot.id)
  .eq("status", "completed");

const documentIds = (botDocuments || []).map((d) => d.id);

if (documentIds.length > 0) {
  const relevantChunks = await retrieveRelevantChunks(
    message,
    documentIds,
    RAG_CONFIG.retrieval.defaultTopK,
    supabase
  );
  // ...chunks get joined and injected into the system prompt
}

retrieveRelevantChunks accepts an explicit list of document IDs to search within, plus an optional Supabase client — the widget path passes the service-role client since there's no visitor session, while the dashboard chat path uses the caller's session-bound client.

If a bot has no documents

Retrieval is simply skipped — the bot falls back to its system_prompt (or a default prompt from RAG_CONFIG) with no injected context. This means a bot can answer general questions from its system prompt alone even before you've uploaded anything, which is useful for testing the embed before content is ready.

Uploading documents

Upload flow, chunking strategy, and embedding provider are unchanged from the base template — see the upload UI in /dashboard/bots/[botId]. Supported formats and size limits are the same defaults as the base template; tighten them per your own risk tolerance before opening bot creation to untrusted users.

Related

  • Architecture for how bot_id fits into the overall data model
  • Abuse Protection for what stops a visitor from running up an owner's retrieval + generation costs