Open source · MIT · TypeScript · Node & Deno
AI Gateway
One HTTP endpoint for every model provider. Name your accounts, alias your models, and call them from any language or from the terminal. Built on AI Bridge, so custom providers and dialects work unchanged.
What It Does
AI Bridge gives TypeScript code one format for every provider. AI Gateway puts that format behind HTTP, so services in any language, scripts and shell pipelines can share it. Credentials stay on the server, callers refer to accounts and models by name, and switching the model behind an alias is a config change, not a code change.
The gateway ships as two packages that share one config format and one HTTP contract.
| Package | What it is |
|---|---|
@productivehub/ai-gateway-api | Mountable Hono HTTP API and a standalone Node or Deno listener |
@productivehub/ai-gateway-cli | The ai-gateway command: completions, model and account discovery, and serve |
The CLI never calls providers directly. It sends the same HTTP requests to the API, either in-process with no socket opened, or to a running server with --url.
One Endpoint, Any Response Shape
POST /{model} runs a completion. The body is always AI Bridge's canonical input, covering messages, media, tools, reasoning, caching and structured output. Query parameters pick the provider, the named account, and the response dialect.
curl 'http://127.0.0.1:8787/llama3.2:latest?provider=ollama&dialect=anthropic' \
-H 'Content-Type: application/json' \
-d '{"messages":[{"role":"user","content":"Hello"}],"maxOutputTokens":256}'
The response keeps the same envelope whatever dialect you ask for. output is in the requested shape, while usage stays canonical, so token accounting looks the same across providers.
{
"provider": "ollama",
"key": "ollama",
"model": "llama3.2:latest",
"dialect": "anthropic",
"output": { "type": "message", "role": "assistant", "content": [...] },
"usage": { "inputTokens": 8, "outputTokens": 3, "totalTokens": 11 },
"raw": { ... },
"meta": { "startedAt": "...", "endedAt": "...", "durationMs": 100 }
} Named Accounts and Model Aliases
A JSON config declares accounts under keys and public model names under models. Two Anthropic accounts, a work one and a personal one, can sit side by side, and callers choose between them by name.
{
"defaultKey": "claude-work",
"keys": {
"claude-work": { "provider": "anthropic", "apiKeyEnv": "ANTHROPIC_WORK_API_KEY" },
"claude-personal": { "provider": "anthropic", "apiKeyEnv": "ANTHROPIC_PERSONAL_API_KEY" },
"cloud": { "provider": "ollama-cloud", "apiKeyEnv": "OLLAMA_CLOUD_API_KEY" }
},
"models": {
"writer": { "key": "claude-work", "model": "your-claude-model-id" },
"coder": { "key": "cloud", "model": "your-cloud-model-id" }
}
} POST /writer resolves to the model and account behind that alias. Native model IDs still work directly with ?key=claude-work. Keys are read from the environment variables you name, and the accounts in the file are the complete registry: nothing else in the environment is added automatically.
From the Terminal
The ai-gateway command reads the same config. Prompts come from arguments or stdin, so it fits into shell pipelines.
ai-gateway complete writer "Summarize this repo in one line"
git diff | ai-gateway complete coder -s "Review this diff"
ai-gateway complete llama3.2 hi --provider ollama --dialect openai
ai-gateway models --key cloud # provider catalog, one model ID per line
ai-gateway models --configured # alias, key, provider, native model
ai-gateway keys # account, provider, base URL
ai-gateway serve --config ./gateway.config.json
With the bridge dialect it prints the reply text. Other dialects print their JSON, and --json prints the full envelope. Exit codes separate provider errors from usage errors, so scripts can tell them apart.
Mount It or Run It Standalone
The API is a Hono app. Mount it inside a server you already run, and it shares that server's listener and middleware.
import { Hono } from "hono";
import { createDefaultGateway } from "@productivehub/ai-gateway-api";
const server = new Hono();
server.route("/api/ai", createDefaultGateway());
// Pass server.fetch to your existing HTTP listener.
Or run it on its own with ai-gateway serve, which uses native Deno.serve on Deno 2+ and @hono/node-server on Node 22+. It binds to 127.0.0.1:8787 by default. For custom registries, createGateway({ bridge }) accepts any AI Bridge instance you build.
Endpoints
| Route | Purpose |
|---|---|
POST /{model} | Run a completion. Query: provider, key, dialect |
GET /models | Provider model catalog for the selected account |
GET /models/configured | Configured aliases with their models, accounts and providers |
GET /keys | Named accounts, without API keys or environment references |
GET /health | Liveness check that never contacts a provider |
The gateway does not include authentication. Attach your existing Hono middleware before mounting it, or keep the standalone listener on localhost. Errors return a short JSON message with a meaningful status code, and SDK payloads and stack traces stay out of HTTP responses.
Status and Contributing
AI Gateway is at version 0.1.0 and is not yet published to npm. It builds from source alongside AI Bridge. Runtime smoke tests drive all four built-in providers through a real listener against mocked upstream HTTP, so they need no API keys or paid requests.
The project is MIT-licensed and maintained by Segev Shmueli as part of ProductiveHub. Read the API and CLI docs and the contributing guide, and open an issue on GitHub for bugs or feature requests.
Running AI Across Teams and Accounts?
We design the infrastructure behind multi-model AI systems: provider access, account separation, and cost visibility. If you are working out how your teams should reach models, the first conversation is free.