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

@aginies/webuikit

v0.7.0

Published

Aginies web UI kit: React components and widgets that embed platform agents into any site

Readme

@aginies/webuikit

React components and widgets that embed Aginies agents into any site: the hosted chat as a bubble, an inline panel or a full page, plus the core primitives of the Aginies design system. The package is public; rendering requires an activation token issued for your deployment, and the platform only answers origins listed in its configuration.

npm install @aginies/webuikit react react-dom

Quick start

import { init, AginiesProvider, ChatWidget } from '@aginies/webuikit'
import '@aginies/webuikit/styles.css'

init({ baseUrl: 'https://app.your-aginies.example', token: 'agn_…', locale: 'tr' })

export function App() {
  return (
    <AginiesProvider>
      <ChatWidget identifier='support' mode='bubble' />
    </AginiesProvider>
  )
}

init() runs the activation handshake (POST /api/ui/activate) once. Until it succeeds the provider renders its fallback; if the platform refuses the token or the origin, nothing renders and one warning is logged.

Hosted pages

The platform's own chat page runs the same widget without a key: new AginiesClient({ baseUrl, hosted: true }) (or init({ baseUrl, hosted: true })). The platform accepts that activation only from its own origin.

Activation keys

Two kinds of token work with init():

  • Tenant keys (agn_pk_…) are created per tenant in the platform's admin console (tenant page, "UI package keys"), each with its own list of allowed origins (https://www.example.com, https://*.example.com or * for development), an optional module list and an optional expiry. The key is publishable: it identifies the tenant and unlocks nothing on its own. A successful activation returns a one-hour session that the client sends as Authorization: Bearer … on every platform call and renews on its own when it expires. Only the tenant's own chats can be reached through it, and only the modules the key enables render; the rest render nothing and log one warning. client.getSession() and client.hasModule('chat') expose both, and useModule('run') does the same inside components.
  • The static key from the platform's UI_PACKAGE_ACTIVATION_KEY works for origins listed in UI_PACKAGE_ALLOWED_ORIGINS. No session is involved: those origins are trusted by configuration. Meant for the platform's own sites and local development.

Platform configuration

| Variable | Purpose | |---|---| | UI_PACKAGE_ACTIVATION_KEY | The static activation token (optional when tenant keys are used). | | UI_PACKAGE_ALLOWED_ORIGINS | Comma-separated origins trusted without a tenant key (CORS, cookies, frame-ancestors). * for local development. | | INTERNAL_API_SECRET | Signs tenant sessions (already required by the platform). |

Components

  • ChatWidget — identifier, mode (bubble | inline | full), position, launcherLabel, theme (dark | light | auto). Streams replies, renders them as Markdown (headings, emphasis, code, links, lists, quotes, tables; never raw HTML), renders structured replies (text, buttons, table, cards, pie, image), lets visitors attach up to five files of 10 MB, and handles password and e-mail protected chats. E-mail protection follows the platform's two-step flow: the address receives a six-digit code, which the widget verifies.
  • Markdown — the same renderer on its own: <Markdown text={reply} />.
  • Voice — when the platform reports speech for the chat (voice: { stt, tts } in the chat configuration) and the browser can record, the composer gains a dictation button (the transcript lands in the draft) and a hands-free conversation: the widget listens, sends what it heard, reads the reply aloud and listens again; a tap interrupts. Recording uses the browser's recorder and transcription runs on the platform's own model, so it works in every browser and no audio leaves the platform. Turn it off with voice={false}.
  • useVoice({ identifier, onTranscript }) — the recorder and player on their own: state, level, startListening, stopListening, speak(text), stopSpeaking.
  • AgentRunner — workflowId, apiKey (an execute-scoped key for that agent only; it is visible to the page), fields (form spec) and onResult. Posts the form as the agent's input, streams text and steps, shows the final output. useAgentRun(workflowId, apiKey) for a custom UI.
  • useChat(identifier) — the same state for a custom UI: messages, send, stop, busy, authNeed, authenticate.
  • ApprovalPanel — workflowId, executionId (from the resume link a "Human in the Loop" block sends), optional contextId, onResumed. Shows what the agent proposes, renders the approver's form the block author configured (string, number, boolean, JSON, select), validates it and resumes the run; queued resumes are reported as such. useApproval(workflowId, executionId) for a custom UI; the approval module must be enabled on the key.
  • Observability (data-driven): StatTiles, SuccessHeatmap (per-agent success by day or hour, threshold-coloured), RunTimeline (steps on the run scale with tokens and cost), CostBars (cost by scenario, unit or channel).
  • Core: Button, Tag, Chip, Panel, Eyebrow, Stat, Field, Input, Textarea, Spinner.
  • Brand: AginiesMark and AginiesLoader, see below.
  • useChat(identifier) — the widget's state for a custom UI: messages, send(text, files), stop, authenticate({ password }), requestCode(email), verifyCode(email, code).
  • AginiesClient — the underlying client (activate, getChat, sendMessage as an async generator, getSession, hasModule, fetchRaw with the session attached).

