{"_id":"@avis-ai/avischat","_rev":"4-65011411246f41c54ffe25a8986b6719","name":"@avis-ai/avischat","dist-tags":{"latest":"1.0.11"},"versions":{"1.0.8":{"name":"@avis-ai/avischat","version":"1.0.8","_id":"@avis-ai/avischat@1.0.8","maintainers":[{"name":"adminavis","email":"admin@avi-s.in"}],"dist":{"shasum":"2ddf68184a20d1aef18c880731cced824822ed2b","tarball":"https://registry.npmjs.org/@avis-ai/avischat/-/avischat-1.0.8.tgz","fileCount":20,"integrity":"sha512-noYk1y0/+JudMxlezN4ZwrpIH2bGcryiAShc7k0KuhZlUp4mlRy1kYvS2MboOGGgZ6tSjbFyt2J152piSE8NrQ==","signatures":[{"sig":"MEUCIBVaXdAJERT+qSflffTwqEAMPgZJ9dLampkxeWA7TNUCAiEAj1OCYyv18y9uUSNUAbEAnPYl8rtxU1lsv1FJpBBfpRo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55243},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"56dbffdee4d5780c594916d2b032b26c51ea3425","scripts":{"build":"tsc -p tsconfig.json","build:watch":"tsc -p tsconfig.json --watch"},"_npmUser":{"name":"adminavis","email":"admin@avi-s.in"},"_npmVersion":"10.9.3","description":"React components and hooks for **Avis AI**: a drop-in chat widget, a headless hook, streaming replies, session memory, and a built-in model picker (OpenAI, Anthropic, Google Gemini, and Ollama-style tags). Assistant messages render **Markdown** with GFM t","directories":{},"_nodeVersion":"22.18.0","dependencies":{"katex":"^0.16.44","remark-gfm":"^4.0.1","remark-math":"^6.0.0","rehype-katex":"^7.0.1","react-markdown":"^10.1.0","@avis-ai/sdk-js":"0.0.6","unist-util-visit":"^5.1.0","hast-util-to-text":"^4.0.2"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.1","typescript":"^5.9.3","@types/hast":"^3.0.4","@types/react":"^18"},"peerDependencies":{"react":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/avischat_1.0.8_1774724428366_0.5243634541700357","host":"s3://npm-registry-packages-npm-production"}},"1.0.9":{"name":"@avis-ai/avischat","version":"1.0.9","_id":"@avis-ai/avischat@1.0.9","maintainers":[{"name":"adminavis","email":"admin@avi-s.in"}],"dist":{"shasum":"da8d17f60549ad616b8d0aa7f479ba584fd44e29","tarball":"https://registry.npmjs.org/@avis-ai/avischat/-/avischat-1.0.9.tgz","fileCount":20,"integrity":"sha512-BkbmxAV0UHFBH+9wIoiOtcHB0bPejFj1gT2N7ZKrjTL7E8XNSIKWL5x7x1Qckbps17oif1PAomQMqcuaNJCm+w==","signatures":[{"sig":"MEUCIHOxqM4SvA7oXHzy8k5AtkJVz2JI1EX6C8Odc0dyfrTQAiEA0ngyN0ewiNN9LjTbs6eicgaiJ10Dd6WEsEX1BL47ENI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55296},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"0f84db41a8d5db6da6a6d95e09f0bbd1ec76f617","scripts":{"build":"tsc -p tsconfig.json","build:watch":"tsc -p tsconfig.json --watch"},"_npmUser":{"name":"adminavis","email":"admin@avi-s.in"},"_npmVersion":"10.9.3","description":"React components and hooks for **Avis AI**: a drop-in chat widget, a headless hook, streaming replies, session memory, and a built-in model picker (OpenAI, Anthropic, and Google Gemini). Assistant messages render **Markdown** with GFM tables, **syntax-hig","directories":{},"_nodeVersion":"22.18.0","dependencies":{"katex":"^0.16.44","remark-gfm":"^4.0.1","remark-math":"^6.0.0","rehype-katex":"^7.0.1","react-markdown":"^10.1.0","@avis-ai/sdk-js":"0.0.6","unist-util-visit":"^5.1.0","hast-util-to-text":"^4.0.2"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.1","typescript":"^5.9.3","@types/hast":"^3.0.4","@types/react":"^18"},"peerDependencies":{"react":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/avischat_1.0.9_1774759080046_0.4087358171332609","host":"s3://npm-registry-packages-npm-production"}},"1.0.10":{"name":"@avis-ai/avischat","version":"1.0.10","_id":"@avis-ai/avischat@1.0.10","maintainers":[{"name":"adminavis","email":"admin@avi-s.in"}],"dist":{"shasum":"49aa1eae1a5cb17acc4c962fe47f10f9b5f9beab","tarball":"https://registry.npmjs.org/@avis-ai/avischat/-/avischat-1.0.10.tgz","fileCount":20,"integrity":"sha512-/hpWgzq3FS34zMxHi4T7PmgJZGX4nSjkIYU02E/j+9CRIocqigwTdGoNlm9fMykzz0fyG4EpmeAg/tYUUJOV7g==","signatures":[{"sig":"MEUCIAs8Gf7LISy+S7OGRgcoA/z/cwo0+t4Q9Ui3YVDpHEPjAiEA02gj4ZN0eis833D618PAObKK79Ftb7GShuiTQcPyRNw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63052},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"74b24b3659705f38a061d42069b15e3e81f8167f","scripts":{"build":"tsc -p tsconfig.json","build:watch":"tsc -p tsconfig.json --watch"},"_npmUser":{"name":"adminavis","email":"admin@avi-s.in"},"_npmVersion":"10.9.3","description":"React components and hooks for **Avis AI**: a drop-in chat widget, optional **floating launcher**, a headless hook, streaming replies, session memory, and a built-in model picker (OpenAI, Anthropic, and Google Gemini). Assistant messages render **Markdown","directories":{},"_nodeVersion":"22.18.0","dependencies":{"katex":"^0.16.44","remark-gfm":"^4.0.1","remark-math":"^6.0.0","rehype-katex":"^7.0.1","react-markdown":"^10.1.0","@avis-ai/sdk-js":"0.0.6","unist-util-visit":"^5.1.0","hast-util-to-text":"^4.0.2"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.1","typescript":"^5.9.3","@types/hast":"^3.0.4","@types/react":"^18"},"peerDependencies":{"react":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/avischat_1.0.10_1775152715873_0.3870423459704966","host":"s3://npm-registry-packages-npm-production"}},"1.0.11":{"name":"@avis-ai/avischat","version":"1.0.11","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"peerDependencies":{"react":">=18.0.0"},"dependencies":{"@avis-ai/sdk-js":"0.0.6","hast-util-to-text":"^4.0.2","katex":"^0.16.44","react-markdown":"^10.1.0","rehype-katex":"^7.0.1","remark-gfm":"^4.0.1","remark-math":"^6.0.0","unist-util-visit":"^5.1.0"},"devDependencies":{"@types/hast":"^3.0.4","@types/react":"^18","react":"^18.3.1","typescript":"^5.9.3"},"scripts":{"build":"tsc -p tsconfig.json","build:watch":"tsc -p tsconfig.json --watch"},"_id":"@avis-ai/avischat@1.0.11","gitHead":"a73e6dca6f591c3e21b6c1f22dacf2085ebf294c","description":"React components and hooks for **Avis AI**: a drop-in chat widget, optional **floating launcher**, a headless hook, streaming replies, session memory, and a built-in model picker (OpenAI, Anthropic, and Google Gemini). Assistant messages render **Markdown","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-bim+g92F6kvvR8ACqtTKKiN39S/TslEv/QqRdNTbhj6fSayJZcBE0tJslUANGx7Bf92EVlmCUCwZTi3QSGljGQ==","shasum":"3714f9a1610b394573dc4d56a18781a5c0d74de6","tarball":"https://registry.npmjs.org/@avis-ai/avischat/-/avischat-1.0.11.tgz","fileCount":20,"unpackedSize":63800,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIF+PAEPOElUD/dDBWSIt4UUK8cqzTTeMryFhvf2g54bSAiEAyYHcLoJeulux44ka2m5ZasgIxrtBGMN0RoYgj+rI8EY="}]},"_npmUser":{"name":"adminavis","email":"admin@avi-s.in"},"directories":{},"maintainers":[{"name":"adminavis","email":"admin@avi-s.in"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/avischat_1.0.11_1775182291352_0.09115476892726626"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-28T19:00:28.313Z","modified":"2026-04-03T02:11:31.674Z","1.0.8":"2026-03-28T19:00:28.528Z","1.0.9":"2026-03-29T04:38:00.183Z","1.0.10":"2026-04-02T17:58:36.018Z","1.0.11":"2026-04-03T02:11:31.501Z"},"description":"React components and hooks for **Avis AI**: a drop-in chat widget, optional **floating launcher**, a headless hook, streaming replies, session memory, and a built-in model picker (OpenAI, Anthropic, and Google Gemini). Assistant messages render **Markdown","maintainers":[{"name":"adminavis","email":"admin@avi-s.in"}],"readme":"# AvisChat (`@avis-ai/avischat`)\r\n\r\nReact components and hooks for **Avis AI**: a drop-in chat widget, optional **floating launcher**, a headless hook, streaming replies, session memory, and a built-in model picker (OpenAI, Anthropic, and Google Gemini). Assistant messages render **Markdown** with GFM tables, **fenced code blocks with copy**, and **KaTeX** math.\r\n\r\n**Demo:** [https://demo-ai.avi-s.in](https://demo-ai.avi-s.in)\r\n\r\n### Vue, Svelte, Angular, or vanilla JS?\r\n\r\n**`@avis-ai/avischat` is React-only** (components + hooks). For other stacks you have two main options:\r\n\r\n1. **Headless client — [`@avis-ai/sdk-js`](https://www.npmjs.com/package/@avis-ai/sdk-js)** — same `Avis` class this package uses under the hood: `chat()`, `chatStream()`, and session ids. Build your own UI in any framework. Full documentation is in the **`@avis-ai/sdk-js` package README** (source tree: `packages/sdk-js/README.md`).\r\n2. **No framework on your page — iframe embed** — load `widget.js` from the API and pass your key. You must set **`data-embed-url`** to a public `/embed` page in production (the script’s default is localhost). Example:\r\n\r\n   ```html\r\n   <script\r\n     src=\"https://api-ai.avi-s.in/widget.js\"\r\n     data-api-key=\"sk_live_YOUR_API_KEY\"\r\n   ></script>\r\n   ```\r\n\r\nThe sections below apply to **React** integrations only.\r\n\r\n## Contents\r\n\r\n- [Getting your API key](#getting-your-api-key)\r\n- [Installation](#installation)\r\n- [Quick start](#quick-start)\r\n- [Making good use](#making-good-use-of-avischat)\r\n- [Components](#components)\r\n- [Floating launcher](#floating-launcher-custom-icon-or-logo)\r\n- [AvisChat props](#avischat-props)\r\n- [useAvisChat hook](#useavischat-hook)\r\n- [Session persistence](#session-persistence-step-by-step)\r\n- [Proxy / production](#using-a-proxy-recommended-for-production)\r\n- [TypeScript types](#typescript-types)\r\n- [Styling & CSS](#styling--css)\r\n- [Errors & accessibility](#errors--accessibility)\r\n- [Framework notes](#framework-notes)\r\n\r\n---\r\n\r\n## Getting your API key\r\n\r\n1. Log in to the **[Dashboard](https://dashboard-ai.avi-s.in)**\r\n2. **Create a project** — name it and set the system prompt  \r\n3. **Copy the API key** — shown once; store it securely  \r\n\r\nUse the key in **`apiKey`**, or keep it on your server and proxy requests (see [proxy](#using-a-proxy-recommended-for-production)).\r\n\r\n---\r\n\r\n## Installation\r\n\r\n**Peer dependency:** React **18+**\r\n\r\n```bash\r\nnpm install @avis-ai/avischat @avis-ai/sdk-js\r\npnpm add @avis-ai/avischat @avis-ai/sdk-js\r\nyarn add @avis-ai/avischat @avis-ai/sdk-js\r\n```\r\n\r\n---\r\n\r\n## Quick start\r\n\r\n```tsx\r\nimport { AvisChat } from \"@avis-ai/avischat\";\r\n\r\nexport function MyChat() {\r\n  return <AvisChat apiKey=\"your-api-key\" />;\r\n}\r\n```\r\n\r\nYou get streaming bubbles, typing state, message input, and (by default) a model dropdown.\r\n\r\n---\r\n\r\n## Making good use of AvisChat\r\n\r\n### Auth: only `apiKey` or `client` is required\r\n\r\nEither pass **`apiKey`** or a **`client`** (`new Avis({ apiKey, baseUrl })` from `@avis-ai/sdk-js`). Everything else is optional.\r\n\r\n### `sessionId` and memory\r\n\r\nThe API stores the **full thread** under **`sessionId`**. Reuse the same id after reload to continue; omit or use a new id for a fresh chat.\r\n\r\nPersist **`sessionId`** (e.g. `localStorage`) yourself — `<AvisChat />` does not expose it. Use **`useAvisChat`** if you want the hook to expose **`sessionId`** for persistence.\r\n\r\n### Pick the right surface\r\n\r\n| Goal | Use |\r\n|------|-----|\r\n| Built-in UI | `<AvisChat />` |\r\n| Custom UI | `useAvisChat` |\r\n| Read/update `sessionId` easily | `useAvisChat` |\r\n\r\n### Knowledge base\r\n\r\nIf the project has a knowledge base in the dashboard, retrieval and grounding happen on the **server**. No extra SDK flags.\r\n\r\n---\r\n\r\n## Components\r\n\r\n### `<AvisChat />`\r\n\r\nSupports **`theme`**, **`model`** / **`models`**, **`sessionId`**, **`baseUrl`**, streaming, and optional **floating** mode.\r\n\r\n```tsx\r\n<AvisChat\r\n  apiKey=\"your-api-key\"\r\n  model=\"gpt-4o\"\r\n  sessionId=\"optional-session-id\"\r\n  theme=\"light\"\r\n  autoFocus\r\n  className=\"my-chat\"\r\n/>\r\n```\r\n\r\n---\r\n\r\n## Floating launcher (custom icon or logo)\r\n\r\n- **`floating={false}` (default):** the panel is **embedded** — it’s always visible (subject to your layout).\r\n- **`floating={true}`:** a **fixed circular launcher** opens/closes the panel.\r\n\r\nUse **`launcherImageSrc`** / **`launcherImageAlt`** for a logo URL, **`launcherIcon`** for any React node (overrides the image), or neither for a built-in glyph. The image **fills** the inner circle; **`launcherButtonStyle`** padding shows as a ring around the art.\r\n\r\n**`floatingTitle`:** non-empty string → header row with title and **×**. Omitted or blank → **no header**; close by clicking the **launcher** again.\r\n\r\n**Open state:** `defaultOpen` (uncontrolled), or **`open` + `onOpenChange`** (controlled).\r\n\r\n**`className`:** applies to the **chat panel** only, not the floating FAB. Style the FAB with **`launcherButtonClassName`** / **`launcherButtonStyle`**.\r\n\r\n```tsx\r\n<AvisChat\r\n  apiKey=\"your-api-key\"\r\n  floating\r\n  theme=\"dark\"\r\n  launcherImageSrc=\"https://example.com/logo.png\"\r\n  launcherImageAlt=\"Chat with us\"\r\n  launcherPosition=\"bottom-right\"\r\n  floatingTitle=\"Support\"\r\n  showModelSelector={false}\r\n/>\r\n```\r\n\r\n`launcherButtonStyle` / `sendButtonStyle` use React’s **`CSSProperties`** (`import type { CSSProperties } from \"react\"`).\r\n\r\n---\r\n\r\n## AvisChat props\r\n\r\n**Required:** **`apiKey`** or **`client`**. All other props are optional.\r\n\r\n| Prop | Type | Default | Description |\r\n|------|------|---------|-------------|\r\n| `apiKey` | `string` | — | API key. Omit if `client` is set. |\r\n| `client` | `Avis` | — | Ready-made client from `@avis-ai/sdk-js`. |\r\n| `baseUrl` | `string` | `https://api-ai.avi-s.in` | API origin (no trailing slash). Dev proxy or self-hosted gateway. |\r\n| `model` | `string` | `\"gpt-4o-mini\"` | Model id; backend must route it. |\r\n| `sessionId` | `string` | generated | Conversation id for server-side memory. |\r\n| `theme` | `\"light\" \\| \"dark\"` | `\"light\"` | |\r\n| `models` | `ModelOption[]` | curated list | `{ value, label, group? }`; `group` → `<optgroup>`. |\r\n| `showModelSelector` | `boolean` | `true` | Hide to lock UI to `model`. |\r\n| `autoFocus` | `boolean` | `false` | Focus the input on mount; in **floating** mode also when the **panel opens**. |\r\n| `className` | `string` | — | CSS class on the **panel** container (not the launcher). |\r\n| `floating` | `boolean` | `false` | Floating FAB + toggle panel. |\r\n| `defaultOpen` | `boolean` | `false` | (Floating) initial open if uncontrolled. |\r\n| `open` | `boolean` | — | (Floating) controlled open. |\r\n| `onOpenChange` | `(open: boolean) => void` | — | (Floating) open/close callback. |\r\n| `floatingTitle` | `string` | — | (Floating) Title + ×, or omit for no header. |\r\n| `launcherPosition` | `\"bottom-right\" \\| \"bottom-left\"` | `\"bottom-right\"` | |\r\n| `launcherAriaLabel` | `string` | `\"Open chat\"` | Launcher `aria-label`. |\r\n| `launcherButtonClassName` | `string` | — | FAB `className`. |\r\n| `launcherButtonStyle` | `CSSProperties` | — | FAB inline styles (merged after defaults). |\r\n| `sendButtonClassName` | `string` | — | Send button `className`. |\r\n| `sendButtonStyle` | `CSSProperties` | — | Send button inline styles (merged after defaults). |\r\n| `launcherIcon` | `ReactNode` | — | Custom FAB content; wins over `launcherImageSrc`. |\r\n| `launcherImageSrc` | `string` | — | Image URL on the FAB. |\r\n| `launcherImageAlt` | `string` | `\"Chat\"` | Alt text for `launcherImageSrc`. |\r\n\r\nThe same hook fields apply to **`useAvisChat`** (`apiKey`, `client`, `baseUrl`, `model`, `sessionId` only).\r\n\r\n---\r\n\r\n## useAvisChat hook\r\n\r\nHeadless streaming + **`sessionId`** + **`reset`**.\r\n\r\n```tsx\r\nimport { useAvisChat } from \"@avis-ai/avischat\";\r\n\r\nfunction CustomChat() {\r\n  const { sessionId, messages, sendMessage, isLoading, error, reset } = useAvisChat({\r\n    apiKey: \"your-api-key\",\r\n  });\r\n\r\n  return (\r\n    <div>\r\n      {messages.map((m, i) => (\r\n        <div key={i}>{m.role}: {m.content}</div>\r\n      ))}\r\n      <button type=\"button\" onClick={() => sendMessage(\"Hello!\")} disabled={isLoading}>\r\n        Send\r\n      </button>\r\n      {error && <p>{error.message}</p>}\r\n      <button type=\"button\" onClick={reset}>New chat</button>\r\n    </div>\r\n  );\r\n}\r\n```\r\n\r\n### Return value\r\n\r\n| Field | Type | Description |\r\n|-------|------|-------------|\r\n| `sessionId` | `string` | Current id — persist and pass back as `sessionId`. |\r\n| `messages` | `AvisChatMessage[]` | `role` + `content`. |\r\n| `sendMessage` | `(content: string) => Promise<void>` | Sends user text; streams assistant reply. |\r\n| `isLoading` | `boolean` | `true` while streaming. |\r\n| `error` | `Error \\| null` | Last request error. |\r\n| `reset` | `() => void` | Clears messages/error; **new** `sessionId`. |\r\n\r\n---\r\n\r\n## Session persistence (step by step)\r\n\r\n1. Load or create a **`sessionId`**  \r\n2. Pass it into **`AvisChat`** or **`useAvisChat`**  \r\n3. When it changes, save it (e.g. `localStorage`)\r\n\r\n### You own `sessionId` with `<AvisChat />`\r\n\r\n```tsx\r\nfunction PersistentAvisChat() {\r\n  const [sessionId] = useState(\r\n    () => localStorage.getItem(\"avis-session\") ?? crypto.randomUUID()\r\n  );\r\n\r\n  useEffect(() => {\r\n    localStorage.setItem(\"avis-session\", sessionId);\r\n  }, [sessionId]);\r\n\r\n  return <AvisChat apiKey=\"your-api-key\" sessionId={sessionId} />;\r\n}\r\n```\r\n\r\n### `useAvisChat` returns `sessionId`\r\n\r\n```tsx\r\nfunction PersistentCustomChat() {\r\n  const [storedSessionId] = useState(\r\n    () => localStorage.getItem(\"avis-session\") ?? undefined\r\n  );\r\n\r\n  const { sessionId, messages, sendMessage, isLoading, error, reset } = useAvisChat({\r\n    apiKey: \"your-api-key\",\r\n    sessionId: storedSessionId,\r\n  });\r\n\r\n  useEffect(() => {\r\n    if (sessionId) localStorage.setItem(\"avis-session\", sessionId);\r\n  }, [sessionId]);\r\n\r\n  return (\r\n    <div>\r\n      {messages.map((m, i) => (\r\n        <div key={i}>{m.role}: {m.content}</div>\r\n      ))}\r\n      {error && <p>{error.message}</p>}\r\n      <button type=\"button\" onClick={reset}>New conversation</button>\r\n    </div>\r\n  );\r\n}\r\n```\r\n\r\n### Next.js / SSR\r\n\r\nDon’t read `localStorage` during the first server render. Initialize **`sessionId`** in **`useState` + `useEffect`** (or pass `undefined` until mounted) so the tree matches SSR, then hydrate a stable id. Example:\r\n\r\n```tsx\r\n\"use client\";\r\nimport { useState, useEffect } from \"react\";\r\nimport { AvisChat } from \"@avis-ai/avischat\";\r\n\r\nconst KEY = \"avis-chat-session\";\r\n\r\nexport function Chat() {\r\n  const [sessionId, setSessionId] = useState<string | null>(null);\r\n\r\n  useEffect(() => {\r\n    let id = localStorage.getItem(KEY);\r\n    if (!id) {\r\n      id = crypto.randomUUID();\r\n      localStorage.setItem(KEY, id);\r\n    }\r\n    setSessionId(id);\r\n  }, []);\r\n\r\n  if (!sessionId) return null; // or a skeleton\r\n\r\n  return (\r\n    <AvisChat\r\n      apiKey={process.env.NEXT_PUBLIC_AVIS_API_KEY!}\r\n      baseUrl={process.env.NEXT_PUBLIC_AVIS_BASE_URL}\r\n      sessionId={sessionId}\r\n    />\r\n  );\r\n}\r\n```\r\n\r\n---\r\n\r\n## Using a proxy (recommended for production)\r\n\r\n`@avis-ai/sdk-js` **warns** if a real **`apiKey`** runs in the browser. For production, proxy **`/v1/chat/completions`** (and related routes) from **your** origin and attach the secret on the server.\r\n\r\n**Option A — `baseUrl` only**\r\n\r\n```tsx\r\n<AvisChat\r\n  apiKey={process.env.NEXT_PUBLIC_AVIS_API_KEY!}\r\n  baseUrl={process.env.NEXT_PUBLIC_AVIS_BASE_URL}\r\n/>\r\n```\r\n\r\n**Option B — shared `Avis` client**\r\n\r\n```tsx\r\nimport { Avis } from \"@avis-ai/sdk-js\";\r\nimport { AvisChat } from \"@avis-ai/avischat\";\r\n\r\nconst client = new Avis({\r\n  apiKey: process.env.NEXT_PUBLIC_AVIS_API_KEY!,\r\n  baseUrl: \"/api/avis-proxy\",\r\n});\r\n\r\nexport function Chat() {\r\n  return <AvisChat client={client} />;\r\n}\r\n```\r\n\r\nIf **`baseUrl`** is unset, the default host is **`https://api-ai.avi-s.in`**.\r\n\r\n---\r\n\r\n## TypeScript types\r\n\r\nRe-exported from **`@avis-ai/avischat`**:\r\n\r\n```ts\r\nimport type {\r\n  AvisChatProps,\r\n  AvisChatMessage,\r\n  ModelOption,\r\n  UseAvisChatOptions,\r\n  UseAvisChatReturn,\r\n} from \"@avis-ai/avischat\";\r\n```\r\n\r\n```ts\r\ninterface AvisChatMessage {\r\n  role: \"system\" | \"user\" | \"assistant\";\r\n  content: string;\r\n}\r\n\r\ninterface ModelOption {\r\n  value: string;\r\n  label: string;\r\n  group?: string;\r\n}\r\n\r\n// UseAvisChatOptions = pick from AvisChatProps: apiKey, client, baseUrl, model, sessionId\r\n// AvisChatProps extends UseAvisChatOptions with UI / floating fields (see props table).\r\n```\r\n\r\n---\r\n\r\n## Styling & CSS\r\n\r\n- Defaults are **inline styles**.  \r\n- **`className`** — panel wrapper (embedded or floating panel).  \r\n- **`launcherButtonClassName`** — floating FAB only.  \r\n- **`launcherButtonStyle` / `sendButtonStyle`** — React `CSSProperties`, merged **on top of** defaults.  \r\n- Messages scroll area: class **`.avis-chat-messages`** (scrollbar theming for light/dark).\r\n\r\n```css\r\n.my-chat {\r\n  height: 500px !important;\r\n  max-height: 90vh !important;\r\n}\r\n```\r\n\r\n---\r\n\r\n## Errors & accessibility\r\n\r\n- **Errors:** `<AvisChat />` shows the last error in a strip **above** the input (from failed stream or network).  \r\n- **Launcher:** set **`launcherAriaLabel`** for a clear FAB label; **`aria-expanded`** tracks panel open state.  \r\n- **Model selector:** labeled select (`aria-label=\"Select model\"`) when visible.\r\n\r\n---\r\n\r\n## Framework notes\r\n\r\n- **React 18+** required.  \r\n- Works with **Vite**, **Next.js**, **CRA**, etc.  \r\n- For **Next.js App Router**, use **`\"use client\"`** on the component tree that imports **`AvisChat` / `useAvisChat`**, and follow the **SSR** `sessionId` pattern above.\r\n","readmeFilename":"README.md"}