litellm-rs 0.6.0

A high-performance AI Gateway written in Rust, providing OpenAI-compatible APIs with intelligent routing, load balancing, and enterprise features
Documentation
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="color-scheme" content="light dark">
  <title>LiteLLM-RS Admin</title>
  <link rel="stylesheet" href="/admin/dashboard/app.css">
  <script src="/admin/dashboard/app.js" defer></script>
</head>
<body>
  <a class="skip-link" href="#main-content">Skip to content</a>
  <header class="topbar">
    <div>
      <p class="eyebrow">LiteLLM-RS</p>
      <h1>Admin dashboard</h1>
    </div>
    <div class="session-actions">
      <span id="session-label">Signed out</span>
      <button id="sign-out" class="secondary" type="button" hidden>Sign out</button>
    </div>
  </header>

  <main id="main-content">
    <section id="login-panel" class="auth-card" aria-labelledby="login-title">
      <div>
        <p class="eyebrow">Secure access</p>
        <h2 id="login-title">Sign in as an administrator</h2>
        <p>Credentials are sent to the existing gateway login endpoint. Tokens
          stay in this tab's memory and are cleared on reload.</p>
      </div>
      <form id="login-form">
        <label for="username">Username</label>
        <input id="username" name="username" autocomplete="username" required>
        <label for="password">Password</label>
        <input id="password" name="password" type="password"
               autocomplete="current-password" required>
        <button type="submit">Sign in</button>
      </form>
    </section>

    <section id="dashboard-shell" hidden>
      <nav class="tabs" aria-label="Dashboard sections">
        <button class="tab active" type="button" data-view="keys"
                aria-controls="keys-panel" aria-selected="true">API keys</button>
        <button class="tab" type="button" data-view="teams"
                aria-controls="teams-panel" aria-selected="false">Teams</button>
        <button class="tab" type="button" data-view="spend"
                aria-controls="spend-panel" aria-selected="false">Spend</button>
      </nav>

      <section id="keys-panel" class="panel" aria-labelledby="keys-title">
        <div class="panel-heading">
          <div>
            <p class="eyebrow">Credentials</p>
            <h2 id="keys-title">API keys</h2>
          </div>
          <button id="refresh-keys" class="secondary" type="button">Refresh</button>
        </div>

        <details class="create-card">
          <summary>Create a scoped key</summary>
          <form id="create-key-form" class="form-grid">
            <label for="key-name">Name</label>
            <input id="key-name" name="name" required maxlength="120">
            <label for="key-description">Description</label>
            <input id="key-description" name="description" maxlength="500">
            <label for="key-team">Owner</label>
            <select id="key-team" name="team_id">
              <option value="">My administrator user</option>
            </select>
            <label for="key-models">Allowed model patterns</label>
            <input id="key-models" name="allowed_models" required
                   placeholder="gpt-4o, claude-*"
                   aria-describedby="key-scope-help">
            <label for="key-endpoints">Allowed endpoint patterns</label>
            <input id="key-endpoints" name="allowed_endpoints" required
                   placeholder="/v1/chat/completions, /v1/embeddings"
                   aria-describedby="key-scope-help">
            <p id="key-scope-help" class="field-help">Comma-separated values are
              required. The unrestricted <code>*</code> value is not accepted.</p>
            <button type="submit">Create key</button>
          </form>
        </details>

        <div class="table-wrap">
          <table>
            <caption>Keys visible to the signed-in administrator</caption>
            <thead>
              <tr>
                <th scope="col">Name</th>
                <th scope="col">Prefix</th>
                <th scope="col">Owner</th>
                <th scope="col">Status</th>
                <th scope="col">Created</th>
                <th scope="col">Action</th>
              </tr>
            </thead>
            <tbody id="keys-body"></tbody>
          </table>
        </div>
        <p id="keys-empty" class="empty-state" hidden>No API keys found.</p>
        <div class="pagination" aria-label="API key pages">
          <button id="keys-previous" class="secondary" type="button">Previous</button>
          <span id="keys-page">Page 1</span>
          <button id="keys-next" class="secondary" type="button">Next</button>
        </div>
      </section>

      <section id="teams-panel" class="panel" aria-labelledby="teams-title" hidden>
        <div class="panel-heading">
          <div>
            <p class="eyebrow">Ownership</p>
            <h2 id="teams-title">Teams</h2>
          </div>
          <button id="refresh-teams" class="secondary" type="button">Refresh</button>
        </div>

        <details class="create-card">
          <summary>Create a team</summary>
          <form id="create-team-form" class="form-grid">
            <label for="team-name">Unique name</label>
            <input id="team-name" name="name" required
                   pattern="[A-Za-z0-9_-]+" maxlength="120"
                   aria-describedby="team-name-help"
                   title="Use only letters, numbers, underscores, and hyphens.">
            <p id="team-name-help" class="field-help">Use only letters, numbers,
              underscores, and hyphens.</p>
            <label for="team-display-name">Display name</label>
            <input id="team-display-name" name="display_name" maxlength="120">
            <label for="team-description">Description</label>
            <input id="team-description" name="description" maxlength="500">
            <button type="submit">Create team</button>
          </form>
        </details>

        <div class="table-wrap">
          <table>
            <caption>Teams visible to the signed-in administrator</caption>
            <thead>
              <tr>
                <th scope="col">Name</th>
                <th scope="col">Display name</th>
                <th scope="col">Status</th>
                <th scope="col">Members</th>
                <th scope="col">Action</th>
              </tr>
            </thead>
            <tbody id="teams-body"></tbody>
          </table>
        </div>
        <p id="teams-empty" class="empty-state" hidden>No teams found.</p>
        <div class="pagination" aria-label="Team pages">
          <button id="teams-previous" class="secondary" type="button">Previous</button>
          <span id="teams-page">Page 1</span>
          <button id="teams-next" class="secondary" type="button">Next</button>
        </div>
      </section>

      <section id="spend-panel" class="panel" aria-labelledby="spend-title" hidden>
        <div class="panel-heading">
          <div>
            <p class="eyebrow">Current pages</p>
            <h2 id="spend-title">Usage and spend</h2>
            <p>Key and team scopes are shown separately to avoid double-counting.</p>
          </div>
          <button id="refresh-spend" class="secondary" type="button">Refresh</button>
        </div>

        <div class="spend-grid">
          <div class="table-wrap">
            <table>
              <caption>Spend for API keys on the current key page</caption>
              <thead>
                <tr>
                  <th scope="col">Key</th>
                  <th scope="col">Today</th>
                  <th scope="col">Total</th>
                  <th scope="col">Requests</th>
                  <th scope="col">Tokens</th>
                </tr>
              </thead>
              <tbody id="key-spend-body"></tbody>
            </table>
          </div>
          <p id="key-spend-empty" class="empty-state" hidden>
            No API keys on the current page.
          </p>
          <div class="table-wrap">
            <table>
              <caption>Spend for teams on the current team page</caption>
              <thead>
                <tr>
                  <th scope="col">Team</th>
                  <th scope="col">Today</th>
                  <th scope="col">Total</th>
                  <th scope="col">Requests</th>
                  <th scope="col">Tokens</th>
                </tr>
              </thead>
              <tbody id="team-spend-body"></tbody>
            </table>
          </div>
          <p id="team-spend-empty" class="empty-state" hidden>
            No teams on the current page.
          </p>
        </div>
      </section>
    </section>
  </main>

  <div id="status-region" class="status" aria-live="polite"></div>
  <div id="error-region" class="error" role="alert" hidden></div>

  <dialog id="raw-key-dialog" aria-labelledby="raw-key-title">
    <h2 id="raw-key-title">Copy this key now</h2>
    <p>The raw key is shown once and is not retained after this dialog closes.</p>
    <pre id="raw-key-value" tabindex="0"></pre>
    <div class="dialog-actions">
      <button id="copy-raw-key" type="button">Copy key</button>
      <button id="dismiss-raw-key" class="secondary" type="button">Dismiss</button>
    </div>
  </dialog>
</body>
</html>