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

@page-speed/agent-everywhere

v0.8.0

Published

A composable, vendor-neutral UI engine for AI agent conversations — placements (panel, widget, overlay, fullscreen, split, mobile, native, workspace), rich artifacts (charts, tables, media, forms, multi-step flows), an orchestration manifest + registry, a

Readme

@page-speed/agent-everywhere

A composable, vendor-neutral UI engine for AI agent conversations. It ships the React building blocks an AI agent needs to render a conversation anywhere — across multiple placements and with a rich library of artifacts — plus a streaming WebSocket transport and an orchestration manifest/registry an agent can use to pick and render components at runtime.

The package is intentionally self-contained and host-agnostic:

  • No framework lock-in — pure React + motion + lucide-react; no next/* imports. Works in Next.js (App or Pages Router), Vite, Remix, CRA, etc.
  • No embedded backend — the transport layer contains no API origin and no route. The host application always supplies its own socket URL (typically from an environment variable), so nothing about any specific deployment is baked into this public package.
  • SSR-safe — browser-only access is guarded; the entry is marked "use client" for React Server Component frameworks.
  • Tree-shakable — ESM + CJS builds with full TypeScript types.

Installation

pnpm add @page-speed/agent-everywhere

Peer dependencies

Provided by the consuming app (versions are intentionally wide so the package slots into existing projects):

| Package | Range | | --- | --- | | react / react-dom | ^18.2 || ^19 | | motion | >=11 | | lucide-react | >=0.460 <2 | | recharts | >=2.13 <4 (optional — only needed for chart artifacts) | | @radix-ui/react-* | >=1.1 (avatar, collapsible, progress, scroll-area, slot, tooltip) |

Tailwind CSS (v3 or v4) is expected in the host app. Components use CSS-variable design tokens (bg-background, text-foreground, bg-primary, …) so they adopt the consumer's theme/skin automatically.

Placements

A single AgentSurface renders the same conversation into any layout — pick a mode and the messages, input, and data region flow into the matching container. There are no per-surface forks of the conversation logic.

| Mode | Container | Use | | --- | --- | --- | | panel | ChatPanel | Inline conversation embedded in a dashboard. | | widget | FloatingWidget | Embeddable launcher + chat (CMS, client sites, third-party pages). | | overlay | OverlayModal | Centered modal conversation. | | fullscreen | FullscreenDashboard | Full-screen chat + report sidebar. | | split | SplitView | Chat beside a live results/preview pane. | | mobile | MobileShell | Full-height mobile-optimized layout. | | native | NativeSurface | Host-placed, position-agnostic pieces — see Native variant. |

import { AgentSurface } from '@page-speed/agent-everywhere';

<AgentSurface
  mode="split"
  title="Page Designer"
  messages={messages}
  isLoading={isStreaming}
  inputValue={draft}
  onInputChange={setDraft}
  onSubmit={() => send(draft)}
  dataPanel={<LivePreview />}
/>;

Native variant

The native variant is unlike the other placements: it has no opinion on position. The agent's composer and conversation renderer are native, fully-customizable pieces the host places anywhere — a docked bottom bar, a pane, a modal, a dashboard card — and styles itself. The two pieces work disconnected from each other, and a provider lets them share one live session even when rendered in completely separate DOM regions.

Simple, controlled case — one component you position yourself:

import { AgentSurface } from '@page-speed/agent-everywhere';

<AgentSurface
  mode="native"
  messages={messages}
  isLoading={isStreaming}
  inputValue={draft}
  onInputChange={setDraft}
  onSubmit={() => send(draft)}
/>;

Decoupled case — one shared session feeding pieces in separate regions of the page. The composer sits idle at the bottom; once the user submits, the host swaps its own content for the conversation surface:

import {
  NativeAgentProvider,
  AgentComposer,
  AgentConversation,
  useNativeAgent,
} from '@page-speed/agent-everywhere';

function PagesDashboard() {
  return (
    <NativeAgentProvider
      // Host supplies the socket URL (or a resolver) — never hardcoded here.
      resolveSocketUrl={resolveSocketUrl}
      websiteId={websiteId}
      pageCategoryId="pages"
      connectionStrategy="lazy" // default: no socket until the first submit
    >
      <Content />
      {/* Place the composer anywhere — here, a docked bottom bar. */}
      <AgentComposer
        className="fixed inset-x-0 bottom-0 m-4"
        footer="Grounded in your connected sources."
      />
    </NativeAgentProvider>
  );
}

