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

@pieai/swimmer-ai-kit

v0.11.0

Published

Small, server-only TypeScript primitives shared by Pie AI products.

Readme

SwimmerAIKit

Small, server-only TypeScript primitives shared by Pie AI products.

This package is the product-line AI socket. Product code must not call OpenRouter or model-vendor SDKs directly. Last reviewed: 2026-08-13.

Scope

Owns:

  • Server environment readers and fallback resolution
  • Product-owned model alias registries
  • OpenRouter model configuration and attribution headers
  • Provider-neutral chat-completion contract (./chat)
  • OpenRouter chat completion transport (./openrouter)
  • Gemini-direct chat completion transport (./gemini)
  • Privacy-safe, provider-neutral AI execution evidence validation
  • Local provider budget reservation/commit/release guards
  • Typed generator registries with optional provider-budget wrapping
  • Structured-output parse/generate on top of ./chat (./structured-output)
  • Named agent registry (./agents): lookup plus chat / structured invoke
  • Content safety (./content-safety): local text rules + Sightengine visual and adult-reference adapters
  • Dual TTS routing (./tts): language → western (ElevenLabs) / chinese (MiniMax)
  • Tripo 3D text-to-model adapter (./tripo)

Does not own prompts, product model policy, product schemas, game logic, wallet RPCs, database access, deployment topology, or a Mastra runtime. Each product deploys its own optional Mastra service and supplies its own model aliases, budgets, generators, standing instructions, and Zod (or other) schemas.

Public API contract

Import a named subpath. The root entry @pieai/swimmer-ai-kit is a compatibility barrel for existing callers (SupaLuv). New code should not add root imports. Runtime values on the root barrel are locked by tests/public-exports.test.ts.

| Subpath | Stability | Source | Use it for | Do not use it for | | --- | --- | --- | --- | --- | | ./env | stable | src/env.ts | Reading server env and key fallbacks | Client bundles, logging secret values | | ./models | stable | src/models.ts | Product alias registries; Mastra OpenRouter model config | Sending HTTP; owning product model policy | | ./chat | evolving | src/chat.ts | Typing a ChatCompletionTransport. ChatMessage.content is a string or text / image parts. | Calling a provider; parsing structured output | | ./structured-output | evolving | src/structured-output.ts | Declaring a { parse } schema and getting a validated object from chat text | Owning product schemas; wrapping Mastra; unifying transport errors | | ./agents | evolving | src/agents.ts | Looking up named agents and invoking them through ./chat / ./structured-output | Constructing Mastra/Agent; owning prompts or model policy | | ./openrouter | stable | src/openrouter.ts | Text and vision chat completions through OpenRouter. Optional signal cancels or times out a request. | Gemini-direct, product prompts | | ./openrouter-authorization | evolving | src/openrouter-authorization.ts | Official HTTPS S256 authorization URL and bounded, single code exchange | User/tenant state, encrypted custody, billing or supplier licensing | | ./pi-oauth | evolving | src/pi-oauth.ts | Pi-owned device login, refresh and bounded text for Copilot, xAI, Kimi Code and Radius | CLI credential discovery, brand login, arbitrary gateways, automatic account rotation | | ./gemini | evolving | src/gemini.ts | Gemini-direct ChatCompletionTransport for the same request shape | OpenRouter ids (google/…), product prompts, Mastra config | | ./execution-evidence | stable | src/execution-evidence.ts | Parsing privacy-safe usage/cost evidence | Pricing, billing decisions, raw provider payloads | | ./provider-budget | stable | src/provider-budget.ts | In-process cents reservation | Cross-process ledgers or wallet truth | | ./generator-registry | stable | src/generator-registry.ts | Wrapping named generators with optional budget | Owning generator implementations | | ./content-safety | stable | src/content-safety/ | Text/visual/adult-reference review; Sightengine signal normalize | Product visual thresholds, copy, or UI policy | | ./tts | stable | src/tts/ | Dual-route speech synthesis | Client-side key handling | | ./tripo | stable | src/tripo.ts | Server-only Tripo text-to-model | Browser runtime; live image_to_model |

