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

@ola-krutrim/ai-sdk

v0.3.1

Published

Drop-in React chat and voice widgets for Agent Bazaar (ChatWidget, ChatButton, VoiceWidget, VoiceButton)

Readme

@ola-krutrim/ai-sdk

Drop-in React components for Agent Bazaar chat and voice. Pass your agent credentials — the SDK handles sessions, streaming, branding, rich content, and voice.

npm install @ola-krutrim/ai-sdk react react-dom
import {
  ChatWidget,
  ChatButton,
  VoiceWidget,
  VoiceButton,
} from "@ola-krutrim/ai-sdk/react";

You need an agent name and agent key from the Agent Bazaar console.


Architecture

Chat and voice are separate widgets. Shared contracts live in base types; each domain has its own widget + launcher.

| Layer | Role | |-------|------| | AiWidgetProps | Type-only base — agent credentials, branding, panel size (not a renderable component) | | AiButtonProps | Shared floating launcher config (type, placement, sizes, defaultOpen, etc.) | | AiButton | Shared launcher UI (circular bubble or bottom header dock + panel shell) | | ChatWidget | Chat-only inline panel | | ChatButton | Chat-only launcher — AiButton + inner ChatWidget | | VoiceWidget | Voice-only inline panel | | VoiceButton | Voice-only launcher — AiButton + inner VoiceWidget | | VoiceMicButton | Inline mic toggle inside the voice panel (not the floating launcher) |

AiButtonProps          AiWidgetProps (type-only)
     │                        │
ChatButton ──► ChatWidget     VoiceButton ──► VoiceWidget
                    │                              │
              useAgentChat                   useAgentVoice

Which component should I use?

| Your goal | Component | |-----------|-----------| | Chat embedded in your page | ChatWidget | | Floating chat launcher | ChatButton | | Voice embedded in your page | VoiceWidget | | Floating voice launcher | VoiceButton |

Rule of thumb: use *Widget when you already have a place in your layout. Use *Button for a fixed launcher that opens a panel.


Chat

Inline — ChatWidget

<ChatWidget
  agentName="my_agent"
  agentKey={import.meta.env.VITE_AGENT_KEY}
  size="medium"
  placeholder="Ask anything…"
/>

Built in automatically:

  • Agent logo, colors, title, and description from GET /details
  • Persistent chat session and streaming replies
  • Text, images, charts/HTML, and custom widget payloads

Floating launcher — ChatButton

Put panel options in chatWidgetProps (required). Launcher options stay on ChatButton.

<ChatButton
  type="circular"
  launcherPosition="bottom_right"
  panelPlacement="top_right"
  buttonSize="medium"
  chatWidgetProps={{
    agentName: "my_agent",
    agentKey: import.meta.env.VITE_AGENT_KEY,
    size: "medium",
    accentColor: "#2563eb",
  }}
/>

ChatButton creates an inner ChatWidget and shares one useAgentChat call — a single GET /details for launcher and panel.

Header launcher

<ChatButton
  type="header"
  headerPosition="bottom_right"
  headerSize="large"
  headerText="medium"
  chatWidgetProps={{
    agentName: "my_agent",
    agentKey: import.meta.env.VITE_AGENT_KEY,
    size: "medium",
  }}
/>

When type="header", the launcher bar acts as the header and the inner ChatWidget hides its own header automatically.

Shared client

import { AgentBazaar } from "@ola-krutrim/ai-sdk";

const client = new AgentBazaar({
  agentName: import.meta.env.VITE_AGENT_NAME,
  agentKey: import.meta.env.VITE_AGENT_KEY,
});

<ChatButton
  type="header"
  headerPosition="bottom_right"
  chatWidgetProps={{ client, size: "medium" }}
/>

Voice

Inline — VoiceWidget

<VoiceWidget
  agentName="my_agent"
  agentKey={import.meta.env.VITE_AGENT_KEY}
  size="medium"
  defaultConnect={false}
  onVoiceError={(error) => console.error(error)}
/>

Tap VoiceMicButton (mic in the panel) to start a session. A waveform appears when agent audio is live. Tap again to hang up.

Floating launcher — VoiceButton

<VoiceButton
  type="circular"
  launcherPosition="bottom_right"
  voiceWidgetProps={{
    agentName: "my_agent",
    agentKey: import.meta.env.VITE_AGENT_KEY,
    size: "medium",
  }}
