Short learning path. Full details: README.md. Agent memory: CLAUDE.md, .agile-v/STATE.md.
An embeddable chat widget (one script tag) backed by a Cloudflare Worker that:
- Stores sessions in KV
- Retrieves FAQ context via Vectorize (RAG + BGE embeddings)
- Streams answers via Workers AI (Llama 3.1 Fast → GLM-4.7-Flash fallback)
- Caps abuse with Rate Limiting (
CHAT_LIMITER, 20/min/IP) - Protects FAQ seeding with
SEED_SECRET - Optional Sentry (
SENTRY_DSN) — Worker SDK + browser tunnelPOST /api/monitoring
src/index.js Worker: routes, RAG, chat, seed, monitoring tunnel, assets
public/widget.js Browser widget (SSE client + optional Sentry via tunnel)
public/vendor/ Self-hosted cb-obs.min.js (Sentry browser SDK; neutral name vs adblock)
public/index.html Demo page
public/robots.txt Block AI scrapers
public/styles.css Built CSS (from src/*.css)
wrangler.jsonc Bindings: AI, VECTORIZE, KV, ASSETS, CHAT_LIMITER
.dev.vars.example Template for SEED_SECRET + SENTRY_DSN
widget.js --POST /api/chat--> Worker
├─ CHAT_LIMITER.limit(ip)
├─ KV session (cookie)
├─ BGE embed → Vectorize topK
└─ stream CHAT_MODELS → SSE → widget
| Method | Path | Notes |
|---|---|---|
| GET | /api/health |
{ status, sentryDsn } |
| POST | /api/chat |
SSE stream; rate-limited |
| GET | /api/history |
Messages for session cookie |
| POST | /api/seed |
Bearer / X-Seed-Secret required |
| POST | /api/monitoring |
Sentry envelope tunnel (DSN allowlist) |
Static: /, /widget.js, /styles.css, /robots.txt, /vendor/cb-obs.min.js
| Name | How | Purpose |
|---|---|---|
AI / VECTORIZE / CHAT_SESSIONS / ASSETS |
wrangler.jsonc |
Core runtime |
CHAT_LIMITER |
wrangler.jsonc → ratelimits |
20 req / 60s / IP |
SEED_SECRET |
.dev.vars locally; dashboard Secret or wrangler secret put in prod |
Authorize seed |
SENTRY_DSN |
Optional secret | Worker Sentry + monitoring tunnel allowlist |
cp .dev.vars.example .dev.vars
npm run dev
npm run deploy
curl -X POST https://YOUR.workers.dev/api/seed \
-H "Authorization: Bearer $SEED_SECRET"- Run
npm run dev→ open local URL → ask an FAQ question - Change one FAQ in
seed()→ redeploy → re-seed - Swap/add a model in
CHAT_MODELSat top ofsrc/index.js - Embed elsewhere: set
window.CHATBOT_BASE_URLthen loadwidget.js - Observability: set
SENTRY_DSN→ deploy → confirm/api/healthhassentryDsnand Network showsPOST /api/monitoring
- Widget only: point
CHATBOT_BASE_URLat this Worker - RAG helper: copy
faq()+EMBED_MODELinto another Worker with Vectorize - Streaming: copy
runChatStream()+ SSE transform pattern
Security reports: SECURITY.md → contact@arnobmahmud.com