Expected consumers: server code in Pie products (Show, Collapse, SupaLuv, Sea, Anvil, TuringPact, Break, Non-Heroes). Browser bundles, edge markup, and product UI must not import this package.

Additional Pi OAuth accounts

./pi-oauth reuses the pinned Pi provider implementations, not copies of their OAuth protocols. piOAuthCapabilities() is an offline inventory of the six requested families: the existing Codex and OpenRouter adapters plus GitHub Copilot, xAI, Kimi Code and Radius. Anthropic account login is excluded. Inventory presence is neither a real login nor permission to sell hosted subscription use. Radius billing is gateway-defined (subscription: null), not inferred as free.

import { authorizePiDevice, createPiOAuthChatTransport } from '@pieai/swimmer-ai-kit/pi-oauth';

// Run in a durable, admitted, owner-bound server operation. The host provides
// the deadline, encrypted challenge/credential storage, consent and cancellation.
const account = await authorizePiDevice({
  provider: 'xai',
  signal: operationSignal,
  onDeviceCode: challenge => retainChallengeForThisOwner(challenge),
});
await retainCredentialForThisConnection(account);
const transport = await createPiOAuthChatTransport({
  account, model: selectedModelId, signal: taskSignal,
  onAttempt: request => retainPrivateTaskRequest(request),
});
// transport.complete() accepts one system message and one user message.
// The existing product task/runtime owns parsing, candidate review and adoption.

Each caller supplies a credential explicitly; no global account singleton, home-directory file, environment key fallback or framework login store is used. The host holds a cross-process claim before refreshPiOAuthCredential, saves the result before inference, and treats a lost outcome as unresolved. Kimi's maintained SDK may itself retry refresh; this adapter adds no retry. Copilot's maintained login can enable unconfigured model policies, so allowCopilotModelPolicyUpdates: true requires an informed product consent step. Enterprise/custom gateways are not silently admitted as arbitrary token destinations.

piOAuthTextModels() returns account-filtered model IDs; Radius reads its official gateway catalog. Catalogs remain connection-local. Model requests use Pi's maintained stream, with a fixed provider destination, caller deadline, one outbound attempt, no tools, bounded request/response bytes, and exact body evidence retained before dispatch. Errors do not expose provider response text or tokens. A displayed device code/URL is also private short-lived authorization material, not diagnostic metadata. Default tests use synthetic HTTP and standalone Node bundles, not real accounts or paid model calls. Directing UI, encrypted custody and live acceptance remain product integration work. See Pi providers and the installed SDK source for provider-specific behavior.

./openrouter-authorization is a provider-protocol adapter, not an Auth service. The host must pin its HTTPS callback to a user-bound, expiring, single-use attempt, persist exchanging before dispatch, and encrypt the returned key outside work/task records. An unknown exchange must not be retried: the provider may already have issued a key. The key is permanent/user-controlled, not a promise of refresh, subscription media allowances, or free model usage. Disconnect and provider-side revocation are separate actions. The adapter never reads environment credentials or starts a localhost server.

Reuse review (2026-09-14): this follows the official PKCE API contract with standard Node crypto and Fetch. Pi 0.85.1's existing OpenRouter flow is CLI-only and owns a loopback listener/manual-code race, so it cannot be directly hosted as the public callback. No Pi or third-party implementation source was copied. The host must separately satisfy the OpenRouter terms, model terms and regional restrictions; the protocol helper is not commercial permission or real-account evidence.

Internal assembly that happens to be exported (prefer the façade):

  • ./content-safety visual-asset helpers (assetLooksImage, visualAssetBlob, …)
  • ./content-safety FetchLike / individual Sightengine factories
  • ./content-safety parseSightengineResponse / maxSightengineScore / sightenginePathMatches (not on the root barrel)
  • ./content-safety createSightengineVisualTransport / readSightengineCredentials (not on the root barrel)
  • ./tts individual ElevenLabs / MiniMax factories when createDualTtsFromEnv is enough
  • ./tripo parse/map helpers when createTripoAdapter is enough

