npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@avis-ai/avischat

v1.0.11

Published

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

Readme

AvisChat (@avis-ai/avischat)

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 with GFM tables, fenced code blocks with copy, and KaTeX math.

Demo: https://demo-ai.avi-s.in

Vue, Svelte, Angular, or vanilla JS?

@avis-ai/avischat is React-only (components + hooks). For other stacks you have two main options:

  1. Headless client — @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).

  2. 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:

    <script
      src="https://api-ai.avi-s.in/widget.js"
      data-api-key="sk_live_YOUR_API_KEY"
    ></script>

The sections below apply to React integrations only.

Contents


Getting your API key

  1. Log in to the Dashboard
  2. Create a project — name it and set the system prompt
  3. Copy the API key — shown once; store it securely

Use the key in apiKey, or keep it on your server and proxy requests (see proxy).


Installation

Peer dependency: React 18+

npm install @avis-ai/avischat @avis-ai/sdk-js
pnpm add @avis-ai/avischat @avis-ai/sdk-js
yarn add @avis-ai/avischat @avis-ai/sdk-js

Quick start

import { AvisChat } from "@avis-ai/avischat";

export function MyChat() {
  return <AvisChat apiKey="your-api-key" />;
}

You get streaming bubbles, typing state, message input, and (by default) a model dropdown.


Making good use of AvisChat

Auth: only apiKey or client is required

Either pass apiKey or a client (new Avis({ apiKey, baseUrl }) from @avis-ai/sdk-js). Everything else is optional.

sessionId and memory

The 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.

Persist sessionId (e.g. localStorage) yourself — <AvisChat /> does not expose it. Use useAvisChat if you want the hook to expose sessionId for persistence.

Pick the right surface

| Goal | Use | |------|-----| | Built-in UI | <AvisChat /> | | Custom UI | useAvisChat | | Read/update sessionId easily | useAvisChat |

Knowledge base

If the project has a knowledge base in the dashboard, retrieval and grounding happen on the server. No extra SDK flags.


Components

<AvisChat />

Supports theme, model / models, sessionId, baseUrl, streaming, and optional floating mode.

<AvisChat
  apiKey="your-api-key"
  model="gpt-4o"
  sessionId="optional-session-id"
  theme="light"
  autoFocus
  className="my-chat"
/>

Floating launcher (custom icon or logo)

  • floating={false} (default): the panel is embedded — it’s always visible (subject to your layout).
  • floating={true}: a fixed circular launcher opens/closes the panel.

Use 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.

floatingTitle: non-empty string → header row with title and ×. Omitted or blank → no header; close by clicking the launcher again.

Open state: defaultOpen (uncontrolled), or open + onOpenChange (controlled).

className: applies to the chat panel only, not the floating FAB. Style the FAB with launcherButtonClassName / launcherButtonStyle.

<AvisChat
  apiKey="your-api-key"
  floating
  theme="dark"
  launcherImageSrc="https://example.com/logo.png"
  launcherImageAlt="Chat with us"
  launcherPosition="bottom-right"
  floatingTitle="Support"
  showModelSelector={false}
/>

launcherButtonStyle / sendButtonStyle use React’s CSSProperties (import type { CSSProperties } from "react").


AvisChat props

Required: apiKey or client. All other props are optional.

| Prop | Type | Default | Description | |------|------|---------|-------------| | apiKey | string | — | API key. Omit if client is set. | | client | Avis | — | Ready-made client from @avis-ai/sdk-js. | | baseUrl | string | https://api-ai.avi-s.in | API origin (no trailing slash). Dev proxy or self-hosted gateway. | | model | string | "gpt-4o-mini" | Model id; backend must route it. | | sessionId | string | generated | Conversation id for server-side memory. | | theme | "light" \| "dark" | "light" | | | models | ModelOption[] | curated list | { value, label, group? }; group<optgroup>. | | showModelSelector | boolean | true | Hide to lock UI to model. | | autoFocus | boolean | false | Focus the input on mount; in floating mode also when the panel opens. | | className | string | — | CSS class on the panel container (not the launcher). | | floating | boolean | false | Floating FAB + toggle panel. | | defaultOpen | boolean | false | (Floating) initial open if uncontrolled. | | open | boolean | — | (Floating) controlled open. | | onOpenChange | (open: boolean) => void | — | (Floating) open/close callback. | | floatingTitle | string | — | (Floating) Title + ×, or omit for no header. | | launcherPosition | "bottom-right" \| "bottom-left" | "bottom-right" | | | launcherAriaLabel | string | "Open chat" | Launcher aria-label. | | launcherButtonClassName | string | — | FAB className. | | launcherButtonStyle | CSSProperties | — | FAB inline styles (merged after defaults). | | sendButtonClassName | string | — | Send button className. | | sendButtonStyle | CSSProperties | — | Send button inline styles (merged after defaults). | | launcherIcon | ReactNode | — | Custom FAB content; wins over launcherImageSrc. | | launcherImageSrc | string | — | Image URL on the FAB. | | launcherImageAlt | string | "Chat" | Alt text for launcherImageSrc. |

The same hook fields apply to useAvisChat (apiKey, client, baseUrl, model, sessionId only).


useAvisChat hook

Headless streaming + sessionId + reset.

