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

@agentlair/openai-agents

v0.2.0

Published

AgentLair adapter for the OpenAI Agents SDK — issue per-agent AATs, attach Bearer tokens to tool calls, emit audit envelopes, and sign outbound HTTP requests with RFC 9421 / Web Bot Auth.

Readme

@agentlair/openai-agents

AgentLair adapter for the OpenAI Agents SDK. Issue an Agent Authentication Token (AAT) per agent run, attach it to outbound tool calls, and emit a signed audit envelope per invocation — without changing how you write agents.

Install

npm install @agentlair/openai-agents @openai/agents
# or
bun add @agentlair/openai-agents @openai/agents

@openai/agents is a (optional) peer dependency. Zero runtime dependencies otherwise. Works in Node 18+, Bun, and edge runtimes (Cloudflare Workers, Deno Deploy).

Get a free AgentLair API key at agentlair.dev — no card required.

Usage

import { Agent, run, tool } from '@openai/agents';
import { withAgentLair } from '@agentlair/openai-agents';
import { z } from 'zod';

const echo = tool({
  name: 'echo',
  description: 'Echo a string back to the caller',
  parameters: z.object({ msg: z.string() }),
  execute: async ({ msg }) => `you said: ${msg}`,
});

const myAgent = new Agent({
  name: 'demo',
  instructions: 'Echo what the user says.',
  tools: [echo],
});

// Wrap once at startup. The original agent is unchanged.
const governed = withAgentLair(myAgent, {
  apiKey: process.env.AGENTLAIR_API_KEY!,
  audience: 'https://my-mcp.example.com',
  scopes: ['mcp:tools:read'],
  agentName: 'demo',
});

const result = await run(governed, 'echo "hello"');
// On every tool call, AgentLair issued (or reused) an AAT and recorded
// an audit envelope. Inspect at https://agentlair.dev/v1/audit/<jti>.

That's it. No changes to your tools or Agent shape — withAgentLair returns a shallow clone with each tool's execute wrapped to issue an AAT and emit an audit envelope.

What it does

  1. Issues an AAT before each tool invocation (cached and reused until expiry by default — one issue per run, not one per tool call).
  2. Records an audit envelope for every tool call — args, result, duration, jti, agent name, audience. Best-effort; failures never block the tool.
  3. Returns a verifiable did:web — each AAT embeds did:web:agentlair.dev:agents:<account_id>, resolvable against AgentLair's JWKS.
  4. Signs outbound HTTP requests with RFC 9421 / Web Bot Auth (v0.2.0+) — signRequest() produces Signature / Signature-Input / Signature-Agent headers that Google Cloud Fraud Defense and any Web Bot Auth–aware origin can verify.

Web Bot Auth (RFC 9421 HTTP Message Signatures)

Sign outbound requests inside a tool so the receiving origin can prove the request came from your AgentLair-anchored agent — no shared secrets, no Bearer rotation:

import { signRequest } from '@agentlair/openai-agents';

// 32-byte Ed25519 keypair — generate once, register the public half at
// POST https://agentlair.dev/v1/agents/signing-keys, then keep the private
// half (and its 32-byte raw seed) wherever your agent stores secrets.
const req = new Request('https://api.example.com/resource');
const signed = await signRequest(req, { privateKey, publicKey });
const res = await fetch(signed);

signRequest adds three headers:

  • Signature-Input — covered components, created, expires, keyid (the RFC 8037 JWK thumbprint), and tag="web-bot-auth".
  • Signature — Ed25519 over the canonical signature base.
  • Signature-Agenthttps://agentlair.dev/agents/<thumbprint> — verifiers fetch the JWK there.

The same Ed25519 keypair you register at /v1/agents/signing-keys is the one used here. AgentLair's directory endpoint at GET /agents/<thumbprint> resolves the public JWK with no auth required, so any verifier (Google Fraud Defense, a custom origin) can complete the loop.

See docs/web-bot-auth for the full architecture.

Explicit Agent Self-Attestation

Agents can post L3 self-attestations directly — no tool wrapping required. Use this when your agent wants to declare intent, record a decision, or attest to a constraint before acting:

import { logAuditEvent } from '@agentlair/openai-agents';