function Content() {
  const { isActive } = useNativeAgent();
  // The host owns the swap — render your own page until the agent is engaged.
  return isActive ? <AgentConversation /> : <PagesTable />;
}

Both AgentComposer and AgentConversation are dual-mode: inside a NativeAgentProvider they wire themselves to the shared session; given explicit value/onChange/onSubmit (composer) or messages (conversation) props they run fully controlled with no provider. For 100%-custom UI, read the session directly with useNativeAgent(). The connection is lazy by default (connectionStrategy="eager" to pre-connect on mount).

AgentWorkspace — the page-level AI layout wrapper

AgentWorkspace composes the native pieces into a full workspace layout: an optional left panel, the host's page content in a growing center column with the prompt composer docked at the bottom, an optional right panel, and a conversation layer that slides in over the center content when the shared session activates (and slides away on reset()).

import {
  NativeAgentProvider,
  AgentWorkspace,
  AgentWorkspacePanelToggle,
} from '@page-speed/agent-everywhere';

<NativeAgentProvider resolveSocketUrl={resolveSocketUrl} websiteId={id} pageCategoryId="pages">
  <AgentWorkspace
    className="h-dvh"
    leftPanel={<KnowledgePanel />}      // omit → no panel, no toggle
    rightPanel={<AnalyticsPanel />}     // widths via left/rightPanelWidth
    composerPlaceholder="Describe a site-wide change…"
    composerHint="Agents render live, interactive artifacts inline."
  >
    <YourPage />
  </AgentWorkspace>
</NativeAgentProvider>;