createOpenRouterChatTransport lives on ./openrouter. createGeminiChatTransport lives on ./gemini. Both implement ChatCompletionTransport. Neither is re-exported from the root barrel. parseStructuredOutput and createStructuredOutputClient live on ./structured-output only. createAgentRegistry lives on ./agents only.

Frozen seams

Re-measured 2026-08-13 (round 3). These look movable and are not. Do not re-open them in a later structural pass unless a real second responsibility or a dedicated capability plan appears.

| Seam | Leave it | Why | | --- | --- | --- | | src/tripo.ts as one file | Yes. ~1243 lines is a review trigger, not a split rule. | One provider pack (credentials, credit budget, transport, adapter, parse). Splitting would make the next Tripo change touch more files for the same job. | | ./models OpenRouter helpers | Yes. Keep createOpenRouterModel / createOpenRouterHeaders on ./models. | Collapse, TuringPact, and Show import ./models. Moving the path is a contract change. | | FetchLike / OpenRouterFetch / GeminiFetch / TripoFetch | Yes. Four test seams, not one shared fetch type. | Unifying them changes published types. | | OpenRouter's six redacted error strings | Yes. Do not rewrite them to match Gemini or a shared class. | Sea parses failed with (\d+). Collapse, Anvil, and SupaLuv catch the façade. A typed helper is a new capability and needs its own plan. | | Shared HTTP/JSON helpers extracted from OpenRouter + Gemini | No extract. | The overlap is isUnknownRecord / isAbortLike / maxTokens checks — not a missing layer. A utils file would be a grab bag. | | requestGeminiChatCompletion façade | Do not add. | The abstraction is already complete(). | | Per-directory Boundary README / knip / madge as gates | Do not add. | 25 files; rg is enough. Extra docs become parallel truth. | | Root barrel growth | Do not add ./chat, ./gemini, ./structured-output, ./agents, or new ./content-safety runtime values to .. | The barrel is locked at 63 runtime keys for existing root callers (SupaLuv). | | Default Sightengine visual decide | Yes. Keep 0.72 / 0.65 / 0.75, exclude nudity.context, and do not map OCR/PII. | Tightening it would silently change SupaLuv visual review. Product policy reads parseSightengineResponse. | | Whitespace-only Sightengine keys | Yes. trim() then missing → undefined. | Empty credentials are not credentials. Creating a provider that will 401 is worse than falling back to local visual-unavailable. |

ChatCompletionRequest.signal is optional, matching TtsSynthesizeRequest. The kit does not pick a default timeout; products that need one pass AbortSignal.timeout(ms). Without a signal the request JSON and fetch init are unchanged.

ChatMessage.content is either a string (the original call shape) or an array of { type: 'text', text } and { type: 'image', url } parts. url is a data: URL or an https: URL. OpenRouter serializes image parts to the OpenAI image_url wire shape. String-only callers do not change.

Show camera-vision migration

Replace server/openRouterHttp.ts / summarizeImageSeed with createOpenRouterChatTransport. Do not pass OpenRouter's nested image_url object — that is the wire format, not the kit contract.

import { createOpenRouterChatTransport } from '@pieai/swimmer-ai-kit/openrouter';

const result = await createOpenRouterChatTransport({
  apiKey,
  appName: 'Show camera seed',
  appUrl: 'https://show.pieaistudio.com',
  fetchImpl,
}).complete({
  maxTokens: 90,
  messages: [
    {
      role: 'user',
      content: [
        { type: 'text', text: visionPrompt },
        { type: 'image', url: seed.dataUrl },
      ],
    },
  ],
  model: 'google/gemini-2.5-flash',
  signal: AbortSignal.timeout(15_000),
  temperature: 0.2,
});

const summary = result.content;

