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

research-agent-ui

v0.1.93

Published

Chat research agent UI: conversation window, article reader, search config, file uploads, and chat history

Readme

research-agent-ui

Chat research agent UI: conversation window, article reader, search config, file uploads, and chat history for QwkSearch-style apps. Includes the shadcn primitives and icons the components depend on, so it can be dropped into a Next.js app with a single dependency.

img1

Usage

import {
  ChatProvider,
  SessionProvider,
  ExtractPanelProvider,
  ChatWindow,
  configureResearchAgentUI,
} from 'research-agent-ui';

configureResearchAgentUI({
  appName: 'MyApp',
  getAutoMediaSearch: () => true,
  // ...see ResearchAgentUIConfig for the full list of overridable values
});

function App() {
  return (
    <SessionProvider authClient={myAuthClient}>
      <ExtractPanelProvider>
        <ChatProvider>
          <ChatWindow />
        </ChatProvider>
      </ExtractPanelProvider>
    </SessionProvider>
  );
}

Storybook

Individual UI pieces can be browsed in isolation with Storybook. Stories render against mock data only (see src/stories/mocks.ts) — no API, auth session, or chat backend is required, so you can develop and review the chat components (message header with timestamp/copy/edit actions, search progress, follow-up suggestions, file & pasted-content cards) on their own.

# from packages/research-agent-ui
bun run storybook        # dev server on http://localhost:6006
bun run build-storybook  # static build → storybook-static/

A light/dark toggle in the toolbar switches between the two token palettes (mirrored from the host app's globals.css in .storybook/preview.css). Add new stories next to their component as *.stories.tsx.

API Routes (research-agent-ui/api)

All 25 Next.js route handlers are exported from the research-agent-ui/api subpath as factory functions. Each factory accepts a deps object that injects your app's database, auth helpers, and other services, so the same handler logic works in any Next.js project without hard-coding any imports.

How it works

The route logic lives in packages/research-agent-ui/src/api/handlers/. Your app's app/api/agent/*/route.ts files become thin wrappers that call the factory and re-export the HTTP method handlers.

Step 1 — install / workspace link

If you are in this monorepo, research-agent-ui is already linked via the workspace:* protocol. For an external project, install the published package:

npm install research-agent-ui
# or
bun add research-agent-ui

Step 2 — create your route files

For each API path, create a route.ts that calls the matching factory and passes in your app's dependencies. Every factory is named create<RouteName>Handler and is exported from research-agent-ui/api.

Example: app/api/agent/chats/route.ts

import { createChatsHandler } from "research-agent-ui/api";
import { getDB } from "@/lib/database";
import { chats, messages } from "@/lib/database/schema";
import { requireUserId } from "@/lib/auth/session";

const handler = createChatsHandler({
  getDB,
  requireUserId,
  schema: { chats, messages },
});
export const { GET, DELETE } = handler;

Example: app/api/agent/article-followups/route.ts

import { createArticleFollowupsHandler } from "research-agent-ui/api";
import { getUserId } from "@/lib/auth/session";
import { getDB } from "@/lib/database";
import { user as userSchema } from "@/lib/database/schema";
import { getEnv } from "@/lib/env";

export const POST = createArticleFollowupsHandler({
  getUserId,
  requireUserId: async () => {
    const id = await getUserId();
    if (!id) throw new Error("Unauthorized");
    return id;
  },
  getDB,
  userSchema,
  getEnv,
});

All available factories and their dep shapes

| Factory | File | Required deps | |---|---|---| | createArticleFollowupsHandler | article-followups | getUserId, requireUserId, getDB, userSchema, getEnv | | createArticleQAHandler | article-qa | getUserId, requireUserId, getDB, userSchema, getEnv | | createChatsHandler | chats | getDB, requireUserId, schema.chats, schema.messages | | createChatByIdHandler | chats/[id] | getDB, requireUserId, schema.chats, schema.messages | | createChatsSearchHandler | chats/search | getDB, requireUserId, schema.chats, schema.messages | | createChatsShareHandler | chats/share | getDB, requireUserId, schema.chats, schema.messages | | createMessagesHandler | messages | getDB, requireUserId, messagesSchema | | createProvidersHandler | providers | getSession | | createProviderByIdHandler | providers/[id] | (none) | | createProviderModelsHandler | providers/[id]/models | (none) | | createMCPServersHandler | mcpservers | configManager, getConfiguredMCPServers | | createMCPServerByIdHandler | mcpservers/[id] | configManager, getConfiguredMCPServers | | createMCPServerToggleHandler | mcpservers/[id]/toggle | configManager, getConfiguredMCPServers | | createSearchHandler | search | searxngDomain? (default: https://search.qwksearch.com) | | createDiscoverHandler | discover | (none) | | createAutocompleteHandler | autocomplete | (none) | | createSuggestionsHandler | suggestions | (none) | | createAgentsHandler | agents | getUserId, requireUserId, getDB, userSchema, getEnv | | createRewriteHandler | rewrite | getEnv, generateText, createGroq | | createVoiceHandler | voice | getUserId, checkTTSRateLimit, generateSpeech | | createTranscriptHandler | transcript | getCloudflareContext | | createTestModelsHandler | test-models | (none) | | createValidateOpenRouterHandler | validate-openrouter | validateOpenRouterModels |

Dep type definitions

All dep interfaces are exported from research-agent-ui/api:

import type {
  ArticleDeps,
  ChatsDeps,
  MessagesDeps,
  ProvidersDeps,
  MCPServersDeps,
  SearchDeps,
  VoiceDeps,
  TranscriptDeps,
  RewriteDeps,
  ValidateOpenRouterDeps,
  AgentsDeps,
} from "research-agent-ui/api";

The chat route

POST /api/agent/chat is not migrated into this package because it delegates to a full handleChatRequest orchestrator that is app-specific (streaming, search integration, database writes). Keep it directly in your app:

// app/api/agent/chat/route.ts
import { handleChatRequest } from "@/lib/chat";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export const POST = handleChatRequest;

Configuration

configureResearchAgentUI overrides app-specific values (branding strings, the Google API key used by the Drive picker, and the auto-media-search toggle) that would otherwise couple this package to a specific app. See ResearchAgentUIConfig in src/config.ts for the full list.