{ "openapi": "3.1.0", "info": { "title": "llmgw admin API", "version": "v1", "description": "The control plane's management API: what `llmgw ctl` and the console use.\n\nIt is served on the admin listener (admin_listen, 127.0.0.1:9090 by default), which stays on loopback unless admin_remote is set: reach it from elsewhere through an SSH tunnel. Every path under /api needs the admin token as a bearer token.\n\nThe listener also refuses, before the token is looked at: a Host header that is a name rather than an address or localhost; a request another site's page sent; and any method but GET and HEAD whose Content-Type is not application/json, even one with no body.\n\nDurations in bodies are integer nanoseconds, as Go encodes them. Generated from the route table in internal/control/adminapi; see docs/admin-api.md." }, "servers": [ { "url": "http://127.0.0.1:9090", "description": "The admin listener at its default address, admin_listen." } ], "security": [ { "adminToken": [] } ], "tags": [ { "name": "agents" }, { "name": "audit" }, { "name": "auth" }, { "name": "canaries" }, { "name": "capacity" }, { "name": "client-jobs" }, { "name": "eval" }, { "name": "explain-placement" }, { "name": "fabric-test" }, { "name": "fabrics" }, { "name": "facility" }, { "name": "federation" }, { "name": "guard" }, { "name": "jobs" }, { "name": "kb" }, { "name": "keys" }, { "name": "metrics" }, { "name": "models" }, { "name": "nodes" }, { "name": "notify" }, { "name": "nvlink" }, { "name": "openapi" }, { "name": "orgs" }, { "name": "plan" }, { "name": "presets" }, { "name": "projects" }, { "name": "quotas" }, { "name": "replicas" }, { "name": "requests" }, { "name": "restart" }, { "name": "settings" }, { "name": "summary" }, { "name": "teams" }, { "name": "train" }, { "name": "updates" }, { "name": "usage" }, { "name": "users" }, { "name": "weights" } ], "paths": { "/api/v1/agents/restart": { "post": { "operationId": "postAgentsRestart", "summary": "Have every node's agent start again; their engines keep serving", "tags": [ "agents" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentRestartView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/audit": { "get": { "operationId": "getAudit", "summary": "Changes made, newest first", "tags": [ "audit" ], "parameters": [ { "name": "since", "in": "query", "description": "How far back: 90m, 24h, 7d; 7d when absent.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "description": "The most events to answer with.", "schema": { "type": "integer" } }, { "name": "actor", "in": "query", "description": "Only changes by this actor.", "schema": { "type": "string" } }, { "name": "contains", "in": "query", "description": "Only events whose action or target contains this.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/store.AuditEvent" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/auth": { "get": { "operationId": "getAuth", "summary": "How people sign in: OIDC, a directory, SCIM, and the directory's last sync", "tags": [ "auth" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/auth/ldap/test": { "post": { "operationId": "postAuthLdapTest", "summary": "Try an auth.ldap block before it is kept: servers, the service account, people and groups", "tags": [ "auth" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LDAPTestRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LDAPTestView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/auth/secrets/{name}": { "put": { "operationId": "putAuthSecretsName", "summary": "Keep ldap-bind, oidc-client-secret or scim-token in the store, for settings to name as store:auth/NAME", "tags": [ "auth" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "ldap-bind, oidc-client-secret or scim-token.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SecretRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/canaries": { "get": { "operationId": "getCanaries", "summary": "Every canary, and how its two sides serve", "tags": [ "canaries" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/modelserve.CanaryView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/capacity": { "get": { "operationId": "getCapacity", "summary": "Every recorded measurement", "tags": [ "capacity" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CapacityView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/client-jobs": { "get": { "operationId": "getClientJobs", "summary": "Jobs clients asked for — 3D models — of every owner, newest first", "tags": [ "client-jobs" ], "parameters": [ { "name": "status", "in": "query", "description": "Only jobs in this status: queued, running, cancelling, completed, failed, cancelled, expired.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "description": "The most jobs to answer with; 50 when absent.", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/JobView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/client-jobs/{id}": { "get": { "operationId": "getClientJobsId", "summary": "One job a client asked for", "tags": [ "client-jobs" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, job_….", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/client-jobs/{id}/cancel": { "post": { "operationId": "postClientJobsIdCancel", "summary": "Stop a job, in the engine's queue too", "tags": [ "client-jobs" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, job_….", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/eval/runs": { "get": { "operationId": "getEvalRuns", "summary": "Quality runs, the newest first", "tags": [ "eval" ], "parameters": [ { "name": "model", "in": "query", "description": "Only this model's runs.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "description": "How many; a sensible number when absent.", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/eval.Live" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/eval/runs/{id}": { "get": { "operationId": "getEvalRunsId", "summary": "One quality run, with each case", "tags": [ "eval" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The quality run's ID, as starting it answered.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/eval.Live" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/eval/suites": { "get": { "operationId": "getEvalSuites", "summary": "The quality suites the control plane can run by name", "tags": [ "eval" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/eval.SuiteInfo" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/explain-placement": { "get": { "operationId": "getExplainPlacement", "summary": "Why a model could not be placed", "tags": [ "explain-placement" ], "parameters": [ { "name": "model", "in": "query", "required": true, "description": "The model's name or an alias.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExplainView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/fabric-test": { "post": { "operationId": "postFabricTest", "summary": "Measure bandwidth between two nodes, rail by rail", "tags": [ "fabric-test" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FabricTestRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FabricTestView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/fabrics": { "get": { "operationId": "getFabrics", "summary": "The physical fabrics and the names nodes give them", "tags": [ "fabrics" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/fabrics.Report" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/fabrics/{id}/topology": { "get": { "operationId": "getFabricsIdTopology", "summary": "One fabric's map, with the cluster's adapters live on it", "tags": [ "fabrics" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The physical fabric's ID, as GET /api/v1/fabrics lists it.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TopologyView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/facility": { "get": { "operationId": "getFacility", "summary": "The failure domains, their power against their caps, and what is held", "tags": [ "facility" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FacilityView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/facility/holds": { "post": { "operationId": "postFacilityHolds", "summary": "Hold a domain for maintenance: nothing new is placed in it", "description": "With drain, each of its nodes is drained too, one replica at a time with the replacement up first.", "tags": [ "facility" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HoldRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HoldView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/facility/holds/{domain}": { "delete": { "operationId": "deleteFacilityHoldsDomain", "summary": "Release a held domain", "description": "Nodes a draining hold drained are made ready again.", "tags": [ "facility" ], "parameters": [ { "name": "domain", "in": "path", "required": true, "description": "The domain as level:name, rack:r12-07, as `llmgw ctl facility` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HoldView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/federation": { "get": { "operationId": "getFederation", "summary": "This cluster's id, and its federation peers with their health and models", "tags": [ "federation" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FederationView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "post": { "operationId": "postFederation", "summary": "Add another llmgw cluster as a peer, or change one", "description": "The peer is checked first: its /ready, timed, and its /v1/models with the key. Its models join the catalog as PEER/MODEL.", "tags": [ "federation" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/federation.AddRequest" } } } }, "responses": { "201": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/federation.Status" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/federation/{peer}": { "delete": { "operationId": "deleteFederationPeer", "summary": "Remove a federation peer and its models", "description": "Refused while a model here falls back to one of the peer's.", "tags": [ "federation" ], "parameters": [ { "name": "peer", "in": "path", "required": true, "description": "The federation peer's name, as `llmgw ctl federation list` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Removed" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/federation/{peer}/sync": { "post": { "operationId": "postFederationPeerSync", "summary": "Check a peer now, rather than at the next interval", "tags": [ "federation" ], "parameters": [ { "name": "peer", "in": "path", "required": true, "description": "The federation peer's name, as `llmgw ctl federation list` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/federation.Status" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/guard": { "get": { "operationId": "getGuard", "summary": "The guardrail policies and where they are attached", "tags": [ "guard" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GuardView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/guard/attachments": { "post": { "operationId": "postGuardAttachments", "summary": "Attach a guardrail policy", "tags": [ "guard" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GuardAttachmentRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/guard.Attachment" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteGuardAttachments", "summary": "Detach a guardrail policy", "tags": [ "guard" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GuardAttachmentRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/guard.Attachment" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/guard/events": { "get": { "operationId": "getGuardEvents", "summary": "What the guardrails did: totals and the newest requests", "tags": [ "guard" ], "parameters": [ { "name": "since", "in": "query", "description": "How far back: 90m, 24h, 7d; 24h when absent.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GuardEventsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/guard/judges": { "get": { "operationId": "getGuardJudges", "summary": "The judge models the policies ask, and what is wrong with each", "tags": [ "guard" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/JudgeView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/guard/judges/ask": { "post": { "operationId": "postGuardJudgesAsk", "summary": "Have a judge read a text and say what it answered; nothing is kept", "tags": [ "guard" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JudgeAskRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JudgeAskView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/jobs": { "get": { "operationId": "getJobs", "summary": "Every job since the control plane started", "tags": [ "jobs" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/modelserve.Job" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/jobs/{id}": { "get": { "operationId": "getJobsId", "summary": "One job", "tags": [ "jobs" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, as starting it answered.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Job" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb": { "get": { "operationId": "getKb", "summary": "Every knowledge-base collection, with its documents' count and grants", "description": "Says why there are none when the store cannot hold them (SQLite, or PostgreSQL without pgvector).", "tags": [ "kb" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb/collections": { "post": { "operationId": "postKbCollections", "summary": "Make a collection, owned by an organization, team, project or person", "description": "The embedding model's dimension is asked of the model when dims is not given, so the model must be able to serve.", "tags": [ "kb" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBCreateRequest" } } } }, "responses": { "201": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBCollectionView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb/collections/{id}": { "delete": { "operationId": "deleteKbCollectionsId", "summary": "Remove a collection with its documents and grants", "tags": [ "kb" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The collection's ID, its name when that is unique, or ORG/NAME.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb/collections/{id}/dataset": { "post": { "operationId": "postKbCollectionsIdDataset", "summary": "Training data from a collection: questions and answers a chat model writes from each chunk", "description": "NDJSON, a line per pair as each chunk is read, or a line with error for a chunk that gave none. For people to correct before an adapter is trained on it.", "tags": [ "kb" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The collection's ID, its name when that is unique, or ORG/NAME.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBDatasetRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBDatasetLine" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb/collections/{id}/documents": { "get": { "operationId": "getKbCollectionsIdDocuments", "summary": "A collection's documents", "tags": [ "kb" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The collection's ID, its name when that is unique, or ORG/NAME.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/KBDocumentView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteKbCollectionsIdDocuments", "summary": "Remove one document from a collection", "tags": [ "kb" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The collection's ID, its name when that is unique, or ORG/NAME.", "schema": { "type": "string" } }, { "name": "name", "in": "query", "required": true, "description": "The document's name, as listed.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb/defaults": { "post": { "operationId": "postKbDefaults", "summary": "Set the collections a part of the tree answers from when a request names none", "description": "On an organization, team, project or key; the narrowest one with a default wins. No collections clears it. A request's own X-Llmgw-Knowledge overrides it, and X-Llmgw-Knowledge: none turns it off.", "tags": [ "kb" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBDefaultRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBDefaultView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb/grants": { "post": { "operationId": "postKbGrants", "summary": "Let a scope, and everything below it, read or write a collection", "description": "Never outside the collection's organization.", "tags": [ "kb" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBGrantRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBGrantView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteKbGrants", "summary": "Take a grant away", "tags": [ "kb" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBGrantRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBGrantView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/kb/search": { "post": { "operationId": "postKbSearch", "summary": "Try a search of a collection, as an administrator", "description": "No tenancy applies: this is for checking what a collection holds and finds.", "tags": [ "kb" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KBSearchRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/KBHitView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/keys": { "get": { "operationId": "getKeys", "summary": "API keys, with their project and owner; never the keys themselves", "tags": [ "keys" ], "parameters": [ { "name": "project", "in": "query", "description": "Only this project's keys: ORG/TEAM/PROJECT or its ID.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/KeyView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "post": { "operationId": "postKeys", "summary": "Issue an API key", "description": "The answer holds the key, once: only its hash is kept. A lifetime longer than a scope above it allows is refused.", "tags": [ "keys" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyCreateRequest" } } } }, "responses": { "201": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyCreated" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/keys/{id}": { "get": { "operationId": "getKeysId", "summary": "One API key", "tags": [ "keys" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The key's ID, as listed (not the key itself).", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteKeysId", "summary": "Revoke an API key", "description": "A soft delete: usage refers to it. A gateway that has it cached accepts it until auth.cache_ttl.", "tags": [ "keys" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The key's ID, as listed (not the key itself).", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/metrics/range": { "post": { "operationId": "postMetricsRange", "summary": "Several Prometheus range queries at once", "description": "Read from the Prometheus monitoring.prometheus names; configured is false without one.", "tags": [ "metrics" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MetricsRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MetricsResult" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models": { "get": { "operationId": "getModels", "summary": "Every model, with its replicas and state", "tags": [ "models" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ModelView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "post": { "operationId": "postModels", "summary": "Add a model to the catalog", "description": "Kept in the store across restarts. Refused when the name is taken, a model in configuration has it, or the definition would make the catalog invalid.", "tags": [ "models" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/catalog.Model" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelAdded" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/serve": { "post": { "operationId": "postModelsServe", "summary": "Fetch a registry repository and serve it", "tags": [ "models" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Request" } } } }, "responses": { "202": { "description": "Accepted: started, and running on.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Job" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}": { "get": { "operationId": "getModelsName", "summary": "One model's definition, as it is in force", "description": "With the defaults the catalog filled in. By its name only, not an alias.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/catalog.Model" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteModelsName", "summary": "Remove a model added at runtime", "description": "A model declared in the cluster's settings is refused: it is changed there.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Removed" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/adapters": { "post": { "operationId": "postModelsNameAdapters", "summary": "Replace a model's LoRA adapters", "description": "Each new file is read first, to check it is an adapter for the model's architecture.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdaptersRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdaptersRequest" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/canary": { "post": { "operationId": "postModelsNameCanary", "summary": "Start a canary of a model's newer weights", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/catalog.Canary" } } } }, "responses": { "202": { "description": "Accepted: started, and running on.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Job" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "put": { "operationId": "putModelsNameCanary", "summary": "Change the share of requests a canary takes", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CanaryPercentRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Result" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteModelsNameCanary", "summary": "Take a canary out: its share first, then the candidate", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Result" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/capacity": { "put": { "operationId": "putModelsNameCapacity", "summary": "Record what a replica was measured to serve", "description": "Replaces an earlier measurement of the same model on the same profile.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/bench.Capacity" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/bench.Capacity" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/class": { "post": { "operationId": "postModelsNameClass", "summary": "Set a model's capacity class", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClassRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClassView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/eval": { "post": { "operationId": "postModelsNameEval", "summary": "Ask a model a quality suite", "description": "Started at once and answered with the run, to be followed at /api/v1/eval/runs/{id}.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/eval.Request" } } } }, "responses": { "202": { "description": "Accepted: started, and running on.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/eval.Live" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/eval-gate": { "put": { "operationId": "putModelsNameEvalGate", "summary": "Hold a model's updates and promotions to a quality suite", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalGateRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalGateView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteModelsNameEvalGate", "summary": "Stop holding a model's updates to a suite", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalGateView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/fallbacks": { "put": { "operationId": "putModelsNameFallbacks", "summary": "Replace the models a model falls back to when it has no capacity", "description": "A model added at runtime only. A federation peer's model, PEER/MODEL, sends the overflow to the other cluster.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FallbacksRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FallbacksView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/headroom": { "get": { "operationId": "getModelsNameHeadroom", "summary": "How many more replicas of a model fit now, and where", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "description": "The most to try placing; 16 when absent or past 64.", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HeadroomView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/origin": { "post": { "operationId": "postModelsNameOrigin", "summary": "Record the repository a model's weights came from", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OriginRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OriginView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/owner": { "post": { "operationId": "postModelsNameOwner", "summary": "Set the part of the tenancy tree a model's capacity counts against", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OwnerRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OwnerView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/promote": { "post": { "operationId": "postModelsNamePromote", "summary": "Make a canary's weights the model's", "description": "With a quality suite, or the model's standing gate, the canary is asked it first and kept below the score.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Change" } } } }, "responses": { "202": { "description": "Accepted: started, and running on.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Job" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/resources": { "post": { "operationId": "postModelsNameResources", "summary": "Set what a model's profiles reserve of a node", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResourcesRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/catalog.Model" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/retry": { "post": { "operationId": "postModelsNameRetry", "summary": "Try a parked model again", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RetryView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/rollback": { "post": { "operationId": "postModelsNameRollback", "summary": "Go back to the weights the last update replaced", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Result" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/scale": { "post": { "operationId": "postModelsNameScale", "summary": "Set how many replicas a model runs", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScaleRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScaleResponse" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/target": { "get": { "operationId": "getModelsNameTarget", "summary": "How many replicas a throughput needs, and whether they fit", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "name": "tokens_per_sec", "in": "query", "required": true, "description": "The output tokens a second wanted of the model.", "schema": { "type": "number" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TargetView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/models/{name}/update": { "post": { "operationId": "postModelsNameUpdate", "summary": "Move a model to its repository's newer weights", "description": "With a quality suite, or the model's standing gate, the new weights are asked it first as a hidden canary.", "tags": [ "models" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The model's name in the catalog.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Change" } } } }, "responses": { "202": { "description": "Accepted: started, and running on.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Job" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nodes": { "get": { "operationId": "getNodes", "summary": "Every node, with its cards, load and fabrics", "tags": [ "nodes" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/NodeView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nodes/{id}": { "delete": { "operationId": "deleteNodesId", "summary": "Forget a node that has gone", "description": "Only a node that is lost, or unreachable with nothing on it; its certificate is revoked.", "tags": [ "nodes" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The node's ID, as `llmgw ctl nodes` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeRemoved" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nodes/{id}/engines": { "post": { "operationId": "postNodesIdEngines", "summary": "Choose an engine's build for a node", "description": "The node installs the build chosen. Build is auto, a build such as cu129, or none.", "tags": [ "nodes" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The node's ID, as `llmgw ctl nodes` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeEngineRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeEngineRequest" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nodes/{id}/labels": { "post": { "operationId": "postNodesIdLabels", "summary": "Set or remove labels on a node, over its agent's own", "description": "Kept in the store. llmgw.io/site, room, row, rack and pdu say where the node is, for facility-aware placement.", "tags": [ "nodes" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The node's ID, as `llmgw ctl nodes` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeLabelsRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeLabelsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nodes/{id}/logs": { "get": { "operationId": "getNodesIdLogs", "summary": "The last lines of a node's logs", "tags": [ "nodes" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The node's ID, as `llmgw ctl nodes` lists it.", "schema": { "type": "string" } }, { "name": "lines", "in": "query", "description": "How many lines; 300 when absent, at most 2000.", "schema": { "type": "integer" } }, { "name": "source", "in": "query", "description": "Which log: agent when absent, or an engine the node lists in sources.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LogsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nodes/{id}/state": { "post": { "operationId": "postNodesIdState", "summary": "Cordon, drain or ready a node", "tags": [ "nodes" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The node's ID, as `llmgw ctl nodes` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeStateRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeStateView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nodes/{id}/upgrade": { "post": { "operationId": "postNodesIdUpgrade", "summary": "Have a node run a release", "tags": [ "nodes" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The node's ID, as `llmgw ctl nodes` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpgradeRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpgradeView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/notify/test": { "post": { "operationId": "postNotifyTest", "summary": "Send a test notification to every webhook", "tags": [ "notify" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/notify.Result" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/nvlink": { "get": { "operationId": "getNvlink", "summary": "The multi-node NVLink domains and what keeps nodes out of them", "tags": [ "nvlink" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/nvlink.Report" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/openapi.json": { "get": { "operationId": "getOpenapiJson", "summary": "This document", "description": "The admin API in OpenAPI 3.1, generated from the route table and built into the binary.", "tags": [ "openapi" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/orgs": { "get": { "operationId": "getOrgs", "summary": "The tenancy tree: every organization, its teams and their projects", "tags": [ "orgs" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/OrgView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "post": { "operationId": "postOrgs", "summary": "Add an organization", "tags": [ "orgs" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyCreateRequest" } } } }, "responses": { "201": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyItem" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/orgs/{id}": { "patch": { "operationId": "patchOrgsId", "summary": "Rename an organization", "tags": [ "orgs" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The organization's ID or name.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyChangeRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyItem" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteOrgsId", "summary": "Remove an organization that has no teams", "tags": [ "orgs" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The organization's ID or name.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/plan": { "get": { "operationId": "getPlan", "summary": "How a registry repository would be served here", "tags": [ "plan" ], "parameters": [ { "name": "repo", "in": "query", "required": true, "description": "The repository, owner/name.", "schema": { "type": "string" } }, { "name": "format", "in": "query", "description": "gguf or safetensors; gguf when absent.", "schema": { "type": "string" } }, { "name": "context", "in": "query", "description": "The context length to plan for, in tokens.", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/modelserve.Plan" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/presets": { "get": { "operationId": "getPresets", "summary": "The models that come with llmgw: whether each fits this cluster, is in the catalog, was declined", "tags": [ "presets" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PresetsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/presets/auto": { "put": { "operationId": "putPresetsAuto", "summary": "Turn on or off the adding of presets when a node fits them", "tags": [ "presets" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PresetsAutoRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PresetsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/presets/{name}": { "post": { "operationId": "postPresetsName", "summary": "Add a preset to the catalog, and clear its decline", "tags": [ "presets" ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The preset's name, as `llmgw ctl model presets` lists it.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelAdded" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/projects": { "post": { "operationId": "postProjects", "summary": "Add a project to a team", "tags": [ "projects" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyCreateRequest" } } } }, "responses": { "201": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyItem" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/projects/{id}": { "patch": { "operationId": "patchProjectsId", "summary": "Rename a project, or move it to another team", "tags": [ "projects" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The project's ID.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyChangeRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyItem" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteProjectsId", "summary": "Remove a project with no people, keys or collections", "description": "A project that ever had a key keeps it, revoked, because usage refers to it; rename such a project instead.", "tags": [ "projects" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The project's ID.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/quotas": { "get": { "operationId": "getQuotas", "summary": "Every capacity quota, with what its scope holds now", "tags": [ "quotas" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/QuotaView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "put": { "operationId": "putQuotas", "summary": "Set a scope's capacity quota", "description": "Replaces the scope's quota whole. The scope may be named by path or by ID; the answer names it by ID.", "tags": [ "quotas" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QuotaRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QuotaSet" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/quotas/{scope}": { "delete": { "operationId": "deleteQuotasScope", "summary": "Remove a scope's capacity quota", "tags": [ "quotas" ], "parameters": [ { "name": "scope", "in": "path", "required": true, "description": "The scope: org:NAME, team:ORG/TEAM, project:ORG/TEAM/PROJECT, or their IDs after the colon.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Removed" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/replicas": { "get": { "operationId": "getReplicas", "summary": "Every replica, with its shards", "tags": [ "replicas" ], "parameters": [ { "name": "model", "in": "query", "description": "Only this model's replicas.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ReplicaView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/requests/{id}": { "get": { "operationId": "getRequestsId", "summary": "What one request went through", "tags": [ "requests" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The request's ID: the x-request-id a client was answered with.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RequestView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/requests/{id}/body": { "get": { "operationId": "getRequestsIdBody", "summary": "A kept request and its answer", "tags": [ "requests" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The request's ID: the x-request-id a client was answered with.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/store.RequestBody" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/requests/{id}/replay": { "post": { "operationId": "postRequestsIdReplay", "summary": "Send a kept request again, to any model", "tags": [ "requests" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The request's ID: the x-request-id a client was answered with.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplayRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplayView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/restart": { "post": { "operationId": "postRestart", "summary": "Restart replicas, every replica of some models, or all", "tags": [ "restart" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestartRequest" } } } }, "responses": { "202": { "description": "Accepted: started, and running on.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestartResult" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/settings": { "get": { "operationId": "getSettings", "summary": "The cluster's settings in force, or one earlier version", "tags": [ "settings" ], "parameters": [ { "name": "version", "in": "query", "description": "An earlier version; the newest when absent.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SettingsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "put": { "operationId": "putSettings", "summary": "Change the cluster's settings: in force on every control plane within seconds", "tags": [ "settings" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SettingsRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SettingsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/settings/history": { "get": { "operationId": "getSettingsHistory", "summary": "Versions of the cluster's settings, newest first", "tags": [ "settings" ], "parameters": [ { "name": "limit", "in": "query", "description": "How many; 20 when absent.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/SettingsView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/settings/rollback": { "post": { "operationId": "postSettingsRollback", "summary": "Put an earlier version of the cluster's settings back in force", "tags": [ "settings" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SettingsRollbackRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SettingsView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/summary": { "get": { "operationId": "getSummary", "summary": "The whole fleet in one answer", "tags": [ "summary" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Summary" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/teams": { "post": { "operationId": "postTeams", "summary": "Add a team to an organization", "tags": [ "teams" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyCreateRequest" } } } }, "responses": { "201": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyItem" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/teams/{id}": { "patch": { "operationId": "patchTeamsId", "summary": "Rename a team, or move it to another organization", "description": "Everything under it moves too, and from then on inherits the new organization's limits.", "tags": [ "teams" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The team's ID.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyChangeRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TenancyItem" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteTeamsId", "summary": "Remove a team that has no projects", "tags": [ "teams" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The team's ID.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/train/jobs": { "post": { "operationId": "postTrainJobs", "summary": "Queue a LoRA adapter's training on a node", "description": "The node trains when its agent is there, nothing else trains on it, and a card has gpu_memory_mib free; the pairs are NDJSON of {\"q\", \"a\"}. An adapter learns how answers sound far better than what they say.", "tags": [ "train" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrainRequest" } } } }, "responses": { "201": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrainJobView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "get": { "operationId": "getTrainJobs", "summary": "Training jobs, newest first", "tags": [ "train" ], "parameters": [ { "name": "limit", "in": "query", "description": "How many; 50 when absent.", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TrainJobView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/train/jobs/{id}": { "get": { "operationId": "getTrainJobsId", "summary": "One training job: how it goes, and what it made", "tags": [ "train" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, as starting it answered.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrainJobView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteTrainJobsId", "summary": "Remove an ended training job and what it made", "tags": [ "train" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, as starting it answered.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/train/jobs/{id}/artifacts/{kind}": { "get": { "operationId": "getTrainJobsIdArtifactsKind", "summary": "What a training job made: peft (a gzipped tar) or gguf", "tags": [ "train" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, as starting it answered.", "schema": { "type": "string" } }, { "name": "kind", "in": "path", "required": true, "description": "What the job made: peft, a gzipped tar of the PEFT adapter, or gguf, the adapter for llama.cpp.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/train/jobs/{id}/cancel": { "post": { "operationId": "postTrainJobsIdCancel", "summary": "Stop a training job", "tags": [ "train" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, as starting it answered.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrainJobView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/train/jobs/{id}/publish": { "post": { "operationId": "postTrainJobsIdPublish", "summary": "Make what a finished job made the model's adapter", "description": "Kept on the mirror — the GGUF for a model llama.cpp serves, the PEFT files for one vLLM serves — and added to the model's adapters after the same check as POST /api/v1/models/{name}/adapters.", "tags": [ "train" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The job's ID, as starting it answered.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrainPublishView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/updates": { "get": { "operationId": "getUpdates", "summary": "Newer weights the registry has for models", "tags": [ "updates" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/modelserve.UpdateInfo" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/updates/check": { "post": { "operationId": "postUpdatesCheck", "summary": "Ask the registry now, about one model or every one", "tags": [ "updates" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/modelserve.UpdateInfo" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/usage": { "get": { "operationId": "getUsage", "summary": "What each group of the tenancy tree spent", "tags": [ "usage" ], "parameters": [ { "name": "by", "in": "query", "description": "org, team or project; team when absent.", "schema": { "type": "string" } }, { "name": "since", "in": "query", "description": "A duration back from now, like 24h; 24h when absent.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ScopeUsageView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/usage/export": { "get": { "operationId": "getUsageExport", "summary": "Usage totals by period and dimension, as CSV or JSON", "tags": [ "usage" ], "parameters": [ { "name": "from", "in": "query", "description": "A date (2026-09-01) or an RFC 3339 time; the first of this month when absent.", "schema": { "type": "string" } }, { "name": "to", "in": "query", "description": "A date or an RFC 3339 time; now when absent.", "schema": { "type": "string" } }, { "name": "period", "in": "query", "description": "hour, day or month; day when absent.", "schema": { "type": "string" } }, { "name": "by", "in": "query", "description": "Dimensions, comma-separated: org, team, project, user, key, model.", "schema": { "type": "string" } }, { "name": "format", "in": "query", "description": "json for JSON; CSV otherwise.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/store.ExportRow" } } }, "text/csv": { "schema": { "type": "string" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/users": { "get": { "operationId": "getUsers", "summary": "People, with where each is a member", "tags": [ "users" ], "parameters": [ { "name": "state", "in": "query", "description": "Only people in this state: pending, active or disabled.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/users/{id}": { "get": { "operationId": "getUsersId", "summary": "One person, with where they are a member", "tags": [ "users" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The person's ID or email.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/users/{id}/memberships": { "post": { "operationId": "postUsersIdMemberships", "summary": "Put a person in an organization, team or project", "description": "Already there, only the role changes.", "tags": [ "users" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The person's ID or email.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MembershipRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } }, "delete": { "operationId": "deleteUsersIdMemberships", "summary": "Take a person out of an organization, team or project", "description": "Their keys in projects they no longer reach are revoked.", "tags": [ "users" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The person's ID or email.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MembershipRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserView" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/weights/collect": { "post": { "operationId": "postWeightsCollect", "summary": "Delete weights that no model uses", "tags": [ "weights" ], "parameters": [ { "$ref": "#/components/parameters/Actor" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CollectRequest" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CollectResult" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } }, "/api/v1/weights/orphans": { "get": { "operationId": "getWeightsOrphans", "summary": "Weights on nodes that no model uses", "tags": [ "weights" ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/OrphanView" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "default": { "$ref": "#/components/responses/Error" } } } } }, "components": { "securitySchemes": { "adminToken": { "type": "http", "scheme": "bearer", "description": "The admin token: the contents of /var/lib/llmgw/admin-token on the control plane (admin_token_file), readable by root and the server. Sent as Authorization: Bearer TOKEN." } }, "parameters": { "Actor": { "name": "X-Llmgw-Actor", "in": "header", "required": false, "description": "Who the change is recorded as made by in the audit log: letters, digits and ._-@, at most 64. unknown when absent.", "schema": { "type": "string" } } }, "responses": { "Error": { "description": "Refused: the error says why.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorView" } } } }, "Unauthorized": { "description": "The token is missing or wrong.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorView" } } } } }, "schemas": { "AdaptersRequest": { "type": "object", "description": "AdaptersRequest replaces a model's LoRA adapters with these.", "properties": { "adapters": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.Adapter" } } } }, "AgentRestartView": { "type": "object", "description": "AgentRestartView names the nodes whose agents were told to restart.", "properties": { "nodes": { "type": "array", "items": { "type": "string" } } } }, "AuthView": { "type": "object", "description": "AuthView is how people sign in on this gateway.", "properties": { "signup_open": { "type": "boolean" }, "oidc": { "$ref": "#/components/schemas/OIDCView", "description": "OIDC is single sign-on through an identity provider: Entra ID, Keycloak, Okta." }, "ldap": { "$ref": "#/components/schemas/LDAPView", "description": "LDAP is sign-in checked by a directory: Active Directory." }, "scim": { "type": "boolean", "description": "SCIM is whether a provider may keep accounts in step." }, "base_url": { "type": "string", "description": "BaseURL is the portal's address, when the settings say it: what a provider's redirect address is made from." } } }, "CanaryPercentRequest": { "type": "object", "description": "CanaryPercentRequest changes the share of a model's requests its canary takes.", "properties": { "percent": { "type": "integer" } } }, "CapacityView": { "type": "object", "description": "CapacityView is one stored measurement, with who recorded it.", "properties": { "model": { "type": "string" }, "profile": { "type": "string" }, "max_concurrency_at_slo": { "type": "integer", "description": "MaxConcurrencyAtSLO is the capacity: the highest concurrency that still met the target. Zero means even one request did not, which is a real result and not a missing one — it says this hardware cannot serve this model at this SLO at all." }, "throughput_tok_per_sec": { "type": "number", "description": "ThroughputTokPerSec and the latencies are taken at that level, not at the peak. Peak throughput arrives long after latency has become unusable, so reporting it would overstate what the hardware can serve." }, "ttft_p99": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "tpot_p99": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "suggested_target_waiting": { "type": "integer", "description": "SuggestedTargetWaiting and SuggestedKVCeiling are the queue depth and cache pressure seen while the SLO was still being met, which is what admission should treat as healthy for this model. Admission currently applies one global default to every model; these are the per-model numbers it should be using instead." }, "suggested_kv_ceiling": { "type": "number" }, "slo": { "$ref": "#/components/schemas/bench.SLO", "description": "SLO is recorded because capacity is meaningless without it. The same replica has a different capacity against a 200ms first-token target than against a 2s one, and a number stored without the target it was measured against cannot be compared with anything." }, "target": { "type": "string", "description": "Target is the endpoint the load actually went to, kept so a profile measured against the gateway is never mistaken for one measured against a replica. Only the second says anything about the hardware." }, "measured_at": { "type": "string", "format": "date-time" }, "measured_by": { "type": "string" } } }, "CheckRequest": { "type": "object", "description": "CheckRequest asks the registry about one model now, or every one.", "properties": { "model": { "type": "string" } } }, "CheckView": { "type": "object", "description": "CheckView is one step of trying a directory.", "properties": { "step": { "type": "string" }, "ok": { "type": "boolean" }, "detail": { "type": "string" } } }, "ClassGPUs": { "type": "object", "description": "ClassGPUs is how many of a node's devices are of one class, and how many of those are free or kept out of placement.", "properties": { "class": { "type": "string" }, "total": { "type": "integer" }, "free": { "type": "integer" }, "unhealthy": { "type": "integer" }, "mig": { "type": "boolean", "description": "MIG marks a class of MIG instances, each of which takes a replica of its own and never joins a tensor-parallel group." } } }, "ClassRequest": { "type": "object", "description": "ClassRequest sets a model's capacity class: critical, standard or opportunistic, or empty to go back to what its scaling implies.", "properties": { "class": { "type": "string" } } }, "ClassUse": { "type": "object", "description": "ClassUse is how much of one kind of card is in use.", "properties": { "class": { "type": "string" }, "total": { "type": "integer" }, "used": { "type": "integer" }, "unhealthy": { "type": "integer", "description": "Unhealthy GPUs are neither used nor available, and counting them as free is how a cluster looks like it has room it does not have." } } }, "ClassView": { "type": "object", "description": "ClassView is a model's capacity class now.", "properties": { "model": { "type": "string" }, "class": { "type": "string" } } }, "CollectRequest": { "type": "object", "description": "CollectRequest limits a sweep to one node. Empty means every node, which is the common case after removing a model from the catalog.", "properties": { "node": { "type": "string" } } }, "CollectResult": { "type": "object", "description": "CollectResult is what was deleted on one node, or why nothing was.", "properties": { "node": { "type": "string" }, "files": { "type": "integer" }, "bytes": { "type": "integer", "format": "int64" }, "error": { "type": "string" } } }, "ComputeView": { "type": "object", "description": "ComputeView is where an engine runs its model, by its own account.", "properties": { "backend": { "type": "string", "description": "Backend is CUDA, Vulkan, Metal, ROCm, GPU or CPU." }, "devices": { "type": "array", "items": { "type": "string" } }, "layers_offloaded": { "type": "integer", "description": "LayersOffloaded of LayersTotal went to the devices; absent when unsaid." }, "layers_total": { "type": "integer" } } }, "ControlPlane": { "type": "object", "description": "ControlPlane is one control plane.", "properties": { "name": { "type": "string" }, "address": { "type": "string" }, "state": { "type": "string", "description": "State is \"leading\", \"standing by\" or \"not answering\"." }, "this": { "type": "boolean", "description": "This is the control plane that answered the summary." } } }, "ControlPlanes": { "type": "object", "description": "ControlPlanes is every control plane of a cluster that has several, as each answered when asked.", "properties": { "members": { "type": "array", "items": { "$ref": "#/components/schemas/ControlPlane" } }, "floating": { "type": "string", "description": "Floating is the address keepalived keeps on the leader (10.0.0.161), and FloatingUp whether it answered as a leader when asked; empty when nothing floats." }, "floating_up": { "type": "boolean" } } }, "DirectorySyncView": { "type": "object", "description": "DirectorySyncView is the last time the leader read the directory.", "properties": { "at": { "type": "string", "format": "date-time" }, "people": { "type": "integer" }, "accounts": { "type": "integer" }, "suspended": { "type": "integer" }, "reinstated": { "type": "integer" }, "roles_changed": { "type": "integer" }, "error": { "type": "string" } } }, "DomainView": { "type": "object", "description": "DomainView is one domain: its nodes, its power and whether it is held.", "properties": { "domain": { "type": "string" }, "level": { "type": "string" }, "name": { "type": "string" }, "nodes": { "type": "array", "items": { "type": "string" } }, "cap_watts": { "type": "number", "description": "CapWatts is the domain's cap, LimitWatts the cap less the margin; both zero when it has none." }, "limit_watts": { "type": "number" }, "other_watts": { "type": "number" }, "reserved_watts": { "type": "number", "description": "ReservedWatts is what is placed in it is estimated to draw; MeasuredWatts what its nodes' sensors read; UsedWatts what counts against the cap, the larger of the two node by node." }, "measured_watts": { "type": "number" }, "used_watts": { "type": "number" }, "held": { "$ref": "#/components/schemas/HoldView", "description": "Held is set when the domain is held." } } }, "ErrorView": { "type": "object", "description": "ErrorView is every refusal: a 4xx or 5xx status with what went wrong.", "properties": { "error": { "type": "string" } } }, "EvalGateRequest": { "type": "object", "description": "EvalGateRequest sets a model's standing quality suite; an empty suite takes it away.", "properties": { "suite": { "type": "string" }, "min_score": { "type": "number" }, "judge": { "type": "string" } } }, "EvalGateView": { "type": "object", "description": "EvalGateView is a model's standing quality gate, as it is now; Eval is absent when it has none.", "properties": { "model": { "type": "string" }, "eval": { "$ref": "#/components/schemas/catalog.EvalGate" } } }, "ExplainView": { "type": "object", "description": "ExplainView is why a model could not be placed.", "properties": { "model": { "type": "string" }, "placed": { "type": "boolean", "description": "Placed is true when the model has replicas, in which case there is nothing to explain." }, "rejections": { "type": "array", "items": { "$ref": "#/components/schemas/RejectionView" }, "description": "Rejections is empty when placement was never attempted, which is itself the answer: the model is satisfied, or the reconciler has not run yet." } } }, "FabricTestRequest": { "type": "object", "description": "FabricTestRequest is a bandwidth test between two nodes.", "properties": { "a": { "type": "string" }, "b": { "type": "string" }, "fabric": { "type": "string", "description": "Fabric is the declared fabric to test over; empty is the one the two nodes share." }, "seconds": { "type": "integer", "description": "Seconds each rail is measured for, from 1 to 30." } } }, "FabricTestView": { "type": "object", "description": "FabricTestView is a bandwidth test between two nodes.", "properties": { "a": { "type": "string" }, "b": { "type": "string" }, "fabric": { "type": "string" }, "ok": { "type": "boolean" }, "rails": { "type": "array", "items": { "$ref": "#/components/schemas/RailView" } }, "notes": { "type": "array", "items": { "type": "string" } }, "took": { "type": "string" } } }, "FabricUse": { "type": "object", "description": "FabricUse is capacity within one fabric.", "properties": { "fabric": { "type": "string" }, "nodes": { "type": "integer" }, "nodes_with_weights": { "type": "integer", "description": "ModelsPresent is how many nodes here hold weights at all, and Models how many distinct models they hold between them.\n\nPer fabric because that is the unit at which the answer is actionable. Fabrics are not connected to one another, so weights in one are not weights in another: a model seeded into a single fabric leaves the rest of the cluster unable to serve it without first moving tens of gigabytes over the management network, and nothing said so." }, "models_present": { "type": "integer" }, "largest_free_block": { "type": "integer", "description": "LargestFreeBlock is the most nodes on this fabric that are entirely free, which is the number that decides whether a multi-node replica can land." } } }, "FacilityView": { "type": "object", "description": "FacilityView is the failure domains as placement sees them.", "properties": { "domains": { "type": "array", "items": { "$ref": "#/components/schemas/DomainView" }, "description": "Domains are every domain a node is in or a budget names, by level (site, room, row, rack, pdu) and then name." }, "holds": { "type": "array", "items": { "$ref": "#/components/schemas/HoldView" }, "description": "Holds are every domain held, including one no node is in yet." }, "margin": { "type": "number", "description": "Margin is the share of every cap kept free." }, "unlocated": { "type": "array", "items": { "type": "string" }, "description": "Unlocated are the nodes with no location label, which placement treats as each in a rack of its own." } } }, "FallbacksRequest": { "type": "object", "description": "FallbacksRequest replaces a model's fallbacks; empty takes them all away.", "properties": { "fallbacks": { "type": "array", "items": { "type": "string" } } } }, "FallbacksView": { "type": "object", "description": "FallbacksView is a model's fallbacks, as they are now.", "properties": { "model": { "type": "string" }, "fallbacks": { "type": "array", "items": { "type": "string" } } } }, "FederationView": { "type": "object", "description": "FederationView is this cluster's id and its peers.", "properties": { "cluster": { "type": "string", "description": "Cluster is this cluster's own id, which its peers see in the hop header." }, "peers": { "type": "array", "items": { "$ref": "#/components/schemas/federation.Status" } } } }, "FetchView": { "type": "object", "description": "FetchView is a download in flight.", "properties": { "source": { "type": "string" }, "bytes_done": { "type": "integer", "format": "int64" }, "bytes_total": { "type": "integer", "format": "int64", "description": "BytesTotal is 0 when the server did not say how large the file is." }, "percent": { "type": "integer", "description": "Percent is absent rather than zero when the total is unknown: an invented percentage that stops moving is worse than a byte count that keeps rising." } } }, "GPUView": { "type": "object", "description": "GPUView is one card as a node's page shows it.", "properties": { "index": { "type": "integer" }, "name": { "type": "string" }, "label": { "type": "string", "description": "Label is the device as people are shown it: \"3\" for a whole card, \"0/mig2\" for card 0's MIG instance 2." }, "class": { "type": "string" }, "card": { "type": "integer", "description": "Card is the physical card's index: the device's own, or for a MIG instance its parent's, which is what the card's sensors are under." }, "mig_profile": { "type": "string", "description": "MIGProfile is the instance's profile, like 3g.40gb; empty for a whole card." }, "memory_total_mb": { "type": "integer" }, "memory_used_mb": { "type": "integer" }, "compute_capability": { "type": "string", "description": "ComputeCapability is what decides which engine builds run on the card: CUDA 13 builds need 7.5, so a V100 (7.0) runs only older ones." }, "numa": { "type": "integer" }, "nvlink_peers": { "type": "array", "items": { "type": "integer" } }, "nearest_nic": { "type": "string", "description": "NearestNIC is the adapter closest to the card, and how close." }, "nic_path": { "type": "string" }, "fabric_state": { "type": "string" }, "domain": { "type": "string" }, "bandwidth": { "type": "string" } } }, "GuardAttachmentRequest": { "type": "object", "description": "GuardAttachmentRequest attaches a policy to a part of the tenancy tree, a key or a person, or with DELETE takes it off again.", "properties": { "target": { "type": "string", "description": "Target is org:NAME, team:ORG/TEAM, project:ORG/TEAM/PROJECT (or the ID after the colon), key:KEY-ID or user:USER-ID." }, "policy": { "type": "string", "description": "Policy is a policy's name in server.yaml's guard.policies." } } }, "GuardAttachmentView": { "type": "object", "description": "GuardAttachmentView is one attachment, with the name people know its scope by.", "properties": { "Scope": { "type": "string" }, "ScopeID": { "type": "string" }, "Policy": { "type": "string" }, "name": { "type": "string" } } }, "GuardCountView": { "type": "object", "description": "GuardCountView is how many requests one policy did one thing to.", "properties": { "project": { "type": "string" }, "action": { "type": "string" }, "policy": { "type": "string" }, "category": { "type": "string" }, "count": { "type": "integer", "format": "int64" } } }, "GuardEventView": { "type": "object", "description": "GuardEventView is one request the guardrails did something to.", "properties": { "at": { "type": "string", "format": "date-time" }, "request_id": { "type": "string" }, "project": { "type": "string" }, "model": { "type": "string" }, "status": { "type": "integer" }, "action": { "type": "string" }, "policy": { "type": "string" }, "category": { "type": "string" }, "rule": { "type": "string", "description": "Rule is what decided it within the category: a pattern's name, or a judge's verdict, \"S6,Specialized Advice\"." }, "guard_ms": { "type": "integer", "format": "int64" } } }, "GuardEventsView": { "type": "object", "description": "GuardEventsView is what the guardrails did since a moment: totals, and the newest requests.", "properties": { "since": { "type": "string", "format": "date-time" }, "counts": { "type": "array", "items": { "$ref": "#/components/schemas/GuardCountView" } }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/GuardEventView" } } } }, "GuardPolicyView": { "type": "object", "description": "GuardPolicyView is what one policy does, in brief.", "properties": { "name": { "type": "string" }, "mode": { "type": "string", "description": "Mode is enforce, shadow or off; Fail is open or closed." }, "fail": { "type": "string" }, "no_store": { "type": "boolean" }, "judge": { "type": "string", "description": "Judge is the judge model, when one reads the text." }, "checks": { "type": "array", "items": { "type": "string" }, "description": "Checks are what it looks for, one line each: \"input: pii email → redact\"." } } }, "GuardView": { "type": "object", "description": "GuardView is the library and where its policies are attached.", "properties": { "enabled": { "type": "boolean", "description": "Enabled is whether the guardrails check anything (guard.enabled)." }, "policies": { "type": "array", "items": { "type": "string" } }, "default": { "type": "array", "items": { "type": "string" } }, "attachments": { "type": "array", "items": { "$ref": "#/components/schemas/GuardAttachmentView" } }, "details": { "type": "array", "items": { "$ref": "#/components/schemas/GuardPolicyView" }, "description": "Details says what each policy does, in the order of Policies." } } }, "HeadroomView": { "type": "object", "description": "HeadroomView is how many more replicas of a model fit now, and where.", "properties": { "model": { "type": "string" }, "current": { "type": "integer", "description": "Current is the replicas holding capacity: starting or ready." }, "more": { "type": "integer", "description": "More is how many more placement would find room for now." }, "nodes": { "type": "array", "items": { "type": "array", "items": { "type": "string" } }, "description": "Nodes is where each of those would go." }, "limited": { "type": "boolean", "description": "Limited is set when More stopped at the limit asked rather than at the cluster's edge: there may be room for more." }, "blocked": { "type": "array", "items": { "type": "string" }, "description": "Blocked says why one more does not fit, a line per node considered." }, "tok_per_sec": { "type": "number", "description": "TokPerSec is what one more replica was measured to serve; 0 unmeasured." }, "by_preempting": { "type": "integer", "description": "ByPreempting is how many more would fit by stopping replicas this model's class may take; Preempts the models those belong to." }, "preempts": { "type": "array", "items": { "type": "string" } } } }, "HoldRequest": { "type": "object", "description": "HoldRequest holds a domain.", "properties": { "domain": { "type": "string", "description": "Domain is level:name: rack:r12-07, pdu:r12-07-a, row:12." }, "reason": { "type": "string" }, "drain": { "type": "boolean", "description": "Drain moves the work in the domain elsewhere too." } } }, "HoldView": { "type": "object", "description": "HoldView is a hold, and the nodes holding or releasing it changed.", "properties": { "domain": { "type": "string" }, "reason": { "type": "string" }, "drain": { "type": "boolean" }, "by": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "nodes": { "type": "array", "items": { "type": "string" }, "description": "Nodes are those this call drained, or made ready again on release." } } }, "IBPortView": { "type": "object", "description": "IBPortView is one port as a page shows it.", "properties": { "hca": { "type": "string" }, "port": { "type": "integer" }, "state": { "type": "string" }, "phys_state": { "type": "string" }, "rate_gbps": { "type": "integer" }, "link_layer": { "type": "string" }, "active": { "type": "boolean" }, "fabric": { "type": "string", "description": "Fabric is the declared fabric this port's adapter carries, if any." }, "physical": { "type": "string", "description": "Physical is the fabric the port is physically on: its subnet manager, or its RoCE network. SMError says why that is not known." }, "sm_error": { "type": "string" }, "errors": { "type": "object", "additionalProperties": { "type": "integer", "format": "int64" }, "description": "Errors are the error counters that are not zero, by name." }, "tx_bytes": { "type": "integer", "format": "int64" }, "rx_bytes": { "type": "integer", "format": "int64" } } }, "IdleReplica": { "type": "object", "description": "IdleReplica is a replica holding hardware nothing is asking for.", "properties": { "id": { "type": "string" }, "model": { "type": "string" }, "idle_seconds": { "type": "integer", "format": "int64" }, "gpus": { "type": "integer" } } }, "JobView": { "type": "object", "description": "JobView is one job.", "properties": { "id": { "type": "string" }, "owner": { "type": "string" }, "key_id": { "type": "string" }, "endpoint": { "type": "string" }, "model": { "type": "string" }, "status": { "type": "string" }, "progress": { "description": "Any JSON value." }, "output_file_id": { "type": "string" }, "content_type": { "type": "string" }, "error": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "started_at": { "type": "string" }, "finished_at": { "type": "string" } } }, "JudgeAskRequest": { "type": "object", "description": "JudgeAskRequest is a text to have a judge read.", "properties": { "model": { "type": "string", "description": "Model is the judge; empty is the one the policies ask, when they ask one." }, "text": { "type": "string" }, "answer": { "type": "string", "description": "Answer, when given, is read as the assistant's reply to Text." } } }, "JudgeAskView": { "type": "object", "description": "JudgeAskView is what the judge answered.", "properties": { "model": { "type": "string" }, "verdict": { "type": "string", "description": "Verdict is safe, unsafe or controversial, as the gateway reads the answer; a policy's judge.controversial says what controversial counts as." }, "categories": { "type": "array", "items": { "type": "string" } }, "raw": { "type": "string", "description": "Raw is the judge's answer as it gave it." }, "took_ms": { "type": "integer", "format": "int64" } } }, "JudgeView": { "type": "object", "description": "JudgeView is one judge model the guardrail policies ask, and whether it can answer them.", "properties": { "model": { "type": "string" }, "policies": { "type": "array", "items": { "type": "string" }, "description": "Policies are those that ask it; Closed those that refuse what it cannot read (fail: closed)." }, "closed": { "type": "array", "items": { "type": "string" } }, "then": { "type": "array", "items": { "type": "string" }, "description": "Then are the judges its policies ask after it, when it gives no verdict: a CPU judge behind a GPU one." }, "in_catalog": { "type": "boolean", "description": "InCatalog is whether a model of that name is in the catalog, and Judge whether it is there as a judge (role: guard)." }, "judge": { "type": "boolean" }, "ready_replicas": { "type": "integer" }, "wanted_replicas": { "type": "integer" }, "last_error": { "type": "string", "description": "LastError is its last failure to give a verdict, if any." }, "last_error_at": { "type": "string" }, "problem": { "type": "string", "description": "Problem says, in words, what is wrong and what to do; empty when nothing is." } } }, "KBCollectionView": { "type": "object", "description": "KBCollectionView is a collection as an administrator sees it.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "org": { "type": "string" }, "org_name": { "type": "string" }, "owner": { "type": "string" }, "owner_name": { "type": "string" }, "embed_model": { "type": "string" }, "dims": { "type": "integer" }, "documents": { "type": "integer" }, "chunks": { "type": "integer" }, "grants": { "type": "array", "items": { "$ref": "#/components/schemas/KBGrantView" }, "description": "Grants are who else may read or write it." }, "created_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "string" } } }, "KBCreateRequest": { "type": "object", "description": "KBCreateRequest makes a collection.", "properties": { "owner": { "type": "string", "description": "Owner is org:NAME, team:ORG/TEAM, project:ORG/TEAM/PROJECT (or the ID after the colon), or user:USER-ID." }, "org": { "type": "string", "description": "Org is the organization a person's collection belongs to; only for user: owners." }, "name": { "type": "string" }, "model": { "type": "string", "description": "Model is the catalog model that embeds its documents." }, "dims": { "type": "integer", "description": "Dims is the model's embedding dimension; asked of the model when 0." } } }, "KBDatasetLine": { "type": "object", "description": "KBDatasetLine is one line of the answer: a pair, or why a chunk gave none.", "properties": { "q": { "type": "string" }, "a": { "type": "string" }, "doc": { "type": "string" }, "ord": { "type": "integer" }, "collection": { "type": "string", "description": "Collection is where the pair came from: an adapter trained on it belongs to a part of the tree that may read it." }, "error": { "type": "string" } } }, "KBDatasetRequest": { "type": "object", "description": "KBDatasetRequest asks for training data from a collection.", "properties": { "model": { "type": "string", "description": "Model writes the questions and answers: a chat model of the catalog." }, "per_chunk": { "type": "integer", "description": "PerChunk is how many pairs each chunk gives; 8 when 0." }, "max_chunks": { "type": "integer", "description": "MaxChunks bounds how many chunks are read; 500 when 0." } } }, "KBDefaultRequest": { "type": "object", "description": "KBDefaultRequest sets the collections a part of the tree answers from when a request names none; none clears it.", "properties": { "target": { "type": "string", "description": "Target is org:, team:, project: (by path or ID) or key:KEY-ID." }, "collections": { "type": "array", "items": { "type": "string" }, "description": "Collections are IDs, names when unique, or ORG/NAME." } } }, "KBDefaultView": { "type": "object", "description": "KBDefaultView is one part of the tree's default collections.", "properties": { "target": { "type": "string" }, "name": { "type": "string" }, "collections": { "type": "array", "items": { "type": "string" }, "description": "Collections are ORG/NAME, in order." }, "at": { "type": "string", "format": "date-time" }, "by": { "type": "string" } } }, "KBDocumentView": { "type": "object", "description": "KBDocumentView is one document in a collection.", "properties": { "name": { "type": "string" }, "digest": { "type": "string" }, "bytes": { "type": "integer", "format": "int64" }, "chunks": { "type": "integer" }, "added_at": { "type": "string", "format": "date-time" }, "added_by": { "type": "string" } } }, "KBGrantRequest": { "type": "object", "description": "KBGrantRequest lets a scope read or write a collection, or with DELETE takes that away.", "properties": { "collection": { "type": "string", "description": "Collection is its ID, its name when that is unique, or ORG/NAME." }, "target": { "type": "string", "description": "Target is org:, team:, project:, key: or user: as for guard policies." }, "perm": { "type": "string", "description": "Perm is read or write; ignored by DELETE." } } }, "KBGrantView": { "type": "object", "description": "KBGrantView is one grant.", "properties": { "target": { "type": "string" }, "name": { "type": "string" }, "perm": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "by": { "type": "string" } } }, "KBHitView": { "type": "object", "description": "KBHitView is one chunk a search found.", "properties": { "document": { "type": "string" }, "ord": { "type": "integer" }, "score": { "type": "number" }, "text": { "type": "string" } } }, "KBSearchRequest": { "type": "object", "description": "KBSearchRequest tries a search, as an administrator: no tenancy applies.", "properties": { "collection": { "type": "string" }, "query": { "type": "string" }, "k": { "type": "integer" } } }, "KBView": { "type": "object", "description": "KBView is every collection, or why there can be none.", "properties": { "available": { "type": "boolean" }, "reason": { "type": "string", "description": "Reason is why not, when not." }, "collections": { "type": "array", "items": { "$ref": "#/components/schemas/KBCollectionView" } }, "defaults": { "type": "array", "items": { "$ref": "#/components/schemas/KBDefaultView" }, "description": "Defaults are the collections parts of the tree answer from when a request names none." } } }, "KeyCreateRequest": { "type": "object", "description": "KeyCreateRequest issues a key: a project's, a person's in a project they are a member of, or a person's own with no project.", "properties": { "name": { "type": "string" }, "project": { "type": "string", "description": "Project is ORG/TEAM/PROJECT or its ID." }, "user": { "type": "string", "description": "User is the person it belongs to, by ID or email." }, "band": { "type": "string" }, "routing_profile": { "type": "string" }, "expires_in": { "type": "string", "description": "ExpiresIn is its lifetime, as 720h; none never expires, unless a scope above it limits how long keys live." } } }, "KeyCreated": { "type": "object", "description": "KeyCreated is a new key, with the key itself: this answer is the only time it is given.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "prefix": { "type": "string", "description": "Prefix is the key's first characters, to tell it apart." }, "project": { "type": "string" }, "project_path": { "type": "string", "description": "ProjectPath is ORG/TEAM/PROJECT, or empty for a personal key." }, "user": { "type": "string" }, "user_email": { "type": "string" }, "band": { "type": "string" }, "routing_profile": { "type": "string" }, "state": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "expires_at": { "type": "string", "format": "date-time" }, "revoked_at": { "type": "string", "format": "date-time" }, "last_used_at": { "type": "string", "format": "date-time" }, "secret": { "type": "string" } } }, "KeyView": { "type": "object", "description": "KeyView is a key as listed: never the key itself, which is not kept.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "prefix": { "type": "string", "description": "Prefix is the key's first characters, to tell it apart." }, "project": { "type": "string" }, "project_path": { "type": "string", "description": "ProjectPath is ORG/TEAM/PROJECT, or empty for a personal key." }, "user": { "type": "string" }, "user_email": { "type": "string" }, "band": { "type": "string" }, "routing_profile": { "type": "string" }, "state": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "expires_at": { "type": "string", "format": "date-time" }, "revoked_at": { "type": "string", "format": "date-time" }, "last_used_at": { "type": "string", "format": "date-time" } } }, "LDAPTestRequest": { "type": "object", "description": "LDAPTestRequest is an auth.ldap block to try, as YAML, and the service account's password when it is not kept yet.", "properties": { "settings": { "type": "string" }, "password": { "type": "string" } } }, "LDAPTestView": { "type": "object", "description": "LDAPTestView is how trying the directory went.", "properties": { "ok": { "type": "boolean" }, "checks": { "type": "array", "items": { "$ref": "#/components/schemas/CheckView" } } } }, "LDAPView": { "type": "object", "description": "LDAPView is auth.ldap as it is in force, and how its last sync went.", "properties": { "urls": { "type": "array", "items": { "type": "string" } }, "base_dn": { "type": "string" }, "bind_dn": { "type": "string" }, "label": { "type": "string" }, "off": { "type": "string", "description": "Off is why this control plane could not use the settings, when it could not; local accounts still sign in." }, "last_sync": { "$ref": "#/components/schemas/DirectorySyncView" } } }, "Live": { "type": "object", "description": "Live is one of the cluster's adapters as its node last reported it.", "properties": { "node": { "type": "string" }, "hca": { "type": "string" }, "state": { "type": "string" }, "phys_state": { "type": "string" }, "gbps": { "type": "integer" }, "tx_bps": { "type": "number" }, "rx_bps": { "type": "number" }, "errors": { "type": "object", "additionalProperties": { "type": "integer", "format": "int64" } } } }, "LoadView": { "type": "object", "description": "LoadView is a node's CPU and memory in use, at its last heartbeat.", "properties": { "cpu_percent": { "type": "number" }, "cpus": { "type": "integer" }, "load1": { "type": "number" }, "load5": { "type": "number" }, "load15": { "type": "number" }, "memory_used_bytes": { "type": "integer", "format": "int64" }, "memory_total_bytes": { "type": "integer", "format": "int64" }, "memory_percent": { "type": "number", "description": "MemPercent is used over used plus available." }, "age_seconds": { "type": "integer", "format": "int64" }, "cpu_temp_c": { "type": "number", "description": "What the node's sensors say; zero is not measured." }, "cpu_power_w": { "type": "number" }, "inlet_temp_c": { "type": "number" }, "gpu_sensors": { "type": "array", "items": { "$ref": "#/components/schemas/inventory.GPUSensor" } } } }, "LogsView": { "type": "object", "description": "LogsView is one of a node's logs, as the node sent it.", "properties": { "node": { "type": "string" }, "source": { "type": "string" }, "lines": { "type": "array", "items": { "type": "string" } }, "sources": { "type": "array", "items": { "type": "string" }, "description": "Sources are every log the node can show: \"agent\", and one per engine running there." }, "error": { "type": "string" } } }, "MembershipRequest": { "type": "object", "description": "MembershipRequest puts a person in an organization, team or project, or with DELETE takes them out.", "properties": { "target": { "type": "string", "description": "Target is org:NAME, team:ORG/TEAM or project:ORG/TEAM/PROJECT, or the ID after the colon." }, "role": { "type": "string", "description": "Role is member or manager; member when absent. Ignored by DELETE." } } }, "MembershipView": { "type": "object", "description": "MembershipView is one place a person belongs.", "properties": { "target": { "type": "string" }, "path": { "type": "string" }, "role": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "by": { "type": "string" } } }, "MetricsQuery": { "type": "object", "description": "MetricsQuery is one line set of a chart: a PromQL expression, and the label naming each line.", "properties": { "id": { "type": "string" }, "expr": { "type": "string" }, "by": { "type": "string" } } }, "MetricsRequest": { "type": "object", "description": "MetricsRequest asks for several queries over one window at once.", "properties": { "window": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "step": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "queries": { "type": "array", "items": { "$ref": "#/components/schemas/MetricsQuery" } } } }, "MetricsResult": { "type": "object", "description": "MetricsResult is each query's lines, by id; Configured is false when no Prometheus is set, and Errors says which queries failed and why.", "properties": { "configured": { "type": "boolean" }, "series": { "type": "object", "additionalProperties": { "type": "array", "items": { "$ref": "#/components/schemas/promq.Series" } } }, "errors": { "type": "object", "additionalProperties": { "type": "string" } } } }, "ModelAdded": { "type": "object", "description": "ModelAdded names the model added to the catalog.", "properties": { "added": { "type": "string" } } }, "ModelTotals": { "type": "object", "description": "ModelTotals counts models by whether they have what they asked for.", "properties": { "total": { "type": "integer" }, "satisfied": { "type": "integer" }, "short": { "type": "integer" } } }, "ModelView": { "type": "object", "description": "ModelView is a model as `ctl models` shows it.", "properties": { "name": { "type": "string" }, "canary": { "$ref": "#/components/schemas/catalog.Canary", "description": "Canary is a share of its requests sent to a candidate; CanaryOf is set on the candidate, naming the model it is a canary of." }, "canary_of": { "type": "string" }, "eval": { "$ref": "#/components/schemas/catalog.EvalGate", "description": "Eval is the quality suite its new weights must pass, when it has one." }, "description": { "type": "string", "description": "Description is what the model is for, when somebody said." }, "aliases": { "type": "array", "items": { "type": "string" } }, "source": { "type": "string" }, "role": { "type": "string", "description": "Role is \"guard\" for a guardrails judge, empty for a model clients use." }, "min_replicas": { "type": "integer" }, "max_replicas": { "type": "integer" }, "ready_replicas": { "type": "integer" }, "total_replicas": { "type": "integer" }, "desired_replicas": { "type": "integer", "description": "Desired is how many it should have now: Min, or for an on-demand model one while it is being asked for and none otherwise." }, "failures": { "type": "integer", "description": "Failures counts replicas that failed to start in a row." }, "parked": { "type": "boolean", "description": "Parked is set once Failures reached the limit; the model is not retried until its definition changes or `ctl retry` is run. Reason is the last error." }, "reason": { "type": "string" }, "unplaceable": { "type": "boolean", "description": "Unplaceable is set when it is short and the last attempt found no node." }, "fallbacks": { "type": "array", "items": { "type": "string" } }, "profiles": { "type": "array", "items": { "type": "string" } }, "memory_gb": { "type": "integer", "description": "MemoryGB and CPUCores are what one replica reserves, from its first profile; MeasuredMemoryGB is the most one of its replicas uses now, 0 when none is measured." }, "cpu_cores": { "type": "integer" }, "measured_memory_gb": { "type": "number" }, "warnings": { "type": "array", "items": { "type": "string" }, "description": "Warnings are what makes its reservation wrong: nothing declared where placement needs a figure, or less declared than it uses." }, "class": { "type": "string", "description": "Class is its capacity class; Preempted the replicas it lost to a higher class; HeldFor the model it is giving room to now, if any." }, "owner": { "type": "string" }, "external": { "type": "string", "description": "External is where a model served outside the cluster goes, provider host and its name for the model; empty for one served here." }, "adapters": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.Adapter" }, "description": "Adapters are the LoRA adapters it serves." }, "preempted": { "type": "integer" }, "held_for": { "type": "string" }, "origin": { "$ref": "#/components/schemas/OriginView", "description": "Origin is the registry repository its weights came from, and at which commit; Update what that repository had when it was last asked." }, "update": { "$ref": "#/components/schemas/modelserve.UpdateInfo" } } }, "NodeEngineRequest": { "type": "object", "description": "NodeEngineRequest chooses one engine's build for a node.", "properties": { "engine": { "type": "string" }, "build": { "type": "string", "description": "Build is \"auto\", a build such as \"cu129\", or \"none\"." } } }, "NodeLabelsRequest": { "type": "object", "description": "NodeLabelsRequest sets and removes labels on a node.", "properties": { "set": { "type": "object", "additionalProperties": { "type": "string" } }, "remove": { "type": "array", "items": { "type": "string" }, "description": "Remove are keys whose label set through the control plane goes; the agent's own value for the key, if it has one, is in force again." } } }, "NodeLabelsView": { "type": "object", "description": "NodeLabelsView is a node's labels after a change.", "properties": { "id": { "type": "string" }, "operator_labels": { "type": "object", "additionalProperties": { "type": "string" }, "description": "OperatorLabels are those set through the control plane." }, "labels": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Labels are what placement matches: the agent's with the operator's over them. Absent for a node that has not registered yet." }, "location": { "$ref": "#/components/schemas/facility.Location" } } }, "NodeRemoved": { "type": "object", "description": "NodeRemoved names the node forgotten. Removed is the string \"true\".", "properties": { "id": { "type": "string" }, "removed": { "type": "string" } } }, "NodeStateRequest": { "type": "object", "description": "NodeStateRequest cordons, drains or readies a node: ready (or uncordon), cordoned (or cordon), draining (or drain).", "properties": { "state": { "type": "string" } } }, "NodeStateView": { "type": "object", "description": "NodeStateView is a node's state after the change.", "properties": { "id": { "type": "string" }, "state": { "type": "string" } } }, "NodeTotals": { "type": "object", "description": "NodeTotals counts nodes by the states that need different responses.", "properties": { "total": { "type": "integer" }, "ready": { "type": "integer" }, "cordoned": { "type": "integer" }, "draining": { "type": "integer" }, "unreachable": { "type": "integer" } } }, "NodeView": { "type": "object", "description": "NodeView is a node as `ctl nodes` shows it.", "properties": { "id": { "type": "string" }, "hostname": { "type": "string" }, "mgmt_addr": { "type": "string" }, "state": { "type": "string" }, "labels": { "type": "object", "additionalProperties": { "type": "string" } }, "gpu_total": { "type": "integer" }, "gpu_free": { "type": "integer" }, "memory_gb": { "type": "integer", "description": "MemoryGB is the machine's RAM, 0 when the agent did not report it. It is what decides whether a CPU profile can be placed here, so it belongs where someone looks when a model will not schedule." }, "cpu_count": { "type": "integer", "description": "CPUCount is the machine's CPUs, 0 when the agent did not report them." }, "engines": { "type": "array", "items": { "type": "string" }, "description": "Engines are the inference engines installed here, as the agent found them. Absent means the agent is older than the probe and said nothing, which is not the same as having none — placement treats it that way too, or a control plane upgrade would empty a fleet." }, "engine_versions": { "type": "object", "additionalProperties": { "type": "string" }, "description": "EngineVersions are the installed engines with their versions: llamacpp → b10991. ComputeCapabilities are its GPUs' CUDA compute capabilities, 7.0 for a V100, so an engine build's support can be read against them." }, "multi_node": { "type": "string", "description": "MultiNode is whether it can take part in replicas spanning nodes: \"ready\", \"down: mlx5_1\" naming the declared adapters whose ports are not active, or empty for a node on no fabric. Its own replicas run either way." }, "compute_capabilities": { "type": "array", "items": { "type": "string" } }, "provision": { "type": "array", "items": { "$ref": "#/components/schemas/inventory.EngineInstall" }, "description": "Provision is where installing each wanted engine stands. An engine is in Engines only once its installation here is ready." }, "engine_builds": { "type": "object", "additionalProperties": { "type": "string" }, "description": "EngineBuilds are the builds chosen for this node, by engine: \"auto\" (its hardware decides), a build (\"cu129\"), or \"none\". Only on a node with GPUs, the only kind with a choice to make." }, "os": { "type": "string", "description": "OS is the operating system and architecture, as the agent read them." }, "warnings": { "type": "array", "items": { "type": "string" }, "description": "Warnings are facts about the machine that make it slow or unusable without making it unhealthy: a VM with no vector instructions runs every model, at a fifth of the speed." }, "models_on_disk": { "type": "array", "items": { "type": "string" }, "description": "Models are the weights this node can see. Absent means it was not asked to look, which is not the same as holding none." }, "disk_free_gb": { "type": "integer", "description": "DiskFreeGB and DiskTotalGB are the filesystems holding those weights, summed. Zero means the agent did not report any, which an older agent and a node with no model directories both do — so it reads as unknown rather than as a full disk.\n\nSummed because an operator asking \"can this node take another model\" wants one number; the per-filesystem detail is in the node's own record for anyone who needs it. Shared filesystems are left out of the sum: the space on a filer is not this node's to spend, and adding it would let a fleet of twenty nodes each believe it has the same free terabyte." }, "disk_total_gb": { "type": "integer" }, "gpu_classes": { "type": "array", "items": { "type": "string" } }, "gpus_by_class": { "type": "array", "items": { "$ref": "#/components/schemas/ClassGPUs" }, "description": "ClassGPUs counts the node's devices by class, in the order of Classes. A node with a card in MIG mode has several classes — each profile its instances are cut to, and any whole card beside them — and GPUTotal alone would add 3g.40gb instances to 80 GB cards." }, "fabrics": { "type": "array", "items": { "type": "string" } }, "unhealthy_gpus": { "type": "array", "items": { "type": "string" }, "description": "Unhealthy lists GPUs kept out of placement and why, which is usually the answer when a node looks idle but nothing will schedule onto it." }, "location": { "$ref": "#/components/schemas/facility.Location", "description": "Location is where the node is in the building, from its llmgw.io/site, room, row, rack and pdu labels; absent when it carries none." }, "held": { "type": "string", "description": "Held names the hold keeping the node out of placement, \"rack r12-07 is held: PDU swap\"; empty when none is." }, "held_domain": { "type": "string", "description": "HeldDomain is the held domain, level:name, for releasing it." }, "operator_labels": { "type": "object", "additionalProperties": { "type": "string" }, "description": "OperatorLabels are the labels set through the control plane, which Labels already includes over the agent's own." }, "last_seen_ago": { "type": "string" }, "agent_version": { "type": "string" }, "features": { "type": "array", "items": { "type": "string" }, "description": "Features are the requests the agent answers beyond the usual: \"fabric-test\". Absent is an agent too old to say." }, "replicas": { "type": "integer" }, "load": { "$ref": "#/components/schemas/LoadView", "description": "Load is how busy the machine is, absent when its agent has not measured it lately — which is unknown, not idle." }, "ib_ports": { "type": "array", "items": { "$ref": "#/components/schemas/IBPortView" }, "description": "IBPorts are the node's InfiniBand and RoCE ports at the last heartbeat." }, "gpus": { "type": "array", "items": { "$ref": "#/components/schemas/GPUView" }, "description": "GPUs are the cards, with how they are wired: NVLink peers, the adapter nearest each, and the NVLink domain each has joined." }, "nvlink_domain": { "type": "string", "description": "NVLinkDomain is the multi-node domain every card has joined, if any." }, "imex": { "type": "string" }, "imex_channels": { "type": "integer" } } }, "OIDCView": { "type": "object", "description": "OIDCView is auth.oidc as it is in force.", "properties": { "issuer": { "type": "string" }, "client_id": { "type": "string" }, "label": { "type": "string" }, "create_accounts": { "type": "boolean" }, "no_passwords": { "type": "boolean" } } }, "OrgView": { "type": "object", "description": "OrgView is an organization with what is in it.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "members": { "type": "integer" }, "teams": { "type": "array", "items": { "$ref": "#/components/schemas/TeamView" } } } }, "OriginRequest": { "type": "object", "description": "OriginRequest names the repository a model's weights came from.", "properties": { "repo": { "type": "string" } } }, "OriginView": { "type": "object", "description": "OriginView is where a model's weights were published.", "properties": { "repo": { "type": "string" }, "revision": { "type": "string" }, "previous": { "type": "string", "description": "Previous is the commit the last update replaced, which it can go back to." } } }, "OrphanView": { "type": "object", "description": "OrphanView is cached weights on one node that no catalog model accounts for.", "properties": { "node": { "type": "string" }, "paths": { "type": "array", "items": { "type": "string" } }, "bytes": { "type": "integer", "format": "int64", "description": "Bytes is what deleting them would free, as far as the node reported. A file whose size was not reported counts as zero rather than being left out, so the list and the number always describe the same set." } } }, "OwnerRequest": { "type": "object", "description": "OwnerRequest sets the part of the tenancy tree a model's capacity counts against: org:NAME, team:ORG/TEAM or project:ORG/TEAM/PROJECT, or their IDs. Empty makes the model shared.", "properties": { "owner": { "type": "string" } } }, "OwnerView": { "type": "object", "description": "OwnerView is a model's owner now, as scope:ID.", "properties": { "model": { "type": "string" }, "owner": { "type": "string" } } }, "ParkedModel": { "type": "object", "description": "ParkedModel is a model no longer retried, and why.", "properties": { "model": { "type": "string" }, "failures": { "type": "integer" }, "reason": { "type": "string" } } }, "PresetView": { "type": "object", "description": "PresetView is one preset as it stands in this cluster.", "properties": { "name": { "type": "string" }, "makes": { "type": "string" }, "description": { "type": "string" }, "card": { "type": "string" }, "licence": { "$ref": "#/components/schemas/catalog.License" }, "fits": { "type": "boolean", "description": "Fits is whether some node has a card that meets the preset's need; FitsClasses names those classes." }, "fits_classes": { "type": "array", "items": { "type": "string" } }, "in_catalog": { "type": "boolean" }, "added_by": { "type": "string", "description": "AddedBy is \"auto\" when the leader added it, who did otherwise, \"\" when it was not added as a preset; AddedAt is when." }, "added_at": { "type": "string", "format": "date-time" }, "declined": { "type": "boolean", "description": "Declined is whether somebody removed it after it was added, so it is not added again by itself; adding it again clears that." }, "blocked": { "type": "string", "description": "Blocked is why the leader does not add it by itself — presets.auto off, no ComfyUI, no card that fits, declined, another model already making the same — empty when it would or has." } } }, "PresetsAutoRequest": { "type": "object", "description": "PresetsAutoRequest turns the automatic adding of presets on or off.", "properties": { "on": { "type": "boolean" } } }, "PresetsView": { "type": "object", "description": "PresetsView is the models that come with llmgw, and whether the leader adds them by itself.", "properties": { "auto": { "type": "boolean", "description": "Auto is whether a preset is added when a node fits it and the catalog has no model that makes what it makes (presets.auto)." }, "comfyui": { "type": "string", "description": "ComfyUI is engines.comfyui as it stands: the version the nodes install, \"\" for none — in which case adding a preset sets it, and the control planes start again on that." }, "presets": { "type": "array", "items": { "$ref": "#/components/schemas/PresetView" } } } }, "ProjectView": { "type": "object", "description": "ProjectView is a project, with how many people and keys are in it.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "team": { "type": "string" }, "path": { "type": "string", "description": "Path is ORG/TEAM/PROJECT by name." }, "users": { "type": "integer" }, "keys": { "type": "integer" }, "active_keys": { "type": "integer" } } }, "QuotaRequest": { "type": "object", "description": "QuotaRequest sets a scope's quota. Scope may be written with an ID or a name: org:Acme, team:Acme/ml, project:Acme/ml/training.", "properties": { "scope": { "type": "string" }, "guarantee": { "$ref": "#/components/schemas/store.Resources" }, "limit": { "$ref": "#/components/schemas/store.Resources" } } }, "QuotaSet": { "type": "object", "description": "QuotaSet is the scope a quota was set on, as org:ID, team:ID or project:ID whatever name it was asked by.", "properties": { "scope": { "type": "string" } } }, "QuotaView": { "type": "object", "description": "QuotaView is one scope's quota with what it holds now.", "properties": { "scope": { "type": "string", "description": "Scope is team:ID; Name is how people know it, \"Acme / ml\"." }, "name": { "type": "string" }, "guarantee": { "$ref": "#/components/schemas/store.Resources" }, "limit": { "$ref": "#/components/schemas/store.Resources" }, "holds": { "$ref": "#/components/schemas/quota.Amount" }, "updated_by": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "RailView": { "type": "object", "description": "RailView is one rail's result.", "properties": { "a": { "type": "string" }, "b": { "type": "string" }, "rate_gbps": { "type": "integer" }, "gbps": { "type": "number" }, "verdict": { "type": "string" }, "detail": { "type": "string" } } }, "RejectionView": { "type": "object", "description": "RejectionView is one rejected candidate.", "properties": { "profile": { "type": "string" }, "pool": { "type": "string" }, "node": { "type": "string" }, "reason": { "type": "string" } } }, "Removed": { "type": "object", "description": "Removed names what was taken away: a model, or a quota's scope.", "properties": { "removed": { "type": "string" } } }, "ReplayRequest": { "type": "object", "description": "ReplayRequest names the model a kept request is sent to again.", "properties": { "model": { "type": "string" } } }, "ReplayView": { "type": "object", "description": "ReplayView is a kept request sent again, beside what it got the first time.", "properties": { "original": { "$ref": "#/components/schemas/store.RequestBody" }, "model": { "type": "string" }, "status": { "type": "integer" }, "body": { "description": "Any JSON value." }, "took_ms": { "type": "integer", "format": "int64" } } }, "ReplicaTotal": { "type": "object", "description": "ReplicaTotal counts replicas by state.", "properties": { "ready": { "type": "integer" }, "starting": { "type": "integer" }, "draining": { "type": "integer" }, "failed": { "type": "integer" } } }, "ReplicaView": { "type": "object", "description": "ReplicaView is a replica as `ctl replicas` shows it.", "properties": { "id": { "type": "string" }, "engine_key": { "type": "string", "description": "EngineKey is the key this replica's engine demands, for `ctl bench` and anyone else holding the admin listener who needs to reach an engine directly. The client-facing pages never render it." }, "restart": { "type": "string", "description": "Restart is \"queued\" or \"replacing\" while an operator's restart of this replica is under way." }, "model": { "type": "string" }, "profile": { "type": "string" }, "stale": { "type": "boolean", "description": "Stale is true when the profile has been edited since this replica was placed, so it is running a definition the catalog no longer holds.\n\nReported rather than acted on. Moving a replica that is serving costs more than the imperfection, and the operator who made the edit is the one who should decide whether it is worth a restart." }, "state": { "type": "string" }, "pool": { "type": "string" }, "fabric": { "type": "string" }, "endpoint": { "type": "string" }, "age_seconds": { "type": "integer", "format": "int64" }, "idle_seconds": { "type": "integer", "format": "int64", "description": "IdleSec is how long since a request was routed here. Negative means the router has not reported any use of this replica, which is not the same as idle — it is what a replica looks like before anything has asked for it, and after a router restart." }, "error": { "type": "string" }, "shards": { "type": "array", "items": { "$ref": "#/components/schemas/ShardView" } } } }, "RequestView": { "type": "object", "description": "RequestView is what one request went through.", "properties": { "request_id": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "key_id": { "type": "string" }, "user_id": { "type": "string" }, "project_id": { "type": "string" }, "model": { "type": "string" }, "served_model": { "type": "string" }, "replica": { "type": "string" }, "status": { "type": "integer" }, "latency_ms": { "type": "integer", "format": "int64" }, "queue_ms": { "type": "integer", "format": "int64" }, "ttft_ms": { "type": "integer", "format": "int64" }, "prompt_tokens": { "type": "integer", "format": "int64" }, "completion_tokens": { "type": "integer", "format": "int64" }, "images": { "type": "integer", "format": "int64" }, "meshes": { "type": "integer", "format": "int64" }, "cost_micros": { "type": "integer", "format": "int64" }, "guard_action": { "type": "string", "description": "What the guardrails did, by name." }, "guard_policy": { "type": "string" }, "guard_category": { "type": "string" }, "guard_rule": { "type": "string" }, "guard_ms": { "type": "integer", "format": "int64" }, "end_user": { "type": "string", "description": "What the client said about it: OpenAI's user field, and its tags." }, "tags": { "type": "object", "additionalProperties": { "type": "string" } }, "cache_hit": { "type": "boolean", "description": "CacheHit is an answer reused from the project's answer cache." } } }, "ResourcesRequest": { "type": "object", "description": "ResourcesRequest sets what a model's profiles reserve of a node.", "properties": { "profile": { "type": "string", "description": "Profile is one profile's name; empty is every profile." }, "memory_gb": { "type": "integer" }, "cpu_cores": { "type": "integer" } } }, "RestartRequest": { "type": "object", "description": "RestartRequest names what to restart: replicas by id, every replica of some models, or — All — every ready replica in the cluster.", "properties": { "replicas": { "type": "array", "items": { "type": "string" } }, "models": { "type": "array", "items": { "type": "string" } }, "all": { "type": "boolean" }, "in_place": { "type": "boolean", "description": "InPlace stops each replica before starting its replacement, rather than starting the replacement beside it first." }, "max_surge": { "type": "integer", "description": "MaxSurge is how many of a model's replicas are replaced beside themselves at once, MaxUnavailable how many are stopped first at once; both zero is one at a time, replaced beside itself." }, "max_unavailable": { "type": "integer" } } }, "RestartResult": { "type": "object", "description": "RestartResult lists the replicas queued.", "properties": { "queued": { "type": "array", "items": { "type": "string" } } } }, "Result": { "type": "object", "description": "Result is what a change that has no other answer says it did.", "properties": { "result": { "type": "string" } } }, "RetryView": { "type": "object", "description": "RetryView says whether the model had been parked, given up on after failing to start, before it was retried.", "properties": { "was_parked": { "type": "boolean" } } }, "ScaleRequest": { "type": "object", "description": "ScaleRequest is how many replicas a model should run.", "properties": { "min": { "type": "integer" }, "max": { "type": "integer", "description": "Max omitted follows Min, which is what the catalog does for a model that declares only a minimum." }, "idle_timeout": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." } } }, "ScaleResponse": { "type": "object", "description": "ScaleResponse reports the scaling that is now in force.\n\nWhat is in force rather than what was asked for: the catalog fills in a max that was left out, and a caller that echoed its own request would print a number the cluster is not using.", "properties": { "model": { "type": "string" }, "min": { "type": "integer" }, "max": { "type": "integer" }, "idle_timeout": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "on_demand": { "type": "boolean" } } }, "ScopeUsageView": { "type": "object", "description": "ScopeUsageView is one group's spend, with its quota when it has one.", "properties": { "scope": { "type": "string" }, "id": { "type": "string" }, "name": { "type": "string" }, "keys": { "type": "integer", "format": "int64" }, "requests": { "type": "integer", "format": "int64" }, "prompt_tokens": { "type": "integer", "format": "int64" }, "completion_tokens": { "type": "integer", "format": "int64" }, "cost_micros": { "type": "integer", "format": "int64" }, "errors": { "type": "integer", "format": "int64" }, "last_at": { "type": "string", "format": "date-time" }, "budget_micros": { "type": "integer", "format": "int64", "description": "Budget is what this level sets, absent when it sets none. A group bounded only by its parent has no budget of its own, and reporting the parent's against each child would read as though each had that much." }, "budget_period": { "type": "string" }, "fraction": { "type": "number", "description": "Fraction is spend over budget, absent for the same reason." } } }, "SecretRequest": { "type": "object", "description": "SecretRequest is a secret for the store to keep.", "properties": { "value": { "type": "string" } } }, "SettingsRequest": { "type": "object", "description": "SettingsRequest is a new version of the cluster's settings, made from the version Base, which must still be the newest.", "properties": { "base": { "type": "integer", "format": "int64" }, "body": { "type": "string" }, "note": { "type": "string" } } }, "SettingsRollbackRequest": { "type": "object", "description": "SettingsRollbackRequest puts an earlier version's settings back in force, as a new version.", "properties": { "version": { "type": "integer", "format": "int64" }, "note": { "type": "string" } } }, "SettingsView": { "type": "object", "description": "SettingsView is one version of the cluster's settings.", "properties": { "version": { "type": "integer", "format": "int64" }, "body": { "type": "string" }, "note": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "by": { "type": "string" }, "local_keys": { "type": "array", "items": { "type": "string" } } } }, "ShardView": { "type": "object", "description": "ShardView is one shard of a replica.", "properties": { "id": { "type": "string" }, "node": { "type": "string" }, "rank": { "type": "integer" }, "gpus": { "type": "array", "items": { "type": "integer" } }, "state": { "type": "string" }, "error": { "type": "string" }, "fetch": { "$ref": "#/components/schemas/FetchView", "description": "Fetch is the download this shard is waiting on, absent when it is not waiting on one. It is what tells a replica pulling a hundred gigabytes apart from one that is wedged — which look identical without it." }, "cpu_cores": { "type": "number", "description": "CPUCores and MemoryBytes are the engine's use of its node, from the node's last heartbeat; zero when not measured." }, "memory_bytes": { "type": "integer", "format": "int64" }, "compute": { "$ref": "#/components/schemas/ComputeView", "description": "Compute is where the engine said it put the model as it became ready: absent when it did not say." } } }, "StoreMember": { "type": "object", "description": "StoreMember is one member of a replicated store, as its Patroni reports it.", "properties": { "name": { "type": "string" }, "host": { "type": "string" }, "role": { "type": "string" }, "state": { "type": "string" }, "lag": { "type": "integer", "format": "int64", "description": "Lag is bytes behind the leader; -1 unknown, 0 for the leader." } } }, "Summary": { "type": "object", "description": "Summary is the whole fleet in one answer.\n\nA per-node listing is the right tool for four nodes and the wrong one for two hundred: the questions that matter at that size — how full am I, what is broken, what is holding cards it is not using — are aggregates, and reading them off a long table is a chore that gets skipped. Everything here is derived from the same state the tables show, so it can never disagree with them; it is a different question asked of the same facts.", "properties": { "version": { "type": "string", "description": "Version is the release the answering control plane runs: not the binary on its disk, which a manual install changes underneath it." }, "nodes": { "$ref": "#/components/schemas/NodeTotals" }, "gpus": { "type": "array", "items": { "$ref": "#/components/schemas/ClassUse" } }, "fabrics": { "type": "array", "items": { "$ref": "#/components/schemas/FabricUse" }, "description": "Fabrics matter because a multi-node replica may never span two of them, so free capacity in the wrong fabric is not capacity for the model that needs it." }, "replicas": { "$ref": "#/components/schemas/ReplicaTotal" }, "models": { "$ref": "#/components/schemas/ModelTotals" }, "unplaceable": { "type": "array", "items": { "type": "string" }, "description": "Unplaceable names models the scheduler currently cannot satisfy. This is the line that turns \"something is wrong\" into a place to look." }, "parked": { "type": "array", "items": { "$ref": "#/components/schemas/ParkedModel" }, "description": "Parked are models that failed every time they started and are no longer retried, with the last error." }, "idle_replicas": { "type": "array", "items": { "$ref": "#/components/schemas/IdleReplica" }, "description": "IdleReplicas are serving replicas nothing has asked for in a while, which on a fleet with more models than GPUs is the first place to find room." }, "store": { "type": "array", "items": { "$ref": "#/components/schemas/StoreMember" }, "description": "Store is the members of the store's cluster when it is replicated, and StoreError why it could not be read; both empty for a single database." }, "store_error": { "type": "string" }, "control_planes": { "$ref": "#/components/schemas/ControlPlanes", "description": "ControlPlanes is the cluster's control planes when there is more than one: which leads, which stand by, and the floating address in front." }, "judges": { "type": "array", "items": { "$ref": "#/components/schemas/JudgeView" }, "description": "Judges are the guardrails' judge models with something wrong." }, "stopped": { "type": "boolean", "description": "Stopped says the operators have stopped the service (llmgw stop): no model runs, and requests for one are answered 503." }, "guard_off": { "type": "boolean", "description": "GuardOff says the guardrails are turned off (guard.enabled: false): no request is checked, whatever the policies say." } } }, "TargetView": { "type": "object", "description": "TargetView is how many replicas a model needs to serve a throughput, from what one replica was measured to serve, and whether the cluster has room.", "properties": { "model": { "type": "string" }, "tok_per_sec": { "type": "number", "description": "TokPerSec is what was asked for; PerReplica what one replica was measured to serve at its SLO, on Profile." }, "per_replica_tok_per_sec": { "type": "number" }, "profile": { "type": "string" }, "needed": { "type": "integer", "description": "Needed replicas in all; Current hold capacity now; More is how many of Needed are not running, and Room how many more fit." }, "current": { "type": "integer" }, "more": { "type": "integer" }, "room": { "type": "integer" }, "fits": { "type": "boolean" }, "blocked": { "type": "array", "items": { "type": "string" } }, "preempts": { "type": "array", "items": { "type": "string" }, "description": "Preempts is whose replicas would be stopped to make the room, when free room alone is not enough; Room counts that room too." } } }, "TeamView": { "type": "object", "description": "TeamView is a team with its projects.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "org": { "type": "string" }, "members": { "type": "integer" }, "projects": { "type": "array", "items": { "$ref": "#/components/schemas/ProjectView" } } } }, "TenancyChangeRequest": { "type": "object", "description": "TenancyChangeRequest renames an organization, team or project, or moves a team to another organization or a project to another team.", "properties": { "name": { "type": "string" }, "in": { "type": "string", "description": "In is where it moves to, by name or ID; not for an organization." } } }, "TenancyCreateRequest": { "type": "object", "description": "TenancyCreateRequest adds an organization, a team or a project.", "properties": { "name": { "type": "string" }, "in": { "type": "string", "description": "In is the organization a team goes in, or the team a project goes in (ORG/TEAM), by name or ID; nothing for an organization." } } }, "TenancyItem": { "type": "object", "description": "TenancyItem is an organization, team or project added or changed.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "in": { "type": "string", "description": "In is the organization a team is in, or the team a project is in, by ID." } } }, "TopologyView": { "type": "object", "description": "TopologyView is one fabric's map, with the cluster's own adapters on it live: their state, rate and traffic from the last heartbeat.", "properties": { "id": { "type": "string" }, "key": { "type": "string" }, "label": { "type": "string" }, "declared": { "type": "array", "items": { "type": "string" } }, "scanned_at": { "type": "string", "format": "date-time" }, "scanned_by": { "type": "string" }, "took_ms": { "type": "integer", "format": "int64" }, "error": { "type": "string" }, "map": { "$ref": "#/components/schemas/topology.View" }, "live": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/Live" } }, "problems": { "type": "array", "items": { "$ref": "#/components/schemas/fabrics.Problem" }, "description": "Problems are the fabric's own, from the analysis of its identity and subnet managers." }, "sm": { "$ref": "#/components/schemas/fabrics.SM" }, "sms": { "type": "array", "items": { "$ref": "#/components/schemas/fabrics.SM" } } } }, "TrainJobView": { "type": "object", "description": "TrainJobView is a job as listed.", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "model": { "type": "string" }, "base_repo": { "type": "string" }, "base_revision": { "type": "string" }, "node": { "type": "string" }, "owner": { "type": "string" }, "gpu_memory_mib": { "type": "integer" }, "params": { "type": "string" }, "gguf": { "type": "boolean" }, "pairs": { "type": "integer" }, "state": { "type": "string" }, "step": { "type": "integer" }, "steps": { "type": "integer" }, "loss": { "type": "number" }, "message": { "type": "string" }, "peak_mib": { "type": "integer" }, "created_at": { "type": "string", "format": "date-time" }, "started_at": { "type": "string", "format": "date-time" }, "finished_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "string" }, "artifacts": { "type": "array", "items": { "type": "string" }, "description": "Artifacts are what it made: peft (a gzipped tar), gguf." } } }, "TrainPublishView": { "type": "object", "description": "TrainPublishView is an adapter published: where the nodes fetch it from, and what to do for replicas to load it.", "properties": { "adapter": { "type": "string" }, "model": { "type": "string" }, "source": { "type": "string" }, "owner": { "type": "string", "description": "Owner is who sees it; empty is every caller of the model." }, "note": { "type": "string" } } }, "TrainRequest": { "type": "object", "description": "TrainRequest queues a job.", "properties": { "name": { "type": "string", "description": "Name is the adapter's: what requests will ask for it by." }, "model": { "type": "string", "description": "Model is the catalog model the adapter is for." }, "base_repo": { "type": "string", "description": "BaseRepo and BaseRevision are the weights trained on: the model's own on its registry, in safetensors (Hugging Face), not a GGUF." }, "base_revision": { "type": "string" }, "node": { "type": "string", "description": "Node trains it; GPUMemoryMiB is what it needs of a card, which can be what an engine there leaves free." }, "gpu_memory_mib": { "type": "integer" }, "owner": { "type": "string", "description": "Owner is who the adapter will belong to: org:, team:, project: (by path or ID), user: or key:. Only callers there see it. When the pairs come from one knowledge base, it defaults to that collection's owner; it must be able to read every collection they come from." }, "public": { "type": "boolean", "description": "Public makes the adapter every caller's its model allows. Refused for pairs from a knowledge base." }, "data": { "type": "string", "description": "Data is the pairs, NDJSON of {\"q\", \"a\"} (llmgw ctl kb dataset)." }, "params": { "type": "object", "additionalProperties": {}, "description": "Params tune the trainer: rank, alpha, dropout, epochs, lr, batch, max_len, seed." }, "gguf": { "type": "boolean", "description": "GGUF also makes the adapter in llama.cpp's format; when absent, it does when the model is served by llama.cpp." } } }, "UpgradeRequest": { "type": "object", "description": "UpgradeRequest names the release a node should run.", "properties": { "version": { "type": "string" } } }, "UpgradeView": { "type": "object", "description": "UpgradeView is the release a node was told to run.", "properties": { "node": { "type": "string" }, "version": { "type": "string" } } }, "UserView": { "type": "object", "description": "UserView is a person, with where they are a member.", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "name": { "type": "string" }, "state": { "type": "string" }, "role": { "type": "string", "description": "Role is the person's part in running the gateway, if any: viewer, operator, billing or admin." }, "memberships": { "type": "array", "items": { "$ref": "#/components/schemas/MembershipView" } }, "created_at": { "type": "string", "format": "date-time" }, "last_login_at": { "type": "string", "format": "date-time" } } }, "bench.Capacity": { "type": "object", "description": "Capacity is what one replica was measured to serve, kept so the measurement outlives the terminal it was printed in.\n\nThe conclusion of a run, not the run. The ramp itself — every concurrency level, its latencies, its errors — is worth reading once, while deciding whether the run was sound; it is not worth carrying around afterwards, and storing it would grow without bound as a model is re-benchmarked. What a later reader needs is the number and enough provenance to judge whether it is still true.", "properties": { "model": { "type": "string" }, "profile": { "type": "string" }, "max_concurrency_at_slo": { "type": "integer", "description": "MaxConcurrencyAtSLO is the capacity: the highest concurrency that still met the target. Zero means even one request did not, which is a real result and not a missing one — it says this hardware cannot serve this model at this SLO at all." }, "throughput_tok_per_sec": { "type": "number", "description": "ThroughputTokPerSec and the latencies are taken at that level, not at the peak. Peak throughput arrives long after latency has become unusable, so reporting it would overstate what the hardware can serve." }, "ttft_p99": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "tpot_p99": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "suggested_target_waiting": { "type": "integer", "description": "SuggestedTargetWaiting and SuggestedKVCeiling are the queue depth and cache pressure seen while the SLO was still being met, which is what admission should treat as healthy for this model. Admission currently applies one global default to every model; these are the per-model numbers it should be using instead." }, "suggested_kv_ceiling": { "type": "number" }, "slo": { "$ref": "#/components/schemas/bench.SLO", "description": "SLO is recorded because capacity is meaningless without it. The same replica has a different capacity against a 200ms first-token target than against a 2s one, and a number stored without the target it was measured against cannot be compared with anything." }, "target": { "type": "string", "description": "Target is the endpoint the load actually went to, kept so a profile measured against the gateway is never mistaken for one measured against a replica. Only the second says anything about the hardware." }, "measured_at": { "type": "string", "format": "date-time" } } }, "bench.SLO": { "type": "object", "description": "SLO is the latency target capacity is measured against.", "properties": { "TTFTp99": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." }, "TPOTp99": { "type": "integer", "format": "int64", "description": "A duration, in nanoseconds." } } }, "canary.Side": { "type": "object", "description": "Side is what one side of a canary served since it began.", "properties": { "requests": { "type": "integer", "format": "int64" }, "errors": { "type": "integer", "format": "int64", "description": "Errors are answers of 500 and up: the engine's failures, not the client's mistakes." }, "ttft_ms": { "type": "number", "description": "TTFT is over streamed requests, Latency over the rest, both means in milliseconds with how many they are over." }, "ttft_count": { "type": "integer", "format": "int64" }, "latency_ms": { "type": "number" }, "latency_count": { "type": "integer", "format": "int64" } } }, "canary.Stat": { "type": "object", "description": "Stat compares the two sides of one model's canary.", "properties": { "canary": { "type": "string" }, "since": { "type": "string", "format": "date-time" }, "stable": { "$ref": "#/components/schemas/canary.Side" }, "candidate": { "$ref": "#/components/schemas/canary.Side" } } }, "catalog.Adapter": { "type": "object", "description": "Adapter is a LoRA adapter served on a model's replicas.", "properties": { "name": { "type": "string", "description": "Name is what clients ask for, like a model name." }, "source": { "type": "string", "description": "Source is the adapter: a GGUF file for llama.cpp; for vLLM a PEFT adapter directory (a mirror version ending in \"/\", a path on the node, or a Hugging Face repository id). Fetched by each node as the model's weights are." }, "scale": { "type": "number", "description": "Scale is how strongly it is applied; zero takes 1." }, "owner": { "type": "string", "description": "Owner is the part of the tenancy tree the adapter belongs to — org:ID, team:ID, project:ID, user:ID or key:ID — and only callers in it see it: to anyone else it is a model that does not exist. An adapter trained on an organisation's documents carries some of what they say in its weights. Empty is every caller the model allows." } } }, "catalog.Canary": { "type": "object", "description": "Canary is a share of a model's requests sent to a candidate, and when to give up on it.", "properties": { "model": { "type": "string", "description": "Model is the candidate: a catalog model, usually this one at newer weights, which clients cannot name themselves." }, "percent": { "type": "integer", "description": "Percent of requests go to it, 0 to 100." }, "min_requests": { "type": "integer", "description": "The candidate is taken out — rolled back — when, over at least MinRequests of its own, its error rate is MaxErrorIncrease above this model's (0.05 is five points), or its mean time to the first token is MaxTTFTRatio times this model's. Zero is 50, 0.05 and 1.5." }, "max_error_increase": { "type": "number" }, "max_ttft_ratio": { "type": "number" } } }, "catalog.Capabilities": { "type": "object", "description": "Capabilities describes what a client may ask a model for.\n\nDeclared by the operator rather than discovered, because there is no way to ask an engine what its model can do. That makes these claims, and a wrong claim is worse than none — which is why `ctl engine-check` verifies tool calling against a running engine rather than trusting this.\n\nThe reason it exists: the gateway forwards a tools array to any model, and a model that cannot use them answers in prose. Every OpenAI-compatible client then behaves as though the model is broken, and the only way to find out was to try it. That cost an afternoon.", "properties": { "tools": { "type": "boolean" }, "vision": { "type": "boolean" }, "embeddings": { "type": "boolean" }, "images": { "type": "boolean", "description": "Images is a model that makes pictures, asked for at /v1/images/generations. Implied by an external model whose API is ComfyUI's." }, "meshes": { "type": "boolean", "description": "Meshes is a model that makes 3D models from a picture, asked for as a job at /v1/3d/generations. Implied by a ComfyUI model whose output is meshes." } } }, "catalog.ComfyUI": { "type": "object", "description": "ComfyUI is a ComfyUI model's workflow and checkpoint.", "properties": { "workflow": { "type": "string", "description": "Workflow is a built-in's name (flux-schnell, the default, or flux-dev) or a JSON file on the control plane, in ComfyUI's API format." }, "checkpoint": { "type": "string", "description": "Checkpoint is the file the workflow's {{checkpoint}} names: the source's own name unless set, which a source that is a set of files must." }, "output": { "type": "string", "description": "Output is what the workflow makes: pictures (the default), asked for at /v1/images/generations; meshes, asked for as a job at /v1/3d/generations from a picture; or video, audio or files. Every kind is asked for as a job at /v1/workflows/runs too." }, "inputs": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.Input" }, "description": "Inputs are what the workflow takes from a request at /v1/workflows/runs, each the placeholder of its name." }, "nodes": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.CustomNode" }, "description": "Nodes are custom nodes the workflow needs, put in each replica's own custom_nodes at the commit named." }, "huggingface_repo": { "type": "string", "description": "HuggingFaceRepo is the repository a custom node loads the weights by name from (Stable Fast 3D's loader asks for stabilityai/stable-fast-3d): the replica's weights are shown to the node there, in the Hugging Face cache of the engines' user, so nothing is fetched and no token is needed when it runs." }, "environment": { "type": "string", "description": "Environment names the models that may share one ComfyUI replica: every model of an environment agrees on the custom nodes they both name, so one replica can carry all of them and ComfyUI moves between their weights itself. Empty is an environment of the model alone." } } }, "catalog.CustomNode": { "type": "object", "description": "CustomNode is a ComfyUI node from a git repository.", "properties": { "repo": { "type": "string", "description": "Repo is the repository, https only." }, "commit": { "type": "string", "description": "Commit is the full commit the node is used at: a branch moves, and a node that changed under a model is a model that changed unasked." }, "requirements": { "type": "array", "items": { "type": "string" }, "description": "Requirements are the PyPI packages the node needs, by name and version range only. They are installed beside the replica, never into ComfyUI's environment: a package named here at the range named, and every other one at the version ComfyUI already runs. One named here is first on ComfyUI's path, so its range must suit ComfyUI too." }, "build": { "type": "array", "items": { "type": "string" }, "description": "Build are directories of the repository that are Python packages to be compiled rather than downloaded: C++ and CUDA extensions no index has (Stable Fast 3D's texture_baker and uv_unwrapper). Each is built as a wheel with ComfyUI's Python for the card the replica runs on, kept on the node for the next replica on the same kind of card, and installed beside the replica like its requirements." } } }, "catalog.EvalGate": { "type": "object", "description": "EvalGate is a quality suite a model's new weights must pass.", "properties": { "suite": { "type": "string", "description": "Suite is a suite's name in control.eval_dir, or one the binary carries (arithmetic, json-format)." }, "min_score": { "type": "number", "description": "MinScore is the score, 0 to 1, to pass at; zero is the suite's own threshold." }, "judge": { "type": "string", "description": "Judge grades the suite's rubric cases, instead of the judge it names." } } }, "catalog.External": { "type": "object", "description": "External is a provider outside the cluster that serves a model.", "properties": { "url": { "type": "string", "description": "URL is the provider's base address, without /v1: https://api.openai.com." }, "model": { "type": "string", "description": "Model is what the provider calls it; requests are rewritten to it." }, "api_key_file": { "type": "string", "description": "APIKeyFile holds the provider's key, on the control plane. A file rather than the key itself, so the key is in neither the catalog, the store nor the audit log; empty for a provider that asks for none." }, "api_key_files": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.ExternalKey" }, "description": "APIKeyFiles are several keys for the provider, in place of APIKeyFile: one endpoint each (external:MODEL#1, #2…), so a key that answers 429 or 401 is passed over while its breaker is open and the request goes to another. A provider's limits are per key." }, "peer": { "type": "string", "description": "Peer names the federated llmgw cluster this model is offered by, for a model that federation added (`llmgw ctl federation add`) rather than one written by hand. Such a model is named PEER/MODEL, comes and goes with the peer's own list, and is sent only while the peer is up." }, "api": { "type": "string", "description": "API is what the provider speaks: OpenAI's, unless this says comfyui — a ComfyUI server, asked for pictures at /v1/images/generations and sent the workflow below with the request's prompt in it. Model is then the checkpoint file the workflow loads, as ComfyUI lists it." }, "workflow": { "type": "string", "description": "Workflow is the ComfyUI workflow, in its API format: a built-in's name (flux-schnell, the default, or flux-dev) or a JSON file on the control plane." }, "output": { "type": "string", "description": "Output is what it makes: pictures, or meshes (see ComfyUI.Output)." } } }, "catalog.ExternalKey": { "type": "object", "description": "ExternalKey is one of a provider's keys.", "properties": { "file": { "type": "string", "description": "File holds the key, on the control plane, as APIKeyFile does." }, "weight": { "type": "number", "description": "Weight is its share of the requests against the others'; zero is 1." } } }, "catalog.GPUNeed": { "type": "object", "description": "GPUNeed is what card a profile needs.", "properties": { "min_compute_capability": { "type": "number", "description": "MinComputeCapability is the oldest architecture that runs it: 7.5 is Turing, 8.0 Ampere (bf16, flash-attention 2), 8.9 Ada (fp8), 9.0 Hopper." }, "min_memory_gb": { "type": "integer", "description": "MinMemoryGB is the card's own memory it needs." } } }, "catalog.GuardModel": { "type": "object", "description": "GuardModel is how a judge model's answers are read.", "properties": { "format": { "type": "string", "description": "Format is qwen3guard (Qwen3Guard-Gen: \"Safety: Safe\", \"Unsafe\" or \"Controversial\", and the categories), llamaguard3 (Meta's Llama Guard 3: \"safe\", or \"unsafe\" and the categories), shieldgemma (Google's ShieldGemma: Yes or No), or json ({\"safe\": false, \"categories\": [\"...\"]})." }, "categories": { "type": "array", "items": { "type": "string" }, "description": "Categories the model is asked about, for shieldgemma — each a policy sentence — and the names reported for llamaguard3's S1, S2, …." } } }, "catalog.Input": { "type": "object", "description": "Input is one thing a workflow takes from a request: the placeholder {{name}} in its graph, filled with the request's inputs.name.", "properties": { "name": { "type": "string", "description": "Name is the placeholder's, and the request's key." }, "type": { "type": "string", "description": "Type is one of text, int, float, bool, choice, image, mask, audio, video, file. The last five are files, sent as base64, a data URL, or the id of a file uploaded to /v1/files, and put in ComfyUI's input directory; the placeholder gets the name they were given there." }, "required": { "type": "boolean", "description": "Required inputs must be in every request; the others take Default, or the workflow's own {{name|default}}." }, "default": {}, "min": { "type": "number", "description": "Min and Max bound a number; for text, Max bounds its length." }, "max": { "type": "number" }, "choices": { "type": "array", "items": { "type": "string" }, "description": "Choices are what a choice may be." }, "max_mb": { "type": "integer", "description": "MaxMB bounds a file input; zero is the type's own bound." }, "doc": { "type": "string", "description": "Doc says what the input is for, to whoever fills it in." } } }, "catalog.License": { "type": "object", "description": "License is the terms what a model makes comes under: said beside every result, and written into a mesh, which travels without the API.", "properties": { "id": { "type": "string", "description": "ID names the licence for a machine: an SPDX identifier where there is one (MIT, Apache-2.0, CC-BY-NC-4.0), else a lowercase name of the licence's own (stability-community, tencent-hunyuan-community). What a person's or a site's choice of licences matches on. Name is for people." }, "name": { "type": "string", "description": "Name is the licence's own: MIT, Apache-2.0." }, "url": { "type": "string" }, "notice": { "type": "string", "description": "Notice is what must accompany what was made: attribution, terms on the output, what the weights were trained on." }, "commercial": { "type": "boolean", "description": "Commercial says whether what is made may be used commercially: nil is not said, which is not the same as yes." }, "excluded_regions": { "type": "array", "items": { "type": "string" }, "description": "ExcludedRegions are where the licence grants nothing: ISO 3166 codes, and EU for the union (Hunyuan's: EU, UK, KR)." }, "revenue_cap_usd": { "type": "integer", "format": "int64", "description": "RevenueCapUSD is the yearly revenue above which the licence asks for another agreement (Stability's community licence: 1000000). Zero is none." }, "attribution": { "type": "string", "description": "Attribution is what a product using the output must show: \"Powered by Stability AI\"." } } }, "catalog.Model": { "type": "object", "description": "Model is a catalog entry as clients see it.", "properties": { "name": { "type": "string" }, "aliases": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string", "description": "Description is what this model is for, in a line.\n\nWritten by whoever added it, because nobody else can say it. A registry offers a pipeline tag and a wall of README, and neither answers the question a person picking from a list is asking: which of these nine names should I send this request to.\n\nIt reaches clients through /v1/models, which is the only view most of them ever see. A gateway serving nine models by name alone makes that choice by guesswork." }, "source": { "type": "string", "description": "Source is the weights path or a HuggingFace id." }, "profiles": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.Profile" } }, "scaling": { "$ref": "#/components/schemas/catalog.Scaling" }, "class": { "type": "string", "description": "Class is how much this model's capacity is worth against another's, when there is not enough for both: critical, standard or opportunistic. Empty is standard, or opportunistic for a model loaded on demand. See EffectiveClass." }, "owner": { "type": "string", "description": "Owner is the part of the tenancy tree whose capacity quota this model counts against, written org:ID, team:ID or project:ID. Empty is shared: held by the cluster, counted against nobody." }, "external": { "$ref": "#/components/schemas/catalog.External", "description": "External is a model served by someone else — an OpenAI-compatible API outside the cluster — rather than by replicas placed here. Such a model has no profiles and nothing is placed for it; the router sends its requests to the provider. Most useful named in another model's fallbacks: used only when the cluster has no capacity left. Its prompts leave the cluster, so which keys may name it is worth an allowlist." }, "comfyui": { "$ref": "#/components/schemas/catalog.ComfyUI", "description": "ComfyUI is how a model whose profiles run engine comfyui makes its pictures: the workflow, and the file it loads." }, "license": { "$ref": "#/components/schemas/catalog.License", "description": "License is the terms of what the model makes, for a model whose output somebody ships: shown with every result and written into a mesh." }, "adapters": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.Adapter" }, "description": "Adapters are LoRA adapters served on this model's replicas, each asked for by its own name as though it were a model. Every replica loads every adapter, applying one only to a request that names it — unless MaxLoadedAdapters is set." }, "max_loaded_adapters": { "type": "integer", "description": "MaxLoadedAdapters, above zero, has each replica hold at most this many adapters at once, loaded when a request first asks for one and unloaded least recently used first to make room. The router sends a request for an adapter to a replica that already holds it while that one has room to take it. vLLM profiles only: llama-server loads adapters at start and cannot load one afterwards. Zero loads every adapter on every replica at start." }, "fallbacks": { "type": "array", "items": { "type": "string" } }, "canary": { "$ref": "#/components/schemas/catalog.Canary", "description": "Canary sends a share of this model's requests to another catalog model — the same model at new weights — to compare the two before moving to it (`llmgw ctl model canary`)." }, "eval": { "$ref": "#/components/schemas/catalog.EvalGate", "description": "Eval is a quality suite new weights must pass before they replace this model's: `llmgw ctl model update` and `model promote` run it against them first, and stop below its score." }, "routing_profile": { "type": "string", "description": "RoutingProfile selects how the router scores endpoints for this model." }, "slo": { "$ref": "#/components/schemas/catalog.SLO" }, "context_length": { "type": "integer", "description": "ContextLength is how many tokens one request may use, prompt and completion together, and MaxOutput bounds the completion alone. Zero means unknown, which is what every model was until now.\n\nThe gateway knew neither, so an over-long prompt was not refused: it was admitted, given a replica, and failed at the engine, and a client sizing its prompts from /v1/models had nothing to read. Worse, the number is not the one an operator writes in the engine's arguments — llama.cpp divides --ctx-size across its parallel slots, so a pool of 8192 across four slots is 2048 a request, and nothing said so." }, "max_output": { "type": "integer" }, "capabilities": { "$ref": "#/components/schemas/catalog.Capabilities", "description": "Capabilities is what this model can do beyond plain completion." }, "query_prefix": { "type": "string", "description": "QueryPrefix is put before a question an embedding model embeds for a knowledge-base search; documents are embedded without it. Models trained with an instruction on the query side want it, Qwen3-Embedding \"Instruct: Given a web search query, retrieve relevant passages that answer the query\\nQuery: \" for one." }, "role": { "type": "string", "description": "Role \"guard\" is a model that judges the gateway's traffic for the guardrails rather than serving clients: hidden from /v1/models and the chat page, refused to any key that names it, critical by default, and always running. Guard says how its answers are read." }, "guard": { "$ref": "#/components/schemas/catalog.GuardModel" }, "origin": { "$ref": "#/components/schemas/catalog.Origin", "description": "Origin is the registry repository the weights came from, at which commit, and each file's checksum there. Written when a model is served from the registry; for one that was not, worked out from the mirror's record of where it fetched the file. It is what lets the control plane say that the repository has published different weights since, and move the model to them." }, "shared": { "$ref": "#/components/schemas/catalog.SharedComfy", "description": "Shared is set on an environment's hidden entry only: the members its replica answers for. Made by the catalog, never written." } } }, "catalog.Origin": { "type": "object", "description": "Origin is where a model's weights were published.", "properties": { "repo": { "type": "string", "description": "Repo is the repository, owner/name." }, "revision": { "type": "string", "description": "Revision is the commit the files were fetched at." }, "files": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.OriginFile" }, "description": "Files are the weights fetched from it, with what the registry published as each one's sha256. A new commit that leaves them alone — a README edited — is not an update." }, "previous": { "$ref": "#/components/schemas/catalog.PreviousOrigin", "description": "Previous is what the last update replaced, kept so it can be gone back to while its files are still on the mirror." } } }, "catalog.OriginFile": { "type": "object", "description": "OriginFile is one weights file of an origin.", "properties": { "path": { "type": "string" }, "sha256": { "type": "string" }, "bytes": { "type": "integer", "format": "int64" } } }, "catalog.PreviousOrigin": { "type": "object", "description": "PreviousOrigin is a model's source before an update, and where it came from.", "properties": { "source": { "type": "string" }, "revision": { "type": "string" }, "files": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.OriginFile" } } } }, "catalog.Profile": { "type": "object", "description": "Profile is how a model runs on one GPU class.", "properties": { "name": { "type": "string" }, "engine": { "type": "string" }, "engine_version": { "type": "string", "description": "EngineVersion restricts the profile to nodes whose installed engine's version starts with it: \"0.11\" takes vLLM 0.11.0 and 0.11.1, not 0.10.2. Empty takes whatever version the node has." }, "gpu_class": { "type": "string" }, "source": { "type": "string", "description": "Source is the weights this profile loads, when not the model's: an embedding model served by vLLM from its repository on a card and by llama.cpp from a GGUF on CPUs is one model with two sources. Empty loads the model's. Updates and canaries move the model's source; a profile with its own keeps it." }, "tp": { "type": "integer" }, "pp": { "type": "integer" }, "gpus_per_node": { "type": "integer", "description": "GPUsPerNode defaults to TP for a single-node profile." }, "nodes": { "type": "integer", "description": "Nodes above 1 makes this a multi-node profile, which requires a fabric." }, "args": { "type": "array", "items": { "type": "string" } }, "env": { "type": "object", "additionalProperties": { "type": "string" } }, "min_memory_gb": { "type": "integer", "description": "MinMemoryGB is the host RAM this profile needs to run.\n\nThe number that matters is the model's working set: the weights, plus the KV cache for the whole context pool, plus the engine's own overhead. For a GPU profile that lives in the cards and this is small; for a CPU profile it is the whole thing, and getting it wrong means an OOM on a node that reported itself healthy.\n\nZero means unconstrained, which is every profile that existed before this. A node that does not report its memory is not excluded either — an older agent must not have its nodes quietly emptied by an upgrade of the control plane." }, "cpu_cores": { "type": "integer", "description": "CPUCores is the cores a replica of a profile with no GPU is given: reserved out of its node's CPUs by placement, as memory is, and what its engine computes on (llama.cpp's --threads).\n\nReserved because an engine takes every core it is told about, and two on one node that each think they have all of them spin against each other: on an 8-vCPU node, two 7B replicas fell from 10 tokens a second to under one each. Zero reserves nothing and leaves the thread count to the node, which is every profile from before this." }, "min_disk_gb": { "type": "integer", "description": "MinDiskGB is the free space a node needs before it can hold these weights.\n\nOnly checked when the node does not already have them: a node holding the file needs no room for it, and requiring the space twice would keep a model off the one node best placed to run it.\n\nDeclared rather than derived, because the size of a model that has never been fetched anywhere is not knowable from here — and a wrong guess fails late, halfway through a download, which is the failure this exists to prevent. Zero means unconstrained, and a node that reports no storage is not excluded: unknown is not full." }, "node_selector": { "type": "object", "additionalProperties": { "type": "string" }, "description": "NodeSelector restricts this profile to nodes carrying every one of these labels, with these values.\n\nA CPU profile otherwise fits everywhere, because there is no card to be free — which is right for a 0.5B model and wrong for a 14B one. Nothing in the inventory says how much memory a node has, so the operator says which nodes are meant for a model instead of the scheduler inferring it. Agents have reported labels since the beginning; this is what reads them." }, "power_watts": { "type": "number", "description": "PowerWatts is what one replica of this profile draws, in watts, split evenly over its nodes, counted against the power cap of every rack, PDU or other domain its nodes are in (facility.budgets in server.yaml). Zero derives it: each card at the power limit it reports, each reserved core at facility.cpu_core_watts. Only matters where a domain has a cap." }, "keep_within": { "type": "string", "description": "KeepWithin keeps a multi-node replica's nodes inside one rack, row, room or site, read from their llmgw.io/rack (and so on) labels: for a fabric whose leaves do not reach across racks, or cables that do not. Nodes without the label are passed over for such a profile. Empty is no constraint." }, "weight": { "type": "number", "description": "Weight is the router's capacity weight. It should come from ctl bench rather than a guess (plan §6.2.1)." }, "priority": { "type": "integer", "description": "Priority orders profiles during placement; highest that fits wins." }, "startup_timeout": { "type": "integer", "format": "int64", "description": "StartupTimeout bounds model loading. A 70B model across two nodes takes tens of minutes, so this is per profile rather than global.\n\nA duration, in nanoseconds." }, "kv_events": { "type": "boolean", "description": "KVEvents has vLLM publish what its prefix cache holds, and the router route this model's requests by it: to the replica holding the most of a prompt's leading blocks (plan §7.5 tier 2). vLLM only.\n\nOff by default, because it costs something on every request: the router asks a replica to tokenize the prompt before placing it, a round trip and the chat template run twice. It pays where prompts share long prefixes that the approximate tree guesses wrong — many replicas, conversations that move between them, evictions. The engine is started with sha256_cbor block hashing and a fixed PYTHONHASHSEED, which the router's hashing assumes; arguments overriding either leave the index empty, and the agent says so in its log." }, "gpu": { "$ref": "#/components/schemas/catalog.GPUNeed", "description": "GPU says what card the profile needs, in place of naming its class: it stands for every class in the cluster that meets it. A catalog entry written once then places sensibly on any site's cards." }, "comfyui": { "$ref": "#/components/schemas/catalog.ProfileComfyUI", "description": "ComfyUI is this profile's own workflow, checkpoint and nodes, over the model's: an fp8 workflow where the card has fp8, fp16 where it has not." } } }, "catalog.ProfileComfyUI": { "type": "object", "description": "ProfileComfyUI is what a ComfyUI profile runs differently from the model: each field set replaces the model's.", "properties": { "workflow": { "type": "string" }, "checkpoint": { "type": "string" }, "nodes": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.CustomNode" } } } }, "catalog.SLO": { "type": "object", "description": "SLO is the latency target a model is expected to meet. `ctl bench` measures capacity against it (plan §6.2.1), and admission holds the lower bands back while the model's recent p99 is past it.", "properties": { "TTFTp99": { "type": "integer", "format": "int64", "description": "TTFTp99 is the time to the first token 99 requests in 100 are within.\n\nA duration, in nanoseconds." }, "TPOTp99": { "type": "integer", "format": "int64", "description": "TPOTp99 is the time per output token, after the first, 99 streamed requests in 100 are within.\n\nA duration, in nanoseconds." } } }, "catalog.ScaleWindow": { "type": "object", "description": "ScaleWindow is a part of the week with its own min and max.", "properties": { "days": { "type": "array", "items": { "type": "string" }, "description": "Days are mon … sun, or weekdays, weekends; empty is every day." }, "from": { "type": "string", "description": "From and To are HH:MM; a window whose To is before its From runs past midnight." }, "to": { "type": "string" }, "min": { "type": "integer" }, "max": { "type": "integer", "description": "Max, when set, is the window's ceiling for load scaling; zero keeps the model's own." } } }, "catalog.Scaling": { "type": "object", "description": "Scaling is how many replicas a model should have.", "properties": { "min": { "type": "integer" }, "max": { "type": "integer" }, "idle_timeout": { "type": "integer", "format": "int64", "description": "IdleTimeout is how long an on-demand model may go unasked-for before its replicas are stopped. Zero takes the cluster default.\n\nMinutes rather than seconds, always. Stopping a replica throws away the KV cache prefix routing spent its effort filling, and a model that flaps in and out loses that entirely — so the saving has to be worth more than the cache, which it only is over a real idle period.\n\nA duration, in nanoseconds." }, "schedule": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.ScaleWindow" }, "description": "Schedule changes min and max by the time of day, in the control plane's control.timezone: more replicas kept through working hours, fewer at night, an on-demand model kept loaded while people are at work. The first window that holds now wins; outside them all, Min and Max apply." }, "prewarm": { "type": "integer", "format": "int64", "description": "Prewarm starts a window this long before it opens, so its replicas have loaded by then: loading a model is minutes, and the people who arrive at nine are the reason for the window.\n\nA duration, in nanoseconds." } } }, "catalog.SharedComfy": { "type": "object", "description": "SharedComfy is what an environment's entry carries of its members.", "properties": { "environment": { "type": "string" }, "members": { "type": "array", "items": { "$ref": "#/components/schemas/catalog.SharedMember" } } } }, "catalog.SharedMember": { "type": "object", "description": "SharedMember is one model a shared replica answers for.", "properties": { "name": { "type": "string" }, "aliases": { "type": "array", "items": { "type": "string" } }, "source": { "type": "string", "description": "Source is the member's weights, which the replica's node fetches." }, "hf_repo": { "type": "string", "description": "HFRepo is the repository its node loads the weights by name from." }, "workflow": { "type": "string", "description": "Workflow and Checkpoint are what a request for it is sent." }, "checkpoint": { "type": "string" } } }, "eval.Live": { "type": "object", "description": "Live is a run as it stands: one running, with how many of its cases are done, or one finished.", "properties": { "id": { "type": "string" }, "model": { "type": "string", "description": "Model is the model the run is about; Target the catalog model that answered, when that was another — its canary, or the new weights an update tried before moving to them." }, "target": { "type": "string" }, "repo": { "type": "string", "description": "Repo and Revision are where the weights that answered came from, when that is known." }, "revision": { "type": "string" }, "suite": { "type": "string", "description": "Suite is its name, SuiteHash the sha256 of its text." }, "suite_hash": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "took_ms": { "type": "integer", "format": "int64" }, "score": { "type": "number", "description": "Score is the cases' scores weighed, 0 to 1; Passed whether it reached Threshold." }, "threshold": { "type": "number" }, "passed": { "type": "boolean" }, "cases": { "type": "integer", "description": "Cases were asked; Below scored under half; Errors got no answer." }, "below": { "type": "integer" }, "errors": { "type": "integer" }, "judge": { "type": "string" }, "by": { "type": "string" }, "job": { "type": "string", "description": "Job is the update or promotion the run gated, if one did." }, "error": { "type": "string", "description": "Error is why the run could not be scored at all." }, "results": { "type": "array", "items": { "$ref": "#/components/schemas/store.EvalCase" } }, "state": { "type": "string" }, "done": { "type": "integer" } } }, "eval.Request": { "type": "object", "description": "Request is a suite to run against a model: one on the control plane, by its name, or one sent whole.", "properties": { "suite": { "type": "string", "description": "Suite is a suite's name in the eval directory, or carried in the binary (arithmetic, json-format)." }, "content": { "type": "string", "description": "Content is a suite's text instead, and File the name of the file it was read from, which names the suite unless it names itself." }, "file": { "type": "string" }, "concurrency": { "type": "integer", "description": "Concurrency, Judge and MinScore are as Options has them." }, "judge": { "type": "string" }, "min_score": { "type": "number" } } }, "eval.SuiteInfo": { "type": "object", "description": "SuiteInfo is a suite the control plane can run by name.", "properties": { "name": { "type": "string" }, "from": { "type": "string", "description": "From is the file it is read from, or \"built in\"." }, "description": { "type": "string" }, "cases": { "type": "integer" }, "threshold": { "type": "number" }, "judge": { "type": "boolean" }, "hash": { "type": "string" }, "error": { "type": "string", "description": "Error is why the file cannot be run." } } }, "fabrics.Change": { "type": "object", "description": "Change is a fabric's master subnet manager changing, as its ports saw it.", "properties": { "at": { "type": "string", "format": "date-time" }, "from": { "type": "string" }, "to": { "type": "string" }, "ports": { "type": "integer" } } }, "fabrics.Member": { "type": "object", "description": "Member is one node's adapters on a physical fabric.", "properties": { "node": { "type": "string" }, "hcas": { "type": "array", "items": { "type": "string" } }, "declared": { "type": "string", "description": "Declared is the name this node gives these adapters, empty when it declares them in no fabric." } } }, "fabrics.Physical": { "type": "object", "description": "Physical is one fabric as the adapters find it.", "properties": { "key": { "type": "string" }, "kind": { "type": "string", "description": "Kind is infiniband or roce." }, "label": { "type": "string", "description": "Label is the key as a person reads it." }, "sm": { "$ref": "#/components/schemas/fabrics.SM", "description": "SM is the master subnet manager, on InfiniBand: the one most of its ports see." }, "sms": { "type": "array", "items": { "$ref": "#/components/schemas/fabrics.SM" }, "description": "SMs is every subnet manager the fabric lists, master first; empty when no port could ask. Standbys counts those that could take over." }, "standbys": { "type": "integer" }, "masters": { "type": "object", "additionalProperties": { "type": "integer" }, "description": "Masters is how many ports see each master, when they do not all agree." }, "changes": { "type": "array", "items": { "$ref": "#/components/schemas/fabrics.Change" }, "description": "Changes are the master changes seen in the last day, newest first." }, "declared": { "type": "array", "items": { "type": "string" }, "description": "Declared are the names nodes gave this fabric; one, when all is well." }, "members": { "type": "array", "items": { "$ref": "#/components/schemas/fabrics.Member" } }, "rate_gbps": { "type": "integer" }, "gid_prefix": { "type": "string" } } }, "fabrics.Problem": { "type": "object", "description": "Problem is one disagreement, in words.", "properties": { "level": { "type": "string" }, "fabric": { "type": "string" }, "message": { "type": "string" } } }, "fabrics.Report": { "type": "object", "description": "Report is the whole picture.", "properties": { "physical": { "type": "array", "items": { "$ref": "#/components/schemas/fabrics.Physical" } }, "problems": { "type": "array", "items": { "$ref": "#/components/schemas/fabrics.Problem" } }, "unverified": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } }, "description": "Unverified are declared fabrics some of whose nodes cannot say which physical fabric they are on, with why." } } }, "fabrics.SM": { "type": "object", "description": "SM is a subnet manager as the ports see it.", "properties": { "guid": { "type": "string" }, "lid": { "type": "integer" }, "priority": { "type": "integer" }, "state": { "type": "string" } } }, "facility.Location": { "type": "object", "description": "Location is where a node is, read from its labels. Empty fields are not known, which places as it always did.", "properties": { "site": { "type": "string" }, "room": { "type": "string" }, "row": { "type": "string" }, "rack": { "type": "string" }, "pdus": { "type": "array", "items": { "type": "string" } } } }, "federation.AddRequest": { "type": "object", "description": "AddRequest adds a peer.", "properties": { "name": { "type": "string", "description": "Name is what this cluster calls the peer, and the prefix of its models: NAME/MODEL." }, "url": { "type": "string", "description": "URL is the peer gateway's client address, without /v1." }, "key_file": { "type": "string", "description": "KeyFile is a file on the control plane holding a key the peer issued to this cluster (or env:NAME, vault:PATH#FIELD)." }, "send_tags": { "type": "boolean", "description": "SendTags makes requests sent to the peer carry x-llmgw-tags naming this cluster and the sending project. Off unless asked: the peer learns who in this cluster is asking." } } }, "federation.ModelStatus": { "type": "object", "description": "ModelStatus is one of a peer's models: its name here, the peer's own, and whether the peer has stopped offering it.", "properties": { "name": { "type": "string" }, "upstream": { "type": "string" }, "withdrawn": { "type": "boolean" } } }, "federation.Status": { "type": "object", "description": "Status is a peer as `llmgw ctl federation list` shows it.", "properties": { "name": { "type": "string" }, "url": { "type": "string" }, "key_file": { "type": "string" }, "send_tags": { "type": "boolean" }, "cluster": { "type": "string", "description": "Cluster is the peer's own cluster id." }, "up": { "type": "boolean" }, "checked": { "type": "string", "format": "date-time", "description": "Checked is when; zero before the first check." }, "latency_ns": { "type": "integer", "format": "int64", "description": "Latency is how long the peer took to answer /ready: the network to the other site and the peer's front, not a model's speed.\n\nA duration, in nanoseconds." }, "error": { "type": "string", "description": "Error is why the peer is down, empty while it is up." }, "latency_ms": { "type": "number", "description": "LatencyMs is Latency in milliseconds, for reading." }, "synced_at": { "type": "string", "format": "date-time", "description": "SyncedAt is when its models last changed here." }, "models": { "type": "array", "items": { "$ref": "#/components/schemas/federation.ModelStatus" } }, "created_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "string" } } }, "guard.Attachment": { "type": "object", "description": "Attachment ties a policy to a part of the tenancy tree: scope is org, team, project, user or key, and ScopeID which one.", "properties": { "Scope": { "type": "string" }, "ScopeID": { "type": "string" }, "Policy": { "type": "string" } } }, "inventory.EngineInstall": { "type": "object", "description": "EngineInstall is where one engine's installation stands on a node.", "properties": { "engine": { "type": "string" }, "version": { "type": "string" }, "variant": { "type": "string" }, "state": { "type": "string", "description": "State is \"installing\", \"ready\", \"failed\" or \"unsupported\"." }, "detail": { "type": "string" } } }, "inventory.GPUSensor": { "type": "object", "description": "GPUSensor is one card's heat and power, and what is throttling it.", "properties": { "index": { "type": "integer" }, "temp_c": { "type": "number" }, "memory_temp_c": { "type": "number" }, "power_w": { "type": "number" }, "power_limit_w": { "type": "number" }, "throttle": { "type": "array", "items": { "type": "string" } }, "util_percent": { "type": "number", "description": "How busy the card is, as of this sample; -1 is not reported. Zero MemoryTotalMB is an agent too old to send these, whose figures are the ones it read at registration." }, "mem_util_percent": { "type": "number" }, "memory_used_mb": { "type": "number" }, "memory_total_mb": { "type": "number" }, "sm_clock_mhz": { "type": "number" }, "ecc_uncorrected": { "type": "number" }, "wear": { "$ref": "#/components/schemas/inventory.GPUWear", "description": "Wear is what wears the card out, read every minute; nil from an agent that does not read it." } } }, "inventory.GPUWear": { "type": "object", "description": "GPUWear is a card's wear and failures. Counts of -1 are not reported for it: a card before Ampere has no remapped rows, one after no retired pages.", "properties": { "pcie_replays": { "type": "integer", "format": "int64" }, "retired_pages_sbe": { "type": "integer", "format": "int64" }, "retired_pages_dbe": { "type": "integer", "format": "int64" }, "retire_pending": { "type": "boolean" }, "remapped_rows_correctable": { "type": "integer", "format": "int64" }, "remapped_rows_uncorrectable": { "type": "integer", "format": "int64" }, "remap_pending": { "type": "boolean" }, "remap_failure": { "type": "boolean" }, "nvlink_crc_errors": { "type": "integer", "format": "int64" }, "nvlink_replay_errors": { "type": "integer", "format": "int64" }, "nvlink_recovery_errors": { "type": "integer", "format": "int64" }, "xid_errors": { "type": "integer", "format": "int64" }, "last_xid": { "type": "integer" }, "last_xid_text": { "type": "string" }, "last_xid_at": { "type": "string", "format": "date-time" } } }, "modelplan.Option": { "type": "object", "description": "Option is one way to run one artifact.", "properties": { "artifact": { "type": "string" }, "format": { "type": "string" }, "engine": { "type": "string" }, "cpu": { "type": "boolean" }, "gpu_class": { "type": "string" }, "fabric": { "type": "string" }, "gpus_per_node": { "type": "integer", "description": "GPUsPerNode cards on each of Nodes nodes." }, "nodes": { "type": "integer" }, "need_gb": { "type": "number", "description": "NeedGB is what one card holds, or for CPU the whole replica in RAM; HaveGB what a card, or the node, offers for it." }, "have_gb": { "type": "number" }, "hosts": { "type": "integer", "description": "Hosts is how many nodes could run it at all, and FreeNow whether one (or enough, together) could right now." }, "free_now": { "type": "boolean" }, "bits_per_weight": { "type": "number", "description": "BitsPerWeight is the artifact's precision, 0 when unknown." } } }, "modelserve.CanaryView": { "type": "object", "description": "CanaryView is one model's canary as it stands.", "properties": { "model": { "type": "string" }, "canary": { "$ref": "#/components/schemas/catalog.Canary" }, "serving": { "$ref": "#/components/schemas/canary.Stat" } } }, "modelserve.Change": { "type": "object", "description": "Change is how an update or a promotion is held to quality.", "properties": { "eval": { "$ref": "#/components/schemas/eval.Request", "description": "Eval is a suite the new weights must pass first. Nil takes the model's own (eval: in its catalog entry), if it has one." }, "skip_eval": { "type": "boolean", "description": "SkipEval moves without the model's own suite; the job says so." } } }, "modelserve.Job": { "type": "object", "description": "Job is one model being served, and where it stands.", "properties": { "id": { "type": "string" }, "kind": { "type": "string", "description": "Kind is \"update\" for a model moved to new weights, empty for one served." }, "request": { "$ref": "#/components/schemas/modelserve.Request" }, "state": { "type": "string" }, "error": { "type": "string" }, "model": { "type": "string" }, "steps": { "type": "array", "items": { "$ref": "#/components/schemas/modelserve.Step" } }, "started": { "type": "string", "format": "date-time" }, "reply": { "type": "string", "description": "Reply is what the model said to the smoke test, and TokensPerSecond how fast it said it." }, "tokens_per_second": { "type": "number" }, "eval": { "$ref": "#/components/schemas/store.EvalRun", "description": "Eval is the quality suite the new weights were asked before they replaced the old, and how they scored, without each case." } } }, "modelserve.Plan": { "type": "object", "description": "Plan is every way a repository's files could run here, best first.", "properties": { "repo": { "type": "string" }, "revision": { "type": "string" }, "format": { "type": "string" }, "architecture": { "type": "string" }, "license": { "type": "string" }, "params": { "type": "integer", "format": "int64" }, "context": { "type": "integer" }, "gated": { "type": "boolean" }, "servable": { "type": "boolean", "description": "Servable is false when the nodes' engine cannot run the model at all, and Reason says why." }, "reason": { "type": "string" }, "note": { "type": "string", "description": "Note is anything the plan could not know, said once." }, "projectors": { "type": "array", "items": { "type": "string" } }, "artifacts": { "type": "array", "items": { "$ref": "#/components/schemas/modelserve.PlannedArtifact" } }, "options": { "type": "array", "items": { "$ref": "#/components/schemas/modelplan.Option" } } } }, "modelserve.PlannedArtifact": { "type": "object", "description": "PlannedArtifact is one file a repository offers, and the best way to run it.", "properties": { "name": { "type": "string", "description": "Name is the file, or the set's name; for original weights, \"original\"." }, "format": { "type": "string", "description": "\"gguf\" or \"safetensors\"" }, "bytes": { "type": "integer", "format": "int64" }, "shards": { "type": "integer" }, "quant": { "type": "string", "description": "Quant is the quantisation read from the name, like Q4_K_M; \"bf16\" for original weights." }, "best": { "$ref": "#/components/schemas/modelplan.Option" } } }, "modelserve.Request": { "type": "object", "description": "Request is what to serve.", "properties": { "repo": { "type": "string", "description": "Repo is the registry repository, owner/name." }, "quant": { "type": "string", "description": "Quant picks the file by its quantisation, Q4_K_M unless given." }, "file": { "type": "string", "description": "File picks it by name instead." }, "projector": { "type": "string", "description": "Projector is a vision model's mmproj file in the repository, fetched beside the weights and loaded with them; empty serves text alone." }, "format": { "type": "string", "description": "Format is \"gguf\", run by llama.cpp, or \"safetensors\": the original weights with their config and tokenizer, run by vLLM on GPUs of GPUClass, across TP of them." }, "cpu": { "type": "boolean", "description": "Where it runs: on the CPU, or on GPUsPerNode cards of GPUClass on each of Nodes nodes. Left empty, the plan decides: the best way the cluster can run the chosen file. TP is GPUsPerNode's older name." }, "gpu_class": { "type": "string" }, "gpus_per_node": { "type": "integer" }, "nodes": { "type": "integer" }, "tp": { "type": "integer" }, "fallbacks": { "type": "boolean", "description": "Fallbacks adds the next best ways, lower in priority, so a model whose first choice is busy runs on another rather than waiting." }, "name": { "type": "string", "description": "Name is the catalog name; the repository suggests one otherwise." }, "aliases": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "replicas": { "type": "integer", "description": "Replicas to run; 0 makes it on demand, loaded when first asked for." }, "guard_format": { "type": "string", "description": "GuardFormat makes it a judge model for the guardrails (role: guard): llamaguard3, qwen3guard, shieldgemma or json. Empty serves clients." }, "class": { "type": "string", "description": "Class is what it may take from others and they from it when there is not room for both: critical, standard or opportunistic. Empty is the catalog's default for its role." }, "ctx_pool": { "type": "integer", "description": "CtxPool is llama.cpp's --ctx-size; ContextLength what one request may use. They default to 16384 and 4096, what four parallel slots divide; llama.cpp is given as many slots as the pool holds requests." }, "context_length": { "type": "integer" }, "tools": { "type": "boolean", "description": "Tools says the model makes tool calls the engine returns as calls: it is written into the catalog, where clients and editors read it. Check a running replica with llmgw ctl tool-check before saying so." }, "embeddings": { "type": "boolean", "description": "Embeddings serves it as an embedding model, which its GGUF header says by itself for most: --embedding, many slots, a batch that holds a whole passage, /v1/embeddings." }, "cpu_cores": { "type": "integer", "description": "CPUCores is what a replica computes on; zero takes half the smallest node it fits on." } } }, "modelserve.Step": { "type": "object", "description": "Step is one stage of a job.", "properties": { "name": { "type": "string" }, "state": { "type": "string" }, "detail": { "type": "string" }, "at": { "type": "string", "format": "date-time" } } }, "modelserve.UpdateInfo": { "type": "object", "description": "UpdateInfo is what the registry has for a model against what it runs.", "properties": { "model": { "type": "string" }, "repo": { "type": "string" }, "current": { "type": "string", "description": "Current is the commit the model runs, Latest the repository's now." }, "latest": { "type": "string" }, "changed": { "type": "array", "items": { "type": "string" }, "description": "Changed are the model's files whose weights differ at Latest, and Missing those Latest no longer has at all." }, "missing": { "type": "array", "items": { "type": "string" } }, "bytes": { "type": "integer", "format": "int64", "description": "Bytes is what an update downloads." }, "available": { "type": "boolean", "description": "Available is true when the model can be moved to Latest." }, "previous": { "type": "string", "description": "Previous is the commit an update replaced, which it can go back to." }, "checked_at": { "type": "string", "format": "date-time" }, "error": { "type": "string" } } }, "notify.Result": { "type": "object", "description": "Result is how one webhook answered a test.", "properties": { "url": { "type": "string" }, "error": { "type": "string" } } }, "nvlink.Domain": { "type": "object", "description": "Domain is one multi-node NVLink domain.", "properties": { "key": { "type": "string" }, "cluster_uuid": { "type": "string" }, "clique_id": { "type": "string" }, "members": { "type": "array", "items": { "$ref": "#/components/schemas/nvlink.Member" } }, "gpus": { "type": "integer" }, "joined": { "type": "integer" }, "usable_nodes": { "type": "integer" } } }, "nvlink.GPU": { "type": "object", "description": "GPU is one card as its domain sees it.", "properties": { "index": { "type": "integer" }, "name": { "type": "string" }, "state": { "type": "string" }, "status": { "type": "string" }, "bandwidth": { "type": "string" }, "joined": { "type": "boolean" } } }, "nvlink.Member": { "type": "object", "description": "Member is one node of a domain.", "properties": { "node": { "type": "string" }, "gpus": { "type": "array", "items": { "$ref": "#/components/schemas/nvlink.GPU" } }, "usable": { "type": "boolean", "description": "Usable is every card joined and IMEX up: what placement requires." }, "imex": { "type": "string" }, "imex_channels": { "type": "integer" } } }, "nvlink.Problem": { "type": "object", "description": "Problem is one thing wrong with a domain.", "properties": { "level": { "type": "string" }, "domain": { "type": "string" }, "message": { "type": "string" } } }, "nvlink.Report": { "type": "object", "description": "Report is every domain and what is wrong with them.", "properties": { "domains": { "type": "array", "items": { "$ref": "#/components/schemas/nvlink.Domain" } }, "problems": { "type": "array", "items": { "$ref": "#/components/schemas/nvlink.Problem" } } } }, "promq.Point": { "type": "object", "description": "Point is one sample.", "properties": { "At": { "type": "string", "format": "date-time" }, "Value": { "type": "number" } } }, "promq.Series": { "type": "object", "description": "Series is one line: a name and its points, oldest first.", "properties": { "Name": { "type": "string" }, "Points": { "type": "array", "items": { "$ref": "#/components/schemas/promq.Point" } } } }, "quota.Amount": { "type": "object", "description": "Amount is how much of each resource something holds or needs.", "properties": { "GPUs": { "type": "integer" }, "CPUCores": { "type": "integer" }, "MemoryGB": { "type": "integer" } } }, "store.AuditEvent": { "type": "object", "description": "AuditEvent is one change: who made it, through what, to what, and how it ended. Detail never holds a secret; the writer takes them out.", "properties": { "id": { "type": "integer", "format": "int64" }, "at": { "type": "string", "format": "date-time" }, "actor": { "type": "string" }, "source": { "type": "string", "description": "api, web" }, "action": { "type": "string", "description": "\"POST /api/v1/models\", \"POST /admin/users/{id}/suspend\"" }, "target": { "type": "string" }, "detail": { "type": "string" }, "status": { "type": "integer" } } }, "store.EvalCase": { "type": "object", "description": "EvalCase is one case of a run: how its answer scored, and why.", "properties": { "id": { "type": "string" }, "kind": { "type": "string" }, "weight": { "type": "number" }, "score": { "type": "number" }, "passed": { "type": "boolean" }, "answer": { "type": "string" }, "detail": { "type": "string" }, "error": { "type": "string" }, "took_ms": { "type": "integer", "format": "int64" } } }, "store.EvalRun": { "type": "object", "description": "EvalRun is one quality suite run against a model, as `llmgw ctl eval` and the gate on an update keep it.", "properties": { "id": { "type": "string" }, "model": { "type": "string", "description": "Model is the model the run is about; Target the catalog model that answered, when that was another — its canary, or the new weights an update tried before moving to them." }, "target": { "type": "string" }, "repo": { "type": "string", "description": "Repo and Revision are where the weights that answered came from, when that is known." }, "revision": { "type": "string" }, "suite": { "type": "string", "description": "Suite is its name, SuiteHash the sha256 of its text." }, "suite_hash": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "took_ms": { "type": "integer", "format": "int64" }, "score": { "type": "number", "description": "Score is the cases' scores weighed, 0 to 1; Passed whether it reached Threshold." }, "threshold": { "type": "number" }, "passed": { "type": "boolean" }, "cases": { "type": "integer", "description": "Cases were asked; Below scored under half; Errors got no answer." }, "below": { "type": "integer" }, "errors": { "type": "integer" }, "judge": { "type": "string" }, "by": { "type": "string" }, "job": { "type": "string", "description": "Job is the update or promotion the run gated, if one did." }, "error": { "type": "string", "description": "Error is why the run could not be scored at all." }, "results": { "type": "array", "items": { "$ref": "#/components/schemas/store.EvalCase" } } } }, "store.ExportRow": { "type": "object", "description": "ExportRow is one line of a usage export: a period, the place, person, key and model it is about — those asked for, the rest empty — and what was used.", "properties": { "Period": { "type": "string", "format": "date-time" }, "Org": { "type": "string" }, "Team": { "type": "string" }, "Project": { "type": "string" }, "User": { "type": "string" }, "Key": { "type": "string" }, "Model": { "type": "string" }, "Requests": { "type": "integer", "format": "int64" }, "Errors": { "type": "integer", "format": "int64" }, "Limited": { "type": "integer", "format": "int64" }, "Prompt": { "type": "integer", "format": "int64" }, "Completion": { "type": "integer", "format": "int64" }, "CostMicros": { "type": "integer", "format": "int64" }, "Images": { "type": "integer", "format": "int64" }, "Meshes": { "type": "integer", "format": "int64" } } }, "store.RequestBody": { "type": "object", "description": "RequestBody is one kept request and its answer.", "properties": { "request_id": { "type": "string" }, "project_id": { "type": "string" }, "at": { "type": "string", "format": "date-time" }, "expires_at": { "type": "string", "format": "date-time" }, "path": { "type": "string" }, "model": { "type": "string" }, "served_model": { "type": "string" }, "status": { "type": "integer" }, "request": { "type": "string" }, "response": { "type": "string", "description": "Response is the answer's text as the client was sent it; Truncated says it was longer than what is kept." }, "truncated": { "type": "boolean" } } }, "store.Resources": { "type": "object", "description": "Resources are amounts of the three things a replica holds of a cluster. Nil is not governed: nothing guaranteed, or nothing limited.", "properties": { "gpus": { "type": "integer" }, "cpu_cores": { "type": "integer" }, "memory_gb": { "type": "integer" } } }, "topology.HostView": { "type": "object", "description": "HostView is an adapter, and the node it is in when the cluster knows it.", "properties": { "guid": { "type": "string" }, "desc": { "type": "string" }, "node": { "type": "string" }, "hca": { "type": "string" }, "rail": { "type": "integer" }, "leaf": { "type": "string" } } }, "topology.LinkView": { "type": "object", "description": "LinkView is a cable, with what it trained at and whether that is short of its kind.", "properties": { "from": { "type": "string" }, "from_port": { "type": "integer" }, "to": { "type": "string" }, "to_port": { "type": "integer" }, "rate": { "type": "string" }, "gbps": { "type": "integer" }, "host": { "type": "boolean" }, "degraded": { "type": "boolean" } } }, "topology.Rail": { "type": "object", "description": "Rail is the leaves one rail's adapters reach.", "properties": { "index": { "type": "integer" }, "leaves": { "type": "array", "items": { "type": "string" } } } }, "topology.SwitchView": { "type": "object", "description": "SwitchView is a switch and its place in the tiers.", "properties": { "guid": { "type": "string" }, "name": { "type": "string" }, "tier": { "type": "integer", "description": "1 leaf, 2 spine, 3 core" }, "ports": { "type": "integer" }, "used": { "type": "integer" }, "lid": { "type": "integer" }, "hosts": { "type": "integer", "description": "Hosts counts adapters hanging off it." } } }, "topology.View": { "type": "object", "description": "View is a fabric's shape, ready to draw.", "properties": { "switches": { "type": "array", "items": { "$ref": "#/components/schemas/topology.SwitchView" } }, "hosts": { "type": "array", "items": { "$ref": "#/components/schemas/topology.HostView" } }, "links": { "type": "array", "items": { "$ref": "#/components/schemas/topology.LinkView" } }, "tiers": { "type": "integer", "description": "Tiers is how many switch levels: 1 for a single switch, 2 for leaf and spine, 3 with a core." }, "expected_host_gbps": { "type": "integer", "description": "Expected is the rate most links of each kind trained at; a link below it is degraded." }, "expected_switch_gbps": { "type": "integer" }, "degraded": { "type": "integer" }, "rails": { "type": "array", "items": { "$ref": "#/components/schemas/topology.Rail" }, "description": "Rails is, per rail — an adapter's position on its node — the leaves it reaches, and Aligned whether each rail has its own." }, "rail_aligned": { "type": "boolean" }, "notes": { "type": "array", "items": { "type": "string" } } } } } } }