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

@axium-lab/helix

v0.3.1

Published

Dialect translation across LLM providers (OpenAI, Anthropic, Gemini) plus a provider-agnostic SDK

Readme

Helix

Translation between LLM wire formats, plus a provider-agnostic SDK.

A single npm package, with no server and no process of its own. It gets imported. The parent project, Axium, is what exposes HTTP.

Branch refactor. Complete rewrite of v0.1, which is frozen on main as a reference and is neither compiled nor tested. It used to be vendored here under old_code/; consult it with git show main:<path> instead.


What works, and what does not

The honest version. Nothing below is aspirational — every ✅ is exercised by the test suite, and most of it against a live server.

Dialects

A dialect is a wire format Helix can both read and write.

| Dialect | Status | Surfaces | |---|---|---| | openai | ✅ complete | /v1/chat/completions and /v1/responses | | gemini | ✅ complete | generateContent / streamGenerateContent, and the Interactions API | | anthropic | ❌ not implemented | — |

Gemini's Interactions API — the surface Google recommends for new work — is opt-in, so existing callers keep the behaviour they have:

new Helix({
  transport: new GeminiTransport({ apiKey }),
  encodeOptions: { surface: 'gemini.interactions' },
});

It adds stored responses (helix.responses.get / .cancel / .delete, store, background, previous_response_id) and reasoning.effort maps directly onto thinking_level. Two things to know before switching:

  • It exposes no sampling controls. temperature, top_p, top_k, n and the penalties do not exist on this surface; each one warns when dropped.
  • Multi-turn tool use needs the whole assistant turn replayed, reasoning included — the signature it carries is validated server-side. In exchange, the round trip works, which it does not on generateContent (see por-arreglar.md).

Anthropic is not started. dialects.anthropic does not exist and will not compile — the registry is typed as a partial record precisely so that a missing dialect is a compile error rather than an undefined at runtime.

Endpoints

An endpoint is where a request goes. Several share one dialect, which is the point of separating the two.

| Transport | Dialect | Generation | Streaming | Models | Files | |---|---|---|---|---|---| | OpenAITransport | openai | ✅ | ✅ | ✅ | ✅ | | AzureTransport | openai | ✅ | ✅ | ✅ | ✅ | | OpenAICompatibleTransport | openai | ✅ | ✅ | ⚠️ | ⚠️ | | GeminiTransport | gemini | ✅ | ✅ | ✅ | ✅ | | GeminiEnterpriseTransport | gemini | ✅ | ✅ | ✅ | ⚠️ via Cloud Storage | | Anthropic | anthropic | ❌ not implemented | | | | | Bedrock | anthropic | ❌ not planned | | | |

⚠️ OpenAI-compatible vendors (Groq, Ollama, OpenRouter, vLLM…) implement the generation surface reliably and the rest inconsistently. Declare what yours supports and helix.capabilities will report it truthfully:

new OpenAICompatibleTransport({
  baseUrl: 'https://api.groq.com/openai/v1',
  apiKey,
  capabilities: { files: false, models: false },
});

⚠️ Gemini Enterprise — the product Google used to call Vertex AIhas no Files API. GeminiEnterpriseTransport backs files.* with Google Cloud Storage when you give it a bucket, and reports capabilities.files: false when you do not. Ids are gs://bucket/object, which the gemini dialect already accepts as a file_id — so you can also skip uploads entirely and reference an object you put there yourself.

Gemini Enterprise authenticates with OAuth rather than a key, in four ways:

const where = { projectId, location: 'us-central1' };

// A service account key. Helix signs the JWT itself — no extra dependency.
new GeminiEnterpriseTransport({ ...where, credentials });

// A token you already have.
new GeminiEnterpriseTransport({ ...where, accessToken });

// Delegation, for Workload Identity Federation or impersonation.
new GeminiEnterpriseTransport({ ...where, getAccessToken });

// Nothing: the GCE/Cloud Run metadata server. How this runs on Google's compute.
new GeminiEnterpriseTransport(where);

Files need credentials or ADC specifically: the Storage client mints its own token and takes a key, so an accessToken authenticates the model endpoint but not Storage.

Operations

| Operation | Status | |---|---| | responses.create | ✅ | | responses.stream | ✅ decoding and encoding, in both directions | | models.list / models.get | ✅ | | files.create / get / list / delete | ✅ | | test.connection | ✅ | | embeddings, batches, images, audio, fine-tuning | ❌ out of scope for v1 |

Known limitations

  • File uploads are held in memory. file takes a Uint8Array; there is no streaming upload. Gemini's own limit for a single-chunk upload is around 20 MB.
  • Model names are not translated. Sending an OpenAI request to Gemini produces a Gemini-shaped call for gpt-4o-mini. Choosing an equivalent model is a policy decision and belongs to the caller.
  • HelixResponse has no passthrough. Unlike requests, provider extras on a response (system_fingerprint, logprobs) survive only inside metadata.raw.