/>

Same launcher options as ChatButton (type, launcherPosition, headerPosition, sizes, etc.) — passed on VoiceButton; agent config in voiceWidgetProps.

Voice dev proxy

For local dev when the app and API run on different ports, use voiceAuth="proxy" and proxy /api/v1/voice/embed so your dev server adds the Bearer token:

// vite.config.ts (example)
server: {
  proxy: {
    "/api/v1/voice/embed": {
      target: "http://127.0.0.1:8000",
      ws: true,
      changeOrigin: true,
      configure: (proxy) => {
        proxy.on("proxyReqWs", (proxyReq) => {
          proxyReq.setHeader("Authorization", `Bearer ${process.env.VITE_AGENT_KEY}`);
        });
      },
    },
  },
},

Chat and voice on the same page

Each component has its own session (separate GET /details per component):

const agent = {
  agentName: "my_agent",
  agentKey: import.meta.env.VITE_AGENT_KEY,
};

<>
  <ChatWidget {...agent} size="large" />
  <VoiceButton
    type="header"
    headerPosition="bottom_right"
    voiceWidgetProps={{ ...agent, size: "medium" }}
  />
</>

Launcher behavior (defaultOpen, minimizeKill)

Applies to ChatButton and VoiceButton:

<ChatButton
  type="header"
  headerPosition="bottom_left"
  defaultOpen={true}
  minimizeKill={false}
  chatWidgetProps={{ agentName: "my_agent", agentKey: "…", size: "medium" }}
/>

| Prop | What it does | |------|----------------| | First click | Session starts only after the user clicks the launcher — even if defaultOpen is true. | | defaultOpen | Panel appears open on load; user still clicks once to start chatting / voice. | | minimizeKill={false} | Close hides the panel; session keeps running. | | minimizeKill={true} (default) | Close ends the session (unmounts the inner widget). |


Hooks (headless / custom UI)

Use hooks when you build your own layout but want SDK session logic:

import { useAgentChat, useAgentVoice } from "@ola-krutrim/ai-sdk/react";

const chat = useAgentChat({
  agentName: "my_agent",
  agentKey: import.meta.env.VITE_AGENT_KEY,
});

const voice = useAgentVoice({
  agentName: "my_agent",
  agentKey: import.meta.env.VITE_AGENT_KEY,
});

Pass pre-loaded state into widgets to avoid duplicate setup:

const chat = useAgentChat({ agentName, agentKey });

<ChatWidget agentName={agentName} agentKey={agentKey} chat={chat} />
<ChatButton chatWidgetProps={{ agentName, agentKey, chat }} />

Same pattern for voice on VoiceWidget / VoiceButton.


Props reference

Shared — AiWidgetProps

| Prop | Type | Description | Default | |------|------|-------------|---------| | Connection | | client | AgentBazaar | Pre-built SDK client | — | | agentName | string | Agent identifier | — | | agentKey | string | API key (Bearer token) | — | | apiBase | string | API host | SDK default | | Layout & look | | size | AiWidgetSize | Panel preset | "medium" | | width / height | string | Dimension overrides | From size | | className / style | — | Root styling | — | | hideHeader | boolean | Hide header bar | false | | showDescription | boolean | Show subtitle | true | | headerColor, logoUrl, title, subtitle, accentColor, backgroundColor, textColor, borderRadius, fontFamily | string | Branding overrides | From agent |

Panel size presets:

| Size | Width | Height | |------|-------|--------| | small | 320px | 440px | | medium | 380px | 520px | | large | 440px | 600px | | extralarge | 520px | 680px |

Set width or height explicitly to override (e.g. width="100%").

Chat-only — ChatWidgetProps

Extends AiWidgetProps:

| Prop | Type | Default | |------|------|---------| | stream | boolean | true | | openingMessages | string[] | From agent | | disableWhileLoading | boolean | true | | placeholder | string | "Type a message…" | | userBubbleColor / agentBubbleColor | string | Theme defaults | | renderWidget / renderHtml / visualization | — | Built-in renderers | | onError / onSessionId | function | — | | chat | UseAgentChatResult | Internal — pass to share state with ChatButton | | supportedMultimedia | SupportedMultimediaKind[] | Widget prop — e.g. ["Image", "Pdf"]; omit/[] = no attachments | | maxMediaAttachments | number | 7 (max 7) | | uploadMedia | (file, type) => Promise<string> | Optional — defaults to §4 upload with agent_key |