import { useAvisChat } from "@avis-ai/avischat";

function CustomChat() {
  const { sessionId, messages, sendMessage, isLoading, error, reset } = useAvisChat({
    apiKey: "your-api-key",
  });

  return (
    <div>
      {messages.map((m, i) => (
        <div key={i}>{m.role}: {m.content}</div>
      ))}
      <button type="button" onClick={() => sendMessage("Hello!")} disabled={isLoading}>
        Send
      </button>
      {error && <p>{error.message}</p>}
      <button type="button" onClick={reset}>New chat</button>
    </div>
  );
}

Return value

| Field | Type | Description | |-------|------|-------------| | sessionId | string | Current id — persist and pass back as sessionId. | | messages | AvisChatMessage[] | role + content. | | sendMessage | (content: string) => Promise<void> | Sends user text; streams assistant reply. | | isLoading | boolean | true while streaming. | | error | Error \| null | Last request error. | | reset | () => void | Clears messages/error; new sessionId. |


Session persistence (step by step)

  1. Load or create a sessionId
  2. Pass it into AvisChat or useAvisChat
  3. When it changes, save it (e.g. localStorage)

You own sessionId with <AvisChat />

function PersistentAvisChat() {
  const [sessionId] = useState(
    () => localStorage.getItem("avis-session") ?? crypto.randomUUID()
  );

  useEffect(() => {
    localStorage.setItem("avis-session", sessionId);
  }, [sessionId]);

  return <AvisChat apiKey="your-api-key" sessionId={sessionId} />;
}

useAvisChat returns sessionId

function PersistentCustomChat() {
  const [storedSessionId] = useState(
    () => localStorage.getItem("avis-session") ?? undefined
  );

  const { sessionId, messages, sendMessage, isLoading, error, reset } = useAvisChat({
    apiKey: "your-api-key",
    sessionId: storedSessionId,
  });

  useEffect(() => {
    if (sessionId) localStorage.setItem("avis-session", sessionId);
  }, [sessionId]);

  return (
    <div>
      {messages.map((m, i) => (
        <div key={i}>{m.role}: {m.content}</div>
      ))}
      {error && <p>{error.message}</p>}
      <button type="button" onClick={reset}>New conversation</button>
    </div>
  );
}

Next.js / SSR

Don’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:

"use client";
import { useState, useEffect } from "react";
import { AvisChat } from "@avis-ai/avischat";

const KEY = "avis-chat-session";

export function Chat() {
  const [sessionId, setSessionId] = useState<string | null>(null);

  useEffect(() => {
    let id = localStorage.getItem(KEY);
    if (!id) {
      id = crypto.randomUUID();
      localStorage.setItem(KEY, id);
    }
    setSessionId(id);
  }, []);

  if (!sessionId) return null; // or a skeleton

  return (
    <AvisChat
      apiKey={process.env.NEXT_PUBLIC_AVIS_API_KEY!}
      baseUrl={process.env.NEXT_PUBLIC_AVIS_BASE_URL}
      sessionId={sessionId}
    />
  );
}

Using a proxy (recommended for production)

@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.

Option A — baseUrl only

<AvisChat
  apiKey={process.env.NEXT_PUBLIC_AVIS_API_KEY!}
  baseUrl={process.env.NEXT_PUBLIC_AVIS_BASE_URL}
/>

Option B — shared Avis client

import { Avis } from "@avis-ai/sdk-js";
import { AvisChat } from "@avis-ai/avischat";

const client = new Avis({
  apiKey: process.env.NEXT_PUBLIC_AVIS_API_KEY!,
  baseUrl: "/api/avis-proxy",
});

export function Chat() {
  return <AvisChat client={client} />;
}

If baseUrl is unset, the default host is https://api-ai.avi-s.in.


TypeScript types

Re-exported from @avis-ai/avischat:

import type {
  AvisChatProps,
  AvisChatMessage,
  ModelOption,
  UseAvisChatOptions,
  UseAvisChatReturn,
} from "@avis-ai/avischat";
interface AvisChatMessage {
  role: "system" | "user" | "assistant";
  content: string;
}

interface ModelOption {
  value: string;
  label: string;
  group?: string;
}

// UseAvisChatOptions = pick from AvisChatProps: apiKey, client, baseUrl, model, sessionId
// AvisChatProps extends UseAvisChatOptions with UI / floating fields (see props table).

Styling & CSS

  • Defaults are inline styles.
  • className — panel wrapper (embedded or floating panel).
  • launcherButtonClassName — floating FAB only.
  • launcherButtonStyle / sendButtonStyle — React CSSProperties, merged on top of defaults.
  • Messages scroll area: class .avis-chat-messages (scrollbar theming for light/dark).
.my-chat {
  height: 500px !important;
  max-height: 90vh !important;
}

Errors & accessibility

  • Errors: <AvisChat /> shows the last error in a strip above the input (from failed stream or network).
  • Launcher: set launcherAriaLabel for a clear FAB label; aria-expanded tracks panel open state.
  • Model selector: labeled select (aria-label="Select model") when visible.

Framework notes

  • React 18+ required.
  • Works with Vite, Next.js, CRA, etc.
  • For Next.js App Router, use "use client" on the component tree that imports AvisChat / useAvisChat, and follow the SSR sessionId pattern above.