ai-gateway/ai-gateway-bundle

PHP AI Gateway — Unified LLM proxy with fallback, caching, rate limiting and cost tracking

Maintainers

Package info

github.com/symfony-ai-gateway/symfony-ai-gateway

Type:symfony-bundle

pkg:composer/ai-gateway/ai-gateway-bundle

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.1 2026-05-15 07:21 UTC

This package is auto-updated.

Last update: 2026-05-15 07:30:22 UTC


README

Symfony bundle that turns any project into an AI gateway — unified LLM access, per-key auth, budget enforcement, cost tracking, and a dashboard.

Packagist

Why?

Every project that calls LLMs reinvents the same plumbing: provider SDKs, API key management, retry logic, cost tracking, budget limits. AIGateway bundles all of this into one Symfony package powered by the official Symfony AI library.

One composer require, all models.

What it does

  • Unified API — Expose /v1/chat/completions, /v1/models, /v1/health in your Symfony app
  • Multi-provider — Two formats cover everything: openai (any OpenAI-compatible endpoint) and anthropic
  • Load balancing — Route requests across multiple deployments with weighted, round-robin, least-busy, cost-based, or latency-based strategies
  • Per-key auth — Hierarchical teams with restrictive rule inheritance
  • Budget enforcement — Daily/monthly per-key budget limits in USD
  • Rate limiting — Sliding window per key
  • Fallback pipelines — Try model A → model B → model C automatically
  • Response caching — Deterministic SHA-256 cache
  • Cost tracking — Token counting and cost per request
  • Streaming SSE — Server-sent events for chat completions
  • Prometheus metricsai_gateway_requests_total, ai_gateway_cost_dollars_total, etc.
  • Web dashboard — Dark-themed UI at /dashboard with Chart.js analytics
  • CLI management — Full provider, model, key, and team management from the command line
  • Route prefix — Optional routes.prefix to mount under /ai-gateway/ or any prefix

Supported Providers

Two formats, 100+ providers:

Format Providers
openai OpenAI, DeepSeek, Google Gemini, Groq, OpenRouter, Mistral, Together AI, AWS Bedrock, Azure OpenAI, Cohere, Fireworks, Perplexity, Ollama, vLLM, HuggingFace TGI, any OpenAI-compatible endpoint
anthropic Anthropic (Claude)

Just set format: openai and point base_url to the provider. Examples:

Provider format base_url
OpenAI openai (default)
DeepSeek openai https://api.deepseek.com
Google Gemini openai https://generativelanguage.googleapis.com/v1beta/openai/
Groq openai https://api.groq.com/openai/v1
OpenRouter openai https://openrouter.ai/api/v1
AWS Bedrock openai https://bedrock-mantle.us-east-1.api.aws/v1
Mistral openai https://api.mistral.ai/v1
Ollama (local) openai http://localhost:11434/v1
Anthropic anthropic (default)

Install

composer require ai-gateway/ai-gateway-bundle

Symfony Flex auto-registers the bundle. If not:

// config/bundles.php
return [
    AIGateway\Bundle\AIGatewayBundle::class => ['all' => true],
];

Configure

# config/packages/ai_gateway.yaml
ai_gateway:
    # Everything is managed via the dashboard or CLI.
    # See "CLI Commands" and "Dashboard" sections below.

    dashboard:
        tokenRequired: true
        token: '%env(DASHBOARD_TOKEN)%'
# .env.local
DASHBOOT_TOKEN=your-secret-token-here

Providers and models are stored in the database and managed via the dashboard or CLI. No YAML editing required after initial setup.

Load routes

Add to your config/routes.yaml:

ai_gateway:
    resource: .
    type: ai_gateway

All routes are now available: /v1/chat/completions, /v1/models, /v1/health, /dashboard, etc.

With a prefix

ai_gateway:
    routes:
        prefix: /ai-gateway
    dashboard:
        token: '%env(DASHBOARD_TOKEN)%'

Routes become /ai-gateway/v1/chat/completions, /ai-gateway/dashboard, etc.

Use in your code

Inject GatewayInterface wherever you need AI:

use AIGateway\Core\GatewayInterface;
use AIGateway\Core\NormalizedRequest;

