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

@predicatelabs/sdk

v1.0.5

Published

TypeScript SDK for Sentience AI Agent Browser Automation

Readme

Predicate TypeScript SDK

A verification & control layer for AI agents that operate browsers

Predicate is built for AI agent developers who already use Playwright / CDP / LangGraph and care about flakiness, cost, determinism, evals, and debugging.

Often described as Jest for Browser AI Agents - but applied to end-to-end agent runs (not unit tests).

The core loop is:

Agent → Snapshot → Action → Verification → Artifact

What Predicate is

  • A verification-first runtime (AgentRuntime) for browser agents
  • Treats the browser as an adapter (Playwright / CDP); AgentRuntime is the product
  • A controlled perception layer (semantic snapshots; pruning/limits; lowers token usage by filtering noise from what models see)
  • A debugging layer (structured traces + failure artifacts)
  • Enables local LLM small models (3B-7B) for browser automation (privacy, compliance, and cost control)
  • Keeps vision models optional (use as a fallback when DOM/snapshot structure falls short, e.g. <canvas>)

What Predicate is not

  • Not a browser driver
  • Not a Playwright replacement
  • Not a vision-first agent framework

Install

npm install @predicatelabs/sdk
npx playwright install chromium

Naming migration (Predicate rebrand)

Use the new Predicate* class names for all new code:

  • PredicateBrowser
  • PredicateAgent
  • PredicateVisualAgent
  • PredicateDebugger
  • backends.PredicateContext

Conceptual example (why this exists)

  • Steps are gated by verifiable UI assertions
  • If progress can’t be proven, the run fails with evidence
  • This is how you make runs reproducible and debuggable, and how you run evals reliably

Quickstart: a verification-first loop

import { PredicateBrowser, AgentRuntime } from '@predicatelabs/sdk';
import { JsonlTraceSink, Tracer } from '@predicatelabs/sdk';
import { exists, urlContains } from '@predicatelabs/sdk';
import type { Page } from 'playwright';

async function main(): Promise<void> {
  const tracer = new Tracer('demo', new JsonlTraceSink('trace.jsonl'));

  const browser = new PredicateBrowser();
  await browser.start();
  const page = browser.getPage();
  if (!page) throw new Error('no page');

  await page.goto('https://example.com');

  // AgentRuntime needs a snapshot provider; PredicateBrowser.snapshot() does not depend on Page,
  // so we wrap it to fit the runtime interface.
  const runtime = new AgentRuntime(
    { snapshot: async (_page: Page, options?: Record<string, any>) => browser.snapshot(options) },
    page,
    tracer
  );

  runtime.beginStep('Verify homepage');
  await runtime.snapshot({ limit: 60 });

  runtime.assert(urlContains('example.com'), 'on_domain', true);
  runtime.assert(exists('role=heading'), 'has_heading');

  runtime.assertDone(exists("text~'Example'"), 'task_complete');

  await browser.close();
}

void main();

PredicateDebugger: attach to your existing agent framework (sidecar mode)

If you already have an agent loop (LangGraph, custom planner/executor), keep it and attach Predicate as a verifier + trace layer.

Key idea: your agent still executes actions — Predicate snapshots and verifies outcomes.

import type { Page } from 'playwright';
import { PredicateDebugger, Tracer, JsonlTraceSink, exists, urlContains } from '@predicatelabs/sdk';

async function runExistingAgent(page: Page): Promise<void> {
  const tracer = new Tracer('run-123', new JsonlTraceSink('trace.jsonl'));
  const dbg = PredicateDebugger.attach(page, tracer);

  await dbg.step('agent_step: navigate + verify', async () => {
    // 1) Let your framework do whatever it does
    await yourAgent.step();

    // 2) Snapshot what the agent produced
    await dbg.snapshot({ limit: 60 });

    // 3) Verify outcomes (with bounded retries)
    await dbg
      .check(urlContains('example.com'), 'on_domain', true)
      .eventually({ timeoutMs: 10_000 });
    await dbg.check(exists('role=heading'), 'has_heading').eventually({ timeoutMs: 10_000 });
  });
}

SDK-driven full loop (snapshots + actions)