Every region is independently optional and controllable:

  • Workspace header is persistent across the page and conversation states so the chrome stays uniform: the left panel toggle, icon, title (conversationTitle), and status line on the left; headerActions (your page's primary action, e.g. a "+ New" button), the session reset, the conversation chevron, and the right panel toggle on the right. Override the status line with headerStatus (useful disconnected), or hide the bar with showHeader={false}.
  • Panels collapse/expand with a smooth width-collapse animation (the outer rail animates to 0 while the inner wrapper keeps its open width, so content clips out instead of reflowing). Uncontrolled by default; controlled via leftPanelOpen/onLeftPanelOpenChange (and the right-side equivalents). The header hosts a toggle at each end; opt into extra floating toggles with showPanelToggles, or place <AgentWorkspacePanelToggle side="…"/> in your own chrome. Panels are gated to lg: viewports.
  • Conversation layer auto-opens on the first submit (or activate()), can be minimized back to the page without ending the session (a "View conversation" chip appears in the dock), and accepts a custom node via conversation for decorated transcripts. Controlled via conversationOpen.
  • Composer dock renders AgentWorkspaceComposer — a pill input with an auto-growing textarea (Enter submits, Shift+Enter inserts a newline), an optional attach affordance (onAttach), and a circular send button. Pass composer={false} to drop it, a node to replace it, or onComposerSubmit to intercept submits.
  • Loading states: render <AgentWorkspaceSkeleton/> while the page's data loads — it mirrors the workspace geometry (panel rails, header, dock) with pulsing placeholders so the resolved layout doesn't shift. Pass children for a custom center skeleton, and leftPanel={false} / rightPanel={false} / composer={false} to match the page's configuration.
  • Programmatic control from anywhere inside: useAgentWorkspace() exposes toggleLeftPanel, setRightPanelOpen, openConversation, closeConversation, and friends for dynamic layout scenarios.

Inline confirmation / proposed-plan panels

Confirmation and proposed-plan panels flow inline in the transcript — attach one to a message via message.confirmation and it renders after that message's content, never pinned over the response. The plan body reuses the same markdown rendering and spacing as assistant messages, so long multi-paragraph / bulleted plans stay readable. Wire onConfirmAction (or use ConfirmationPanel directly) to handle the action buttons.

const messages = [
  {
    id: 'm1',
    role: 'assistant',
    content: 'Here is the response and the plan.',
    timestamp: new Date(),
    confirmation: {
      title: 'Proposed plan',
      summary: '3 pages to change',
      body: '## What changes\n\n- Rebuild the platform page\n- Refresh OG images',
      actions: [
        { id: 'apply', label: 'Apply changes' },
        { id: 'cancel', label: 'Cancel', variant: 'outline' },
      ],
    },
  },
];

<AgentSurface
  mode="widget"
  messages={messages}
  onConfirmAction={(messageId, actionId) => apply(messageId, actionId)}
/>;

Artifacts

Components an agent can render inside responses, grouped by category. All are prop-driven and individually importable:

  • Data displayChartContainer, MetricsGrid, DataTable, ProgressTracker, SentimentDisplay, MediaGallery, AllocationBreakdown, AnalyticsDashboard, ReportView.
  • InteractiveEntityCard, OptionCards, ListingFeed, ControlGrid, RecommendationCards, ScheduleTimeline, SettingsPanel, AgentHandoff, ConfirmationPanel, PersonaSelector.
  • MessagesMessageList, MessageWithReasoning, MessageWithSteps, MessageWithFeedback, MessageWithAttachments, ConversationArtifact.
  • InputPromptInput, MultimodalInput, QuickReplies, TemplateSelector, InlineSuggestionsInput, FileDropZone, PromptLibrary.
  • SpecialtyImageGenerator, WritingAssistant, OnboardingWizard, QuizCard, GuidedLessonFlow, MediaEditorCanvas.

Streaming transport

The transport layer speaks a small, camelCase WebSocket envelope protocol for streaming chat: assistant_message_start*_delta / *_thinking_deltaassistant_message_blocksassistant_message_complete, with an error envelope and a connection_ready handshake.

The package embeds no origin and no route. Supply your own socket URL (or a resolver). The path below is an illustrative placeholder — substitute the route your own backend exposes, ideally read from an environment variable.

useSemanticBuilder (drop-in hook)

import {
  useSemanticBuilder,
  buildSocketUrl,
} from '@page-speed/agent-everywhere';

function Designer({ websiteId, pageCategoryId, blocks, onBlocks }) {
  const conversation = useSemanticBuilder({
    // Host supplies the URL — never hardcode it in shared code.
    resolveSocketUrl: ({ websiteId, pageCategoryId }) =>
      buildSocketUrl(
        process.env.NEXT_PUBLIC_API_BASE_URL!, // e.g. https://api.your-app.example
        '/your/backend/route/{websiteId}/{pageCategoryId}/chat',
        { websiteId, pageCategoryId },
      ),
    websiteId,
    pageCategoryId,
    pageName: 'Home',
    blocks,
    enabled: true,
    onGeneratedBlocks: onBlocks,
  });

  const { messages, isStreaming, statusLabel, sendMessage } = conversation;
  // …render with <AgentSurface mode="split" … />
}

The hook returns { messages, connectionState, connectionError, statusLabel, isConnected, isStreaming, sendMessage, retry, reset } and manages connection lifecycle, reconnect with backoff, the streaming message state machine, hidden (background) requests, and block-extraction fallbacks. Pass seedWelcomeMessage: false to start with an empty transcript (the native variant does this for its idle composer).

Low-level client

For non-React hosts or custom integrations, use the client directly:

import { SemanticBuilderSocketClient } from '@page-speed/agent-everywhere';

const client = new SemanticBuilderSocketClient({
  websiteId: 42,
  pageCategoryId: 'home',
  socketUrl: makeYourWssUrl(), // host-provided
  onEnvelope: (e) => { /* handle assistant_* / blocks / complete / error */ },
  onStateChange: (s) => { /* idle | connecting | ready | streaming | error */ },
});
client.connect();

Orchestration

A data-only manifest describes every component an orchestrator (or LLM) can select, plus a runtime registry to resolve a manifest name to a real component.

import {
  registerAllComponents,
  componentManifest,
  findComponentsByCapability,
  DynamicRenderer,
} from '@page-speed/agent-everywhere';

registerAllComponents(); // once at startup

const [entry] = findComponentsByCapability('chart');
<DynamicRenderer instruction={{ component: entry.name, props: { data } }} />;

Local development

pnpm install
pnpm type-check
pnpm test
pnpm build

License

UNLICENSED — private package. Distributed for use within OpenSite/Toastability applications.