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

ag-ui-validate

v0.4.0

Published

Conformance validator for the AG-UI protocol. Feed it an event stream, get every violation with a rule ID, a severity, and a link to the governing spec section.

Readme

ag-ui-validate

Conformance validator for the AG-UI protocol (Agent–User Interaction Protocol). Point it at an AG-UI endpoint — or feed it a recorded event stream — and it reports every way the stream violates the protocol, with a rule ID, a severity, a location, and a link to the governing spec section.

✖ AGUI203  error  event 42  TOOL_CALL_START id 'call_7' never terminated
✖ AGUI302  error  event 51  STATE_DELTA failed to apply: /items/3: '3' is not a valid index for an array of length 0
✖ AGUI503  error  event 60  Unknown event type 'runStarted' — did you mean 'RUN_STARTED'?
ℹ AGUI902  info   —         None of the 61 events carry the optional timestamp property

2 errors, 0 warnings, 1 info — 3 of 7 AG-UI features exercised

Status: released to both npm (npm install ag-ui-validate) and PyPI (pip install ag-ui-validate). Both packages version in lockstep — same rule catalog, same fixture corpus, byte-identical CLI; see Python below.

Why

AG-UI has SDKs and integrations, but no conformance tooling: nothing tells an implementer your stream is subtly wrong, here's the rule and the spec section. This project is that tool — the AG-UI analogue of what a2a-inspector is for A2A.

Three design commitments make it trustworthy:

  • Every diagnostic cites the spec. Each of the 46 rules carries a specUrl (and where possible an exact specQuote) pointing at the governing section of docs.ag-ui.com or the WHATWG SSE spec. Behaviour the spec doesn't clearly govern is reported at info severity at most, and logged in docs/spec-questions.md for filing upstream.
  • The validator never throws. Broken input is its input. Malformed JSON, unknown event types, hostile objects — all diagnostics, never exceptions (fuzz-tested against 50k hostile inputs).
  • False positives are treated as worse than false negatives. The rules are grounded in @ag-ui/core v0.0.59 and the current docs; where the two disagree, the SDK wins and the discrepancy is recorded.

Quickstart

npm install --save-dev ag-ui-validate

CLI

npx ag-ui-validate http://localhost:8000/agui   # live endpoint (POSTs a RunAgentInput)
npx ag-ui-validate run.jsonl                    # recorded stream (NDJSON/JSONL or SSE capture)
cat run.jsonl | npx ag-ui-validate -            # stdin

Exit codes: 0 clean, 1 findings at or above the --fail-on threshold (error by default, or warnings over --max-warnings), 2 tool failure. Timing-based transport rules are meaningless for recordings, so they are reported as skipped with a reason rather than risking false positives.

Useful flags (see --help for all):

| Flag | Effect | | --- | --- | | --json / --sarif / --junit | machine-readable report on stdout (SARIF 2.1.0 for code scanning, JUnit XML for CI) | | --group | one line per rule with a count — for large streams with repeated findings (totals stay exact) | | --rule AGUI105=error, --off AGUI902 | per-rule severity overrides | | --features shared-state,... | declare exercised features (enables e.g. AGUI305) | | --max-warnings 0 | fail CI on any warning | | --fail-on <error\|warning\|none> | severity that triggers a nonzero exit (default error; none for report-only runs) | | --header "Authorization: Bearer …", --timeout 30 | endpoint options |

Validate in CI (GitHub Action)

- uses: langport-dev/ag-ui-validate-action@v1
  with:
    target: http://localhost:8000/agui   # or a recorded .jsonl file
    sarif-file: agui.sarif               # optional: upload via codeql-action

The step fails on error-severity findings, writes a findings table (with a counts-by-category breakdown) to the job summary, annotates the PR inline with ::error/::warning for each finding, and exposes errors/warnings/info/sarif-path/report-path outputs — see langport-dev/ag-ui-validate-action.

Test your agent in Vitest

import "ag-ui-validate/vitest" // registers the matcher (put it in setupFiles)

it("streams a conformant run", async () => {
  const events = await captureRunEvents(myAgent) // however you record them
  expect(events).toBeValidAGUI()
})

The matcher takes an array of events (objects or JSON strings) or a whole JSONL capture as one string. Failures print each finding with its rule ID and spec link. Options mirror the validator: { features, severityOverrides, maxWarnings } — e.g. expect(events).toBeValidAGUI({ maxWarnings: 0 }) to fail on warnings too. The raw matcher function is also exported, so Jest users can expect.extend({ toBeValidAGUI }) themselves.

Validate recorded events (pure, runs anywhere)

import { createValidator } from "ag-ui-validate"

const v = createValidator({
  features: ["shared-state"],            // optional: enables feature-specific rules
  severityOverrides: { AGUI902: "off" }, // optional: tune or disable rules
})

for (const event of events) {
  // feed parsed objects or raw JSON strings — bad JSON is a diagnostic
  const diagnostics = v.feed(event)      // findings, as soon as detectable
}
v.finalize()                             // end-of-stream checks

const { diagnostics, summary, features, skipped } = v.report()

The core is a pure function over an event sequence: zero I/O, zero runtime dependencies, isomorphic across Node 22+, browsers, Deno, and Workers.

Validate a live endpoint

import { validateEndpoint } from "ag-ui-validate/transport"

const { report, status, eventCount } = await validateEndpoint(
  "http://localhost:8000/agui",
  {
    headers: { authorization: "Bearer …" },
    onDiagnostic: (d) => console.error(`${d.severity} ${d.rule} ${d.message}`),
  },
)

The transport layer POSTs a minimal RunAgentInput, consumes the SSE or NDJSON response, streams every frame through the core, and additionally evaluates the transport-level rules that recorded input can't exercise: SSE framing (including the classic missing-data:-prefix bug), Content-Type, keepalive gaps, buffered-not-flushed responses, and mid-run disconnects.

