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

@uiresponse/agui-client

v0.2.0

Published

The validating AG-UI client: consumes any AG-UI backend; renders UIR payloads with validation before paint; degrades honestly on foreign backends.

Readme

@uiresponse/agui-client

The validating AG-UI client. Connect it to any AG-UI agent and it renders the run: streamed text as prose, shared state as data — and when the backend is a UIR server, the full generated interface, schema-validated block by block before anything paints.

It is an ordinary AG-UI client in every way that matters: it consumes the standard event vocabulary (RUN_*, TEXT_MESSAGE_*, TOOL_CALL_*, STATE_SNAPSHOT/STATE_DELTA with RFC 6902 patches, MESSAGES_SNAPSHOT, STEP_*) over the reference HTTP + SSE transport, and it tolerates vocabulary it does not know. What no other client in the ecosystem does: when a backend carries UIR's validated-UI payloads — namespaced uir.* custom events riding beside the standard state — this client draws them as live, data-bound interface, with the validation verdicts the backend streamed per block. No verdicts, no tiles. That is the whole contract.

Package name and status are pre-rename working names; not yet published. Wire shapes are coded against @ag-ui/core 0.0.57, the same pin as the UIR server's translation module.

Install

npm install @uiresponse/agui-client   # after first publish; in this repo it resolves workspace-locally

React ≥18 is an optional peer — skip it entirely if you only use the headless core.

Quick start (React)

Point <AguiRun> at an AG-UI endpoint and give it an ask:

import { AguiRun, makeUirResolve } from "@uiresponse/agui-client";
import "@uiresponse/agui-client/styles.css";
import "@uiresponse/renderer-react/styles.css"; // dresses the UIR rendering, when a run earns it

export default function Answer() {
  return (
    <AguiRun
      endpoint="/v1/agui"
      ask="how is the next release tracking?"
      resolve={makeUirResolve()} // UIR backends: datasets resolve by page id against /v1/resolve
    />
  );
}

Against an UIR backend (any uir server exposes /v1/agui) you get the product behavior over the standard wire: prose first, then the interface assembling skeleton-first on a ~480ms reveal beat, per-block validation ticks, narration valued from real rows, and a closing line that waits for the content it closes. Rows never ride the AG-UI stream — blocks carry queries and bindings, and resolve fetches rows out of band (that is makeUirResolve, or your own data plane).

Against a foreign backend — one that has never heard of UIR — the same component renders the run honestly: streamed messages as prose, tool calls and steps as activity lines, the shared state object as data. It never crashes on unknown vocabulary and never dresses unvalidated state up as interface. If your agent's state happens to contain a page key — even a perfect imitation of an UIR document, even alongside non-verdict uir.* events — you still get the plain state view: the bar for drawing a tile is that block's own streamed verdict, nothing less.

<AguiRun> props

| Prop | Type | What it does | | --- | --- | --- | | endpoint | string | The AG-UI run endpoint (POST + SSE). Required. | | ask | string | The user's ask. A new value starts a new run; the previous run aborts. | | messages | array | Optional RunAgentInput-style history, sent in the request body. | | threadId | string | Optional thread continuity, sent in the request body. | | body, headers, fetchImpl | | Extra body fields, extra headers, injectable fetch. | | resolve | ({page, dataset, params, signal}) => Promise<{rows, columns?}> | The one data surface for UIR runs. Without it, tiles state the omission — they never fake rows. | | theme, params | | Passed through to the UIR renderer (brand tokens; url/session params). | | onFinished | (state) => void | After the stream closed and every reveal actually landed. | | onError | (error) => void | Transport/HTTP failures. Protocol RUN_ERRORs land in state instead. |

Quick start (headless — no React)

import { consumeAguiRun, uirView } from "@uiresponse/agui-client/core";

const state = await consumeAguiRun({
  endpoint: "http://localhost:8787/v1/agui",
  ask: "show me every artist and their pipeline stage as a table",
  onEvent: (event, state) => console.log(event.type),
});

