
Security News
npm Tooling Bug Incorrectly Marks One-Character Packages as Security Holders
npm confirmed a tooling bug incorrectly marked several one-character packages as security holders and said it was working on a rollback.
@page-speed/agent-everywhere
Advanced tools
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
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:
motion + lucide-react; no next/*
imports. Works in Next.js (App or Pages Router), Vite, Remix, CRA, etc."use client" for React Server Component frameworks.pnpm add @page-speed/agent-everywhere
Provided by the consuming app (versions are intentionally wide so the package slots into existing projects):
| Package | Range |
|---|---|
react / react-dom | `^18.2 |
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.
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 />}
/>;
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 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:
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}.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.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.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.useAgentWorkspace() exposes
toggleLeftPanel, setRightPanelOpen, openConversation,
closeConversation, and friends for dynamic layout scenarios.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)}
/>;
Components an agent can render inside responses, grouped by category. All are prop-driven and individually importable:
ChartContainer, MetricsGrid, DataTable,
ProgressTracker, SentimentDisplay, MediaGallery, AllocationBreakdown,
AnalyticsDashboard, ReportView.EntityCard, OptionCards, ListingFeed, ControlGrid,
RecommendationCards, ScheduleTimeline, SettingsPanel, AgentHandoff,
ConfirmationPanel, PersonaSelector.MessageList, MessageWithReasoning, MessageWithSteps,
MessageWithFeedback, MessageWithAttachments, ConversationArtifact.PromptInput, MultimodalInput, QuickReplies,
TemplateSelector, InlineSuggestionsInput, FileDropZone, PromptLibrary.ImageGenerator, WritingAssistant, OnboardingWizard,
QuizCard, GuidedLessonFlow, MediaEditorCanvas.The transport layer speaks a small, camelCase WebSocket envelope protocol for
streaming chat: assistant_message_start → *_delta / *_thinking_delta →
assistant_message_blocks → assistant_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).
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();
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 } }} />;
pnpm install
pnpm type-check
pnpm test
pnpm build
UNLICENSED — private package. Distributed for use within OpenSite/Toastability applications.
FAQs
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
We found that @page-speed/agent-everywhere demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
npm confirmed a tooling bug incorrectly marked several one-character packages as security holders and said it was working on a rollback.

Research
/Security News
Newer packages in this compromise use native extensions and .pth loaders to execute JavaScript stealers in developer environments.

Research
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.