The same part array works for Show's OpenRouter visual-moderation path. Kit throws on HTTP / provider failure; Show currently inspects response.ok itself, so the catch / fail-closed mapping stays in Show. Do not change Show in this package.

When SHOW_MODEL_PROVIDER !== openrouter, use createGeminiChatTransport instead of stuffing Gemini into ./openrouter. Pass a Gemini model id (gemini-2.5-flash), not an OpenRouter id (google/gemini-2.5-flash). Gemini image parts must be data: URLs — the transport does not fetch https: images.

Non-Heroes character-AI migration

Replace new Mastra({ agents: { …: new Agent(…) } }). Keep product schemas, standing instructions, and the Colyseus-safe timeout wrapper in Non-Heroes.

import { createAgentRegistry } from '@pieai/swimmer-ai-kit/agents';
import { createGeminiChatTransport } from '@pieai/swimmer-ai-kit/gemini';
import { createOpenRouterChatTransport } from '@pieai/swimmer-ai-kit/openrouter';

const transport =
  modelProvider === 'gemini'
    ? createGeminiChatTransport({ apiKey: geminiApiKey })
    : createOpenRouterChatTransport({
        apiKey: openRouterApiKey,
        appName: 'Non-Heroes character AI',
        appUrl: 'https://non-heroes.pieaistudio.com',
      });

const agents = createAgentRegistry({
  agents: {
    'non-heroes-boss-ai': {
      instructions: productOwnedBossInstructions,
      model:
        modelProvider === 'gemini' ? 'gemini-2.5-flash' : 'google/gemini-2.5-flash',
      name: 'Non-Heroes Boss AI',
    },
  },
  transport,
});

const result = await agents.generateStructured({
  agentId: 'non-heroes-boss-ai',
  instructions: perRequestInstructions,
  maxTokens: 320,
  prompt,
  schema: bossAiOutputSchema,
  signal: AbortSignal.timeout(timeoutMs),
  temperature: 0.35,
});

return result.object;

Pass a transport-native model id. Do not pass Mastra's openrouter/google/… wrapper to ./openrouter, and do not pass google/gemini-2.5-flash to ./gemini. Do not set process.env.GOOGLE_API_KEY just to satisfy Mastra. Zod schemas stay in the product — kit only calls schema.parse.

Usage

Install the exact reviewed npm version:

pnpm add @pieai/[email protected]

Import only the narrow module needed by the service:

import {
  createContentModerationProvider,
  ADULT_COMEDY_MODERATION_POLICY,
} from '@pieai/swimmer-ai-kit/content-safety';
import { createDualTtsRouter, resolveTtsRoute } from '@pieai/swimmer-ai-kit/tts';
import { firstDefinedEnv } from '@pieai/swimmer-ai-kit/env';
import { parseAiExecutionEvidence } from '@pieai/swimmer-ai-kit/execution-evidence';
import {
  createModelRegistry,
  createOpenRouterModel,
} from '@pieai/swimmer-ai-kit/models';
import { requestOpenRouterChatCompletion } from '@pieai/swimmer-ai-kit/openrouter';
import { createGeminiChatTransport } from '@pieai/swimmer-ai-kit/gemini';
import type { ChatCompletionTransport } from '@pieai/swimmer-ai-kit/chat';
import { createStructuredOutputClient } from '@pieai/swimmer-ai-kit/structured-output';
import { createAgentRegistry } from '@pieai/swimmer-ai-kit/agents';

Execution evidence accepts bounded identifiers, exact integer-string usage and cost fields, and explicit completeness states. Unknown fields are discarded so raw prompts, completions, provider payloads, and accidental credential fields cannot cross through the parsed result. Products still decide pricing and whether a failed attempt is billable.

Assess a real-person reference separately from harmful-content moderation:

const moderation = createContentModerationProvider({
  sightengineApiUser: process.env.SIGHTENGINE_API_USER,
  sightengineApiSecret: process.env.SIGHTENGINE_API_SECRET,
});

