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

@vtex/agentic-ui

v0.4.6

Published

A comprehensive React/Next.js library for building AI agent interfaces with chat, canvas, and interactive components integrated with VTEX Raccoon.

Readme

@vtex/agentic-ui

A comprehensive React/Next.js library for building AI agent interfaces with chat, canvas, and interactive components integrated with VTEX Raccoon.

Overview

@vtex/agentic-ui provides a complete toolkit for creating an AI agent user interfaces within the VTEX ecosystem. It offers a standardized way to build conversational interfaces, display rich content, manage state, and integrate seamlessly with VTEX Admin applications.

Main Features

  • React Components - Pre-built components for chat, canvas, messages, threads, and tools
  • Composable Architecture - MessageComposer and other components use composition pattern for maximum flexibility
  • Agent Integration System - useAgentPlatform hook and createAgent() function for type-safe agent configuration
  • UI Protocol - Standardized communication layer between frontend and backend with automatic authentication
  • SSE Integration - Server-Sent Events with automatic reconnection, backoff, and connection management
  • State Management - Built-in hooks and utilities powered by Jotai
  • VTEX Admin Integration - Drop-in solution for admin application development with route-based agent loading
  • Tool Registry - Extensible system for custom tool rendering with canvas and inline modes
  • TypeScript Support - Full type safety across the entire library with Zod schema validation

Installation

pnpm add @vtex/agentic-ui@latest

Peer Dependencies

This package requires the following peer dependencies:

  • react >= 18.3
  • react-dom >= 18.3
  • next >= 14
  • @vtex/shoreline (latest)
  • @vtex/raccoon-next (latest)
  • @vtex/raccoon-analytics (latest)
  • @tanstack/react-table ^8.21.3
  • typescript >= 5

Documentation

| Guide | Description | |-------|-------------| | Components | Complete reference for all React components, hooks, and utilities | | UI Protocol | Communication protocol specification and data fetching hooks | | Server-Sent Events (SSE) | Real-time communication utilities with automatic reconnection | | Admin Integration | Integration solution for VTEX Admin applications | | Migration Guide | Step-by-step guide for migrating from 0.2.4 to 0.4.1 |

Quick Start

This example demonstrates how to set up a Next.js application with Raccoon and agentic-ui.

Step 1: Setup Application Root

Create your _app.tsx file with the necessary providers:

import type { AppProps } from "next/app";
import { useRouter } from "next/router";
import { connect, bootstrap, useAdmin } from "@vtex/raccoon-next";
import {
  ChatProvider,
  useAgentPlatform,
  AgenticUIProvider,
} from "@vtex/agentic-ui";
import { IntlProvider } from "react-intl";

// Import required styles
import "@vtex/shoreline/css";
import "@vtex/agentic-ui/css";

import { agents } from "../agents";
import { messages } from "../messages";

// Initialize Raccoon connection
connect();

function AppContent({ Component, pageProps }: AppProps) {
  const router = useRouter();
  // Load agent configuration based on current route
  const { isLoading, agent, error } = useAgentPlatform({
    agents,
    pathname: router.asPath,
  });

  const { locale = "en-US", account, token } = useAdmin();

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error || !agent) {
    return <div>Failed to load agent</div>;
  }

  return (
    <AgenticUIProvider
      agent={agent}
      locale={locale}
      account={account}
      token={token}
    >
      <IntlProvider
        locale={locale}
        messages={
          messages[locale as keyof typeof messages] ?? messages["en-US"]
        }
        defaultLocale="en-US"
      >
        <ChatProvider>
          <Component {...pageProps} />
        </ChatProvider>
      </IntlProvider>
    </AgenticUIProvider>
  );
}

function App(props: AppProps) {
  return <AppContent {...props} />;
}

export default bootstrap(App);

Step 2: Create an Agent Home Page

Create a page component that renders the initial chat interface at pages/app/[app]/index.tsx:

import { useState } from "react";
import { useIntl } from "react-intl";
import { useNavigation } from "@vtex/raccoon-next";
import {
  AgentHome,
  ChatLayout,
  MessageComposer,
  MessageComposerInput,
  MessageComposerTextarea,
  MessageComposerControls,
  MessageComposerSendButton,
  MessageComposerSuggestions,
  Suggestion,
  useAgenticUI,
  useChatContext,
  useResetAtoms,
  useStatus,
} from "@vtex/agentic-ui";

export default function AgenticPage() {
  const { reset } = useResetAtoms();
  const { agent } = useAgenticUI();
  const { formatMessage } = useIntl();
  const { stop, sendMessage, appSlug } = useChatContext();
  const { loading } = useStatus();
  const { navigate } = useNavigation();
  const [input, setInput] = useState("");

  const basePath = `/app/${appSlug}`;

  async function handleSendMessage() {
    const userContent = input.trim();
    setInput("");
    try {
      const { threadId } = await sendMessage({
        inputs: [{ type: "text", text: userContent }],
      });
      navigate(`${basePath}/${threadId}`);
    } catch (error) {
      console.error(error);
    }
  }

  return (
    <ChatLayout
      type="home"
      onThreadClick={(threadId) => {
        reset();
        navigate(`${basePath}/${threadId}`);
      }}
    >
      <div data-chat-container data-is-empty>
        <AgentHome
          title={formatMessage({ id: agent?.ui.title })}
          subtitle={formatMessage({ id: agent?.ui.subtitle })}
          name={formatMessage({ id: agent?.ui.name })}
        />

        <MessageComposer
          input={input}
          setInput={setInput}
          isLoading={loading}
          isEmpty
          onSend={handleSendMessage}
          onStop={stop}
        >
          <MessageComposerInput autoGrow>
            <MessageComposerTextarea />
            <MessageComposerControls>
              <MessageComposerSendButton />
            </MessageComposerControls>
          </MessageComposerInput>

          <MessageComposerSuggestions>
            {agent?.ui.promptSuggestions.map((prompt) => (
              <Suggestion
                key={formatMessage({ id: prompt.title })}
                title={formatMessage({ id: prompt.title })}
                description={formatMessage({ id: prompt.description })}
                promptText={formatMessage({ id: prompt.promptText })}
                requiresUrl={prompt.requiresUrl}
                requiresImage={prompt.requiresImage}
              />
            ))}
          </MessageComposerSuggestions>
        </MessageComposer>
      </div>
    </ChatLayout>
  );
}