Brand

AginiesMark is the Aginies mark as inline SVG (size in px, default 24; title for the accessible name, default "Aginies"; decorative hides it from assistive technology). It is the one place in the kit where the brand gradients appear; the mark is identical on dark and light ground and has no monochrome version. The site uses it between 22 and 44 px.

AginiesLoader is the brand loading state: the mark animated with CSS keyframes only, no timers. tier picks the size and placement: page (96 px, a full-viewport overlay with the wordmark and the label under it), region (40 px, centred in its container, default) or inline (16 px, in a line of text). variant picks the motion: orbit (default; the ring turns once per --motion-loader-spin, the diamond counter-turns in eased quarter pulses, the crescent breathes), pulse (the mark stands still, a --signal-soft halo beats behind it once per --motion-loader-pulse) or draw (the ring draws itself in half a spin, then the diamond, then both fade). Page and region tiers are a polite live region (role="status", aria-busy) named by label (default: the translated "Loading"); the inline tier is hidden from assistive technology unless it has a label. Under prefers-reduced-motion: reduce, or below an .agi-motion-reduce ancestor, the mark stands still with a slow two-step fade (and not even that inline). On screens up to 640 px the page tier drops to 72 px and every duration shortens by a quarter. demo/loader-variants.html shows the three variants side by side without a build step.

<AginiesProvider fallback={<AginiesLoader tier='page' label='Opening the console' />}>
  …
</AginiesProvider>

Theming

Styles come from @aginies/tokens (0.4.0 and later): light by default, .dark / [data-theme="dark"] on an ancestor (or the widget's theme prop) for the dark palette. With no theme set, the page follows the visitor's prefers-color-scheme; only when the browser reports no preference does the light palette apply (before 0.7.0 that fallback was dark). An embed that must always be dark passes theme="dark". Override --signal, --bg, --panel and friends on a wrapper to whitelabel.

A tenant's overrides can also travel with the activation: when the activation payload carries theme (a map of custom properties, { "--signal": "#0077C2", "--radius-md": "8px" }), AginiesProvider wraps its children in <div class="agi-root"> (display: contents, so it takes no space of its own) and sets the accepted entries on it. Accepted are keys that start with -- and values that are plain colours (hex, rgb() / hsl() / oklch() / oklab() with numeric arguments, colour keywords) or lengths (px, rem, em, %, vw, vh, unitless numbers). var(), url(), calc(), font stacks and anything else are dropped. themeVariables(theme) is the filter, exported for tooling.

Localisation

Widgets ship Turkish and English strings; locale on init() or AginiesProvider picks one. Replace individual strings with translations, by section and key:

<AginiesProvider locale='tr' translations={{ chat: { placeholder: 'Sorunuzu yazın…' } }}>

translator(locale, overrides?) builds the same function outside React; useAginies().t is the one the provider made, overrides included.