const decision = await moderation.reviewAdultReference?.({
  kind: 'image',
  dataUrl: uploadedImageDataUrl,
});

if (decision?.status !== 'adult') {
  // Product decides how to explain minor, uncertain, or no_real_face.
}

The assessment uses Sightengine face-age, requires exactly one real face, and fails closed when credentials, the classifier, or a reliable score are unavailable. A normal photo of a minor is not labeled child exploitation: the result is minor_reference_detected, a feature eligibility decision.

Sightengine signals vs default decide

parseSightengineDecision is the published default decide. It does not change when a product wants a stricter (or looser) visual rule.

parseSightengineResponse is the normalize step that default decide used to throw away:

  • signals: every finite number in the JSON tree, with lowercased path keys. This includes text.email, nudity.context.indoor_other, nudity.bikini, and non-risk numbers such as request.operations.
  • raw: the classifier payload as returned. OCR match arrays and text.detected_categories are often strings, not numbers — they live here.

maxSightengineScore and sightenginePathMatches let a product write its own predicates. Example — block OCR email/phone the way Show's latch test does, without changing kit defaults:

import {
  maxSightengineScore,
  parseSightengineResponse,
  sightenginePathMatches,
} from '@pieai/swimmer-ai-kit/content-safety';

const parsed = parseSightengineResponse(raw);
if (parsed.ok) {
  const pii = maxSightengineScore(parsed.signals, (path) =>
    sightenginePathMatches(path, [/email/, /phone/, /ssn/, /pii/]),
  );
  if (pii !== undefined && pii >= 0.7) {
    // Product decision. Kit default still allows this payload.
  }
}

nudity.context.indoor_other is a scene-location class (indoor vs beach/pool), not an adult-content score. Sightengine documents it for combining with swimwear ("allow bikini at a pool, not indoors"). A product that wants that rule should join nudity.bikini with nudity.context.*. Treating indoor_other alone as visual_adult is expressible and is probably wrong.

Whitespace-only apiUser / apiSecret stay missing credentials. readSightengineCredentials, createSightengineVisualTransport, and createSightengineVisualProvider all return undefined so callers fall back to local visual_review_unavailable. That is input validation, not a policy threshold.

Show Sightengine migration

Do not wrap kit default decide and then re-run Show's parser. Use the transport, then apply Show's predicates to signals / raw.

import {
  createSightengineVisualTransport,
  maxSightengineScore,
  moderationFallback,
  sightenginePathMatches,
} from '@pieai/swimmer-ai-kit/content-safety';

const transport = createSightengineVisualTransport({
  apiSecret: process.env.SIGHTENGINE_API_SECRET,
  apiUser: process.env.SIGHTENGINE_API_USER,
  fetchImpl,
});

const checked = await transport?.check(asset);
if (!checked) {
  // keys missing — same as today's kit factory
}
if (!checked?.ok) {
  return moderationFallback(checked?.reasonCode ?? 'visual_review_unavailable', 'sightengine');
}

const pii = maxSightengineScore(checked.signals, (path) =>
  sightenginePathMatches(path, [/email/, /phone/, /ssn/, /pii/]),
);
if (pii !== undefined && pii >= 0.7) {
  return {
    allowed: false,
    category: 'private_info',
    provider: 'sightengine',
    reasonCode: 'visual_private_info',
  };
}

Kit still does not own Show's local text rules, reviewOutput asset extraction, or OpenRouter vision fallback. FormData filenames stay asset-image.png / asset-video.mp4; Sightengine does not use the name as a signal. Do not change Show in this package.

Secrets are inputs only. This package never stores, logs, or bundles secret values.

Images API

createOpenRouterImageTransport and OpenRouterImageError live on @pieai/swimmer-ai-kit/openrouter-images, not the root barrel. The transport uses the dedicated Images API reviewed on 2026-09-13, not a chat-output workaround. Existing brand headers and usage normalization are reused; normalizeOpenRouterUsage is now also exported from ./openrouter without changing its behavior.

