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

@ajentify/chat

v0.3.2

Published

React chat component and headless logic layer for the Ajentify token streaming server

Readme

@ajentify/chat

A React npm package that gives developers a fully headless logic layer (Zustand stores + hooks) and an optional UI (plain-CSS components built on Radix) for connecting to the Ajentify token streaming server.

v0.2 is a major release. It's frictionless out of the box: no Tailwind / typography-plugin requirement on the host, auto-injected styles, full-color theme tokens, and built-in helpers for the event client, server router, panel state, and typed client-side tools. See CHANGELOG.md for the migration steps.

Install

npm install @ajentify/chat
# or
pnpm add @ajentify/chat

That's it — the chat's stylesheet is auto-injected from <AjentifyProvider> on first mount. No import '@ajentify/chat/styles.css' line, no Tailwind setup on the host. (If you want SSR pre-paint, the file is still exported and can be imported manually.)

Quickstart

import { AjentifyProvider, createAjentifyEventClient } from '@ajentify/chat';
import { ChatPanel, ChatToggleButton } from '@ajentify/chat/ui';

const onAjentifyEvent = createAjentifyEventClient({
  url: '/api/ajentify-event',
  credentials: 'include',
});

export function App() {
  return (
    <AjentifyProvider config={{ onAjentifyEvent }}>
      <header>
        <ChatToggleButton label="Ask Aj" />
      </header>
      <ChatPanel desktopVariant="inline">
        <YourPages />
      </ChatPanel>
    </AjentifyProvider>
  );
}

The backend route /api/ajentify-event proxies every event variant to the Ajentify REST API with your org-scoped API key so it never reaches the browser:

// app/api/ajentify-event/route.ts (Next.js App Router)
import { createAjentifyEventRouter, toNextRouteHandler } from '@ajentify/chat/server';
import { cookies } from 'next/headers';

const handler = createAjentifyEventRouter({
  apiKey: process.env.AJENTIFY_API_KEY!,
  agentId: process.env.AJENTIFY_AGENT_ID!,
  getClientId: () => cookies().get('ajentify_client_id')?.value ?? null,
  setClientId: (_req, id) => cookies().set('ajentify_client_id', id, { httpOnly: true }),
});

export const POST = toNextRouteHandler(handler);

Express / Hono shims are exported alongside toNextRouteHandler from @ajentify/chat/server.

Hooks

import {
  useChat,
  useCurrentContext,
  useContexts,
  useContextHistory,
  useClientSideTools,
  useGetPageData,
  useDoPageAction,
  useChatPanel,        // v0.2: open/close the panel from anywhere
  useAjentifyConfig,
} from '@ajentify/chat';

useChat() is the convenience hook:

const { messages, send, status, agent, pendingResponse } = useChat();

useChatPanel() reads/writes the built-in panel state — pair it with <ChatToggleButton /> or roll your own button. Pass open / onOpenChange to <ChatPanel /> to take over manually.

Client-side tools

defineClientSideTools<TTools>(...) is a typed dispatcher that replaces the args.x as string | undefined casts every consumer was writing by hand:

import { defineClientSideTools } from '@ajentify/chat';

type Tools = {
  list_todos: { args: {}; result: Todo[] };
  navigate:   { args: { path: string }; result: { ok: boolean } };
};

const clientSideTools = defineClientSideTools<Tools>({
  list_todos: () => api.listTodos(),
  navigate:   ({ path }) => { router.push(path); return { ok: true }; },
});

<AjentifyProvider config={{ onAjentifyEvent, clientSideTools }}>

Missing handlers throw a descriptive AjentifyError and warn in dev.

Page-level tools

The agent can call two special tools — get_page_data and do_page_action — to read the current page and act on it. Mount these from any page:

useGetPageData(() => ({
  data: { selected_order_id: orderId },
  actions: {
    refund_order: {
      description: 'Refund the currently selected order',
      argsSchema: {
        type: 'object',
        properties: { amount: { type: 'number' } },
        required: ['amount'],
      },
    },
  },
}), [orderId]);

useDoPageAction(async (key, args) => {
  if (key === 'refund_order') {
    await refundOrder(orderId, args.amount as number);
    return { ok: true };
  }
  throw new Error(`unknown action: ${key}`);
}, [orderId]);

UI

Importing from @ajentify/chat/ui is optional — use the headless hooks if you want your own UI. If you want the bundled experience:

import {
  ChatPanel,
  ChatView,
  ChatHeader,
  ChatMessages,
  ChatInput,
  ChatToggleButton,
} from '@ajentify/chat/ui';

<ChatPanel /> is opinionated: slide-in from the right, draggable resize handle on desktop, full-screen sheet on mobile. <ChatView /> is the fill-parent variant if you want to drop it inside your own layout.

Starter prompts

Render 1–3 starter chips on the new-chat hero — clicking sends instantly:

<ChatPanel
  suggestedPrompts={['How does X work?', 'Show me my open orders']}
  newChatView={`Hey there, ${user.firstName}`}
/>

Mount behaviour

When <ChatView /> (or <ChatPanel />) mounts on a fresh session, it auto-calls startNewContext() so the user lands on a ready-to-type chat. The provider's agentSpeaksFirst flag is the only knob:

  • agentSpeaksFirst: false (default) — enters a local 'draft' state. No create_context call is made until the user sends their first message.
  • agentSpeaksFirst: true — eagerly calls create_context and opens the WebSocket so the agent can stream its greeting before the user types.

If the eager call fails, the chat falls back to a "Couldn't start a new chat — Try again" affordance and does not auto-retry. Customise it with the emptyState prop.

Theming

Every visual surface is themed through plain CSS custom properties under the --aj-* namespace. v0.2 ships them as full CSS colors (not HSL channels), so any color format works — oklch(...), #hex, rgb(...), hsl(...). Alpha modulation is done internally via color-mix(...).

:root {
  --aj-primary: oklch(0.55 0.18 270);
  --aj-radius: 1rem;
}
.dark {
  --aj-background: #0a0a0a;
  --aj-foreground: #fafafa;
}

Layout / spacing knobs are CSS variables too:

:root {
  --aj-panel-width: 480px;
  --aj-messages-padding-x: 1.5rem;
  --aj-messages-padding-y: 2rem;
  --aj-messages-gap: 1rem;
  --aj-bubble-padding-x: 1rem;
  --aj-bubble-padding-y: 0.625rem;
  --aj-bubble-radius: 1.25rem;
  --aj-prose-font-size: 0.9375rem;
}

shadcn / Radix Themes / Mantine bridge

Hand the chat your host's CSS variables — full colors pass through directly:

<AjentifyProvider config={{ onAjentifyEvent, themeBridge: 'shadcn' }}>

Or supply a custom map:

themeBridge={{
  tokens: {
    background: '--mantine-color-body',
    foreground: '--mantine-color-text',
    primary:    '--mantine-color-blue-6',
    border:     '--mantine-color-default-border',
  },
}}

Per-slot overrides

Every component still accepts a classNames prop for one-off tweaks; in most apps the CSS variables alone are enough.

SSR / Next.js

All components and hooks that touch browser APIs are marked "use client". Put <AjentifyProvider> inside a client component near the root. TokenStreamingClient, the types, and @ajentify/chat/server are server-safe.