Intelligent routing layer for Quilonix Studio — an AI-native coding platform where multiple AI providers connect through a single gateway.
Quilonix AI Gateway is a lightweight, modular TypeScript service that sits between Quilonix Studio's frontend and multiple AI coding providers. It provides:
- Unified API — one endpoint for all providers
- Smart routing — automatically picks the best provider per request
- Streaming — consistent SSE interface regardless of upstream format
- Resilience — circuit breakers, retries, and automatic fallback
- Security — encrypted credential storage, no telemetry sent externally
┌─────────────────────────────────────────────────┐
│ Quilonix Studio (Frontend) │
└───────────────────────┬─────────────────────────┘
│ HTTP / SSE
▼
┌─────────────────────────────────────────────────┐
│ Quilonix AI Gateway │
│ │
│ ┌─────────┐ ┌────────┐ ┌──────────────────┐ │
│ │ API │→ │ Router │→ │ Request Pipeline │ │
│ └─────────┘ └────────┘ └──────────────────┘ │
│ │ │ │ │
│ ┌─────────┐ ┌────────┐ ┌──────────────────┐ │
│ │Sessions │ │Circuit │ │ Stream Manager │ │
│ │ │ │Breaker │ │ │ │
│ └─────────┘ └────────┘ └──────────────────┘ │
│ │
│ ┌────────────── Connector Registry ───────────┐│
│ │ OpenAI │ Ollama │ OpenRouter │ ... more ... ││
│ └─────────────────────────────────────────────┘│
└─────────────────────────────────────────────────┘
# Install dependencies
npm install
# Development (with hot reload)
npm run dev
# Build for production
npm run build
# Run production build
npm start
# Run tests
npm testThe gateway starts at http://127.0.0.1:4190 by default.
| Method | Path | Description |
|---|---|---|
POST |
/chat |
Chat completion (non-streaming) |
POST |
/stream |
Chat completion (SSE streaming) |
DELETE |
/stream/:id |
Cancel an active stream |
GET |
/models |
List available models |
GET |
/providers |
List providers and status |
POST |
/providers/connect |
Connect a provider |
POST |
/providers/disconnect |
Disconnect a provider |
GET |
/tools |
List available tools |
POST |
/tools/execute |
Execute a tool |
POST |
/sessions |
Get/create a workspace session |
GET |
/sessions/:id/conversations |
List conversations |
POST |
/sessions/:id/conversations |
Create a conversation |
GET |
/health |
Gateway health check |
Environment variables (all optional):
| Variable | Default | Description |
|---|---|---|
QUILONIX_PORT |
4190 |
Server port |
QUILONIX_HOST |
127.0.0.1 |
Bind address |
QUILONIX_LOG_LEVEL |
info |
Log level |
QUILONIX_ENCRYPTION_KEY |
— | 32+ char key for credential encryption |
QUILONIX_ROUTING_STRATEGY |
fallback-chain |
Default routing strategy |
QUILONIX_PREFERRED_PROVIDER |
— | Preferred provider ID |
QUILONIX_HEALTH_CHECK_INTERVAL |
30000 |
Health check interval (ms) |
QUILONIX_WORKSPACE_ROOT |
cwd |
Sandbox root for filesystem/terminal tools |
Per-provider base URLs and OAuth client IDs are also configurable — see .env.example.
src/
├── main.ts # Entry point
└── packages/
├── api/ # HTTP routes (Hono)
│ ├── app.ts # App factory
│ └── routes/ # Route handlers
├── auth/ # Authentication & credentials
│ ├── auth-manager.ts # Auth orchestration
│ ├── credential-store.ts # Encrypted credential storage
│ └── strategies/ # Pluggable auth strategies
│ ├── api-key.strategy.ts
│ ├── oauth.strategy.ts
│ ├── device-auth.strategy.ts
│ └── session-token.strategy.ts
├── config/ # Configuration & validation
│ ├── gateway-config.ts # Config manager
│ └── schema.ts # Zod schemas
├── connectors/ # Provider abstraction
│ ├── connector.interface.ts # The Connector contract
│ ├── base-connector.ts # Shared connector logic
│ ├── connector-registry.ts # Connector lookup & lifecycle
│ ├── openai-compatible.connector.ts # Reusable base for OpenAI-protocol providers
│ └── providers/
│ ├── provider-catalog.ts # Declarative registry of OpenAI-compatible providers
│ ├── connector-factory.ts # Builds & registers all connectors
│ ├── ollama.connector.ts # Native protocol: local Ollama
│ ├── anthropic.connector.ts # Native protocol: Claude Messages API
│ └── gemini.connector.ts # Native protocol: Gemini generateContent
├── gateway/ # Core orchestrator
│ ├── gateway.ts # Top-level Gateway class
│ └── request-pipeline.ts # Request lifecycle
├── logging/ # Structured logging (pino)
├── router/ # Smart routing engine
│ ├── router.ts # Routing strategies
│ ├── circuit-breaker.ts # Failure isolation
│ └── latency-tracker.ts # Latency-based routing
├── sessions/ # Workspace & conversation state
├── shared/ # Types, errors, event bus
├── streaming/ # Unified streaming
│ ├── stream-manager.ts # Stream lifecycle
│ └── stream-buffer.ts # Async iterable buffer
├── telemetry/ # Local-only metrics
└── tools/ # Unified tool execution layer
├── tool-registry.ts # Registration + provider-agnostic execution
└── builtin/ # Sandboxed built-in tools
├── filesystem.tools.ts # read/write/list (workspace-sandboxed)
└── terminal.tools.ts # run_command + git status/diff/log
| Provider | Auth Strategy | Notes |
|---|---|---|
| OpenAI Codex | API Key | OpenAI chat completions API |
| OpenRouter | API Key | Unified access to many upstream models |
| GitHub Copilot | Device Auth | OAuth device flow (RFC 8628) |
| Cursor | Session Token | Captured from Cursor login |
| Kiro | OAuth (paste token) | Free Claude-family with monthly credits |
| Antigravity | OAuth browser sign-in | Real Google sign-in, zero setup |
| Windsurf | OAuth (paste token) | Windsurf/Codeium account token |
| Continue | API Key | Routes to configured OpenAI-compatible host |
| Cline | API Key | Configurable OpenAI-compatible endpoint |
| OpenClaw | API Key | OpenAI-compatible endpoint |
| Qoder | Session Token | Free tier (Kimi/DeepSeek family) |
| Ollama | None | Local models, no auth (native protocol) |
| Anthropic (Claude) | API Key | Native Messages API (/v1/messages) |
| Google Gemini | API Key | Native generateContent API |
Most coding providers speak the OpenAI-compatible protocol and differ only in
base URL, auth strategy, and model list. These are declared as one-line entries in
the provider catalog (providers/provider-catalog.ts) and share a single
OpenAICompatibleConnector implementation.
Providers with a native (non-OpenAI) protocol get a dedicated connector class:
- Ollama — local
/api/chatprotocol - Anthropic (Claude) — native Messages API (
/v1/messages,x-api-key, content blocks, named SSE events) - Google Gemini — native
generateContentAPI (contents/parts,?key=auth)
These are registered via NATIVE_CONNECTORS in the connector factory.
Authentication is fully isolated into pluggable strategies:
ApiKeyStrategy— static bearer tokenOAuthStrategy— access token + refresh token rotationDeviceAuthStrategy— OAuth device flow for headless/CLI clientsSessionTokenStrategy— session token or cookie from web login
For OAuth providers, Quilonix mirrors how the official CLIs authenticate: it reuses each tool's real, first-party OAuth client and runs a temporary loopback server on that client's fixed callback port to catch the redirect. No OAuth app registration is required.
Flow (OAuthFlowManager + oauth-provider-config.ts):
- Dashboard →
POST /auth/oauth/start→ gateway starts a loopback server on the provider's port (e.g. Antigravity →localhost:51121/oauth-callback) and returns the provider's authorization URL. - The browser opens it; the user logs in at the real provider (e.g. Google).
- The provider redirects to the loopback server, which exchanges the code (PKCE or client-secret per provider) and connects the provider.
- Dashboard polls
GET /auth/oauth/statusuntilconnected.
Verified real configs live in oauth-provider-config.ts: Antigravity
(Google client, no PKCE, port 51121) and OpenAI Codex (PKCE, port 1455).
Providers without a verified client fall back to token paste, so a broken
invalid_client browser flow is never shown.
OpenAI-compatible provider (the common case) — add ONE catalog entry:
// src/packages/connectors/providers/provider-catalog.ts
{
id: 'my-provider',
displayName: 'My Provider',
kind: 'openai-compatible',
notes: 'API key auth against an OpenAI-compatible endpoint.',
buildSpec: () => ({
id: 'my-provider',
displayName: 'My Provider',
baseUrl: 'https://api.myprovider.com/v1',
authStrategy: new ApiKeyStrategy(),
defaultContextWindow: 128000,
}),
}That's it — no request code, no streaming code, no new class. It's built and registered automatically by the connector factory.
Provider with a non-OpenAI protocol — extend BaseConnector:
export class MyConnector extends BaseConnector {
readonly id = 'my-provider';
readonly displayName = 'My Provider';
readonly supportedAuthMethods = ['api-key'];
protected async onInitialize() { /* setup */ }
protected async onAuthenticate(creds) { /* validate */ }
protected async onRefreshSession() { return true; }
protected async onHealthCheck() { return 'healthy'; }
protected async onDisconnect() { /* cleanup */ }
async listModels() { /* ... */ }
async sendChat(options) { /* ... */ }
async *streamChat(options) { /* ... */ }
}Then add it to buildAllConnectors() in connector-factory.ts.
| Strategy | Description |
|---|---|
preferred |
Always use the configured preferred provider |
lowest-latency |
Pick the provider with the lowest observed latency |
round-robin |
Distribute evenly across providers |
quality-first |
Pick by known code-generation quality |
fallback-chain |
Use configured priority order |
user-preference |
Respect user's provider preference |
Routing rules can be added programmatically to match on task category, model pattern, or provider availability.
- Credentials encrypted at rest with AES-256-GCM when
QUILONIX_ENCRYPTION_KEYis set - No external telemetry — all metrics stay local
- CORS restricted to configured origins
- Structured error responses (no stack traces leaked to clients)
- Runtime: Node.js ≥ 20
- Language: TypeScript (strict mode)
- Framework: Hono (lightweight, web-standards based)
- Validation: Zod
- Logging: pino (structured JSON)
- Testing: Vitest
MIT