{{/* The limits tab of the people page. */}} {{define "limits_body"}} {{if not .BudgetsBind}} {{/* A budget is spend per period and spend comes from a price table. With no prices every request costs nothing, so these numbers read as limits and bind on nothing. Self-hosted models having no per-token price is ordinary; showing somebody a budget without saying so is not. */}} {{end}} {{if .Error}}{{end}} {{if .Message}}

{{.Message}}

{{end}} {{if .Rows}} {{/* The tree is the interface. A quota belongs to a branch, so the form to set one opens on that branch rather than asking somebody to name it again in a box at the bottom. */}} {{range .Rows}} {{if .MemberEditing}} {{end}} {{if .Editing}} {{end}} {{end}}
WhereRequests/minTokens/min BudgetSpent
{{.Path}} {{.Scope}} {{if .Models}}
only {{.Models}}
{{else if .ModelsFrom}}
models limited by {{.ModelsFrom}}
{{end}} {{if .Member}}
each member here: {{.Member}}
{{end}} {{if .Shadowed}} {{/* A value that is written here and never reached. Resolution takes the most restrictive along the chain, so without saying so the page would show a number as though it applied. */}}
{{.Shadowed}}
{{end}}
{{template "quota-value" dict "Own" .RPM "Up" .RPMUp "From" .RPMFrom}} {{template "quota-value" dict "Own" .TPM "Up" .TPMUp "From" .TPMFrom}} {{if .Budget}}{{.Budget}}{{if .Period}}/{{.Period}}{{end}} {{else}}{{template "quota-value" dict "Own" "" "Up" .BudgetUp "From" .BudgetFrom}}{{end}} {{.Spend}} {{if .HasPct}} {{.Percent}}%{{end}} {{if .Editing}}close {{else}}{{if .HasAny}}change{{else}}set{{end}}{{end}} {{if .MemberEditing}}close {{else}}per member{{end}}
{{template "quota-form" (dict "Scope" (printf "%s-member" .Scope) "ID" .ID "F" .MemberRaw "CSRF" $.CSRF "Title" (printf "Each member of %s, separately" .Crumb) "Note" "Every member gets this much here, counted apart from the others — a fair share rather than one pool.")}}

Quota for {{.Crumb}}, shared by everything beneath it. A blank field means no limit of that kind, not a limit of zero.

Cancel

60 ↑ is held by a limit set higher up — hover it to see where. A value set here is in normal type.

{{else}}

Nothing to give a quota to yet. Make an organization on the Organizations & people tab first.

{{end}}

People

A person's own limit covers everything they do, across all their keys, projects and the chat page. {{.Personal}}

{{if .People}} {{range .People}} {{if .Editing}} {{end}} {{end}}
PersonRequests/minTokens/min BudgetSpent
{{.Email}} {{if .Models}}
only {{.Models}}
{{end}}
{{or .RPM "—"}} {{or .TPM "—"}} {{if .Budget}}{{.Budget}}{{if .Period}}/{{.Period}}{{end}}{{else}}—{{end}} {{.Spend}} {{if .HasPct}} {{.Percent}}%{{end}} {{if .Editing}}close {{else}}{{if .HasAny}}change{{else}}set{{end}}{{end}}
{{template "quota-form" (dict "Scope" "user" "ID" .ID "CSRF" $.CSRF "F" (dict "RPM" .RPM "TPM" .TPM "Budget" .Budget "Period" .Period "Models" .Models "HasAny" .HasAny) "Title" (printf "%s, everywhere" .Email) "Note" "Across every key this person holds, every project they use and the chat page.")}}
{{else}}

Nobody has been approved yet.

{{end}} {{if .HasCapacity}}

Capacity

What a part of the tree is guaranteed of the cluster, and the most it may hold: GPUs, CPU cores and memory, counted from the replicas of the models it owns and of those beneath it. What it holds within its guarantee is never taken for someone else's model; beyond it, it borrows free room and gives it back when asked. A model's owner is set on its card on the mirror page.

{{if .Capacity}} {{range .Capacity}}{{end}}
WhereGPUsCoresMemory GBSet by
{{or .Name .Scope}} {{or .GPUs "—"}} {{or .Cores "—"}} {{or .Memory "—"}} {{.UpdatedBy}} change

Each figure is held of guaranteed (at most the limit); — is not governed.

{{else}}

No capacity quotas: every model shares the cluster by its class alone.

{{end}} {{if .Scopes}}

{{if .CapForm.Scope}}Change{{else}}Set{{end}} a capacity quota. A blank field is not governed; 0 is none at all.

{{if .CapForm.Scope}}Cancel{{end}}
{{else}}

Nothing to give a capacity quota to yet. Make an organization on the Organizations & people tab first.

{{end}} {{end}}
How limits combine

Along a branch the most restrictive value wins, so a team cannot raise what its organization set and a project cannot raise its team's. Only an organization's own limit is bounded by nothing. Model lists intersect: a project cannot allow a model its team withheld.

Per-key limits are not set here: a key is bounded by its project, and putting every caller's throughput one click from an admin session is more than this page should do — llmgw keys limits --scope key.

{{end}} {{/* A limit as the table shows it: the row's own value, else the one it is held to from above, marked as inherited and saying from where. */}} {{/* The form for a limit that is not a branch's own: per member, or a person. */}} {{define "quota-form"}}
{{/* From a panel on the people tab: the answer comes back to that panel. */}} {{with .Sel}}{{end}}

{{.Title}}. {{.Note}} A blank field means no limit of that kind.

{{if not .Sel}}Cancel{{end}}
{{end}} {{define "quota-value"}}{{if .Own}}{{.Own}}{{else if .Up}}{{.Up}} ↑{{else}}—{{end}}{{end}}