Skip to content

Find a component

Loading the directory…

↑ ↓ to select · Enter to open · Esc to closeBrowse all →
Contributor login

Sitegpt

Bijection component for SiteGPT: ask your AI support chatbot from Bijection functions and keep its knowledge base transactionally in sync with your Bijection tables.

Bijection source
git clone https://github.com/bijectionhq/sitegpt.git
cd sitegpt
git checkout d0f1e0292f441d77e6e7b8f9a310f018caea3203

Bijection repository access is required. Request access.

Description

Bijection component for SiteGPT: ask your AI support chatbot from Bijection functions and keep its knowledge base transactionally in sync with your Bijection tables.

Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.

Available to evaluate

Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.

Getting started

  1. Get the source at the revision above and read its package documentation.
  2. Check the required Bijection SDK version, dependencies, and external service credentials.
  3. Follow the package setup instructions and the guide to using components.
  4. Exercise the component in your deployment according to your project’s verification rules.

Open source

Maintained source: bijectionhq/sitegpt. Based on sitegpt/convex-component. License: MIT. Consult the repository for license terms, notices, and contributor attribution.

From the upstream publisher

Convex component for SiteGPT: ask your AI support chatbot from Convex functions and keep its knowledge base transactionally in sync with your Convex tables.

Explore the demo ↗

Upstream overview

From the upstream package documentation.

SiteGPT gives your product an AI support agent trained on your own content. This component connects it to your Convex backend in both directions: call sitegpt.ask() from an action to get grounded answers inside your app, and call sitegpt.syncDocument() inside your mutations to keep the agent's knowledge base transactionally in sync with your Convex tables. Content that commits is content the bot knows: no cron jobs, no drift, no manual re-uploads. Typed helpers cover the rest of the SiteGPT API: knowledge ingestion, documents, conversations, messages, and leads.

Use cases

From the upstream package documentation.

  • An in-app "Ask AI" box: send the user's question from a Convex action with sitegpt.ask() and render the grounded answer, with a threadId for follow-up questions
  • Ticket deflection: answer from the knowledge base first, and escalate to your human inbox only when the bot cannot help
  • Docs, FAQs, or product data that already live in Convex tables: sitegpt.syncDocument() in the same mutation that saves a row keeps the bot current, and sitegpt.removeDocument() makes it forget deleted content
  • Live sync dashboards: sitegpt.getSyncState() is a subscribable query, so your admin UI can show each document's push status in real time
  • Custom support analytics: page through conversations, messages, and captured leads with typed helpers and build your own views inside your app

How it works

From the upstream package documentation.

Install the package and mount the component in convex/convex.config.ts using app.use(sitegpt, ...), binding your SITEGPT_API_TOKEN environment variable. Then instantiate a SiteGPT client in your functions file, optionally setting a defaultChatbotId to avoid passing it on every call.

The sitegpt.ask() method runs inside a Convex action and calls the SiteGPT REST API synchronously, returning the answer and a threadId for continuing the conversation in subsequent calls. All API-backed methods run in actions; sync methods run in mutations and queries.

The transactional knowledge sync works by writing a shadow row to the component's internal table inside your mutation's transaction. Because component mutations participate in the same ACID transaction as your own writes, the sync intent is recorded atomically or not at all. A scheduled background worker then pushes changes to SiteGPT with retries using exponential backoff starting at 5 seconds, doubling up to roughly 5 minutes between attempts across 8 tries. Content is hashed so unchanged documents are skipped, and deletions are prioritized over updates in the batch queue.

Error handling for the API layer throws a ConvexError with structured data including status, code, and message. The sync worker catches its own errors and records them on the shadow row as lastError, preventing failures from surfacing into your mutations after commit. You can force a retry with sitegpt.retrySync() after addressing the underlying issue.

Upstream package FAQ

Does the SiteGPT Convex component store my content in Convex permanently?

The SiteGPT Convex component stores one shadow row per synced key in the component's own table. Content is held in the row until it is pushed to SiteGPT, then cleared. A failed row retains its content so retrySync can push it later. API wrapper methods like ask() and listConversations() store nothing in Convex.

What happens if the SiteGPT API is unavailable when a sync is triggered?

The sync intent is written atomically to the component's shadow table at mutation commit time, so no data is lost if the API is down. The background worker retries with exponential backoff starting at 5 seconds, doubling up to roughly 5 minutes between attempts. After 8 failed attempts the row is marked failed and will retry on the next syncDocument, removeDocument, or retrySync call for that key.

