TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1# PolyLLM — UI brief for contributors (humans and agents)23PolyLLM (www.polyllm.io) is a **universal control center for AI models**: users bring their own API keys4(OpenAI, Anthropic, Gemini, xAI), discover current models, configure them precisely, chat with real streaming,5compare models in the Arena and track usage/costs. Tagline: **"Your models. Your keys. One workspace."**67## Stack & conventions8- Next.js 16 App Router, React 19, TypeScript strict, Tailwind v4 (tokens in `src/app/globals.css`), shadcn-style9 primitives in `src/components/ui/*` (button, input/textarea/label/field, badge, dialog, dropdown-menu, popover,10 select, slider, switch, tabs, tooltip, toast (`toast.success/error/info`), misc: Card/CardHeader/CardBody, Stat,11 PageHeader, EmptyState, Skeleton, CopyButton, Kbd, Spinner, Divider). Icons: `lucide-react`. Motion: `motion/react` (sparingly).12- Client data: `useApi<T>(url)` (SWR) and `api<T>(url, { method, json })` from `src/lib/client/api.ts`;13 `streamEvents(url, body, onEvent, signal)` for SSE. Types: `src/lib/client/types.ts`. Provider metadata:14 `src/lib/client/providers.ts` (`PROVIDERS`, `PROVIDER_ORDER`, `providerName`). Brand: `src/components/brand/logo.tsx`15 (`Logo`, `LogoMark`), `src/components/brand/provider-icon.tsx` (`ProviderIcon`).16- App state: `useApp()` from `src/components/app/store.tsx` → `{ user, preferences, updatePreferences, models, modelsByKey,17 favorites, recents, connectedProviders, connections, folders, toggleFavorite, refreshModels, refreshConnections,18 selectedModelKey, setSelectedModelKey, setPaletteOpen }`. Everything under `/app/*` is wrapped by the shell19 (sidebar + command palette) in `src/app/app/layout.tsx`; pages render inside `<div className="relative flex min-w-0 flex-1 flex-col">`.20 A page should typically be `<main className="min-h-0 flex-1 overflow-y-auto scrollbar-thin"><div className="mx-auto w-full max-w-5xl px-4 py-6 sm:px-6 lg:px-8">…</div></main>`.21- Auth client: `authClient`, `signIn`, `signUp`, `signOut`, `useSession` from `src/lib/auth-client.ts` (Better Auth 1.7).22 Server: `requireUser()` / `getSession()` in `src/lib/session.ts`.23- Formatting helpers: `formatUsd`, `formatTokens`, `formatMs`, `formatRelative`, `formatNumber`, `cn` in `src/lib/utils.ts`.24- Never render key material. Connections only expose `keyHint` like `sk-••••••••9A2K`.25- React Compiler lint rules apply: no setState synchronously in effects without the eslint-disable, no components defined26 inside render, derive state with useMemo. Run `pnpm lint` and `pnpm typecheck`.2728## Design language (must feel premium, unique, not a template)29- Minimal, dense-when-useful, excellent typography (Geist Sans/Mono via `font-sans`/`font-mono`), subtle borders30 (`border-border`), surfaces `bg-bg / bg-bg-subtle / bg-bg-muted / bg-bg-elevated`, text `text-fg / text-fg-muted / text-fg-subtle`,31 accent `text-accent / bg-accent / bg-accent-soft`, semantic `success/warning/danger/info` (+ `-soft`). Radii `rounded-md/lg/xl`.32 Provider colors: `text-openai`, `text-anthropic`, `text-gemini`, `text-xai` or `style={{color: PROVIDERS[p].colorVar}}`.33- Dark and light must both look great. No cheap gradients, no childish AI imagery, no huge empty whitespace, no boxed-card overload.34 A single restrained gradient (`.text-gradient`) is allowed for hero words. Use `.dot-grid` / `.glass` utilities sparingly.35- Mobile first: no horizontal overflow, 16px inputs on mobile (`text-[15px] sm:text-sm` is already in Input), safe-area aware.36- Keyboard-first: ⌘K palette, ⌘N new chat, ⌘Enter send, Esc stop, ⌘/ model selector, ⌘B sidebar.37- Accessibility: semantic HTML, labels, visible focus, aria on icon buttons, reduced motion respected.3839## API routes (all JSON unless noted; all under a verified session)40- `GET /api/models` → `{ models: PolyModel[], favorites: string[], recents: string[], connectedProviders }`;41 `POST /api/models {action:"toggle-favorite", modelKey}`; `POST /api/models/sync {provider?}` → `{results: SyncResult[]}`.42- `GET /api/providers` → `{connections: PublicConnection[]}`; `PUT /api/providers {provider, apiKey}` → `{ok, error?, modelsAvailable?, connections}`;43 `POST /api/providers {action:"validate", provider}`; `DELETE /api/providers?provider=`.44- `GET /api/conversations?q&provider&model&folder&archived=1&pinned=1&since&until&limit&cursor`; `POST /api/conversations`;45 `GET|PATCH|DELETE /api/conversations/:id`; `POST /api/conversations/:id/actions {action: duplicate|branch|export|share|unshare|share-status|delete-message}`.46- `POST /api/chat` (SSE) body `ChatRequestInput` → events `ChatStreamEvent` (see `src/lib/client/types.ts`).47- `GET /api/folders`, `POST {name,color}`, `PATCH {id,…}`, `DELETE ?id=`.48- `POST /api/attachments` (multipart `file`) → `{attachment}`; `GET /api/attachments?id=` streams the file.49- `GET /api/usage?range=today|7d|30d|all` → `{ totals, series[{bucket,requests,inputTokens,outputTokens,costUsd}], byProvider[], byModel[], recent[] }`.50- `GET /api/presets` → `{modelPresets, promptPresets}`; `POST /api/presets?kind=model|prompt`; `PATCH ?kind&id`; `DELETE ?kind&id`.51- `GET /api/preferences` / `PATCH /api/preferences` (theme, defaultModelKey, defaultSystemPrompt, enterToSend, streaming, codeWrap, showReasoning, showCosts, autoTitle, onboardingCompleted).52- `GET /api/arena` → `{sessions}`; `POST /api/arena {prompt, systemPrompt?, modelKeys[1..4], settings?, attachmentIds?}` → `{session}`;53 `POST /api/arena/stream {sessionId, modelKey}` (SSE: meta → text-delta/reasoning-delta/citation → done|error); `PATCH /api/arena {responseId, ratings}`.54- `GET /api/account` → `{audit}`; `GET /api/account?export=1` downloads the full account export.55- `GET /api/search?q=`.56- Admin: `GET /api/admin/providers`, `POST /api/admin/providers {action:"sync", provider?}` (owner only, `user.isAdmin`).57- Better Auth: `/api/auth/*` (client SDK). Email verification is mandatory: unverified users are redirected to `/verify-email`.5859## Model capability sheet (drives every configuration UI)60`PolyModel.capabilities` {text, vision, audioInput, audioOutput, imageGeneration, video, reasoning, tools, structuredOutput,61streaming, files, webSearch}; `parameters` {temperature, topP, topK, maxTokens, reasoningEffort, reasoningEffortLevels[],62thinkingBudget, thinkingBudgetRange, stop, seed, frequencyPenalty, presencePenalty, verbosity, temperatureRange};63`limits` {contextTokens, maxOutputTokens}; `pricing` {inputPerMillion, cachedInputPerMillion, outputPerMillion};64`status` active|preview|deprecated|unknown; `metadata.shutdownDate`, `metadata.aliases`, etc. **Never show a control the model does not support.**65