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

@ifc-lite/ai

v0.2.0

Published

Provider-independent AI request core: transport contract, typed outcomes, root budgets, usage receipts and bounded JSON output parsing

Readme

@ifc-lite/ai

Provider-independent core for AI requests in ifc-lite: the web viewer, Flow AI nodes and headless hosts (CLI) share it, so a budget or an outcome means the same thing everywhere.

It holds no provider client, no credentials and no UI state. A host brings its own transport (a browser SSE client, a BYOK provider client, a headless HTTP call) and this package does the rest:

  • Typed outcomes. runModelRequest resolves to completed, truncated, cancelled, timeout, error or refused, never an exception, with an overall deadline and caller cancellation.
  • Root budgets. A RootBudget caps the requests and output tokens of one task end to end. Every retry, repair, chunk, Flow lane or resumed run reserves from the same root, so no loop can spend more than it allows. Budgets are plain data and can be persisted and restored (restoreRootBudget) without resetting what was spent.
  • Usage receipts. One receipt per request that reached the transport: model, route, times, outcome and the provider-reported token counts. Counts are never estimated; usageReported: false says the provider did not report them. A receipt never holds a prompt, a reply or a credential.
  • Request provenance. Dispatched receipts retain the actual granted output-token ceiling, effective parent deadline and a safe terminal-reason enum. promptVersion is an optional producer declaration; a generic host remains unknown. An explicit prepareInput producer callback serializes {messages, system?, outputSchema?} under the parent deadline. The core parses once and dispatches and digests that same owned JSON snapshot. Versioned SHA256 digests bind its sorted-key logical system/messages/schema and exact UTF8 completed output text. Caller model and route changes cannot retarget the dispatched receipt. They identify neither provider wire bytes nor native output artifacts. Generic custom transports without this explicit JSON boundary preserve their opaque inputs untouched and report inputDigestUnavailable: 'opaque-input'. No accessor/Proxy detection by reflection is attempted. Explicit serialization is a native producer action, not a metadata probe; a serialization/shape failure returns a request error without dispatch or provenance. JSON parsing/serialization is native request preparation, not bounded digest traversal. Logical digest traversal stops at 100,000 inspected values/fields or 4,000,000 UTF16 units and reports digest-limit without refusing the host request or hashing truncated input; this exceeds the viewer's 90,000-unit context plus 1,200,000-unit image limit. Unknown provider reasons become unknown; raw error text, endpoints and credentials are excluded. Legacy receipts omit provenance rather than reconstructing it.
  • Bounded JSON output. parseJsonOutput accepts one complete JSON value (optionally in a single ```json fence), bounded by size, depth and value count, and refuses truncated replies and prototype keys. It never extracts JSON from prose.
  • Response schemas. An optional outputSchema: JsonResponseSchema carries an actual JSON object contract to the transport. A transport that sends it reports onOutputFormat('json-schema'); a parser-only transport reports text. Typed-request receipts include the reported outputFormat, describing the outgoing protocol rather than promising model quality or validating evidence. It stays absent when cancellation prevents dispatch or the transport does not report its protocol. Receipts never contain the schema or its source identifiers. Unsupported schema requests fail without a hidden retry as text.

A host that detects a documented provider limit before dispatch can return { kind: 'refused', reason: 'unsupported-schema', message }. This outcome has no usage receipt and does not consume the root budget; it differs from budget exhaustion. Native Flow nodes report the limitation without claiming rows were sent. The viewer checks Anthropic's documented 16-union and 24-optional-parameter limits before reserving a request.

Install

npm install @ifc-lite/ai

One request

import { createRootBudget, parseJsonOutput, runModelRequest, type AiTransport } from '@ifc-lite/ai';

type Message = { role: 'user' | 'assistant'; content: string };

// Your transport: call `onChunk` for every piece of output and `onComplete` with the whole text.
const transport: AiTransport<Message> = async (call) => {
  const text = '{"label":"routing"}';
  call.onChunk(text);
  call.onFinishReason('stop');
  call.onTokenUsage({ inputTokens: 120, outputTokens: 9 });
  call.onComplete(text);
};

const budget = createRootBudget({ maxRequests: 6, maxOutputTokens: 8000 });
const outcome = await runModelRequest({
  model: 'my-model', route: 'my-host', transport,
  promptVersion: 'my-host.classification.v1',
  messages: [{ role: 'user', content: 'Classify this clash.' }],
  prepareInput: () => JSON.stringify({ messages: [{ role: 'user', content: 'Classify this clash.' }] }),
  maxOutputTokens: 1024, routeCeiling: 8192, budget, timeoutMs: 60_000,
}, { onReceipt: (receipt) => console.log(receipt.outcome, receipt.usageReported) });

if (outcome.kind === 'completed') {
  const parsed = parseJsonOutput(outcome.text);
  if (parsed.ok) console.log(parsed.value);
}

Two optional hooks let a host observe requests without wrapping the core:

  • onStart({ id, model, route, startedAt, cancel }) runs once when a request is handed to the transport (never for one refused by the budget or cancelled before dispatch). Its id is the id of the receipt the request will produce, and cancel() aborts it, so an activity list can show it running and offer Cancel.
  • onReceipt(receipt) runs once per dispatched request, before the outcome resolves.

A transport must not retry on its own: a retry is a new request that spends the root budget again, and only the caller decides that.

License

MPL-2.0

Portable native change artifacts

@ifc-lite/ai/artifacts is a separate entry exposing parseModelChangeBatch, changeKey, native change types, editable attributes and bounded provider guidance. It is the canonical parser consumed by viewer correction previews and Flow ai.propose. Parsing validates the native data contract; hosts must resolve targets and recheck current values, permissions and reviewer selection before applying any changes. Importing the request core alone does not load the artifact validator. See the Flow guide.

@ifc-lite/ai/chat-completions exposes the shared opt-in flowAiConfig and chatCompletionsTransport consumed by CLI and MCP Flow hosts. Both hosts route every call through runModelRequest with one persistable root pool; credentials remain host configuration. The request-core and artifact entries stay separate.

FlowAiConfig.structuredOutput explicitly enables response_format for a compatible upstream. flowAiConfig reads IFC_LITE_AI_STRUCTURED_OUTPUT=true or false; the exact official OpenAI endpoint defaults to enabled, while arbitrary compatible endpoints, including the default OpenRouter endpoint, default to parser-only. Configure support for the actual upstream model.