Install

Published publicly on npm — no registry configuration and no token needed:

npm install @axium-lab/helix

Node 22 or newer; ESM and CJS builds both ship.


What it is for

Two use cases from one engine:

  1. Dialect translation. Convert a request in one provider's format into another's, and the response back. Helix exposes the functions; Axium mounts them on HTTP routes so a client only changes its baseURL.
  2. Provider-agnostic SDK. A facade that also normalises models and files, which LangChain does not cover.
import { Helix, OpenAITransport } from '@axium-lab/helix';

const helix = new Helix({ transport: new OpenAITransport({ apiKey }) });

const res = await helix.responses.create({
  model: 'gpt-4o-mini',
  instructions: 'Be concise.',
  input: [{ role: 'user', content: [{ type: 'input_text', text: 'Hello.' }] }],
});

Swapping the transport is the only edit needed to talk to a different provider.

Full surface in API.md; the design explained in CONCEPTS.md. Both are also published as a browsable site under docs/ — open docs/index.html.


The design principle

Both use cases are the same engine walked in opposite directions. Every dialect is a module with four functions:

| function | translation (used by Axium) | SDK | |---|---|---| | decodeRequest wire→IR | ✅ | — | | encodeRequest IR→wire | — | ✅ | | decodeResponse wire→IR | — | ✅ | | encodeResponse IR→wire | ✅ | — |

With a central IR this is N+M transformers instead of N×M. And because HTTP lives in Axium, all four are public API: breaking that contract is a breaking change.

The axes are kept apart deliberately:

  • A dialect knows wire formats and never touches the network.
  • A transport knows URLs and credentials and never reads a payload.

Which is why azure is not a provider but an endpoint speaking the openai dialect — and why adding it required no translation code at all.

Two documented exceptions exist, both in transports that must read a body: Azure needs the deployment name from body.model for its URL, and Gemini's file upload is a two-step resumable exchange. A third would mean the contract should grow multi-step operations rather than collect exceptions.


No required runtime dependencies

package.json declares no dependencies. The provider SDKs are devDependencies used through import type only, to type foreign wire formats without shipping them — enforced by verbatimModuleSyntax and verified at build time by scripts/check-dist.mjs, which fails the build if any of them reaches the emitted .d.ts.

That check matters: a leaked type would turn a devDependency into a peer dependency for every consumer, and TypeScript gives no warning about it.

One optionalDependency: @google-cloud/storage, which backs files.* on Gemini Enterprise. It is reached through a dynamic import() that only runs when you configure a bucket, and tsup marks it external so it is never inlined — leaving it out of the bundle entirely rather than shipping 1.9 MB to everyone. Install it if you want files there; otherwise nothing changes for you. Everything else, OAuth signing included, is plain fetch and crypto.subtle.


Development

npm install
npm run typecheck
npm test              # everything
npm run build         # tsup + the dist guard

Tests

| Tier | Against | Network | What it validates | |---|---|---|---| | test:unit | fixtures on disk | no | dialects, the IR, pure logic | | test:mock | llm-mock | yes | transports, assembly, real wire shapes | | test:integration | real providers | yes | self-skips without credentials | | test:manual | real providers | yes | a scratchpad, not a check — excluded from npm test and from CI |

The manual tier is a mode, not a directory in the run: HELIX_MANUAL=1 makes the run contain tests/manual/ and nothing else, and without it those files are not collected at all — so no CI can reach a scratchpad that spends money. A positional argument picks one file:

npm run test:manual                          # the whole tier
npm run test:manual -- structured-output     # one file

The unit tier is guarded: a unit test that reaches the network fails. Three did so by accident during development, and each passed for the wrong reason — an auth failure throws just as convincingly as a missing implementation.

llm-mock needs no credentials and costs nothing; it is configured in .env.test, committed on purpose. Real provider keys go in .env.test.local, which is git-ignored.


Why v0.1 is kept

v0.1 is frozen on main with 8 ADRs, as a map of provider quirks paid for against real APIs. Several were carried into this rewrite and re-confirmed against a live server:

  • Azure lists deployments with api-version=2023-03-15-preview hardcoded: newer versions return 404 on that endpoint even when valid for inference (ADR-0004).
  • Gemini Files enforces a fixed 48 h retention; purpose and expires_after are accepted and ignored.
  • Gemini Enterprise has no Files API at all, and is fronted by Cloud Storage instead.
  • Gemini Enterprise lists publisher models globally and only on v1beta1 — the project-qualified path 404s, and so does v1. The same shape as Azure's pinned api-version above, re-confirmed against a live project on 2026-08-15.
  • Eleven error categories with httpStatus fallbacks (502 connection, 504 timeout, 500 otherwise) so an error can be forwarded straight to a client (ADR-0006).

Consult it without leaving the branch:

git show main:src/internal/providers/azure/azure.models.ts