Each request requires a model, provider tag, prompt and caller-owned abort signal. It pins one image, allow_fallbacks: false, buffered PNG output and up to four bounded inline PNG/JPEG/WebP reference data URLs. It does not fetch reference URLs, retry, load host auth, discover models, choose prices, reserve funds, write files or adopt media. Products must verify the selected endpoint's current capabilities and price before obtaining consent.

The request hook runs after serialization and before sending; failure prevents dispatch. The returned-body hook receives bounded raw data before parsing for product-owned recovery. Hooks contain no headers but may contain private work or reference bytes, so products must apply their own authorized, redacted retention boundary. Error causes distinguish cancellation, rejection, storage, transport and invalid responses while financial outcome remains unknown after dispatch. Never infer a refund or retry from cancellation alone.

Provider-reported MIME and canonical base64 are transport evidence, not proof of valid media or artistic quality. Products still inspect bytes and candidates before adopting them. Video generation is not implemented by this subpath; existing TTS and vision contracts remain separate. Only synthetic HTTP tests have run; no real image, provider account or model bill has been tested.

The transport first shipped in 0.7.0. The 0.9.0 candidate adds parseOpenRouterImageResponse(model, retainedBody) on this same subpath, so a product can recover a previously retained response without calling generation again. It checks the bounded response shape/base64/MIME and normalizes usage; the product still verifies actual image bytes, owner/task binding, adoption and settlement. Parsing is not proof of image quality or authority to charge a user.

User-owned Codex connection (server only)

@pieai/swimmer-ai-kit/openai-codex consumes the public APIs of the optional peer @earendil-works/[email protected]. Install that peer only in servers using this subpath; existing transports and root exports are unchanged. Node 24 is required.

Use authorizeCodexDevice({ signal, onDeviceCode }) in an isolated, bounded job. The callback receives only the official verification URL, user-visible code and expiry, not the private device identifier. Store the returned credential through the host's encrypted, owner-bound custody service. No credential is discovered from the machine, environment, browser or global Pi session. The host must obtain appropriate account consent and verify the provider's supported deployment use; this library does not grant commercial permission.

refreshCodexCredential(credential, signal) performs one refresh. The host holds an exclusive cross-process connection claim, saves the rotated credential before using it and treats a lost acknowledgement as uncertain. Never retry an uncertain refresh or infer provider-side revocation from a local disconnect.

createCodexChatTransport({ credential, model, onAttempt, fetchImpl? }) implements the existing chat contract for one system message and one text user message. Choose an explicit ID from codexTextModels(); catalog presence is not proof of account entitlement. A required abort signal, one SSE attempt, no tools, no hidden retry and no account/API-key fallback bound the execution. The credential and model are pinned when the transport is created.

onAttempt runs at the SDK's final fetch boundary. It receives decompressed JSON, its SHA-256 and the actual wire-body SHA-256 (identity or zstd encoding), without headers or credentials. This body may contain private work: retain it only through the product's authorized evidence store, with its redaction/retention rules. A callback failure prevents dispatch; the observer cannot modify the transmitted request. Observation is an attempted submission, not proof the provider read it.

The transport bounds request and response bytes and requires a completed stream. It does not claim a hard output-token cap: the Codex subscription protocol does not send max_output_tokens, even when the generic contract has maxTokens. Products must expose bounded calls/deadlines and the user's actual account quota. Reported usage has no invented API cost or free-credit promise. No ChatGPT web memory, image/video entitlement, account sharing or automatic quota rotation is provided. Current evidence is real installed SDK plus synthetic HTTP, not a real user login or paid model test.

Verify

pnpm typecheck, pnpm test, pnpm build, or pnpm verify.

Origins

The first extraction came from behavior already present in TuringPact and Show. Show now consumes ./env, ./models, ./provider-budget, and ./generator-registry; its camera-vision and OpenRouter moderation paths still call OpenRouter outside this kit.

doc/LearningFrom0/ is a historical beginner tutorial. It is not the public API SSOT.