Can I sync documents to multiple SiteGPT chatbots from the same Convex deployment?

Yes. Every method on the SiteGPT Convex component accepts an optional chatbotId argument that overrides the defaultChatbotId set on the client. You can pass different chatbot IDs on individual calls to route content or queries to different chatbots.

What API token scopes does the SiteGPT Convex component require?

The required scopes depend on which methods you use. For the knowledge sync feature specifically, the token needs both knowledge:write and knowledge:delete because the sync engine handles both upserts and deletions. The ask() method requires conversations:write. Full scope requirements per method are documented in the component README.

How do I observe whether a document has been successfully synced to SiteGPT?

The SiteGPT Convex component provides a getSyncState() method you can call from a Convex query, which is reactive and subscribable like any Convex query. It returns the current sync status for a given key, including whether it is pending, synced, or failed, and exposes the lastError field on failed rows.

Use with agents and CLI

Give your coding agent the component’s source identity and setup guidance.

agent-prompt.md
Help me integrate Sitegpt with Bijection.

Read: https://bijection.com/components/sitegpt/SKILL.md

Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.

Upstream README.md

View repository ↗

Documentation from sitegpt/convex-component, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.

SiteGPT Convex Component

Add an AI support agent to your Convex app, powered by SiteGPT.

Two things this component gives you:

  1. Ask your chatbot from server functions. Call sitegpt.ask(ctx, ...) in an action and get the AI answer back, grounded in your chatbot's knowledge base. Build in-app help, ticket deflection, internal tools, or agent workflows without touching the widget.
  2. Transactional knowledge sync. Your product content already lives in Convex tables. Call sitegpt.syncDocument(ctx, ...) inside the same mutation that writes your data, and the chatbot's knowledge base follows automatically: the sync intent commits atomically with your write, a background worker pushes it to SiteGPT with retries, and deleting the row makes the bot forget it. No cron jobs, no drift.

Plus typed helpers for the rest of the SiteGPT API: knowledge ingestion (links, sitemaps, crawls, files, YouTube), conversations, messages, and leads.

Prerequisites

  • A SiteGPT account with a chatbot. No account yet? npx @sitegpt/cli onboarding start <your-website> creates a working preview chatbot without signing up.
  • A SiteGPT API token: create one in the SiteGPT dashboard under Settings, or with sitegpt tokens create.

Installation

npm install @sitegpt/convex

Mount the component and bind the token in convex/convex.config.ts:

import sitegpt from '@sitegpt/convex/convex.config.js'
import { defineApp } from 'convex/server'
import { v } from 'convex/values'

const app = defineApp({
  env: { SITEGPT_API_TOKEN: v.string() },
})

app.use(sitegpt, {
  env: { SITEGPT_API_TOKEN: app.env.SITEGPT_API_TOKEN },
})

export default app

Set the token on your deployment:

npx convex env set SITEGPT_API_TOKEN sgpt_...

Then create the client anywhere in your convex/ functions:

import { SiteGPT } from '@sitegpt/convex'
import { components } from './_generated/api'

const sitegpt = new SiteGPT(components.sitegpt, {
  defaultChatbotId: 'your-chatbot-id', // optional, saves passing it per call
})

Ask the chatbot

The SiteGPT API generates the answer synchronously, so one action call returns the reply:

import { action } from './_generated/server'
import { v } from 'convex/values'

export const askSupport = action({
  args: { question: v.string(), threadId: v.optional(v.string()) },
  handler: async (ctx, args) => {
    const result = await sitegpt.ask(ctx, {
      message: args.question,
      threadId: args.threadId, // omit to start a new conversation
    })
    return { answer: result.answer, threadId: result.threadId }
  },
})

Pass the returned threadId on the next call to continue the same conversation. Conversations show up in your SiteGPT dashboard like any other chat, so escalation, history, and analytics keep working.

Transactional knowledge sync

Keep the chatbot's knowledge in lockstep with a Convex table by syncing in the same mutation that writes it:

export const saveArticle = mutation({
  args: { slug: v.string(), title: v.string(), body: v.string() },
  handler: async (ctx, args) => {
    // ... write the article to your own table ...

    await sitegpt.syncDocument(ctx, {
      key: `articles/${args.slug}`,      // your stable identifier
      name: args.title,                  // display name in the dashboard
      content: `# ${args.title}\n\n${args.body}`,
    })
  },
})