// Agent declares it will not exceed budget before starting work
const entry = await logAuditEvent(
  {
    category: 'budget',
    action: 'budget.no_exceed',
    details: { limit_usd: 10, projected_usd: 2.5, model: 'gpt-4o-mini' },
  },
  { apiKey: process.env.AGENTLAIR_API_KEY! },
);
console.log(entry.id);         // e.g. "WSZqkmVNIzXrxwqnIwbF"
console.log(entry.signature);  // Ed25519 sig — independently verifiable
console.log(entry.prev_hash);  // SHA-256 of previous chain entry

The entry is hash-chained and Ed25519-signed server-side. Verify the chain at GET /v1/audit/log.

Valid categories: task, tool_call, observation, reasoning, output, budget, memory, session, and more — see ALLOWED_AUDIT_CATEGORIES. Action format: lowercase dot-separated, e.g. "task.complete", "budget.no_exceed". Validates against AUDIT_ACTION_REGEX client-side before the network call. Throws AuditLogError with typed code on validation failures or non-2xx responses.

Lower-level API

If you want fine-grained control:

import { issueAATForAgent, recordAuditEvent, wrapTool } from '@agentlair/openai-agents';

// Issue a token by hand
const aat = await issueAATForAgent({
  apiKey: process.env.AGENTLAIR_API_KEY!,
  audience: 'https://my-mcp.example.com',
  scopes: ['mcp:tools:read', 'mcp:tools:execute'],
  ttl: 3600,
});
console.log(aat.jti);      // aat_xxxxxxxxxxxxxxxx
console.log(aat.did);      // did:web:agentlair.dev:agents:acc_...
console.log(aat.token);    // eyJhbGciOiJFZERTQSIsImtpZCI6...

// Wrap a single tool with a custom audit sink
const wrapped = wrapTool(myTool, {
  apiKey: process.env.AGENTLAIR_API_KEY!,
  audience: 'https://my-mcp.example.com',
  preIssuedAAT: aat,
  onAuditEvent: (e) => myObservabilityPipeline.send(e),
});

Options

| Option | Type | Default | Notes | | --- | --- | --- | --- | | apiKey | string | — | Required. al_live_* or al_pod_* from agentlair.dev. | | audience | string | — | Required. Target service URL the AAT will be presented to. | | scopes | string[] | ['mcp:tools:read'] | Each must match ^[a-z][a-z0-9._:-]*$. | | ttl | number | 3600 | Lifetime in seconds. Max 86400. | | agentName | string | — | al_name claim in the AAT. | | agentEmail | string | — | al_email claim in the AAT. | | agentLairBaseUrl | string | https://agentlair.dev | Override for staging/self-host. | | cacheAAT | boolean | true | Reuse the AAT across tool calls until expiry. | | preIssuedAAT | AAT | — | Skip the issue call entirely. Useful in tests. | | onAuditEvent | function | best-effort POST | Custom audit sink. Failures never block the tool. | | fetchImpl | typeof fetch | global fetch | For testing or edge runtimes. |

Verification

Audit envelopes are signed with AgentLair's Ed25519 audit key. To verify a token or audit entry independently:

# Token — verify against JWKS
curl https://agentlair.dev/.well-known/jwks.json

# Per-token metadata
curl https://agentlair.dev/v1/audit/<jti>

Errors

issueAATForAgent throws AgentLairError with a typed code:

| Code | Meaning | | --- | --- | | invalid_options | apiKey or audience missing/malformed | | network_error | fetch threw (DNS, timeout, etc.) | | http_error | non-2xx response from /v1/tokens/issue (check .status) | | invalid_response | unparseable JSON or unexpected shape |

Tool wrapping (wrapTool, withAgentLair) never throws on AgentLair-side failures — the original tool error (if any) is rethrown unchanged.

logAuditEvent throws AuditLogError with a typed code:

| Code | Meaning | | --- | --- | | invalid_category | category not in ALLOWED_AUDIT_CATEGORIES | | invalid_action | action violates AUDIT_ACTION_REGEX or length limit (1–128 chars) | | details_too_large | details JSON-serialised size exceeds 4 KB | | network_error | fetch threw (DNS, timeout, etc.) | | http_error | non-2xx response from /v1/audit/log (check .status) | | invalid_response | unparseable JSON or unexpected response shape |

Reference

License

Apache-2.0