> ## Documentation Index
> Fetch the complete documentation index at: https://help.hoopai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 2026 03 29 hoopai ai widget design

# HoopAI AI Chat Widget — Design Spec

**Date:** 2026-03-29
**Status:** Approved

***

## Problem

The current VoiceGlow/ConvoCore widget is broken and unreliable. It is a third-party hosted service with no control over uptime, UI, or AI behaviour. API keys cannot be managed securely and the UI does not match the HoopAI design system.

## Goal

Replace VoiceGlow entirely with a fully custom AI chat widget powered by Claude Haiku 4.5 via OpenRouter, backed by a Cloudflare Worker proxy that keeps all API keys off the client. The widget should match Mintlify's native AI panel UX — a right-side drawer that pushes page content left — and feel like a first-class part of the docs site.

***

## Architecture

```
Browser (help.hoopai.com — static Mintlify)
  theme/chat-widget.js
      │
      │  POST /chat  (SSE stream)
      ▼
  Cloudflare Worker  (hoopai-chat-api.workers.dev)
      │  env: OPENROUTER_API_KEY  (secret, never in code)
      │  env: BRAVE_SEARCH_API_KEY  (secret, optional)
      │
      ├──▶  OpenRouter → anthropic/claude-haiku-4-5  (streaming)
      └──▶  Brave Search API  (web search tool)
```

### Why Cloudflare Workers

* Edge-deployed, \~0ms cold start, global low latency
* Free tier: 100k requests/day — more than sufficient for a help centre
* Secrets stored in Cloudflare dashboard, never in git or code
* Streaming SSE supported natively
* No separate server to maintain

***

## Part 1 — Cloudflare Worker

**Location:** `worker/` directory in the repo (Mintlify ignores this)

### Files

```
worker/
  wrangler.toml     — worker config (name, compat date, vars)
  src/index.js      — worker entry point
```

### Endpoint: `POST /chat`

**Request body:**

```json theme={null}
{
  "messages": [{ "role": "user", "content": "..." }],
  "pageContext": { "title": "...", "url": "..." }
}
```

**Response:** `text/event-stream` (SSE), OpenRouter streaming format passed through directly.

### Tools the AI can call

| Tool                    | Description                     | Implementation                                         |
| ----------------------- | ------------------------------- | ------------------------------------------------------ |
| `web_search`            | Search the web for current info | Calls Brave Search API from the Worker                 |
| `create_support_ticket` | Create a support ticket         | Sends structured payload to a configurable webhook URL |

### Security

* CORS: `Access-Control-Allow-Origin` locked to `https://help.hoopai.com` and `http://localhost:3000`
* No other origin can call the worker
* `OPENROUTER_API_KEY` set via `wrangler secret put` — never in code
* Rate limiting: Cloudflare's default per-IP rate limiting applies

### System prompt (injected by worker)

```
You are a helpful support assistant for HoopAI — an all-in-one CRM and marketing platform.
You are embedded in the HoopAI Help Center documentation site.
Current page: {pageContext.title} ({pageContext.url})

Answer questions about HoopAI features directly and concisely.
When the user asks about something not covered in your training, use web_search to find current information.
When a user has an unresolved issue that needs human support, offer to create a support ticket using create_support_ticket.
Never mention GoHighLevel, HighLevel, GHL, Marketing Muse, or WhoPayI — always say "HoopAI" or "Hoop".
```

***

## Part 2 — Custom Chat Widget

**Location:** `theme/chat-widget.js` (replaces current VoiceGlow file entirely)
**CSS:** New `#hoopai-panel-*` rules added to `theme/custom.css`

### Panel Behaviour

* Fixed right-side drawer, `position: fixed`, `top: 0`, `right: 0`, `height: 100vh`
* Default width: `380px`. Expanded width: `680px`. Both transition smoothly.
* When open: `body.hoopai-panel-open #content-side-layout { margin-right: 380px }` — content pushes left
* When expanded: margin increases to `680px`
* Transition: `0.25s ease` on both the panel and the content margin
* Z-index: high enough to sit above Mintlify's sidebar overlay but below modals
* Inherits dark/light mode automatically via existing `--ds-*` CSS custom properties

### Panel Structure (HTML)

```
#hoopai-panel
  #hoopai-panel-header
    .hoopai-panel-logo    (sparkle icon)
    .hoopai-panel-title   ("Ask AI")
    .hoopai-panel-actions
      #hoopai-expand-btn  (expand/collapse)
      #hoopai-clear-btn   (clear conversation)
      #hoopai-close-btn   (close panel)
  #hoopai-panel-messages
    .hoopai-msg-empty     (shown when no messages — suggested prompts)
    .hoopai-msg-user      (user message bubble)
    .hoopai-msg-assistant (assistant bubble, streams in token by token)
    .hoopai-msg-tool      (tool call pill: "Searching the web…")
  #hoopai-panel-footer
    #hoopai-input         (textarea, auto-grows)
    #hoopai-send-btn      (send, disabled while streaming)
```

### Suggested prompts (empty state)

Three prompts generated from the current page title shown as clickable chips. Clicking one fills the input and sends.

### Streaming

* Uses `fetch` with `ReadableStream` to consume the SSE from the Worker
* Renders tokens progressively into the assistant bubble as they arrive
* Shows an animated three-dot indicator while waiting for first token
* Send button disabled + shows stop icon during streaming; clicking it aborts the stream

### Tool call display

When the AI calls `web_search` or `create_support_ticket`, a pill appears in the message list:

* `🔍 Searching the web…` → replaced with `🔍 Web search complete` when done
* `🎫 Creating support ticket…` → replaced with `✓ Ticket created` when done

### Page context injection

Every new conversation automatically prepends page context. When triggered from:

* **Navbar / page Ask AI button** — context message shown as a small pill above the input: `📄 Reading: <page title>`
* **Code block Ask AI button** — code snippet shown in a collapsed expandable above the input

### Ask AI entry points (all preserved from current widget)

1. Navbar button (desktop) — `#assistant-entry`
2. Mobile header button — `#assistant-entry-mobile`
3. Code block button — `data-ask-ai-injected`
4. Page-level button — `#page-ask-ai-btn`
5. Keyboard shortcut — `Ctrl+I` / `Cmd+I`

### Dark / light mode

All colours use `var(--ds-*)` tokens from `theme/custom.css`. No hardcoded colours in widget JS or CSS. Panel automatically matches the site theme.

***

## Part 3 — Deployment Steps

1. Install Wrangler CLI locally: `npm install -g wrangler`
2. Authenticate: `CLOUDFLARE_API_TOKEN=<token> wrangler whoami`
3. Deploy worker: `CLOUDFLARE_API_TOKEN=<token> wrangler deploy`
4. Set secrets:
   ```
   wrangler secret put OPENROUTER_API_KEY
   wrangler secret put BRAVE_SEARCH_API_KEY   (optional, enables web search)
   ```
5. Capture deployed Worker URL (`https://hoopai-chat-api.<account>.workers.dev`)
6. Embed Worker URL in `theme/chat-widget.js` as `WORKER_URL` constant
7. Remove VoiceGlow script and `window.VG_CONFIG` from widget JS

***

## Out of Scope (this phase)

* Custom domain for the Worker (can be added later in Cloudflare dashboard)
* Conversation persistence across page loads (each page load starts fresh)
* User authentication / per-user history
* HoopAI CRM integration for ticket creation (webhook URL to be provided by user)
* Brave Search setup (slot wired, key optional — web search gracefully disabled if key absent)