Chat attachments (multimedia)

Pass supportedMultimedia on ChatWidget (or chatWidgetProps on ChatButton). The SDK does not read this from GET /details — you configure it in your app.

<ChatWidget
  agentName="my_agent"
  agentKey={agentKey}
  supportedMultimedia={["Image", "Pdf"]}
  maxMediaAttachments={5}
/>

When the array is non-empty, the 📎 button appears beside Send. Upload runs automatically with agent_key (presigned URL flow). Optional uploadMedia only if you use custom storage.

Voice-only — VoiceWidgetProps

Extends AiWidgetProps:

| Prop | Type | Default | |------|------|---------| | voiceEnable | boolean | From agent details | | defaultConnect | boolean | false | | voiceUserId | string | — | | voiceMetadata | object | — | | voiceWsUrl | string | Auto | | voiceAuth | "query" \| "proxy" | "query" | | recorderSampleRate / playerSampleRate | number | SDK default | | onVoiceError | function | — | | voice | UseAgentVoiceResult | Internal — pass to share state with VoiceButton |

Launcher — AiButtonProps

Used by ChatButton and VoiceButton:

| Prop | Type | Default | |------|------|---------| | type | "circular" \| "header" | "circular" | | launcherPosition | AiPanelPlacement | "bottom_right" | | panelPlacement | AiPanelPlacement | "top_right" | | headerPosition | "bottom_left" \| "bottom_right" | "bottom_right" | | panelGap | number | 12 | | defaultOpen | boolean | false | | minimizeKill | boolean | true | | buttonSize / headerSize / headerText | AiWidgetSize | "medium" | | zIndex | number | 9999 | | showDescription | boolean | true | | chatWidgetProps | ChatWidgetProps | Required on ChatButton | | voiceWidgetProps | VoiceWidgetProps | Required on VoiceButton |

Placement values (AiPanelPlacement): top_left, top_right, top_center, bottom_left, bottom_right, bottom_center, left_center, right_center

Launcher size presets (circular button / header dock width):

| Size | Button | Header dock | |------|--------|-------------| | small | 44px | 280px | | medium | 56px | 360px | | large | 72px | 440px | | extralarge | 88px | 520px |

headerText controls logo, title, subtitle, and padding inside the header bar (independent of headerSize).

ChatButtonProps / VoiceButtonProps

interface ChatButtonProps extends AiButtonProps {
  chatWidgetProps: ChatWidgetProps; // required
}

interface VoiceButtonProps extends AiButtonProps {
  voiceWidgetProps: VoiceWidgetProps; // required
}

Other exports

From @ola-krutrim/ai-sdk/react:

| Export | Purpose | |--------|---------| | AiButton | Launcher shell for custom compositions | | useAgentChat / useAgentVoice | Headless session hooks | | VoiceMicButton, VoiceSessionView, VoiceWaveform | Voice UI building blocks | | HtmlVisualization, AgentTurnBubble, DefaultWidget | Rich message rendering | | resolveTheme, groupMessages | Theming and message helpers |

Core HTTP client (no React):

import { AgentBazaar } from "@ola-krutrim/ai-sdk";

Breaking changes (chat/voice split)

| Before | After | |--------|-------| | Voice props on ChatWidget (voiceEnable, defaultMode, …) | Use VoiceWidget / VoiceButton | | Flat props on ChatButton | chatWidgetProps required | | VoiceButton = inline mic | VoiceMicButton (launcher is now VoiceButton) | | — | New: VoiceWidget, AiButton, AiWidgetProps, AiButtonProps |

Deprecated type aliases (still exported): ChatButtonSize, ChatWidgetSize → use AiWidgetSize; ChatButtonType → AiButtonType; ChatPanelPlacement → AiPanelPlacement.


Environment variables

VITE_AGENT_NAME=my_agent
VITE_AGENT_KEY=your-agent-key
VITE_API_BASE=https://your-api-host.com   # optional
VITE_VOICE_PROXY=true                     # optional — use proxy auth in dev

Never expose the agent key in client code unless your deployment model allows it; use a server-side proxy or embed tokens when required.


Playground

See the react_test app in this monorepo for a live prop explorer with Chat / Voice nav and widget vs launcher toggle.


License

MIT