export const deleteArticle = mutation({
  args: { slug: v.string() },
  handler: async (ctx, args) => {
    // ... delete the article from your own table ...
    await sitegpt.removeDocument(ctx, { key: `articles/${args.slug}` })
  },
})

How it works:

  • syncDocument writes a shadow row in the component's own table. Because component mutations join your mutation's transaction, the intent commits atomically with your write. If your mutation throws, nothing is recorded.
  • A scheduled worker pushes the change to SiteGPT right after commit: first push creates a knowledge document, later pushes update it in place (content is re-embedded automatically), removeDocument deletes it.
  • Unchanged content is detected by hash and skipped, so calling syncDocument on every save is free.
  • Failures retry with exponential backoff, doubling from 5s (5s, 10s, 20s, ... up to ~5 minutes between tries). After 8 attempts the row is marked failed and left alone until the next syncDocument, removeDocument, or retrySync for that key.
  • Everything reasserts state on wake-up: if content changes while a push is in flight, or a delete lands mid-create, the worker converges to the latest intent.

Observe sync state live from a query (it is subscribable like any Convex query):

export const articleSyncState = query({
  args: { slug: v.string() },
  handler: async (ctx, args) =>
    sitegpt.getSyncState(ctx, { key: `articles/${args.slug}` }),
})

Limits worth knowing:

  • One synced document holds up to 900 KB of UTF-8 content. Split bigger sources into multiple keys (that also improves retrieval).
  • Pushes run in batches of 10; a bulk import of thousands of documents drains steadily rather than instantly. Deletions are prioritized over content updates so takedowns never wait behind churn.

API surface

All API-backed methods run in actions (they call the SiteGPT REST API). Sync methods run in mutations and queries.

AreaMethods
Chatask
Knowledge syncsyncDocument, removeDocument, retrySync, getSyncState, listSyncStates
Knowledge ingestionaddLinks, addSitemap, crawlWebsite, addYoutube, uploadFiles, setCustomText
Knowledge documentslistDocuments, getDocument, updateDocumentContent, deleteDocument, deleteDocuments, resyncDocuments, getDocumentStats
ConversationslistConversations, getConversation, listMessages
LeadslistLeads, getLead
Accountme, usage, limits, listChatbots, getChatbot

You can also call the component actions directly via ctx.runAction(components.sitegpt.knowledge.addLinks, ...) if you prefer not to use the client class.

Token scopes

Create the API token with the scopes for the methods you use:

MethodsScope
askconversations:write
listConversations, getConversation, listMessagesconversations:read
syncDocument, retrySync, ingestion methods, updateDocumentContent, resyncDocumentsknowledge:write
removeDocument, deleteDocument, deleteDocumentsknowledge:delete
listDocuments, getDocument, getDocumentStatsknowledge:read
listLeads, getLeadleads:read
me, usage, limitsaccount:read
listChatbots, getChatbotchatbots:read

A token used for the knowledge sync needs both knowledge:write and knowledge:delete: removeDocument (and the delete half of the sync engine) calls the document delete endpoints.

Error handling

API failures throw a ConvexError whose data carries { kind: 'SiteGptApiError', status, code, message, hint? }. The sync worker catches these itself and records them on the row (lastError), so sync never throws into your mutations after commit.

Testing

The package ships a convex-test helper:

import { convexTest } from 'convex-test'
import sitegptTest from '@sitegpt/convex/test'

const t = convexTest(schema, modules)
sitegptTest.register(t)

Stub fetch to fake the SiteGPT API; see this repo's tests/sync.test.ts for full examples, including the sync state machine.

Example

A runnable example app lives in examples/basic: an articles table mirrored into a chatbot plus an in-app ask endpoint.

FAQ

Does this store my data in Convex? Only the sync engine stores state: one shadow row per synced key. Content is held in the row until pushed, then cleared; a failed row keeps its content so retrySync can push it later. The API wrapper methods store nothing.

Can I sync multiple chatbots? Yes. Every method takes an optional chatbotId; defaultChatbotId is just a convenience.

What happens if SiteGPT is down during a sync? The intent is already durable in the shadow row, so nothing is lost: the worker retries with backoff and converges when the API is reachable again.

Which plans can use this? Any plan with API access. Rate limits follow your SiteGPT plan.

License

MIT

Keywords