const view = uirView(state);
if (view.mode === "uir") {
  // a validated UIR document: view.page, view.narration, view.validated
} else {
  // prose in state.messages/state.timeline, tools in state.toolCalls, data in state.state
}

consumeAguiRun resolves with the final run state; onEvent/onState fire per event, in order. A stream that closes without RUN_FINISHED settles as a truncation error rather than hanging running: true. Everything the wire said is kept: unknown custom events are counted, tool calls and steps collected, and a JSON Patch this client cannot apply degrades to "last good state + patchError" — the UIR adapter's convergence snapshots repair exactly this.

What "validating" means here

A UIR backend schema-checks every block at generation time, as it streams — and publishes the verdicts on the wire as uir.block_verdict custom events, with repair rounds (uir.round, uir.block_repaired) on the record. This client is verdict-aware, not a second validator: it does not re-run schema checks in the browser; it renders exactly the claims the backend streamed, and no claim it did not. Concretely:

  1. it assembles the interface from the standard AG-UI state events (snapshot + RFC 6902 deltas), so any generic client sees the same document;
  2. a tile draws only when its own block's verdict was streamed — per block, no defaults, no inheritance from the run looking UIR-ish;
  3. the page-level validated flag (the renderer's green tick) is stricter still: a UIR document, every page block covered by a verdict, every verdict ok, the run finished clean;
  4. it reflects the backend's honesty about failure: a failed validation round arrives as a reset snapshot (AG-UI has no un-paint), and this client withdraws the blocks — and their verdicts — rather than leaving a stale answer or stale coverage on screen.

The missing-verdict cases, precisely

| Case | What happened | What this client does | Why | | --- | --- | --- | --- | | No verdicts at all | The state carries a UIR-shaped document but no uir.block_verdict ever arrived — a foreign imitation, or a middlebox stripped the Customs. Non-verdict uir.* events (ack, status) don't change this. | Plain data view. No tiles. | The verdict vocabulary is the opt-in; the verdict is the claim being rendered. Shape is not a claim. | | Partial coverage | Some blocks have verdicts, later ones don't (truncated stream, translator gap). | Draws only the covered blocks; reports the rest as withheld (the React surface says so on screen); validated is false. | The covered blocks' claim is true of them regardless of the tail, and withdrawing a true answer punishes the user for a transport fault. But a partially-covered answer must not wear the whole-answer tick. | | Ordering skew | A verdict arrives before its block's state delta (proxied wires may interleave). | Buffered by block id; covers the block when it lands. A verdict for a block that never arrives covers nothing. | Which frame landed first is the transport's business; "this block was validated" doesn't depend on it. | | Repaint after a failed round | The un-paint snapshot withdraws the blocks; round 2 re-streams them. | The verdict ledger clears with the un-paint — a repainted block must earn a fresh verdict. | Round 1's paperwork must not cover round 2's content. |

Every row is a test in tests/ (cases labeled (a)/(b)/(c)), with the UIR fixtures produced by the shipping server-side translator.

API

| Export | From | What it is | | --- | --- | --- | | AguiRun, makeUirResolve | . | The React surface. | | consumeAguiRun | . or ./core | POST + SSE → reduced run state. | | emptyAguiRun, reduceAguiEvent | . or ./core | The pure reducer, one AG-UI event at a time. | | uirView | . or ./core | (state) => { mode: "uir"\|"plain", page, narration, validated } — what the run has earned. | | revealTypeFor | . or ./core | Beat classification for the reveal pacer (presentation policy, not wire semantics). | | applyJsonPatch | . or ./core | RFC 6902, all six ops, atomic. |

Testing

npm test

The suite runs two backends through the reducer: real UIR wire fixtures produced by the shipping server-side translator (so a translator change that would break this client breaks the suite first), and a synthetic foreign agent speaking the documented shapes this repo never emits — token-delta text, streamed tool-call args, move/copy/test patches, MESSAGES_SNAPSHOT. The transport tests deliver SSE in 3-byte chunks, because a TCP boundary owes the client nothing.