Render a report

The CLI's output formats are plain functions over a Report, importable for your own tooling:

import { formatReportSummary, toSarif, toJUnit } from "ag-ui-validate/report"

Diagnostic shape

{
  "rule": "AGUI203",
  "severity": "error",            // "error" | "warning" | "info"
  "message": "TOOL_CALL_START id 'call_7' never terminated",
  "eventIndex": 42,               // 0-based; -1 for end-of-stream findings
  "eventType": "RUN_FINISHED",    // optional
  "pointer": "/toolCallId",       // optional RFC 6901 pointer into the event
  "relatedEventIndex": 17,        // optional, e.g. the unterminated start
  "specUrl": "https://docs.ag-ui.com/concepts/events#tool-call-events"
}

Python

A native Python port ships in py/ — the same rule catalog, the same fixture corpus, and a CLI with byte-identical flags, error messages, and JSON/SARIF/JUnit output to the TypeScript one above. It's checked against the TypeScript implementation on every PR by Parity CI (see docs/TESTING.md for how, and docs/PYTHON-PORT-PLAN.md for the port's full milestone history).

pip install ag-ui-validate   # or "ag-ui-validate[transport]" for just the endpoint-validating extras

CLI

ag-ui-validate http://localhost:8000/agui   # live endpoint (POSTs a RunAgentInput)
ag-ui-validate run.jsonl                    # recorded stream (NDJSON/JSONL or SSE capture)
cat run.jsonl | ag-ui-validate -            # stdin

Same exit codes and the same flags as the CLI above (see ag-ui-validate --help) — the Python argument parser is a direct, hand-rolled port of the TypeScript one rather than argparse/click, specifically to keep both CLIs' invocation and error messages byte-for-byte identical.

Test your agent in pytest

from ag_ui_validate.pytest_plugin import assert_valid_agui

def test_my_agent_stream(captured_events):
    assert_valid_agui(captured_events, features=["shared-state"], max_warnings=0)

assert_valid_agui accepts a list of events (dicts or JSON strings) or a whole JSONL capture as one string, and raises AssertionError with every finding's rule ID and spec link on failure. It registers automatically as a pytest plugin on install — no conftest.py setup needed. An async counterpart validates a live endpoint directly from a test:

from ag_ui_validate.pytest_plugin import assert_valid_agui_endpoint

async def test_my_live_agent():
    await assert_valid_agui_endpoint("http://localhost:8000/agui", max_warnings=0)

assert_valid_agui has zero runtime dependencies; only the endpoint-validating helpers (assert_valid_agui_endpoint, validate_agui_endpoint) pull in httpx (pip install ag-ui-validate[transport]).

The rule catalog

46 rules, maintained as data in spec/catalog.json, shared by both implementations in this repo (TypeScript and Python) rather than duplicated. Every rule has its own page — spec grounding, rule index (generated from the catalog, drift-checked in CI):

| Group | IDs | Examples | |---|---|---| | Lifecycle | AGUI001–008 | run must start with RUN_STARTED, terminate with RUN_FINISHED/RUN_ERROR, nothing after a terminal event | | Text messages | AGUI101–106 | content without start, unterminated messages, duplicate messageId | | Tool calls | AGUI201–208 | unterminated calls, args that don't concatenate to valid JSON, results referencing unknown calls | | State | AGUI301–305 | RFC 6902 patch validity, deltas that fail to apply to reconstructed state | | Reasoning | AGUI401–402 | reasoning content without an open reasoning message | | Transport | AGUI501–508 | SSE framing, Content-Type, keepalive gaps, buffering, dropped connections | | Subagents | AGUI601–606 | duplicate/unmatched SUBAGENT_STARTED/FINISHED/ERROR, unterminated subagents, unknown parentSubagentRunId, continuation events that disagree with their entity's owner | | Hygiene | AGUI901–903 | RAW-wrapping typed events, missing timestamps, un-namespaced CUSTOM names |

The event taxonomy itself (36 wire types, field schemas) is derived from @ag-ui/core's own schemas and drift-tested against the installed SDK on every run.

The fixture corpus

spec/fixtures/ is a language-neutral conformance corpus: 7 valid streams (one per canonical AG-UI feature — the false-positive guards) and 46 invalid fixtures (one per rule) with exact expected diagnostics. Any validator implementation that consumes the shared catalog can be tested against it; the replay protocol is documented in the corpus README.

Development

npm ci
npm run typecheck   # includes a src-only pass proving the core uses no Node APIs
npm run build       # dual ESM/CJS via tsdown
npm test            # full suite: unit + corpus + drift + purity + SDK alignment
npm run demo        # pretty-printed findings for a deliberately broken stream
npm run e2e         # live-transport checks against a real local HTTP server
npm run fuzz        # 50k hostile inputs against the never-throws invariant
npm run links:check # every specUrl resolves and every anchor exists

Component-by-component instructions live in docs/TESTING.md. Spec ambiguities found while grounding the rules are tracked in docs/spec-questions.md.

Adding a rule: add the catalog entry (with its specUrl), add the fixture stream + intended findings to js/scripts/build-fixtures.mjs, and run npm run fixtures:build — the meta-tests fail until both exist. Rule proposals belong upstream as issues on ag-ui-protocol/ag-ui first; this project does not invent rules the spec doesn't support.

Releasing: merge the pending changesets (npx changeset version) via a PR, then publish a GitHub release tagged vX.Y.Z (matching package.json) — the Publish workflow typechecks, builds, tests, and publishes to npm with provenance via trusted publishing. The workflow fails fast if the tag and package.json disagree.

License

MIT — maintained by Faraz.