final class MyService
{
    public function __construct(
        private readonly GatewayInterface $gateway,
    ) {}

    public function ask(string $prompt): string
    {
        $request = new NormalizedRequest(
            model: 'smart',
            messages: [['role' => 'user', 'content' => $prompt]],
        );

        $response = $this->gateway->chat($request);

        return $response->content;
    }
}

You control the routes, auth, and middleware. AIGateway handles the provider communication via Symfony AI.

Dashboard Protection

The dashboard (/dashboard/*) exposes sensitive data: API keys, teams, budgets, usage stats. You have three options to protect it:

Option 1: Symfony Firewall (recommended for existing projects)

If your project already has authentication, put the dashboard behind your firewall:

# config/packages/security.yaml
security:
    firewalls:
        dashboard:
            pattern: ^/dashboard
            # your existing auth config...

This is the standard Symfony approach — the dashboard inherits your app's login system, roles, etc.

Option 2: Dashboard Token (built-in)

For projects without a full auth system, enable the built-in token protection:

# config/packages/ai_gateway.yaml
ai_gateway:
    dashboard:
        tokenRequired: true
        token: '%env(DASHBOARD_TOKEN)%'
# .env.local
DASHBOARD_TOKEN=your-secret-token-here

When enabled, accessing /dashboard without a valid token shows a login form. Once authenticated, the token is passed in all links (?token=...).

API routes (/v1/*) are not affected — only the dashboard UI.

Option 3: Both

You can combine both: the firewall handles the main auth, and the dashboard token adds an extra layer. Or use the firewall for the main app and the token for a separate standalone deployment.

Disable the dashboard entirely

ai_gateway:
    dashboard:
        enabled: false

Dashboard CRUD

The dashboard lets you manage everything from the browser — no YAML editing required. Tables are auto-created on first dashboard access.

Providers

Add, edit, or delete LLM providers directly from /dashboard/providers. Each provider has:

Field Description
Name Unique identifier (used in model config)
Format openai, anthropic, gemini, ollama, or azure
API Key Provider credential
Base URL Custom endpoint (leave empty for provider default)
Completions Path Defaults to /v1/chat/completions

Models

Create model aliases at /dashboard/models that map to a provider's model ID:

Field Description
Alias Gateway-facing name (e.g. gpt_4o)
Provider Links to a provider (from above)
Model Provider's model ID (e.g. gpt-4o)
Input Price Cost per million input tokens (USD)
Output Price Cost per million output tokens (USD)

Keys & Teams

Create API keys and teams from /dashboard/keys/new and /dashboard/teams/new. See the Auth & Teams section for the hierarchy model.

CLI Commands

All management can be done via CLI — ideal for automation, CI/CD, or headless setups.

Provider commands

# Create a provider
php bin/console provider:create \
    --name openai \
    --format openai \
    --api-key 'sk-...'

# Custom endpoint (OpenAI-compatible)
php bin/console provider:create \
    --name deepseek \
    --format openai \
    --api-key 'sk-...' \
    --base-url 'https://api.deepseek.com'

# Anthropic
php bin/console provider:create \
    --name anthropic \
    --format anthropic \
    --api-key 'sk-ant-...'

# Ollama (local)
php bin/console provider:create \
    --name ollama \
    --format ollama \
    --base-url 'http://localhost:11434'

# List providers
php bin/console provider:list

# Delete a provider (removes its models too)
php bin/console provider:delete openai

Model commands

# Create a model
php bin/console model:create \
    --alias gpt_4o \
    --provider openai \
    --model gpt-4o \
    --pricing-input 2.50 \
    --pricing-output 10.00

# List models
php bin/console model:list

# Delete a model
php bin/console model:delete gpt_4o

Team commands

# Create a team
php bin/console team:create \
    --name "Engineering" \
    --budget-per-day 100 \
    --budget-per-month 2000 \
    --rate-limit 60 \
    --models "gpt_4o,claude_sonnet"

# List teams
php bin/console team:list

# Show team details
php bin/console team:info <team-id>

API Key commands

# Create a key
php bin/console key:create \
    --name "Frontend App" \
    --team <team-id> \
    --budget-per-day 20 \
    --budget-per-month 400 \
    --rate-limit 30 \
    --models "gpt_4o" \
    --expires 1767225600

# List keys
php bin/console key:list

# Show key details
php bin/console key:info <key-id>

# Revoke a key
php bin/console key:revoke <key-id>

Stats

php bin/console stats
Command Description
provider:create Create a provider (openai, anthropic, gemini, ollama, azure)
provider:list List all providers
provider:delete Delete a provider and its models
model:create Create a model alias
model:list List all models
model:delete Delete a model alias
key:create Create an API key with optional overrides
key:list List all API keys
key:info Show key details + usage
key:revoke Disable an API key
team:create Create a team with rules
team:list List all teams
team:info Show team details + keys
stats Show gateway usage statistics

Auth & Teams

API key authentication is always enabled. Every request to /v1/* must include a valid Authorization: Bearer <key> header. This ensures all usage is tracked and billable.

Hierarchy

A team defines maximum limits. A key inherits team rules and can only restrict further:

Team "Engineering" ($100/day, gpt_4o + claude_sonnet)
  └── Key "Mathieu" ($20/day, gpt_4o only)
  └── Key "CI Bot" ($5/day, claude_sonnet only, 10 req/min)

Keys without a team have their own independent limits.

Key override validation

When a key belongs to a team, its overrides are validated against the team's limits at creation and edit time:

  • Budget/day must be ≤ team limit
  • Budget/month must be ≤ team limit
  • Rate limit must be ≤ team limit
  • Model whitelist must be a subset of the team's allowed models

Supported Providers

Provider Format Notes
OpenAI openai Native or custom base URL
Anthropic anthropic Claude models
Any OpenAI-compatible openai + base_url DeepSeek, Groq, OpenRouter, Mistral, Gemini, Ollama, Bedrock...

API Endpoints

Method Path Description
POST /v1/chat/completions Chat completion (supports stream: true)
GET /v1/models List available models
GET /v1/health Health check
GET /v1/metrics Prometheus metrics
GET /v1/stats JSON usage statistics
GET /dashboard Web dashboard — overview
GET /dashboard/providers List providers
GET/POST /dashboard/providers/new Add a provider
GET/POST /dashboard/providers/{name}/edit Edit a provider
POST /dashboard/providers/{name}/delete Delete a provider
GET /dashboard/models List models
GET/POST /dashboard/models/new Add a model
GET/POST /dashboard/models/{alias}/edit Edit a model
POST /dashboard/models/{alias}/delete Delete a model
GET /dashboard/keys List API keys
GET/POST /dashboard/keys/new Create an API key
GET /dashboard/keys/{id} Key details + usage
GET/POST /dashboard/keys/{id}/edit Edit key overrides + team
POST /dashboard/keys/{id}/revoke Revoke an API key
GET /dashboard/teams List teams
GET/POST /dashboard/teams/new Create a team
GET/POST /dashboard/teams/{id}/edit Edit a team
GET /dashboard/teams/{id} Team details + keys
GET /dashboard/requests Request logs & analytics

Configuration Reference

ai_gateway:
    routes:
        enabled: true              # Enable/disable route loading
        prefix: ''                 # Route prefix (e.g. /ai-gateway)

    dashboard:
        enabled: true              # Show/hide dashboard routes
        tokenRequired: false       # Require token to access dashboard
        token: null                # Token string or env var (e.g. '%env(DASHBOARD_TOKEN)%')

    # Optional: retry configuration
    retry:
        max_attempts: 2
        delay_ms: 1000
        backoff: fixed|exponential

Note: providers and models are stored in the database and managed via the dashboard or CLI commands.

Standalone Server

A pre-configured standalone server is available at symfony-ai-gateway-standalone — clone, configure, run. No Symfony knowledge required.

  • FrankenPHP (Go runtime, worker mode, concurrent requests)
  • SQLite with persistent volume
  • Dashboard and CLI for full management
  • One command to start: docker compose up -d

See the standalone repo for setup instructions.

Requirements

  • PHP >= 8.2
  • Symfony ^7.0 || ^8.0
  • Doctrine DBAL ^4.4 (for auth/rate-limit storage, SQLite or any DBAL-supported DB)

License

MIT