If you want Predicate to drive the loop end-to-end, you can use the SDK primitives directly: take a snapshot, select elements, act, then verify.

import { PredicateBrowser, snapshot, find, typeText, click, waitFor } from '@predicatelabs/sdk';

async function loginExample(): Promise<void> {
  const browser = new PredicateBrowser();
  await browser.start();
  const page = browser.getPage();
  if (!page) throw new Error('no page');

  await page.goto('https://example.com/login');

  const snap = await snapshot(browser);
  const email = find(snap, "role=textbox text~'email'");
  const password = find(snap, "role=textbox text~'password'");
  const submit = find(snap, "role=button text~'sign in'");
  if (!email || !password || !submit) throw new Error('login form not found');

  await typeText(browser, email.id, '[email protected]');
  await typeText(browser, password.id, 'password123');
  await click(browser, submit.id);

  const ok = await waitFor(browser, "role=heading text~'Dashboard'", 10_000);
  if (!ok.found) throw new Error('login failed');

  await browser.close();
}

Capabilities (lifecycle guarantees)

Controlled perception

  • Semantic snapshots instead of raw DOM dumps
  • Pruning knobs via SnapshotOptions (limit/filter)
  • Snapshot diagnostics that help decide when “structure is insufficient”

Constrained action space

  • Action primitives operate on stable IDs / rects derived from snapshots
  • Optional helpers for ordinality (“click the 3rd result”)

Verified progress

  • Predicates like exists(...), urlMatches(...), isEnabled(...), valueEquals(...)
  • Fluent assertion DSL via expect(...)
  • Retrying verification via runtime.check(...).eventually(...)

Scroll verification (prevent no-op scroll drift)

A common agent failure mode is “scrolling” without the UI actually advancing (overlays, nested scrollers, focus issues). Use AgentRuntime.scrollBy(...) to deterministically verify scroll had effect via before/after scrollTop.

runtime.beginStep('Scroll the page and verify it moved');
const ok = await runtime.scrollBy(600, {
  verify: true,
  minDeltaPx: 50,
  label: 'scroll_effective',
  required: true,
  timeoutMs: 5_000,
});
if (!ok) {
  throw new Error('Scroll had no effect (likely blocked by overlay or nested scroller).');
}

Explained failure

  • JSONL trace events (Tracer + JsonlTraceSink)
  • Optional failure artifact bundles (snapshots, diagnostics, step timelines, frames/clip)
  • Deterministic failure semantics: when required assertions can’t be proven, the run fails with artifacts you can replay

Framework interoperability

  • Bring your own LLM and orchestration (LangGraph, custom loops)
  • Register explicit LLM-callable tools with ToolRegistry

ToolRegistry (LLM-callable tools)

import { ToolRegistry, registerDefaultTools } from '@predicatelabs/sdk';

const registry = new ToolRegistry();
registerDefaultTools(registry);
const toolsForLLM = registry.llmTools();

Permissions (avoid Chrome permission bubbles)

Chrome permission prompts are outside the DOM and can be invisible to snapshots. Prefer setting a policy before navigation.

import { PredicateBrowser } from '@predicatelabs/sdk';
import type { PermissionPolicy } from '@predicatelabs/sdk';

const policy: PermissionPolicy = {
  default: 'clear',
  autoGrant: ['geolocation'],
  geolocation: { latitude: 37.77, longitude: -122.41, accuracy: 50 },
  origin: 'https://example.com',
};

// `permissionPolicy` is the last constructor argument; pass `keepAlive` right before it.
const browser = new PredicateBrowser(
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  false,
  policy
);
await browser.start();

If your backend supports it, you can also use ToolRegistry permission tools (grant_permissions, clear_permissions, set_geolocation) mid-run.

Downloads (verification predicate)

import { downloadCompleted } from '@predicatelabs/sdk';

runtime.assert(downloadCompleted('report.csv'), 'download_ok', true);

Debugging (fast)

  • Manual driver CLI:
npx predicate driver --url https://example.com
  • Verification + artifacts + debugging with time-travel traces (Predicate Studio demo):

If the video tag doesn’t render in your GitHub README view, use this link: sentience-studio-demo.mp4

  • Predicate SDK Documentation: https://predicatelabs.dev/docs