Step 3: Create a Thread/Conversation Page

Create a page for ongoing conversations at pages/app/[app]/[threadId]/index.tsx:

import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { useNavigation } from "@vtex/raccoon-next";
import {
  ChatLayout,
  MessageComposer,
  MessageComposerInput,
  MessageComposerTextarea,
  MessageComposerControls,
  MessageComposerSendButton,
  MessageComposerFeedback,
  MessagesArea,
  useChatContext,
  useMessageIds,
  useResetAtoms,
  useStatus,
  useThreadId,
} from "@vtex/agentic-ui";

export default function ThreadPage() {
  const { stop, sendMessage, appSlug } = useChatContext();
  const { navigate } = useNavigation();
  const router = useRouter();
  const { threadId, setThreadId } = useThreadId();
  const { reset } = useResetAtoms();
  const { loading } = useStatus();
  const { messageIds } = useMessageIds();
  const [input, setInput] = useState("");

  const basePath = `/app/${appSlug}`;

  async function handleSendMessage() {
    const userContent = input.trim();
    setInput("");
    try {
      await sendMessage({ inputs: [{ type: "text", text: userContent }] });
    } catch (error) {
      console.error(error);
    }
  }

  // Sync threadId from router query
  useEffect(() => {
    if (!router.query.threadId || Array.isArray(router.query.threadId)) return;
    if (threadId === router.query.threadId) return;
    setThreadId(router.query.threadId);
  }, [router.query.threadId]);

  return (
    <ChatLayout
      type="thread"
      onNavigateBack={() => {
        reset();
        navigate(basePath);
      }}
      onThreadClick={(threadId) => {
        reset();
        navigate(`${basePath}/${threadId}`);
      }}
    >
      <div data-chat-container data-is-empty={false}>
        <MessagesArea
          messageIds={messageIds}
          error={null}
          isLoading={loading}
        />

        <MessageComposer
          input={input}
          setInput={setInput}
          isLoading={loading}
          isEmpty={false}
          onSend={handleSendMessage}
          onStop={stop}
        >
          <MessageComposerInput>
            <MessageComposerTextarea />
            <MessageComposerControls>
              <MessageComposerSendButton />
            </MessageComposerControls>
          </MessageComposerInput>
          <MessageComposerFeedback />
        </MessageComposer>
      </div>
    </ChatLayout>
  );
}

The useAgentPlatform hook automatically detects the agent based on the URL path, and the threadId parameter is used to load the specific conversation. The useThreadId hook manages the thread ID state and syncs with the router query parameter.

Step 4: Create Agent Configurations

Agents are configured in your consuming application (not in the library). Create agent configuration files in your agents/ folder. For example, create agents/my-agent.ts:

import { createAgent } from "@vtex/agentic-ui";

export default createAgent({
  slug: "my-agent",
  id: "MY_AGENT_ID",
  apiUrl: process.env.NEXT_PUBLIC_MY_AGENT_BASE_URL ?? "",
  routes: {
    frontend: "/app/my-agent",
    stream: "/api/agent/responses",
    tasks: "/api/agent/tasks",
  },
  settings: {
    enableFeedback: true,
    enableImageProcessing: false,
  },
  ui: {
    name: "My Agent",
    title: "My Agent Assistant",
    subtitle: "Help with custom operations",
    promptSuggestions: [
      {
        title: "Get Started",
        description: "Learn what I can do",
        promptText: "What operations can you help me with?",
      },
      {
        title: "Analyze Data",
        description: "Process and analyze your data",
        promptText: "Help me analyze my sales data",
      },
    ],
  },
});

Then create agents/index.ts to export all agents as an array:

import myAgent from "./my-agent";

export const agents = [myAgent];

Import and use this array in your _app.tsx (as shown in Step 1). The useAgentPlatform hook will match the current route to the appropriate agent configuration. For more details, see Admin Integration documentation.

Step 5: Start Development

pnpm dev

Your agent interface is now ready! Users can:

  • Start new conversations from the home page
  • Continue existing conversations via thread pages
  • Interact with tools and view rich content in the canvas
  • Navigate between different threads seamlessly

Useful Links

Development

Local Development

When developing the agentic-ui package, changes will automatically reflect in dependent applications like @ui/. Start the development mode with:

pnpm install
pnpm dev

This enables hot-reload, allowing you to see your changes immediately in any application that depends on this package.

Building

To build the package for production:

pnpm install
pnpm build

This compiles the TypeScript code and generates the distribution files in the dist/ directory.

Publishing

To publish a new version to npm, follow these steps (be sure to be in the root of the repository):

  1. Bump the version (choose patch, minor, or major):

    pnpm lerna version patch --force-publish
    # or
    pnpm lerna version minor --force-publish
  2. Publish to npm:

    pnpm lerna publish from-git

The version bump will create a git tag and update the package.json. Publishing from git ensures only tagged releases are published.