diff --git a/README.md b/README.md index 37cdb33..b4e386e 100644 --- a/README.md +++ b/README.md @@ -37,4 +37,4 @@ async with AsyncManagementClient(api_key="my-api-key") as client: ## Upgrading from 0.8.2 and earlier Version 0.9.0 is a rewrite and shares no API with the earlier `baseten` releases. -Code written against 0.8.2 or earlier will not work. Pin `baseten<0.9` to keep it. \ No newline at end of file +Code written against 0.8.2 or earlier will not work. Pin `baseten<0.9` to keep it. diff --git a/baseten/client/__init__.py b/baseten/client/__init__.py index ca1f663..a866705 100644 --- a/baseten/client/__init__.py +++ b/baseten/client/__init__.py @@ -2,7 +2,9 @@ Use :class:`ManagementClient` or :class:`AsyncManagementClient` for the management API, and :class:`InferenceClient` or :class:`AsyncInferenceClient` -for the inference API. +for the inference API. :class:`SandboxClient` and :class:`AsyncSandboxClient` +reach one sandbox's execution API directly; the higher-level surface lives in +:mod:`baseten.sandbox`. """ from baseten.client._inference import ( @@ -15,12 +17,20 @@ ManagementClient, ManagementClientOptions, ) +from baseten.client._sandbox import ( + AsyncSandboxClient, + SandboxClient, + SandboxClientOptions, +) __all__ = [ "AsyncInferenceClient", "AsyncManagementClient", + "AsyncSandboxClient", "InferenceClient", "InferenceClientOptions", "ManagementClient", "ManagementClientOptions", + "SandboxClient", + "SandboxClientOptions", ] diff --git a/baseten/client/_sandbox.py b/baseten/client/_sandbox.py new file mode 100644 index 0000000..6d26535 --- /dev/null +++ b/baseten/client/_sandbox.py @@ -0,0 +1,205 @@ +from __future__ import annotations + +from collections.abc import Mapping +from dataclasses import dataclass +from typing import Self + +import httpx + +import baseten.client.sandboxapi +from baseten.client._user_agent import with_user_agent + + +@dataclass(frozen=True) +class SandboxClientOptions: + """Options for :class:`SandboxClient` and :class:`AsyncSandboxClient`. + + Obtain via :attr:`SandboxClient.options` to inspect the values a client + was constructed with. + """ + + token: str + """Sandbox token for authentication.""" + + base_url: str + """Base URL of the sandbox, without a trailing slash. + + Each sandbox is reached at its own host, so there is no default. + """ + + headers: Mapping[str, str] | None = None + """Additional headers to send on every request.""" + + +class SandboxClient: + """Synchronous client for one sandbox's execution-plane API. + + Can be used as a context manager to ensure the underlying HTTP client is + closed on exit. + """ + + def __init__( + self, + *, + token: str, + base_url: str, + headers: Mapping[str, str] | None = None, + http_client_override: httpx.Client | None = None, + close_http_client_on_close: bool | None = None, + ) -> None: + """Create a new synchronous sandbox client. + + Args: + token: Sandbox token for authentication. + base_url: Base URL of the sandbox, without a trailing slash. + headers: Additional headers to send on every request. + http_client_override: Pre-configured httpx client. When provided, + the caller is responsible for setting base URL and all + headers. + close_http_client_on_close: Whether :meth:`close` should close the + underlying HTTP client. Defaults to ``True`` when the client + is created internally, ``False`` when *http_client_override* + is provided. + """ + self._options = SandboxClientOptions( + token=token, base_url=base_url, headers=headers + ) + if http_client_override is None: + request_headers: dict[str, str] = {**(headers or {})} + # Empty token is an advanced opt-out from sending Authorization. + if token != "": + request_headers["Authorization"] = f"Bearer {token}" + self._http_client = httpx.Client( + base_url=base_url, + headers=with_user_agent(request_headers), + ) + self.close_http_client_on_close = ( + True + if close_http_client_on_close is None + else close_http_client_on_close + ) + else: + self._http_client = http_client_override + self.close_http_client_on_close = ( + False + if close_http_client_on_close is None + else close_http_client_on_close + ) + self._api = baseten.client.sandboxapi.ApiClient(self._http_client) + + @property + def options(self) -> SandboxClientOptions: + """Client options.""" + return self._options + + @property + def http_client(self) -> httpx.Client: + """The underlying HTTP client.""" + return self._http_client + + @property + def api(self) -> baseten.client.sandboxapi.ApiClient: + """The generated API client. + + The generated API surface is not covered by stability guarantees and + may change between versions. + """ + return self._api + + def close(self) -> None: + """Close the client, optionally closing the underlying HTTP client.""" + if self.close_http_client_on_close: + self._http_client.close() + + def __enter__(self) -> Self: + return self + + def __exit__(self, *args: object) -> None: + self.close() + + +class AsyncSandboxClient: + """Asynchronous client for one sandbox's execution-plane API. + + Can be used as an async context manager to ensure the underlying HTTP + client is closed on exit. + """ + + def __init__( + self, + *, + token: str, + base_url: str, + headers: Mapping[str, str] | None = None, + http_client_override: httpx.AsyncClient | None = None, + close_http_client_on_close: bool | None = None, + ) -> None: + """Create a new asynchronous sandbox client. + + Args: + token: Sandbox token for authentication. + base_url: Base URL of the sandbox, without a trailing slash. + headers: Additional headers to send on every request. + http_client_override: Pre-configured httpx client. When provided, + the caller is responsible for setting base URL and all + headers. + close_http_client_on_close: Whether :meth:`close` should close the + underlying HTTP client. Defaults to ``True`` when the client + is created internally, ``False`` when *http_client_override* + is provided. + """ + self._options = SandboxClientOptions( + token=token, base_url=base_url, headers=headers + ) + if http_client_override is None: + request_headers: dict[str, str] = {**(headers or {})} + # Empty token is an advanced opt-out from sending Authorization. + if token != "": + request_headers["Authorization"] = f"Bearer {token}" + self._http_client = httpx.AsyncClient( + base_url=base_url, + headers=with_user_agent(request_headers), + ) + self.close_http_client_on_close = ( + True + if close_http_client_on_close is None + else close_http_client_on_close + ) + else: + self._http_client = http_client_override + self.close_http_client_on_close = ( + False + if close_http_client_on_close is None + else close_http_client_on_close + ) + self._api = baseten.client.sandboxapi.AsyncApiClient(self._http_client) + + @property + def options(self) -> SandboxClientOptions: + """Client options.""" + return self._options + + @property + def http_client(self) -> httpx.AsyncClient: + """The underlying HTTP client.""" + return self._http_client + + @property + def api(self) -> baseten.client.sandboxapi.AsyncApiClient: + """The generated API client. + + The generated API surface is not covered by stability guarantees and + may change between versions. + """ + return self._api + + async def close(self) -> None: + """Close the client, optionally closing the underlying HTTP client.""" + if self.close_http_client_on_close: + await self._http_client.aclose() + + async def __aenter__(self) -> Self: + return self + + async def __aexit__(self, *args: object) -> None: + await self.close() diff --git a/baseten/client/inferenceapi/_client.py b/baseten/client/inferenceapi/_client.py index ae50cd8..b60ddae 100644 --- a/baseten/client/inferenceapi/_client.py +++ b/baseten/client/inferenceapi/_client.py @@ -5,7 +5,7 @@ import contextlib import urllib.parse from dataclasses import dataclass -from typing import Any, TypeVar +from typing import Any, Literal, TypeVar import httpx from pydantic import BaseModel, ValidationError @@ -58,8 +58,10 @@ class _ApiRequest: path_args: list[str] body: Any query: Any - success_code: int + success_codes: list[int] error_codes: dict[int, str] | None + body_content_type: str | None = None + accept: str | None = None class ApiClient: @@ -86,7 +88,7 @@ def async_predict( path_args=[env_name], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -109,7 +111,7 @@ def async_predict_deployment( path_args=[deployment_id], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -132,7 +134,7 @@ def async_predict_development( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -155,7 +157,7 @@ def async_predict_production( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -178,7 +180,7 @@ def async_predict_regional( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -201,7 +203,7 @@ def async_run_remote( path_args=[env_name], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -223,7 +225,7 @@ def async_run_remote_deployment( path_args=[deployment_id], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -245,7 +247,7 @@ def async_run_remote_development( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -267,7 +269,7 @@ def async_run_remote_production( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -289,7 +291,7 @@ def async_run_remote_regional( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -309,7 +311,7 @@ def cancel_async_request(self, *, request_id: str) -> CancelAsyncRequestOutput: path_args=[request_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -324,7 +326,7 @@ def get_async_queue_status(self, *, env_name: str) -> GetAsyncQueueStatusOutput: path_args=[env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -341,7 +343,7 @@ def get_async_queue_status_deployment( path_args=[deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -356,7 +358,7 @@ def get_async_queue_status_development(self) -> GetAsyncQueueStatusOutput: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -371,7 +373,7 @@ def get_async_queue_status_production(self) -> GetAsyncQueueStatusOutput: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -386,7 +388,7 @@ def get_async_queue_status_regional(self) -> GetAsyncQueueStatusOutput: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -403,7 +405,7 @@ def get_async_request_status( path_args=[request_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -418,7 +420,7 @@ def predict(self, *, env_name: str, request: PredictInput) -> PredictOutput: path_args=[env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -430,6 +432,34 @@ def predict(self, *, env_name: str, request: PredictInput) -> PredictOutput: ), ) + def predict_raw( + self, + *, + env_name: str, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call the model deployment associated with a specified environment. Returns the response unread, in the requested content type. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/environments/{}/predict", + path_args=[env_name], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + def predict_deployment( self, *, deployment_id: str, request: PredictInput ) -> PredictOutput: @@ -442,7 +472,7 @@ def predict_deployment( path_args=[deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -454,6 +484,34 @@ def predict_deployment( ), ) + def predict_deployment_raw( + self, + *, + deployment_id: str, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call a specific deployment of a model by deployment ID. Returns the response unread, in the requested content type. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/deployment/{}/predict", + path_args=[deployment_id], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + def predict_development(self, *, request: PredictInput) -> PredictOutput: """Call the development deployment of a model.""" return self._do_json( @@ -464,7 +522,7 @@ def predict_development(self, *, request: PredictInput) -> PredictOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -476,6 +534,33 @@ def predict_development(self, *, request: PredictInput) -> PredictOutput: ), ) + def predict_development_raw( + self, + *, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call the development deployment of a model. Returns the response unread, in the requested content type. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/development/predict", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + def predict_production(self, *, request: PredictInput) -> PredictOutput: """Call the production environment of a model.""" return self._do_json( @@ -486,7 +571,7 @@ def predict_production(self, *, request: PredictInput) -> PredictOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -498,6 +583,33 @@ def predict_production(self, *, request: PredictInput) -> PredictOutput: ), ) + def predict_production_raw( + self, + *, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call the production environment of a model. Returns the response unread, in the requested content type. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/production/predict", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + def predict_regional(self, *, request: PredictInput) -> PredictOutput: """Call a regional environment of a model.""" return self._do_json( @@ -508,7 +620,7 @@ def predict_regional(self, *, request: PredictInput) -> PredictOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -520,6 +632,33 @@ def predict_regional(self, *, request: PredictInput) -> PredictOutput: ), ) + def predict_regional_raw( + self, + *, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call a regional environment of a model. Returns the response unread, in the requested content type. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/predict", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + def run_remote(self, *, env_name: str, request: RunRemoteInput) -> RunRemoteOutput: """Call the chain deployment associated with a specified environment.""" return self._do_json( @@ -530,7 +669,7 @@ def run_remote(self, *, env_name: str, request: RunRemoteInput) -> RunRemoteOutp path_args=[env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -554,7 +693,7 @@ def run_remote_deployment( path_args=[deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -576,7 +715,7 @@ def run_remote_development(self, *, request: RunRemoteInput) -> RunRemoteOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -598,7 +737,7 @@ def run_remote_production(self, *, request: RunRemoteInput) -> RunRemoteOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -620,7 +759,7 @@ def run_remote_regional(self, *, request: RunRemoteInput) -> RunRemoteOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -641,7 +780,7 @@ def wake(self, *, env_name: str) -> None: path_args=[env_name], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -655,7 +794,7 @@ def wake_deployment(self, *, deployment_id: str) -> None: path_args=[deployment_id], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -669,7 +808,7 @@ def wake_development(self) -> None: path_args=[], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -683,7 +822,7 @@ def wake_production(self) -> None: path_args=[], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -697,38 +836,84 @@ def wake_regional(self) -> None: path_args=[], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) - def _do(self, request: _ApiRequest) -> httpx.Response: + def _build_request(self, request: _ApiRequest) -> httpx.Request: path = request.path_fmt.format( *[urllib.parse.quote(a, safe="") for a in request.path_args] ) json_body = None + content_body = None + files_body = None + headers: dict[str, str] = {} + if request.accept is not None: + headers["Accept"] = request.accept if request.body is not None: - if isinstance(request.body, BaseModel): - # Only fields the caller set are sent, so unset fields fall - # back to the server default rather than being reset here. - # An explicit None is kept, since null can mean "clear". - json_body = request.body.model_dump(mode="json", exclude_unset=True) + if request.body_content_type is None: + if isinstance(request.body, BaseModel): + # Only fields the caller set are sent, so unset fields fall + # back to the server default rather than being reset here. + # An explicit None is kept, since null can mean "clear". + # by_alias: a field renamed for Python (e.g. async_ for + # "async") must serialize under its API name. + json_body = request.body.model_dump( + mode="json", exclude_unset=True, by_alias=True + ) + else: + json_body = request.body + elif request.body_content_type == "multipart/form-data": + # httpx derives the multipart Content-Type, boundary included. + files_body = request.body else: - json_body = request.body + headers["Content-Type"] = request.body_content_type + content_body = request.body params = None if request.query is not None: if isinstance(request.query, BaseModel): # As above, plus dropping None: a null query parameter is # meaningless and would otherwise serialize as an empty string. params = request.query.model_dump( - mode="json", exclude_unset=True, exclude_none=True + mode="json", exclude_unset=True, exclude_none=True, by_alias=True ) else: params = request.query - response = self._http_client.request( - request.method, path, json=json_body, params=params + return self._http_client.build_request( + request.method, + path, + json=json_body, + content=content_body, + files=files_body, + params=params, + headers=headers, ) - if response.status_code != request.success_code: + + def _do(self, request: _ApiRequest) -> httpx.Response: + response = self._http_client.send(self._build_request(request)) + if response.status_code not in request.success_codes: + if request.error_codes and response.status_code in request.error_codes: + error_name = request.error_codes[response.status_code] + if error_name in _ERROR_TYPES: + model_cls, exc_cls, field_name = _ERROR_TYPES[error_name] + # A body that does not match the declared error schema + # falls through to the generic ResponseError below. + model = None + with contextlib.suppress(ValidationError): + model = model_cls.model_validate_json(response.content) + if model is not None: + raise exc_cls( + status_code=response.status_code, # ty: ignore[unknown-argument] + **{field_name: model}, + ) + raise ResponseError(status_code=response.status_code, body=response.text) + return response + + def _do_raw(self, request: _ApiRequest) -> httpx.Response: + response = self._http_client.send(self._build_request(request), stream=True) + if response.status_code not in request.success_codes: + response.read() if request.error_codes and response.status_code in request.error_codes: error_name = request.error_codes[response.status_code] if error_name in _ERROR_TYPES: @@ -783,7 +968,7 @@ async def async_predict( path_args=[env_name], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -806,7 +991,7 @@ async def async_predict_deployment( path_args=[deployment_id], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -829,7 +1014,7 @@ async def async_predict_development( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -852,7 +1037,7 @@ async def async_predict_production( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -875,7 +1060,7 @@ async def async_predict_regional( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -898,7 +1083,7 @@ async def async_run_remote( path_args=[env_name], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -920,7 +1105,7 @@ async def async_run_remote_deployment( path_args=[deployment_id], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -942,7 +1127,7 @@ async def async_run_remote_development( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -964,7 +1149,7 @@ async def async_run_remote_production( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -986,7 +1171,7 @@ async def async_run_remote_regional( path_args=[], body=request, query=None, - success_code=201, + success_codes=[201], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1008,7 +1193,7 @@ async def cancel_async_request( path_args=[request_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -1025,7 +1210,7 @@ async def get_async_queue_status( path_args=[env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -1042,7 +1227,7 @@ async def get_async_queue_status_deployment( path_args=[deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -1057,7 +1242,7 @@ async def get_async_queue_status_development(self) -> GetAsyncQueueStatusOutput: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -1072,7 +1257,7 @@ async def get_async_queue_status_production(self) -> GetAsyncQueueStatusOutput: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -1087,7 +1272,7 @@ async def get_async_queue_status_regional(self) -> GetAsyncQueueStatusOutput: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -1104,7 +1289,7 @@ async def get_async_request_status( path_args=[request_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes={401: "ErrorResponse", 429: "ErrorResponse"}, ), ) @@ -1119,7 +1304,7 @@ async def predict(self, *, env_name: str, request: PredictInput) -> PredictOutpu path_args=[env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1131,6 +1316,34 @@ async def predict(self, *, env_name: str, request: PredictInput) -> PredictOutpu ), ) + async def predict_raw( + self, + *, + env_name: str, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call the model deployment associated with a specified environment. Returns the response unread, in the requested content type. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/environments/{}/predict", + path_args=[env_name], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + async def predict_deployment( self, *, deployment_id: str, request: PredictInput ) -> PredictOutput: @@ -1143,7 +1356,7 @@ async def predict_deployment( path_args=[deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1155,6 +1368,34 @@ async def predict_deployment( ), ) + async def predict_deployment_raw( + self, + *, + deployment_id: str, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call a specific deployment of a model by deployment ID. Returns the response unread, in the requested content type. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/deployment/{}/predict", + path_args=[deployment_id], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + async def predict_development(self, *, request: PredictInput) -> PredictOutput: """Call the development deployment of a model.""" return await self._do_json( @@ -1165,7 +1406,7 @@ async def predict_development(self, *, request: PredictInput) -> PredictOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1177,6 +1418,33 @@ async def predict_development(self, *, request: PredictInput) -> PredictOutput: ), ) + async def predict_development_raw( + self, + *, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call the development deployment of a model. Returns the response unread, in the requested content type. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/development/predict", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + async def predict_production(self, *, request: PredictInput) -> PredictOutput: """Call the production environment of a model.""" return await self._do_json( @@ -1187,7 +1455,7 @@ async def predict_production(self, *, request: PredictInput) -> PredictOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1199,6 +1467,33 @@ async def predict_production(self, *, request: PredictInput) -> PredictOutput: ), ) + async def predict_production_raw( + self, + *, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call the production environment of a model. Returns the response unread, in the requested content type. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/production/predict", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + async def predict_regional(self, *, request: PredictInput) -> PredictOutput: """Call a regional environment of a model.""" return await self._do_json( @@ -1209,7 +1504,7 @@ async def predict_regional(self, *, request: PredictInput) -> PredictOutput: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1221,6 +1516,33 @@ async def predict_regional(self, *, request: PredictInput) -> PredictOutput: ), ) + async def predict_regional_raw( + self, + *, + request: PredictInput, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Call a regional environment of a model. Returns the response unread, in the requested content type. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/predict", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 401: "ErrorResponse", + 429: "ErrorResponse", + 502: "ErrorResponse", + 503: "ErrorResponse", + 504: "ErrorResponse", + }, + accept=accept, + ) + ) + async def run_remote( self, *, env_name: str, request: RunRemoteInput ) -> RunRemoteOutput: @@ -1233,7 +1555,7 @@ async def run_remote( path_args=[env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1257,7 +1579,7 @@ async def run_remote_deployment( path_args=[deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1281,7 +1603,7 @@ async def run_remote_development( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1305,7 +1627,7 @@ async def run_remote_production( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1327,7 +1649,7 @@ async def run_remote_regional(self, *, request: RunRemoteInput) -> RunRemoteOutp path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes={ 400: "ErrorResponse", 401: "ErrorResponse", @@ -1348,7 +1670,7 @@ async def wake(self, *, env_name: str) -> None: path_args=[env_name], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -1362,7 +1684,7 @@ async def wake_deployment(self, *, deployment_id: str) -> None: path_args=[deployment_id], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -1376,7 +1698,7 @@ async def wake_development(self) -> None: path_args=[], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -1390,7 +1712,7 @@ async def wake_production(self) -> None: path_args=[], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) @@ -1404,38 +1726,86 @@ async def wake_regional(self) -> None: path_args=[], body=None, query=None, - success_code=202, + success_codes=[202], error_codes={401: "ErrorResponse"}, ) ) - async def _do(self, request: _ApiRequest) -> httpx.Response: + def _build_request(self, request: _ApiRequest) -> httpx.Request: path = request.path_fmt.format( *[urllib.parse.quote(a, safe="") for a in request.path_args] ) json_body = None + content_body = None + files_body = None + headers: dict[str, str] = {} + if request.accept is not None: + headers["Accept"] = request.accept if request.body is not None: - if isinstance(request.body, BaseModel): - # Only fields the caller set are sent, so unset fields fall - # back to the server default rather than being reset here. - # An explicit None is kept, since null can mean "clear". - json_body = request.body.model_dump(mode="json", exclude_unset=True) + if request.body_content_type is None: + if isinstance(request.body, BaseModel): + # Only fields the caller set are sent, so unset fields fall + # back to the server default rather than being reset here. + # An explicit None is kept, since null can mean "clear". + # by_alias: a field renamed for Python (e.g. async_ for + # "async") must serialize under its API name. + json_body = request.body.model_dump( + mode="json", exclude_unset=True, by_alias=True + ) + else: + json_body = request.body + elif request.body_content_type == "multipart/form-data": + # httpx derives the multipart Content-Type, boundary included. + files_body = request.body else: - json_body = request.body + headers["Content-Type"] = request.body_content_type + content_body = request.body params = None if request.query is not None: if isinstance(request.query, BaseModel): # As above, plus dropping None: a null query parameter is # meaningless and would otherwise serialize as an empty string. params = request.query.model_dump( - mode="json", exclude_unset=True, exclude_none=True + mode="json", exclude_unset=True, exclude_none=True, by_alias=True ) else: params = request.query - response = await self._http_client.request( - request.method, path, json=json_body, params=params + return self._http_client.build_request( + request.method, + path, + json=json_body, + content=content_body, + files=files_body, + params=params, + headers=headers, + ) + + async def _do(self, request: _ApiRequest) -> httpx.Response: + response = await self._http_client.send(self._build_request(request)) + if response.status_code not in request.success_codes: + if request.error_codes and response.status_code in request.error_codes: + error_name = request.error_codes[response.status_code] + if error_name in _ERROR_TYPES: + model_cls, exc_cls, field_name = _ERROR_TYPES[error_name] + # A body that does not match the declared error schema + # falls through to the generic ResponseError below. + model = None + with contextlib.suppress(ValidationError): + model = model_cls.model_validate_json(response.content) + if model is not None: + raise exc_cls( + status_code=response.status_code, # ty: ignore[unknown-argument] + **{field_name: model}, + ) + raise ResponseError(status_code=response.status_code, body=response.text) + return response + + async def _do_raw(self, request: _ApiRequest) -> httpx.Response: + response = await self._http_client.send( + self._build_request(request), stream=True ) - if response.status_code != request.success_code: + if response.status_code not in request.success_codes: + await response.aread() if request.error_codes and response.status_code in request.error_codes: error_name = request.error_codes[response.status_code] if error_name in _ERROR_TYPES: diff --git a/baseten/client/managementapi/__init__.py b/baseten/client/managementapi/__init__.py index 9f12cc8..3b0d0f6 100644 --- a/baseten/client/managementapi/__init__.py +++ b/baseten/client/managementapi/__init__.py @@ -12,6 +12,7 @@ from ._client import ApiClient, AsyncApiClient, ResponseError from ._models import ( + Action, ActivateResponse, ActiveJobAtSubmit, APIKey, @@ -59,6 +60,10 @@ AuditLogEventModelDeploymentRequestBackpressureSettingsChanged, AuditLogEventModelDeploymentRetried, AuditLogEventModelPromotionControlAction, + AuditLogEventModelRenamed, + AuditLogEventProviderConnectionCreated, + AuditLogEventProviderConnectionDeleted, + AuditLogEventProviderConnectionUpdated, AuditLogEventReplicaTerminated, AuditLogEventRequireGroupBasedAdminsEnabled, AuditLogEventSecretDeleted, @@ -82,6 +87,7 @@ AuditLogSource, AuthCode, AuthMethod, + AuthSecretName, AutoscalingSchedule, AutoscalingScheduleSettings, AutoscalingScheduleSettingsRequest, @@ -94,6 +100,9 @@ AWSCredentials, AwsIamDockerAuth, AwsOidcDockerAuth, + Background, + Background1, + BackgroundHarnessModels, BasetenLatestCheckpointConfig, BasetenNamedCheckpointConfig, BenchmarkSnapshot, @@ -119,6 +128,8 @@ CheckpointFile, Checkpoints, CheckpointSyncStatus, + CleanupImagesParams, + CleanupImagesResponse, Component, ComputeCost, ComputeCost1, @@ -148,6 +159,10 @@ CreateLoopsSessionResponse, CreateModelDeploymentRequest, CreateModelRequest, + CreateRouteRequest, + CreateSandboxParams, + CreateSandboxRequest, + CreateTokenRequest, CreateTrainingJob, CreateTrainingJobAccelerator, CreateTrainingJobCacheConfig, @@ -158,6 +173,7 @@ CreateTrainingJobResponse, CreateTrainingJobRuntime, CreateTrainingJobS3Artifact, + CreateVolumeSyncRequest, CreateVolumeTokenRequest, CreateVolumeTokenResponse, CreditsUsed, @@ -166,13 +182,20 @@ DailyTrainingUsage, DeactivateLoopsDeploymentResponse, DeactivateLoopsRunResponse, + DeactivateLoopsSamplerResponse, DeactivateResponse, DedicatedItem, DedicatedUsage, + DeleteImageParams, + DeleteImageTagParams, + DeleteRoutesHarnessConfigsParams, + DeleteSandboxParams, DeleteVolumeRequest, DeleteVolumeResponse, DeleteVolumeVersionRequest, DeleteVolumeVersionResponse, + DeployLoopsCheckpointRequest, + DeployLoopsCheckpointResponse, Deployment, DeploymentArchivePayload, DeploymentArchiveSource, @@ -190,6 +213,10 @@ Deployments, DeploymentStatus, DeploymentTombstone, + Description, + Description1, + DisplayName, + DisplayName1, DockerAuth, DockerAuthType, DownloadDeploymentResponse, @@ -198,6 +225,7 @@ EffectiveRateLimit, EffectiveUsageLimit, EmbeddingBenchmarkMetrics, + EnablementDetails, Endpoint, EndpointsResponse, EndpointTarget, @@ -211,6 +239,11 @@ EnvironmentGroupUser, Environments, EnvironmentTombstone, + ExploreCost, + ExploreCostValues, + ExploreMetadata, + ExploreMetadataAPIFormats, + ExploreMetadataResponse, FileSummary, GatewayEvent, GatewayEventsResponse, @@ -219,48 +252,58 @@ GatewayProvider, GcpOidcDockerAuth, GcpServiceAccountJsonDockerAuth, - GetAuditLogsRequest, + GetApiKeysParams, + GetAuditLogsParams, GetAuthCodesResponse, - GetBillingModelApisRequest, - GetBillingUsageSummaryRequest, + GetBillingModelApisParams, + GetBillingToolCallUsageParams, + GetBillingUsageSummaryParams, GetBlobCredentialsResponse, GetCacheSummaryResponse, - GetChainsAuditLogsRequest, - GetChainsDeploymentsChainletsLogsRequest, + GetChainsAuditLogsParams, + GetChainsDeploymentsChainletsLogsParams, GetDeploymentLogsRequest, GetDeploymentPatchesStateResponse, - GetGatewayEventsRequest, + GetExploreMetadataParams, + GetGatewayEventsParams, + GetImageBuildLogsParams, + GetImageParams, GetLogsResponse, + GetLoopsCapabilitiesParams, GetLoopsCapabilitiesResponse, - GetLoopsCheckpointsFilesRequest, - GetLoopsCheckpointsRequest, + GetLoopsCheckpointsFilesParams, + GetLoopsCheckpointsParams, GetLoopsDeploymentMetricsRequest, GetLoopsDeploymentMetricsResponse, GetLoopsDeploymentResponse, - GetLoopsDeploymentsDebugArchiveFilesRequest, - GetLoopsDeploymentsLogsRequest, - GetLoopsDeploymentsRequest, + GetLoopsDeploymentsDebugArchiveFilesParams, + GetLoopsDeploymentsLogsParams, + GetLoopsDeploymentsParams, GetLoopsRunResponse, - GetLoopsRunsRequest, + GetLoopsRunsParams, GetLoopsSamplerResponse, - GetLoopsSamplersRequest, + GetLoopsSamplersParams, GetLoopsSessionResponse, GetLoopsUserConfigResponse, - GetModelApisRequest, - GetModelApisUsageRequest, + GetModelApisParams, + GetModelApisUsageParams, GetModelMetricsResponse, - GetModelsAuditLogsRequest, - GetModelsDeploymentsConfigRequest, - GetModelsDeploymentsLogsRequest, - GetModelsDeploymentsMetricsRequest, - GetModelsDeploymentsRequest, - GetModelsEnvironmentsLogsRequest, - GetModelsEnvironmentsMetricsRequest, - GetModelsRequest, - GetTeamsLoopsRunsRequest, - GetTeamsLoopsSamplersRequest, - GetTeamsModelsRequest, - GetTeamsRequest, + GetModelsAuditLogsParams, + GetModelsDeploymentsConfigParams, + GetModelsDeploymentsLogsParams, + GetModelsDeploymentsMetricsParams, + GetModelsDeploymentsParams, + GetModelsEnvironmentsLogsParams, + GetModelsEnvironmentsMetricsParams, + GetModelsParams, + GetRoutesHarnessConfigsParams, + GetRoutesParams, + GetRoutesUsageParams, + GetSandboxParams, + GetTeamsLoopsRunsParams, + GetTeamsLoopsSamplersParams, + GetTeamsModelsParams, + GetTeamsParams, GetTrainingGpuCapacityResponse, GetTrainingJobCheckpointFilesResponse, GetTrainingJobCheckpointsResponse, @@ -270,18 +313,24 @@ GetTrainingJobQueueContextResponse, GetTrainingJobResponse, GetTrainingProjectResponse, - GetTrainingProjectsJobsCheckpointFilesRequest, - GetTrainingProjectsJobsLogsRequest, - GetTrainingProjectsJobsMetricsRequest, - GetUsersRequest, - GetVolumesNamespacesRequest, - GetVolumesRequest, - GetVolumesVersionsRequest, + GetTrainingProjectsJobsCheckpointFilesParams, + GetTrainingProjectsJobsLogsParams, + GetTrainingProjectsJobsMetricsParams, + GetUsersParams, + GetVolumesNamespacesParams, + GetVolumesParams, + GetVolumesSyncsParams, + GetVolumesVersionsParams, GitInfo, Group, GroupHierarchy, GroupMetadata, GroupsResponse, + Image, + ImageBuildLog, + ImageBuildLogsResponse, + ImageStatus, + ImageTag, InferenceVolumeByStatusDatapoint, InProgressPromotion, InProgressPromotionStatus, @@ -307,10 +356,18 @@ LimitEnforcement, LimitType, ListAuditLogsResponse, + ListImagesParams, + ListImagesResponse, + ListImageTagsParams, + ListImageTagsResponse, ListLoopsCheckpointsResponse, ListLoopsDeploymentsResponse, ListLoopsRunsResponse, ListLoopsSamplersResponse, + ListSandboxesParams, + ListSandboxesResponse, + ListSandboxLibraryImagesParams, + ListSandboxLibraryImagesResponse, ListTrainingJobsResponse, ListTrainingProjectsResponse, ListVolumeNamespacesResponse, @@ -324,6 +381,9 @@ LoopsCheckpoint, LoopsCheckpointConfig, LoopsCheckpointFilesResponse, + LoopsCheckpointS3Source, + LoopsCheckpointSourceResponse, + LoopsCheckpointVolumeSource, LoopsDebugArchiveFilesResponse, LoopsDeployment, LoopsDeploymentMetrics, @@ -335,9 +395,11 @@ LoopsSampler, LoopsSamplerStatus, LoopsSession, + LoopsUseCase, LoopsUserConfig, MaxScaleDownRate, MaxScaleDownRate1, + MaxSeqLen, Model, ModelAPI, ModelApiCostDimension, @@ -364,6 +426,7 @@ Name1, Name2, Name3, + Name4, OneTimeAutoscalingSchedule, OneTimeAutoscalingScheduleUpsert, OrderBy, @@ -379,11 +442,18 @@ PendingJobAheadAtSubmit, PrepareModelUploadRequest, PrepareModelUploadResponse, + Primary, + Primary2, + PrimaryHarnessModels, PromoteRequest, PromoteToChainEnvironmentRequest, PromoteToEnvironmentRequest, PromotionCleanupStrategy, PromotionSettings, + Protocol, + PushImageParams, + PushImageRequest, + PushImageResponse, QueueEvent, RateLimit, RateLimitUnit, @@ -404,6 +474,46 @@ RetryDeploymentResponse, RollingDeployConfig, RollingDeployStrategy, + Route, + RouteHarness, + RouteHarnessConfig, + RouteHarnessConfigsResponse, + RouteHarnessConfigTombstone, + RouteHarnessModel, + RouteHarnessModelSource, + RouteHarnessRole, + RouteProvider, + RouteSpendLimit, + RoutesResponse, + RoutesUsageBucket, + RoutesUsageResponse, + RoutesUsageResult, + RouteTargetAnthropic, + RouteTargetBasetenModelAPI, + RouteTargetOpenAI, + RouteTargetXAI, + RouteTombstone, + RouteUsageDimension, + Sandbox, + SandboxApiPagination, + SandboxConfiguration, + SandboxDateExpirationPolicy, + SandboxDuration, + SandboxEnv, + SandboxExpirationPolicy, + SandboxLibraryImage, + SandboxLibraryImageCreationOptions, + SandboxLibraryImageVolume, + SandboxLifecycle, + SandboxMetadataLabels, + SandboxNetwork, + SandboxPort, + SandboxPorts, + SandboxProxyConfig, + SandboxProxyTarget, + SandboxStatus, + SandboxTTLIdleExpirationPolicy, + SandboxTTLMaxAgeExpirationPolicy, Schedules, Schedules1, SearchPattern, @@ -413,11 +523,16 @@ SecretReference, Secrets, SecretTombstone, + SetClaudeCodeHarnessConfig, + SetCodexHarnessConfig, + SetOpenCodeHarnessConfig, + SetRouteHarnessConfigRequest, SharedEndpointRegion, SignalPromotionResponse, SignSSHCertificateRequest, SignSSHCertificateResponse, SortOrder, + StatusItem, StopTrainingJobRequest, StopTrainingJobResponse, StorageMetrics, @@ -437,9 +552,14 @@ Targets, Team, TeamId, + TeamId1, Teams, TeamTrainingGpuCapacityItem, TerminateReplicaResponse, + Token, + TokenScope, + ToolCallUsageBucket, + ToolCallUsageResponse, Total, TrainerCheckpointTarget, TrainingGpuCapacityItem, @@ -457,15 +577,21 @@ TrainingWeightAuth, TrussUserEnv, TTSBenchmarkMetrics, + Type, + Type1, + Type2, UpdateAutoscalingScheduleSettings, UpdateAutoscalingSettings, UpdateAutoscalingSettingsResponse, UpdateAutoscalingSettingsStatus, + UpdateBackgroundHarnessModels, UpdateChainEnvironmentRequest, UpdateChainEnvironmentResponse, UpdateChainletEnvironmentAutoscalingSettingsRequest, UpdateChainletEnvironmentInstanceTypeRequest, UpdateChainletEnvironmentInstanceTypeResponse, + UpdateClaudeCodeHarnessConfig, + UpdateCodexHarnessConfig, UpdateDeploymentRequest, UpdateEndpointRequest, UpdateEnvironmentGroupManageAccess, @@ -476,9 +602,17 @@ UpdateGroupRequest, UpdateLibraryListingRequest, UpdateLibraryListingVersionRequest, + UpdateModelRequest, + UpdateOpenCodeHarnessConfig, + UpdatePrimaryHarnessModels, UpdatePromotionSettings, UpdateRequestBackpressureSettings, UpdateRollingDeployConfig, + UpdateRouteHarnessConfigRequest, + UpdateRouteRequest, + UpdateRouteSpendLimitRequest, + UpdateSandboxParams, + UpdateSandboxRequest, UpdateTrainingJobRequest, UpdateTrainingJobResponse, UpsertSecretRequest, @@ -500,6 +634,21 @@ ValidateLoopsCheckpointResponse, VertexTargetConfig, Volume, + VolumeSync, + VolumeSyncAuthenticationAWSAssumeRole, + VolumeSyncAuthenticationAWSOIDC, + VolumeSyncAuthenticationGCPOIDC, + VolumeSyncDestination, + VolumeSyncError, + VolumeSyncs, + VolumeSyncSourceAzure, + VolumeSyncSourceBasetenTraining, + VolumeSyncSourceCoreWeave, + VolumeSyncSourceGCS, + VolumeSyncSourceHuggingFace, + VolumeSyncSourceR2, + VolumeSyncSourceS3, + VolumeSyncStatus, VolumeTag, VolumeTokenScope, VolumeVersion, @@ -515,6 +664,7 @@ "APIKeyTombstone", "APIKeys", "AWSCredentials", + "Action", "ActivateResponse", "ActiveJobAtSubmit", "ApiClient", @@ -558,6 +708,10 @@ "AuditLogEventModelDeploymentRequestBackpressureSettingsChanged", "AuditLogEventModelDeploymentRetried", "AuditLogEventModelPromotionControlAction", + "AuditLogEventModelRenamed", + "AuditLogEventProviderConnectionCreated", + "AuditLogEventProviderConnectionDeleted", + "AuditLogEventProviderConnectionUpdated", "AuditLogEventReplicaTerminated", "AuditLogEventRequireGroupBasedAdminsEnabled", "AuditLogEventSecretDeleted", @@ -581,6 +735,7 @@ "AuditLogSource", "AuthCode", "AuthMethod", + "AuthSecretName", "AutoscalingSchedule", "AutoscalingScheduleSettings", "AutoscalingScheduleSettingsRequest", @@ -592,6 +747,9 @@ "AwsAssumeRoleDockerAuth", "AwsIamDockerAuth", "AwsOidcDockerAuth", + "Background", + "Background1", + "BackgroundHarnessModels", "BasetenLatestCheckpointConfig", "BasetenNamedCheckpointConfig", "BenchmarkSnapshot", @@ -617,6 +775,8 @@ "CheckpointFile", "CheckpointSyncStatus", "Checkpoints", + "CleanupImagesParams", + "CleanupImagesResponse", "Component", "ComputeCost", "ComputeCost1", @@ -645,6 +805,10 @@ "CreateLoopsSessionResponse", "CreateModelDeploymentRequest", "CreateModelRequest", + "CreateRouteRequest", + "CreateSandboxParams", + "CreateSandboxRequest", + "CreateTokenRequest", "CreateTrainingJob", "CreateTrainingJobAccelerator", "CreateTrainingJobCacheConfig", @@ -655,6 +819,7 @@ "CreateTrainingJobResponse", "CreateTrainingJobRuntime", "CreateTrainingJobS3Artifact", + "CreateVolumeSyncRequest", "CreateVolumeTokenRequest", "CreateVolumeTokenResponse", "CreatedModelDeployment", @@ -664,13 +829,20 @@ "DailyTrainingUsage", "DeactivateLoopsDeploymentResponse", "DeactivateLoopsRunResponse", + "DeactivateLoopsSamplerResponse", "DeactivateResponse", "DedicatedItem", "DedicatedUsage", + "DeleteImageParams", + "DeleteImageTagParams", + "DeleteRoutesHarnessConfigsParams", + "DeleteSandboxParams", "DeleteVolumeRequest", "DeleteVolumeResponse", "DeleteVolumeVersionRequest", "DeleteVolumeVersionResponse", + "DeployLoopsCheckpointRequest", + "DeployLoopsCheckpointResponse", "Deployment", "DeploymentArchivePayload", "DeploymentArchiveSource", @@ -688,6 +860,10 @@ "DeploymentStatus", "DeploymentTombstone", "Deployments", + "Description", + "Description1", + "DisplayName", + "DisplayName1", "DockerAuth", "DockerAuthType", "DownloadDeploymentResponse", @@ -696,6 +872,7 @@ "EffectiveRateLimit", "EffectiveUsageLimit", "EmbeddingBenchmarkMetrics", + "EnablementDetails", "Endpoint", "EndpointTarget", "EndpointTargetRequest", @@ -709,6 +886,11 @@ "EnvironmentGroups", "EnvironmentTombstone", "Environments", + "ExploreCost", + "ExploreCostValues", + "ExploreMetadata", + "ExploreMetadataAPIFormats", + "ExploreMetadataResponse", "FileSummary", "GatewayEvent", "GatewayEventTokens", @@ -717,48 +899,58 @@ "GatewayProvider", "GcpOidcDockerAuth", "GcpServiceAccountJsonDockerAuth", - "GetAuditLogsRequest", + "GetApiKeysParams", + "GetAuditLogsParams", "GetAuthCodesResponse", - "GetBillingModelApisRequest", - "GetBillingUsageSummaryRequest", + "GetBillingModelApisParams", + "GetBillingToolCallUsageParams", + "GetBillingUsageSummaryParams", "GetBlobCredentialsResponse", "GetCacheSummaryResponse", - "GetChainsAuditLogsRequest", - "GetChainsDeploymentsChainletsLogsRequest", + "GetChainsAuditLogsParams", + "GetChainsDeploymentsChainletsLogsParams", "GetDeploymentLogsRequest", "GetDeploymentPatchesStateResponse", - "GetGatewayEventsRequest", + "GetExploreMetadataParams", + "GetGatewayEventsParams", + "GetImageBuildLogsParams", + "GetImageParams", "GetLogsResponse", + "GetLoopsCapabilitiesParams", "GetLoopsCapabilitiesResponse", - "GetLoopsCheckpointsFilesRequest", - "GetLoopsCheckpointsRequest", + "GetLoopsCheckpointsFilesParams", + "GetLoopsCheckpointsParams", "GetLoopsDeploymentMetricsRequest", "GetLoopsDeploymentMetricsResponse", "GetLoopsDeploymentResponse", - "GetLoopsDeploymentsDebugArchiveFilesRequest", - "GetLoopsDeploymentsLogsRequest", - "GetLoopsDeploymentsRequest", + "GetLoopsDeploymentsDebugArchiveFilesParams", + "GetLoopsDeploymentsLogsParams", + "GetLoopsDeploymentsParams", "GetLoopsRunResponse", - "GetLoopsRunsRequest", + "GetLoopsRunsParams", "GetLoopsSamplerResponse", - "GetLoopsSamplersRequest", + "GetLoopsSamplersParams", "GetLoopsSessionResponse", "GetLoopsUserConfigResponse", - "GetModelApisRequest", - "GetModelApisUsageRequest", + "GetModelApisParams", + "GetModelApisUsageParams", "GetModelMetricsResponse", - "GetModelsAuditLogsRequest", - "GetModelsDeploymentsConfigRequest", - "GetModelsDeploymentsLogsRequest", - "GetModelsDeploymentsMetricsRequest", - "GetModelsDeploymentsRequest", - "GetModelsEnvironmentsLogsRequest", - "GetModelsEnvironmentsMetricsRequest", - "GetModelsRequest", - "GetTeamsLoopsRunsRequest", - "GetTeamsLoopsSamplersRequest", - "GetTeamsModelsRequest", - "GetTeamsRequest", + "GetModelsAuditLogsParams", + "GetModelsDeploymentsConfigParams", + "GetModelsDeploymentsLogsParams", + "GetModelsDeploymentsMetricsParams", + "GetModelsDeploymentsParams", + "GetModelsEnvironmentsLogsParams", + "GetModelsEnvironmentsMetricsParams", + "GetModelsParams", + "GetRoutesHarnessConfigsParams", + "GetRoutesParams", + "GetRoutesUsageParams", + "GetSandboxParams", + "GetTeamsLoopsRunsParams", + "GetTeamsLoopsSamplersParams", + "GetTeamsModelsParams", + "GetTeamsParams", "GetTrainingGpuCapacityResponse", "GetTrainingJobCheckpointFilesResponse", "GetTrainingJobCheckpointsResponse", @@ -768,18 +960,24 @@ "GetTrainingJobQueueContextResponse", "GetTrainingJobResponse", "GetTrainingProjectResponse", - "GetTrainingProjectsJobsCheckpointFilesRequest", - "GetTrainingProjectsJobsLogsRequest", - "GetTrainingProjectsJobsMetricsRequest", - "GetUsersRequest", - "GetVolumesNamespacesRequest", - "GetVolumesRequest", - "GetVolumesVersionsRequest", + "GetTrainingProjectsJobsCheckpointFilesParams", + "GetTrainingProjectsJobsLogsParams", + "GetTrainingProjectsJobsMetricsParams", + "GetUsersParams", + "GetVolumesNamespacesParams", + "GetVolumesParams", + "GetVolumesSyncsParams", + "GetVolumesVersionsParams", "GitInfo", "Group", "GroupHierarchy", "GroupMetadata", "GroupsResponse", + "Image", + "ImageBuildLog", + "ImageBuildLogsResponse", + "ImageStatus", + "ImageTag", "InProgressPromotion", "InProgressPromotionStatus", "InferenceVolumeByStatusDatapoint", @@ -807,10 +1005,18 @@ "LimitEnforcement", "LimitType", "ListAuditLogsResponse", + "ListImageTagsParams", + "ListImageTagsResponse", + "ListImagesParams", + "ListImagesResponse", "ListLoopsCheckpointsResponse", "ListLoopsDeploymentsResponse", "ListLoopsRunsResponse", "ListLoopsSamplersResponse", + "ListSandboxLibraryImagesParams", + "ListSandboxLibraryImagesResponse", + "ListSandboxesParams", + "ListSandboxesResponse", "ListTrainingJobsResponse", "ListTrainingProjectsResponse", "ListVolumeNamespacesResponse", @@ -822,6 +1028,9 @@ "LoopsCheckpoint", "LoopsCheckpointConfig", "LoopsCheckpointFilesResponse", + "LoopsCheckpointS3Source", + "LoopsCheckpointSourceResponse", + "LoopsCheckpointVolumeSource", "LoopsDebugArchiveFilesResponse", "LoopsDeployment", "LoopsDeploymentMetrics", @@ -833,9 +1042,11 @@ "LoopsSampler", "LoopsSamplerStatus", "LoopsSession", + "LoopsUseCase", "LoopsUserConfig", "MaxScaleDownRate", "MaxScaleDownRate1", + "MaxSeqLen", "Model", "ModelAPI", "ModelAPIOrgDetails", @@ -862,6 +1073,7 @@ "Name1", "Name2", "Name3", + "Name4", "OneTimeAutoscalingSchedule", "OneTimeAutoscalingScheduleUpsert", "OrderBy", @@ -877,11 +1089,18 @@ "PendingJobAheadAtSubmit", "PrepareModelUploadRequest", "PrepareModelUploadResponse", + "Primary", + "Primary2", + "PrimaryHarnessModels", "PromoteRequest", "PromoteToChainEnvironmentRequest", "PromoteToEnvironmentRequest", "PromotionCleanupStrategy", "PromotionSettings", + "Protocol", + "PushImageParams", + "PushImageRequest", + "PushImageResponse", "QueueEvent", "RateLimit", "RateLimitUnit", @@ -903,6 +1122,46 @@ "RetryDeploymentResponse", "RollingDeployConfig", "RollingDeployStrategy", + "Route", + "RouteHarness", + "RouteHarnessConfig", + "RouteHarnessConfigTombstone", + "RouteHarnessConfigsResponse", + "RouteHarnessModel", + "RouteHarnessModelSource", + "RouteHarnessRole", + "RouteProvider", + "RouteSpendLimit", + "RouteTargetAnthropic", + "RouteTargetBasetenModelAPI", + "RouteTargetOpenAI", + "RouteTargetXAI", + "RouteTombstone", + "RouteUsageDimension", + "RoutesResponse", + "RoutesUsageBucket", + "RoutesUsageResponse", + "RoutesUsageResult", + "Sandbox", + "SandboxApiPagination", + "SandboxConfiguration", + "SandboxDateExpirationPolicy", + "SandboxDuration", + "SandboxEnv", + "SandboxExpirationPolicy", + "SandboxLibraryImage", + "SandboxLibraryImageCreationOptions", + "SandboxLibraryImageVolume", + "SandboxLifecycle", + "SandboxMetadataLabels", + "SandboxNetwork", + "SandboxPort", + "SandboxPorts", + "SandboxProxyConfig", + "SandboxProxyTarget", + "SandboxStatus", + "SandboxTTLIdleExpirationPolicy", + "SandboxTTLMaxAgeExpirationPolicy", "Schedules", "Schedules1", "SearchPattern", @@ -912,11 +1171,16 @@ "SecretReference", "SecretTombstone", "Secrets", + "SetClaudeCodeHarnessConfig", + "SetCodexHarnessConfig", + "SetOpenCodeHarnessConfig", + "SetRouteHarnessConfigRequest", "SharedEndpointRegion", "SignSSHCertificateRequest", "SignSSHCertificateResponse", "SignalPromotionResponse", "SortOrder", + "StatusItem", "StopTrainingJobRequest", "StopTrainingJobResponse", "StorageMetrics", @@ -937,9 +1201,14 @@ "Targets", "Team", "TeamId", + "TeamId1", "TeamTrainingGpuCapacityItem", "Teams", "TerminateReplicaResponse", + "Token", + "TokenScope", + "ToolCallUsageBucket", + "ToolCallUsageResponse", "Total", "TrainerCheckpointTarget", "TrainingGpuCapacityItem", @@ -956,15 +1225,21 @@ "TrainingUsage", "TrainingWeightAuth", "TrussUserEnv", + "Type", + "Type1", + "Type2", "UpdateAutoscalingScheduleSettings", "UpdateAutoscalingSettings", "UpdateAutoscalingSettingsResponse", "UpdateAutoscalingSettingsStatus", + "UpdateBackgroundHarnessModels", "UpdateChainEnvironmentRequest", "UpdateChainEnvironmentResponse", "UpdateChainletEnvironmentAutoscalingSettingsRequest", "UpdateChainletEnvironmentInstanceTypeRequest", "UpdateChainletEnvironmentInstanceTypeResponse", + "UpdateClaudeCodeHarnessConfig", + "UpdateCodexHarnessConfig", "UpdateDeploymentRequest", "UpdateEndpointRequest", "UpdateEnvironmentGroupManageAccess", @@ -975,9 +1250,17 @@ "UpdateGroupRequest", "UpdateLibraryListingRequest", "UpdateLibraryListingVersionRequest", + "UpdateModelRequest", + "UpdateOpenCodeHarnessConfig", + "UpdatePrimaryHarnessModels", "UpdatePromotionSettings", "UpdateRequestBackpressureSettings", "UpdateRollingDeployConfig", + "UpdateRouteHarnessConfigRequest", + "UpdateRouteRequest", + "UpdateRouteSpendLimitRequest", + "UpdateSandboxParams", + "UpdateSandboxRequest", "UpdateTrainingJobRequest", "UpdateTrainingJobResponse", "UpsertSecretRequest", @@ -999,6 +1282,21 @@ "ValidateLoopsCheckpointResponse", "VertexTargetConfig", "Volume", + "VolumeSync", + "VolumeSyncAuthenticationAWSAssumeRole", + "VolumeSyncAuthenticationAWSOIDC", + "VolumeSyncAuthenticationGCPOIDC", + "VolumeSyncDestination", + "VolumeSyncError", + "VolumeSyncSourceAzure", + "VolumeSyncSourceBasetenTraining", + "VolumeSyncSourceCoreWeave", + "VolumeSyncSourceGCS", + "VolumeSyncSourceHuggingFace", + "VolumeSyncSourceR2", + "VolumeSyncSourceS3", + "VolumeSyncStatus", + "VolumeSyncs", "VolumeTag", "VolumeTokenScope", "VolumeVersion", diff --git a/baseten/client/managementapi/_client.py b/baseten/client/managementapi/_client.py index e35ecc3..1e083e6 100644 --- a/baseten/client/managementapi/_client.py +++ b/baseten/client/managementapi/_client.py @@ -22,6 +22,8 @@ ChainEnvironment, Chains, ChainTombstone, + CleanupImagesParams, + CleanupImagesResponse, CreateApiKeyForGroupRequest, CreateApiKeyForGroupResponse, CreateAPIKeyRequest, @@ -43,17 +45,29 @@ CreateLoopsSessionResponse, CreateModelDeploymentRequest, CreateModelRequest, + CreateRouteRequest, + CreateSandboxParams, + CreateSandboxRequest, + CreateTokenRequest, CreateTrainingJobRequest, CreateTrainingJobResponse, + CreateVolumeSyncRequest, CreateVolumeTokenRequest, CreateVolumeTokenResponse, DeactivateLoopsDeploymentResponse, DeactivateLoopsRunResponse, + DeactivateLoopsSamplerResponse, DeactivateResponse, + DeleteImageParams, + DeleteImageTagParams, + DeleteRoutesHarnessConfigsParams, + DeleteSandboxParams, DeleteVolumeRequest, DeleteVolumeResponse, DeleteVolumeVersionRequest, DeleteVolumeVersionResponse, + DeployLoopsCheckpointRequest, + DeployLoopsCheckpointResponse, Deployment, DeploymentConfigResponse, Deployments, @@ -68,50 +82,61 @@ EnvironmentGroups, Environments, EnvironmentTombstone, + ExploreMetadataResponse, GatewayEventsResponse, GatewayKeyInfo, - GetAuditLogsRequest, + GetApiKeysParams, + GetAuditLogsParams, GetAuthCodesResponse, - GetBillingModelApisRequest, - GetBillingUsageSummaryRequest, + GetBillingModelApisParams, + GetBillingToolCallUsageParams, + GetBillingUsageSummaryParams, GetBlobCredentialsResponse, GetCacheSummaryResponse, - GetChainsAuditLogsRequest, - GetChainsDeploymentsChainletsLogsRequest, + GetChainsAuditLogsParams, + GetChainsDeploymentsChainletsLogsParams, GetDeploymentLogsRequest, GetDeploymentPatchesStateResponse, - GetGatewayEventsRequest, + GetExploreMetadataParams, + GetGatewayEventsParams, + GetImageBuildLogsParams, + GetImageParams, GetLogsResponse, + GetLoopsCapabilitiesParams, GetLoopsCapabilitiesResponse, - GetLoopsCheckpointsFilesRequest, - GetLoopsCheckpointsRequest, + GetLoopsCheckpointsFilesParams, + GetLoopsCheckpointsParams, GetLoopsDeploymentMetricsRequest, GetLoopsDeploymentMetricsResponse, GetLoopsDeploymentResponse, - GetLoopsDeploymentsDebugArchiveFilesRequest, - GetLoopsDeploymentsLogsRequest, - GetLoopsDeploymentsRequest, + GetLoopsDeploymentsDebugArchiveFilesParams, + GetLoopsDeploymentsLogsParams, + GetLoopsDeploymentsParams, GetLoopsRunResponse, - GetLoopsRunsRequest, + GetLoopsRunsParams, GetLoopsSamplerResponse, - GetLoopsSamplersRequest, + GetLoopsSamplersParams, GetLoopsSessionResponse, GetLoopsUserConfigResponse, - GetModelApisRequest, - GetModelApisUsageRequest, + GetModelApisParams, + GetModelApisUsageParams, GetModelMetricsResponse, - GetModelsAuditLogsRequest, - GetModelsDeploymentsConfigRequest, - GetModelsDeploymentsLogsRequest, - GetModelsDeploymentsMetricsRequest, - GetModelsDeploymentsRequest, - GetModelsEnvironmentsLogsRequest, - GetModelsEnvironmentsMetricsRequest, - GetModelsRequest, - GetTeamsLoopsRunsRequest, - GetTeamsLoopsSamplersRequest, - GetTeamsModelsRequest, - GetTeamsRequest, + GetModelsAuditLogsParams, + GetModelsDeploymentsConfigParams, + GetModelsDeploymentsLogsParams, + GetModelsDeploymentsMetricsParams, + GetModelsDeploymentsParams, + GetModelsEnvironmentsLogsParams, + GetModelsEnvironmentsMetricsParams, + GetModelsParams, + GetRoutesHarnessConfigsParams, + GetRoutesParams, + GetRoutesUsageParams, + GetSandboxParams, + GetTeamsLoopsRunsParams, + GetTeamsLoopsSamplersParams, + GetTeamsModelsParams, + GetTeamsParams, GetTrainingGpuCapacityResponse, GetTrainingJobCheckpointFilesResponse, GetTrainingJobCheckpointsResponse, @@ -121,15 +146,18 @@ GetTrainingJobQueueContextResponse, GetTrainingJobResponse, GetTrainingProjectResponse, - GetTrainingProjectsJobsCheckpointFilesRequest, - GetTrainingProjectsJobsLogsRequest, - GetTrainingProjectsJobsMetricsRequest, - GetUsersRequest, - GetVolumesNamespacesRequest, - GetVolumesRequest, - GetVolumesVersionsRequest, + GetTrainingProjectsJobsCheckpointFilesParams, + GetTrainingProjectsJobsLogsParams, + GetTrainingProjectsJobsMetricsParams, + GetUsersParams, + GetVolumesNamespacesParams, + GetVolumesParams, + GetVolumesSyncsParams, + GetVolumesVersionsParams, Group, GroupsResponse, + Image, + ImageBuildLogsResponse, InstanceTypePrices, InstanceTypes, KeysForGroupResponse, @@ -140,10 +168,18 @@ LibraryListingVersions, LibraryListingVersionTombstone, ListAuditLogsResponse, + ListImagesParams, + ListImagesResponse, + ListImageTagsParams, + ListImageTagsResponse, ListLoopsCheckpointsResponse, ListLoopsDeploymentsResponse, ListLoopsRunsResponse, ListLoopsSamplersResponse, + ListSandboxesParams, + ListSandboxesResponse, + ListSandboxLibraryImagesParams, + ListSandboxLibraryImagesResponse, ListTrainingJobsResponse, ListTrainingProjectsResponse, ListVolumeNamespacesResponse, @@ -151,6 +187,7 @@ ListVolumeVersionsResponse, LLMModelHandle, LoopsCheckpointFilesResponse, + LoopsCheckpointSourceResponse, LoopsDebugArchiveFilesResponse, Model, ModelAPI, @@ -171,6 +208,9 @@ PromoteRequest, PromoteToChainEnvironmentRequest, PromoteToEnvironmentRequest, + PushImageParams, + PushImageRequest, + PushImageResponse, RecreateTrainingJobResponse, Regions, RegisterAPIKeyRequest, @@ -179,11 +219,21 @@ RestoreVolumeVersionRequest, RestoreVolumeVersionResponse, RetryDeploymentResponse, + Route, + RouteHarnessConfig, + RouteHarnessConfigsResponse, + RouteHarnessConfigTombstone, + RouteSpendLimit, + RoutesResponse, + RoutesUsageResponse, + RouteTombstone, + Sandbox, SearchTrainingJobsRequest, SearchTrainingJobsResponse, Secret, Secrets, SecretTombstone, + SetRouteHarnessConfigRequest, SignalPromotionResponse, SignSSHCertificateRequest, SignSSHCertificateResponse, @@ -194,6 +244,8 @@ Team, Teams, TerminateReplicaResponse, + Token, + ToolCallUsageResponse, TrainingJobTombstone, TrainingProjectTombstone, UpdateAutoscalingSettings, @@ -211,7 +263,13 @@ UpdateGroupRequest, UpdateLibraryListingRequest, UpdateLibraryListingVersionRequest, + UpdateModelRequest, UpdateRequestBackpressureSettings, + UpdateRouteHarnessConfigRequest, + UpdateRouteRequest, + UpdateRouteSpendLimitRequest, + UpdateSandboxParams, + UpdateSandboxRequest, UpdateTrainingJobRequest, UpdateTrainingJobResponse, UpsertSecretRequest, @@ -223,6 +281,8 @@ ValidateLoopsCheckpointRequest, ValidateLoopsCheckpointResponse, Volume, + VolumeSync, + VolumeSyncs, VolumeVersionDetail, ) @@ -245,8 +305,10 @@ class _ApiRequest: path_args: list[str] body: Any query: Any - success_code: int + success_codes: list[int] error_codes: dict[int, str] | None + body_content_type: str | None = None + accept: str | None = None class ApiClient: @@ -261,6 +323,43 @@ def __init__(self, http_client: httpx.Client) -> None: """Create a new client. The caller is responsible for closing *http_client*.""" self._http_client = http_client + def cleanup_images( + self, *, params: CleanupImagesParams | None = None + ) -> CleanupImagesResponse: + """Clean up unused images""" + return self._do_json( + CleanupImagesResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/sandboxes/cleanup_images", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def create_sandbox( + self, + *, + params: CreateSandboxParams | None = None, + request: CreateSandboxRequest, + ) -> Sandbox: + """Create a sandbox""" + return self._do_json( + Sandbox, + _ApiRequest( + method="POST", + path_fmt="/v1/sandboxes/instances", + path_args=[], + body=request, + query=params, + success_codes=[201], + error_codes=None, + ), + ) + def delete_api_keys(self, *, api_key_prefix: str) -> APIKeyTombstone: """Deletes an API key by prefix""" return self._do_json( @@ -271,7 +370,7 @@ def delete_api_keys(self, *, api_key_prefix: str) -> APIKeyTombstone: path_args=[api_key_prefix], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -286,7 +385,7 @@ def delete_chains(self, *, chain_id: str) -> ChainTombstone: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -303,7 +402,7 @@ def delete_chains_deployments( path_args=[chain_id, chain_deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -318,7 +417,45 @@ def delete_gateway_endpoints(self, *, endpoint_id: str) -> EndpointTombstone: path_args=[endpoint_id], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def delete_image( + self, *, image_name: str, params: DeleteImageParams | None = None + ) -> Image: + """Delete a sandbox image""" + return self._do_json( + Image, + _ApiRequest( + method="DELETE", + path_fmt="/v1/sandboxes/images/{}", + path_args=[image_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def delete_image_tag( + self, + *, + image_name: str, + tag_name: str, + params: DeleteImageTagParams | None = None, + ) -> Image: + """Delete an image tag""" + return self._do_json( + Image, + _ApiRequest( + method="DELETE", + path_fmt="/v1/sandboxes/images/{}/tags/{}", + path_args=[image_name, tag_name], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -335,7 +472,7 @@ def delete_library_listings( path_args=[user_defined_listing_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -352,7 +489,7 @@ def delete_library_listings_versions( path_args=[user_defined_listing_id, version_tag], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -367,7 +504,7 @@ def delete_models(self, *, model_id: str) -> ModelTombstone: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -384,7 +521,7 @@ def delete_models_deployments( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -401,7 +538,7 @@ def delete_models_deployments_replicas( path_args=[model_id, deployment_id, replica_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -418,7 +555,56 @@ def delete_models_environments( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def delete_routes(self, *, route_id: str) -> RouteTombstone: + """Deletes a route""" + return self._do_json( + RouteTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/routes/{}", + path_args=[route_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def delete_routes_harness_configs( + self, *, harness: str, params: DeleteRoutesHarnessConfigsParams + ) -> RouteHarnessConfigTombstone: + """Clears default models for a coding harness""" + return self._do_json( + RouteHarnessConfigTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/routes/harness-configs/{}", + path_args=[harness], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def delete_sandbox( + self, *, sandbox_name: str, params: DeleteSandboxParams | None = None + ) -> Sandbox: + """Delete a sandbox""" + return self._do_json( + Sandbox, + _ApiRequest( + method="DELETE", + path_fmt="/v1/sandboxes/instances/{}", + path_args=[sandbox_name], + body=None, + query=params, + success_codes=[202], error_codes=None, ), ) @@ -433,7 +619,7 @@ def delete_secrets(self, *, secret_name: str) -> SecretTombstone: path_args=[secret_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -450,7 +636,7 @@ def delete_teams_secrets( path_args=[team_id, secret_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -467,7 +653,7 @@ def delete_training_projects( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -484,7 +670,7 @@ def delete_training_projects_jobs( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -501,7 +687,7 @@ def delete_volumes( path_args=[volume_namespace, volume_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -523,12 +709,12 @@ def delete_volumes_versions( path_args=[volume_namespace, volume_name, volume_version], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - def get_api_keys(self) -> APIKeys: + def get_api_keys(self, *, params: GetApiKeysParams | None = None) -> APIKeys: """Lists API keys (metadata only, no plain text keys)""" return self._do_json( APIKeys, @@ -537,14 +723,14 @@ def get_api_keys(self) -> APIKeys: path_fmt="/v1/api_keys", path_args=[], body=None, - query=None, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_audit_logs( - self, *, request: GetAuditLogsRequest | None = None + self, *, params: GetAuditLogsParams | None = None ) -> ListAuditLogsResponse: """Gets the audit log for the workspace""" return self._do_json( @@ -554,14 +740,14 @@ def get_audit_logs( path_fmt="/v1/audit_logs", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_billing_model_apis( - self, *, request: GetBillingModelApisRequest | None = None + self, *, params: GetBillingModelApisParams | None = None ) -> ModelApisCostsResponse: """Gets daily Model APIs costs""" return self._do_json( @@ -571,14 +757,31 @@ def get_billing_model_apis( path_fmt="/v1/billing/model_apis", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_billing_tool_call_usage( + self, *, params: GetBillingToolCallUsageParams + ) -> ToolCallUsageResponse: + """Gets server-side tool call usage""" + return self._do_json( + ToolCallUsageResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/billing/tool_call_usage", + path_args=[], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) def get_billing_usage_summary( - self, *, request: GetBillingUsageSummaryRequest + self, *, params: GetBillingUsageSummaryParams ) -> UsageSummary: """Gets billing usage summary for a date range""" return self._do_json( @@ -588,8 +791,8 @@ def get_billing_usage_summary( path_fmt="/v1/billing/usage_summary", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -604,7 +807,7 @@ def get_blobs_credentials_model(self) -> GetBlobCredentialsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -619,7 +822,7 @@ def get_blobs_credentials_train(self) -> GetBlobCredentialsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -634,13 +837,13 @@ def get_chains(self) -> Chains: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) def get_chains_audit_logs( - self, *, chain_id: str, request: GetChainsAuditLogsRequest | None = None + self, *, chain_id: str, params: GetChainsAuditLogsParams | None = None ) -> ListAuditLogsResponse: """Gets the audit log for a chain""" return self._do_json( @@ -650,8 +853,8 @@ def get_chains_audit_logs( path_fmt="/v1/chains/{}/audit_logs", path_args=[chain_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -666,7 +869,7 @@ def get_chains_chain_id(self, *, chain_id: str) -> Chain: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -681,7 +884,7 @@ def get_chains_deployments(self, *, chain_id: str) -> ChainDeployments: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -698,7 +901,7 @@ def get_chains_deployments_chain_deployment_id( path_args=[chain_id, chain_deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -709,7 +912,7 @@ def get_chains_deployments_chainlets_logs( chain_id: str, chain_deployment_id: str, chainlet_id: str, - request: GetChainsDeploymentsChainletsLogsRequest | None = None, + params: GetChainsDeploymentsChainletsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a chainlet within a chain deployment""" return self._do_json( @@ -719,8 +922,8 @@ def get_chains_deployments_chainlets_logs( path_fmt="/v1/chains/{}/deployments/{}/chainlets/{}/logs", path_args=[chain_id, chain_deployment_id, chainlet_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -735,7 +938,7 @@ def get_chains_environments(self, *, chain_id: str) -> Environments: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -752,7 +955,7 @@ def get_chains_environments_env_name( path_args=[chain_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -767,7 +970,7 @@ def get_environment_groups(self) -> EnvironmentGroups: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -782,7 +985,24 @@ def get_environment_groups_env_name(self, *, env_name: str) -> EnvironmentGroup: path_args=[env_name], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def get_explore_metadata( + self, *, params: GetExploreMetadataParams | None = None + ) -> ExploreMetadataResponse: + """Lists model metadata""" + return self._do_json( + ExploreMetadataResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/explore/metadata", + path_args=[], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -797,7 +1017,7 @@ def get_gateway_endpoints(self) -> EndpointsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -812,13 +1032,13 @@ def get_gateway_endpoints_endpoint_id(self, *, endpoint_id: str) -> Endpoint: path_args=[endpoint_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) def get_gateway_events( - self, *, request: GetGatewayEventsRequest | None = None + self, *, params: GetGatewayEventsParams | None = None ) -> GatewayEventsResponse: """Lists gateway events""" return self._do_json( @@ -828,8 +1048,8 @@ def get_gateway_events( path_fmt="/v1/gateway/events", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -844,7 +1064,7 @@ def get_gateway_groups(self) -> GroupsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -859,7 +1079,7 @@ def get_gateway_groups_api_keys(self, *, group_id: str) -> KeysForGroupResponse: path_args=[group_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -876,7 +1096,7 @@ def get_gateway_groups_api_keys_api_key_prefix( path_args=[group_id, api_key_prefix], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -891,7 +1111,41 @@ def get_gateway_groups_group_id(self, *, group_id: str) -> Group: path_args=[group_id], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def get_image( + self, *, image_name: str, params: GetImageParams | None = None + ) -> Image: + """Get a sandbox image""" + return self._do_json( + Image, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images/{}", + path_args=[image_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_image_build_logs( + self, *, image_name: str, params: GetImageBuildLogsParams | None = None + ) -> ImageBuildLogsResponse: + """Get image build logs""" + return self._do_json( + ImageBuildLogsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images/{}/logs", + path_args=[image_name], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -906,7 +1160,7 @@ def get_instance_type_prices(self) -> InstanceTypePrices: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -921,7 +1175,7 @@ def get_instance_types(self) -> InstanceTypes: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -936,7 +1190,7 @@ def get_library_listings(self) -> LibraryListings: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -953,7 +1207,7 @@ def get_library_listings_user_defined_listing_id( path_args=[user_defined_listing_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -970,7 +1224,7 @@ def get_library_listings_versions( path_args=[user_defined_listing_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -987,12 +1241,14 @@ def get_library_listings_versions_version_tag( path_args=[user_defined_listing_id, version_tag], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - def get_loops_capabilities(self) -> GetLoopsCapabilitiesResponse: + def get_loops_capabilities( + self, *, params: GetLoopsCapabilitiesParams | None = None + ) -> GetLoopsCapabilitiesResponse: """Gets Loops server capabilities""" return self._do_json( GetLoopsCapabilitiesResponse, @@ -1001,14 +1257,14 @@ def get_loops_capabilities(self) -> GetLoopsCapabilitiesResponse: path_fmt="/v1/loops/capabilities", path_args=[], body=None, - query=None, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_loops_checkpoints( - self, *, request: GetLoopsCheckpointsRequest | None = None + self, *, params: GetLoopsCheckpointsParams | None = None ) -> ListLoopsCheckpointsResponse: """Lists Loops checkpoints""" return self._do_json( @@ -1018,8 +1274,8 @@ def get_loops_checkpoints( path_fmt="/v1/loops/checkpoints", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1028,7 +1284,7 @@ def get_loops_checkpoints_files( self, *, checkpoint_id: str, - request: GetLoopsCheckpointsFilesRequest | None = None, + params: GetLoopsCheckpointsFilesParams | None = None, ) -> LoopsCheckpointFilesResponse: """Gets Loops checkpoint files""" return self._do_json( @@ -1038,14 +1294,31 @@ def get_loops_checkpoints_files( path_fmt="/v1/loops/checkpoints/{}/files", path_args=[checkpoint_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_loops_checkpoints_source( + self, *, checkpoint_id: str + ) -> LoopsCheckpointSourceResponse: + """Gets where a Loops checkpoint's files come from""" + return self._do_json( + LoopsCheckpointSourceResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/loops/checkpoints/{}/source", + path_args=[checkpoint_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) def get_loops_deployments( - self, *, request: GetLoopsDeploymentsRequest | None = None + self, *, params: GetLoopsDeploymentsParams | None = None ) -> ListLoopsDeploymentsResponse: """Lists Loops deployments""" return self._do_json( @@ -1055,8 +1328,8 @@ def get_loops_deployments( path_fmt="/v1/loops/deployments", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1065,7 +1338,7 @@ def get_loops_deployments_debug_archive_files( self, *, deployment_id: str, - request: GetLoopsDeploymentsDebugArchiveFilesRequest | None = None, + params: GetLoopsDeploymentsDebugArchiveFilesParams | None = None, ) -> LoopsDebugArchiveFilesResponse: """Gets Loops debug archive files""" return self._do_json( @@ -1075,8 +1348,8 @@ def get_loops_deployments_debug_archive_files( path_fmt="/v1/loops/deployments/{}/debug_archive/files", path_args=[deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1093,16 +1366,13 @@ def get_loops_deployments_deployment_id( path_args=[deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) def get_loops_deployments_logs( - self, - *, - deployment_id: str, - request: GetLoopsDeploymentsLogsRequest | None = None, + self, *, deployment_id: str, params: GetLoopsDeploymentsLogsParams | None = None ) -> GetLogsResponse: """Gets logs for a Loops trainer deployment""" return self._do_json( @@ -1112,14 +1382,14 @@ def get_loops_deployments_logs( path_fmt="/v1/loops/deployments/{}/logs", path_args=[deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_loops_runs( - self, *, request: GetLoopsRunsRequest | None = None + self, *, params: GetLoopsRunsParams | None = None ) -> ListLoopsRunsResponse: """Lists Loops runs""" return self._do_json( @@ -1129,8 +1399,8 @@ def get_loops_runs( path_fmt="/v1/loops/runs", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1145,13 +1415,13 @@ def get_loops_runs_run_id(self, *, run_id: str) -> GetLoopsRunResponse: path_args=[run_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) def get_loops_samplers( - self, *, request: GetLoopsSamplersRequest | None = None + self, *, params: GetLoopsSamplersParams | None = None ) -> ListLoopsSamplersResponse: """Lists Loops samplers""" return self._do_json( @@ -1161,8 +1431,8 @@ def get_loops_samplers( path_fmt="/v1/loops/samplers", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1179,7 +1449,7 @@ def get_loops_samplers_sampler_id( path_args=[sampler_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1194,7 +1464,7 @@ def get_loops_sessions(self, *, session_id: str) -> GetLoopsSessionResponse: path_args=[session_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1209,13 +1479,13 @@ def get_loops_user_config(self) -> GetLoopsUserConfigResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) def get_model_apis( - self, *, request: GetModelApisRequest | None = None + self, *, params: GetModelApisParams | None = None ) -> ModelAPIsResponse: """Lists Model APIs""" return self._do_json( @@ -1225,8 +1495,8 @@ def get_model_apis( path_fmt="/v1/model_apis", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1241,13 +1511,13 @@ def get_model_apis_model_api_name(self, *, model_api_name: str) -> ModelAPI: path_args=[model_api_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) def get_model_apis_usage( - self, *, request: GetModelApisUsageRequest | None = None + self, *, params: GetModelApisUsageParams | None = None ) -> ModelApisUsageResponse: """Gets Model APIs token usage in time buckets""" return self._do_json( @@ -1257,13 +1527,13 @@ def get_model_apis_usage( path_fmt="/v1/model_apis/usage", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) - def get_models(self, *, request: GetModelsRequest | None = None) -> Models: + def get_models(self, *, params: GetModelsParams | None = None) -> Models: """Gets all models""" return self._do_json( Models, @@ -1272,14 +1542,14 @@ def get_models(self, *, request: GetModelsRequest | None = None) -> Models: path_fmt="/v1/models", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_models_audit_logs( - self, *, model_id: str, request: GetModelsAuditLogsRequest | None = None + self, *, model_id: str, params: GetModelsAuditLogsParams | None = None ) -> ListAuditLogsResponse: """Gets the audit log for a model""" return self._do_json( @@ -1289,14 +1559,14 @@ def get_models_audit_logs( path_fmt="/v1/models/{}/audit_logs", path_args=[model_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_models_deployments( - self, *, model_id: str, request: GetModelsDeploymentsRequest | None = None + self, *, model_id: str, params: GetModelsDeploymentsParams | None = None ) -> Deployments: """Gets all deployments of a model""" return self._do_json( @@ -1306,8 +1576,8 @@ def get_models_deployments( path_fmt="/v1/models/{}/deployments", path_args=[model_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1317,7 +1587,7 @@ def get_models_deployments_config( *, model_id: str, deployment_id: str, - request: GetModelsDeploymentsConfigRequest | None = None, + params: GetModelsDeploymentsConfigParams | None = None, ) -> DeploymentConfigResponse: """Gets a deployment's config""" return self._do_json( @@ -1327,8 +1597,8 @@ def get_models_deployments_config( path_fmt="/v1/models/{}/deployments/{}/config", path_args=[model_id, deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1345,7 +1615,7 @@ def get_models_deployments_deployment_id( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1360,7 +1630,7 @@ def get_models_deployments_development(self, *, model_id: str) -> Deployment: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1377,7 +1647,7 @@ def get_models_deployments_download( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1387,7 +1657,7 @@ def get_models_deployments_logs( *, model_id: str, deployment_id: str, - request: GetModelsDeploymentsLogsRequest | None = None, + params: GetModelsDeploymentsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a model deployment""" return self._do_json( @@ -1397,8 +1667,8 @@ def get_models_deployments_logs( path_fmt="/v1/models/{}/deployments/{}/logs", path_args=[model_id, deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1408,7 +1678,7 @@ def get_models_deployments_metrics( *, model_id: str, deployment_id: str, - request: GetModelsDeploymentsMetricsRequest | None = None, + params: GetModelsDeploymentsMetricsParams | None = None, ) -> GetModelMetricsResponse: """Gets the metrics for a model deployment""" return self._do_json( @@ -1418,8 +1688,8 @@ def get_models_deployments_metrics( path_fmt="/v1/models/{}/deployments/{}/metrics", path_args=[model_id, deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1436,7 +1706,7 @@ def get_models_deployments_patches_state( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1451,7 +1721,7 @@ def get_models_deployments_production(self, *, model_id: str) -> Deployment: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1466,7 +1736,7 @@ def get_models_environments(self, *, model_id: str) -> Environments: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1483,7 +1753,7 @@ def get_models_environments_env_name( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1493,7 +1763,7 @@ def get_models_environments_logs( *, model_id: str, env_name: str, - request: GetModelsEnvironmentsLogsRequest | None = None, + params: GetModelsEnvironmentsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a model environment""" return self._do_json( @@ -1503,8 +1773,8 @@ def get_models_environments_logs( path_fmt="/v1/models/{}/environments/{}/logs", path_args=[model_id, env_name], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1514,7 +1784,7 @@ def get_models_environments_metrics( *, model_id: str, env_name: str, - request: GetModelsEnvironmentsMetricsRequest | None = None, + params: GetModelsEnvironmentsMetricsParams | None = None, ) -> GetModelMetricsResponse: """Gets the metrics for a model environment.""" return self._do_json( @@ -1524,8 +1794,8 @@ def get_models_environments_metrics( path_fmt="/v1/models/{}/environments/{}/metrics", path_args=[model_id, env_name], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1540,7 +1810,7 @@ def get_models_model_id(self, *, model_id: str) -> Model: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1555,7 +1825,7 @@ def get_organizations_me(self) -> OrganizationInfo: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1570,7 +1840,103 @@ def get_regions(self) -> Regions: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def get_routes(self, *, params: GetRoutesParams | None = None) -> RoutesResponse: + """Lists routes""" + return self._do_json( + RoutesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/routes", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_routes_harness_configs( + self, *, params: GetRoutesHarnessConfigsParams + ) -> RouteHarnessConfigsResponse: + """Lists default models for coding harnesses""" + return self._do_json( + RouteHarnessConfigsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/harness-configs", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_routes_route_id(self, *, route_id: str) -> Route: + """Gets a route""" + return self._do_json( + Route, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/{}", + path_args=[route_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_routes_spend_limits(self, *, user_id: str) -> RouteSpendLimit: + """Gets a user's spend limits""" + return self._do_json( + RouteSpendLimit, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/spend_limits/{}", + path_args=[user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_routes_usage( + self, *, params: GetRoutesUsageParams | None = None + ) -> RoutesUsageResponse: + """Gets daily route usage and estimated costs""" + return self._do_json( + RoutesUsageResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/usage", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_sandbox( + self, *, sandbox_name: str, params: GetSandboxParams | None = None + ) -> Sandbox: + """Get a sandbox""" + return self._do_json( + Sandbox, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/instances/{}", + path_args=[sandbox_name], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1585,12 +1951,12 @@ def get_secrets(self) -> Secrets: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - def get_teams(self, *, request: GetTeamsRequest | None = None) -> Teams: + def get_teams(self, *, params: GetTeamsParams | None = None) -> Teams: """Lists all teams""" return self._do_json( Teams, @@ -1599,8 +1965,8 @@ def get_teams(self, *, request: GetTeamsRequest | None = None) -> Teams: path_fmt="/v1/teams", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1615,7 +1981,7 @@ def get_teams_environment_groups(self, *, team_id: str) -> EnvironmentGroups: path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1632,13 +1998,13 @@ def get_teams_environment_groups_env_name( path_args=[team_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) def get_teams_loops_runs( - self, *, team_id: str, request: GetTeamsLoopsRunsRequest | None = None + self, *, team_id: str, params: GetTeamsLoopsRunsParams | None = None ) -> ListLoopsRunsResponse: """Lists a team's Loops runs""" return self._do_json( @@ -1648,14 +2014,14 @@ def get_teams_loops_runs( path_fmt="/v1/teams/{}/loops/runs", path_args=[team_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_teams_loops_samplers( - self, *, team_id: str, request: GetTeamsLoopsSamplersRequest | None = None + self, *, team_id: str, params: GetTeamsLoopsSamplersParams | None = None ) -> ListLoopsSamplersResponse: """Lists a team's Loops samplers""" return self._do_json( @@ -1665,14 +2031,14 @@ def get_teams_loops_samplers( path_fmt="/v1/teams/{}/loops/samplers", path_args=[team_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_teams_models( - self, *, team_id: str, request: GetTeamsModelsRequest | None = None + self, *, team_id: str, params: GetTeamsModelsParams | None = None ) -> Models: """Gets all models""" return self._do_json( @@ -1682,8 +2048,8 @@ def get_teams_models( path_fmt="/v1/teams/{}/models", path_args=[team_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1698,7 +2064,7 @@ def get_teams_regions(self, *, team_id: str) -> Regions: path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1713,7 +2079,7 @@ def get_teams_secrets(self, *, team_id: str) -> Secrets: path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1728,7 +2094,7 @@ def get_teams_team_id(self, *, team_id: str) -> Team: path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1743,7 +2109,7 @@ def get_training_capacity(self) -> GetTrainingGpuCapacityResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1760,7 +2126,7 @@ def get_training_jobs_queue_context( path_args=[training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1775,7 +2141,7 @@ def get_training_projects(self) -> ListTrainingProjectsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1792,7 +2158,7 @@ def get_training_projects_cache_summary( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1809,7 +2175,7 @@ def get_training_projects_jobs( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1826,7 +2192,7 @@ def get_training_projects_jobs_auth_codes( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1836,7 +2202,7 @@ def get_training_projects_jobs_checkpoint_files( *, training_project_id: str, training_job_id: str, - request: GetTrainingProjectsJobsCheckpointFilesRequest | None = None, + params: GetTrainingProjectsJobsCheckpointFilesParams | None = None, ) -> GetTrainingJobCheckpointFilesResponse: """Gets training job checkpoint files""" return self._do_json( @@ -1846,8 +2212,8 @@ def get_training_projects_jobs_checkpoint_files( path_fmt="/v1/training_projects/{}/jobs/{}/checkpoint_files", path_args=[training_project_id, training_job_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1864,7 +2230,7 @@ def get_training_projects_jobs_checkpoints( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1881,7 +2247,7 @@ def get_training_projects_jobs_download( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1891,7 +2257,7 @@ def get_training_projects_jobs_logs( *, training_project_id: str, training_job_id: str, - request: GetTrainingProjectsJobsLogsRequest | None = None, + params: GetTrainingProjectsJobsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a training job""" return self._do_json( @@ -1901,8 +2267,8 @@ def get_training_projects_jobs_logs( path_fmt="/v1/training_projects/{}/jobs/{}/logs", path_args=[training_project_id, training_job_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1912,7 +2278,7 @@ def get_training_projects_jobs_metrics( *, training_project_id: str, training_job_id: str, - request: GetTrainingProjectsJobsMetricsRequest | None = None, + params: GetTrainingProjectsJobsMetricsParams | None = None, ) -> GetTrainingJobMetricsResponse: """Gets the metrics for a training job""" return self._do_json( @@ -1922,8 +2288,8 @@ def get_training_projects_jobs_metrics( path_fmt="/v1/training_projects/{}/jobs/{}/metrics", path_args=[training_project_id, training_job_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1940,7 +2306,7 @@ def get_training_projects_jobs_training_job_id( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -1957,12 +2323,12 @@ def get_training_projects_training_project_id( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - def get_users(self, *, request: GetUsersRequest | None = None) -> UsersResponse: + def get_users(self, *, params: GetUsersParams | None = None) -> UsersResponse: """Lists users in the workspace""" return self._do_json( UsersResponse, @@ -1971,8 +2337,8 @@ def get_users(self, *, request: GetUsersRequest | None = None) -> UsersResponse: path_fmt="/v1/users", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -1987,7 +2353,7 @@ def get_users_me(self) -> UserInfo: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2002,12 +2368,12 @@ def get_users_user_id(self, *, user_id: str) -> UserInfo: path_args=[user_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - def get_volumes(self, *, request: GetVolumesRequest) -> ListVolumesResponse: + def get_volumes(self, *, params: GetVolumesParams) -> ListVolumesResponse: """Gets the volumes in a namespace""" return self._do_json( ListVolumesResponse, @@ -2016,14 +2382,14 @@ def get_volumes(self, *, request: GetVolumesRequest) -> ListVolumesResponse: path_fmt="/v1/volumes", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) def get_volumes_namespaces( - self, *, request: GetVolumesNamespacesRequest | None = None + self, *, params: GetVolumesNamespacesParams | None = None ) -> ListVolumeNamespacesResponse: """Gets the volume namespaces in your workspace""" return self._do_json( @@ -2033,8 +2399,40 @@ def get_volumes_namespaces( path_fmt="/v1/volumes/namespaces", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_volumes_syncs( + self, *, params: GetVolumesSyncsParams | None = None + ) -> VolumeSyncs: + """Lists volume syncs""" + return self._do_json( + VolumeSyncs, + _ApiRequest( + method="GET", + path_fmt="/v1/volumes/syncs", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_volumes_syncs_volume_sync_id(self, *, volume_sync_id: str) -> VolumeSync: + """Gets a volume sync""" + return self._do_json( + VolumeSync, + _ApiRequest( + method="GET", + path_fmt="/v1/volumes/syncs/{}", + path_args=[volume_sync_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -2044,7 +2442,7 @@ def get_volumes_versions( *, volume_namespace: str, volume_name: str, - request: GetVolumesVersionsRequest | None = None, + params: GetVolumesVersionsParams | None = None, ) -> ListVolumeVersionsResponse: """Gets the versions of a volume""" return self._do_json( @@ -2054,8 +2452,8 @@ def get_volumes_versions( path_fmt="/v1/volumes/{}/{}/versions", path_args=[volume_namespace, volume_name], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -2072,7 +2470,7 @@ def get_volumes_versions_volume_version( path_args=[volume_namespace, volume_name, volume_version], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2089,7 +2487,75 @@ def get_volumes_volume_name( path_args=[volume_namespace, volume_name], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def list_image_tags( + self, *, image_name: str, params: ListImageTagsParams | None = None + ) -> ListImageTagsResponse: + """List image tags""" + return self._do_json( + ListImageTagsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images/{}/tags", + path_args=[image_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def list_images( + self, *, params: ListImagesParams | None = None + ) -> ListImagesResponse: + """List sandbox images""" + return self._do_json( + ListImagesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def list_sandbox_library_images( + self, *, params: ListSandboxLibraryImagesParams | None = None + ) -> ListSandboxLibraryImagesResponse: + """List built-in sandbox images""" + return self._do_json( + ListSandboxLibraryImagesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/library_images", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def list_sandboxes( + self, *, params: ListSandboxesParams | None = None + ) -> ListSandboxesResponse: + """List sandboxes""" + return self._do_json( + ListSandboxesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/instances", + path_args=[], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -2106,7 +2572,7 @@ def patch_chains_environments( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2127,7 +2593,7 @@ def patch_chains_environments_chainlet_settings_autoscaling_settings( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2144,7 +2610,7 @@ def patch_environment_groups( path_args=[env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2161,7 +2627,7 @@ def patch_gateway_endpoints( path_args=[endpoint_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2178,7 +2644,7 @@ def patch_gateway_groups( path_args=[group_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2195,7 +2661,7 @@ def patch_library_listings( path_args=[user_defined_listing_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2216,7 +2682,7 @@ def patch_library_listings_versions( path_args=[user_defined_listing_id, version_tag], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2233,7 +2699,22 @@ def patch_loops_user_config( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def patch_models(self, *, model_id: str, request: UpdateModelRequest) -> Model: + """Updates a model by ID""" + return self._do_json( + Model, + _ApiRequest( + method="PATCH", + path_fmt="/v1/models/{}", + path_args=[model_id], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -2250,7 +2731,7 @@ def patch_models_deployments( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2267,7 +2748,7 @@ def patch_models_deployments_autoscaling_settings( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2284,7 +2765,7 @@ def patch_models_deployments_development_autoscaling_settings( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2301,7 +2782,7 @@ def patch_models_deployments_production_autoscaling_settings( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2322,7 +2803,7 @@ def patch_models_deployments_request_backpressure_settings( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2339,7 +2820,56 @@ def patch_models_environments( path_args=[model_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def patch_routes(self, *, route_id: str, request: UpdateRouteRequest) -> Route: + """Updates a route's display name or description""" + return self._do_json( + Route, + _ApiRequest( + method="PATCH", + path_fmt="/v1/routes/{}", + path_args=[route_id], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def patch_routes_harness_configs( + self, *, request: UpdateRouteHarnessConfigRequest + ) -> RouteHarnessConfig: + """Updates default models for a coding harness""" + return self._do_json( + RouteHarnessConfig, + _ApiRequest( + method="PATCH", + path_fmt="/v1/routes/harness-configs", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def patch_routes_spend_limits( + self, *, user_id: str, request: UpdateRouteSpendLimitRequest + ) -> RouteSpendLimit: + """Updates a user's spend limits""" + return self._do_json( + RouteSpendLimit, + _ApiRequest( + method="PATCH", + path_fmt="/v1/routes/spend_limits/{}", + path_args=[user_id], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -2356,7 +2886,7 @@ def patch_teams_environment_groups( path_args=[team_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2373,7 +2903,7 @@ def patch_training_capacity( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2394,7 +2924,7 @@ def patch_training_projects_jobs( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2416,7 +2946,7 @@ def patch_training_projects_jobs_interactive_sessions( path_args=[training_project_id, training_job_id, session_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2431,7 +2961,7 @@ def post_api_keys(self, *, request: CreateAPIKeyRequest) -> APIKey: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2448,7 +2978,7 @@ def post_chains_deployments_deactivate( path_args=[chain_id, chain_deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2465,7 +2995,7 @@ def post_chains_environments( path_args=[chain_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2486,7 +3016,7 @@ def post_chains_environments_chainlet_settings_instance_types_update( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2503,7 +3033,7 @@ def post_chains_environments_promote( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2518,7 +3048,7 @@ def post_gateway_endpoints(self, *, request: CreateEndpointRequest) -> Endpoint: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2533,7 +3063,7 @@ def post_gateway_groups(self, *, request: CreateGroupRequest) -> Group: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2550,7 +3080,7 @@ def post_gateway_groups_api_keys( path_args=[group_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2567,7 +3097,7 @@ def post_gateway_groups_api_keys_register( path_args=[group_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2584,7 +3114,7 @@ def post_library_listings( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2604,7 +3134,7 @@ def post_library_listings_versions( path_args=[user_defined_listing_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2619,7 +3149,7 @@ def post_llm_models(self, *, request: CreateLLMModelRequest) -> LLMModelHandle: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2636,7 +3166,24 @@ def post_llm_models_deployments( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def post_loops_checkpoints_deploy( + self, *, request: DeployLoopsCheckpointRequest + ) -> DeployLoopsCheckpointResponse: + """Deploys Loops checkpoints""" + return self._do_json( + DeployLoopsCheckpointResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/loops/checkpoints/deploy", + path_args=[], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -2653,7 +3200,7 @@ def post_loops_checkpoints_validate( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2670,7 +3217,7 @@ def post_loops_deployments_deactivate( path_args=[deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2687,7 +3234,7 @@ def post_loops_deployments_metrics( path_args=[deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2704,7 +3251,7 @@ def post_loops_runs( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2719,7 +3266,7 @@ def post_loops_runs_deactivate(self, *, run_id: str) -> DeactivateLoopsRunRespon path_args=[run_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2736,7 +3283,24 @@ def post_loops_samplers( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def post_loops_samplers_deactivate( + self, *, sampler_id: str + ) -> DeactivateLoopsSamplerResponse: + """Deactivates a standalone Loops sampler""" + return self._do_json( + DeactivateLoopsSamplerResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/loops/samplers/{}/deactivate", + path_args=[sampler_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -2751,7 +3315,7 @@ def post_loops_sessions(self) -> CreateLoopsSessionResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2768,7 +3332,7 @@ def post_loops_trainers( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2783,7 +3347,7 @@ def post_models(self, *, request: CreateModelRequest) -> CreatedModelDeployment: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2800,7 +3364,7 @@ def post_models_deployments( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2817,7 +3381,7 @@ def post_models_deployments_activate( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2834,7 +3398,7 @@ def post_models_deployments_deactivate( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2851,7 +3415,7 @@ def post_models_deployments_development_activate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2868,7 +3432,7 @@ def post_models_deployments_development_deactivate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2885,7 +3449,7 @@ def post_models_deployments_development_promote( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2902,7 +3466,7 @@ def post_models_deployments_development_retry( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2919,7 +3483,7 @@ def post_models_deployments_logs( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2940,7 +3504,7 @@ def post_models_deployments_patches( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2961,7 +3525,7 @@ def post_models_deployments_patches_sync( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2978,7 +3542,7 @@ def post_models_deployments_production_activate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -2995,7 +3559,7 @@ def post_models_deployments_production_deactivate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3012,7 +3576,7 @@ def post_models_deployments_production_retry( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3029,7 +3593,7 @@ def post_models_deployments_promote( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3046,7 +3610,7 @@ def post_models_deployments_retry( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3063,7 +3627,7 @@ def post_models_deployments_ssh_sign( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3080,7 +3644,7 @@ def post_models_environments( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3097,7 +3661,7 @@ def post_models_environments_activate( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3114,7 +3678,7 @@ def post_models_environments_cancel_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3131,7 +3695,7 @@ def post_models_environments_deactivate( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3148,7 +3712,7 @@ def post_models_environments_force_cancel_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3165,7 +3729,7 @@ def post_models_environments_force_roll_forward_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3182,7 +3746,7 @@ def post_models_environments_pause_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3199,7 +3763,7 @@ def post_models_environments_promote( path_args=[model_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3216,7 +3780,7 @@ def post_models_environments_resume_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3233,7 +3797,22 @@ def post_prepare_model_upload( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def post_routes(self, *, request: CreateRouteRequest) -> Route: + """Creates a route""" + return self._do_json( + Route, + _ApiRequest( + method="POST", + path_fmt="/v1/routes", + path_args=[], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -3248,7 +3827,7 @@ def post_secrets(self, *, request: UpsertSecretRequest) -> Secret: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3265,7 +3844,7 @@ def post_teams_api_keys( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3282,7 +3861,7 @@ def post_teams_llm_models( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3299,7 +3878,7 @@ def post_teams_loops_runs( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3316,7 +3895,7 @@ def post_teams_loops_samplers( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3331,7 +3910,7 @@ def post_teams_loops_sessions(self, *, team_id: str) -> CreateLoopsSessionRespon path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3348,7 +3927,7 @@ def post_teams_loops_trainers( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3365,7 +3944,7 @@ def post_teams_models( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3382,7 +3961,7 @@ def post_teams_secrets( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3399,7 +3978,22 @@ def post_teams_training_projects( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def post_token(self, *, request: CreateTokenRequest) -> Token: + """Creates a sandbox access token""" + return self._do_json( + Token, + _ApiRequest( + method="POST", + path_fmt="/v1/token", + path_args=[], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -3416,7 +4010,7 @@ def post_training_jobs_search( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3433,7 +4027,7 @@ def post_training_projects( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3450,7 +4044,7 @@ def post_training_projects_jobs( path_args=[training_project_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3471,7 +4065,7 @@ def post_training_projects_jobs_logs( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3492,7 +4086,7 @@ def post_training_projects_jobs_metrics( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3509,7 +4103,7 @@ def post_training_projects_jobs_recreate( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3530,7 +4124,7 @@ def post_training_projects_jobs_ssh_sign( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3551,7 +4145,37 @@ def post_training_projects_jobs_stop( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + def post_volumes_syncs(self, *, request: CreateVolumeSyncRequest) -> VolumeSync: + """Starts a volume sync""" + return self._do_json( + VolumeSync, + _ApiRequest( + method="POST", + path_fmt="/v1/volumes/syncs", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def post_volumes_syncs_cancel(self, *, volume_sync_id: str) -> VolumeSync: + """Cancels a volume sync""" + return self._do_json( + VolumeSync, + _ApiRequest( + method="POST", + path_fmt="/v1/volumes/syncs/{}/cancel", + path_args=[volume_sync_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -3568,7 +4192,7 @@ def post_volumes_token( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3581,7 +4205,7 @@ def post_volumes_versions_restore( volume_version: str, request: RestoreVolumeVersionRequest, ) -> RestoreVolumeVersionResponse: - """Restores a deleted version of a volume""" + """Restores a deleted or expired version of a volume""" return self._do_json( RestoreVolumeVersionResponse, _ApiRequest( @@ -3590,38 +4214,118 @@ def post_volumes_versions_restore( path_args=[volume_namespace, volume_name, volume_version], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - def _do(self, request: _ApiRequest) -> httpx.Response: + def push_image( + self, *, params: PushImageParams | None = None, request: PushImageRequest + ) -> PushImageResponse: + """Push a sandbox image""" + return self._do_json( + PushImageResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/sandboxes/images", + path_args=[], + body=request, + query=params, + success_codes=[202], + error_codes=None, + ), + ) + + def put_routes_harness_configs( + self, *, request: SetRouteHarnessConfigRequest + ) -> RouteHarnessConfig: + """Sets default models for a coding harness""" + return self._do_json( + RouteHarnessConfig, + _ApiRequest( + method="PUT", + path_fmt="/v1/routes/harness-configs", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def update_sandbox( + self, + *, + sandbox_name: str, + params: UpdateSandboxParams | None = None, + request: UpdateSandboxRequest, + ) -> Sandbox: + """Update a sandbox""" + return self._do_json( + Sandbox, + _ApiRequest( + method="PATCH", + path_fmt="/v1/sandboxes/instances/{}", + path_args=[sandbox_name], + body=request, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def _build_request(self, request: _ApiRequest) -> httpx.Request: path = request.path_fmt.format( *[urllib.parse.quote(a, safe="") for a in request.path_args] ) json_body = None + content_body = None + files_body = None + headers: dict[str, str] = {} + if request.accept is not None: + headers["Accept"] = request.accept if request.body is not None: - if isinstance(request.body, BaseModel): - # Only fields the caller set are sent, so unset fields fall - # back to the server default rather than being reset here. - # An explicit None is kept, since null can mean "clear". - json_body = request.body.model_dump(mode="json", exclude_unset=True) + if request.body_content_type is None: + if isinstance(request.body, BaseModel): + # Only fields the caller set are sent, so unset fields fall + # back to the server default rather than being reset here. + # An explicit None is kept, since null can mean "clear". + # by_alias: a field renamed for Python (e.g. async_ for + # "async") must serialize under its API name. + json_body = request.body.model_dump( + mode="json", exclude_unset=True, by_alias=True + ) + else: + json_body = request.body + elif request.body_content_type == "multipart/form-data": + # httpx derives the multipart Content-Type, boundary included. + files_body = request.body else: - json_body = request.body + headers["Content-Type"] = request.body_content_type + content_body = request.body params = None if request.query is not None: if isinstance(request.query, BaseModel): # As above, plus dropping None: a null query parameter is # meaningless and would otherwise serialize as an empty string. params = request.query.model_dump( - mode="json", exclude_unset=True, exclude_none=True + mode="json", exclude_unset=True, exclude_none=True, by_alias=True ) else: params = request.query - response = self._http_client.request( - request.method, path, json=json_body, params=params + return self._http_client.build_request( + request.method, + path, + json=json_body, + content=content_body, + files=files_body, + params=params, + headers=headers, ) - if response.status_code != request.success_code: + + def _do(self, request: _ApiRequest) -> httpx.Response: + response = self._http_client.send(self._build_request(request)) + if response.status_code not in request.success_codes: raise ResponseError(status_code=response.status_code, body=response.text) return response @@ -3647,6 +4351,43 @@ def __init__(self, http_client: httpx.AsyncClient) -> None: """Create a new client. The caller is responsible for closing *http_client*.""" self._http_client = http_client + async def cleanup_images( + self, *, params: CleanupImagesParams | None = None + ) -> CleanupImagesResponse: + """Clean up unused images""" + return await self._do_json( + CleanupImagesResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/sandboxes/cleanup_images", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def create_sandbox( + self, + *, + params: CreateSandboxParams | None = None, + request: CreateSandboxRequest, + ) -> Sandbox: + """Create a sandbox""" + return await self._do_json( + Sandbox, + _ApiRequest( + method="POST", + path_fmt="/v1/sandboxes/instances", + path_args=[], + body=request, + query=params, + success_codes=[201], + error_codes=None, + ), + ) + async def delete_api_keys(self, *, api_key_prefix: str) -> APIKeyTombstone: """Deletes an API key by prefix""" return await self._do_json( @@ -3657,7 +4398,7 @@ async def delete_api_keys(self, *, api_key_prefix: str) -> APIKeyTombstone: path_args=[api_key_prefix], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3672,7 +4413,7 @@ async def delete_chains(self, *, chain_id: str) -> ChainTombstone: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3689,7 +4430,7 @@ async def delete_chains_deployments( path_args=[chain_id, chain_deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3704,7 +4445,45 @@ async def delete_gateway_endpoints(self, *, endpoint_id: str) -> EndpointTombsto path_args=[endpoint_id], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def delete_image( + self, *, image_name: str, params: DeleteImageParams | None = None + ) -> Image: + """Delete a sandbox image""" + return await self._do_json( + Image, + _ApiRequest( + method="DELETE", + path_fmt="/v1/sandboxes/images/{}", + path_args=[image_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def delete_image_tag( + self, + *, + image_name: str, + tag_name: str, + params: DeleteImageTagParams | None = None, + ) -> Image: + """Delete an image tag""" + return await self._do_json( + Image, + _ApiRequest( + method="DELETE", + path_fmt="/v1/sandboxes/images/{}/tags/{}", + path_args=[image_name, tag_name], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -3721,7 +4500,7 @@ async def delete_library_listings( path_args=[user_defined_listing_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3738,7 +4517,7 @@ async def delete_library_listings_versions( path_args=[user_defined_listing_id, version_tag], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3753,7 +4532,7 @@ async def delete_models(self, *, model_id: str) -> ModelTombstone: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3770,7 +4549,7 @@ async def delete_models_deployments( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3787,7 +4566,7 @@ async def delete_models_deployments_replicas( path_args=[model_id, deployment_id, replica_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3804,7 +4583,56 @@ async def delete_models_environments( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def delete_routes(self, *, route_id: str) -> RouteTombstone: + """Deletes a route""" + return await self._do_json( + RouteTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/routes/{}", + path_args=[route_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def delete_routes_harness_configs( + self, *, harness: str, params: DeleteRoutesHarnessConfigsParams + ) -> RouteHarnessConfigTombstone: + """Clears default models for a coding harness""" + return await self._do_json( + RouteHarnessConfigTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/routes/harness-configs/{}", + path_args=[harness], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def delete_sandbox( + self, *, sandbox_name: str, params: DeleteSandboxParams | None = None + ) -> Sandbox: + """Delete a sandbox""" + return await self._do_json( + Sandbox, + _ApiRequest( + method="DELETE", + path_fmt="/v1/sandboxes/instances/{}", + path_args=[sandbox_name], + body=None, + query=params, + success_codes=[202], error_codes=None, ), ) @@ -3819,7 +4647,7 @@ async def delete_secrets(self, *, secret_name: str) -> SecretTombstone: path_args=[secret_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3836,7 +4664,7 @@ async def delete_teams_secrets( path_args=[team_id, secret_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3853,7 +4681,7 @@ async def delete_training_projects( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3870,7 +4698,7 @@ async def delete_training_projects_jobs( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3887,7 +4715,7 @@ async def delete_volumes( path_args=[volume_namespace, volume_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -3909,12 +4737,12 @@ async def delete_volumes_versions( path_args=[volume_namespace, volume_name, volume_version], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - async def get_api_keys(self) -> APIKeys: + async def get_api_keys(self, *, params: GetApiKeysParams | None = None) -> APIKeys: """Lists API keys (metadata only, no plain text keys)""" return await self._do_json( APIKeys, @@ -3923,14 +4751,14 @@ async def get_api_keys(self) -> APIKeys: path_fmt="/v1/api_keys", path_args=[], body=None, - query=None, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_audit_logs( - self, *, request: GetAuditLogsRequest | None = None + self, *, params: GetAuditLogsParams | None = None ) -> ListAuditLogsResponse: """Gets the audit log for the workspace""" return await self._do_json( @@ -3940,14 +4768,14 @@ async def get_audit_logs( path_fmt="/v1/audit_logs", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_billing_model_apis( - self, *, request: GetBillingModelApisRequest | None = None + self, *, params: GetBillingModelApisParams | None = None ) -> ModelApisCostsResponse: """Gets daily Model APIs costs""" return await self._do_json( @@ -3957,14 +4785,31 @@ async def get_billing_model_apis( path_fmt="/v1/billing/model_apis", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_billing_tool_call_usage( + self, *, params: GetBillingToolCallUsageParams + ) -> ToolCallUsageResponse: + """Gets server-side tool call usage""" + return await self._do_json( + ToolCallUsageResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/billing/tool_call_usage", + path_args=[], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_billing_usage_summary( - self, *, request: GetBillingUsageSummaryRequest + self, *, params: GetBillingUsageSummaryParams ) -> UsageSummary: """Gets billing usage summary for a date range""" return await self._do_json( @@ -3974,8 +4819,8 @@ async def get_billing_usage_summary( path_fmt="/v1/billing/usage_summary", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -3990,7 +4835,7 @@ async def get_blobs_credentials_model(self) -> GetBlobCredentialsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4005,7 +4850,7 @@ async def get_blobs_credentials_train(self) -> GetBlobCredentialsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4020,13 +4865,13 @@ async def get_chains(self) -> Chains: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) async def get_chains_audit_logs( - self, *, chain_id: str, request: GetChainsAuditLogsRequest | None = None + self, *, chain_id: str, params: GetChainsAuditLogsParams | None = None ) -> ListAuditLogsResponse: """Gets the audit log for a chain""" return await self._do_json( @@ -4036,8 +4881,8 @@ async def get_chains_audit_logs( path_fmt="/v1/chains/{}/audit_logs", path_args=[chain_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4052,7 +4897,7 @@ async def get_chains_chain_id(self, *, chain_id: str) -> Chain: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4067,7 +4912,7 @@ async def get_chains_deployments(self, *, chain_id: str) -> ChainDeployments: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4084,7 +4929,7 @@ async def get_chains_deployments_chain_deployment_id( path_args=[chain_id, chain_deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4095,7 +4940,7 @@ async def get_chains_deployments_chainlets_logs( chain_id: str, chain_deployment_id: str, chainlet_id: str, - request: GetChainsDeploymentsChainletsLogsRequest | None = None, + params: GetChainsDeploymentsChainletsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a chainlet within a chain deployment""" return await self._do_json( @@ -4105,8 +4950,8 @@ async def get_chains_deployments_chainlets_logs( path_fmt="/v1/chains/{}/deployments/{}/chainlets/{}/logs", path_args=[chain_id, chain_deployment_id, chainlet_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4121,7 +4966,7 @@ async def get_chains_environments(self, *, chain_id: str) -> Environments: path_args=[chain_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4138,7 +4983,7 @@ async def get_chains_environments_env_name( path_args=[chain_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4153,7 +4998,7 @@ async def get_environment_groups(self) -> EnvironmentGroups: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4170,7 +5015,24 @@ async def get_environment_groups_env_name( path_args=[env_name], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_explore_metadata( + self, *, params: GetExploreMetadataParams | None = None + ) -> ExploreMetadataResponse: + """Lists model metadata""" + return await self._do_json( + ExploreMetadataResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/explore/metadata", + path_args=[], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4185,7 +5047,7 @@ async def get_gateway_endpoints(self) -> EndpointsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4200,13 +5062,13 @@ async def get_gateway_endpoints_endpoint_id(self, *, endpoint_id: str) -> Endpoi path_args=[endpoint_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) async def get_gateway_events( - self, *, request: GetGatewayEventsRequest | None = None + self, *, params: GetGatewayEventsParams | None = None ) -> GatewayEventsResponse: """Lists gateway events""" return await self._do_json( @@ -4216,8 +5078,8 @@ async def get_gateway_events( path_fmt="/v1/gateway/events", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4232,7 +5094,7 @@ async def get_gateway_groups(self) -> GroupsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4249,7 +5111,7 @@ async def get_gateway_groups_api_keys( path_args=[group_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4266,7 +5128,7 @@ async def get_gateway_groups_api_keys_api_key_prefix( path_args=[group_id, api_key_prefix], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4277,11 +5139,45 @@ async def get_gateway_groups_group_id(self, *, group_id: str) -> Group: Group, _ApiRequest( method="GET", - path_fmt="/v1/gateway/groups/{}", - path_args=[group_id], + path_fmt="/v1/gateway/groups/{}", + path_args=[group_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_image( + self, *, image_name: str, params: GetImageParams | None = None + ) -> Image: + """Get a sandbox image""" + return await self._do_json( + Image, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images/{}", + path_args=[image_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_image_build_logs( + self, *, image_name: str, params: GetImageBuildLogsParams | None = None + ) -> ImageBuildLogsResponse: + """Get image build logs""" + return await self._do_json( + ImageBuildLogsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images/{}/logs", + path_args=[image_name], body=None, - query=None, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4296,7 +5192,7 @@ async def get_instance_type_prices(self) -> InstanceTypePrices: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4311,7 +5207,7 @@ async def get_instance_types(self) -> InstanceTypes: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4326,7 +5222,7 @@ async def get_library_listings(self) -> LibraryListings: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4343,7 +5239,7 @@ async def get_library_listings_user_defined_listing_id( path_args=[user_defined_listing_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4360,7 +5256,7 @@ async def get_library_listings_versions( path_args=[user_defined_listing_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4377,12 +5273,14 @@ async def get_library_listings_versions_version_tag( path_args=[user_defined_listing_id, version_tag], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - async def get_loops_capabilities(self) -> GetLoopsCapabilitiesResponse: + async def get_loops_capabilities( + self, *, params: GetLoopsCapabilitiesParams | None = None + ) -> GetLoopsCapabilitiesResponse: """Gets Loops server capabilities""" return await self._do_json( GetLoopsCapabilitiesResponse, @@ -4391,14 +5289,14 @@ async def get_loops_capabilities(self) -> GetLoopsCapabilitiesResponse: path_fmt="/v1/loops/capabilities", path_args=[], body=None, - query=None, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_loops_checkpoints( - self, *, request: GetLoopsCheckpointsRequest | None = None + self, *, params: GetLoopsCheckpointsParams | None = None ) -> ListLoopsCheckpointsResponse: """Lists Loops checkpoints""" return await self._do_json( @@ -4408,8 +5306,8 @@ async def get_loops_checkpoints( path_fmt="/v1/loops/checkpoints", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4418,7 +5316,7 @@ async def get_loops_checkpoints_files( self, *, checkpoint_id: str, - request: GetLoopsCheckpointsFilesRequest | None = None, + params: GetLoopsCheckpointsFilesParams | None = None, ) -> LoopsCheckpointFilesResponse: """Gets Loops checkpoint files""" return await self._do_json( @@ -4428,14 +5326,31 @@ async def get_loops_checkpoints_files( path_fmt="/v1/loops/checkpoints/{}/files", path_args=[checkpoint_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_loops_checkpoints_source( + self, *, checkpoint_id: str + ) -> LoopsCheckpointSourceResponse: + """Gets where a Loops checkpoint's files come from""" + return await self._do_json( + LoopsCheckpointSourceResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/loops/checkpoints/{}/source", + path_args=[checkpoint_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) async def get_loops_deployments( - self, *, request: GetLoopsDeploymentsRequest | None = None + self, *, params: GetLoopsDeploymentsParams | None = None ) -> ListLoopsDeploymentsResponse: """Lists Loops deployments""" return await self._do_json( @@ -4445,8 +5360,8 @@ async def get_loops_deployments( path_fmt="/v1/loops/deployments", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4455,7 +5370,7 @@ async def get_loops_deployments_debug_archive_files( self, *, deployment_id: str, - request: GetLoopsDeploymentsDebugArchiveFilesRequest | None = None, + params: GetLoopsDeploymentsDebugArchiveFilesParams | None = None, ) -> LoopsDebugArchiveFilesResponse: """Gets Loops debug archive files""" return await self._do_json( @@ -4465,8 +5380,8 @@ async def get_loops_deployments_debug_archive_files( path_fmt="/v1/loops/deployments/{}/debug_archive/files", path_args=[deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4483,16 +5398,13 @@ async def get_loops_deployments_deployment_id( path_args=[deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) async def get_loops_deployments_logs( - self, - *, - deployment_id: str, - request: GetLoopsDeploymentsLogsRequest | None = None, + self, *, deployment_id: str, params: GetLoopsDeploymentsLogsParams | None = None ) -> GetLogsResponse: """Gets logs for a Loops trainer deployment""" return await self._do_json( @@ -4502,14 +5414,14 @@ async def get_loops_deployments_logs( path_fmt="/v1/loops/deployments/{}/logs", path_args=[deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_loops_runs( - self, *, request: GetLoopsRunsRequest | None = None + self, *, params: GetLoopsRunsParams | None = None ) -> ListLoopsRunsResponse: """Lists Loops runs""" return await self._do_json( @@ -4519,8 +5431,8 @@ async def get_loops_runs( path_fmt="/v1/loops/runs", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4535,13 +5447,13 @@ async def get_loops_runs_run_id(self, *, run_id: str) -> GetLoopsRunResponse: path_args=[run_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) async def get_loops_samplers( - self, *, request: GetLoopsSamplersRequest | None = None + self, *, params: GetLoopsSamplersParams | None = None ) -> ListLoopsSamplersResponse: """Lists Loops samplers""" return await self._do_json( @@ -4551,8 +5463,8 @@ async def get_loops_samplers( path_fmt="/v1/loops/samplers", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4569,7 +5481,7 @@ async def get_loops_samplers_sampler_id( path_args=[sampler_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4584,7 +5496,7 @@ async def get_loops_sessions(self, *, session_id: str) -> GetLoopsSessionRespons path_args=[session_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4599,13 +5511,13 @@ async def get_loops_user_config(self) -> GetLoopsUserConfigResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) async def get_model_apis( - self, *, request: GetModelApisRequest | None = None + self, *, params: GetModelApisParams | None = None ) -> ModelAPIsResponse: """Lists Model APIs""" return await self._do_json( @@ -4615,8 +5527,8 @@ async def get_model_apis( path_fmt="/v1/model_apis", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4631,13 +5543,13 @@ async def get_model_apis_model_api_name(self, *, model_api_name: str) -> ModelAP path_args=[model_api_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) async def get_model_apis_usage( - self, *, request: GetModelApisUsageRequest | None = None + self, *, params: GetModelApisUsageParams | None = None ) -> ModelApisUsageResponse: """Gets Model APIs token usage in time buckets""" return await self._do_json( @@ -4647,13 +5559,13 @@ async def get_model_apis_usage( path_fmt="/v1/model_apis/usage", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) - async def get_models(self, *, request: GetModelsRequest | None = None) -> Models: + async def get_models(self, *, params: GetModelsParams | None = None) -> Models: """Gets all models""" return await self._do_json( Models, @@ -4662,14 +5574,14 @@ async def get_models(self, *, request: GetModelsRequest | None = None) -> Models path_fmt="/v1/models", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_models_audit_logs( - self, *, model_id: str, request: GetModelsAuditLogsRequest | None = None + self, *, model_id: str, params: GetModelsAuditLogsParams | None = None ) -> ListAuditLogsResponse: """Gets the audit log for a model""" return await self._do_json( @@ -4679,14 +5591,14 @@ async def get_models_audit_logs( path_fmt="/v1/models/{}/audit_logs", path_args=[model_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_models_deployments( - self, *, model_id: str, request: GetModelsDeploymentsRequest | None = None + self, *, model_id: str, params: GetModelsDeploymentsParams | None = None ) -> Deployments: """Gets all deployments of a model""" return await self._do_json( @@ -4696,8 +5608,8 @@ async def get_models_deployments( path_fmt="/v1/models/{}/deployments", path_args=[model_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4707,7 +5619,7 @@ async def get_models_deployments_config( *, model_id: str, deployment_id: str, - request: GetModelsDeploymentsConfigRequest | None = None, + params: GetModelsDeploymentsConfigParams | None = None, ) -> DeploymentConfigResponse: """Gets a deployment's config""" return await self._do_json( @@ -4717,8 +5629,8 @@ async def get_models_deployments_config( path_fmt="/v1/models/{}/deployments/{}/config", path_args=[model_id, deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4735,7 +5647,7 @@ async def get_models_deployments_deployment_id( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4750,7 +5662,7 @@ async def get_models_deployments_development(self, *, model_id: str) -> Deployme path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4767,7 +5679,7 @@ async def get_models_deployments_download( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4777,7 +5689,7 @@ async def get_models_deployments_logs( *, model_id: str, deployment_id: str, - request: GetModelsDeploymentsLogsRequest | None = None, + params: GetModelsDeploymentsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a model deployment""" return await self._do_json( @@ -4787,8 +5699,8 @@ async def get_models_deployments_logs( path_fmt="/v1/models/{}/deployments/{}/logs", path_args=[model_id, deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4798,7 +5710,7 @@ async def get_models_deployments_metrics( *, model_id: str, deployment_id: str, - request: GetModelsDeploymentsMetricsRequest | None = None, + params: GetModelsDeploymentsMetricsParams | None = None, ) -> GetModelMetricsResponse: """Gets the metrics for a model deployment""" return await self._do_json( @@ -4808,8 +5720,8 @@ async def get_models_deployments_metrics( path_fmt="/v1/models/{}/deployments/{}/metrics", path_args=[model_id, deployment_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4826,7 +5738,7 @@ async def get_models_deployments_patches_state( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4841,7 +5753,7 @@ async def get_models_deployments_production(self, *, model_id: str) -> Deploymen path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4856,7 +5768,7 @@ async def get_models_environments(self, *, model_id: str) -> Environments: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4873,7 +5785,7 @@ async def get_models_environments_env_name( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4883,7 +5795,7 @@ async def get_models_environments_logs( *, model_id: str, env_name: str, - request: GetModelsEnvironmentsLogsRequest | None = None, + params: GetModelsEnvironmentsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a model environment""" return await self._do_json( @@ -4893,8 +5805,8 @@ async def get_models_environments_logs( path_fmt="/v1/models/{}/environments/{}/logs", path_args=[model_id, env_name], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4904,7 +5816,7 @@ async def get_models_environments_metrics( *, model_id: str, env_name: str, - request: GetModelsEnvironmentsMetricsRequest | None = None, + params: GetModelsEnvironmentsMetricsParams | None = None, ) -> GetModelMetricsResponse: """Gets the metrics for a model environment.""" return await self._do_json( @@ -4914,8 +5826,8 @@ async def get_models_environments_metrics( path_fmt="/v1/models/{}/environments/{}/metrics", path_args=[model_id, env_name], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4930,7 +5842,7 @@ async def get_models_model_id(self, *, model_id: str) -> Model: path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4945,7 +5857,7 @@ async def get_organizations_me(self) -> OrganizationInfo: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -4960,7 +5872,105 @@ async def get_regions(self) -> Regions: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_routes( + self, *, params: GetRoutesParams | None = None + ) -> RoutesResponse: + """Lists routes""" + return await self._do_json( + RoutesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/routes", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_routes_harness_configs( + self, *, params: GetRoutesHarnessConfigsParams + ) -> RouteHarnessConfigsResponse: + """Lists default models for coding harnesses""" + return await self._do_json( + RouteHarnessConfigsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/harness-configs", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_routes_route_id(self, *, route_id: str) -> Route: + """Gets a route""" + return await self._do_json( + Route, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/{}", + path_args=[route_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_routes_spend_limits(self, *, user_id: str) -> RouteSpendLimit: + """Gets a user's spend limits""" + return await self._do_json( + RouteSpendLimit, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/spend_limits/{}", + path_args=[user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_routes_usage( + self, *, params: GetRoutesUsageParams | None = None + ) -> RoutesUsageResponse: + """Gets daily route usage and estimated costs""" + return await self._do_json( + RoutesUsageResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/routes/usage", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_sandbox( + self, *, sandbox_name: str, params: GetSandboxParams | None = None + ) -> Sandbox: + """Get a sandbox""" + return await self._do_json( + Sandbox, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/instances/{}", + path_args=[sandbox_name], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -4975,12 +5985,12 @@ async def get_secrets(self) -> Secrets: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - async def get_teams(self, *, request: GetTeamsRequest | None = None) -> Teams: + async def get_teams(self, *, params: GetTeamsParams | None = None) -> Teams: """Lists all teams""" return await self._do_json( Teams, @@ -4989,8 +5999,8 @@ async def get_teams(self, *, request: GetTeamsRequest | None = None) -> Teams: path_fmt="/v1/teams", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5005,7 +6015,7 @@ async def get_teams_environment_groups(self, *, team_id: str) -> EnvironmentGrou path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5022,13 +6032,13 @@ async def get_teams_environment_groups_env_name( path_args=[team_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) async def get_teams_loops_runs( - self, *, team_id: str, request: GetTeamsLoopsRunsRequest | None = None + self, *, team_id: str, params: GetTeamsLoopsRunsParams | None = None ) -> ListLoopsRunsResponse: """Lists a team's Loops runs""" return await self._do_json( @@ -5038,14 +6048,14 @@ async def get_teams_loops_runs( path_fmt="/v1/teams/{}/loops/runs", path_args=[team_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_teams_loops_samplers( - self, *, team_id: str, request: GetTeamsLoopsSamplersRequest | None = None + self, *, team_id: str, params: GetTeamsLoopsSamplersParams | None = None ) -> ListLoopsSamplersResponse: """Lists a team's Loops samplers""" return await self._do_json( @@ -5055,14 +6065,14 @@ async def get_teams_loops_samplers( path_fmt="/v1/teams/{}/loops/samplers", path_args=[team_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_teams_models( - self, *, team_id: str, request: GetTeamsModelsRequest | None = None + self, *, team_id: str, params: GetTeamsModelsParams | None = None ) -> Models: """Gets all models""" return await self._do_json( @@ -5072,8 +6082,8 @@ async def get_teams_models( path_fmt="/v1/teams/{}/models", path_args=[team_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5088,7 +6098,7 @@ async def get_teams_regions(self, *, team_id: str) -> Regions: path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5103,7 +6113,7 @@ async def get_teams_secrets(self, *, team_id: str) -> Secrets: path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5118,7 +6128,7 @@ async def get_teams_team_id(self, *, team_id: str) -> Team: path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5133,7 +6143,7 @@ async def get_training_capacity(self) -> GetTrainingGpuCapacityResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5150,7 +6160,7 @@ async def get_training_jobs_queue_context( path_args=[training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5165,7 +6175,7 @@ async def get_training_projects(self) -> ListTrainingProjectsResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5182,7 +6192,7 @@ async def get_training_projects_cache_summary( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5199,7 +6209,7 @@ async def get_training_projects_jobs( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5216,7 +6226,7 @@ async def get_training_projects_jobs_auth_codes( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5226,7 +6236,7 @@ async def get_training_projects_jobs_checkpoint_files( *, training_project_id: str, training_job_id: str, - request: GetTrainingProjectsJobsCheckpointFilesRequest | None = None, + params: GetTrainingProjectsJobsCheckpointFilesParams | None = None, ) -> GetTrainingJobCheckpointFilesResponse: """Gets training job checkpoint files""" return await self._do_json( @@ -5236,8 +6246,8 @@ async def get_training_projects_jobs_checkpoint_files( path_fmt="/v1/training_projects/{}/jobs/{}/checkpoint_files", path_args=[training_project_id, training_job_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5254,7 +6264,7 @@ async def get_training_projects_jobs_checkpoints( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5271,7 +6281,7 @@ async def get_training_projects_jobs_download( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5281,7 +6291,7 @@ async def get_training_projects_jobs_logs( *, training_project_id: str, training_job_id: str, - request: GetTrainingProjectsJobsLogsRequest | None = None, + params: GetTrainingProjectsJobsLogsParams | None = None, ) -> GetLogsResponse: """Gets the logs for a training job""" return await self._do_json( @@ -5291,8 +6301,8 @@ async def get_training_projects_jobs_logs( path_fmt="/v1/training_projects/{}/jobs/{}/logs", path_args=[training_project_id, training_job_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5302,7 +6312,7 @@ async def get_training_projects_jobs_metrics( *, training_project_id: str, training_job_id: str, - request: GetTrainingProjectsJobsMetricsRequest | None = None, + params: GetTrainingProjectsJobsMetricsParams | None = None, ) -> GetTrainingJobMetricsResponse: """Gets the metrics for a training job""" return await self._do_json( @@ -5312,8 +6322,8 @@ async def get_training_projects_jobs_metrics( path_fmt="/v1/training_projects/{}/jobs/{}/metrics", path_args=[training_project_id, training_job_id], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5330,7 +6340,7 @@ async def get_training_projects_jobs_training_job_id( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5347,14 +6357,12 @@ async def get_training_projects_training_project_id( path_args=[training_project_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - async def get_users( - self, *, request: GetUsersRequest | None = None - ) -> UsersResponse: + async def get_users(self, *, params: GetUsersParams | None = None) -> UsersResponse: """Lists users in the workspace""" return await self._do_json( UsersResponse, @@ -5363,8 +6371,8 @@ async def get_users( path_fmt="/v1/users", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5379,7 +6387,7 @@ async def get_users_me(self) -> UserInfo: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5394,12 +6402,12 @@ async def get_users_user_id(self, *, user_id: str) -> UserInfo: path_args=[user_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - async def get_volumes(self, *, request: GetVolumesRequest) -> ListVolumesResponse: + async def get_volumes(self, *, params: GetVolumesParams) -> ListVolumesResponse: """Gets the volumes in a namespace""" return await self._do_json( ListVolumesResponse, @@ -5408,14 +6416,14 @@ async def get_volumes(self, *, request: GetVolumesRequest) -> ListVolumesRespons path_fmt="/v1/volumes", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) async def get_volumes_namespaces( - self, *, request: GetVolumesNamespacesRequest | None = None + self, *, params: GetVolumesNamespacesParams | None = None ) -> ListVolumeNamespacesResponse: """Gets the volume namespaces in your workspace""" return await self._do_json( @@ -5425,8 +6433,42 @@ async def get_volumes_namespaces( path_fmt="/v1/volumes/namespaces", path_args=[], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_volumes_syncs( + self, *, params: GetVolumesSyncsParams | None = None + ) -> VolumeSyncs: + """Lists volume syncs""" + return await self._do_json( + VolumeSyncs, + _ApiRequest( + method="GET", + path_fmt="/v1/volumes/syncs", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_volumes_syncs_volume_sync_id( + self, *, volume_sync_id: str + ) -> VolumeSync: + """Gets a volume sync""" + return await self._do_json( + VolumeSync, + _ApiRequest( + method="GET", + path_fmt="/v1/volumes/syncs/{}", + path_args=[volume_sync_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -5436,7 +6478,7 @@ async def get_volumes_versions( *, volume_namespace: str, volume_name: str, - request: GetVolumesVersionsRequest | None = None, + params: GetVolumesVersionsParams | None = None, ) -> ListVolumeVersionsResponse: """Gets the versions of a volume""" return await self._do_json( @@ -5446,8 +6488,8 @@ async def get_volumes_versions( path_fmt="/v1/volumes/{}/{}/versions", path_args=[volume_namespace, volume_name], body=None, - query=request, - success_code=200, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5464,7 +6506,7 @@ async def get_volumes_versions_volume_version( path_args=[volume_namespace, volume_name, volume_version], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5481,7 +6523,75 @@ async def get_volumes_volume_name( path_args=[volume_namespace, volume_name], body=None, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def list_image_tags( + self, *, image_name: str, params: ListImageTagsParams | None = None + ) -> ListImageTagsResponse: + """List image tags""" + return await self._do_json( + ListImageTagsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images/{}/tags", + path_args=[image_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def list_images( + self, *, params: ListImagesParams | None = None + ) -> ListImagesResponse: + """List sandbox images""" + return await self._do_json( + ListImagesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/images", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def list_sandbox_library_images( + self, *, params: ListSandboxLibraryImagesParams | None = None + ) -> ListSandboxLibraryImagesResponse: + """List built-in sandbox images""" + return await self._do_json( + ListSandboxLibraryImagesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/library_images", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def list_sandboxes( + self, *, params: ListSandboxesParams | None = None + ) -> ListSandboxesResponse: + """List sandboxes""" + return await self._do_json( + ListSandboxesResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/sandboxes/instances", + path_args=[], + body=None, + query=params, + success_codes=[200], error_codes=None, ), ) @@ -5498,7 +6608,7 @@ async def patch_chains_environments( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5519,7 +6629,7 @@ async def patch_chains_environments_chainlet_settings_autoscaling_settings( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5536,7 +6646,7 @@ async def patch_environment_groups( path_args=[env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5553,7 +6663,7 @@ async def patch_gateway_endpoints( path_args=[endpoint_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5570,7 +6680,7 @@ async def patch_gateway_groups( path_args=[group_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5587,7 +6697,7 @@ async def patch_library_listings( path_args=[user_defined_listing_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5608,7 +6718,7 @@ async def patch_library_listings_versions( path_args=[user_defined_listing_id, version_tag], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5625,7 +6735,24 @@ async def patch_loops_user_config( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def patch_models( + self, *, model_id: str, request: UpdateModelRequest + ) -> Model: + """Updates a model by ID""" + return await self._do_json( + Model, + _ApiRequest( + method="PATCH", + path_fmt="/v1/models/{}", + path_args=[model_id], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -5642,7 +6769,7 @@ async def patch_models_deployments( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5659,7 +6786,7 @@ async def patch_models_deployments_autoscaling_settings( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5676,7 +6803,7 @@ async def patch_models_deployments_development_autoscaling_settings( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5693,7 +6820,7 @@ async def patch_models_deployments_production_autoscaling_settings( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5714,7 +6841,7 @@ async def patch_models_deployments_request_backpressure_settings( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5731,7 +6858,58 @@ async def patch_models_environments( path_args=[model_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def patch_routes( + self, *, route_id: str, request: UpdateRouteRequest + ) -> Route: + """Updates a route's display name or description""" + return await self._do_json( + Route, + _ApiRequest( + method="PATCH", + path_fmt="/v1/routes/{}", + path_args=[route_id], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def patch_routes_harness_configs( + self, *, request: UpdateRouteHarnessConfigRequest + ) -> RouteHarnessConfig: + """Updates default models for a coding harness""" + return await self._do_json( + RouteHarnessConfig, + _ApiRequest( + method="PATCH", + path_fmt="/v1/routes/harness-configs", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def patch_routes_spend_limits( + self, *, user_id: str, request: UpdateRouteSpendLimitRequest + ) -> RouteSpendLimit: + """Updates a user's spend limits""" + return await self._do_json( + RouteSpendLimit, + _ApiRequest( + method="PATCH", + path_fmt="/v1/routes/spend_limits/{}", + path_args=[user_id], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -5748,7 +6926,7 @@ async def patch_teams_environment_groups( path_args=[team_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5765,7 +6943,7 @@ async def patch_training_capacity( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5786,7 +6964,7 @@ async def patch_training_projects_jobs( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5808,7 +6986,7 @@ async def patch_training_projects_jobs_interactive_sessions( path_args=[training_project_id, training_job_id, session_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5823,7 +7001,7 @@ async def post_api_keys(self, *, request: CreateAPIKeyRequest) -> APIKey: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5840,7 +7018,7 @@ async def post_chains_deployments_deactivate( path_args=[chain_id, chain_deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5857,7 +7035,7 @@ async def post_chains_environments( path_args=[chain_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5878,7 +7056,7 @@ async def post_chains_environments_chainlet_settings_instance_types_update( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5895,7 +7073,7 @@ async def post_chains_environments_promote( path_args=[chain_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5912,7 +7090,7 @@ async def post_gateway_endpoints( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5927,7 +7105,7 @@ async def post_gateway_groups(self, *, request: CreateGroupRequest) -> Group: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5944,7 +7122,7 @@ async def post_gateway_groups_api_keys( path_args=[group_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5961,7 +7139,7 @@ async def post_gateway_groups_api_keys_register( path_args=[group_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5978,7 +7156,7 @@ async def post_library_listings( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -5998,7 +7176,7 @@ async def post_library_listings_versions( path_args=[user_defined_listing_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6015,7 +7193,7 @@ async def post_llm_models( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6032,7 +7210,24 @@ async def post_llm_models_deployments( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def post_loops_checkpoints_deploy( + self, *, request: DeployLoopsCheckpointRequest + ) -> DeployLoopsCheckpointResponse: + """Deploys Loops checkpoints""" + return await self._do_json( + DeployLoopsCheckpointResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/loops/checkpoints/deploy", + path_args=[], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -6049,7 +7244,7 @@ async def post_loops_checkpoints_validate( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6066,7 +7261,7 @@ async def post_loops_deployments_deactivate( path_args=[deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6083,7 +7278,7 @@ async def post_loops_deployments_metrics( path_args=[deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6100,7 +7295,7 @@ async def post_loops_runs( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6117,7 +7312,7 @@ async def post_loops_runs_deactivate( path_args=[run_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6134,7 +7329,24 @@ async def post_loops_samplers( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def post_loops_samplers_deactivate( + self, *, sampler_id: str + ) -> DeactivateLoopsSamplerResponse: + """Deactivates a standalone Loops sampler""" + return await self._do_json( + DeactivateLoopsSamplerResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/loops/samplers/{}/deactivate", + path_args=[sampler_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -6149,7 +7361,7 @@ async def post_loops_sessions(self) -> CreateLoopsSessionResponse: path_args=[], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6166,7 +7378,7 @@ async def post_loops_trainers( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6183,7 +7395,7 @@ async def post_models( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6200,7 +7412,7 @@ async def post_models_deployments( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6217,7 +7429,7 @@ async def post_models_deployments_activate( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6234,7 +7446,7 @@ async def post_models_deployments_deactivate( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6251,7 +7463,7 @@ async def post_models_deployments_development_activate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6268,7 +7480,7 @@ async def post_models_deployments_development_deactivate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6285,7 +7497,7 @@ async def post_models_deployments_development_promote( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6302,7 +7514,7 @@ async def post_models_deployments_development_retry( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6319,7 +7531,7 @@ async def post_models_deployments_logs( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6340,7 +7552,7 @@ async def post_models_deployments_patches( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6361,7 +7573,7 @@ async def post_models_deployments_patches_sync( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6378,7 +7590,7 @@ async def post_models_deployments_production_activate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6395,7 +7607,7 @@ async def post_models_deployments_production_deactivate( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6412,7 +7624,7 @@ async def post_models_deployments_production_retry( path_args=[model_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6429,7 +7641,7 @@ async def post_models_deployments_promote( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6446,7 +7658,7 @@ async def post_models_deployments_retry( path_args=[model_id, deployment_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6463,7 +7675,7 @@ async def post_models_deployments_ssh_sign( path_args=[model_id, deployment_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6480,7 +7692,7 @@ async def post_models_environments( path_args=[model_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6497,7 +7709,7 @@ async def post_models_environments_activate( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6514,7 +7726,7 @@ async def post_models_environments_cancel_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6531,7 +7743,7 @@ async def post_models_environments_deactivate( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6548,7 +7760,7 @@ async def post_models_environments_force_cancel_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6565,7 +7777,7 @@ async def post_models_environments_force_roll_forward_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6582,7 +7794,7 @@ async def post_models_environments_pause_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6599,7 +7811,7 @@ async def post_models_environments_promote( path_args=[model_id, env_name], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6616,7 +7828,7 @@ async def post_models_environments_resume_promotion( path_args=[model_id, env_name], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6633,7 +7845,22 @@ async def post_prepare_model_upload( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def post_routes(self, *, request: CreateRouteRequest) -> Route: + """Creates a route""" + return await self._do_json( + Route, + _ApiRequest( + method="POST", + path_fmt="/v1/routes", + path_args=[], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -6648,7 +7875,7 @@ async def post_secrets(self, *, request: UpsertSecretRequest) -> Secret: path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6665,7 +7892,7 @@ async def post_teams_api_keys( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6682,7 +7909,7 @@ async def post_teams_llm_models( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6699,7 +7926,7 @@ async def post_teams_loops_runs( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6716,7 +7943,7 @@ async def post_teams_loops_samplers( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6733,7 +7960,7 @@ async def post_teams_loops_sessions( path_args=[team_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6750,7 +7977,7 @@ async def post_teams_loops_trainers( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6767,7 +7994,7 @@ async def post_teams_models( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6784,7 +8011,7 @@ async def post_teams_secrets( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6801,7 +8028,22 @@ async def post_teams_training_projects( path_args=[team_id], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def post_token(self, *, request: CreateTokenRequest) -> Token: + """Creates a sandbox access token""" + return await self._do_json( + Token, + _ApiRequest( + method="POST", + path_fmt="/v1/token", + path_args=[], + body=request, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -6818,7 +8060,7 @@ async def post_training_jobs_search( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6835,7 +8077,7 @@ async def post_training_projects( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6852,7 +8094,7 @@ async def post_training_projects_jobs( path_args=[training_project_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6873,7 +8115,7 @@ async def post_training_projects_jobs_logs( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6894,7 +8136,7 @@ async def post_training_projects_jobs_metrics( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6911,7 +8153,7 @@ async def post_training_projects_jobs_recreate( path_args=[training_project_id, training_job_id], body=None, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6932,7 +8174,7 @@ async def post_training_projects_jobs_ssh_sign( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6953,7 +8195,39 @@ async def post_training_projects_jobs_stop( path_args=[training_project_id, training_job_id], body=request, query=None, - success_code=200, + success_codes=[200], + error_codes=None, + ), + ) + + async def post_volumes_syncs( + self, *, request: CreateVolumeSyncRequest + ) -> VolumeSync: + """Starts a volume sync""" + return await self._do_json( + VolumeSync, + _ApiRequest( + method="POST", + path_fmt="/v1/volumes/syncs", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def post_volumes_syncs_cancel(self, *, volume_sync_id: str) -> VolumeSync: + """Cancels a volume sync""" + return await self._do_json( + VolumeSync, + _ApiRequest( + method="POST", + path_fmt="/v1/volumes/syncs/{}/cancel", + path_args=[volume_sync_id], + body=None, + query=None, + success_codes=[200], error_codes=None, ), ) @@ -6970,7 +8244,7 @@ async def post_volumes_token( path_args=[], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) @@ -6983,7 +8257,7 @@ async def post_volumes_versions_restore( volume_version: str, request: RestoreVolumeVersionRequest, ) -> RestoreVolumeVersionResponse: - """Restores a deleted version of a volume""" + """Restores a deleted or expired version of a volume""" return await self._do_json( RestoreVolumeVersionResponse, _ApiRequest( @@ -6992,38 +8266,118 @@ async def post_volumes_versions_restore( path_args=[volume_namespace, volume_name, volume_version], body=request, query=None, - success_code=200, + success_codes=[200], error_codes=None, ), ) - async def _do(self, request: _ApiRequest) -> httpx.Response: + async def push_image( + self, *, params: PushImageParams | None = None, request: PushImageRequest + ) -> PushImageResponse: + """Push a sandbox image""" + return await self._do_json( + PushImageResponse, + _ApiRequest( + method="POST", + path_fmt="/v1/sandboxes/images", + path_args=[], + body=request, + query=params, + success_codes=[202], + error_codes=None, + ), + ) + + async def put_routes_harness_configs( + self, *, request: SetRouteHarnessConfigRequest + ) -> RouteHarnessConfig: + """Sets default models for a coding harness""" + return await self._do_json( + RouteHarnessConfig, + _ApiRequest( + method="PUT", + path_fmt="/v1/routes/harness-configs", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def update_sandbox( + self, + *, + sandbox_name: str, + params: UpdateSandboxParams | None = None, + request: UpdateSandboxRequest, + ) -> Sandbox: + """Update a sandbox""" + return await self._do_json( + Sandbox, + _ApiRequest( + method="PATCH", + path_fmt="/v1/sandboxes/instances/{}", + path_args=[sandbox_name], + body=request, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def _build_request(self, request: _ApiRequest) -> httpx.Request: path = request.path_fmt.format( *[urllib.parse.quote(a, safe="") for a in request.path_args] ) json_body = None + content_body = None + files_body = None + headers: dict[str, str] = {} + if request.accept is not None: + headers["Accept"] = request.accept if request.body is not None: - if isinstance(request.body, BaseModel): - # Only fields the caller set are sent, so unset fields fall - # back to the server default rather than being reset here. - # An explicit None is kept, since null can mean "clear". - json_body = request.body.model_dump(mode="json", exclude_unset=True) + if request.body_content_type is None: + if isinstance(request.body, BaseModel): + # Only fields the caller set are sent, so unset fields fall + # back to the server default rather than being reset here. + # An explicit None is kept, since null can mean "clear". + # by_alias: a field renamed for Python (e.g. async_ for + # "async") must serialize under its API name. + json_body = request.body.model_dump( + mode="json", exclude_unset=True, by_alias=True + ) + else: + json_body = request.body + elif request.body_content_type == "multipart/form-data": + # httpx derives the multipart Content-Type, boundary included. + files_body = request.body else: - json_body = request.body + headers["Content-Type"] = request.body_content_type + content_body = request.body params = None if request.query is not None: if isinstance(request.query, BaseModel): # As above, plus dropping None: a null query parameter is # meaningless and would otherwise serialize as an empty string. params = request.query.model_dump( - mode="json", exclude_unset=True, exclude_none=True + mode="json", exclude_unset=True, exclude_none=True, by_alias=True ) else: params = request.query - response = await self._http_client.request( - request.method, path, json=json_body, params=params + return self._http_client.build_request( + request.method, + path, + json=json_body, + content=content_body, + files=files_body, + params=params, + headers=headers, ) - if response.status_code != request.success_code: + + async def _do(self, request: _ApiRequest) -> httpx.Response: + response = await self._http_client.send(self._build_request(request)) + if response.status_code not in request.success_codes: raise ResponseError(status_code=response.status_code, body=response.text) return response diff --git a/baseten/client/managementapi/_models.py b/baseten/client/managementapi/_models.py index deb73a1..200f447 100644 --- a/baseten/client/managementapi/_models.py +++ b/baseten/client/managementapi/_models.py @@ -7,7 +7,7 @@ from enum import StrEnum from typing import Annotated, Any, Literal -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, RootModel +from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, Field, RootModel class DeploymentConfigOutputFormat(StrEnum): @@ -299,6 +299,22 @@ class ResourceKind(StrEnum): CHAINLET = "CHAINLET" +class RouteHarness(StrEnum): + claude_code = "claude-code" + opencode = "opencode" + codex = "codex" + + +class RouteHarnessModelSource(StrEnum): + team = "team" + baseten = "baseten" + + +class RouteHarnessRole(StrEnum): + primary = "primary" + background = "background" + + class GatewayProvider(StrEnum): ANTHROPIC = "ANTHROPIC" OPENAI = "OPENAI" @@ -309,7 +325,7 @@ class GatewayProvider(StrEnum): OPENAI_COMPATIBLE = "OPENAI_COMPATIBLE" -class GetVolumesRequest(BaseModel): +class GetVolumesParams(BaseModel): cursor: Annotated[ str | None, Field( @@ -335,7 +351,7 @@ class GetVolumesRequest(BaseModel): ] -class GetVolumesNamespacesRequest(BaseModel): +class GetVolumesNamespacesParams(BaseModel): cursor: Annotated[ str | None, Field( @@ -354,17 +370,40 @@ class GetVolumesNamespacesRequest(BaseModel): ] = 100 -class GetVolumesVersionsRequest(BaseModel): +class GetVolumesSyncsParams(BaseModel): + cursor: Annotated[ + str | None, + Field( + description="Opaque cursor returned by a previous page. Omit to fetch the first page.", + title="Cursor", + ), + ] = None + limit: Annotated[ + int, + Field( + description="Maximum number of items to return.", + ge=1, + le=1000, + title="Limit", + ), + ] = 100 + ref: Annotated[ + str | None, + Field(description="Exact destination reference to match.", title="Ref"), + ] = None + + +class GetVolumesVersionsParams(BaseModel): include_tombstoned: Annotated[ bool, Field( - description="Whether to include deleted versions. A deleted version carries a TOMBSTONED lifecycle and stays restorable until its recovery deadline passes.", + description="Whether to include deleted and expired versions. Such a version carries a TOMBSTONED lifecycle and stays restorable until its recovery deadline passes.", title="Include Tombstoned", ), ] = False -class GetTeamsRequest(BaseModel): +class GetTeamsParams(BaseModel): name: Annotated[ str | None, Field( @@ -374,7 +413,7 @@ class GetTeamsRequest(BaseModel): ] = None -class GetModelsRequest(BaseModel): +class GetModelsParams(BaseModel): name: Annotated[ str | None, Field( @@ -384,7 +423,7 @@ class GetModelsRequest(BaseModel): ] = None -class GetTeamsModelsRequest(BaseModel): +class GetTeamsModelsParams(BaseModel): name: Annotated[ str | None, Field( @@ -394,7 +433,7 @@ class GetTeamsModelsRequest(BaseModel): ] = None -class GetModelsDeploymentsRequest(BaseModel): +class GetModelsDeploymentsParams(BaseModel): name: Annotated[ str | None, Field( @@ -404,7 +443,7 @@ class GetModelsDeploymentsRequest(BaseModel): ] = None -class GetModelsDeploymentsConfigRequest(BaseModel): +class GetModelsDeploymentsConfigParams(BaseModel): output_format: Annotated[ DeploymentConfigOutputFormat, Field( @@ -469,7 +508,7 @@ class SearchPattern(RootModel[str]): ] = None -class GetTrainingProjectsJobsMetricsRequest(BaseModel): +class GetTrainingProjectsJobsMetricsParams(BaseModel): end_epoch_millis: Annotated[ int | None, Field( @@ -493,7 +532,7 @@ class GetTrainingProjectsJobsMetricsRequest(BaseModel): ] = None -class GetTrainingProjectsJobsCheckpointFilesRequest(BaseModel): +class GetTrainingProjectsJobsCheckpointFilesParams(BaseModel): page_size: Annotated[ int, Field( @@ -510,7 +549,19 @@ class GetTrainingProjectsJobsCheckpointFilesRequest(BaseModel): ] = 0 -class GetLoopsRunsRequest(BaseModel): +class MaxSeqLen(RootModel[int]): + root: Annotated[ + int | None, + Field( + description="The sequence length the caller intends to train at — the same value they would pass as 'max_seq_len' when creating the run. Models that cannot serve it are reported as not enabled rather than returned with a ceiling the caller cannot use. Omit for the model's highest enabled sequence length.", + examples=[32768], + ge=1, + title="Max Seq Len", + ), + ] = None + + +class GetLoopsRunsParams(BaseModel): run_id: Annotated[ str | None, Field(description="Filter by run ID.", examples=["k4q95w5"], title="Run Id"), @@ -533,7 +584,7 @@ class GetLoopsRunsRequest(BaseModel): ] = None -class GetLoopsSamplersRequest(BaseModel): +class GetLoopsSamplersParams(BaseModel): scope: Annotated[ str | None, Field( @@ -544,7 +595,7 @@ class GetLoopsSamplersRequest(BaseModel): ] = None -class GetLoopsCheckpointsRequest(BaseModel): +class GetLoopsCheckpointsParams(BaseModel): run_id: Annotated[ str | None, Field( @@ -571,7 +622,7 @@ class GetLoopsCheckpointsRequest(BaseModel): ] = None -class GetLoopsCheckpointsFilesRequest(BaseModel): +class GetLoopsCheckpointsFilesParams(BaseModel): page_size: Annotated[ int, Field( @@ -588,7 +639,7 @@ class GetLoopsCheckpointsFilesRequest(BaseModel): ] = 0 -class GetLoopsDeploymentsRequest(BaseModel): +class GetLoopsDeploymentsParams(BaseModel): scope: Annotated[ str | None, Field( @@ -599,7 +650,7 @@ class GetLoopsDeploymentsRequest(BaseModel): ] = None -class GetLoopsDeploymentsDebugArchiveFilesRequest(BaseModel): +class GetLoopsDeploymentsDebugArchiveFilesParams(BaseModel): page_size: Annotated[ int, Field( @@ -615,7 +666,7 @@ class GetLoopsDeploymentsDebugArchiveFilesRequest(BaseModel): ] = None -class GetTeamsLoopsRunsRequest(BaseModel): +class GetTeamsLoopsRunsParams(BaseModel): run_id: Annotated[ str | None, Field(description="Filter by run ID.", examples=["k4q95w5"], title="Run Id"), @@ -638,7 +689,7 @@ class GetTeamsLoopsRunsRequest(BaseModel): ] = None -class GetTeamsLoopsSamplersRequest(BaseModel): +class GetTeamsLoopsSamplersParams(BaseModel): scope: Annotated[ str | None, Field( @@ -649,7 +700,20 @@ class GetTeamsLoopsSamplersRequest(BaseModel): ] = None -class GetModelApisRequest(BaseModel): +class GetApiKeysParams(BaseModel): + type: Annotated[ + APIKeyCategory | None, Field(description="Filter by API key type") + ] = None + created_by_me: Annotated[ + bool, + Field( + description="Return only keys created by the authenticated user", + title="Created By Me", + ), + ] = False + + +class GetModelApisParams(BaseModel): cursor: Annotated[ str | None, Field( @@ -675,7 +739,7 @@ class GetModelApisRequest(BaseModel): ] = False -class GetBillingUsageSummaryRequest(BaseModel): +class GetBillingUsageSummaryParams(BaseModel): start_date: Annotated[ AwareDatetime, Field( @@ -692,7 +756,24 @@ class GetBillingUsageSummaryRequest(BaseModel): ] -class GetUsersRequest(BaseModel): +class GetBillingToolCallUsageParams(BaseModel): + start_date: Annotated[ + date_aliased, + Field( + description="Inclusive UTC calendar day at the start of the query range.", + title="Start Date", + ), + ] + end_date: Annotated[ + date_aliased | None, + Field( + description="Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included. The date range cannot exceed 90 days.", + title="End Date", + ), + ] = None + + +class GetUsersParams(BaseModel): cursor: Annotated[ str | None, Field( @@ -730,7 +811,7 @@ class Limit5(RootModel[int]): ] = None -class GetGatewayEventsRequest(BaseModel): +class GetGatewayEventsParams(BaseModel): start_time: Annotated[ AwareDatetime | None, Field( @@ -772,6445 +853,9308 @@ class GetGatewayEventsRequest(BaseModel): ] = None -class PaginationResponse(BaseModel): - has_more: Annotated[ - bool, - Field( - description="Whether more items exist after this page.", title="Has More" - ), - ] +class GetExploreMetadataParams(BaseModel): cursor: Annotated[ str | None, Field( - description="Opaque cursor to pass into the next request. Null when there is no next page.", + description="Opaque cursor returned by a previous page. Omit to fetch the first page.", title="Cursor", ), ] = None - - -class VolumeTag(BaseModel): - name: Annotated[ - str, Field(description="Tag name. Tags are case-sensitive.", title="Name") - ] - digest: Annotated[ - str, + limit: Annotated[ + int, Field( - description="Digest of the version the tag points at, as `b3:`.", - title="Digest", + description="Maximum number of items to return.", + ge=1, + le=1000, + title="Limit", ), - ] + ] = 100 + provider: Annotated[ + str | None, + Field( + description="Filter to a provider by slug prefix, e.g. 'anthropic'. Preserved by the cursor; if repeated, must match the original filter.", + title="Provider", + ), + ] = None + q: Annotated[ + str | None, + Field( + description="Case-insensitive substring search over metadata slugs. Preserved by the cursor; if repeated, must match the original filter.", + title="Q", + ), + ] = None -class VolumeVersionSummary(BaseModel): - digest: Annotated[ - str, +class GetRoutesParams(BaseModel): + cursor: Annotated[ + str | None, Field( - description="Content digest of the version, as `b3:`.", title="Digest" + description="Opaque cursor returned by a previous page. Omit to fetch the first page.", + title="Cursor", ), - ] - total_size_bytes: Annotated[ + ] = None + limit: Annotated[ int, Field( - description="Total size of the version's files in bytes.", - title="Total Size Bytes", + description="Maximum number of items to return.", + ge=1, + le=1000, + title="Limit", ), - ] - created_at: Annotated[ - AwareDatetime, + ] = 100 + team_id: Annotated[ + str | None, Field( - description="When the version was committed, in ISO 8601 format.", - title="Created At", + description="Filter by owning team ID. Preserved by the cursor; if repeated, must match the original filter.", + title="Team Id", ), - ] - - -class VolumeTokenScope(StrEnum): - PULL = "PULL" - INSPECT = "INSPECT" - PUSH = "PUSH" - TAG = "TAG" - - -class CorrelationId(RootModel[str]): - root: Annotated[ + ] = None + name: Annotated[ str | None, Field( - description="Optional client-chosen identifier, at most 128 printable ASCII characters. Echoed into server logs to link the issued token to a client operation.", - max_length=128, - pattern="^[\\x21-\\x7e]+$", - title="Correlation Id", + description="Filter by exact route name. Preserved by the cursor; if repeated, must match the original filter.", + title="Name", ), ] = None -class CreateVolumeTokenRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - scopes: Annotated[ - list[VolumeTokenScope], +class GetRoutesHarnessConfigsParams(BaseModel): + team_id: Annotated[ + str, Field( - description="Capabilities the token grants, at least one. Requesting PUSH or TAG requires organization-level model management permission.", + description="Identifier of the team whose default models to list.", min_length=1, - title="Scopes", + title="Team Id", ), ] - namespaces: Annotated[ - list[str], + + +class DeleteRoutesHarnessConfigsParams(BaseModel): + team_id: Annotated[ + str, Field( - description="Volume namespaces the token is limited to, lowercase ASCII, at least one. Pass only the namespaces the operation needs.", + description="Identifier of the team whose default models to clear.", min_length=1, - title="Namespaces", + title="Team Id", ), ] - volumes: Annotated[ - list[str], + + +class StatusItem(RootModel[str]): + root: Annotated[str, Field(min_length=1)] + + +class ListSandboxesParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Volume names the token is limited to, lowercase ASCII, exact names only, at least one. The limit applies to every requested scope in every requested namespace.", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", min_length=1, - title="Volumes", ), - ] - correlation_id: Annotated[ - CorrelationId | None, + ] = None + cursor: Annotated[ + str | None, Field( - description="Optional client-chosen identifier, at most 128 printable ASCII characters. Echoed into server logs to link the issued token to a client operation.", - title="Correlation Id", + description="Opaque cursor from the previous page; omit for the first page.", + examples=[ + "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + ], ), ] = None - - -class CreateVolumeTokenResponse(BaseModel): - token: Annotated[ - str, + limit: Annotated[ + int, Field( - description="Volume access token. Pass as a bearer token to the volume APIs.", - title="Token", + description="Maximum number of items to return.", + examples=[20], + ge=1, + le=100, ), - ] - expires_at: Annotated[ - AwareDatetime, + ] = 20 + q: Annotated[ + str | None, Field( - description="Token expiry in ISO 8601 format. Tokens cannot be renewed; exchange again for a fresh token.", - title="Expires At", + description="Search indexed sandbox names and labels. Search is applied before pagination.", + examples=["api-review"], ), - ] - scopes: Annotated[ - list[VolumeTokenScope], - Field(description="Effective capabilities granted.", title="Scopes"), - ] - namespaces: Annotated[ - list[str], + ] = None + status: Annotated[ + list[StatusItem] | None, Field( - description="Effective namespaces granted, in canonical lowercase form.", - title="Namespaces", + description="Deployment statuses. Repeat the query parameter for each status, for example status=DEPLOYED&status=FAILED. Unknown values are rejected. Cannot be combined with external_id.", + examples=[["DEPLOYED", "FAILED"]], + min_length=1, ), - ] - volumes: Annotated[ - list[str], + ] = None + external_id: Annotated[ + str | None, Field( - description="Effective volume names granted, in canonical lowercase form.", - title="Volumes", + description="Filter by a caller-owned external identifier. Cannot be combined with status.", + examples=["api-review-20260916-001"], ), - ] - bdn_endpoint: Annotated[ + ] = None + + +class CreateSandboxParams(BaseModel): + team_id: Annotated[ str | None, Field( - description="Base URL of the volume API this token authenticates against. Null when the environment does not expose a public volume API yet.", - title="Bdn Endpoint", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] + ] = None -class ListVolumeNamespacesResponse(BaseModel): - items: Annotated[list[str], Field(description="Items in this page.", title="Items")] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] +class GetSandboxParams(BaseModel): + team_id: Annotated[ + str | None, + Field( + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, + ), + ] = None + show_secrets: Annotated[ + bool, + Field( + description="Reveal environment variable values for workspace administrators. Defaults to false. Callers without the admin role receive masked values even when true." + ), + ] = False -class DeleteVolumeRequest(BaseModel): - expected_sequence: Annotated[ - int | None, +class UpdateSandboxParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so it cannot act on a volume someone else has pushed to. Take the value from a volume's sequence, or from volume_sequence.", - title="Expected Sequence", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), ] = None -class DeleteVolumeResponse(BaseModel): - namespace: Annotated[ - str, - Field( - description="Namespace the volume belongs to, in lowercase.", - title="Namespace", - ), - ] - name: Annotated[ - str, Field(description="Name of the volume, in lowercase.", title="Name") - ] - versions_deleted: Annotated[ - int, +class DeleteSandboxParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Number of versions this request deleted. Zero when the volume had no live versions left, which is not an error.", - title="Versions Deleted", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] - volume_sequence: Annotated[ - int, + ] = None + + +class ListSandboxLibraryImagesParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Revision of the volume after the delete.", - title="Volume Sequence", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] + ] = None -class VolumeVersion(BaseModel): - namespace: Annotated[ - str, +class ListImagesParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Namespace the volume belongs to, in lowercase.", - title="Namespace", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] - volume: Annotated[ - str, Field(description="Name of the volume, in lowercase.", title="Volume") - ] - version_ref: Annotated[ - str, + ] = None + cursor: Annotated[ + str | None, Field( - description="Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", - title="Version Ref", + description="Opaque cursor from the previous page; omit for the first page.", + examples=[ + "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + ], ), - ] - digest: Annotated[ + ] = None + limit: Annotated[ + int, + Field( + description="Maximum number of items to return.", + examples=[20], + ge=1, + le=100, + ), + ] = 20 + sort: Annotated[ str, Field( - description="Content digest of the version, as `b3:`.", title="Digest" + description="Sort by repository name or creation time: name:asc, name:desc, createdAt:asc, or createdAt:desc. Keep the same sort when following a cursor." ), - ] - sequence: Annotated[ - int | None, + ] = "createdAt:desc" + q: Annotated[ + str | None, Field( - description="Revision the version was committed at. Null for versions committed before the volume service recorded it.", - title="Sequence", + description="Case-sensitive repository name prefix. Search is applied before pagination." ), - ] - lifecycle: Annotated[ - str, + ] = None + + +class PushImageParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Lifecycle state of the version, for example ALIVE or TOMBSTONED.", - title="Lifecycle", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] - is_head: Annotated[ - bool, + ] = None + + +class CleanupImagesParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Whether the reserved `head` tag points at this version.", - title="Is Head", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] - tags: Annotated[ - list[str], + ] = None + + +class GetImageParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Tags pointing at this version that your API key can read.", - title="Tags", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] - total_size_bytes: Annotated[ - int | None, + ] = None + + +class DeleteImageParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Total size of the version's files in bytes. Null when not recorded.", - title="Total Size Bytes", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] - created_at: Annotated[ - AwareDatetime, + ] = None + + +class GetImageBuildLogsParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="When the version was committed, in ISO 8601 format.", - title="Created At", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), - ] - tombstoned_at: Annotated[ + ] = None + start_time: Annotated[ AwareDatetime | None, Field( - description="When the version was deleted, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - title="Tombstoned At", + description="Inclusive RFC 3339 start time. Defaults to 24 hours before end_time." ), - ] - delete_after: Annotated[ + ] = None + end_time: Annotated[ AwareDatetime | None, + Field(description="RFC 3339 end time. Defaults to the current time."), + ] = None + limit: Annotated[ + int, + Field(description="Maximum number of log entries to return.", ge=1, le=1000), + ] = 100 + offset: Annotated[ + int, Field( - description="When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - title="Delete After", + description="Number of log entries to skip. Narrow the time range beyond 10000 entries.", + ge=0, + le=10000, ), - ] + ] = 0 -class ListVolumeVersionsResponse(BaseModel): - versions: Annotated[ - list[VolumeVersion], - Field(description="Versions of the volume, newest first.", title="Versions"), - ] - volume_sequence: Annotated[ +class ListImageTagsParams(BaseModel): + team_id: Annotated[ + str | None, + Field( + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, + ), + ] = None + cursor: Annotated[ + str | None, + Field( + description="Opaque cursor from the previous page; omit for the first page.", + examples=[ + "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + ], + ), + ] = None + limit: Annotated[ int, Field( - description="Revision of the volume as a whole when the versions were read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since. Distinct from the per-version sequence, which is the revision a version was committed at.", - title="Volume Sequence", + description="Maximum number of items to return.", + examples=[20], + ge=1, + le=100, ), - ] + ] = 20 + sort: Annotated[ + str, + Field( + description="Sort by tag name: name:asc or name:desc. Keep the same sort when following a cursor." + ), + ] = "name:asc" + q: Annotated[ + str | None, + Field( + description="Case-sensitive tag name prefix. Cannot be combined with name. Forces ascending name order." + ), + ] = None + name: Annotated[ + str | None, + Field( + description="Exact tag name. Cannot be combined with q. Forces ascending name order." + ), + ] = None -class DeleteVolumeVersionRequest(BaseModel): - expected_sequence: Annotated[ - int | None, +class DeleteImageTagParams(BaseModel): + team_id: Annotated[ + str | None, Field( - description="Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so a read followed by a delete cannot act on a version a tag has since been moved off. Take the value from volume_sequence.", - title="Expected Sequence", + description="Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + min_length=1, ), ] = None -class DeleteVolumeVersionResponse(BaseModel): - namespace: Annotated[ - str, +class PaginationResponse(BaseModel): + has_more: Annotated[ + bool, Field( - description="Namespace the volume belongs to, in lowercase.", - title="Namespace", + description="Whether more items exist after this page.", title="Has More" ), ] - volume: Annotated[ - str, Field(description="Name of the volume, in lowercase.", title="Volume") - ] - version_ref: Annotated[ - str, + cursor: Annotated[ + str | None, Field( - description="Full address of the deleted version, as `bdn:/@`.", - title="Version Ref", + description="Opaque cursor to pass into the next request. Null when there is no next page.", + title="Cursor", ), + ] = None + + +class VolumeTag(BaseModel): + name: Annotated[ + str, Field(description="Tag name. Tags are case-sensitive.", title="Name") ] digest: Annotated[ str, Field( - description="Content digest of the deleted version, as `b3:`.", + description="Digest of the version the tag points at, as `b3:`.", title="Digest", ), ] - lifecycle: Annotated[ - str, + expires_at: Annotated[ + AwareDatetime | None, Field( - description="Lifecycle state of the version after the delete.", - title="Lifecycle", + description="When the tag stops resolving and leaves the volume, in ISO 8601 format. Null for a tag that never expires. The version it points at is not affected.", + title="Expires At", ), ] - delete_after: Annotated[ - AwareDatetime, + + +class VolumeVersionSummary(BaseModel): + digest: Annotated[ + str, Field( - description="When the version stops being restorable, in ISO 8601 format. Until then it can be returned to service.", - title="Delete After", + description="Content digest of the version, as `b3:`.", title="Digest" ), ] - volume_sequence: Annotated[ + total_size_bytes: Annotated[ int, Field( - description="Revision of the volume after the delete.", - title="Volume Sequence", + description="Total size of the version's files in bytes.", + title="Total Size Bytes", ), ] - - -class VolumeVersionDetail(BaseModel): - namespace: Annotated[ - str, + created_at: Annotated[ + AwareDatetime, Field( - description="Namespace the volume belongs to, in lowercase.", - title="Namespace", + description="When the version was committed, in ISO 8601 format.", + title="Created At", ), ] - volume: Annotated[ - str, Field(description="Name of the volume, in lowercase.", title="Volume") - ] - version_ref: Annotated[ - str, - Field( - description="Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", - title="Version Ref", - ), - ] - digest: Annotated[ - str, + + +class VolumeTokenScope(StrEnum): + PULL = "PULL" + INSPECT = "INSPECT" + PUSH = "PUSH" + TAG = "TAG" + + +class CorrelationId(RootModel[str]): + root: Annotated[ + str | None, Field( - description="Content digest of the version, as `b3:`.", title="Digest" + description="Optional client-chosen identifier, at most 128 printable ASCII characters. Echoed into server logs to link the issued token to a client operation.", + max_length=128, + pattern="^[\\x21-\\x7e]+$", + title="Correlation Id", ), - ] - sequence: Annotated[ - int | None, + ] = None + + +class CreateVolumeTokenRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + scopes: Annotated[ + list[VolumeTokenScope], Field( - description="Revision the version was committed at. Null for versions committed before the volume service recorded it.", - title="Sequence", + description="Capabilities the token grants, at least one. Requesting PUSH or TAG requires organization-level model management permission.", + min_length=1, + title="Scopes", ), ] - lifecycle: Annotated[ - str, + namespaces: Annotated[ + list[str], Field( - description="Lifecycle state of the version, for example ALIVE or TOMBSTONED.", - title="Lifecycle", + description="Volume namespaces the token is limited to, lowercase ASCII, at least one. Pass only the namespaces the operation needs.", + min_length=1, + title="Namespaces", ), ] - is_head: Annotated[ - bool, + volumes: Annotated[ + list[str], Field( - description="Whether the reserved `head` tag points at this version.", - title="Is Head", + description="Volume names the token is limited to, lowercase ASCII, exact names only, at least one. The limit applies to every requested scope in every requested namespace.", + min_length=1, + title="Volumes", ), ] - tags: Annotated[ - list[str], + correlation_id: Annotated[ + CorrelationId | None, Field( - description="Tags pointing at this version that your API key can read.", - title="Tags", + description="Optional client-chosen identifier, at most 128 printable ASCII characters. Echoed into server logs to link the issued token to a client operation.", + title="Correlation Id", ), - ] - total_size_bytes: Annotated[ - int | None, + ] = None + + +class CreateVolumeTokenResponse(BaseModel): + token: Annotated[ + str, Field( - description="Total size of the version's files in bytes. Null when not recorded.", - title="Total Size Bytes", + description="Volume access token. Pass as a bearer token to the volume APIs.", + title="Token", ), ] - created_at: Annotated[ + expires_at: Annotated[ AwareDatetime, Field( - description="When the version was committed, in ISO 8601 format.", - title="Created At", + description="Token expiry in ISO 8601 format. Tokens cannot be renewed; exchange again for a fresh token.", + title="Expires At", ), ] - tombstoned_at: Annotated[ - AwareDatetime | None, - Field( - description="When the version was deleted, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - title="Tombstoned At", - ), + scopes: Annotated[ + list[VolumeTokenScope], + Field(description="Effective capabilities granted.", title="Scopes"), ] - delete_after: Annotated[ - AwareDatetime | None, + namespaces: Annotated[ + list[str], Field( - description="When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - title="Delete After", + description="Effective namespaces granted, in canonical lowercase form.", + title="Namespaces", ), ] - entry_count: Annotated[ - int | None, + volumes: Annotated[ + list[str], Field( - description="Number of files in the version. Null when not recorded.", - title="Entry Count", + description="Effective volume names granted, in canonical lowercase form.", + title="Volumes", ), ] - volume_sequence: Annotated[ - int, + bdn_endpoint: Annotated[ + str | None, Field( - description="Revision of the volume as a whole when this version was read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since.", - title="Volume Sequence", + description="Base URL of the volume API this token authenticates against. Null when the environment does not expose a public volume API yet.", + title="Bdn Endpoint", ), ] -class RestoreVolumeVersionRequest(BaseModel): - expected_sequence: Annotated[ - int | None, - Field( - description="Revision the volume is expected to be at. When set, the restore fails with a conflict if the volume has changed since. Take the value from volume_sequence.", - title="Expected Sequence", - ), - ] = None +class ListVolumeNamespacesResponse(BaseModel): + items: Annotated[list[str], Field(description="Items in this page.", title="Items")] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] -class RestoreVolumeVersionResponse(BaseModel): - namespace: Annotated[ +class VolumeSyncAuthenticationAWSAssumeRole(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + role_arn: Annotated[ str, Field( - description="Namespace the volume belongs to, in lowercase.", - title="Namespace", + description="AWS IAM role ARN to assume.", min_length=1, title="Role Arn" ), ] - volume: Annotated[ - str, Field(description="Name of the volume, in lowercase.", title="Volume") - ] - version_ref: Annotated[ + region: Annotated[ str, Field( - description="Full address of the restored version, as `bdn:/@`.", - title="Version Ref", + description="AWS region for the assumed role session.", + min_length=1, + title="Region", ), ] - digest: Annotated[ + + +class VolumeSyncAuthenticationAWSOIDC(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + role_arn: Annotated[ str, Field( - description="Content digest of the restored version, as `b3:`.", - title="Digest", + description="AWS IAM role ARN to assume through OIDC.", + min_length=1, + title="Role Arn", ), ] - lifecycle: Annotated[ + region: Annotated[ str, Field( - description="Lifecycle state of the version after the restore.", - title="Lifecycle", - ), - ] - volume_sequence: Annotated[ - int, - Field( - description="Revision of the volume after the restore.", - title="Volume Sequence", + description="AWS region for the OIDC role session.", + min_length=1, + title="Region", ), ] -class Secret(BaseModel): - id: Annotated[ +class VolumeSyncAuthenticationGCPOIDC(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + service_account: Annotated[ str, Field( - description="Stable identifier for the secret. Unchanged across rotation.", - examples=["3kZ9xqd"], - title="Id", + description="GCP service account to impersonate through OIDC.", + min_length=1, + title="Service Account", ), ] - created_at: Annotated[ - AwareDatetime, + workload_identity_provider: Annotated[ + str, Field( - description="Time the secret was created in ISO 8601 format", - title="Created At", + description="Full resource name of the GCP workload identity provider.", + min_length=1, + title="Workload Identity Provider", ), ] - name: Annotated[str, Field(description="Name of the secret", title="Name")] - team_name: Annotated[ - str, - Field(description="Name of the team the secret belongs to", title="Team Name"), - ] - -class Secrets(BaseModel): - secrets: Annotated[list[Secret], Field(title="Secrets")] - -class UpsertSecretRequest(BaseModel): - name: Annotated[ +class VolumeSyncDestination(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + ref: Annotated[ str, Field( - description="Name of the new or existing secret", - examples=["my_secret"], - title="Name", + description="Destination as bdn:/ with an optional tag.", + title="Ref", ), ] - value: Annotated[ + + +class VolumeSyncError(BaseModel): + code: Annotated[ str, Field( - description="Value of the secret", - examples=["my_secret_value"], - title="Value", + description="Stable machine-readable failure classification.", title="Code" ), ] + message: Annotated[ + str, Field(description="Redacted user-facing failure message.", title="Message") + ] -class SecretTombstone(BaseModel): - name: Annotated[str, Field(description="Name of the deleted secret", title="Name")] - - -class EnvironmentGroupUser(BaseModel): - user_id: Annotated[ - str, Field(description="Unique identifier for the user.", title="User Id") - ] - email: Annotated[ - str | None, Field(description="Email address of the user.", title="Email") - ] = None - name: Annotated[ - str | None, Field(description="Display name of the user.", title="Name") +class AuthSecretName(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="Optional workspace secret containing credentials for this source.", + min_length=1, + title="Auth Secret Name", + ), ] = None -class UpdateEnvironmentGroupManageAccess(BaseModel): - is_restricted: Annotated[ - bool, +class VolumeSyncSourceAzure(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + uri: Annotated[ + str, Field( - description="Whether to restrict this environment to a specific set of users.", - title="Is Restricted", + description="Remote source URI to materialize into the destination volume.", + title="Uri", ), ] - user_ids: Annotated[ + include: Annotated[ list[str] | None, - Field( - description="IDs of users granted manage access while restricted. Only meaningful when is_restricted is true.", - title="User Ids", - ), + Field(description="Glob patterns selecting files to include.", title="Include"), ] = None - - -class UpdateEnvironmentGroupRequest(BaseModel): - manage_access: Annotated[ - UpdateEnvironmentGroupManageAccess | None, + exclude: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to exclude.", title="Exclude"), + ] = None + auth_secret_name: Annotated[ + AuthSecretName | None, Field( - description="Manage-access settings to apply. Omit to leave manage access unchanged." + description="Optional workspace secret containing credentials for this source.", + title="Auth Secret Name", ), ] = None + type: Annotated[ + Literal["AZURE"], + Field(description="Azure Blob Storage source type.", title="Type"), + ] -class Team(BaseModel): - id: Annotated[str, Field(description="Unique identifier of the team", title="Id")] - name: Annotated[str, Field(description="Name of the team", title="Name")] - default: Annotated[ - bool, +class VolumeSyncSourceBasetenTraining(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + uri: Annotated[ + str, Field( - description="Whether this is the default team for the organization", - title="Default", + description="Remote source URI to materialize into the destination volume.", + title="Uri", ), ] - created_at: Annotated[ - AwareDatetime, - Field( - description="Time the team was created in ISO 8601 format", - title="Created At", - ), + include: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to include.", title="Include"), + ] = None + exclude: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to exclude.", title="Exclude"), + ] = None + type: Annotated[ + Literal["BASETEN_TRAINING"], + Field(description="Baseten training artifact source type.", title="Type"), ] -class Teams(BaseModel): - teams: Annotated[list[Team], Field(description="A list of teams", title="Teams")] - - -class Region(BaseModel): - slug: Annotated[ +class VolumeSyncSourceCoreWeave(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + uri: Annotated[ str, Field( - description="Stable identifier for the region, used when selecting a deployment region.", - examples=["us"], - title="Slug", + description="Remote source URI to materialize into the destination volume.", + title="Uri", ), ] - display_name: Annotated[ - str, + include: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to include.", title="Include"), + ] = None + exclude: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to exclude.", title="Exclude"), + ] = None + auth_secret_name: Annotated[ + AuthSecretName | None, Field( - description="Human-readable name of the region.", - examples=["United States"], - title="Display Name", + description="Optional workspace secret containing credentials for this source.", + title="Auth Secret Name", ), + ] = None + type: Annotated[ + Literal["COREWEAVE"], + Field(description="CoreWeave object storage source type.", title="Type"), ] -class Regions(BaseModel): - regions: Annotated[list[Region], Field(title="Regions")] - - -class InstanceType(BaseModel): - id: Annotated[ - str, Field(description="Identifier string for the instance type", title="Id") - ] - name: Annotated[ - str, Field(description="Display name of the instance type", title="Name") - ] - memory_limit_mib: Annotated[ - int, +class VolumeSyncSourceGCS(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + uri: Annotated[ + str, Field( - description="Memory limit of the instance type in Mebibytes", - title="Memory Limit Mib", + description="Remote source URI to materialize into the destination volume.", + title="Uri", ), ] - millicpu_limit: Annotated[ - int, + include: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to include.", title="Include"), + ] = None + exclude: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to exclude.", title="Exclude"), + ] = None + auth_secret_name: Annotated[ + AuthSecretName | None, Field( - description="CPU limit of the instance type in millicpu", - title="Millicpu Limit", + description="Optional workspace secret containing credentials for this source.", + title="Auth Secret Name", ), + ] = None + type: Annotated[ + Literal["GCS"], + Field(description="Google Cloud Storage source type.", title="Type"), ] - gpu_count: Annotated[ - int, Field(description="Number of GPUs on the instance type", title="Gpu Count") - ] - gpu_type: Annotated[ - str | None, - Field(description="Type of GPU on the instance type", title="Gpu Type"), - ] - gpu_memory_limit_mib: Annotated[ - int | None, + gcp_oidc: Annotated[ + VolumeSyncAuthenticationGCPOIDC | None, Field( - description="Memory limit of the GPU on the instance type in Mebibytes", - title="Gpu Memory Limit Mib", + description="GCP OIDC authentication for this source. Cannot be combined with auth_secret_name." ), - ] - - -class InstanceTypes(BaseModel): - instance_types: Annotated[list[InstanceType], Field(title="Instance Types")] + ] = None -class LoopsUserConfig(BaseModel): - trainer_accelerator_priority: Annotated[ - list[str] | None, +class VolumeSyncSourceHuggingFace(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + uri: Annotated[ + str, Field( - description="Ordered allowlist of GPU types for your Loops trainer deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", - examples=[["H100", "H200"]], - title="Trainer Accelerator Priority", + description="Remote source URI to materialize into the destination volume.", + title="Uri", ), ] - sampler_accelerator_priority: Annotated[ + include: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to include.", title="Include"), + ] = None + exclude: Annotated[ list[str] | None, + Field(description="Glob patterns selecting files to exclude.", title="Exclude"), + ] = None + auth_secret_name: Annotated[ + AuthSecretName | None, Field( - description="Ordered allowlist of GPU types for your Loops sampler deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", - examples=[["H100", "H200"]], - title="Sampler Accelerator Priority", + description="Optional workspace secret containing credentials for this source.", + title="Auth Secret Name", ), + ] = None + type: Annotated[ + Literal["HUGGING_FACE"], + Field(description="Hugging Face source type.", title="Type"), ] -class GetLoopsUserConfigResponse(BaseModel): - user_config: Annotated[ - LoopsUserConfig, Field(description="The caller's Loops user config.") +class VolumeSyncSourceR2(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + uri: Annotated[ + str, + Field( + description="Remote source URI to materialize into the destination volume.", + title="Uri", + ), + ] + include: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to include.", title="Include"), + ] = None + exclude: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to exclude.", title="Exclude"), + ] = None + auth_secret_name: Annotated[ + AuthSecretName | None, + Field( + description="Optional workspace secret containing credentials for this source.", + title="Auth Secret Name", + ), + ] = None + type: Annotated[ + Literal["R2"], Field(description="Cloudflare R2 source type.", title="Type") ] -class PatchLoopsUserConfigRequest(BaseModel): - trainer_accelerator_priority: Annotated[ - list[str] | None, +class VolumeSyncSourceS3(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + uri: Annotated[ + str, Field( - description="Ordered list of GPU types for trainer deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", - examples=[["H100", "H200"]], - title="Trainer Accelerator Priority", + description="Remote source URI to materialize into the destination volume.", + title="Uri", ), + ] + include: Annotated[ + list[str] | None, + Field(description="Glob patterns selecting files to include.", title="Include"), ] = None - sampler_accelerator_priority: Annotated[ + exclude: Annotated[ list[str] | None, + Field(description="Glob patterns selecting files to exclude.", title="Exclude"), + ] = None + auth_secret_name: Annotated[ + AuthSecretName | None, Field( - description="Ordered list of GPU types for sampler deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", - examples=[["H100", "H200"]], - title="Sampler Accelerator Priority", + description="Optional workspace secret containing credentials for this source.", + title="Auth Secret Name", + ), + ] = None + type: Annotated[ + Literal["S3"], Field(description="Amazon S3 source type.", title="Type") + ] + aws_assume_role: Annotated[ + VolumeSyncAuthenticationAWSAssumeRole | None, + Field( + description="AWS AssumeRole authentication for this source. Cannot be combined with auth_secret_name." + ), + ] = None + aws_oidc: Annotated[ + VolumeSyncAuthenticationAWSOIDC | None, + Field( + description="AWS OIDC authentication for this source. Cannot be combined with other authentication fields." ), ] = None -class PatchLoopsUserConfigResponse(BaseModel): - user_config: Annotated[ - LoopsUserConfig, Field(description="The updated Loops user config.") - ] +class VolumeSyncStatus(StrEnum): + PENDING = "PENDING" + SYNCING = "SYNCING" + READY = "READY" + FAILED = "FAILED" + CANCELED = "CANCELED" -class InstanceTypeWithPrice(BaseModel): - instance_type: Annotated[ - InstanceType, Field(description="Instance type properties.") +class VolumeSync(BaseModel): + sync_id: Annotated[ + str, Field(description="Identifier of this sync operation.", title="Sync Id") ] - price: Annotated[ - float, Field(description="Usage price in USD / minute.", title="Price") + status: Annotated[ + VolumeSyncStatus, Field(description="Current lifecycle state of the sync.") ] - - -class InstanceTypePrices(BaseModel): - instance_types: Annotated[ - list[InstanceTypeWithPrice], Field(title="Instance Types") + source: Annotated[ + VolumeSyncSourceHuggingFace + | VolumeSyncSourceS3 + | VolumeSyncSourceGCS + | VolumeSyncSourceAzure + | VolumeSyncSourceR2 + | VolumeSyncSourceCoreWeave + | VolumeSyncSourceBasetenTraining, + Field( + description="Remote source being synced.", + discriminator="type", + title="Source", + ), ] - - -class DeploymentArchivePayload(BaseModel): - config: Annotated[ - dict[str, Any], - Field(description="Parsed model config as a JSON object.", title="Config"), + destination: Annotated[ + VolumeSyncDestination, Field(description="BDN volume being populated.") ] - raw_config: Annotated[ + volume_version_id: Annotated[ str | None, Field( - description="Original config.yaml text, persisted as-is on the deployment. Best-effort: invalid raw configs are logged and dropped without failing the request.", - title="Raw Config", - ), - ] = None - user_env: Annotated[ - dict[str, Any] | None, - Field( - description="Client environment metadata (e.g. client version, Python version). Validated server-side.", - title="User Env", + description="Produced artifact identifier; null until the sync is ready.", + title="Volume Version Id", ), ] = None - environment_name: Annotated[ + version_ref: Annotated[ str | None, Field( - description="Stable environment to push to (e.g. `production`). If unset, the deployment is created without environment selection. Caller must have push permission for the named environment.", - title="Environment Name", + description="Immutable BDN reference; null until the sync is ready.", + title="Version Ref", ), ] = None - create_environment_if_missing: Annotated[ - bool, - Field( - description="Create the environment named by `environment_name` if it does not exist yet. If false, a push to an environment that does not exist is rejected. Only meaningful when `environment_name` is set to something other than `production`, which always exists. This field currently defaults to true, but that default will change to false in a future release. Set it explicitly to avoid a behavior change.", - title="Create Environment If Missing", - ), - ] = True - region: Annotated[ + content_digest: Annotated[ str | None, - Field(description="Region in which to deploy the model", title="Region"), - ] = None - preserve_env_instance_type: Annotated[ - bool, Field( - description="Retain the target environment's current instance type rather than the one in `config`. Only meaningful when `environment_name` is set and that environment already exists.", - title="Preserve Env Instance Type", + description="BLAKE3 digest of the synced content; null until available.", + title="Content Digest", ), - ] = True - deploy_timeout_minutes: Annotated[ + ] = None + total_size_bytes: Annotated[ int | None, Field( - description="Deploy timeout in minutes; allowed range 10 to 1440. Server default applies if unset.", - title="Deploy Timeout Minutes", + description="Total size of the synced content in bytes; null until available.", + title="Total Size Bytes", ), ] = None - deployment_name: Annotated[ - str | None, + created_at: Annotated[ + AwareDatetime, + Field(description="Time at which the sync was created.", title="Created At"), + ] + completed_at: Annotated[ + AwareDatetime | None, Field( - description="Optional human-readable name for the deployment.", - title="Deployment Name", + description="Time at which the sync reached a terminal state.", + title="Completed At", ), ] = None - labels: Annotated[ - dict[str, Any] | None, - Field( - description="User-provided key-value labels for the deployment.", - title="Labels", - ), + error: Annotated[ + VolumeSyncError | None, + Field(description="Redacted failure details; null unless the sync failed."), ] = None - is_development: Annotated[ - bool, - Field( - description="If true, push as a development deployment: the model's single mutable dev slot, created if absent and overwritten in place otherwise. The following fields must be left at their defaults: `environment_name`, `preserve_env_instance_type`, `deployment_name`.", - title="Is Development", - ), - ] = False -class PrepareModelUploadRequest(BaseModel): - deployment: Annotated[ - DeploymentArchivePayload, - Field( - description="Deployment-level payload, identical to the payload sent at commit." - ), +class VolumeSyncs(BaseModel): + items: Annotated[ + list[VolumeSync], Field(description="Items in this page.", title="Items") ] - name: Annotated[ - str | None, + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class CreateVolumeSyncRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + source: Annotated[ + VolumeSyncSourceHuggingFace + | VolumeSyncSourceS3 + | VolumeSyncSourceGCS + | VolumeSyncSourceAzure + | VolumeSyncSourceR2 + | VolumeSyncSourceCoreWeave + | VolumeSyncSourceBasetenTraining, + Field( + description="Remote source to sync from.", + discriminator="type", + title="Source", + ), + ] + destination: Annotated[ + VolumeSyncDestination, Field(description="BDN volume to sync into.") + ] + + +class DeleteVolumeRequest(BaseModel): + expected_sequence: Annotated[ + int | None, Field( - description="Set to validate a new-model push. Exactly one of `name` or `model_id` is required.", - title="Name", + description="Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so it cannot act on a volume someone else has pushed to. Take the value from a volume's sequence, or from volume_sequence.", + title="Expected Sequence", ), ] = None - team_id: Annotated[ - str | None, + + +class DeleteVolumeResponse(BaseModel): + namespace: Annotated[ + str, Field( - description="Team the new model will belong to. Only valid when `name` is set; defaults to the organization's default team when omitted. Must not be set when `model_id` is set (the existing model already has a team).", - title="Team Id", + description="Namespace the volume belongs to, in lowercase.", + title="Namespace", ), - ] = None - model_id: Annotated[ - str | None, + ] + name: Annotated[ + str, Field(description="Name of the volume, in lowercase.", title="Name") + ] + versions_deleted: Annotated[ + int, Field( - description="Set to validate an add-deployment push to an existing model. Exactly one of `name` or `model_id` is required.", - title="Model Id", + description="Number of versions this request deleted. Zero when the volume had no live versions left, which is not an error.", + title="Versions Deleted", ), - ] = None - dry_run: Annotated[ - bool, + ] + volume_sequence: Annotated[ + int, Field( - description="If true, validate the payload only and do not issue upload credentials. The response sets `creds`, `s3_bucket`, and `s3_key` to `null`.", - title="Dry Run", + description="Revision of the volume after the delete.", + title="Volume Sequence", ), - ] = False + ] -class AWSCredentials(BaseModel): - aws_access_key_id: Annotated[ - str, Field(description="The AWS access key ID", title="Aws Access Key Id") +class VolumeVersion(BaseModel): + namespace: Annotated[ + str, + Field( + description="Namespace the volume belongs to, in lowercase.", + title="Namespace", + ), ] - aws_secret_access_key: Annotated[ + volume: Annotated[ + str, Field(description="Name of the volume, in lowercase.", title="Volume") + ] + version_ref: Annotated[ str, - Field(description="The AWS secret access key", title="Aws Secret Access Key"), + Field( + description="Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", + title="Version Ref", + ), ] - aws_session_token: Annotated[ - str, Field(description="The AWS session token", title="Aws Session Token") + digest: Annotated[ + str, + Field( + description="Content digest of the version, as `b3:`.", title="Digest" + ), ] - - -class PrepareModelUploadResponse(BaseModel): - creds: Annotated[ - AWSCredentials | None, + sequence: Annotated[ + int | None, Field( - description="STS credentials to upload the model archive. Null when no archive upload is required." + description="Revision the version was committed at. Null for versions committed before the volume service recorded it.", + title="Sequence", ), - ] = None - s3_bucket: Annotated[ - str | None, + ] + lifecycle: Annotated[ + str, Field( - description="S3 bucket the credentials are scoped to. Null when no archive upload is required.", - title="S3 Bucket", + description="Lifecycle state of the version: ALIVE, or TOMBSTONED once it has been deleted or has expired.", + title="Lifecycle", ), - ] = None - s3_key: Annotated[ - str | None, + ] + is_head: Annotated[ + bool, Field( - description="S3 key the credentials are scoped to. Pass this to `POST /v1/models` (in the `model_archive` source) once the upload completes. Null when no archive upload is required.", - title="S3 Key", + description="Whether the reserved `head` tag points at this version.", + title="Is Head", ), - ] = None - s3_region: Annotated[ - str | None, + ] + tags: Annotated[ + list[str], Field( - description="AWS region the S3 bucket resides in. Null when no archive upload is required.", - title="S3 Region", + description="Tags pointing at this version that your API key can read.", + title="Tags", ), - ] = None - - -class AuditLogActorType(StrEnum): - USER = "USER" - API_KEY = "API_KEY" - BASETEN_USER = "BASETEN_USER" - BASETEN_SYSTEM = "BASETEN_SYSTEM" - TOMBSTONE_USER = "TOMBSTONE_USER" - - -class AuditLogActor(BaseModel): - type: Annotated[ - AuditLogActorType, Field(description="Kind of actor that performed the action.") ] - email: Annotated[ - str | None, + total_size_bytes: Annotated[ + int | None, Field( - description="Email of the acting user, when the actor is a user.", - title="Email", + description="Total size of the version's files in bytes. Null when not recorded.", + title="Total Size Bytes", ), - ] = None - api_key_prefix: Annotated[ - str | None, + ] + created_at: Annotated[ + AwareDatetime, Field( - description="Prefix of the acting API key, when the actor is an API key.", - title="Api Key Prefix", + description="When the version was committed, in ISO 8601 format.", + title="Created At", ), - ] = None - api_key_name: Annotated[ - str | None, + ] + expires_at: Annotated[ + AwareDatetime | None, Field( - description="Display name of the acting API key, when the actor is an API key.", - title="Api Key Name", + description="When the version expires, in ISO 8601 format. At that instant it becomes TOMBSTONED with `tombstoned_at` set to this value, and every tag pointing at it drops. Null for a version that never expires, and null once the lifecycle is TOMBSTONED.", + title="Expires At", ), - ] = None - - -class AuditLogApiKeyType(StrEnum): - PERSONAL = "PERSONAL" - CREATOR_SERVICE_ACCOUNT = "CREATOR_SERVICE_ACCOUNT" - MANAGE_API_KEYS_SERVICE_ACCOUNT = "MANAGE_API_KEYS_SERVICE_ACCOUNT" - INVOKE_ALL_MODELS_SERVICE_ACCOUNT = "INVOKE_ALL_MODELS_SERVICE_ACCOUNT" - INVOKE_ALLOWED_MODELS_SERVICE_ACCOUNT = "INVOKE_ALLOWED_MODELS_SERVICE_ACCOUNT" - INVOKE_SCOPED_ENVS_AND_MODELS_SERVICE_ACCOUNT = ( - "INVOKE_SCOPED_ENVS_AND_MODELS_SERVICE_ACCOUNT" - ) - EXPORT_METRICS_ALL_MODELS_SERVICE_ACCOUNT = ( - "EXPORT_METRICS_ALL_MODELS_SERVICE_ACCOUNT" - ) - EXPORT_METRICS_ALLOWED_MODELS_SERVICE_ACCOUNT = ( - "EXPORT_METRICS_ALLOWED_MODELS_SERVICE_ACCOUNT" - ) - INVOKE_ALL_SHARED_ENDPOINTS_SERVICE_ACCOUNT = ( - "INVOKE_ALL_SHARED_ENDPOINTS_SERVICE_ACCOUNT" - ) - INVOKE_ALLOWED_SHARED_ENDPOINTS_SERVICE_ACCOUNT = ( - "INVOKE_ALLOWED_SHARED_ENDPOINTS_SERVICE_ACCOUNT" - ) - INVOKE_ALL_ROUTES = "INVOKE_ALL_ROUTES" - - -class AuditLogEventApiKeyCreated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["API_KEY_CREATED"], Field(title="Event Type")] - api_key_id: Annotated[str, Field(title="Api Key Id")] - api_key_type: AuditLogApiKeyType - prefix: Annotated[str, Field(title="Prefix")] + ] + tombstoned_at: Annotated[ + AwareDatetime | None, + Field( + description="When the version was deleted or expired, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + title="Tombstoned At", + ), + ] + delete_after: Annotated[ + AwareDatetime | None, + Field( + description="When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + title="Delete After", + ), + ] -class AuditLogEventApiKeyDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["API_KEY_DELETED"], Field(title="Event Type")] - api_key_id: Annotated[str, Field(title="Api Key Id")] - api_key_type: AuditLogApiKeyType - prefix: Annotated[str, Field(title="Prefix")] +class ListVolumeVersionsResponse(BaseModel): + versions: Annotated[ + list[VolumeVersion], + Field(description="Versions of the volume, newest first.", title="Versions"), + ] + volume_sequence: Annotated[ + int, + Field( + description="Revision of the volume as a whole when the versions were read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since. Distinct from the per-version sequence, which is the revision a version was committed at.", + title="Volume Sequence", + ), + ] -class AuditLogEventAutoscalingScheduleAction(StrEnum): - CREATED = "CREATED" - UPDATED = "UPDATED" - DELETED = "DELETED" - UNCHANGED = "UNCHANGED" +class DeleteVolumeVersionRequest(BaseModel): + expected_sequence: Annotated[ + int | None, + Field( + description="Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so a read followed by a delete cannot act on a version a tag has since been moved off. Take the value from volume_sequence.", + title="Expected Sequence", + ), + ] = None -class AuditLogEventAutoscalingScheduleSettings(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - min_replica: Annotated[int, Field(title="Min Replica")] - max_replica: Annotated[int, Field(title="Max Replica")] - concurrency_target: Annotated[int | None, Field(title="Concurrency Target")] - autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] - scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] - target_utilization_percentage: Annotated[ - int | None, Field(title="Target Utilization Percentage") +class DeleteVolumeVersionResponse(BaseModel): + namespace: Annotated[ + str, + Field( + description="Namespace the volume belongs to, in lowercase.", + title="Namespace", + ), ] - target_in_flight_tokens: Annotated[ - int | None, Field(title="Target In Flight Tokens") + volume: Annotated[ + str, Field(description="Name of the volume, in lowercase.", title="Volume") ] - max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] - schedule_name: Annotated[str, Field(title="Schedule Name")] - enabled: Annotated[bool, Field(title="Enabled")] - cadence: Annotated[str, Field(title="Cadence")] - timezone: Annotated[str, Field(title="Timezone")] - weekdays: Annotated[list[str] | None, Field(title="Weekdays")] - start_hour: Annotated[int | None, Field(title="Start Hour")] - start_minute: Annotated[int | None, Field(title="Start Minute")] - end_hour: Annotated[int | None, Field(title="End Hour")] - end_minute: Annotated[int | None, Field(title="End Minute")] - start_at: Annotated[str | None, Field(title="Start At")] = None - end_at: Annotated[str | None, Field(title="End At")] = None - - -class AuditLogEventAutoscalingSettings(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - min_replica: Annotated[int, Field(title="Min Replica")] - max_replica: Annotated[int, Field(title="Max Replica")] - concurrency_target: Annotated[int, Field(title="Concurrency Target")] - autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] - scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] - target_utilization_percentage: Annotated[ - int | None, Field(title="Target Utilization Percentage") + version_ref: Annotated[ + str, + Field( + description="Full address of the deleted version, as `bdn:/@`.", + title="Version Ref", + ), ] - target_in_flight_tokens: Annotated[ - int | None, Field(title="Target In Flight Tokens") + digest: Annotated[ + str, + Field( + description="Content digest of the deleted version, as `b3:`.", + title="Digest", + ), ] - max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] - - -class AuditLogEventChainDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["CHAIN_DELETED"], Field(title="Event Type")] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] - - -class AuditLogEventChainDeployed(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["CHAIN_DEPLOYED"], Field(title="Event Type")] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] - chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] - is_primary: Annotated[bool, Field(title="Is Primary")] - publish: Annotated[bool, Field(title="Publish")] - - -class AuditLogEventChainDeploymentActivated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["CHAIN_DEPLOYMENT_ACTIVATED"], Field(title="Event Type") + lifecycle: Annotated[ + str, + Field( + description="Lifecycle state of the version after the delete.", + title="Lifecycle", + ), ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] - chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] - - -class AuditLogEventChainDeploymentDeactivated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["CHAIN_DEPLOYMENT_DEACTIVATED"], Field(title="Event Type") + delete_after: Annotated[ + AwareDatetime, + Field( + description="When the version stops being restorable, in ISO 8601 format. Until then it can be returned to service.", + title="Delete After", + ), ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] - chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] - - -class AuditLogEventChainDeploymentDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["CHAIN_DEPLOYMENT_DELETED"], Field(title="Event Type") + volume_sequence: Annotated[ + int, + Field( + description="Revision of the volume after the delete.", + title="Volume Sequence", + ), ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] - deployment_name: Annotated[str | None, Field(title="Deployment Name")] -class AuditLogEventChainDeploymentPromoted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["CHAIN_DEPLOYMENT_PROMOTED"], Field(title="Event Type") +class VolumeVersionDetail(BaseModel): + namespace: Annotated[ + str, + Field( + description="Namespace the volume belongs to, in lowercase.", + title="Namespace", + ), ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] - chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] - environment_name: Annotated[str | None, Field(title="Environment Name")] - environment_id: Annotated[str | None, Field(title="Environment Id")] - - -class AuditLogEventChainEnvironmentCreated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["CHAIN_ENVIRONMENT_CREATED"], Field(title="Event Type") + volume: Annotated[ + str, Field(description="Name of the volume, in lowercase.", title="Volume") ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - environment_name: Annotated[str, Field(title="Environment Name")] - redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] - ramp_up_while_promoting: Annotated[ - bool | None, Field(title="Ramp Up While Promoting") + version_ref: Annotated[ + str, + Field( + description="Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", + title="Version Ref", + ), ] - ramp_up_duration_seconds: Annotated[ - int | None, Field(title="Ramp Up Duration Seconds") + digest: Annotated[ + str, + Field( + description="Content digest of the version, as `b3:`.", title="Digest" + ), ] - - -class AuditLogEventChainEnvironmentUpdated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["CHAIN_ENVIRONMENT_UPDATED"], Field(title="Event Type") + sequence: Annotated[ + int | None, + Field( + description="Revision the version was committed at. Null for versions committed before the volume service recorded it.", + title="Sequence", + ), ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - environment_name: Annotated[str, Field(title="Environment Name")] - redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] - ramp_up_while_promoting: Annotated[ - bool | None, Field(title="Ramp Up While Promoting") + lifecycle: Annotated[ + str, + Field( + description="Lifecycle state of the version: ALIVE, or TOMBSTONED once it has been deleted or has expired.", + title="Lifecycle", + ), ] - ramp_up_duration_seconds: Annotated[ - int | None, Field(title="Ramp Up Duration Seconds") + is_head: Annotated[ + bool, + Field( + description="Whether the reserved `head` tag points at this version.", + title="Is Head", + ), ] - - -class AuditLogEventChainletAutoscalingSettingsChanged(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - min_replica: Annotated[int, Field(title="Min Replica")] - max_replica: Annotated[int, Field(title="Max Replica")] - concurrency_target: Annotated[int, Field(title="Concurrency Target")] - autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] - scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] - target_utilization_percentage: Annotated[ - int | None, Field(title="Target Utilization Percentage") + tags: Annotated[ + list[str], + Field( + description="Tags pointing at this version that your API key can read.", + title="Tags", + ), ] - target_in_flight_tokens: Annotated[ - int | None, Field(title="Target In Flight Tokens") + total_size_bytes: Annotated[ + int | None, + Field( + description="Total size of the version's files in bytes. Null when not recorded.", + title="Total Size Bytes", + ), ] - max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] - event_type: Annotated[ - Literal["CHAINLET_AUTOSCALING_SETTINGS_CHANGED"], Field(title="Event Type") + created_at: Annotated[ + AwareDatetime, + Field( + description="When the version was committed, in ISO 8601 format.", + title="Created At", + ), ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] - chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] - chainlet_name: Annotated[str, Field(title="Chainlet Name")] - chainlet_id: Annotated[str, Field(title="Chainlet Id")] - previous_settings: AuditLogEventAutoscalingSettings | None - - -class AuditLogEventChainletInstanceTypeChanged(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["CHAINLET_INSTANCE_TYPE_CHANGED"], Field(title="Event Type") + expires_at: Annotated[ + AwareDatetime | None, + Field( + description="When the version expires, in ISO 8601 format. At that instant it becomes TOMBSTONED with `tombstoned_at` set to this value, and every tag pointing at it drops. Null for a version that never expires, and null once the lifecycle is TOMBSTONED.", + title="Expires At", + ), ] - chain_id: Annotated[str, Field(title="Chain Id")] - chain_name: Annotated[str, Field(title="Chain Name")] - chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] - chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] - chainlet_name: Annotated[str, Field(title="Chainlet Name")] - chainlet_id: Annotated[str, Field(title="Chainlet Id")] - instance_type_name: Annotated[str, Field(title="Instance Type Name")] - - -class AuditLogEventDirectoryGroupRoleUpdated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["DIRECTORY_GROUP_ROLE_UPDATED"], Field(title="Event Type") + tombstoned_at: Annotated[ + AwareDatetime | None, + Field( + description="When the version was deleted or expired, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + title="Tombstoned At", + ), ] - directory_group_id: Annotated[str, Field(title="Directory Group Id")] - directory_group_name: Annotated[str, Field(title="Directory Group Name")] - new_role_name: Annotated[str, Field(title="New Role Name")] - team_id: Annotated[str | None, Field(title="Team Id")] - team_name: Annotated[str | None, Field(title="Team Name")] - - -class AuditLogEventEnvironmentCreated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - min_replica: Annotated[int, Field(title="Min Replica")] - max_replica: Annotated[int, Field(title="Max Replica")] - concurrency_target: Annotated[int, Field(title="Concurrency Target")] - autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] - scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] - target_utilization_percentage: Annotated[ - int | None, Field(title="Target Utilization Percentage") + delete_after: Annotated[ + AwareDatetime | None, + Field( + description="When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + title="Delete After", + ), ] - target_in_flight_tokens: Annotated[ - int | None, Field(title="Target In Flight Tokens") + entry_count: Annotated[ + int | None, + Field( + description="Number of files in the version. Null when not recorded.", + title="Entry Count", + ), ] - max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] - redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] - rolling_deploy: Annotated[bool | None, Field(title="Rolling Deploy")] - rolling_deploy_strategy: Annotated[ - str | None, Field(title="Rolling Deploy Strategy") + volume_sequence: Annotated[ + int, + Field( + description="Revision of the volume as a whole when this version was read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since.", + title="Volume Sequence", + ), ] - max_unavailable_percent: Annotated[ - int | None, Field(title="Max Unavailable Percent") + + +class RestoreVolumeVersionRequest(BaseModel): + expected_sequence: Annotated[ + int | None, + Field( + description="Revision the volume is expected to be at. When set, the restore fails with a conflict if the volume has changed since. Take the value from volume_sequence.", + title="Expected Sequence", + ), + ] = None + + +class RestoreVolumeVersionResponse(BaseModel): + namespace: Annotated[ + str, + Field( + description="Namespace the volume belongs to, in lowercase.", + title="Namespace", + ), ] - max_surge_percent: Annotated[int | None, Field(title="Max Surge Percent")] - stabilization_time_seconds: Annotated[ - int | None, Field(title="Stabilization Time Seconds") + volume: Annotated[ + str, Field(description="Name of the volume, in lowercase.", title="Volume") ] - replica_overhead_percent: Annotated[ - int | None, Field(title="Replica Overhead Percent") + version_ref: Annotated[ + str, + Field( + description="Full address of the restored version, as `bdn:/@`.", + title="Version Ref", + ), ] - promotion_cleanup_strategy: Annotated[ - str | None, Field(title="Promotion Cleanup Strategy") + digest: Annotated[ + str, + Field( + description="Content digest of the restored version, as `b3:`.", + title="Digest", + ), ] - ramp_up_while_promoting: Annotated[ - bool | None, Field(title="Ramp Up While Promoting") + lifecycle: Annotated[ + str, + Field( + description="Lifecycle state of the version after the restore.", + title="Lifecycle", + ), ] - ramp_up_duration_seconds: Annotated[ - int | None, Field(title="Ramp Up Duration Seconds") + volume_sequence: Annotated[ + int, + Field( + description="Revision of the volume after the restore.", + title="Volume Sequence", + ), ] - ramp_up_step_size: Annotated[int | None, Field(title="Ramp Up Step Size")] - request_backpressure_policy: Annotated[ - str | None, Field(title="Request Backpressure Policy") - ] = None - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - environment_name: Annotated[str, Field(title="Environment Name")] - deployment_type: Annotated[str | None, Field(title="Deployment Type")] - event_type: Annotated[Literal["ENVIRONMENT_CREATED"], Field(title="Event Type")] -class AuditLogEventEnvironmentDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["ENVIRONMENT_DELETED"], Field(title="Event Type")] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - environment_name: Annotated[str, Field(title="Environment Name")] +class TokenScope(StrEnum): + sandboxes = "sandboxes" -class AuditLogEventEnvironmentSettings(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - min_replica: Annotated[int, Field(title="Min Replica")] - max_replica: Annotated[int, Field(title="Max Replica")] - concurrency_target: Annotated[int, Field(title="Concurrency Target")] - autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] - scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] - target_utilization_percentage: Annotated[ - int | None, Field(title="Target Utilization Percentage") - ] - target_in_flight_tokens: Annotated[ - int | None, Field(title="Target In Flight Tokens") +class CreateTokenRequest(BaseModel): + scopes: Annotated[ + list[TokenScope], + Field( + description="What the token should grant access to. Only `sandboxes` is supported today; the token then authenticates against the sandbox API.", + examples=[["sandboxes"]], + min_length=1, + title="Scopes", + ), ] - max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] - redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] - rolling_deploy: Annotated[bool | None, Field(title="Rolling Deploy")] - rolling_deploy_strategy: Annotated[ - str | None, Field(title="Rolling Deploy Strategy") + + +class Token(BaseModel): + token: Annotated[ + str, + Field( + description="Short-lived bearer token for the sandbox API. Send it as Authorization: Bearer .", + title="Token", + ), ] - max_unavailable_percent: Annotated[ - int | None, Field(title="Max Unavailable Percent") + expires_at: Annotated[ + AwareDatetime, + Field( + description="Token expiry in ISO 8601 format. Tokens cannot be renewed; request a new one.", + title="Expires At", + ), ] - max_surge_percent: Annotated[int | None, Field(title="Max Surge Percent")] - stabilization_time_seconds: Annotated[ - int | None, Field(title="Stabilization Time Seconds") + + +class Secret(BaseModel): + id: Annotated[ + str, + Field( + description="Stable identifier for the secret. Unchanged across rotation.", + examples=["3kZ9xqd"], + title="Id", + ), ] - replica_overhead_percent: Annotated[ - int | None, Field(title="Replica Overhead Percent") + created_at: Annotated[ + AwareDatetime, + Field( + description="Time the secret was created in ISO 8601 format", + title="Created At", + ), ] - promotion_cleanup_strategy: Annotated[ - str | None, Field(title="Promotion Cleanup Strategy") + name: Annotated[str, Field(description="Name of the secret", title="Name")] + team_name: Annotated[ + str, + Field(description="Name of the team the secret belongs to", title="Team Name"), ] - ramp_up_while_promoting: Annotated[ - bool | None, Field(title="Ramp Up While Promoting") + + +class Secrets(BaseModel): + secrets: Annotated[list[Secret], Field(title="Secrets")] + + +class UpsertSecretRequest(BaseModel): + name: Annotated[ + str, + Field( + description="Name of the new or existing secret", + examples=["my_secret"], + title="Name", + ), ] - ramp_up_duration_seconds: Annotated[ - int | None, Field(title="Ramp Up Duration Seconds") + value: Annotated[ + str, + Field( + description="Value of the secret", + examples=["my_secret_value"], + title="Value", + ), ] - ramp_up_step_size: Annotated[int | None, Field(title="Ramp Up Step Size")] - request_backpressure_policy: Annotated[ - str | None, Field(title="Request Backpressure Policy") - ] = None -class AuditLogEventGatewayEndpointCreated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["GATEWAY_ENDPOINT_CREATED"], Field(title="Event Type") - ] - gateway_endpoint_id: Annotated[str, Field(title="Gateway Endpoint Id")] - slug: Annotated[str, Field(title="Slug")] +class SecretTombstone(BaseModel): + name: Annotated[str, Field(description="Name of the deleted secret", title="Name")] -class AuditLogEventGatewayEndpointDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["GATEWAY_ENDPOINT_DELETED"], Field(title="Event Type") +class EnvironmentGroupUser(BaseModel): + user_id: Annotated[ + str, Field(description="Unique identifier for the user.", title="User Id") ] - gateway_endpoint_id: Annotated[str, Field(title="Gateway Endpoint Id")] - slug: Annotated[str, Field(title="Slug")] + email: Annotated[ + str | None, Field(description="Email address of the user.", title="Email") + ] = None + name: Annotated[ + str | None, Field(description="Display name of the user.", title="Name") + ] = None -class AuditLogEventGatewayEndpointUpdated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["GATEWAY_ENDPOINT_UPDATED"], Field(title="Event Type") +class UpdateEnvironmentGroupManageAccess(BaseModel): + is_restricted: Annotated[ + bool, + Field( + description="Whether to restrict this environment to a specific set of users.", + title="Is Restricted", + ), ] - gateway_endpoint_id: Annotated[str, Field(title="Gateway Endpoint Id")] - slug: Annotated[str, Field(title="Slug")] - previous_slug: Annotated[str | None, Field(title="Previous Slug")] - - -class AuditLogEventModelDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["MODEL_DELETED"], Field(title="Event Type")] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] + user_ids: Annotated[ + list[str] | None, + Field( + description="IDs of users granted manage access while restricted. Only meaningful when is_restricted is true.", + title="User Ids", + ), + ] = None -class AuditLogEventModelDeployed(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["MODEL_DEPLOYED"], Field(title="Event Type")] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - scale_previous_to_zero: Annotated[bool, Field(title="Scale Previous To Zero")] - trusted: Annotated[bool, Field(title="Trusted")] - publish: Annotated[bool, Field(title="Publish")] - environment_name: Annotated[str | None, Field(title="Environment Name")] +class UpdateEnvironmentGroupRequest(BaseModel): + manage_access: Annotated[ + UpdateEnvironmentGroupManageAccess | None, + Field( + description="Manage-access settings to apply. Omit to leave manage access unchanged." + ), + ] = None -class AuditLogEventModelDeploymentActivated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_ACTIVATED"], Field(title="Event Type") +class Team(BaseModel): + id: Annotated[str, Field(description="Unique identifier of the team", title="Id")] + name: Annotated[str, Field(description="Name of the team", title="Name")] + default: Annotated[ + bool, + Field( + description="Whether this is the default team for the organization", + title="Default", + ), ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - - -class AuditLogEventModelDeploymentDeactivated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_DEACTIVATED"], Field(title="Event Type") + created_at: Annotated[ + AwareDatetime, + Field( + description="Time the team was created in ISO 8601 format", + title="Created At", + ), ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] -class AuditLogEventModelDeploymentDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_DELETED"], Field(title="Event Type") - ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] +class Teams(BaseModel): + teams: Annotated[list[Team], Field(description="A list of teams", title="Teams")] -class AuditLogEventModelDeploymentInstanceTypeChanged(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED"], Field(title="Event Type") +class Region(BaseModel): + slug: Annotated[ + str, + Field( + description="Stable identifier for the region, used when selecting a deployment region.", + examples=["us"], + title="Slug", + ), ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - instance_type_name: Annotated[str, Field(title="Instance Type Name")] - - -class AuditLogEventModelDeploymentPromoted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_PROMOTED"], Field(title="Event Type") + display_name: Annotated[ + str, + Field( + description="Human-readable name of the region.", + examples=["United States"], + title="Display Name", + ), ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - environment_name: Annotated[str | None, Field(title="Environment Name")] - environment_id: Annotated[str | None, Field(title="Environment Id")] -class AuditLogEventModelDeploymentRequestBackpressureSettingsChanged(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED"], - Field(title="Event Type"), - ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - policy: Annotated[str | None, Field(title="Policy")] = None - previous_policy: Annotated[str | None, Field(title="Previous Policy")] = None +class Regions(BaseModel): + regions: Annotated[list[Region], Field(title="Regions")] -class AuditLogEventModelDeploymentRetried(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_RETRIED"], Field(title="Event Type") +class InstanceType(BaseModel): + id: Annotated[ + str, Field(description="Identifier string for the instance type", title="Id") + ] + name: Annotated[ + str, Field(description="Display name of the instance type", title="Name") + ] + memory_limit_mib: Annotated[ + int, + Field( + description="Memory limit of the instance type in Mebibytes", + title="Memory Limit Mib", + ), + ] + millicpu_limit: Annotated[ + int, + Field( + description="CPU limit of the instance type in millicpu", + title="Millicpu Limit", + ), + ] + gpu_count: Annotated[ + int, Field(description="Number of GPUs on the instance type", title="Gpu Count") + ] + gpu_type: Annotated[ + str | None, + Field(description="Type of GPU on the instance type", title="Gpu Type"), + ] + gpu_memory_limit_mib: Annotated[ + int | None, + Field( + description="Memory limit of the GPU on the instance type in Mebibytes", + title="Gpu Memory Limit Mib", + ), ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - retried: Annotated[bool, Field(title="Retried")] -class AuditLogEventReplicaTerminated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["REPLICA_TERMINATED"], Field(title="Event Type")] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - replica_id: Annotated[str, Field(title="Replica Id")] +class InstanceTypes(BaseModel): + instance_types: Annotated[list[InstanceType], Field(title="Instance Types")] -class AuditLogEventRequireGroupBasedAdminsEnabled(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["REQUIRE_GROUP_BASED_ADMINS_ENABLED"], Field(title="Event Type") +class LoopsUserConfig(BaseModel): + trainer_accelerator_priority: Annotated[ + list[str] | None, + Field( + description="Ordered allowlist of GPU types for your Loops trainer deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", + examples=[["H100", "H200"]], + title="Trainer Accelerator Priority", + ), + ] + sampler_accelerator_priority: Annotated[ + list[str] | None, + Field( + description="Ordered allowlist of GPU types for your Loops sampler deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", + examples=[["H100", "H200"]], + title="Sampler Accelerator Priority", + ), ] - organization_id: Annotated[str, Field(title="Organization Id")] -class AuditLogEventSecretDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["SECRET_DELETED"], Field(title="Event Type")] - secret_id: Annotated[str, Field(title="Secret Id")] - secret_name: Annotated[str, Field(title="Secret Name")] +class GetLoopsUserConfigResponse(BaseModel): + user_config: Annotated[ + LoopsUserConfig, Field(description="The caller's Loops user config.") + ] -class AuditLogEventSecretUpdated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["SECRET_UPDATED"], Field(title="Event Type")] - secret_id: Annotated[str, Field(title="Secret Id")] - secret_name: Annotated[str, Field(title="Secret Name")] +class PatchLoopsUserConfigRequest(BaseModel): + trainer_accelerator_priority: Annotated[ + list[str] | None, + Field( + description="Ordered list of GPU types for trainer deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", + examples=[["H100", "H200"]], + title="Trainer Accelerator Priority", + ), + ] = None + sampler_accelerator_priority: Annotated[ + list[str] | None, + Field( + description="Ordered list of GPU types for sampler deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", + examples=[["H100", "H200"]], + title="Sampler Accelerator Priority", + ), + ] = None -class AuditLogEventSshCertificateSigned(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["SSH_CERTIFICATE_SIGNED"], Field(title="Event Type")] - workload_type: Annotated[str, Field(title="Workload Type")] - workload_id: Annotated[str, Field(title="Workload Id")] - project_id: Annotated[str, Field(title="Project Id")] - replica_id: Annotated[str, Field(title="Replica Id")] - proxy_address: Annotated[str, Field(title="Proxy Address")] - expires_at: Annotated[str, Field(title="Expires At")] +class PatchLoopsUserConfigResponse(BaseModel): + user_config: Annotated[ + LoopsUserConfig, Field(description="The updated Loops user config.") + ] -class AuditLogEventType(StrEnum): - MODEL_DEPLOYED = "MODEL_DEPLOYED" - MODEL_DEPLOYMENT_ACTIVATED = "MODEL_DEPLOYMENT_ACTIVATED" - MODEL_DEPLOYMENT_DEACTIVATED = "MODEL_DEPLOYMENT_DEACTIVATED" - MODEL_DEPLOYMENT_RETRIED = "MODEL_DEPLOYMENT_RETRIED" - MODEL_DEPLOYMENT_PROMOTED = "MODEL_DEPLOYMENT_PROMOTED" - MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED = ( - "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED" - ) - MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED = ( - "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED" - ) - MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED = "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED" - MODEL_DEPLOYMENT_DELETED = "MODEL_DEPLOYMENT_DELETED" - MODEL_DELETED = "MODEL_DELETED" - CHAIN_DEPLOYED = "CHAIN_DEPLOYED" - CHAIN_DEPLOYMENT_ACTIVATED = "CHAIN_DEPLOYMENT_ACTIVATED" - CHAIN_DEPLOYMENT_DEACTIVATED = "CHAIN_DEPLOYMENT_DEACTIVATED" - CHAIN_DEPLOYMENT_PROMOTED = "CHAIN_DEPLOYMENT_PROMOTED" - CHAINLET_AUTOSCALING_SETTINGS_CHANGED = "CHAINLET_AUTOSCALING_SETTINGS_CHANGED" - CHAINLET_INSTANCE_TYPE_CHANGED = "CHAINLET_INSTANCE_TYPE_CHANGED" - CHAIN_DEPLOYMENT_DELETED = "CHAIN_DEPLOYMENT_DELETED" - CHAIN_DELETED = "CHAIN_DELETED" - CHAIN_ENVIRONMENT_CREATED = "CHAIN_ENVIRONMENT_CREATED" - CHAIN_ENVIRONMENT_UPDATED = "CHAIN_ENVIRONMENT_UPDATED" - SECRET_UPDATED = "SECRET_UPDATED" - SECRET_DELETED = "SECRET_DELETED" - API_KEY_CREATED = "API_KEY_CREATED" - API_KEY_DELETED = "API_KEY_DELETED" - GATEWAY_ENDPOINT_CREATED = "GATEWAY_ENDPOINT_CREATED" - GATEWAY_ENDPOINT_UPDATED = "GATEWAY_ENDPOINT_UPDATED" - GATEWAY_ENDPOINT_DELETED = "GATEWAY_ENDPOINT_DELETED" - USER_INVITED = "USER_INVITED" - USER_JOINED_ORGANIZATION = "USER_JOINED_ORGANIZATION" - WEBHOOK_SIGNING_SECRET_CREATED = "WEBHOOK_SIGNING_SECRET_CREATED" - WEBHOOK_SIGNING_SECRET_ROTATED = "WEBHOOK_SIGNING_SECRET_ROTATED" - WEBHOOK_SIGNING_SECRET_DELETED = "WEBHOOK_SIGNING_SECRET_DELETED" - USER_ROLE_UPDATED = "USER_ROLE_UPDATED" - USER_TEAM_ROLE_UPDATED = "USER_TEAM_ROLE_UPDATED" - USER_REMOVED = "USER_REMOVED" - DIRECTORY_GROUP_ROLE_UPDATED = "DIRECTORY_GROUP_ROLE_UPDATED" - REQUIRE_GROUP_BASED_ADMINS_ENABLED = "REQUIRE_GROUP_BASED_ADMINS_ENABLED" - ENVIRONMENT_CREATED = "ENVIRONMENT_CREATED" - ENVIRONMENT_UPDATED = "ENVIRONMENT_UPDATED" - ENVIRONMENT_DELETED = "ENVIRONMENT_DELETED" - REPLICA_TERMINATED = "REPLICA_TERMINATED" - MODEL_PROMOTION_CONTROL_ACTION = "MODEL_PROMOTION_CONTROL_ACTION" - SSH_CERTIFICATE_SIGNED = "SSH_CERTIFICATE_SIGNED" - VOLUME_DELETED = "VOLUME_DELETED" - VOLUME_VERSION_DELETED = "VOLUME_VERSION_DELETED" - VOLUME_VERSION_RESTORED = "VOLUME_VERSION_RESTORED" +class InstanceTypeWithPrice(BaseModel): + instance_type: Annotated[ + InstanceType, Field(description="Instance type properties.") + ] + price: Annotated[ + float, Field(description="Usage price in USD / minute.", title="Price") + ] -class AuditLogEventUserInvited(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["USER_INVITED"], Field(title="Event Type")] - invited_user_email: Annotated[str, Field(title="Invited User Email")] - role_name: Annotated[str, Field(title="Role Name")] +class InstanceTypePrices(BaseModel): + instance_types: Annotated[ + list[InstanceTypeWithPrice], Field(title="Instance Types") + ] -class AuditLogEventUserJoinedOrganization(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["USER_JOINED_ORGANIZATION"], Field(title="Event Type") +class DeploymentArchivePayload(BaseModel): + config: Annotated[ + dict[str, Any], + Field(description="Parsed model config as a JSON object.", title="Config"), ] - new_user_email: Annotated[str, Field(title="New User Email")] - user_id: Annotated[str, Field(title="User Id")] + raw_config: Annotated[ + str | None, + Field( + description="Original config.yaml text, persisted as-is on the deployment. Best-effort: invalid raw configs are logged and dropped without failing the request.", + title="Raw Config", + ), + ] = None + user_env: Annotated[ + dict[str, Any] | None, + Field( + description="Client environment metadata (e.g. client version, Python version). Validated server-side.", + title="User Env", + ), + ] = None + environment_name: Annotated[ + str | None, + Field( + description="Stable environment to push to (e.g. `production`). If unset, the deployment is created without environment selection. Caller must have push permission for the named environment.", + title="Environment Name", + ), + ] = None + create_environment_if_missing: Annotated[ + bool, + Field( + description="Create the environment named by `environment_name` if it does not exist yet. If false, a push to an environment that does not exist is rejected. Only meaningful when `environment_name` is set to something other than `production`, which always exists. This field currently defaults to true, but that default will change to false in a future release. Set it explicitly to avoid a behavior change.", + title="Create Environment If Missing", + ), + ] = True + region: Annotated[ + str | None, + Field(description="Region in which to deploy the model", title="Region"), + ] = None + preserve_env_instance_type: Annotated[ + bool, + Field( + description="Retain the target environment's current instance type rather than the one in `config`. Only meaningful when `environment_name` is set and that environment already exists.", + title="Preserve Env Instance Type", + ), + ] = True + deploy_timeout_minutes: Annotated[ + int | None, + Field( + description="Deploy timeout in minutes; allowed range 10 to 1440. Server default applies if unset.", + title="Deploy Timeout Minutes", + ), + ] = None + deployment_name: Annotated[ + str | None, + Field( + description="Optional human-readable name for the deployment.", + title="Deployment Name", + ), + ] = None + labels: Annotated[ + dict[str, Any] | None, + Field( + description="User-provided key-value labels for the deployment.", + title="Labels", + ), + ] = None + is_development: Annotated[ + bool, + Field( + description="If true, push as a development deployment: the model's single mutable dev slot, created if absent and overwritten in place otherwise. The following fields must be left at their defaults: `environment_name`, `preserve_env_instance_type`, `deployment_name`.", + title="Is Development", + ), + ] = False -class AuditLogEventUserRemoved(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["USER_REMOVED"], Field(title="Event Type")] - removed_user_email: Annotated[str, Field(title="Removed User Email")] +class PrepareModelUploadRequest(BaseModel): + deployment: Annotated[ + DeploymentArchivePayload, + Field( + description="Deployment-level payload, identical to the payload sent at commit." + ), + ] + name: Annotated[ + str | None, + Field( + description="Set to validate a new-model push. Exactly one of `name` or `model_id` is required.", + title="Name", + ), + ] = None + team_id: Annotated[ + str | None, + Field( + description="Team the new model will belong to. Only valid when `name` is set; defaults to the organization's default team when omitted. Must not be set when `model_id` is set (the existing model already has a team).", + title="Team Id", + ), + ] = None + model_id: Annotated[ + str | None, + Field( + description="Set to validate an add-deployment push to an existing model. Exactly one of `name` or `model_id` is required.", + title="Model Id", + ), + ] = None + dry_run: Annotated[ + bool, + Field( + description="If true, validate the payload only and do not issue upload credentials. The response sets `creds`, `s3_bucket`, and `s3_key` to `null`.", + title="Dry Run", + ), + ] = False -class AuditLogEventUserRoleUpdated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["USER_ROLE_UPDATED"], Field(title="Event Type")] - user_id: Annotated[str, Field(title="User Id")] - user_email: Annotated[str, Field(title="User Email")] - new_role_name: Annotated[str, Field(title="New Role Name")] +class AWSCredentials(BaseModel): + aws_access_key_id: Annotated[ + str, Field(description="The AWS access key ID", title="Aws Access Key Id") + ] + aws_secret_access_key: Annotated[ + str, + Field(description="The AWS secret access key", title="Aws Secret Access Key"), + ] + aws_session_token: Annotated[ + str, Field(description="The AWS session token", title="Aws Session Token") + ] -class AuditLogEventUserTeamRoleUpdated(BaseModel): +class PrepareModelUploadResponse(BaseModel): + creds: Annotated[ + AWSCredentials | None, + Field( + description="STS credentials to upload the model archive. Null when no archive upload is required." + ), + ] = None + s3_bucket: Annotated[ + str | None, + Field( + description="S3 bucket the credentials are scoped to. Null when no archive upload is required.", + title="S3 Bucket", + ), + ] = None + s3_key: Annotated[ + str | None, + Field( + description="S3 key the credentials are scoped to. Pass this to `POST /v1/models` (in the `model_archive` source) once the upload completes. Null when no archive upload is required.", + title="S3 Key", + ), + ] = None + s3_region: Annotated[ + str | None, + Field( + description="AWS region the S3 bucket resides in. Null when no archive upload is required.", + title="S3 Region", + ), + ] = None + + +class AuditLogActorType(StrEnum): + USER = "USER" + API_KEY = "API_KEY" + BASETEN_USER = "BASETEN_USER" + BASETEN_SYSTEM = "BASETEN_SYSTEM" + TOMBSTONE_USER = "TOMBSTONE_USER" + + +class AuditLogActor(BaseModel): + type: Annotated[ + AuditLogActorType, Field(description="Kind of actor that performed the action.") + ] + email: Annotated[ + str | None, + Field( + description="Email of the acting user, when the actor is a user.", + title="Email", + ), + ] = None + api_key_prefix: Annotated[ + str | None, + Field( + description="Prefix of the acting API key, when the actor is an API key.", + title="Api Key Prefix", + ), + ] = None + api_key_name: Annotated[ + str | None, + Field( + description="Display name of the acting API key, when the actor is an API key.", + title="Api Key Name", + ), + ] = None + + +class AuditLogApiKeyType(StrEnum): + PERSONAL = "PERSONAL" + CREATOR_SERVICE_ACCOUNT = "CREATOR_SERVICE_ACCOUNT" + MANAGE_API_KEYS_SERVICE_ACCOUNT = "MANAGE_API_KEYS_SERVICE_ACCOUNT" + INVOKE_ALL_MODELS_SERVICE_ACCOUNT = "INVOKE_ALL_MODELS_SERVICE_ACCOUNT" + INVOKE_ALLOWED_MODELS_SERVICE_ACCOUNT = "INVOKE_ALLOWED_MODELS_SERVICE_ACCOUNT" + INVOKE_SCOPED_ENVS_AND_MODELS_SERVICE_ACCOUNT = ( + "INVOKE_SCOPED_ENVS_AND_MODELS_SERVICE_ACCOUNT" + ) + EXPORT_METRICS_ALL_MODELS_SERVICE_ACCOUNT = ( + "EXPORT_METRICS_ALL_MODELS_SERVICE_ACCOUNT" + ) + EXPORT_METRICS_ALLOWED_MODELS_SERVICE_ACCOUNT = ( + "EXPORT_METRICS_ALLOWED_MODELS_SERVICE_ACCOUNT" + ) + INVOKE_ALL_SHARED_ENDPOINTS_SERVICE_ACCOUNT = ( + "INVOKE_ALL_SHARED_ENDPOINTS_SERVICE_ACCOUNT" + ) + INVOKE_ALLOWED_SHARED_ENDPOINTS_SERVICE_ACCOUNT = ( + "INVOKE_ALLOWED_SHARED_ENDPOINTS_SERVICE_ACCOUNT" + ) + INVOKE_ALL_ROUTES = "INVOKE_ALL_ROUTES" + + +class AuditLogEventApiKeyCreated(BaseModel): model_config = ConfigDict( extra="forbid", ) - event_type: Annotated[Literal["USER_TEAM_ROLE_UPDATED"], Field(title="Event Type")] - user_id: Annotated[str, Field(title="User Id")] - user_email: Annotated[str, Field(title="User Email")] - team_id: Annotated[str, Field(title="Team Id")] - team_name: Annotated[str, Field(title="Team Name")] - new_role_name: Annotated[str, Field(title="New Role Name")] + event_type: Annotated[Literal["API_KEY_CREATED"], Field(title="Event Type")] + api_key_id: Annotated[str, Field(title="Api Key Id")] + api_key_type: AuditLogApiKeyType + prefix: Annotated[str, Field(title="Prefix")] -class AuditLogEventVolumeDeleted(BaseModel): +class AuditLogEventApiKeyDeleted(BaseModel): model_config = ConfigDict( extra="forbid", ) - event_type: Annotated[Literal["VOLUME_DELETED"], Field(title="Event Type")] - volume_ref: Annotated[str, Field(title="Volume Ref")] - namespace: Annotated[str, Field(title="Namespace")] - volume_name: Annotated[str, Field(title="Volume Name")] - versions_deleted: Annotated[int, Field(title="Versions Deleted")] + event_type: Annotated[Literal["API_KEY_DELETED"], Field(title="Event Type")] + api_key_id: Annotated[str, Field(title="Api Key Id")] + api_key_type: AuditLogApiKeyType + prefix: Annotated[str, Field(title="Prefix")] + + +class AuditLogEventAutoscalingScheduleAction(StrEnum): + CREATED = "CREATED" + UPDATED = "UPDATED" + DELETED = "DELETED" + UNCHANGED = "UNCHANGED" + + +class AuditLogEventAutoscalingScheduleSettings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + min_replica: Annotated[int, Field(title="Min Replica")] + max_replica: Annotated[int, Field(title="Max Replica")] + concurrency_target: Annotated[int | None, Field(title="Concurrency Target")] + autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] + scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] + target_utilization_percentage: Annotated[ + int | None, Field(title="Target Utilization Percentage") + ] + target_in_flight_tokens: Annotated[ + int | None, Field(title="Target In Flight Tokens") + ] + max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] + schedule_name: Annotated[str, Field(title="Schedule Name")] + enabled: Annotated[bool, Field(title="Enabled")] + cadence: Annotated[str, Field(title="Cadence")] + timezone: Annotated[str, Field(title="Timezone")] + weekdays: Annotated[list[str] | None, Field(title="Weekdays")] + start_hour: Annotated[int | None, Field(title="Start Hour")] + start_minute: Annotated[int | None, Field(title="Start Minute")] + end_hour: Annotated[int | None, Field(title="End Hour")] + end_minute: Annotated[int | None, Field(title="End Minute")] + start_at: Annotated[str | None, Field(title="Start At")] = None + end_at: Annotated[str | None, Field(title="End At")] = None + + +class AuditLogEventAutoscalingSettings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + min_replica: Annotated[int, Field(title="Min Replica")] + max_replica: Annotated[int, Field(title="Max Replica")] + concurrency_target: Annotated[int, Field(title="Concurrency Target")] + autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] + scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] + target_utilization_percentage: Annotated[ + int | None, Field(title="Target Utilization Percentage") + ] + target_in_flight_tokens: Annotated[ + int | None, Field(title="Target In Flight Tokens") + ] + max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] + + +class AuditLogEventChainDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["CHAIN_DELETED"], Field(title="Event Type")] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] + + +class AuditLogEventChainDeployed(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["CHAIN_DEPLOYED"], Field(title="Event Type")] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] + chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] + is_primary: Annotated[bool, Field(title="Is Primary")] + publish: Annotated[bool, Field(title="Publish")] + + +class AuditLogEventChainDeploymentActivated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["CHAIN_DEPLOYMENT_ACTIVATED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] + chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] + + +class AuditLogEventChainDeploymentDeactivated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["CHAIN_DEPLOYMENT_DEACTIVATED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] + chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] + + +class AuditLogEventChainDeploymentDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["CHAIN_DEPLOYMENT_DELETED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] + deployment_name: Annotated[str | None, Field(title="Deployment Name")] + + +class AuditLogEventChainDeploymentPromoted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["CHAIN_DEPLOYMENT_PROMOTED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] + chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] + environment_name: Annotated[str | None, Field(title="Environment Name")] + environment_id: Annotated[str | None, Field(title="Environment Id")] + + +class AuditLogEventChainEnvironmentCreated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["CHAIN_ENVIRONMENT_CREATED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + environment_name: Annotated[str, Field(title="Environment Name")] + redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] + ramp_up_while_promoting: Annotated[ + bool | None, Field(title="Ramp Up While Promoting") + ] + ramp_up_duration_seconds: Annotated[ + int | None, Field(title="Ramp Up Duration Seconds") + ] + + +class AuditLogEventChainEnvironmentUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["CHAIN_ENVIRONMENT_UPDATED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + environment_name: Annotated[str, Field(title="Environment Name")] + redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] + ramp_up_while_promoting: Annotated[ + bool | None, Field(title="Ramp Up While Promoting") + ] + ramp_up_duration_seconds: Annotated[ + int | None, Field(title="Ramp Up Duration Seconds") + ] + + +class AuditLogEventChainletAutoscalingSettingsChanged(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + min_replica: Annotated[int, Field(title="Min Replica")] + max_replica: Annotated[int, Field(title="Max Replica")] + concurrency_target: Annotated[int, Field(title="Concurrency Target")] + autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] + scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] + target_utilization_percentage: Annotated[ + int | None, Field(title="Target Utilization Percentage") + ] + target_in_flight_tokens: Annotated[ + int | None, Field(title="Target In Flight Tokens") + ] + max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] + event_type: Annotated[ + Literal["CHAINLET_AUTOSCALING_SETTINGS_CHANGED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] + chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] + chainlet_name: Annotated[str, Field(title="Chainlet Name")] + chainlet_id: Annotated[str, Field(title="Chainlet Id")] + previous_settings: AuditLogEventAutoscalingSettings | None + + +class AuditLogEventChainletInstanceTypeChanged(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["CHAINLET_INSTANCE_TYPE_CHANGED"], Field(title="Event Type") + ] + chain_id: Annotated[str, Field(title="Chain Id")] + chain_name: Annotated[str, Field(title="Chain Name")] + chain_deployment_id: Annotated[str, Field(title="Chain Deployment Id")] + chain_deployment_name: Annotated[str | None, Field(title="Chain Deployment Name")] + chainlet_name: Annotated[str, Field(title="Chainlet Name")] + chainlet_id: Annotated[str, Field(title="Chainlet Id")] + instance_type_name: Annotated[str, Field(title="Instance Type Name")] + + +class AuditLogEventDirectoryGroupRoleUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["DIRECTORY_GROUP_ROLE_UPDATED"], Field(title="Event Type") + ] + directory_group_id: Annotated[str, Field(title="Directory Group Id")] + directory_group_name: Annotated[str, Field(title="Directory Group Name")] + new_role_name: Annotated[str, Field(title="New Role Name")] + team_id: Annotated[str | None, Field(title="Team Id")] + team_name: Annotated[str | None, Field(title="Team Name")] + + +class AuditLogEventEnvironmentCreated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + min_replica: Annotated[int, Field(title="Min Replica")] + max_replica: Annotated[int, Field(title="Max Replica")] + concurrency_target: Annotated[int, Field(title="Concurrency Target")] + autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] + scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] + target_utilization_percentage: Annotated[ + int | None, Field(title="Target Utilization Percentage") + ] + target_in_flight_tokens: Annotated[ + int | None, Field(title="Target In Flight Tokens") + ] + max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] + redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] + rolling_deploy: Annotated[bool | None, Field(title="Rolling Deploy")] + rolling_deploy_strategy: Annotated[ + str | None, Field(title="Rolling Deploy Strategy") + ] + max_unavailable_percent: Annotated[ + int | None, Field(title="Max Unavailable Percent") + ] + max_surge_percent: Annotated[int | None, Field(title="Max Surge Percent")] + stabilization_time_seconds: Annotated[ + int | None, Field(title="Stabilization Time Seconds") + ] + replica_overhead_percent: Annotated[ + int | None, Field(title="Replica Overhead Percent") + ] + promotion_cleanup_strategy: Annotated[ + str | None, Field(title="Promotion Cleanup Strategy") + ] + ramp_up_while_promoting: Annotated[ + bool | None, Field(title="Ramp Up While Promoting") + ] + ramp_up_duration_seconds: Annotated[ + int | None, Field(title="Ramp Up Duration Seconds") + ] + ramp_up_step_size: Annotated[int | None, Field(title="Ramp Up Step Size")] + request_backpressure_policy: Annotated[ + str | None, Field(title="Request Backpressure Policy") + ] = None + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + environment_name: Annotated[str, Field(title="Environment Name")] + deployment_type: Annotated[str | None, Field(title="Deployment Type")] + event_type: Annotated[Literal["ENVIRONMENT_CREATED"], Field(title="Event Type")] + + +class AuditLogEventEnvironmentDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["ENVIRONMENT_DELETED"], Field(title="Event Type")] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + environment_name: Annotated[str, Field(title="Environment Name")] + + +class AuditLogEventEnvironmentSettings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + min_replica: Annotated[int, Field(title="Min Replica")] + max_replica: Annotated[int, Field(title="Max Replica")] + concurrency_target: Annotated[int, Field(title="Concurrency Target")] + autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] + scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] + target_utilization_percentage: Annotated[ + int | None, Field(title="Target Utilization Percentage") + ] + target_in_flight_tokens: Annotated[ + int | None, Field(title="Target In Flight Tokens") + ] + max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] + redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] + rolling_deploy: Annotated[bool | None, Field(title="Rolling Deploy")] + rolling_deploy_strategy: Annotated[ + str | None, Field(title="Rolling Deploy Strategy") + ] + max_unavailable_percent: Annotated[ + int | None, Field(title="Max Unavailable Percent") + ] + max_surge_percent: Annotated[int | None, Field(title="Max Surge Percent")] + stabilization_time_seconds: Annotated[ + int | None, Field(title="Stabilization Time Seconds") + ] + replica_overhead_percent: Annotated[ + int | None, Field(title="Replica Overhead Percent") + ] + promotion_cleanup_strategy: Annotated[ + str | None, Field(title="Promotion Cleanup Strategy") + ] + ramp_up_while_promoting: Annotated[ + bool | None, Field(title="Ramp Up While Promoting") + ] + ramp_up_duration_seconds: Annotated[ + int | None, Field(title="Ramp Up Duration Seconds") + ] + ramp_up_step_size: Annotated[int | None, Field(title="Ramp Up Step Size")] + request_backpressure_policy: Annotated[ + str | None, Field(title="Request Backpressure Policy") + ] = None + + +class AuditLogEventGatewayEndpointCreated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["GATEWAY_ENDPOINT_CREATED"], Field(title="Event Type") + ] + gateway_endpoint_id: Annotated[str, Field(title="Gateway Endpoint Id")] + slug: Annotated[str, Field(title="Slug")] + + +class AuditLogEventGatewayEndpointDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["GATEWAY_ENDPOINT_DELETED"], Field(title="Event Type") + ] + gateway_endpoint_id: Annotated[str, Field(title="Gateway Endpoint Id")] + slug: Annotated[str, Field(title="Slug")] + + +class AuditLogEventGatewayEndpointUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["GATEWAY_ENDPOINT_UPDATED"], Field(title="Event Type") + ] + gateway_endpoint_id: Annotated[str, Field(title="Gateway Endpoint Id")] + slug: Annotated[str, Field(title="Slug")] + previous_slug: Annotated[str | None, Field(title="Previous Slug")] + + +class AuditLogEventModelDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["MODEL_DELETED"], Field(title="Event Type")] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + + +class AuditLogEventModelDeployed(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["MODEL_DEPLOYED"], Field(title="Event Type")] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + scale_previous_to_zero: Annotated[bool, Field(title="Scale Previous To Zero")] + trusted: Annotated[bool, Field(title="Trusted")] + publish: Annotated[bool, Field(title="Publish")] + environment_name: Annotated[str | None, Field(title="Environment Name")] + + +class AuditLogEventModelDeploymentActivated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_ACTIVATED"], Field(title="Event Type") + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + + +class AuditLogEventModelDeploymentDeactivated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_DEACTIVATED"], Field(title="Event Type") + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + + +class AuditLogEventModelDeploymentDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_DELETED"], Field(title="Event Type") + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + + +class AuditLogEventModelDeploymentInstanceTypeChanged(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED"], Field(title="Event Type") + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + instance_type_name: Annotated[str, Field(title="Instance Type Name")] + + +class AuditLogEventModelDeploymentPromoted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_PROMOTED"], Field(title="Event Type") + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + environment_name: Annotated[str | None, Field(title="Environment Name")] + environment_id: Annotated[str | None, Field(title="Environment Id")] + + +class AuditLogEventModelDeploymentRequestBackpressureSettingsChanged(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED"], + Field(title="Event Type"), + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + policy: Annotated[str | None, Field(title="Policy")] = None + previous_policy: Annotated[str | None, Field(title="Previous Policy")] = None + + +class AuditLogEventModelDeploymentRetried(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_RETRIED"], Field(title="Event Type") + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + retried: Annotated[bool, Field(title="Retried")] + + +class AuditLogEventModelRenamed(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["MODEL_RENAMED"], Field(title="Event Type")] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + previous_name: Annotated[str | None, Field(title="Previous Name")] + + +class AuditLogEventProviderConnectionCreated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["PROVIDER_CONNECTION_CREATED"], Field(title="Event Type") + ] + provider_connection_id: Annotated[str, Field(title="Provider Connection Id")] + provider: Annotated[str, Field(title="Provider")] + secret_name: Annotated[str, Field(title="Secret Name")] + + +class AuditLogEventProviderConnectionDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["PROVIDER_CONNECTION_DELETED"], Field(title="Event Type") + ] + provider_connection_id: Annotated[str, Field(title="Provider Connection Id")] + provider: Annotated[str, Field(title="Provider")] + secret_name: Annotated[str, Field(title="Secret Name")] + + +class AuditLogEventProviderConnectionUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["PROVIDER_CONNECTION_UPDATED"], Field(title="Event Type") + ] + provider_connection_id: Annotated[str, Field(title="Provider Connection Id")] + provider: Annotated[str, Field(title="Provider")] + secret_name: Annotated[str, Field(title="Secret Name")] + + +class AuditLogEventReplicaTerminated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["REPLICA_TERMINATED"], Field(title="Event Type")] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + replica_id: Annotated[str, Field(title="Replica Id")] + + +class AuditLogEventRequireGroupBasedAdminsEnabled(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["REQUIRE_GROUP_BASED_ADMINS_ENABLED"], Field(title="Event Type") + ] + organization_id: Annotated[str, Field(title="Organization Id")] + + +class AuditLogEventSecretDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["SECRET_DELETED"], Field(title="Event Type")] + secret_id: Annotated[str, Field(title="Secret Id")] + secret_name: Annotated[str, Field(title="Secret Name")] + + +class AuditLogEventSecretUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["SECRET_UPDATED"], Field(title="Event Type")] + secret_id: Annotated[str, Field(title="Secret Id")] + secret_name: Annotated[str, Field(title="Secret Name")] + + +class AuditLogEventSshCertificateSigned(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["SSH_CERTIFICATE_SIGNED"], Field(title="Event Type")] + workload_type: Annotated[str, Field(title="Workload Type")] + workload_id: Annotated[str, Field(title="Workload Id")] + project_id: Annotated[str, Field(title="Project Id")] + replica_id: Annotated[str, Field(title="Replica Id")] + proxy_address: Annotated[str, Field(title="Proxy Address")] + expires_at: Annotated[str, Field(title="Expires At")] + + +class AuditLogEventType(StrEnum): + MODEL_DEPLOYED = "MODEL_DEPLOYED" + MODEL_DEPLOYMENT_ACTIVATED = "MODEL_DEPLOYMENT_ACTIVATED" + MODEL_DEPLOYMENT_DEACTIVATED = "MODEL_DEPLOYMENT_DEACTIVATED" + MODEL_DEPLOYMENT_RETRIED = "MODEL_DEPLOYMENT_RETRIED" + MODEL_DEPLOYMENT_PROMOTED = "MODEL_DEPLOYMENT_PROMOTED" + MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED = ( + "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED" + ) + MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED = ( + "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED" + ) + MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED = "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED" + MODEL_DEPLOYMENT_DELETED = "MODEL_DEPLOYMENT_DELETED" + MODEL_DELETED = "MODEL_DELETED" + MODEL_RENAMED = "MODEL_RENAMED" + CHAIN_DEPLOYED = "CHAIN_DEPLOYED" + CHAIN_DEPLOYMENT_ACTIVATED = "CHAIN_DEPLOYMENT_ACTIVATED" + CHAIN_DEPLOYMENT_DEACTIVATED = "CHAIN_DEPLOYMENT_DEACTIVATED" + CHAIN_DEPLOYMENT_PROMOTED = "CHAIN_DEPLOYMENT_PROMOTED" + CHAINLET_AUTOSCALING_SETTINGS_CHANGED = "CHAINLET_AUTOSCALING_SETTINGS_CHANGED" + CHAINLET_INSTANCE_TYPE_CHANGED = "CHAINLET_INSTANCE_TYPE_CHANGED" + CHAIN_DEPLOYMENT_DELETED = "CHAIN_DEPLOYMENT_DELETED" + CHAIN_DELETED = "CHAIN_DELETED" + CHAIN_ENVIRONMENT_CREATED = "CHAIN_ENVIRONMENT_CREATED" + CHAIN_ENVIRONMENT_UPDATED = "CHAIN_ENVIRONMENT_UPDATED" + SECRET_UPDATED = "SECRET_UPDATED" + SECRET_DELETED = "SECRET_DELETED" + API_KEY_CREATED = "API_KEY_CREATED" + API_KEY_DELETED = "API_KEY_DELETED" + GATEWAY_ENDPOINT_CREATED = "GATEWAY_ENDPOINT_CREATED" + GATEWAY_ENDPOINT_UPDATED = "GATEWAY_ENDPOINT_UPDATED" + GATEWAY_ENDPOINT_DELETED = "GATEWAY_ENDPOINT_DELETED" + PROVIDER_CONNECTION_CREATED = "PROVIDER_CONNECTION_CREATED" + PROVIDER_CONNECTION_UPDATED = "PROVIDER_CONNECTION_UPDATED" + PROVIDER_CONNECTION_DELETED = "PROVIDER_CONNECTION_DELETED" + USER_INVITED = "USER_INVITED" + USER_JOINED_ORGANIZATION = "USER_JOINED_ORGANIZATION" + WEBHOOK_SIGNING_SECRET_CREATED = "WEBHOOK_SIGNING_SECRET_CREATED" + WEBHOOK_SIGNING_SECRET_ROTATED = "WEBHOOK_SIGNING_SECRET_ROTATED" + WEBHOOK_SIGNING_SECRET_DELETED = "WEBHOOK_SIGNING_SECRET_DELETED" + USER_ROLE_UPDATED = "USER_ROLE_UPDATED" + USER_TEAM_ROLE_UPDATED = "USER_TEAM_ROLE_UPDATED" + USER_REMOVED = "USER_REMOVED" + DIRECTORY_GROUP_ROLE_UPDATED = "DIRECTORY_GROUP_ROLE_UPDATED" + REQUIRE_GROUP_BASED_ADMINS_ENABLED = "REQUIRE_GROUP_BASED_ADMINS_ENABLED" + ENVIRONMENT_CREATED = "ENVIRONMENT_CREATED" + ENVIRONMENT_UPDATED = "ENVIRONMENT_UPDATED" + ENVIRONMENT_DELETED = "ENVIRONMENT_DELETED" + REPLICA_TERMINATED = "REPLICA_TERMINATED" + MODEL_PROMOTION_CONTROL_ACTION = "MODEL_PROMOTION_CONTROL_ACTION" + SSH_CERTIFICATE_SIGNED = "SSH_CERTIFICATE_SIGNED" + VOLUME_DELETED = "VOLUME_DELETED" + VOLUME_VERSION_DELETED = "VOLUME_VERSION_DELETED" + VOLUME_VERSION_RESTORED = "VOLUME_VERSION_RESTORED" + + +class AuditLogEventUserInvited(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["USER_INVITED"], Field(title="Event Type")] + invited_user_email: Annotated[str, Field(title="Invited User Email")] + role_name: Annotated[str, Field(title="Role Name")] + + +class AuditLogEventUserJoinedOrganization(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["USER_JOINED_ORGANIZATION"], Field(title="Event Type") + ] + new_user_email: Annotated[str, Field(title="New User Email")] + user_id: Annotated[str, Field(title="User Id")] + + +class AuditLogEventUserRemoved(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["USER_REMOVED"], Field(title="Event Type")] + removed_user_email: Annotated[str, Field(title="Removed User Email")] + + +class AuditLogEventUserRoleUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["USER_ROLE_UPDATED"], Field(title="Event Type")] + user_id: Annotated[str, Field(title="User Id")] + user_email: Annotated[str, Field(title="User Email")] + new_role_name: Annotated[str, Field(title="New Role Name")] + + +class AuditLogEventUserTeamRoleUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["USER_TEAM_ROLE_UPDATED"], Field(title="Event Type")] + user_id: Annotated[str, Field(title="User Id")] + user_email: Annotated[str, Field(title="User Email")] + team_id: Annotated[str, Field(title="Team Id")] + team_name: Annotated[str, Field(title="Team Name")] + new_role_name: Annotated[str, Field(title="New Role Name")] + + +class AuditLogEventVolumeDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["VOLUME_DELETED"], Field(title="Event Type")] + volume_ref: Annotated[str, Field(title="Volume Ref")] + namespace: Annotated[str, Field(title="Namespace")] + volume_name: Annotated[str, Field(title="Volume Name")] + versions_deleted: Annotated[int, Field(title="Versions Deleted")] + + +class AuditLogEventVolumeVersionDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["VOLUME_VERSION_DELETED"], Field(title="Event Type")] + volume_ref: Annotated[str, Field(title="Volume Ref")] + namespace: Annotated[str, Field(title="Namespace")] + volume_name: Annotated[str, Field(title="Volume Name")] + version: Annotated[str, Field(title="Version")] + digest: Annotated[str, Field(title="Digest")] + + +class AuditLogEventVolumeVersionRestored(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[Literal["VOLUME_VERSION_RESTORED"], Field(title="Event Type")] + volume_ref: Annotated[str, Field(title="Volume Ref")] + namespace: Annotated[str, Field(title="Namespace")] + volume_name: Annotated[str, Field(title="Volume Name")] + version: Annotated[str, Field(title="Version")] + digest: Annotated[str, Field(title="Digest")] + + +class AuditLogEventWebhookSigningSecretCreated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["WEBHOOK_SIGNING_SECRET_CREATED"], Field(title="Event Type") + ] + webhook_signing_secret_id: Annotated[str, Field(title="Webhook Signing Secret Id")] + + +class AuditLogEventWebhookSigningSecretDeleted(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["WEBHOOK_SIGNING_SECRET_DELETED"], Field(title="Event Type") + ] + webhook_signing_secret_id: Annotated[str, Field(title="Webhook Signing Secret Id")] + + +class AuditLogEventWebhookSigningSecretRotated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["WEBHOOK_SIGNING_SECRET_ROTATED"], Field(title="Event Type") + ] + webhook_signing_secret_id: Annotated[str, Field(title="Webhook Signing Secret Id")] + + +class AuditLogPromotionControlAction(StrEnum): + PAUSE = "PAUSE" + RESUME = "RESUME" + FORCE_CANCEL = "FORCE_CANCEL" + FORCE_ROLL_FORWARD = "FORCE_ROLL_FORWARD" + GRACEFUL_CANCEL = "GRACEFUL_CANCEL" + + +class AuditLogSource(StrEnum): + UI = "UI" + API = "API" + MCP = "MCP" + SYSTEM = "SYSTEM" + OTHER = "OTHER" + + +class AuditLogEventTypeGroup(StrEnum): + DEPLOYED = "DEPLOYED" + PROMOTED = "PROMOTED" + ACTIVATED_DEACTIVATED = "ACTIVATED_DEACTIVATED" + AUTOSCALING_SETTINGS = "AUTOSCALING_SETTINGS" + REQUEST_BACKPRESSURE_SETTINGS = "REQUEST_BACKPRESSURE_SETTINGS" + INSTANCE_TYPE_CHANGED = "INSTANCE_TYPE_CHANGED" + ENVIRONMENT_SETTINGS = "ENVIRONMENT_SETTINGS" + REPLICA_TERMINATED = "REPLICA_TERMINATED" + DELETED = "DELETED" + METADATA = "METADATA" + SECRETS = "SECRETS" + API_KEYS = "API_KEYS" + GATEWAY = "GATEWAY" + CODE = "CODE" + WEBHOOK_SIGNING_SECRETS = "WEBHOOK_SIGNING_SECRETS" + USER_MANAGEMENT = "USER_MANAGEMENT" + DIRECTORY_GROUP_MANAGEMENT = "DIRECTORY_GROUP_MANAGEMENT" + SSH = "SSH" + + +class AuditLogSortDirection(StrEnum): + DESC = "DESC" + ASC = "ASC" + + +class Model(BaseModel): + id: Annotated[str, Field(description="Unique identifier of the model", title="Id")] + created_at: Annotated[ + AwareDatetime, + Field( + description="Time the model was created in ISO 8601 format", + title="Created At", + ), + ] + name: Annotated[str, Field(description="Name of the model", title="Name")] + deployments_count: Annotated[ + int, + Field( + description="Number of deployments of the model", title="Deployments Count" + ), + ] + production_deployment_id: Annotated[ + str | None, + Field( + description="Unique identifier of the production deployment of the model", + title="Production Deployment Id", + ), + ] + development_deployment_id: Annotated[ + str | None, + Field( + description="Unique identifier of the development deployment of the model", + title="Development Deployment Id", + ), + ] + instance_type_name: Annotated[ + str, + Field( + description="Name of the instance type for the production deployment of the model", + title="Instance Type Name", + ), + ] + team_name: Annotated[ + str, + Field( + description="Name of the team associated with the model.", title="Team Name" + ), + ] + + +class Models(BaseModel): + models: Annotated[list[Model], Field(title="Models")] + + +class LibraryListingSource(BaseModel): + kind: Annotated[Literal["library_listing"], Field(title="Kind")] = "library_listing" + lab_display_name: Annotated[ + str, + Field( + description="Identifier of the publishing organization, as returned by `GET /v1/library_models`.", + title="Lab Display Name", + ), + ] + user_defined_listing_id: Annotated[ + str, + Field( + description="Listing identifier within the publishing organization.", + title="User Defined Listing Id", + ), + ] + deployed_model_name: Annotated[ + str | None, + Field( + description="Optional name for the new deployed model. Defaults to the listing's configured name.", + title="Deployed Model Name", + ), + ] = None + + +class ModelArchiveSource(BaseModel): + kind: Annotated[Literal["model_archive"], Field(title="Kind")] = "model_archive" + name: Annotated[str, Field(description="Name of the new model.", title="Name")] + deployment: Annotated[ + DeploymentArchivePayload, + Field( + description="Deployment-level configuration for the model's first deployment." + ), + ] + s3_key: Annotated[ + str | None, + Field( + description="S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", + title="S3 Key", + ), + ] = None + disable_archive_download: Annotated[ + bool, + Field( + description="If true, the uploaded archive is not downloadable after creation. Locked at model creation; cannot be changed by subsequent deployments.", + title="Disable Archive Download", + ), + ] = False + + +class CreateModelRequest(BaseModel): + source: Annotated[ + LibraryListingSource | ModelArchiveSource, + Field( + description="Where the new model is created from.", + discriminator="kind", + title="Source", + ), + ] + + +class AutoscalingSettings(BaseModel): + min_replica: Annotated[ + int, Field(description="Minimum number of replicas", title="Min Replica") + ] + max_replica: Annotated[ + int, Field(description="Maximum number of replicas", title="Max Replica") + ] + autoscaling_window: Annotated[ + int | None, + Field( + description="Timeframe of traffic considered for autoscaling decisions", + title="Autoscaling Window", + ), + ] + scale_down_delay: Annotated[ + int | None, + Field( + description="Waiting period before scaling down any active replica", + title="Scale Down Delay", + ), + ] + concurrency_target: Annotated[ + int, + Field( + description="Number of requests per replica before scaling up", + title="Concurrency Target", + ), + ] + target_utilization_percentage: Annotated[ + int | None, + Field( + description="Target utilization percentage for scaling up/down.", + title="Target Utilization Percentage", + ), + ] + target_in_flight_tokens: Annotated[ + int | None, + Field( + description="Target number of in-flight tokens for autoscaling decisions. Early access only.", + title="Target In Flight Tokens", + ), + ] = None + max_scale_down_rate: Annotated[ + int | None, + Field( + description="Maximum percentage of replicas that can be removed per autoscaling window (1–50). E.g. 20 means at most 20% of replicas are removed per window.", + title="Max Scale Down Rate", + ), + ] = None + + +class DeploymentStatus(StrEnum): + BUILDING = "BUILDING" + DEPLOYING = "DEPLOYING" + DEPLOY_FAILED = "DEPLOY_FAILED" + LOADING_MODEL = "LOADING_MODEL" + ACTIVE = "ACTIVE" + UNHEALTHY = "UNHEALTHY" + BUILD_FAILED = "BUILD_FAILED" + BUILD_STOPPED = "BUILD_STOPPED" + DEACTIVATING = "DEACTIVATING" + INACTIVE = "INACTIVE" + FAILED = "FAILED" + UPDATING = "UPDATING" + SCALED_TO_ZERO = "SCALED_TO_ZERO" + WAKING_UP = "WAKING_UP" + + +class RequestBackpressurePolicy(StrEnum): + QUEUE_ON_FULL = "QUEUE_ON_FULL" + REJECT_ON_FULL = "REJECT_ON_FULL" + + +class RequestBackpressureSettings(BaseModel): + policy: Annotated[ + RequestBackpressurePolicy | None, + Field(description="Backpressure policy. Null when no policy is set."), + ] = None + + +class ModelTombstone(BaseModel): + id: Annotated[str, Field(description="Unique identifier of the model", title="Id")] + deleted: Annotated[ + bool, Field(description="Whether the model was deleted", title="Deleted") + ] + + +class Name1(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="New name for the model, unique within its team. Renaming does not change the model ID, endpoints, or deployments. Pushes that still use the old model_name create another model or target a model that now uses that name, so update config.yaml after renaming.", + examples=["my-model"], + max_length=255, + min_length=1, + title="Name", + ), + ] = None + + +class UpdateModelRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + name: Annotated[ + Name1 | None, + Field( + description="New name for the model, unique within its team. Renaming does not change the model ID, endpoints, or deployments. Pushes that still use the old model_name create another model or target a model that now uses that name, so update config.yaml after renaming.", + examples=["my-model"], + title="Name", + ), + ] = None + + +class DeploymentArchiveSource(BaseModel): + kind: Annotated[Literal["model_archive"], Field(title="Kind")] = "model_archive" + deployment: Annotated[ + DeploymentArchivePayload, Field(description="Deployment-level configuration.") + ] + s3_key: Annotated[ + str | None, + Field( + description="S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", + title="S3 Key", + ), + ] = None + + +class CreateModelDeploymentRequest(BaseModel): + source: Annotated[ + DeploymentArchiveSource, + Field( + description="Where the new deployment is created from.", + discriminator="kind", + title="Source", + ), + ] + + +class DeploymentTombstone(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the deployment", title="Id") + ] + deleted: Annotated[ + bool, Field(description="Whether the deployment was deleted", title="Deleted") + ] + model_id: Annotated[ + str, Field(description="Unique identifier of the model", title="Model Id") + ] + + +class Name2(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="New name for the deployment, unique among the model's deployments. Only alphanumeric characters, hyphens, underscores, and periods are allowed.", + examples=["my-deployment"], + max_length=255, + min_length=1, + title="Name", + ), + ] = None + + +class UpdateDeploymentRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + name: Annotated[ + Name2 | None, + Field( + description="New name for the deployment, unique among the model's deployments. Only alphanumeric characters, hyphens, underscores, and periods are allowed.", + examples=["my-deployment"], + title="Name", + ), + ] = None + + +class MaxScaleDownRate(RootModel[int]): + root: Annotated[ + int | None, + Field( + description="Maximum percentage of replicas that can be removed per autoscaling window (1–50). E.g. 20 means at most 20% of replicas are removed per window.", + examples=[20], + ge=1, + le=50, + title="Max Scale Down Rate", + ), + ] = None + + +class UpdateAutoscalingSettings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + min_replica: Annotated[ + int | None, + Field( + description="Minimum number of replicas", examples=[0], title="Min Replica" + ), + ] = None + max_replica: Annotated[ + int | None, + Field( + description="Maximum number of replicas", examples=[7], title="Max Replica" + ), + ] = None + autoscaling_window: Annotated[ + int | None, + Field( + description="Timeframe of traffic considered for autoscaling decisions", + examples=[600], + title="Autoscaling Window", + ), + ] = None + scale_down_delay: Annotated[ + int | None, + Field( + description="Waiting period before scaling down any active replica", + examples=[120], + title="Scale Down Delay", + ), + ] = None + concurrency_target: Annotated[ + int | None, + Field( + description="Number of requests per replica before scaling up", + examples=[2], + title="Concurrency Target", + ), + ] = None + target_utilization_percentage: Annotated[ + int | None, + Field( + description="Target utilization percentage for scaling up/down.", + examples=[70], + title="Target Utilization Percentage", + ), + ] = None + target_in_flight_tokens: Annotated[ + int | None, + Field( + description="Target number of in-flight tokens for autoscaling decisions. Early access only.", + examples=[40000], + title="Target In Flight Tokens", + ), + ] = None + max_scale_down_rate: Annotated[ + MaxScaleDownRate | None, + Field( + description="Maximum percentage of replicas that can be removed per autoscaling window (1–50). E.g. 20 means at most 20% of replicas are removed per window.", + examples=[20], + title="Max Scale Down Rate", + ), + ] = None + + +class UpdateAutoscalingSettingsStatus(StrEnum): + ACCEPTED = "ACCEPTED" + QUEUED = "QUEUED" + UNCHANGED = "UNCHANGED" + + +class UpdateAutoscalingSettingsResponse(BaseModel): + status: Annotated[ + UpdateAutoscalingSettingsStatus, + Field(description="Status of the request to update autoscaling settings"), + ] + message: Annotated[ + str, + Field( + description="A message describing the status of the request to update autoscaling settings", + title="Message", + ), + ] + + +class UpdateRequestBackpressureSettings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + policy: Annotated[ + RequestBackpressurePolicy | None, + Field( + description="Backpressure policy to apply. Null indicates no policy (on update, clears an existing one).", + examples=["REJECT_ON_FULL"], + ), + ] = None + + +class PromoteRequest(BaseModel): + scale_down_previous_production: Annotated[ + bool, + Field( + description="Whether to scale down the previous production deployment after promoting", + examples=[True], + title="Scale Down Previous Production", + ), + ] = True + preserve_env_instance_type: Annotated[ + bool, + Field( + description="Whether to use the promoting deployment's instance type or preserve target environment's instance type", + examples=[True], + title="Preserve Env Instance Type", + ), + ] = True + + +class ActivateResponse(BaseModel): + success: Annotated[ + bool, + Field( + description="Whether the deployment was successfully activated", + title="Success", + ), + ] = True + no_op: Annotated[ + bool, + Field( + description="Whether the request did nothing because the deployment was already active or on its way to becoming active", + title="No Op", + ), + ] = False + + +class DeactivateResponse(BaseModel): + success: Annotated[ + bool, + Field( + description="Whether the deployment was successfully deactivated", + title="Success", + ), + ] = True + no_op: Annotated[ + bool, + Field( + description="Whether the request did nothing because the deployment was already inactive", + title="No Op", + ), + ] = False + + +class DownloadDeploymentResponse(BaseModel): + download_url: Annotated[ + str, + Field( + description="Presigned URL to download the truss tar file", + title="Download Url", + ), + ] + + +class DeploymentConfigResponse(BaseModel): + config: Annotated[ + dict[str, Any] | None, + Field(description="The parsed config of the deployment.", title="Config"), + ] = None + raw_config: Annotated[ + str | None, + Field( + description="The original config.yaml text — preserves comments, ordering, formatting.", + title="Raw Config", + ), + ] = None + + +class LogLevel(StrEnum): + DEBUG = "DEBUG" + INFO = "INFO" + WARNING = "WARNING" + ERROR = "ERROR" + + +class Log(BaseModel): + timestamp: Annotated[ + str, + Field( + description="Epoch nanosecond timestamp of the log message.", + title="Timestamp", + ), + ] + message: Annotated[ + str, + Field( + description="The contents of the log message. When the logger captured an exception, the traceback is appended after the message.", + title="Message", + ), + ] + replica: Annotated[ + str | None, + Field( + description="The replica the log line was emitted from.", title="Replica" + ), + ] + request_id: Annotated[ + str | None, + Field( + description="The request ID associated with an inference request.", + title="Request Id", + ), + ] = None + level: Annotated[ + LogLevel | None, + Field( + description="Severity of the log line, if one was detected. null when unknown." + ), + ] = None + + +class GetLogsResponse(BaseModel): + logs: Annotated[ + list[Log], Field(description="Logs for a specific entity.", title="Logs") + ] + + +class SortOrder(StrEnum): + asc = "asc" + desc = "desc" + + +class Limit6(RootModel[int]): + root: Annotated[ + int, + Field( + description="Limit of logs to fetch in a single request", + ge=1, + le=1000, + title="Limit", + ), + ] = 500 + + +class GetDeploymentLogsRequest(BaseModel): + start_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + title="Start Epoch Millis", + ), + ] = None + end_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + title="End Epoch Millis", + ), + ] = None + direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( + None + ) + limit: Annotated[ + Limit6 | None, + Field( + description="Limit of logs to fetch in a single request", + title="Limit", + validate_default=True, + ), + ] = Limit6.model_validate(500) + min_level: Annotated[ + LogLevel | None, + Field( + description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + ), + ] = None + replica: Annotated[ + Replica | None, + Field( + description="Only return logs emitted by this replica (5-char short ID).", + title="Replica", + ), + ] = None + request_id: Annotated[ + RequestId | None, + Field( + description="Only return logs tagged with this inference request ID.", + title="Request Id", + ), + ] = None + component: Annotated[ + Component | None, + Field(description="Only return logs from this component.", title="Component"), + ] = None + search_pattern: Annotated[ + SearchPattern | None, + Field( + description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", + title="Search Pattern", + ), + ] = None + includes: Annotated[ + list[str] | None, + Field( + description="Case-sensitive substrings that must all appear in the log message.", + max_length=8, + title="Includes", + ), + ] = None + excludes: Annotated[ + list[str] | None, + Field( + description="Case-sensitive substrings; lines containing any of these are dropped.", + max_length=8, + title="Excludes", + ), + ] = None + + +class DeploymentPatchAction(StrEnum): + ADD = "ADD" + UPDATE = "UPDATE" + REMOVE = "REMOVE" + + +class DeploymentPatchOpConfig(BaseModel): + type: Annotated[Literal["config"], Field(title="Type")] = "config" + config: Annotated[ + dict[str, Any], + Field(description="The full parsed config as a JSON object.", title="Config"), + ] + path: Annotated[ + str, Field(description="Config file path within the source.", title="Path") + ] = "config.yaml" + + +class DeploymentPatchOpEnvVar(BaseModel): + type: Annotated[Literal["environment_variable"], Field(title="Type")] = ( + "environment_variable" + ) + action: Annotated[ + DeploymentPatchAction, Field(description="How this op changes the variable.") + ] + name: Annotated[ + str, Field(description="The environment variable name.", title="Name") + ] + value: Annotated[ + str | None, + Field( + description="The environment variable value. Required for add and update.", + title="Value", + ), + ] = None + + +class DeploymentPatchOpExternalData(BaseModel): + type: Annotated[Literal["external_data"], Field(title="Type")] = "external_data" + action: Annotated[ + DeploymentPatchAction, + Field( + description="How this op changes the item. `UPDATE` is treated identically to `ADD`." + ), + ] + item: Annotated[ + dict[str, str], + Field(description="The single external data item descriptor.", title="Item"), + ] + + +class DeploymentPatchOpModelCode(BaseModel): + type: Annotated[Literal["model_code"], Field(title="Type")] = "model_code" + action: Annotated[ + DeploymentPatchAction, Field(description="How this op changes the file.") + ] + path: Annotated[ + str, + Field( + description="File path relative to the model code directory.", title="Path" + ), + ] + content: Annotated[ + str | None, + Field( + description="UTF-8 file content. Null for removals and binary files.", + title="Content", + ), + ] = None + content_bytes: Annotated[ + str | None, + Field( + description="Base64-encoded content for binary files.", + title="Content Bytes", + ), + ] = None + hot_reload: Annotated[ + bool, + Field( + description="Whether the running server can pick up this change without a restart.", + title="Hot Reload", + ), + ] = False + + +class DeploymentPatchOpPackage(BaseModel): + type: Annotated[Literal["package"], Field(title="Type")] = "package" + action: Annotated[ + DeploymentPatchAction, Field(description="How this op changes the file.") + ] + path: Annotated[ + str, + Field( + description="File path relative to the bundled packages directory.", + title="Path", + ), + ] + content: Annotated[ + str | None, + Field( + description="UTF-8 file content. Null for removals and binary files.", + title="Content", + ), + ] = None + content_bytes: Annotated[ + str | None, + Field( + description="Base64-encoded content for binary files.", + title="Content Bytes", + ), + ] = None + + +class DeploymentPatchOpPythonRequirement(BaseModel): + type: Annotated[Literal["python_requirement"], Field(title="Type")] = ( + "python_requirement" + ) + action: Annotated[ + DeploymentPatchAction, Field(description="How this op changes the requirement.") + ] + requirement: Annotated[ + str, + Field( + description="The requirement to apply. For removals this is the package name; otherwise the full requirements.txt-style line.", + title="Requirement", + ), + ] + + +class DeploymentPatchPoint(BaseModel): + content_hashes: Annotated[ + dict[str, str | None], + Field( + description="Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", + title="Content Hashes", + ), + ] + config: Annotated[ + str, + Field( + description="The verbatim config.yaml text for this source state.", + title="Config", + ), + ] + requirements: Annotated[ + list[str] | None, + Field( + description="Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", + title="Requirements", + ), + ] = None + + +class PatchOps( + RootModel[ + DeploymentPatchOpModelCode + | DeploymentPatchOpPackage + | DeploymentPatchOpConfig + | DeploymentPatchOpPythonRequirement + | DeploymentPatchOpEnvVar + | DeploymentPatchOpExternalData + ] +): + root: Annotated[ + DeploymentPatchOpModelCode + | DeploymentPatchOpPackage + | DeploymentPatchOpConfig + | DeploymentPatchOpPythonRequirement + | DeploymentPatchOpEnvVar + | DeploymentPatchOpExternalData, + Field(discriminator="type"), + ] + + +class CreateDeploymentPatchRequest(BaseModel): + prev_patch_hash: Annotated[ + str, + Field( + description="Content hash of the patch point this patch is applied on - the link the staged patch must build on. A stale value (the base moved underneath the client) is rejected with a conflict.", + title="Prev Patch Hash", + ), + ] + next_patch_point: Annotated[ + DeploymentPatchPoint, + Field( + description="The source state after this patch. The server derives its content hash from `content_hashes`." + ), + ] + patch_ops: Annotated[ + list[PatchOps], + Field( + description="The ordered ops that make up this patch. At least one op is required; a patch that changes nothing is not a valid request. There is no op for a directory: a directory comes into existence when the first file under it is added, and is removed when its last file is removed, so directory creation and deletion happen implicitly through the file ops. Adding or removing an otherwise empty directory therefore produces no ops even though it changes the source hash; do not send a patch request for such a change.", + min_length=1, + title="Patch Ops", + ), + ] + + +class DeploymentPatchPointWithHash(BaseModel): + content_hashes: Annotated[ + dict[str, str | None], + Field( + description="Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", + title="Content Hashes", + ), + ] + config: Annotated[ + str, + Field( + description="The verbatim config.yaml text for this source state.", + title="Config", + ), + ] + requirements: Annotated[ + list[str] | None, + Field( + description="Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", + title="Requirements", + ), + ] = None + hash: Annotated[ + str, + Field( + description="Content hash identifying this exact source state, and the link patches build on. It is derived deterministically from `content_hashes`, so a request need not send it - the server derives it. It is derived by sorting the `content_hashes` keys as paths, splitting each key on '/' into its path components and ordering the keys by comparing those component lists element by element, each component compared by Unicode code point (equivalently UTF-8 byte order). Treating '/' as a path separator this way, rather than as the ordinary character U+002F, means a key that is an ancestor path sorts before a sibling whose name extends the first differing component (so e.g. 'a/b' sorts before 'a.b'). A blake3 hasher is then built, and for each key in that order updated with the blake3 digest (32 raw bytes) of the key encoded as UTF-8, then, when the entry is a file (non-null value), with that file's digest as 32 raw bytes. The stream uses raw digest bytes, but the values in `content_hashes` are those digests hex-encoded (64 hex chars), so decode each value from hex first. Directory entries (null value) contribute only their key digest. The result is the hasher's own hex digest.", + title="Hash", + ), + ] + + +class CreateDeploymentPatchResponse(BaseModel): + patch_point: Annotated[ + DeploymentPatchPointWithHash, + Field( + description="The resulting patch point the staged patch produced; matches the pending point a subsequent state read returns." + ), + ] + + +class GetDeploymentPatchesStateResponse(BaseModel): + running_patch_point: Annotated[ + DeploymentPatchPointWithHash, + Field(description="The patch point the deployment is recorded as running."), + ] + pending_patch_point: Annotated[ + DeploymentPatchPointWithHash | None, + Field( + description="The latest staged-but-unsynced patch point, or null when the deployment is recorded as caught up." + ), + ] = None + + +class SyncDeploymentPatchesRequest(BaseModel): + pass + + +class SyncDeploymentPatchesResponse(BaseModel): + needs_full_deploy_reason: Annotated[ + str | None, + Field( + description="If set, the change cannot be patched and a full push is required; the value explains why. If null, the deployment is now in sync.", + title="Needs Full Deploy Reason", + ), + ] = None + + +class ModelMetricKind(StrEnum): + GAUGE = "GAUGE" + COUNTER = "COUNTER" + HISTOGRAM = "HISTOGRAM" + + +class ModelMetricMode(StrEnum): + CURRENT = "CURRENT" + SUMMARY = "SUMMARY" + SERIES = "SERIES" + + +class ModelMetricUnitHint(StrEnum): + PER_SECOND = "PER_SECOND" + SECONDS = "SECONDS" + BYTES = "BYTES" + MEBIBYTES = "MEBIBYTES" + COUNT = "COUNT" + RATIO = "RATIO" + + +class ModelMetricValueSet(BaseModel): + start_epoch_millis: Annotated[ + int, + Field( + description="Start of the step. The step spans until the next value set's start, or the window end for the last one; a summary has a single value set starting at the window start.", + title="Start Epoch Millis", + ), + ] + values: Annotated[ + list[list[float | None]], + Field( + description="Metric values aligned to the ``metric_descriptors`` index. Each entry is a list aligned to that descriptor's ``label_sets`` (a single-element list for a plain metric). A series with no data in this step is null.", + title="Values", + ), + ] + + +class TerminateReplicaResponse(BaseModel): + success: Annotated[ + bool, + Field( + description="Whether the replica was successfully terminated", + title="Success", + ), + ] = True + + +class SignSSHCertificateRequest(BaseModel): + public_key: Annotated[ + str, + Field( + description="The user's SSH public key (e.g., 'ssh-ed25519 AAAA... user@host').", + title="Public Key", + ), + ] + replica_id: Annotated[ + str | None, + Field( + description="The replica to connect to. Required for training jobs (e.g. '0'). Optional for inference (server picks a running replica if omitted).", + title="Replica Id", + ), + ] = None + + +class SignSSHCertificateResponse(BaseModel): + ssh_certificate: Annotated[ + str, + Field( + description="The signed SSH certificate in OpenSSH format.", + title="Ssh Certificate", + ), + ] + jwt: Annotated[ + str, + Field( + description="Signed JWT (ES256) for SSH proxy authorization.", title="Jwt" + ), + ] + proxy_address: Annotated[ + str, + Field( + description="Address of the SSH proxy to connect to (host:port).", + title="Proxy Address", + ), + ] + ssh_cert_expires_at: Annotated[ + AwareDatetime, + Field( + description="When the certificate expires, in ISO 8601 format.", + title="Ssh Cert Expires At", + ), + ] + + +class AutoscalingScheduleSettings(BaseModel): + min_replica: Annotated[ + int, Field(description="Minimum number of replicas", title="Min Replica") + ] + max_replica: Annotated[ + int, Field(description="Maximum number of replicas", title="Max Replica") + ] + autoscaling_window: Annotated[ + int | None, + Field( + description="Timeframe of traffic considered for autoscaling decisions. Null inherits the environment value.", + title="Autoscaling Window", + ), + ] + scale_down_delay: Annotated[ + int | None, + Field( + description="Waiting period before scaling down any active replica. Null inherits the environment value.", + title="Scale Down Delay", + ), + ] + concurrency_target: Annotated[ + int | None, + Field( + description="Number of requests per replica before scaling up. Null inherits the environment value.", + title="Concurrency Target", + ), + ] + target_utilization_percentage: Annotated[ + int | None, + Field( + description="Target utilization percentage for scaling up/down. Null inherits the environment value.", + title="Target Utilization Percentage", + ), + ] + target_in_flight_tokens: Annotated[ + int | None, + Field( + description="Target number of in-flight tokens for autoscaling decisions. Null inherits the environment value. Early access only.", + title="Target In Flight Tokens", + ), + ] + max_scale_down_rate: Annotated[ + int | None, + Field( + description="Maximum percentage of replicas that can be removed per autoscaling window. Null inherits the environment value.", + title="Max Scale Down Rate", + ), + ] + + +class AutoscalingScheduleState(BaseModel): + schedule_id: Annotated[ + str | None, + Field( + description="Stable schedule identifier, or null when the baseline settings apply", + title="Schedule Id", + ), + ] + autoscaling_settings: Annotated[ + AutoscalingSettings, + Field( + description="Autoscaling settings on the current serving deployment. In a PATCH response, this snapshot can precede asynchronous schedule reconciliation; poll the GET endpoint for the applied state." + ), + ] + + +class Cadence(StrEnum): + DAILY = "DAILY" + HOURLY = "HOURLY" + + +class AutoscalingScheduleWeekday(StrEnum): + SUNDAY = "SUNDAY" + MONDAY = "MONDAY" + TUESDAY = "TUESDAY" + WEDNESDAY = "WEDNESDAY" + THURSDAY = "THURSDAY" + FRIDAY = "FRIDAY" + SATURDAY = "SATURDAY" + + +class InProgressPromotionStatus(StrEnum): + RELEASING = "RELEASING" + RAMPING_UP = "RAMPING_UP" + RAMPING_DOWN = "RAMPING_DOWN" + PAUSED = "PAUSED" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + CANCELED = "CANCELED" + + +class InProgressPromotion(BaseModel): + status: Annotated[ + InProgressPromotionStatus, Field(description="Status of the promotion") + ] + percent_traffic_to_new_version: Annotated[ + int, + Field( + description="Percentage of traffic routed to the candidate deployment", + title="Percent Traffic To New Version", + ), + ] + error_message: Annotated[ + str | None, + Field(description="Error message if promotion failed", title="Error Message"), + ] = None + rolling_deploy: Annotated[ + bool | None, + Field(description="Whether this is a rolling deploy", title="Rolling Deploy"), + ] = None + + +class OneTimeAutoscalingSchedule(BaseModel): + id: Annotated[ + str, Field(description="Stable unique identifier of the schedule", title="Id") + ] + name: Annotated[str, Field(description="Name of the schedule", title="Name")] + enabled: Annotated[ + bool, Field(description="Whether the schedule is enabled", title="Enabled") + ] + autoscaling_settings: Annotated[ + AutoscalingScheduleSettings, + Field( + description="Raw autoscaling overrides applied during the schedule window" + ), + ] + cadence: Annotated[ + Literal["ONE_TIME"], + Field(description="One-time schedule cadence", title="Cadence"), + ] + start_at: Annotated[ + AwareDatetime, + Field(description="Inclusive start of the schedule window", title="Start At"), + ] + end_at: Annotated[ + AwareDatetime, + Field(description="Exclusive end of the schedule window", title="End At"), + ] + + +class PromotionCleanupStrategy(StrEnum): + KEEP = "KEEP" + SCALE_TO_ZERO = "SCALE_TO_ZERO" + DEACTIVATE = "DEACTIVATE" + + +class RollingDeployStrategy(StrEnum): + REPLICA = "REPLICA" + + +class UpdateRollingDeployConfig(BaseModel): + rolling_deploy_strategy: Annotated[ + RollingDeployStrategy | None, + Field( + description="The rolling deploy strategy to use for promotions.", + examples=["REPLICA"], + ), + ] = None + max_surge_percent: Annotated[ + int | None, + Field( + description="The maximum surge percentage for rolling deploys.", + examples=[25], + title="Max Surge Percent", + ), + ] = None + max_unavailable_percent: Annotated[ + int | None, + Field( + description="The maximum unavailable percentage for rolling deploys.", + examples=[10], + title="Max Unavailable Percent", + ), + ] = None + stabilization_time_seconds: Annotated[ + int | None, + Field( + description="The stabilization time in seconds for rolling deploys.", + examples=[300], + title="Stabilization Time Seconds", + ), + ] = None + replica_overhead_percent: Annotated[ + int | None, + Field( + description="The replica overhead percentage for rolling deploys.", + examples=[0], + title="Replica Overhead Percent", + ), + ] = None + + +class EnvironmentTombstone(BaseModel): + name: Annotated[str, Field(description="Name of the environment", title="Name")] + model_id: Annotated[ + str, Field(description="Unique identifier of the model", title="Model Id") + ] + deleted: Annotated[ + bool, Field(description="Whether the environment was deleted", title="Deleted") + ] + + +class MaxScaleDownRate1(RootModel[int]): + root: Annotated[ + int, + Field( + description="Maximum percentage of replicas that can be removed per autoscaling window. Null stores no schedule override and follows the current environment value.", + ge=1, + le=50, + title="Max Scale Down Rate", + ), + ] + + +class AutoscalingScheduleSettingsRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + min_replica: Annotated[ + int, Field(description="Minimum number of replicas", title="Min Replica") + ] + max_replica: Annotated[ + int, Field(description="Maximum number of replicas", title="Max Replica") + ] + autoscaling_window: Annotated[ + int | None, + Field( + description="Timeframe of traffic considered for autoscaling decisions. Null stores no schedule override and follows the current environment value.", + title="Autoscaling Window", + ), + ] + scale_down_delay: Annotated[ + int | None, + Field( + description="Waiting period before scaling down any active replica. Null stores no schedule override and follows the current environment value.", + title="Scale Down Delay", + ), + ] + concurrency_target: Annotated[ + int | None, + Field( + description="Number of requests per replica before scaling up. Null stores no schedule override and follows the current environment value.", + title="Concurrency Target", + ), + ] + target_utilization_percentage: Annotated[ + int | None, + Field( + description="Target utilization percentage for scaling up/down. Null stores no schedule override and follows the current environment value.", + title="Target Utilization Percentage", + ), + ] + target_in_flight_tokens: Annotated[ + int | None, + Field( + description="Target number of in-flight tokens for autoscaling decisions. Null stores no schedule override and follows the current environment value. Early access only.", + title="Target In Flight Tokens", + ), + ] + max_scale_down_rate: Annotated[ + MaxScaleDownRate1 | None, + Field( + description="Maximum percentage of replicas that can be removed per autoscaling window. Null stores no schedule override and follows the current environment value.", + title="Max Scale Down Rate", + ), + ] + + +class AutoscalingScheduleUpsert(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + id: Annotated[ + str | None, + Field( + description="Stable schedule identifier. Omit this field to create a schedule.", + title="Id", + ), + ] = None + name: Annotated[str, Field(description="Name of the schedule", title="Name")] + enabled: Annotated[ + bool, Field(description="Whether the schedule is enabled", title="Enabled") + ] + autoscaling_settings: Annotated[ + AutoscalingScheduleSettingsRequest, + Field( + description="Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." + ), + ] + cadence: Annotated[ + Literal["DAILY", "HOURLY"], + Field(description="Recurring schedule cadence", title="Cadence"), + ] + weekdays: Annotated[ + list[AutoscalingScheduleWeekday], + Field(description="Weekdays on which the schedule runs", title="Weekdays"), + ] + start_hour: Annotated[ + int | None, + Field( + description="Start hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", + title="Start Hour", + ), + ] = None + start_minute: Annotated[ + int, + Field(description="Start minute of the schedule window", title="Start Minute"), + ] + end_hour: Annotated[ + int | None, + Field( + description="End hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", + title="End Hour", + ), + ] = None + end_minute: Annotated[ + int, Field(description="End minute of the schedule window", title="End Minute") + ] + + +class OneTimeAutoscalingScheduleUpsert(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + id: Annotated[ + str | None, + Field( + description="Stable schedule identifier. Omit this field to create a schedule.", + title="Id", + ), + ] = None + name: Annotated[str, Field(description="Name of the schedule", title="Name")] + enabled: Annotated[ + bool, Field(description="Whether the schedule is enabled", title="Enabled") + ] + autoscaling_settings: Annotated[ + AutoscalingScheduleSettingsRequest, + Field( + description="Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." + ), + ] + cadence: Annotated[ + Literal["ONE_TIME"], + Field(description="One-time schedule cadence", title="Cadence"), + ] + start_at: Annotated[ + AwareDatetime, + Field( + description="Inclusive start of the schedule window in ISO 8601 format. New schedules must start in the future.", + title="Start At", + ), + ] + end_at: Annotated[ + AwareDatetime, + Field( + description="Exclusive end of the schedule window in ISO 8601 format", + title="End At", + ), + ] + + +class Schedules1( + RootModel[AutoscalingScheduleUpsert | OneTimeAutoscalingScheduleUpsert] +): + root: Annotated[ + AutoscalingScheduleUpsert | OneTimeAutoscalingScheduleUpsert, + Field(discriminator="cadence"), + ] + + +class UpdateAutoscalingScheduleSettings(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + timezone: Annotated[ + str | None, + Field( + description="IANA timezone shared by the resulting collection. Omission preserves the current timezone; null is allowed only when deleting every schedule.", + title="Timezone", + ), + ] = None + schedules: Annotated[ + list[Schedules1] | None, + Field( + description="Complete schedules to create or replace. Existing schedules omitted from this list are unchanged.", + title="Schedules", + ), + ] = None + delete_schedules: Annotated[ + list[str] | None, + Field( + description="Stable identifiers of schedules to delete. To clear all schedules, include every existing schedule identifier.", + title="Delete Schedules", + ), + ] = None + + +class PromoteToEnvironmentRequest(BaseModel): + scale_down_previous_deployment: Annotated[ + bool, + Field( + description="Whether to scale down the previous deployment after promoting", + examples=[True], + title="Scale Down Previous Deployment", + ), + ] = True + deployment_id: Annotated[ + str, + Field(description="The id of the deployment to promote", title="Deployment Id"), + ] + preserve_env_instance_type: Annotated[ + bool, + Field( + description="Whether to use the promoting deployment's instance type or preserve target environment's instance type", + examples=[True], + title="Preserve Env Instance Type", + ), + ] = True + + +class CancelPromotionStatus(StrEnum): + CANCELED = "CANCELED" + RAMPING_DOWN = "RAMPING_DOWN" + + +class CancelPromotionResponse(BaseModel): + status: Annotated[ + CancelPromotionStatus, + Field( + description="Status of the request to cancel a promotion. Can be CANCELED or RAMPING_DOWN." + ), + ] + message: Annotated[ + str, + Field( + description="A message describing the status of the request to cancel a promotion", + title="Message", + ), + ] + + +class SignalPromotionResponse(BaseModel): + success: Annotated[ + bool, + Field(description="Whether the signal was successfully sent", title="Success"), + ] + + +class Chain(BaseModel): + id: Annotated[str, Field(description="Unique identifier of the chain", title="Id")] + created_at: Annotated[ + AwareDatetime, + Field( + description="Time the chain was created in ISO 8601 format", + title="Created At", + ), + ] + name: Annotated[str, Field(description="Name of the chain", title="Name")] + deployments_count: Annotated[ + int, + Field( + description="Number of deployments of the chain", title="Deployments Count" + ), + ] + team_name: Annotated[ + str, + Field( + description="Name of the team associated with the chain", title="Team Name" + ), + ] + + +class Chains(BaseModel): + chains: Annotated[list[Chain], Field(title="Chains")] + + +class ChainTombstone(BaseModel): + id: Annotated[str, Field(description="Unique identifier of the chain", title="Id")] + deleted: Annotated[ + bool, Field(description="Whether the chain was deleted", title="Deleted") + ] + + +class Chainlet(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the chainlet", title="Id") + ] + name: Annotated[str, Field(description="Name of the chainlet", title="Name")] + autoscaling_settings: Annotated[ + AutoscalingSettings | None, + Field( + description="Autoscaling settings for the chainlet. If null, it has not finished deploying" + ), + ] + instance_type_name: Annotated[ + str, + Field( + description="Name of the instance type the chainlet is deployed on", + title="Instance Type Name", + ), + ] + active_replica_count: Annotated[ + int, + Field(description="Number of active replicas", title="Active Replica Count"), + ] + status: Annotated[DeploymentStatus, Field(description="Status of the chainlet")] + + +class ChainDeploymentTombstone(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the chain deployment", title="Id") + ] + deleted: Annotated[ + bool, + Field(description="Whether the chain deployment was deleted", title="Deleted"), + ] + chain_id: Annotated[ + str, Field(description="Unique identifier of the chain", title="Chain Id") + ] + + +class ChainletEnvironmentSettingsRequest(BaseModel): + chainlet_name: Annotated[ + str, + Field( + description="Name of the chainlet", + examples=["HelloWorld"], + title="Chainlet Name", + ), + ] + autoscaling_settings: Annotated[ + UpdateAutoscalingSettings | None, + Field( + description="Autoscaling settings for the chainlet", + examples=[ + { + "autoscaling_window": 60, + "concurrency_target": 1, + "max_replica": 1, + "max_scale_down_rate": None, + "min_replica": 0, + "scale_down_delay": 900, + "target_in_flight_tokens": None, + "target_utilization_percentage": 70, + } + ], + ), + ] = None + instance_type_id: Annotated[ + str, + Field( + description="ID of the instance type to use for the chainlet", + examples=["1x4", "2x8", "A10G:2x24x96", "H100:2x52x468"], + title="Instance Type Id", + ), + ] = "1x2" + + +class ChainletEnvironmentSettings(BaseModel): + chainlet_name: Annotated[ + str, Field(description="Name of the chainlet", title="Chainlet Name") + ] + autoscaling_settings: Annotated[ + AutoscalingSettings | None, + Field( + description="Autoscaling settings for the chainlet. If null, it has not finished deploying" + ), + ] + instance_type: Annotated[ + InstanceType, Field(description="Instance type for the chainlet") + ] + + +class UpdateChainEnvironmentResponse(BaseModel): + ok: Annotated[ + bool, Field(description="Whether the update was successful", title="Ok") + ] + + +class PromoteToChainEnvironmentRequest(BaseModel): + scale_down_previous_deployment: Annotated[ + bool, + Field( + description="Whether to scale down the previous deployment after promoting", + examples=[True], + title="Scale Down Previous Deployment", + ), + ] = True + deployment_id: Annotated[ + str, + Field( + description="The id of the chain deployment to promote", + title="Deployment Id", + ), + ] + + +class ChainletEnvironmentAutoscalingSettingsUpdate(BaseModel): + chainlet_name: Annotated[ + str, + Field( + description="Name of the chainlet", + examples=["HelloWorld"], + title="Chainlet Name", + ), + ] + autoscaling_settings: Annotated[ + UpdateAutoscalingSettings, + Field( + description="Autoscaling settings for the chainlet", + examples=[ + { + "autoscaling_window": 800, + "concurrency_target": 3, + "max_replica": 2, + "max_scale_down_rate": None, + "min_replica": 1, + "scale_down_delay": 60, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + } + ], + ), + ] + + +class UpdateChainletEnvironmentAutoscalingSettingsRequest(BaseModel): + updates: Annotated[ + list[ChainletEnvironmentAutoscalingSettingsUpdate], + Field( + description="Mapping of chainlet name to the desired chainlet autoscaling settings. If the chainlet name doesn't exist, an error is returned.", + examples=[ + [ + { + "autoscaling_settings": { + "autoscaling_window": 800, + "concurrency_target": 4, + "max_replica": 3, + "max_scale_down_rate": None, + "min_replica": 2, + "scale_down_delay": 63, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + }, + "chainlet_name": "HelloWorld", + } + ], + [ + { + "autoscaling_settings": { + "autoscaling_window": None, + "concurrency_target": None, + "max_replica": None, + "max_scale_down_rate": None, + "min_replica": 0, + "scale_down_delay": None, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + }, + "chainlet_name": "HelloWorld", + }, + { + "autoscaling_settings": { + "autoscaling_window": None, + "concurrency_target": None, + "max_replica": None, + "max_scale_down_rate": None, + "min_replica": 0, + "scale_down_delay": None, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + }, + "chainlet_name": "RandInt", + }, + ], + ], + title="Updates", + ), + ] + + +class ChainletEnvironmentInstanceTypeUpdate(BaseModel): + chainlet_name: Annotated[ + str, + Field( + description="Name of the chainlet", + examples=["HelloWorld"], + title="Chainlet Name", + ), + ] + instance_type_id: Annotated[ + str, + Field( + description="Key of the instance type to use for the chainlet", + examples=["1x4", "2x8", "A10G:2x24x96"], + title="Instance Type Id", + ), + ] + + +class UpdateChainletEnvironmentInstanceTypeRequest(BaseModel): + updates: Annotated[ + list[ChainletEnvironmentInstanceTypeUpdate], + Field( + description="Mapping of chainlet name to the desired chainlet instance type. If the chainlet name doesn't exist, an error is returned.", + examples=[ + [ + {"chainlet_name": "HelloWorld", "instance_type_id": "1x4"}, + {"chainlet_name": "RandInt", "instance_type_id": "A10G:2x24x96"}, + ] + ], + title="Updates", + ), + ] + + +class UpsertTrainingProject(BaseModel): + name: Annotated[ + str, + Field( + description="Name of the training project.", + examples=["My Training Project"], + title="Name", + ), + ] + + +class UpsertTrainingProjectRequest(BaseModel): + training_project: Annotated[ + UpsertTrainingProject, Field(description="The training project to upsert.") + ] + + +class TrainingProjectSummary(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the training project.", title="Id") + ] + name: Annotated[ + str, Field(description="Name of the training project.", title="Name") + ] + + +class User(BaseModel): + email: Annotated[ + str | None, Field(description="Email of the user.", title="Email") + ] = None + + +class AwsAssumeRoleDockerAuth(BaseModel): + role_arn: Annotated[ + str, + Field( + description="AWS IAM role ARN that Baseten assumes to pull from the registry. The role's trust policy must allow Baseten's AWS principal with your Baseten-provided external ID.", + title="Role Arn", + ), + ] + region: Annotated[ + str, Field(description="AWS region of the registry", title="Region") + ] + + +class AwsOidcDockerAuth(BaseModel): + role_arn: Annotated[ + str, + Field(description="AWS IAM role ARN for OIDC authentication", title="Role Arn"), + ] + region: Annotated[ + str, Field(description="AWS region for OIDC authentication", title="Region") + ] + + +class CreateTrainingJobAccelerator(BaseModel): + accelerator: Annotated[ + str, + Field( + description="GPU type for the training job.", + examples=["H100"], + title="Accelerator", + ), + ] + count: Annotated[ + int, + Field( + description="GPUs needed for the training job.", examples=[2], title="Count" + ), + ] + + +class CreateTrainingJobCompute(BaseModel): + node_count: Annotated[ + int, + Field( + description="Number of nodes for the training job.", + examples=[1], + title="Node Count", + ), + ] = 1 + cpu_count: Annotated[ + int, + Field( + description="Number of cpus for the training job.", + examples=[1], + title="Cpu Count", + ), + ] = 1 + memory: Annotated[ + str, + Field( + description="Memory for the training job.", examples=["2Gi"], title="Memory" + ), + ] = "2Gi" + accelerator: Annotated[ + CreateTrainingJobAccelerator | None, + Field( + description="GPU specification for the training job", + examples=[{"accelerator": "H100", "count": 2}], + ), + ] = None + availability_model: Annotated[ + V1AvailabilityModel, + Field( + description="Capacity guarantee for the job. 'dedicated' (the default) runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress.", + examples=["spot"], + ), + ] = V1AvailabilityModel.dedicated + + +class GcpOidcDockerAuth(BaseModel): + service_account: Annotated[ + str, + Field( + description="GCP service account name for OIDC authentication", + title="Service Account", + ), + ] + workload_identity_provider: Annotated[ + str, + Field( + description="GCP workload identity provider for OIDC authentication", + title="Workload Identity Provider", + ), + ] + + +class InteractiveSessionConfig(BaseModel): + trigger: Annotated[ + V1InteractiveSessionTrigger, + Field( + description="When to create the interactive session. 'on_startup' creates on job start, 'on_failure' creates on job failure, 'on_demand' bypasses automatic session creation." + ), + ] = V1InteractiveSessionTrigger.on_demand + timeout_minutes: Annotated[ + int, + Field( + description="Number of minutes before the interactive session times out.", + examples=[480, 1440, 10080], + title="Timeout Minutes", + ), + ] = 480 + session_provider: Annotated[ + V1InteractiveSessionProvider, + Field(description="The IDE client for the interactive session."), + ] = V1InteractiveSessionProvider.vs_code + auth_provider: Annotated[ + V1InteractiveSessionAuthProvider, + Field(description="The authentication provider for the interactive session."), + ] = V1InteractiveSessionAuthProvider.github + + +class SecretReference(BaseModel): + name: Annotated[ + str, + Field( + description="Name of the secret to reference.", + examples=["hf_token"], + title="Name", + ), + ] + + +class TrainingWeightAuth(BaseModel): + auth_method: Annotated[ + AuthMethod, Field(description="Method used to authenticate the weight source.") + ] + auth_secret_name: Annotated[ + str | None, + Field( + description="Name of the workspace secret used for custom-secret authentication.", + title="Auth Secret Name", + ), + ] = None + aws_oidc_role_arn: Annotated[ + str | None, + Field( + description="AWS IAM role ARN used for OIDC authentication.", + title="Aws Oidc Role Arn", + ), + ] = None + aws_oidc_region: Annotated[ + str | None, + Field( + description="AWS region used for OIDC authentication.", + title="Aws Oidc Region", + ), + ] = None + gcp_oidc_service_account: Annotated[ + str | None, + Field( + description="GCP service account used for OIDC authentication.", + title="Gcp Oidc Service Account", + ), + ] = None + gcp_oidc_workload_id_provider: Annotated[ + str | None, + Field( + description="GCP workload identity provider used for OIDC authentication.", + title="Gcp Oidc Workload Id Provider", + ), + ] = None + aws_assume_role_arn: Annotated[ + str | None, + Field( + description="AWS IAM role ARN that Baseten assumes to access the weight source.", + title="Aws Assume Role Arn", + ), + ] = None + aws_assume_role_region: Annotated[ + str | None, + Field( + description="AWS region used for assume-role authentication.", + title="Aws Assume Role Region", + ), + ] = None -class AuditLogEventVolumeVersionDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["VOLUME_VERSION_DELETED"], Field(title="Event Type")] - volume_ref: Annotated[str, Field(title="Volume Ref")] - namespace: Annotated[str, Field(title="Namespace")] - volume_name: Annotated[str, Field(title="Volume Name")] - version: Annotated[str, Field(title="Version")] - digest: Annotated[str, Field(title="Digest")] +class TrainingJobTombstone(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the training job", title="Id") + ] + deleted: Annotated[ + bool, Field(description="Whether the training job was deleted", title="Deleted") + ] + training_project_id: Annotated[ + str, + Field( + description="Unique identifier of the training project", + title="Training Project Id", + ), + ] -class AuditLogEventVolumeVersionRestored(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[Literal["VOLUME_VERSION_RESTORED"], Field(title="Event Type")] - volume_ref: Annotated[str, Field(title="Volume Ref")] - namespace: Annotated[str, Field(title="Namespace")] - volume_name: Annotated[str, Field(title="Volume Name")] - version: Annotated[str, Field(title="Version")] - digest: Annotated[str, Field(title="Digest")] +class UpdateTrainingJobRequest(BaseModel): + priority: Annotated[ + int | None, + Field( + description="New queue priority for a PENDING training job. Higher values are dequeued first. Only jobs in the PENDING state can have their priority changed.", + examples=[0, 10, 100], + title="Priority", + ), + ] = None + availability_model: Annotated[ + V1AvailabilityModel | None, + Field( + description="New capacity guarantee for a PENDING training job. 'dedicated' runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress. Only jobs in the PENDING state can have their availability model changed.", + examples=["spot"], + ), + ] = None -class AuditLogEventWebhookSigningSecretCreated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["WEBHOOK_SIGNING_SECRET_CREATED"], Field(title="Event Type") +class DownloadTrainingJobResponse(BaseModel): + artifact_presigned_urls: Annotated[ + list[str], + Field( + description="Presigned URLs for the job's uploaded artifacts.", + title="Artifact Presigned Urls", + ), ] - webhook_signing_secret_id: Annotated[str, Field(title="Webhook Signing Secret Id")] -class AuditLogEventWebhookSigningSecretDeleted(BaseModel): - model_config = ConfigDict( - extra="forbid", +class GetTrainingJobLogsRequest(BaseModel): + start_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + title="Start Epoch Millis", + ), + ] = None + end_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + title="End Epoch Millis", + ), + ] = None + direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( + None ) - event_type: Annotated[ - Literal["WEBHOOK_SIGNING_SECRET_DELETED"], Field(title="Event Type") - ] - webhook_signing_secret_id: Annotated[str, Field(title="Webhook Signing Secret Id")] + limit: Annotated[ + Limit6 | None, + Field( + description="Limit of logs to fetch in a single request", + title="Limit", + validate_default=True, + ), + ] = Limit6.model_validate(500) + min_level: Annotated[ + LogLevel | None, + Field( + description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + ), + ] = None -class AuditLogEventWebhookSigningSecretRotated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["WEBHOOK_SIGNING_SECRET_ROTATED"], Field(title="Event Type") +class TrainingJobMetric(BaseModel): + value: Annotated[ + float, Field(description="The value of the metric.", title="Value") + ] + timestamp: Annotated[ + AwareDatetime, + Field( + description="The timestamp of the metric in ISO 8601 format.", + title="Timestamp", + ), ] - webhook_signing_secret_id: Annotated[str, Field(title="Webhook Signing Secret Id")] - - -class AuditLogPromotionControlAction(StrEnum): - PAUSE = "PAUSE" - RESUME = "RESUME" - FORCE_CANCEL = "FORCE_CANCEL" - FORCE_ROLL_FORWARD = "FORCE_ROLL_FORWARD" - GRACEFUL_CANCEL = "GRACEFUL_CANCEL" - - -class AuditLogSource(StrEnum): - UI = "UI" - API = "API" - MCP = "MCP" - SYSTEM = "SYSTEM" - OTHER = "OTHER" -class AuditLogEventTypeGroup(StrEnum): - DEPLOYED = "DEPLOYED" - PROMOTED = "PROMOTED" - ACTIVATED_DEACTIVATED = "ACTIVATED_DEACTIVATED" - AUTOSCALING_SETTINGS = "AUTOSCALING_SETTINGS" - REQUEST_BACKPRESSURE_SETTINGS = "REQUEST_BACKPRESSURE_SETTINGS" - INSTANCE_TYPE_CHANGED = "INSTANCE_TYPE_CHANGED" - ENVIRONMENT_SETTINGS = "ENVIRONMENT_SETTINGS" - REPLICA_TERMINATED = "REPLICA_TERMINATED" - DELETED = "DELETED" - SECRETS = "SECRETS" - API_KEYS = "API_KEYS" - GATEWAY = "GATEWAY" - WEBHOOK_SIGNING_SECRETS = "WEBHOOK_SIGNING_SECRETS" - USER_MANAGEMENT = "USER_MANAGEMENT" - DIRECTORY_GROUP_MANAGEMENT = "DIRECTORY_GROUP_MANAGEMENT" - SSH = "SSH" +class GetTrainingJobMetricsRequest(BaseModel): + end_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch millis timestamp to end fetching metrics", + title="End Epoch Millis", + ), + ] = None + start_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch millis timestamp to start fetching metrics.", + title="Start Epoch Millis", + ), + ] = None + step_seconds: Annotated[ + int | None, + Field( + description="Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", + title="Step Seconds", + ), + ] = None -class AuditLogSortDirection(StrEnum): - DESC = "DESC" - ASC = "ASC" +class StopTrainingJobRequest(BaseModel): + pass -class Model(BaseModel): - id: Annotated[str, Field(description="Unique identifier of the model", title="Id")] +class TrainingJobCheckpoint(BaseModel): + checkpoint_id: Annotated[ + str, Field(description="The ID of the checkpoint.", title="Checkpoint Id") + ] created_at: Annotated[ AwareDatetime, Field( - description="Time the model was created in ISO 8601 format", + description="The timestamp of the checkpoint in ISO 8601 format.", title="Created At", ), ] - name: Annotated[str, Field(description="Name of the model", title="Name")] - deployments_count: Annotated[ - int, + checkpoint_type: Annotated[ + str, Field(description="The type of checkpoint.", title="Checkpoint Type") + ] + base_model: Annotated[ + str | None, + Field(description="The base model of the checkpoint.", title="Base Model"), + ] + lora_adapter_config: Annotated[ + dict[str, Any] | None, Field( - description="Number of deployments of the model", title="Deployments Count" + description="The adapter config of the checkpoint.", + title="Lora Adapter Config", ), ] - production_deployment_id: Annotated[ + size_bytes: Annotated[ + int, + Field(description="The size of the checkpoint in bytes.", title="Size Bytes"), + ] + sync_status: Annotated[ str | None, Field( - description="Unique identifier of the production deployment of the model", - title="Production Deployment Id", + description="Sync state of the checkpoint: SYNCING or COMPLETE.", + title="Sync Status", + ), + ] = None + training_job_id: Annotated[ + str, Field(description="The ID of the training job.", title="Training Job Id") + ] + + +class GetTrainingJobCheckpointFilesResponse(BaseModel): + presigned_urls: Annotated[ + list[CheckpointFile], + Field( + description="List of presigned URLs for checkpoint files.", + title="Presigned Urls", ), ] - development_deployment_id: Annotated[ - str | None, + next_page_token: Annotated[ + int | None, Field( - description="Unique identifier of the development deployment of the model", - title="Development Deployment Id", + description="Token to use for fetching the next page of results. None when there are no more results.", + title="Next Page Token", + ), + ] = None + total_count: Annotated[ + int, + Field( + description="Total number of checkpoint files available.", + title="Total Count", ), ] - instance_type_name: Annotated[ + + +class AuthCode(BaseModel): + session_id: Annotated[ str, Field( - description="Name of the instance type for the production deployment of the model", - title="Instance Type Name", + description="Unique identifier of the interactive session.", + title="Session Id", ), ] - team_name: Annotated[ + replica_id: Annotated[ str, Field( - description="Name of the team associated with the model.", title="Team Name" + description="Replica identifier in gXXrY format (e.g., 'g00r0' for group 0, replica 0).", + title="Replica Id", ), ] - - -class Models(BaseModel): - models: Annotated[list[Model], Field(title="Models")] - - -class LibraryListingSource(BaseModel): - kind: Annotated[Literal["library_listing"], Field(title="Kind")] = "library_listing" - lab_display_name: Annotated[ + auth_code: Annotated[ str, Field( - description="Identifier of the publishing organization, as returned by `GET /v1/library_models`.", - title="Lab Display Name", + description="The device authentication code (e.g., '4F64-C0D9').", + title="Auth Code", ), ] - user_defined_listing_id: Annotated[ + auth_url: Annotated[ str, Field( - description="Listing identifier within the publishing organization.", - title="User Defined Listing Id", + description="URL where the user should enter the auth code (e.g., 'https://github.com/login/device').", + title="Auth Url", ), ] - deployed_model_name: Annotated[ - str | None, + generated_at: Annotated[ + AwareDatetime | None, Field( - description="Optional name for the new deployed model. Defaults to the listing's configured name.", - title="Deployed Model Name", + description="When the auth code was generated, in ISO 8601 format.", + title="Generated At", ), ] = None - - -class ModelArchiveSource(BaseModel): - kind: Annotated[Literal["model_archive"], Field(title="Kind")] = "model_archive" - name: Annotated[str, Field(description="Name of the new model.", title="Name")] - deployment: Annotated[ - DeploymentArchivePayload, - Field( - description="Deployment-level configuration for the model's first deployment." - ), - ] - s3_key: Annotated[ + tunnel_name: Annotated[ str | None, + Field(description="The name of the tunnel node.", title="Tunnel Name"), + ] = None + expires_at: Annotated[ + AwareDatetime | None, Field( - description="S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", - title="S3 Key", + description="When the session expires, in ISO 8601 format.", + title="Expires At", ), ] = None - disable_archive_download: Annotated[ - bool, + working_directory: Annotated[ + str | None, Field( - description="If true, the uploaded archive is not downloadable after creation. Locked at model creation; cannot be changed by subsequent deployments.", - title="Disable Archive Download", + description="The working directory of the session.", + title="Working Directory", ), - ] = False + ] = None -class CreateModelRequest(BaseModel): - source: Annotated[ - LibraryListingSource | ModelArchiveSource, +class GetAuthCodesResponse(BaseModel): + auth_codes: Annotated[ + list[AuthCode], Field( - description="Where the new model is created from.", - discriminator="kind", - title="Source", + description="List of auth codes for each node that has an active interactive session.", + title="Auth Codes", ), ] -class AutoscalingSettings(BaseModel): - min_replica: Annotated[ - int, Field(description="Minimum number of replicas", title="Min Replica") - ] - max_replica: Annotated[ - int, Field(description="Maximum number of replicas", title="Max Replica") - ] - autoscaling_window: Annotated[ +class PatchInteractiveSessionRequest(BaseModel): + timeout_minutes: Annotated[ int | None, Field( - description="Timeframe of traffic considered for autoscaling decisions", - title="Autoscaling Window", + description="For on_startup sessions, minutes to add to the expiration. For on_demand/on_failure sessions, minutes to add to the timeout. Use -1 for infinite timeout (bumps by 10 years).", + title="Timeout Minutes", ), - ] - scale_down_delay: Annotated[ - int | None, + ] = None + trigger: Annotated[ + V1InteractiveSessionTrigger | None, Field( - description="Waiting period before scaling down any active replica", - title="Scale Down Delay", + description="Update when the interactive session is created. Cannot be changed if the session trigger is 'on_startup'." ), + ] = None + + +class InteractiveSession(BaseModel): + id: Annotated[ + str, + Field(description="Unique identifier of the interactive session.", title="Id"), ] - concurrency_target: Annotated[ + trigger: Annotated[ + str, + Field(description="When the interactive session is created.", title="Trigger"), + ] + timeout_minutes: Annotated[ int, Field( - description="Number of requests per replica before scaling up", - title="Concurrency Target", + description="Minutes before the session times out.", title="Timeout Minutes" ), ] - target_utilization_percentage: Annotated[ - int | None, + session_provider: Annotated[ + str, + Field(description="The IDE client for the session.", title="Session Provider"), + ] + auth_provider: Annotated[ + str, Field( - description="Target utilization percentage for scaling up/down.", - title="Target Utilization Percentage", + description="The authentication provider for the session.", + title="Auth Provider", ), ] - target_in_flight_tokens: Annotated[ - int | None, + pod_name: Annotated[ + str, + Field(description="Pod name / node rank for the session.", title="Pod Name"), + ] + expires_at: Annotated[ + AwareDatetime | None, Field( - description="Target number of in-flight tokens for autoscaling decisions. Early access only.", - title="Target In Flight Tokens", + description="When the session expires, in ISO 8601 format.", + title="Expires At", ), ] = None - max_scale_down_rate: Annotated[ - int | None, - Field( - description="Maximum percentage of replicas that can be removed per autoscaling window (1–50). E.g. 20 means at most 20% of replicas are removed per window.", - title="Max Scale Down Rate", - ), + tunnel_name: Annotated[ + str | None, + Field(description="The tunnel name for the session.", title="Tunnel Name"), ] = None - - -class DeploymentStatus(StrEnum): - BUILDING = "BUILDING" - DEPLOYING = "DEPLOYING" - DEPLOY_FAILED = "DEPLOY_FAILED" - LOADING_MODEL = "LOADING_MODEL" - ACTIVE = "ACTIVE" - UNHEALTHY = "UNHEALTHY" - BUILD_FAILED = "BUILD_FAILED" - BUILD_STOPPED = "BUILD_STOPPED" - DEACTIVATING = "DEACTIVATING" - INACTIVE = "INACTIVE" - FAILED = "FAILED" - UPDATING = "UPDATING" - SCALED_TO_ZERO = "SCALED_TO_ZERO" - WAKING_UP = "WAKING_UP" - - -class RequestBackpressurePolicy(StrEnum): - QUEUE_ON_FULL = "QUEUE_ON_FULL" - REJECT_ON_FULL = "REJECT_ON_FULL" - - -class RequestBackpressureSettings(BaseModel): - policy: Annotated[ - RequestBackpressurePolicy | None, - Field(description="Backpressure policy. Null when no policy is set."), + auth_code: Annotated[ + str | None, + Field(description="The device authentication code.", title="Auth Code"), ] = None - - -class ModelTombstone(BaseModel): - id: Annotated[str, Field(description="Unique identifier of the model", title="Id")] - deleted: Annotated[ - bool, Field(description="Whether the model was deleted", title="Deleted") - ] - - -class DeploymentArchiveSource(BaseModel): - kind: Annotated[Literal["model_archive"], Field(title="Kind")] = "model_archive" - deployment: Annotated[ - DeploymentArchivePayload, Field(description="Deployment-level configuration.") - ] - s3_key: Annotated[ + auth_url: Annotated[ str | None, Field( - description="S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", - title="S3 Key", + description="URL where the user should enter the auth code.", + title="Auth Url", ), ] = None - - -class CreateModelDeploymentRequest(BaseModel): - source: Annotated[ - DeploymentArchiveSource, + auth_code_generated_at: Annotated[ + AwareDatetime | None, Field( - description="Where the new deployment is created from.", - discriminator="kind", - title="Source", + description="When the auth code was generated.", + title="Auth Code Generated At", ), - ] - - -class DeploymentTombstone(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the deployment", title="Id") - ] - deleted: Annotated[ - bool, Field(description="Whether the deployment was deleted", title="Deleted") - ] - model_id: Annotated[ - str, Field(description="Unique identifier of the model", title="Model Id") - ] - - -class Name1(RootModel[str]): - root: Annotated[ - str | None, + ] = None + authenticated_at: Annotated[ + AwareDatetime | None, Field( - description="New name for the deployment, unique among the model's deployments. Only alphanumeric characters, hyphens, underscores, and periods are allowed.", - examples=["my-deployment"], - max_length=255, - min_length=1, - title="Name", + description="When the session was authenticated.", title="Authenticated At" ), ] = None - - -class UpdateDeploymentRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - name: Annotated[ - Name1 | None, + working_directory: Annotated[ + str | None, Field( - description="New name for the deployment, unique among the model's deployments. Only alphanumeric characters, hyphens, underscores, and periods are allowed.", - examples=["my-deployment"], - title="Name", + description="The working directory of the session.", + title="Working Directory", ), ] = None -class MaxScaleDownRate(RootModel[int]): - root: Annotated[ - int | None, +class PatchInteractiveSessionResponse(BaseModel): + interactive_session: Annotated[ + InteractiveSession, Field(description="The updated interactive session.") + ] + message: Annotated[ + str, Field( - description="Maximum percentage of replicas that can be removed per autoscaling window (1–50). E.g. 20 means at most 20% of replicas are removed per window.", - examples=[20], - ge=1, - le=50, - title="Max Scale Down Rate", + description="Human-readable summary of what was updated.", title="Message" ), - ] = None + ] -class UpdateAutoscalingSettings(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - min_replica: Annotated[ - int | None, - Field( - description="Minimum number of replicas", examples=[0], title="Min Replica" - ), - ] = None - max_replica: Annotated[ - int | None, +class GetCacheSummaryResponse(BaseModel): + timestamp: Annotated[ + str, Field( - description="Maximum number of replicas", examples=[7], title="Max Replica" + description="Timestamp when the cache summary was captured", + title="Timestamp", ), - ] = None - autoscaling_window: Annotated[ - int | None, + ] + project_id: Annotated[ + str, + Field(description="Project ID associated with the cache", title="Project Id"), + ] + file_summaries: Annotated[ + list[FileSummary], + Field(description="List of files in the cache", title="File Summaries"), + ] + + +class TrainingProjectTombstone(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the training project", title="Id") + ] + deleted: Annotated[ + bool, + Field(description="Whether the training project was deleted", title="Deleted"), + ] + + +class OrderBy(BaseModel): + field: Annotated[ + str, Field( - description="Timeframe of traffic considered for autoscaling decisions", - examples=[600], - title="Autoscaling Window", + description="The field to order by.", examples=["created_at"], title="Field" ), - ] = None - scale_down_delay: Annotated[ - int | None, + ] + order: Annotated[ + str, Field( - description="Waiting period before scaling down any active replica", - examples=[120], - title="Scale Down Delay", + description="The direction to order by.", + examples=["asc", "desc"], + title="Order", ), - ] = None - concurrency_target: Annotated[ - int | None, + ] + + +class SearchTrainingJobsRequest(BaseModel): + project_id: Annotated[ + str | None, Field( - description="Number of requests per replica before scaling up", - examples=[2], - title="Concurrency Target", + description="Filter the training jobs by project ID.", + examples=["n4q95w5"], + title="Project Id", ), ] = None - target_utilization_percentage: Annotated[ - int | None, + job_id: Annotated[ + str | None, Field( - description="Target utilization percentage for scaling up/down.", - examples=[70], - title="Target Utilization Percentage", + description="Filter the training jobs by job ID.", + examples=["p7qr9qv"], + title="Job Id", ), ] = None - target_in_flight_tokens: Annotated[ - int | None, + statuses: Annotated[ + list[str] | None, Field( - description="Target number of in-flight tokens for autoscaling decisions. Early access only.", - examples=[40000], - title="Target In Flight Tokens", + description="Filter the training jobs by status.", + examples=[["TRAINING_JOB_RUNNING", "TRAINING_JOB_COMPLETED"]], + title="Statuses", ), ] = None - max_scale_down_rate: Annotated[ - MaxScaleDownRate | None, + order_by: Annotated[ + list[OrderBy], Field( - description="Maximum percentage of replicas that can be removed per autoscaling window (1–50). E.g. 20 means at most 20% of replicas are removed per window.", - examples=[20], - title="Max Scale Down Rate", + description="Order the training jobs by a field. Currently supports created_at", + title="Order By", + validate_default=True, ), - ] = None - - -class UpdateAutoscalingSettingsStatus(StrEnum): - ACCEPTED = "ACCEPTED" - QUEUED = "QUEUED" - UNCHANGED = "UNCHANGED" + ] = [OrderBy.model_validate({"field": "created_at", "order": "desc"})] -class UpdateAutoscalingSettingsResponse(BaseModel): - status: Annotated[ - UpdateAutoscalingSettingsStatus, - Field(description="Status of the request to update autoscaling settings"), +class EnablementDetails(BaseModel): + reason: Annotated[ + str, + Field( + description="Machine-readable reason the model is not enabled. Currently one of 'needs_approval', 'sequence_length_unsupported' or 'loops_not_enabled'. Deliberately not a closed enum: values are added as the check learns to distinguish cases that call for a different action, so treat an unrecognized value as 'not enabled, reason unknown' rather than an error.", + examples=["needs_approval"], + title="Reason", + ), ] - message: Annotated[ + reason_detail: Annotated[ str, Field( - description="A message describing the status of the request to update autoscaling settings", - title="Message", + description="Human-readable explanation of the reason.", + title="Reason Detail", ), ] - - -class UpdateRequestBackpressureSettings(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - policy: Annotated[ - RequestBackpressurePolicy | None, + remediation: Annotated[ + str, Field( - description="Backpressure policy to apply. Null indicates no policy (on update, clears an existing one).", - examples=["REJECT_ON_FULL"], + description="Human-readable next step to enable the model.", + title="Remediation", ), - ] = None + ] -class PromoteRequest(BaseModel): - scale_down_previous_production: Annotated[ - bool, +class SupportedModel(BaseModel): + model_name: Annotated[ + str, Field(description="The name of the supported model.", title="Model Name") + ] + max_seq_len: Annotated[ + int, Field( - description="Whether to scale down the previous production deployment after promoting", - examples=[True], - title="Scale Down Previous Production", + description="The longest sequence length Baseten supports for this model. Independent of the caller: see 'max_enabled_seq_len' for what this workspace can actually train at. Named to match the 'max_seq_len' query parameter and the field of the same name on run creation, so one name follows the value through the API.", + title="Max Seq Len", ), - ] = True - preserve_env_instance_type: Annotated[ - bool, + ] + max_enabled_seq_len: Annotated[ + int, Field( - description="Whether to use the promoting deployment's instance type or preserve target environment's instance type", - examples=[True], - title="Preserve Env Instance Type", + description="The longest sequence length this workspace can train at. Lower than 'max_seq_len' when the longer configurations need hardware the workspace is not approved for — a model's longer sequence lengths often need a bigger SKU of the same GPU. Zero when the workspace cannot run the model at all, so a client can compare against a required length without a null case.", + title="Max Enabled Seq Len", ), - ] = True - - -class ActivateResponse(BaseModel): - success: Annotated[ - bool, + ] = 0 + max_context_length: Annotated[ + int, Field( - description="Whether the deployment was successfully activated", - title="Success", + deprecated=True, + description="Deprecated. Use 'max_seq_len', which carries the same value. Kept so existing clients keep working.", + title="Max Context Length", ), - ] = True - no_op: Annotated[ + ] + supports_vision_language: Annotated[ bool, Field( - description="Whether the request did nothing because the deployment was already active or on its way to becoming active", - title="No Op", + description="Whether the model accepts image inputs alongside text.", + title="Supports Vision Language", ), - ] = False - - -class DeactivateResponse(BaseModel): - success: Annotated[ + ] + enabled: Annotated[ bool, Field( - description="Whether the deployment was successfully deactivated", - title="Success", + description="Whether this workspace can start a run with this model now. False means Baseten supports it but the workspace cannot use it yet; 'not_enabled' says why. Capacity is resolved when the run is created, so true is not a guarantee that GPUs are free.", + title="Enabled", ), ] = True - no_op: Annotated[ - bool, + enablement_details: Annotated[ + EnablementDetails | None, Field( - description="Whether the request did nothing because the deployment was already inactive", - title="No Op", + description="Why the model is not enabled, and what would change it. Present only when 'enabled' is false — an enabled model has nothing to explain. Read 'enabled' for the state; this is the detail behind it." ), - ] = False + ] = None -class DownloadDeploymentResponse(BaseModel): - download_url: Annotated[ - str, +class GetLoopsCapabilitiesResponse(BaseModel): + supported_models: Annotated[ + list[SupportedModel], Field( - description="Presigned URL to download the truss tar file", - title="Download Url", + description="Models Baseten supports for this use case, each carrying an 'enabled' flag saying whether this workspace can run it now, and 'enablement_details' when it cannot. Filter on 'enabled' to get the models you can use.", + title="Supported Models", ), ] -class DeploymentConfigResponse(BaseModel): - config: Annotated[ - dict[str, Any] | None, - Field(description="The parsed config of the deployment.", title="Config"), - ] = None - raw_config: Annotated[ - str | None, +class LoopsUseCase(StrEnum): + rl = "rl" + sft = "sft" + + +class LoopsSession(BaseModel): + id: Annotated[str, Field(title="Id")] + + +class CreateLoopsSessionResponse(BaseModel): + session: LoopsSession + + +class GetLoopsSessionResponse(BaseModel): + session: Annotated[LoopsSession, Field(description="The Loops session.")] + + +class LoopsRunStatusName(StrEnum): + ACTIVE = "ACTIVE" + INACTIVE = "INACTIVE" + + +class LoopsRunStatus(BaseModel): + name: Annotated[ + LoopsRunStatusName, Field( - description="The original config.yaml text — preserves comments, ordering, formatting.", - title="Raw Config", + description="ACTIVE while the run is live; INACTIVE once replaced by a newer run or shut down." ), - ] = None + ] -class LogLevel(StrEnum): - DEBUG = "DEBUG" - INFO = "INFO" - WARNING = "WARNING" - ERROR = "ERROR" +class LoopsSamplerStatus(BaseModel): + name: Annotated[ + DeploymentStatus, Field(description="The current status of the Loops sampler.") + ] -class Log(BaseModel): - timestamp: Annotated[ +class LoopsSampler(BaseModel): + id: Annotated[str, Field(title="Id")] + base_url: Annotated[str, Field(title="Base Url")] + base_model: Annotated[ str, Field( - description="Epoch nanosecond timestamp of the log message.", - title="Timestamp", + description="The HuggingFace base model the sampler is serving.", + title="Base Model", ), ] - message: Annotated[ - str, + created_at: Annotated[ + AwareDatetime, Field( - description="The contents of the log message. When the logger captured an exception, the traceback is appended after the message.", - title="Message", + description="Time the sampler was created in ISO 8601 format", + title="Created At", ), ] - replica: Annotated[ - str | None, - Field( - description="The replica the log line was emitted from.", title="Replica" - ), + model_id: Annotated[ + str, + Field(description="Hashid of the underlying Baseten model.", title="Model Id"), ] - request_id: Annotated[ - str | None, - Field( - description="The request ID associated with an inference request.", - title="Request Id", - ), - ] = None - level: Annotated[ - LogLevel | None, + deployment_id: Annotated[ + str, Field( - description="Severity of the log line, if one was detected. null when unknown." + description="Hashid of the specific model deployment (version).", + title="Deployment Id", ), - ] = None - - -class GetLogsResponse(BaseModel): - logs: Annotated[ - list[Log], Field(description="Logs for a specific entity.", title="Logs") ] + status: Annotated[ + LoopsSamplerStatus, Field(description="The sampler's current status.") + ] + user: Annotated[User, Field(description="The user who owns the sampler.")] + instance_type: Annotated[ + InstanceType | None, Field(description="Instance type serving the sampler.") + ] = None + node_count: Annotated[ + int, + Field(description="Number of nodes serving the sampler.", title="Node Count"), + ] = 1 -class SortOrder(StrEnum): - asc = "asc" - desc = "desc" - - -class Limit6(RootModel[int]): +class Name3(RootModel[str]): root: Annotated[ - int, + str | None, Field( - description="Limit of logs to fetch in a single request", - ge=1, - le=1000, - title="Limit", + description="Optional display name for the run. Defaults to the base model name when omitted.", + max_length=255, + min_length=1, + title="Name", ), - ] = 500 + ] = None -class GetDeploymentLogsRequest(BaseModel): - start_epoch_millis: Annotated[ - int | None, +class CreateLoopsRunRequest(BaseModel): + session_id: Annotated[ + str, Field( - description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - title="Start Epoch Millis", + description="ID of the Loops session this run belongs to.", + title="Session Id", ), - ] = None - end_epoch_millis: Annotated[ - int | None, + ] + base_model: Annotated[ + str, + Field(description="Base model ID (e.g. 'Qwen/Qwen3-8B').", title="Base Model"), + ] + name: Annotated[ + Name3 | None, Field( - description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - title="End Epoch Millis", + description="Optional display name for the run. Defaults to the base model name when omitted.", + title="Name", ), ] = None - direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( - None - ) - limit: Annotated[ - Limit6 | None, - Field( - description="Limit of logs to fetch in a single request", - title="Limit", - validate_default=True, - ), - ] = Limit6.model_validate(500) - min_level: Annotated[ - LogLevel | None, + max_seq_len: Annotated[ + int | None, Field( - description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + description="Maximum prompt length (in tokens) the run must handle. Set this to the longest training example you plan to send. Defaults to the maximum supported by the model configuration.", + title="Max Seq Len", ), ] = None - replica: Annotated[ - Replica | None, + lora_rank: Annotated[ + int, Field(description="LoRA rank.", ge=1, title="Lora Rank") + ] = 64 + seed: Annotated[ + int | None, Field(description="Random seed for reproducibility.", title="Seed") + ] = None + scale_down_delay_seconds: Annotated[ + int, Field( - description="Only return logs emitted by this replica (5-char short ID).", - title="Replica", + description="Seconds of inactivity before the run scales to zero. Must be between 1 and 3600 (1 hour). Defaults to 900 (15 minutes).", + gt=0, + le=3600, + title="Scale Down Delay Seconds", ), - ] = None - request_id: Annotated[ - RequestId | None, + ] = 900 + availability_model: Annotated[ + V1AvailabilityModel, Field( - description="Only return logs tagged with this inference request ID.", - title="Request Id", + description="Capacity the trainer runs on. 'dedicated' is not preempted. 'spot' runs below inference and reaches idle reserved capacity, but the run is stopped if its GPUs are reclaimed and cannot be resumed.", + examples=["spot"], ), - ] = None - component: Annotated[ - Component | None, - Field(description="Only return logs from this component.", title="Component"), - ] = None - search_pattern: Annotated[ - SearchPattern | None, + ] = V1AvailabilityModel.dedicated + replicas: Annotated[ + int, Field( - description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", - title="Search Pattern", + description="Number of data-parallel trainer replicas. Each replica is one full copy of the model's preset node group, so the trainer deployment runs (preset node_count * replicas) nodes (e.g. replicas=4 on a 4-node preset → 16 nodes, 4 DP workers). Must be a positive integer. Defaults to 1.", + ge=1, + title="Replicas", ), - ] = None - includes: Annotated[ - list[str] | None, + ] = 1 + path: Annotated[ + str | None, Field( - description="Case-sensitive substrings that must all appear in the log message.", - max_length=8, - title="Includes", + description="Optional bt:// URI of an existing checkpoint to load weights from on startup. Form: bt://loops:/weights/.", + examples=["bt://loops:k4q95w5/weights/step-100"], + title="Path", ), ] = None - excludes: Annotated[ - list[str] | None, + reuse_from_run_id: Annotated[ + str | None, Field( - description="Case-sensitive substrings; lines containing any of these are dropped.", - max_length=8, - title="Excludes", + description="Optional ID of a prior Loops run whose trainer and/or sampler should be reused for this run instead of provisioning fresh. The prior run must use the same base model and belong to the same team.", + title="Reuse From Run Id", ), ] = None - - -class DeploymentPatchAction(StrEnum): - ADD = "ADD" - UPDATE = "UPDATE" - REMOVE = "REMOVE" - - -class DeploymentPatchOpConfig(BaseModel): - type: Annotated[Literal["config"], Field(title="Type")] = "config" - config: Annotated[ - dict[str, Any], - Field(description="The full parsed config as a JSON object.", title="Config"), - ] - path: Annotated[ - str, Field(description="Config file path within the source.", title="Path") - ] = "config.yaml" - - -class DeploymentPatchOpEnvVar(BaseModel): - type: Annotated[Literal["environment_variable"], Field(title="Type")] = ( - "environment_variable" - ) - action: Annotated[ - DeploymentPatchAction, Field(description="How this op changes the variable.") - ] - name: Annotated[ - str, Field(description="The environment variable name.", title="Name") - ] - value: Annotated[ + reuse_from_session_id: Annotated[ str | None, Field( - description="The environment variable value. Required for add and update.", - title="Value", + description="Optional ID of a prior Loops session whose trainer and/or sampler should be reused for this run. Deprecated in favor of reuse_from_run_id.", + title="Reuse From Session Id", ), ] = None -class DeploymentPatchOpExternalData(BaseModel): - type: Annotated[Literal["external_data"], Field(title="Type")] = "external_data" - action: Annotated[ - DeploymentPatchAction, +class DeactivateLoopsRunResponse(BaseModel): + id: Annotated[str, Field(description="The deactivated Loops run ID.", title="Id")] + base_model: Annotated[ + str, Field( - description="How this op changes the item. `UPDATE` is treated identically to `ADD`." + description="The base model whose Loops run was deactivated.", + title="Base Model", ), ] - item: Annotated[ - dict[str, str], - Field(description="The single external data item descriptor.", title="Item"), - ] + user: Annotated[User, Field(description="The user who owns the Loops run.")] -class DeploymentPatchOpModelCode(BaseModel): - type: Annotated[Literal["model_code"], Field(title="Type")] = "model_code" - action: Annotated[ - DeploymentPatchAction, Field(description="How this op changes the file.") +class ListLoopsSamplersResponse(BaseModel): + samplers: Annotated[ + list[LoopsSampler], Field(description="List of samplers.", title="Samplers") ] - path: Annotated[ + + +class CreateLoopsSamplerRequest(BaseModel): + availability_model: Annotated[ + V1AvailabilityModel | None, + Field( + description="Capacity the sampler runs on. 'spot' allows preemption when its GPUs are reclaimed. Defaults to 'dedicated' for standalone samplers. Paired samplers inherit their run's availability model; an explicit value must match it." + ), + ] = None + session_id: Annotated[ str, Field( - description="File path relative to the model code directory.", title="Path" + description="ID of the Loops session this sampler belongs to.", + title="Session Id", ), ] - content: Annotated[ + base_model: Annotated[ str | None, Field( - description="UTF-8 file content. Null for removals and binary files.", - title="Content", + description="Base model ID for a standalone sampler (for example, a baseline).", + title="Base Model", ), ] = None - content_bytes: Annotated[ + run_id: Annotated[ str | None, Field( - description="Base64-encoded content for binary files.", - title="Content Bytes", + description="ID of an existing run to attach this sampler to. When set, the sampler is paired to the run and weight-syncs from its trainer, and base_model is inherited from the run. Omit to create a standalone sampler.", + title="Run Id", ), ] = None - hot_reload: Annotated[ - bool, + max_seq_length: Annotated[ + int | None, Field( - description="Whether the running server can pick up this change without a restart.", - title="Hot Reload", + description="Maximum prompt length (in tokens) the sampler must handle. Set this to the longest prompt you plan to send.", + title="Max Seq Length", ), - ] = False + ] = None + model_path: Annotated[ + str | None, + Field( + description="bt:// URI of an existing sampler checkpoint to serve. Form: bt://loops:/sampler_weights/.", + examples=["bt://loops:k4q95w5/sampler_weights/step-100"], + title="Model Path", + ), + ] = None + reuse_from_session_id: Annotated[ + str | None, + Field( + description="Optional ID of a prior Loops session to reuse a trainer and/or sampler from. Deprecated.", + title="Reuse From Session Id", + ), + ] = None -class DeploymentPatchOpPackage(BaseModel): - type: Annotated[Literal["package"], Field(title="Type")] = "package" - action: Annotated[ - DeploymentPatchAction, Field(description="How this op changes the file.") +class CreateLoopsSamplerResponse(BaseModel): + sampler: LoopsSampler + + +class DeactivateLoopsSamplerResponse(BaseModel): + id: Annotated[ + str, Field(description="The deactivated Loops sampler ID.", title="Id") ] - path: Annotated[ + base_model: Annotated[ str, Field( - description="File path relative to the bundled packages directory.", - title="Path", + description="The base model the deactivated sampler was serving.", + title="Base Model", ), ] - content: Annotated[ + user: Annotated[User, Field(description="The user who owns the Loops sampler.")] + + +class GetLoopsSamplerResponse(BaseModel): + sampler: Annotated[LoopsSampler, Field(description="The Loops sampler.")] + + +class LoopsCheckpoint(BaseModel): + checkpoint_id: Annotated[ + str, Field(description="The ID of the checkpoint.", title="Checkpoint Id") + ] + created_at: Annotated[ + AwareDatetime, + Field( + description="The timestamp of the checkpoint in ISO 8601 format.", + title="Created At", + ), + ] + checkpoint_type: Annotated[ + str, Field(description="The type of checkpoint.", title="Checkpoint Type") + ] + base_model: Annotated[ str | None, + Field(description="The base model of the checkpoint.", title="Base Model"), + ] + lora_adapter_config: Annotated[ + dict[str, Any] | None, Field( - description="UTF-8 file content. Null for removals and binary files.", - title="Content", + description="The adapter config of the checkpoint.", + title="Lora Adapter Config", ), - ] = None - content_bytes: Annotated[ + ] + size_bytes: Annotated[ + int, + Field(description="The size of the checkpoint in bytes.", title="Size Bytes"), + ] + sync_status: Annotated[ str | None, Field( - description="Base64-encoded content for binary files.", - title="Content Bytes", + description="Sync state of the checkpoint: SYNCING or COMPLETE.", + title="Sync Status", ), ] = None + id: Annotated[str, Field(description="The checkpoint ID.", title="Id")] + run_id: Annotated[ + str, + Field( + description="The ID of the run that produced the checkpoint.", + title="Run Id", + ), + ] + target: Annotated[ + TrainerCheckpointTarget, + Field( + description="Whether this checkpoint is loadable by the sampler or by the run." + ), + ] -class DeploymentPatchOpPythonRequirement(BaseModel): - type: Annotated[Literal["python_requirement"], Field(title="Type")] = ( - "python_requirement" - ) - action: Annotated[ - DeploymentPatchAction, Field(description="How this op changes the requirement.") +class ListLoopsCheckpointsResponse(BaseModel): + checkpoints: Annotated[ + list[LoopsCheckpoint], + Field(description="Matching checkpoints.", title="Checkpoints"), ] - requirement: Annotated[ + + +class ValidateLoopsCheckpointRequest(BaseModel): + checkpoint_path: Annotated[ str, Field( - description="The requirement to apply. For removals this is the package name; otherwise the full requirements.txt-style line.", - title="Requirement", + description="bt:// URI of a sampler checkpoint. Form: bt://loops:/sampler_weights/.", + examples=["bt://loops:k4q95w5/sampler_weights/step-100"], + title="Checkpoint Path", ), ] -class DeploymentPatchPoint(BaseModel): - content_hashes: Annotated[ - dict[str, str | None], +class ValidateLoopsCheckpointResponse(BaseModel): + pass + + +class DeployLoopsCheckpointRequest(BaseModel): + checkpoint_ids: Annotated[ + list[str], Field( - description="Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", - title="Content Hashes", + description="Sampler checkpoint IDs to deploy together.", + min_length=1, + title="Checkpoint Ids", ), ] - config: Annotated[ + model_name: Annotated[ str, Field( - description="The verbatim config.yaml text for this source state.", - title="Config", + description="Name for the created model.", min_length=1, title="Model Name" ), ] - requirements: Annotated[ - list[str] | None, + instance_type_id: Annotated[ + str, Field( - description="Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", - title="Requirements", + description="Instance type ID for the deployment.", title="Instance Type Id" ), - ] = None - - -class PatchOps( - RootModel[ - DeploymentPatchOpModelCode - | DeploymentPatchOpPackage - | DeploymentPatchOpConfig - | DeploymentPatchOpPythonRequirement - | DeploymentPatchOpEnvVar - | DeploymentPatchOpExternalData ] -): - root: Annotated[ - DeploymentPatchOpModelCode - | DeploymentPatchOpPackage - | DeploymentPatchOpConfig - | DeploymentPatchOpPythonRequirement - | DeploymentPatchOpEnvVar - | DeploymentPatchOpExternalData, - Field(discriminator="type"), + hf_secret_name: Annotated[ + str, + Field( + description="Name of the team-scoped secret that supplies HF_TOKEN.", + min_length=1, + title="Hf Secret Name", + ), ] -class CreateDeploymentPatchRequest(BaseModel): - prev_patch_hash: Annotated[ +class DeployLoopsCheckpointResponse(BaseModel): + model_id: Annotated[ + str, Field(description="ID of the created or updated model.", title="Model Id") + ] + deployment_id: Annotated[ str, Field( - description="Content hash of the patch point this patch is applied on - the link the staged patch must build on. A stale value (the base moved underneath the client) is rejected with a conflict.", - title="Prev Patch Hash", + description="ID of the created model version deployment.", + title="Deployment Id", ), ] - next_patch_point: Annotated[ - DeploymentPatchPoint, + + +class LoopsCheckpointFilesResponse(BaseModel): + presigned_urls: Annotated[ + list[CheckpointFile], Field( - description="The source state after this patch. The server derives its content hash from `content_hashes`." + description="List of presigned URLs for checkpoint files.", + title="Presigned Urls", ), ] - patch_ops: Annotated[ - list[PatchOps], + next_page_token: Annotated[ + int | None, Field( - description="The ordered ops that make up this patch. At least one op is required; a patch that changes nothing is not a valid request. There is no op for a directory: a directory comes into existence when the first file under it is added, and is removed when its last file is removed, so directory creation and deletion happen implicitly through the file ops. Adding or removing an otherwise empty directory therefore produces no ops even though it changes the source hash; do not send a patch request for such a change.", - min_length=1, - title="Patch Ops", + description="Token to use for fetching the next page of results. None when there are no more results.", + title="Next Page Token", + ), + ] = None + total_count: Annotated[ + int, + Field( + description="Total number of checkpoint files available.", + title="Total Count", ), ] -class DeploymentPatchPointWithHash(BaseModel): - content_hashes: Annotated[ - dict[str, str | None], +class LoopsCheckpointS3Source(BaseModel): + kind: Annotated[Literal["s3"], Field(title="Kind")] = "s3" + + +class LoopsCheckpointVolumeSource(BaseModel): + kind: Annotated[Literal["volume"], Field(title="Kind")] = "volume" + volume_ref: Annotated[ + str, Field( - description="Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", - title="Content Hashes", + description="Ref of the volume version holding the checkpoint, as `bdn:/:`.", + title="Volume Ref", ), ] - config: Annotated[ + path: Annotated[ str, Field( - description="The verbatim config.yaml text for this source state.", - title="Config", + description="Directory inside that version holding the checkpoint's files.", + title="Path", ), ] - requirements: Annotated[ - list[str] | None, + + +class LoopsCheckpointSourceResponse(BaseModel): + source: Annotated[ + LoopsCheckpointS3Source | LoopsCheckpointVolumeSource, Field( - description="Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", - title="Requirements", + description="`s3` means the files endpoint serves presigned URLs for this checkpoint; `volume` carries the ref to pull instead.", + discriminator="kind", + title="Source", + ), + ] + + +class LoopsDeploymentStatus(BaseModel): + name: Annotated[Name, Field(description="Latest status of the Loops deployment.")] + + +class LoopsDeployment(BaseModel): + id: Annotated[str, Field(description="The Loops deployment ID.", title="Id")] + active_run_id: Annotated[ + str | None, + Field( + description="The ID of the run currently active on this deployment, if any. Null when the deployment's runs have been marked inactive (e.g. scale-to-zero) without a successor.", + title="Active Run Id", ), ] = None - hash: Annotated[ + latest_run_id: Annotated[ + str | None, + Field( + description="The ID of the most recent run on this deployment, active or not, so idle deployments still expose a usable run handle. Null only if the deployment has no runs.", + title="Latest Run Id", + ), + ] = None + base_model: Annotated[ str, Field( - description="Content hash identifying this exact source state, and the link patches build on. It is derived deterministically from `content_hashes`, so a request need not send it - the server derives it. It is derived by sorting the `content_hashes` keys as paths, splitting each key on '/' into its path components and ordering the keys by comparing those component lists element by element, each component compared by Unicode code point (equivalently UTF-8 byte order). Treating '/' as a path separator this way, rather than as the ordinary character U+002F, means a key that is an ancestor path sorts before a sibling whose name extends the first differing component (so e.g. 'a/b' sorts before 'a.b'). A blake3 hasher is then built, and for each key in that order updated with the blake3 digest (32 raw bytes) of the key encoded as UTF-8, then, when the entry is a file (non-null value), with that file's digest as 32 raw bytes. The stream uses raw digest bytes, but the values in `content_hashes` are those digests hex-encoded (64 hex chars), so decode each value from hex first. Directory entries (null value) contribute only their key digest. The result is the hasher's own hex digest.", - title="Hash", + description="The HuggingFace base model the deployment is fine-tuning.", + title="Base Model", ), ] - - -class CreateDeploymentPatchResponse(BaseModel): - patch_point: Annotated[ - DeploymentPatchPointWithHash, + base_url: Annotated[str, Field(description="The run's base URL.", title="Base Url")] + status: Annotated[ + LoopsDeploymentStatus, Field(description="Latest deployment status.") + ] + user: Annotated[User, Field(description="The user who owns the Loops deployment.")] + created_at: Annotated[ + AwareDatetime, Field( - description="The resulting patch point the staged patch produced; matches the pending point a subsequent state read returns." + description="Time the deployment was created in ISO 8601 format.", + title="Created At", ), ] - - -class GetDeploymentPatchesStateResponse(BaseModel): - running_patch_point: Annotated[ - DeploymentPatchPointWithHash, - Field(description="The patch point the deployment is recorded as running."), + availability_model: Annotated[ + V1AvailabilityModel, Field(description="Capacity the trainer was scheduled on.") + ] = V1AvailabilityModel.dedicated + instance_type: Annotated[ + InstanceType, Field(description="Instance type backing the trainer.") ] - pending_patch_point: Annotated[ - DeploymentPatchPointWithHash | None, - Field( - description="The latest staged-but-unsynced patch point, or null when the deployment is recorded as caught up." - ), + node_count: Annotated[ + int, + Field(description="Number of nodes backing the trainer.", title="Node Count"), + ] = 1 + sampler: Annotated[ + LoopsSampler | None, Field(description="The sampler bound to this deployment.") ] = None -class SyncDeploymentPatchesRequest(BaseModel): - pass +class ListLoopsDeploymentsResponse(BaseModel): + deployments: Annotated[ + list[LoopsDeployment], + Field(description="Active Loops deployments.", title="Deployments"), + ] -class SyncDeploymentPatchesResponse(BaseModel): - needs_full_deploy_reason: Annotated[ - str | None, +class DeactivateLoopsDeploymentResponse(BaseModel): + id: Annotated[ + str, Field(description="The deactivated Loops deployment ID.", title="Id") + ] + base_model: Annotated[ + str, Field( - description="If set, the change cannot be patched and a full push is required; the value explains why. If null, the deployment is now in sync.", - title="Needs Full Deploy Reason", + description="The base model whose Loops deployment was deactivated.", + title="Base Model", ), - ] = None - - -class ModelMetricKind(StrEnum): - GAUGE = "GAUGE" - COUNTER = "COUNTER" - HISTOGRAM = "HISTOGRAM" + ] + user: Annotated[User, Field(description="The user who owned the Loops deployment.")] -class ModelMetricMode(StrEnum): - CURRENT = "CURRENT" - SUMMARY = "SUMMARY" - SERIES = "SERIES" +class GetLoopsDeploymentResponse(BaseModel): + deployment: Annotated[LoopsDeployment, Field(description="The Loops deployment.")] -class ModelMetricUnitHint(StrEnum): - PER_SECOND = "PER_SECOND" - SECONDS = "SECONDS" - BYTES = "BYTES" - MEBIBYTES = "MEBIBYTES" - COUNT = "COUNT" - RATIO = "RATIO" +class LoopsDebugArchiveFilesResponse(BaseModel): + presigned_urls: Annotated[list[CheckpointFile], Field(title="Presigned Urls")] + next_page_token: Annotated[str | None, Field(title="Next Page Token")] = None -class ModelMetricValueSet(BaseModel): +class GetLoopsDeploymentMetricsRequest(BaseModel): + end_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch millis to end fetching metrics.", + title="End Epoch Millis", + ), + ] = None start_epoch_millis: Annotated[ - int, + int | None, Field( - description="Start of the step. The step spans until the next value set's start, or the window end for the last one; a summary has a single value set starting at the window start.", + description="Epoch millis to start fetching metrics.", title="Start Epoch Millis", ), - ] - values: Annotated[ - list[list[float | None]], + ] = None + step_seconds: Annotated[ + int | None, Field( - description="Metric values aligned to the ``metric_descriptors`` index. Each entry is a list aligned to that descriptor's ``label_sets`` (a single-element list for a plain metric). A series with no data in this step is null.", - title="Values", + description="Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", + title="Step Seconds", + ), + ] = None + time_divisor_seconds: Annotated[ + int | None, + Field( + description="Unit of time for request-volume metrics, in seconds (e.g. 60 for requests/minute). Defaults to per-second.", + title="Time Divisor Seconds", ), + ] = None + + +class InferenceVolumeByStatusDatapoint(BaseModel): + timestamp: Annotated[ + AwareDatetime, Field(description="ISO 8601 timestamp.", title="Timestamp") + ] + status_2xx: Annotated[ + float, Field(description="2xx requests per second.", title="Status 2Xx") + ] + status_4xx: Annotated[ + float, Field(description="4xx requests per second.", title="Status 4Xx") + ] + status_5xx: Annotated[ + float, Field(description="5xx requests per second.", title="Status 5Xx") ] -class TerminateReplicaResponse(BaseModel): - success: Annotated[ - bool, +class ResponseTimeDatapoint(BaseModel): + timestamp: Annotated[ + AwareDatetime, Field(description="ISO 8601 timestamp.", title="Timestamp") + ] + p50: Annotated[ + float | None, Field( - description="Whether the replica was successfully terminated", - title="Success", + description="50th percentile request latency (milliseconds).", title="P50" ), - ] = True - - -class SignSSHCertificateRequest(BaseModel): - public_key: Annotated[ - str, + ] = None + p95: Annotated[ + float | None, Field( - description="The user's SSH public key (e.g., 'ssh-ed25519 AAAA... user@host').", - title="Public Key", + description="95th percentile request latency (milliseconds).", title="P95" ), - ] - replica_id: Annotated[ - str | None, + ] = None + p99: Annotated[ + float | None, Field( - description="The replica to connect to. Required for training jobs (e.g. '0'). Optional for inference (server picks a running replica if omitted).", - title="Replica Id", + description="99th percentile request latency (milliseconds).", title="P99" ), ] = None -class SignSSHCertificateResponse(BaseModel): - ssh_certificate: Annotated[ +class TeamTrainingGpuCapacityItem(BaseModel): + team_id: Annotated[str, Field(description="Team identifier", title="Team Id")] + team_name: Annotated[str, Field(description="Team name", title="Team Name")] + gpu_type: Annotated[ str, Field( - description="The signed SSH certificate in OpenSSH format.", - title="Ssh Certificate", + description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" ), ] - jwt: Annotated[ - str, + baseline: Annotated[ + int, Field( - description="Signed JWT (ES256) for SSH proxy authorization.", title="Jwt" + description="Baseline GPU allocation for the team. 0 if not configured.", + title="Baseline", ), ] - proxy_address: Annotated[ - str, + limit: Annotated[ + int, Field( - description="Address of the SSH proxy to connect to (host:port).", - title="Proxy Address", + description="Maximum concurrent GPUs of this type for this team", + title="Limit", ), ] - ssh_cert_expires_at: Annotated[ - AwareDatetime, + usage_count: Annotated[ + int, Field( - description="When the certificate expires, in ISO 8601 format.", - title="Ssh Cert Expires At", + description="GPUs currently in use by the team's active training jobs", + title="Usage Count", ), ] + dedicated_usage_count: Annotated[ + int, + Field( + description="Portion of usage_count from dedicated (on-demand) jobs.", + title="Dedicated Usage Count", + ), + ] = 0 + spot_usage_count: Annotated[ + int, + Field( + description="Portion of usage_count from spot jobs.", + title="Spot Usage Count", + ), + ] = 0 -class AutoscalingScheduleSettings(BaseModel): - min_replica: Annotated[ - int, Field(description="Minimum number of replicas", title="Min Replica") - ] - max_replica: Annotated[ - int, Field(description="Maximum number of replicas", title="Max Replica") +class TrainingGpuCapacityItem(BaseModel): + gpu_type: Annotated[ + str, + Field( + description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" + ), ] - autoscaling_window: Annotated[ - int | None, + baseline: Annotated[ + int, Field( - description="Timeframe of traffic considered for autoscaling decisions. Null inherits the environment value.", - title="Autoscaling Window", + description="Baseline GPU allocation; jobs below this threshold are expected to run immediately. 0 if not configured.", + title="Baseline", ), ] - scale_down_delay: Annotated[ - int | None, + limit: Annotated[ + int, Field( - description="Waiting period before scaling down any active replica. Null inherits the environment value.", - title="Scale Down Delay", + description="Maximum concurrent GPUs of this type for this org", + title="Limit", ), ] - concurrency_target: Annotated[ - int | None, + usage_count: Annotated[ + int, Field( - description="Number of requests per replica before scaling up. Null inherits the environment value.", - title="Concurrency Target", + description="GPUs currently in use by active training jobs", + title="Usage Count", ), ] - target_utilization_percentage: Annotated[ - int | None, + dedicated_usage_count: Annotated[ + int, + Field( + description="Portion of usage_count from dedicated (on-demand) jobs, which run against the baseline.", + title="Dedicated Usage Count", + ), + ] = 0 + spot_usage_count: Annotated[ + int, Field( - description="Target utilization percentage for scaling up/down. Null inherits the environment value.", - title="Target Utilization Percentage", + description="Portion of usage_count from spot jobs, which burst into the peak and may push usage above the limit.", + title="Spot Usage Count", ), - ] - target_in_flight_tokens: Annotated[ - int | None, + ] = 0 + + +class GetTrainingGpuCapacityResponse(BaseModel): + gpu_capacities: Annotated[ + list[TrainingGpuCapacityItem], Field( - description="Target number of in-flight tokens for autoscaling decisions. Null inherits the environment value. Early access only.", - title="Target In Flight Tokens", + description="Org-level GPU capacity limits and current usage per GPU type", + title="Gpu Capacities", ), ] - max_scale_down_rate: Annotated[ - int | None, + team_gpu_capacities: Annotated[ + list[TeamTrainingGpuCapacityItem] | None, Field( - description="Maximum percentage of replicas that can be removed per autoscaling window. Null inherits the environment value.", - title="Max Scale Down Rate", + description="Per-team GPU capacity limits and current usage per GPU type", + title="Team Gpu Capacities", ), - ] + ] = None -class AutoscalingScheduleState(BaseModel): - schedule_id: Annotated[ - str | None, +class PatchTeamTrainingGpuCapacityRequest(BaseModel): + team_id: Annotated[str, Field(description="Team identifier", title="Team Id")] + gpu_type: Annotated[ + str, Field( - description="Stable schedule identifier, or null when the baseline settings apply", - title="Schedule Id", + description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" ), ] - autoscaling_settings: Annotated[ - AutoscalingSettings, + max_gpus: Annotated[ + int, Field( - description="Autoscaling settings on the current serving deployment. In a PATCH response, this snapshot can precede asynchronous schedule reconciliation; poll the GET endpoint for the applied state." + description="Max concurrent GPUs of this type the team may use", + examples=[8, 16, 32], + title="Max Gpus", ), ] -class Cadence(StrEnum): - DAILY = "DAILY" - HOURLY = "HOURLY" - - -class AutoscalingScheduleWeekday(StrEnum): - SUNDAY = "SUNDAY" - MONDAY = "MONDAY" - TUESDAY = "TUESDAY" - WEDNESDAY = "WEDNESDAY" - THURSDAY = "THURSDAY" - FRIDAY = "FRIDAY" - SATURDAY = "SATURDAY" - - -class InProgressPromotionStatus(StrEnum): - RELEASING = "RELEASING" - RAMPING_UP = "RAMPING_UP" - RAMPING_DOWN = "RAMPING_DOWN" - PAUSED = "PAUSED" - SUCCEEDED = "SUCCEEDED" - FAILED = "FAILED" - CANCELED = "CANCELED" +class PatchTeamTrainingGpuCapacityResponse(BaseModel): + team_gpu_capacity: Annotated[ + TeamTrainingGpuCapacityItem, + Field(description="The updated per-team GPU capacity limit"), + ] -class InProgressPromotion(BaseModel): - status: Annotated[ - InProgressPromotionStatus, Field(description="Status of the promotion") - ] - percent_traffic_to_new_version: Annotated[ - int, - Field( - description="Percentage of traffic routed to the candidate deployment", - title="Percent Traffic To New Version", - ), +class ActiveJobAtSubmit(BaseModel): + training_job_id: Annotated[ + str, + Field(description="Hashid of the other training job", title="Training Job Id"), ] - error_message: Annotated[ - str | None, - Field(description="Error message if promotion failed", title="Error Message"), - ] = None - rolling_deploy: Annotated[ - bool | None, - Field(description="Whether this is a rolling deploy", title="Rolling Deploy"), + training_job_name: Annotated[ + str | None, Field(description="Other job's name", title="Training Job Name") ] = None - - -class OneTimeAutoscalingSchedule(BaseModel): - id: Annotated[ - str, Field(description="Stable unique identifier of the schedule", title="Id") + instance_type_name: Annotated[ + str, + Field(description="Instance type of the other job", title="Instance Type Name"), ] - name: Annotated[str, Field(description="Name of the schedule", title="Name")] - enabled: Annotated[ - bool, Field(description="Whether the schedule is enabled", title="Enabled") + total_gpus: Annotated[ + int, Field(description="gpu_count * effective_node_count", title="Total Gpus") ] - autoscaling_settings: Annotated[ - AutoscalingScheduleSettings, + workload_plane_name: Annotated[ + str, Field( - description="Raw autoscaling overrides applied during the schedule window" + description="Workload plane the other job was on", + title="Workload Plane Name", ), ] - cadence: Annotated[ - Literal["ONE_TIME"], - Field(description="One-time schedule cadence", title="Cadence"), - ] - start_at: Annotated[ - AwareDatetime, - Field(description="Inclusive start of the schedule window", title="Start At"), + status_at_submit: Annotated[ + str, + Field( + description="Other job's status as of submitted_at (one of ACTIVE_STATES)", + title="Status At Submit", + ), ] - end_at: Annotated[ + status_set_at: Annotated[ AwareDatetime, - Field(description="Exclusive end of the schedule window", title="End At"), + Field(description="When that status was set", title="Status Set At"), ] -class PromotionCleanupStrategy(StrEnum): - KEEP = "KEEP" - SCALE_TO_ZERO = "SCALE_TO_ZERO" - DEACTIVATE = "DEACTIVATE" - - -class RollingDeployStrategy(StrEnum): - REPLICA = "REPLICA" - - -class UpdateRollingDeployConfig(BaseModel): - rolling_deploy_strategy: Annotated[ - RollingDeployStrategy | None, - Field( - description="The rolling deploy strategy to use for promotions.", - examples=["REPLICA"], - ), - ] = None - max_surge_percent: Annotated[ - int | None, - Field( - description="The maximum surge percentage for rolling deploys.", - examples=[25], - title="Max Surge Percent", - ), - ] = None - max_unavailable_percent: Annotated[ - int | None, +class CapacityAtSubmit(BaseModel): + gpu_type: Annotated[ + str, Field( - description="The maximum unavailable percentage for rolling deploys.", - examples=[10], - title="Max Unavailable Percent", + description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" ), - ] = None - stabilization_time_seconds: Annotated[ + ] + max_gpus: Annotated[ + int, + Field(description="Current max concurrent GPUs of this type", title="Max Gpus"), + ] + min_gpus: Annotated[ int | None, Field( - description="The stabilization time in seconds for rolling deploys.", - examples=[300], - title="Stabilization Time Seconds", + description="Current baseline GPU allocation, if configured", + title="Min Gpus", ), ] = None - replica_overhead_percent: Annotated[ - int | None, + last_modified: Annotated[ + AwareDatetime, Field( - description="The replica overhead percentage for rolling deploys.", - examples=[0], - title="Replica Overhead Percent", + description="When the capacity row was last modified", title="Last Modified" ), - ] = None + ] -class EnvironmentTombstone(BaseModel): - name: Annotated[str, Field(description="Name of the environment", title="Name")] - model_id: Annotated[ - str, Field(description="Unique identifier of the model", title="Model Id") +class PendingJobAheadAtSubmit(BaseModel): + training_job_id: Annotated[ + str, + Field(description="Hashid of the other training job", title="Training Job Id"), ] - deleted: Annotated[ - bool, Field(description="Whether the environment was deleted", title="Deleted") + training_job_name: Annotated[ + str | None, Field(description="Other job's name", title="Training Job Name") + ] = None + instance_type_name: Annotated[ + str, + Field(description="Instance type of the other job", title="Instance Type Name"), ] - - -class MaxScaleDownRate1(RootModel[int]): - root: Annotated[ + requested_gpus: Annotated[ int, - Field( - description="Maximum percentage of replicas that can be removed per autoscaling window. Null stores no schedule override and follows the current environment value.", - ge=1, - le=50, - title="Max Scale Down Rate", - ), + Field(description="gpu_count * effective_node_count", title="Requested Gpus"), ] - - -class AutoscalingScheduleSettingsRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - min_replica: Annotated[ - int, Field(description="Minimum number of replicas", title="Min Replica") + priority: Annotated[ + int, + Field(description="Effective priority (NULL coalesced to 0)", title="Priority"), ] - max_replica: Annotated[ - int, Field(description="Maximum number of replicas", title="Max Replica") + submitted_at: Annotated[ + AwareDatetime, + Field(description="The other job's submission time", title="Submitted At"), ] - autoscaling_window: Annotated[ - int | None, + + +class QueueEvent(BaseModel): + training_job_id: Annotated[ + str, Field( - description="Timeframe of traffic considered for autoscaling decisions. Null stores no schedule override and follows the current environment value.", - title="Autoscaling Window", + description="Hashid of the training job this event is for", + title="Training Job Id", ), ] - scale_down_delay: Annotated[ - int | None, + training_job_name: Annotated[ + str | None, Field(description="Job name", title="Training Job Name") + ] = None + status: Annotated[ + str, Field(description="TrainingJobStatus.Name value", title="Status") + ] + created: Annotated[ + AwareDatetime, + Field(description="When the status row was inserted", title="Created"), + ] + event_message: Annotated[ + str | None, Field( - description="Waiting period before scaling down any active replica. Null stores no schedule override and follows the current environment value.", - title="Scale Down Delay", + description="Human-readable event message from the status metadata", + title="Event Message", ), - ] - concurrency_target: Annotated[ + ] = None + exit_code: Annotated[ int | None, Field( - description="Number of requests per replica before scaling up. Null stores no schedule override and follows the current environment value.", - title="Concurrency Target", + description="Exit code from the status metadata, if any", title="Exit Code" ), + ] = None + + +class GetTrainingJobQueueContextResponse(BaseModel): + target_job_id: Annotated[ + str, + Field(description="Hashid of the target training job", title="Target Job Id"), ] - target_utilization_percentage: Annotated[ - int | None, - Field( - description="Target utilization percentage for scaling up/down. Null stores no schedule override and follows the current environment value.", - title="Target Utilization Percentage", - ), + target_job_name: Annotated[ + str | None, Field(description="Target job's name", title="Target Job Name") + ] = None + gpu_type: Annotated[ + str, Field(description="GPU type the target requested", title="Gpu Type") ] - target_in_flight_tokens: Annotated[ - int | None, + requested_gpus: Annotated[ + int, Field( - description="Target number of in-flight tokens for autoscaling decisions. Null stores no schedule override and follows the current environment value. Early access only.", - title="Target In Flight Tokens", + description="GPUs the target requested (gpu_count * effective_node_count)", + title="Requested Gpus", ), ] - max_scale_down_rate: Annotated[ - MaxScaleDownRate1 | None, + submitted_at: Annotated[ + AwareDatetime, Field( - description="Maximum percentage of replicas that can be removed per autoscaling window. Null stores no schedule override and follows the current environment value.", - title="Max Scale Down Rate", + description="When the job row was inserted (= API POST time)", + title="Submitted At", ), ] - - -class AutoscalingScheduleUpsert(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - id: Annotated[ - str | None, + released_at: Annotated[ + AwareDatetime | None, Field( - description="Stable schedule identifier. Omit this field to create a schedule.", - title="Id", + description="When the job's TRAINING_JOB_CREATED status was set, i.e. the moment it was released from PENDING. None if still PENDING.", + title="Released At", ), ] = None - name: Annotated[str, Field(description="Name of the schedule", title="Name")] - enabled: Annotated[ - bool, Field(description="Whether the schedule is enabled", title="Enabled") - ] - autoscaling_settings: Annotated[ - AutoscalingScheduleSettingsRequest, - Field( - description="Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." - ), - ] - cadence: Annotated[ - Literal["DAILY", "HOURLY"], - Field(description="Recurring schedule cadence", title="Cadence"), - ] - weekdays: Annotated[ - list[AutoscalingScheduleWeekday], - Field(description="Weekdays on which the schedule runs", title="Weekdays"), - ] - start_hour: Annotated[ + pending_seconds: Annotated[ int | None, Field( - description="Start hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", - title="Start Hour", + description="released_at - submitted_at in seconds. None if still PENDING.", + title="Pending Seconds", ), ] = None - start_minute: Annotated[ - int, - Field(description="Start minute of the schedule window", title="Start Minute"), - ] - end_hour: Annotated[ - int | None, + org_capacity: Annotated[ + CapacityAtSubmit | None, Field( - description="End hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", - title="End Hour", + description="Org-level cap for (org, gpu_type). None if no cap is configured." ), ] = None - end_minute: Annotated[ - int, Field(description="End minute of the schedule window", title="End Minute") - ] - - -class OneTimeAutoscalingScheduleUpsert(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - id: Annotated[ - str | None, + team_capacity: Annotated[ + CapacityAtSubmit | None, Field( - description="Stable schedule identifier. Omit this field to create a schedule.", - title="Id", + description="Team-level cap for (team, gpu_type). None if no team cap is configured." ), ] = None - name: Annotated[str, Field(description="Name of the schedule", title="Name")] - enabled: Annotated[ - bool, Field(description="Whether the schedule is enabled", title="Enabled") - ] - autoscaling_settings: Annotated[ - AutoscalingScheduleSettingsRequest, + active_at_submit: Annotated[ + list[ActiveJobAtSubmit], Field( - description="Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." + description="Jobs in the same (org, gpu_type) pool that were holding capacity at submitted_at", + title="Active At Submit", ), ] - cadence: Annotated[ - Literal["ONE_TIME"], - Field(description="One-time schedule cadence", title="Cadence"), + pending_ahead_at_submit: Annotated[ + list[PendingJobAheadAtSubmit], + Field( + description="PENDING jobs in the same (org, gpu_type) pool that were ahead of the target in dequeue FIFO order at submitted_at (priority DESC then created ASC). These also block the target's release.", + title="Pending Ahead At Submit", + ), ] - start_at: Annotated[ - AwareDatetime, + events: Annotated[ + list[QueueEvent], Field( - description="Inclusive start of the schedule window in ISO 8601 format. New schedules must start in the future.", - title="Start At", + description="Every status event in [submitted_at, events_window_end] for the target job, every job in active_at_submit, and every job in pending_ahead_at_submit, oldest first.", + title="Events", ), ] - end_at: Annotated[ + events_window_end: Annotated[ AwareDatetime, Field( - description="Exclusive end of the schedule window in ISO 8601 format", - title="End At", + description="released_at if set, else 'now' (events ongoing)", + title="Events Window End", ), ] -class Schedules1( - RootModel[AutoscalingScheduleUpsert | OneTimeAutoscalingScheduleUpsert] -): - root: Annotated[ - AutoscalingScheduleUpsert | OneTimeAutoscalingScheduleUpsert, - Field(discriminator="cadence"), +class GetBlobCredentialsResponse(BaseModel): + creds: Annotated[ + AWSCredentials, Field(description="The credentials to upload the blob to") + ] + s3_key: Annotated[ + str, Field(description="The S3 key to upload the blob to", title="S3 Key") + ] + s3_bucket: Annotated[ + str, Field(description="The S3 bucket to upload the blob to", title="S3 Bucket") ] -class UpdateAutoscalingScheduleSettings(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - timezone: Annotated[ +class TeamId(RootModel[str]): + root: Annotated[ str | None, Field( - description="IANA timezone shared by the resulting collection. Omission preserves the current timezone; null is allowed only when deleting every schedule.", - title="Timezone", + description="Team ID for a team-scoped key. When omitted, uses the team in the URL if present, otherwise your organization's default team. Must match the URL team when both are provided. Not supported for PERSONAL or WORKSPACE_MANAGE_API_KEYS keys.", + min_length=1, + title="Team Id", ), ] = None - schedules: Annotated[ - list[Schedules1] | None, + + +class CreateAPIKeyRequest(BaseModel): + name: Annotated[ + str | None, Field( - description="Complete schedules to create or replace. Existing schedules omitted from this list are unchanged.", - title="Schedules", + description="Optional name for the API key", + examples=["my-api-key"], + title="Name", ), ] = None - delete_schedules: Annotated[ + type: Annotated[ + APIKeyCategory, + Field( + description="Type of the API key.", + examples=[ + "PERSONAL", + "ROUTES", + "WORKSPACE_MANAGE_API_KEYS", + "WORKSPACE_EXPORT_METRICS", + "WORKSPACE_INVOKE", + "WORKSPACE_MANAGE_ALL", + ], + ), + ] + model_ids: Annotated[ list[str] | None, Field( - description="Stable identifiers of schedules to delete. To clear all schedules, include every existing schedule identifier.", - title="Delete Schedules", + description="List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", + examples=[["aaaaaaaa"]], + title="Model Ids", ), ] = None - - -class PromoteToEnvironmentRequest(BaseModel): - scale_down_previous_deployment: Annotated[ - bool, + team_id: Annotated[ + TeamId | None, Field( - description="Whether to scale down the previous deployment after promoting", - examples=[True], - title="Scale Down Previous Deployment", + description="Team ID for a team-scoped key. When omitted, uses the team in the URL if present, otherwise your organization's default team. Must match the URL team when both are provided. Not supported for PERSONAL or WORKSPACE_MANAGE_API_KEYS keys.", + title="Team Id", ), - ] = True - deployment_id: Annotated[ - str, - Field(description="The id of the deployment to promote", title="Deployment Id"), + ] = None + + +class APIKey(BaseModel): + api_key: Annotated[str, Field(description="The API key string", title="Api Key")] + + +class APIKeyOwner(BaseModel): + user_id: Annotated[ + str, Field(description="Unique identifier for the user", title="User Id") + ] + email: Annotated[ + str | None, Field(description="Email address of the user", title="Email") + ] = None + name: Annotated[ + str | None, Field(description="Display name of the user", title="Name") + ] = None + + +class APIKeyTombstone(BaseModel): + prefix: Annotated[ + str, Field(description="Unique prefix of the API key", title="Prefix") ] - preserve_env_instance_type: Annotated[ - bool, - Field( - description="Whether to use the promoting deployment's instance type or preserve target environment's instance type", - examples=[True], - title="Preserve Env Instance Type", - ), - ] = True -class CancelPromotionStatus(StrEnum): - CANCELED = "CANCELED" - RAMPING_DOWN = "RAMPING_DOWN" +class LimitType(StrEnum): + REQUEST = "REQUEST" + TOKEN = "TOKEN" + CONCURRENT_REQUEST = "CONCURRENT_REQUEST" + UNCACHED_INPUT_TOKEN = "UNCACHED_INPUT_TOKEN" + OUTPUT_TOKEN = "OUTPUT_TOKEN" -class CancelPromotionResponse(BaseModel): - status: Annotated[ - CancelPromotionStatus, +class ModelAPIOrgDetails(BaseModel): + added_at: Annotated[ + AwareDatetime, Field( - description="Status of the request to cancel a promotion. Can be CANCELED or RAMPING_DOWN." + description="When the workspace first added this Model API.", + title="Added At", ), ] - message: Annotated[ - str, + last_used_at: Annotated[ + AwareDatetime | None, Field( - description="A message describing the status of the request to cancel a promotion", - title="Message", + description="When the workspace last invoked this Model API. Null if the workspace has never invoked it.", + title="Last Used At", ), - ] - - -class SignalPromotionResponse(BaseModel): - success: Annotated[ - bool, - Field(description="Whether the signal was successfully sent", title="Success"), - ] + ] = None -class Chain(BaseModel): - id: Annotated[str, Field(description="Unique identifier of the chain", title="Id")] - created_at: Annotated[ - AwareDatetime, - Field( - description="Time the chain was created in ISO 8601 format", - title="Created At", - ), - ] - name: Annotated[str, Field(description="Name of the chain", title="Name")] - deployments_count: Annotated[ - int, +class CostPerMillionInputTokens(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="Number of deployments of the chain", title="Deployments Count" + description="Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", + examples=["0.13"], + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Cost Per Million Input Tokens", ), ] - team_name: Annotated[ + + +class CostPerMillionOutputTokens(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="Name of the team associated with the chain", title="Team Name" + description="Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", + examples=["0.50"], + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Cost Per Million Output Tokens", ), ] -class Chains(BaseModel): - chains: Annotated[list[Chain], Field(title="Chains")] +class RateLimitUnit(StrEnum): + SECOND = "SECOND" + MINUTE = "MINUTE" -class ChainTombstone(BaseModel): - id: Annotated[str, Field(description="Unique identifier of the chain", title="Id")] - deleted: Annotated[ - bool, Field(description="Whether the chain was deleted", title="Deleted") +class RateLimit(BaseModel): + type: Annotated[ + LimitType, + Field(description="The type of the rate limit", examples=["TOKEN", "REQUEST"]), ] - - -class Chainlet(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the chainlet", title="Id") + unit: Annotated[ + RateLimitUnit, + Field(description="The unit of the rate limit", examples=["SECOND", "MINUTE"]), ] - name: Annotated[str, Field(description="Name of the chainlet", title="Name")] - autoscaling_settings: Annotated[ - AutoscalingSettings | None, + threshold: Annotated[ + int, Field( - description="Autoscaling settings for the chainlet. If null, it has not finished deploying" + description="The threshold for the rate limit", + examples=[1000, 50000], + ge=0, + title="Threshold", ), ] - instance_type_name: Annotated[ - str, + + +class ModelApisUsageResult(BaseModel): + api_key_prefix: Annotated[ + str | None, Field( - description="Name of the instance type the chainlet is deployed on", - title="Instance Type Name", + description="Prefix of the API key the usage is attributed to. Null when not grouping by api_key or when the request was not authenticated with an API key.", + title="Api Key Prefix", + ), + ] = None + user_id: Annotated[ + str | None, + Field( + description="User the usage is attributed to. Null when not grouping by user or when the credential is not user-scoped.", + title="User Id", + ), + ] = None + model: Annotated[ + str | None, + Field( + description="Model that served the usage. Null when not grouping by model.", + title="Model", + ), + ] = None + input_tokens: Annotated[ + int, + Field( + description="Total input tokens, cached and uncached combined.", + title="Input Tokens", ), ] - active_replica_count: Annotated[ + cached_input_tokens: Annotated[ int, - Field(description="Number of active replicas", title="Active Replica Count"), + Field( + description="Input tokens served from the prompt cache.", + title="Cached Input Tokens", + ), ] - status: Annotated[DeploymentStatus, Field(description="Status of the chainlet")] - - -class ChainDeploymentTombstone(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the chain deployment", title="Id") + uncached_input_tokens: Annotated[ + int, + Field( + description="Input tokens not served from the prompt cache.", + title="Uncached Input Tokens", + ), ] - deleted: Annotated[ - bool, - Field(description="Whether the chain deployment was deleted", title="Deleted"), + output_tokens: Annotated[ + int, Field(description="Total output tokens.", title="Output Tokens") ] - chain_id: Annotated[ - str, Field(description="Unique identifier of the chain", title="Chain Id") + request_count: Annotated[ + int, Field(description="Total number of requests.", title="Request Count") ] -class ChainletEnvironmentSettingsRequest(BaseModel): - chainlet_name: Annotated[ - str, +class UsageDimension(StrEnum): + api_key = "api_key" + user = "user" + model = "model" + + +class CreateLLMModelRequest(BaseModel): + resources: Annotated[ + dict[str, Any], + Field(description="Resources allocated to the model", title="Resources"), + ] + region: Annotated[ + str | None, + Field(description="Region in which to deploy the model", title="Region"), + ] = None + llm_version: Annotated[ + str | None, + Field(description="Version of the helm chart to use.", title="Llm Version"), + ] = None + llm_config: Annotated[ + dict[str, Any] | None, Field( - description="Name of the chainlet", - examples=["HelloWorld"], - title="Chainlet Name", + description="Configuration specific to the LLM model", title="Llm Config" ), - ] + ] = None + environment_variables: Annotated[ + dict[str, Any] | None, + Field( + description="Environment variables for the model", + title="Environment Variables", + ), + ] = None + model_metadata: Annotated[ + dict[str, Any] | None, + Field( + description="Model metadata persisted into model_config", + title="Model Metadata", + ), + ] = None autoscaling_settings: Annotated[ UpdateAutoscalingSettings | None, Field( - description="Autoscaling settings for the chainlet", + description="Autoscaling settings for the model", examples=[ { - "autoscaling_window": 60, - "concurrency_target": 1, - "max_replica": 1, + "autoscaling_window": 600, + "concurrency_target": None, + "max_replica": 5, "max_scale_down_rate": None, - "min_replica": 0, - "scale_down_delay": 900, + "min_replica": 1, + "scale_down_delay": 300, "target_in_flight_tokens": None, - "target_utilization_percentage": 70, + "target_utilization_percentage": None, } ], ), ] = None - instance_type_id: Annotated[ - str, + additional_autoscaling_config: Annotated[ + dict[str, Any] | None, Field( - description="ID of the instance type to use for the chainlet", - examples=["1x4", "2x8", "A10G:2x24x96", "H100:2x52x468"], - title="Instance Type Id", + description="Additional autoscaling configuration (e.g. target in-flight tokens)", + examples=[{"metrics": [{"name": "in_flight_tokens", "target": 40000}]}], + title="Additional Autoscaling Config", ), - ] = "1x2" - - -class ChainletEnvironmentSettings(BaseModel): - chainlet_name: Annotated[ - str, Field(description="Name of the chainlet", title="Chainlet Name") - ] - autoscaling_settings: Annotated[ - AutoscalingSettings | None, + ] = None + metadata: Annotated[ + dict[str, Any] | None, Field( - description="Autoscaling settings for the chainlet. If null, it has not finished deploying" + description="User-defined metadata for the deployment", + examples=[{"environment": "production", "git_sha": "abc123"}], + title="Metadata", + ), + ] = None + weights: Annotated[ + list[dict[str, Any]] | None, + Field( + description="Weight configurations for BDN model weight distribution", + examples=[ + [ + { + "mount_location": "/models/base", + "source": "hf://meta-llama/Llama-3-8B", + } + ] + ], + title="Weights", ), - ] - instance_type: Annotated[ - InstanceType, Field(description="Instance type for the chainlet") - ] + ] = None + name: Annotated[str, Field(description="Name of the model", title="Name")] -class UpdateChainEnvironmentResponse(BaseModel): - ok: Annotated[ - bool, Field(description="Whether the update was successful", title="Ok") +class LLMModelHandle(BaseModel): + model_id: Annotated[ + str, Field(description="Unique identifier of the model", title="Model Id") + ] + version_id: Annotated[ + str, + Field(description="Unique identifier of the model version", title="Version Id"), + ] + hostname: Annotated[ + str, Field(description="Hostname used to invoke the model", title="Hostname") ] + instance_type_name: Annotated[ + str | None, + Field( + description="Name of the instance type the model deployment is running on", + title="Instance Type Name", + ), + ] = None -class PromoteToChainEnvironmentRequest(BaseModel): - scale_down_previous_deployment: Annotated[ - bool, +class CreateLLMModelVersionRequest(BaseModel): + resources: Annotated[ + dict[str, Any], + Field(description="Resources allocated to the model", title="Resources"), + ] + region: Annotated[ + str | None, + Field(description="Region in which to deploy the model", title="Region"), + ] = None + llm_version: Annotated[ + str | None, + Field(description="Version of the helm chart to use.", title="Llm Version"), + ] = None + llm_config: Annotated[ + dict[str, Any] | None, Field( - description="Whether to scale down the previous deployment after promoting", - examples=[True], - title="Scale Down Previous Deployment", + description="Configuration specific to the LLM model", title="Llm Config" ), - ] = True - deployment_id: Annotated[ - str, + ] = None + environment_variables: Annotated[ + dict[str, Any] | None, Field( - description="The id of the chain deployment to promote", - title="Deployment Id", + description="Environment variables for the model", + title="Environment Variables", ), - ] - - -class ChainletEnvironmentAutoscalingSettingsUpdate(BaseModel): - chainlet_name: Annotated[ - str, + ] = None + model_metadata: Annotated[ + dict[str, Any] | None, Field( - description="Name of the chainlet", - examples=["HelloWorld"], - title="Chainlet Name", + description="Model metadata persisted into model_config", + title="Model Metadata", ), - ] + ] = None autoscaling_settings: Annotated[ - UpdateAutoscalingSettings, + UpdateAutoscalingSettings | None, Field( - description="Autoscaling settings for the chainlet", + description="Autoscaling settings for the model", examples=[ { - "autoscaling_window": 800, - "concurrency_target": 3, - "max_replica": 2, + "autoscaling_window": 600, + "concurrency_target": None, + "max_replica": 5, "max_scale_down_rate": None, "min_replica": 1, - "scale_down_delay": 60, + "scale_down_delay": 300, "target_in_flight_tokens": None, "target_utilization_percentage": None, } ], ), - ] - - -class UpdateChainletEnvironmentAutoscalingSettingsRequest(BaseModel): - updates: Annotated[ - list[ChainletEnvironmentAutoscalingSettingsUpdate], - Field( - description="Mapping of chainlet name to the desired chainlet autoscaling settings. If the chainlet name doesn't exist, an error is returned.", - examples=[ - [ - { - "autoscaling_settings": { - "autoscaling_window": 800, - "concurrency_target": 4, - "max_replica": 3, - "max_scale_down_rate": None, - "min_replica": 2, - "scale_down_delay": 63, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - }, - "chainlet_name": "HelloWorld", - } - ], - [ - { - "autoscaling_settings": { - "autoscaling_window": None, - "concurrency_target": None, - "max_replica": None, - "max_scale_down_rate": None, - "min_replica": 0, - "scale_down_delay": None, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - }, - "chainlet_name": "HelloWorld", - }, - { - "autoscaling_settings": { - "autoscaling_window": None, - "concurrency_target": None, - "max_replica": None, - "max_scale_down_rate": None, - "min_replica": 0, - "scale_down_delay": None, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - }, - "chainlet_name": "RandInt", - }, - ], - ], - title="Updates", - ), - ] - - -class ChainletEnvironmentInstanceTypeUpdate(BaseModel): - chainlet_name: Annotated[ - str, + ] = None + additional_autoscaling_config: Annotated[ + dict[str, Any] | None, Field( - description="Name of the chainlet", - examples=["HelloWorld"], - title="Chainlet Name", + description="Additional autoscaling configuration (e.g. target in-flight tokens)", + examples=[{"metrics": [{"name": "in_flight_tokens", "target": 40000}]}], + title="Additional Autoscaling Config", ), - ] - instance_type_id: Annotated[ - str, + ] = None + metadata: Annotated[ + dict[str, Any] | None, Field( - description="Key of the instance type to use for the chainlet", - examples=["1x4", "2x8", "A10G:2x24x96"], - title="Instance Type Id", + description="User-defined metadata for the deployment", + examples=[{"environment": "production", "git_sha": "abc123"}], + title="Metadata", ), - ] - - -class UpdateChainletEnvironmentInstanceTypeRequest(BaseModel): - updates: Annotated[ - list[ChainletEnvironmentInstanceTypeUpdate], + ] = None + weights: Annotated[ + list[dict[str, Any]] | None, Field( - description="Mapping of chainlet name to the desired chainlet instance type. If the chainlet name doesn't exist, an error is returned.", + description="Weight configurations for BDN model weight distribution", examples=[ [ - {"chainlet_name": "HelloWorld", "instance_type_id": "1x4"}, - {"chainlet_name": "RandInt", "instance_type_id": "A10G:2x24x96"}, + { + "mount_location": "/models/base", + "source": "hf://meta-llama/Llama-3-8B", + } ] ], - title="Updates", - ), - ] - - -class UpsertTrainingProject(BaseModel): - name: Annotated[ - str, - Field( - description="Name of the training project.", - examples=["My Training Project"], - title="Name", + title="Weights", ), - ] - - -class UpsertTrainingProjectRequest(BaseModel): - training_project: Annotated[ - UpsertTrainingProject, Field(description="The training project to upsert.") - ] - - -class TrainingProjectSummary(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the training project.", title="Id") - ] - name: Annotated[ - str, Field(description="Name of the training project.", title="Name") - ] - - -class User(BaseModel): - email: Annotated[ - str | None, Field(description="Email of the user.", title="Email") ] = None -class AwsAssumeRoleDockerAuth(BaseModel): - role_arn: Annotated[ - str, - Field( - description="AWS IAM role ARN that Baseten assumes to pull from the registry. The role's trust policy must allow Baseten's AWS principal with your Baseten-provided external ID.", - title="Role Arn", - ), - ] - region: Annotated[ - str, Field(description="AWS region of the registry", title="Region") - ] - - -class AwsOidcDockerAuth(BaseModel): - role_arn: Annotated[ - str, - Field(description="AWS IAM role ARN for OIDC authentication", title="Role Arn"), - ] - region: Annotated[ - str, Field(description="AWS region for OIDC authentication", title="Region") - ] +class LibraryListingMetadata(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + parameter_count: Annotated[int | None, Field(title="Parameter Count")] = None + context_length: Annotated[int | None, Field(title="Context Length")] = None + input_modalities: Annotated[ + list[LibraryListingModality], Field(title="Input Modalities") + ] = [LibraryListingModality.text] + output_modalities: Annotated[ + list[LibraryListingModality], Field(title="Output Modalities") + ] = [LibraryListingModality.text] + license: Annotated[str, Field(title="License")] + variant: Annotated[str | None, Field(title="Variant")] = None + publisher: Annotated[str | None, Field(title="Publisher")] = None + model_api_slug: Annotated[str | None, Field(title="Model Api Slug")] = None + release_date: Annotated[date_aliased | None, Field(title="Release Date")] = None + description: Annotated[str | None, Field(title="Description")] = None + trending: Annotated[bool, Field(title="Trending")] = False -class CreateTrainingJobAccelerator(BaseModel): - accelerator: Annotated[ +class LibraryListing(BaseModel): + display_name: Annotated[ str, - Field( - description="GPU type for the training job.", - examples=["H100"], - title="Accelerator", - ), + Field(description="Display name of the library listing", title="Display Name"), ] - count: Annotated[ - int, + user_defined_id: Annotated[ + str, Field( - description="GPUs needed for the training job.", examples=[2], title="Count" + description="User-defined identifier of the library listing", + title="User Defined Id", ), ] - - -class CreateTrainingJobCompute(BaseModel): - node_count: Annotated[ - int, + is_public: Annotated[ + bool, Field( - description="Number of nodes for the training job.", - examples=[1], - title="Node Count", + description="Whether the listing is publicly accessible", title="Is Public" ), - ] = 1 - cpu_count: Annotated[ - int, + ] + trending: Annotated[ + bool | None, + Field(description="Whether the listing is trending", title="Trending"), + ] + closed_source: Annotated[ + bool, Field( - description="Number of cpus for the training job.", - examples=[1], - title="Cpu Count", + description="Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", + title="Closed Source", ), - ] = 1 - memory: Annotated[ - str, + ] + created_at: Annotated[ + AwareDatetime, Field( - description="Memory for the training job.", examples=["2Gi"], title="Memory" + description="Time the listing was created in ISO 8601 format", + title="Created At", ), - ] = "2Gi" - accelerator: Annotated[ - CreateTrainingJobAccelerator | None, + ] + modified_at: Annotated[ + AwareDatetime, + Field(description="Time the listing was last modified", title="Modified At"), + ] + metadata: Annotated[ + LibraryListingMetadata | None, Field( - description="GPU specification for the training job", - examples=[{"accelerator": "H100", "count": 2}], + description="Model-level metadata for this listing, if it has been uploaded." ), ] = None - availability_model: Annotated[ - V1AvailabilityModel, - Field( - description="Capacity guarantee for the job. 'dedicated' (the default) runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress.", - examples=["spot"], - ), - ] = V1AvailabilityModel.dedicated -class GcpOidcDockerAuth(BaseModel): - service_account: Annotated[ +class LibraryListings(BaseModel): + listings: Annotated[list[LibraryListing], Field(title="Listings")] + + +class CreateLibraryListingRequest(BaseModel): + display_name: Annotated[ str, - Field( - description="GCP service account name for OIDC authentication", - title="Service Account", - ), + Field(description="Display name of the library listing", title="Display Name"), ] - workload_identity_provider: Annotated[ + user_defined_id: Annotated[ str, Field( - description="GCP workload identity provider for OIDC authentication", - title="Workload Identity Provider", + description="User-defined identifier of the library listing", + title="User Defined Id", ), ] - - -class InteractiveSessionConfig(BaseModel): - trigger: Annotated[ - V1InteractiveSessionTrigger, + is_public: Annotated[ + bool, Field( - description="When to create the interactive session. 'on_startup' creates on job start, 'on_failure' creates on job failure, 'on_demand' bypasses automatic session creation." + description="Whether the listing is publicly accessible", title="Is Public" ), - ] = V1InteractiveSessionTrigger.on_demand - timeout_minutes: Annotated[ - int, + ] = False + closed_source: Annotated[ + bool, Field( - description="Number of minutes before the interactive session times out.", - examples=[480, 1440, 10080], - title="Timeout Minutes", + description="Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", + title="Closed Source", ), - ] = 480 - session_provider: Annotated[ - V1InteractiveSessionProvider, - Field(description="The IDE client for the interactive session."), - ] = V1InteractiveSessionProvider.vs_code - auth_provider: Annotated[ - V1InteractiveSessionAuthProvider, - Field(description="The authentication provider for the interactive session."), - ] = V1InteractiveSessionAuthProvider.github + ] = False -class SecretReference(BaseModel): - name: Annotated[ +class LibraryListingTombstone(BaseModel): + user_defined_id: Annotated[ str, Field( - description="Name of the secret to reference.", - examples=["hf_token"], - title="Name", + description="User-defined identifier of the library listing", + title="User Defined Id", ), ] + deleted: Annotated[ + bool, + Field(description="Whether the library listing was deleted", title="Deleted"), + ] -class TrainingWeightAuth(BaseModel): - auth_method: Annotated[ - AuthMethod, Field(description="Method used to authenticate the weight source.") - ] - auth_secret_name: Annotated[ - str | None, - Field( - description="Name of the workspace secret used for custom-secret authentication.", - title="Auth Secret Name", - ), - ] = None - aws_oidc_role_arn: Annotated[ - str | None, - Field( - description="AWS IAM role ARN used for OIDC authentication.", - title="Aws Oidc Role Arn", - ), - ] = None - aws_oidc_region: Annotated[ - str | None, - Field( - description="AWS region used for OIDC authentication.", - title="Aws Oidc Region", - ), - ] = None - gcp_oidc_service_account: Annotated[ +class UpdateLibraryListingRequest(BaseModel): + display_name: Annotated[ str | None, Field( - description="GCP service account used for OIDC authentication.", - title="Gcp Oidc Service Account", + description="New display name for the library listing", title="Display Name" ), ] = None - gcp_oidc_workload_id_provider: Annotated[ - str | None, + is_public: Annotated[ + bool | None, Field( - description="GCP workload identity provider used for OIDC authentication.", - title="Gcp Oidc Workload Id Provider", + description="Whether the listing is publicly accessible", title="Is Public" ), ] = None - aws_assume_role_arn: Annotated[ - str | None, - Field( - description="AWS IAM role ARN that Baseten assumes to access the weight source.", - title="Aws Assume Role Arn", - ), + trending: Annotated[ + bool | None, + Field(description="Whether the listing is trending", title="Trending"), ] = None - aws_assume_role_region: Annotated[ - str | None, + metadata: Annotated[ + LibraryListingMetadata | None, Field( - description="AWS region used for assume-role authentication.", - title="Aws Assume Role Region", + description="Model-level metadata for the listing. When provided, replaces the stored metadata. Unknown fields are rejected." ), ] = None -class TrainingJobTombstone(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the training job", title="Id") - ] - deleted: Annotated[ - bool, Field(description="Whether the training job was deleted", title="Deleted") - ] - training_project_id: Annotated[ - str, - Field( - description="Unique identifier of the training project", - title="Training Project Id", - ), - ] +class EmbeddingBenchmarkMetrics(BaseModel): + e2e_latency_ms_p50: Annotated[float | None, Field(title="E2E Latency Ms P50")] = ( + None + ) + e2e_latency_ms_p99: Annotated[float | None, Field(title="E2E Latency Ms P99")] = ( + None + ) + input_tokens_per_sec: Annotated[ + float | None, Field(title="Input Tokens Per Sec") + ] = None + requests_per_sec: Annotated[float | None, Field(title="Requests Per Sec")] = None -class UpdateTrainingJobRequest(BaseModel): - priority: Annotated[ - int | None, - Field( - description="New queue priority for a PENDING training job. Higher values are dequeued first. Only jobs in the PENDING state can have their priority changed.", - examples=[0, 10, 100], - title="Priority", - ), +class LLMBenchmarkMetrics(BaseModel): + ttft_ms_p50: Annotated[float | None, Field(title="Ttft Ms P50")] = None + output_tokens_per_sec_per_user_p50: Annotated[ + float | None, Field(title="Output Tokens Per Sec Per User P50") ] = None - availability_model: Annotated[ - V1AvailabilityModel | None, - Field( - description="New capacity guarantee for a PENDING training job. 'dedicated' runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress. Only jobs in the PENDING state can have their availability model changed.", - examples=["spot"], - ), + max_concurrent_users_at_50ms_tpot: Annotated[ + int | None, Field(title="Max Concurrent Users At 50Ms Tpot") + ] = None + requests_per_sec_p50: Annotated[ + float | None, Field(title="Requests Per Sec P50") + ] = None + cost_per_1m_tokens_usd: Annotated[ + float | None, Field(title="Cost Per 1M Tokens Usd") ] = None -class DownloadTrainingJobResponse(BaseModel): - artifact_presigned_urls: Annotated[ - list[str], - Field( - description="Presigned URLs for the job's uploaded artifacts.", - title="Artifact Presigned Urls", - ), - ] +class TTSBenchmarkMetrics(BaseModel): + ttft_ms_p50: Annotated[float | None, Field(title="Ttft Ms P50")] = None + max_concurrent_streams_at_rtf1: Annotated[ + int | None, Field(title="Max Concurrent Streams At Rtf1") + ] = None + ttft_ms_p50_at_max_concurrency: Annotated[ + float | None, Field(title="Ttft Ms P50 At Max Concurrency") + ] = None + cost_per_audio_minute_usd: Annotated[ + float | None, Field(title="Cost Per Audio Minute Usd") + ] = None -class GetTrainingJobLogsRequest(BaseModel): - start_epoch_millis: Annotated[ - int | None, +class CreateLibraryListingVersionRequest(BaseModel): + display_name: Annotated[ + str | None, Field( - description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - title="Start Epoch Millis", + description="Display name of the library listing. Required when creating a new listing.", + title="Display Name", ), ] = None - end_epoch_millis: Annotated[ - int | None, + is_public: Annotated[ + bool, Field( - description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - title="End Epoch Millis", + description="Whether the listing is publicly accessible. Only used when creating a new listing.", + title="Is Public", ), - ] = None - direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( - None - ) - limit: Annotated[ - Limit6 | None, + ] = False + oracle_version_id: Annotated[ + str, Field( - description="Limit of logs to fetch in a single request", - title="Limit", - validate_default=True, + description="Id of the source model version to publish", + title="Oracle Version Id", ), - ] = Limit6.model_validate(500) - min_level: Annotated[ - LogLevel | None, + ] + allow_truss_download: Annotated[ + bool, Field( - description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + description="Whether users deploying this model can download the Truss", + title="Allow Truss Download", ), - ] = None + ] = False + closed_source: Annotated[ + bool, + Field( + description="Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream). Only used when creating a new listing.", + title="Closed Source", + ), + ] = False + version_tag: Annotated[ + str, + Field(description="Human-readable tag for this version", title="Version Tag"), + ] -class TrainingJobMetric(BaseModel): - value: Annotated[ - float, Field(description="The value of the metric.", title="Value") +class LibraryListingVersionTombstone(BaseModel): + version_tag: Annotated[ + str, + Field(description="Human-readable tag for this version", title="Version Tag"), ] - timestamp: Annotated[ - AwareDatetime, + deleted: Annotated[ + bool, Field( - description="The timestamp of the metric in ISO 8601 format.", - title="Timestamp", + description="Whether the library listing version was deleted", + title="Deleted", ), ] -class GetTrainingJobMetricsRequest(BaseModel): - end_epoch_millis: Annotated[ - int | None, +class ModelApisCostResult(BaseModel): + api_key_prefixes: Annotated[ + list[str] | None, Field( - description="Epoch millis timestamp to end fetching metrics", - title="End Epoch Millis", + description="The single attributed API key prefix for this result. Null when not grouping by api_key_prefix or when attribution is unavailable.", + title="Api Key Prefixes", ), ] = None - start_epoch_millis: Annotated[ - int | None, + user_id: Annotated[ + str | None, Field( - description="Epoch millis timestamp to start fetching metrics.", - title="Start Epoch Millis", + description="Attributed user ID. Null when not grouping by user or when attribution is unavailable.", + title="User Id", ), ] = None - step_seconds: Annotated[ - int | None, + model: Annotated[ + str | None, Field( - description="Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", - title="Step Seconds", + description="Model identifier. Null when not grouping by model.", + title="Model", ), ] = None - - -class StopTrainingJobRequest(BaseModel): - pass - - -class TrainingJobCheckpoint(BaseModel): - checkpoint_id: Annotated[ - str, Field(description="The ID of the checkpoint.", title="Checkpoint Id") - ] - created_at: Annotated[ - AwareDatetime, - Field( - description="The timestamp of the checkpoint in ISO 8601 format.", - title="Created At", - ), - ] - checkpoint_type: Annotated[ - str, Field(description="The type of checkpoint.", title="Checkpoint Type") - ] - base_model: Annotated[ + service_tier: Annotated[ str | None, - Field(description="The base model of the checkpoint.", title="Base Model"), - ] - lora_adapter_config: Annotated[ - dict[str, Any] | None, Field( - description="The adapter config of the checkpoint.", - title="Lora Adapter Config", + description="Service tier. Null when not grouping by service_tier or when attribution is unavailable.", + title="Service Tier", ), - ] - size_bytes: Annotated[ - int, - Field(description="The size of the checkpoint in bytes.", title="Size Bytes"), - ] - sync_status: Annotated[ - str | None, + ] = None + subtotal: Annotated[ + str, Field( - description="Sync state of the checkpoint: SYNCING or COMPLETE.", - title="Sync Status", + description="Model API cost in USD for this day and grouping combination, returned as an exact decimal string preserving fractional-cent amounts. This amount may differ from finalized invoice amounts.", + examples=["0.00000123"], + title="Subtotal", ), - ] = None - training_job_id: Annotated[ - str, Field(description="The ID of the training job.", title="Training Job Id") ] -class GetTrainingJobCheckpointFilesResponse(BaseModel): - presigned_urls: Annotated[ - list[CheckpointFile], - Field( - description="List of presigned URLs for checkpoint files.", - title="Presigned Urls", - ), - ] - next_page_token: Annotated[ - int | None, - Field( - description="Token to use for fetching the next page of results. None when there are no more results.", - title="Next Page Token", - ), - ] = None - total_count: Annotated[ - int, - Field( - description="Total number of checkpoint files available.", - title="Total Count", - ), - ] +class ModelApiCostDimension(StrEnum): + api_key_prefix = "api_key_prefix" + user = "user" + model = "model" + service_tier = "service_tier" -class AuthCode(BaseModel): - session_id: Annotated[ - str, - Field( - description="Unique identifier of the interactive session.", - title="Session Id", - ), +class ChainMetadata(BaseModel): + chain_id: Annotated[ + str, Field(description="Unique identifier of the chain", title="Chain Id") ] - replica_id: Annotated[ + chain_name: Annotated[ + str | None, Field(description="Name of the chain", title="Chain Name") + ] = None + chain_deployment_id: Annotated[ str, Field( - description="Replica identifier in gXXrY format (e.g., 'g00r0' for group 0, replica 0).", - title="Replica Id", + description="Unique identifier of the chain deployment", + title="Chain Deployment Id", ), ] - auth_code: Annotated[ + + +class Subtotal(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="The device authentication code (e.g., '4F64-C0D9').", - title="Auth Code", + description="Subtotal cost incurred on this date in dollars", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", ), ] - auth_url: Annotated[ + + +class ComputeCost(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="URL where the user should enter the auth code (e.g., 'https://github.com/login/device').", - title="Auth Url", + description="Compute cost incurred on this date in dollars", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Compute Cost", ), ] - generated_at: Annotated[ - AwareDatetime | None, - Field( - description="When the auth code was generated, in ISO 8601 format.", - title="Generated At", - ), - ] = None - tunnel_name: Annotated[ - str | None, - Field(description="The name of the tunnel node.", title="Tunnel Name"), - ] = None - expires_at: Annotated[ - AwareDatetime | None, - Field( - description="When the session expires, in ISO 8601 format.", - title="Expires At", - ), - ] = None - working_directory: Annotated[ - str | None, - Field( - description="The working directory of the session.", - title="Working Directory", - ), - ] = None -class GetAuthCodesResponse(BaseModel): - auth_codes: Annotated[ - list[AuthCode], +class SurchargeCost(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="List of auth codes for each node that has an active interactive session.", - title="Auth Codes", + description="Model distribution surcharge incurred on this date in dollars", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Surcharge Cost", ), ] -class PatchInteractiveSessionRequest(BaseModel): - timeout_minutes: Annotated[ - int | None, - Field( - description="For on_startup sessions, minutes to add to the expiration. For on_demand/on_failure sessions, minutes to add to the timeout. Use -1 for infinite timeout (bumps by 10 years).", - title="Timeout Minutes", - ), - ] = None - trigger: Annotated[ - V1InteractiveSessionTrigger | None, +class DailyDedicatedUsage(BaseModel): + date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] + subtotal: Annotated[ + float | Subtotal, Field( - description="Update when the interactive session is created. Cannot be changed if the session trigger is 'on_startup'." + description="Subtotal cost incurred on this date in dollars", + title="Subtotal", ), - ] = None - - -class InteractiveSession(BaseModel): - id: Annotated[ - str, - Field(description="Unique identifier of the interactive session.", title="Id"), - ] - trigger: Annotated[ - str, - Field(description="When the interactive session is created.", title="Trigger"), ] - timeout_minutes: Annotated[ - int, + compute_cost: Annotated[ + float | ComputeCost, Field( - description="Minutes before the session times out.", title="Timeout Minutes" + description="Compute cost incurred on this date in dollars", + title="Compute Cost", ), ] - session_provider: Annotated[ - str, - Field(description="The IDE client for the session.", title="Session Provider"), - ] - auth_provider: Annotated[ - str, + surcharge_cost: Annotated[ + float | SurchargeCost, Field( - description="The authentication provider for the session.", - title="Auth Provider", + description="Model distribution surcharge incurred on this date in dollars", + title="Surcharge Cost", ), ] - pod_name: Annotated[ - str, - Field(description="Pod name / node rank for the session.", title="Pod Name"), + minutes: Annotated[ + int, Field(description="Minutes used on this date", title="Minutes") ] - expires_at: Annotated[ - AwareDatetime | None, + inference_requests: Annotated[ + int, Field( - description="When the session expires, in ISO 8601 format.", - title="Expires At", + description="Number of inference requests on this date", + title="Inference Requests", ), - ] = None - tunnel_name: Annotated[ - str | None, - Field(description="The tunnel name for the session.", title="Tunnel Name"), - ] = None - auth_code: Annotated[ - str | None, - Field(description="The device authentication code.", title="Auth Code"), - ] = None - auth_url: Annotated[ - str | None, + ] + + +class DailyModelApiUsage(BaseModel): + date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] + subtotal: Annotated[ + float | Subtotal, Field( - description="URL where the user should enter the auth code.", - title="Auth Url", + description="Subtotal cost incurred on this date in dollars", + title="Subtotal", ), - ] = None - auth_code_generated_at: Annotated[ - AwareDatetime | None, + ] + input_tokens: Annotated[ + int, + Field(description="Number of input tokens on this date", title="Input Tokens"), + ] + output_tokens: Annotated[ + int, Field( - description="When the auth code was generated.", - title="Auth Code Generated At", + description="Number of output tokens on this date", title="Output Tokens" ), - ] = None - authenticated_at: Annotated[ - AwareDatetime | None, + ] + cached_input_tokens: Annotated[ + int, Field( - description="When the session was authenticated.", title="Authenticated At" + description="Number of cached input tokens on this date", + title="Cached Input Tokens", ), - ] = None - working_directory: Annotated[ - str | None, + ] + + +class DailyTrainingUsage(BaseModel): + date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] + subtotal: Annotated[ + float | Subtotal, Field( - description="The working directory of the session.", - title="Working Directory", + description="Subtotal cost incurred on this date in dollars", + title="Subtotal", ), - ] = None + ] + minutes: Annotated[ + int, Field(description="Minutes used on this date", title="Minutes") + ] -class PatchInteractiveSessionResponse(BaseModel): - interactive_session: Annotated[ - InteractiveSession, Field(description="The updated interactive session.") - ] - message: Annotated[ +class Subtotal3(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="Human-readable summary of what was updated.", title="Message" + description="Subtotal cost in dollars for this billable resource", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", ), ] -class GetCacheSummaryResponse(BaseModel): - timestamp: Annotated[ +class ComputeCost1(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="Timestamp when the cache summary was captured", - title="Timestamp", + description="Compute cost in dollars for this billable resource", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Compute Cost", ), ] - project_id: Annotated[ - str, - Field(description="Project ID associated with the cache", title="Project Id"), - ] - file_summaries: Annotated[ - list[FileSummary], - Field(description="List of files in the cache", title="File Summaries"), - ] -class TrainingProjectTombstone(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the training project", title="Id") - ] - deleted: Annotated[ - bool, - Field(description="Whether the training project was deleted", title="Deleted"), +class SurchargeCost1(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + description="Model distribution surcharge in dollars for this billable resource", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Surcharge Cost", + ), ] -class OrderBy(BaseModel): - field: Annotated[ +class Subtotal4(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="The field to order by.", examples=["created_at"], title="Field" + description="Subtotal cost in dollars after applying credits used", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", ), ] - order: Annotated[ + + +class CreditsUsed(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="The direction to order by.", - examples=["asc", "desc"], - title="Order", + description="Credits applied in dollars", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Credits Used", ), ] -class SearchTrainingJobsRequest(BaseModel): - project_id: Annotated[ - str | None, - Field( - description="Filter the training jobs by project ID.", - examples=["n4q95w5"], - title="Project Id", - ), - ] = None - job_id: Annotated[ - str | None, - Field( - description="Filter the training jobs by job ID.", - examples=["p7qr9qv"], - title="Job Id", - ), - ] = None - statuses: Annotated[ - list[str] | None, +class Total(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="Filter the training jobs by status.", - examples=[["TRAINING_JOB_RUNNING", "TRAINING_JOB_COMPLETED"]], - title="Statuses", + description="Total cost in dollars", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Total", ), - ] = None - order_by: Annotated[ - list[OrderBy], + ] + + +class Subtotal5(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="Order the training jobs by a field. Currently supports created_at", - title="Order By", - validate_default=True, + description="Subtotal cost in dollars for this model", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", ), - ] = [OrderBy.model_validate({"field": "created_at", "order": "desc"})] + ] -class SupportedModel(BaseModel): - model_name: Annotated[ - str, Field(description="The name of the supported model.", title="Model Name") +class ModelApiItem(BaseModel): + model_name: Annotated[str, Field(description="Model name", title="Model Name")] + model_family: Annotated[ + str | None, + Field(description="Model family (e.g., Meta, DeepSeek)", title="Model Family"), + ] = None + subtotal: Annotated[ + float | Subtotal5, + Field(description="Subtotal cost in dollars for this model", title="Subtotal"), ] - max_context_length: Annotated[ + input_tokens: Annotated[ int, - Field( - description="The maximum context length (in tokens) supported by this model.", - title="Max Context Length", - ), + Field(description="Total input tokens for this model", title="Input Tokens"), ] - supports_vision_language: Annotated[ - bool, + output_tokens: Annotated[ + int, + Field(description="Total output tokens for this model", title="Output Tokens"), + ] + cached_input_tokens: Annotated[ + int, Field( - description="Whether the model accepts image inputs alongside text.", - title="Supports Vision Language", + description="Total cached input tokens for this model", + title="Cached Input Tokens", ), ] + daily: Annotated[ + list[DailyModelApiUsage] | None, + Field(description="Daily usage breakdown", title="Daily"), + ] = None -class GetLoopsCapabilitiesResponse(BaseModel): - supported_models: Annotated[ - list[SupportedModel], +class Subtotal6(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="List of models available on the server.", - title="Supported Models", + description="Subtotal cost in dollars after applying credits used", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", ), ] -class LoopsSession(BaseModel): - id: Annotated[str, Field(title="Id")] - - -class CreateLoopsSessionResponse(BaseModel): - session: LoopsSession - - -class GetLoopsSessionResponse(BaseModel): - session: Annotated[LoopsSession, Field(description="The Loops session.")] - - -class LoopsRunStatusName(StrEnum): - ACTIVE = "ACTIVE" - INACTIVE = "INACTIVE" - - -class LoopsRunStatus(BaseModel): - name: Annotated[ - LoopsRunStatusName, +class ModelApisUsage(BaseModel): + subtotal: Annotated[ + float | Subtotal6, Field( - description="ACTIVE while the run is live; INACTIVE once replaced by a newer run or shut down." + description="Subtotal cost in dollars after applying credits used", + title="Subtotal", ), ] - - -class LoopsSamplerStatus(BaseModel): - name: Annotated[ - DeploymentStatus, Field(description="The current status of the Loops sampler.") + credits_used: Annotated[ + float | CreditsUsed, + Field(description="Credits applied in dollars", title="Credits Used"), ] + total: Annotated[ + float | Total, Field(description="Total cost in dollars", title="Total") + ] + breakdown: Annotated[ + list[ModelApiItem] | None, + Field(description="Per-model usage breakdown", title="Breakdown"), + ] = None -class LoopsSampler(BaseModel): - id: Annotated[str, Field(title="Id")] - base_url: Annotated[str, Field(title="Base Url")] - base_model: Annotated[ +class Subtotal7(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ str, Field( - description="The HuggingFace base model the sampler is serving.", - title="Base Model", + description="Subtotal cost in dollars for this billable resource", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", ), ] - created_at: Annotated[ - AwareDatetime, + + +class Subtotal8(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="Time the sampler was created in ISO 8601 format", - title="Created At", + description="Subtotal cost in dollars after applying credits used", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", ), ] - model_id: Annotated[ + + +class ToolCallUsageBucket(BaseModel): + date: Annotated[ + date_aliased, + Field(description="UTC day the usage was recorded on.", title="Date"), + ] + provider: Annotated[ str, - Field(description="Hashid of the underlying Baseten model.", title="Model Id"), + Field(description="Tool provider, such as exa or parallel.", title="Provider"), ] - deployment_id: Annotated[ + sku: Annotated[ str, Field( - description="Hashid of the specific model deployment (version).", - title="Deployment Id", + description="Charge unit, as `/`. The unit is what the provider reported, or the tool name when it reported none. Its meaning varies by provider.", + title="Sku", ), ] - status: Annotated[ - LoopsSamplerStatus, Field(description="The sampler's current status.") + model: Annotated[ + str, Field(description="Model that made the tool calls.", title="Model") + ] + calls: Annotated[int, Field(description="Number of tool calls.", title="Calls")] + quantity: Annotated[ + float, + Field( + description="Billable quantity in the provider's sku unit, summed over the calls.", + title="Quantity", + ), ] - user: Annotated[User, Field(description="The user who owns the sampler.")] - instance_type: Annotated[ - InstanceType | None, Field(description="Instance type serving the sampler.") - ] = None - node_count: Annotated[ - int, - Field(description="Number of nodes serving the sampler.", title="Node Count"), - ] = 1 -class Name2(RootModel[str]): - root: Annotated[ +class ToolCallUsageResponse(BaseModel): + items: Annotated[list[ToolCallUsageBucket] | None, Field(title="Items")] = None + + +class UserInfo(BaseModel): + user_id: Annotated[ + str, Field(description="Unique identifier for the user", title="User Id") + ] + email: Annotated[ + str | None, Field(description="Email address of the user", title="Email") + ] = None + name: Annotated[ + str | None, Field(description="Display name of the user", title="Name") + ] = None + workspace_name: Annotated[ str | None, - Field( - description="Optional display name for the run. Defaults to the base model name when omitted.", - max_length=255, - min_length=1, - title="Name", - ), + Field(description="Name of the user's workspace", title="Workspace Name"), ] = None -class CreateLoopsRunRequest(BaseModel): - session_id: Annotated[ +class UsersResponse(BaseModel): + items: Annotated[ + list[UserInfo], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class AwsAssumeRole(BaseModel): + baseten_role_arn: Annotated[ str, Field( - description="ID of the Loops session this run belongs to.", - title="Session Id", + description="Baseten role ARN to allow in an IAM role's trust policy", + title="Baseten Role Arn", ), ] - base_model: Annotated[ + external_id: Annotated[ str, - Field(description="Base model ID (e.g. 'Qwen/Qwen3-8B').", title="Base Model"), - ] - name: Annotated[ - Name2 | None, - Field( - description="Optional display name for the run. Defaults to the base model name when omitted.", - title="Name", - ), - ] = None - max_seq_len: Annotated[ - int | None, - Field( - description="Maximum prompt length (in tokens) the run must handle. Set this to the longest training example you plan to send. Defaults to the maximum supported by the model configuration.", - title="Max Seq Len", - ), - ] = None - lora_rank: Annotated[ - int, Field(description="LoRA rank.", ge=1, title="Lora Rank") - ] = 64 - seed: Annotated[ - int | None, Field(description="Random seed for reproducibility.", title="Seed") - ] = None - scale_down_delay_seconds: Annotated[ - int, - Field( - description="Seconds of inactivity before the run scales to zero. Must be between 1 and 3600 (1 hour). Defaults to 900 (15 minutes).", - gt=0, - le=3600, - title="Scale Down Delay Seconds", - ), - ] = 900 - availability_model: Annotated[ - V1AvailabilityModel, - Field( - description="Capacity the trainer runs on. 'dedicated' is not preempted. 'spot' runs below inference and reaches idle reserved capacity, but the run is stopped if its GPUs are reclaimed and cannot be resumed.", - examples=["spot"], - ), - ] = V1AvailabilityModel.dedicated - replicas: Annotated[ - int, - Field( - description="Number of data-parallel trainer replicas. Each replica is one full copy of the model's preset node group, so the trainer deployment runs (preset node_count * replicas) nodes (e.g. replicas=4 on a 4-node preset → 16 nodes, 4 DP workers). Must be a positive integer. Defaults to 1.", - ge=1, - title="Replicas", - ), - ] = 1 - path: Annotated[ - str | None, Field( - description="Optional bt:// URI of an existing checkpoint to load weights from on startup. Form: bt://loops:/weights/.", - examples=["bt://loops:k4q95w5/weights/step-100"], - title="Path", + description="sts:ExternalId Baseten presents when assuming the role", + title="External Id", ), + ] + + +class OrganizationInfo(BaseModel): + org_id: Annotated[ + str, Field(description="Unique identifier for the organization", title="Org Id") + ] + name: Annotated[ + str | None, Field(description="Display name of the organization", title="Name") ] = None - reuse_from_run_id: Annotated[ - str | None, + created_at: Annotated[ + AwareDatetime, Field( - description="Optional ID of a prior Loops run whose trainer and/or sampler should be reused for this run instead of provisioning fresh. The prior run must use the same base model and belong to the same team.", - title="Reuse From Run Id", + description="Time the organization was created in ISO 8601 format", + title="Created At", ), - ] = None - reuse_from_session_id: Annotated[ - str | None, + ] + aws_assume_role: Annotated[ + AwsAssumeRole | None, Field( - description="Optional ID of a prior Loops session whose trainer and/or sampler should be reused for this run. Deprecated in favor of reuse_from_run_id.", - title="Reuse From Session Id", + description="AWS AssumeRole trust-policy inputs; null while the method is not enabled for the organization" ), ] = None -class DeactivateLoopsRunResponse(BaseModel): - id: Annotated[str, Field(description="The deactivated Loops run ID.", title="Id")] - base_model: Annotated[ - str, - Field( - description="The base model whose Loops run was deactivated.", - title="Base Model", - ), +class GatewayEventTokens(BaseModel): + inputTokens: Annotated[ + int, Field(description="Cached and uncached input tokens.", title="Inputtokens") + ] + outputTokens: Annotated[ + int, Field(description="Output tokens.", title="Outputtokens") + ] + cachedInputTokens: Annotated[ + int, Field(description="Cached input tokens.", title="Cachedinputtokens") ] - user: Annotated[User, Field(description="The user who owns the Loops run.")] -class ListLoopsSamplersResponse(BaseModel): - samplers: Annotated[ - list[LoopsSampler], Field(description="List of samplers.", title="Samplers") +class GatewayEvent(BaseModel): + type: Annotated[str, Field(description="Event type.", title="Type")] = ( + "API_BILLING_USAGE" + ) + idempotencyKey: Annotated[ + str, Field(description="Deduplication key.", title="Idempotencykey") ] + timestamp: Annotated[ + str, Field(description="Billing event time (ISO 8601, UTC).", title="Timestamp") + ] + requestId: Annotated[ + str, Field(description="Inference request ID.", title="Requestid") + ] + modelSlug: Annotated[str, Field(description="Served model.", title="Modelslug")] + externalEntityId: Annotated[ + str, Field(description="Calling group's external ID.", title="Externalentityid") + ] + apiKeyPrefix: Annotated[ + str, Field(description="API key prefix.", title="Apikeyprefix") + ] + tokens: GatewayEventTokens -class CreateLoopsSamplerRequest(BaseModel): - session_id: Annotated[ - str, - Field( - description="ID of the Loops session this sampler belongs to.", - title="Session Id", - ), +class GatewayEventsResponse(BaseModel): + items: Annotated[ + list[GatewayEvent], Field(description="Items in this page.", title="Items") ] - base_model: Annotated[ - str | None, - Field( - description="Base model ID for a standalone sampler (for example, a baseline).", - title="Base Model", - ), + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class ExploreCostValues(BaseModel): + input: Annotated[ + float | None, + Field(description="USD per 1M input tokens, when available.", title="Input"), ] = None - run_id: Annotated[ - str | None, - Field( - description="ID of an existing run to attach this sampler to. When set, the sampler is paired to the run and weight-syncs from its trainer, and base_model is inherited from the run. Omit to create a standalone sampler.", - title="Run Id", - ), + output: Annotated[ + float | None, + Field(description="USD per 1M output tokens, when available.", title="Output"), ] = None - max_seq_length: Annotated[ - int | None, + cache_read: Annotated[ + float | None, Field( - description="Maximum prompt length (in tokens) the sampler must handle. Set this to the longest prompt you plan to send.", - title="Max Seq Length", + description="USD per 1M input tokens read from cache, when available.", + title="Cache Read", ), ] = None - model_path: Annotated[ - str | None, + cache_write: Annotated[ + float | None, Field( - description="bt:// URI of an existing sampler checkpoint to serve. Form: bt://loops:/sampler_weights/.", - examples=["bt://loops:k4q95w5/sampler_weights/step-100"], - title="Model Path", + description="USD per 1M input tokens written to cache, when available.", + title="Cache Write", ), ] = None - reuse_from_session_id: Annotated[ - str | None, + + +class ExploreMetadataAPIFormats(BaseModel): + messages: Annotated[ + bool, Field(description="Anthropic Messages API support.", title="Messages") + ] = False + responses: Annotated[ + bool, Field(description="OpenAI Responses API support.", title="Responses") + ] = False + chat_completions: Annotated[ + bool, Field( - description="Optional ID of a prior Loops session to reuse a trainer and/or sampler from. Deprecated.", - title="Reuse From Session Id", + description="OpenAI Chat Completions API support.", title="Chat Completions" ), - ] = None + ] = False -class CreateLoopsSamplerResponse(BaseModel): - sampler: LoopsSampler +class RouteTargetAnthropic(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + type: Annotated[ + Literal["ANTHROPIC"], + Field(description="Target kind for Anthropic.", title="Type"), + ] + model: Annotated[ + str, + Field( + description="Model name sent to the provider.", min_length=1, title="Model" + ), + ] + secret_name: Annotated[ + str, + Field( + description="Name of a credential secret owned by the route's team.", + min_length=1, + title="Secret Name", + ), + ] -class GetLoopsSamplerResponse(BaseModel): - sampler: Annotated[LoopsSampler, Field(description="The Loops sampler.")] +class RouteTargetBasetenModelAPI(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + type: Annotated[ + Literal["BASETEN_MODEL_API"], + Field(description="Target kind for a Baseten Model API.", title="Type"), + ] + model: Annotated[ + str, + Field(description="Name of the target Model API.", min_length=1, title="Model"), + ] -class LoopsCheckpoint(BaseModel): - checkpoint_id: Annotated[ - str, Field(description="The ID of the checkpoint.", title="Checkpoint Id") +class RouteTargetOpenAI(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + type: Annotated[ + Literal["OPENAI"], Field(description="Target kind for OpenAI.", title="Type") ] - created_at: Annotated[ - AwareDatetime, + model: Annotated[ + str, Field( - description="The timestamp of the checkpoint in ISO 8601 format.", - title="Created At", + description="Model name sent to the provider.", min_length=1, title="Model" ), ] - checkpoint_type: Annotated[ - str, Field(description="The type of checkpoint.", title="Checkpoint Type") - ] - base_model: Annotated[ - str | None, - Field(description="The base model of the checkpoint.", title="Base Model"), - ] - lora_adapter_config: Annotated[ - dict[str, Any] | None, + secret_name: Annotated[ + str, Field( - description="The adapter config of the checkpoint.", - title="Lora Adapter Config", + description="Name of a credential secret owned by the route's team.", + min_length=1, + title="Secret Name", ), ] - size_bytes: Annotated[ - int, - Field(description="The size of the checkpoint in bytes.", title="Size Bytes"), + + +class RouteTargetXAI(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + type: Annotated[ + Literal["XAI"], Field(description="Target kind for xAI.", title="Type") ] - sync_status: Annotated[ - str | None, - Field( - description="Sync state of the checkpoint: SYNCING or COMPLETE.", - title="Sync Status", - ), - ] = None - id: Annotated[str, Field(description="The checkpoint ID.", title="Id")] - run_id: Annotated[ + model: Annotated[ str, Field( - description="The ID of the run that produced the checkpoint.", - title="Run Id", + description="Model name sent to the provider.", min_length=1, title="Model" ), ] - target: Annotated[ - TrainerCheckpointTarget, + secret_name: Annotated[ + str, Field( - description="Whether this checkpoint is loadable by the sampler or by the run." + description="Name of a credential secret owned by the route's team.", + min_length=1, + title="Secret Name", ), ] -class ListLoopsCheckpointsResponse(BaseModel): - checkpoints: Annotated[ - list[LoopsCheckpoint], - Field(description="Matching checkpoints.", title="Checkpoints"), - ] +class TeamId1(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="Identifier of the team that owns the route. When omitted, uses your organization's default team.", + examples=["abc1234"], + min_length=1, + title="Team Id", + ), + ] = None -class ValidateLoopsCheckpointRequest(BaseModel): - checkpoint_path: Annotated[ - str, +class DisplayName(RootModel[str]): + root: Annotated[ + str | None, Field( - description="bt:// URI of a sampler checkpoint. Form: bt://loops:/sampler_weights/.", - examples=["bt://loops:k4q95w5/sampler_weights/step-100"], - title="Checkpoint Path", + description="Display label. Omit to use the route name; null is not accepted.", + examples=["Assistant"], + max_length=255, + min_length=1, + title="Display Name", ), - ] + ] = None -class ValidateLoopsCheckpointResponse(BaseModel): - pass +class Description(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="Short description of the route. Omit for no description; null is not accepted.", + examples=["Assistant for code review and debugging."], + max_length=1000, + title="Description", + ), + ] = None -class LoopsCheckpointFilesResponse(BaseModel): - presigned_urls: Annotated[ - list[CheckpointFile], +class CreateRouteRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ + TeamId1 | None, Field( - description="List of presigned URLs for checkpoint files.", - title="Presigned Urls", + description="Identifier of the team that owns the route. When omitted, uses your organization's default team.", + examples=["abc1234"], + title="Team Id", ), - ] - next_page_token: Annotated[ - int | None, + ] = None + display_name: Annotated[ + DisplayName | None, Field( - description="Token to use for fetching the next page of results. None when there are no more results.", - title="Next Page Token", + description="Display label. Omit to use the route name; null is not accepted.", + examples=["Assistant"], + title="Display Name", ), ] = None - total_count: Annotated[ - int, - Field( - description="Total number of checkpoint files available.", - title="Total Count", + target: Annotated[ + RouteTargetBasetenModelAPI + | RouteTargetAnthropic + | RouteTargetOpenAI + | RouteTargetXAI, + Field( + description="Upstream target for the route.", + discriminator="type", + examples=[{"model": "zai-org/GLM-5.3", "type": "BASETEN_MODEL_API"}], + title="Target", ), ] + description: Annotated[ + Description | None, + Field( + description="Short description of the route. Omit for no description; null is not accepted.", + examples=["Assistant for code review and debugging."], + title="Description", + ), + ] = None -class LoopsDeploymentStatus(BaseModel): - name: Annotated[Name, Field(description="Latest status of the Loops deployment.")] +class RouteProvider(StrEnum): + BASETEN_MODEL_API = "BASETEN_MODEL_API" + OPENAI = "OPENAI" + ANTHROPIC = "ANTHROPIC" + XAI = "XAI" + VERTEX = "VERTEX" + OPENAI_COMPATIBLE = "OPENAI_COMPATIBLE" -class LoopsDeployment(BaseModel): - id: Annotated[str, Field(description="The Loops deployment ID.", title="Id")] - active_run_id: Annotated[ +class RoutesUsageResult(BaseModel): + user_id: Annotated[ str | None, Field( - description="The ID of the run currently active on this deployment, if any. Null when the deployment's runs have been marked inactive (e.g. scale-to-zero) without a successor.", - title="Active Run Id", + description="ID of the user who created the Routes key. Null when not grouping by USER.", + title="User Id", + ), + ] = None + model: Annotated[ + str | None, + Field( + description="Model name. For external providers, the model name sent to the provider. Null when not grouping by MODEL.", + title="Model", ), ] = None - latest_run_id: Annotated[ - str | None, + provider: Annotated[ + RouteProvider | None, Field( - description="The ID of the most recent run on this deployment, active or not, so idle deployments still expose a usable run handle. Null only if the deployment has no runs.", - title="Latest Run Id", + description="Provider that served the requests. Null when not grouping by PROVIDER." ), ] = None - base_model: Annotated[ + cost_usd: Annotated[ str, Field( - description="The HuggingFace base model the deployment is fine-tuning.", - title="Base Model", + description="Estimated cost in USD, returned as an exact decimal string. Costs for OpenAI, Anthropic, and xAI estimate what you pay those providers; they are not Baseten charges.", + examples=["0.00035625"], + title="Cost Usd", ), ] - base_url: Annotated[str, Field(description="The run's base URL.", title="Base Url")] - status: Annotated[ - LoopsDeploymentStatus, Field(description="Latest deployment status.") - ] - user: Annotated[User, Field(description="The user who owns the Loops deployment.")] - created_at: Annotated[ - AwareDatetime, + input_tokens: Annotated[ + int, Field( - description="Time the deployment was created in ISO 8601 format.", - title="Created At", + description="Input tokens, including cached input tokens.", + title="Input Tokens", ), ] - availability_model: Annotated[ - V1AvailabilityModel, Field(description="Capacity the trainer was scheduled on.") - ] = V1AvailabilityModel.dedicated - instance_type: Annotated[ - InstanceType, Field(description="Instance type backing the trainer.") - ] - node_count: Annotated[ + cached_input_tokens: Annotated[ int, - Field(description="Number of nodes backing the trainer.", title="Node Count"), - ] = 1 - sampler: Annotated[ - LoopsSampler | None, Field(description="The sampler bound to this deployment.") - ] = None - - -class ListLoopsDeploymentsResponse(BaseModel): - deployments: Annotated[ - list[LoopsDeployment], - Field(description="Active Loops deployments.", title="Deployments"), - ] - - -class DeactivateLoopsDeploymentResponse(BaseModel): - id: Annotated[ - str, Field(description="The deactivated Loops deployment ID.", title="Id") + Field( + description="Input tokens read from the prompt cache.", + title="Cached Input Tokens", + ), ] - base_model: Annotated[ - str, + uncached_input_tokens: Annotated[ + int, Field( - description="The base model whose Loops deployment was deactivated.", - title="Base Model", + description="Input tokens not read from the prompt cache, including tokens written to the cache.", + title="Uncached Input Tokens", ), ] - user: Annotated[User, Field(description="The user who owned the Loops deployment.")] - - -class GetLoopsDeploymentResponse(BaseModel): - deployment: Annotated[LoopsDeployment, Field(description="The Loops deployment.")] + output_tokens: Annotated[ + int, Field(description="Output tokens.", title="Output Tokens") + ] -class LoopsDebugArchiveFilesResponse(BaseModel): - presigned_urls: Annotated[list[CheckpointFile], Field(title="Presigned Urls")] - next_page_token: Annotated[str | None, Field(title="Next Page Token")] = None +class RouteUsageDimension(StrEnum): + USER = "USER" + MODEL = "MODEL" + PROVIDER = "PROVIDER" -class GetLoopsDeploymentMetricsRequest(BaseModel): - end_epoch_millis: Annotated[ - int | None, +class RouteSpendLimit(BaseModel): + user_id: Annotated[ + str, Field(description="ID of the user.", examples=["abc1234"], title="User Id") + ] + email: Annotated[ + str | None, Field( - description="Epoch millis to end fetching metrics.", - title="End Epoch Millis", + description="Email address of the user.", + examples=["dev@example.com"], + title="Email", ), - ] = None - start_epoch_millis: Annotated[ - int | None, + ] + monthly_limit_usd: Annotated[ + str | None, Field( - description="Epoch millis to start fetching metrics.", - title="Start Epoch Millis", + description="Standing spend limit in USD for each UTC calendar month, returned as an exact decimal string. Null when the user has no standing limit.", + examples=["200"], + title="Monthly Limit Usd", ), - ] = None - step_seconds: Annotated[ - int | None, + ] + + +class UpdateRouteSpendLimitRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + monthly_limit_usd: Annotated[ + str | None, Field( - description="Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", - title="Step Seconds", + description="Standing spend limit in USD for each UTC calendar month, as a non-negative decimal string with at most 9 decimal places. Send null to remove the limit; omit to leave it unchanged.", + examples=["200"], + title="Monthly Limit Usd", ), ] = None - time_divisor_seconds: Annotated[ - int | None, + + +class Primary(RootModel[str]): + root: Annotated[ + str | None, Field( - description="Unit of time for request-volume metrics, in seconds (e.g. 60 for requests/minute). Defaults to per-second.", - title="Time Divisor Seconds", + description="Route ID for the primary model, which new sessions use. Omit to keep the current route, or pass null to use Baseten's default.", + examples=["abc1234"], + min_length=1, + title="Primary", ), ] = None -class InferenceVolumeByStatusDatapoint(BaseModel): - timestamp: Annotated[ - AwareDatetime, Field(description="ISO 8601 timestamp.", title="Timestamp") - ] - status_2xx: Annotated[ - float, Field(description="2xx requests per second.", title="Status 2Xx") - ] - status_4xx: Annotated[ - float, Field(description="4xx requests per second.", title="Status 4Xx") - ] - status_5xx: Annotated[ - float, Field(description="5xx requests per second.", title="Status 5Xx") - ] - - -class ResponseTimeDatapoint(BaseModel): - timestamp: Annotated[ - AwareDatetime, Field(description="ISO 8601 timestamp.", title="Timestamp") - ] - p50: Annotated[ - float | None, +class Background(RootModel[str]): + root: Annotated[ + str | None, Field( - description="50th percentile request latency (milliseconds).", title="P50" + description="Route ID for background tasks, such as session titles. Omit to keep the current route, or pass null to use Baseten's default.", + examples=["def5678"], + min_length=1, + title="Background", ), ] = None - p95: Annotated[ - float | None, + + +class UpdateBackgroundHarnessModels(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + primary: Annotated[ + Primary | None, Field( - description="95th percentile request latency (milliseconds).", title="P95" + description="Route ID for the primary model, which new sessions use. Omit to keep the current route, or pass null to use Baseten's default.", + examples=["abc1234"], + title="Primary", ), ] = None - p99: Annotated[ - float | None, + background: Annotated[ + Background | None, Field( - description="99th percentile request latency (milliseconds).", title="P99" + description="Route ID for background tasks, such as session titles. Omit to keep the current route, or pass null to use Baseten's default.", + examples=["def5678"], + title="Background", ), ] = None -class TeamTrainingGpuCapacityItem(BaseModel): - team_id: Annotated[str, Field(description="Team identifier", title="Team Id")] - team_name: Annotated[str, Field(description="Team name", title="Team Name")] - gpu_type: Annotated[ +class UpdateClaudeCodeHarnessConfig(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ str, Field( - description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" - ), - ] - baseline: Annotated[ - int, - Field( - description="Baseline GPU allocation for the team. 0 if not configured.", - title="Baseline", + description="Identifier of the team whose default models to set. Every route must belong to this team.", + min_length=1, + title="Team Id", ), ] - limit: Annotated[ - int, + harness: Annotated[ + Literal["claude-code"], Field( - description="Maximum concurrent GPUs of this type for this team", - title="Limit", + description="Claude Code, which supports the `primary` and `background` roles.", + title="Harness", ), ] - usage_count: Annotated[ - int, + models: Annotated[ + UpdateBackgroundHarnessModels, Field( - description="GPUs currently in use by the team's active training jobs", - title="Usage Count", + description="Route IDs for the model roles to change. Roles left out are unchanged." ), ] - dedicated_usage_count: Annotated[ - int, - Field( - description="Portion of usage_count from dedicated (on-demand) jobs.", - title="Dedicated Usage Count", - ), - ] = 0 - spot_usage_count: Annotated[ - int, - Field( - description="Portion of usage_count from spot jobs.", - title="Spot Usage Count", - ), - ] = 0 -class TrainingGpuCapacityItem(BaseModel): - gpu_type: Annotated[ +class UpdateOpenCodeHarnessConfig(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ str, Field( - description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" + description="Identifier of the team whose default models to set. Every route must belong to this team.", + min_length=1, + title="Team Id", ), ] - baseline: Annotated[ - int, + harness: Annotated[ + Literal["opencode"], Field( - description="Baseline GPU allocation; jobs below this threshold are expected to run immediately. 0 if not configured.", - title="Baseline", + description="OpenCode, which supports the `primary` and `background` roles.", + title="Harness", ), ] - limit: Annotated[ - int, + models: Annotated[ + UpdateBackgroundHarnessModels, Field( - description="Maximum concurrent GPUs of this type for this org", - title="Limit", + description="Route IDs for the model roles to change. Roles left out are unchanged." ), ] - usage_count: Annotated[ - int, + + +class UpdatePrimaryHarnessModels(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + primary: Annotated[ + Primary | None, Field( - description="GPUs currently in use by active training jobs", - title="Usage Count", + description="Route ID for the primary model, which new sessions use. Omit to keep the current route, or pass null to use Baseten's default.", + examples=["abc1234"], + title="Primary", ), - ] - dedicated_usage_count: Annotated[ - int, + ] = None + + +class Primary2(RootModel[str]): + root: Annotated[ + str | None, Field( - description="Portion of usage_count from dedicated (on-demand) jobs, which run against the baseline.", - title="Dedicated Usage Count", + description="Route ID for the primary model, which new sessions use. Omit to use Baseten's default.", + examples=["abc1234"], + min_length=1, + title="Primary", ), - ] = 0 - spot_usage_count: Annotated[ - int, + ] = None + + +class Background1(RootModel[str]): + root: Annotated[ + str | None, Field( - description="Portion of usage_count from spot jobs, which burst into the peak and may push usage above the limit.", - title="Spot Usage Count", + description="Route ID for background tasks, such as session titles. Omit to use Baseten's default.", + examples=["def5678"], + min_length=1, + title="Background", ), - ] = 0 + ] = None -class GetTrainingGpuCapacityResponse(BaseModel): - gpu_capacities: Annotated[ - list[TrainingGpuCapacityItem], +class BackgroundHarnessModels(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + primary: Annotated[ + Primary2 | None, Field( - description="Org-level GPU capacity limits and current usage per GPU type", - title="Gpu Capacities", + description="Route ID for the primary model, which new sessions use. Omit to use Baseten's default.", + examples=["abc1234"], + title="Primary", ), - ] - team_gpu_capacities: Annotated[ - list[TeamTrainingGpuCapacityItem] | None, + ] = None + background: Annotated[ + Background1 | None, Field( - description="Per-team GPU capacity limits and current usage per GPU type", - title="Team Gpu Capacities", + description="Route ID for background tasks, such as session titles. Omit to use Baseten's default.", + examples=["def5678"], + title="Background", + ), + ] = None + + +class PrimaryHarnessModels(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + primary: Annotated[ + Primary2 | None, + Field( + description="Route ID for the primary model, which new sessions use. Omit to use Baseten's default.", + examples=["abc1234"], + title="Primary", ), ] = None -class PatchTeamTrainingGpuCapacityRequest(BaseModel): - team_id: Annotated[str, Field(description="Team identifier", title="Team Id")] - gpu_type: Annotated[ +class SetClaudeCodeHarnessConfig(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ str, Field( - description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" + description="Identifier of the team whose default models to set. Every route must belong to this team.", + min_length=1, + title="Team Id", ), ] - max_gpus: Annotated[ - int, + harness: Annotated[ + Literal["claude-code"], Field( - description="Max concurrent GPUs of this type the team may use", - examples=[8, 16, 32], - title="Max Gpus", + description="Claude Code, which supports the `primary` and `background` roles.", + title="Harness", ), ] - - -class PatchTeamTrainingGpuCapacityResponse(BaseModel): - team_gpu_capacity: Annotated[ - TeamTrainingGpuCapacityItem, - Field(description="The updated per-team GPU capacity limit"), + models: Annotated[ + BackgroundHarnessModels, + Field( + description="Route ID for each model role. Roles left out use Baseten's defaults." + ), ] -class ActiveJobAtSubmit(BaseModel): - training_job_id: Annotated[ - str, - Field(description="Hashid of the other training job", title="Training Job Id"), - ] - training_job_name: Annotated[ - str | None, Field(description="Other job's name", title="Training Job Name") - ] = None - instance_type_name: Annotated[ - str, - Field(description="Instance type of the other job", title="Instance Type Name"), - ] - total_gpus: Annotated[ - int, Field(description="gpu_count * effective_node_count", title="Total Gpus") - ] - workload_plane_name: Annotated[ +class SetCodexHarnessConfig(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ str, Field( - description="Workload plane the other job was on", - title="Workload Plane Name", + description="Identifier of the team whose default models to set. Every route must belong to this team.", + min_length=1, + title="Team Id", ), ] - status_at_submit: Annotated[ - str, + harness: Annotated[ + Literal["codex"], Field( - description="Other job's status as of submitted_at (one of ACTIVE_STATES)", - title="Status At Submit", + description="Codex, which supports only the `primary` role.", + title="Harness", ), ] - status_set_at: Annotated[ - AwareDatetime, - Field(description="When that status was set", title="Status Set At"), + models: Annotated[ + PrimaryHarnessModels, + Field( + description="Route ID for each model role. Roles left out use Baseten's defaults." + ), ] -class CapacityAtSubmit(BaseModel): - gpu_type: Annotated[ +class SetOpenCodeHarnessConfig(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ str, Field( - description="GPU type identifier (e.g. H100, A100-40GB)", title="Gpu Type" + description="Identifier of the team whose default models to set. Every route must belong to this team.", + min_length=1, + title="Team Id", ), ] - max_gpus: Annotated[ - int, - Field(description="Current max concurrent GPUs of this type", title="Max Gpus"), - ] - min_gpus: Annotated[ - int | None, + harness: Annotated[ + Literal["opencode"], Field( - description="Current baseline GPU allocation, if configured", - title="Min Gpus", + description="OpenCode, which supports the `primary` and `background` roles.", + title="Harness", ), - ] = None - last_modified: Annotated[ - AwareDatetime, + ] + models: Annotated[ + BackgroundHarnessModels, Field( - description="When the capacity row was last modified", title="Last Modified" + description="Route ID for each model role. Roles left out use Baseten's defaults." ), ] -class PendingJobAheadAtSubmit(BaseModel): - training_job_id: Annotated[ - str, - Field(description="Hashid of the other training job", title="Training Job Id"), +class SetRouteHarnessConfigRequest( + RootModel[ + SetClaudeCodeHarnessConfig | SetOpenCodeHarnessConfig | SetCodexHarnessConfig ] - training_job_name: Annotated[ - str | None, Field(description="Other job's name", title="Training Job Name") - ] = None - instance_type_name: Annotated[ - str, - Field(description="Instance type of the other job", title="Instance Type Name"), +): + root: Annotated[ + SetClaudeCodeHarnessConfig | SetOpenCodeHarnessConfig | SetCodexHarnessConfig, + Field(discriminator="harness", title="SetRouteHarnessConfigRequestV1"), ] - requested_gpus: Annotated[ - int, - Field(description="gpu_count * effective_node_count", title="Requested Gpus"), + + +class RouteHarnessConfigTombstone(BaseModel): + harness: Annotated[ + RouteHarness, Field(description="Harness whose default models were cleared.") ] - priority: Annotated[ - int, - Field(description="Effective priority (NULL coalesced to 0)", title="Priority"), + team_id: Annotated[ + str, + Field( + description="Identifier of the team whose default models were cleared.", + title="Team Id", + ), ] - submitted_at: Annotated[ - AwareDatetime, - Field(description="The other job's submission time", title="Submitted At"), + + +class RouteTombstone(BaseModel): + id: Annotated[ + str, Field(description="Stable identifier of the deleted route.", title="Id") ] + name: Annotated[str, Field(description="Name of the deleted route.", title="Name")] -class QueueEvent(BaseModel): - training_job_id: Annotated[ - str, +class Description1(RootModel[str]): + root: Annotated[ + str | None, Field( - description="Hashid of the training job this event is for", - title="Training Job Id", + description="New description. Omit to keep the current description; use an empty string to clear it. Null is not accepted.", + examples=["Assistant for code review and debugging."], + max_length=1000, + title="Description", ), - ] - training_job_name: Annotated[ - str | None, Field(description="Job name", title="Training Job Name") ] = None - status: Annotated[ - str, Field(description="TrainingJobStatus.Name value", title="Status") - ] - created: Annotated[ - AwareDatetime, - Field(description="When the status row was inserted", title="Created"), - ] - event_message: Annotated[ + + +class DisplayName1(RootModel[str]): + root: Annotated[ str | None, Field( - description="Human-readable event message from the status metadata", - title="Event Message", + description="New display label. Omit to keep the current label; null is not accepted.", + examples=["Assistant"], + max_length=255, + min_length=1, + title="Display Name", ), ] = None - exit_code: Annotated[ - int | None, + + +class UpdateRouteRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + description: Annotated[ + Description1 | None, Field( - description="Exit code from the status metadata, if any", title="Exit Code" + description="New description. Omit to keep the current description; use an empty string to clear it. Null is not accepted.", + examples=["Assistant for code review and debugging."], + title="Description", + ), + ] = None + display_name: Annotated[ + DisplayName1 | None, + Field( + description="New display label. Omit to keep the current label; null is not accepted.", + examples=["Assistant"], + title="Display Name", ), ] = None -class GetTrainingJobQueueContextResponse(BaseModel): - target_job_id: Annotated[ +class SharedEndpointRegion(StrEnum): + UNRESTRICTED = "UNRESTRICTED" + EU = "EU" + + +class VertexTargetConfig(BaseModel): + project_id: Annotated[ str, - Field(description="Hashid of the target training job", title="Target Job Id"), - ] - target_job_name: Annotated[ - str | None, Field(description="Target job's name", title="Target Job Name") - ] = None - gpu_type: Annotated[ - str, Field(description="GPU type the target requested", title="Gpu Type") + Field( + description="Google Cloud project ID or project number.", + examples=["my-gcp-project", "464036093014"], + title="Project Id", + ), ] - requested_gpus: Annotated[ - int, + location: Annotated[ + str, Field( - description="GPUs the target requested (gpu_count * effective_node_count)", - title="Requested Gpus", + description="Google Cloud location.", examples=["global"], title="Location" ), ] - submitted_at: Annotated[ - AwareDatetime, + + +class EndpointTargetRequest(BaseModel): + provider: Annotated[ + GatewayProvider, Field( - description="When the job row was inserted (= API POST time)", - title="Submitted At", + description="Upstream provider for this target.", + examples=["ANTHROPIC", "OPENAI", "OPENAI_COMPATIBLE", "BASETEN"], ), ] - released_at: Annotated[ - AwareDatetime | None, + secret_id: Annotated[ + str | None, Field( - description="When the job's TRAINING_JOB_CREATED status was set, i.e. the moment it was released from PENDING. None if still PENDING.", - title="Released At", + description="Secret holding the provider credential. Required for external providers.", + examples=["3kZ9xqd"], + title="Secret Id", ), ] = None - pending_seconds: Annotated[ - int | None, + target_model: Annotated[ + str | None, Field( - description="released_at - submitted_at in seconds. None if still PENDING.", - title="Pending Seconds", + description="Model name to send upstream. Required for external providers and optional for BASETEN targets.", + examples=["gpt-4o"], + title="Target Model", ), ] = None - org_capacity: Annotated[ - CapacityAtSubmit | None, + base_url: Annotated[ + str | None, Field( - description="Org-level cap for (org, gpu_type). None if no cap is configured." + description="HTTPS base URL of the upstream OpenAI-compatible server. Must not include a port. Required for and only valid with OPENAI_COMPATIBLE.", + examples=["https://my-vllm.example.com"], + title="Base Url", ), ] = None - team_capacity: Annotated[ - CapacityAtSubmit | None, + model_id: Annotated[ + str | None, Field( - description="Team-level cap for (team, gpu_type). None if no team cap is configured." + description="Baseten model to route to. Required for and only valid with BASETEN.", + examples=["3kZ9xqd"], + title="Model Id", ), ] = None - active_at_submit: Annotated[ - list[ActiveJobAtSubmit], + environment_name: Annotated[ + str | None, Field( - description="Jobs in the same (org, gpu_type) pool that were holding capacity at submitted_at", - title="Active At Submit", + description="Baseten model environment to route to. Only valid with BASETEN. Omit or pass `production` to target production.", + examples=["staging"], + title="Environment Name", ), - ] - pending_ahead_at_submit: Annotated[ - list[PendingJobAheadAtSubmit], + ] = None + vertex_config: Annotated[ + VertexTargetConfig | None, Field( - description="PENDING jobs in the same (org, gpu_type) pool that were ahead of the target in dequeue FIFO order at submitted_at (priority DESC then created ASC). These also block the target's release.", - title="Pending Ahead At Submit", + description="Google Vertex configuration. Required for and only valid with VERTEX." ), - ] - events: Annotated[ - list[QueueEvent], - Field( - description="Every status event in [submitted_at, events_window_end] for the target job, every job in active_at_submit, and every job in pending_ahead_at_submit, oldest first.", - title="Events", + ] = None + + +class CreateEndpointRequest(BaseModel): + slug: Annotated[ + str, + Field( + description="Globally-unique slug of the form '{org_prefix}/{name}'.", + examples=["baseten/mymodel-4"], + title="Slug", ), ] - events_window_end: Annotated[ - AwareDatetime, + region: Annotated[ + SharedEndpointRegion, Field(description="Region the new routing serves.") + ] = SharedEndpointRegion.UNRESTRICTED + targets: Annotated[ + list[EndpointTargetRequest], Field( - description="released_at if set, else 'now' (events ongoing)", - title="Events Window End", + description="The endpoint's upstream targets. Exactly one target is supported at this time.", + examples=[ + [ + { + "environment_name": "staging", + "model_id": "3kZ9xqd", + "provider": "BASETEN", + "target_model": "custom/model-name", + } + ], + [ + { + "provider": "OPENAI", + "secret_id": "3kZ9xqd", + "target_model": "gpt-4o", + } + ], + [ + { + "base_url": "https://my-vllm.example.com", + "provider": "OPENAI_COMPATIBLE", + "secret_id": "3kZ9xqd", + "target_model": "my-model", + } + ], + ], + max_length=1, + min_length=1, + title="Targets", ), ] -class GetBlobCredentialsResponse(BaseModel): - creds: Annotated[ - AWSCredentials, Field(description="The credentials to upload the blob to") - ] - s3_key: Annotated[ - str, Field(description="The S3 key to upload the blob to", title="S3 Key") +class EndpointTombstone(BaseModel): + id: Annotated[ + str, Field(description="Identifier of the deleted endpoint.", title="Id") ] - s3_bucket: Annotated[ - str, Field(description="The S3 bucket to upload the blob to", title="S3 Bucket") + slug: Annotated[ + str, Field(description="Slug of the deleted endpoint.", title="Slug") ] -class TeamId(RootModel[str]): +class Targets(RootModel[list[EndpointTargetRequest]]): root: Annotated[ - str | None, + list[EndpointTargetRequest] | None, Field( - description="Team ID for a team-scoped key. When omitted, uses the team in the URL if present, otherwise your organization's default team. Must match the URL team when both are provided. Not supported for PERSONAL or WORKSPACE_MANAGE_API_KEYS keys.", + description="The endpoint's upstream targets. Exactly one target is supported at this time.", + examples=[ + [ + { + "environment_name": "staging", + "model_id": "3kZ9xqd", + "provider": "BASETEN", + "target_model": "custom/model-name", + } + ], + [ + { + "provider": "OPENAI", + "secret_id": "3kZ9xqd", + "target_model": "gpt-4o", + } + ], + [ + { + "base_url": "https://my-vllm.example.com", + "provider": "OPENAI_COMPATIBLE", + "secret_id": "3kZ9xqd", + "target_model": "my-model", + } + ], + ], + max_length=1, min_length=1, - title="Team Id", + title="Targets", ), ] = None -class CreateAPIKeyRequest(BaseModel): - name: Annotated[ - str | None, - Field( - description="Optional name for the API key", - examples=["my-api-key"], - title="Name", - ), - ] = None - type: Annotated[ - APIKeyCategory, +class UpdateEndpointRequest(BaseModel): + targets: Annotated[ + Targets | None, Field( - description="Type of the API key.", + description="The endpoint's upstream targets. Exactly one target is supported at this time.", examples=[ - "PERSONAL", - "ROUTES", - "WORKSPACE_MANAGE_API_KEYS", - "WORKSPACE_EXPORT_METRICS", - "WORKSPACE_INVOKE", - "WORKSPACE_MANAGE_ALL", + [ + { + "environment_name": "staging", + "model_id": "3kZ9xqd", + "provider": "BASETEN", + "target_model": "custom/model-name", + } + ], + [ + { + "provider": "OPENAI", + "secret_id": "3kZ9xqd", + "target_model": "gpt-4o", + } + ], + [ + { + "base_url": "https://my-vllm.example.com", + "provider": "OPENAI_COMPATIBLE", + "secret_id": "3kZ9xqd", + "target_model": "my-model", + } + ], ], - ), - ] - model_ids: Annotated[ - list[str] | None, - Field( - description="List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", - examples=[["aaaaaaaa"]], - title="Model Ids", - ), - ] = None - team_id: Annotated[ - TeamId | None, - Field( - description="Team ID for a team-scoped key. When omitted, uses the team in the URL if present, otherwise your organization's default team. Must match the URL team when both are provided. Not supported for PERSONAL or WORKSPACE_MANAGE_API_KEYS keys.", - title="Team Id", + title="Targets", ), ] = None -class APIKey(BaseModel): - api_key: Annotated[str, Field(description="The API key string", title="Api Key")] - - -class APIKeyOwner(BaseModel): - user_id: Annotated[ - str, Field(description="Unique identifier for the user", title="User Id") +class EffectiveRateLimit(BaseModel): + type: Annotated[ + LimitType, + Field(description="The type of the rate limit", examples=["TOKEN", "REQUEST"]), ] - email: Annotated[ - str | None, Field(description="Email address of the user", title="Email") - ] = None - name: Annotated[ - str | None, Field(description="Display name of the user", title="Name") - ] = None - - -class APIKeyTombstone(BaseModel): - prefix: Annotated[ - str, Field(description="Unique prefix of the API key", title="Prefix") + unit: Annotated[ + RateLimitUnit, + Field(description="The unit of the rate limit", examples=["SECOND", "MINUTE"]), ] - - -class LimitType(StrEnum): - REQUEST = "REQUEST" - TOKEN = "TOKEN" - - -class ModelAPIOrgDetails(BaseModel): - added_at: Annotated[ - AwareDatetime, + threshold: Annotated[ + int, Field( - description="When the workspace first added this Model API.", - title="Added At", + description="The threshold for the rate limit", + examples=[1000, 50000], + ge=0, + title="Threshold", ), ] - last_used_at: Annotated[ - AwareDatetime | None, + source_group: Annotated[ + str, Field( - description="When the workspace last invoked this Model API. Null if the workspace has never invoked it.", - title="Last Used At", + description="ID of the group in the hierarchy this limit is anchored to.", + examples=["abc123"], + title="Source Group", ), - ] = None + ] -class CostPerMillionInputTokens(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) +class Name4(RootModel[str]): root: Annotated[ - str, + str | None, Field( - description="Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", - examples=["0.13"], - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Cost Per Million Input Tokens", + description="Optional display name for the group.", + examples=["Acme prod"], + max_length=255, + title="Name", ), - ] + ] = None -class CostPerMillionOutputTokens(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ +class GroupMetadata(BaseModel): + name: Annotated[ + Name4 | None, + Field( + description="Optional display name for the group.", + examples=["Acme prod"], + title="Name", + ), + ] = None + external_entity_id: Annotated[ str, Field( - description="Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", - examples=["0.50"], - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Cost Per Million Output Tokens", + description="External-system identifier for this group. Unique within the caller's org.", + examples=["cust_42"], + max_length=255, + min_length=1, + title="External Entity Id", ), ] -class RateLimitUnit(StrEnum): - SECOND = "SECOND" - MINUTE = "MINUTE" +class LimitEnforcement(StrEnum): + CASCADING = "CASCADING" + INDEPENDENT = "INDEPENDENT" -class RateLimit(BaseModel): +class UsageLimitUnit(StrEnum): + DAY = "DAY" + + +class UsageLimit(BaseModel): type: Annotated[ LimitType, - Field(description="The type of the rate limit", examples=["TOKEN", "REQUEST"]), + Field(description="The type of the usage limit", examples=["REQUEST", "TOKEN"]), ] unit: Annotated[ - RateLimitUnit, - Field(description="The unit of the rate limit", examples=["SECOND", "MINUTE"]), + UsageLimitUnit, + Field(description="The unit of the usage limit", examples=["DAY"]), ] threshold: Annotated[ int, Field( - description="The threshold for the rate limit", - examples=[1000, 50000], + description="The threshold for the usage limit", + examples=[10000000], ge=0, title="Threshold", ), ] -class ModelApisUsageResult(BaseModel): - api_key_prefix: Annotated[ - str | None, +class CreateGroupHierarchy(BaseModel): + limit_enforcement: Annotated[ + LimitEnforcement | None, Field( - description="Prefix of the API key the usage is attributed to. Null when not grouping by api_key or when the request was not authenticated with an API key.", - title="Api Key Prefix", + description="Limit behavior. Child groups inherit their parent's behavior when omitted; root groups default to Independent for backwards compatibility.", + examples=["INDEPENDENT"], ), ] = None - user_id: Annotated[ - str | None, + parent_group_id: Annotated[ + str | None, Field(examples=["abc123"], title="Parent Group Id") + ] = None + + +class UpdateGroupMetadata(BaseModel): + name: Annotated[ + Name4 | None, Field( - description="User the usage is attributed to. Null when not grouping by user or when the credential is not user-scoped.", - title="User Id", + description="Optional display name for the group.", + examples=["Acme prod"], + title="Name", ), ] = None - model: Annotated[ + + +class GatewayKeyInfo(BaseModel): + prefix: Annotated[ + str, Field(description="The prefix of the Model API key.", title="Prefix") + ] + name: Annotated[ + str | None, Field(description="Optional display name.", title="Name") + ] = None + + +class KeysForGroupResponse(BaseModel): + items: Annotated[ + list[GatewayKeyInfo], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class CreateApiKeyForGroupRequest(BaseModel): + name: Annotated[ str | None, Field( - description="Model that served the usage. Null when not grouping by model.", - title="Model", + description="Optional display name for the new key.", + examples=["prod-key-1"], + title="Name", ), ] = None - input_tokens: Annotated[ - int, + + +class CreateApiKeyForGroupResponse(BaseModel): + api_key: Annotated[ + str, Field( - description="Total input tokens, cached and uncached combined.", - title="Input Tokens", + description="Plaintext key string, returned exactly once.", title="Api Key" ), ] - cached_input_tokens: Annotated[ - int, + prefix: Annotated[ + str, Field(description="Key prefix (the part before the dot).", title="Prefix") + ] + name: Annotated[ + str | None, Field(description="Display name of the key.", title="Name") + ] = None + + +class RegisterAPIKeyRequest(BaseModel): + name: Annotated[ + str | None, Field( - description="Input tokens served from the prompt cache.", - title="Cached Input Tokens", + description="Optional name for the Model API key", + examples=["my-model-api-key"], + title="Name", + ), + ] = None + key: Annotated[ + str, + Field( + description="Value of the API key to register", + examples=["my-secure-api-key-value"], + title="Key", ), ] - uncached_input_tokens: Annotated[ + + +class RegisterAPIKeyResponse(BaseModel): + ok: Annotated[ + bool, Field(description="Whether the registration was successful", title="Ok") + ] + + +class ImageBuildLog(BaseModel): + timestamp: AwareDatetime + message: str + severity: Annotated[int, Field(description="Numeric OpenTelemetry severity level.")] + + +class ImageBuildLogsResponse(BaseModel): + logs: list[ImageBuildLog] + total_count: Annotated[ int, Field( - description="Input tokens not served from the prompt cache.", - title="Uncached Input Tokens", + description="Number of matching log entries in the requested time range." ), ] - output_tokens: Annotated[ - int, Field(description="Total output tokens.", title="Output Tokens") - ] - request_count: Annotated[ - int, Field(description="Total number of requests.", title="Request Count") + + +class SandboxDuration(RootModel[str]): + root: Annotated[ + str, + Field( + description="Duration using seconds, minutes, hours, or composite durations such as 1h30m. Whole days and weeks are also supported, for example 7d or 2w.", + examples=["24h"], + pattern="^[+-]?(0|[0-9]+[dw]|([0-9]+(\\.[0-9]*)?|\\.[0-9]+)(ns|us|µs|μs|ms|s|m|h)(([0-9]+(\\.[0-9]*)?|\\.[0-9]+)(ns|us|µs|μs|ms|s|m|h))*)$", + ), ] -class UsageDimension(StrEnum): - api_key = "api_key" - user = "user" - model = "model" +class Action(StrEnum): + DELETE = "DELETE" -class CreateLLMModelRequest(BaseModel): - resources: Annotated[ - dict[str, Any], - Field(description="Resources allocated to the model", title="Resources"), - ] - region: Annotated[ - str | None, - Field(description="Region in which to deploy the model", title="Region"), - ] = None - llm_version: Annotated[ - str | None, - Field(description="Version of the helm chart to use.", title="Llm Version"), - ] = None - llm_config: Annotated[ - dict[str, Any] | None, +class Type(StrEnum): + TTL_IDLE = "TTL_IDLE" + + +class SandboxTTLIdleExpirationPolicy(BaseModel): + action: Action + type: Literal["TTL_IDLE"] + value: SandboxDuration + + +class Type1(StrEnum): + TTL_MAX_AGE = "TTL_MAX_AGE" + + +class SandboxTTLMaxAgeExpirationPolicy(BaseModel): + action: Action + type: Literal["TTL_MAX_AGE"] + value: SandboxDuration + + +class Type2(StrEnum): + DATE = "DATE" + + +class SandboxDateExpirationPolicy(BaseModel): + action: Action + type: Literal["DATE"] + value: Annotated[AwareDatetime, Field(examples=["2026-09-23T21:26:58Z"])] + + +class SandboxProxyTarget(BaseModel): + body: Annotated[ + dict[str, str] | None, Field( - description="Configuration specific to the LLM model", title="Llm Config" + description="Body fields to inject into matching requests. Values may contain {{SECRET:name}} references resolved from this rule's secrets.", + examples=[{"user": "baseten-api-review-0916"}], ), ] = None - environment_variables: Annotated[ - dict[str, Any] | None, + destinations: Annotated[ + list[str] | None, Field( - description="Environment variables for the model", - title="Environment Variables", + description='Destination domains this rule applies to. Use ["*"] for a global rule that matches all destinations.', + examples=[["api.openai.com"]], ), ] = None - model_metadata: Annotated[ - dict[str, Any] | None, + headers: Annotated[ + dict[str, str] | None, Field( - description="Model metadata persisted into model_config", - title="Model Metadata", + description="Headers to inject into matching requests. Values may contain {{SECRET:name}} references resolved from this rule's secrets.", + examples=[{"Authorization": "Bearer {{SECRET:openai-key}}"}], ), ] = None - autoscaling_settings: Annotated[ - UpdateAutoscalingSettings | None, + secrets: Annotated[ + dict[str, str] | None, Field( - description="Autoscaling settings for the model", - examples=[ - { - "autoscaling_window": 600, - "concurrency_target": None, - "max_replica": 5, - "max_scale_down_rate": None, - "min_replica": 1, - "scale_down_delay": 300, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - } - ], + description="Named secret values for this routing rule, referenced in headers/body via {{SECRET:name}}. Stored encrypted at rest. Write-only: never returned in API responses.", + examples=[{"openai-key": "sk-proj-demo-not-a-valid-api-key"}], ), ] = None - additional_autoscaling_config: Annotated[ - dict[str, Any] | None, + + +class SandboxEnv(BaseModel): + name: Annotated[ + str | None, + Field(description="Name of the environment variable", examples=["NODE_ENV"]), + ] = None + secret: Annotated[ + bool, Field( - description="Additional autoscaling configuration (e.g. target in-flight tokens)", - examples=[{"metrics": [{"name": "in_flight_tokens", "target": 40000}]}], - title="Additional Autoscaling Config", + description='Whether the value is a secret. Defaults to true; secret values are returned as "****". Set false explicitly to return the original value.', + examples=[False], ), + ] = True + value: Annotated[ + str | None, + Field(description="Value of the environment variable", examples=["production"]), ] = None - metadata: Annotated[ - dict[str, Any] | None, + + +class Protocol(StrEnum): + HTTP = "HTTP" + TCP = "TCP" + UDP = "UDP" + TLS = "TLS" + + +class SandboxPort(BaseModel): + name: Annotated[ + str | None, Field(description="The name of the port", examples=["http"]) + ] = None + protocol: Annotated[ + Protocol | None, + Field(description="The protocol of the port", examples=["HTTP"]), + ] = None + target: Annotated[ + int, Field( - description="User-defined metadata for the deployment", - examples=[{"environment": "production", "git_sha": "abc123"}], - title="Metadata", + description="The target port of the port", examples=[3000], ge=1, le=65535 ), - ] = None - weights: Annotated[ - list[dict[str, Any]] | None, + ] + + +class SandboxMetadataLabels(RootModel[dict[str, str]]): + root: dict[str, str] + + +class SandboxStatus(StrEnum): + DEPLOYING = "DEPLOYING" + DEPLOYED = "DEPLOYED" + FAILED = "FAILED" + DEACTIVATING = "DEACTIVATING" + DEACTIVATED = "DEACTIVATED" + DELETING = "DELETING" + TERMINATED = "TERMINATED" + ARCHIVING = "ARCHIVING" + ARCHIVED = "ARCHIVED" + UNARCHIVING = "UNARCHIVING" + BUILDING = "BUILDING" + UPLOADING = "UPLOADING" + + +class SandboxApiPagination(BaseModel): + has_more: Annotated[ + bool, Field(description="Whether another page is available.", examples=[True]) + ] + cursor: Annotated[ + str | None, Field( - description="Weight configurations for BDN model weight distribution", + description="Opaque cursor to pass to the next list request. Keep the same filters.", examples=[ - [ - { - "mount_location": "/models/base", - "source": "hf://meta-llama/Llama-3-8B", - } - ] + "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" ], - title="Weights", + min_length=1, ), ] = None - name: Annotated[str, Field(description="Name of the model", title="Name")] -class LLMModelHandle(BaseModel): - model_id: Annotated[ - str, Field(description="Unique identifier of the model", title="Model Id") - ] - version_id: Annotated[ - str, - Field(description="Unique identifier of the model version", title="Version Id"), - ] - hostname: Annotated[ - str, Field(description="Hostname used to invoke the model", title="Hostname") - ] - instance_type_name: Annotated[ - str | None, +class ImageStatus(StrEnum): + UPLOADING = "UPLOADING" + BUILDING = "BUILDING" + BUILT = "BUILT" + FAILED = "FAILED" + + +class ImageTag(BaseModel): + name: Annotated[str, Field(description="Image tag name.", examples=["latest"])] + created_at: Annotated[ + AwareDatetime | None, + Field( + description="Time the tag was created.", examples=["2026-09-16T21:20:00Z"] + ), + ] = None + updated_at: Annotated[ + AwareDatetime | None, Field( - description="Name of the instance type the model deployment is running on", - title="Instance Type Name", + description="Time the tag was last updated.", + examples=["2026-09-16T21:25:00Z"], ), ] = None + size: Annotated[ + int | None, + Field(description="Image size in bytes.", examples=[134217728], ge=0), + ] = None -class CreateLLMModelVersionRequest(BaseModel): - resources: Annotated[ - dict[str, Any], - Field(description="Resources allocated to the model", title="Resources"), +class Image(BaseModel): + name: Annotated[ + str, + Field( + description="Stable repository name supplied when pushing the image.", + examples=["base-image"], + ), ] - region: Annotated[ - str | None, - Field(description="Region in which to deploy the model", title="Region"), - ] = None - llm_version: Annotated[ - str | None, - Field(description="Version of the helm chart to use.", title="Llm Version"), - ] = None - llm_config: Annotated[ - dict[str, Any] | None, + status: Annotated[ + ImageStatus, Field( - description="Configuration specific to the LLM model", title="Llm Config" + description="Image processing status. Only BUILT images are ready to use.", + examples=["BUILT"], ), - ] = None - environment_variables: Annotated[ - dict[str, Any] | None, + ] + created_at: Annotated[ + AwareDatetime | None, Field( - description="Environment variables for the model", - title="Environment Variables", + description="Time the image was created.", examples=["2026-09-15T21:20:00Z"] ), ] = None - model_metadata: Annotated[ - dict[str, Any] | None, + updated_at: Annotated[ + AwareDatetime | None, Field( - description="Model metadata persisted into model_config", - title="Model Metadata", + description="Time the image was last updated.", + examples=["2026-09-16T21:25:00Z"], ), ] = None - autoscaling_settings: Annotated[ - UpdateAutoscalingSettings | None, + last_deployed_at: Annotated[ + AwareDatetime | None, Field( - description="Autoscaling settings for the model", - examples=[ - { - "autoscaling_window": 600, - "concurrency_target": None, - "max_replica": 5, - "max_scale_down_rate": None, - "min_replica": 1, - "scale_down_delay": 300, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - } - ], + description="Most recent deployment time across all tags, if deployed.", + examples=["2026-09-16T21:26:58.545765901Z"], ), ] = None - additional_autoscaling_config: Annotated[ - dict[str, Any] | None, + size: Annotated[ + int | None, Field( - description="Additional autoscaling configuration (e.g. target in-flight tokens)", - examples=[{"metrics": [{"name": "in_flight_tokens", "target": 40000}]}], - title="Additional Autoscaling Config", + description="Total repository size in bytes.", examples=[260046848], ge=0 ), ] = None - metadata: Annotated[ - dict[str, Any] | None, + tag_count: Annotated[ + int | None, Field( - description="User-defined metadata for the deployment", - examples=[{"environment": "production", "git_sha": "abc123"}], - title="Metadata", + description="Number of image versions in the repository.", + examples=[2], + ge=0, ), ] = None - weights: Annotated[ - list[dict[str, Any]] | None, + tags: Annotated[ + list[ImageTag], Field( - description="Weight configurations for BDN model weight distribution", + description="Empty for list and get summary responses. Use GET /sandboxes/images/{image_name}/tags to retrieve paginated image versions.", examples=[ [ { - "mount_location": "/models/base", - "source": "hf://meta-llama/Llama-3-8B", - } + "name": "latest", + "created_at": "2026-09-16T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "size": 134217728, + }, + { + "name": "20260915212000", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-15T21:25:00Z", + "size": 125829120, + }, ] ], - title="Weights", ), - ] = None - - -class LibraryListingMetadata(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - parameter_count: Annotated[int | None, Field(title="Parameter Count")] = None - context_length: Annotated[int | None, Field(title="Context Length")] = None - input_modalities: Annotated[ - list[LibraryListingModality], Field(title="Input Modalities") - ] = [LibraryListingModality.text] - output_modalities: Annotated[ - list[LibraryListingModality], Field(title="Output Modalities") - ] = [LibraryListingModality.text] - license: Annotated[str, Field(title="License")] - variant: Annotated[str | None, Field(title="Variant")] = None - publisher: Annotated[str | None, Field(title="Publisher")] = None - model_api_slug: Annotated[str | None, Field(title="Model Api Slug")] = None - release_date: Annotated[date_aliased | None, Field(title="Release Date")] = None - description: Annotated[str | None, Field(title="Description")] = None - trending: Annotated[bool, Field(title="Trending")] = False + ] -class LibraryListing(BaseModel): - display_name: Annotated[ - str, - Field(description="Display name of the library listing", title="Display Name"), - ] - user_defined_id: Annotated[ +class PushImageRequest(BaseModel): + name: Annotated[ str, Field( - description="User-defined identifier of the library listing", - title="User Defined Id", + description="Target image repository name. Reusing a name pushes a new version to the existing repository.", + examples=["base-image"], + min_length=1, ), ] - is_public: Annotated[ - bool, + image: Annotated[ + str | None, Field( - description="Whether the listing is publicly accessible", title="Is Public" + description="Optional source registry image reference including a registry hostname. When omitted, the response provides an archive upload URL. The uploaded ZIP archive must not exceed 5 GB.", + examples=["docker.io/b10/base-image:latest"], ), - ] - trending: Annotated[ - bool | None, - Field(description="Whether the listing is trending", title="Trending"), - ] - closed_source: Annotated[ - bool, + ] = None + docker_config: Annotated[ + str | None, Field( - description="Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", - title="Closed Source", + description="Optional serialized registry authentication configuration for importing a private image. Used only when image is supplied; never returned.", + examples=[ + '{"auths":{"https://index.docker.io/v1/":{"auth":"YjEwLXJldmlldzpkZW1vLW5vdC1hLXZhbGlkLXJlZ2lzdHJ5LXRva2Vu"}}}' + ], ), + ] = None + + +class PushImageResponse(BaseModel): + name: Annotated[ + str, Field(description="Target image repository name.", examples=["base-image"]) ] - created_at: Annotated[ - AwareDatetime, + status: Annotated[ + ImageStatus, Field( - description="Time the listing was created in ISO 8601 format", - title="Created At", + description="Image processing status. Only BUILT images are ready to use.", + examples=["BUILDING"], ), ] - modified_at: Annotated[ - AwareDatetime, - Field(description="Time the listing was last modified", title="Modified At"), - ] - metadata: Annotated[ - LibraryListingMetadata | None, + upload_url: Annotated[ + AnyUrl | None, Field( - description="Model-level metadata for this listing, if it has been uploaded." + description="Temporary signed URL for uploading the source ZIP archive with HTTP PUT. Present only when no source image was supplied. The uploaded ZIP archive must not exceed 5 GB. Uploading starts asynchronous processing. This storage upload is separate from the API endpoints.", + examples=[ + "https://uploads.b10.run/images/base-image/20260916212658/source.zip?expires=2026-09-16T22%3A26%3A58Z&signature=demo-not-a-valid-upload-signature" + ], + ), + ] = None + image: Annotated[ + str | None, + Field( + description="Registered image reference including its tag, when available. Tags are assigned by the service; GET /sandboxes/images/{image_name} returns the available tags once processing completes.", + examples=["b10/base-image:latest"], ), ] = None -class LibraryListings(BaseModel): - listings: Annotated[list[LibraryListing], Field(title="Listings")] - - -class CreateLibraryListingRequest(BaseModel): - display_name: Annotated[ +class SandboxLibraryImageVolume(BaseModel): + name: Annotated[ str, - Field(description="Display name of the library listing", title="Display Name"), + Field( + description="Volume name, or an internal identifier for ephemeral volumes.", + examples=["scratch"], + ), ] - user_defined_id: Annotated[ + mount_path: Annotated[ str, Field( - description="User-defined identifier of the library listing", - title="User Defined Id", + description="Absolute filesystem path where the volume is mounted.", + examples=["/mnt/data"], ), ] - is_public: Annotated[ - bool, + type: Annotated[ + str | None, Field( - description="Whether the listing is publicly accessible", title="Is Public" + description="Volume type, persistent when empty.", examples=["ephemeral"] ), - ] = False - closed_source: Annotated[ - bool, + ] = None + size_mb: Annotated[ + int | None, Field( - description="Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", - title="Closed Source", + description="Storage capacity in megabytes for ephemeral volumes.", + examples=[10240], ), - ] = False + ] = None + read_only: Annotated[ + bool | None, + Field(description="Whether the volume is mounted read-only.", examples=[False]), + ] = None -class LibraryListingTombstone(BaseModel): - user_defined_id: Annotated[ +class SandboxLibraryImageCreationOptions(BaseModel): + extra_args: Annotated[ + dict[str, str] | None, Field(description="Kernel selection arguments.") + ] = None + volumes: Annotated[ + list[SandboxLibraryImageVolume] | None, Field(description="Volume attachments.") + ] = None + + +class CleanupImagesResponse(BaseModel): + deleted: Annotated[ + int, Field(description="Number of image versions removed.", examples=[3], ge=0) + ] + message: Annotated[ str, Field( - description="User-defined identifier of the library listing", - title="User Defined Id", + description="Human-readable cleanup result.", + examples=[ + "Removed 3 unused image versions. Image versions used by active sandboxes were retained." + ], ), ] - deleted: Annotated[ - bool, - Field(description="Whether the library listing was deleted", title="Deleted"), + + +class Checkpoints( + RootModel[ + BasetenLatestCheckpointConfig + | BasetenNamedCheckpointConfig + | LoopsCheckpointConfig + ] +): + root: Annotated[ + BasetenLatestCheckpointConfig + | BasetenNamedCheckpointConfig + | LoopsCheckpointConfig, + Field(discriminator="typ"), ] -class UpdateLibraryListingRequest(BaseModel): - display_name: Annotated[ +class LoadCheckpointConfig(BaseModel): + enabled: Annotated[ + bool, + Field(description="Whether checkpoint loading is enabled", title="Enabled"), + ] = False + download_folder: Annotated[ + str, + Field( + description="Folder where checkpoints will be downloaded", + title="Download Folder", + ), + ] = "/tmp/loaded_checkpoints" + checkpoints: Annotated[ + list[Checkpoints] | None, + Field(description="List of checkpoint configurations", title="Checkpoints"), + ] = None + + +class GetAuditLogsParams(BaseModel): + cursor: Annotated[ + str | None, + Field( + description="Opaque cursor returned by a previous page. Omit to fetch the first page.", + title="Cursor", + ), + ] = None + limit: Annotated[ + int, + Field( + description="Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", + ge=1, + le=200, + title="Limit", + ), + ] = 20 + direction: Annotated[ + AuditLogSortDirection, + Field( + description="Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." + ), + ] = AuditLogSortDirection.DESC + search: Annotated[ str | None, Field( - description="New display name for the library listing", title="Display Name" + description="Case-insensitive substring matched against resource names and IDs in the entry.", + title="Search", ), ] = None - is_public: Annotated[ - bool | None, + event_type_groups: Annotated[ + list[AuditLogEventTypeGroup] | None, Field( - description="Whether the listing is publicly accessible", title="Is Public" + description="When set, returns only entries whose event type falls in one of these groups.", + title="Event Type Groups", ), ] = None - trending: Annotated[ - bool | None, - Field(description="Whether the listing is trending", title="Trending"), - ] = None - metadata: Annotated[ - LibraryListingMetadata | None, + user_ids: Annotated[ + list[str] | None, Field( - description="Model-level metadata for the listing. When provided, replaces the stored metadata. Unknown fields are rejected." + description="When set, returns only entries whose acting user is one of these IDs.", + title="User Ids", ), ] = None - - -class EmbeddingBenchmarkMetrics(BaseModel): - e2e_latency_ms_p50: Annotated[float | None, Field(title="E2E Latency Ms P50")] = ( - None - ) - e2e_latency_ms_p99: Annotated[float | None, Field(title="E2E Latency Ms P99")] = ( - None - ) - input_tokens_per_sec: Annotated[ - float | None, Field(title="Input Tokens Per Sec") - ] = None - requests_per_sec: Annotated[float | None, Field(title="Requests Per Sec")] = None - - -class LLMBenchmarkMetrics(BaseModel): - ttft_ms_p50: Annotated[float | None, Field(title="Ttft Ms P50")] = None - output_tokens_per_sec_per_user_p50: Annotated[ - float | None, Field(title="Output Tokens Per Sec Per User P50") - ] = None - max_concurrent_users_at_50ms_tpot: Annotated[ - int | None, Field(title="Max Concurrent Users At 50Ms Tpot") + deployment_ids: Annotated[ + list[str] | None, + Field( + description="When set, returns only entries referencing one of these model deployment IDs.", + title="Deployment Ids", + ), ] = None - requests_per_sec_p50: Annotated[ - float | None, Field(title="Requests Per Sec P50") + chain_deployment_ids: Annotated[ + list[str] | None, + Field( + description="When set, returns only entries referencing one of these chain deployment IDs.", + title="Chain Deployment Ids", + ), ] = None - cost_per_1m_tokens_usd: Annotated[ - float | None, Field(title="Cost Per 1M Tokens Usd") + environment_names: Annotated[ + list[str] | None, + Field( + description="When set, returns only entries for one of these environments.", + title="Environment Names", + ), ] = None - - -class TTSBenchmarkMetrics(BaseModel): - ttft_ms_p50: Annotated[float | None, Field(title="Ttft Ms P50")] = None - max_concurrent_streams_at_rtf1: Annotated[ - int | None, Field(title="Max Concurrent Streams At Rtf1") + sources: Annotated[ + list[AuditLogSource] | None, + Field( + description="When set, returns only entries issued from one of these surfaces.", + title="Sources", + ), ] = None - ttft_ms_p50_at_max_concurrency: Annotated[ - float | None, Field(title="Ttft Ms P50 At Max Concurrency") + start_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", + title="Start Epoch Millis", + ), ] = None - cost_per_audio_minute_usd: Annotated[ - float | None, Field(title="Cost Per Audio Minute Usd") + end_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds for the end of the window. Defaults to the current time.", + title="End Epoch Millis", + ), ] = None -class CreateLibraryListingVersionRequest(BaseModel): - display_name: Annotated[ +class GetModelsAuditLogsParams(BaseModel): + cursor: Annotated[ str | None, Field( - description="Display name of the library listing. Required when creating a new listing.", - title="Display Name", + description="Opaque cursor returned by a previous page. Omit to fetch the first page.", + title="Cursor", ), ] = None - is_public: Annotated[ - bool, + limit: Annotated[ + int, Field( - description="Whether the listing is publicly accessible. Only used when creating a new listing.", - title="Is Public", + description="Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", + ge=1, + le=200, + title="Limit", ), - ] = False - oracle_version_id: Annotated[ - str, + ] = 20 + direction: Annotated[ + AuditLogSortDirection, Field( - description="Id of the source model version to publish", - title="Oracle Version Id", + description="Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." ), - ] - allow_truss_download: Annotated[ - bool, + ] = AuditLogSortDirection.DESC + search: Annotated[ + str | None, Field( - description="Whether users deploying this model can download the Truss", - title="Allow Truss Download", + description="Case-insensitive substring matched against resource names and IDs in the entry.", + title="Search", ), - ] = False - closed_source: Annotated[ - bool, + ] = None + event_type_groups: Annotated[ + list[AuditLogEventTypeGroup] | None, Field( - description="Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream). Only used when creating a new listing.", - title="Closed Source", + description="When set, returns only entries whose event type falls in one of these groups.", + title="Event Type Groups", ), - ] = False - version_tag: Annotated[ - str, - Field(description="Human-readable tag for this version", title="Version Tag"), - ] - - -class LibraryListingVersionTombstone(BaseModel): - version_tag: Annotated[ - str, - Field(description="Human-readable tag for this version", title="Version Tag"), - ] - deleted: Annotated[ - bool, + ] = None + user_ids: Annotated[ + list[str] | None, Field( - description="Whether the library listing version was deleted", - title="Deleted", + description="When set, returns only entries whose acting user is one of these IDs.", + title="User Ids", ), - ] - - -class ModelApisCostResult(BaseModel): - api_key_prefixes: Annotated[ + ] = None + deployment_ids: Annotated[ list[str] | None, Field( - description="The single attributed API key prefix for this result. Null when not grouping by api_key_prefix or when attribution is unavailable.", - title="Api Key Prefixes", + description="When set, returns only entries referencing one of these model deployment IDs.", + title="Deployment Ids", ), ] = None - user_id: Annotated[ - str | None, + chain_deployment_ids: Annotated[ + list[str] | None, Field( - description="Attributed user ID. Null when not grouping by user or when attribution is unavailable.", - title="User Id", + description="When set, returns only entries referencing one of these chain deployment IDs.", + title="Chain Deployment Ids", ), ] = None - model: Annotated[ - str | None, + environment_names: Annotated[ + list[str] | None, Field( - description="Model identifier. Null when not grouping by model.", - title="Model", + description="When set, returns only entries for one of these environments.", + title="Environment Names", ), ] = None - service_tier: Annotated[ - str | None, + sources: Annotated[ + list[AuditLogSource] | None, Field( - description="Service tier. Null when not grouping by service_tier or when attribution is unavailable.", - title="Service Tier", + description="When set, returns only entries issued from one of these surfaces.", + title="Sources", ), ] = None - subtotal: Annotated[ - str, + start_epoch_millis: Annotated[ + int | None, Field( - description="Model API cost in USD for this day and grouping combination, returned as an exact decimal string preserving fractional-cent amounts. This amount may differ from finalized invoice amounts.", - examples=["0.00000123"], - title="Subtotal", + description="Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", + title="Start Epoch Millis", ), - ] - - -class ModelApiCostDimension(StrEnum): - api_key_prefix = "api_key_prefix" - user = "user" - model = "model" - service_tier = "service_tier" - - -class ChainMetadata(BaseModel): - chain_id: Annotated[ - str, Field(description="Unique identifier of the chain", title="Chain Id") - ] - chain_name: Annotated[ - str | None, Field(description="Name of the chain", title="Chain Name") ] = None - chain_deployment_id: Annotated[ - str, + end_epoch_millis: Annotated[ + int | None, Field( - description="Unique identifier of the chain deployment", - title="Chain Deployment Id", + description="Epoch milliseconds for the end of the window. Defaults to the current time.", + title="End Epoch Millis", ), - ] + ] = None -class Subtotal(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", +class GetModelsDeploymentsLogsParams(BaseModel): + start_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + title="Start Epoch Millis", + ), + ] = None + end_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + title="End Epoch Millis", + ), + ] = None + direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( + None ) - root: Annotated[ - str, + limit: Annotated[ + Limit | None, Field( - description="Subtotal cost incurred on this date in dollars", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Subtotal", + description="Limit of logs to fetch in a single request", + title="Limit", + validate_default=True, ), - ] - - -class ComputeCost(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = Limit.model_validate(500) + min_level: Annotated[ + LogLevel | None, Field( - description="Compute cost incurred on this date in dollars", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Compute Cost", + description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." ), - ] - - -class SurchargeCost(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = None + replica: Annotated[ + Replica | None, Field( - description="Model distribution surcharge incurred on this date in dollars", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Surcharge Cost", + description="Only return logs emitted by this replica (5-char short ID).", + title="Replica", ), - ] - - -class DailyDedicatedUsage(BaseModel): - date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] - subtotal: Annotated[ - float | Subtotal, + ] = None + request_id: Annotated[ + RequestId | None, Field( - description="Subtotal cost incurred on this date in dollars", - title="Subtotal", + description="Only return logs tagged with this inference request ID.", + title="Request Id", ), - ] - compute_cost: Annotated[ - float | ComputeCost, + ] = None + component: Annotated[ + Component | None, + Field(description="Only return logs from this component.", title="Component"), + ] = None + search_pattern: Annotated[ + SearchPattern | None, Field( - description="Compute cost incurred on this date in dollars", - title="Compute Cost", + description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", + title="Search Pattern", ), - ] - surcharge_cost: Annotated[ - float | SurchargeCost, + ] = None + includes: Annotated[ + list[str] | None, Field( - description="Model distribution surcharge incurred on this date in dollars", - title="Surcharge Cost", + description="Case-sensitive substrings that must all appear in the log message.", + max_length=8, + title="Includes", ), - ] - minutes: Annotated[ - int, Field(description="Minutes used on this date", title="Minutes") - ] - inference_requests: Annotated[ - int, + ] = None + excludes: Annotated[ + list[str] | None, Field( - description="Number of inference requests on this date", - title="Inference Requests", + description="Case-sensitive substrings; lines containing any of these are dropped.", + max_length=8, + title="Excludes", ), - ] + ] = None -class DailyModelApiUsage(BaseModel): - date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] - subtotal: Annotated[ - float | Subtotal, +class GetModelsDeploymentsMetricsParams(BaseModel): + mode: Annotated[ + ModelMetricMode, Field( - description="Subtotal cost incurred on this date in dollars", - title="Subtotal", + description="'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." ), - ] - input_tokens: Annotated[ - int, - Field(description="Number of input tokens on this date", title="Input Tokens"), - ] - output_tokens: Annotated[ - int, + ] = ModelMetricMode.CURRENT + start_epoch_millis: Annotated[ + int | None, Field( - description="Number of output tokens on this date", title="Output Tokens" + description="Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", + title="Start Epoch Millis", ), - ] - cached_input_tokens: Annotated[ - int, + ] = None + end_epoch_millis: Annotated[ + int | None, Field( - description="Number of cached input tokens on this date", - title="Cached Input Tokens", + description="Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", + title="End Epoch Millis", ), - ] - - -class DailyTrainingUsage(BaseModel): - date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] - subtotal: Annotated[ - float | Subtotal, + ] = None + metrics: Annotated[ + list[str] | None, Field( - description="Subtotal cost incurred on this date in dollars", - title="Subtotal", + description="Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", + title="Metrics", ), - ] - minutes: Annotated[ - int, Field(description="Minutes used on this date", title="Minutes") - ] + ] = None -class Subtotal3(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, +class GetModelsEnvironmentsLogsParams(BaseModel): + start_epoch_millis: Annotated[ + int | None, Field( - description="Subtotal cost in dollars for this billable resource", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Subtotal", + description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + title="Start Epoch Millis", ), - ] - - -class ComputeCost1(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = None + end_epoch_millis: Annotated[ + int | None, Field( - description="Compute cost in dollars for this billable resource", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Compute Cost", + description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + title="End Epoch Millis", ), - ] - - -class SurchargeCost1(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", + ] = None + direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( + None ) - root: Annotated[ - str, + limit: Annotated[ + Limit | None, Field( - description="Model distribution surcharge in dollars for this billable resource", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Surcharge Cost", + description="Limit of logs to fetch in a single request", + title="Limit", + validate_default=True, ), - ] - - -class Subtotal4(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = Limit.model_validate(500) + min_level: Annotated[ + LogLevel | None, Field( - description="Subtotal cost in dollars after applying credits used", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Subtotal", + description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." ), - ] - - -class CreditsUsed(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = None + replica: Annotated[ + Replica | None, Field( - description="Credits applied in dollars", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Credits Used", + description="Only return logs emitted by this replica (5-char short ID).", + title="Replica", ), - ] - - -class Total(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = None + request_id: Annotated[ + RequestId | None, Field( - description="Total cost in dollars", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Total", + description="Only return logs tagged with this inference request ID.", + title="Request Id", + ), + ] = None + component: Annotated[ + Component | None, + Field(description="Only return logs from this component.", title="Component"), + ] = None + search_pattern: Annotated[ + SearchPattern | None, + Field( + description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", + title="Search Pattern", ), - ] - - -class Subtotal5(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = None + includes: Annotated[ + list[str] | None, Field( - description="Subtotal cost in dollars for this model", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Subtotal", + description="Case-sensitive substrings that must all appear in the log message.", + max_length=8, + title="Includes", ), - ] - - -class ModelApiItem(BaseModel): - model_name: Annotated[str, Field(description="Model name", title="Model Name")] - model_family: Annotated[ - str | None, - Field(description="Model family (e.g., llama, mistral)", title="Model Family"), ] = None - subtotal: Annotated[ - float | Subtotal5, - Field(description="Subtotal cost in dollars for this model", title="Subtotal"), - ] - input_tokens: Annotated[ - int, - Field(description="Total input tokens for this model", title="Input Tokens"), - ] - output_tokens: Annotated[ - int, - Field(description="Total output tokens for this model", title="Output Tokens"), - ] - cached_input_tokens: Annotated[ - int, + excludes: Annotated[ + list[str] | None, Field( - description="Total cached input tokens for this model", - title="Cached Input Tokens", + description="Case-sensitive substrings; lines containing any of these are dropped.", + max_length=8, + title="Excludes", ), - ] - daily: Annotated[ - list[DailyModelApiUsage] | None, - Field(description="Daily usage breakdown", title="Daily"), ] = None -class Subtotal6(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, +class GetModelsEnvironmentsMetricsParams(BaseModel): + mode: Annotated[ + ModelMetricMode, Field( - description="Subtotal cost in dollars after applying credits used", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Subtotal", + description="'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." ), - ] - - -class ModelApisUsage(BaseModel): - subtotal: Annotated[ - float | Subtotal6, + ] = ModelMetricMode.CURRENT + start_epoch_millis: Annotated[ + int | None, Field( - description="Subtotal cost in dollars after applying credits used", - title="Subtotal", + description="Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", + title="Start Epoch Millis", ), - ] - credits_used: Annotated[ - float | CreditsUsed, - Field(description="Credits applied in dollars", title="Credits Used"), - ] - total: Annotated[ - float | Total, Field(description="Total cost in dollars", title="Total") - ] - breakdown: Annotated[ - list[ModelApiItem] | None, - Field(description="Per-model usage breakdown", title="Breakdown"), ] = None - - -class Subtotal7(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + end_epoch_millis: Annotated[ + int | None, Field( - description="Subtotal cost in dollars for this billable resource", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Subtotal", + description="Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", + title="End Epoch Millis", ), - ] - - -class Subtotal8(RootModel[str]): - model_config = ConfigDict( - regex_engine="python-re", - ) - root: Annotated[ - str, + ] = None + metrics: Annotated[ + list[str] | None, Field( - description="Subtotal cost in dollars after applying credits used", - pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - title="Subtotal", + description="Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", + title="Metrics", ), - ] + ] = None -class UserInfo(BaseModel): - user_id: Annotated[ - str, Field(description="Unique identifier for the user", title="User Id") - ] - email: Annotated[ - str | None, Field(description="Email address of the user", title="Email") - ] = None - name: Annotated[ - str | None, Field(description="Display name of the user", title="Name") - ] = None - workspace_name: Annotated[ +class GetChainsAuditLogsParams(BaseModel): + cursor: Annotated[ str | None, - Field(description="Name of the user's workspace", title="Workspace Name"), + Field( + description="Opaque cursor returned by a previous page. Omit to fetch the first page.", + title="Cursor", + ), ] = None - - -class UsersResponse(BaseModel): - items: Annotated[ - list[UserInfo], Field(description="Items in this page.", title="Items") - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] - - -class AwsAssumeRole(BaseModel): - baseten_role_arn: Annotated[ - str, + limit: Annotated[ + int, Field( - description="Baseten role ARN to allow in an IAM role's trust policy", - title="Baseten Role Arn", + description="Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", + ge=1, + le=200, + title="Limit", ), - ] - external_id: Annotated[ - str, + ] = 20 + direction: Annotated[ + AuditLogSortDirection, Field( - description="sts:ExternalId Baseten presents when assuming the role", - title="External Id", + description="Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." ), - ] - - -class OrganizationInfo(BaseModel): - org_id: Annotated[ - str, Field(description="Unique identifier for the organization", title="Org Id") - ] - name: Annotated[ - str | None, Field(description="Display name of the organization", title="Name") - ] = None - created_at: Annotated[ - AwareDatetime, + ] = AuditLogSortDirection.DESC + search: Annotated[ + str | None, Field( - description="Time the organization was created in ISO 8601 format", - title="Created At", + description="Case-insensitive substring matched against resource names and IDs in the entry.", + title="Search", ), - ] - aws_assume_role: Annotated[ - AwsAssumeRole | None, + ] = None + event_type_groups: Annotated[ + list[AuditLogEventTypeGroup] | None, Field( - description="AWS AssumeRole trust-policy inputs; null while the method is not enabled for the organization" + description="When set, returns only entries whose event type falls in one of these groups.", + title="Event Type Groups", ), ] = None - - -class GatewayEventTokens(BaseModel): - inputTokens: Annotated[ - int, Field(description="Cached and uncached input tokens.", title="Inputtokens") - ] - outputTokens: Annotated[ - int, Field(description="Output tokens.", title="Outputtokens") - ] - cachedInputTokens: Annotated[ - int, Field(description="Cached input tokens.", title="Cachedinputtokens") - ] - - -class GatewayEvent(BaseModel): - type: Annotated[str, Field(description="Event type.", title="Type")] = ( - "API_BILLING_USAGE" - ) - idempotencyKey: Annotated[ - str, Field(description="Deduplication key.", title="Idempotencykey") - ] - timestamp: Annotated[ - str, Field(description="Billing event time (ISO 8601, UTC).", title="Timestamp") - ] - requestId: Annotated[ - str, Field(description="Inference request ID.", title="Requestid") - ] - modelSlug: Annotated[str, Field(description="Served model.", title="Modelslug")] - externalEntityId: Annotated[ - str, Field(description="Calling group's external ID.", title="Externalentityid") - ] - apiKeyPrefix: Annotated[ - str, Field(description="API key prefix.", title="Apikeyprefix") - ] - tokens: GatewayEventTokens - - -class GatewayEventsResponse(BaseModel): - items: Annotated[ - list[GatewayEvent], Field(description="Items in this page.", title="Items") - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] - - -class SharedEndpointRegion(StrEnum): - UNRESTRICTED = "UNRESTRICTED" - EU = "EU" - - -class VertexTargetConfig(BaseModel): - project_id: Annotated[ - str, + user_ids: Annotated[ + list[str] | None, + Field( + description="When set, returns only entries whose acting user is one of these IDs.", + title="User Ids", + ), + ] = None + deployment_ids: Annotated[ + list[str] | None, Field( - description="Google Cloud project ID or project number.", - examples=["my-gcp-project", "464036093014"], - title="Project Id", + description="When set, returns only entries referencing one of these model deployment IDs.", + title="Deployment Ids", ), - ] - location: Annotated[ - str, + ] = None + chain_deployment_ids: Annotated[ + list[str] | None, Field( - description="Google Cloud location.", examples=["global"], title="Location" + description="When set, returns only entries referencing one of these chain deployment IDs.", + title="Chain Deployment Ids", ), - ] + ] = None + environment_names: Annotated[ + list[str] | None, + Field( + description="When set, returns only entries for one of these environments.", + title="Environment Names", + ), + ] = None + sources: Annotated[ + list[AuditLogSource] | None, + Field( + description="When set, returns only entries issued from one of these surfaces.", + title="Sources", + ), + ] = None + start_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", + title="Start Epoch Millis", + ), + ] = None + end_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch milliseconds for the end of the window. Defaults to the current time.", + title="End Epoch Millis", + ), + ] = None -class EndpointTargetRequest(BaseModel): - provider: Annotated[ - GatewayProvider, +class GetChainsDeploymentsChainletsLogsParams(BaseModel): + start_epoch_millis: Annotated[ + int | None, Field( - description="Upstream provider for this target.", - examples=["ANTHROPIC", "OPENAI", "OPENAI_COMPATIBLE", "BASETEN"], + description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + title="Start Epoch Millis", ), - ] - secret_id: Annotated[ - str | None, + ] = None + end_epoch_millis: Annotated[ + int | None, Field( - description="Secret holding the provider credential. Required for external providers.", - examples=["3kZ9xqd"], - title="Secret Id", + description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + title="End Epoch Millis", ), ] = None - target_model: Annotated[ - str | None, + direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( + None + ) + limit: Annotated[ + Limit | None, Field( - description="Model name to send upstream. Required for external providers and optional for BASETEN targets.", - examples=["gpt-4o"], - title="Target Model", + description="Limit of logs to fetch in a single request", + title="Limit", + validate_default=True, ), - ] = None - base_url: Annotated[ - str | None, + ] = Limit.model_validate(500) + min_level: Annotated[ + LogLevel | None, Field( - description="HTTPS base URL of the upstream OpenAI-compatible server. Must not include a port. Required for and only valid with OPENAI_COMPATIBLE.", - examples=["https://my-vllm.example.com"], - title="Base Url", + description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." ), ] = None - model_id: Annotated[ - str | None, + replica: Annotated[ + Replica | None, Field( - description="Baseten model to route to. Required for and only valid with BASETEN.", - examples=["3kZ9xqd"], - title="Model Id", + description="Only return logs emitted by this replica (5-char short ID).", + title="Replica", ), ] = None - environment_name: Annotated[ - str | None, + request_id: Annotated[ + RequestId | None, Field( - description="Baseten model environment to route to. Only valid with BASETEN. Omit or pass `production` to target production.", - examples=["staging"], - title="Environment Name", + description="Only return logs tagged with this inference request ID.", + title="Request Id", ), ] = None - vertex_config: Annotated[ - VertexTargetConfig | None, + component: Annotated[ + Component | None, + Field(description="Only return logs from this component.", title="Component"), + ] = None + search_pattern: Annotated[ + SearchPattern | None, Field( - description="Google Vertex configuration. Required for and only valid with VERTEX." + description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", + title="Search Pattern", ), ] = None - - -class CreateEndpointRequest(BaseModel): - slug: Annotated[ - str, + includes: Annotated[ + list[str] | None, Field( - description="Globally-unique slug of the form '{org_prefix}/{name}'.", - examples=["baseten/mymodel-4"], - title="Slug", + description="Case-sensitive substrings that must all appear in the log message.", + max_length=8, + title="Includes", ), - ] - region: Annotated[ - SharedEndpointRegion, Field(description="Region the new routing serves.") - ] = SharedEndpointRegion.UNRESTRICTED - targets: Annotated[ - list[EndpointTargetRequest], + ] = None + excludes: Annotated[ + list[str] | None, Field( - description="The endpoint's upstream targets. Exactly one target is supported at this time.", - examples=[ - [ - { - "environment_name": "staging", - "model_id": "3kZ9xqd", - "provider": "BASETEN", - "target_model": "custom/model-name", - } - ], - [ - { - "provider": "OPENAI", - "secret_id": "3kZ9xqd", - "target_model": "gpt-4o", - } - ], - [ - { - "base_url": "https://my-vllm.example.com", - "provider": "OPENAI_COMPATIBLE", - "secret_id": "3kZ9xqd", - "target_model": "my-model", - } - ], - ], - max_length=1, - min_length=1, - title="Targets", + description="Case-sensitive substrings; lines containing any of these are dropped.", + max_length=8, + title="Excludes", ), - ] - - -class EndpointTombstone(BaseModel): - id: Annotated[ - str, Field(description="Identifier of the deleted endpoint.", title="Id") - ] - slug: Annotated[ - str, Field(description="Slug of the deleted endpoint.", title="Slug") - ] + ] = None -class Targets(RootModel[list[EndpointTargetRequest]]): - root: Annotated[ - list[EndpointTargetRequest] | None, +class GetTrainingProjectsJobsLogsParams(BaseModel): + start_epoch_millis: Annotated[ + int | None, Field( - description="The endpoint's upstream targets. Exactly one target is supported at this time.", - examples=[ - [ - { - "environment_name": "staging", - "model_id": "3kZ9xqd", - "provider": "BASETEN", - "target_model": "custom/model-name", - } - ], - [ - { - "provider": "OPENAI", - "secret_id": "3kZ9xqd", - "target_model": "gpt-4o", - } - ], - [ - { - "base_url": "https://my-vllm.example.com", - "provider": "OPENAI_COMPATIBLE", - "secret_id": "3kZ9xqd", - "target_model": "my-model", - } - ], - ], - max_length=1, - min_length=1, - title="Targets", + description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + title="Start Epoch Millis", ), ] = None - - -class UpdateEndpointRequest(BaseModel): - targets: Annotated[ - Targets | None, + end_epoch_millis: Annotated[ + int | None, Field( - description="The endpoint's upstream targets. Exactly one target is supported at this time.", - examples=[ - [ - { - "environment_name": "staging", - "model_id": "3kZ9xqd", - "provider": "BASETEN", - "target_model": "custom/model-name", - } - ], - [ - { - "provider": "OPENAI", - "secret_id": "3kZ9xqd", - "target_model": "gpt-4o", - } - ], - [ - { - "base_url": "https://my-vllm.example.com", - "provider": "OPENAI_COMPATIBLE", - "secret_id": "3kZ9xqd", - "target_model": "my-model", - } - ], - ], - title="Targets", + description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + title="End Epoch Millis", ), ] = None - - -class EffectiveRateLimit(BaseModel): - type: Annotated[ - LimitType, - Field(description="The type of the rate limit", examples=["TOKEN", "REQUEST"]), - ] - unit: Annotated[ - RateLimitUnit, - Field(description="The unit of the rate limit", examples=["SECOND", "MINUTE"]), - ] - threshold: Annotated[ - int, + direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( + None + ) + limit: Annotated[ + Limit | None, Field( - description="The threshold for the rate limit", - examples=[1000, 50000], - ge=0, - title="Threshold", + description="Limit of logs to fetch in a single request", + title="Limit", + validate_default=True, ), - ] - source_group: Annotated[ - str, + ] = Limit.model_validate(500) + min_level: Annotated[ + LogLevel | None, Field( - description="ID of the group in the hierarchy this limit is anchored to.", - examples=["abc123"], - title="Source Group", + description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." ), - ] + ] = None -class Name3(RootModel[str]): - root: Annotated[ +class GetLoopsCapabilitiesParams(BaseModel): + model: Annotated[ str | None, Field( - description="Optional display name for the group.", - examples=["Acme prod"], - max_length=255, - title="Name", + description="Restrict the response to one model, identified by its HuggingFace repo id. A supported model comes back with its 'enabled' flag and, when false, its 'enablement_details'. An empty list means Baseten does not support that model. Omit to list every supported model.", + examples=["Qwen/Qwen3-8B"], + title="Model", ), ] = None - - -class GroupMetadata(BaseModel): - name: Annotated[ - Name3 | None, + use_case: Annotated[ + LoopsUseCase, Field( - description="Optional display name for the group.", - examples=["Acme prod"], - title="Name", + description="What the caller intends to run. Defaults to 'rl', the stricter of the two: an RL run needs both a trainer and a sampler, so anything enabled for 'rl' is also enabled for 'sft'.", + examples=["rl"], ), - ] = None - external_entity_id: Annotated[ - str, + ] = LoopsUseCase.rl + max_seq_len: Annotated[ + MaxSeqLen | None, Field( - description="External-system identifier for this group. Unique within the caller's org.", - examples=["cust_42"], - max_length=255, - min_length=1, - title="External Entity Id", + description="The sequence length the caller intends to train at — the same value they would pass as 'max_seq_len' when creating the run. Models that cannot serve it are reported as not enabled rather than returned with a ceiling the caller cannot use. Omit for the model's highest enabled sequence length.", + examples=[32768], + title="Max Seq Len", ), - ] - - -class LimitEnforcement(StrEnum): - CASCADING = "CASCADING" - INDEPENDENT = "INDEPENDENT" - - -class UsageLimitUnit(StrEnum): - DAY = "DAY" + ] = None -class UsageLimit(BaseModel): - type: Annotated[ - LimitType, - Field(description="The type of the usage limit", examples=["REQUEST", "TOKEN"]), - ] - unit: Annotated[ - UsageLimitUnit, - Field(description="The unit of the usage limit", examples=["DAY"]), - ] - threshold: Annotated[ - int, +class GetLoopsDeploymentsLogsParams(BaseModel): + start_epoch_millis: Annotated[ + int | None, Field( - description="The threshold for the usage limit", - examples=[10000000], - ge=0, - title="Threshold", + description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + title="Start Epoch Millis", ), - ] - - -class CreateGroupHierarchy(BaseModel): - limit_enforcement: Annotated[ - LimitEnforcement | None, + ] = None + end_epoch_millis: Annotated[ + int | None, Field( - description="Limit behavior. Child groups inherit their parent's behavior when omitted; root groups default to Independent for backwards compatibility.", - examples=["INDEPENDENT"], + description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + title="End Epoch Millis", ), ] = None - parent_group_id: Annotated[ - str | None, Field(examples=["abc123"], title="Parent Group Id") + direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( + None + ) + limit: Annotated[ + Limit | None, + Field( + description="Limit of logs to fetch in a single request", + title="Limit", + validate_default=True, + ), + ] = Limit.model_validate(500) + min_level: Annotated[ + LogLevel | None, + Field( + description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + ), ] = None -class UpdateGroupMetadata(BaseModel): - name: Annotated[ - Name3 | None, +class GetModelApisUsageParams(BaseModel): + start_time: Annotated[ + AwareDatetime | None, Field( - description="Optional display name for the group.", - examples=["Acme prod"], - title="Name", + description="Start of the query range (ISO 8601, UTC), inclusive. Snapped down to the start of its bucket. Required on the first page, and ignored when you pass a cursor.", + title="Start Time", ), ] = None - - -class GatewayKeyInfo(BaseModel): - prefix: Annotated[ - str, Field(description="The prefix of the Model API key.", title="Prefix") - ] - name: Annotated[ - str | None, Field(description="Optional display name.", title="Name") + end_time: Annotated[ + AwareDatetime | None, + Field( + description="End of the query range (ISO 8601, UTC), exclusive. Defaults to the current time.", + title="End Time", + ), ] = None - - -class KeysForGroupResponse(BaseModel): - items: Annotated[ - list[GatewayKeyInfo], Field(description="Items in this page.", title="Items") - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] - - -class CreateApiKeyForGroupRequest(BaseModel): - name: Annotated[ - str | None, + bucket_width: Annotated[ + BucketWidth, + Field(description="Width of each time bucket: 1m, 1h, or 1d. Defaults to 1d."), + ] = BucketWidth.field_1d + group_by: Annotated[ + list[UsageDimension] | None, Field( - description="Optional display name for the new key.", - examples=["prod-key-1"], - title="Name", + description="Dimensions to break usage down by, repeated once per dimension: api_key, user, model. Defaults to model.", + title="Group By", ), ] = None - - -class CreateApiKeyForGroupResponse(BaseModel): - api_key: Annotated[ - str, + api_keys: Annotated[ + list[str] | None, Field( - description="Plaintext key string, returned exactly once.", title="Api Key" + description="Return only usage for these API key prefixes, repeated once per prefix.", + title="Api Keys", ), - ] - prefix: Annotated[ - str, Field(description="Key prefix (the part before the dot).", title="Prefix") - ] - name: Annotated[ - str | None, Field(description="Display name of the key.", title="Name") ] = None - - -class RegisterAPIKeyRequest(BaseModel): - name: Annotated[ - str | None, + user_ids: Annotated[ + list[str] | None, Field( - description="Optional name for the Model API key", - examples=["my-model-api-key"], - title="Name", + description="Return only usage attributed to these user IDs, repeated once per ID.", + title="User Ids", ), ] = None - key: Annotated[ - str, + models: Annotated[ + list[str] | None, Field( - description="Value of the API key to register", - examples=["my-secure-api-key-value"], - title="Key", + description="Return only usage for these models, repeated once per model.", + title="Models", ), - ] - - -class RegisterAPIKeyResponse(BaseModel): - ok: Annotated[ - bool, Field(description="Whether the registration was successful", title="Ok") - ] - - -class Checkpoints( - RootModel[ - BasetenLatestCheckpointConfig - | BasetenNamedCheckpointConfig - | LoopsCheckpointConfig - ] -): - root: Annotated[ - BasetenLatestCheckpointConfig - | BasetenNamedCheckpointConfig - | LoopsCheckpointConfig, - Field(discriminator="typ"), - ] - - -class LoadCheckpointConfig(BaseModel): - enabled: Annotated[ - bool, - Field(description="Whether checkpoint loading is enabled", title="Enabled"), - ] = False - download_folder: Annotated[ - str, + ] = None + limit: Annotated[ + int | None, Field( - description="Folder where checkpoints will be downloaded", - title="Download Folder", + description="Number of time buckets to return. Defaults and maximums depend on bucket_width: 1d defaults to 7 and allows 31, 1h defaults to 24 and allows 168, 1m defaults to 60 and allows 1440.", + title="Limit", + ), + ] = None + cursor: Annotated[ + str | None, + Field( + description="Opaque cursor from the pagination.cursor field of a previous response", + title="Cursor", ), - ] = "/tmp/loaded_checkpoints" - checkpoints: Annotated[ - list[Checkpoints] | None, - Field(description="List of checkpoint configurations", title="Checkpoints"), ] = None -class GetAuditLogsRequest(BaseModel): +class GetBillingModelApisParams(BaseModel): cursor: Annotated[ str | None, Field( @@ -7221,84 +10165,64 @@ class GetAuditLogsRequest(BaseModel): limit: Annotated[ int, Field( - description="Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", + description="Number of daily cost buckets to return. Defaults to 7; maximum 31.", ge=1, - le=200, + le=31, title="Limit", ), - ] = 20 - direction: Annotated[ - AuditLogSortDirection, - Field( - description="Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." - ), - ] = AuditLogSortDirection.DESC - search: Annotated[ - str | None, + ] = 7 + start_date: Annotated[ + date_aliased | None, Field( - description="Case-insensitive substring matched against resource names and IDs in the entry.", - title="Search", + description="Inclusive UTC calendar day at the start of the query range. Defaults to the previous UTC date, cannot be before 2026-08-05, and is ignored when you pass a cursor.", + title="Start Date", ), ] = None - event_type_groups: Annotated[ - list[AuditLogEventTypeGroup] | None, + end_date: Annotated[ + date_aliased | None, Field( - description="When set, returns only entries whose event type falls in one of these groups.", - title="Event Type Groups", + description="Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included. The date range cannot exceed 90 days.", + title="End Date", ), ] = None - user_ids: Annotated[ - list[str] | None, + group_by: Annotated[ + list[ModelApiCostDimension] | None, Field( - description="When set, returns only entries whose acting user is one of these IDs.", - title="User Ids", + description="Dimensions to break costs down by, repeated once per dimension: api_key_prefix, user, model, or service_tier. Each result represents one observed combination of the requested dimensions within that day. For example, grouping by api_key_prefix and user returns each API-key and user pair that had usage. Combinations without usage are omitted, so result counts can differ between days. Omit for daily organization totals.", + title="Group By", ), ] = None - deployment_ids: Annotated[ + api_key_prefixes: Annotated[ list[str] | None, Field( - description="When set, returns only entries referencing one of these model deployment IDs.", - title="Deployment Ids", + description="Return only costs for these exact API key prefixes, repeated once per prefix.", + title="Api Key Prefixes", ), ] = None - chain_deployment_ids: Annotated[ + user_ids: Annotated[ list[str] | None, Field( - description="When set, returns only entries referencing one of these chain deployment IDs.", - title="Chain Deployment Ids", + description="Return only costs attributed to these exact user IDs, repeated once per ID.", + title="User Ids", ), ] = None - environment_names: Annotated[ + models: Annotated[ list[str] | None, Field( - description="When set, returns only entries for one of these environments.", - title="Environment Names", - ), - ] = None - sources: Annotated[ - list[AuditLogSource] | None, - Field( - description="When set, returns only entries issued from one of these surfaces.", - title="Sources", - ), - ] = None - start_epoch_millis: Annotated[ - int | None, - Field( - description="Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", - title="Start Epoch Millis", + description="Return only costs for these exact model identifiers, repeated once per model.", + title="Models", ), ] = None - end_epoch_millis: Annotated[ - int | None, + service_tiers: Annotated[ + list[str] | None, Field( - description="Epoch milliseconds for the end of the window. Defaults to the current time.", - title="End Epoch Millis", + description="Return only costs for these exact service tiers, repeated once per tier.", + title="Service Tiers", ), ] = None -class GetModelsAuditLogsRequest(BaseModel): +class GetRoutesUsageParams(BaseModel): cursor: Annotated[ str | None, Field( @@ -7309,3011 +10233,3445 @@ class GetModelsAuditLogsRequest(BaseModel): limit: Annotated[ int, Field( - description="Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", + description="Number of daily buckets to return. Defaults to 7; maximum 31.", ge=1, - le=200, + le=31, title="Limit", ), - ] = 20 - direction: Annotated[ - AuditLogSortDirection, + ] = 7 + start_date: Annotated[ + date_aliased | None, Field( - description="Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." + description="Inclusive UTC calendar day at the start of the query range. Defaults to the previous UTC date, and is ignored when you pass a cursor.", + title="Start Date", ), - ] = AuditLogSortDirection.DESC - search: Annotated[ - str | None, + ] = None + end_date: Annotated[ + date_aliased | None, Field( - description="Case-insensitive substring matched against resource names and IDs in the entry.", - title="Search", + description="Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included.", + title="End Date", ), ] = None - event_type_groups: Annotated[ - list[AuditLogEventTypeGroup] | None, + group_by: Annotated[ + list[RouteUsageDimension] | None, Field( - description="When set, returns only entries whose event type falls in one of these groups.", - title="Event Type Groups", + description="Dimensions to break usage down by, repeated once per dimension: USER, MODEL, or PROVIDER. Each result represents one observed combination of the requested dimensions within that day, and results are sorted by those values. Combinations without usage are omitted, so result counts can differ between days. Defaults to MODEL.", + title="Group By", ), ] = None user_ids: Annotated[ list[str] | None, Field( - description="When set, returns only entries whose acting user is one of these IDs.", + description="Return only usage from Routes keys created by these user IDs, repeated once per ID.", title="User Ids", ), ] = None - deployment_ids: Annotated[ - list[str] | None, - Field( - description="When set, returns only entries referencing one of these model deployment IDs.", - title="Deployment Ids", - ), - ] = None - chain_deployment_ids: Annotated[ - list[str] | None, - Field( - description="When set, returns only entries referencing one of these chain deployment IDs.", - title="Chain Deployment Ids", - ), - ] = None - environment_names: Annotated[ + models: Annotated[ list[str] | None, Field( - description="When set, returns only entries for one of these environments.", - title="Environment Names", - ), - ] = None - sources: Annotated[ - list[AuditLogSource] | None, - Field( - description="When set, returns only entries issued from one of these surfaces.", - title="Sources", - ), - ] = None - start_epoch_millis: Annotated[ - int | None, - Field( - description="Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", - title="Start Epoch Millis", + description="Return only usage for these exact model names, repeated once per model.", + title="Models", ), ] = None - end_epoch_millis: Annotated[ - int | None, + providers: Annotated[ + list[RouteProvider] | None, Field( - description="Epoch milliseconds for the end of the window. Defaults to the current time.", - title="End Epoch Millis", + description="Return only usage for these providers, repeated once per provider.", + title="Providers", ), ] = None -class GetModelsDeploymentsLogsRequest(BaseModel): - start_epoch_millis: Annotated[ - int | None, +class Volume(BaseModel): + namespace: Annotated[ + str, Field( - description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - title="Start Epoch Millis", + description="Namespace the volume belongs to, in lowercase.", + title="Namespace", ), - ] = None - end_epoch_millis: Annotated[ - int | None, + ] + name: Annotated[ + str, Field(description="Name of the volume, in lowercase.", title="Name") + ] + version_ref: Annotated[ + str, Field( - description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - title="End Epoch Millis", + description="Full address of the volume, as `bdn:/`. Paste this into the `bdn.mounts` section of a config.yaml.", + title="Version Ref", ), - ] = None - direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( - None - ) - limit: Annotated[ - Limit | None, + ] + sequence: Annotated[ + int, Field( - description="Limit of logs to fetch in a single request", - title="Limit", - validate_default=True, + description="Revision counter for the volume, incremented on every commit, tag change, delete, and restore. A tag or version that expires leaves without changing it; the next write then increments it once. Use it to detect that a volume was written to.", + title="Sequence", ), - ] = Limit.model_validate(500) - min_level: Annotated[ - LogLevel | None, + ] + updated_at: Annotated[ + AwareDatetime, Field( - description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + description="When the volume was last written to, in ISO 8601 format. An expiry does not update it.", + title="Updated At", ), - ] = None - replica: Annotated[ - Replica | None, + ] + expires_at: Annotated[ + AwareDatetime | None, Field( - description="Only return logs emitted by this replica (5-char short ID).", - title="Replica", + description="When the whole volume expires, in ISO 8601 format. At that instant every live version is deleted, every tag drops, and the volume leaves the volume listing; each version then stays restorable until its recovery deadline passes. Null for a volume that never expires.", + title="Expires At", ), - ] = None - request_id: Annotated[ - RequestId | None, + ] + head: Annotated[ + VolumeVersionSummary | None, Field( - description="Only return logs tagged with this inference request ID.", - title="Request Id", + description="Version that the reserved `head` tag points at, which a reference with no tag or digest resolves to. Never an expiring version. Null when the volume has no head, or when your API key cannot read it." ), - ] = None - component: Annotated[ - Component | None, - Field(description="Only return logs from this component.", title="Component"), - ] = None - search_pattern: Annotated[ - SearchPattern | None, + ] + tags: Annotated[ + list[VolumeTag], Field( - description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", - title="Search Pattern", + description="Tags on the volume that your API key can read. A tag with `expires_at` leaves this list at that instant.", + title="Tags", ), - ] = None - includes: Annotated[ - list[str] | None, + ] + tag_count: Annotated[ + int, Field( - description="Case-sensitive substrings that must all appear in the log message.", - max_length=8, - title="Includes", + description="Total number of tags on the volume, which can exceed the length of `tags` when your API key cannot read all of them. Counts only tags that have not expired.", + title="Tag Count", ), - ] = None - excludes: Annotated[ - list[str] | None, + ] + versions_alive: Annotated[ + int, Field( - description="Case-sensitive substrings; lines containing any of these are dropped.", - max_length=8, - title="Excludes", + description="Number of versions that have not been deleted or expired.", + title="Versions Alive", ), - ] = None - - -class GetModelsDeploymentsMetricsRequest(BaseModel): - mode: Annotated[ - ModelMetricMode, + ] + versions_tombstoned: Annotated[ + int, Field( - description="'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." + description="Number of versions that have been deleted or expired and are still within their recovery window.", + title="Versions Tombstoned", ), - ] = ModelMetricMode.CURRENT - start_epoch_millis: Annotated[ - int | None, + ] + versions_untagged: Annotated[ + int, Field( - description="Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", - title="Start Epoch Millis", + description="Number of live versions that no tag points at.", + title="Versions Untagged", ), - ] = None - end_epoch_millis: Annotated[ - int | None, + ] + versions_expiring: Annotated[ + int, Field( - description="Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", - title="End Epoch Millis", + description="Number of live versions with an expiry still ahead of them. A version that has already expired counts in `versions_tombstoned` instead.", + title="Versions Expiring", ), - ] = None - metrics: Annotated[ - list[str] | None, + ] + versions_earliest_expires_at: Annotated[ + AwareDatetime | None, Field( - description="Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", - title="Metrics", + description="Earliest expiry among the live versions, in ISO 8601 format. Null when no live version is scheduled to expire.", + title="Versions Earliest Expires At", ), - ] = None + ] -class GetModelsEnvironmentsLogsRequest(BaseModel): - start_epoch_millis: Annotated[ - int | None, +class ListVolumesResponse(BaseModel): + items: Annotated[ + list[Volume], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class EnvironmentGroupManageAccess(BaseModel): + is_restricted: Annotated[ + bool, Field( - description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - title="Start Epoch Millis", + description="Whether the environment is restricted to a specific set of users.", + title="Is Restricted", ), - ] = None - end_epoch_millis: Annotated[ - int | None, + ] + users: Annotated[ + list[EnvironmentGroupUser] | None, Field( - description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - title="End Epoch Millis", + description="Users who can manage the environment while it is restricted, including organization and team admins who always have access. Empty when the environment is unrestricted.", + title="Users", ), ] = None - direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( - None - ) - limit: Annotated[ - Limit | None, + + +class EnvironmentGroup(BaseModel): + name: Annotated[ + str, Field( - description="Limit of logs to fetch in a single request", - title="Limit", - validate_default=True, + description="Name of the environment group, matching the environment name it governs.", + examples=["staging"], + title="Name", ), - ] = Limit.model_validate(500) - min_level: Annotated[ - LogLevel | None, + ] + team_id: Annotated[ + str, Field( - description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + description="Unique identifier of the team the environment group belongs to.", + title="Team Id", ), - ] = None - replica: Annotated[ - Replica | None, + ] + team_name: Annotated[ + str, Field( - description="Only return logs emitted by this replica (5-char short ID).", - title="Replica", + description="Name of the team the environment group belongs to.", + title="Team Name", ), - ] = None - request_id: Annotated[ - RequestId | None, + ] + manage_access: Annotated[ + EnvironmentGroupManageAccess, Field( - description="Only return logs tagged with this inference request ID.", - title="Request Id", + description="Settings controlling who can manage this environment group." ), + ] + + +class EnvironmentGroups(BaseModel): + items: Annotated[ + list[EnvironmentGroup], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class AuditLogEventAutoscalingScheduleChange(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + action: AuditLogEventAutoscalingScheduleAction + schedule_id: Annotated[str, Field(title="Schedule Id")] + previous: AuditLogEventAutoscalingScheduleSettings | None + current: AuditLogEventAutoscalingScheduleSettings | None + + +class AuditLogEventEnvironmentUpdated(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + schedules: Annotated[ + list[AuditLogEventAutoscalingScheduleChange] | None, Field(title="Schedules") + ] + min_replica: Annotated[int, Field(title="Min Replica")] + max_replica: Annotated[int, Field(title="Max Replica")] + concurrency_target: Annotated[int, Field(title="Concurrency Target")] + autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] + scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] + target_utilization_percentage: Annotated[ + int | None, Field(title="Target Utilization Percentage") + ] + target_in_flight_tokens: Annotated[ + int | None, Field(title="Target In Flight Tokens") + ] + max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] + redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] + rolling_deploy: Annotated[bool | None, Field(title="Rolling Deploy")] + rolling_deploy_strategy: Annotated[ + str | None, Field(title="Rolling Deploy Strategy") + ] + max_unavailable_percent: Annotated[ + int | None, Field(title="Max Unavailable Percent") + ] + max_surge_percent: Annotated[int | None, Field(title="Max Surge Percent")] + stabilization_time_seconds: Annotated[ + int | None, Field(title="Stabilization Time Seconds") + ] + replica_overhead_percent: Annotated[ + int | None, Field(title="Replica Overhead Percent") + ] + promotion_cleanup_strategy: Annotated[ + str | None, Field(title="Promotion Cleanup Strategy") + ] + ramp_up_while_promoting: Annotated[ + bool | None, Field(title="Ramp Up While Promoting") + ] + ramp_up_duration_seconds: Annotated[ + int | None, Field(title="Ramp Up Duration Seconds") + ] + ramp_up_step_size: Annotated[int | None, Field(title="Ramp Up Step Size")] + request_backpressure_policy: Annotated[ + str | None, Field(title="Request Backpressure Policy") ] = None - component: Annotated[ - Component | None, - Field(description="Only return logs from this component.", title="Component"), - ] = None - search_pattern: Annotated[ - SearchPattern | None, + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + environment_name: Annotated[str, Field(title="Environment Name")] + deployment_type: Annotated[str | None, Field(title="Deployment Type")] + event_type: Annotated[Literal["ENVIRONMENT_UPDATED"], Field(title="Event Type")] + previous_settings: AuditLogEventEnvironmentSettings | None + + +class AuditLogEventModelDeploymentAutoscalingSettingsChanged(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + schedules: Annotated[ + list[AuditLogEventAutoscalingScheduleChange] | None, Field(title="Schedules") + ] + min_replica: Annotated[int, Field(title="Min Replica")] + max_replica: Annotated[int, Field(title="Max Replica")] + concurrency_target: Annotated[int, Field(title="Concurrency Target")] + autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] + scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] + target_utilization_percentage: Annotated[ + int | None, Field(title="Target Utilization Percentage") + ] + target_in_flight_tokens: Annotated[ + int | None, Field(title="Target In Flight Tokens") + ] + max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] + event_type: Annotated[ + Literal["MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED"], + Field(title="Event Type"), + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + deployment_type: Annotated[str | None, Field(title="Deployment Type")] + previous_settings: AuditLogEventAutoscalingSettings | None + + +class AuditLogEventModelPromotionControlAction(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + event_type: Annotated[ + Literal["MODEL_PROMOTION_CONTROL_ACTION"], Field(title="Event Type") + ] + model_id: Annotated[str, Field(title="Model Id")] + model_name: Annotated[str, Field(title="Model Name")] + deployment_id: Annotated[str, Field(title="Deployment Id")] + deployment_name: Annotated[str, Field(title="Deployment Name")] + environment_name: Annotated[str, Field(title="Environment Name")] + environment_id: Annotated[str | None, Field(title="Environment Id")] + action: AuditLogPromotionControlAction + + +class Deployment(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the deployment", title="Id") + ] + created_at: Annotated[ + AwareDatetime, Field( - description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", - title="Search Pattern", + description="Time the deployment was created in ISO 8601 format", + title="Created At", ), - ] = None - includes: Annotated[ - list[str] | None, + ] + name: Annotated[str, Field(description="Name of the deployment", title="Name")] + model_id: Annotated[ + str, Field(description="Unique identifier of the model", title="Model Id") + ] + is_production: Annotated[ + bool, Field( - description="Case-sensitive substrings that must all appear in the log message.", - max_length=8, - title="Includes", + description="Whether the deployment is the production deployment of the model", + title="Is Production", ), - ] = None - excludes: Annotated[ - list[str] | None, + ] + is_development: Annotated[ + bool, + Field( + description="Whether the deployment is the development deployment of the model", + title="Is Development", + ), + ] + status: Annotated[DeploymentStatus, Field(description="Status of the deployment")] + active_replica_count: Annotated[ + int, + Field(description="Number of active replicas", title="Active Replica Count"), + ] + autoscaling_settings: Annotated[ + AutoscalingSettings | None, Field( - description="Case-sensitive substrings; lines containing any of these are dropped.", - max_length=8, - title="Excludes", + description="Autoscaling settings for the deployment. If null, the model has not finished deploying" ), - ] = None - - -class GetModelsEnvironmentsMetricsRequest(BaseModel): - mode: Annotated[ - ModelMetricMode, + ] + instance_type_name: Annotated[ + str | None, Field( - description="'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." + description="Name of the instance type the model deployment is running on", + title="Instance Type Name", ), - ] = ModelMetricMode.CURRENT - start_epoch_millis: Annotated[ - int | None, + ] + environment: Annotated[ + str | None, Field( - description="Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", - title="Start Epoch Millis", + description="The environment associated with the deployment", + title="Environment", ), - ] = None - end_epoch_millis: Annotated[ - int | None, + ] + labels: Annotated[ + dict[str, Any] | None, Field( - description="Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", - title="End Epoch Millis", + description="User-provided key-value labels for the deployment", + title="Labels", ), ] = None - metrics: Annotated[ - list[str] | None, + region: Annotated[ + Region | None, + Field(description="The selected region for the deployment, if any"), + ] = None + request_backpressure_settings: Annotated[ + RequestBackpressureSettings, Field( - description="Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", - title="Metrics", + description="Effective request backpressure settings for the deployment." ), - ] = None + ] -class GetChainsAuditLogsRequest(BaseModel): - cursor: Annotated[ - str | None, - Field( - description="Opaque cursor returned by a previous page. Omit to fetch the first page.", - title="Cursor", - ), - ] = None - limit: Annotated[ - int, +class CreatedModelDeployment(BaseModel): + model: Annotated[ + Model, Field( - description="Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", - ge=1, - le=200, - title="Limit", + description="The model the deployment belongs to. May have been created by this call." ), - ] = 20 - direction: Annotated[ - AuditLogSortDirection, + ] + deployment: Annotated[ + Deployment, Field(description="The newly created deployment.") + ] + + +class Deployments(BaseModel): + deployments: Annotated[ + list[Deployment], + Field(description="A list of deployments of a model", title="Deployments"), + ] + + +class RetryDeploymentResponse(BaseModel): + retried: Annotated[ + bool, Field( - description="Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." + description="Whether the retry was successfully initiated", title="Retried" ), - ] = AuditLogSortDirection.DESC - search: Annotated[ + ] + reason: Annotated[ str | None, Field( - description="Case-insensitive substring matched against resource names and IDs in the entry.", - title="Search", + description="Explanation of the result. Provided when retried is false to explain why retry was not possible.", + title="Reason", ), ] = None - event_type_groups: Annotated[ - list[AuditLogEventTypeGroup] | None, + deployment: Annotated[ + Deployment, Field(description="The deployment that was retried") + ] + + +class ModelMetricDescriptor(BaseModel): + name: Annotated[str, Field(description="Canonical metric name.", title="Name")] + unit_hint: Annotated[ + ModelMetricUnitHint, Field(description="Advisory unit of the metric's values.") + ] + kind: Annotated[ + ModelMetricKind, Field( - description="When set, returns only entries whose event type falls in one of these groups.", - title="Event Type Groups", + description="Semantic hint for how the metric behaves (GAUGE, COUNTER, HISTOGRAM)." ), - ] = None - user_ids: Annotated[ - list[str] | None, + ] + label_sets: Annotated[ + list[dict[str, str]], Field( - description="When set, returns only entries whose acting user is one of these IDs.", - title="User Ids", + description="The metric's series, in order. Each entry is the set of labels identifying one series; the value at the same index in each value set's ``values`` is that series' value. A plain metric has a single entry with no labels (`{}`). A histogram has one entry per quantile plus an average, e.g. {'quantile': '0.5'} … {'quantile': '0.99'}, {'stat': 'avg'}. A by-status metric has one entry per status, e.g. {'status': '2xx'}.", + title="Label Sets", ), - ] = None - deployment_ids: Annotated[ - list[str] | None, + ] + + +class GetModelMetricsResponse(BaseModel): + start_epoch_millis: Annotated[ + int, + Field(description="Start of the returned window.", title="Start Epoch Millis"), + ] + end_epoch_millis: Annotated[ + int, Field(description="End of the returned window.", title="End Epoch Millis") + ] + mode: Annotated[ModelMetricMode, Field(description="The aggregation mode used.")] + step_seconds: Annotated[ + int | None, Field( - description="When set, returns only entries referencing one of these model deployment IDs.", - title="Deployment Ids", + description="Seconds per step; populated only in SERIES mode, null otherwise.", + title="Step Seconds", ), - ] = None - chain_deployment_ids: Annotated[ - list[str] | None, + ] + metric_descriptors: Annotated[ + list[ModelMetricDescriptor], Field( - description="When set, returns only entries referencing one of these chain deployment IDs.", - title="Chain Deployment Ids", + description="Descriptors for each metric; position defines the values index.", + title="Metric Descriptors", ), - ] = None - environment_names: Annotated[ - list[str] | None, + ] + metric_values: Annotated[ + list[ModelMetricValueSet], Field( - description="When set, returns only entries for one of these environments.", - title="Environment Names", + description="Metric values per time step covering the window. In summary mode this always contains exactly one value set spanning the whole window.", + title="Metric Values", ), - ] = None - sources: Annotated[ - list[AuditLogSource] | None, + ] + + +class AutoscalingSchedule(BaseModel): + id: Annotated[ + str, Field(description="Stable unique identifier of the schedule", title="Id") + ] + name: Annotated[str, Field(description="Name of the schedule", title="Name")] + enabled: Annotated[ + bool, Field(description="Whether the schedule is enabled", title="Enabled") + ] + autoscaling_settings: Annotated[ + AutoscalingScheduleSettings, Field( - description="When set, returns only entries issued from one of these surfaces.", - title="Sources", + description="Raw autoscaling overrides applied during the schedule window" ), - ] = None - start_epoch_millis: Annotated[ - int | None, + ] + cadence: Annotated[ + Literal["DAILY", "HOURLY"], Field( - description="Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", - title="Start Epoch Millis", + description="Cadence of the schedule. DAILY runs once per selected weekday; HOURLY repeats the minute window every hour on selected weekdays.", + title="Cadence", ), - ] = None - end_epoch_millis: Annotated[ + ] + weekdays: Annotated[ + list[AutoscalingScheduleWeekday], + Field(description="Weekdays on which the schedule runs", title="Weekdays"), + ] + start_hour: Annotated[ int | None, Field( - description="Epoch milliseconds for the end of the window. Defaults to the current time.", - title="End Epoch Millis", + description="Start hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", + title="Start Hour", ), ] = None - - -class GetChainsDeploymentsChainletsLogsRequest(BaseModel): - start_epoch_millis: Annotated[ + start_minute: Annotated[ + int, + Field(description="Start minute of the schedule window", title="Start Minute"), + ] + end_hour: Annotated[ int | None, Field( - description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - title="Start Epoch Millis", + description="End hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", + title="End Hour", ), ] = None - end_epoch_millis: Annotated[ - int | None, + end_minute: Annotated[ + int, Field(description="End minute of the schedule window", title="End Minute") + ] + + +class Schedules(RootModel[AutoscalingSchedule | OneTimeAutoscalingSchedule]): + root: Annotated[ + AutoscalingSchedule | OneTimeAutoscalingSchedule, Field(discriminator="cadence") + ] + + +class EnvironmentAutoscalingSchedules(BaseModel): + timezone: Annotated[ + str | None, Field( - description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - title="End Epoch Millis", + description="IANA timezone shared by all schedules. Omitted when no schedules exist.", + title="Timezone", ), ] = None - direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( - None - ) - limit: Annotated[ - Limit | None, + schedules: Annotated[ + list[Schedules], Field( - description="Limit of logs to fetch in a single request", - title="Limit", - validate_default=True, + description="Autoscaling schedules ordered by creation time and stable identifier", + title="Schedules", ), - ] = Limit.model_validate(500) - min_level: Annotated[ - LogLevel | None, + ] + applied_state: Annotated[ + AutoscalingScheduleState | None, Field( - description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + description="Autoscaling state on the current serving deployment, or null when no deployment exists" ), - ] = None - replica: Annotated[ - Replica | None, + ] + + +class RollingDeployConfig(BaseModel): + rolling_deploy_strategy: Annotated[ + RollingDeployStrategy, Field( - description="Only return logs emitted by this replica (5-char short ID).", - title="Replica", + description="The rolling deploy strategy to use for promotions.", + examples=["REPLICA"], ), - ] = None - request_id: Annotated[ - RequestId | None, + ] = RollingDeployStrategy.REPLICA + max_surge_percent: Annotated[ + int, Field( - description="Only return logs tagged with this inference request ID.", - title="Request Id", + description="The maximum surge percentage for rolling deploys.", + examples=[25], + title="Max Surge Percent", ), - ] = None - component: Annotated[ - Component | None, - Field(description="Only return logs from this component.", title="Component"), - ] = None - search_pattern: Annotated[ - SearchPattern | None, + ] = 25 + max_unavailable_percent: Annotated[ + int, Field( - description="RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", - title="Search Pattern", + description="The maximum unavailable percentage for rolling deploys.", + examples=[10], + title="Max Unavailable Percent", ), - ] = None - includes: Annotated[ - list[str] | None, + ] = 0 + stabilization_time_seconds: Annotated[ + int, Field( - description="Case-sensitive substrings that must all appear in the log message.", - max_length=8, - title="Includes", + description="The stabilization time in seconds for rolling deploys.", + examples=[300], + title="Stabilization Time Seconds", ), - ] = None - excludes: Annotated[ - list[str] | None, + ] = 0 + replica_overhead_percent: Annotated[ + int, Field( - description="Case-sensitive substrings; lines containing any of these are dropped.", - max_length=8, - title="Excludes", + description="The replica overhead percentage for rolling deploys.", + examples=[0], + title="Replica Overhead Percent", ), - ] = None + ] = 0 -class GetTrainingProjectsJobsLogsRequest(BaseModel): - start_epoch_millis: Annotated[ - int | None, +class UpdatePromotionSettings(BaseModel): + redeploy_on_promotion: Annotated[ + bool | None, Field( - description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - title="Start Epoch Millis", + description="Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", + examples=[True], + title="Redeploy On Promotion", ), ] = None - end_epoch_millis: Annotated[ - int | None, + rolling_deploy: Annotated[ + bool | None, Field( - description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - title="End Epoch Millis", + description="Whether the environment should rely on rolling deploy orchestration.", + examples=[True], + title="Rolling Deploy", ), ] = None - direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( - None - ) - limit: Annotated[ - Limit | None, - Field( - description="Limit of logs to fetch in a single request", - title="Limit", - validate_default=True, - ), - ] = Limit.model_validate(500) - min_level: Annotated[ - LogLevel | None, + promotion_cleanup_strategy: Annotated[ + PromotionCleanupStrategy | None, Field( - description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + description="The cleanup strategy to use after a promotion completes.", + examples=["SCALE_TO_ZERO"], ), ] = None - - -class GetLoopsDeploymentsLogsRequest(BaseModel): - start_epoch_millis: Annotated[ - int | None, + rolling_deploy_config: Annotated[ + UpdateRollingDeployConfig | None, + Field(description="Rolling deploy configuration for promotions"), + ] = None + ramp_up_while_promoting: Annotated[ + bool | None, Field( - description="Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - title="Start Epoch Millis", + description="Whether to ramp up traffic while promoting", + examples=[True], + title="Ramp Up While Promoting", ), ] = None - end_epoch_millis: Annotated[ + ramp_up_duration_seconds: Annotated[ int | None, Field( - description="Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - title="End Epoch Millis", + description="Duration of the ramp up in seconds", + examples=[600], + title="Ramp Up Duration Seconds", ), ] = None - direction: Annotated[SortOrder | None, Field(description="Sort order for logs")] = ( - None - ) - limit: Annotated[ - Limit | None, + + +class CreateEnvironmentRequest(BaseModel): + name: Annotated[ + str, Field( - description="Limit of logs to fetch in a single request", - title="Limit", - validate_default=True, + description="Name of the environment", examples=["staging"], title="Name" ), - ] = Limit.model_validate(500) - min_level: Annotated[ - LogLevel | None, + ] + autoscaling_settings: Annotated[ + UpdateAutoscalingSettings | None, Field( - description="Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + description="Autoscaling settings for the environment", + examples=[ + { + "autoscaling_window": 800, + "concurrency_target": 3, + "max_replica": 2, + "max_scale_down_rate": None, + "min_replica": 1, + "scale_down_delay": 60, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + } + ], ), ] = None - - -class GetModelApisUsageRequest(BaseModel): - start_time: Annotated[ - AwareDatetime | None, + promotion_settings: Annotated[ + UpdatePromotionSettings | None, Field( - description="Start of the query range (ISO 8601, UTC), inclusive. Snapped down to the start of its bucket. Required on the first page, and ignored when you pass a cursor.", - title="Start Time", + description="Promotion settings for the environment. New Model environments use rolling promotions by default. Set `rolling_deploy` to `false` to opt out.", + examples=[ + { + "promotion_cleanup_strategy": None, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": True, + "redeploy_on_promotion": True, + "rolling_deploy": False, + "rolling_deploy_config": None, + } + ], ), ] = None - end_time: Annotated[ - AwareDatetime | None, - Field( - description="End of the query range (ISO 8601, UTC), exclusive. Defaults to the current time.", - title="End Time", - ), + request_backpressure_settings: Annotated[ + UpdateRequestBackpressureSettings | None, + Field(description="Request backpressure settings for the environment."), ] = None - bucket_width: Annotated[ - BucketWidth, - Field(description="Width of each time bucket: 1m, 1h, or 1d. Defaults to 1d."), - ] = BucketWidth.field_1d - group_by: Annotated[ - list[UsageDimension] | None, + + +class UpdateEnvironmentRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + autoscaling_settings: Annotated[ + UpdateAutoscalingSettings | None, Field( - description="Dimensions to break usage down by, repeated once per dimension: api_key, user, model. Defaults to model.", - title="Group By", + description="Autoscaling settings for the environment", + examples=[ + { + "autoscaling_window": 800, + "concurrency_target": 3, + "max_replica": 2, + "max_scale_down_rate": None, + "min_replica": 1, + "scale_down_delay": 60, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + } + ], ), ] = None - api_keys: Annotated[ - list[str] | None, + promotion_settings: Annotated[ + UpdatePromotionSettings | None, Field( - description="Return only usage for these API key prefixes, repeated once per prefix.", - title="Api Keys", + description="Promotion settings for the environment", + examples=[ + { + "promotion_cleanup_strategy": None, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": True, + "redeploy_on_promotion": True, + "rolling_deploy": None, + "rolling_deploy_config": None, + } + ], ), ] = None - user_ids: Annotated[ - list[str] | None, + autoscaling_schedule_settings: Annotated[ + UpdateAutoscalingScheduleSettings | None, Field( - description="Return only usage attributed to these user IDs, repeated once per ID.", - title="User Ids", + description="Partial autoscaling schedule collection update. Omitted collection fields and existing schedules are unchanged; each submitted schedule is a complete create or replacement.", + examples=[ + { + "schedules": [ + { + "autoscaling_settings": { + "autoscaling_window": None, + "concurrency_target": None, + "max_replica": 8, + "max_scale_down_rate": None, + "min_replica": 2, + "scale_down_delay": None, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + }, + "cadence": "DAILY", + "enabled": True, + "end_hour": 10, + "end_minute": 0, + "name": "weekday-peak", + "start_hour": 8, + "start_minute": 0, + "weekdays": [ + "MONDAY", + "TUESDAY", + "WEDNESDAY", + "THURSDAY", + "FRIDAY", + ], + } + ], + "timezone": "America/Los_Angeles", + }, + {"delete_schedules": ["schedule-id"]}, + ], ), ] = None - models: Annotated[ - list[str] | None, + request_backpressure_settings: Annotated[ + UpdateRequestBackpressureSettings | None, Field( - description="Return only usage for these models, repeated once per model.", - title="Models", + description="Request backpressure settings for the environment.", + examples=[{"policy": "REJECT_ON_FULL"}], ), ] = None - limit: Annotated[ - int | None, + + +class ChainDeployment(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the chain deployment", title="Id") + ] + created_at: Annotated[ + AwareDatetime, Field( - description="Number of time buckets to return. Defaults and maximums depend on bucket_width: 1d defaults to 7 and allows 31, 1h defaults to 24 and allows 168, 1m defaults to 60 and allows 1440.", - title="Limit", + description="Time the chain deployment was created in ISO 8601 format", + title="Created At", ), - ] = None - cursor: Annotated[ + ] + chain_id: Annotated[ + str, Field(description="Unique identifier of the chain", title="Chain Id") + ] + environment: Annotated[ str | None, Field( - description="Opaque cursor from the pagination.cursor field of a previous response", - title="Cursor", + description="Environment the chain deployment is deployed in", + title="Environment", ), - ] = None + ] + chainlets: Annotated[ + list[Chainlet], + Field(description="Chainlets in the chain deployment", title="Chainlets"), + ] + status: Annotated[ + DeploymentStatus, Field(description="Status of the chain deployment") + ] -class GetBillingModelApisRequest(BaseModel): - cursor: Annotated[ - str | None, - Field( - description="Opaque cursor returned by a previous page. Omit to fetch the first page.", - title="Cursor", - ), - ] = None - limit: Annotated[ - int, - Field( - description="Number of daily cost buckets to return. Defaults to 7; maximum 31.", - ge=1, - le=31, - title="Limit", - ), - ] = 7 - start_date: Annotated[ - date_aliased | None, - Field( - description="Inclusive UTC calendar day at the start of the query range. Defaults to the previous UTC date, cannot be before 2026-08-05, and is ignored when you pass a cursor.", - title="Start Date", - ), - ] = None - end_date: Annotated[ - date_aliased | None, - Field( - description="Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included. The date range cannot exceed 90 days.", - title="End Date", - ), - ] = None - group_by: Annotated[ - list[ModelApiCostDimension] | None, - Field( - description="Dimensions to break costs down by, repeated once per dimension: api_key_prefix, user, model, or service_tier. Each result represents one observed combination of the requested dimensions within that day. For example, grouping by api_key_prefix and user returns each API-key and user pair that had usage. Combinations without usage are omitted, so result counts can differ between days. Omit for daily organization totals.", - title="Group By", - ), - ] = None - api_key_prefixes: Annotated[ - list[str] | None, +class ChainDeployments(BaseModel): + deployments: Annotated[ + list[ChainDeployment], + Field(description="A list of chain deployments", title="Deployments"), + ] + + +class CreateChainEnvironmentRequest(BaseModel): + name: Annotated[ + str, Field( - description="Return only costs for these exact API key prefixes, repeated once per prefix.", - title="Api Key Prefixes", + description="Name of the environment", examples=["staging"], title="Name" ), - ] = None - user_ids: Annotated[ - list[str] | None, + ] + promotion_settings: Annotated[ + UpdatePromotionSettings | None, Field( - description="Return only costs attributed to these exact user IDs, repeated once per ID.", - title="User Ids", + description="Promotion settings for the environment", + examples=[ + { + "promotion_cleanup_strategy": None, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": True, + "redeploy_on_promotion": True, + "rolling_deploy": None, + "rolling_deploy_config": None, + } + ], ), ] = None - models: Annotated[ - list[str] | None, + chainlet_settings: Annotated[ + list[ChainletEnvironmentSettingsRequest] | None, Field( - description="Return only costs for these exact model identifiers, repeated once per model.", - title="Models", + description="Mapping of chainlet name to the desired chainlet environment settings", + examples=[ + [ + { + "autoscaling_settings": { + "autoscaling_window": 800, + "concurrency_target": 4, + "max_replica": 3, + "max_scale_down_rate": None, + "min_replica": 2, + "scale_down_delay": 63, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + }, + "chainlet_name": "HelloWorld", + "instance_type_id": "2x8", + }, + { + "autoscaling_settings": { + "autoscaling_window": None, + "concurrency_target": None, + "max_replica": 3, + "max_scale_down_rate": None, + "min_replica": 3, + "scale_down_delay": None, + "target_in_flight_tokens": None, + "target_utilization_percentage": None, + }, + "chainlet_name": "RandInt", + "instance_type_id": "A10Gx8x32", + }, + ] + ], + title="Chainlet Settings", ), ] = None - service_tiers: Annotated[ - list[str] | None, + + +class UpdateChainEnvironmentRequest(BaseModel): + promotion_settings: Annotated[ + UpdatePromotionSettings | None, Field( - description="Return only costs for these exact service tiers, repeated once per tier.", - title="Service Tiers", + description="Promotion settings for the environment", + examples=[ + { + "promotion_cleanup_strategy": None, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": True, + "redeploy_on_promotion": None, + "rolling_deploy": None, + "rolling_deploy_config": None, + } + ], ), ] = None -class Volume(BaseModel): - namespace: Annotated[ - str, - Field( - description="Namespace the volume belongs to, in lowercase.", - title="Namespace", - ), - ] - name: Annotated[ - str, Field(description="Name of the volume, in lowercase.", title="Name") - ] - version_ref: Annotated[ - str, +class UpdateChainletEnvironmentInstanceTypeResponse(BaseModel): + requires_redeployment: Annotated[ + bool, Field( - description="Full address of the volume, as `bdn:/`. Paste this into the `bdn.mounts` section of a config.yaml.", - title="Version Ref", + description="Whether the resource update requires a re-deployment to update the instance type.", + title="Requires Redeployment", ), ] - sequence: Annotated[ - int, + chain_deployment: Annotated[ + ChainDeployment | None, Field( - description="Revision counter for the volume, incremented on every commit and tag change. Use it to detect that a volume changed.", - title="Sequence", + description="The chain deployment resulting from the resource update, if any." ), ] - updated_at: Annotated[ - AwareDatetime, + chainlet_environment_settings: Annotated[ + list[ChainletEnvironmentSettings], Field( - description="When the volume last changed, in ISO 8601 format.", - title="Updated At", + description="The updated chainlet environment settings", + title="Chainlet Environment Settings", ), ] - head: Annotated[ - VolumeVersionSummary | None, - Field( - description="Version that the reserved `head` tag points at, which a reference with no tag or digest resolves to. Null when the volume has no head, or when your API key cannot read it." - ), + + +class TrainingJob(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the training job.", title="Id") ] - tags: Annotated[ - list[VolumeTag], + created_at: Annotated[ + AwareDatetime, Field( - description="Tags on the volume that your API key can read.", title="Tags" + description="Time the job was created in ISO 8601 format.", + title="Created At", ), ] - tag_count: Annotated[ - int, + current_status: Annotated[ + str, Field( - description="Total number of tags on the volume, which can exceed the length of `tags` when your API key cannot read all of them.", - title="Tag Count", + description="Current status of the training job.", title="Current Status" ), ] - versions_alive: Annotated[ - int, + error_message: Annotated[ + str | None, Field( - description="Number of versions that have not been deleted.", - title="Versions Alive", + description="Error message if the training job failed.", + title="Error Message", ), + ] = None + instance_type: Annotated[ + InstanceType, Field(description="Instance type of the training job.") ] - versions_tombstoned: Annotated[ + node_count: Annotated[ int, Field( - description="Number of versions that have been deleted.", - title="Versions Tombstoned", + description="Number of nodes the job runs on. The instance type describes a single node, so the job's total GPU count is gpu_count multiplied by node_count.", + examples=[2], + ge=1, + title="Node Count", ), - ] - versions_untagged: Annotated[ - int, + ] = 1 + updated_at: Annotated[ + AwareDatetime, Field( - description="Number of versions that no tag points at.", - title="Versions Untagged", + description="Time the job was updated in ISO 8601 format.", + title="Updated At", ), ] - - -class ListVolumesResponse(BaseModel): - items: Annotated[ - list[Volume], Field(description="Items in this page.", title="Items") + training_project_id: Annotated[ + str, + Field(description="ID of the training project.", title="Training Project Id"), ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") + training_project: Annotated[ + TrainingProjectSummary, Field(description="Summary of the training project.") ] - - -class EnvironmentGroupManageAccess(BaseModel): - is_restricted: Annotated[ - bool, + name: Annotated[ + str | None, Field( - description="Whether the environment is restricted to a specific set of users.", - title="Is Restricted", + description="Name of the training job.", + examples=["gpt-oss-job"], + title="Name", ), - ] - users: Annotated[ - list[EnvironmentGroupUser] | None, + ] = None + checkpoint_sync_status: Annotated[ + CheckpointSyncStatus | None, + Field(description="Checkpoint sync status of the training job."), + ] = None + priority: Annotated[ + int, Field( - description="Users who can manage the environment while it is restricted, including organization and team admins who always have access. Empty when the environment is unrestricted.", - title="Users", + description="Queue priority. Higher values are dequeued first. NULL is treated as 0.", + title="Priority", + ), + ] = 0 + availability_model: Annotated[ + V1AvailabilityModel, + Field( + description="Capacity guarantee for the job. 'dedicated' is non-preemptible on-demand capacity; 'spot' is interruptible." ), + ] = V1AvailabilityModel.dedicated + user: Annotated[ + User | None, Field(description="The user who created the training job.") ] = None -class EnvironmentGroup(BaseModel): +class TrainingProject(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the training project", title="Id") + ] name: Annotated[ - str, + str, Field(description="Name of the training project.", title="Name") + ] + created_at: Annotated[ + AwareDatetime, Field( - description="Name of the environment group, matching the environment name it governs.", - examples=["staging"], - title="Name", + description="Time the training project was created in ISO 8601 format.", + title="Created At", ), ] - team_id: Annotated[ - str, + updated_at: Annotated[ + AwareDatetime, Field( - description="Unique identifier of the team the environment group belongs to.", - title="Team Id", + description="Time the training project was updated in ISO 8601 format.", + title="Updated At", ), ] team_name: Annotated[ - str, + str | None, Field( - description="Name of the team the environment group belongs to.", + description="Name of the team associated with the training project.", title="Team Name", ), - ] - manage_access: Annotated[ - EnvironmentGroupManageAccess, + ] = None + latest_job: Annotated[ + TrainingJob | None, Field( - description="Settings controlling who can manage this environment group." + description="Most recently created training job for the training project." ), ] -class EnvironmentGroups(BaseModel): - items: Annotated[ - list[EnvironmentGroup], Field(description="Items in this page.", title="Items") - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") +class UpsertTrainingProjectResponse(BaseModel): + training_project: Annotated[ + TrainingProject, Field(description="The upserted training project.") ] -class AuditLogEventAutoscalingScheduleChange(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - action: AuditLogEventAutoscalingScheduleAction - schedule_id: Annotated[str, Field(title="Schedule Id")] - previous: AuditLogEventAutoscalingScheduleSettings | None - current: AuditLogEventAutoscalingScheduleSettings | None - - -class AuditLogEventEnvironmentUpdated(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schedules: Annotated[ - list[AuditLogEventAutoscalingScheduleChange] | None, Field(title="Schedules") - ] - min_replica: Annotated[int, Field(title="Min Replica")] - max_replica: Annotated[int, Field(title="Max Replica")] - concurrency_target: Annotated[int, Field(title="Concurrency Target")] - autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] - scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] - target_utilization_percentage: Annotated[ - int | None, Field(title="Target Utilization Percentage") - ] - target_in_flight_tokens: Annotated[ - int | None, Field(title="Target In Flight Tokens") - ] - max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] - redeploy_on_promotion: Annotated[bool | None, Field(title="Redeploy On Promotion")] - rolling_deploy: Annotated[bool | None, Field(title="Rolling Deploy")] - rolling_deploy_strategy: Annotated[ - str | None, Field(title="Rolling Deploy Strategy") - ] - max_unavailable_percent: Annotated[ - int | None, Field(title="Max Unavailable Percent") - ] - max_surge_percent: Annotated[int | None, Field(title="Max Surge Percent")] - stabilization_time_seconds: Annotated[ - int | None, Field(title="Stabilization Time Seconds") - ] - replica_overhead_percent: Annotated[ - int | None, Field(title="Replica Overhead Percent") - ] - promotion_cleanup_strategy: Annotated[ - str | None, Field(title="Promotion Cleanup Strategy") - ] - ramp_up_while_promoting: Annotated[ - bool | None, Field(title="Ramp Up While Promoting") - ] - ramp_up_duration_seconds: Annotated[ - int | None, Field(title="Ramp Up Duration Seconds") +class ListTrainingProjectsResponse(BaseModel): + training_projects: Annotated[ + list[TrainingProject], + Field(description="List of training projects.", title="Training Projects"), ] - ramp_up_step_size: Annotated[int | None, Field(title="Ramp Up Step Size")] - request_backpressure_policy: Annotated[ - str | None, Field(title="Request Backpressure Policy") - ] = None - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - environment_name: Annotated[str, Field(title="Environment Name")] - deployment_type: Annotated[str | None, Field(title="Deployment Type")] - event_type: Annotated[Literal["ENVIRONMENT_UPDATED"], Field(title="Event Type")] - previous_settings: AuditLogEventEnvironmentSettings | None -class AuditLogEventModelDeploymentAutoscalingSettingsChanged(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - schedules: Annotated[ - list[AuditLogEventAutoscalingScheduleChange] | None, Field(title="Schedules") - ] - min_replica: Annotated[int, Field(title="Min Replica")] - max_replica: Annotated[int, Field(title="Max Replica")] - concurrency_target: Annotated[int, Field(title="Concurrency Target")] - autoscaling_window: Annotated[int | None, Field(title="Autoscaling Window")] - scale_down_delay: Annotated[int | None, Field(title="Scale Down Delay")] - target_utilization_percentage: Annotated[ - int | None, Field(title="Target Utilization Percentage") - ] - target_in_flight_tokens: Annotated[ - int | None, Field(title="Target In Flight Tokens") +class ListTrainingJobsResponse(BaseModel): + training_project: Annotated[ + TrainingProject, Field(description="The training project.") ] - max_scale_down_rate: Annotated[float | None, Field(title="Max Scale Down Rate")] - event_type: Annotated[ - Literal["MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED"], - Field(title="Event Type"), + training_jobs: Annotated[ + list[TrainingJob], + Field(description="List of training jobs.", title="Training Jobs"), ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - deployment_type: Annotated[str | None, Field(title="Deployment Type")] - previous_settings: AuditLogEventAutoscalingSettings | None -class AuditLogEventModelPromotionControlAction(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - event_type: Annotated[ - Literal["MODEL_PROMOTION_CONTROL_ACTION"], Field(title="Event Type") +class AwsIamDockerAuth(BaseModel): + access_key_secret_ref: Annotated[ + SecretReference, Field(description="Name of the access key secret") + ] + secret_access_key_secret_ref: Annotated[ + SecretReference, Field(description="Name of the secret key secret") ] - model_id: Annotated[str, Field(title="Model Id")] - model_name: Annotated[str, Field(title="Model Name")] - deployment_id: Annotated[str, Field(title="Deployment Id")] - deployment_name: Annotated[str, Field(title="Deployment Name")] - environment_name: Annotated[str, Field(title="Environment Name")] - environment_id: Annotated[str | None, Field(title="Environment Id")] - action: AuditLogPromotionControlAction -class Deployment(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the deployment", title="Id") - ] - created_at: Annotated[ - AwareDatetime, +class CreateJobWeightConfig(BaseModel): + source: Annotated[ + str, Field( - description="Time the deployment was created in ISO 8601 format", - title="Created At", + description="Weight source URI. Supported formats: hf://, s3://, gs://, r2://, cw://", + examples=[ + "hf://meta-llama/Llama-3-8B@main", + "s3://my-bucket/models/llama", + "gs://my-bucket/models/llama", + "r2://account_id.bucket/models/llama", + "r2://account_id.eu.bucket/models/llama", + "cw://my-bucket/models/llama", + ], + title="Source", ), ] - name: Annotated[str, Field(description="Name of the deployment", title="Name")] - model_id: Annotated[ - str, Field(description="Unique identifier of the model", title="Model Id") - ] - is_production: Annotated[ - bool, - Field( - description="Whether the deployment is the production deployment of the model", - title="Is Production", + mount_location: Annotated[ + str, + Field( + description="Path where weights will be mounted in the container", + examples=["/app/models/base", "/models/llama"], + title="Mount Location", ), ] - is_development: Annotated[ - bool, + allow_patterns: Annotated[ + list[str] | None, Field( - description="Whether the deployment is the development deployment of the model", - title="Is Development", + description="File patterns to include (Unix-style shell patterns)", + examples=[["*.safetensors", "config.json"]], + title="Allow Patterns", ), - ] - status: Annotated[DeploymentStatus, Field(description="Status of the deployment")] - active_replica_count: Annotated[ - int, - Field(description="Number of active replicas", title="Active Replica Count"), - ] - autoscaling_settings: Annotated[ - AutoscalingSettings | None, + ] = None + ignore_patterns: Annotated[ + list[str] | None, Field( - description="Autoscaling settings for the deployment. If null, the model has not finished deploying" + description="File patterns to exclude (Unix-style shell patterns)", + examples=[["*.bin", "*.h5"]], + title="Ignore Patterns", ), - ] - instance_type_name: Annotated[ + ] = None + auth_secret_name: Annotated[ str | None, Field( - description="Name of the instance type the model deployment is running on", - title="Instance Type Name", + description="Name of the workspace secret for authentication (e.g., HuggingFace token)", + examples=["hf_token", "aws_credentials"], + title="Auth Secret Name", ), - ] - environment: Annotated[ - str | None, + ] = None + auth: Annotated[ + TrainingWeightAuth | None, Field( - description="The environment associated with the deployment", - title="Environment", + description="Authentication configuration for the weight source.", + examples=[ + {"auth_method": "CUSTOM_SECRET", "auth_secret_name": "hf_token"}, + { + "auth_method": "AWS_OIDC", + "aws_oidc_region": "us-east-1", + "aws_oidc_role_arn": "arn:aws:iam::123456789012:role/weights-access", + }, + { + "auth_method": "GCP_OIDC", + "gcp_oidc_service_account": "weights-reader@example.iam.gserviceaccount.com", + "gcp_oidc_workload_id_provider": "projects/123456789/locations/global/workloadIdentityPools/baseten/providers/baseten", + }, + { + "auth_method": "AWS_ASSUME_ROLE", + "aws_assume_role_arn": "arn:aws:iam::123456789012:role/baseten-customer-access", + "aws_assume_role_region": "us-east-1", + }, + ], ), - ] - labels: Annotated[ - dict[str, Any] | None, + ] = None + + +class CreateTrainingJobRuntime(BaseModel): + start_commands: Annotated[ + list[str] | None, Field( - description="User-provided key-value labels for the deployment", - title="Labels", + description="Commands to execute when starting the runtime.", + examples=[["python main.py"]], + title="Start Commands", ), ] = None - region: Annotated[ - Region | None, - Field(description="The selected region for the deployment, if any"), + environment_variables: Annotated[ + dict[str, str | SecretReference] | None, + Field( + description="Environment variables to set in the runtime.", + examples=[{"API_KEY": "your_api_key_here", "PATH": "/usr/bin"}], + title="Environment Variables", + ), ] = None - request_backpressure_settings: Annotated[ - RequestBackpressureSettings, + artifacts: Annotated[ + list[CreateTrainingJobS3Artifact] | None, + Field(description="Runtime artifacts for the training job.", title="Artifacts"), + ] = None + enable_cache: Annotated[ + bool | None, Field( - description="Effective request backpressure settings for the deployment." + description="Deprecated. Use cache_config instead.", + examples=[True], + title="Enable Cache", + ), + ] = None + cache_config: Annotated[ + CreateTrainingJobCacheConfig | None, + Field( + description="Configuration for the read-write cache.", + examples=[ + { + "enable_legacy_hf_mount": True, + "enabled": True, + "mount_base_path": "/root/.cache", + "require_cache_affinity": True, + } + ], + ), + ] = None + checkpointing_config: Annotated[ + CreateTrainingJobCheckpointingConfig | None, + Field( + description="Configuration for checkpointing.", + examples=[ + { + "checkpoint_path": "/mnt/ckpts", + "enabled": True, + "volume_size_gib": None, + } + ], ), + ] = None + load_checkpoint_config: Annotated[ + LoadCheckpointConfig | None, + Field(description="Configuration for loading checkpoints"), + ] = None + + +class GcpServiceAccountJsonDockerAuth(BaseModel): + service_account_json_secret_ref: Annotated[ + SecretReference, Field(description="Name of the service account secret") ] -class CreatedModelDeployment(BaseModel): - model: Annotated[ - Model, +class RegistrySecretDockerAuth(BaseModel): + secret_ref: Annotated[ + SecretReference, Field( - description="The model the deployment belongs to. May have been created by this call." + description="Reference to a Baseten secret containing credentials in the format 'username:password'" ), ] - deployment: Annotated[ - Deployment, Field(description="The newly created deployment.") - ] -class Deployments(BaseModel): - deployments: Annotated[ - list[Deployment], - Field(description="A list of deployments of a model", title="Deployments"), +class CreateTrainingJobResponse(BaseModel): + training_job: Annotated[TrainingJob, Field(description="The created training job.")] + + +class GetTrainingJobResponse(BaseModel): + training_project: Annotated[ + TrainingProject, Field(description="The training project.") ] + training_job: Annotated[TrainingJob, Field(description="The fetched training job.")] -class RetryDeploymentResponse(BaseModel): - retried: Annotated[ - bool, +class UpdateTrainingJobResponse(BaseModel): + training_job: Annotated[TrainingJob, Field(description="The updated training job.")] + + +class RecreateTrainingJobResponse(BaseModel): + training_job: Annotated[TrainingJob, Field(description="The created training job.")] + + +class StorageMetrics(BaseModel): + usage_bytes: Annotated[ + list[TrainingJobMetric], Field( - description="Whether the retry was successfully initiated", title="Retried" + description="The number of bytes used on the storage entity.", + title="Usage Bytes", ), ] - reason: Annotated[ - str | None, + utilization: Annotated[ + list[TrainingJobMetric], Field( - description="Explanation of the result. Provided when retried is false to explain why retry was not possible.", - title="Reason", + description="The utilization of the storage entity as a decimal percentage.", + title="Utilization", ), - ] = None - deployment: Annotated[ - Deployment, Field(description="The deployment that was retried") ] -class ModelMetricDescriptor(BaseModel): - name: Annotated[str, Field(description="Canonical metric name.", title="Name")] - unit_hint: Annotated[ - ModelMetricUnitHint, Field(description="Advisory unit of the metric's values.") +class TrainingJobMetrics(BaseModel): + gpu_memory_usage_bytes: Annotated[ + dict[str, list[TrainingJobMetric]], + Field( + description="A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", + title="Gpu Memory Usage Bytes", + ), ] - kind: Annotated[ - ModelMetricKind, + gpu_utilization: Annotated[ + dict[str, list[TrainingJobMetric]], Field( - description="Semantic hint for how the metric behaves (GAUGE, COUNTER, HISTOGRAM)." + description="A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", + title="Gpu Utilization", ), ] - label_sets: Annotated[ - list[dict[str, str]], + cpu_usage: Annotated[ + list[TrainingJobMetric], Field( - description="The metric's series, in order. Each entry is the set of labels identifying one series; the value at the same index in each value set's ``values`` is that series' value. A plain metric has a single entry with no labels (`{}`). A histogram has one entry per quantile plus an average, e.g. {'quantile': '0.5'} … {'quantile': '0.99'}, {'stat': 'avg'}. A by-status metric has one entry per status, e.g. {'status': '2xx'}.", - title="Label Sets", + description="The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", + title="Cpu Usage", + ), + ] + cpu_memory_usage_bytes: Annotated[ + list[TrainingJobMetric], + Field( + description="The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", + title="Cpu Memory Usage Bytes", + ), + ] + ephemeral_storage: Annotated[ + StorageMetrics, + Field( + description="The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." ), ] -class GetModelMetricsResponse(BaseModel): - start_epoch_millis: Annotated[ - int, - Field(description="Start of the returned window.", title="Start Epoch Millis"), - ] - end_epoch_millis: Annotated[ - int, Field(description="End of the returned window.", title="End Epoch Millis") +class TrainingJobNodeMetrics(BaseModel): + node_id: Annotated[str, Field(description="The name of the node.", title="Node Id")] + metrics: Annotated[ + TrainingJobMetrics, Field(description="The metrics for the node.") ] - mode: Annotated[ModelMetricMode, Field(description="The aggregation mode used.")] - step_seconds: Annotated[ - int | None, + + +class GetTrainingJobMetricsResponse(BaseModel): + gpu_memory_usage_bytes: Annotated[ + dict[str, list[TrainingJobMetric]], Field( - description="Seconds per step; populated only in SERIES mode, null otherwise.", - title="Step Seconds", + description="A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", + title="Gpu Memory Usage Bytes", ), ] - metric_descriptors: Annotated[ - list[ModelMetricDescriptor], + gpu_utilization: Annotated[ + dict[str, list[TrainingJobMetric]], Field( - description="Descriptors for each metric; position defines the values index.", - title="Metric Descriptors", + description="A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", + title="Gpu Utilization", ), ] - metric_values: Annotated[ - list[ModelMetricValueSet], + cpu_usage: Annotated[ + list[TrainingJobMetric], Field( - description="Metric values per time step covering the window. In summary mode this always contains exactly one value set spanning the whole window.", - title="Metric Values", + description="The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", + title="Cpu Usage", ), ] - - -class AutoscalingSchedule(BaseModel): - id: Annotated[ - str, Field(description="Stable unique identifier of the schedule", title="Id") - ] - name: Annotated[str, Field(description="Name of the schedule", title="Name")] - enabled: Annotated[ - bool, Field(description="Whether the schedule is enabled", title="Enabled") - ] - autoscaling_settings: Annotated[ - AutoscalingScheduleSettings, + cpu_memory_usage_bytes: Annotated[ + list[TrainingJobMetric], Field( - description="Raw autoscaling overrides applied during the schedule window" + description="The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", + title="Cpu Memory Usage Bytes", ), ] - cadence: Annotated[ - Literal["DAILY", "HOURLY"], + ephemeral_storage: Annotated[ + StorageMetrics, Field( - description="Cadence of the schedule. DAILY runs once per selected weekday; HOURLY repeats the minute window every hour on selected weekdays.", - title="Cadence", + description="The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." ), ] - weekdays: Annotated[ - list[AutoscalingScheduleWeekday], - Field(description="Weekdays on which the schedule runs", title="Weekdays"), + training_job: Annotated[TrainingJob, Field(description="The training job.")] + cache: Annotated[ + StorageMetrics | None, + Field(description="The storage usage for the read-write cache."), ] - start_hour: Annotated[ - int | None, + per_node_metrics: Annotated[ + list[TrainingJobNodeMetrics], Field( - description="Start hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", - title="Start Hour", + description="The metrics for each node in the training job.", + title="Per Node Metrics", ), - ] = None - start_minute: Annotated[ - int, - Field(description="Start minute of the schedule window", title="Start Minute"), ] - end_hour: Annotated[ - int | None, - Field( - description="End hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", - title="End Hour", - ), - ] = None - end_minute: Annotated[ - int, Field(description="End minute of the schedule window", title="End Minute") + + +class StopTrainingJobResponse(BaseModel): + training_job: Annotated[TrainingJob, Field(description="The stopped training job.")] + + +class GetTrainingJobCheckpointsResponse(BaseModel): + training_job: Annotated[TrainingJob, Field(description="The training job.")] + checkpoints: Annotated[ + list[TrainingJobCheckpoint], + Field(description="The checkpoints for the training job.", title="Checkpoints"), ] -class Schedules(RootModel[AutoscalingSchedule | OneTimeAutoscalingSchedule]): - root: Annotated[ - AutoscalingSchedule | OneTimeAutoscalingSchedule, Field(discriminator="cadence") +class GetTrainingProjectResponse(BaseModel): + training_project: Annotated[ + TrainingProject, Field(description="The training project.") ] -class EnvironmentAutoscalingSchedules(BaseModel): - timezone: Annotated[ +class SearchTrainingJobsResponse(BaseModel): + training_jobs: Annotated[ + list[TrainingJob], + Field(description="List of training jobs.", title="Training Jobs"), + ] + + +class LoopsRun(BaseModel): + id: Annotated[str, Field(description="The run ID.", title="Id")] + session_id: Annotated[ + str, + Field(description="The session ID this run belongs to.", title="Session Id"), + ] + deployment_id: Annotated[ str | None, Field( - description="IANA timezone shared by all schedules. Omitted when no schedules exist.", - title="Timezone", + description="The ID of the Loops deployment the run executes on, if it has one.", + title="Deployment Id", ), ] = None - schedules: Annotated[ - list[Schedules], + name: Annotated[str, Field(description="The run's display name.", title="Name")] + base_model: Annotated[ + str, Field( - description="Autoscaling schedules ordered by creation time and stable identifier", - title="Schedules", + description="The HuggingFace base model the run is fine-tuning.", + title="Base Model", ), ] - applied_state: Annotated[ - AutoscalingScheduleState | None, + base_url: Annotated[str, Field(description="The run's base URL.", title="Base Url")] + created_at: Annotated[ + AwareDatetime, Field( - description="Autoscaling state on the current serving deployment, or null when no deployment exists" + description="Time the run was created in ISO 8601 format", + title="Created At", ), ] - - -class RollingDeployConfig(BaseModel): - rolling_deploy_strategy: Annotated[ - RollingDeployStrategy, - Field( - description="The rolling deploy strategy to use for promotions.", - examples=["REPLICA"], - ), - ] = RollingDeployStrategy.REPLICA - max_surge_percent: Annotated[ - int, - Field( - description="The maximum surge percentage for rolling deploys.", - examples=[25], - title="Max Surge Percent", - ), - ] = 25 - max_unavailable_percent: Annotated[ - int, + status: Annotated[LoopsRunStatus, Field(description="The run's current status.")] + user: Annotated[User, Field(description="The user who owns the run.")] + sampler: Annotated[ + LoopsSampler | None, Field( - description="The maximum unavailable percentage for rolling deploys.", - examples=[10], - title="Max Unavailable Percent", + description="The sampler bound to this run, or null for a trainer-only run that has not yet created a sampler." ), - ] = 0 - stabilization_time_seconds: Annotated[ - int, + ] = None + + +class ListLoopsRunsResponse(BaseModel): + runs: Annotated[list[LoopsRun], Field(description="List of runs.", title="Runs")] + + +class CreateLoopsRunResponse(BaseModel): + run: LoopsRun + + +class GetLoopsRunResponse(BaseModel): + run: Annotated[ + LoopsRun, Field(description="The Loops run with its associated sampler.") + ] + + +class LoopsDeploymentNodeMetrics(BaseModel): + node_id: Annotated[ + str, Field(description="Identifier for the node.", title="Node Id") + ] + gpu_memory_usage_bytes: Annotated[ + dict[str, list[TrainingJobMetric]], Field( - description="The stabilization time in seconds for rolling deploys.", - examples=[300], - title="Stabilization Time Seconds", + description="GPU memory usage bytes per GPU rank.", + title="Gpu Memory Usage Bytes", ), - ] = 0 - replica_overhead_percent: Annotated[ - int, + ] + gpu_utilization: Annotated[ + dict[str, list[TrainingJobMetric]], Field( - description="The replica overhead percentage for rolling deploys.", - examples=[0], - title="Replica Overhead Percent", + description="Fractional GPU utilization per GPU rank.", + title="Gpu Utilization", ), - ] = 0 + ] + cpu_usage: Annotated[ + list[TrainingJobMetric], + Field(description="CPU usage in cores.", title="Cpu Usage"), + ] + cpu_memory_usage_bytes: Annotated[ + list[TrainingJobMetric], + Field(description="CPU memory usage bytes.", title="Cpu Memory Usage Bytes"), + ] + ephemeral_storage: Annotated[ + StorageMetrics, Field(description="Ephemeral storage usage.") + ] -class UpdatePromotionSettings(BaseModel): - redeploy_on_promotion: Annotated[ - bool | None, +class APIKeyInfo(BaseModel): + prefix: Annotated[ + str, Field(description="The prefix of the API key", title="Prefix") + ] + name: Annotated[ + str | None, Field( - description="Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", - examples=[True], - title="Redeploy On Promotion", + description="Optional name for the API key", + examples=["my-api-key"], + title="Name", ), ] = None - rolling_deploy: Annotated[ - bool | None, + type: Annotated[ + APIKeyCategory, Field( - description="Whether the environment should rely on rolling deploy orchestration.", - examples=[True], - title="Rolling Deploy", + description="Type of the API key.", + examples=[ + "PERSONAL", + "ROUTES", + "WORKSPACE_MANAGE_API_KEYS", + "WORKSPACE_EXPORT_METRICS", + "WORKSPACE_INVOKE", + "WORKSPACE_MANAGE_ALL", + ], ), - ] = None - promotion_cleanup_strategy: Annotated[ - PromotionCleanupStrategy | None, + ] + model_ids: Annotated[ + list[str] | None, Field( - description="The cleanup strategy to use after a promotion completes.", - examples=["SCALE_TO_ZERO"], + description="List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", + examples=[["aaaaaaaa"]], + title="Model Ids", ), ] = None - rolling_deploy_config: Annotated[ - UpdateRollingDeployConfig | None, - Field(description="Rolling deploy configuration for promotions"), + team_name: Annotated[ + str | None, + Field( + description="The name of the team associated with the API key", + title="Team Name", + ), ] = None - ramp_up_while_promoting: Annotated[ - bool | None, + created_at: Annotated[ + AwareDatetime, + Field(description="Creation time in ISO 8601 format", title="Created At"), + ] + last_used_at: Annotated[ + AwareDatetime | None, Field( - description="Whether to ramp up traffic while promoting", - examples=[True], - title="Ramp Up While Promoting", + description="Last recorded use in ISO 8601 format, or null if unavailable. Updates may be delayed.", + title="Last Used At", ), ] = None - ramp_up_duration_seconds: Annotated[ - int | None, + owner: Annotated[ + APIKeyOwner | None, Field( - description="Duration of the ramp up in seconds", - examples=[600], - title="Ramp Up Duration Seconds", + description="The user who owns the API key. Only present for personal API keys." ), ] = None -class CreateEnvironmentRequest(BaseModel): +class APIKeys(BaseModel): + keys: Annotated[ + list[APIKeyInfo], + Field(description="A list of API key information", title="Keys"), + ] + + +class ModelAPI(BaseModel): name: Annotated[ str, Field( - description="Name of the environment", examples=["staging"], title="Name" + description="Identifier of the Model API. Stable, URL-safe slug used as the public identifier.", + examples=["llama-3-3-70b-instruct"], + title="Name", ), ] - autoscaling_settings: Annotated[ - UpdateAutoscalingSettings | None, + display_name: Annotated[ + str, Field( - description="Autoscaling settings for the environment", - examples=[ - { - "autoscaling_window": 800, - "concurrency_target": 3, - "max_replica": 2, - "max_scale_down_rate": None, - "min_replica": 1, - "scale_down_delay": 60, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - } - ], + description="Human-readable name of the Model API.", + examples=["Llama 3.3 70B Instruct"], + title="Display Name", ), - ] = None - promotion_settings: Annotated[ - UpdatePromotionSettings | None, + ] + description: Annotated[ + str, Field(description="Description of the Model API.", title="Description") + ] + model_family: Annotated[ + str | None, Field( - description="Promotion settings for the environment", - examples=[ - { - "promotion_cleanup_strategy": None, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": True, - "redeploy_on_promotion": True, - "rolling_deploy": True, - "rolling_deploy_config": None, - } - ], + description="Family the underlying model belongs to.", + examples=["Meta", "DeepSeek", "Qwen"], + title="Model Family", ), ] = None - request_backpressure_settings: Annotated[ - UpdateRequestBackpressureSettings | None, - Field(description="Request backpressure settings for the environment."), - ] = None - - -class UpdateEnvironmentRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - autoscaling_settings: Annotated[ - UpdateAutoscalingSettings | None, + release_date: Annotated[ + date_aliased, Field( - description="Autoscaling settings for the environment", - examples=[ - { - "autoscaling_window": 800, - "concurrency_target": 3, - "max_replica": 2, - "max_scale_down_rate": None, - "min_replica": 1, - "scale_down_delay": 60, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - } - ], + description="Date the Model API was made available.", title="Release Date" ), - ] = None - promotion_settings: Annotated[ - UpdatePromotionSettings | None, + ] + invoke_url: Annotated[ + str, Field( - description="Promotion settings for the environment", - examples=[ - { - "promotion_cleanup_strategy": None, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": True, - "redeploy_on_promotion": True, - "rolling_deploy": None, - "rolling_deploy_config": None, - } - ], + description="Base URL for invoking the Model API. OpenAI-shaped routes (e.g. /v1/chat/completions) live underneath this host.", + examples=["https://inference.baseten.co"], + title="Invoke Url", ), - ] = None - autoscaling_schedule_settings: Annotated[ - UpdateAutoscalingScheduleSettings | None, + ] + context_length: Annotated[ + int, Field( - description="Partial autoscaling schedule collection update. Omitted collection fields and existing schedules are unchanged; each submitted schedule is a complete create or replacement.", - examples=[ - { - "schedules": [ - { - "autoscaling_settings": { - "autoscaling_window": None, - "concurrency_target": None, - "max_replica": 8, - "max_scale_down_rate": None, - "min_replica": 2, - "scale_down_delay": None, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - }, - "cadence": "DAILY", - "enabled": True, - "end_hour": 10, - "end_minute": 0, - "name": "weekday-peak", - "start_hour": 8, - "start_minute": 0, - "weekdays": [ - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY", - ], - } - ], - "timezone": "America/Los_Angeles", - }, - {"delete_schedules": ["schedule-id"]}, - ], + description="The model's context window length, in tokens.", + examples=[8192], + title="Context Length", + ), + ] + cost_per_million_input_tokens: Annotated[ + float | CostPerMillionInputTokens | None, + Field( + description="Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", + examples=["0.13"], + title="Cost Per Million Input Tokens", + ), + ] + cost_per_million_output_tokens: Annotated[ + float | CostPerMillionOutputTokens | None, + Field( + description="Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", + examples=["0.50"], + title="Cost Per Million Output Tokens", + ), + ] + rate_limits: Annotated[ + list[RateLimit], + Field( + description="Rate limits in effect for the workspace. Workspace-specific overrides are returned when the workspace has added this Model API and configured them; otherwise the catalog default rate limits are returned.", + title="Rate Limits", + ), + ] + org_details: Annotated[ + ModelAPIOrgDetails | None, + Field( + description="Workspace-specific state. Null when the workspace has not added this Model API." ), ] = None - request_backpressure_settings: Annotated[ - UpdateRequestBackpressureSettings | None, + + +class ModelAPIsResponse(BaseModel): + items: Annotated[ + list[ModelAPI], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class ModelApisUsageBucket(BaseModel): + start_time: Annotated[ + AwareDatetime, + Field(description="Start of the bucket (inclusive), UTC", title="Start Time"), + ] + end_time: Annotated[ + AwareDatetime, + Field(description="End of the bucket (exclusive), UTC", title="End Time"), + ] + results: Annotated[ + list[ModelApisUsageResult] | None, Field( - description="Request backpressure settings for the environment.", - examples=[{"policy": "REJECT_ON_FULL"}], + description="Usage totals for this bucket, ordered by total tokens descending", + title="Results", ), ] = None -class ChainDeployment(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the chain deployment", title="Id") +class ModelApisUsageResponse(BaseModel): + items: Annotated[ + list[ModelApisUsageBucket], + Field(description="Items in this page.", title="Items"), + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class BenchmarkSnapshot(BaseModel): + run_id: Annotated[str, Field(title="Run Id")] + measured_at: Annotated[date_aliased, Field(title="Measured At")] + llm: LLMBenchmarkMetrics | None = None + tts: TTSBenchmarkMetrics | None = None + embedding: EmbeddingBenchmarkMetrics | None = None + replicas: Annotated[int | None, Field(title="Replicas")] = 2 + profile: Annotated[str | None, Field(title="Profile")] = "512x256" + + +class LibraryListingVersion(BaseModel): + version_tag: Annotated[ + str, + Field(description="Human-readable tag for this version", title="Version Tag"), + ] + is_live: Annotated[ + bool, + Field(description="Whether this version is the live version", title="Is Live"), + ] + allow_truss_download: Annotated[ + bool, + Field( + description="Whether users deploying this model can download the Truss", + title="Allow Truss Download", + ), + ] + oracle_version_id: Annotated[ + str, + Field(description="Id of the source model version", title="Oracle Version Id"), ] created_at: Annotated[ AwareDatetime, Field( - description="Time the chain deployment was created in ISO 8601 format", + description="Time the version was created in ISO 8601 format", title="Created At", ), ] - chain_id: Annotated[ - str, Field(description="Unique identifier of the chain", title="Chain Id") + modified_at: Annotated[ + AwareDatetime, + Field(description="Time the version was last modified", title="Modified At"), ] - environment: Annotated[ - str | None, + benchmark: Annotated[ + BenchmarkSnapshot | None, Field( - description="Environment the chain deployment is deployed in", - title="Environment", + description="Benchmark snapshot for this version, if one has been uploaded." ), - ] - chainlets: Annotated[ - list[Chainlet], - Field(description="Chainlets in the chain deployment", title="Chainlets"), - ] - status: Annotated[ - DeploymentStatus, Field(description="Status of the chain deployment") - ] + ] = None -class ChainDeployments(BaseModel): - deployments: Annotated[ - list[ChainDeployment], - Field(description="A list of chain deployments", title="Deployments"), - ] +class LibraryListingVersions(BaseModel): + versions: Annotated[list[LibraryListingVersion], Field(title="Versions")] -class CreateChainEnvironmentRequest(BaseModel): - name: Annotated[ - str, - Field( - description="Name of the environment", examples=["staging"], title="Name" - ), - ] - promotion_settings: Annotated[ - UpdatePromotionSettings | None, +class UpdateLibraryListingVersionRequest(BaseModel): + is_live: Annotated[ + bool | None, Field( - description="Promotion settings for the environment", - examples=[ - { - "promotion_cleanup_strategy": None, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": True, - "redeploy_on_promotion": True, - "rolling_deploy": None, - "rolling_deploy_config": None, - } - ], + description="Whether this version should be the live version. Setting to true demotes the current live version.", + title="Is Live", ), ] = None - chainlet_settings: Annotated[ - list[ChainletEnvironmentSettingsRequest] | None, + allow_truss_download: Annotated[ + bool | None, Field( - description="Mapping of chainlet name to the desired chainlet environment settings", - examples=[ - [ - { - "autoscaling_settings": { - "autoscaling_window": 800, - "concurrency_target": 4, - "max_replica": 3, - "max_scale_down_rate": None, - "min_replica": 2, - "scale_down_delay": 63, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - }, - "chainlet_name": "HelloWorld", - "instance_type_id": "2x8", - }, - { - "autoscaling_settings": { - "autoscaling_window": None, - "concurrency_target": None, - "max_replica": 3, - "max_scale_down_rate": None, - "min_replica": 3, - "scale_down_delay": None, - "target_in_flight_tokens": None, - "target_utilization_percentage": None, - }, - "chainlet_name": "RandInt", - "instance_type_id": "A10Gx8x32", - }, - ] - ], - title="Chainlet Settings", + description="Whether users deploying this model can download the Truss", + title="Allow Truss Download", ), ] = None - - -class UpdateChainEnvironmentRequest(BaseModel): - promotion_settings: Annotated[ - UpdatePromotionSettings | None, + benchmark: Annotated[ + BenchmarkSnapshot | None, Field( - description="Promotion settings for the environment", - examples=[ - { - "promotion_cleanup_strategy": None, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": True, - "redeploy_on_promotion": None, - "rolling_deploy": None, - "rolling_deploy_config": None, - } - ], + description="Benchmark snapshot for this version. When provided, replaces the stored benchmark." ), ] = None -class UpdateChainletEnvironmentInstanceTypeResponse(BaseModel): - requires_redeployment: Annotated[ - bool, +class ModelApisCostBucket(BaseModel): + date: Annotated[ + date_aliased, Field( - description="Whether the resource update requires a re-deployment to update the instance type.", - title="Requires Redeployment", + description="UTC calendar date for this bucket, from midnight inclusive to the next midnight exclusive.", + title="Date", ), ] - chain_deployment: Annotated[ - ChainDeployment | None, + results: Annotated[ + list[ModelApisCostResult] | None, Field( - description="The chain deployment resulting from the resource update, if any." + description="Cost totals for the observed combinations of requested dimensions in this bucket, ordered by those dimensions. Empty when the day has no matching usage.", + title="Results", ), + ] = None + + +class ModelApisCostsResponse(BaseModel): + items: Annotated[ + list[ModelApisCostBucket], + Field(description="Items in this page.", title="Items"), ] - chainlet_environment_settings: Annotated[ - list[ChainletEnvironmentSettings], - Field( - description="The updated chainlet environment settings", - title="Chainlet Environment Settings", - ), + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") ] -class TrainingJob(BaseModel): +class BillableResource(BaseModel): id: Annotated[ - str, Field(description="Unique identifier of the training job.", title="Id") + str, Field(description="Unique identifier of the resource", title="Id") ] - created_at: Annotated[ - AwareDatetime, + kind: Annotated[ + ResourceKind, Field( - description="Time the job was created in ISO 8601 format.", - title="Created At", + description="Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, or LOOPS_SAMPLER)" ), ] - current_status: Annotated[ - str, + name: Annotated[ + str | None, Field(description="Name of the resource", title="Name") + ] = None + model_id: Annotated[ + str | None, Field( - description="Current status of the training job.", title="Current Status" + description="Unique identifier of the parent model for model deployments and chainlets", + title="Model Id", ), - ] - error_message: Annotated[ + ] = None + model_name: Annotated[ str | None, Field( - description="Error message if the training job failed.", - title="Error Message", + description="Name of the parent resource (e.g., model name for model deployments, training project name for training jobs)", + title="Model Name", ), ] = None - instance_type: Annotated[ - InstanceType, Field(description="Instance type of the training job.") - ] - node_count: Annotated[ - int, + is_deleted: Annotated[ + bool, Field( - description="Number of nodes the job runs on. The instance type describes a single node, so the job's total GPU count is gpu_count multiplied by node_count.", - examples=[2], - ge=1, - title="Node Count", + description="Indicates if the resource has been deleted", title="Is Deleted" ), - ] = 1 - updated_at: Annotated[ - AwareDatetime, + ] + instance_type: Annotated[ + str | None, Field(description="Instance type used", title="Instance Type") + ] = None + base_model: Annotated[ + str | None, Field( - description="Time the job was updated in ISO 8601 format.", - title="Updated At", + description="Base model used by this Loops trainer or sampler", + title="Base Model", ), - ] - training_project_id: Annotated[ - str, - Field(description="ID of the training project.", title="Training Project Id"), - ] - training_project: Annotated[ - TrainingProjectSummary, Field(description="Summary of the training project.") - ] - name: Annotated[ + ] = None + environment_name: Annotated[ str | None, Field( - description="Name of the training job.", - examples=["gpt-oss-job"], - title="Name", + description="Environment name (e.g., 'production', 'staging')", + title="Environment Name", ), ] = None - checkpoint_sync_status: Annotated[ - CheckpointSyncStatus | None, - Field(description="Checkpoint sync status of the training job."), + chain_metadata: Annotated[ + ChainMetadata | None, + Field(description="Chain metadata if this is a chainlet deployment"), ] = None - priority: Annotated[ - int, + team_id: Annotated[ + str | None, Field( - description="Queue priority. Higher values are dequeued first. NULL is treated as 0.", - title="Priority", + description="Unique identifier of the team that owns the resource. Only present for organizations with multiple teams enabled.", + title="Team Id", ), - ] = 0 - availability_model: Annotated[ - V1AvailabilityModel, + ] = None + team_name: Annotated[ + str | None, Field( - description="Capacity guarantee for the job. 'dedicated' is non-preemptible on-demand capacity; 'spot' is interruptible." + description="Name of the team that owns the resource. Only present for organizations with multiple teams enabled.", + title="Team Name", ), - ] = V1AvailabilityModel.dedicated - user: Annotated[ - User | None, Field(description="The user who created the training job.") ] = None -class TrainingProject(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the training project", title="Id") - ] - name: Annotated[ - str, Field(description="Name of the training project.", title="Name") +class DedicatedItem(BaseModel): + billable_resource: Annotated[ + BillableResource, Field(description="The model deployment resource") ] - created_at: Annotated[ - AwareDatetime, + subtotal: Annotated[ + float | Subtotal3, Field( - description="Time the training project was created in ISO 8601 format.", - title="Created At", + description="Subtotal cost in dollars for this billable resource", + title="Subtotal", ), ] - updated_at: Annotated[ - AwareDatetime, + compute_cost: Annotated[ + float | ComputeCost1, Field( - description="Time the training project was updated in ISO 8601 format.", - title="Updated At", + description="Compute cost in dollars for this billable resource", + title="Compute Cost", ), ] - team_name: Annotated[ - str | None, + surcharge_cost: Annotated[ + float | SurchargeCost1, Field( - description="Name of the team associated with the training project.", - title="Team Name", + description="Model distribution surcharge in dollars for this billable resource", + title="Surcharge Cost", ), - ] = None - latest_job: Annotated[ - TrainingJob | None, + ] + minutes: Annotated[ + int, Field( - description="Most recently created training job for the training project." + description="Total minutes used for this billable resource", title="Minutes" ), ] - - -class UpsertTrainingProjectResponse(BaseModel): - training_project: Annotated[ - TrainingProject, Field(description="The upserted training project.") + inference_requests: Annotated[ + int, + Field( + description="Total inference requests for this billable resource", + title="Inference Requests", + ), ] + daily: Annotated[ + list[DailyDedicatedUsage] | None, + Field(description="Daily usage breakdown", title="Daily"), + ] = None -class ListTrainingProjectsResponse(BaseModel): - training_projects: Annotated[ - list[TrainingProject], - Field(description="List of training projects.", title="Training Projects"), +class DedicatedUsage(BaseModel): + subtotal: Annotated[ + float | Subtotal4, + Field( + description="Subtotal cost in dollars after applying credits used", + title="Subtotal", + ), ] - - -class ListTrainingJobsResponse(BaseModel): - training_project: Annotated[ - TrainingProject, Field(description="The training project.") + credits_used: Annotated[ + float | CreditsUsed, + Field(description="Credits applied in dollars", title="Credits Used"), ] - training_jobs: Annotated[ - list[TrainingJob], - Field(description="List of training jobs.", title="Training Jobs"), + total: Annotated[ + float | Total, Field(description="Total cost in dollars", title="Total") ] + minutes: Annotated[int, Field(description="Total minutes used", title="Minutes")] + breakdown: Annotated[ + list[DedicatedItem] | None, + Field(description="Per-deployment usage breakdown", title="Breakdown"), + ] = None -class AwsIamDockerAuth(BaseModel): - access_key_secret_ref: Annotated[ - SecretReference, Field(description="Name of the access key secret") - ] - secret_access_key_secret_ref: Annotated[ - SecretReference, Field(description="Name of the secret key secret") +class TrainingItem(BaseModel): + billable_resource: Annotated[ + BillableResource, Field(description="The training job resource") ] - - -class CreateJobWeightConfig(BaseModel): - source: Annotated[ - str, + subtotal: Annotated[ + float | Subtotal7, Field( - description="Weight source URI. Supported formats: hf://, s3://, gs://, r2://, cw://", - examples=[ - "hf://meta-llama/Llama-3-8B@main", - "s3://my-bucket/models/llama", - "gs://my-bucket/models/llama", - "r2://account_id.bucket/models/llama", - "r2://account_id.eu.bucket/models/llama", - "cw://my-bucket/models/llama", - ], - title="Source", + description="Subtotal cost in dollars for this billable resource", + title="Subtotal", ), ] - mount_location: Annotated[ - str, + minutes: Annotated[ + int, Field( - description="Path where weights will be mounted in the container", - examples=["/app/models/base", "/models/llama"], - title="Mount Location", + description="Total minutes used for this billable resource", title="Minutes" ), ] - allow_patterns: Annotated[ - list[str] | None, + daily: Annotated[ + list[DailyTrainingUsage] | None, + Field(description="Daily usage breakdown", title="Daily"), + ] = None + + +class TrainingUsage(BaseModel): + subtotal: Annotated[ + float | Subtotal8, Field( - description="File patterns to include (Unix-style shell patterns)", - examples=[["*.safetensors", "config.json"]], - title="Allow Patterns", + description="Subtotal cost in dollars after applying credits used", + title="Subtotal", ), + ] + credits_used: Annotated[ + float | CreditsUsed, + Field(description="Credits applied in dollars", title="Credits Used"), + ] + total: Annotated[ + float | Total, Field(description="Total cost in dollars", title="Total") + ] + minutes: Annotated[int, Field(description="Total minutes used", title="Minutes")] + breakdown: Annotated[ + list[TrainingItem] | None, + Field(description="Per-job usage breakdown", title="Breakdown"), ] = None - ignore_patterns: Annotated[ - list[str] | None, + + +class UsageSummary(BaseModel): + dedicated_usage: Annotated[ + DedicatedUsage | None, Field(description="Dedicated model serving usage") + ] = None + training_usage: Annotated[ + TrainingUsage | None, Field(description="Training usage") + ] = None + model_apis_usage: Annotated[ + ModelApisUsage | None, Field(description="Model APIs usage") + ] = None + + +class ExploreCost(BaseModel): + input: Annotated[ + float | None, + Field(description="USD per 1M input tokens, when available.", title="Input"), + ] = None + output: Annotated[ + float | None, + Field(description="USD per 1M output tokens, when available.", title="Output"), + ] = None + cache_read: Annotated[ + float | None, Field( - description="File patterns to exclude (Unix-style shell patterns)", - examples=[["*.bin", "*.h5"]], - title="Ignore Patterns", + description="USD per 1M input tokens read from cache, when available.", + title="Cache Read", ), ] = None - auth_secret_name: Annotated[ - str | None, + cache_write: Annotated[ + float | None, Field( - description="Name of the workspace secret for authentication (e.g., HuggingFace token)", - examples=["hf_token", "aws_credentials"], - title="Auth Secret Name", + description="USD per 1M input tokens written to cache, when available.", + title="Cache Write", ), ] = None - auth: Annotated[ - TrainingWeightAuth | None, + long_context: Annotated[ + ExploreCostValues | None, Field( - description="Authentication configuration for the weight source.", - examples=[ - {"auth_method": "CUSTOM_SECRET", "auth_secret_name": "hf_token"}, - { - "auth_method": "AWS_OIDC", - "aws_oidc_region": "us-east-1", - "aws_oidc_role_arn": "arn:aws:iam::123456789012:role/weights-access", - }, - { - "auth_method": "GCP_OIDC", - "gcp_oidc_service_account": "weights-reader@example.iam.gserviceaccount.com", - "gcp_oidc_workload_id_provider": "projects/123456789/locations/global/workloadIdentityPools/baseten/providers/baseten", - }, - { - "auth_method": "AWS_ASSUME_ROLE", - "aws_assume_role_arn": "arn:aws:iam::123456789012:role/baseten-customer-access", - "aws_assume_role_region": "us-east-1", - }, - ], + description="Prices for long-context requests, when the provider tiers by context length." ), ] = None -class CreateTrainingJobRuntime(BaseModel): - start_commands: Annotated[ - list[str] | None, +class ExploreMetadata(BaseModel): + slug: Annotated[ + str | None, Field( - description="Commands to execute when starting the runtime.", - examples=[["python main.py"]], - title="Start Commands", + description="Metadata slug, e.g. 'anthropic/claude-opus-4'; null for rows without one.", + title="Slug", ), - ] = None - environment_variables: Annotated[ - dict[str, str | SecretReference] | None, + ] + display_name: Annotated[ + str | None, + Field(description="Model display name, when available.", title="Display Name"), + ] + release_date: Annotated[ + date_aliased | None, Field( - description="Environment variables to set in the runtime.", - examples=[{"API_KEY": "your_api_key_here", "PATH": "/usr/bin"}], - title="Environment Variables", + description="Model release date. Month-only source dates use the first day of that month.", + title="Release Date", ), - ] = None - artifacts: Annotated[ - list[CreateTrainingJobS3Artifact] | None, - Field(description="Runtime artifacts for the training job.", title="Artifacts"), - ] = None - enable_cache: Annotated[ - bool | None, + ] + provider: Annotated[ + str | None, Field( - description="Deprecated. Use cache_config instead.", - examples=[True], - title="Enable Cache", + description="Provider key derived from the slug prefix, e.g. 'anthropic'; null for unprefixed slugs.", + title="Provider", ), - ] = None - cache_config: Annotated[ - CreateTrainingJobCacheConfig | None, + ] + context_window: Annotated[ + int | None, + Field(description="Total context window in tokens.", title="Context Window"), + ] + max_output_tokens: Annotated[ + int | None, Field( - description="Configuration for the read-write cache.", - examples=[ - { - "enable_legacy_hf_mount": True, - "enabled": True, - "mount_base_path": "/root/.cache", - "require_cache_affinity": True, - } - ], + description="Maximum output tokens per response.", title="Max Output Tokens" ), - ] = None - checkpointing_config: Annotated[ - CreateTrainingJobCheckpointingConfig | None, - Field( - description="Configuration for checkpointing.", - examples=[ - { - "checkpoint_path": "/mnt/ckpts", - "enabled": True, - "volume_size_gib": None, - } - ], + ] + input_modalities: Annotated[ + list[str], + Field(description="Accepted input modalities.", title="Input Modalities"), + ] + tools: Annotated[ + bool | None, + Field(description="Whether the model supports tool calling.", title="Tools"), + ] + reasoning_effort_levels: Annotated[ + list[str] | None, + Field( + description="Reasoning effort levels the model supports.", + title="Reasoning Effort Levels", ), - ] = None - load_checkpoint_config: Annotated[ - LoadCheckpointConfig | None, - Field(description="Configuration for loading checkpoints"), - ] = None - - -class GcpServiceAccountJsonDockerAuth(BaseModel): - service_account_json_secret_ref: Annotated[ - SecretReference, Field(description="Name of the service account secret") ] - - -class RegistrySecretDockerAuth(BaseModel): - secret_ref: Annotated[ - SecretReference, + parallel_tool_calls: Annotated[ + bool | None, Field( - description="Reference to a Baseten secret containing credentials in the format 'username:password'" + description="Whether the model supports parallel tool calls.", + title="Parallel Tool Calls", ), ] - - -class CreateTrainingJobResponse(BaseModel): - training_job: Annotated[TrainingJob, Field(description="The created training job.")] - - -class GetTrainingJobResponse(BaseModel): - training_project: Annotated[ - TrainingProject, Field(description="The training project.") + supported_api_formats: Annotated[ + ExploreMetadataAPIFormats | None, + Field(description="API formats the model supports."), + ] + cost: Annotated[ + ExploreCost | None, + Field(description="Provider list prices in USD per 1M tokens, when available."), ] - training_job: Annotated[TrainingJob, Field(description="The fetched training job.")] - - -class UpdateTrainingJobResponse(BaseModel): - training_job: Annotated[TrainingJob, Field(description="The updated training job.")] -class RecreateTrainingJobResponse(BaseModel): - training_job: Annotated[TrainingJob, Field(description="The created training job.")] +class ExploreMetadataResponse(BaseModel): + items: Annotated[ + list[ExploreMetadata], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] -class StorageMetrics(BaseModel): - usage_bytes: Annotated[ - list[TrainingJobMetric], +class Route(BaseModel): + id: Annotated[str, Field(description="Stable route identifier.", title="Id")] + name: Annotated[ + str, Field( - description="The number of bytes used on the storage entity.", - title="Usage Bytes", + description="Name to send in the inference request's model field.", + title="Name", ), ] - utilization: Annotated[ - list[TrainingJobMetric], + team_id: Annotated[ + str, Field(description="Identifier of the owning team.", title="Team Id") + ] + team_name: Annotated[ + str, Field(description="Name of the owning team.", title="Team Name") + ] + display_name: Annotated[ + str, Field( - description="The utilization of the storage entity as a decimal percentage.", - title="Utilization", + description="Display label, defaulting to the route name.", + title="Display Name", ), ] - - -class TrainingJobMetrics(BaseModel): - gpu_memory_usage_bytes: Annotated[ - dict[str, list[TrainingJobMetric]], + description: Annotated[ + str, Field( - description="A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", - title="Gpu Memory Usage Bytes", + description="Short description of the route, empty when unset.", + title="Description", ), ] - gpu_utilization: Annotated[ - dict[str, list[TrainingJobMetric]], + target: Annotated[ + RouteTargetBasetenModelAPI + | RouteTargetAnthropic + | RouteTargetOpenAI + | RouteTargetXAI, Field( - description="A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", - title="Gpu Utilization", + description="Configured upstream target.", + discriminator="type", + title="Target", ), ] - cpu_usage: Annotated[ - list[TrainingJobMetric], + metadata: Annotated[ + ExploreMetadata | None, Field( - description="The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", - title="Cpu Usage", + description="Resolved model metadata; null when the route has no linked metadata row." ), ] - cpu_memory_usage_bytes: Annotated[ - list[TrainingJobMetric], + invoke_url: Annotated[ + str, Field( - description="The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", - title="Cpu Memory Usage Bytes", + description="Base URL for inference requests using this route.", + title="Invoke Url", ), ] - ephemeral_storage: Annotated[ - StorageMetrics, + created_at: Annotated[ + AwareDatetime, Field(description="Creation time, ISO 8601.", title="Created At") + ] + + +class RoutesResponse(BaseModel): + items: Annotated[ + list[Route], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class RoutesUsageBucket(BaseModel): + date: Annotated[ + date_aliased, Field( - description="The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." + description="UTC calendar date for this bucket, from midnight inclusive to the next midnight exclusive.", + title="Date", + ), + ] + results: Annotated[ + list[RoutesUsageResult], + Field( + description="Usage broken down by the requested dimensions. Empty when there is no usage.", + title="Results", ), ] -class TrainingJobNodeMetrics(BaseModel): - node_id: Annotated[str, Field(description="The name of the node.", title="Node Id")] - metrics: Annotated[ - TrainingJobMetrics, Field(description="The metrics for the node.") +class RoutesUsageResponse(BaseModel): + items: Annotated[ + list[RoutesUsageBucket], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") ] -class GetTrainingJobMetricsResponse(BaseModel): - gpu_memory_usage_bytes: Annotated[ - dict[str, list[TrainingJobMetric]], +class RouteHarnessModel(BaseModel): + source: Annotated[ + RouteHarnessModelSource, Field( - description="A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", - title="Gpu Memory Usage Bytes", + description="Who chose this role's route: `team` if a team admin set it, or `baseten` if it is Baseten's default, chosen from the team's Model API routes." ), ] - gpu_utilization: Annotated[ - dict[str, list[TrainingJobMetric]], + route: Annotated[Route, Field(description="Route to use for this role.")] + + +class UpdateCodexHarnessConfig(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ + str, Field( - description="A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", - title="Gpu Utilization", + description="Identifier of the team whose default models to set. Every route must belong to this team.", + min_length=1, + title="Team Id", ), ] - cpu_usage: Annotated[ - list[TrainingJobMetric], + harness: Annotated[ + Literal["codex"], Field( - description="The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", - title="Cpu Usage", + description="Codex, which supports only the `primary` role.", + title="Harness", ), ] - cpu_memory_usage_bytes: Annotated[ - list[TrainingJobMetric], + models: Annotated[ + UpdatePrimaryHarnessModels, Field( - description="The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", - title="Cpu Memory Usage Bytes", + description="Route IDs for the model roles to change. Roles left out are unchanged." ), ] - ephemeral_storage: Annotated[ - StorageMetrics, + + +class UpdateRouteHarnessConfigRequest( + RootModel[ + UpdateClaudeCodeHarnessConfig + | UpdateOpenCodeHarnessConfig + | UpdateCodexHarnessConfig + ] +): + root: Annotated[ + UpdateClaudeCodeHarnessConfig + | UpdateOpenCodeHarnessConfig + | UpdateCodexHarnessConfig, + Field(discriminator="harness", title="UpdateRouteHarnessConfigRequestV1"), + ] + + +class EndpointTarget(BaseModel): + provider: Annotated[GatewayProvider, Field(description="Upstream provider.")] + secret_id: Annotated[ + str | None, Field(description="Referenced secret, if any.", title="Secret Id") + ] = None + target_model: Annotated[ + str | None, + Field(description="Upstream model name, if any.", title="Target Model"), + ] = None + base_url: Annotated[ + str | None, Field( - description="The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." + description="Custom OpenAI-compatible base URL, if any.", title="Base Url" + ), + ] = None + model_id: Annotated[ + str | None, Field(description="Baseten model, if any.", title="Model Id") + ] = None + environment_name: Annotated[ + str | None, + Field( + description="Baseten model environment, if non-production.", + title="Environment Name", ), + ] = None + vertex_config: Annotated[ + VertexTargetConfig | None, + Field(description="Google Vertex configuration, if any."), + ] = None + + +class Endpoint(BaseModel): + id: Annotated[ + str, Field(description="Stable identifier for the endpoint.", title="Id") ] - training_job: Annotated[TrainingJob, Field(description="The training job.")] - cache: Annotated[ - StorageMetrics | None, - Field(description="The storage usage for the read-write cache."), + slug: Annotated[ + str, + Field( + description="Globally-unique routing slug.", + examples=["baseten/mymodel-4"], + title="Slug", + ), ] - per_node_metrics: Annotated[ - list[TrainingJobNodeMetrics], + region: Annotated[ + SharedEndpointRegion, + Field(description="Region this endpoint's routing serves."), + ] + created_at: Annotated[ + AwareDatetime, Field(description="Creation time, ISO 8601.", title="Created At") + ] + updated_at: Annotated[ + AwareDatetime, + Field(description="Last update time, ISO 8601.", title="Updated At"), + ] + targets: Annotated[ + list[EndpointTarget], Field( - description="The metrics for each node in the training job.", - title="Per Node Metrics", + description="The endpoint's upstream targets. Exactly one target is supported at this time.", + title="Targets", ), ] -class StopTrainingJobResponse(BaseModel): - training_job: Annotated[TrainingJob, Field(description="The stopped training job.")] +class EndpointsResponse(BaseModel): + items: Annotated[ + list[Endpoint], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] -class GetTrainingJobCheckpointsResponse(BaseModel): - training_job: Annotated[TrainingJob, Field(description="The training job.")] - checkpoints: Annotated[ - list[TrainingJobCheckpoint], - Field(description="The checkpoints for the training job.", title="Checkpoints"), +class EffectiveUsageLimit(BaseModel): + type: Annotated[ + LimitType, + Field(description="The type of the usage limit", examples=["REQUEST", "TOKEN"]), + ] + unit: Annotated[ + UsageLimitUnit, + Field(description="The unit of the usage limit", examples=["DAY"]), + ] + threshold: Annotated[ + int, + Field( + description="The threshold for the usage limit", + examples=[10000000], + ge=0, + title="Threshold", + ), + ] + source_group: Annotated[ + str, + Field( + description="ID of the group in the hierarchy this limit is anchored to.", + examples=["abc123"], + title="Source Group", + ), ] -class GetTrainingProjectResponse(BaseModel): - training_project: Annotated[ - TrainingProject, Field(description="The training project.") +class GroupHierarchy(BaseModel): + limit_enforcement: Annotated[ + LimitEnforcement, Field(examples=["CASCADING", "INDEPENDENT"]) ] + parent_group_id: Annotated[ + str | None, Field(examples=["abc123"], title="Parent Group Id") + ] = None -class SearchTrainingJobsResponse(BaseModel): - training_jobs: Annotated[ - list[TrainingJob], - Field(description="List of training jobs.", title="Training Jobs"), - ] +class ModelConfig(BaseModel): + slug: Annotated[str, Field(description="Shared endpoint slug.", title="Slug")] + rate_limits: Annotated[list[RateLimit] | None, Field(title="Rate Limits")] = None + usage_limits: Annotated[list[UsageLimit] | None, Field(title="Usage Limits")] = None -class LoopsRun(BaseModel): - id: Annotated[str, Field(description="The run ID.", title="Id")] - session_id: Annotated[ - str, - Field(description="The session ID this run belongs to.", title="Session Id"), +class CreateGroupRequest(BaseModel): + metadata: Annotated[ + GroupMetadata, Field(description="Group identity + display metadata.") ] - deployment_id: Annotated[ - str | None, - Field( - description="The ID of the Loops deployment the run executes on, if it has one.", - title="Deployment Id", - ), - ] = None - name: Annotated[str, Field(description="The run's display name.", title="Name")] - base_model: Annotated[ - str, + models: Annotated[ + list[ModelConfig], Field( - description="The HuggingFace base model the run is fine-tuning.", - title="Base Model", + description="Per-model rate and usage limit configuration. Defines the group's complete model set. Must be non-empty.", + examples=[[{"slug": "my-org/claude"}]], + min_length=1, + title="Models", ), ] - base_url: Annotated[str, Field(description="The run's base URL.", title="Base Url")] - created_at: Annotated[ - AwareDatetime, + hierarchy: Annotated[ + CreateGroupHierarchy, Field( - description="Time the run was created in ISO 8601 format", - title="Created At", + description="Parent linkage and limit enforcement mode. Immutable after creation." ), ] - status: Annotated[LoopsRunStatus, Field(description="The run's current status.")] - user: Annotated[User, Field(description="The user who owns the run.")] - sampler: Annotated[ - LoopsSampler | None, + + +class UpdateGroupRequest(BaseModel): + metadata: Annotated[ + UpdateGroupMetadata | None, + Field(description="Mutable group metadata.", examples=[{"name": "Acme Prod"}]), + ] = None + models: Annotated[ + list[ModelConfig] | None, Field( - description="The sampler bound to this run, or null for a trainer-only run that has not yet created a sampler." + description="Per-model rate and usage limit configuration.", title="Models" ), ] = None -class ListLoopsRunsResponse(BaseModel): - runs: Annotated[list[LoopsRun], Field(description="List of runs.", title="Runs")] - - -class CreateLoopsRunResponse(BaseModel): - run: LoopsRun - - -class GetLoopsRunResponse(BaseModel): - run: Annotated[ - LoopsRun, Field(description="The Loops run with its associated sampler.") - ] - - -class LoopsDeploymentNodeMetrics(BaseModel): - node_id: Annotated[ - str, Field(description="Identifier for the node.", title="Node Id") - ] - gpu_memory_usage_bytes: Annotated[ - dict[str, list[TrainingJobMetric]], - Field( - description="GPU memory usage bytes per GPU rank.", - title="Gpu Memory Usage Bytes", - ), +class SandboxExpirationPolicy( + RootModel[ + SandboxTTLIdleExpirationPolicy + | SandboxTTLMaxAgeExpirationPolicy + | SandboxDateExpirationPolicy ] - gpu_utilization: Annotated[ - dict[str, list[TrainingJobMetric]], +): + root: Annotated[ + SandboxTTLIdleExpirationPolicy + | SandboxTTLMaxAgeExpirationPolicy + | SandboxDateExpirationPolicy, Field( - description="Fractional GPU utilization per GPU rank.", - title="Gpu Utilization", + description="Expiration policy. The type determines whether value is a duration or an absolute timestamp.", + discriminator="type", ), ] - cpu_usage: Annotated[ - list[TrainingJobMetric], - Field(description="CPU usage in cores.", title="Cpu Usage"), - ] - cpu_memory_usage_bytes: Annotated[ - list[TrainingJobMetric], - Field(description="CPU memory usage bytes.", title="Cpu Memory Usage Bytes"), - ] - ephemeral_storage: Annotated[ - StorageMetrics, Field(description="Ephemeral storage usage.") - ] -class APIKeyInfo(BaseModel): - prefix: Annotated[ - str, Field(description="The prefix of the API key", title="Prefix") - ] - name: Annotated[ - str | None, - Field( - description="Optional name for the API key", - examples=["my-api-key"], - title="Name", - ), - ] = None - type: Annotated[ - APIKeyCategory, +class SandboxProxyConfig(BaseModel): + allowed_domains: Annotated[ + list[str] | None, Field( - description="Type of the API key.", + description="List of allowed external domains (allowlist). When set, only these domains are reachable. Supports wildcards (e.g. *.storage.example.com).", examples=[ - "PERSONAL", - "WORKSPACE_MANAGE_API_KEYS", - "WORKSPACE_EXPORT_METRICS", - "WORKSPACE_INVOKE", - "WORKSPACE_MANAGE_ALL", + [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org", + ] ], ), - ] - model_ids: Annotated[ + ] = None + bypass: Annotated[ list[str] | None, Field( - description="List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", - examples=[["aaaaaaaa"]], - title="Model Ids", + description="Domains that bypass the proxy entirely via the NO_PROXY directive. Traffic to these destinations goes direct, not through the CONNECT tunnel. Supports wildcards. Note that localhost, private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), 169.254.169.254, .local and .internal are always bypassed by default.", + examples=[["registry.npmjs.org"]], ), ] = None - team_name: Annotated[ - str | None, + forbidden_domains: Annotated[ + list[str] | None, Field( - description="The name of the team associated with the API key", - title="Team Name", + description="List of forbidden external domains (denylist). When set, all domains except these are reachable. Supports wildcards (e.g. *.malware.com). If both allowed_domains and forbidden_domains are set, allowed_domains takes precedence.", + examples=[["facebook.com", "*.facebook.com"]], ), ] = None - owner: Annotated[ - APIKeyOwner | None, + routing: Annotated[ + list[SandboxProxyTarget] | None, Field( - description="The user who owns the API key. Only present for personal API keys." + description='Per-destination routing rules with header/body injection and secrets. Use destinations ["*"] for global rules that apply to all destinations.', + examples=[ + [ + { + "destinations": ["api.openai.com"], + "headers": {"Authorization": "Bearer {{SECRET:openai-key}}"}, + "body": {"user": "baseten-api-review-0916"}, + "secrets": {"openai-key": "sk-proj-demo-not-a-valid-api-key"}, + } + ] + ], ), ] = None -class APIKeys(BaseModel): - keys: Annotated[ - list[APIKeyInfo], - Field(description="A list of API key information", title="Keys"), +class SandboxPorts(RootModel[list[SandboxPort]]): + root: Annotated[ + list[SandboxPort], + Field( + description="Set of ports for a resource", + examples=[[{"name": "http", "protocol": "HTTP", "target": 3000}]], + ), ] -class ModelAPI(BaseModel): +class ListImagesResponse(BaseModel): + items: Annotated[list[Image], Field(description="Image repositories on this page.")] + pagination: SandboxApiPagination + + +class ListImageTagsResponse(BaseModel): + items: list[ImageTag] + pagination: SandboxApiPagination + + +class SandboxLibraryImage(BaseModel): name: Annotated[ str, Field( - description="Identifier of the Model API. Stable, URL-safe slug used as the public identifier.", - examples=["llama-3-3-70b-instruct"], - title="Name", + description="Stable identifier of the built-in image.", + examples=["base-image"], ), ] display_name: Annotated[ - str, - Field( - description="Human-readable name of the Model API.", - examples=["Llama 3.3 70B Instruct"], - title="Display Name", - ), - ] + str | None, Field(description="Human-readable name.", examples=["Base Image"]) + ] = None description: Annotated[ - str, Field(description="Description of the Model API.", title="Description") - ] - model_family: Annotated[ str | None, Field( - description="Family the underlying model belongs to.", - examples=["META", "DEEPSEEK", "QWEN"], - title="Model Family", + description="Short description.", + examples=["A minimal sandbox environment with the sandbox execution API."], ), ] = None - release_date: Annotated[ - date_aliased, - Field( - description="Date the Model API was made available.", title="Release Date" - ), - ] - invoke_url: Annotated[ + long_description: Annotated[ + str | None, Field(description="Detailed description.") + ] = None + image: Annotated[ str, Field( - description="Base URL for invoking the Model API. OpenAI-shaped routes (e.g. /v1/chat/completions) live underneath this host.", - examples=["https://inference.baseten.co"], - title="Invoke Url", - ), - ] - context_length: Annotated[ - int, - Field( - description="The model's context window length, in tokens.", - examples=[8192], - title="Context Length", - ), - ] - cost_per_million_input_tokens: Annotated[ - float | CostPerMillionInputTokens | None, - Field( - description="Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", - examples=["0.13"], - title="Cost Per Million Input Tokens", + description="Image reference including its tag, usable as the image of a sandbox.", + examples=["baseten/base-image:latest"], ), ] - cost_per_million_output_tokens: Annotated[ - float | CostPerMillionOutputTokens | None, + memory: Annotated[ + int | None, Field( - description="Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", - examples=["0.50"], - title="Cost Per Million Output Tokens", + description="Recommended memory allocation in megabytes.", examples=[4096] ), - ] - rate_limits: Annotated[ - list[RateLimit], + ] = None + ports: SandboxPorts | None = None + categories: Annotated[ + list[str] | None, Field(description="Categories of the image.") + ] = None + tags: Annotated[list[str] | None, Field(description="Tags of the image.")] = None + url: Annotated[str | None, Field(description="Documentation URL.")] = None + icon: Annotated[str | None, Field(description="Icon URL.")] = None + icon_light: Annotated[str | None, Field(description="Light-mode icon URL.")] = None + icon_dark: Annotated[str | None, Field(description="Dark-mode icon URL.")] = None + enterprise: Annotated[ + bool | None, Field( - description="Rate limits in effect for the workspace. Workspace-specific overrides are returned when the workspace has added this Model API and configured them; otherwise the catalog default rate limits are returned.", - title="Rate Limits", + description="Whether the image requires an enterprise plan.", + examples=[False], ), - ] - org_details: Annotated[ - ModelAPIOrgDetails | None, + ] = None + hidden: Annotated[ + bool | None, Field( - description="Workspace-specific state. Null when the workspace has not added this Model API." + description="Whether the image is hidden. Always false in listings.", + examples=[False], ), - ] = None - - -class ModelAPIsResponse(BaseModel): - items: Annotated[ - list[ModelAPI], Field(description="Items in this page.", title="Items") - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] - - -class ModelApisUsageBucket(BaseModel): - start_time: Annotated[ - AwareDatetime, - Field(description="Start of the bucket (inclusive), UTC", title="Start Time"), - ] - end_time: Annotated[ - AwareDatetime, - Field(description="End of the bucket (exclusive), UTC", title="End Time"), - ] - results: Annotated[ - list[ModelApisUsageResult] | None, + ] = None + coming_soon: Annotated[ + bool | None, Field( - description="Usage totals for this bucket, ordered by total tokens descending", - title="Results", + description="Whether the image is not yet available. Always false in listings.", + examples=[False], ), ] = None + creation_options: SandboxLibraryImageCreationOptions | None = None -class ModelApisUsageResponse(BaseModel): - items: Annotated[ - list[ModelApisUsageBucket], - Field(description="Items in this page.", title="Items"), - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] - - -class BenchmarkSnapshot(BaseModel): - run_id: Annotated[str, Field(title="Run Id")] - measured_at: Annotated[date_aliased, Field(title="Measured At")] - llm: LLMBenchmarkMetrics | None = None - tts: TTSBenchmarkMetrics | None = None - embedding: EmbeddingBenchmarkMetrics | None = None - replicas: Annotated[int | None, Field(title="Replicas")] = 2 - profile: Annotated[str | None, Field(title="Profile")] = "512x256" +class ListSandboxLibraryImagesResponse(BaseModel): + items: Annotated[list[SandboxLibraryImage], Field(description="Built-in images.")] -class LibraryListingVersion(BaseModel): - version_tag: Annotated[ - str, - Field(description="Human-readable tag for this version", title="Version Tag"), - ] - is_live: Annotated[ - bool, - Field(description="Whether this version is the live version", title="Is Live"), +class AuditLogEntry(BaseModel): + id: Annotated[ + str, Field(description="Unique identifier of the audit-log entry.", title="Id") ] - allow_truss_download: Annotated[ - bool, + created: Annotated[ + AwareDatetime, Field( - description="Whether users deploying this model can download the Truss", - title="Allow Truss Download", + description="Time the action occurred, in ISO 8601 format.", title="Created" ), ] - oracle_version_id: Annotated[ - str, - Field(description="Id of the source model version", title="Oracle Version Id"), + event_type: Annotated[ + AuditLogEventType, Field(description="Type of action that was recorded.") ] - created_at: Annotated[ - AwareDatetime, + event_data: Annotated[ + AuditLogEventModelDeployed + | AuditLogEventModelDeploymentActivated + | AuditLogEventModelDeploymentDeactivated + | AuditLogEventModelDeploymentRetried + | AuditLogEventModelDeploymentPromoted + | AuditLogEventModelDeploymentAutoscalingSettingsChanged + | AuditLogEventModelDeploymentRequestBackpressureSettingsChanged + | AuditLogEventModelDeploymentInstanceTypeChanged + | AuditLogEventModelDeploymentDeleted + | AuditLogEventModelDeleted + | AuditLogEventModelRenamed + | AuditLogEventChainDeployed + | AuditLogEventChainDeploymentActivated + | AuditLogEventChainDeploymentDeactivated + | AuditLogEventChainDeploymentPromoted + | AuditLogEventChainletAutoscalingSettingsChanged + | AuditLogEventChainletInstanceTypeChanged + | AuditLogEventChainDeploymentDeleted + | AuditLogEventChainDeleted + | AuditLogEventChainEnvironmentCreated + | AuditLogEventChainEnvironmentUpdated + | AuditLogEventSecretUpdated + | AuditLogEventSecretDeleted + | AuditLogEventApiKeyCreated + | AuditLogEventApiKeyDeleted + | AuditLogEventGatewayEndpointCreated + | AuditLogEventGatewayEndpointUpdated + | AuditLogEventGatewayEndpointDeleted + | AuditLogEventProviderConnectionCreated + | AuditLogEventProviderConnectionUpdated + | AuditLogEventProviderConnectionDeleted + | AuditLogEventUserInvited + | AuditLogEventUserJoinedOrganization + | AuditLogEventWebhookSigningSecretCreated + | AuditLogEventWebhookSigningSecretRotated + | AuditLogEventWebhookSigningSecretDeleted + | AuditLogEventUserRoleUpdated + | AuditLogEventUserTeamRoleUpdated + | AuditLogEventUserRemoved + | AuditLogEventDirectoryGroupRoleUpdated + | AuditLogEventRequireGroupBasedAdminsEnabled + | AuditLogEventEnvironmentCreated + | AuditLogEventEnvironmentUpdated + | AuditLogEventEnvironmentDeleted + | AuditLogEventReplicaTerminated + | AuditLogEventModelPromotionControlAction + | AuditLogEventSshCertificateSigned + | AuditLogEventVolumeDeleted + | AuditLogEventVolumeVersionDeleted + | AuditLogEventVolumeVersionRestored, Field( - description="Time the version was created in ISO 8601 format", - title="Created At", + description="Structured details of the action, discriminated by `event_type`.", + discriminator="event_type", + title="Event Data", ), ] - modified_at: Annotated[ - AwareDatetime, - Field(description="Time the version was last modified", title="Modified At"), + source: Annotated[ + AuditLogSource | None, + Field(description="Surface that issued the action, if known."), + ] = None + actor: Annotated[ + AuditLogActor, Field(description="The actor that performed the action.") ] - benchmark: Annotated[ - BenchmarkSnapshot | None, + client_name: Annotated[ + str | None, Field( - description="Benchmark snapshot for this version, if one has been uploaded." + description="Name of the client that issued the action, if known.", + title="Client Name", + ), + ] = None + client_version: Annotated[ + str | None, + Field( + description="Version of the client that issued the action, if known.", + title="Client Version", + ), + ] = None + client_session_id: Annotated[ + str | None, + Field( + description="Opaque identifier grouping actions from the same client session, if known.", + title="Client Session Id", ), ] = None -class LibraryListingVersions(BaseModel): - versions: Annotated[list[LibraryListingVersion], Field(title="Versions")] +class ListAuditLogsResponse(BaseModel): + items: Annotated[ + list[AuditLogEntry], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] -class UpdateLibraryListingVersionRequest(BaseModel): - is_live: Annotated[ +class PromotionSettings(BaseModel): + redeploy_on_promotion: Annotated[ bool | None, Field( - description="Whether this version should be the live version. Setting to true demotes the current live version.", - title="Is Live", + description="Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", + examples=[True], + title="Redeploy On Promotion", ), - ] = None - allow_truss_download: Annotated[ + ] = False + rolling_deploy: Annotated[ bool | None, Field( - description="Whether users deploying this model can download the Truss", - title="Allow Truss Download", + description="Whether the environment should rely on rolling deploy orchestration.", + examples=[True], + title="Rolling Deploy", ), - ] = None - benchmark: Annotated[ - BenchmarkSnapshot | None, + ] = False + promotion_cleanup_strategy: Annotated[ + PromotionCleanupStrategy | None, Field( - description="Benchmark snapshot for this version. When provided, replaces the stored benchmark." + description="The cleanup strategy to use after a promotion completes.", + examples=["SCALE_TO_ZERO"], ), + ] = PromotionCleanupStrategy.SCALE_TO_ZERO + rolling_deploy_config: Annotated[ + RollingDeployConfig | None, + Field(description="Rolling deploy configuration for promotions"), ] = None - - -class ModelApisCostBucket(BaseModel): - date: Annotated[ - date_aliased, + ramp_up_while_promoting: Annotated[ + bool | None, Field( - description="UTC calendar date for this bucket, from midnight inclusive to the next midnight exclusive.", - title="Date", + description="Whether to ramp up traffic while promoting", + examples=[True], + title="Ramp Up While Promoting", ), - ] - results: Annotated[ - list[ModelApisCostResult] | None, + ] = False + ramp_up_duration_seconds: Annotated[ + int | None, Field( - description="Cost totals for the observed combinations of requested dimensions in this bucket, ordered by those dimensions. Empty when the day has no matching usage.", - title="Results", + description="Duration of the ramp up in seconds", + examples=[600], + title="Ramp Up Duration Seconds", ), - ] = None + ] = 600 -class ModelApisCostsResponse(BaseModel): - items: Annotated[ - list[ModelApisCostBucket], - Field(description="Items in this page.", title="Items"), +class ChainEnvironment(BaseModel): + name: Annotated[str, Field(description="Name of the environment", title="Name")] + created_at: Annotated[ + AwareDatetime, + Field( + description="Time the environment was created in ISO 8601 format", + title="Created At", + ), ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") + chain_id: Annotated[ + str, Field(description="Unique identifier of the chain", title="Chain Id") ] - - -class BillableResource(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the resource", title="Id") + promotion_settings: Annotated[ + PromotionSettings, Field(description="Promotion settings for the environment") ] - kind: Annotated[ - ResourceKind, + chainlet_settings: Annotated[ + list[ChainletEnvironmentSettings], Field( - description="Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, or LOOPS_SAMPLER)" + description="Environment settings for the chainlets", + title="Chainlet Settings", ), ] - name: Annotated[ - str | None, Field(description="Name of the resource", title="Name") - ] = None - model_id: Annotated[ - str | None, + current_deployment: Annotated[ + ChainDeployment | None, + Field(description="Current chain deployment of the environment"), + ] + candidate_deployment: Annotated[ + ChainDeployment | None, Field( - description="Unique identifier of the parent model for model deployments and chainlets", - title="Model Id", + description="Candidate chain deployment being promoted to the environment, if a promotion is in progress" ), ] = None - model_name: Annotated[ - str | None, - Field( - description="Name of the parent resource (e.g., model name for model deployments, training project name for training jobs)", - title="Model Name", - ), + in_progress_promotion: Annotated[ + InProgressPromotion | None, + Field(description="Details of the in-progress promotion, if any"), ] = None - is_deleted: Annotated[ - bool, + + +class DockerAuth(BaseModel): + registry: Annotated[ + str, Field(description="Registry to authenticate with", title="Registry") + ] + auth_method: Annotated[ + DockerAuthType, Field( - description="Indicates if the resource has been deleted", title="Is Deleted" + description="Method to authenticate with the registry", + examples=[ + "GCP_SERVICE_ACCOUNT_JSON", + "AWS_IAM", + "AWS_OIDC", + "GCP_OIDC", + "REGISTRY_SECRET", + "AWS_ASSUME_ROLE", + ], ), ] - instance_type: Annotated[ - str | None, Field(description="Instance type used", title="Instance Type") + gcp_service_account_json_docker_auth: Annotated[ + GcpServiceAccountJsonDockerAuth | None, + Field(description="GCP service account details for the registry"), ] = None - base_model: Annotated[ - str | None, - Field( - description="Base model used by this Loops trainer or sampler", - title="Base Model", - ), + aws_iam_docker_auth: Annotated[ + AwsIamDockerAuth | None, Field(description="AWS details for the registry") ] = None - environment_name: Annotated[ - str | None, - Field( - description="Environment name (e.g., 'production', 'staging')", - title="Environment Name", - ), + aws_oidc_docker_auth: Annotated[ + AwsOidcDockerAuth | None, Field(description="AWS OIDC details for the registry") ] = None - chain_metadata: Annotated[ - ChainMetadata | None, - Field(description="Chain metadata if this is a chainlet deployment"), + gcp_oidc_docker_auth: Annotated[ + GcpOidcDockerAuth | None, Field(description="GCP OIDC details for the registry") ] = None - team_id: Annotated[ - str | None, + registry_secret_docker_auth: Annotated[ + RegistrySecretDockerAuth | None, Field( - description="Unique identifier of the team that owns the resource. Only present for organizations with multiple teams enabled.", - title="Team Id", + description="Required when auth_method is REGISTRY_SECRET. Supports any Docker registry (Docker Hub, GHCR, NGC, etc.) via username:password credentials stored as a Baseten secret." ), ] = None - team_name: Annotated[ - str | None, + aws_assume_role_docker_auth: Annotated[ + AwsAssumeRoleDockerAuth | None, Field( - description="Name of the team that owns the resource. Only present for organizations with multiple teams enabled.", - title="Team Name", + description="Required when auth_method is AWS_ASSUME_ROLE. Baseten assumes the given IAM role with its own AWS principal and your organization's external ID, with no OIDC provider registration in your account." ), ] = None -class DedicatedItem(BaseModel): - billable_resource: Annotated[ - BillableResource, Field(description="The model deployment resource") - ] - subtotal: Annotated[ - float | Subtotal3, +class LoopsDeploymentMetrics(BaseModel): + inference_volume: Annotated[ + list[TrainingJobMetric], Field( - description="Subtotal cost in dollars for this billable resource", - title="Subtotal", + description="Number of inference requests per unit time (requests per second).", + title="Inference Volume", ), ] - compute_cost: Annotated[ - float | ComputeCost1, + concurrent_requests: Annotated[ + list[TrainingJobMetric], Field( - description="Compute cost in dollars for this billable resource", - title="Compute Cost", + description="Number of in-progress concurrent inference requests. Source: the queue-proxy ``revision_queue_depth`` gauge on ``http-usermetric``.", + title="Concurrent Requests", ), ] - surcharge_cost: Annotated[ - float | SurchargeCost1, + response_time_stats: Annotated[ + list[ResponseTimeDatapoint], Field( - description="Model distribution surcharge in dollars for this billable resource", - title="Surcharge Cost", + description="Percentiles of the response time distribution.", + title="Response Time Stats", ), ] - minutes: Annotated[ - int, + inference_volume_by_status: Annotated[ + list[InferenceVolumeByStatusDatapoint], Field( - description="Total minutes used for this billable resource", title="Minutes" + description="Request rate split by response code class.", + title="Inference Volume By Status", ), ] - inference_requests: Annotated[ - int, + gpu_memory_usage_bytes: Annotated[ + dict[str, list[TrainingJobMetric]], Field( - description="Total inference requests for this billable resource", - title="Inference Requests", + description="Leader-pod GPU memory bytes per GPU rank.", + title="Gpu Memory Usage Bytes", ), ] - daily: Annotated[ - list[DailyDedicatedUsage] | None, - Field(description="Daily usage breakdown", title="Daily"), - ] = None - - -class DedicatedUsage(BaseModel): - subtotal: Annotated[ - float | Subtotal4, + gpu_utilization: Annotated[ + dict[str, list[TrainingJobMetric]], Field( - description="Subtotal cost in dollars after applying credits used", - title="Subtotal", + description="Leader-pod fractional GPU utilization per GPU rank.", + title="Gpu Utilization", ), ] - credits_used: Annotated[ - float | CreditsUsed, - Field(description="Credits applied in dollars", title="Credits Used"), - ] - total: Annotated[ - float | Total, Field(description="Total cost in dollars", title="Total") - ] - minutes: Annotated[int, Field(description="Total minutes used", title="Minutes")] - breakdown: Annotated[ - list[DedicatedItem] | None, - Field(description="Per-deployment usage breakdown", title="Breakdown"), - ] = None - - -class TrainingItem(BaseModel): - billable_resource: Annotated[ - BillableResource, Field(description="The training job resource") + cpu_usage: Annotated[ + list[TrainingJobMetric], + Field(description="Leader-pod CPU usage in cores.", title="Cpu Usage"), ] - subtotal: Annotated[ - float | Subtotal7, + cpu_memory_usage_bytes: Annotated[ + list[TrainingJobMetric], Field( - description="Subtotal cost in dollars for this billable resource", - title="Subtotal", + description="Leader-pod CPU memory usage bytes.", + title="Cpu Memory Usage Bytes", ), ] - minutes: Annotated[ - int, + ephemeral_storage: Annotated[ + StorageMetrics, Field(description="Leader-pod ephemeral storage usage.") + ] + per_node_metrics: Annotated[ + list[LoopsDeploymentNodeMetrics], Field( - description="Total minutes used for this billable resource", title="Minutes" + description="Per-node compute breakdown for multinode trainer deployments.", + title="Per Node Metrics", ), ] - daily: Annotated[ - list[DailyTrainingUsage] | None, - Field(description="Daily usage breakdown", title="Daily"), - ] = None -class TrainingUsage(BaseModel): - subtotal: Annotated[ - float | Subtotal8, - Field( - description="Subtotal cost in dollars after applying credits used", - title="Subtotal", - ), - ] - credits_used: Annotated[ - float | CreditsUsed, - Field(description="Credits applied in dollars", title="Credits Used"), +class GetLoopsDeploymentMetricsResponse(BaseModel): + deployment_id: Annotated[ + str, Field(description="The trainer deployment ID.", title="Deployment Id") ] - total: Annotated[ - float | Total, Field(description="Total cost in dollars", title="Total") + metrics: Annotated[ + LoopsDeploymentMetrics, Field(description="Metrics for the deployment.") ] - minutes: Annotated[int, Field(description="Total minutes used", title="Minutes")] - breakdown: Annotated[ - list[TrainingItem] | None, - Field(description="Per-job usage breakdown", title="Breakdown"), - ] = None -class UsageSummary(BaseModel): - dedicated_usage: Annotated[ - DedicatedUsage | None, Field(description="Dedicated model serving usage") - ] = None - training_usage: Annotated[ - TrainingUsage | None, Field(description="Training usage") - ] = None - model_apis_usage: Annotated[ - ModelApisUsage | None, Field(description="Model APIs usage") - ] = None +class RouteHarnessConfig(BaseModel): + models: Annotated[ + dict[RouteHarnessRole, RouteHarnessModel], + Field(description="Route for each model role, keyed by role.", title="Models"), + ] -class EndpointTarget(BaseModel): - provider: Annotated[GatewayProvider, Field(description="Upstream provider.")] - secret_id: Annotated[ - str | None, Field(description="Referenced secret, if any.", title="Secret Id") - ] = None - target_model: Annotated[ - str | None, - Field(description="Upstream model name, if any.", title="Target Model"), - ] = None - base_url: Annotated[ - str | None, - Field( - description="Custom OpenAI-compatible base URL, if any.", title="Base Url" - ), - ] = None - model_id: Annotated[ - str | None, Field(description="Baseten model, if any.", title="Model Id") - ] = None - environment_name: Annotated[ - str | None, +class RouteHarnessConfigsResponse(BaseModel): + harness_configs: Annotated[ + dict[RouteHarness, RouteHarnessConfig], Field( - description="Baseten model environment, if non-production.", - title="Environment Name", + description="Default models for each harness, keyed by harness. A harness is omitted when none of its roles has a route.", + title="Harness Configs", ), + ] + + +class EffectiveModelConfig(BaseModel): + slug: Annotated[str, Field(description="Shared endpoint slug.", title="Slug")] + rate_limits: Annotated[ + list[EffectiveRateLimit] | None, Field(title="Rate Limits") ] = None - vertex_config: Annotated[ - VertexTargetConfig | None, - Field(description="Google Vertex configuration, if any."), + usage_limits: Annotated[ + list[EffectiveUsageLimit] | None, Field(title="Usage Limits") ] = None -class Endpoint(BaseModel): +class Group(BaseModel): id: Annotated[ - str, Field(description="Stable identifier for the endpoint.", title="Id") + str, Field(description="Internal Baseten ID for the group.", title="Id") ] - slug: Annotated[ - str, + metadata: Annotated[ + GroupMetadata, Field(description="Group identity + display metadata.") + ] + models: Annotated[list[ModelConfig] | None, Field(title="Models")] = None + effective_models: Annotated[ + list[EffectiveModelConfig] | None, Field(title="Effective Models") + ] = None + hierarchy: Annotated[ + GroupHierarchy, Field( - description="Globally-unique routing slug.", - examples=["baseten/mymodel-4"], - title="Slug", + description="Parent linkage and limit enforcement mode. Parent is null for root groups." ), ] - region: Annotated[ - SharedEndpointRegion, - Field(description="Region this endpoint's routing serves."), - ] created_at: Annotated[ - AwareDatetime, Field(description="Creation time, ISO 8601.", title="Created At") - ] - updated_at: Annotated[ - AwareDatetime, - Field(description="Last update time, ISO 8601.", title="Updated At"), - ] - targets: Annotated[ - list[EndpointTarget], - Field( - description="The endpoint's upstream targets. Exactly one target is supported at this time.", - title="Targets", - ), + AwareDatetime, + Field(description="When this group was created.", title="Created At"), ] -class EndpointsResponse(BaseModel): +class GroupsResponse(BaseModel): items: Annotated[ - list[Endpoint], Field(description="Items in this page.", title="Items") + list[Group], Field(description="Items in this page.", title="Items") ] pagination: Annotated[ PaginationResponse, Field(description="Pagination metadata for the page.") ] -class EffectiveUsageLimit(BaseModel): - type: Annotated[ - LimitType, - Field(description="The type of the usage limit", examples=["REQUEST", "TOKEN"]), - ] - unit: Annotated[ - UsageLimitUnit, - Field(description="The unit of the usage limit", examples=["DAY"]), - ] - threshold: Annotated[ - int, +class SandboxLifecycle(BaseModel): + expiration_policies: Annotated[ + list[SandboxExpirationPolicy] | None, Field( - description="The threshold for the usage limit", - examples=[10000000], - ge=0, - title="Threshold", + description="List of expiration policies. Multiple policies can be combined; whichever condition is met first triggers the action.", + examples=[ + [ + {"action": "DELETE", "type": "TTL_IDLE", "value": "24h"}, + {"action": "DELETE", "type": "TTL_MAX_AGE", "value": "7d"}, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z", + }, + ] + ], ), - ] - source_group: Annotated[ - str, + ] = None + terminated_retention: Annotated[ + str | None, Field( - description="ID of the group in the hierarchy this limit is anchored to.", - examples=["abc123"], - title="Source Group", + description="Duration to keep the sandbox record after termination for log access (e.g., '1h', '24h', '7d'). Defaults to 5m. Subject to maximum quota limits.", + examples=["24h"], ), - ] - - -class GroupHierarchy(BaseModel): - limit_enforcement: Annotated[ - LimitEnforcement, Field(examples=["CASCADING", "INDEPENDENT"]) - ] - parent_group_id: Annotated[ - str | None, Field(examples=["abc123"], title="Parent Group Id") ] = None -class ModelConfig(BaseModel): - slug: Annotated[str, Field(description="Shared endpoint slug.", title="Slug")] - rate_limits: Annotated[list[RateLimit] | None, Field(title="Rate Limits")] = None - usage_limits: Annotated[list[UsageLimit] | None, Field(title="Usage Limits")] = None - - -class CreateGroupRequest(BaseModel): - metadata: Annotated[ - GroupMetadata, Field(description="Group identity + display metadata.") - ] - models: Annotated[ - list[ModelConfig], +class SandboxNetwork(BaseModel): + proxy: Annotated[ + SandboxProxyConfig | None, Field( - description="Per-model rate and usage limit configuration. Defines the group's complete model set. Must be non-empty.", - examples=[[{"slug": "my-org/claude"}]], - min_length=1, - title="Models", + description="Proxy configuration for routing sandbox HTTP traffic through the platform proxy with MITM inspection and per-destination header/body injection", + examples=[ + { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org", + ], + "bypass": ["registry.npmjs.org"], + "forbidden_domains": ["facebook.com", "*.facebook.com"], + "routing": [ + { + "destinations": ["api.openai.com"], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": {"user": "baseten-api-review-0916"}, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + }, + } + ], + } + ], ), - ] - hierarchy: Annotated[ - CreateGroupHierarchy, + ] = None + subnet: Annotated[ + str | None, Field( - description="Parent linkage and limit enforcement mode. Immutable after creation." + description='Subnet name for the sandbox. Defaults to "default" at creation.', + examples=["default"], ), - ] + ] = None -class UpdateGroupRequest(BaseModel): - metadata: Annotated[ - UpdateGroupMetadata | None, - Field(description="Mutable group metadata.", examples=[{"name": "Acme Prod"}]), +class SandboxConfiguration(BaseModel): + enabled: Annotated[ + bool, + Field( + description="When false, the sandbox is disabled and will not accept connections", + examples=[True], + ), + ] = True + lifecycle: Annotated[ + SandboxLifecycle | None, + Field( + description="Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", + examples=[ + { + "expiration_policies": [ + {"action": "DELETE", "type": "TTL_IDLE", "value": "24h"}, + {"action": "DELETE", "type": "TTL_MAX_AGE", "value": "7d"}, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z", + }, + ], + "terminated_retention": "24h", + } + ], + ), ] = None - models: Annotated[ - list[ModelConfig] | None, + network: Annotated[ + SandboxNetwork | None, Field( - description="Per-model rate and usage limit configuration.", title="Models" + description="Network configuration for a sandbox including subnet, domain filtering, and proxy settings", + examples=[ + { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org", + ], + "bypass": ["registry.npmjs.org"], + "forbidden_domains": ["facebook.com", "*.facebook.com"], + "routing": [ + { + "destinations": ["api.openai.com"], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": {"user": "baseten-api-review-0916"}, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + }, + } + ], + }, + "subnet": "default", + } + ], ), ] = None - - -class AuditLogEntry(BaseModel): - id: Annotated[ - str, Field(description="Unique identifier of the audit-log entry.", title="Id") - ] - created: Annotated[ - AwareDatetime, + region: Annotated[ + str | None, Field( - description="Time the action occurred, in ISO 8601 format.", title="Created" + description="Region where the sandbox runs (for example us-pdx-1 or eu-lon-1). When omitted at creation, the closest region is selected.", + examples=["us-pdx-1"], ), - ] - event_type: Annotated[ - AuditLogEventType, Field(description="Type of action that was recorded.") - ] - event_data: Annotated[ - AuditLogEventModelDeployed - | AuditLogEventModelDeploymentActivated - | AuditLogEventModelDeploymentDeactivated - | AuditLogEventModelDeploymentRetried - | AuditLogEventModelDeploymentPromoted - | AuditLogEventModelDeploymentAutoscalingSettingsChanged - | AuditLogEventModelDeploymentRequestBackpressureSettingsChanged - | AuditLogEventModelDeploymentInstanceTypeChanged - | AuditLogEventModelDeploymentDeleted - | AuditLogEventModelDeleted - | AuditLogEventChainDeployed - | AuditLogEventChainDeploymentActivated - | AuditLogEventChainDeploymentDeactivated - | AuditLogEventChainDeploymentPromoted - | AuditLogEventChainletAutoscalingSettingsChanged - | AuditLogEventChainletInstanceTypeChanged - | AuditLogEventChainDeploymentDeleted - | AuditLogEventChainDeleted - | AuditLogEventChainEnvironmentCreated - | AuditLogEventChainEnvironmentUpdated - | AuditLogEventSecretUpdated - | AuditLogEventSecretDeleted - | AuditLogEventApiKeyCreated - | AuditLogEventApiKeyDeleted - | AuditLogEventGatewayEndpointCreated - | AuditLogEventGatewayEndpointUpdated - | AuditLogEventGatewayEndpointDeleted - | AuditLogEventUserInvited - | AuditLogEventUserJoinedOrganization - | AuditLogEventWebhookSigningSecretCreated - | AuditLogEventWebhookSigningSecretRotated - | AuditLogEventWebhookSigningSecretDeleted - | AuditLogEventUserRoleUpdated - | AuditLogEventUserTeamRoleUpdated - | AuditLogEventUserRemoved - | AuditLogEventDirectoryGroupRoleUpdated - | AuditLogEventRequireGroupBasedAdminsEnabled - | AuditLogEventEnvironmentCreated - | AuditLogEventEnvironmentUpdated - | AuditLogEventEnvironmentDeleted - | AuditLogEventReplicaTerminated - | AuditLogEventModelPromotionControlAction - | AuditLogEventSshCertificateSigned - | AuditLogEventVolumeDeleted - | AuditLogEventVolumeVersionDeleted - | AuditLogEventVolumeVersionRestored, + ] = None + envs: Annotated[ + list[SandboxEnv] | None, Field( - description="Structured details of the action, discriminated by `event_type`.", - discriminator="event_type", - title="Event Data", + description="Environment variables injected into the sandbox.", + examples=[ + [ + {"name": "NODE_ENV", "secret": False, "value": "production"}, + {"name": "PORT", "secret": False, "value": "3000"}, + ] + ], ), - ] - source: Annotated[ - AuditLogSource | None, - Field(description="Surface that issued the action, if known."), ] = None - actor: Annotated[ - AuditLogActor, Field(description="The actor that performed the action.") - ] - client_name: Annotated[ + image: Annotated[ str | None, Field( - description="Name of the client that issued the action, if known.", - title="Client Name", + description="Image reference including its tag. Built-in image references are returned in the canonical baseten/ namespace. Use baseten/base-image:latest to get started with the built-in sandbox execution API. This image is available directly without building, pushing, or listing images through GET /v1/sandboxes/images.", + examples=["baseten/base-image:latest"], ), ] = None - client_version: Annotated[ - str | None, + memory: Annotated[ + int | None, Field( - description="Version of the client that issued the action, if known.", - title="Client Version", + description="Memory allocation in megabytes. Also determines CPU allocation (CPU cores = memory in MB / 2048, e.g., 4096MB = 2 CPUs).", + examples=[4096], + ge=1, ), ] = None - client_session_id: Annotated[ + ports: Annotated[ + SandboxPorts | None, + Field( + description="Set of ports for a resource", + examples=[[{"name": "http", "protocol": "HTTP", "target": 3000}]], + ), + ] = None + external_id: Annotated[ str | None, Field( - description="Opaque identifier grouping actions from the same client session, if known.", - title="Client Session Id", + description="Caller-owned identifier for external lookups. Max 64 chars, alphanumeric + dash.", + examples=["api-review-20260916-001"], + max_length=64, + pattern="^[A-Za-z0-9-]+$", + ), + ] = None + labels: Annotated[ + SandboxMetadataLabels | None, + Field( + description="Key-value pairs for organizing and filtering resources. Labels can be used to categorize resources by environment, project, team, or any custom taxonomy.", + examples=[ + {"env": "development", "project": "api-review", "team": "engineering"} + ], ), ] = None -class ListAuditLogsResponse(BaseModel): - items: Annotated[ - list[AuditLogEntry], Field(description="Items in this page.", title="Items") - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] - - -class PromotionSettings(BaseModel): - redeploy_on_promotion: Annotated[ +class CreateSandboxRequest(BaseModel): + create_if_not_exists: Annotated[ bool | None, Field( - description="Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", - examples=[True], - title="Redeploy On Promotion", + description="When true, return the existing live sandbox with this name or recreate it if it is failed, terminated, or being deleted. The server handles concurrent creation and deletion races with a bounded wait; persistent contention returns a conflict. Requires name. Existing configuration is preserved. Defaults to false when omitted." + ), + ] = None + name: Annotated[ + str | None, + Field( + description="Optional unique sandbox name. Generated by the server when omitted; immutable after creation.", + examples=["baseten-api-review-0916"], + min_length=1, + ), + ] = None + lifecycle: Annotated[ + SandboxLifecycle | None, + Field( + description="Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", + examples=[ + { + "expiration_policies": [ + {"action": "DELETE", "type": "TTL_IDLE", "value": "24h"}, + {"action": "DELETE", "type": "TTL_MAX_AGE", "value": "7d"}, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z", + }, + ], + "terminated_retention": "24h", + } + ], + ), + ] = None + network: Annotated[ + SandboxNetwork | None, + Field( + description="Network configuration for a sandbox including subnet, domain filtering, and proxy settings", + examples=[ + { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org", + ], + "bypass": ["registry.npmjs.org"], + "forbidden_domains": ["facebook.com", "*.facebook.com"], + "routing": [ + { + "destinations": ["api.openai.com"], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": {"user": "baseten-api-review-0916"}, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + }, + } + ], + }, + "subnet": "default", + } + ], + ), + ] = None + region: Annotated[ + str | None, + Field( + description="Region where the sandbox runs (for example us-pdx-1 or eu-lon-1). When omitted at creation, the closest region is selected.", + examples=["us-pdx-1"], + ), + ] = None + envs: Annotated[ + list[SandboxEnv] | None, + Field( + description="Environment variables injected into the sandbox.", + examples=[ + [ + {"name": "NODE_ENV", "secret": False, "value": "production"}, + {"name": "PORT", "secret": False, "value": "3000"}, + ] + ], + ), + ] = None + image: Annotated[ + str, + Field( + description="Image reference including its tag. Defaults to baseten/base-image:latest, the built-in sandbox execution API. This image is available directly without building, pushing, or listing images through GET /v1/sandboxes/images.", + examples=["baseten/base-image:latest"], ), - ] = False - rolling_deploy: Annotated[ - bool | None, + ] = "baseten/base-image:latest" + memory: Annotated[ + int, Field( - description="Whether the environment should rely on rolling deploy orchestration.", - examples=[True], - title="Rolling Deploy", + description="Memory allocation in megabytes. Also determines CPU allocation (CPU cores = memory in MB / 2048, e.g., 4096MB = 2 CPUs). Defaults to 4096.", + examples=[4096], + ge=1, ), - ] = False - promotion_cleanup_strategy: Annotated[ - PromotionCleanupStrategy | None, + ] = 4096 + ports: Annotated[ + SandboxPorts | None, Field( - description="The cleanup strategy to use after a promotion completes.", - examples=["SCALE_TO_ZERO"], + description="Set of ports for a resource", + examples=[[{"name": "http", "protocol": "HTTP", "target": 3000}]], ), - ] = PromotionCleanupStrategy.SCALE_TO_ZERO - rolling_deploy_config: Annotated[ - RollingDeployConfig | None, - Field(description="Rolling deploy configuration for promotions"), ] = None - ramp_up_while_promoting: Annotated[ - bool | None, + external_id: Annotated[ + str | None, Field( - description="Whether to ramp up traffic while promoting", - examples=[True], - title="Ramp Up While Promoting", + description="Caller-owned identifier for external lookups. Max 64 chars, alphanumeric + dash.", + examples=["api-review-20260916-001"], + max_length=64, + pattern="^[A-Za-z0-9-]+$", ), - ] = False - ramp_up_duration_seconds: Annotated[ - int | None, + ] = None + labels: Annotated[ + SandboxMetadataLabels | None, Field( - description="Duration of the ramp up in seconds", - examples=[600], - title="Ramp Up Duration Seconds", + description="Key-value pairs for organizing and filtering resources. Labels can be used to categorize resources by environment, project, team, or any custom taxonomy.", + examples=[ + {"env": "development", "project": "api-review", "team": "engineering"} + ], ), - ] = 600 + ] = None -class ChainEnvironment(BaseModel): - name: Annotated[str, Field(description="Name of the environment", title="Name")] - created_at: Annotated[ - AwareDatetime, +class UpdateSandboxRequest(BaseModel): + enabled: Annotated[ + bool | None, Field( - description="Time the environment was created in ISO 8601 format", - title="Created At", + description="When false, the sandbox is disabled and will not accept connections", + examples=[True], ), - ] - chain_id: Annotated[ - str, Field(description="Unique identifier of the chain", title="Chain Id") - ] - promotion_settings: Annotated[ - PromotionSettings, Field(description="Promotion settings for the environment") - ] - chainlet_settings: Annotated[ - list[ChainletEnvironmentSettings], + ] = None + lifecycle: Annotated[ + SandboxLifecycle | None, Field( - description="Environment settings for the chainlets", - title="Chainlet Settings", + description="Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", + examples=[ + { + "expiration_policies": [ + {"action": "DELETE", "type": "TTL_IDLE", "value": "24h"}, + {"action": "DELETE", "type": "TTL_MAX_AGE", "value": "7d"}, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z", + }, + ], + "terminated_retention": "24h", + } + ], ), - ] - current_deployment: Annotated[ - ChainDeployment | None, - Field(description="Current chain deployment of the environment"), - ] - candidate_deployment: Annotated[ - ChainDeployment | None, + ] = None + region: Annotated[ + str | None, Field( - description="Candidate chain deployment being promoted to the environment, if a promotion is in progress" + description="Region where the sandbox runs (for example us-pdx-1 or eu-lon-1). When omitted at creation, the closest region is selected.", + examples=["us-pdx-1"], ), ] = None - - -class DockerAuth(BaseModel): - registry: Annotated[ - str, Field(description="Registry to authenticate with", title="Registry") - ] - auth_method: Annotated[ - DockerAuthType, + envs: Annotated[ + list[SandboxEnv] | None, Field( - description="Method to authenticate with the registry", + description="Environment variables injected into the sandbox.", examples=[ - "GCP_SERVICE_ACCOUNT_JSON", - "AWS_IAM", - "AWS_OIDC", - "GCP_OIDC", - "REGISTRY_SECRET", - "AWS_ASSUME_ROLE", + [ + {"name": "NODE_ENV", "secret": False, "value": "production"}, + {"name": "PORT", "secret": False, "value": "3000"}, + ] ], ), - ] - gcp_service_account_json_docker_auth: Annotated[ - GcpServiceAccountJsonDockerAuth | None, - Field(description="GCP service account details for the registry"), - ] = None - aws_iam_docker_auth: Annotated[ - AwsIamDockerAuth | None, Field(description="AWS details for the registry") ] = None - aws_oidc_docker_auth: Annotated[ - AwsOidcDockerAuth | None, Field(description="AWS OIDC details for the registry") + image: Annotated[ + str | None, + Field( + description="Image reference including its tag. Built-in image references are returned in the canonical baseten/ namespace. Use baseten/base-image:latest to get started with the built-in sandbox execution API. This image is available directly without building, pushing, or listing images through GET /v1/sandboxes/images.", + examples=["baseten/base-image:latest"], + ), ] = None - gcp_oidc_docker_auth: Annotated[ - GcpOidcDockerAuth | None, Field(description="GCP OIDC details for the registry") + ports: Annotated[ + SandboxPorts | None, + Field( + description="Set of ports for a resource", + examples=[[{"name": "http", "protocol": "HTTP", "target": 3000}]], + ), ] = None - registry_secret_docker_auth: Annotated[ - RegistrySecretDockerAuth | None, + external_id: Annotated[ + str | None, Field( - description="Required when auth_method is REGISTRY_SECRET. Supports any Docker registry (Docker Hub, GHCR, NGC, etc.) via username:password credentials stored as a Baseten secret." + description="Caller-owned identifier for external lookups. Max 64 chars, alphanumeric + dash.", + examples=["api-review-20260916-001"], + max_length=64, + pattern="^[A-Za-z0-9-]+$", ), ] = None - aws_assume_role_docker_auth: Annotated[ - AwsAssumeRoleDockerAuth | None, + labels: Annotated[ + SandboxMetadataLabels | None, Field( - description="Required when auth_method is AWS_ASSUME_ROLE. Baseten assumes the given IAM role with its own AWS principal and your organization's external ID, with no OIDC provider registration in your account." + description="Key-value pairs for organizing and filtering resources. Labels can be used to categorize resources by environment, project, team, or any custom taxonomy.", + examples=[ + { + "env": "development", + "project": "api-review", + "team": "engineering", + "revision": "2", + } + ], ), ] = None -class LoopsDeploymentMetrics(BaseModel): - inference_volume: Annotated[ - list[TrainingJobMetric], +class Sandbox(SandboxConfiguration): + name: Annotated[ + str, Field( - description="Number of inference requests per unit time (requests per second).", - title="Inference Volume", + description="Immutable sandbox name, provided by the client or generated by the server, used in sandbox_name path parameters.", + examples=["baseten-api-review-0916"], ), ] - concurrent_requests: Annotated[ - list[TrainingJobMetric], + url: Annotated[ + AnyUrl, Field( - description="Number of in-progress concurrent inference requests. Source: the queue-proxy ``revision_queue_depth`` gauge on ``http-usermetric``.", - title="Concurrent Requests", + description='Base URL of this sandbox\'s execution API, always present on successful creation. The URL is assigned before deployment completes; inspect status for readiness. Use this exact returned URL; do not reconstruct its hostname. Authenticate requests with your authentication token using Authorization: Bearer . Do not send the Baseten API key directly. No additional routing headers are required. Fetch GET {url}/swagger/doc.json with that header for the API reference served by this sandbox. For example, POST {url}/process with Content-Type: application/json and {"command":"echo hello","waitForCompletion":true} executes a command and waits for its result. Execution API fields use camelCase, independently of this API\'s snake_case fields.', + examples=["https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run"], ), ] - response_time_stats: Annotated[ - list[ResponseTimeDatapoint], - Field( - description="Percentiles of the response time distribution.", - title="Response Time Stats", - ), + status: Annotated[ + SandboxStatus, + Field(description="Sandbox deployment status.", examples=["DEPLOYED"]), ] - inference_volume_by_status: Annotated[ - list[InferenceVolumeByStatusDatapoint], + created_at: Annotated[ + AwareDatetime, Field( - description="Request rate split by response code class.", - title="Inference Volume By Status", + description="Time the sandbox was created.", + examples=["2026-09-16T21:26:58.545765901Z"], ), ] - gpu_memory_usage_bytes: Annotated[ - dict[str, list[TrainingJobMetric]], + updated_at: Annotated[ + AwareDatetime | None, Field( - description="Leader-pod GPU memory bytes per GPU rank.", - title="Gpu Memory Usage Bytes", + description="Time the sandbox was last updated.", + examples=["2026-09-16T21:31:13Z"], ), - ] - gpu_utilization: Annotated[ - dict[str, list[TrainingJobMetric]], + ] = None + created_by: Annotated[ + str | None, Field( - description="Leader-pod fractional GPU utilization per GPU rank.", - title="Gpu Utilization", + description="User or service account that created the sandbox.", + examples=["sandbox-automation"], ), - ] - cpu_usage: Annotated[ - list[TrainingJobMetric], - Field(description="Leader-pod CPU usage in cores.", title="Cpu Usage"), - ] - cpu_memory_usage_bytes: Annotated[ - list[TrainingJobMetric], + ] = None + updated_by: Annotated[ + str | None, Field( - description="Leader-pod CPU memory usage bytes.", - title="Cpu Memory Usage Bytes", + description="User or service account that last updated the sandbox.", + examples=["sandbox-automation"], ), - ] - ephemeral_storage: Annotated[ - StorageMetrics, Field(description="Leader-pod ephemeral storage usage.") - ] - per_node_metrics: Annotated[ - list[LoopsDeploymentNodeMetrics], + ] = None + last_used_at: Annotated[ + AwareDatetime | None, Field( - description="Per-node compute breakdown for multinode trainer deployments.", - title="Per Node Metrics", + description="Time the sandbox was last used.", + examples=["2026-09-16T21:31:13Z"], ), - ] - - -class GetLoopsDeploymentMetricsResponse(BaseModel): - deployment_id: Annotated[ - str, Field(description="The trainer deployment ID.", title="Deployment Id") - ] - metrics: Annotated[ - LoopsDeploymentMetrics, Field(description="Metrics for the deployment.") - ] - - -class EffectiveModelConfig(BaseModel): - slug: Annotated[str, Field(description="Shared endpoint slug.", title="Slug")] - rate_limits: Annotated[ - list[EffectiveRateLimit] | None, Field(title="Rate Limits") - ] = None - usage_limits: Annotated[ - list[EffectiveUsageLimit] | None, Field(title="Usage Limits") - ] = None - - -class Group(BaseModel): - id: Annotated[ - str, Field(description="Internal Baseten ID for the group.", title="Id") - ] - metadata: Annotated[ - GroupMetadata, Field(description="Group identity + display metadata.") - ] - models: Annotated[list[ModelConfig] | None, Field(title="Models")] = None - effective_models: Annotated[ - list[EffectiveModelConfig] | None, Field(title="Effective Models") ] = None - hierarchy: Annotated[ - GroupHierarchy, + expires_in: Annotated[ + int | None, Field( - description="Parent linkage and limit enforcement mode. Parent is null for root groups." + description="Seconds remaining before automatic deletion, when expiration is configured.", + examples=[86400], + ge=0, ), - ] - created_at: Annotated[ - AwareDatetime, - Field(description="When this group was created.", title="Created At"), - ] + ] = None -class GroupsResponse(BaseModel): +class ListSandboxesResponse(BaseModel): items: Annotated[ - list[Group], Field(description="Items in this page.", title="Items") + list[Sandbox], + Field( + description="Resources on this page.", + examples=[ + [ + { + "enabled": True, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h", + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d", + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z", + }, + ], + "terminated_retention": "24h", + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org", + ], + "bypass": ["registry.npmjs.org"], + "forbidden_domains": ["facebook.com", "*.facebook.com"], + "routing": [ + { + "destinations": ["api.openai.com"], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": {"user": "baseten-api-review-0916"}, + } + ], + }, + "subnet": "default", + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": False, + "value": "production", + }, + {"name": "PORT", "secret": False, "value": "3000"}, + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [{"name": "http", "protocol": "HTTP", "target": 3000}], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering", + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400, + } + ] + ], + ), ] pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") + SandboxApiPagination, + Field( + description="Cursor pagination information. The cursor is present only when another page is available.", + examples=[ + { + "has_more": True, + "cursor": "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ", + } + ], + ), ] diff --git a/baseten/client/sandboxapi/__init__.py b/baseten/client/sandboxapi/__init__.py new file mode 100644 index 0000000..95ac2cd --- /dev/null +++ b/baseten/client/sandboxapi/__init__.py @@ -0,0 +1,164 @@ +# Code generated by apigen. DO NOT EDIT. + +"""Generated client and models for the Baseten Sandbox API. + +Use :class:`ApiClient` for synchronous access or :class:`AsyncApiClient` for +asynchronous access. + +Types in this module are generated from the OpenAPI specification and are NOT +covered by any stability or compatibility guarantees. They may change without +notice between versions. +""" + +from ._client import ApiClient, AsyncApiClient, ResponseError, ResponseErrorResponse +from ._models import ( + ApplyEditRequest, + ApplyEditResponse, + ArchiveChange, + ArchiveChangeKind, + ArchiveExportState, + ArchiveManifest, + ArchiveQuiesceState, + ArchiveRestoreState, + ContentSearchMatch, + ContentSearchResponse, + DeleteFilesystemParams, + DeleteFilesystemTreeParams, + DeleteNetworkProcessMonitorResponse, + Directory, + DriveListResponse, + DriveMountInfo, + DriveMountRequest, + DriveMountResponse, + DriveUnmountResponse, + ErrorResponse, + ExportOptions, + ExportProgress, + ExportResult, + File, + FileRequest, + FilesystemMultipartUpload, + FilesystemUploadedPart, + FileWithContent, + FindMatch, + FindResponse, + FuzzySearchMatch, + FuzzySearchResponse, + GetCodegenRerankingParams, + GetFilesystemContentSearchParams, + GetFilesystemFindParams, + GetFilesystemParams, + GetFilesystemResponse, + GetFilesystemSearchParams, + GetFilesystemTreeResponse, + GetNetworkProcessPortsResponse, + GetProcessResponse, + GetWatchFilesystemParams, + HandlerReloadResponse, + HealthResponse, + MultipartCompleteRequest, + MultipartInitiateRequest, + MultipartInitiateResponse, + MultipartListPartsResponse, + MultipartListUploadsResponse, + MultipartPartInfo, + MultipartUpload, + MultipartUploadPartResponse, + PortMonitorRequest, + PostNetworkProcessMonitorResponse, + ProcessLogs, + ProcessRequest, + ProcessResponse, + ProcessUpgradeState, + PutFilesystemMultipartPartParams, + PutFilesystemTreeResponse, + QuiesceStatus, + RankedFile, + RerankingResponse, + RestoreProgress, + Status, + Subdirectory, + SuccessResponse, + TreeRequest, + TunnelConfigRequest, + UpgradeRequest, + UpgradeStatus, +) + +__all__ = [ + "ApiClient", + "ApplyEditRequest", + "ApplyEditResponse", + "ArchiveChange", + "ArchiveChangeKind", + "ArchiveExportState", + "ArchiveManifest", + "ArchiveQuiesceState", + "ArchiveRestoreState", + "AsyncApiClient", + "ContentSearchMatch", + "ContentSearchResponse", + "DeleteFilesystemParams", + "DeleteFilesystemTreeParams", + "DeleteNetworkProcessMonitorResponse", + "Directory", + "DriveListResponse", + "DriveMountInfo", + "DriveMountRequest", + "DriveMountResponse", + "DriveUnmountResponse", + "ErrorResponse", + "ExportOptions", + "ExportProgress", + "ExportResult", + "File", + "FileRequest", + "FileWithContent", + "FilesystemMultipartUpload", + "FilesystemUploadedPart", + "FindMatch", + "FindResponse", + "FuzzySearchMatch", + "FuzzySearchResponse", + "GetCodegenRerankingParams", + "GetFilesystemContentSearchParams", + "GetFilesystemFindParams", + "GetFilesystemParams", + "GetFilesystemResponse", + "GetFilesystemSearchParams", + "GetFilesystemTreeResponse", + "GetNetworkProcessPortsResponse", + "GetProcessResponse", + "GetWatchFilesystemParams", + "HandlerReloadResponse", + "HealthResponse", + "MultipartCompleteRequest", + "MultipartInitiateRequest", + "MultipartInitiateResponse", + "MultipartListPartsResponse", + "MultipartListUploadsResponse", + "MultipartPartInfo", + "MultipartUpload", + "MultipartUploadPartResponse", + "PortMonitorRequest", + "PostNetworkProcessMonitorResponse", + "ProcessLogs", + "ProcessRequest", + "ProcessResponse", + "ProcessUpgradeState", + "PutFilesystemMultipartPartParams", + "PutFilesystemTreeResponse", + "QuiesceStatus", + "RankedFile", + "RerankingResponse", + "ResponseError", + "ResponseErrorResponse", + "RestoreProgress", + "Status", + "Subdirectory", + "SuccessResponse", + "TreeRequest", + "TunnelConfigRequest", + "UpgradeRequest", + "UpgradeStatus", +] diff --git a/baseten/client/sandboxapi/_client.py b/baseten/client/sandboxapi/_client.py new file mode 100644 index 0000000..261162e --- /dev/null +++ b/baseten/client/sandboxapi/_client.py @@ -0,0 +1,1991 @@ +# Code generated by apigen/clientgen. DO NOT EDIT. + +from __future__ import annotations + +import contextlib +import urllib.parse +from collections.abc import Mapping +from dataclasses import dataclass +from typing import IO, Any, Literal, TypeVar, cast + +import httpx +from pydantic import BaseModel, ValidationError + +from ._models import ( + ApplyEditRequest, + ApplyEditResponse, + ContentSearchResponse, + DeleteFilesystemParams, + DeleteFilesystemTreeParams, + DeleteNetworkProcessMonitorResponse, + DriveListResponse, + DriveMountRequest, + DriveMountResponse, + DriveUnmountResponse, + ErrorResponse, + ExportOptions, + ExportProgress, + ExportResult, + FileRequest, + FindResponse, + FuzzySearchResponse, + GetCodegenRerankingParams, + GetFilesystemContentSearchParams, + GetFilesystemFindParams, + GetFilesystemParams, + GetFilesystemResponse, + GetFilesystemSearchParams, + GetFilesystemTreeResponse, + GetNetworkProcessPortsResponse, + GetProcessResponse, + GetWatchFilesystemParams, + HandlerReloadResponse, + HealthResponse, + MultipartCompleteRequest, + MultipartInitiateRequest, + MultipartInitiateResponse, + MultipartListPartsResponse, + MultipartListUploadsResponse, + MultipartUploadPartResponse, + PortMonitorRequest, + PostNetworkProcessMonitorResponse, + ProcessLogs, + ProcessRequest, + ProcessResponse, + PutFilesystemMultipartPartParams, + PutFilesystemTreeResponse, + QuiesceStatus, + RerankingResponse, + SuccessResponse, + TreeRequest, + TunnelConfigRequest, + UpgradeRequest, +) + +_T = TypeVar("_T", bound=BaseModel) + + +@dataclass +class ResponseError(Exception): + status_code: int + body: str + + def __str__(self) -> str: + return f"baseten API error (HTTP {self.status_code}): {self.body}" + + +@dataclass +class ResponseErrorResponse(Exception): + status_code: int + error_response: ErrorResponse + + def __str__(self) -> str: + return f"baseten API error (HTTP {self.status_code}): {self.error_response.model_dump_json()}" + + +_ERROR_TYPES: dict[str, tuple[type[BaseModel], type[Exception], str]] = { + "ErrorResponse": (ErrorResponse, ResponseErrorResponse, "error_response"), +} + + +@dataclass +class _ApiRequest: + method: str + path_fmt: str + path_args: list[str] + body: Any + query: Any + success_codes: list[int] + error_codes: dict[int, str] | None + body_content_type: str | None = None + accept: str | None = None + + +class ApiClient: + """Generated HTTP client for the Baseten API. + + Methods on this client are generated from the OpenAPI specification + and are NOT covered by any stability or compatibility guarantees. + They may change without notice between versions. + """ + + def __init__(self, http_client: httpx.Client) -> None: + """Create a new client. The caller is responsible for closing *http_client*.""" + self._http_client = http_client + + def delete_drives_mount(self, *, mount_path: str) -> DriveUnmountResponse: + """Detach a drive from a local path""" + return self._do_json( + DriveUnmountResponse, + _ApiRequest( + method="DELETE", + path_fmt="/drives/mount/{}", + path_args=[mount_path], + body=None, + query=None, + success_codes=[200], + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + def delete_filesystem( + self, *, path: str, params: DeleteFilesystemParams | None = None + ) -> SuccessResponse: + """Delete file or directory""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def delete_filesystem_multipart_abort(self, *, upload_id: str) -> SuccessResponse: + """Abort multipart upload""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/filesystem-multipart/{}/abort", + path_args=[upload_id], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def delete_filesystem_tree( + self, *, path: str, params: DeleteFilesystemTreeParams | None = None + ) -> SuccessResponse: + """Delete directory tree""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/filesystem/tree/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def delete_network_process_monitor( + self, *, pid: str + ) -> DeleteNetworkProcessMonitorResponse: + """Stop monitoring ports for a process""" + return self._do_json( + DeleteNetworkProcessMonitorResponse, + _ApiRequest( + method="DELETE", + path_fmt="/network/process/{}/monitor", + path_args=[pid], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def delete_network_tunnel(self) -> SuccessResponse: + """Disconnect tunnel""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/network/tunnel", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + def delete_process(self, *, identifier: str) -> SuccessResponse: + """Stop a process""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/process/{}", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def delete_process_kill(self, *, identifier: str) -> SuccessResponse: + """Kill a process""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/process/{}/kill", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def delete_process_stdin(self, *, identifier: str) -> SuccessResponse: + """Close a process's stdin""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/process/{}/stdin", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={404: "ErrorResponse", 409: "ErrorResponse"}, + ), + ) + + def get_archive_status(self) -> QuiesceStatus: + """Get the archive status""" + return self._do_json( + QuiesceStatus, + _ApiRequest( + method="GET", + path_fmt="/archive/status", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_codegen_reranking( + self, *, path: str, params: GetCodegenRerankingParams + ) -> RerankingResponse: + """Code reranking/semantic search""" + return self._do_json( + RerankingResponse, + _ApiRequest( + method="GET", + path_fmt="/codegen/reranking/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 503: "ErrorResponse", + }, + ), + ) + + def get_drives_mount(self) -> DriveListResponse: + """List currently mounted drives""" + return self._do_json( + DriveListResponse, + _ApiRequest( + method="GET", + path_fmt="/drives/mount", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={500: "ErrorResponse"}, + ), + ) + + def get_filesystem( + self, *, path: str, params: GetFilesystemParams | None = None + ) -> GetFilesystemResponse: + """Get file or directory information""" + return self._do_json( + GetFilesystemResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_filesystem_raw( + self, + *, + path: str, + params: GetFilesystemParams | None = None, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Get file or directory information. Returns the response unread, in the requested content type. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="GET", + path_fmt="/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + accept=accept, + ) + ) + + def get_filesystem_content_search( + self, *, path: str, params: GetFilesystemContentSearchParams + ) -> ContentSearchResponse: + """Search for text content in files""" + return self._do_json( + ContentSearchResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-content-search/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_filesystem_find( + self, *, path: str, params: GetFilesystemFindParams | None = None + ) -> FindResponse: + """Find files and directories""" + return self._do_json( + FindResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-find/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_filesystem_multipart(self) -> MultipartListUploadsResponse: + """List multipart uploads""" + return self._do_json( + MultipartListUploadsResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-multipart", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={500: "ErrorResponse"}, + ), + ) + + def get_filesystem_multipart_parts( + self, *, upload_id: str + ) -> MultipartListPartsResponse: + """List parts""" + return self._do_json( + MultipartListPartsResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-multipart/{}/parts", + path_args=[upload_id], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_filesystem_search( + self, *, path: str, params: GetFilesystemSearchParams | None = None + ) -> FuzzySearchResponse: + """Fuzzy search for files and directories""" + return self._do_json( + FuzzySearchResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-search/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_filesystem_tree(self, *, path: str) -> GetFilesystemTreeResponse: + """Get directory tree""" + return self._do_json( + GetFilesystemTreeResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem/tree/{}", + path_args=[path], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_health(self) -> HealthResponse: + """Health check""" + return self._do_json( + HealthResponse, + _ApiRequest( + method="GET", + path_fmt="/health", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_network_process_ports(self, *, pid: str) -> GetNetworkProcessPortsResponse: + """Get open ports for a process""" + return self._do_json( + GetNetworkProcessPortsResponse, + _ApiRequest( + method="GET", + path_fmt="/network/process/{}/ports", + path_args=[pid], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_process(self) -> GetProcessResponse: + """List all processes""" + return self._do_json( + GetProcessResponse, + _ApiRequest( + method="GET", + path_fmt="/process", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_process_identifier(self, *, identifier: str) -> ProcessResponse: + """Get process by identifier""" + return self._do_json( + ProcessResponse, + _ApiRequest( + method="GET", + path_fmt="/process/{}", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={404: "ErrorResponse"}, + ), + ) + + def get_process_logs(self, *, identifier: str) -> ProcessLogs: + """Get process logs""" + return self._do_json( + ProcessLogs, + _ApiRequest( + method="GET", + path_fmt="/process/{}/logs", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def get_process_logs_stream(self, *, identifier: str) -> httpx.Response: + """Stream process logs in real time. Returns the response unread. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="GET", + path_fmt="/process/{}/logs/stream", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes=None, + accept="text/plain", + ) + ) + + def get_watch_filesystem( + self, *, path: str, params: GetWatchFilesystemParams | None = None + ) -> httpx.Response: + """Stream file modification events in a directory. Returns the response unread. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="GET", + path_fmt="/watch/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes=None, + accept="text/plain", + ) + ) + + def post_archive_export( + self, *, request: ExportOptions + ) -> ExportResult | ExportProgress: + """Export the filesystem changes to a presigned URL""" + return self._do_json_with_status( + {200: ExportResult, 202: ExportProgress}, + _ApiRequest( + method="POST", + path_fmt="/archive/export", + path_args=[], + body=request, + query=None, + success_codes=[200, 202], + error_codes={ + 400: "ErrorResponse", + 409: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def post_archive_resume(self) -> QuiesceStatus: + """Lift the archive freeze""" + return self._do_json( + QuiesceStatus, + _ApiRequest( + method="POST", + path_fmt="/archive/resume", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={409: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + def post_drives_mount(self, *, request: DriveMountRequest) -> DriveMountResponse: + """Attach a drive to a local path""" + return self._do_json( + DriveMountResponse, + _ApiRequest( + method="POST", + path_fmt="/drives/mount", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 403: "ErrorResponse", + 409: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def post_environment_reload(self) -> HandlerReloadResponse: + """Reload environment from guest metadata""" + return self._do_json( + HandlerReloadResponse, + _ApiRequest( + method="POST", + path_fmt="/environment/reload", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={404: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + def post_filesystem_multipart_complete( + self, *, upload_id: str, request: MultipartCompleteRequest + ) -> SuccessResponse: + """Complete multipart upload""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="POST", + path_fmt="/filesystem-multipart/{}/complete", + path_args=[upload_id], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def post_filesystem_multipart_initiate( + self, *, path: str, request: MultipartInitiateRequest + ) -> MultipartInitiateResponse: + """Initiate multipart upload""" + return self._do_json( + MultipartInitiateResponse, + _ApiRequest( + method="POST", + path_fmt="/filesystem-multipart/initiate/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + def post_network_process_monitor( + self, *, pid: str, request: PortMonitorRequest + ) -> PostNetworkProcessMonitorResponse: + """Start monitoring ports for a process""" + return self._do_json( + PostNetworkProcessMonitorResponse, + _ApiRequest( + method="POST", + path_fmt="/network/process/{}/monitor", + path_args=[pid], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def post_process(self, *, request: ProcessRequest) -> ProcessResponse: + """Execute a command""" + return self._do_json( + ProcessResponse, + _ApiRequest( + method="POST", + path_fmt="/process", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def post_process_raw( + self, + *, + request: ProcessRequest, + accept: Literal["application/json", "text/event-stream"], + ) -> httpx.Response: + """Execute a command. Returns the response unread, in the requested content type. The caller must close the response.""" + return self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/process", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + accept=accept, + ) + ) + + def post_process_stdin( + self, *, identifier: str, content: bytes | IO[bytes] | str + ) -> SuccessResponse: + """Write to a process's stdin""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="POST", + path_fmt="/process/{}/stdin", + path_args=[identifier], + body=content, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 409: "ErrorResponse", + 413: "ErrorResponse", + 500: "ErrorResponse", + 503: "ErrorResponse", + }, + body_content_type="application/octet-stream", + ), + ) + + def post_upgrade(self, *, request: UpgradeRequest) -> SuccessResponse: + """Upgrade the sandbox-api""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="POST", + path_fmt="/upgrade", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={500: "ErrorResponse"}, + ), + ) + + def put_codegen_fastapply( + self, *, path: str, request: ApplyEditRequest + ) -> ApplyEditResponse: + """Apply code edit""" + return self._do_json( + ApplyEditResponse, + _ApiRequest( + method="PUT", + path_fmt="/codegen/fastapply/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 503: "ErrorResponse", + }, + ), + ) + + def put_filesystem(self, *, path: str, request: FileRequest) -> SuccessResponse: + """Create or update a file or directory""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="PUT", + path_fmt="/filesystem/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def put_filesystem_multipart_part( + self, *, upload_id: str, params: PutFilesystemMultipartPartParams, files: Any + ) -> MultipartUploadPartResponse: + """Upload part. *files* is sent as httpx ``files``.""" + return self._do_json( + MultipartUploadPartResponse, + _ApiRequest( + method="PUT", + path_fmt="/filesystem-multipart/{}/part", + path_args=[upload_id], + body=files, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + body_content_type="multipart/form-data", + ), + ) + + def put_filesystem_tree( + self, *, path: str, request: TreeRequest + ) -> PutFilesystemTreeResponse: + """Create or update directory tree""" + return self._do_json( + PutFilesystemTreeResponse, + _ApiRequest( + method="PUT", + path_fmt="/filesystem/tree/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def put_network_tunnel_config( + self, *, request: TunnelConfigRequest + ) -> SuccessResponse: + """Update tunnel configuration""" + return self._do_json( + SuccessResponse, + _ApiRequest( + method="PUT", + path_fmt="/network/tunnel/config", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def _build_request(self, request: _ApiRequest) -> httpx.Request: + path = request.path_fmt.format( + *[urllib.parse.quote(a, safe="") for a in request.path_args] + ) + json_body = None + content_body = None + files_body = None + headers: dict[str, str] = {} + if request.accept is not None: + headers["Accept"] = request.accept + if request.body is not None: + if request.body_content_type is None: + if isinstance(request.body, BaseModel): + # Only fields the caller set are sent, so unset fields fall + # back to the server default rather than being reset here. + # An explicit None is kept, since null can mean "clear". + # by_alias: a field renamed for Python (e.g. async_ for + # "async") must serialize under its API name. + json_body = request.body.model_dump( + mode="json", exclude_unset=True, by_alias=True + ) + else: + json_body = request.body + elif request.body_content_type == "multipart/form-data": + # httpx derives the multipart Content-Type, boundary included. + files_body = request.body + else: + headers["Content-Type"] = request.body_content_type + content_body = request.body + params = None + if request.query is not None: + if isinstance(request.query, BaseModel): + # As above, plus dropping None: a null query parameter is + # meaningless and would otherwise serialize as an empty string. + params = request.query.model_dump( + mode="json", exclude_unset=True, exclude_none=True, by_alias=True + ) + else: + params = request.query + return self._http_client.build_request( + request.method, + path, + json=json_body, + content=content_body, + files=files_body, + params=params, + headers=headers, + ) + + def _do(self, request: _ApiRequest) -> httpx.Response: + response = self._http_client.send(self._build_request(request)) + if response.status_code not in request.success_codes: + if request.error_codes and response.status_code in request.error_codes: + error_name = request.error_codes[response.status_code] + if error_name in _ERROR_TYPES: + model_cls, exc_cls, field_name = _ERROR_TYPES[error_name] + # A body that does not match the declared error schema + # falls through to the generic ResponseError below. + model = None + with contextlib.suppress(ValidationError): + model = model_cls.model_validate_json(response.content) + if model is not None: + raise exc_cls( + status_code=response.status_code, # ty: ignore[unknown-argument] + **{field_name: model}, + ) + raise ResponseError(status_code=response.status_code, body=response.text) + return response + + def _do_raw(self, request: _ApiRequest) -> httpx.Response: + response = self._http_client.send(self._build_request(request), stream=True) + if response.status_code not in request.success_codes: + response.read() + if request.error_codes and response.status_code in request.error_codes: + error_name = request.error_codes[response.status_code] + if error_name in _ERROR_TYPES: + model_cls, exc_cls, field_name = _ERROR_TYPES[error_name] + # A body that does not match the declared error schema + # falls through to the generic ResponseError below. + model = None + with contextlib.suppress(ValidationError): + model = model_cls.model_validate_json(response.content) + if model is not None: + raise exc_cls( + status_code=response.status_code, # ty: ignore[unknown-argument] + **{field_name: model}, + ) + raise ResponseError(status_code=response.status_code, body=response.text) + return response + + def _do_json(self, response_type: type[_T], request: _ApiRequest) -> _T: + response = self._do(request) + content_type = response.headers.get("content-type", "") + if not content_type.startswith("application/json"): + raise ValueError( + f"unexpected content type {content_type!r}, expected application/json" + ) + return response_type.model_validate_json(response.content) + + def _do_json_with_status( + self, response_types: Mapping[int, type[_T]], request: _ApiRequest + ) -> _T: + response = self._do(request) + response_type = response_types.get(response.status_code) + if response_type is None: + # A bodyless success code, such as 204 alongside a JSON 200. The + # call site's return type includes None only when one is declared, + # so this cast is unreachable otherwise. + return cast(_T, None) + content_type = response.headers.get("content-type", "") + if not content_type.startswith("application/json"): + raise ValueError( + f"unexpected content type {content_type!r}, expected application/json" + ) + return response_type.model_validate_json(response.content) + + +class AsyncApiClient: + """Generated HTTP client for the Baseten API. + + Methods on this client are generated from the OpenAPI specification + and are NOT covered by any stability or compatibility guarantees. + They may change without notice between versions. + """ + + def __init__(self, http_client: httpx.AsyncClient) -> None: + """Create a new client. The caller is responsible for closing *http_client*.""" + self._http_client = http_client + + async def delete_drives_mount(self, *, mount_path: str) -> DriveUnmountResponse: + """Detach a drive from a local path""" + return await self._do_json( + DriveUnmountResponse, + _ApiRequest( + method="DELETE", + path_fmt="/drives/mount/{}", + path_args=[mount_path], + body=None, + query=None, + success_codes=[200], + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + async def delete_filesystem( + self, *, path: str, params: DeleteFilesystemParams | None = None + ) -> SuccessResponse: + """Delete file or directory""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def delete_filesystem_multipart_abort( + self, *, upload_id: str + ) -> SuccessResponse: + """Abort multipart upload""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/filesystem-multipart/{}/abort", + path_args=[upload_id], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def delete_filesystem_tree( + self, *, path: str, params: DeleteFilesystemTreeParams | None = None + ) -> SuccessResponse: + """Delete directory tree""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/filesystem/tree/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def delete_network_process_monitor( + self, *, pid: str + ) -> DeleteNetworkProcessMonitorResponse: + """Stop monitoring ports for a process""" + return await self._do_json( + DeleteNetworkProcessMonitorResponse, + _ApiRequest( + method="DELETE", + path_fmt="/network/process/{}/monitor", + path_args=[pid], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def delete_network_tunnel(self) -> SuccessResponse: + """Disconnect tunnel""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/network/tunnel", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + async def delete_process(self, *, identifier: str) -> SuccessResponse: + """Stop a process""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/process/{}", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def delete_process_kill(self, *, identifier: str) -> SuccessResponse: + """Kill a process""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/process/{}/kill", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def delete_process_stdin(self, *, identifier: str) -> SuccessResponse: + """Close a process's stdin""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="DELETE", + path_fmt="/process/{}/stdin", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={404: "ErrorResponse", 409: "ErrorResponse"}, + ), + ) + + async def get_archive_status(self) -> QuiesceStatus: + """Get the archive status""" + return await self._do_json( + QuiesceStatus, + _ApiRequest( + method="GET", + path_fmt="/archive/status", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_codegen_reranking( + self, *, path: str, params: GetCodegenRerankingParams + ) -> RerankingResponse: + """Code reranking/semantic search""" + return await self._do_json( + RerankingResponse, + _ApiRequest( + method="GET", + path_fmt="/codegen/reranking/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 503: "ErrorResponse", + }, + ), + ) + + async def get_drives_mount(self) -> DriveListResponse: + """List currently mounted drives""" + return await self._do_json( + DriveListResponse, + _ApiRequest( + method="GET", + path_fmt="/drives/mount", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={500: "ErrorResponse"}, + ), + ) + + async def get_filesystem( + self, *, path: str, params: GetFilesystemParams | None = None + ) -> GetFilesystemResponse: + """Get file or directory information""" + return await self._do_json( + GetFilesystemResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_filesystem_raw( + self, + *, + path: str, + params: GetFilesystemParams | None = None, + accept: Literal["application/json", "application/octet-stream"], + ) -> httpx.Response: + """Get file or directory information. Returns the response unread, in the requested content type. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="GET", + path_fmt="/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + accept=accept, + ) + ) + + async def get_filesystem_content_search( + self, *, path: str, params: GetFilesystemContentSearchParams + ) -> ContentSearchResponse: + """Search for text content in files""" + return await self._do_json( + ContentSearchResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-content-search/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_filesystem_find( + self, *, path: str, params: GetFilesystemFindParams | None = None + ) -> FindResponse: + """Find files and directories""" + return await self._do_json( + FindResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-find/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_filesystem_multipart(self) -> MultipartListUploadsResponse: + """List multipart uploads""" + return await self._do_json( + MultipartListUploadsResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-multipart", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={500: "ErrorResponse"}, + ), + ) + + async def get_filesystem_multipart_parts( + self, *, upload_id: str + ) -> MultipartListPartsResponse: + """List parts""" + return await self._do_json( + MultipartListPartsResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-multipart/{}/parts", + path_args=[upload_id], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_filesystem_search( + self, *, path: str, params: GetFilesystemSearchParams | None = None + ) -> FuzzySearchResponse: + """Fuzzy search for files and directories""" + return await self._do_json( + FuzzySearchResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem-search/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_filesystem_tree(self, *, path: str) -> GetFilesystemTreeResponse: + """Get directory tree""" + return await self._do_json( + GetFilesystemTreeResponse, + _ApiRequest( + method="GET", + path_fmt="/filesystem/tree/{}", + path_args=[path], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_health(self) -> HealthResponse: + """Health check""" + return await self._do_json( + HealthResponse, + _ApiRequest( + method="GET", + path_fmt="/health", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_network_process_ports( + self, *, pid: str + ) -> GetNetworkProcessPortsResponse: + """Get open ports for a process""" + return await self._do_json( + GetNetworkProcessPortsResponse, + _ApiRequest( + method="GET", + path_fmt="/network/process/{}/ports", + path_args=[pid], + body=None, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_process(self) -> GetProcessResponse: + """List all processes""" + return await self._do_json( + GetProcessResponse, + _ApiRequest( + method="GET", + path_fmt="/process", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_process_identifier(self, *, identifier: str) -> ProcessResponse: + """Get process by identifier""" + return await self._do_json( + ProcessResponse, + _ApiRequest( + method="GET", + path_fmt="/process/{}", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={404: "ErrorResponse"}, + ), + ) + + async def get_process_logs(self, *, identifier: str) -> ProcessLogs: + """Get process logs""" + return await self._do_json( + ProcessLogs, + _ApiRequest( + method="GET", + path_fmt="/process/{}/logs", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def get_process_logs_stream(self, *, identifier: str) -> httpx.Response: + """Stream process logs in real time. Returns the response unread. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="GET", + path_fmt="/process/{}/logs/stream", + path_args=[identifier], + body=None, + query=None, + success_codes=[200], + error_codes=None, + accept="text/plain", + ) + ) + + async def get_watch_filesystem( + self, *, path: str, params: GetWatchFilesystemParams | None = None + ) -> httpx.Response: + """Stream file modification events in a directory. Returns the response unread. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="GET", + path_fmt="/watch/filesystem/{}", + path_args=[path], + body=None, + query=params, + success_codes=[200], + error_codes=None, + accept="text/plain", + ) + ) + + async def post_archive_export( + self, *, request: ExportOptions + ) -> ExportResult | ExportProgress: + """Export the filesystem changes to a presigned URL""" + return await self._do_json_with_status( + {200: ExportResult, 202: ExportProgress}, + _ApiRequest( + method="POST", + path_fmt="/archive/export", + path_args=[], + body=request, + query=None, + success_codes=[200, 202], + error_codes={ + 400: "ErrorResponse", + 409: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def post_archive_resume(self) -> QuiesceStatus: + """Lift the archive freeze""" + return await self._do_json( + QuiesceStatus, + _ApiRequest( + method="POST", + path_fmt="/archive/resume", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={409: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + async def post_drives_mount( + self, *, request: DriveMountRequest + ) -> DriveMountResponse: + """Attach a drive to a local path""" + return await self._do_json( + DriveMountResponse, + _ApiRequest( + method="POST", + path_fmt="/drives/mount", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 403: "ErrorResponse", + 409: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def post_environment_reload(self) -> HandlerReloadResponse: + """Reload environment from guest metadata""" + return await self._do_json( + HandlerReloadResponse, + _ApiRequest( + method="POST", + path_fmt="/environment/reload", + path_args=[], + body=None, + query=None, + success_codes=[200], + error_codes={404: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + async def post_filesystem_multipart_complete( + self, *, upload_id: str, request: MultipartCompleteRequest + ) -> SuccessResponse: + """Complete multipart upload""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="POST", + path_fmt="/filesystem-multipart/{}/complete", + path_args=[upload_id], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def post_filesystem_multipart_initiate( + self, *, path: str, request: MultipartInitiateRequest + ) -> MultipartInitiateResponse: + """Initiate multipart upload""" + return await self._do_json( + MultipartInitiateResponse, + _ApiRequest( + method="POST", + path_fmt="/filesystem-multipart/initiate/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, + ), + ) + + async def post_network_process_monitor( + self, *, pid: str, request: PortMonitorRequest + ) -> PostNetworkProcessMonitorResponse: + """Start monitoring ports for a process""" + return await self._do_json( + PostNetworkProcessMonitorResponse, + _ApiRequest( + method="POST", + path_fmt="/network/process/{}/monitor", + path_args=[pid], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def post_process(self, *, request: ProcessRequest) -> ProcessResponse: + """Execute a command""" + return await self._do_json( + ProcessResponse, + _ApiRequest( + method="POST", + path_fmt="/process", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def post_process_raw( + self, + *, + request: ProcessRequest, + accept: Literal["application/json", "text/event-stream"], + ) -> httpx.Response: + """Execute a command. Returns the response unread, in the requested content type. The caller must close the response.""" + return await self._do_raw( + _ApiRequest( + method="POST", + path_fmt="/process", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + accept=accept, + ) + ) + + async def post_process_stdin( + self, *, identifier: str, content: bytes | str + ) -> SuccessResponse: + """Write to a process's stdin""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="POST", + path_fmt="/process/{}/stdin", + path_args=[identifier], + body=content, + query=None, + success_codes=[200], + error_codes={ + 404: "ErrorResponse", + 409: "ErrorResponse", + 413: "ErrorResponse", + 500: "ErrorResponse", + 503: "ErrorResponse", + }, + body_content_type="application/octet-stream", + ), + ) + + async def post_upgrade(self, *, request: UpgradeRequest) -> SuccessResponse: + """Upgrade the sandbox-api""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="POST", + path_fmt="/upgrade", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={500: "ErrorResponse"}, + ), + ) + + async def put_codegen_fastapply( + self, *, path: str, request: ApplyEditRequest + ) -> ApplyEditResponse: + """Apply code edit""" + return await self._do_json( + ApplyEditResponse, + _ApiRequest( + method="PUT", + path_fmt="/codegen/fastapply/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 503: "ErrorResponse", + }, + ), + ) + + async def put_filesystem( + self, *, path: str, request: FileRequest + ) -> SuccessResponse: + """Create or update a file or directory""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="PUT", + path_fmt="/filesystem/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def put_filesystem_multipart_part( + self, *, upload_id: str, params: PutFilesystemMultipartPartParams, files: Any + ) -> MultipartUploadPartResponse: + """Upload part. *files* is sent as httpx ``files``.""" + return await self._do_json( + MultipartUploadPartResponse, + _ApiRequest( + method="PUT", + path_fmt="/filesystem-multipart/{}/part", + path_args=[upload_id], + body=files, + query=params, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 404: "ErrorResponse", + 500: "ErrorResponse", + }, + body_content_type="multipart/form-data", + ), + ) + + async def put_filesystem_tree( + self, *, path: str, request: TreeRequest + ) -> PutFilesystemTreeResponse: + """Create or update directory tree""" + return await self._do_json( + PutFilesystemTreeResponse, + _ApiRequest( + method="PUT", + path_fmt="/filesystem/tree/{}", + path_args=[path], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + async def put_network_tunnel_config( + self, *, request: TunnelConfigRequest + ) -> SuccessResponse: + """Update tunnel configuration""" + return await self._do_json( + SuccessResponse, + _ApiRequest( + method="PUT", + path_fmt="/network/tunnel/config", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 422: "ErrorResponse", + 500: "ErrorResponse", + }, + ), + ) + + def _build_request(self, request: _ApiRequest) -> httpx.Request: + path = request.path_fmt.format( + *[urllib.parse.quote(a, safe="") for a in request.path_args] + ) + json_body = None + content_body = None + files_body = None + headers: dict[str, str] = {} + if request.accept is not None: + headers["Accept"] = request.accept + if request.body is not None: + if request.body_content_type is None: + if isinstance(request.body, BaseModel): + # Only fields the caller set are sent, so unset fields fall + # back to the server default rather than being reset here. + # An explicit None is kept, since null can mean "clear". + # by_alias: a field renamed for Python (e.g. async_ for + # "async") must serialize under its API name. + json_body = request.body.model_dump( + mode="json", exclude_unset=True, by_alias=True + ) + else: + json_body = request.body + elif request.body_content_type == "multipart/form-data": + # httpx derives the multipart Content-Type, boundary included. + files_body = request.body + else: + headers["Content-Type"] = request.body_content_type + content_body = request.body + params = None + if request.query is not None: + if isinstance(request.query, BaseModel): + # As above, plus dropping None: a null query parameter is + # meaningless and would otherwise serialize as an empty string. + params = request.query.model_dump( + mode="json", exclude_unset=True, exclude_none=True, by_alias=True + ) + else: + params = request.query + return self._http_client.build_request( + request.method, + path, + json=json_body, + content=content_body, + files=files_body, + params=params, + headers=headers, + ) + + async def _do(self, request: _ApiRequest) -> httpx.Response: + response = await self._http_client.send(self._build_request(request)) + if response.status_code not in request.success_codes: + if request.error_codes and response.status_code in request.error_codes: + error_name = request.error_codes[response.status_code] + if error_name in _ERROR_TYPES: + model_cls, exc_cls, field_name = _ERROR_TYPES[error_name] + # A body that does not match the declared error schema + # falls through to the generic ResponseError below. + model = None + with contextlib.suppress(ValidationError): + model = model_cls.model_validate_json(response.content) + if model is not None: + raise exc_cls( + status_code=response.status_code, # ty: ignore[unknown-argument] + **{field_name: model}, + ) + raise ResponseError(status_code=response.status_code, body=response.text) + return response + + async def _do_raw(self, request: _ApiRequest) -> httpx.Response: + response = await self._http_client.send( + self._build_request(request), stream=True + ) + if response.status_code not in request.success_codes: + await response.aread() + if request.error_codes and response.status_code in request.error_codes: + error_name = request.error_codes[response.status_code] + if error_name in _ERROR_TYPES: + model_cls, exc_cls, field_name = _ERROR_TYPES[error_name] + # A body that does not match the declared error schema + # falls through to the generic ResponseError below. + model = None + with contextlib.suppress(ValidationError): + model = model_cls.model_validate_json(response.content) + if model is not None: + raise exc_cls( + status_code=response.status_code, # ty: ignore[unknown-argument] + **{field_name: model}, + ) + raise ResponseError(status_code=response.status_code, body=response.text) + return response + + async def _do_json(self, response_type: type[_T], request: _ApiRequest) -> _T: + response = await self._do(request) + content_type = response.headers.get("content-type", "") + if not content_type.startswith("application/json"): + raise ValueError( + f"unexpected content type {content_type!r}, expected application/json" + ) + return response_type.model_validate_json(response.content) + + async def _do_json_with_status( + self, response_types: Mapping[int, type[_T]], request: _ApiRequest + ) -> _T: + response = await self._do(request) + response_type = response_types.get(response.status_code) + if response_type is None: + # A bodyless success code, such as 204 alongside a JSON 200. The + # call site's return type includes None only when one is declared, + # so this cast is unreachable otherwise. + return cast(_T, None) + content_type = response.headers.get("content-type", "") + if not content_type.startswith("application/json"): + raise ValueError( + f"unexpected content type {content_type!r}, expected application/json" + ) + return response_type.model_validate_json(response.content) diff --git a/baseten/client/sandboxapi/_models.py b/baseten/client/sandboxapi/_models.py new file mode 100644 index 0000000..8edfe99 --- /dev/null +++ b/baseten/client/sandboxapi/_models.py @@ -0,0 +1,929 @@ +# generated by datamodel-codegen: +# filename: + +from __future__ import annotations + +from enum import StrEnum +from typing import Annotated + +from pydantic import BaseModel, ConfigDict, Field, RootModel + + +class ApplyEditRequest(BaseModel): + codeEdit: Annotated[ + str, + Field( + examples=[ + "// Add world parameter\nfunction hello(world) {\n console.log('Hello', world);\n}" + ] + ), + ] + model: Annotated[str | None, Field(examples=["relace-apply-3"])] = None + + +class ApplyEditResponse(BaseModel): + message: Annotated[ + str | None, Field(examples=["Code edit applied successfully"]) + ] = None + originalContent: Annotated[ + str | None, Field(examples=["function hello() {\n console.log('Hello');\n}"]) + ] = None + path: Annotated[str | None, Field(examples=["src/main.js"])] = None + provider: Annotated[str | None, Field(examples=["Relace"])] = None + success: Annotated[bool | None, Field(examples=[True])] = None + updatedContent: Annotated[ + str | None, + Field(examples=["function hello(world) {\n console.log('Hello', world);\n}"]), + ] = None + + +class ArchiveManifest(BaseModel): + added: Annotated[ + int | None, + Field( + description="Added and Modified count the archive's payload members.", + examples=[11], + ), + ] = None + apiVersion: Annotated[ + str | None, + Field( + description="APIVersion is the sandbox-api build that produced the archive.", + examples=["v0.1.0"], + ), + ] = None + createdAt: str + deleted: Annotated[ + list[str] | None, + Field( + description="Deleted are paths the image has and the sandbox deleted. Tar cannot carry\na deletion, so import applies these from the manifest." + ), + ] = None + excludes: Annotated[ + list[str] | None, + Field(description="Excludes are the paths left out of the comparison."), + ] = None + imageDevice: Annotated[ + str | None, + Field( + description="ImageDevice is the device the pristine image was read from, for the record:\nit says where the sandbox that exported the archive found its image.", + examples=["/dev/vda"], + ), + ] = None + modified: Annotated[int | None, Field(examples=[3])] = None + payloadBytes: Annotated[ + int | None, + Field( + description="PayloadBytes is the total content size of the payload members.", + examples=[3073449], + ), + ] = None + processes: Annotated[ + bool | None, + Field( + description="Processes tells whether ProcessesName is present.", + examples=[True], + ), + ] = None + root: Annotated[ + str, + Field( + description="Root is the directory the paths are relative to.", + examples=["/"], + ), + ] + version: Annotated[int, Field(examples=[1])] + + +class ContentSearchMatch(BaseModel): + column: Annotated[int, Field(examples=[10])] + context: Annotated[ + str | None, Field(examples=["previous line\ncurrent line\nnext line"]) + ] = None + line: Annotated[int, Field(examples=[42])] + path: Annotated[str, Field(examples=["src/main.go"])] + text: Annotated[str, Field(examples=["const searchText = 'example'"])] + + +class ContentSearchResponse(BaseModel): + matches: list[ContentSearchMatch] + query: Annotated[str, Field(examples=["searchText"])] + total: Annotated[int, Field(examples=[5])] + + +class DriveMountInfo(BaseModel): + driveName: str | None = None + drivePath: str | None = None + gidMap: Annotated[ + str | None, Field(description="The local GID used for this mount") + ] = None + mountPath: str | None = None + readOnly: bool | None = None + uidMap: Annotated[ + str | None, Field(description="The local UID used for this mount") + ] = None + + +class DriveMountRequest(BaseModel): + driveName: str + drivePath: Annotated[str | None, Field(description='Optional, defaults to "/"')] = ( + None + ) + gidMap: Annotated[ + str | None, + Field(description="Optional, local GID to map (filer GID is always 0)"), + ] = None + mountPath: str + readOnly: Annotated[ + bool | None, Field(description="Optional, defaults to false") + ] = None + uidMap: Annotated[ + str | None, + Field(description="Optional, local UID to map (filer UID is always 0)"), + ] = None + + +class DriveMountResponse(BaseModel): + driveName: str | None = None + drivePath: str | None = None + gidMap: Annotated[ + str | None, Field(description="The local GID used for this mount") + ] = None + message: str | None = None + mountPath: str | None = None + readOnly: bool | None = None + success: bool | None = None + uidMap: Annotated[ + str | None, Field(description="The local UID used for this mount") + ] = None + + +class DriveUnmountResponse(BaseModel): + message: str | None = None + mountPath: str | None = None + success: bool | None = None + + +class ErrorResponse(BaseModel): + error: Annotated[str, Field(examples=["Error message"])] + + +class File(BaseModel): + group: str + lastModified: str + name: str + owner: str + path: str + permissions: str + size: int + + +class FileRequest(BaseModel): + content: Annotated[str | None, Field(examples=["file contents here"])] = None + isDirectory: Annotated[bool | None, Field(examples=[False])] = None + permissions: Annotated[str | None, Field(examples=["0644"])] = None + + +class FileWithContent(BaseModel): + content: str + group: str + lastModified: str + name: str + owner: str + path: str + permissions: str + size: int + + +class FindMatch(BaseModel): + path: Annotated[str, Field(examples=["src/main.go"])] + type: Annotated[str, Field(description='"file" or "directory"', examples=["file"])] + + +class FindResponse(BaseModel): + matches: list[FindMatch] + total: Annotated[int, Field(examples=[5])] + + +class FuzzySearchMatch(BaseModel): + path: Annotated[str, Field(examples=["src/main.go"])] + score: Annotated[int, Field(examples=[100])] + type: Annotated[str, Field(description='"file" or "directory"', examples=["file"])] + + +class FuzzySearchResponse(BaseModel): + matches: list[FuzzySearchMatch] + total: Annotated[int, Field(examples=[5])] + + +class MultipartInitiateRequest(BaseModel): + permissions: Annotated[str | None, Field(examples=["0644"])] = None + + +class MultipartInitiateResponse(BaseModel): + path: Annotated[str | None, Field(examples=["/tmp/largefile.dat"])] = None + uploadId: Annotated[ + str | None, Field(examples=["550e8400-e29b-41d4-a716-446655440000"]) + ] = None + + +class MultipartPartInfo(BaseModel): + etag: Annotated[ + str | None, Field(examples=["5d41402abc4b2a76b9719d911017c592"]) + ] = None + partNumber: Annotated[int | None, Field(examples=[1])] = None + + +class MultipartUpload(BaseModel): + abortUrl: Annotated[ + str | None, + Field( + description="AbortURL is a presigned DELETE URL that discards the parts already\nuploaded. Without it a failed export leaves them on the storage until a\nlifecycle rule removes them." + ), + ] = None + completeUrl: Annotated[ + str | None, + Field( + description="CompleteURL is a presigned POST URL that assembles the parts." + ), + ] = None + partSize: Annotated[ + int | None, + Field( + description="PartSize is the number of bytes sent to every part but the last.", + examples=[536870912], + ), + ] = None + partUrls: Annotated[ + list[str] | None, + Field( + description="PartURLs are presigned PUT URLs, one per part, in order. Extra ones are\nleft unused." + ), + ] = None + + +class MultipartUploadPartResponse(BaseModel): + etag: Annotated[ + str | None, Field(examples=["5d41402abc4b2a76b9719d911017c592"]) + ] = None + partNumber: Annotated[int | None, Field(examples=[1])] = None + size: Annotated[int | None, Field(examples=[5242880])] = None + + +class PortMonitorRequest(BaseModel): + callback: Annotated[ + str | None, + Field( + description="URL to call when a new port is detected", + examples=["http://localhost:3000/callback"], + ), + ] = None + + +class ProcessLogs(BaseModel): + logs: Annotated[str, Field(examples=["logs output"])] + stderr: Annotated[str, Field(examples=["stderr output"])] + stdout: Annotated[str, Field(examples=["stdout output"])] + + +class ProcessRequest(BaseModel): + command: Annotated[str, Field(examples=["ls -la"])] + env: Annotated[dict[str, str] | None, Field(examples=[{'{"PORT"': ' "3000"}'}])] = ( + None + ) + keepAlive: Annotated[ + bool | None, + Field( + description="Disable scale-to-zero while process runs. Default timeout is 600s (10 minutes). Set timeout to 0 for infinite.", + examples=[False], + ), + ] = None + maxRestarts: Annotated[ + int | None, + Field( + description="Maximum number of restarts on failure. Set to a negative value (e.g. -1) for unlimited restarts.", + examples=[3], + ), + ] = None + name: Annotated[str | None, Field(examples=["my-process"])] = None + restartOnFailure: Annotated[bool | None, Field(examples=[True])] = None + stdin: Annotated[ + bool | None, + Field( + description="Open a writable stdin pipe, fed via POST /process/{identifier}/stdin and closed via DELETE. The pipe does not survive a sandbox-api restart: the process then sees EOF.", + examples=[False], + ), + ] = None + timeout: Annotated[ + int | None, + Field( + description="Timeout in seconds. When keepAlive is true, defaults to 600s (10 minutes). Set to 0 for infinite (no auto-kill).", + examples=[30], + ), + ] = None + waitForCompletion: Annotated[bool | None, Field(examples=[False])] = None + waitForPorts: Annotated[list[int] | None, Field(examples=[[3000, 8080]])] = None + workingDir: Annotated[str | None, Field(examples=["/home/user"])] = None + + +class Status(StrEnum): + failed = "failed" + killed = "killed" + stopped = "stopped" + running = "running" + completed = "completed" + + +class ProcessResponse(BaseModel): + command: Annotated[str, Field(examples=["ls -la"])] + completedAt: Annotated[str, Field(examples=["Wed, 01 Jan 2023 12:01:00 GMT"])] + exitCode: Annotated[int, Field(examples=[0])] + keepAlive: Annotated[ + bool | None, + Field( + description="Whether scale-to-zero is disabled for this process", + examples=[False], + ), + ] = None + logs: Annotated[str, Field(examples=["logs output"])] + maxRestarts: Annotated[int | None, Field(examples=[3])] = None + name: Annotated[str, Field(examples=["my-process"])] + pid: Annotated[str, Field(examples=["1234"])] + restartCount: Annotated[int | None, Field(examples=[2])] = None + restartOnFailure: Annotated[bool | None, Field(examples=[True])] = None + startedAt: Annotated[str, Field(examples=["Wed, 01 Jan 2023 12:00:00 GMT"])] + status: Annotated[Status, Field(examples=["running"])] + stderr: Annotated[str, Field(examples=["stderr output"])] + stdin: Annotated[ + bool | None, + Field( + description="Whether the process was started with a writable stdin pipe", + examples=[False], + ), + ] = None + stdout: Annotated[str, Field(examples=["stdout output"])] + workingDir: Annotated[str, Field(examples=["/home/user"])] + + +class RankedFile(BaseModel): + content: str | None = None + path: str | None = None + score: float | None = None + + +class RerankingResponse(BaseModel): + files: list[RankedFile] | None = None + message: Annotated[str | None, Field(examples=["Found 5 relevant files"])] = None + success: Annotated[bool | None, Field(examples=[True])] = None + + +class Subdirectory(BaseModel): + name: str + path: str + + +class SuccessResponse(BaseModel): + message: Annotated[str, Field(examples=["File created successfully"])] + path: Annotated[str | None, Field(examples=["/path/to/file"])] = None + + +class TreeRequest(BaseModel): + files: Annotated[ + dict[str, str] | None, + Field( + examples=[{'"dir/file2.txt"': '"content2"}', '{"file1.txt"': '"content1"'}] + ), + ] = None + + +class TunnelConfigRequest(BaseModel): + config: Annotated[ + str, + Field( + description="Base64-encoded tunnel config JSON", + examples=["eyJsb2NhbF9pcCI6ICIxMC4wLjAuMS8zMiIsIC4uLn0="], + ), + ] + + +class UpgradeRequest(BaseModel): + baseUrl: Annotated[ + str | None, + Field( + description="Base URL for releases (useful for forks)", + examples=["https://github.com/blaxel-ai/sandbox/releases"], + ), + ] = None + version: Annotated[ + str | None, + Field( + description='Version to upgrade to: "latest" (default), "develop", "main", or specific tag like "v1.0.0"', + examples=["latest"], + ), + ] = None + + +class GetCodegenRerankingParams(BaseModel): + query: Annotated[str, Field(description="Natural language query to search for")] + scoreThreshold: Annotated[ + float | None, Field(description="Minimum relevance score (default: 0.5)") + ] = None + tokenLimit: Annotated[ + int | None, Field(description="Maximum tokens to return (default: 30000)") + ] = None + filePattern: Annotated[ + str | None, + Field( + description="Regex pattern to filter files (e.g., .*\\\\.ts$ for TypeScript files)" + ), + ] = None + + +class GetFilesystemContentSearchParams(BaseModel): + query: Annotated[str, Field(description="Text to search for")] + caseSensitive: Annotated[ + bool | None, Field(description="Case sensitive search (default: false)") + ] = None + maxResults: Annotated[ + int | None, + Field(description="Maximum number of results to return (default: 100)"), + ] = None + filePattern: Annotated[ + str | None, Field(description="File pattern to include (e.g., *.go)") + ] = None + excludeDirs: Annotated[ + str | None, + Field( + description="Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage)" + ), + ] = None + + +class GetFilesystemFindParams(BaseModel): + type: Annotated[ + str | None, Field(description="Type of search (file or directory)") + ] = None + patterns: Annotated[ + str | None, + Field(description="Comma-separated file patterns to include (e.g., *.go,*.js)"), + ] = None + maxResults: Annotated[ + int | None, + Field( + description="Maximum number of results to return (default: 20). If set to 0, all results will be returned." + ), + ] = None + excludeDirs: Annotated[ + str | None, + Field( + description="Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage). Use empty string to skip no directories." + ), + ] = None + excludeHidden: Annotated[ + bool | None, + Field(description="Exclude hidden files and directories (default: true)"), + ] = None + + +class PutFilesystemMultipartPartParams(BaseModel): + partNumber: Annotated[int, Field(description="Part number (1-10000)")] + + +class GetFilesystemSearchParams(BaseModel): + maxResults: Annotated[ + int | None, + Field(description="Maximum number of results to return (default: 20)"), + ] = None + patterns: Annotated[ + str | None, + Field(description="Comma-separated file patterns to include (e.g., *.go,*.js)"), + ] = None + excludeDirs: Annotated[ + str | None, + Field( + description="Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage). Use empty string to skip no directories." + ), + ] = None + excludeHidden: Annotated[ + bool | None, + Field(description="Exclude hidden files and directories (default: true)"), + ] = None + + +class DeleteFilesystemParams(BaseModel): + recursive: Annotated[ + bool | None, Field(description="Delete directory recursively") + ] = None + + +class GetFilesystemParams(BaseModel): + download: Annotated[ + bool | None, Field(description="Force download mode for files") + ] = None + + +class DeleteFilesystemTreeParams(BaseModel): + recursive: Annotated[ + bool | None, Field(description="Delete directory recursively") + ] = None + + +class GetWatchFilesystemParams(BaseModel): + ignore: Annotated[ + str | None, Field(description="Ignore patterns (comma-separated)") + ] = None + + +class DeleteNetworkProcessMonitorResponse(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + + +class PostNetworkProcessMonitorResponse(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + + +class GetNetworkProcessPortsResponse(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + + +class GetProcessResponse(RootModel[list[ProcessResponse]]): + root: list[ProcessResponse] + + +class ArchiveChangeKind(StrEnum): + ChangeAdded = "added" + ChangeModified = "modified" + ChangeDeleted = "deleted" + + +class ArchiveExportState(StrEnum): + ExportRunning = "running" + ExportSucceeded = "succeeded" + ExportFailed = "failed" + + +class ArchiveQuiesceState(StrEnum): + StateActive = "active" + StateQuiescing = "quiescing" + StateQuiesced = "quiesced" + StateRestoring = "restoring" + + +class ArchiveRestoreState(StrEnum): + RestoreDownloading = "downloading" + RestoreExtracting = "extracting" + RestoreRelaunching = "relaunching" + RestoreSucceeded = "succeeded" + RestoreFailed = "failed" + + +class FilesystemUploadedPart(BaseModel): + etag: Annotated[ + str | None, Field(examples=["5d41402abc4b2a76b9719d911017c592"]) + ] = None + partNumber: Annotated[int | None, Field(examples=[1])] = None + size: Annotated[int | None, Field(examples=[5242880])] = None + uploadedAt: str | None = None + + +class HandlerReloadResponse(BaseModel): + applied: int | None = None + generation: int | None = None + removed: int | None = None + + +class ProcessUpgradeState(StrEnum): + UpgradeStateIdle = "idle" + UpgradeStateRunning = "running" + UpgradeStateCompleted = "completed" + UpgradeStateFailed = "failed" + + +class Directory(BaseModel): + files: list[File] + name: str + path: str + subdirectories: Annotated[ + list[Subdirectory], Field(description="@name Subdirectories") + ] + + +class DriveListResponse(BaseModel): + mounts: list[DriveMountInfo] | None = None + + +class ExportOptions(BaseModel): + model_config = ConfigDict(populate_by_name=True) + + async_: Annotated[ + bool | None, + Field( + alias="async", + description="Async starts the export and answers immediately, leaving it to run: an\narchive of a large filesystem takes longer than a request may be held\nopen. Its progress is reported by /archive/status.", + examples=[False], + ), + ] = None + dryRun: Annotated[ + bool | None, + Field( + description="DryRun reports what would be archived, and its exact size, without\nstopping anything and without uploading.", + examples=[False], + ), + ] = None + excludes: Annotated[ + list[str] | None, + Field(description="Excludes are added to the paths excluded by default."), + ] = None + headers: Annotated[ + dict[str, str] | None, + Field( + description="Headers are sent with the upload request as given. A presigned URL only\naccepts the headers it was signed for, so these have to match what the\ncaller signed: sending one that was not signed, or signing one that is not\nsent, is rejected as a signature mismatch. Typical use is a storage class,\nx-amz-storage-class: GLACIER_IR." + ), + ] = None + imageDevice: Annotated[ + str | None, + Field( + description="ImageDevice is the device holding the pristine image. It is found on its\nown, wherever the sandbox booted from attached it, and naming one here\nonly overrides that.", + examples=["/dev/vda"], + ), + ] = None + imageMountPoint: Annotated[ + str | None, + Field( + description="ImageMountPoint is a directory where the pristine image is already mounted.\nWhen set the image device is neither mounted nor unmounted.", + examples=["/mnt/lower"], + ), + ] = None + multipart: Annotated[ + MultipartUpload | None, + Field( + description="Multipart uploads the archive part by part instead, which is how an\narchive larger than the 5 GB a single PUT accepts is stored. It takes\nprecedence over URL." + ), + ] = None + saveProcesses: Annotated[ + bool | None, + Field( + description="SaveProcesses stores the process list in the archive so restore can\nrelaunch the workload. Defaults to true; set it to false to archive\nstorage only.", + examples=[True], + ), + ] = None + stopTimeoutSeconds: Annotated[ + int | None, + Field( + description="StopTimeoutSeconds bounds the graceful stop of each process.", + examples=[30], + ), + ] = None + url: Annotated[ + str | None, + Field( + description="URL is a presigned S3 PUT URL the archive is streamed to. Empty is only\nvalid with DryRun, or with Multipart.", + examples=["https://bucket.s3.amazonaws.com/key?..."], + ), + ] = None + + +class ExportProgress(BaseModel): + error: Annotated[ + str | None, + Field( + description="Error is why the export failed, without the presigned URL it used." + ), + ] = None + finishedAt: str | None = None + size: Annotated[ + int | None, + Field( + description="Size is the archive's exact size, known once the filesystem is scanned.", + examples=[3074211], + ), + ] = None + startedAt: str | None = None + state: Annotated[ArchiveExportState | None, Field(examples=["running"])] = None + uploaded: Annotated[ + bool | None, + Field( + description="Uploaded reports whether the storage holds the archive.", + examples=[False], + ), + ] = None + + +class MultipartCompleteRequest(BaseModel): + parts: list[MultipartPartInfo] | None = None + + +class MultipartListPartsResponse(BaseModel): + parts: list[FilesystemUploadedPart] | None = None + uploadId: Annotated[ + str | None, Field(examples=["550e8400-e29b-41d4-a716-446655440000"]) + ] = None + + +class RestoreProgress(BaseModel): + deleted: Annotated[int | None, Field(examples=[3])] = None + downloaded: Annotated[ + int | None, + Field( + description="Downloaded is how much of the archive has been read so far.", + examples=[1048576], + ), + ] = None + error: Annotated[ + str | None, + Field( + description="Error is why the restore failed, without the presigned URL it used." + ), + ] = None + finishedAt: str | None = None + restored: Annotated[ + int | None, + Field( + description="Restored and Deleted count what the archive changed on the filesystem.", + examples=[1204], + ), + ] = None + size: Annotated[ + int | None, + Field( + description="Size is the archive's size as the storage announced it, and zero when it\nannounced none - a client showing a percentage has to allow for that.", + examples=[3074211], + ), + ] = None + startedAt: str | None = None + state: Annotated[ArchiveRestoreState | None, Field(examples=["extracting"])] = None + + +class UpgradeStatus(BaseModel): + binaryPath: Annotated[ + str | None, + Field( + description="Path to downloaded binary", examples=["/tmp/sandbox-api-new"] + ), + ] = None + bytesDownloaded: Annotated[ + int | None, Field(description="Bytes downloaded", examples=[25034936]) + ] = None + downloadUrl: Annotated[ + str | None, + Field(description="URL used for download", examples=["https://github.com/..."]), + ] = None + error: Annotated[ + str | None, + Field( + description="Error message if failed", + examples=["Failed to download binary"], + ), + ] = None + lastAttempt: Annotated[ + str | None, Field(description="When the upgrade was attempted") + ] = None + status: Annotated[ + ProcessUpgradeState, + Field( + description="Current state (idle, running, completed, failed)", + examples=["running"], + ), + ] + step: Annotated[ + str, + Field( + description="Current/last step (none, starting, download, validate, replace, completed, skipped)", + examples=["download"], + ), + ] + version: Annotated[ + str, Field(description="Version being upgraded to", examples=["latest"]) + ] + + +class GetFilesystemResponse(RootModel[Directory | FileWithContent | bytes]): + root: Directory | FileWithContent | bytes + + +class GetFilesystemTreeResponse(RootModel[Directory | FileWithContent | bytes]): + root: Directory | FileWithContent | bytes + + +class PutFilesystemTreeResponse(RootModel[Directory | FileWithContent | bytes]): + root: Directory | FileWithContent | bytes + + +class ArchiveChange(BaseModel): + kind: Annotated[ArchiveChangeKind, Field(examples=["added"])] + path: Annotated[ + str, + Field( + description="Path is relative to the root, without a leading slash.", + examples=["usr/bin/curl"], + ), + ] + size: Annotated[ + int | None, + Field( + description="Size is the file content size in bytes, 0 for anything but a regular file.", + examples=[256216], + ), + ] = None + + +class FilesystemMultipartUpload(BaseModel): + initiatedAt: str | None = None + parts: dict[str, FilesystemUploadedPart] | None = None + path: Annotated[str | None, Field(examples=["/tmp/largefile.dat"])] = None + permissions: Annotated[int | None, Field(examples=[420])] = None + uploadId: Annotated[ + str | None, Field(examples=["550e8400-e29b-41d4-a716-446655440000"]) + ] = None + + +class ExportResult(BaseModel): + changes: Annotated[ + list[ArchiveChange] | None, + Field( + description="Changes lists every path in the archive. Only filled for a dry run,\nwhere it is the point of the call." + ), + ] = None + duration: Annotated[str | None, Field(examples=["4.2s"])] = None + manifest: ArchiveManifest + size: Annotated[ + int | None, + Field( + description="Size is the exact number of bytes uploaded, known before the upload\nstarts since the archive is not compressed.", + examples=[3074211], + ), + ] = None + stoppedProcesses: Annotated[ + list[str] | None, + Field( + description="StoppedProcesses are the processes stopped to freeze the filesystem." + ), + ] = None + uploaded: Annotated[ + bool | None, + Field(description="Uploaded is false for a dry run.", examples=[True]), + ] = None + + +class HealthResponse(BaseModel): + arch: Annotated[str, Field(examples=["amd64"])] + buildTime: Annotated[str, Field(examples=["2026-01-29T17:36:52+00:00"])] + gitCommit: Annotated[str, Field(examples=["abc123"])] + goVersion: Annotated[str, Field(examples=["go1.25.0"])] + lastUpgrade: UpgradeStatus + os: Annotated[str, Field(examples=["linux"])] + startedAt: Annotated[str, Field(examples=["2026-01-29T18:45:49+00:00"])] + status: Annotated[str, Field(examples=["ok"])] + upgradeCount: Annotated[int, Field(examples=[0])] + uptime: Annotated[str, Field(examples=["1h30m"])] + uptimeSeconds: Annotated[float, Field(examples=[5400.5])] + version: Annotated[str, Field(examples=["v0.1.0"])] + + +class MultipartListUploadsResponse(BaseModel): + uploads: list[FilesystemMultipartUpload] | None = None + + +class QuiesceStatus(BaseModel): + export: Annotated[ + ExportProgress | None, + Field( + description="Export reports the export started asynchronously, if there was one. It is\nhow a caller that did not wait for the export learns that the archive is\non the storage, or why it is not." + ), + ] = None + readOnlyRoot: Annotated[ + bool | None, + Field( + description="ReadOnlyRoot reports whether the root mount was remounted read-only, which\nis what actually stops writes; false means the freeze relies only on the\nAPI refusing calls, and the reason says why.", + examples=[True], + ), + ] = None + reason: Annotated[ + str | None, + Field( + description="Reason is a human readable explanation of why the sandbox is frozen.", + examples=["archive export"], + ), + ] = None + restore: Annotated[ + RestoreProgress | None, + Field( + description="Restore reports the archive this sandbox was started from, if it was\nstarted from one: how far its restore has got, and how it ended." + ), + ] = None + since: Annotated[ + str | None, Field(description="Since is when the sandbox left StateActive.") + ] = None + state: Annotated[ArchiveQuiesceState, Field(examples=["quiesced"])] + stoppedProcesses: Annotated[ + list[str] | None, + Field( + description="StoppedProcesses are the process identifiers stopped while quiescing." + ), + ] = None diff --git a/pyproject.toml b/pyproject.toml index e628519..3342aa0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "baseten" -version = "0.11.0" +version = "0.12.0" description = "Baseten Python SDK" readme = "README.md" license = "MIT" diff --git a/scripts/apigen/__main__.py b/scripts/apigen/__main__.py index 93d924b..db43a5a 100644 --- a/scripts/apigen/__main__.py +++ b/scripts/apigen/__main__.py @@ -7,11 +7,14 @@ import argparse import ast +import json import subprocess import sys import urllib.request from pathlib import Path +import yaml + from scripts.apigen.clientgen import generate_client from scripts.apigen.postprocess import postprocess_models from scripts.apigen.preprocess import preprocess_spec, preprocess_truss_config_schema @@ -21,6 +24,7 @@ TRUSS_CONFIG_SCHEMA_URL = ( "https://raw.githubusercontent.com/basetenlabs/truss/main/truss/config.schema.json" ) +SANDBOX_SPEC_URL = "https://raw.githubusercontent.com/blaxel-ai/sandbox/main/sandbox-api/docs/openapi.yml" APIGEN_DIR = Path(__file__).parent SPECS_DIR = APIGEN_DIR / "specs" @@ -42,11 +46,13 @@ def main() -> None: download_spec(MANAGEMENT_SPEC_URL, SPECS_DIR / "management.json") download_spec(INFERENCE_SPEC_URL, SPECS_DIR / "inference.json") download_spec(TRUSS_CONFIG_SCHEMA_URL, SPECS_DIR / "config.schema.json") + download_spec(SANDBOX_SPEC_URL, SPECS_DIR / "sandbox.yml") generate_api( SPECS_DIR / "management.json", CLIENT_DIR / "managementapi", "Management" ) generate_api(SPECS_DIR / "inference.json", CLIENT_DIR / "inferenceapi", "Inference") + generate_api(SPECS_DIR / "sandbox.yml", CLIENT_DIR / "sandboxapi", "Sandbox") generate_modelconfig(SPECS_DIR / "config.schema.json", CLIENT_DIR / "modelconfig") @@ -56,11 +62,21 @@ def download_spec(url: str, dest: Path) -> None: dest.write_bytes(resp.read()) +def _read_spec(spec_file: Path) -> bytes: + # YAML specs are committed exactly as upstream serves them and converted + # here rather than at download time. Timestamp scalars are serialized back + # to ISO strings, matching how js-yaml keeps them for the JS SDK. + if spec_file.suffix in (".yml", ".yaml"): + doc = yaml.safe_load(spec_file.read_text()) + return json.dumps(doc, default=lambda value: value.isoformat()).encode() + return spec_file.read_bytes() + + def generate_api(spec_file: Path, out_dir: Path, display_name: str) -> None: print(f"Generating {out_dir.name} from {spec_file}") out_dir.mkdir(parents=True, exist_ok=True) - preprocessed = preprocess_spec(spec_file.read_bytes()) + preprocessed = preprocess_spec(_read_spec(spec_file)) models_file = out_dir / "_models.py" run_datamodel_codegen(preprocessed, models_file) diff --git a/scripts/apigen/clientgen.py b/scripts/apigen/clientgen.py index b321dca..f00246b 100644 --- a/scripts/apigen/clientgen.py +++ b/scripts/apigen/clientgen.py @@ -13,6 +13,9 @@ def generate_client(spec_data: bytes, out_file: Path) -> None: _PATH_PARAM_RE = re.compile(r"\{(\w+)\}") +_JSON_CONTENT = "application/json" +_MULTIPART_CONTENT = "multipart/form-data" + @dataclass class _Operation: @@ -20,14 +23,16 @@ class _Operation: http_method: str path: str path_params: list[str] + query_ref: str + query_required: bool has_body: bool req_body_ref: str - resp_ref: str - success_code: int + body_content_type: str + json_responses: list[tuple[int, str]] + raw_accepts: list[str] + success_codes: list[int] error_codes: dict[int, str] | None summary: str - query_ref: str - query_required: bool def resolve_method_names(spec: dict) -> dict[tuple[str, str], str]: @@ -66,9 +71,14 @@ def resolve_method_names(spec: dict) -> dict[tuple[str, str], str]: return result -def query_request_model_name(method_name: str) -> str: +def query_params_model_name(method_name: str) -> str: """Model name for an operation's injected query-parameter schema.""" - return _snake_to_pascal(method_name) + "Request" + return _snake_to_pascal(method_name) + "Params" + + +def response_type_model_name(method_name: str) -> str: + """Model name for an operation's injected inline response schema.""" + return _snake_to_pascal(method_name) + "Response" def _snake_to_pascal(s: str) -> str: @@ -90,36 +100,45 @@ def _extract_operations(spec: dict) -> list[_Operation]: for p in op_data.get("parameters", []) if isinstance(p, dict) and p.get("in") == "query" ] - query_ref = query_request_model_name(name) if query_params else "" - query_required = any(p.get("required") for p in query_params) + json_responses = _json_response_refs(spec, op_data) + # Several JSON success codes return a union narrowed by type, so a + # schema shared by two codes would hide which code was returned. + json_refs = [ref for _, ref in json_responses] + if len(json_refs) != len(set(json_refs)): + raise ValueError( + f"{http_method.upper()} {path} shares a response schema " + f"across success codes: {json_responses}" + ) ops.append( _Operation( name=name, http_method=http_method.upper(), path=path, path_params=_PATH_PARAM_RE.findall(path), + query_ref=query_params_model_name(name) if query_params else "", + query_required=any(p.get("required") for p in query_params), has_body="requestBody" in op_data, req_body_ref=_body_schema_ref(spec, op_data), - resp_ref=_response_schema_ref(spec, op_data), - success_code=_extract_success_code(op_data, http_method, path), + body_content_type=_body_content_type(spec, op_data), + json_responses=json_responses, + raw_accepts=_raw_response_accepts(spec, op_data), + success_codes=_extract_success_codes(op_data, http_method, path), error_codes=_error_code_map(spec, op_data), summary=op_data.get("summary", ""), - query_ref=query_ref, - query_required=query_required, ) ) ops.sort(key=lambda o: o.name) return ops -def _extract_success_code(op: dict, http_method: str, path: str) -> int: +def _extract_success_codes(op: dict, http_method: str, path: str) -> list[int]: responses = op.get("responses", {}) - codes = [int(c) for c in responses if c.isdigit() and 200 <= int(c) < 300] - if len(codes) != 1: + codes = sorted(int(c) for c in responses if c.isdigit() and 200 <= int(c) < 300) + if not codes: raise ValueError( - f"expected exactly one 2xx response for {http_method.upper()} {path}, got {codes}" + f"expected at least one 2xx response for {http_method.upper()} {path}" ) - return codes[0] + return codes def _derive_method_name( @@ -161,10 +180,7 @@ def _json_content_schema_ref(node: dict | None) -> str: if node is None: return "" ref = ( - node.get("content", {}) - .get("application/json", {}) - .get("schema", {}) - .get("$ref", "") + node.get("content", {}).get(_JSON_CONTENT, {}).get("schema", {}).get("$ref", "") ) return ref.rsplit("/", 1)[-1] if ref else "" @@ -176,26 +192,58 @@ def _body_schema_ref(spec: dict, op: dict) -> str: return _json_content_schema_ref(_resolve_ref(spec, rb)) -def _response_schema_ref(spec: dict, op: dict) -> str: +def _body_content_type(spec: dict, op: dict) -> str: + """Non-JSON request body content type, or "" for JSON or no body. + + JSON is preferred when an operation declares several body encodings. + """ + rb = _resolve_ref(spec, op.get("requestBody")) + if rb is None: + return "" + content_types = list(rb.get("content", {})) + if _JSON_CONTENT in content_types: + return "" + return content_types[0] if content_types else "" + + +def _success_responses(op: dict) -> dict[str, dict]: responses = op.get("responses", {}) - for code in ("200", "201", "202"): - resp_node = responses.get(code) - if not isinstance(resp_node, dict): - continue + return { + code: resp + for code, resp in responses.items() + if code.isdigit() and 200 <= int(code) < 300 and isinstance(resp, dict) + } + + +def _json_response_refs(spec: dict, op: dict) -> list[tuple[int, str]]: + result: list[tuple[int, str]] = [] + for code, resp_node in _success_responses(op).items(): resolved = _resolve_ref(spec, resp_node) if ref := _json_content_schema_ref(resolved): - return ref - # If the response was a $ref to components/responses and has JSON - # content, use the response component name as the type. - if resp_node.get("$ref") and _has_json_content(resolved): - return resp_node["$ref"].rsplit("/", 1)[-1] - return "" + result.append((int(code), ref)) + elif resp_node.get("$ref") and _has_json_content(resolved): + # A $ref to components/responses with JSON content: use the + # response component name as the type. + result.append((int(code), resp_node["$ref"].rsplit("/", 1)[-1])) + return result + + +def _raw_response_accepts(spec: dict, op: dict) -> list[str]: + accepts: set[str] = set() + for resp_node in _success_responses(op).values(): + resolved = _resolve_ref(spec, resp_node) + if resolved is None: + continue + for content_type in resolved.get("content", {}): + if content_type != _JSON_CONTENT: + accepts.add(content_type) + return sorted(accepts) def _has_json_content(node: dict | None) -> bool: if node is None: return False - return "application/json" in node.get("content", {}) + return _JSON_CONTENT in node.get("content", {}) def _error_code_map(spec: dict, op: dict) -> dict[int, str] | None: @@ -218,8 +266,12 @@ def _path_fmt(path: str) -> str: def _render_client(ops: list[_Operation]) -> str: - has_typed_resp = any(op.resp_ref for op in ops) - has_no_resp = any(not op.resp_ref for op in ops) + has_typed_resp = any(op.json_responses for op in ops) + # Status dispatch covers an operation with more than one success code and + # at least one JSON schema among them, since the others may be bodyless. + has_status_resp = any(op.json_responses and len(op.success_codes) > 1 for op in ops) + has_raw = any(op.raw_accepts for op in ops) + has_no_resp = any(not op.json_responses and not op.raw_accepts for op in ops) error_refs = sorted({ref for op in ops for ref in (op.error_codes or {}).values()}) @@ -229,8 +281,8 @@ def _render_client(ops: list[_Operation]) -> str: model_imports.add(op.req_body_ref) if op.query_ref: model_imports.add(op.query_ref) - if op.resp_ref: - model_imports.add(op.resp_ref) + for _, ref in op.json_responses: + model_imports.add(ref) for ref in (op.error_codes or {}).values(): model_imports.add(ref) @@ -241,8 +293,9 @@ def _render_client(ops: list[_Operation]) -> str: import contextlib import urllib.parse +from collections.abc import Mapping from dataclasses import dataclass -from typing import Any, TypeVar +from typing import Any, IO, Literal, TypeVar, cast import httpx from pydantic import BaseModel, ValidationError @@ -297,15 +350,17 @@ class _ApiRequest: path_args: list[str] body: Any query: Any - success_code: int + success_codes: list[int] error_codes: dict[int, str] | None + body_content_type: str | None = None + accept: str | None = None """ src += "\n\n" + _render_client_class( - ops, has_typed_resp, has_no_resp, is_async=False + ops, has_typed_resp, has_status_resp, has_raw, has_no_resp, is_async=False ) src += "\n\n" + _render_client_class( - ops, has_typed_resp, has_no_resp, is_async=True + ops, has_typed_resp, has_status_resp, has_raw, has_no_resp, is_async=True ) src += "\n" return src @@ -314,6 +369,8 @@ class _ApiRequest: def _render_client_class( ops: list[_Operation], has_typed_resp: bool, + has_status_resp: bool, + has_raw: bool, has_no_resp: bool, *, is_async: bool, @@ -338,7 +395,14 @@ def __init__(self, http_client: {http_cls}) -> None: """ for op in ops: - src += "\n" + _render_method(op, is_async=is_async) + if op.json_responses: + src += "\n" + _render_method(op, is_async=is_async, is_raw=False) + if op.raw_accepts: + src += "\n" + _render_method(op, is_async=is_async, is_raw=True) + elif op.raw_accepts: + src += "\n" + _render_method(op, is_async=is_async, is_raw=True) + else: + src += "\n" + _render_method(op, is_async=is_async, is_raw=False) error_dispatch = "" if any(op.error_codes for op in ops): @@ -360,31 +424,70 @@ def __init__(self, http_client: {http_cls}) -> None: """ src += f""" - {adef} _do(self, request: _ApiRequest) -> httpx.Response: + def _build_request(self, request: _ApiRequest) -> httpx.Request: path = request.path_fmt.format( *[urllib.parse.quote(a, safe="") for a in request.path_args] ) json_body = None + content_body = None + files_body = None + headers: dict[str, str] = {{}} + if request.accept is not None: + headers["Accept"] = request.accept if request.body is not None: - if isinstance(request.body, BaseModel): - # Only fields the caller set are sent, so unset fields fall - # back to the server default rather than being reset here. - # An explicit None is kept, since null can mean "clear". - json_body = request.body.model_dump(mode="json", exclude_unset=True) + if request.body_content_type is None: + if isinstance(request.body, BaseModel): + # Only fields the caller set are sent, so unset fields fall + # back to the server default rather than being reset here. + # An explicit None is kept, since null can mean "clear". + # by_alias: a field renamed for Python (e.g. async_ for + # "async") must serialize under its API name. + json_body = request.body.model_dump( + mode="json", exclude_unset=True, by_alias=True + ) + else: + json_body = request.body + elif request.body_content_type == "{_MULTIPART_CONTENT}": + # httpx derives the multipart Content-Type, boundary included. + files_body = request.body else: - json_body = request.body + headers["Content-Type"] = request.body_content_type + content_body = request.body params = None if request.query is not None: if isinstance(request.query, BaseModel): # As above, plus dropping None: a null query parameter is # meaningless and would otherwise serialize as an empty string. params = request.query.model_dump( - mode="json", exclude_unset=True, exclude_none=True + mode="json", exclude_unset=True, exclude_none=True, by_alias=True ) else: params = request.query - response = {aw}self._http_client.request(request.method, path, json=json_body, params=params) - if response.status_code != request.success_code: + return self._http_client.build_request( + request.method, + path, + json=json_body, + content=content_body, + files=files_body, + params=params, + headers=headers, + ) + + {adef} _do(self, request: _ApiRequest) -> httpx.Response: + response = {aw}self._http_client.send(self._build_request(request)) + if response.status_code not in request.success_codes: +{error_dispatch}\ + raise ResponseError(status_code=response.status_code, body=response.text) + return response +""" + + if has_raw: + resp_read = "await response.aread()" if is_async else "response.read()" + src += f""" + {adef} _do_raw(self, request: _ApiRequest) -> httpx.Response: + response = {aw}self._http_client.send(self._build_request(request), stream=True) + if response.status_code not in request.success_codes: + {resp_read} {error_dispatch}\ raise ResponseError(status_code=response.status_code, body=response.text) return response @@ -400,6 +503,24 @@ def __init__(self, http_client: {http_cls}) -> None: return response_type.model_validate_json(response.content) """ + if has_status_resp: + src += f""" + {adef} _do_json_with_status( + self, response_types: Mapping[int, type[_T]], request: _ApiRequest + ) -> _T: + response = {aw}self._do(request) + response_type = response_types.get(response.status_code) + if response_type is None: + # A bodyless success code, such as 204 alongside a JSON 200. The + # call site's return type includes None only when one is declared, + # so this cast is unreachable otherwise. + return cast(_T, None) + content_type = response.headers.get("content-type", "") + if not content_type.startswith("application/json"): + raise ValueError(f"unexpected content type {{content_type!r}}, expected application/json") + return response_type.model_validate_json(response.content) +""" + if has_no_resp: src += f""" {adef} _do_no_response(self, request: _ApiRequest) -> None: @@ -409,40 +530,54 @@ def __init__(self, http_client: {http_cls}) -> None: return src -def _render_method(op: _Operation, *, is_async: bool) -> str: +def _render_method(op: _Operation, *, is_async: bool, is_raw: bool) -> str: adef = "async def" if is_async else "def" aw = "await " if is_async else "" - # An operation carries at most one input model: a request body (any - # method other than GET) or query parameters (GET only). Both surface - # as a single keyword-only `request` argument. Query requests with no - # required fields are optional so callers can omit them entirely; body - # requests are always required so an empty body still sends `{}`. + # Query params go on `params`, request bodies on `request` (JSON) or + # `files`/`content` for non-JSON. Bodies are always required so an empty + # body still sends `{{}}`; query params only when the spec marks one. + kwargs: list[str] = [f"{_camel_to_snake(p)}: str" for p in op.path_params] if op.query_ref: - input_type = op.query_ref - input_required = op.query_required - elif op.has_body: - input_type = op.req_body_ref if op.req_body_ref else "Any" - input_required = True - else: - input_type = "" - input_required = False - - params = ["self"] - if op.path_params or input_type: - params.append("*") - for p in op.path_params: - params.append(f"{p}: str") - if input_type: - if input_required: - params.append(f"request: {input_type}") + if op.query_required: + kwargs.append(f"params: {op.query_ref}") else: - params.append(f"request: {input_type} | None = None") + kwargs.append(f"params: {op.query_ref} | None = None") + if op.has_body: + if op.body_content_type == _MULTIPART_CONTENT: + kwargs.append("files: Any") + elif op.body_content_type: + # AsyncClient cannot send a sync file object, so the async + # signature advertises only what it can deliver. + content_type = "bytes | str" if is_async else "bytes | IO[bytes] | str" + kwargs.append(f"content: {content_type}") + elif op.req_body_ref: + kwargs.append(f"request: {op.req_body_ref}") + else: + kwargs.append("request: Any") + + # Every content type the success responses can produce. More than one + # means the caller has to say which it wants via `accept`. + content_types = ([_JSON_CONTENT] if op.json_responses else []) + op.raw_accepts + if is_raw and len(content_types) > 1: + accept_type = "Literal[" + ", ".join(repr(c) for c in content_types) + "]" + kwargs.append(f"accept: {accept_type}") + accept_expr = "accept" + elif is_raw: + accept_expr = repr(content_types[0]) + else: + accept_expr = "None" - ret = f" -> {op.resp_ref}" if op.resp_ref else " -> None" - path_args = f"[{', '.join(op.path_params)}]" if op.path_params else "[]" - body_arg = "request" if (input_type and not op.query_ref) else "None" - query_arg = "request" if op.query_ref else "None" + if op.has_body: + if op.body_content_type == _MULTIPART_CONTENT: + body_arg = "files" + elif op.body_content_type: + body_arg = "content" + else: + body_arg = "request" + else: + body_arg = "None" + query_arg = "params" if op.query_ref else "None" if op.error_codes: codes = sorted(op.error_codes.items()) @@ -450,22 +585,61 @@ def _render_method(op: _Operation, *, is_async: bool) -> str: else: error_expr = "None" - req = ( - f"_ApiRequest(" - f"method={op.http_method!r}, " - f"path_fmt={_path_fmt(op.path)!r}, " - f"path_args={path_args}, " - f"body={body_arg}, " - f"query={query_arg}, " - f"success_code={op.success_code}, " - f"error_codes={error_expr})" - ) + req_parts = [ + f"method={op.http_method!r}", + f"path_fmt={_path_fmt(op.path)!r}", + "path_args=[" + ", ".join(_camel_to_snake(p) for p in op.path_params) + "]" + if op.path_params + else "path_args=[]", + f"body={body_arg}", + f"query={query_arg}", + f"success_codes={op.success_codes!r}", + f"error_codes={error_expr}", + ] + if op.body_content_type: + req_parts.append(f"body_content_type={op.body_content_type!r}") + if accept_expr != "None": + req_parts.append(f"accept={accept_expr}") + req = "_ApiRequest(" + ", ".join(req_parts) + ")" + + # The suffix marks the sibling of a JSON method, so a raw-only operation, + # having no sibling to be confused with, keeps the plain name. + name = f"{op.name}_raw" if is_raw and op.json_responses else op.name + sig_args = ["self"] + if kwargs: + sig_args.append("*") + + if is_raw: + ret = "httpx.Response" + body = f"return {aw}self._do_raw({req})" + elif op.json_responses and len(op.success_codes) > 1: + # Success codes without a JSON schema (e.g. a 204 alongside a JSON + # 200) yield None. + json_refs = dict(op.json_responses) + types_expr = ( + "{" + ", ".join(f"{code}: {ref}" for code, ref in op.json_responses) + "}" + ) + refs = list(dict.fromkeys(ref for _, ref in op.json_responses)) + if any(code not in json_refs for code in op.success_codes): + refs.append("None") + ret = " | ".join(refs) + body = f"return {aw}self._do_json_with_status({types_expr}, {req})" + elif op.json_responses: + ret = op.json_responses[0][1] + body = f"return {aw}self._do_json({op.json_responses[0][1]}, {req})" + else: + ret = "None" + body = f"{aw}self._do_no_response({req})" - sig = f" {adef} {op.name}({', '.join(params)}){ret}:" + sig = f" {adef} {name}({', '.join(sig_args + kwargs)}) -> {ret}:" if op.summary: - sig += f'\n """{op.summary}"""' - - if op.resp_ref: - return f"{sig}\n return {aw}self._do_json({op.resp_ref}, {req})\n" - else: - return f"{sig}\n {aw}self._do_no_response({req})\n" + summary = op.summary + if is_raw: + summary = summary.rstrip(".") + ". Returns the response unread" + if accept_expr == "accept": + summary += ", in the requested content type" + summary += ". The caller must close the response." + if body_arg == "files": + summary = summary.rstrip(".") + ". *files* is sent as httpx ``files``." + sig += f'\n """{summary}"""' + return f"{sig}\n {body}\n" diff --git a/scripts/apigen/postprocess.py b/scripts/apigen/postprocess.py index 300dc1d..6d17433 100644 --- a/scripts/apigen/postprocess.py +++ b/scripts/apigen/postprocess.py @@ -43,9 +43,78 @@ def postprocess_models(src: str) -> str: src = src.replace(", RootModel, constr", ", RootModel") src = src.replace(", constr,", ",") src = src.replace(", constr\n", "\n") + src = _allow_population_by_field_name(src) return _validate_literal_model_defaults(src) +def _allow_population_by_field_name(src: str) -> str: + # Pydantic accepts only the alias by default, so a Python-renamed field + # (async_ for the API's "async") was not passable; generated classes with + # aliased fields accept both names. + tree = ast.parse(src) + lines = src.splitlines(keepends=True) + for node in reversed(tree.body): + if not (isinstance(node, ast.ClassDef) and _has_aliased_field(node)): + continue + config_assign = next( + ( + stmt + for stmt in node.body + if isinstance(stmt, ast.Assign) + and isinstance(stmt.targets[0], ast.Name) + and stmt.targets[0].id == "model_config" + ), + None, + ) + if config_assign is not None: + start = config_assign.lineno - 1 + end = config_assign.end_lineno + if "populate_by_name" in "".join(lines[start:end]): + continue + lines[start:end] = [ + "".join(lines[start:end]).replace( + "ConfigDict(", "ConfigDict(populate_by_name=True, ", 1 + ) + ] + else: + insert_at = node.body[0].lineno - 1 + indent = " " * node.body[0].col_offset + lines.insert( + insert_at, + f"{indent}model_config = ConfigDict(populate_by_name=True)\n\n", + ) + result = "".join(lines) + if "ConfigDict(" in result and not re.search( + r"^from pydantic import .*\bConfigDict\b", result, re.MULTILINE + ): + # An injected model_config is the file's first ConfigDict use. + result, substitutions = re.subn( + r"^from pydantic import ", + "from pydantic import ConfigDict, ", + result, + count=1, + ) + if substitutions == 0: + raise ValueError("injected model_config needs a pydantic import line") + return result + + +def _has_aliased_field(class_node: ast.ClassDef) -> bool: + for stmt in class_node.body: + if not isinstance(stmt, ast.AnnAssign): + continue + for subnode in ast.walk(stmt): + if not ( + isinstance(subnode, ast.Call) + and isinstance(subnode.func, ast.Name) + and subnode.func.id == "Field" + ): + continue + if any(keyword.arg == "alias" for keyword in subnode.keywords): + return True + return False + + def _validate_literal_model_defaults(src: str) -> str: # datamodel-code-generator emits a schema default verbatim even when the # field is model-typed, e.g. `x: Model = {"a": 1}` or `x: Limit | None = diff --git a/scripts/apigen/preprocess.py b/scripts/apigen/preprocess.py index 7213ada..8f0ade6 100644 --- a/scripts/apigen/preprocess.py +++ b/scripts/apigen/preprocess.py @@ -4,7 +4,11 @@ import json import re -from scripts.apigen.clientgen import query_request_model_name, resolve_method_names +from scripts.apigen.clientgen import ( + query_params_model_name, + resolve_method_names, + response_type_model_name, +) def preprocess_truss_config_schema(data: bytes) -> bytes: @@ -50,6 +54,8 @@ def _rename_defs_refs(node: object, renames: dict[str, str]) -> None: def preprocess_spec(data: bytes) -> bytes: doc = json.loads(data) + _flatten_parameters(doc) + # datamodel-code-generator has --openapi-scopes for schemas and # requestbodies, but not for responses. Hoist inline schemas from # both responses and requestBodies into components/schemas so they @@ -64,12 +70,19 @@ def preprocess_spec(data: bytes) -> bytes: # dropped, and the query schemas we add next are never at risk. _prune_unused_schemas(doc) - # Synthesize a request schema per GET operation's query parameters so + # Synthesize a params schema per operation's query parameters so # datamodel-code-generator emits a typed model for them (it only # generates query-parameter models under the paths scope, which drags # in unwanted per-operation wrappers). Injected before the V1 rename # below so their $refs to enums are rewritten with everything else. - _inject_query_request_schemas(doc) + _inject_query_params_schemas(doc) + + # Hoist inline 2xx application/json response schemas into + # components/schemas so datamodel-code-generator emits a named model the + # client can return. Without this, an operation whose success response is + # an inline oneOf, array, or free-form object has no resolvable type name. + # Injected before the V1 rename, for the same reason as the query schemas. + _inject_response_schemas(doc) # datamodel-code-generator generates empty BaseModel classes for # schemas that are bare type: object with no properties (e.g. @@ -77,8 +90,9 @@ def preprocess_spec(data: bytes) -> bytes: # generate dict[str, Any] instead. _fix_bare_object_schemas(doc) - # Management API schemas are suffixed with V1 (e.g. ModelV1). Strip - # the suffix so generated class names are cleaner (e.g. Model). + # Schema renames: a trailing V1 is stripped (ModelV1 -> Model) and names + # that are not valid Python identifiers are folded to PascalCase + # (archive.Change -> ArchiveChange). schema_renames = _build_v1_renames(doc) if schema_renames: _rename_refs(doc, schema_renames) @@ -89,6 +103,35 @@ def preprocess_spec(data: bytes) -> bytes: return json.dumps(doc, indent=2).encode() +def _flatten_parameters(doc: dict) -> None: + # Operations inherit path-item parameters, and either level may $ref + # components/parameters; inline both so downstream steps see concrete + # parameter objects. + component_params = doc.get("components", {}).get("parameters", {}) + + def resolve(param: dict) -> dict: + ref = param.get("$ref") + if ref is None: + return param + resolved = component_params.get(ref.rsplit("/", 1)[-1]) + if resolved is None: + raise ValueError(f"unresolved parameter reference {ref}") + return copy.deepcopy(resolved) + + for path_item in doc.get("paths", {}).values(): + if not isinstance(path_item, dict): + continue + item_params = [ + resolve(p) for p in path_item.pop("parameters", []) if isinstance(p, dict) + ] + for http_method, op in path_item.items(): + if http_method == "parameters" or not isinstance(op, dict): + continue + op["parameters"] = copy.deepcopy(item_params) + [ + resolve(p) for p in op.get("parameters", []) if isinstance(p, dict) + ] + + def _hoist_component_schemas(doc: dict) -> None: # Hoist inline JSON schemas from components/responses and # components/requestBodies into components/schemas. Entries that are @@ -169,13 +212,12 @@ def _collect_schema_refs(node: object, out: set[str]) -> None: _collect_schema_refs(child, out) -def _inject_query_request_schemas(doc: dict) -> None: +def _inject_query_params_schemas(doc: dict) -> None: # Build an object schema whose properties are the operation's query # parameters, named to match its client method (e.g. get_users -> - # GetUsersRequest). Each parameter's own schema (enum $refs, arrays, + # GetUsersParams). Each parameter's own schema (enum $refs, arrays, # nullable wrappers, constraints) is reused verbatim so the third - # party types every field. GET carries only query params and every - # other method only a body, so this name never collides with a body. + # party types every field. schemas = doc.setdefault("components", {}).setdefault("schemas", {}) method_names = resolve_method_names(doc) @@ -190,13 +232,7 @@ def _inject_query_request_schemas(doc: dict) -> None: ] if not query_params: continue - if "requestBody" in op: - raise ValueError( - f"{http_method.upper()} {path} has both a request body and " - "query parameters; the client generator assumes GET carries " - "only query parameters and other methods only a body" - ) - name = query_request_model_name(method_names[(path, http_method)]) + name = query_params_model_name(method_names[(path, http_method)]) if name in schemas: raise ValueError( f"injected query schema {name} collides with an existing schema" @@ -216,6 +252,45 @@ def _inject_query_request_schemas(doc: dict) -> None: schemas[name] = obj +def _inject_response_schemas(doc: dict) -> None: + schemas = doc.setdefault("components", {}).setdefault("schemas", {}) + method_names = resolve_method_names(doc) + + for path, path_item in doc.get("paths", {}).items(): + for http_method, op in path_item.items(): + if http_method == "parameters" or not isinstance(op, dict): + continue + responses = op.get("responses", {}) + success_codes = sorted( + c + for c in responses + if c.isdigit() + and 200 <= int(c) < 300 + and isinstance(responses[c], dict) + ) + for code in success_codes: + json_content = ( + responses[code].get("content", {}).get("application/json") + ) + schema = ( + json_content.get("schema") + if isinstance(json_content, dict) + else None + ) + if not isinstance(schema, dict) or "$ref" in schema: + continue + base = response_type_model_name(method_names[(path, http_method)]) + # Only the first success code gets the bare name, so several + # 2xx bodies yield one schema per code, not a collision. + schema_name = base if code == success_codes[0] else f"{base}{code}" + if schema_name in schemas: + raise ValueError( + f"injected response schema {schema_name} collides with an existing schema" + ) + schemas[schema_name] = schema + json_content["schema"] = {"$ref": f"#/components/schemas/{schema_name}"} + + def _fix_bare_object_schemas(doc: dict) -> None: schemas = doc.get("components", {}).get("schemas", {}) for schema in schemas.values(): @@ -233,15 +308,32 @@ def _fix_bare_object_schemas(doc: dict) -> None: def _build_v1_renames(doc: dict) -> dict[str, str]: + # A trailing V1 is dropped, and a name that is not a valid Python + # identifier (e.g. archive.Change) is folded into PascalCase so it can + # be emitted and imported by name. schemas = doc.get("components", {}).get("schemas", {}) - renames = {} + renames: dict[str, str] = {} for name in schemas: - if name.endswith("V1"): - renames[name] = name[:-2] + renamed = name.removesuffix("V1") + if not re.fullmatch(r"[A-Za-z_]\w*", renamed): + renamed = "".join( + part[0].upper() + part[1:] + for part in re.split(r"[.-]", renamed) + if part + ) + if renamed != name: + renames[name] = renamed + taken = {n for n in schemas if n not in renames} + for old, new in renames.items(): + if new in taken: + raise ValueError( + f"schema rename {old} -> {new} collides with an existing schema name" + ) + taken.add(new) return renames -_REF_PATTERN = re.compile(r"#/components/schemas/(\w+)") +_REF_PATTERN = re.compile(r"#/components/schemas/([^/]+)") def _rename_refs(node: object, renames: dict[str, str]) -> None: diff --git a/scripts/apigen/specs/management.json b/scripts/apigen/specs/management.json index 245594c..7e1635c 100644 --- a/scripts/apigen/specs/management.json +++ b/scripts/apigen/specs/management.json @@ -28,7 +28,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'namespace': None}\n)\n\nprint(response.text)" } ], - "description": "Returns one row per volume in the namespace, each with its tags, head version, and version counts. Pass namespace to choose the namespace, which is required because the volume service has no cross-namespace inventory. Versions live on the versions sub-resource, so this response stays a fixed size per volume no matter how long a volume's history is.", + "description": "Returns one row per volume in the namespace, each with its tags, head version, version counts, and any scheduled expiry. Pass namespace to choose the namespace, which is required because the volume service has no cross-namespace inventory. Versions live on the versions sub-resource, so this response stays a fixed size per volume no matter how long a volume's history is. A volume with no live versions left, whether deleted or expired, is not listed.", "parameters": [ { "name": "cursor", @@ -188,6 +188,190 @@ "x-stability": "unstable" } }, + "/v1/volumes/syncs": { + "get": { + "summary": "Lists volume syncs", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/volumes/syncs \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes/syncs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'ref': None}\n)\n\nprint(response.text)" + } + ], + "description": "Lists volume syncs in the active workspace, newest first. Results may be narrowed by an exact destination ref.", + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cursor" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "description": "Maximum number of items to return.", + "schema": { + "default": 100, + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "name": "ref", + "in": "query", + "required": false, + "description": "Exact destination reference to match.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ref" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VolumeSyncsV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "post": { + "summary": "Starts a volume sync", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/volumes/syncs \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"source\": null,\n \"destination\": {\n \"ref\": null\n }\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes/syncs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'source': None, 'destination': {'ref': None}}\n)\n\nprint(response.text)" + } + ], + "description": "Starts one durable asynchronous transfer from a remote source into a BDN volume.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateVolumeSyncRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VolumeSyncV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/volumes/syncs/{volume_sync_id}": { + "get": { + "summary": "Gets a volume sync", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/volumes/syncs/{volume_sync_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes/syncs/{volume_sync_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VolumeSyncV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "parameters": [ + { + "$ref": "#/components/parameters/volume_sync_id" + } + ] + }, + "/v1/volumes/syncs/{volume_sync_id}/cancel": { + "post": { + "summary": "Cancels a volume sync", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/volumes/syncs/{volume_sync_id}/cancel \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes/syncs/{volume_sync_id}/cancel\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + } + ], + "description": "Requests cancellation of a pending or running sync. Repeated cancellation and cancellation of terminal syncs return the existing state. Once cancellation is accepted, a later completion callback cannot replace the CANCELED state.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VolumeSyncV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "parameters": [ + { + "$ref": "#/components/parameters/volume_sync_id" + } + ] + }, "/v1/volumes/{volume_namespace}/{volume_name}": { "delete": { "summary": "Deletes a volume", @@ -246,7 +430,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes/{volume_namespace}/{volume_name}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } ], - "description": "Returns a volume with its tags, head version, and version counts. Versions live on the versions sub-resource so they can be paged separately.", + "description": "Returns a volume with its tags, head version, version counts, and any scheduled expiry. Versions live on the versions sub-resource so they can be paged separately. A volume whose versions have all been deleted or have expired is still returned, with zero live versions.", "responses": { "200": { "description": "", @@ -275,13 +459,13 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes/{volume_namespace}/{volume_name}/versions\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={}\n)\n\nprint(response.text)" } ], - "description": "Returns every live version of the volume, newest first, each with its digest, size, lifecycle, and the tags pointing at it. Pass include_tombstoned to list deleted versions alongside them.", + "description": "Returns every live version of the volume, newest first, each with its digest, size, lifecycle, the tags pointing at it, and any scheduled expiry. Pass include_tombstoned to list deleted and expired versions alongside them.", "parameters": [ { "name": "include_tombstoned", "in": "query", "required": false, - "description": "Whether to include deleted versions. A deleted version carries a TOMBSTONED lifecycle and stays restorable until its recovery deadline passes.", + "description": "Whether to include deleted and expired versions. Such a version carries a TOMBSTONED lifecycle and stays restorable until its recovery deadline passes.", "schema": { "default": false, "title": "Include Tombstoned", @@ -391,7 +575,7 @@ }, "/v1/volumes/{volume_namespace}/{volume_name}/versions/{volume_version}/restore": { "post": { - "summary": "Restores a deleted version of a volume", + "summary": "Restores a deleted or expired version of a volume", "x-codeSamples": [ { "lang": "bash", @@ -402,7 +586,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/volumes/{volume_namespace}/{volume_name}/versions/{volume_version}/restore\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'expected_sequence': None}\n)\n\nprint(response.text)" } ], - "description": "Returns a deleted version to service, provided its recovery deadline has not passed. The tags the version carried when it was deleted are not restored with it, so re-tag it if anything depended on those. Address the version by digest: a deleted version has no tags left to name it by.", + "description": "Returns a deleted or expired version to service, provided its recovery deadline has not passed. The tags the version carried are not restored with it, so re-tag it if anything depended on those, and a restored version never expires until something sets a new expiry. Address the version by digest: a tombstoned version has no tags left to name it by.", "requestBody": { "content": { "application/json": { @@ -439,6 +623,45 @@ } ] }, + "/v1/token": { + "post": { + "summary": "Creates a sandbox access token", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/token \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"scopes\": [\n \"sandboxes\"\n ]\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/token\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'scopes': ['sandboxes']}\n)\n\nprint(response.text)" + } + ], + "description": "Exchanges your Baseten credentials for a short-lived token that authenticates against the sandbox API. The token carries every team you belong to. Tokens expire after two hours and cannot be renewed; request a new one when needed. This endpoint is experimental and may change or be removed without notice.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTokenRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, "/v1/secrets": { "get": { "summary": "Gets all secrets (metadata only, no plain text keys)", @@ -1569,6 +1792,42 @@ } } } + }, + "patch": { + "summary": "Updates a model by ID", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/models/{model_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"my-model\"\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/models/{model_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'name': 'my-model'}\n)\n\nprint(response.text)" + } + ], + "description": "Updates the mutable fields of a model and returns the updated model. Renaming does not change the model ID, endpoints, or deployments. Pushes that still use the old model_name create another model or target a model that now uses that name, so update config.yaml after renaming.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateModelRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelV1" + } + } + } + } + } } }, "/v1/models/{model_id}/audit_logs": { @@ -3307,11 +3566,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/models/{model_id}/environments \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"staging\",\n \"autoscaling_settings\": {\n \"autoscaling_window\": 800,\n \"concurrency_target\": 3,\n \"max_replica\": 2,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 60,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"promotion_settings\": {\n \"promotion_cleanup_strategy\": null,\n \"ramp_up_duration_seconds\": 600,\n \"ramp_up_while_promoting\": true,\n \"redeploy_on_promotion\": true,\n \"rolling_deploy\": true,\n \"rolling_deploy_config\": null\n },\n \"request_backpressure_settings\": null\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/models/{model_id}/environments \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"staging\",\n \"autoscaling_settings\": {\n \"autoscaling_window\": 800,\n \"concurrency_target\": 3,\n \"max_replica\": 2,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 60,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"promotion_settings\": {\n \"promotion_cleanup_strategy\": null,\n \"ramp_up_duration_seconds\": 600,\n \"ramp_up_while_promoting\": true,\n \"redeploy_on_promotion\": true,\n \"rolling_deploy\": false,\n \"rolling_deploy_config\": null\n },\n \"request_backpressure_settings\": null\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/models/{model_id}/environments\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'name': 'staging', 'autoscaling_settings': {'autoscaling_window': 800, 'concurrency_target': 3, 'max_replica': 2, 'max_scale_down_rate': None, 'min_replica': 1, 'scale_down_delay': 60, 'target_in_flight_tokens': None, 'target_utilization_percentage': None}, 'promotion_settings': {'promotion_cleanup_strategy': None, 'ramp_up_duration_seconds': 600, 'ramp_up_while_promoting': True, 'redeploy_on_promotion': True, 'rolling_deploy': True, 'rolling_deploy_config': None}, 'request_backpressure_settings': None}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/models/{model_id}/environments\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'name': 'staging', 'autoscaling_settings': {'autoscaling_window': 800, 'concurrency_target': 3, 'max_replica': 2, 'max_scale_down_rate': None, 'min_replica': 1, 'scale_down_delay': 60, 'target_in_flight_tokens': None, 'target_utilization_percentage': None}, 'promotion_settings': {'promotion_cleanup_strategy': None, 'ramp_up_duration_seconds': 600, 'ramp_up_while_promoting': True, 'redeploy_on_promotion': True, 'rolling_deploy': False, 'rolling_deploy_config': None}, 'request_backpressure_settings': None}\n)\n\nprint(response.text)" } ], "description": "Creates an environment for the specified model and returns the environment.", @@ -6056,35 +6315,93 @@ }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/capabilities\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/capabilities\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'model': 'Qwen/Qwen3-8B', 'use_case': 'rl', 'max_seq_len': 32768}\n)\n\nprint(response.text)" } ], - "description": "Returns the list of models supported by the Loops server, including each model's maximum context length and whether it supports vision-language inputs.", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetLoopsCapabilitiesResponseV1" + "description": "Returns the list of models supported by the Loops server, including each model's maximum context length and whether it supports vision-language inputs. Each entry carries an 'enabled' flag saying whether this workspace can run it now, and 'enablement_details' explaining why when it cannot; filter on 'enabled' for the usable set. Capacity is resolved when the run is created, not here. Pass ?model= to ask about one model \u2014 an empty list means Baseten does not support it. Pass ?use_case=sft for a run that needs no sampler, and ?max_seq_len= to check a specific sequence length.", + "parameters": [ + { + "name": "model", + "in": "query", + "required": false, + "description": "Restrict the response to one model, identified by its HuggingFace repo id. A supported model comes back with its 'enabled' flag and, when false, its 'enablement_details'. An empty list means Baseten does not support that model. Omit to list every supported model.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" } - } + ], + "default": null, + "examples": [ + "Qwen/Qwen3-8B" + ], + "title": "Model" } - } - } - } - }, - "/v1/loops/sessions": { - "post": { - "summary": "Creates a Loops session", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/sessions \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { - "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/sessions\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "name": "use_case", + "in": "query", + "required": false, + "description": "What the caller intends to run. Defaults to 'rl', the stricter of the two: an RL run needs both a trainer and a sampler, so anything enabled for 'rl' is also enabled for 'sft'.", + "schema": { + "$ref": "#/components/schemas/LoopsUseCaseV1", + "default": "rl", + "examples": [ + "rl" + ] + } + }, + { + "name": "max_seq_len", + "in": "query", + "required": false, + "description": "The sequence length the caller intends to train at \u2014 the same value they would pass as 'max_seq_len' when creating the run. Models that cannot serve it are reported as not enabled rather than returned with a ceiling the caller cannot use. Omit for the model's highest enabled sequence length.", + "schema": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "examples": [ + 32768 + ], + "title": "Max Seq Len" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetLoopsCapabilitiesResponseV1" + } + } + } + } + } + } + }, + "/v1/loops/sessions": { + "post": { + "summary": "Creates a Loops session", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/sessions \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/sessions\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } ], "description": "Creates a Loops session scoped to the calling org.", @@ -6277,7 +6594,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/runs/{run_id}/deactivate\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } ], - "description": "Shuts down a Loops run by ID, tearing down both the run and its paired sampler. Saved checkpoints remain accessible.", + "description": "Shuts down a Loops run by ID, tearing down both the run and its paired sampler. Succeeds if the run is already inactive. Saved checkpoints remain accessible.", "responses": { "200": { "description": "", @@ -6423,11 +6740,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/samplers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"session_id\": null,\n \"base_model\": null,\n \"run_id\": null,\n \"max_seq_length\": null,\n \"model_path\": \"bt://loops:k4q95w5/sampler_weights/step-100\",\n \"reuse_from_session_id\": null\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/samplers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"availability_model\": null,\n \"session_id\": null,\n \"base_model\": null,\n \"run_id\": null,\n \"max_seq_length\": null,\n \"model_path\": \"bt://loops:k4q95w5/sampler_weights/step-100\",\n \"reuse_from_session_id\": null\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/samplers\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'session_id': None, 'base_model': None, 'run_id': None, 'max_seq_length': None, 'model_path': 'bt://loops:k4q95w5/sampler_weights/step-100', 'reuse_from_session_id': None}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/samplers\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'availability_model': None, 'session_id': None, 'base_model': None, 'run_id': None, 'max_seq_length': None, 'model_path': 'bt://loops:k4q95w5/sampler_weights/step-100', 'reuse_from_session_id': None}\n)\n\nprint(response.text)" } ], "description": "Creates a standalone Loops sampler not linked to a run.", @@ -6455,6 +6772,39 @@ } } }, + "/v1/loops/samplers/{sampler_id}/deactivate": { + "post": { + "summary": "Deactivates a standalone Loops sampler", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/samplers/{sampler_id}/deactivate \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/samplers/{sampler_id}/deactivate\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + } + ], + "description": "Shuts down a standalone Loops sampler by ID. Succeeds if it is already inactive. A sampler paired to a run always returns 409 with the run's ID, even if it is inactive.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivateLoopsSamplerResponseV1" + } + } + } + } + } + }, + "parameters": [ + { + "$ref": "#/components/parameters/sampler_id" + } + ] + }, "/v1/loops/samplers/{sampler_id}": { "get": { "summary": "Gets a Loops sampler", @@ -6619,6 +6969,44 @@ } } }, + "/v1/loops/checkpoints/deploy": { + "post": { + "summary": "Deploys Loops checkpoints", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/checkpoints/deploy \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"checkpoint_ids\": null,\n \"model_name\": null,\n \"instance_type_id\": null,\n \"hf_secret_name\": null\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/checkpoints/deploy\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'checkpoint_ids': None, 'model_name': None, 'instance_type_id': None, 'hf_secret_name': None}\n)\n\nprint(response.text)" + } + ], + "description": "Creates an inference deployment from one or more Loops sampler checkpoints. Confirm the user intends to create billable resources before calling it. This operation is not idempotent; repeating the request can create another deployment.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeployLoopsCheckpointRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeployLoopsCheckpointResponseV1" + } + } + } + } + } + } + }, "/v1/loops/checkpoints/{checkpoint_id}/files": { "get": { "summary": "Gets Loops checkpoint files", @@ -6678,6 +7066,39 @@ } ] }, + "/v1/loops/checkpoints/{checkpoint_id}/source": { + "get": { + "summary": "Gets where a Loops checkpoint's files come from", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/loops/checkpoints/{checkpoint_id}/source \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/checkpoints/{checkpoint_id}/source\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + } + ], + "description": "Reports how to fetch a checkpoint's files: `s3` when the files endpoint serves presigned URLs for it, or `volume` with the ref to pull. Clients that download checkpoints should ask here first.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoopsCheckpointSourceResponseV1" + } + } + } + } + } + }, + "parameters": [ + { + "$ref": "#/components/parameters/checkpoint_id" + } + ] + }, "/v1/loops/deployments": { "get": { "summary": "Lists Loops deployments", @@ -7299,11 +7720,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/loops/samplers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"session_id\": null,\n \"base_model\": null,\n \"run_id\": null,\n \"max_seq_length\": null,\n \"model_path\": \"bt://loops:k4q95w5/sampler_weights/step-100\",\n \"reuse_from_session_id\": null\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/loops/samplers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"availability_model\": null,\n \"session_id\": null,\n \"base_model\": null,\n \"run_id\": null,\n \"max_seq_length\": null,\n \"model_path\": \"bt://loops:k4q95w5/sampler_weights/step-100\",\n \"reuse_from_session_id\": null\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/teams/{team_id}/loops/samplers\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'session_id': None, 'base_model': None, 'run_id': None, 'max_seq_length': None, 'model_path': 'bt://loops:k4q95w5/sampler_weights/step-100', 'reuse_from_session_id': None}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/teams/{team_id}/loops/samplers\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'availability_model': None, 'session_id': None, 'base_model': None, 'run_id': None, 'max_seq_length': None, 'model_path': 'bt://loops:k4q95w5/sampler_weights/step-100', 'reuse_from_session_id': None}\n)\n\nprint(response.text)" } ], "description": "Creates a standalone Loops sampler not linked to a run; the sampler belongs to the given team.", @@ -7536,10 +7957,40 @@ }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/api_keys\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/api_keys\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'type': 'WORKSPACE_INVOKE'}\n)\n\nprint(response.text)" } ], "description": "Returns metadata for your personal API keys and the workspace and team API keys you can manage. Organization admins also receive every member's personal API keys, each with an owner identifying the member it belongs to.", + "parameters": [ + { + "name": "type", + "in": "query", + "required": false, + "description": "Filter by API key type", + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/APIKeyCategory" + }, + { + "type": "null" + } + ], + "default": null + } + }, + { + "name": "created_by_me", + "in": "query", + "required": false, + "description": "Return only keys created by the authenticated user", + "schema": { + "default": false, + "title": "Created By Me", + "type": "boolean" + } + } + ], "responses": { "200": { "description": "", @@ -8557,6 +9008,66 @@ } } }, + "/v1/billing/tool_call_usage": { + "get": { + "summary": "Gets server-side tool call usage", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/billing/tool_call_usage \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/billing/tool_call_usage\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'start_date': None, 'end_date': None}\n)\n\nprint(response.text)" + } + ], + "description": "Returns your organization's server-side tool call usage (web search and fetch tools Baseten executes on your behalf) as daily rows grouped by provider, charge unit (sku), and model.", + "parameters": [ + { + "name": "start_date", + "in": "query", + "required": true, + "description": "Inclusive UTC calendar day at the start of the query range.", + "schema": { + "format": "date", + "title": "Start Date", + "type": "string" + } + }, + { + "name": "end_date", + "in": "query", + "required": false, + "description": "Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included. The date range cannot exceed 90 days.", + "schema": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End Date" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToolCallUsageResponseV1" + } + } + } + } + } + } + }, "/v1/users": { "get": { "summary": "Lists users in the workspace", @@ -8860,80 +9371,87 @@ } } }, - "/v1/gateway/endpoints": { + "/v1/explore/metadata": { "get": { - "summary": "Lists Gateway endpoints", + "summary": "Lists model metadata", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/endpoints \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/explore/metadata \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/explore/metadata\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'provider': None, 'q': None}\n)\n\nprint(response.text)" } ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EndpointsResponseV1" + "description": "Lists all live model metadata rows, e.g. for model pickers.", + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" } - } + ], + "default": null, + "title": "Cursor" } - } - } - }, - "post": { - "summary": "Creates a Gateway endpoint", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/endpoints \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"slug\": \"baseten/mymodel-4\",\n \"region\": \"UNRESTRICTED\",\n \"targets\": [\n {\n \"environment_name\": \"staging\",\n \"model_id\": \"3kZ9xqd\",\n \"provider\": \"BASETEN\",\n \"target_model\": \"custom/model-name\"\n }\n ]\n}'" }, { - "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'slug': 'baseten/mymodel-4', 'region': 'UNRESTRICTED', 'targets': [{'environment_name': 'staging', 'model_id': '3kZ9xqd', 'provider': 'BASETEN', 'target_model': 'custom/model-name'}]}\n)\n\nprint(response.text)" - } - ], - "description": "Provisions an endpoint for the given slug and its upstream target. Exactly one target is supported at this time. The slug's prefix must be one your organization owns.", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateEndpointRequestV1" - } + "name": "limit", + "in": "query", + "required": false, + "description": "Maximum number of items to return.", + "schema": { + "default": 100, + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" } }, - "required": true - }, - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EndpointV1" + { + "name": "provider", + "in": "query", + "required": false, + "description": "Filter to a provider by slug prefix, e.g. 'anthropic'. Preserved by the cursor; if repeated, must match the original filter.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" } - } + ], + "default": null, + "title": "Provider" } - } - } - } - }, - "/v1/gateway/endpoints/{endpoint_id}": { - "delete": { - "summary": "Deletes a Gateway endpoint", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request DELETE \\\n--url https://api.baseten.co/v1/gateway/endpoints/{endpoint_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { - "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints/{endpoint_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"DELETE\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "name": "q", + "in": "query", + "required": false, + "description": "Case-insensitive substring search over metadata slugs. Preserved by the cursor; if repeated, must match the original filter.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Q" + } } ], "responses": { @@ -8942,91 +9460,96 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EndpointTombstoneV1" + "$ref": "#/components/schemas/ExploreMetadataResponseV1" } } } } - } - }, - "parameters": [ - { - "$ref": "#/components/parameters/endpoint_id" - } - ], + }, + "x-stability": "unstable" + } + }, + "/v1/routes": { "get": { - "summary": "Gets a Gateway endpoint", + "summary": "Lists routes", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/endpoints/{endpoint_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/routes \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints/{endpoint_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'team_id': None, 'name': None}\n)\n\nprint(response.text)" } ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EndpointV1" + "description": "Lists routes you can invoke, newest first, optionally filtered by team and exact name.", + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" } - } + ], + "default": null, + "title": "Cursor" } - } - } - }, - "patch": { - "summary": "Updates a Gateway endpoint", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/gateway/endpoints/{endpoint_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"targets\": [\n {\n \"environment_name\": \"staging\",\n \"model_id\": \"3kZ9xqd\",\n \"provider\": \"BASETEN\",\n \"target_model\": \"custom/model-name\"\n }\n ]\n}'" }, { - "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints/{endpoint_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'targets': [{'environment_name': 'staging', 'model_id': '3kZ9xqd', 'provider': 'BASETEN', 'target_model': 'custom/model-name'}]}\n)\n\nprint(response.text)" - } - ], - "description": "Updates the endpoint's provided mutable fields. If targets are provided, the full target list is replaced. Exactly one target is supported at this time.", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateEndpointRequestV1" - } + "name": "limit", + "in": "query", + "required": false, + "description": "Maximum number of items to return.", + "schema": { + "default": 100, + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" } }, - "required": true - }, - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EndpointV1" + { + "name": "team_id", + "in": "query", + "required": false, + "description": "Filter by owning team ID. Preserved by the cursor; if repeated, must match the original filter.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" } - } + ], + "default": null, + "title": "Team Id" } - } - } - } - }, - "/v1/gateway/groups": { - "get": { - "summary": "Lists groups", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { - "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "name": "name", + "in": "query", + "required": false, + "description": "Filter by exact route name. Preserved by the cursor; if repeated, must match the original filter.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + } } ], "responses": { @@ -9035,31 +9558,32 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GroupsResponseV1" + "$ref": "#/components/schemas/RoutesResponseV1" } } } } - } + }, + "x-stability": "unstable" }, "post": { - "summary": "Creates a group", + "summary": "Creates a route", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/groups \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"metadata\": {\n \"name\": \"Acme prod\",\n \"external_entity_id\": \"cust_42\"\n },\n \"models\": [\n {\n \"slug\": \"my-org/claude\"\n }\n ],\n \"hierarchy\": {\n \"limit_enforcement\": \"INDEPENDENT\",\n \"parent_group_id\": \"abc123\"\n }\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/routes \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"team_id\": \"abc1234\",\n \"display_name\": \"Assistant\",\n \"target\": {\n \"model\": \"zai-org/GLM-5.3\",\n \"type\": \"BASETEN_MODEL_API\"\n },\n \"description\": \"Assistant for code review and debugging.\"\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'metadata': {'name': 'Acme prod', 'external_entity_id': 'cust_42'}, 'models': [{'slug': 'my-org/claude'}], 'hierarchy': {'limit_enforcement': 'INDEPENDENT', 'parent_group_id': 'abc123'}}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'team_id': 'abc1234', 'display_name': 'Assistant', 'target': {'model': 'zai-org/GLM-5.3', 'type': 'BASETEN_MODEL_API'}, 'description': 'Assistant for code review and debugging.'}\n)\n\nprint(response.text)" } ], - "description": "Creates a group and its endpoint configuration.", + "description": "Creates and derives a name for the provided route configuration", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateGroupRequestV1" + "$ref": "#/components/schemas/CreateRouteRequestV1" } } }, @@ -9071,131 +9595,218 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GroupV1" + "$ref": "#/components/schemas/RouteV1" } } } } - } + }, + "x-stability": "unstable" } }, - "/v1/gateway/groups/{group_id}": { + "/v1/routes/usage": { "get": { - "summary": "Gets a group", + "summary": "Gets daily route usage and estimated costs", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/routes/usage \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/usage\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'start_date': None, 'end_date': None}\n)\n\nprint(response.text)" } ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GroupV1" + "description": "Buckets are UTC days, and days with no usage are included. Organization admins see all route usage in the organization. Other members, including viewers, see only usage from Routes keys they created, including keys that have since expired, been revoked, or been deleted. Usage is metered every 15 minutes, so the current hour can lag. Model API costs use your prices at the time of each request and include tool calls. xAI costs are the charges xAI reports. OpenAI and Anthropic costs are estimated from Baseten's reference prices and may differ from your provider's bill. Vertex and OpenAI-compatible usage is not included. Costs for OpenAI, Anthropic, and xAI estimate what you pay those providers; they are not Baseten charges. Usage is retained for 92 days.", + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" } - } + ], + "default": null, + "title": "Cursor" } - } - } - }, - "parameters": [ - { - "$ref": "#/components/parameters/group_id" - } - ], - "patch": { - "summary": "Updates a group", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"metadata\": {\n \"name\": \"Acme Prod\"\n },\n \"models\": null\n}'" }, { - "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'metadata': {'name': 'Acme Prod'}, 'models': None}\n)\n\nprint(response.text)" - } - ], - "description": "Updates the group's mutable fields.", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateGroupRequestV1" - } + "name": "limit", + "in": "query", + "required": false, + "description": "Number of daily buckets to return. Defaults to 7; maximum 31.", + "schema": { + "default": 7, + "maximum": 31, + "minimum": 1, + "title": "Limit", + "type": "integer" } }, - "required": true - }, + { + "name": "start_date", + "in": "query", + "required": false, + "description": "Inclusive UTC calendar day at the start of the query range. Defaults to the previous UTC date, and is ignored when you pass a cursor.", + "schema": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start Date" + } + }, + { + "name": "end_date", + "in": "query", + "required": false, + "description": "Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included.", + "schema": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End Date" + } + }, + { + "name": "group_by", + "in": "query", + "required": false, + "description": "Dimensions to break usage down by, repeated once per dimension: USER, MODEL, or PROVIDER. Each result represents one observed combination of the requested dimensions within that day, and results are sorted by those values. Combinations without usage are omitted, so result counts can differ between days. Defaults to MODEL.", + "schema": { + "items": { + "$ref": "#/components/schemas/RouteUsageDimensionV1" + }, + "title": "Group By", + "type": "array" + } + }, + { + "name": "user_ids", + "in": "query", + "required": false, + "description": "Return only usage from Routes keys created by these user IDs, repeated once per ID.", + "schema": { + "items": { + "type": "string" + }, + "title": "User Ids", + "type": "array" + } + }, + { + "name": "models", + "in": "query", + "required": false, + "description": "Return only usage for these exact model names, repeated once per model.", + "schema": { + "items": { + "type": "string" + }, + "title": "Models", + "type": "array" + } + }, + { + "name": "providers", + "in": "query", + "required": false, + "description": "Return only usage for these providers, repeated once per provider.", + "schema": { + "items": { + "$ref": "#/components/schemas/RouteProviderV1" + }, + "title": "Providers", + "type": "array" + } + } + ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GroupV1" + "$ref": "#/components/schemas/RoutesUsageResponseV1" } } } } - } + }, + "x-stability": "unstable" } }, - "/v1/gateway/groups/{group_id}/api_keys": { + "/v1/routes/spend_limits/{user_id}": { "get": { - "summary": "Lists API keys for a group", + "summary": "Gets a user's spend limits", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/routes/spend_limits/{user_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/spend_limits/{user_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } ], + "description": "Spend limits cap what a Baseten Code user can spend each month. Personal API keys are not limited. Users can read their own spend limits; only organization admins can read other users' spend limits or change them.", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/KeysForGroupResponseV1" + "$ref": "#/components/schemas/RouteSpendLimitV1" } } } } - } + }, + "x-stability": "unstable" }, "parameters": [ { - "$ref": "#/components/parameters/group_id" + "$ref": "#/components/parameters/user_id" } ], - "post": { - "summary": "Creates an API key for a group", + "patch": { + "summary": "Updates a user's spend limits", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"prod-key-1\"\n}'" + "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/routes/spend_limits/{user_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"monthly_limit_usd\": \"200\"\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'name': 'prod-key-1'}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/spend_limits/{user_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'monthly_limit_usd': '200'}\n)\n\nprint(response.text)" } ], - "description": "Creates a new API key for the given group.", + "description": "Once the user's metered spend in a month reaches the limit, requests with Routes keys they created are rejected until the limit is raised or the next month starts. A limit of 0 blocks the user after their first metered request. Spend is metered every 15 minutes and can lag, so a user can go over the limit. If the user has spend this month, changes take effect within seconds; otherwise at the next metering run.", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateApiKeyForGroupRequestV1" + "$ref": "#/components/schemas/UpdateRouteSpendLimitRequestV1" } } }, @@ -9207,33 +9818,74 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateApiKeyForGroupResponseV1" + "$ref": "#/components/schemas/RouteSpendLimitV1" } } } } - } + }, + "x-stability": "unstable" } }, - "/v1/gateway/groups/{group_id}/api_keys/register": { - "post": { - "summary": "Registers an API key for a group", + "/v1/routes/harness-configs": { + "get": { + "summary": "Lists default models for coding harnesses", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/register \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"my-model-api-key\",\n \"key\": \"my-secure-api-key-value\"\n}'" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/routes/harness-configs \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/register\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'name': 'my-model-api-key', 'key': 'my-secure-api-key-value'}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/harness-configs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'team_id': None}\n)\n\nprint(response.text)" } ], - "description": "Registers a Gateway API key with the provided value and name.", + "description": "Each role uses the route a team admin set for it (`source` is `team`). A role with no route set uses Baseten's default (`source` is `baseten`), chosen from the team's Model API routes: the recommended model for `primary` and the lowest-priced model for `background`. Baseten's defaults never use external-provider routes.", + "parameters": [ + { + "name": "team_id", + "in": "query", + "required": true, + "description": "Identifier of the team whose default models to list.", + "schema": { + "minLength": 1, + "title": "Team Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteHarnessConfigsResponseV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "patch": { + "summary": "Updates default models for a coding harness", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/routes/harness-configs \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"team_id\": \"abc1234\",\n \"harness\": \"claude-code\",\n \"models\": {\n \"background\": \"ghi9012\"\n }\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/harness-configs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'team_id': 'abc1234', 'harness': 'claude-code', 'models': {'background': 'ghi9012'}}\n)\n\nprint(response.text)" + } + ], + "description": "Changes only the model roles in the request and leaves the others unchanged. Set a role to null to use Baseten's default. Requires team admin, and every route must belong to the team.", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RegisterAPIKeyRequestV1" + "$ref": "#/components/schemas/UpdateRouteHarnessConfigRequestV1" } } }, @@ -9245,30 +9897,77 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RegisterAPIKeyResponseV1" + "$ref": "#/components/schemas/RouteHarnessConfigV1" } } } } - } + }, + "x-stability": "unstable" }, - "parameters": [ - { - "$ref": "#/components/parameters/group_id" - } - ] + "put": { + "summary": "Sets default models for a coding harness", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request PUT \\\n--url https://api.baseten.co/v1/routes/harness-configs \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"team_id\": \"abc1234\",\n \"harness\": \"claude-code\",\n \"models\": {\n \"primary\": \"def5678\",\n \"background\": \"ghi9012\"\n }\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/harness-configs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PUT\",\n url,\n headers=headers,\n json={'team_id': 'abc1234', 'harness': 'claude-code', 'models': {'primary': 'def5678', 'background': 'ghi9012'}}\n)\n\nprint(response.text)" + } + ], + "description": "Replaces every model role of one harness. Roles left out use Baseten's defaults. Requires team admin, and every route must belong to the team. The `harness` in the request body determines which roles are accepted.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetRouteHarnessConfigRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteHarnessConfigV1" + } + } + } + } + }, + "x-stability": "unstable" + } }, - "/v1/gateway/groups/{group_id}/api_keys/{api_key_prefix}": { - "get": { - "summary": "Gets an API key for a group", + "/v1/routes/harness-configs/{harness}": { + "delete": { + "summary": "Clears default models for a coding harness", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/{api_key_prefix} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + "source": "curl --request DELETE \\\n--url https://api.baseten.co/v1/routes/harness-configs/{harness} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/{api_key_prefix}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/harness-configs/{harness}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"DELETE\",\n url,\n headers=headers,\n params={'team_id': None}\n)\n\nprint(response.text)" + } + ], + "description": "Removes the team's routes for every role of the harness, so each role uses Baseten's default. Requires team admin.", + "parameters": [ + { + "name": "team_id", + "in": "query", + "required": true, + "description": "Identifier of the team whose default models to clear.", + "schema": { + "minLength": 1, + "title": "Team Id", + "type": "string" + } } ], "responses": { @@ -9277,1524 +9976,1542 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GatewayKeyInfoV1" + "$ref": "#/components/schemas/RouteHarnessConfigTombstoneV1" } } } } - } + }, + "x-stability": "unstable" }, "parameters": [ { - "$ref": "#/components/parameters/group_id" - }, - { - "$ref": "#/components/parameters/api_key_prefix" + "$ref": "#/components/parameters/harness" } ] - } - }, - "openapi": "3.1.0", - "components": { - "schemas": { - "PaginationResponseV1": { - "properties": { - "has_more": { - "description": "Whether more items exist after this page.", - "title": "Has More", - "type": "boolean" + }, + "/v1/routes/{route_id}": { + "delete": { + "summary": "Deletes a route", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request DELETE \\\n--url https://api.baseten.co/v1/routes/{route_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, - "cursor": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/{route_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"DELETE\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteTombstoneV1" + } } - ], - "default": null, - "description": "Opaque cursor to pass into the next request. Null when there is no next page.", - "title": "Cursor" + } } }, - "required": [ - "has_more" - ], - "title": "PaginationResponseV1", - "type": "object" + "x-stability": "unstable" }, - "VolumeTagV1": { - "properties": { - "name": { - "description": "Tag name. Tags are case-sensitive.", - "title": "Name", - "type": "string" + "parameters": [ + { + "$ref": "#/components/parameters/route_id" + } + ], + "get": { + "summary": "Gets a route", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/routes/{route_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, - "digest": { - "description": "Digest of the version the tag points at, as `b3:`.", - "title": "Digest", - "type": "string" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/{route_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } - }, - "required": [ - "name", - "digest" ], - "title": "VolumeTagV1", - "type": "object" - }, - "VolumeV1": { - "properties": { - "namespace": { - "description": "Namespace the volume belongs to, in lowercase.", - "title": "Namespace", - "type": "string" - }, - "name": { - "description": "Name of the volume, in lowercase.", - "title": "Name", - "type": "string" - }, - "version_ref": { - "description": "Full address of the volume, as `bdn:/`. Paste this into the `bdn.mounts` section of a config.yaml.", - "title": "Version Ref", - "type": "string" - }, - "sequence": { - "description": "Revision counter for the volume, incremented on every commit and tag change. Use it to detect that a volume changed.", - "title": "Sequence", - "type": "integer" - }, - "updated_at": { - "description": "When the volume last changed, in ISO 8601 format.", - "format": "date-time", - "title": "Updated At", - "type": "string" - }, - "head": { - "anyOf": [ - { - "$ref": "#/components/schemas/VolumeVersionSummaryV1" - }, - { - "type": "null" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteV1" + } } - ], - "description": "Version that the reserved `head` tag points at, which a reference with no tag or digest resolves to. Null when the volume has no head, or when your API key cannot read it." - }, - "tags": { - "description": "Tags on the volume that your API key can read.", - "items": { - "$ref": "#/components/schemas/VolumeTagV1" - }, - "title": "Tags", - "type": "array" - }, - "tag_count": { - "description": "Total number of tags on the volume, which can exceed the length of `tags` when your API key cannot read all of them.", - "title": "Tag Count", - "type": "integer" - }, - "versions_alive": { - "description": "Number of versions that have not been deleted.", - "title": "Versions Alive", - "type": "integer" - }, - "versions_tombstoned": { - "description": "Number of versions that have been deleted.", - "title": "Versions Tombstoned", - "type": "integer" - }, - "versions_untagged": { - "description": "Number of versions that no tag points at.", - "title": "Versions Untagged", - "type": "integer" + } } }, - "required": [ - "namespace", - "name", - "version_ref", - "sequence", - "updated_at", - "head", - "tags", - "tag_count", - "versions_alive", - "versions_tombstoned", - "versions_untagged" - ], - "title": "VolumeV1", - "type": "object" + "x-stability": "unstable" }, - "VolumeVersionSummaryV1": { - "properties": { - "digest": { - "description": "Content digest of the version, as `b3:`.", - "title": "Digest", - "type": "string" + "patch": { + "summary": "Updates a route's display name or description", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/routes/{route_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"description\": \"Assistant for code review and debugging.\",\n \"display_name\": \"Assistant\"\n}'" }, - "total_size_bytes": { - "description": "Total size of the version's files in bytes.", - "title": "Total Size Bytes", - "type": "integer" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/routes/{route_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'description': 'Assistant for code review and debugging.', 'display_name': 'Assistant'}\n)\n\nprint(response.text)" + } + ], + "description": "The route name, target, and owning team are immutable.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateRouteRequestV1" + } + } }, - "created_at": { - "description": "When the version was committed, in ISO 8601 format.", - "format": "date-time", - "title": "Created At", - "type": "string" + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteV1" + } + } + } } }, - "required": [ - "digest", - "total_size_bytes", - "created_at" + "x-stability": "unstable" + } + }, + "/v1/gateway/endpoints": { + "get": { + "summary": "Lists Gateway endpoints", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/endpoints \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + } ], - "title": "VolumeVersionSummaryV1", - "type": "object" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EndpointsResponseV1" + } + } + } + } + } }, - "ListVolumesResponseV1": { - "description": "A page of volumes in one namespace.", - "properties": { - "items": { - "description": "Items in this page.", - "items": { - "$ref": "#/components/schemas/VolumeV1" - }, - "title": "Items", - "type": "array" + "post": { + "summary": "Creates a Gateway endpoint", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/endpoints \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"slug\": \"baseten/mymodel-4\",\n \"region\": \"UNRESTRICTED\",\n \"targets\": [\n {\n \"environment_name\": \"staging\",\n \"model_id\": \"3kZ9xqd\",\n \"provider\": \"BASETEN\",\n \"target_model\": \"custom/model-name\"\n }\n ]\n}'" }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'slug': 'baseten/mymodel-4', 'region': 'UNRESTRICTED', 'targets': [{'environment_name': 'staging', 'model_id': '3kZ9xqd', 'provider': 'BASETEN', 'target_model': 'custom/model-name'}]}\n)\n\nprint(response.text)" } - }, - "required": [ - "items", - "pagination" ], - "title": "ListVolumesResponseV1", - "type": "object" - }, - "ListVolumesRequestV1": { - "properties": { - "cursor": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + "description": "Provisions an endpoint for the given slug and its upstream target. Exactly one target is supported at this time. The slug's prefix must be one your organization owns.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEndpointRequestV1" } - ], - "default": null, - "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", - "title": "Cursor" - }, - "limit": { - "default": 100, - "description": "Maximum number of volumes to return.", - "maximum": 1000, - "minimum": 1, - "title": "Limit", - "type": "integer" + } }, - "namespace": { - "description": "Namespace to list volumes in. Required, because the volume service has no cross-namespace inventory.", - "title": "Namespace", - "type": "string" - } + "required": true }, - "required": [ - "namespace" - ], - "title": "ListVolumesRequestV1", - "type": "object" - }, - "VolumeTokenScopeV1": { - "description": "Capability a volume token grants.\n\n- ``PULL``: read volume data.\n- ``INSPECT``: read volume metadata without data access.\n- ``PUSH``: upload and commit volume versions.\n- ``TAG``: move or remove tags.", - "enum": [ - "PULL", - "INSPECT", - "PUSH", - "TAG" - ], - "title": "VolumeTokenScopeV1", - "type": "string" - }, - "CreateVolumeTokenRequestV1": { - "additionalProperties": false, - "properties": { - "scopes": { - "description": "Capabilities the token grants, at least one. Requesting PUSH or TAG requires organization-level model management permission.", - "items": { - "$ref": "#/components/schemas/VolumeTokenScopeV1" - }, - "minItems": 1, - "title": "Scopes", - "type": "array" - }, - "namespaces": { - "description": "Volume namespaces the token is limited to, lowercase ASCII, at least one. Pass only the namespaces the operation needs.", - "items": { - "type": "string" - }, - "minItems": 1, - "title": "Namespaces", - "type": "array" - }, - "volumes": { - "description": "Volume names the token is limited to, lowercase ASCII, exact names only, at least one. The limit applies to every requested scope in every requested namespace.", - "items": { - "type": "string" - }, - "minItems": 1, - "title": "Volumes", - "type": "array" - }, - "correlation_id": { - "anyOf": [ - { - "maxLength": 128, - "pattern": "^[\\x21-\\x7e]+$", - "type": "string" - }, - { - "type": "null" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EndpointV1" + } } - ], - "default": null, - "description": "Optional client-chosen identifier, at most 128 printable ASCII characters. Echoed into server logs to link the issued token to a client operation.", - "title": "Correlation Id" + } + } + } + } + }, + "/v1/gateway/endpoints/{endpoint_id}": { + "delete": { + "summary": "Deletes a Gateway endpoint", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request DELETE \\\n--url https://api.baseten.co/v1/gateway/endpoints/{endpoint_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints/{endpoint_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"DELETE\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } - }, - "required": [ - "scopes", - "namespaces", - "volumes" ], - "title": "CreateVolumeTokenRequestV1", - "type": "object" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EndpointTombstoneV1" + } + } + } + } + } }, - "CreateVolumeTokenResponseV1": { - "properties": { - "token": { - "description": "Volume access token. Pass as a bearer token to the volume APIs.", - "title": "Token", - "type": "string" - }, - "expires_at": { - "description": "Token expiry in ISO 8601 format. Tokens cannot be renewed; exchange again for a fresh token.", - "format": "date-time", - "title": "Expires At", - "type": "string" - }, - "scopes": { - "description": "Effective capabilities granted.", - "items": { - "$ref": "#/components/schemas/VolumeTokenScopeV1" - }, - "title": "Scopes", - "type": "array" - }, - "namespaces": { - "description": "Effective namespaces granted, in canonical lowercase form.", - "items": { - "type": "string" - }, - "title": "Namespaces", - "type": "array" - }, - "volumes": { - "description": "Effective volume names granted, in canonical lowercase form.", - "items": { - "type": "string" - }, - "title": "Volumes", - "type": "array" + "parameters": [ + { + "$ref": "#/components/parameters/endpoint_id" + } + ], + "get": { + "summary": "Gets a Gateway endpoint", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/endpoints/{endpoint_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, - "bdn_endpoint": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Base URL of the volume API this token authenticates against. Null when the environment does not expose a public volume API yet.", - "title": "Bdn Endpoint" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints/{endpoint_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } - }, - "required": [ - "token", - "expires_at", - "scopes", - "namespaces", - "volumes", - "bdn_endpoint" ], - "title": "CreateVolumeTokenResponseV1", - "type": "object" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EndpointV1" + } + } + } + } + } }, - "ListVolumeNamespacesResponseV1": { - "description": "A page of namespaces the caller can read.", - "properties": { - "items": { - "description": "Items in this page.", - "items": { - "type": "string" - }, - "title": "Items", - "type": "array" + "patch": { + "summary": "Updates a Gateway endpoint", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/gateway/endpoints/{endpoint_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"targets\": [\n {\n \"environment_name\": \"staging\",\n \"model_id\": \"3kZ9xqd\",\n \"provider\": \"BASETEN\",\n \"target_model\": \"custom/model-name\"\n }\n ]\n}'" }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/endpoints/{endpoint_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'targets': [{'environment_name': 'staging', 'model_id': '3kZ9xqd', 'provider': 'BASETEN', 'target_model': 'custom/model-name'}]}\n)\n\nprint(response.text)" } - }, - "required": [ - "items", - "pagination" ], - "title": "ListVolumeNamespacesResponseV1", - "type": "object" - }, - "ListVolumeNamespacesRequestV1": { - "properties": { - "cursor": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + "description": "Updates the endpoint's provided mutable fields. If targets are provided, the full target list is replaced. Exactly one target is supported at this time.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEndpointRequestV1" } - ], - "default": null, - "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", - "title": "Cursor" + } }, - "limit": { - "default": 100, - "description": "Maximum number of namespaces to return.", - "maximum": 1000, - "minimum": 1, - "title": "Limit", - "type": "integer" - } + "required": true }, - "title": "ListVolumeNamespacesRequestV1", - "type": "object" - }, - "DeleteVolumeRequestV1": { - "properties": { - "expected_sequence": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EndpointV1" + } } - ], - "default": null, - "description": "Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so it cannot act on a volume someone else has pushed to. Take the value from a volume's sequence, or from volume_sequence.", - "title": "Expected Sequence" + } } - }, - "title": "DeleteVolumeRequestV1", - "type": "object" - }, - "DeleteVolumeResponseV1": { - "properties": { - "namespace": { - "description": "Namespace the volume belongs to, in lowercase.", - "title": "Namespace", - "type": "string" - }, - "name": { - "description": "Name of the volume, in lowercase.", - "title": "Name", - "type": "string" - }, - "versions_deleted": { - "description": "Number of versions this request deleted. Zero when the volume had no live versions left, which is not an error.", - "title": "Versions Deleted", - "type": "integer" + } + } + }, + "/v1/gateway/groups": { + "get": { + "summary": "Lists groups", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, - "volume_sequence": { - "description": "Revision of the volume after the delete.", - "title": "Volume Sequence", - "type": "integer" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } - }, - "required": [ - "namespace", - "name", - "versions_deleted", - "volume_sequence" ], - "title": "DeleteVolumeResponseV1", - "type": "object" - }, - "VolumeVersionV1": { - "properties": { - "namespace": { - "description": "Namespace the volume belongs to, in lowercase.", - "title": "Namespace", - "type": "string" - }, - "volume": { - "description": "Name of the volume, in lowercase.", - "title": "Volume", - "type": "string" - }, - "version_ref": { - "description": "Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", - "title": "Version Ref", - "type": "string" - }, - "digest": { - "description": "Content digest of the version, as `b3:`.", - "title": "Digest", - "type": "string" - }, - "sequence": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupsResponseV1" + } } - ], - "description": "Revision the version was committed at. Null for versions committed before the volume service recorded it.", - "title": "Sequence" - }, - "lifecycle": { - "description": "Lifecycle state of the version, for example ALIVE or TOMBSTONED.", - "title": "Lifecycle", - "type": "string" - }, - "is_head": { - "description": "Whether the reserved `head` tag points at this version.", - "title": "Is Head", - "type": "boolean" - }, - "tags": { - "description": "Tags pointing at this version that your API key can read.", - "items": { - "type": "string" - }, - "title": "Tags", - "type": "array" + } + } + } + }, + "post": { + "summary": "Creates a group", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/groups \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"metadata\": {\n \"name\": \"Acme prod\",\n \"external_entity_id\": \"cust_42\"\n },\n \"models\": [\n {\n \"slug\": \"my-org/claude\"\n }\n ],\n \"hierarchy\": {\n \"limit_enforcement\": \"INDEPENDENT\",\n \"parent_group_id\": \"abc123\"\n }\n}'" }, - "total_size_bytes": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'metadata': {'name': 'Acme prod', 'external_entity_id': 'cust_42'}, 'models': [{'slug': 'my-org/claude'}], 'hierarchy': {'limit_enforcement': 'INDEPENDENT', 'parent_group_id': 'abc123'}}\n)\n\nprint(response.text)" + } + ], + "description": "Creates a group and its endpoint configuration.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGroupRequestV1" } - ], - "description": "Total size of the version's files in bytes. Null when not recorded.", - "title": "Total Size Bytes" - }, - "created_at": { - "description": "When the version was committed, in ISO 8601 format.", - "format": "date-time", - "title": "Created At", - "type": "string" + } }, - "tombstoned_at": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupV1" + } } - ], - "description": "When the version was deleted, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - "title": "Tombstoned At" + } + } + } + } + }, + "/v1/gateway/groups/{group_id}": { + "get": { + "summary": "Gets a group", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, - "delete_after": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "description": "When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - "title": "Delete After" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } - }, - "required": [ - "namespace", - "volume", - "version_ref", - "digest", - "sequence", - "lifecycle", - "is_head", - "tags", - "total_size_bytes", - "created_at", - "tombstoned_at", - "delete_after" ], - "title": "VolumeVersionV1", - "type": "object" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupV1" + } + } + } + } + } }, - "ListVolumeVersionsResponseV1": { - "description": "Every version of a volume, newest first.\n\nUnpaginated: `limit` and `cursor` are absent rather than accepted and\nignored, so adding them once the volume service pages this listing is a\npurely additive change.", - "properties": { - "versions": { - "description": "Versions of the volume, newest first.", - "items": { - "$ref": "#/components/schemas/VolumeVersionV1" - }, - "title": "Versions", - "type": "array" + "parameters": [ + { + "$ref": "#/components/parameters/group_id" + } + ], + "patch": { + "summary": "Updates a group", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"metadata\": {\n \"name\": \"Acme Prod\"\n },\n \"models\": null\n}'" }, - "volume_sequence": { - "description": "Revision of the volume as a whole when the versions were read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since. Distinct from the per-version sequence, which is the revision a version was committed at.", - "title": "Volume Sequence", - "type": "integer" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'metadata': {'name': 'Acme Prod'}, 'models': None}\n)\n\nprint(response.text)" } - }, - "required": [ - "versions", - "volume_sequence" ], - "title": "ListVolumeVersionsResponseV1", - "type": "object" - }, - "ListVolumeVersionsRequestV1": { - "properties": { - "include_tombstoned": { - "default": false, - "description": "Whether to include deleted versions. A deleted version carries a TOMBSTONED lifecycle and stays restorable until its recovery deadline passes.", - "title": "Include Tombstoned", - "type": "boolean" - } + "description": "Updates the group's mutable fields.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateGroupRequestV1" + } + } + }, + "required": true }, - "title": "ListVolumeVersionsRequestV1", - "type": "object" - }, - "DeleteVolumeVersionRequestV1": { - "properties": { - "expected_sequence": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupV1" + } } - ], - "default": null, - "description": "Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so a read followed by a delete cannot act on a version a tag has since been moved off. Take the value from volume_sequence.", - "title": "Expected Sequence" + } } - }, - "title": "DeleteVolumeVersionRequestV1", - "type": "object" - }, - "DeleteVolumeVersionResponseV1": { - "properties": { - "namespace": { - "description": "Namespace the volume belongs to, in lowercase.", - "title": "Namespace", - "type": "string" + } + } + }, + "/v1/gateway/groups/{group_id}/api_keys": { + "get": { + "summary": "Lists API keys for a group", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, - "volume": { - "description": "Name of the volume, in lowercase.", - "title": "Volume", - "type": "string" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeysForGroupResponseV1" + } + } + } + } + } + }, + "parameters": [ + { + "$ref": "#/components/parameters/group_id" + } + ], + "post": { + "summary": "Creates an API key for a group", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"prod-key-1\"\n}'" }, - "version_ref": { - "description": "Full address of the deleted version, as `bdn:/@`.", - "title": "Version Ref", - "type": "string" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'name': 'prod-key-1'}\n)\n\nprint(response.text)" + } + ], + "description": "Creates a new API key for the given group.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyForGroupRequestV1" + } + } }, - "digest": { - "description": "Content digest of the deleted version, as `b3:`.", - "title": "Digest", - "type": "string" + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyForGroupResponseV1" + } + } + } + } + } + } + }, + "/v1/gateway/groups/{group_id}/api_keys/register": { + "post": { + "summary": "Registers an API key for a group", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/register \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"my-model-api-key\",\n \"key\": \"my-secure-api-key-value\"\n}'" }, - "lifecycle": { - "description": "Lifecycle state of the version after the delete.", - "title": "Lifecycle", - "type": "string" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/register\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'name': 'my-model-api-key', 'key': 'my-secure-api-key-value'}\n)\n\nprint(response.text)" + } + ], + "description": "Registers a Gateway API key with the provided value and name.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterAPIKeyRequestV1" + } + } }, - "delete_after": { - "description": "When the version stops being restorable, in ISO 8601 format. Until then it can be returned to service.", - "format": "date-time", - "title": "Delete After", - "type": "string" + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterAPIKeyResponseV1" + } + } + } + } + } + }, + "parameters": [ + { + "$ref": "#/components/parameters/group_id" + } + ] + }, + "/v1/gateway/groups/{group_id}/api_keys/{api_key_prefix}": { + "get": { + "summary": "Gets an API key for a group", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/{api_key_prefix} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" }, - "volume_sequence": { - "description": "Revision of the volume after the delete.", - "title": "Volume Sequence", - "type": "integer" + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/gateway/groups/{group_id}/api_keys/{api_key_prefix}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n json={}\n)\n\nprint(response.text)" } - }, - "required": [ - "namespace", - "volume", - "version_ref", - "digest", - "lifecycle", - "delete_after", - "volume_sequence" ], - "title": "DeleteVolumeVersionResponseV1", - "type": "object" + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GatewayKeyInfoV1" + } + } + } + } + } }, - "VolumeVersionDetailV1": { - "description": "One version, with the fields only a single-version read reports.", - "properties": { - "namespace": { - "description": "Namespace the volume belongs to, in lowercase.", - "title": "Namespace", - "type": "string" + "parameters": [ + { + "$ref": "#/components/parameters/group_id" + }, + { + "$ref": "#/components/parameters/api_key_prefix" + } + ] + }, + "/v1/sandboxes/instances": { + "get": { + "operationId": "ListSandboxes", + "summary": "List sandboxes", + "description": "Return a cursor-paginated page of sandboxes. Terminated sandboxes are hidden by default.", + "tags": [ + "Sandboxes" + ], + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" }, - "volume": { - "description": "Name of the volume, in lowercase.", - "title": "Volume", - "type": "string" + { + "$ref": "#/components/parameters/TeamIdHeader" }, - "version_ref": { - "description": "Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", - "title": "Version Ref", - "type": "string" + { + "$ref": "#/components/parameters/Cursor" }, - "digest": { - "description": "Content digest of the version, as `b3:`.", - "title": "Digest", - "type": "string" + { + "$ref": "#/components/parameters/Limit" }, - "sequence": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Revision the version was committed at. Null for versions committed before the volume service recorded it.", - "title": "Sequence" - }, - "lifecycle": { - "description": "Lifecycle state of the version, for example ALIVE or TOMBSTONED.", - "title": "Lifecycle", - "type": "string" - }, - "is_head": { - "description": "Whether the reserved `head` tag points at this version.", - "title": "Is Head", - "type": "boolean" - }, - "tags": { - "description": "Tags pointing at this version that your API key can read.", - "items": { - "type": "string" - }, - "title": "Tags", - "type": "array" + { + "name": "q", + "in": "query", + "description": "Search indexed sandbox names and labels. Search is applied before pagination.", + "required": false, + "schema": { + "type": "string", + "example": "api-review" + } }, - "total_size_bytes": { - "anyOf": [ - { - "type": "integer" + { + "name": "status", + "in": "query", + "description": "Deployment statuses. Repeat the query parameter for each status, for example status=DEPLOYED&status=FAILED. Unknown values are rejected. Cannot be combined with external_id.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "minLength": 1 }, - { - "type": "null" + "example": [ + "DEPLOYED", + "FAILED" + ] + } + }, + { + "name": "external_id", + "in": "query", + "description": "Filter by a caller-owned external identifier. Cannot be combined with status.", + "required": false, + "schema": { + "type": "string", + "example": "api-review-20260916-001" + } + } + ], + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSandboxesResponseV1" + }, + "examples": { + "page": { + "$ref": "#/components/examples/SandboxesPage" + }, + "last_page": { + "$ref": "#/components/examples/SandboxesLastPage" + } + } } - ], - "description": "Total size of the version's files in bytes. Null when not recorded.", - "title": "Total Size Bytes" + } }, - "created_at": { - "description": "When the version was committed, in ISO 8601 format.", - "format": "date-time", - "title": "Created At", - "type": "string" + "400": { + "$ref": "#/components/responses/SandboxError400" }, - "tombstoned_at": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "description": "When the version was deleted, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - "title": "Tombstoned At" + "401": { + "$ref": "#/components/responses/SandboxError401" }, - "delete_after": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "description": "When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", - "title": "Delete After" + "403": { + "$ref": "#/components/responses/SandboxError403" }, - "entry_count": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of files in the version. Null when not recorded.", - "title": "Entry Count" + "429": { + "$ref": "#/components/responses/SandboxError429" }, - "volume_sequence": { - "description": "Revision of the volume as a whole when this version was read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since.", - "title": "Volume Sequence", - "type": "integer" + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "namespace", - "volume", - "version_ref", - "digest", - "sequence", - "lifecycle", - "is_head", - "tags", - "total_size_bytes", - "created_at", - "tombstoned_at", - "delete_after", - "entry_count", - "volume_sequence" - ], - "title": "VolumeVersionDetailV1", - "type": "object" + "x-stability": "unstable" }, - "RestoreVolumeVersionRequestV1": { - "properties": { - "expected_sequence": { - "anyOf": [ - { - "type": "integer" + "post": { + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" + } + ], + "operationId": "CreateSandbox", + "summary": "Create a sandbox", + "description": "Create a sandbox with an optional client-provided name, generated by the server when omitted. The request waits briefly for deployment, then returns the created resource. Deployment may continue after the response; inspect status to determine readiness. Names belonging to failed or terminated sandboxes can be reused; an active sandbox reserves its name. Every field is optional. The server applies image and memory defaults; SDKs should omit fields the caller did not set. A request with no body creates a sandbox from baseten/base-image:latest, the built-in image with the sandbox execution API ready to use, with 4096 MB of memory. It is available directly; no image build, push, or GET /v1/sandboxes/images is needed. Use the returned url to execute commands with your authentication token as a Bearer token, not your Baseten API key.", + "tags": [ + "Sandboxes" + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSandboxRequestV1" }, - { - "type": "null" + "examples": { + "quickstart": { + "$ref": "#/components/examples/CreateSandboxQuickstart" + }, + "complete": { + "$ref": "#/components/examples/CreateSandbox" + } } - ], - "default": null, - "description": "Revision the volume is expected to be at. When set, the restore fails with a conflict if the volume has changed since. Take the value from volume_sequence.", - "title": "Expected Sequence" + } } }, - "title": "RestoreVolumeVersionRequestV1", - "type": "object" - }, - "RestoreVolumeVersionResponseV1": { - "properties": { - "namespace": { - "description": "Namespace the volume belongs to, in lowercase.", - "title": "Namespace", - "type": "string" + "responses": { + "201": { + "description": "Sandbox created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/SandboxReady" + } + } + } + } }, - "volume": { - "description": "Name of the volume, in lowercase.", - "title": "Volume", - "type": "string" + "400": { + "$ref": "#/components/responses/SandboxError400" }, - "version_ref": { - "description": "Full address of the restored version, as `bdn:/@`.", - "title": "Version Ref", - "type": "string" + "401": { + "$ref": "#/components/responses/SandboxError401" }, - "digest": { - "description": "Content digest of the restored version, as `b3:`.", - "title": "Digest", - "type": "string" + "403": { + "$ref": "#/components/responses/SandboxError403" }, - "lifecycle": { - "description": "Lifecycle state of the version after the restore.", - "title": "Lifecycle", - "type": "string" + "409": { + "description": "An active sandbox with the requested name already exists. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "ALREADY_EXISTS", + "message": "A sandbox with this name already exists.", + "details": { + "name": "baseten-api-review-0916" + } + } + } + } }, - "volume_sequence": { - "description": "Revision of the volume after the restore.", - "title": "Volume Sequence", - "type": "integer" + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "namespace", - "volume", - "version_ref", - "digest", - "lifecycle", - "volume_sequence" + "x-stability": "unstable" + } + }, + "/v1/sandboxes/instances/{sandbox_name}": { + "parameters": [ + { + "$ref": "#/components/parameters/SandboxName" + } + ], + "get": { + "operationId": "GetSandbox", + "summary": "Get a sandbox", + "description": "Return the sandbox configuration and status.", + "tags": [ + "Sandboxes" ], - "title": "RestoreVolumeVersionResponseV1", - "type": "object" - }, - "SecretV1": { - "description": "A Baseten secret. Note that we do not support retrieving secret values.", - "properties": { - "id": { - "description": "Stable identifier for the secret. Unchanged across rotation.", - "examples": [ - "3kZ9xqd" - ], - "title": "Id", - "type": "string" + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" }, - "created_at": { - "description": "Time the secret was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" + { + "$ref": "#/components/parameters/TeamIdHeader" }, - "name": { - "description": "Name of the secret", - "title": "Name", - "type": "string" + { + "name": "show_secrets", + "in": "query", + "description": "Reveal environment variable values for workspace administrators. Defaults to false. Callers without the admin role receive masked values even when true.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/SandboxReady" + } + } + } + } }, - "team_name": { - "description": "Name of the team the secret belongs to", - "title": "Team Name", - "type": "string" + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "id", - "created_at", - "name", - "team_name" - ], - "title": "SecretV1", - "type": "object" - }, - "SecretsV1": { - "description": "A list of Baseten secrets.", - "properties": { - "secrets": { - "items": { - "$ref": "#/components/schemas/SecretV1" - }, - "title": "Secrets", - "type": "array" - } - }, - "required": [ - "secrets" - ], - "title": "SecretsV1", - "type": "object" + "x-stability": "unstable" }, - "UpsertSecretRequestV1": { - "description": "A request to create or update a Baseten secret by name.", - "properties": { - "name": { - "description": "Name of the new or existing secret", - "examples": [ - "my_secret" - ], - "title": "Name", - "type": "string" + "patch": { + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" }, - "value": { - "description": "Value of the secret", - "examples": [ - "my_secret_value" - ], - "title": "Value", - "type": "string" + { + "$ref": "#/components/parameters/TeamIdHeader" } - }, - "required": [ - "name", - "value" ], - "title": "UpsertSecretRequestV1", - "type": "object" - }, - "SecretTombstoneV1": { - "description": "A secret tombstone.", - "properties": { - "name": { - "description": "Name of the deleted secret", - "title": "Name", - "type": "string" - } - }, - "required": [ - "name" + "operationId": "UpdateSandbox", + "summary": "Update a sandbox", + "description": "Partially update configuration. Omitted fields remain unchanged; supplied arrays and maps replace their previous values. Structured objects update only supplied fields. Changes to image may reset running state. The name, memory, and network configuration are immutable after creation. Supplying memory or network returns 400, including unchanged, empty, or null values.", + "tags": [ + "Sandboxes" ], - "title": "SecretTombstoneV1", - "type": "object" - }, - "EnvironmentGroupManageAccessV1": { - "description": "Who is allowed to manage an environment group.", - "properties": { - "is_restricted": { - "description": "Whether the environment is restricted to a specific set of users.", - "title": "Is Restricted", - "type": "boolean" - }, - "users": { - "description": "Users who can manage the environment while it is restricted, including organization and team admins who always have access. Empty when the environment is unrestricted.", - "items": { - "$ref": "#/components/schemas/EnvironmentGroupUserV1" - }, - "title": "Users", - "type": "array" + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSandboxRequestV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/UpdateSandbox" + } + } + } } }, - "required": [ - "is_restricted" - ], - "title": "EnvironmentGroupManageAccessV1", - "type": "object" - }, - "EnvironmentGroupUserV1": { - "description": "A user referenced by an environment group's manage access.", - "properties": { - "user_id": { - "description": "Unique identifier for the user.", - "title": "User Id", - "type": "string" - }, - "email": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/SandboxUpdated" + } + } } - ], - "default": null, - "description": "Email address of the user.", - "title": "Email" + } }, - "name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" + "400": { + "description": "Invalid request, including attempts to change memory or network configuration.", + "content": { + "application/json": { + "example": { + "code": "INVALID_REQUEST", + "message": "Memory and network configuration cannot be changed after creation." + } } - ], - "default": null, - "description": "Display name of the user.", - "title": "Name" + } + }, + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "409": { + "$ref": "#/components/responses/SandboxError409" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "user_id" - ], - "title": "EnvironmentGroupUserV1", - "type": "object" + "x-stability": "unstable" }, - "EnvironmentGroupV1": { - "description": "A team-scoped grouping of same-named environments (e.g. \"production\", \"staging\").\n\nRestricting an environment group limits who can manage the environment of that name\nacross every model and chain in the team.", - "properties": { - "name": { - "description": "Name of the environment group, matching the environment name it governs.", - "examples": [ - "staging" - ], - "title": "Name", - "type": "string" + "delete": { + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" }, - "team_id": { - "description": "Unique identifier of the team the environment group belongs to.", - "title": "Team Id", - "type": "string" + { + "$ref": "#/components/parameters/TeamIdHeader" + } + ], + "operationId": "DeleteSandbox", + "summary": "Delete a sandbox", + "description": "Permanently delete the sandbox and its local data asynchronously. The returned resource has status DELETING.", + "tags": [ + "Sandboxes" + ], + "responses": { + "202": { + "description": "Request accepted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/SandboxDeleting" + } + } + } + } }, - "team_name": { - "description": "Name of the team the environment group belongs to.", - "title": "Team Name", - "type": "string" + "401": { + "$ref": "#/components/responses/SandboxError401" }, - "manage_access": { - "$ref": "#/components/schemas/EnvironmentGroupManageAccessV1", - "description": "Settings controlling who can manage this environment group." + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "409": { + "$ref": "#/components/responses/SandboxError409" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "name", - "team_id", - "team_name", - "manage_access" + "x-stability": "unstable" + } + }, + "/v1/sandboxes/library_images": { + "get": { + "operationId": "ListSandboxLibraryImages", + "summary": "List built-in sandbox images", + "description": "Return the built-in sandbox images available to every team. Use the image field directly as the image of a sandbox, without building or pushing it. Hidden and upcoming images are excluded.", + "tags": [ + "Images" ], - "title": "EnvironmentGroupV1", - "type": "object" - }, - "EnvironmentGroupsV1": { - "description": "A page of environment groups.", - "properties": { - "items": { - "description": "Items in this page.", - "items": { - "$ref": "#/components/schemas/EnvironmentGroupV1" - }, - "title": "Items", - "type": "array" + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." + { + "$ref": "#/components/parameters/TeamIdHeader" } - }, - "required": [ - "items", - "pagination" ], - "title": "EnvironmentGroupsV1", - "type": "object" - }, - "UpdateEnvironmentGroupManageAccessV1": { - "description": "Manage-access settings to apply to an environment group.", - "properties": { - "is_restricted": { - "description": "Whether to restrict this environment to a specific set of users.", - "title": "Is Restricted", - "type": "boolean" + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSandboxLibraryImagesResponseV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/SandboxLibraryImages" + } + } + } + } }, - "user_ids": { - "description": "IDs of users granted manage access while restricted. Only meaningful when is_restricted is true.", - "items": { - "type": "string" - }, - "title": "User Ids", - "type": "array" + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "is_restricted" + "x-stability": "unstable" + } + }, + "/v1/sandboxes/images": { + "get": { + "operationId": "ListImages", + "summary": "List sandbox images", + "description": "Return one cursor-paginated page of image repository summaries. Tags are listed separately. Pages can be empty when non-sandbox repositories are excluded; follow pagination.cursor while pagination.has_more is true. Prefix search forces ascending name order.", + "tags": [ + "Images" ], - "title": "UpdateEnvironmentGroupManageAccessV1", - "type": "object" - }, - "UpdateEnvironmentGroupRequestV1": { - "description": "A request to update an existing environment group.", - "properties": { - "manage_access": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdateEnvironmentGroupManageAccessV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Manage-access settings to apply. Omit to leave manage access unchanged." + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" + }, + { + "$ref": "#/components/parameters/Cursor" + }, + { + "$ref": "#/components/parameters/Limit" + }, + { + "name": "sort", + "in": "query", + "description": "Sort by repository name or creation time: name:asc, name:desc, createdAt:asc, or createdAt:desc. Keep the same sort when following a cursor.", + "schema": { + "type": "string", + "default": "createdAt:desc" + } + }, + { + "name": "q", + "in": "query", + "description": "Case-sensitive repository name prefix. Search is applied before pagination.", + "schema": { + "type": "string" + } } - }, - "title": "UpdateEnvironmentGroupRequestV1", - "type": "object" - }, - "TeamV1": { - "description": "A team.", - "properties": { - "id": { - "description": "Unique identifier of the team", - "title": "Id", - "type": "string" + ], + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListImagesResponseV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/ImagesList" + } + } + } + } }, - "name": { - "description": "Name of the team", - "title": "Name", - "type": "string" + "400": { + "$ref": "#/components/responses/SandboxError400" }, - "default": { - "type": "boolean", - "description": "Whether this is the default team for the organization", - "title": "Default" + "401": { + "$ref": "#/components/responses/SandboxError401" }, - "created_at": { - "description": "Time the team was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "id", - "name", - "default", - "created_at" - ], - "title": "TeamV1", - "type": "object" + "x-stability": "unstable" }, - "TeamsV1": { - "description": "A list of teams.", - "properties": { - "teams": { - "description": "A list of teams", - "items": { - "$ref": "#/components/schemas/TeamV1" - }, - "title": "Teams", - "type": "array" + "post": { + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" } - }, - "required": [ - "teams" ], - "title": "TeamsV1", - "type": "object" - }, - "TeamsRequestV1": { - "description": "Request parameters for listing teams.", - "properties": { - "name": { - "anyOf": [ - { - "type": "string" + "operationId": "PushImage", + "summary": "Push a sandbox image", + "description": "With image supplied, import the registry image asynchronously. Otherwise return an upload URL for a ZIP source archive containing its Dockerfile and build context. The uploaded ZIP archive must not exceed 5 GB. Processing starts after upload. No sandbox is created. Poll the image until BUILT or FAILED.", + "tags": [ + "Images" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushImageRequestV1" }, - { - "type": "null" + "examples": { + "archive": { + "$ref": "#/components/examples/PushArchive" + }, + "registry": { + "$ref": "#/components/examples/PushRegistry" + } } - ], - "default": null, - "description": "When set, returns only the team with this exact name, if any.", - "title": "Name" + } } }, - "title": "TeamsRequestV1", - "type": "object" - }, - "RegionV1": { - "description": "A region that deployments can be placed in.", - "properties": { - "slug": { - "description": "Stable identifier for the region, used when selecting a deployment region.", - "examples": [ - "us" - ], - "title": "Slug", - "type": "string" + "responses": { + "202": { + "description": "Request accepted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushImageResponseV1" + }, + "examples": { + "archive": { + "$ref": "#/components/examples/PushArchiveAccepted" + }, + "registry": { + "$ref": "#/components/examples/PushRegistryAccepted" + } + } + } + } }, - "display_name": { - "description": "Human-readable name of the region.", - "examples": [ - "United States" - ], - "title": "Display Name", - "type": "string" + "400": { + "$ref": "#/components/responses/SandboxError400" + }, + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "slug", - "display_name" - ], - "title": "RegionV1", - "type": "object" - }, - "RegionsV1": { - "description": "A list of regions.", - "properties": { - "regions": { - "items": { - "$ref": "#/components/schemas/RegionV1" - }, - "title": "Regions", - "type": "array" + "x-stability": "unstable" + } + }, + "/v1/sandboxes/cleanup_images": { + "post": { + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" } - }, - "required": [ - "regions" ], - "title": "RegionsV1", - "type": "object" - }, - "InstanceTypeV1": { - "description": "An instance type.", - "properties": { - "id": { - "description": "Identifier string for the instance type", - "title": "Id", - "type": "string" - }, - "name": { - "description": "Display name of the instance type", - "title": "Name", - "type": "string" + "operationId": "CleanupImages", + "summary": "Clean up unused images", + "description": "Remove unused sandbox image versions. Versions referenced by active deployments are preserved.", + "tags": [ + "Images" + ], + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CleanupImagesResponseV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/CleanupImages" + } + } + } + } }, - "memory_limit_mib": { - "description": "Memory limit of the instance type in Mebibytes", - "title": "Memory Limit Mib", - "type": "integer" + "400": { + "$ref": "#/components/responses/SandboxError400" }, - "millicpu_limit": { - "description": "CPU limit of the instance type in millicpu", - "title": "Millicpu Limit", - "type": "integer" + "401": { + "$ref": "#/components/responses/SandboxError401" }, - "gpu_count": { - "description": "Number of GPUs on the instance type", - "title": "Gpu Count", - "type": "integer" + "403": { + "$ref": "#/components/responses/SandboxError403" }, - "gpu_type": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Type of GPU on the instance type", - "title": "Gpu Type" + "429": { + "$ref": "#/components/responses/SandboxError429" }, - "gpu_memory_limit_mib": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Memory limit of the GPU on the instance type in Mebibytes", - "title": "Gpu Memory Limit Mib" + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "id", - "name", - "memory_limit_mib", - "millicpu_limit", - "gpu_count", - "gpu_type", - "gpu_memory_limit_mib" + "x-stability": "unstable" + } + }, + "/v1/sandboxes/images/{image_name}": { + "parameters": [ + { + "$ref": "#/components/parameters/ImageName" + } + ], + "get": { + "operationId": "GetImage", + "summary": "Get a sandbox image", + "description": "Return the repository summary and processing status. Use the tag listing endpoint for image versions.", + "tags": [ + "Images" ], - "title": "InstanceTypeV1", - "type": "object" - }, - "InstanceTypesV1": { - "description": "A list of instance types.", - "properties": { - "instance_types": { - "items": { - "$ref": "#/components/schemas/InstanceTypeV1" - }, - "title": "Instance Types", - "type": "array" + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" } - }, - "required": [ - "instance_types" ], - "title": "InstanceTypesV1", - "type": "object" - }, - "LoopsUserConfigV1": { - "description": "The caller's Loops user-level config (accelerator priorities).", - "properties": { - "trainer_accelerator_priority": { - "anyOf": [ - { - "items": { - "type": "string" + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImageV1" }, - "type": "array" - }, - { - "type": "null" + "examples": { + "complete": { + "$ref": "#/components/examples/ImageSummary" + } + } } - ], - "description": "Ordered allowlist of GPU types for your Loops trainer deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", - "examples": [ - [ - "H100", - "H200" - ] - ], - "title": "Trainer Accelerator Priority" + } }, - "sampler_accelerator_priority": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Ordered allowlist of GPU types for your Loops sampler deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", - "examples": [ - [ - "H100", - "H200" - ] - ], - "title": "Sampler Accelerator Priority" + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "trainer_accelerator_priority", - "sampler_accelerator_priority" - ], - "title": "LoopsUserConfigV1", - "type": "object" + "x-stability": "unstable" }, - "GetLoopsUserConfigResponseV1": { - "description": "Response for ``GET /v1/loops/user_config``.", - "properties": { - "user_config": { - "$ref": "#/components/schemas/LoopsUserConfigV1", - "description": "The caller's Loops user config." + "delete": { + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" } - }, - "required": [ - "user_config" ], - "title": "GetLoopsUserConfigResponseV1", - "type": "object" - }, - "PatchLoopsUserConfigRequestV1": { - "description": "Request body for ``PATCH /v1/loops/user_config``.\n\nFollows JSON Merge Patch (RFC 7396) semantics per field: omit the field\nto leave it unchanged, send ``null`` to clear and inherit the org-level\nallowlist, send a list to set the allowlist. Empty lists are rejected\nbecause the storage layer normalizes ``null`` and ``[]`` identically, so\naccepting both would create two ways to spell the same intent.", - "properties": { - "trainer_accelerator_priority": { - "anyOf": [ - { - "items": { - "type": "string" + "operationId": "DeleteImage", + "summary": "Delete a sandbox image", + "description": "Delete the image repository and all its tags. Reject deletion if any version is referenced by an active deployment. Return the deleted image.", + "tags": [ + "Images" + ], + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImageV1" }, - "type": "array" - }, - { - "type": "null" + "examples": { + "complete": { + "$ref": "#/components/examples/ImageReady" + } + } } - ], - "default": null, - "description": "Ordered list of GPU types for trainer deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", - "examples": [ - [ - "H100", - "H200" - ] - ], - "title": "Trainer Accelerator Priority", - "x-null-distinct": true + } }, - "sampler_accelerator_priority": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Ordered list of GPU types for sampler deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", - "examples": [ - [ - "H100", - "H200" - ] - ], - "title": "Sampler Accelerator Priority", - "x-null-distinct": true + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "409": { + "$ref": "#/components/responses/SandboxError409" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "title": "PatchLoopsUserConfigRequestV1", - "type": "object" - }, - "PatchLoopsUserConfigResponseV1": { - "description": "Response for ``PATCH /v1/loops/user_config``.", - "properties": { - "user_config": { - "$ref": "#/components/schemas/LoopsUserConfigV1", - "description": "The updated Loops user config." + "x-stability": "unstable" + } + }, + "/v1/sandboxes/images/{image_name}/logs": { + "parameters": [ + { + "$ref": "#/components/parameters/ImageName" + } + ], + "get": { + "operationId": "GetImageBuildLogs", + "summary": "Get image build logs", + "description": "Return one page of logs from the latest recorded build of this image, including failed builds, newest first. Logs may take a short time to appear. Defaults to the last 24 hours; the requested time range must not exceed 7 days. Keep start_time and end_time fixed when paging with offset. A new build changes the log source; this endpoint does not retrieve a historical build by ID. While a new upload is waiting to start, logs may still refer to the preceding build. Older builds without a recorded environment use image-level build logs within the requested time range.", + "tags": [ + "Images" + ], + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" + }, + { + "name": "start_time", + "in": "query", + "description": "Inclusive RFC 3339 start time. Defaults to 24 hours before end_time.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "end_time", + "in": "query", + "description": "RFC 3339 end time. Defaults to the current time.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of log entries to return.", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1000, + "default": 100 + } + }, + { + "name": "offset", + "in": "query", + "description": "Number of log entries to skip. Narrow the time range beyond 10000 entries.", + "schema": { + "type": "integer", + "minimum": 0, + "maximum": 10000, + "default": 0 + } } - }, - "required": [ - "user_config" ], - "title": "PatchLoopsUserConfigResponseV1", - "type": "object" - }, - "InstanceTypeWithPriceV1": { - "properties": { - "instance_type": { - "$ref": "#/components/schemas/InstanceTypeV1", - "description": "Instance type properties." + "responses": { + "200": { + "description": "Build logs in the requested time range. An empty array means no logs are available in that range.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImageBuildLogsResponseV1" + }, + "example": { + "logs": [ + { + "timestamp": "2026-09-29T12:00:00Z", + "message": "Step 1/2: loading build context", + "severity": 9 + } + ], + "total_count": 1 + } + } + } }, - "price": { - "description": "Usage price in USD / minute.", - "title": "Price", - "type": "number" + "400": { + "$ref": "#/components/responses/SandboxError400" + }, + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" + }, + "503": { + "description": "Build log service is temporarily unavailable. Returns a JSON error with code and message." } }, - "required": [ - "instance_type", - "price" - ], - "title": "InstanceTypeWithPriceV1", - "type": "object" - }, - "InstanceTypePricesV1": { - "description": "A list of instance types.", - "properties": { - "instance_types": { - "items": { - "$ref": "#/components/schemas/InstanceTypeWithPriceV1" - }, - "title": "Instance Types", - "type": "array" + "x-stability": "unstable" + } + }, + "/v1/sandboxes/images/{image_name}/tags": { + "parameters": [ + { + "$ref": "#/components/parameters/ImageName" + } + ], + "get": { + "operationId": "ListImageTags", + "summary": "List image tags", + "description": "Return one cursor-paginated page of image versions.", + "tags": [ + "Images" + ], + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" + }, + { + "$ref": "#/components/parameters/Cursor" + }, + { + "$ref": "#/components/parameters/Limit" + }, + { + "name": "sort", + "in": "query", + "description": "Sort by tag name: name:asc or name:desc. Keep the same sort when following a cursor.", + "schema": { + "type": "string", + "default": "name:asc" + } + }, + { + "name": "q", + "in": "query", + "description": "Case-sensitive tag name prefix. Cannot be combined with name. Forces ascending name order.", + "schema": { + "type": "string" + } + }, + { + "name": "name", + "in": "query", + "description": "Exact tag name. Cannot be combined with q. Forces ascending name order.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListImageTagsResponseV1" + } + } + } + }, + "400": { + "$ref": "#/components/responses/SandboxError400" + }, + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" } }, - "required": [ - "instance_types" + "x-stability": "unstable" + } + }, + "/v1/sandboxes/images/{image_name}/tags/{tag_name}": { + "parameters": [ + { + "$ref": "#/components/parameters/ImageName" + }, + { + "$ref": "#/components/parameters/TagName" + } + ], + "delete": { + "parameters": [ + { + "$ref": "#/components/parameters/TeamId" + }, + { + "$ref": "#/components/parameters/TeamIdHeader" + } ], - "title": "InstanceTypePricesV1", - "type": "object" - }, - "DeploymentArchivePayloadV1": { - "description": "Deployment-level fields for a model-archive push.\n\nShared by every endpoint that creates a deployment from an uploaded archive:\n`POST /v1/prepare_model_upload`, the `model_archive` source on `POST\n/v1/models`, and `POST /v1/models/{model_id}/deployments`.", + "operationId": "DeleteImageTag", + "summary": "Delete an image tag", + "description": "Delete a specific image version. Reject deletion if the version is referenced by an active deployment. Return the updated image with its remaining tags, possibly empty.", + "tags": [ + "Images" + ], + "responses": { + "200": { + "description": "Successful operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImageV1" + }, + "examples": { + "complete": { + "$ref": "#/components/examples/ImageAfterTagDeletion" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/SandboxError401" + }, + "403": { + "$ref": "#/components/responses/SandboxError403" + }, + "404": { + "$ref": "#/components/responses/SandboxError404" + }, + "409": { + "$ref": "#/components/responses/SandboxError409" + }, + "429": { + "$ref": "#/components/responses/SandboxError429" + }, + "500": { + "$ref": "#/components/responses/SandboxError500" + } + }, + "x-stability": "unstable" + } + } + }, + "openapi": "3.1.0", + "components": { + "schemas": { + "PaginationResponseV1": { "properties": { - "config": { - "additionalProperties": true, - "description": "Parsed model config as a JSON object.", - "title": "Config", - "type": "object" + "has_more": { + "description": "Whether more items exist after this page.", + "title": "Has More", + "type": "boolean" }, - "raw_config": { + "cursor": { "anyOf": [ { "type": "string" @@ -10804,216 +11521,221 @@ } ], "default": null, - "description": "Original config.yaml text, persisted as-is on the deployment. Best-effort: invalid raw configs are logged and dropped without failing the request.", - "title": "Raw Config" + "description": "Opaque cursor to pass into the next request. Null when there is no next page.", + "title": "Cursor" + } + }, + "required": [ + "has_more" + ], + "title": "PaginationResponseV1", + "type": "object" + }, + "VolumeTagV1": { + "properties": { + "name": { + "description": "Tag name. Tags are case-sensitive.", + "title": "Name", + "type": "string" }, - "user_env": { - "anyOf": [ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Client environment metadata (e.g. client version, Python version). Validated server-side.", - "title": "User Env" + "digest": { + "description": "Digest of the version the tag points at, as `b3:`.", + "title": "Digest", + "type": "string" }, - "environment_name": { + "expires_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { "type": "null" } ], - "default": null, - "description": "Stable environment to push to (e.g. `production`). If unset, the deployment is created without environment selection. Caller must have push permission for the named environment.", - "title": "Environment Name" + "description": "When the tag stops resolving and leaves the volume, in ISO 8601 format. Null for a tag that never expires. The version it points at is not affected.", + "title": "Expires At" + } + }, + "required": [ + "name", + "digest", + "expires_at" + ], + "title": "VolumeTagV1", + "type": "object" + }, + "VolumeV1": { + "properties": { + "namespace": { + "description": "Namespace the volume belongs to, in lowercase.", + "title": "Namespace", + "type": "string" }, - "create_environment_if_missing": { - "default": true, - "description": "Create the environment named by `environment_name` if it does not exist yet. If false, a push to an environment that does not exist is rejected. Only meaningful when `environment_name` is set to something other than `production`, which always exists. This field currently defaults to true, but that default will change to false in a future release. Set it explicitly to avoid a behavior change.", - "title": "Create Environment If Missing", - "type": "boolean" + "name": { + "description": "Name of the volume, in lowercase.", + "title": "Name", + "type": "string" }, - "region": { + "version_ref": { + "description": "Full address of the volume, as `bdn:/`. Paste this into the `bdn.mounts` section of a config.yaml.", + "title": "Version Ref", + "type": "string" + }, + "sequence": { + "description": "Revision counter for the volume, incremented on every commit, tag change, delete, and restore. A tag or version that expires leaves without changing it; the next write then increments it once. Use it to detect that a volume was written to.", + "title": "Sequence", + "type": "integer" + }, + "updated_at": { + "description": "When the volume was last written to, in ISO 8601 format. An expiry does not update it.", + "format": "date-time", + "title": "Updated At", + "type": "string" + }, + "expires_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { "type": "null" } ], - "default": null, - "description": "Region in which to deploy the model", - "title": "Region" - }, - "preserve_env_instance_type": { - "default": true, - "description": "Retain the target environment's current instance type rather than the one in `config`. Only meaningful when `environment_name` is set and that environment already exists.", - "title": "Preserve Env Instance Type", - "type": "boolean" + "description": "When the whole volume expires, in ISO 8601 format. At that instant every live version is deleted, every tag drops, and the volume leaves the volume listing; each version then stays restorable until its recovery deadline passes. Null for a volume that never expires.", + "title": "Expires At" }, - "deploy_timeout_minutes": { + "head": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/VolumeVersionSummaryV1" }, { "type": "null" } ], - "default": null, - "description": "Deploy timeout in minutes; allowed range 10 to 1440. Server default applies if unset.", - "title": "Deploy Timeout Minutes" + "description": "Version that the reserved `head` tag points at, which a reference with no tag or digest resolves to. Never an expiring version. Null when the volume has no head, or when your API key cannot read it." }, - "deployment_name": { + "tags": { + "description": "Tags on the volume that your API key can read. A tag with `expires_at` leaves this list at that instant.", + "items": { + "$ref": "#/components/schemas/VolumeTagV1" + }, + "title": "Tags", + "type": "array" + }, + "tag_count": { + "description": "Total number of tags on the volume, which can exceed the length of `tags` when your API key cannot read all of them. Counts only tags that have not expired.", + "title": "Tag Count", + "type": "integer" + }, + "versions_alive": { + "description": "Number of versions that have not been deleted or expired.", + "title": "Versions Alive", + "type": "integer" + }, + "versions_tombstoned": { + "description": "Number of versions that have been deleted or expired and are still within their recovery window.", + "title": "Versions Tombstoned", + "type": "integer" + }, + "versions_untagged": { + "description": "Number of live versions that no tag points at.", + "title": "Versions Untagged", + "type": "integer" + }, + "versions_expiring": { + "description": "Number of live versions with an expiry still ahead of them. A version that has already expired counts in `versions_tombstoned` instead.", + "title": "Versions Expiring", + "type": "integer" + }, + "versions_earliest_expires_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { "type": "null" } ], - "default": null, - "description": "Optional human-readable name for the deployment.", - "title": "Deployment Name" - }, - "labels": { - "anyOf": [ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "null" - } - ], - "default": null, - "description": "User-provided key-value labels for the deployment.", - "title": "Labels" - }, - "is_development": { - "default": false, - "description": "If true, push as a development deployment: the model's single mutable dev slot, created if absent and overwritten in place otherwise. The following fields must be left at their defaults: `environment_name`, `preserve_env_instance_type`, `deployment_name`.", - "title": "Is Development", - "type": "boolean" + "description": "Earliest expiry among the live versions, in ISO 8601 format. Null when no live version is scheduled to expire.", + "title": "Versions Earliest Expires At" } }, "required": [ - "config" + "namespace", + "name", + "version_ref", + "sequence", + "updated_at", + "expires_at", + "head", + "tags", + "tag_count", + "versions_alive", + "versions_tombstoned", + "versions_untagged", + "versions_expiring", + "versions_earliest_expires_at" ], - "title": "DeploymentArchivePayloadV1", + "title": "VolumeV1", "type": "object" }, - "PrepareModelUploadRequestV1": { - "description": "Body for `POST /v1/prepare_model_upload`.\n\nValidates the same payload the commit endpoint will validate, and on\n`dry_run=false` issues STS upload credentials. Exactly one of `name` or\n`model_id` is required: `name` validates the new-model path (`POST\n/v1/models`); `model_id` validates the add-deployment path (`POST\n/v1/models/{model_id}/deployments`).", + "VolumeVersionSummaryV1": { "properties": { - "deployment": { - "$ref": "#/components/schemas/DeploymentArchivePayloadV1", - "description": "Deployment-level payload, identical to the payload sent at commit." - }, - "name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Set to validate a new-model push. Exactly one of `name` or `model_id` is required.", - "title": "Name" - }, - "team_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Team the new model will belong to. Only valid when `name` is set; defaults to the organization's default team when omitted. Must not be set when `model_id` is set (the existing model already has a team).", - "title": "Team Id" + "digest": { + "description": "Content digest of the version, as `b3:`.", + "title": "Digest", + "type": "string" }, - "model_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Set to validate an add-deployment push to an existing model. Exactly one of `name` or `model_id` is required.", - "title": "Model Id" + "total_size_bytes": { + "description": "Total size of the version's files in bytes.", + "title": "Total Size Bytes", + "type": "integer" }, - "dry_run": { - "default": false, - "description": "If true, validate the payload only and do not issue upload credentials. The response sets `creds`, `s3_bucket`, and `s3_key` to `null`.", - "title": "Dry Run", - "type": "boolean" + "created_at": { + "description": "When the version was committed, in ISO 8601 format.", + "format": "date-time", + "title": "Created At", + "type": "string" } }, "required": [ - "deployment" + "digest", + "total_size_bytes", + "created_at" ], - "title": "PrepareModelUploadRequestV1", + "title": "VolumeVersionSummaryV1", "type": "object" }, - "AWSCredentialsV1": { - "description": "AWS credentials", + "ListVolumesResponseV1": { + "description": "A page of volumes in one namespace.", "properties": { - "aws_access_key_id": { - "description": "The AWS access key ID", - "title": "Aws Access Key Id", - "type": "string" - }, - "aws_secret_access_key": { - "description": "The AWS secret access key", - "title": "Aws Secret Access Key", - "type": "string" + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/VolumeV1" + }, + "title": "Items", + "type": "array" }, - "aws_session_token": { - "description": "The AWS session token", - "title": "Aws Session Token", - "type": "string" + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "aws_access_key_id", - "aws_secret_access_key", - "aws_session_token" + "items", + "pagination" ], - "title": "AWSCredentialsV1", + "title": "ListVolumesResponseV1", "type": "object" }, - "PrepareModelUploadResponseV1": { - "description": "Response from `POST /v1/prepare_model_upload`.\n\nReturns STS upload credentials when the push requires an archive upload. All\nfour fields (`creds`, `s3_bucket`, `s3_key`, `s3_region`) are `null` when no\nupload is needed: either `dry_run=true` (validation only) or a model format\nthat is not built from an uploaded archive (for example, BIS-LLM, which is\nbuilt from its config alone).", + "ListVolumesRequestV1": { "properties": { - "creds": { - "anyOf": [ - { - "$ref": "#/components/schemas/AWSCredentialsV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "STS credentials to upload the model archive. Null when no archive upload is required." - }, - "s3_bucket": { + "cursor": { "anyOf": [ { "type": "string" @@ -11023,74 +11745,75 @@ } ], "default": null, - "description": "S3 bucket the credentials are scoped to. Null when no archive upload is required.", - "title": "S3 Bucket" + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "s3_key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "S3 key the credentials are scoped to. Pass this to `POST /v1/models` (in the `model_archive` source) once the upload completes. Null when no archive upload is required.", - "title": "S3 Key" + "limit": { + "default": 100, + "description": "Maximum number of volumes to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" }, - "s3_region": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "AWS region the S3 bucket resides in. Null when no archive upload is required.", - "title": "S3 Region" + "namespace": { + "description": "Namespace to list volumes in. Required, because the volume service has no cross-namespace inventory.", + "title": "Namespace", + "type": "string" } }, - "title": "PrepareModelUploadResponseV1", + "required": [ + "namespace" + ], + "title": "ListVolumesRequestV1", "type": "object" }, - "AuditLogActorTypeV1": { - "description": "Kind of actor that performed an audited action.", + "VolumeTokenScopeV1": { + "description": "Capability a volume token grants.\n\n- ``PULL``: read volume data.\n- ``INSPECT``: read volume metadata without data access.\n- ``PUSH``: upload and commit volume versions.\n- ``TAG``: move or remove tags.", "enum": [ - "USER", - "API_KEY", - "BASETEN_USER", - "BASETEN_SYSTEM", - "TOMBSTONE_USER" + "PULL", + "INSPECT", + "PUSH", + "TAG" ], - "title": "AuditLogActorTypeV1", + "title": "VolumeTokenScopeV1", "type": "string" }, - "AuditLogActorV1": { - "description": "The actor that performed an audited action.", + "CreateVolumeTokenRequestV1": { + "additionalProperties": false, "properties": { - "type": { - "$ref": "#/components/schemas/AuditLogActorTypeV1", - "description": "Kind of actor that performed the action." + "scopes": { + "description": "Capabilities the token grants, at least one. Requesting PUSH or TAG requires organization-level model management permission.", + "items": { + "$ref": "#/components/schemas/VolumeTokenScopeV1" + }, + "minItems": 1, + "title": "Scopes", + "type": "array" }, - "email": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Email of the acting user, when the actor is a user.", - "title": "Email" + "namespaces": { + "description": "Volume namespaces the token is limited to, lowercase ASCII, at least one. Pass only the namespaces the operation needs.", + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Namespaces", + "type": "array" }, - "api_key_prefix": { + "volumes": { + "description": "Volume names the token is limited to, lowercase ASCII, exact names only, at least one. The limit applies to every requested scope in every requested namespace.", + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Volumes", + "type": "array" + }, + "correlation_id": { "anyOf": [ { + "maxLength": 128, + "pattern": "^[\\x21-\\x7e]+$", "type": "string" }, { @@ -11098,10 +11821,105 @@ } ], "default": null, - "description": "Prefix of the acting API key, when the actor is an API key.", - "title": "Api Key Prefix" - }, - "api_key_name": { + "description": "Optional client-chosen identifier, at most 128 printable ASCII characters. Echoed into server logs to link the issued token to a client operation.", + "title": "Correlation Id" + } + }, + "required": [ + "scopes", + "namespaces", + "volumes" + ], + "title": "CreateVolumeTokenRequestV1", + "type": "object" + }, + "CreateVolumeTokenResponseV1": { + "properties": { + "token": { + "description": "Volume access token. Pass as a bearer token to the volume APIs.", + "title": "Token", + "type": "string" + }, + "expires_at": { + "description": "Token expiry in ISO 8601 format. Tokens cannot be renewed; exchange again for a fresh token.", + "format": "date-time", + "title": "Expires At", + "type": "string" + }, + "scopes": { + "description": "Effective capabilities granted.", + "items": { + "$ref": "#/components/schemas/VolumeTokenScopeV1" + }, + "title": "Scopes", + "type": "array" + }, + "namespaces": { + "description": "Effective namespaces granted, in canonical lowercase form.", + "items": { + "type": "string" + }, + "title": "Namespaces", + "type": "array" + }, + "volumes": { + "description": "Effective volume names granted, in canonical lowercase form.", + "items": { + "type": "string" + }, + "title": "Volumes", + "type": "array" + }, + "bdn_endpoint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Base URL of the volume API this token authenticates against. Null when the environment does not expose a public volume API yet.", + "title": "Bdn Endpoint" + } + }, + "required": [ + "token", + "expires_at", + "scopes", + "namespaces", + "volumes", + "bdn_endpoint" + ], + "title": "CreateVolumeTokenResponseV1", + "type": "object" + }, + "ListVolumeNamespacesResponseV1": { + "description": "A page of namespaces the caller can read.", + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "type": "string" + }, + "title": "Items", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "ListVolumeNamespacesResponseV1", + "type": "object" + }, + "ListVolumeNamespacesRequestV1": { + "properties": { + "cursor": { "anyOf": [ { "type": "string" @@ -11111,279 +11929,159 @@ } ], "default": null, - "description": "Display name of the acting API key, when the actor is an API key.", - "title": "Api Key Name" + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" + }, + "limit": { + "default": 100, + "description": "Maximum number of namespaces to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + "title": "ListVolumeNamespacesRequestV1", + "type": "object" + }, + "VolumeSyncAuthenticationAWSAssumeRoleV1": { + "additionalProperties": false, + "description": "Authentication using an AWS IAM role assumed by Baseten.", + "properties": { + "role_arn": { + "description": "AWS IAM role ARN to assume.", + "minLength": 1, + "title": "Role Arn", + "type": "string" + }, + "region": { + "description": "AWS region for the assumed role session.", + "minLength": 1, + "title": "Region", + "type": "string" } }, "required": [ - "type" + "role_arn", + "region" ], - "title": "AuditLogActorV1", + "title": "VolumeSyncAuthenticationAWSAssumeRoleV1", "type": "object" }, - "AuditLogApiKeyTypeV1": { - "description": "Type of API key recorded on an API-key event.", - "enum": [ - "PERSONAL", - "CREATOR_SERVICE_ACCOUNT", - "MANAGE_API_KEYS_SERVICE_ACCOUNT", - "INVOKE_ALL_MODELS_SERVICE_ACCOUNT", - "INVOKE_ALLOWED_MODELS_SERVICE_ACCOUNT", - "INVOKE_SCOPED_ENVS_AND_MODELS_SERVICE_ACCOUNT", - "EXPORT_METRICS_ALL_MODELS_SERVICE_ACCOUNT", - "EXPORT_METRICS_ALLOWED_MODELS_SERVICE_ACCOUNT", - "INVOKE_ALL_SHARED_ENDPOINTS_SERVICE_ACCOUNT", - "INVOKE_ALLOWED_SHARED_ENDPOINTS_SERVICE_ACCOUNT", - "INVOKE_ALL_ROUTES" + "VolumeSyncAuthenticationAWSOIDCV1": { + "additionalProperties": false, + "description": "Authentication using an AWS IAM role and Baseten workload identity.", + "properties": { + "role_arn": { + "description": "AWS IAM role ARN to assume through OIDC.", + "minLength": 1, + "title": "Role Arn", + "type": "string" + }, + "region": { + "description": "AWS region for the OIDC role session.", + "minLength": 1, + "title": "Region", + "type": "string" + } + }, + "required": [ + "role_arn", + "region" ], - "title": "AuditLogApiKeyTypeV1", - "type": "string" + "title": "VolumeSyncAuthenticationAWSOIDCV1", + "type": "object" }, - "AuditLogEntryV1": { - "description": "A single audit-log entry.", + "VolumeSyncAuthenticationGCPOIDCV1": { + "additionalProperties": false, + "description": "Authentication using GCP Workload Identity Federation.", "properties": { - "id": { - "description": "Unique identifier of the audit-log entry.", - "title": "Id", + "service_account": { + "description": "GCP service account to impersonate through OIDC.", + "minLength": 1, + "title": "Service Account", "type": "string" }, - "created": { - "description": "Time the action occurred, in ISO 8601 format.", - "format": "date-time", - "title": "Created", + "workload_identity_provider": { + "description": "Full resource name of the GCP workload identity provider.", + "minLength": 1, + "title": "Workload Identity Provider", + "type": "string" + } + }, + "required": [ + "service_account", + "workload_identity_provider" + ], + "title": "VolumeSyncAuthenticationGCPOIDCV1", + "type": "object" + }, + "VolumeSyncDestinationV1": { + "additionalProperties": false, + "description": "BDN destination for a volume sync.", + "properties": { + "ref": { + "description": "Destination as bdn:/ with an optional tag.", + "title": "Ref", + "type": "string" + } + }, + "required": [ + "ref" + ], + "title": "VolumeSyncDestinationV1", + "type": "object" + }, + "VolumeSyncErrorV1": { + "description": "Public failure details for a volume sync.", + "properties": { + "code": { + "description": "Stable machine-readable failure classification.", + "title": "Code", "type": "string" }, - "event_type": { - "$ref": "#/components/schemas/AuditLogEventTypeV1", - "description": "Type of action that was recorded." + "message": { + "description": "Redacted user-facing failure message.", + "title": "Message", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "title": "VolumeSyncErrorV1", + "type": "object" + }, + "VolumeSyncSourceAzureV1": { + "additionalProperties": false, + "description": "Azure Blob Storage source.", + "properties": { + "uri": { + "description": "Remote source URI to materialize into the destination volume.", + "title": "Uri", + "type": "string" }, - "event_data": { - "description": "Structured details of the action, discriminated by `event_type`.", - "discriminator": { - "mapping": { - "API_KEY_CREATED": "#/components/schemas/AuditLogEventApiKeyCreatedV1", - "API_KEY_DELETED": "#/components/schemas/AuditLogEventApiKeyDeletedV1", - "CHAINLET_AUTOSCALING_SETTINGS_CHANGED": "#/components/schemas/AuditLogEventChainletAutoscalingSettingsChangedV1", - "CHAINLET_INSTANCE_TYPE_CHANGED": "#/components/schemas/AuditLogEventChainletInstanceTypeChangedV1", - "CHAIN_DELETED": "#/components/schemas/AuditLogEventChainDeletedV1", - "CHAIN_DEPLOYED": "#/components/schemas/AuditLogEventChainDeployedV1", - "CHAIN_DEPLOYMENT_ACTIVATED": "#/components/schemas/AuditLogEventChainDeploymentActivatedV1", - "CHAIN_DEPLOYMENT_DEACTIVATED": "#/components/schemas/AuditLogEventChainDeploymentDeactivatedV1", - "CHAIN_DEPLOYMENT_DELETED": "#/components/schemas/AuditLogEventChainDeploymentDeletedV1", - "CHAIN_DEPLOYMENT_PROMOTED": "#/components/schemas/AuditLogEventChainDeploymentPromotedV1", - "CHAIN_ENVIRONMENT_CREATED": "#/components/schemas/AuditLogEventChainEnvironmentCreatedV1", - "CHAIN_ENVIRONMENT_UPDATED": "#/components/schemas/AuditLogEventChainEnvironmentUpdatedV1", - "DIRECTORY_GROUP_ROLE_UPDATED": "#/components/schemas/AuditLogEventDirectoryGroupRoleUpdatedV1", - "ENVIRONMENT_CREATED": "#/components/schemas/AuditLogEventEnvironmentCreatedV1", - "ENVIRONMENT_DELETED": "#/components/schemas/AuditLogEventEnvironmentDeletedV1", - "ENVIRONMENT_UPDATED": "#/components/schemas/AuditLogEventEnvironmentUpdatedV1", - "GATEWAY_ENDPOINT_CREATED": "#/components/schemas/AuditLogEventGatewayEndpointCreatedV1", - "GATEWAY_ENDPOINT_DELETED": "#/components/schemas/AuditLogEventGatewayEndpointDeletedV1", - "GATEWAY_ENDPOINT_UPDATED": "#/components/schemas/AuditLogEventGatewayEndpointUpdatedV1", - "MODEL_DELETED": "#/components/schemas/AuditLogEventModelDeletedV1", - "MODEL_DEPLOYED": "#/components/schemas/AuditLogEventModelDeployedV1", - "MODEL_DEPLOYMENT_ACTIVATED": "#/components/schemas/AuditLogEventModelDeploymentActivatedV1", - "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED": "#/components/schemas/AuditLogEventModelDeploymentAutoscalingSettingsChangedV1", - "MODEL_DEPLOYMENT_DEACTIVATED": "#/components/schemas/AuditLogEventModelDeploymentDeactivatedV1", - "MODEL_DEPLOYMENT_DELETED": "#/components/schemas/AuditLogEventModelDeploymentDeletedV1", - "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED": "#/components/schemas/AuditLogEventModelDeploymentInstanceTypeChangedV1", - "MODEL_DEPLOYMENT_PROMOTED": "#/components/schemas/AuditLogEventModelDeploymentPromotedV1", - "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED": "#/components/schemas/AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1", - "MODEL_DEPLOYMENT_RETRIED": "#/components/schemas/AuditLogEventModelDeploymentRetriedV1", - "MODEL_PROMOTION_CONTROL_ACTION": "#/components/schemas/AuditLogEventModelPromotionControlActionV1", - "REPLICA_TERMINATED": "#/components/schemas/AuditLogEventReplicaTerminatedV1", - "REQUIRE_GROUP_BASED_ADMINS_ENABLED": "#/components/schemas/AuditLogEventRequireGroupBasedAdminsEnabledV1", - "SECRET_DELETED": "#/components/schemas/AuditLogEventSecretDeletedV1", - "SECRET_UPDATED": "#/components/schemas/AuditLogEventSecretUpdatedV1", - "SSH_CERTIFICATE_SIGNED": "#/components/schemas/AuditLogEventSshCertificateSignedV1", - "USER_INVITED": "#/components/schemas/AuditLogEventUserInvitedV1", - "USER_JOINED_ORGANIZATION": "#/components/schemas/AuditLogEventUserJoinedOrganizationV1", - "USER_REMOVED": "#/components/schemas/AuditLogEventUserRemovedV1", - "USER_ROLE_UPDATED": "#/components/schemas/AuditLogEventUserRoleUpdatedV1", - "USER_TEAM_ROLE_UPDATED": "#/components/schemas/AuditLogEventUserTeamRoleUpdatedV1", - "VOLUME_DELETED": "#/components/schemas/AuditLogEventVolumeDeletedV1", - "VOLUME_VERSION_DELETED": "#/components/schemas/AuditLogEventVolumeVersionDeletedV1", - "VOLUME_VERSION_RESTORED": "#/components/schemas/AuditLogEventVolumeVersionRestoredV1", - "WEBHOOK_SIGNING_SECRET_CREATED": "#/components/schemas/AuditLogEventWebhookSigningSecretCreatedV1", - "WEBHOOK_SIGNING_SECRET_DELETED": "#/components/schemas/AuditLogEventWebhookSigningSecretDeletedV1", - "WEBHOOK_SIGNING_SECRET_ROTATED": "#/components/schemas/AuditLogEventWebhookSigningSecretRotatedV1" - }, - "propertyName": "event_type" + "include": { + "description": "Glob patterns selecting files to include.", + "items": { + "type": "string" }, - "oneOf": [ - { - "$ref": "#/components/schemas/AuditLogEventModelDeployedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentActivatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentDeactivatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentRetriedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentPromotedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentAutoscalingSettingsChangedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentInstanceTypeChangedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeploymentDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainDeployedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainDeploymentActivatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainDeploymentDeactivatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainDeploymentPromotedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainletAutoscalingSettingsChangedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainletInstanceTypeChangedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainDeploymentDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainEnvironmentCreatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventChainEnvironmentUpdatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventSecretUpdatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventSecretDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventApiKeyCreatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventApiKeyDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventGatewayEndpointCreatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventGatewayEndpointUpdatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventGatewayEndpointDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventUserInvitedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventUserJoinedOrganizationV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventWebhookSigningSecretCreatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventWebhookSigningSecretRotatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventWebhookSigningSecretDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventUserRoleUpdatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventUserTeamRoleUpdatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventUserRemovedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventDirectoryGroupRoleUpdatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventRequireGroupBasedAdminsEnabledV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventEnvironmentCreatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventEnvironmentUpdatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventEnvironmentDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventReplicaTerminatedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventModelPromotionControlActionV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventSshCertificateSignedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventVolumeDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventVolumeVersionDeletedV1" - }, - { - "$ref": "#/components/schemas/AuditLogEventVolumeVersionRestoredV1" - } - ], - "title": "Event Data" - }, - "source": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuditLogSourceV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Surface that issued the action, if known." - }, - "actor": { - "$ref": "#/components/schemas/AuditLogActorV1", - "description": "The actor that performed the action." + "title": "Include", + "type": "array" }, - "client_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Name of the client that issued the action, if known.", - "title": "Client Name" + "exclude": { + "description": "Glob patterns selecting files to exclude.", + "items": { + "type": "string" + }, + "title": "Exclude", + "type": "array" }, - "client_version": { + "auth_secret_name": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -11391,276 +12089,469 @@ } ], "default": null, - "description": "Version of the client that issued the action, if known.", - "title": "Client Version" + "description": "Optional workspace secret containing credentials for this source.", + "title": "Auth Secret Name" }, - "client_session_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Opaque identifier grouping actions from the same client session, if known.", - "title": "Client Session Id" + "type": { + "const": "AZURE", + "description": "Azure Blob Storage source type.", + "title": "Type", + "type": "string" } }, "required": [ - "id", - "created", - "event_type", - "event_data", - "actor" + "uri", + "type" ], - "title": "AuditLogEntryV1", + "title": "VolumeSyncSourceAzureV1", "type": "object" }, - "AuditLogEventApiKeyCreatedV1": { + "VolumeSyncSourceBasetenTrainingV1": { "additionalProperties": false, - "description": "An API key was created.", + "description": "Baseten training artifact source.", "properties": { - "event_type": { - "const": "API_KEY_CREATED", - "title": "Event Type", + "uri": { + "description": "Remote source URI to materialize into the destination volume.", + "title": "Uri", "type": "string" }, - "api_key_id": { - "title": "Api Key Id", - "type": "string" + "include": { + "description": "Glob patterns selecting files to include.", + "items": { + "type": "string" + }, + "title": "Include", + "type": "array" }, - "api_key_type": { - "$ref": "#/components/schemas/AuditLogApiKeyTypeV1" + "exclude": { + "description": "Glob patterns selecting files to exclude.", + "items": { + "type": "string" + }, + "title": "Exclude", + "type": "array" }, - "prefix": { - "title": "Prefix", + "type": { + "const": "BASETEN_TRAINING", + "description": "Baseten training artifact source type.", + "title": "Type", "type": "string" } }, "required": [ - "event_type", - "api_key_id", - "api_key_type", - "prefix" + "uri", + "type" ], - "title": "AuditLogEventApiKeyCreatedV1", + "title": "VolumeSyncSourceBasetenTrainingV1", "type": "object" }, - "AuditLogEventApiKeyDeletedV1": { + "VolumeSyncSourceCoreWeaveV1": { "additionalProperties": false, - "description": "An API key was revoked.", + "description": "CoreWeave object storage source.", "properties": { - "event_type": { - "const": "API_KEY_DELETED", - "title": "Event Type", + "uri": { + "description": "Remote source URI to materialize into the destination volume.", + "title": "Uri", "type": "string" }, - "api_key_id": { - "title": "Api Key Id", - "type": "string" + "include": { + "description": "Glob patterns selecting files to include.", + "items": { + "type": "string" + }, + "title": "Include", + "type": "array" }, - "api_key_type": { - "$ref": "#/components/schemas/AuditLogApiKeyTypeV1" + "exclude": { + "description": "Glob patterns selecting files to exclude.", + "items": { + "type": "string" + }, + "title": "Exclude", + "type": "array" }, - "prefix": { - "title": "Prefix", + "auth_secret_name": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional workspace secret containing credentials for this source.", + "title": "Auth Secret Name" + }, + "type": { + "const": "COREWEAVE", + "description": "CoreWeave object storage source type.", + "title": "Type", "type": "string" } }, "required": [ - "event_type", - "api_key_id", - "api_key_type", - "prefix" + "uri", + "type" ], - "title": "AuditLogEventApiKeyDeletedV1", + "title": "VolumeSyncSourceCoreWeaveV1", "type": "object" }, - "AuditLogEventAutoscalingScheduleActionV1": { - "description": "What an autoscaling change did to one schedule.", - "enum": [ - "CREATED", - "UPDATED", - "DELETED", - "UNCHANGED" - ], - "title": "AuditLogEventAutoscalingScheduleActionV1", - "type": "string" - }, - "AuditLogEventAutoscalingScheduleChangeV1": { + "VolumeSyncSourceGCSV1": { "additionalProperties": false, - "description": "What an autoscaling change did to one schedule, and the schedule on either side of it.\n`previous` is null on a create, `current` on a delete, and an unchanged schedule carries only\n`current`. Not itself a payload in the discriminated union.", + "description": "Google Cloud Storage source.", "properties": { - "action": { - "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleActionV1" - }, - "schedule_id": { - "title": "Schedule Id", + "uri": { + "description": "Remote source URI to materialize into the destination volume.", + "title": "Uri", "type": "string" }, - "previous": { + "include": { + "description": "Glob patterns selecting files to include.", + "items": { + "type": "string" + }, + "title": "Include", + "type": "array" + }, + "exclude": { + "description": "Glob patterns selecting files to exclude.", + "items": { + "type": "string" + }, + "title": "Exclude", + "type": "array" + }, + "auth_secret_name": { "anyOf": [ { - "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleSettingsV1" + "minLength": 1, + "type": "string" }, { "type": "null" } - ] + ], + "default": null, + "description": "Optional workspace secret containing credentials for this source.", + "title": "Auth Secret Name" }, - "current": { + "type": { + "const": "GCS", + "description": "Google Cloud Storage source type.", + "title": "Type", + "type": "string" + }, + "gcp_oidc": { "anyOf": [ { - "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleSettingsV1" + "$ref": "#/components/schemas/VolumeSyncAuthenticationGCPOIDCV1" }, { "type": "null" } - ] + ], + "default": null, + "description": "GCP OIDC authentication for this source. Cannot be combined with auth_secret_name." } }, "required": [ - "action", - "schedule_id", - "previous", - "current" + "uri", + "type" ], - "title": "AuditLogEventAutoscalingScheduleChangeV1", + "title": "VolumeSyncSourceGCSV1", "type": "object" }, - "AuditLogEventAutoscalingScheduleSettingsV1": { + "VolumeSyncSourceHuggingFaceV1": { "additionalProperties": false, - "description": "One autoscaling schedule's timing and autoscaling settings. Not itself a union payload.", + "description": "Hugging Face source.", "properties": { - "min_replica": { - "title": "Min Replica", - "type": "integer" + "uri": { + "description": "Remote source URI to materialize into the destination volume.", + "title": "Uri", + "type": "string" }, - "max_replica": { - "title": "Max Replica", - "type": "integer" + "include": { + "description": "Glob patterns selecting files to include.", + "items": { + "type": "string" + }, + "title": "Include", + "type": "array" }, - "concurrency_target": { + "exclude": { + "description": "Glob patterns selecting files to exclude.", + "items": { + "type": "string" + }, + "title": "Exclude", + "type": "array" + }, + "auth_secret_name": { "anyOf": [ { - "type": "integer" + "minLength": 1, + "type": "string" }, { "type": "null" } ], - "title": "Concurrency Target" + "default": null, + "description": "Optional workspace secret containing credentials for this source.", + "title": "Auth Secret Name" }, - "autoscaling_window": { + "type": { + "const": "HUGGING_FACE", + "description": "Hugging Face source type.", + "title": "Type", + "type": "string" + } + }, + "required": [ + "uri", + "type" + ], + "title": "VolumeSyncSourceHuggingFaceV1", + "type": "object" + }, + "VolumeSyncSourceR2V1": { + "additionalProperties": false, + "description": "Cloudflare R2 source.", + "properties": { + "uri": { + "description": "Remote source URI to materialize into the destination volume.", + "title": "Uri", + "type": "string" + }, + "include": { + "description": "Glob patterns selecting files to include.", + "items": { + "type": "string" + }, + "title": "Include", + "type": "array" + }, + "exclude": { + "description": "Glob patterns selecting files to exclude.", + "items": { + "type": "string" + }, + "title": "Exclude", + "type": "array" + }, + "auth_secret_name": { "anyOf": [ { - "type": "integer" + "minLength": 1, + "type": "string" }, { "type": "null" } ], - "title": "Autoscaling Window" + "default": null, + "description": "Optional workspace secret containing credentials for this source.", + "title": "Auth Secret Name" }, - "scale_down_delay": { + "type": { + "const": "R2", + "description": "Cloudflare R2 source type.", + "title": "Type", + "type": "string" + } + }, + "required": [ + "uri", + "type" + ], + "title": "VolumeSyncSourceR2V1", + "type": "object" + }, + "VolumeSyncSourceS3V1": { + "additionalProperties": false, + "description": "Amazon S3 source.", + "properties": { + "uri": { + "description": "Remote source URI to materialize into the destination volume.", + "title": "Uri", + "type": "string" + }, + "include": { + "description": "Glob patterns selecting files to include.", + "items": { + "type": "string" + }, + "title": "Include", + "type": "array" + }, + "exclude": { + "description": "Glob patterns selecting files to exclude.", + "items": { + "type": "string" + }, + "title": "Exclude", + "type": "array" + }, + "auth_secret_name": { "anyOf": [ { - "type": "integer" + "minLength": 1, + "type": "string" }, { "type": "null" } ], - "title": "Scale Down Delay" + "default": null, + "description": "Optional workspace secret containing credentials for this source.", + "title": "Auth Secret Name" }, - "target_utilization_percentage": { + "type": { + "const": "S3", + "description": "Amazon S3 source type.", + "title": "Type", + "type": "string" + }, + "aws_assume_role": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/VolumeSyncAuthenticationAWSAssumeRoleV1" }, { "type": "null" } ], - "title": "Target Utilization Percentage" + "default": null, + "description": "AWS AssumeRole authentication for this source. Cannot be combined with auth_secret_name." }, - "target_in_flight_tokens": { + "aws_oidc": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/VolumeSyncAuthenticationAWSOIDCV1" }, { "type": "null" } ], - "title": "Target In Flight Tokens" + "default": null, + "description": "AWS OIDC authentication for this source. Cannot be combined with other authentication fields." + } + }, + "required": [ + "uri", + "type" + ], + "title": "VolumeSyncSourceS3V1", + "type": "object" + }, + "VolumeSyncStatusV1": { + "enum": [ + "PENDING", + "SYNCING", + "READY", + "FAILED", + "CANCELED" + ], + "title": "VolumeSyncStatusV1", + "type": "string" + }, + "VolumeSyncV1": { + "description": "Current state and result of a volume sync.", + "properties": { + "sync_id": { + "description": "Identifier of this sync operation.", + "title": "Sync Id", + "type": "string" }, - "max_scale_down_rate": { - "anyOf": [ + "status": { + "$ref": "#/components/schemas/VolumeSyncStatusV1", + "description": "Current lifecycle state of the sync." + }, + "source": { + "description": "Remote source being synced.", + "discriminator": { + "mapping": { + "AZURE": "#/components/schemas/VolumeSyncSourceAzureV1", + "BASETEN_TRAINING": "#/components/schemas/VolumeSyncSourceBasetenTrainingV1", + "COREWEAVE": "#/components/schemas/VolumeSyncSourceCoreWeaveV1", + "GCS": "#/components/schemas/VolumeSyncSourceGCSV1", + "HUGGING_FACE": "#/components/schemas/VolumeSyncSourceHuggingFaceV1", + "R2": "#/components/schemas/VolumeSyncSourceR2V1", + "S3": "#/components/schemas/VolumeSyncSourceS3V1" + }, + "propertyName": "type" + }, + "oneOf": [ { - "type": "number" + "$ref": "#/components/schemas/VolumeSyncSourceHuggingFaceV1" }, { - "type": "null" + "$ref": "#/components/schemas/VolumeSyncSourceS3V1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceGCSV1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceAzureV1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceR2V1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceCoreWeaveV1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceBasetenTrainingV1" } ], - "title": "Max Scale Down Rate" - }, - "schedule_name": { - "title": "Schedule Name", - "type": "string" - }, - "enabled": { - "title": "Enabled", - "type": "boolean" - }, - "cadence": { - "title": "Cadence", - "type": "string" + "title": "Source" }, - "timezone": { - "title": "Timezone", - "type": "string" + "destination": { + "$ref": "#/components/schemas/VolumeSyncDestinationV1", + "description": "BDN volume being populated." }, - "weekdays": { + "volume_version_id": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "string" }, { "type": "null" } ], - "title": "Weekdays" + "default": null, + "description": "Produced artifact identifier; null until the sync is ready.", + "title": "Volume Version Id" }, - "start_hour": { + "version_ref": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Start Hour" + "default": null, + "description": "Immutable BDN reference; null until the sync is ready.", + "title": "Version Ref" }, - "start_minute": { + "content_digest": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Start Minute" + "default": null, + "description": "BLAKE3 digest of the synced content; null until available.", + "title": "Content Digest" }, - "end_hour": { + "total_size_bytes": { "anyOf": [ { "type": "integer" @@ -11669,22 +12560,20 @@ "type": "null" } ], - "title": "End Hour" + "default": null, + "description": "Total size of the synced content in bytes; null until available.", + "title": "Total Size Bytes" }, - "end_minute": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "End Minute" + "created_at": { + "description": "Time at which the sync was created.", + "format": "date-time", + "title": "Created At", + "type": "string" }, - "start_at": { + "completed_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { @@ -11692,526 +12581,490 @@ } ], "default": null, - "title": "Start At" + "description": "Time at which the sync reached a terminal state.", + "title": "Completed At" }, - "end_at": { + "error": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/VolumeSyncErrorV1" }, { "type": "null" } ], "default": null, - "title": "End At" + "description": "Redacted failure details; null unless the sync failed." } }, "required": [ - "min_replica", - "max_replica", - "concurrency_target", - "autoscaling_window", - "scale_down_delay", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate", - "schedule_name", - "enabled", - "cadence", - "timezone", - "weekdays", - "start_hour", - "start_minute", - "end_hour", - "end_minute" + "sync_id", + "status", + "source", + "destination", + "created_at" ], - "title": "AuditLogEventAutoscalingScheduleSettingsV1", + "title": "VolumeSyncV1", "type": "object" }, - "AuditLogEventAutoscalingSettingsV1": { - "additionalProperties": false, - "description": "Autoscaling settings for a deployment or environment.", + "VolumeSyncsV1": { + "description": "A page of volume syncs in the active workspace.", "properties": { - "min_replica": { - "title": "Min Replica", - "type": "integer" - }, - "max_replica": { - "title": "Max Replica", - "type": "integer" - }, - "concurrency_target": { - "title": "Concurrency Target", - "type": "integer" + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/VolumeSyncV1" + }, + "title": "Items", + "type": "array" }, - "autoscaling_window": { + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "VolumeSyncsV1", + "type": "object" + }, + "VolumeSyncsRequestV1": { + "description": "Filters and pagination for listing volume syncs in the active workspace.", + "properties": { + "cursor": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Autoscaling Window" + "default": null, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "scale_down_delay": { + "limit": { + "default": 100, + "description": "Maximum number of items to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + }, + "ref": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Scale Down Delay" - }, - "target_utilization_percentage": { - "anyOf": [ + "default": null, + "description": "Exact destination reference to match.", + "title": "Ref" + } + }, + "title": "VolumeSyncsRequestV1", + "type": "object" + }, + "CreateVolumeSyncRequestV1": { + "additionalProperties": false, + "description": "Request to start an asynchronous volume sync.", + "properties": { + "source": { + "description": "Remote source to sync from.", + "discriminator": { + "mapping": { + "AZURE": "#/components/schemas/VolumeSyncSourceAzureV1", + "BASETEN_TRAINING": "#/components/schemas/VolumeSyncSourceBasetenTrainingV1", + "COREWEAVE": "#/components/schemas/VolumeSyncSourceCoreWeaveV1", + "GCS": "#/components/schemas/VolumeSyncSourceGCSV1", + "HUGGING_FACE": "#/components/schemas/VolumeSyncSourceHuggingFaceV1", + "R2": "#/components/schemas/VolumeSyncSourceR2V1", + "S3": "#/components/schemas/VolumeSyncSourceS3V1" + }, + "propertyName": "type" + }, + "oneOf": [ { - "type": "integer" + "$ref": "#/components/schemas/VolumeSyncSourceHuggingFaceV1" }, { - "type": "null" - } - ], - "title": "Target Utilization Percentage" - }, - "target_in_flight_tokens": { - "anyOf": [ + "$ref": "#/components/schemas/VolumeSyncSourceS3V1" + }, { - "type": "integer" + "$ref": "#/components/schemas/VolumeSyncSourceGCSV1" }, { - "type": "null" + "$ref": "#/components/schemas/VolumeSyncSourceAzureV1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceR2V1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceCoreWeaveV1" + }, + { + "$ref": "#/components/schemas/VolumeSyncSourceBasetenTrainingV1" } ], - "title": "Target In Flight Tokens" + "title": "Source" }, - "max_scale_down_rate": { + "destination": { + "$ref": "#/components/schemas/VolumeSyncDestinationV1", + "description": "BDN volume to sync into." + } + }, + "required": [ + "source", + "destination" + ], + "title": "CreateVolumeSyncRequestV1", + "type": "object" + }, + "DeleteVolumeRequestV1": { + "properties": { + "expected_sequence": { "anyOf": [ { - "type": "number" + "type": "integer" }, { "type": "null" } ], - "title": "Max Scale Down Rate" + "default": null, + "description": "Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so it cannot act on a volume someone else has pushed to. Take the value from a volume's sequence, or from volume_sequence.", + "title": "Expected Sequence" } }, - "required": [ - "min_replica", - "max_replica", - "concurrency_target", - "autoscaling_window", - "scale_down_delay", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate" - ], - "title": "AuditLogEventAutoscalingSettingsV1", + "title": "DeleteVolumeRequestV1", "type": "object" }, - "AuditLogEventChainDeletedV1": { - "additionalProperties": false, - "description": "A chain was deleted.", + "DeleteVolumeResponseV1": { "properties": { - "event_type": { - "const": "CHAIN_DELETED", - "title": "Event Type", + "namespace": { + "description": "Namespace the volume belongs to, in lowercase.", + "title": "Namespace", "type": "string" }, - "chain_id": { - "title": "Chain Id", + "name": { + "description": "Name of the volume, in lowercase.", + "title": "Name", "type": "string" }, - "chain_name": { - "title": "Chain Name", - "type": "string" + "versions_deleted": { + "description": "Number of versions this request deleted. Zero when the volume had no live versions left, which is not an error.", + "title": "Versions Deleted", + "type": "integer" }, - "chain_deployment_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Chain Deployment Name" + "volume_sequence": { + "description": "Revision of the volume after the delete.", + "title": "Volume Sequence", + "type": "integer" } }, "required": [ - "event_type", - "chain_id", - "chain_name", - "chain_deployment_name" + "namespace", + "name", + "versions_deleted", + "volume_sequence" ], - "title": "AuditLogEventChainDeletedV1", + "title": "DeleteVolumeResponseV1", "type": "object" }, - "AuditLogEventChainDeployedV1": { - "additionalProperties": false, - "description": "A chain deployment was created.", + "VolumeVersionV1": { "properties": { - "event_type": { - "const": "CHAIN_DEPLOYED", - "title": "Event Type", + "namespace": { + "description": "Namespace the volume belongs to, in lowercase.", + "title": "Namespace", "type": "string" }, - "chain_id": { - "title": "Chain Id", + "volume": { + "description": "Name of the volume, in lowercase.", + "title": "Volume", "type": "string" }, - "chain_name": { - "title": "Chain Name", + "version_ref": { + "description": "Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", + "title": "Version Ref", "type": "string" }, - "chain_deployment_id": { - "title": "Chain Deployment Id", + "digest": { + "description": "Content digest of the version, as `b3:`.", + "title": "Digest", "type": "string" }, - "chain_deployment_name": { + "sequence": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "title": "Chain Deployment Name" + "description": "Revision the version was committed at. Null for versions committed before the volume service recorded it.", + "title": "Sequence" }, - "is_primary": { - "title": "Is Primary", - "type": "boolean" + "lifecycle": { + "description": "Lifecycle state of the version: ALIVE, or TOMBSTONED once it has been deleted or has expired.", + "title": "Lifecycle", + "type": "string" }, - "publish": { - "title": "Publish", + "is_head": { + "description": "Whether the reserved `head` tag points at this version.", + "title": "Is Head", "type": "boolean" - } - }, - "required": [ - "event_type", - "chain_id", - "chain_name", - "chain_deployment_id", - "chain_deployment_name", - "is_primary", - "publish" - ], - "title": "AuditLogEventChainDeployedV1", - "type": "object" - }, - "AuditLogEventChainDeploymentActivatedV1": { - "additionalProperties": false, - "description": "A chain deployment was activated.", - "properties": { - "event_type": { - "const": "CHAIN_DEPLOYMENT_ACTIVATED", - "title": "Event Type", - "type": "string" - }, - "chain_id": { - "title": "Chain Id", - "type": "string" - }, - "chain_name": { - "title": "Chain Name", - "type": "string" - }, - "chain_deployment_id": { - "title": "Chain Deployment Id", - "type": "string" - }, - "chain_deployment_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Chain Deployment Name" - } - }, - "required": [ - "event_type", - "chain_id", - "chain_name", - "chain_deployment_id", - "chain_deployment_name" - ], - "title": "AuditLogEventChainDeploymentActivatedV1", - "type": "object" - }, - "AuditLogEventChainDeploymentDeactivatedV1": { - "additionalProperties": false, - "description": "A chain deployment was deactivated.", - "properties": { - "event_type": { - "const": "CHAIN_DEPLOYMENT_DEACTIVATED", - "title": "Event Type", - "type": "string" - }, - "chain_id": { - "title": "Chain Id", - "type": "string" - }, - "chain_name": { - "title": "Chain Name", - "type": "string" }, - "chain_deployment_id": { - "title": "Chain Deployment Id", - "type": "string" + "tags": { + "description": "Tags pointing at this version that your API key can read.", + "items": { + "type": "string" + }, + "title": "Tags", + "type": "array" }, - "chain_deployment_name": { + "total_size_bytes": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "title": "Chain Deployment Name" - } - }, - "required": [ - "event_type", - "chain_id", - "chain_name", - "chain_deployment_id", - "chain_deployment_name" - ], - "title": "AuditLogEventChainDeploymentDeactivatedV1", - "type": "object" - }, - "AuditLogEventChainDeploymentDeletedV1": { - "additionalProperties": false, - "description": "A chain deployment was deleted.", - "properties": { - "event_type": { - "const": "CHAIN_DEPLOYMENT_DELETED", - "title": "Event Type", - "type": "string" - }, - "chain_id": { - "title": "Chain Id", - "type": "string" - }, - "chain_name": { - "title": "Chain Name", - "type": "string" + "description": "Total size of the version's files in bytes. Null when not recorded.", + "title": "Total Size Bytes" }, - "chain_deployment_id": { - "title": "Chain Deployment Id", + "created_at": { + "description": "When the version was committed, in ISO 8601 format.", + "format": "date-time", + "title": "Created At", "type": "string" }, - "deployment_name": { + "expires_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { "type": "null" } ], - "title": "Deployment Name" - } - }, - "required": [ - "event_type", - "chain_id", - "chain_name", - "chain_deployment_id", - "deployment_name" - ], - "title": "AuditLogEventChainDeploymentDeletedV1", - "type": "object" - }, - "AuditLogEventChainDeploymentPromotedV1": { - "additionalProperties": false, - "description": "A chain deployment was promoted to an environment.", - "properties": { - "event_type": { - "const": "CHAIN_DEPLOYMENT_PROMOTED", - "title": "Event Type", - "type": "string" - }, - "chain_id": { - "title": "Chain Id", - "type": "string" - }, - "chain_name": { - "title": "Chain Name", - "type": "string" - }, - "chain_deployment_id": { - "title": "Chain Deployment Id", - "type": "string" + "description": "When the version expires, in ISO 8601 format. At that instant it becomes TOMBSTONED with `tombstoned_at` set to this value, and every tag pointing at it drops. Null for a version that never expires, and null once the lifecycle is TOMBSTONED.", + "title": "Expires At" }, - "chain_deployment_name": { + "tombstoned_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { "type": "null" } ], - "title": "Chain Deployment Name" + "description": "When the version was deleted or expired, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + "title": "Tombstoned At" }, - "environment_name": { + "delete_after": { "anyOf": [ { + "format": "date-time", "type": "string" }, { "type": "null" } ], - "title": "Environment Name" + "description": "When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + "title": "Delete After" + } + }, + "required": [ + "namespace", + "volume", + "version_ref", + "digest", + "sequence", + "lifecycle", + "is_head", + "tags", + "total_size_bytes", + "created_at", + "expires_at", + "tombstoned_at", + "delete_after" + ], + "title": "VolumeVersionV1", + "type": "object" + }, + "ListVolumeVersionsResponseV1": { + "description": "Every version of a volume, newest first.\n\nUnpaginated: `limit` and `cursor` are absent rather than accepted and\nignored, so adding them once the volume service pages this listing is a\npurely additive change.", + "properties": { + "versions": { + "description": "Versions of the volume, newest first.", + "items": { + "$ref": "#/components/schemas/VolumeVersionV1" + }, + "title": "Versions", + "type": "array" }, - "environment_id": { + "volume_sequence": { + "description": "Revision of the volume as a whole when the versions were read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since. Distinct from the per-version sequence, which is the revision a version was committed at.", + "title": "Volume Sequence", + "type": "integer" + } + }, + "required": [ + "versions", + "volume_sequence" + ], + "title": "ListVolumeVersionsResponseV1", + "type": "object" + }, + "ListVolumeVersionsRequestV1": { + "properties": { + "include_tombstoned": { + "default": false, + "description": "Whether to include deleted and expired versions. Such a version carries a TOMBSTONED lifecycle and stays restorable until its recovery deadline passes.", + "title": "Include Tombstoned", + "type": "boolean" + } + }, + "title": "ListVolumeVersionsRequestV1", + "type": "object" + }, + "DeleteVolumeVersionRequestV1": { + "properties": { + "expected_sequence": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "title": "Environment Id" + "default": null, + "description": "Revision the volume is expected to be at. When set, the delete fails with a conflict if the volume has changed since, so a read followed by a delete cannot act on a version a tag has since been moved off. Take the value from volume_sequence.", + "title": "Expected Sequence" } }, - "required": [ - "event_type", - "chain_id", - "chain_name", - "chain_deployment_id", - "chain_deployment_name", - "environment_name", - "environment_id" - ], - "title": "AuditLogEventChainDeploymentPromotedV1", + "title": "DeleteVolumeVersionRequestV1", "type": "object" }, - "AuditLogEventChainEnvironmentCreatedV1": { - "additionalProperties": false, - "description": "A chain environment was created.", + "DeleteVolumeVersionResponseV1": { "properties": { - "event_type": { - "const": "CHAIN_ENVIRONMENT_CREATED", - "title": "Event Type", + "namespace": { + "description": "Namespace the volume belongs to, in lowercase.", + "title": "Namespace", "type": "string" }, - "chain_id": { - "title": "Chain Id", + "volume": { + "description": "Name of the volume, in lowercase.", + "title": "Volume", "type": "string" }, - "chain_name": { - "title": "Chain Name", + "version_ref": { + "description": "Full address of the deleted version, as `bdn:/@`.", + "title": "Version Ref", "type": "string" }, - "environment_name": { - "title": "Environment Name", + "digest": { + "description": "Content digest of the deleted version, as `b3:`.", + "title": "Digest", "type": "string" }, - "redeploy_on_promotion": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Redeploy On Promotion" + "lifecycle": { + "description": "Lifecycle state of the version after the delete.", + "title": "Lifecycle", + "type": "string" }, - "ramp_up_while_promoting": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Ramp Up While Promoting" + "delete_after": { + "description": "When the version stops being restorable, in ISO 8601 format. Until then it can be returned to service.", + "format": "date-time", + "title": "Delete After", + "type": "string" }, - "ramp_up_duration_seconds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Ramp Up Duration Seconds" + "volume_sequence": { + "description": "Revision of the volume after the delete.", + "title": "Volume Sequence", + "type": "integer" } }, "required": [ - "event_type", - "chain_id", - "chain_name", - "environment_name", - "redeploy_on_promotion", - "ramp_up_while_promoting", - "ramp_up_duration_seconds" + "namespace", + "volume", + "version_ref", + "digest", + "lifecycle", + "delete_after", + "volume_sequence" ], - "title": "AuditLogEventChainEnvironmentCreatedV1", + "title": "DeleteVolumeVersionResponseV1", "type": "object" }, - "AuditLogEventChainEnvironmentUpdatedV1": { - "additionalProperties": false, - "description": "A chain environment was updated.", + "VolumeVersionDetailV1": { + "description": "One version, with the fields only a single-version read reports.", "properties": { - "event_type": { - "const": "CHAIN_ENVIRONMENT_UPDATED", - "title": "Event Type", + "namespace": { + "description": "Namespace the volume belongs to, in lowercase.", + "title": "Namespace", "type": "string" }, - "chain_id": { - "title": "Chain Id", + "volume": { + "description": "Name of the volume, in lowercase.", + "title": "Volume", "type": "string" }, - "chain_name": { - "title": "Chain Name", + "version_ref": { + "description": "Full address of this version, as `bdn:/@`. Paste this into the `bdn.mounts` section of a config.yaml to pin to it.", + "title": "Version Ref", "type": "string" }, - "environment_name": { - "title": "Environment Name", + "digest": { + "description": "Content digest of the version, as `b3:`.", + "title": "Digest", "type": "string" }, - "redeploy_on_promotion": { + "sequence": { "anyOf": [ { - "type": "boolean" + "type": "integer" }, { "type": "null" } ], - "title": "Redeploy On Promotion" + "description": "Revision the version was committed at. Null for versions committed before the volume service recorded it.", + "title": "Sequence" }, - "ramp_up_while_promoting": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Ramp Up While Promoting" + "lifecycle": { + "description": "Lifecycle state of the version: ALIVE, or TOMBSTONED once it has been deleted or has expired.", + "title": "Lifecycle", + "type": "string" }, - "ramp_up_duration_seconds": { + "is_head": { + "description": "Whether the reserved `head` tag points at this version.", + "title": "Is Head", + "type": "boolean" + }, + "tags": { + "description": "Tags pointing at this version that your API key can read.", + "items": { + "type": "string" + }, + "title": "Tags", + "type": "array" + }, + "total_size_bytes": { "anyOf": [ { "type": "integer" @@ -12220,71 +13073,55 @@ "type": "null" } ], - "title": "Ramp Up Duration Seconds" - } - }, - "required": [ - "event_type", - "chain_id", - "chain_name", - "environment_name", - "redeploy_on_promotion", - "ramp_up_while_promoting", - "ramp_up_duration_seconds" - ], - "title": "AuditLogEventChainEnvironmentUpdatedV1", - "type": "object" - }, - "AuditLogEventChainletAutoscalingSettingsChangedV1": { - "additionalProperties": false, - "description": "A chainlet's autoscaling settings were changed.", - "properties": { - "min_replica": { - "title": "Min Replica", - "type": "integer" - }, - "max_replica": { - "title": "Max Replica", - "type": "integer" + "description": "Total size of the version's files in bytes. Null when not recorded.", + "title": "Total Size Bytes" }, - "concurrency_target": { - "title": "Concurrency Target", - "type": "integer" + "created_at": { + "description": "When the version was committed, in ISO 8601 format.", + "format": "date-time", + "title": "Created At", + "type": "string" }, - "autoscaling_window": { + "expires_at": { "anyOf": [ { - "type": "integer" + "format": "date-time", + "type": "string" }, { "type": "null" } ], - "title": "Autoscaling Window" + "description": "When the version expires, in ISO 8601 format. At that instant it becomes TOMBSTONED with `tombstoned_at` set to this value, and every tag pointing at it drops. Null for a version that never expires, and null once the lifecycle is TOMBSTONED.", + "title": "Expires At" }, - "scale_down_delay": { + "tombstoned_at": { "anyOf": [ { - "type": "integer" + "format": "date-time", + "type": "string" }, { "type": "null" } ], - "title": "Scale Down Delay" + "description": "When the version was deleted or expired, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + "title": "Tombstoned At" }, - "target_utilization_percentage": { + "delete_after": { "anyOf": [ { - "type": "integer" + "format": "date-time", + "type": "string" }, { "type": "null" } ], - "title": "Target Utilization Percentage" + "description": "When the version stops being restorable, in ISO 8601 format. Null unless the lifecycle is TOMBSTONED.", + "title": "Delete After" }, - "target_in_flight_tokens": { + "entry_count": { "anyOf": [ { "type": "integer" @@ -12293,167 +13130,278 @@ "type": "null" } ], - "title": "Target In Flight Tokens" + "description": "Number of files in the version. Null when not recorded.", + "title": "Entry Count" }, - "max_scale_down_rate": { + "volume_sequence": { + "description": "Revision of the volume as a whole when this version was read. Pass it as expected_sequence on a later delete to make that delete conditional on the volume not having changed since.", + "title": "Volume Sequence", + "type": "integer" + } + }, + "required": [ + "namespace", + "volume", + "version_ref", + "digest", + "sequence", + "lifecycle", + "is_head", + "tags", + "total_size_bytes", + "created_at", + "expires_at", + "tombstoned_at", + "delete_after", + "entry_count", + "volume_sequence" + ], + "title": "VolumeVersionDetailV1", + "type": "object" + }, + "RestoreVolumeVersionRequestV1": { + "properties": { + "expected_sequence": { "anyOf": [ { - "type": "number" + "type": "integer" }, { "type": "null" } ], - "title": "Max Scale Down Rate" + "default": null, + "description": "Revision the volume is expected to be at. When set, the restore fails with a conflict if the volume has changed since. Take the value from volume_sequence.", + "title": "Expected Sequence" + } + }, + "title": "RestoreVolumeVersionRequestV1", + "type": "object" + }, + "RestoreVolumeVersionResponseV1": { + "properties": { + "namespace": { + "description": "Namespace the volume belongs to, in lowercase.", + "title": "Namespace", + "type": "string" }, - "event_type": { - "const": "CHAINLET_AUTOSCALING_SETTINGS_CHANGED", - "title": "Event Type", + "volume": { + "description": "Name of the volume, in lowercase.", + "title": "Volume", "type": "string" }, - "chain_id": { - "title": "Chain Id", + "version_ref": { + "description": "Full address of the restored version, as `bdn:/@`.", + "title": "Version Ref", "type": "string" }, - "chain_name": { - "title": "Chain Name", + "digest": { + "description": "Content digest of the restored version, as `b3:`.", + "title": "Digest", "type": "string" }, - "chain_deployment_id": { - "title": "Chain Deployment Id", + "lifecycle": { + "description": "Lifecycle state of the version after the restore.", + "title": "Lifecycle", "type": "string" }, - "chain_deployment_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + "volume_sequence": { + "description": "Revision of the volume after the restore.", + "title": "Volume Sequence", + "type": "integer" + } + }, + "required": [ + "namespace", + "volume", + "version_ref", + "digest", + "lifecycle", + "volume_sequence" + ], + "title": "RestoreVolumeVersionResponseV1", + "type": "object" + }, + "TokenScopeV1": { + "description": "What a token minted by POST /v1/token grants access to.", + "enum": [ + "sandboxes" + ], + "title": "TokenScopeV1", + "type": "string" + }, + "CreateTokenRequestV1": { + "properties": { + "scopes": { + "description": "What the token should grant access to. Only `sandboxes` is supported today; the token then authenticates against the sandbox API.", + "examples": [ + [ + "sandboxes" + ] ], - "title": "Chain Deployment Name" - }, - "chainlet_name": { - "title": "Chainlet Name", + "items": { + "$ref": "#/components/schemas/TokenScopeV1" + }, + "minItems": 1, + "title": "Scopes", + "type": "array" + } + }, + "required": [ + "scopes" + ], + "title": "CreateTokenRequestV1", + "type": "object" + }, + "TokenV1": { + "properties": { + "token": { + "description": "Short-lived bearer token for the sandbox API. Send it as Authorization: Bearer .", + "title": "Token", "type": "string" }, - "chainlet_id": { - "title": "Chainlet Id", + "expires_at": { + "description": "Token expiry in ISO 8601 format. Tokens cannot be renewed; request a new one.", + "format": "date-time", + "title": "Expires At", "type": "string" - }, - "previous_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuditLogEventAutoscalingSettingsV1" - }, - { - "type": "null" - } - ] } }, "required": [ - "min_replica", - "max_replica", - "concurrency_target", - "autoscaling_window", - "scale_down_delay", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate", - "event_type", - "chain_id", - "chain_name", - "chain_deployment_id", - "chain_deployment_name", - "chainlet_name", - "chainlet_id", - "previous_settings" + "token", + "expires_at" ], - "title": "AuditLogEventChainletAutoscalingSettingsChangedV1", + "title": "TokenV1", "type": "object" }, - "AuditLogEventChainletInstanceTypeChangedV1": { - "additionalProperties": false, - "description": "A chainlet's instance type was changed.", + "SecretV1": { + "description": "A Baseten secret. Note that we do not support retrieving secret values.", "properties": { - "event_type": { - "const": "CHAINLET_INSTANCE_TYPE_CHANGED", - "title": "Event Type", + "id": { + "description": "Stable identifier for the secret. Unchanged across rotation.", + "examples": [ + "3kZ9xqd" + ], + "title": "Id", "type": "string" }, - "chain_id": { - "title": "Chain Id", + "created_at": { + "description": "Time the secret was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", "type": "string" }, - "chain_name": { - "title": "Chain Name", + "name": { + "description": "Name of the secret", + "title": "Name", "type": "string" }, - "chain_deployment_id": { - "title": "Chain Deployment Id", + "team_name": { + "description": "Name of the team the secret belongs to", + "title": "Team Name", "type": "string" - }, - "chain_deployment_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + } + }, + "required": [ + "id", + "created_at", + "name", + "team_name" + ], + "title": "SecretV1", + "type": "object" + }, + "SecretsV1": { + "description": "A list of Baseten secrets.", + "properties": { + "secrets": { + "items": { + "$ref": "#/components/schemas/SecretV1" + }, + "title": "Secrets", + "type": "array" + } + }, + "required": [ + "secrets" + ], + "title": "SecretsV1", + "type": "object" + }, + "UpsertSecretRequestV1": { + "description": "A request to create or update a Baseten secret by name.", + "properties": { + "name": { + "description": "Name of the new or existing secret", + "examples": [ + "my_secret" ], - "title": "Chain Deployment Name" - }, - "chainlet_name": { - "title": "Chainlet Name", - "type": "string" - }, - "chainlet_id": { - "title": "Chainlet Id", + "title": "Name", "type": "string" }, - "instance_type_name": { - "title": "Instance Type Name", + "value": { + "description": "Value of the secret", + "examples": [ + "my_secret_value" + ], + "title": "Value", "type": "string" } }, "required": [ - "event_type", - "chain_id", - "chain_name", - "chain_deployment_id", - "chain_deployment_name", - "chainlet_name", - "chainlet_id", - "instance_type_name" + "name", + "value" ], - "title": "AuditLogEventChainletInstanceTypeChangedV1", + "title": "UpsertSecretRequestV1", "type": "object" }, - "AuditLogEventDirectoryGroupRoleUpdatedV1": { - "additionalProperties": false, - "description": "A directory group's role was updated.", + "SecretTombstoneV1": { + "description": "A secret tombstone.", "properties": { - "event_type": { - "const": "DIRECTORY_GROUP_ROLE_UPDATED", - "title": "Event Type", - "type": "string" - }, - "directory_group_id": { - "title": "Directory Group Id", - "type": "string" - }, - "directory_group_name": { - "title": "Directory Group Name", + "name": { + "description": "Name of the deleted secret", + "title": "Name", "type": "string" + } + }, + "required": [ + "name" + ], + "title": "SecretTombstoneV1", + "type": "object" + }, + "EnvironmentGroupManageAccessV1": { + "description": "Who is allowed to manage an environment group.", + "properties": { + "is_restricted": { + "description": "Whether the environment is restricted to a specific set of users.", + "title": "Is Restricted", + "type": "boolean" }, - "new_role_name": { - "title": "New Role Name", + "users": { + "description": "Users who can manage the environment while it is restricted, including organization and team admins who always have access. Empty when the environment is unrestricted.", + "items": { + "$ref": "#/components/schemas/EnvironmentGroupUserV1" + }, + "title": "Users", + "type": "array" + } + }, + "required": [ + "is_restricted" + ], + "title": "EnvironmentGroupManageAccessV1", + "type": "object" + }, + "EnvironmentGroupUserV1": { + "description": "A user referenced by an environment group's manage access.", + "properties": { + "user_id": { + "description": "Unique identifier for the user.", + "title": "User Id", "type": "string" }, - "team_id": { + "email": { "anyOf": [ { "type": "string" @@ -12462,9 +13410,11 @@ "type": "null" } ], - "title": "Team Id" - }, - "team_name": { + "default": null, + "description": "Email address of the user.", + "title": "Email" + }, + "name": { "anyOf": [ { "type": "string" @@ -12473,169 +13423,262 @@ "type": "null" } ], - "title": "Team Name" + "default": null, + "description": "Display name of the user.", + "title": "Name" } }, "required": [ - "event_type", - "directory_group_id", - "directory_group_name", - "new_role_name", - "team_id", - "team_name" + "user_id" ], - "title": "AuditLogEventDirectoryGroupRoleUpdatedV1", + "title": "EnvironmentGroupUserV1", "type": "object" }, - "AuditLogEventEnvironmentCreatedV1": { - "additionalProperties": false, - "description": "A model environment was created.", + "EnvironmentGroupV1": { + "description": "A team-scoped grouping of same-named environments (e.g. \"production\", \"staging\").\n\nRestricting an environment group limits who can manage the environment of that name\nacross every model and chain in the team.", "properties": { - "min_replica": { - "title": "Min Replica", - "type": "integer" + "name": { + "description": "Name of the environment group, matching the environment name it governs.", + "examples": [ + "staging" + ], + "title": "Name", + "type": "string" }, - "max_replica": { - "title": "Max Replica", - "type": "integer" + "team_id": { + "description": "Unique identifier of the team the environment group belongs to.", + "title": "Team Id", + "type": "string" }, - "concurrency_target": { - "title": "Concurrency Target", - "type": "integer" + "team_name": { + "description": "Name of the team the environment group belongs to.", + "title": "Team Name", + "type": "string" }, - "autoscaling_window": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Autoscaling Window" + "manage_access": { + "$ref": "#/components/schemas/EnvironmentGroupManageAccessV1", + "description": "Settings controlling who can manage this environment group." + } + }, + "required": [ + "name", + "team_id", + "team_name", + "manage_access" + ], + "title": "EnvironmentGroupV1", + "type": "object" + }, + "EnvironmentGroupsV1": { + "description": "A page of environment groups.", + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/EnvironmentGroupV1" + }, + "title": "Items", + "type": "array" }, - "scale_down_delay": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Scale Down Delay" + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "EnvironmentGroupsV1", + "type": "object" + }, + "UpdateEnvironmentGroupManageAccessV1": { + "description": "Manage-access settings to apply to an environment group.", + "properties": { + "is_restricted": { + "description": "Whether to restrict this environment to a specific set of users.", + "title": "Is Restricted", + "type": "boolean" }, - "target_utilization_percentage": { + "user_ids": { + "description": "IDs of users granted manage access while restricted. Only meaningful when is_restricted is true.", + "items": { + "type": "string" + }, + "title": "User Ids", + "type": "array" + } + }, + "required": [ + "is_restricted" + ], + "title": "UpdateEnvironmentGroupManageAccessV1", + "type": "object" + }, + "UpdateEnvironmentGroupRequestV1": { + "description": "A request to update an existing environment group.", + "properties": { + "manage_access": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/UpdateEnvironmentGroupManageAccessV1" }, { "type": "null" } ], - "title": "Target Utilization Percentage" + "default": null, + "description": "Manage-access settings to apply. Omit to leave manage access unchanged." + } + }, + "title": "UpdateEnvironmentGroupRequestV1", + "type": "object" + }, + "TeamV1": { + "description": "A team.", + "properties": { + "id": { + "description": "Unique identifier of the team", + "title": "Id", + "type": "string" }, - "target_in_flight_tokens": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Target In Flight Tokens" + "name": { + "description": "Name of the team", + "title": "Name", + "type": "string" }, - "max_scale_down_rate": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "title": "Max Scale Down Rate" + "default": { + "type": "boolean", + "description": "Whether this is the default team for the organization", + "title": "Default" }, - "redeploy_on_promotion": { + "created_at": { + "description": "Time the team was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", + "type": "string" + } + }, + "required": [ + "id", + "name", + "default", + "created_at" + ], + "title": "TeamV1", + "type": "object" + }, + "TeamsV1": { + "description": "A list of teams.", + "properties": { + "teams": { + "description": "A list of teams", + "items": { + "$ref": "#/components/schemas/TeamV1" + }, + "title": "Teams", + "type": "array" + } + }, + "required": [ + "teams" + ], + "title": "TeamsV1", + "type": "object" + }, + "TeamsRequestV1": { + "description": "Request parameters for listing teams.", + "properties": { + "name": { "anyOf": [ { - "type": "boolean" + "type": "string" }, { "type": "null" } ], - "title": "Redeploy On Promotion" - }, - "rolling_deploy": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } + "default": null, + "description": "When set, returns only the team with this exact name, if any.", + "title": "Name" + } + }, + "title": "TeamsRequestV1", + "type": "object" + }, + "RegionV1": { + "description": "A region that deployments can be placed in.", + "properties": { + "slug": { + "description": "Stable identifier for the region, used when selecting a deployment region.", + "examples": [ + "us" ], - "title": "Rolling Deploy" + "title": "Slug", + "type": "string" }, - "rolling_deploy_strategy": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + "display_name": { + "description": "Human-readable name of the region.", + "examples": [ + "United States" ], - "title": "Rolling Deploy Strategy" + "title": "Display Name", + "type": "string" + } + }, + "required": [ + "slug", + "display_name" + ], + "title": "RegionV1", + "type": "object" + }, + "RegionsV1": { + "description": "A list of regions.", + "properties": { + "regions": { + "items": { + "$ref": "#/components/schemas/RegionV1" + }, + "title": "Regions", + "type": "array" + } + }, + "required": [ + "regions" + ], + "title": "RegionsV1", + "type": "object" + }, + "InstanceTypeV1": { + "description": "An instance type.", + "properties": { + "id": { + "description": "Identifier string for the instance type", + "title": "Id", + "type": "string" }, - "max_unavailable_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Unavailable Percent" + "name": { + "description": "Display name of the instance type", + "title": "Name", + "type": "string" }, - "max_surge_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Surge Percent" + "memory_limit_mib": { + "description": "Memory limit of the instance type in Mebibytes", + "title": "Memory Limit Mib", + "type": "integer" }, - "stabilization_time_seconds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Stabilization Time Seconds" + "millicpu_limit": { + "description": "CPU limit of the instance type in millicpu", + "title": "Millicpu Limit", + "type": "integer" }, - "replica_overhead_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Replica Overhead Percent" + "gpu_count": { + "description": "Number of GPUs on the instance type", + "title": "Gpu Count", + "type": "integer" }, - "promotion_cleanup_strategy": { + "gpu_type": { "anyOf": [ { "type": "string" @@ -12644,236 +13687,309 @@ "type": "null" } ], - "title": "Promotion Cleanup Strategy" + "description": "Type of GPU on the instance type", + "title": "Gpu Type" }, - "ramp_up_while_promoting": { + "gpu_memory_limit_mib": { "anyOf": [ { - "type": "boolean" + "type": "integer" }, { "type": "null" } ], - "title": "Ramp Up While Promoting" - }, - "ramp_up_duration_seconds": { + "description": "Memory limit of the GPU on the instance type in Mebibytes", + "title": "Gpu Memory Limit Mib" + } + }, + "required": [ + "id", + "name", + "memory_limit_mib", + "millicpu_limit", + "gpu_count", + "gpu_type", + "gpu_memory_limit_mib" + ], + "title": "InstanceTypeV1", + "type": "object" + }, + "InstanceTypesV1": { + "description": "A list of instance types.", + "properties": { + "instance_types": { + "items": { + "$ref": "#/components/schemas/InstanceTypeV1" + }, + "title": "Instance Types", + "type": "array" + } + }, + "required": [ + "instance_types" + ], + "title": "InstanceTypesV1", + "type": "object" + }, + "LoopsUserConfigV1": { + "description": "The caller's Loops user-level config (accelerator priorities).", + "properties": { + "trainer_accelerator_priority": { "anyOf": [ { - "type": "integer" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "title": "Ramp Up Duration Seconds" + "description": "Ordered allowlist of GPU types for your Loops trainer deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", + "examples": [ + [ + "H100", + "H200" + ] + ], + "title": "Trainer Accelerator Priority" }, - "ramp_up_step_size": { + "sampler_accelerator_priority": { "anyOf": [ { - "type": "integer" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "title": "Ramp Up Step Size" - }, - "request_backpressure_policy": { + "description": "Ordered allowlist of GPU types for your Loops sampler deployments, highest priority first. Intersected with the org-level allowlist (org acts as a ceiling). Null means 'inherit the org-level allowlist'.", + "examples": [ + [ + "H100", + "H200" + ] + ], + "title": "Sampler Accelerator Priority" + } + }, + "required": [ + "trainer_accelerator_priority", + "sampler_accelerator_priority" + ], + "title": "LoopsUserConfigV1", + "type": "object" + }, + "GetLoopsUserConfigResponseV1": { + "description": "Response for ``GET /v1/loops/user_config``.", + "properties": { + "user_config": { + "$ref": "#/components/schemas/LoopsUserConfigV1", + "description": "The caller's Loops user config." + } + }, + "required": [ + "user_config" + ], + "title": "GetLoopsUserConfigResponseV1", + "type": "object" + }, + "PatchLoopsUserConfigRequestV1": { + "description": "Request body for ``PATCH /v1/loops/user_config``.\n\nFollows JSON Merge Patch (RFC 7396) semantics per field: omit the field\nto leave it unchanged, send ``null`` to clear and inherit the org-level\nallowlist, send a list to set the allowlist. Empty lists are rejected\nbecause the storage layer normalizes ``null`` and ``[]`` identically, so\naccepting both would create two ways to spell the same intent.", + "properties": { + "trainer_accelerator_priority": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "title": "Request Backpressure Policy" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "environment_name": { - "title": "Environment Name", - "type": "string" + "description": "Ordered list of GPU types for trainer deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", + "examples": [ + [ + "H100", + "H200" + ] + ], + "title": "Trainer Accelerator Priority", + "x-null-distinct": true }, - "deployment_type": { + "sampler_accelerator_priority": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "title": "Deployment Type" - }, - "event_type": { - "const": "ENVIRONMENT_CREATED", - "title": "Event Type", - "type": "string" + "default": null, + "description": "Ordered list of GPU types for sampler deployments, highest priority first. Send a list to set; send null to clear (inherit org allowlist); omit to leave unchanged. Empty list is rejected.", + "examples": [ + [ + "H100", + "H200" + ] + ], + "title": "Sampler Accelerator Priority", + "x-null-distinct": true } }, - "required": [ - "min_replica", - "max_replica", - "concurrency_target", - "autoscaling_window", - "scale_down_delay", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate", - "redeploy_on_promotion", - "rolling_deploy", - "rolling_deploy_strategy", - "max_unavailable_percent", - "max_surge_percent", - "stabilization_time_seconds", - "replica_overhead_percent", - "promotion_cleanup_strategy", - "ramp_up_while_promoting", - "ramp_up_duration_seconds", - "ramp_up_step_size", - "model_id", - "model_name", - "environment_name", - "deployment_type", - "event_type" + "title": "PatchLoopsUserConfigRequestV1", + "type": "object" + }, + "PatchLoopsUserConfigResponseV1": { + "description": "Response for ``PATCH /v1/loops/user_config``.", + "properties": { + "user_config": { + "$ref": "#/components/schemas/LoopsUserConfigV1", + "description": "The updated Loops user config." + } + }, + "required": [ + "user_config" ], - "title": "AuditLogEventEnvironmentCreatedV1", + "title": "PatchLoopsUserConfigResponseV1", "type": "object" }, - "AuditLogEventEnvironmentDeletedV1": { - "additionalProperties": false, - "description": "A model environment was deleted.", + "InstanceTypeWithPriceV1": { "properties": { - "event_type": { - "const": "ENVIRONMENT_DELETED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" + "instance_type": { + "$ref": "#/components/schemas/InstanceTypeV1", + "description": "Instance type properties." }, - "environment_name": { - "title": "Environment Name", - "type": "string" + "price": { + "description": "Usage price in USD / minute.", + "title": "Price", + "type": "number" } }, "required": [ - "event_type", - "model_id", - "model_name", - "environment_name" + "instance_type", + "price" ], - "title": "AuditLogEventEnvironmentDeletedV1", + "title": "InstanceTypeWithPriceV1", "type": "object" }, - "AuditLogEventEnvironmentSettingsV1": { - "additionalProperties": false, - "description": "Full environment settings (autoscaling + rolling promotion + deprecated canary);\nshared base for the environment events and the type of their previous_settings\nsnapshots. Not itself a payload in the discriminated union.", + "InstanceTypePricesV1": { + "description": "A list of instance types.", "properties": { - "min_replica": { - "title": "Min Replica", - "type": "integer" - }, - "max_replica": { - "title": "Max Replica", - "type": "integer" - }, - "concurrency_target": { - "title": "Concurrency Target", - "type": "integer" + "instance_types": { + "items": { + "$ref": "#/components/schemas/InstanceTypeWithPriceV1" + }, + "title": "Instance Types", + "type": "array" + } + }, + "required": [ + "instance_types" + ], + "title": "InstanceTypePricesV1", + "type": "object" + }, + "DeploymentArchivePayloadV1": { + "description": "Deployment-level fields for a model-archive push.\n\nShared by every endpoint that creates a deployment from an uploaded archive:\n`POST /v1/prepare_model_upload`, the `model_archive` source on `POST\n/v1/models`, and `POST /v1/models/{model_id}/deployments`.", + "properties": { + "config": { + "additionalProperties": true, + "description": "Parsed model config as a JSON object.", + "title": "Config", + "type": "object" }, - "autoscaling_window": { + "raw_config": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Autoscaling Window" + "default": null, + "description": "Original config.yaml text, persisted as-is on the deployment. Best-effort: invalid raw configs are logged and dropped without failing the request.", + "title": "Raw Config" }, - "scale_down_delay": { + "user_env": { "anyOf": [ { - "type": "integer" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], - "title": "Scale Down Delay" + "default": null, + "description": "Client environment metadata (e.g. client version, Python version). Validated server-side.", + "title": "User Env" }, - "target_utilization_percentage": { + "environment_name": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Target Utilization Percentage" + "default": null, + "description": "Stable environment to push to (e.g. `production`). If unset, the deployment is created without environment selection. Caller must have push permission for the named environment.", + "title": "Environment Name" }, - "target_in_flight_tokens": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Target In Flight Tokens" + "create_environment_if_missing": { + "default": true, + "description": "Create the environment named by `environment_name` if it does not exist yet. If false, a push to an environment that does not exist is rejected. Only meaningful when `environment_name` is set to something other than `production`, which always exists. This field currently defaults to true, but that default will change to false in a future release. Set it explicitly to avoid a behavior change.", + "title": "Create Environment If Missing", + "type": "boolean" }, - "max_scale_down_rate": { + "region": { "anyOf": [ { - "type": "number" + "type": "string" }, { "type": "null" } ], - "title": "Max Scale Down Rate" + "default": null, + "description": "Region in which to deploy the model", + "title": "Region" }, - "redeploy_on_promotion": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Redeploy On Promotion" + "preserve_env_instance_type": { + "default": true, + "description": "Retain the target environment's current instance type rather than the one in `config`. Only meaningful when `environment_name` is set and that environment already exists.", + "title": "Preserve Env Instance Type", + "type": "boolean" }, - "rolling_deploy": { + "deploy_timeout_minutes": { "anyOf": [ { - "type": "boolean" + "type": "integer" }, { "type": "null" } ], - "title": "Rolling Deploy" + "default": null, + "description": "Deploy timeout in minutes; allowed range 10 to 1440. Server default applies if unset.", + "title": "Deploy Timeout Minutes" }, - "rolling_deploy_strategy": { + "deployment_name": { "anyOf": [ { "type": "string" @@ -12882,53 +13998,58 @@ "type": "null" } ], - "title": "Rolling Deploy Strategy" - }, - "max_unavailable_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Unavailable Percent" + "default": null, + "description": "Optional human-readable name for the deployment.", + "title": "Deployment Name" }, - "max_surge_percent": { + "labels": { "anyOf": [ { - "type": "integer" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], - "title": "Max Surge Percent" + "default": null, + "description": "User-provided key-value labels for the deployment.", + "title": "Labels" }, - "stabilization_time_seconds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Stabilization Time Seconds" + "is_development": { + "default": false, + "description": "If true, push as a development deployment: the model's single mutable dev slot, created if absent and overwritten in place otherwise. The following fields must be left at their defaults: `environment_name`, `preserve_env_instance_type`, `deployment_name`.", + "title": "Is Development", + "type": "boolean" + } + }, + "required": [ + "config" + ], + "title": "DeploymentArchivePayloadV1", + "type": "object" + }, + "PrepareModelUploadRequestV1": { + "description": "Body for `POST /v1/prepare_model_upload`.\n\nValidates the same payload the commit endpoint will validate, and on\n`dry_run=false` issues STS upload credentials. Exactly one of `name` or\n`model_id` is required: `name` validates the new-model path (`POST\n/v1/models`); `model_id` validates the add-deployment path (`POST\n/v1/models/{model_id}/deployments`).", + "properties": { + "deployment": { + "$ref": "#/components/schemas/DeploymentArchivePayloadV1", + "description": "Deployment-level payload, identical to the payload sent at commit." }, - "replica_overhead_percent": { + "name": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Replica Overhead Percent" + "default": null, + "description": "Set to validate a new-model push. Exactly one of `name` or `model_id` is required.", + "title": "Name" }, - "promotion_cleanup_strategy": { + "team_id": { "anyOf": [ { "type": "string" @@ -12937,186 +14058,3829 @@ "type": "null" } ], - "title": "Promotion Cleanup Strategy" + "default": null, + "description": "Team the new model will belong to. Only valid when `name` is set; defaults to the organization's default team when omitted. Must not be set when `model_id` is set (the existing model already has a team).", + "title": "Team Id" }, - "ramp_up_while_promoting": { + "model_id": { "anyOf": [ { - "type": "boolean" + "type": "string" }, { "type": "null" } ], - "title": "Ramp Up While Promoting" + "default": null, + "description": "Set to validate an add-deployment push to an existing model. Exactly one of `name` or `model_id` is required.", + "title": "Model Id" }, - "ramp_up_duration_seconds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Ramp Up Duration Seconds" + "dry_run": { + "default": false, + "description": "If true, validate the payload only and do not issue upload credentials. The response sets `creds`, `s3_bucket`, and `s3_key` to `null`.", + "title": "Dry Run", + "type": "boolean" + } + }, + "required": [ + "deployment" + ], + "title": "PrepareModelUploadRequestV1", + "type": "object" + }, + "AWSCredentialsV1": { + "description": "AWS credentials", + "properties": { + "aws_access_key_id": { + "description": "The AWS access key ID", + "title": "Aws Access Key Id", + "type": "string" }, - "ramp_up_step_size": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Ramp Up Step Size" + "aws_secret_access_key": { + "description": "The AWS secret access key", + "title": "Aws Secret Access Key", + "type": "string" }, - "request_backpressure_policy": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Request Backpressure Policy" + "aws_session_token": { + "description": "The AWS session token", + "title": "Aws Session Token", + "type": "string" } }, "required": [ - "min_replica", - "max_replica", - "concurrency_target", - "autoscaling_window", - "scale_down_delay", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate", - "redeploy_on_promotion", - "rolling_deploy", - "rolling_deploy_strategy", - "max_unavailable_percent", - "max_surge_percent", - "stabilization_time_seconds", - "replica_overhead_percent", - "promotion_cleanup_strategy", - "ramp_up_while_promoting", - "ramp_up_duration_seconds", - "ramp_up_step_size" + "aws_access_key_id", + "aws_secret_access_key", + "aws_session_token" ], - "title": "AuditLogEventEnvironmentSettingsV1", + "title": "AWSCredentialsV1", "type": "object" }, - "AuditLogEventEnvironmentUpdatedV1": { - "additionalProperties": false, - "description": "A model environment's settings were updated.", + "PrepareModelUploadResponseV1": { + "description": "Response from `POST /v1/prepare_model_upload`.\n\nReturns STS upload credentials when the push requires an archive upload. All\nfour fields (`creds`, `s3_bucket`, `s3_key`, `s3_region`) are `null` when no\nupload is needed: either `dry_run=true` (validation only) or a model format\nthat is not built from an uploaded archive (for example, BIS-LLM, which is\nbuilt from its config alone).", "properties": { - "schedules": { + "creds": { "anyOf": [ { - "items": { - "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleChangeV1" - }, - "type": "array" + "$ref": "#/components/schemas/AWSCredentialsV1" }, { "type": "null" } ], - "title": "Schedules" - }, - "min_replica": { - "title": "Min Replica", - "type": "integer" - }, - "max_replica": { - "title": "Max Replica", - "type": "integer" - }, - "concurrency_target": { - "title": "Concurrency Target", - "type": "integer" + "default": null, + "description": "STS credentials to upload the model archive. Null when no archive upload is required." }, - "autoscaling_window": { + "s3_bucket": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Autoscaling Window" + "default": null, + "description": "S3 bucket the credentials are scoped to. Null when no archive upload is required.", + "title": "S3 Bucket" }, - "scale_down_delay": { + "s3_key": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Scale Down Delay" + "default": null, + "description": "S3 key the credentials are scoped to. Pass this to `POST /v1/models` (in the `model_archive` source) once the upload completes. Null when no archive upload is required.", + "title": "S3 Key" }, - "target_utilization_percentage": { + "s3_region": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Target Utilization Percentage" + "default": null, + "description": "AWS region the S3 bucket resides in. Null when no archive upload is required.", + "title": "S3 Region" + } + }, + "title": "PrepareModelUploadResponseV1", + "type": "object" + }, + "AuditLogActorTypeV1": { + "description": "Kind of actor that performed an audited action.", + "enum": [ + "USER", + "API_KEY", + "BASETEN_USER", + "BASETEN_SYSTEM", + "TOMBSTONE_USER" + ], + "title": "AuditLogActorTypeV1", + "type": "string" + }, + "AuditLogActorV1": { + "description": "The actor that performed an audited action.", + "properties": { + "type": { + "$ref": "#/components/schemas/AuditLogActorTypeV1", + "description": "Kind of actor that performed the action." }, - "target_in_flight_tokens": { + "email": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Target In Flight Tokens" + "default": null, + "description": "Email of the acting user, when the actor is a user.", + "title": "Email" }, - "max_scale_down_rate": { + "api_key_prefix": { "anyOf": [ { - "type": "number" + "type": "string" }, { "type": "null" } ], - "title": "Max Scale Down Rate" + "default": null, + "description": "Prefix of the acting API key, when the actor is an API key.", + "title": "Api Key Prefix" }, - "redeploy_on_promotion": { + "api_key_name": { "anyOf": [ { - "type": "boolean" + "type": "string" }, { "type": "null" } ], - "title": "Redeploy On Promotion" + "default": null, + "description": "Display name of the acting API key, when the actor is an API key.", + "title": "Api Key Name" + } + }, + "required": [ + "type" + ], + "title": "AuditLogActorV1", + "type": "object" + }, + "AuditLogApiKeyTypeV1": { + "description": "Type of API key recorded on an API-key event.", + "enum": [ + "PERSONAL", + "CREATOR_SERVICE_ACCOUNT", + "MANAGE_API_KEYS_SERVICE_ACCOUNT", + "INVOKE_ALL_MODELS_SERVICE_ACCOUNT", + "INVOKE_ALLOWED_MODELS_SERVICE_ACCOUNT", + "INVOKE_SCOPED_ENVS_AND_MODELS_SERVICE_ACCOUNT", + "EXPORT_METRICS_ALL_MODELS_SERVICE_ACCOUNT", + "EXPORT_METRICS_ALLOWED_MODELS_SERVICE_ACCOUNT", + "INVOKE_ALL_SHARED_ENDPOINTS_SERVICE_ACCOUNT", + "INVOKE_ALLOWED_SHARED_ENDPOINTS_SERVICE_ACCOUNT", + "INVOKE_ALL_ROUTES" + ], + "title": "AuditLogApiKeyTypeV1", + "type": "string" + }, + "AuditLogEntryV1": { + "description": "A single audit-log entry.", + "properties": { + "id": { + "description": "Unique identifier of the audit-log entry.", + "title": "Id", + "type": "string" }, - "rolling_deploy": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Rolling Deploy" + "created": { + "description": "Time the action occurred, in ISO 8601 format.", + "format": "date-time", + "title": "Created", + "type": "string" }, - "rolling_deploy_strategy": { + "event_type": { + "$ref": "#/components/schemas/AuditLogEventTypeV1", + "description": "Type of action that was recorded." + }, + "event_data": { + "description": "Structured details of the action, discriminated by `event_type`.", + "discriminator": { + "mapping": { + "API_KEY_CREATED": "#/components/schemas/AuditLogEventApiKeyCreatedV1", + "API_KEY_DELETED": "#/components/schemas/AuditLogEventApiKeyDeletedV1", + "CHAINLET_AUTOSCALING_SETTINGS_CHANGED": "#/components/schemas/AuditLogEventChainletAutoscalingSettingsChangedV1", + "CHAINLET_INSTANCE_TYPE_CHANGED": "#/components/schemas/AuditLogEventChainletInstanceTypeChangedV1", + "CHAIN_DELETED": "#/components/schemas/AuditLogEventChainDeletedV1", + "CHAIN_DEPLOYED": "#/components/schemas/AuditLogEventChainDeployedV1", + "CHAIN_DEPLOYMENT_ACTIVATED": "#/components/schemas/AuditLogEventChainDeploymentActivatedV1", + "CHAIN_DEPLOYMENT_DEACTIVATED": "#/components/schemas/AuditLogEventChainDeploymentDeactivatedV1", + "CHAIN_DEPLOYMENT_DELETED": "#/components/schemas/AuditLogEventChainDeploymentDeletedV1", + "CHAIN_DEPLOYMENT_PROMOTED": "#/components/schemas/AuditLogEventChainDeploymentPromotedV1", + "CHAIN_ENVIRONMENT_CREATED": "#/components/schemas/AuditLogEventChainEnvironmentCreatedV1", + "CHAIN_ENVIRONMENT_UPDATED": "#/components/schemas/AuditLogEventChainEnvironmentUpdatedV1", + "DIRECTORY_GROUP_ROLE_UPDATED": "#/components/schemas/AuditLogEventDirectoryGroupRoleUpdatedV1", + "ENVIRONMENT_CREATED": "#/components/schemas/AuditLogEventEnvironmentCreatedV1", + "ENVIRONMENT_DELETED": "#/components/schemas/AuditLogEventEnvironmentDeletedV1", + "ENVIRONMENT_UPDATED": "#/components/schemas/AuditLogEventEnvironmentUpdatedV1", + "GATEWAY_ENDPOINT_CREATED": "#/components/schemas/AuditLogEventGatewayEndpointCreatedV1", + "GATEWAY_ENDPOINT_DELETED": "#/components/schemas/AuditLogEventGatewayEndpointDeletedV1", + "GATEWAY_ENDPOINT_UPDATED": "#/components/schemas/AuditLogEventGatewayEndpointUpdatedV1", + "MODEL_DELETED": "#/components/schemas/AuditLogEventModelDeletedV1", + "MODEL_DEPLOYED": "#/components/schemas/AuditLogEventModelDeployedV1", + "MODEL_DEPLOYMENT_ACTIVATED": "#/components/schemas/AuditLogEventModelDeploymentActivatedV1", + "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED": "#/components/schemas/AuditLogEventModelDeploymentAutoscalingSettingsChangedV1", + "MODEL_DEPLOYMENT_DEACTIVATED": "#/components/schemas/AuditLogEventModelDeploymentDeactivatedV1", + "MODEL_DEPLOYMENT_DELETED": "#/components/schemas/AuditLogEventModelDeploymentDeletedV1", + "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED": "#/components/schemas/AuditLogEventModelDeploymentInstanceTypeChangedV1", + "MODEL_DEPLOYMENT_PROMOTED": "#/components/schemas/AuditLogEventModelDeploymentPromotedV1", + "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED": "#/components/schemas/AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1", + "MODEL_DEPLOYMENT_RETRIED": "#/components/schemas/AuditLogEventModelDeploymentRetriedV1", + "MODEL_PROMOTION_CONTROL_ACTION": "#/components/schemas/AuditLogEventModelPromotionControlActionV1", + "MODEL_RENAMED": "#/components/schemas/AuditLogEventModelRenamedV1", + "PROVIDER_CONNECTION_CREATED": "#/components/schemas/AuditLogEventProviderConnectionCreatedV1", + "PROVIDER_CONNECTION_DELETED": "#/components/schemas/AuditLogEventProviderConnectionDeletedV1", + "PROVIDER_CONNECTION_UPDATED": "#/components/schemas/AuditLogEventProviderConnectionUpdatedV1", + "REPLICA_TERMINATED": "#/components/schemas/AuditLogEventReplicaTerminatedV1", + "REQUIRE_GROUP_BASED_ADMINS_ENABLED": "#/components/schemas/AuditLogEventRequireGroupBasedAdminsEnabledV1", + "SECRET_DELETED": "#/components/schemas/AuditLogEventSecretDeletedV1", + "SECRET_UPDATED": "#/components/schemas/AuditLogEventSecretUpdatedV1", + "SSH_CERTIFICATE_SIGNED": "#/components/schemas/AuditLogEventSshCertificateSignedV1", + "USER_INVITED": "#/components/schemas/AuditLogEventUserInvitedV1", + "USER_JOINED_ORGANIZATION": "#/components/schemas/AuditLogEventUserJoinedOrganizationV1", + "USER_REMOVED": "#/components/schemas/AuditLogEventUserRemovedV1", + "USER_ROLE_UPDATED": "#/components/schemas/AuditLogEventUserRoleUpdatedV1", + "USER_TEAM_ROLE_UPDATED": "#/components/schemas/AuditLogEventUserTeamRoleUpdatedV1", + "VOLUME_DELETED": "#/components/schemas/AuditLogEventVolumeDeletedV1", + "VOLUME_VERSION_DELETED": "#/components/schemas/AuditLogEventVolumeVersionDeletedV1", + "VOLUME_VERSION_RESTORED": "#/components/schemas/AuditLogEventVolumeVersionRestoredV1", + "WEBHOOK_SIGNING_SECRET_CREATED": "#/components/schemas/AuditLogEventWebhookSigningSecretCreatedV1", + "WEBHOOK_SIGNING_SECRET_DELETED": "#/components/schemas/AuditLogEventWebhookSigningSecretDeletedV1", + "WEBHOOK_SIGNING_SECRET_ROTATED": "#/components/schemas/AuditLogEventWebhookSigningSecretRotatedV1" + }, + "propertyName": "event_type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/AuditLogEventModelDeployedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentActivatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentDeactivatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentRetriedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentPromotedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentAutoscalingSettingsChangedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentInstanceTypeChangedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeploymentDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelRenamedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainDeployedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainDeploymentActivatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainDeploymentDeactivatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainDeploymentPromotedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainletAutoscalingSettingsChangedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainletInstanceTypeChangedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainDeploymentDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainEnvironmentCreatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventChainEnvironmentUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventSecretUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventSecretDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventApiKeyCreatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventApiKeyDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventGatewayEndpointCreatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventGatewayEndpointUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventGatewayEndpointDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventProviderConnectionCreatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventProviderConnectionUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventProviderConnectionDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventUserInvitedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventUserJoinedOrganizationV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventWebhookSigningSecretCreatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventWebhookSigningSecretRotatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventWebhookSigningSecretDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventUserRoleUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventUserTeamRoleUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventUserRemovedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventDirectoryGroupRoleUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventRequireGroupBasedAdminsEnabledV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventEnvironmentCreatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventEnvironmentUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventEnvironmentDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventReplicaTerminatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventModelPromotionControlActionV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventSshCertificateSignedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventVolumeDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventVolumeVersionDeletedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventVolumeVersionRestoredV1" + } + ], + "title": "Event Data" + }, + "source": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogSourceV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Surface that issued the action, if known." + }, + "actor": { + "$ref": "#/components/schemas/AuditLogActorV1", + "description": "The actor that performed the action." + }, + "client_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Name of the client that issued the action, if known.", + "title": "Client Name" + }, + "client_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Version of the client that issued the action, if known.", + "title": "Client Version" + }, + "client_session_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Opaque identifier grouping actions from the same client session, if known.", + "title": "Client Session Id" + } + }, + "required": [ + "id", + "created", + "event_type", + "event_data", + "actor" + ], + "title": "AuditLogEntryV1", + "type": "object" + }, + "AuditLogEventApiKeyCreatedV1": { + "additionalProperties": false, + "description": "An API key was created.", + "properties": { + "event_type": { + "const": "API_KEY_CREATED", + "title": "Event Type", + "type": "string" + }, + "api_key_id": { + "title": "Api Key Id", + "type": "string" + }, + "api_key_type": { + "$ref": "#/components/schemas/AuditLogApiKeyTypeV1" + }, + "prefix": { + "title": "Prefix", + "type": "string" + } + }, + "required": [ + "event_type", + "api_key_id", + "api_key_type", + "prefix" + ], + "title": "AuditLogEventApiKeyCreatedV1", + "type": "object" + }, + "AuditLogEventApiKeyDeletedV1": { + "additionalProperties": false, + "description": "An API key was revoked.", + "properties": { + "event_type": { + "const": "API_KEY_DELETED", + "title": "Event Type", + "type": "string" + }, + "api_key_id": { + "title": "Api Key Id", + "type": "string" + }, + "api_key_type": { + "$ref": "#/components/schemas/AuditLogApiKeyTypeV1" + }, + "prefix": { + "title": "Prefix", + "type": "string" + } + }, + "required": [ + "event_type", + "api_key_id", + "api_key_type", + "prefix" + ], + "title": "AuditLogEventApiKeyDeletedV1", + "type": "object" + }, + "AuditLogEventAutoscalingScheduleActionV1": { + "description": "What an autoscaling change did to one schedule.", + "enum": [ + "CREATED", + "UPDATED", + "DELETED", + "UNCHANGED" + ], + "title": "AuditLogEventAutoscalingScheduleActionV1", + "type": "string" + }, + "AuditLogEventAutoscalingScheduleChangeV1": { + "additionalProperties": false, + "description": "What an autoscaling change did to one schedule, and the schedule on either side of it.\n`previous` is null on a create, `current` on a delete, and an unchanged schedule carries only\n`current`. Not itself a payload in the discriminated union.", + "properties": { + "action": { + "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleActionV1" + }, + "schedule_id": { + "title": "Schedule Id", + "type": "string" + }, + "previous": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleSettingsV1" + }, + { + "type": "null" + } + ] + }, + "current": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleSettingsV1" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "action", + "schedule_id", + "previous", + "current" + ], + "title": "AuditLogEventAutoscalingScheduleChangeV1", + "type": "object" + }, + "AuditLogEventAutoscalingScheduleSettingsV1": { + "additionalProperties": false, + "description": "One autoscaling schedule's timing and autoscaling settings. Not itself a union payload.", + "properties": { + "min_replica": { + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "title": "Max Replica", + "type": "integer" + }, + "concurrency_target": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Concurrency Target" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Scale Down Delay" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Max Scale Down Rate" + }, + "schedule_name": { + "title": "Schedule Name", + "type": "string" + }, + "enabled": { + "title": "Enabled", + "type": "boolean" + }, + "cadence": { + "title": "Cadence", + "type": "string" + }, + "timezone": { + "title": "Timezone", + "type": "string" + }, + "weekdays": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Weekdays" + }, + "start_hour": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Start Hour" + }, + "start_minute": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Start Minute" + }, + "end_hour": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "End Hour" + }, + "end_minute": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "End Minute" + }, + "start_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start At" + }, + "end_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End At" + } + }, + "required": [ + "min_replica", + "max_replica", + "concurrency_target", + "autoscaling_window", + "scale_down_delay", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate", + "schedule_name", + "enabled", + "cadence", + "timezone", + "weekdays", + "start_hour", + "start_minute", + "end_hour", + "end_minute" + ], + "title": "AuditLogEventAutoscalingScheduleSettingsV1", + "type": "object" + }, + "AuditLogEventAutoscalingSettingsV1": { + "additionalProperties": false, + "description": "Autoscaling settings for a deployment or environment.", + "properties": { + "min_replica": { + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "title": "Max Replica", + "type": "integer" + }, + "concurrency_target": { + "title": "Concurrency Target", + "type": "integer" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Scale Down Delay" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Max Scale Down Rate" + } + }, + "required": [ + "min_replica", + "max_replica", + "concurrency_target", + "autoscaling_window", + "scale_down_delay", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate" + ], + "title": "AuditLogEventAutoscalingSettingsV1", + "type": "object" + }, + "AuditLogEventChainDeletedV1": { + "additionalProperties": false, + "description": "A chain was deleted.", + "properties": { + "event_type": { + "const": "CHAIN_DELETED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chain Deployment Name" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "chain_deployment_name" + ], + "title": "AuditLogEventChainDeletedV1", + "type": "object" + }, + "AuditLogEventChainDeployedV1": { + "additionalProperties": false, + "description": "A chain deployment was created.", + "properties": { + "event_type": { + "const": "CHAIN_DEPLOYED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_id": { + "title": "Chain Deployment Id", + "type": "string" + }, + "chain_deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chain Deployment Name" + }, + "is_primary": { + "title": "Is Primary", + "type": "boolean" + }, + "publish": { + "title": "Publish", + "type": "boolean" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "chain_deployment_id", + "chain_deployment_name", + "is_primary", + "publish" + ], + "title": "AuditLogEventChainDeployedV1", + "type": "object" + }, + "AuditLogEventChainDeploymentActivatedV1": { + "additionalProperties": false, + "description": "A chain deployment was activated.", + "properties": { + "event_type": { + "const": "CHAIN_DEPLOYMENT_ACTIVATED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_id": { + "title": "Chain Deployment Id", + "type": "string" + }, + "chain_deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chain Deployment Name" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "chain_deployment_id", + "chain_deployment_name" + ], + "title": "AuditLogEventChainDeploymentActivatedV1", + "type": "object" + }, + "AuditLogEventChainDeploymentDeactivatedV1": { + "additionalProperties": false, + "description": "A chain deployment was deactivated.", + "properties": { + "event_type": { + "const": "CHAIN_DEPLOYMENT_DEACTIVATED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_id": { + "title": "Chain Deployment Id", + "type": "string" + }, + "chain_deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chain Deployment Name" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "chain_deployment_id", + "chain_deployment_name" + ], + "title": "AuditLogEventChainDeploymentDeactivatedV1", + "type": "object" + }, + "AuditLogEventChainDeploymentDeletedV1": { + "additionalProperties": false, + "description": "A chain deployment was deleted.", + "properties": { + "event_type": { + "const": "CHAIN_DEPLOYMENT_DELETED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_id": { + "title": "Chain Deployment Id", + "type": "string" + }, + "deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Deployment Name" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "chain_deployment_id", + "deployment_name" + ], + "title": "AuditLogEventChainDeploymentDeletedV1", + "type": "object" + }, + "AuditLogEventChainDeploymentPromotedV1": { + "additionalProperties": false, + "description": "A chain deployment was promoted to an environment.", + "properties": { + "event_type": { + "const": "CHAIN_DEPLOYMENT_PROMOTED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_id": { + "title": "Chain Deployment Id", + "type": "string" + }, + "chain_deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chain Deployment Name" + }, + "environment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Environment Name" + }, + "environment_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Environment Id" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "chain_deployment_id", + "chain_deployment_name", + "environment_name", + "environment_id" + ], + "title": "AuditLogEventChainDeploymentPromotedV1", + "type": "object" + }, + "AuditLogEventChainEnvironmentCreatedV1": { + "additionalProperties": false, + "description": "A chain environment was created.", + "properties": { + "event_type": { + "const": "CHAIN_ENVIRONMENT_CREATED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "environment_name": { + "title": "Environment Name", + "type": "string" + }, + "redeploy_on_promotion": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Redeploy On Promotion" + }, + "ramp_up_while_promoting": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Ramp Up While Promoting" + }, + "ramp_up_duration_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Duration Seconds" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "environment_name", + "redeploy_on_promotion", + "ramp_up_while_promoting", + "ramp_up_duration_seconds" + ], + "title": "AuditLogEventChainEnvironmentCreatedV1", + "type": "object" + }, + "AuditLogEventChainEnvironmentUpdatedV1": { + "additionalProperties": false, + "description": "A chain environment was updated.", + "properties": { + "event_type": { + "const": "CHAIN_ENVIRONMENT_UPDATED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "environment_name": { + "title": "Environment Name", + "type": "string" + }, + "redeploy_on_promotion": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Redeploy On Promotion" + }, + "ramp_up_while_promoting": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Ramp Up While Promoting" + }, + "ramp_up_duration_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Duration Seconds" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "environment_name", + "redeploy_on_promotion", + "ramp_up_while_promoting", + "ramp_up_duration_seconds" + ], + "title": "AuditLogEventChainEnvironmentUpdatedV1", + "type": "object" + }, + "AuditLogEventChainletAutoscalingSettingsChangedV1": { + "additionalProperties": false, + "description": "A chainlet's autoscaling settings were changed.", + "properties": { + "min_replica": { + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "title": "Max Replica", + "type": "integer" + }, + "concurrency_target": { + "title": "Concurrency Target", + "type": "integer" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Scale Down Delay" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Max Scale Down Rate" + }, + "event_type": { + "const": "CHAINLET_AUTOSCALING_SETTINGS_CHANGED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_id": { + "title": "Chain Deployment Id", + "type": "string" + }, + "chain_deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chain Deployment Name" + }, + "chainlet_name": { + "title": "Chainlet Name", + "type": "string" + }, + "chainlet_id": { + "title": "Chainlet Id", + "type": "string" + }, + "previous_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventAutoscalingSettingsV1" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "min_replica", + "max_replica", + "concurrency_target", + "autoscaling_window", + "scale_down_delay", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate", + "event_type", + "chain_id", + "chain_name", + "chain_deployment_id", + "chain_deployment_name", + "chainlet_name", + "chainlet_id", + "previous_settings" + ], + "title": "AuditLogEventChainletAutoscalingSettingsChangedV1", + "type": "object" + }, + "AuditLogEventChainletInstanceTypeChangedV1": { + "additionalProperties": false, + "description": "A chainlet's instance type was changed.", + "properties": { + "event_type": { + "const": "CHAINLET_INSTANCE_TYPE_CHANGED", + "title": "Event Type", + "type": "string" + }, + "chain_id": { + "title": "Chain Id", + "type": "string" + }, + "chain_name": { + "title": "Chain Name", + "type": "string" + }, + "chain_deployment_id": { + "title": "Chain Deployment Id", + "type": "string" + }, + "chain_deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chain Deployment Name" + }, + "chainlet_name": { + "title": "Chainlet Name", + "type": "string" + }, + "chainlet_id": { + "title": "Chainlet Id", + "type": "string" + }, + "instance_type_name": { + "title": "Instance Type Name", + "type": "string" + } + }, + "required": [ + "event_type", + "chain_id", + "chain_name", + "chain_deployment_id", + "chain_deployment_name", + "chainlet_name", + "chainlet_id", + "instance_type_name" + ], + "title": "AuditLogEventChainletInstanceTypeChangedV1", + "type": "object" + }, + "AuditLogEventDirectoryGroupRoleUpdatedV1": { + "additionalProperties": false, + "description": "A directory group's role was updated.", + "properties": { + "event_type": { + "const": "DIRECTORY_GROUP_ROLE_UPDATED", + "title": "Event Type", + "type": "string" + }, + "directory_group_id": { + "title": "Directory Group Id", + "type": "string" + }, + "directory_group_name": { + "title": "Directory Group Name", + "type": "string" + }, + "new_role_name": { + "title": "New Role Name", + "type": "string" + }, + "team_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Team Id" + }, + "team_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Team Name" + } + }, + "required": [ + "event_type", + "directory_group_id", + "directory_group_name", + "new_role_name", + "team_id", + "team_name" + ], + "title": "AuditLogEventDirectoryGroupRoleUpdatedV1", + "type": "object" + }, + "AuditLogEventEnvironmentCreatedV1": { + "additionalProperties": false, + "description": "A model environment was created.", + "properties": { + "min_replica": { + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "title": "Max Replica", + "type": "integer" + }, + "concurrency_target": { + "title": "Concurrency Target", + "type": "integer" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Scale Down Delay" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Max Scale Down Rate" + }, + "redeploy_on_promotion": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Redeploy On Promotion" + }, + "rolling_deploy": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Rolling Deploy" + }, + "rolling_deploy_strategy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Rolling Deploy Strategy" + }, + "max_unavailable_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Max Unavailable Percent" + }, + "max_surge_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Max Surge Percent" + }, + "stabilization_time_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Stabilization Time Seconds" + }, + "replica_overhead_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Replica Overhead Percent" + }, + "promotion_cleanup_strategy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Promotion Cleanup Strategy" + }, + "ramp_up_while_promoting": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Ramp Up While Promoting" + }, + "ramp_up_duration_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Duration Seconds" + }, + "ramp_up_step_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Step Size" + }, + "request_backpressure_policy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Request Backpressure Policy" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "environment_name": { + "title": "Environment Name", + "type": "string" + }, + "deployment_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Deployment Type" + }, + "event_type": { + "const": "ENVIRONMENT_CREATED", + "title": "Event Type", + "type": "string" + } + }, + "required": [ + "min_replica", + "max_replica", + "concurrency_target", + "autoscaling_window", + "scale_down_delay", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate", + "redeploy_on_promotion", + "rolling_deploy", + "rolling_deploy_strategy", + "max_unavailable_percent", + "max_surge_percent", + "stabilization_time_seconds", + "replica_overhead_percent", + "promotion_cleanup_strategy", + "ramp_up_while_promoting", + "ramp_up_duration_seconds", + "ramp_up_step_size", + "model_id", + "model_name", + "environment_name", + "deployment_type", + "event_type" + ], + "title": "AuditLogEventEnvironmentCreatedV1", + "type": "object" + }, + "AuditLogEventEnvironmentDeletedV1": { + "additionalProperties": false, + "description": "A model environment was deleted.", + "properties": { + "event_type": { + "const": "ENVIRONMENT_DELETED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "environment_name": { + "title": "Environment Name", + "type": "string" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "environment_name" + ], + "title": "AuditLogEventEnvironmentDeletedV1", + "type": "object" + }, + "AuditLogEventEnvironmentSettingsV1": { + "additionalProperties": false, + "description": "Full environment settings (autoscaling + rolling promotion + deprecated canary);\nshared base for the environment events and the type of their previous_settings\nsnapshots. Not itself a payload in the discriminated union.", + "properties": { + "min_replica": { + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "title": "Max Replica", + "type": "integer" + }, + "concurrency_target": { + "title": "Concurrency Target", + "type": "integer" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Scale Down Delay" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Max Scale Down Rate" + }, + "redeploy_on_promotion": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Redeploy On Promotion" + }, + "rolling_deploy": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Rolling Deploy" + }, + "rolling_deploy_strategy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Rolling Deploy Strategy" + }, + "max_unavailable_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Max Unavailable Percent" + }, + "max_surge_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Max Surge Percent" + }, + "stabilization_time_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Stabilization Time Seconds" + }, + "replica_overhead_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Replica Overhead Percent" + }, + "promotion_cleanup_strategy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Promotion Cleanup Strategy" + }, + "ramp_up_while_promoting": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Ramp Up While Promoting" + }, + "ramp_up_duration_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Duration Seconds" + }, + "ramp_up_step_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Step Size" + }, + "request_backpressure_policy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Request Backpressure Policy" + } + }, + "required": [ + "min_replica", + "max_replica", + "concurrency_target", + "autoscaling_window", + "scale_down_delay", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate", + "redeploy_on_promotion", + "rolling_deploy", + "rolling_deploy_strategy", + "max_unavailable_percent", + "max_surge_percent", + "stabilization_time_seconds", + "replica_overhead_percent", + "promotion_cleanup_strategy", + "ramp_up_while_promoting", + "ramp_up_duration_seconds", + "ramp_up_step_size" + ], + "title": "AuditLogEventEnvironmentSettingsV1", + "type": "object" + }, + "AuditLogEventEnvironmentUpdatedV1": { + "additionalProperties": false, + "description": "A model environment's settings were updated.", + "properties": { + "schedules": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleChangeV1" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Schedules" + }, + "min_replica": { + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "title": "Max Replica", + "type": "integer" + }, + "concurrency_target": { + "title": "Concurrency Target", + "type": "integer" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Scale Down Delay" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Max Scale Down Rate" + }, + "redeploy_on_promotion": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Redeploy On Promotion" + }, + "rolling_deploy": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Rolling Deploy" + }, + "rolling_deploy_strategy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Rolling Deploy Strategy" + }, + "max_unavailable_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Max Unavailable Percent" + }, + "max_surge_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Max Surge Percent" + }, + "stabilization_time_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Stabilization Time Seconds" + }, + "replica_overhead_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Replica Overhead Percent" + }, + "promotion_cleanup_strategy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Promotion Cleanup Strategy" + }, + "ramp_up_while_promoting": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Ramp Up While Promoting" + }, + "ramp_up_duration_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Duration Seconds" + }, + "ramp_up_step_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ramp Up Step Size" + }, + "request_backpressure_policy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Request Backpressure Policy" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "environment_name": { + "title": "Environment Name", + "type": "string" + }, + "deployment_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Deployment Type" + }, + "event_type": { + "const": "ENVIRONMENT_UPDATED", + "title": "Event Type", + "type": "string" + }, + "previous_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventEnvironmentSettingsV1" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "schedules", + "min_replica", + "max_replica", + "concurrency_target", + "autoscaling_window", + "scale_down_delay", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate", + "redeploy_on_promotion", + "rolling_deploy", + "rolling_deploy_strategy", + "max_unavailable_percent", + "max_surge_percent", + "stabilization_time_seconds", + "replica_overhead_percent", + "promotion_cleanup_strategy", + "ramp_up_while_promoting", + "ramp_up_duration_seconds", + "ramp_up_step_size", + "model_id", + "model_name", + "environment_name", + "deployment_type", + "event_type", + "previous_settings" + ], + "title": "AuditLogEventEnvironmentUpdatedV1", + "type": "object" + }, + "AuditLogEventGatewayEndpointCreatedV1": { + "additionalProperties": false, + "description": "A Frontier Gateway endpoint was created.", + "properties": { + "event_type": { + "const": "GATEWAY_ENDPOINT_CREATED", + "title": "Event Type", + "type": "string" + }, + "gateway_endpoint_id": { + "title": "Gateway Endpoint Id", + "type": "string" + }, + "slug": { + "title": "Slug", + "type": "string" + } + }, + "required": [ + "event_type", + "gateway_endpoint_id", + "slug" + ], + "title": "AuditLogEventGatewayEndpointCreatedV1", + "type": "object" + }, + "AuditLogEventGatewayEndpointDeletedV1": { + "additionalProperties": false, + "description": "A Frontier Gateway endpoint was deleted.", + "properties": { + "event_type": { + "const": "GATEWAY_ENDPOINT_DELETED", + "title": "Event Type", + "type": "string" + }, + "gateway_endpoint_id": { + "title": "Gateway Endpoint Id", + "type": "string" + }, + "slug": { + "title": "Slug", + "type": "string" + } + }, + "required": [ + "event_type", + "gateway_endpoint_id", + "slug" + ], + "title": "AuditLogEventGatewayEndpointDeletedV1", + "type": "object" + }, + "AuditLogEventGatewayEndpointUpdatedV1": { + "additionalProperties": false, + "description": "A Frontier Gateway endpoint was updated.", + "properties": { + "event_type": { + "const": "GATEWAY_ENDPOINT_UPDATED", + "title": "Event Type", + "type": "string" + }, + "gateway_endpoint_id": { + "title": "Gateway Endpoint Id", + "type": "string" + }, + "slug": { + "title": "Slug", + "type": "string" + }, + "previous_slug": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Previous Slug" + } + }, + "required": [ + "event_type", + "gateway_endpoint_id", + "slug", + "previous_slug" + ], + "title": "AuditLogEventGatewayEndpointUpdatedV1", + "type": "object" + }, + "AuditLogEventModelDeletedV1": { + "additionalProperties": false, + "description": "A model was deleted.", + "properties": { + "event_type": { + "const": "MODEL_DELETED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + } + }, + "required": [ + "event_type", + "model_id", + "model_name" + ], + "title": "AuditLogEventModelDeletedV1", + "type": "object" + }, + "AuditLogEventModelDeployedV1": { + "additionalProperties": false, + "description": "A model deployment was created.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "scale_previous_to_zero": { + "title": "Scale Previous To Zero", + "type": "boolean" + }, + "trusted": { + "title": "Trusted", + "type": "boolean" + }, + "publish": { + "title": "Publish", + "type": "boolean" + }, + "environment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Environment Name" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name", + "scale_previous_to_zero", + "trusted", + "publish", + "environment_name" + ], + "title": "AuditLogEventModelDeployedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentActivatedV1": { + "additionalProperties": false, + "description": "A model deployment was activated.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYMENT_ACTIVATED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name" + ], + "title": "AuditLogEventModelDeploymentActivatedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentAutoscalingSettingsChangedV1": { + "additionalProperties": false, + "description": "A model deployment's autoscaling settings were changed.", + "properties": { + "schedules": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleChangeV1" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Schedules" + }, + "min_replica": { + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "title": "Max Replica", + "type": "integer" + }, + "concurrency_target": { + "title": "Concurrency Target", + "type": "integer" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Scale Down Delay" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Max Scale Down Rate" + }, + "event_type": { + "const": "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "deployment_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Deployment Type" + }, + "previous_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventAutoscalingSettingsV1" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "schedules", + "min_replica", + "max_replica", + "concurrency_target", + "autoscaling_window", + "scale_down_delay", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate", + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name", + "deployment_type", + "previous_settings" + ], + "title": "AuditLogEventModelDeploymentAutoscalingSettingsChangedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentDeactivatedV1": { + "additionalProperties": false, + "description": "A model deployment was deactivated.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYMENT_DEACTIVATED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name" + ], + "title": "AuditLogEventModelDeploymentDeactivatedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentDeletedV1": { + "additionalProperties": false, + "description": "A model deployment was deleted.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYMENT_DELETED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name" + ], + "title": "AuditLogEventModelDeploymentDeletedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentInstanceTypeChangedV1": { + "additionalProperties": false, + "description": "A model deployment's instance type was changed.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "instance_type_name": { + "title": "Instance Type Name", + "type": "string" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name", + "instance_type_name" + ], + "title": "AuditLogEventModelDeploymentInstanceTypeChangedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentPromotedV1": { + "additionalProperties": false, + "description": "A model deployment was promoted to an environment.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYMENT_PROMOTED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "environment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Environment Name" + }, + "environment_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Environment Id" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name", + "environment_name", + "environment_id" + ], + "title": "AuditLogEventModelDeploymentPromotedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1": { + "additionalProperties": false, + "description": "A model deployment's request backpressure settings were changed.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "policy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Policy" + }, + "previous_policy": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Previous Policy" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name" + ], + "title": "AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1", + "type": "object" + }, + "AuditLogEventModelDeploymentRetriedV1": { + "additionalProperties": false, + "description": "A model deployment build was retried.", + "properties": { + "event_type": { + "const": "MODEL_DEPLOYMENT_RETRIED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "retried": { + "title": "Retried", + "type": "boolean" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name", + "retried" + ], + "title": "AuditLogEventModelDeploymentRetriedV1", + "type": "object" + }, + "AuditLogEventModelPromotionControlActionV1": { + "additionalProperties": false, + "description": "A user-initiated promotion control signal was sent to a rolling promotion.", + "properties": { + "event_type": { + "const": "MODEL_PROMOTION_CONTROL_ACTION", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "environment_name": { + "title": "Environment Name", + "type": "string" + }, + "environment_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Environment Id" + }, + "action": { + "$ref": "#/components/schemas/AuditLogPromotionControlActionV1" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name", + "environment_name", + "environment_id", + "action" + ], + "title": "AuditLogEventModelPromotionControlActionV1", + "type": "object" + }, + "AuditLogEventModelRenamedV1": { + "additionalProperties": false, + "description": "A model was renamed. `model_name` is the new name.", + "properties": { + "event_type": { + "const": "MODEL_RENAMED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "previous_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Previous Name" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "previous_name" + ], + "title": "AuditLogEventModelRenamedV1", + "type": "object" + }, + "AuditLogEventProviderConnectionCreatedV1": { + "additionalProperties": false, + "properties": { + "event_type": { + "const": "PROVIDER_CONNECTION_CREATED", + "title": "Event Type", + "type": "string" + }, + "provider_connection_id": { + "title": "Provider Connection Id", + "type": "string" + }, + "provider": { + "title": "Provider", + "type": "string" + }, + "secret_name": { + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "event_type", + "provider_connection_id", + "provider", + "secret_name" + ], + "title": "AuditLogEventProviderConnectionCreatedV1", + "type": "object" + }, + "AuditLogEventProviderConnectionDeletedV1": { + "additionalProperties": false, + "properties": { + "event_type": { + "const": "PROVIDER_CONNECTION_DELETED", + "title": "Event Type", + "type": "string" + }, + "provider_connection_id": { + "title": "Provider Connection Id", + "type": "string" + }, + "provider": { + "title": "Provider", + "type": "string" + }, + "secret_name": { + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "event_type", + "provider_connection_id", + "provider", + "secret_name" + ], + "title": "AuditLogEventProviderConnectionDeletedV1", + "type": "object" + }, + "AuditLogEventProviderConnectionUpdatedV1": { + "additionalProperties": false, + "properties": { + "event_type": { + "const": "PROVIDER_CONNECTION_UPDATED", + "title": "Event Type", + "type": "string" + }, + "provider_connection_id": { + "title": "Provider Connection Id", + "type": "string" + }, + "provider": { + "title": "Provider", + "type": "string" + }, + "secret_name": { + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "event_type", + "provider_connection_id", + "provider", + "secret_name" + ], + "title": "AuditLogEventProviderConnectionUpdatedV1", + "type": "object" + }, + "AuditLogEventReplicaTerminatedV1": { + "additionalProperties": false, + "description": "A replica of a model deployment was terminated.", + "properties": { + "event_type": { + "const": "REPLICA_TERMINATED", + "title": "Event Type", + "type": "string" + }, + "model_id": { + "title": "Model Id", + "type": "string" + }, + "model_name": { + "title": "Model Name", + "type": "string" + }, + "deployment_id": { + "title": "Deployment Id", + "type": "string" + }, + "deployment_name": { + "title": "Deployment Name", + "type": "string" + }, + "replica_id": { + "title": "Replica Id", + "type": "string" + } + }, + "required": [ + "event_type", + "model_id", + "model_name", + "deployment_id", + "deployment_name", + "replica_id" + ], + "title": "AuditLogEventReplicaTerminatedV1", + "type": "object" + }, + "AuditLogEventRequireGroupBasedAdminsEnabledV1": { + "additionalProperties": false, + "description": "Group-based admin enforcement was enabled for the organization.", + "properties": { + "event_type": { + "const": "REQUIRE_GROUP_BASED_ADMINS_ENABLED", + "title": "Event Type", + "type": "string" + }, + "organization_id": { + "title": "Organization Id", + "type": "string" + } + }, + "required": [ + "event_type", + "organization_id" + ], + "title": "AuditLogEventRequireGroupBasedAdminsEnabledV1", + "type": "object" + }, + "AuditLogEventSecretDeletedV1": { + "additionalProperties": false, + "description": "A secret was deleted.", + "properties": { + "event_type": { + "const": "SECRET_DELETED", + "title": "Event Type", + "type": "string" + }, + "secret_id": { + "title": "Secret Id", + "type": "string" + }, + "secret_name": { + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "event_type", + "secret_id", + "secret_name" + ], + "title": "AuditLogEventSecretDeletedV1", + "type": "object" + }, + "AuditLogEventSecretUpdatedV1": { + "additionalProperties": false, + "description": "A secret was created or updated.", + "properties": { + "event_type": { + "const": "SECRET_UPDATED", + "title": "Event Type", + "type": "string" + }, + "secret_id": { + "title": "Secret Id", + "type": "string" + }, + "secret_name": { + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "event_type", + "secret_id", + "secret_name" + ], + "title": "AuditLogEventSecretUpdatedV1", + "type": "object" + }, + "AuditLogEventSshCertificateSignedV1": { + "additionalProperties": false, + "description": "An SSH certificate was signed for a workload.", + "properties": { + "event_type": { + "const": "SSH_CERTIFICATE_SIGNED", + "title": "Event Type", + "type": "string" + }, + "workload_type": { + "title": "Workload Type", + "type": "string" + }, + "workload_id": { + "title": "Workload Id", + "type": "string" + }, + "project_id": { + "title": "Project Id", + "type": "string" + }, + "replica_id": { + "title": "Replica Id", + "type": "string" + }, + "proxy_address": { + "title": "Proxy Address", + "type": "string" + }, + "expires_at": { + "title": "Expires At", + "type": "string" + } + }, + "required": [ + "event_type", + "workload_type", + "workload_id", + "project_id", + "replica_id", + "proxy_address", + "expires_at" + ], + "title": "AuditLogEventSshCertificateSignedV1", + "type": "object" + }, + "AuditLogEventTypeV1": { + "description": "Type of action recorded by an audit-log entry.", + "enum": [ + "MODEL_DEPLOYED", + "MODEL_DEPLOYMENT_ACTIVATED", + "MODEL_DEPLOYMENT_DEACTIVATED", + "MODEL_DEPLOYMENT_RETRIED", + "MODEL_DEPLOYMENT_PROMOTED", + "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED", + "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED", + "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED", + "MODEL_DEPLOYMENT_DELETED", + "MODEL_DELETED", + "MODEL_RENAMED", + "CHAIN_DEPLOYED", + "CHAIN_DEPLOYMENT_ACTIVATED", + "CHAIN_DEPLOYMENT_DEACTIVATED", + "CHAIN_DEPLOYMENT_PROMOTED", + "CHAINLET_AUTOSCALING_SETTINGS_CHANGED", + "CHAINLET_INSTANCE_TYPE_CHANGED", + "CHAIN_DEPLOYMENT_DELETED", + "CHAIN_DELETED", + "CHAIN_ENVIRONMENT_CREATED", + "CHAIN_ENVIRONMENT_UPDATED", + "SECRET_UPDATED", + "SECRET_DELETED", + "API_KEY_CREATED", + "API_KEY_DELETED", + "GATEWAY_ENDPOINT_CREATED", + "GATEWAY_ENDPOINT_UPDATED", + "GATEWAY_ENDPOINT_DELETED", + "PROVIDER_CONNECTION_CREATED", + "PROVIDER_CONNECTION_UPDATED", + "PROVIDER_CONNECTION_DELETED", + "USER_INVITED", + "USER_JOINED_ORGANIZATION", + "WEBHOOK_SIGNING_SECRET_CREATED", + "WEBHOOK_SIGNING_SECRET_ROTATED", + "WEBHOOK_SIGNING_SECRET_DELETED", + "USER_ROLE_UPDATED", + "USER_TEAM_ROLE_UPDATED", + "USER_REMOVED", + "DIRECTORY_GROUP_ROLE_UPDATED", + "REQUIRE_GROUP_BASED_ADMINS_ENABLED", + "ENVIRONMENT_CREATED", + "ENVIRONMENT_UPDATED", + "ENVIRONMENT_DELETED", + "REPLICA_TERMINATED", + "MODEL_PROMOTION_CONTROL_ACTION", + "SSH_CERTIFICATE_SIGNED", + "VOLUME_DELETED", + "VOLUME_VERSION_DELETED", + "VOLUME_VERSION_RESTORED" + ], + "title": "AuditLogEventTypeV1", + "type": "string" + }, + "AuditLogEventUserInvitedV1": { + "additionalProperties": false, + "description": "A user was invited to the organization.", + "properties": { + "event_type": { + "const": "USER_INVITED", + "title": "Event Type", + "type": "string" + }, + "invited_user_email": { + "title": "Invited User Email", + "type": "string" + }, + "role_name": { + "title": "Role Name", + "type": "string" + } + }, + "required": [ + "event_type", + "invited_user_email", + "role_name" + ], + "title": "AuditLogEventUserInvitedV1", + "type": "object" + }, + "AuditLogEventUserJoinedOrganizationV1": { + "additionalProperties": false, + "description": "A user joined the organization.", + "properties": { + "event_type": { + "const": "USER_JOINED_ORGANIZATION", + "title": "Event Type", + "type": "string" + }, + "new_user_email": { + "title": "New User Email", + "type": "string" + }, + "user_id": { + "title": "User Id", + "type": "string" + } + }, + "required": [ + "event_type", + "new_user_email", + "user_id" + ], + "title": "AuditLogEventUserJoinedOrganizationV1", + "type": "object" + }, + "AuditLogEventUserRemovedV1": { + "additionalProperties": false, + "description": "A user was removed from the organization.", + "properties": { + "event_type": { + "const": "USER_REMOVED", + "title": "Event Type", + "type": "string" + }, + "removed_user_email": { + "title": "Removed User Email", + "type": "string" + } + }, + "required": [ + "event_type", + "removed_user_email" + ], + "title": "AuditLogEventUserRemovedV1", + "type": "object" + }, + "AuditLogEventUserRoleUpdatedV1": { + "additionalProperties": false, + "description": "A user's organization role was updated.", + "properties": { + "event_type": { + "const": "USER_ROLE_UPDATED", + "title": "Event Type", + "type": "string" + }, + "user_id": { + "title": "User Id", + "type": "string" + }, + "user_email": { + "title": "User Email", + "type": "string" + }, + "new_role_name": { + "title": "New Role Name", + "type": "string" + } + }, + "required": [ + "event_type", + "user_id", + "user_email", + "new_role_name" + ], + "title": "AuditLogEventUserRoleUpdatedV1", + "type": "object" + }, + "AuditLogEventUserTeamRoleUpdatedV1": { + "additionalProperties": false, + "description": "A user's team role was updated.", + "properties": { + "event_type": { + "const": "USER_TEAM_ROLE_UPDATED", + "title": "Event Type", + "type": "string" + }, + "user_id": { + "title": "User Id", + "type": "string" + }, + "user_email": { + "title": "User Email", + "type": "string" + }, + "team_id": { + "title": "Team Id", + "type": "string" + }, + "team_name": { + "title": "Team Name", + "type": "string" + }, + "new_role_name": { + "title": "New Role Name", + "type": "string" + } + }, + "required": [ + "event_type", + "user_id", + "user_email", + "team_id", + "team_name", + "new_role_name" + ], + "title": "AuditLogEventUserTeamRoleUpdatedV1", + "type": "object" + }, + "AuditLogEventVolumeDeletedV1": { + "additionalProperties": false, + "description": "A volume was deleted, tombstoning every version it still held.", + "properties": { + "event_type": { + "const": "VOLUME_DELETED", + "title": "Event Type", + "type": "string" + }, + "volume_ref": { + "title": "Volume Ref", + "type": "string" + }, + "namespace": { + "title": "Namespace", + "type": "string" + }, + "volume_name": { + "title": "Volume Name", + "type": "string" + }, + "versions_deleted": { + "title": "Versions Deleted", + "type": "integer" + } + }, + "required": [ + "event_type", + "volume_ref", + "namespace", + "volume_name", + "versions_deleted" + ], + "title": "AuditLogEventVolumeDeletedV1", + "type": "object" + }, + "AuditLogEventVolumeVersionDeletedV1": { + "additionalProperties": false, + "description": "One version of a volume was deleted.", + "properties": { + "event_type": { + "const": "VOLUME_VERSION_DELETED", + "title": "Event Type", + "type": "string" + }, + "volume_ref": { + "title": "Volume Ref", + "type": "string" + }, + "namespace": { + "title": "Namespace", + "type": "string" + }, + "volume_name": { + "title": "Volume Name", + "type": "string" + }, + "version": { + "title": "Version", + "type": "string" + }, + "digest": { + "title": "Digest", + "type": "string" + } + }, + "required": [ + "event_type", + "volume_ref", + "namespace", + "volume_name", + "version", + "digest" + ], + "title": "AuditLogEventVolumeVersionDeletedV1", + "type": "object" + }, + "AuditLogEventVolumeVersionRestoredV1": { + "additionalProperties": false, + "description": "A deleted version of a volume was restored.", + "properties": { + "event_type": { + "const": "VOLUME_VERSION_RESTORED", + "title": "Event Type", + "type": "string" + }, + "volume_ref": { + "title": "Volume Ref", + "type": "string" + }, + "namespace": { + "title": "Namespace", + "type": "string" + }, + "volume_name": { + "title": "Volume Name", + "type": "string" + }, + "version": { + "title": "Version", + "type": "string" + }, + "digest": { + "title": "Digest", + "type": "string" + } + }, + "required": [ + "event_type", + "volume_ref", + "namespace", + "volume_name", + "version", + "digest" + ], + "title": "AuditLogEventVolumeVersionRestoredV1", + "type": "object" + }, + "AuditLogEventWebhookSigningSecretCreatedV1": { + "additionalProperties": false, + "description": "A webhook signing secret was created.", + "properties": { + "event_type": { + "const": "WEBHOOK_SIGNING_SECRET_CREATED", + "title": "Event Type", + "type": "string" + }, + "webhook_signing_secret_id": { + "title": "Webhook Signing Secret Id", + "type": "string" + } + }, + "required": [ + "event_type", + "webhook_signing_secret_id" + ], + "title": "AuditLogEventWebhookSigningSecretCreatedV1", + "type": "object" + }, + "AuditLogEventWebhookSigningSecretDeletedV1": { + "additionalProperties": false, + "description": "A webhook signing secret was deleted.", + "properties": { + "event_type": { + "const": "WEBHOOK_SIGNING_SECRET_DELETED", + "title": "Event Type", + "type": "string" + }, + "webhook_signing_secret_id": { + "title": "Webhook Signing Secret Id", + "type": "string" + } + }, + "required": [ + "event_type", + "webhook_signing_secret_id" + ], + "title": "AuditLogEventWebhookSigningSecretDeletedV1", + "type": "object" + }, + "AuditLogEventWebhookSigningSecretRotatedV1": { + "additionalProperties": false, + "description": "A webhook signing secret was rotated.", + "properties": { + "event_type": { + "const": "WEBHOOK_SIGNING_SECRET_ROTATED", + "title": "Event Type", + "type": "string" + }, + "webhook_signing_secret_id": { + "title": "Webhook Signing Secret Id", + "type": "string" + } + }, + "required": [ + "event_type", + "webhook_signing_secret_id" + ], + "title": "AuditLogEventWebhookSigningSecretRotatedV1", + "type": "object" + }, + "AuditLogPromotionControlActionV1": { + "description": "User-initiated promotion control signal recorded on a promotion-control event.", + "enum": [ + "PAUSE", + "RESUME", + "FORCE_CANCEL", + "FORCE_ROLL_FORWARD", + "GRACEFUL_CANCEL" + ], + "title": "AuditLogPromotionControlActionV1", + "type": "string" + }, + "AuditLogSourceV1": { + "description": "Surface that issued the audited action.", + "enum": [ + "UI", + "API", + "MCP", + "SYSTEM", + "OTHER" + ], + "title": "AuditLogSourceV1", + "type": "string" + }, + "ListAuditLogsResponseV1": { + "description": "A page of audit-log entries, newest first by default.", + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/AuditLogEntryV1" + }, + "title": "Items", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "ListAuditLogsResponseV1", + "type": "object" + }, + "AuditLogEventTypeGroupV1": { + "description": "Coarse grouping of event types, used to filter the audit log.", + "enum": [ + "DEPLOYED", + "PROMOTED", + "ACTIVATED_DEACTIVATED", + "AUTOSCALING_SETTINGS", + "REQUEST_BACKPRESSURE_SETTINGS", + "INSTANCE_TYPE_CHANGED", + "ENVIRONMENT_SETTINGS", + "REPLICA_TERMINATED", + "DELETED", + "METADATA", + "SECRETS", + "API_KEYS", + "GATEWAY", + "CODE", + "WEBHOOK_SIGNING_SECRETS", + "USER_MANAGEMENT", + "DIRECTORY_GROUP_MANAGEMENT", + "SSH" + ], + "title": "AuditLogEventTypeGroupV1", + "type": "string" + }, + "AuditLogSortDirectionV1": { + "description": "Sort order of returned entries, by creation time.", + "enum": [ + "DESC", + "ASC" + ], + "title": "AuditLogSortDirectionV1", + "type": "string" + }, + "ListAuditLogsRequestV1": { + "description": "Query params for listing audit-log entries.", + "properties": { + "cursor": { "anyOf": [ { "type": "string" @@ -13125,86 +17889,85 @@ "type": "null" } ], - "title": "Rolling Deploy Strategy" + "default": null, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "max_unavailable_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Unavailable Percent" + "limit": { + "default": 20, + "description": "Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", + "maximum": 200, + "minimum": 1, + "title": "Limit", + "type": "integer" }, - "max_surge_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Surge Percent" + "direction": { + "$ref": "#/components/schemas/AuditLogSortDirectionV1", + "default": "DESC", + "description": "Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." }, - "stabilization_time_seconds": { + "search": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "title": "Stabilization Time Seconds" + "default": null, + "description": "Case-insensitive substring matched against resource names and IDs in the entry.", + "title": "Search" }, - "replica_overhead_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Replica Overhead Percent" + "event_type_groups": { + "description": "When set, returns only entries whose event type falls in one of these groups.", + "items": { + "$ref": "#/components/schemas/AuditLogEventTypeGroupV1" + }, + "title": "Event Type Groups", + "type": "array" }, - "promotion_cleanup_strategy": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Promotion Cleanup Strategy" + "user_ids": { + "description": "When set, returns only entries whose acting user is one of these IDs.", + "items": { + "type": "string" + }, + "title": "User Ids", + "type": "array" }, - "ramp_up_while_promoting": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Ramp Up While Promoting" + "deployment_ids": { + "description": "When set, returns only entries referencing one of these model deployment IDs.", + "items": { + "type": "string" + }, + "title": "Deployment Ids", + "type": "array" }, - "ramp_up_duration_seconds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Ramp Up Duration Seconds" + "chain_deployment_ids": { + "description": "When set, returns only entries referencing one of these chain deployment IDs.", + "items": { + "type": "string" + }, + "title": "Chain Deployment Ids", + "type": "array" }, - "ramp_up_step_size": { + "environment_names": { + "description": "When set, returns only entries for one of these environments.", + "items": { + "type": "string" + }, + "title": "Environment Names", + "type": "array" + }, + "sources": { + "description": "When set, returns only entries issued from one of these surfaces.", + "items": { + "$ref": "#/components/schemas/AuditLogSourceV1" + }, + "title": "Sources", + "type": "array" + }, + "start_epoch_millis": { "anyOf": [ { "type": "integer" @@ -13213,33 +17976,52 @@ "type": "null" } ], - "title": "Ramp Up Step Size" + "default": null, + "description": "Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", + "title": "Start Epoch Millis" }, - "request_backpressure_policy": { + "end_epoch_millis": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "title": "Request Backpressure Policy" - }, - "model_id": { - "title": "Model Id", + "description": "Epoch milliseconds for the end of the window. Defaults to the current time.", + "title": "End Epoch Millis" + } + }, + "title": "ListAuditLogsRequestV1", + "type": "object" + }, + "ModelV1": { + "description": "A model.", + "properties": { + "id": { + "description": "Unique identifier of the model", + "title": "Id", "type": "string" }, - "model_name": { - "title": "Model Name", + "created_at": { + "description": "Time the model was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", "type": "string" }, - "environment_name": { - "title": "Environment Name", + "name": { + "description": "Name of the model", + "title": "Name", "type": "string" }, - "deployment_type": { + "deployments_count": { + "description": "Number of deployments of the model", + "title": "Deployments Count", + "type": "integer" + }, + "production_deployment_id": { "anyOf": [ { "type": "string" @@ -13248,125 +18030,66 @@ "type": "null" } ], - "title": "Deployment Type" - }, - "event_type": { - "const": "ENVIRONMENT_UPDATED", - "title": "Event Type", - "type": "string" + "description": "Unique identifier of the production deployment of the model", + "title": "Production Deployment Id" }, - "previous_settings": { + "development_deployment_id": { "anyOf": [ { - "$ref": "#/components/schemas/AuditLogEventEnvironmentSettingsV1" + "type": "string" }, { "type": "null" } - ] - } - }, - "required": [ - "schedules", - "min_replica", - "max_replica", - "concurrency_target", - "autoscaling_window", - "scale_down_delay", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate", - "redeploy_on_promotion", - "rolling_deploy", - "rolling_deploy_strategy", - "max_unavailable_percent", - "max_surge_percent", - "stabilization_time_seconds", - "replica_overhead_percent", - "promotion_cleanup_strategy", - "ramp_up_while_promoting", - "ramp_up_duration_seconds", - "ramp_up_step_size", - "model_id", - "model_name", - "environment_name", - "deployment_type", - "event_type", - "previous_settings" - ], - "title": "AuditLogEventEnvironmentUpdatedV1", - "type": "object" - }, - "AuditLogEventGatewayEndpointCreatedV1": { - "additionalProperties": false, - "description": "A Frontier Gateway endpoint was created.", - "properties": { - "event_type": { - "const": "GATEWAY_ENDPOINT_CREATED", - "title": "Event Type", - "type": "string" + ], + "description": "Unique identifier of the development deployment of the model", + "title": "Development Deployment Id" }, - "gateway_endpoint_id": { - "title": "Gateway Endpoint Id", + "instance_type_name": { + "description": "Name of the instance type for the production deployment of the model", + "title": "Instance Type Name", "type": "string" }, - "slug": { - "title": "Slug", + "team_name": { + "description": "Name of the team associated with the model.", + "title": "Team Name", "type": "string" } }, "required": [ - "event_type", - "gateway_endpoint_id", - "slug" + "id", + "created_at", + "name", + "deployments_count", + "production_deployment_id", + "development_deployment_id", + "instance_type_name", + "team_name" ], - "title": "AuditLogEventGatewayEndpointCreatedV1", + "title": "ModelV1", "type": "object" }, - "AuditLogEventGatewayEndpointDeletedV1": { - "additionalProperties": false, - "description": "A Frontier Gateway endpoint was deleted.", + "ModelsV1": { + "description": "A list of models.", "properties": { - "event_type": { - "const": "GATEWAY_ENDPOINT_DELETED", - "title": "Event Type", - "type": "string" - }, - "gateway_endpoint_id": { - "title": "Gateway Endpoint Id", - "type": "string" - }, - "slug": { - "title": "Slug", - "type": "string" + "models": { + "items": { + "$ref": "#/components/schemas/ModelV1" + }, + "title": "Models", + "type": "array" } }, "required": [ - "event_type", - "gateway_endpoint_id", - "slug" + "models" ], - "title": "AuditLogEventGatewayEndpointDeletedV1", + "title": "ModelsV1", "type": "object" }, - "AuditLogEventGatewayEndpointUpdatedV1": { - "additionalProperties": false, - "description": "A Frontier Gateway endpoint was updated.", + "ModelsRequestV1": { + "description": "Request parameters for listing models.", "properties": { - "event_type": { - "const": "GATEWAY_ENDPOINT_UPDATED", - "title": "Event Type", - "type": "string" - }, - "gateway_endpoint_id": { - "title": "Gateway Endpoint Id", - "type": "string" - }, - "slug": { - "title": "Slug", - "type": "string" - }, - "previous_slug": { + "name": { "anyOf": [ { "type": "string" @@ -13375,82 +18098,34 @@ "type": "null" } ], - "title": "Previous Slug" - } - }, - "required": [ - "event_type", - "gateway_endpoint_id", - "slug", - "previous_slug" - ], - "title": "AuditLogEventGatewayEndpointUpdatedV1", - "type": "object" - }, - "AuditLogEventModelDeletedV1": { - "additionalProperties": false, - "description": "A model was deleted.", - "properties": { - "event_type": { - "const": "MODEL_DELETED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" + "default": null, + "description": "When set, returns only models with this exact name, if any. On a team-scoped route this matches at most one model; on the org-wide route it may match models in multiple teams, since names are unique only within a team.", + "title": "Name" } }, - "required": [ - "event_type", - "model_id", - "model_name" - ], - "title": "AuditLogEventModelDeletedV1", + "title": "ModelsRequestV1", "type": "object" }, - "AuditLogEventModelDeployedV1": { - "additionalProperties": false, - "description": "A model deployment was created.", + "LibraryListingSourceV1": { + "description": "Create a model by forking a library listing accessible to the caller's organization.", "properties": { - "event_type": { - "const": "MODEL_DEPLOYED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", + "kind": { + "const": "library_listing", + "default": "library_listing", + "title": "Kind", "type": "string" }, - "deployment_id": { - "title": "Deployment Id", + "lab_display_name": { + "description": "Identifier of the publishing organization, as returned by `GET /v1/library_models`.", + "title": "Lab Display Name", "type": "string" }, - "deployment_name": { - "title": "Deployment Name", + "user_defined_listing_id": { + "description": "Listing identifier within the publishing organization.", + "title": "User Defined Listing Id", "type": "string" }, - "scale_previous_to_zero": { - "title": "Scale Previous To Zero", - "type": "boolean" - }, - "trusted": { - "title": "Trusted", - "type": "boolean" - }, - "publish": { - "title": "Publish", - "type": "boolean" - }, - "environment_name": { + "deployed_model_name": { "anyOf": [ { "type": "string" @@ -13459,89 +18134,105 @@ "type": "null" } ], - "title": "Environment Name" + "default": null, + "description": "Optional name for the new deployed model. Defaults to the listing's configured name.", + "title": "Deployed Model Name" } }, "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name", - "scale_previous_to_zero", - "trusted", - "publish", - "environment_name" + "lab_display_name", + "user_defined_listing_id" ], - "title": "AuditLogEventModelDeployedV1", + "title": "LibraryListingSourceV1", "type": "object" }, - "AuditLogEventModelDeploymentActivatedV1": { - "additionalProperties": false, - "description": "A model deployment was activated.", + "ModelArchiveSourceV1": { + "description": "Create a model from an archive previously uploaded via the credentials\nissued by `POST /v1/prepare_model_upload`.", "properties": { - "event_type": { - "const": "MODEL_DEPLOYMENT_ACTIVATED", - "title": "Event Type", + "kind": { + "const": "model_archive", + "default": "model_archive", + "title": "Kind", "type": "string" }, - "model_id": { - "title": "Model Id", + "name": { + "description": "Name of the new model.", + "title": "Name", "type": "string" }, - "model_name": { - "title": "Model Name", - "type": "string" + "deployment": { + "$ref": "#/components/schemas/DeploymentArchivePayloadV1", + "description": "Deployment-level configuration for the model's first deployment." }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" + "s3_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", + "title": "S3 Key" }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" + "disable_archive_download": { + "default": false, + "description": "If true, the uploaded archive is not downloadable after creation. Locked at model creation; cannot be changed by subsequent deployments.", + "title": "Disable Archive Download", + "type": "boolean" } }, "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name" + "name", + "deployment" ], - "title": "AuditLogEventModelDeploymentActivatedV1", + "title": "ModelArchiveSourceV1", "type": "object" }, - "AuditLogEventModelDeploymentAutoscalingSettingsChangedV1": { - "additionalProperties": false, - "description": "A model deployment's autoscaling settings were changed.", + "CreateModelRequestV1": { + "description": "Body for creating a model via `POST /v1/models`.", "properties": { - "schedules": { - "anyOf": [ + "source": { + "description": "Where the new model is created from.", + "discriminator": { + "mapping": { + "library_listing": "#/components/schemas/LibraryListingSourceV1", + "model_archive": "#/components/schemas/ModelArchiveSourceV1" + }, + "propertyName": "kind" + }, + "oneOf": [ { - "items": { - "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleChangeV1" - }, - "type": "array" + "$ref": "#/components/schemas/LibraryListingSourceV1" }, { - "type": "null" + "$ref": "#/components/schemas/ModelArchiveSourceV1" } ], - "title": "Schedules" - }, + "title": "Source" + } + }, + "required": [ + "source" + ], + "title": "CreateModelRequestV1", + "type": "object" + }, + "AutoscalingSettingsV1": { + "description": "Autoscaling settings for a deployment.", + "properties": { "min_replica": { + "description": "Minimum number of replicas", "title": "Min Replica", "type": "integer" }, "max_replica": { + "description": "Maximum number of replicas", "title": "Max Replica", "type": "integer" }, - "concurrency_target": { - "title": "Concurrency Target", - "type": "integer" - }, "autoscaling_window": { "anyOf": [ { @@ -13551,6 +18242,7 @@ "type": "null" } ], + "description": "Timeframe of traffic considered for autoscaling decisions", "title": "Autoscaling Window" }, "scale_down_delay": { @@ -13562,8 +18254,14 @@ "type": "null" } ], + "description": "Waiting period before scaling down any active replica", "title": "Scale Down Delay" }, + "concurrency_target": { + "description": "Number of requests per replica before scaling up", + "title": "Concurrency Target", + "type": "integer" + }, "target_utilization_percentage": { "anyOf": [ { @@ -13573,6 +18271,7 @@ "type": "null" } ], + "description": "Target utilization percentage for scaling up/down.", "title": "Target Utilization Percentage" }, "target_in_flight_tokens": { @@ -13584,222 +18283,123 @@ "type": "null" } ], + "default": null, + "description": "Target number of in-flight tokens for autoscaling decisions. Early access only.", "title": "Target In Flight Tokens" }, "max_scale_down_rate": { "anyOf": [ { - "type": "number" + "type": "integer" }, { "type": "null" } ], + "default": null, + "description": "Maximum percentage of replicas that can be removed per autoscaling window (1\u201350). E.g. 20 means at most 20% of replicas are removed per window.", "title": "Max Scale Down Rate" - }, - "event_type": { - "const": "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" - }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" - }, - "deployment_type": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Deployment Type" - }, - "previous_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuditLogEventAutoscalingSettingsV1" - }, - { - "type": "null" - } - ] } }, "required": [ - "schedules", "min_replica", "max_replica", - "concurrency_target", "autoscaling_window", "scale_down_delay", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate", - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name", - "deployment_type", - "previous_settings" + "concurrency_target", + "target_utilization_percentage" ], - "title": "AuditLogEventModelDeploymentAutoscalingSettingsChangedV1", + "title": "AutoscalingSettingsV1", "type": "object" }, - "AuditLogEventModelDeploymentDeactivatedV1": { - "additionalProperties": false, - "description": "A model deployment was deactivated.", - "properties": { - "event_type": { - "const": "MODEL_DEPLOYMENT_DEACTIVATED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" - }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" - } - }, - "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name" + "DeploymentStatusV1": { + "description": "The status of a deployment.", + "enum": [ + "BUILDING", + "DEPLOYING", + "DEPLOY_FAILED", + "LOADING_MODEL", + "ACTIVE", + "UNHEALTHY", + "BUILD_FAILED", + "BUILD_STOPPED", + "DEACTIVATING", + "INACTIVE", + "FAILED", + "UPDATING", + "SCALED_TO_ZERO", + "WAKING_UP" ], - "title": "AuditLogEventModelDeploymentDeactivatedV1", - "type": "object" + "title": "DeploymentStatusV1", + "type": "string" }, - "AuditLogEventModelDeploymentDeletedV1": { - "additionalProperties": false, - "description": "A model deployment was deleted.", + "DeploymentV1": { + "description": "A deployment of a model.", "properties": { - "event_type": { - "const": "MODEL_DEPLOYMENT_DELETED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", + "id": { + "description": "Unique identifier of the deployment", + "title": "Id", "type": "string" }, - "deployment_id": { - "title": "Deployment Id", + "created_at": { + "description": "Time the deployment was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", "type": "string" }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" - } - }, - "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name" - ], - "title": "AuditLogEventModelDeploymentDeletedV1", - "type": "object" - }, - "AuditLogEventModelDeploymentInstanceTypeChangedV1": { - "additionalProperties": false, - "description": "A model deployment's instance type was changed.", - "properties": { - "event_type": { - "const": "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED", - "title": "Event Type", + "name": { + "description": "Name of the deployment", + "title": "Name", "type": "string" }, "model_id": { + "description": "Unique identifier of the model", "title": "Model Id", "type": "string" }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" - }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" + "is_production": { + "description": "Whether the deployment is the production deployment of the model", + "title": "Is Production", + "type": "boolean" }, - "instance_type_name": { - "title": "Instance Type Name", - "type": "string" - } - }, - "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name", - "instance_type_name" - ], - "title": "AuditLogEventModelDeploymentInstanceTypeChangedV1", - "type": "object" - }, - "AuditLogEventModelDeploymentPromotedV1": { - "additionalProperties": false, - "description": "A model deployment was promoted to an environment.", - "properties": { - "event_type": { - "const": "MODEL_DEPLOYMENT_PROMOTED", - "title": "Event Type", - "type": "string" + "is_development": { + "description": "Whether the deployment is the development deployment of the model", + "title": "Is Development", + "type": "boolean" }, - "model_id": { - "title": "Model Id", - "type": "string" + "status": { + "$ref": "#/components/schemas/DeploymentStatusV1", + "description": "Status of the deployment" }, - "model_name": { - "title": "Model Name", - "type": "string" + "active_replica_count": { + "description": "Number of active replicas", + "title": "Active Replica Count", + "type": "integer" }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" + "autoscaling_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/AutoscalingSettingsV1" + }, + { + "type": "null" + } + ], + "description": "Autoscaling settings for the deployment. If null, the model has not finished deploying" }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" + "instance_type_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Name of the instance type the model deployment is running on", + "title": "Instance Type Name" }, - "environment_name": { + "environment": { "anyOf": [ { "type": "string" @@ -13808,840 +18408,866 @@ "type": "null" } ], - "title": "Environment Name" + "description": "The environment associated with the deployment", + "title": "Environment" }, - "environment_id": { + "labels": { "anyOf": [ { - "type": "string" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], - "title": "Environment Id" - } - }, - "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name", - "environment_name", - "environment_id" - ], - "title": "AuditLogEventModelDeploymentPromotedV1", - "type": "object" - }, - "AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1": { - "additionalProperties": false, - "description": "A model deployment's request backpressure settings were changed.", - "properties": { - "event_type": { - "const": "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" - }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" + "default": null, + "description": "User-provided key-value labels for the deployment", + "title": "Labels" }, - "policy": { + "region": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/RegionV1" }, { "type": "null" } ], "default": null, - "title": "Policy" + "description": "The selected region for the deployment, if any" }, - "previous_policy": { + "request_backpressure_settings": { + "$ref": "#/components/schemas/RequestBackpressureSettingsV1", + "description": "Effective request backpressure settings for the deployment." + } + }, + "required": [ + "id", + "created_at", + "name", + "model_id", + "is_production", + "is_development", + "status", + "active_replica_count", + "autoscaling_settings", + "instance_type_name", + "environment", + "request_backpressure_settings" + ], + "title": "DeploymentV1", + "type": "object" + }, + "RequestBackpressurePolicyV1": { + "enum": [ + "QUEUE_ON_FULL", + "REJECT_ON_FULL" + ], + "title": "RequestBackpressurePolicyV1", + "type": "string" + }, + "RequestBackpressureSettingsV1": { + "description": "Request backpressure settings for a deployment or environment.", + "properties": { + "policy": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/RequestBackpressurePolicyV1" }, { "type": "null" } ], "default": null, - "title": "Previous Policy" + "description": "Backpressure policy. Null when no policy is set." + } + }, + "title": "RequestBackpressureSettingsV1", + "type": "object" + }, + "CreatedModelDeploymentV1": { + "description": "A newly created deployment and its model.", + "properties": { + "model": { + "$ref": "#/components/schemas/ModelV1", + "description": "The model the deployment belongs to. May have been created by this call." + }, + "deployment": { + "$ref": "#/components/schemas/DeploymentV1", + "description": "The newly created deployment." } }, "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name" + "model", + "deployment" ], - "title": "AuditLogEventModelDeploymentRequestBackpressureSettingsChangedV1", + "title": "CreatedModelDeploymentV1", "type": "object" }, - "AuditLogEventModelDeploymentRetriedV1": { - "additionalProperties": false, - "description": "A model deployment build was retried.", + "ModelTombstoneV1": { + "description": "A model tombstone.", "properties": { - "event_type": { - "const": "MODEL_DEPLOYMENT_RETRIED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" - }, - "deployment_name": { - "title": "Deployment Name", + "id": { + "description": "Unique identifier of the model", + "title": "Id", "type": "string" }, - "retried": { - "title": "Retried", + "deleted": { + "description": "Whether the model was deleted", + "title": "Deleted", "type": "boolean" } }, "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name", - "retried" + "id", + "deleted" ], - "title": "AuditLogEventModelDeploymentRetriedV1", + "title": "ModelTombstoneV1", "type": "object" }, - "AuditLogEventModelPromotionControlActionV1": { + "UpdateModelRequestV1": { "additionalProperties": false, - "description": "A user-initiated promotion control signal was sent to a rolling promotion.", + "description": "A request to update a model.", "properties": { - "event_type": { - "const": "MODEL_PROMOTION_CONTROL_ACTION", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "deployment_id": { - "title": "Deployment Id", - "type": "string" - }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" - }, - "environment_name": { - "title": "Environment Name", - "type": "string" - }, - "environment_id": { + "name": { "anyOf": [ { + "maxLength": 255, + "minLength": 1, "type": "string" }, { "type": "null" } ], - "title": "Environment Id" - }, - "action": { - "$ref": "#/components/schemas/AuditLogPromotionControlActionV1" + "default": null, + "description": "New name for the model, unique within its team. Renaming does not change the model ID, endpoints, or deployments. Pushes that still use the old model_name create another model or target a model that now uses that name, so update config.yaml after renaming.", + "examples": [ + "my-model" + ], + "title": "Name" + } + }, + "title": "UpdateModelRequestV1", + "type": "object" + }, + "DeploymentsV1": { + "description": "A list of deployments of a model.", + "properties": { + "deployments": { + "description": "A list of deployments of a model", + "items": { + "$ref": "#/components/schemas/DeploymentV1" + }, + "title": "Deployments", + "type": "array" } }, "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name", - "environment_name", - "environment_id", - "action" + "deployments" ], - "title": "AuditLogEventModelPromotionControlActionV1", + "title": "DeploymentsV1", "type": "object" }, - "AuditLogEventReplicaTerminatedV1": { - "additionalProperties": false, - "description": "A replica of a model deployment was terminated.", + "DeploymentsRequestV1": { + "description": "Request parameters for listing a model's deployments.", "properties": { - "event_type": { - "const": "REPLICA_TERMINATED", - "title": "Event Type", - "type": "string" - }, - "model_id": { - "title": "Model Id", - "type": "string" - }, - "model_name": { - "title": "Model Name", - "type": "string" - }, - "deployment_id": { - "title": "Deployment Id", + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "When set, returns only the deployment with this exact name, if any.", + "title": "Name" + } + }, + "title": "DeploymentsRequestV1", + "type": "object" + }, + "DeploymentArchiveSourceV1": { + "description": "Add a deployment from an archive previously uploaded via the credentials\nissued by `POST /v1/prepare_model_upload`.", + "properties": { + "kind": { + "const": "model_archive", + "default": "model_archive", + "title": "Kind", "type": "string" }, - "deployment_name": { - "title": "Deployment Name", - "type": "string" + "deployment": { + "$ref": "#/components/schemas/DeploymentArchivePayloadV1", + "description": "Deployment-level configuration." }, - "replica_id": { - "title": "Replica Id", - "type": "string" + "s3_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", + "title": "S3 Key" } }, "required": [ - "event_type", - "model_id", - "model_name", - "deployment_id", - "deployment_name", - "replica_id" + "deployment" ], - "title": "AuditLogEventReplicaTerminatedV1", + "title": "DeploymentArchiveSourceV1", "type": "object" }, - "AuditLogEventRequireGroupBasedAdminsEnabledV1": { - "additionalProperties": false, - "description": "Group-based admin enforcement was enabled for the organization.", + "CreateModelDeploymentRequestV1": { + "description": "Body for adding a deployment to an existing model via\n`POST /v1/models/{model_id}/deployments`.", "properties": { - "event_type": { - "const": "REQUIRE_GROUP_BASED_ADMINS_ENABLED", - "title": "Event Type", - "type": "string" - }, - "organization_id": { - "title": "Organization Id", - "type": "string" + "source": { + "description": "Where the new deployment is created from.", + "discriminator": { + "mapping": { + "model_archive": "#/components/schemas/DeploymentArchiveSourceV1" + }, + "propertyName": "kind" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/DeploymentArchiveSourceV1" + } + ], + "title": "Source" } }, "required": [ - "event_type", - "organization_id" + "source" ], - "title": "AuditLogEventRequireGroupBasedAdminsEnabledV1", + "title": "CreateModelDeploymentRequestV1", "type": "object" }, - "AuditLogEventSecretDeletedV1": { - "additionalProperties": false, - "description": "A secret was deleted.", + "DeploymentTombstoneV1": { + "description": "A model deployment tombstone.", "properties": { - "event_type": { - "const": "SECRET_DELETED", - "title": "Event Type", + "id": { + "description": "Unique identifier of the deployment", + "title": "Id", "type": "string" }, - "secret_id": { - "title": "Secret Id", - "type": "string" + "deleted": { + "description": "Whether the deployment was deleted", + "title": "Deleted", + "type": "boolean" }, - "secret_name": { - "title": "Secret Name", + "model_id": { + "description": "Unique identifier of the model", + "title": "Model Id", "type": "string" } }, "required": [ - "event_type", - "secret_id", - "secret_name" + "id", + "deleted", + "model_id" ], - "title": "AuditLogEventSecretDeletedV1", + "title": "DeploymentTombstoneV1", "type": "object" }, - "AuditLogEventSecretUpdatedV1": { + "UpdateDeploymentRequestV1": { "additionalProperties": false, - "description": "A secret was created or updated.", + "description": "A request to update a deployment.", "properties": { - "event_type": { - "const": "SECRET_UPDATED", - "title": "Event Type", - "type": "string" - }, - "secret_id": { - "title": "Secret Id", - "type": "string" - }, - "secret_name": { - "title": "Secret Name", - "type": "string" + "name": { + "anyOf": [ + { + "maxLength": 255, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "New name for the deployment, unique among the model's deployments. Only alphanumeric characters, hyphens, underscores, and periods are allowed.", + "examples": [ + "my-deployment" + ], + "title": "Name" } }, - "required": [ - "event_type", - "secret_id", - "secret_name" - ], - "title": "AuditLogEventSecretUpdatedV1", + "title": "UpdateDeploymentRequestV1", "type": "object" }, - "AuditLogEventSshCertificateSignedV1": { + "UpdateAutoscalingSettingsV1": { "additionalProperties": false, - "description": "An SSH certificate was signed for a workload.", + "description": "A request to update autoscaling settings for a deployment. All fields are optional, and we only update ones passed in.", "properties": { - "event_type": { - "const": "SSH_CERTIFICATE_SIGNED", - "title": "Event Type", - "type": "string" + "min_replica": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Minimum number of replicas", + "examples": [ + 0 + ], + "title": "Min Replica" }, - "workload_type": { - "title": "Workload Type", - "type": "string" + "max_replica": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Maximum number of replicas", + "examples": [ + 7 + ], + "title": "Max Replica" }, - "workload_id": { - "title": "Workload Id", - "type": "string" + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Timeframe of traffic considered for autoscaling decisions", + "examples": [ + 600 + ], + "title": "Autoscaling Window" }, - "project_id": { - "title": "Project Id", - "type": "string" + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Waiting period before scaling down any active replica", + "examples": [ + 120 + ], + "title": "Scale Down Delay" }, - "replica_id": { - "title": "Replica Id", - "type": "string" + "concurrency_target": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Number of requests per replica before scaling up", + "examples": [ + 2 + ], + "title": "Concurrency Target" + }, + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Target utilization percentage for scaling up/down.", + "examples": [ + 70 + ], + "title": "Target Utilization Percentage" }, - "proxy_address": { - "title": "Proxy Address", - "type": "string" + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Target number of in-flight tokens for autoscaling decisions. Early access only.", + "examples": [ + 40000 + ], + "title": "Target In Flight Tokens" }, - "expires_at": { - "title": "Expires At", - "type": "string" + "max_scale_down_rate": { + "anyOf": [ + { + "maximum": 50, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Maximum percentage of replicas that can be removed per autoscaling window (1\u201350). E.g. 20 means at most 20% of replicas are removed per window.", + "examples": [ + 20 + ], + "title": "Max Scale Down Rate" } }, - "required": [ - "event_type", - "workload_type", - "workload_id", - "project_id", - "replica_id", - "proxy_address", - "expires_at" - ], - "title": "AuditLogEventSshCertificateSignedV1", + "title": "UpdateAutoscalingSettingsV1", "type": "object" }, - "AuditLogEventTypeV1": { - "description": "Type of action recorded by an audit-log entry.", + "UpdateAutoscalingSettingsStatusV1": { + "description": "The status of a request to update autoscaling settings.", "enum": [ - "MODEL_DEPLOYED", - "MODEL_DEPLOYMENT_ACTIVATED", - "MODEL_DEPLOYMENT_DEACTIVATED", - "MODEL_DEPLOYMENT_RETRIED", - "MODEL_DEPLOYMENT_PROMOTED", - "MODEL_DEPLOYMENT_AUTOSCALING_SETTINGS_CHANGED", - "MODEL_DEPLOYMENT_REQUEST_BACKPRESSURE_SETTINGS_CHANGED", - "MODEL_DEPLOYMENT_INSTANCE_TYPE_CHANGED", - "MODEL_DEPLOYMENT_DELETED", - "MODEL_DELETED", - "CHAIN_DEPLOYED", - "CHAIN_DEPLOYMENT_ACTIVATED", - "CHAIN_DEPLOYMENT_DEACTIVATED", - "CHAIN_DEPLOYMENT_PROMOTED", - "CHAINLET_AUTOSCALING_SETTINGS_CHANGED", - "CHAINLET_INSTANCE_TYPE_CHANGED", - "CHAIN_DEPLOYMENT_DELETED", - "CHAIN_DELETED", - "CHAIN_ENVIRONMENT_CREATED", - "CHAIN_ENVIRONMENT_UPDATED", - "SECRET_UPDATED", - "SECRET_DELETED", - "API_KEY_CREATED", - "API_KEY_DELETED", - "GATEWAY_ENDPOINT_CREATED", - "GATEWAY_ENDPOINT_UPDATED", - "GATEWAY_ENDPOINT_DELETED", - "USER_INVITED", - "USER_JOINED_ORGANIZATION", - "WEBHOOK_SIGNING_SECRET_CREATED", - "WEBHOOK_SIGNING_SECRET_ROTATED", - "WEBHOOK_SIGNING_SECRET_DELETED", - "USER_ROLE_UPDATED", - "USER_TEAM_ROLE_UPDATED", - "USER_REMOVED", - "DIRECTORY_GROUP_ROLE_UPDATED", - "REQUIRE_GROUP_BASED_ADMINS_ENABLED", - "ENVIRONMENT_CREATED", - "ENVIRONMENT_UPDATED", - "ENVIRONMENT_DELETED", - "REPLICA_TERMINATED", - "MODEL_PROMOTION_CONTROL_ACTION", - "SSH_CERTIFICATE_SIGNED", - "VOLUME_DELETED", - "VOLUME_VERSION_DELETED", - "VOLUME_VERSION_RESTORED" + "ACCEPTED", + "QUEUED", + "UNCHANGED" ], - "title": "AuditLogEventTypeV1", + "title": "UpdateAutoscalingSettingsStatusV1", "type": "string" }, - "AuditLogEventUserInvitedV1": { - "additionalProperties": false, - "description": "A user was invited to the organization.", - "properties": { - "event_type": { - "const": "USER_INVITED", - "title": "Event Type", - "type": "string" - }, - "invited_user_email": { - "title": "Invited User Email", - "type": "string" - }, - "role_name": { - "title": "Role Name", - "type": "string" - } - }, - "required": [ - "event_type", - "invited_user_email", - "role_name" - ], - "title": "AuditLogEventUserInvitedV1", - "type": "object" - }, - "AuditLogEventUserJoinedOrganizationV1": { - "additionalProperties": false, - "description": "A user joined the organization.", - "properties": { - "event_type": { - "const": "USER_JOINED_ORGANIZATION", - "title": "Event Type", - "type": "string" - }, - "new_user_email": { - "title": "New User Email", - "type": "string" - }, - "user_id": { - "title": "User Id", - "type": "string" - } - }, - "required": [ - "event_type", - "new_user_email", - "user_id" - ], - "title": "AuditLogEventUserJoinedOrganizationV1", - "type": "object" - }, - "AuditLogEventUserRemovedV1": { - "additionalProperties": false, - "description": "A user was removed from the organization.", + "UpdateAutoscalingSettingsResponseV1": { + "description": "The response to a request to update autoscaling settings.", "properties": { - "event_type": { - "const": "USER_REMOVED", - "title": "Event Type", - "type": "string" + "status": { + "$ref": "#/components/schemas/UpdateAutoscalingSettingsStatusV1", + "description": "Status of the request to update autoscaling settings" }, - "removed_user_email": { - "title": "Removed User Email", + "message": { + "description": "A message describing the status of the request to update autoscaling settings", + "title": "Message", "type": "string" } }, "required": [ - "event_type", - "removed_user_email" + "status", + "message" ], - "title": "AuditLogEventUserRemovedV1", + "title": "UpdateAutoscalingSettingsResponseV1", "type": "object" }, - "AuditLogEventUserRoleUpdatedV1": { + "UpdateRequestBackpressureSettingsV1": { "additionalProperties": false, - "description": "A user's organization role was updated.", + "description": "A request to update request backpressure settings.", "properties": { - "event_type": { - "const": "USER_ROLE_UPDATED", - "title": "Event Type", - "type": "string" - }, - "user_id": { - "title": "User Id", - "type": "string" - }, - "user_email": { - "title": "User Email", - "type": "string" - }, - "new_role_name": { - "title": "New Role Name", - "type": "string" + "policy": { + "anyOf": [ + { + "$ref": "#/components/schemas/RequestBackpressurePolicyV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Backpressure policy to apply. Null indicates no policy (on update, clears an existing one).", + "examples": [ + "REJECT_ON_FULL" + ], + "x-null-distinct": true } }, - "required": [ - "event_type", - "user_id", - "user_email", - "new_role_name" - ], - "title": "AuditLogEventUserRoleUpdatedV1", + "title": "UpdateRequestBackpressureSettingsV1", "type": "object" }, - "AuditLogEventUserTeamRoleUpdatedV1": { - "additionalProperties": false, - "description": "A user's team role was updated.", + "PromoteRequestV1": { + "description": "A request to promote a deployment to production.", "properties": { - "event_type": { - "const": "USER_TEAM_ROLE_UPDATED", - "title": "Event Type", - "type": "string" - }, - "user_id": { - "title": "User Id", - "type": "string" - }, - "user_email": { - "title": "User Email", - "type": "string" - }, - "team_id": { - "title": "Team Id", - "type": "string" - }, - "team_name": { - "title": "Team Name", - "type": "string" + "scale_down_previous_production": { + "default": true, + "description": "Whether to scale down the previous production deployment after promoting", + "examples": [ + true + ], + "title": "Scale Down Previous Production", + "type": "boolean" }, - "new_role_name": { - "title": "New Role Name", - "type": "string" + "preserve_env_instance_type": { + "default": true, + "description": "Whether to use the promoting deployment's instance type or preserve target environment's instance type", + "examples": [ + true + ], + "title": "Preserve Env Instance Type", + "type": "boolean" } }, - "required": [ - "event_type", - "user_id", - "user_email", - "team_id", - "team_name", - "new_role_name" - ], - "title": "AuditLogEventUserTeamRoleUpdatedV1", + "title": "PromoteRequestV1", "type": "object" }, - "AuditLogEventVolumeDeletedV1": { - "additionalProperties": false, - "description": "A volume was deleted, tombstoning every version it still held.", + "ActivateResponseV1": { + "description": "The response to a request to activate a deployment.", "properties": { - "event_type": { - "const": "VOLUME_DELETED", - "title": "Event Type", - "type": "string" - }, - "volume_ref": { - "title": "Volume Ref", - "type": "string" - }, - "namespace": { - "title": "Namespace", - "type": "string" - }, - "volume_name": { - "title": "Volume Name", - "type": "string" + "success": { + "default": true, + "description": "Whether the deployment was successfully activated", + "title": "Success", + "type": "boolean" }, - "versions_deleted": { - "title": "Versions Deleted", - "type": "integer" + "no_op": { + "default": false, + "description": "Whether the request did nothing because the deployment was already active or on its way to becoming active", + "title": "No Op", + "type": "boolean" } }, - "required": [ - "event_type", - "volume_ref", - "namespace", - "volume_name", - "versions_deleted" - ], - "title": "AuditLogEventVolumeDeletedV1", + "title": "ActivateResponseV1", "type": "object" }, - "AuditLogEventVolumeVersionDeletedV1": { - "additionalProperties": false, - "description": "One version of a volume was deleted.", + "DeactivateResponseV1": { + "description": "The response to a request to deactivate a deployment.", "properties": { - "event_type": { - "const": "VOLUME_VERSION_DELETED", - "title": "Event Type", - "type": "string" - }, - "volume_ref": { - "title": "Volume Ref", - "type": "string" - }, - "namespace": { - "title": "Namespace", - "type": "string" - }, - "volume_name": { - "title": "Volume Name", - "type": "string" - }, - "version": { - "title": "Version", - "type": "string" + "success": { + "default": true, + "description": "Whether the deployment was successfully deactivated", + "title": "Success", + "type": "boolean" }, - "digest": { - "title": "Digest", - "type": "string" + "no_op": { + "default": false, + "description": "Whether the request did nothing because the deployment was already inactive", + "title": "No Op", + "type": "boolean" } }, - "required": [ - "event_type", - "volume_ref", - "namespace", - "volume_name", - "version", - "digest" - ], - "title": "AuditLogEventVolumeVersionDeletedV1", + "title": "DeactivateResponseV1", "type": "object" }, - "AuditLogEventVolumeVersionRestoredV1": { - "additionalProperties": false, - "description": "A deleted version of a volume was restored.", + "RetryDeploymentResponseV1": { + "description": "The response to a request to retry a deployment.", "properties": { - "event_type": { - "const": "VOLUME_VERSION_RESTORED", - "title": "Event Type", - "type": "string" - }, - "volume_ref": { - "title": "Volume Ref", - "type": "string" - }, - "namespace": { - "title": "Namespace", - "type": "string" - }, - "volume_name": { - "title": "Volume Name", - "type": "string" + "retried": { + "description": "Whether the retry was successfully initiated", + "title": "Retried", + "type": "boolean" }, - "version": { - "title": "Version", - "type": "string" + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Explanation of the result. Provided when retried is false to explain why retry was not possible.", + "title": "Reason" }, - "digest": { - "title": "Digest", - "type": "string" + "deployment": { + "$ref": "#/components/schemas/DeploymentV1", + "description": "The deployment that was retried" } }, "required": [ - "event_type", - "volume_ref", - "namespace", - "volume_name", - "version", - "digest" + "retried", + "deployment" ], - "title": "AuditLogEventVolumeVersionRestoredV1", + "title": "RetryDeploymentResponseV1", "type": "object" }, - "AuditLogEventWebhookSigningSecretCreatedV1": { - "additionalProperties": false, - "description": "A webhook signing secret was created.", + "DownloadDeploymentResponseV1": { + "description": "The response to a request to download a deployment's truss.", "properties": { - "event_type": { - "const": "WEBHOOK_SIGNING_SECRET_CREATED", - "title": "Event Type", - "type": "string" - }, - "webhook_signing_secret_id": { - "title": "Webhook Signing Secret Id", + "download_url": { + "description": "Presigned URL to download the truss tar file", + "title": "Download Url", "type": "string" } }, "required": [ - "event_type", - "webhook_signing_secret_id" + "download_url" ], - "title": "AuditLogEventWebhookSigningSecretCreatedV1", + "title": "DownloadDeploymentResponseV1", "type": "object" }, - "AuditLogEventWebhookSigningSecretDeletedV1": { - "additionalProperties": false, - "description": "A webhook signing secret was deleted.", + "DeploymentConfigResponseV1": { + "description": "The config of a deployment. Fields are populated per `output_format`.", "properties": { - "event_type": { - "const": "WEBHOOK_SIGNING_SECRET_DELETED", - "title": "Event Type", - "type": "string" + "config": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The parsed config of the deployment.", + "title": "Config" }, - "webhook_signing_secret_id": { - "title": "Webhook Signing Secret Id", - "type": "string" + "raw_config": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The original config.yaml text \u2014 preserves comments, ordering, formatting.", + "title": "Raw Config" } }, - "required": [ - "event_type", - "webhook_signing_secret_id" + "title": "DeploymentConfigResponseV1", + "type": "object" + }, + "DeploymentConfigOutputFormat": { + "enum": [ + "raw", + "parsed", + "both" + ], + "title": "DeploymentConfigOutputFormat", + "type": "string" + }, + "GetDeploymentConfigRequestV1": { + "description": "Query params for ``GET /v1/models/.../deployments/.../config``.", + "properties": { + "output_format": { + "$ref": "#/components/schemas/DeploymentConfigOutputFormat", + "default": "both", + "description": "'raw': verbatim config.yaml with comments (not available for deployments created before 2026-04-30). 'parsed': dict with server-side defaults applied (always available). 'both': both fields populated." + } + }, + "title": "GetDeploymentConfigRequestV1", + "type": "object" + }, + "LogLevelV1": { + "description": "A log severity level.", + "enum": [ + "DEBUG", + "INFO", + "WARNING", + "ERROR" ], - "title": "AuditLogEventWebhookSigningSecretDeletedV1", - "type": "object" + "title": "LogLevelV1", + "type": "string" }, - "AuditLogEventWebhookSigningSecretRotatedV1": { - "additionalProperties": false, - "description": "A webhook signing secret was rotated.", + "LogV1": { "properties": { - "event_type": { - "const": "WEBHOOK_SIGNING_SECRET_ROTATED", - "title": "Event Type", + "timestamp": { + "description": "Epoch nanosecond timestamp of the log message.", + "title": "Timestamp", "type": "string" }, - "webhook_signing_secret_id": { - "title": "Webhook Signing Secret Id", + "message": { + "description": "The contents of the log message. When the logger captured an exception, the traceback is appended after the message.", + "title": "Message", "type": "string" + }, + "replica": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The replica the log line was emitted from.", + "title": "Replica" + }, + "request_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The request ID associated with an inference request.", + "title": "Request Id" + }, + "level": { + "anyOf": [ + { + "$ref": "#/components/schemas/LogLevelV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Severity of the log line, if one was detected. null when unknown." } }, "required": [ - "event_type", - "webhook_signing_secret_id" + "timestamp", + "message", + "replica" ], - "title": "AuditLogEventWebhookSigningSecretRotatedV1", + "title": "LogV1", "type": "object" }, - "AuditLogPromotionControlActionV1": { - "description": "User-initiated promotion control signal recorded on a promotion-control event.", - "enum": [ - "PAUSE", - "RESUME", - "FORCE_CANCEL", - "FORCE_ROLL_FORWARD", - "GRACEFUL_CANCEL" - ], - "title": "AuditLogPromotionControlActionV1", - "type": "string" - }, - "AuditLogSourceV1": { - "description": "Surface that issued the audited action.", - "enum": [ - "UI", - "API", - "MCP", - "SYSTEM", - "OTHER" - ], - "title": "AuditLogSourceV1", - "type": "string" - }, - "ListAuditLogsResponseV1": { - "description": "A page of audit-log entries, newest first by default.", + "GetLogsResponseV1": { + "description": "A response to querying logs.", "properties": { - "items": { - "description": "Items in this page.", + "logs": { + "description": "Logs for a specific entity.", "items": { - "$ref": "#/components/schemas/AuditLogEntryV1" + "$ref": "#/components/schemas/LogV1" }, - "title": "Items", + "title": "Logs", "type": "array" - }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." } }, "required": [ - "items", - "pagination" + "logs" ], - "title": "ListAuditLogsResponseV1", + "title": "GetLogsResponseV1", "type": "object" }, - "AuditLogEventTypeGroupV1": { - "description": "Coarse grouping of event types, used to filter the audit log.", - "enum": [ - "DEPLOYED", - "PROMOTED", - "ACTIVATED_DEACTIVATED", - "AUTOSCALING_SETTINGS", - "REQUEST_BACKPRESSURE_SETTINGS", - "INSTANCE_TYPE_CHANGED", - "ENVIRONMENT_SETTINGS", - "REPLICA_TERMINATED", - "DELETED", - "SECRETS", - "API_KEYS", - "GATEWAY", - "WEBHOOK_SIGNING_SECRETS", - "USER_MANAGEMENT", - "DIRECTORY_GROUP_MANAGEMENT", - "SSH" - ], - "title": "AuditLogEventTypeGroupV1", - "type": "string" - }, - "AuditLogSortDirectionV1": { - "description": "Sort order of returned entries, by creation time.", + "SortOrderV1": { "enum": [ - "DESC", - "ASC" + "asc", + "desc" ], - "title": "AuditLogSortDirectionV1", + "title": "SortOrderV1", "type": "string" }, - "ListAuditLogsRequestV1": { - "description": "Query params for listing audit-log entries.", + "GetDeploymentLogsRequestV1": { + "description": "A request to fetch deployment logs.", "properties": { - "cursor": { + "start_epoch_millis": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", - "title": "Cursor" + "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + "title": "Start Epoch Millis" }, - "limit": { - "default": 20, - "description": "Maximum number of entries to return per page. Defaults to 20, and must be between 1 and 200.", - "maximum": 200, - "minimum": 1, - "title": "Limit", - "type": "integer" + "end_epoch_millis": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + "title": "End Epoch Millis" }, "direction": { - "$ref": "#/components/schemas/AuditLogSortDirectionV1", - "default": "DESC", - "description": "Sort order by the time the action occurred. Defaults to DESC (newest first). Ignored when paginating with a cursor." + "anyOf": [ + { + "$ref": "#/components/schemas/SortOrderV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Sort order for logs" + }, + "limit": { + "anyOf": [ + { + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 500, + "description": "Limit of logs to fetch in a single request", + "title": "Limit" + }, + "min_level": { + "anyOf": [ + { + "$ref": "#/components/schemas/LogLevelV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + }, + "replica": { + "anyOf": [ + { + "maxLength": 256, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Only return logs emitted by this replica (5-char short ID).", + "title": "Replica" + }, + "request_id": { + "anyOf": [ + { + "maxLength": 256, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Only return logs tagged with this inference request ID.", + "title": "Request Id" + }, + "component": { + "anyOf": [ + { + "maxLength": 256, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Only return logs from this component.", + "title": "Component" }, - "search": { + "search_pattern": { "anyOf": [ { + "maxLength": 256, "type": "string" }, { @@ -14649,112 +19275,214 @@ } ], "default": null, - "description": "Case-insensitive substring matched against resource names and IDs in the entry.", - "title": "Search" - }, - "event_type_groups": { - "description": "When set, returns only entries whose event type falls in one of these groups.", - "items": { - "$ref": "#/components/schemas/AuditLogEventTypeGroupV1" - }, - "title": "Event Type Groups", - "type": "array" + "description": "RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", + "title": "Search Pattern" }, - "user_ids": { - "description": "When set, returns only entries whose acting user is one of these IDs.", + "includes": { + "description": "Case-sensitive substrings that must all appear in the log message.", "items": { "type": "string" }, - "title": "User Ids", + "maxItems": 8, + "title": "Includes", "type": "array" }, - "deployment_ids": { - "description": "When set, returns only entries referencing one of these model deployment IDs.", + "excludes": { + "description": "Case-sensitive substrings; lines containing any of these are dropped.", "items": { "type": "string" }, - "title": "Deployment Ids", + "maxItems": 8, + "title": "Excludes", "type": "array" + } + }, + "title": "GetDeploymentLogsRequestV1", + "type": "object" + }, + "DeploymentPatchActionV1": { + "description": "How a patch op changes its target.", + "enum": [ + "ADD", + "UPDATE", + "REMOVE" + ], + "title": "DeploymentPatchActionV1", + "type": "string" + }, + "DeploymentPatchOpConfigV1": { + "description": "Replace the config when config.yaml changes.\n\nConfig has no action: it is always a full replacement of the parsed config.\nDerived changes (environment variables, external data, requirements) are\nemitted as their own ops alongside this one.", + "properties": { + "type": { + "const": "config", + "default": "config", + "title": "Type", + "type": "string" }, - "chain_deployment_ids": { - "description": "When set, returns only entries referencing one of these chain deployment IDs.", - "items": { - "type": "string" - }, - "title": "Chain Deployment Ids", - "type": "array" + "config": { + "additionalProperties": true, + "description": "The full parsed config as a JSON object.", + "title": "Config", + "type": "object" }, - "environment_names": { - "description": "When set, returns only entries for one of these environments.", - "items": { + "path": { + "default": "config.yaml", + "description": "Config file path within the source.", + "title": "Path", + "type": "string" + } + }, + "required": [ + "config" + ], + "title": "DeploymentPatchOpConfigV1", + "type": "object" + }, + "DeploymentPatchOpEnvVarV1": { + "description": "Add, update, or remove a single environment variable.", + "properties": { + "type": { + "const": "environment_variable", + "default": "environment_variable", + "title": "Type", + "type": "string" + }, + "action": { + "$ref": "#/components/schemas/DeploymentPatchActionV1", + "description": "How this op changes the variable." + }, + "name": { + "description": "The environment variable name.", + "title": "Name", + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The environment variable value. Required for add and update.", + "title": "Value" + } + }, + "required": [ + "action", + "name" + ], + "title": "DeploymentPatchOpEnvVarV1", + "type": "object" + }, + "DeploymentPatchOpExternalDataV1": { + "description": "Add, update, or remove a single external data item.\n\nExternal data is referenced by config, not stored in the source. The backend\nonly adds or removes it, where adding re-downloads (overwriting any existing\nfile), so `update` is accepted and treated identically to `add`.", + "properties": { + "type": { + "const": "external_data", + "default": "external_data", + "title": "Type", + "type": "string" + }, + "action": { + "$ref": "#/components/schemas/DeploymentPatchActionV1", + "description": "How this op changes the item. `UPDATE` is treated identically to `ADD`." + }, + "item": { + "additionalProperties": { "type": "string" }, - "title": "Environment Names", - "type": "array" + "description": "The single external data item descriptor.", + "title": "Item", + "type": "object" + } + }, + "required": [ + "action", + "item" + ], + "title": "DeploymentPatchOpExternalDataV1", + "type": "object" + }, + "DeploymentPatchOpModelCodeV1": { + "description": "Add, update, or remove a file under the model code directory.", + "properties": { + "type": { + "const": "model_code", + "default": "model_code", + "title": "Type", + "type": "string" }, - "sources": { - "description": "When set, returns only entries issued from one of these surfaces.", - "items": { - "$ref": "#/components/schemas/AuditLogSourceV1" - }, - "title": "Sources", - "type": "array" + "action": { + "$ref": "#/components/schemas/DeploymentPatchActionV1", + "description": "How this op changes the file." }, - "start_epoch_millis": { + "path": { + "description": "File path relative to the model code directory.", + "title": "Path", + "type": "string" + }, + "content": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Epoch milliseconds for the start of the window. Defaults to the beginning of the audit-log history.", - "title": "Start Epoch Millis" + "description": "UTF-8 file content. Null for removals and binary files.", + "title": "Content" }, - "end_epoch_millis": { + "content_bytes": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Epoch milliseconds for the end of the window. Defaults to the current time.", - "title": "End Epoch Millis" + "description": "Base64-encoded content for binary files.", + "title": "Content Bytes" + }, + "hot_reload": { + "default": false, + "description": "Whether the running server can pick up this change without a restart.", + "title": "Hot Reload", + "type": "boolean" } }, - "title": "ListAuditLogsRequestV1", + "required": [ + "action", + "path" + ], + "title": "DeploymentPatchOpModelCodeV1", "type": "object" }, - "ModelV1": { - "description": "A model.", + "DeploymentPatchOpPackageV1": { + "description": "Add, update, or remove a file under the bundled packages directory.", "properties": { - "id": { - "description": "Unique identifier of the model", - "title": "Id", + "type": { + "const": "package", + "default": "package", + "title": "Type", "type": "string" }, - "created_at": { - "description": "Time the model was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" + "action": { + "$ref": "#/components/schemas/DeploymentPatchActionV1", + "description": "How this op changes the file." }, - "name": { - "description": "Name of the model", - "title": "Name", + "path": { + "description": "File path relative to the bundled packages directory.", + "title": "Path", "type": "string" }, - "deployments_count": { - "description": "Number of deployments of the model", - "title": "Deployments Count", - "type": "integer" - }, - "production_deployment_id": { + "content": { "anyOf": [ { "type": "string" @@ -14763,10 +19491,11 @@ "type": "null" } ], - "description": "Unique identifier of the production deployment of the model", - "title": "Production Deployment Id" + "default": null, + "description": "UTF-8 file content. Null for removals and binary files.", + "title": "Content" }, - "development_deployment_id": { + "content_bytes": { "anyOf": [ { "type": "string" @@ -14775,644 +19504,717 @@ "type": "null" } ], - "description": "Unique identifier of the development deployment of the model", - "title": "Development Deployment Id" - }, - "instance_type_name": { - "description": "Name of the instance type for the production deployment of the model", - "title": "Instance Type Name", + "default": null, + "description": "Base64-encoded content for binary files.", + "title": "Content Bytes" + } + }, + "required": [ + "action", + "path" + ], + "title": "DeploymentPatchOpPackageV1", + "type": "object" + }, + "DeploymentPatchOpPythonRequirementV1": { + "description": "Add, update, or remove a single Python requirement.", + "properties": { + "type": { + "const": "python_requirement", + "default": "python_requirement", + "title": "Type", "type": "string" }, - "team_name": { - "description": "Name of the team associated with the model.", - "title": "Team Name", + "action": { + "$ref": "#/components/schemas/DeploymentPatchActionV1", + "description": "How this op changes the requirement." + }, + "requirement": { + "description": "The requirement to apply. For removals this is the package name; otherwise the full requirements.txt-style line.", + "title": "Requirement", "type": "string" } }, "required": [ - "id", - "created_at", - "name", - "deployments_count", - "production_deployment_id", - "development_deployment_id", - "instance_type_name", - "team_name" + "action", + "requirement" ], - "title": "ModelV1", + "title": "DeploymentPatchOpPythonRequirementV1", "type": "object" }, - "ModelsV1": { - "description": "A list of models.", + "DeploymentPatchPointV1": { + "description": "A patch point: the source state the next patch is computed against.\n\nThe content hash that identifies a point is derived from this state (see\n`DeploymentPatchPointWithHashV1.hash`), so a request only sends the state and\nthe server stamps the hash. A previous point's hash plus the current local\nsource is enough to compute the next patch, so the watch client reads the\npoint it is patching off of.", "properties": { - "models": { + "content_hashes": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": "Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", + "title": "Content Hashes", + "type": "object" + }, + "config": { + "description": "The verbatim config.yaml text for this source state.", + "title": "Config", + "type": "string" + }, + "requirements": { + "description": "Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", "items": { - "$ref": "#/components/schemas/ModelV1" + "type": "string" }, - "title": "Models", + "title": "Requirements", "type": "array" } }, "required": [ - "models" + "content_hashes", + "config" ], - "title": "ModelsV1", - "type": "object" - }, - "ModelsRequestV1": { - "description": "Request parameters for listing models.", - "properties": { - "name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "When set, returns only models with this exact name, if any. On a team-scoped route this matches at most one model; on the org-wide route it may match models in multiple teams, since names are unique only within a team.", - "title": "Name" - } - }, - "title": "ModelsRequestV1", + "title": "DeploymentPatchPointV1", "type": "object" }, - "LibraryListingSourceV1": { - "description": "Create a model by forking a library listing accessible to the caller's organization.", + "CreateDeploymentPatchRequestV1": { + "description": "A patch to stage against the development deployment.\n\nStaging is durable on its own: the patch is persisted independently of the\nlater sync, so a failed sync does not lose it.", "properties": { - "kind": { - "const": "library_listing", - "default": "library_listing", - "title": "Kind", - "type": "string" - }, - "lab_display_name": { - "description": "Identifier of the publishing organization, as returned by `GET /v1/library_models`.", - "title": "Lab Display Name", + "prev_patch_hash": { + "description": "Content hash of the patch point this patch is applied on - the link the staged patch must build on. A stale value (the base moved underneath the client) is rejected with a conflict.", + "title": "Prev Patch Hash", "type": "string" }, - "user_defined_listing_id": { - "description": "Listing identifier within the publishing organization.", - "title": "User Defined Listing Id", - "type": "string" + "next_patch_point": { + "$ref": "#/components/schemas/DeploymentPatchPointV1", + "description": "The source state after this patch. The server derives its content hash from `content_hashes`." }, - "deployed_model_name": { - "anyOf": [ - { - "type": "string" + "patch_ops": { + "description": "The ordered ops that make up this patch. At least one op is required; a patch that changes nothing is not a valid request. There is no op for a directory: a directory comes into existence when the first file under it is added, and is removed when its last file is removed, so directory creation and deletion happen implicitly through the file ops. Adding or removing an otherwise empty directory therefore produces no ops even though it changes the source hash; do not send a patch request for such a change.", + "items": { + "discriminator": { + "mapping": { + "config": "#/components/schemas/DeploymentPatchOpConfigV1", + "environment_variable": "#/components/schemas/DeploymentPatchOpEnvVarV1", + "external_data": "#/components/schemas/DeploymentPatchOpExternalDataV1", + "model_code": "#/components/schemas/DeploymentPatchOpModelCodeV1", + "package": "#/components/schemas/DeploymentPatchOpPackageV1", + "python_requirement": "#/components/schemas/DeploymentPatchOpPythonRequirementV1" + }, + "propertyName": "type" }, - { - "type": "null" - } - ], - "default": null, - "description": "Optional name for the new deployed model. Defaults to the listing's configured name.", - "title": "Deployed Model Name" + "oneOf": [ + { + "$ref": "#/components/schemas/DeploymentPatchOpModelCodeV1" + }, + { + "$ref": "#/components/schemas/DeploymentPatchOpPackageV1" + }, + { + "$ref": "#/components/schemas/DeploymentPatchOpConfigV1" + }, + { + "$ref": "#/components/schemas/DeploymentPatchOpPythonRequirementV1" + }, + { + "$ref": "#/components/schemas/DeploymentPatchOpEnvVarV1" + }, + { + "$ref": "#/components/schemas/DeploymentPatchOpExternalDataV1" + } + ] + }, + "minItems": 1, + "title": "Patch Ops", + "type": "array" } }, "required": [ - "lab_display_name", - "user_defined_listing_id" + "prev_patch_hash", + "next_patch_point", + "patch_ops" ], - "title": "LibraryListingSourceV1", + "title": "CreateDeploymentPatchRequestV1", "type": "object" }, - "ModelArchiveSourceV1": { - "description": "Create a model from an archive previously uploaded via the credentials\nissued by `POST /v1/prepare_model_upload`.", + "DeploymentPatchPointWithHashV1": { + "description": "A patch point plus its server-assigned content hash, returned in responses.\n\nRequests omit the hash (the server derives it from the source state); responses\ninclude it so the watch client can echo it back as the next patch's\n`prev_patch_hash` without having to recompute the fold itself.", "properties": { - "kind": { - "const": "model_archive", - "default": "model_archive", - "title": "Kind", - "type": "string" + "content_hashes": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": "Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", + "title": "Content Hashes", + "type": "object" }, - "name": { - "description": "Name of the new model.", - "title": "Name", + "config": { + "description": "The verbatim config.yaml text for this source state.", + "title": "Config", "type": "string" }, - "deployment": { - "$ref": "#/components/schemas/DeploymentArchivePayloadV1", - "description": "Deployment-level configuration for the model's first deployment." - }, - "s3_key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", - "title": "S3 Key" + "requirements": { + "description": "Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", + "items": { + "type": "string" + }, + "title": "Requirements", + "type": "array" }, - "disable_archive_download": { - "default": false, - "description": "If true, the uploaded archive is not downloadable after creation. Locked at model creation; cannot be changed by subsequent deployments.", - "title": "Disable Archive Download", - "type": "boolean" + "hash": { + "description": "Content hash identifying this exact source state, and the link patches build on. It is derived deterministically from `content_hashes`, so a request need not send it - the server derives it. It is derived by sorting the `content_hashes` keys as paths, splitting each key on '/' into its path components and ordering the keys by comparing those component lists element by element, each component compared by Unicode code point (equivalently UTF-8 byte order). Treating '/' as a path separator this way, rather than as the ordinary character U+002F, means a key that is an ancestor path sorts before a sibling whose name extends the first differing component (so e.g. 'a/b' sorts before 'a.b'). A blake3 hasher is then built, and for each key in that order updated with the blake3 digest (32 raw bytes) of the key encoded as UTF-8, then, when the entry is a file (non-null value), with that file's digest as 32 raw bytes. The stream uses raw digest bytes, but the values in `content_hashes` are those digests hex-encoded (64 hex chars), so decode each value from hex first. Directory entries (null value) contribute only their key digest. The result is the hasher's own hex digest.", + "title": "Hash", + "type": "string" } }, "required": [ - "name", - "deployment" + "content_hashes", + "config", + "hash" ], - "title": "ModelArchiveSourceV1", + "title": "DeploymentPatchPointWithHashV1", "type": "object" }, - "CreateModelRequestV1": { - "description": "Body for creating a model via `POST /v1/models`.", + "CreateDeploymentPatchResponseV1": { + "description": "The created patch, represented by the patch point it produced.", "properties": { - "source": { - "description": "Where the new model is created from.", - "discriminator": { - "mapping": { - "library_listing": "#/components/schemas/LibraryListingSourceV1", - "model_archive": "#/components/schemas/ModelArchiveSourceV1" - }, - "propertyName": "kind" - }, - "oneOf": [ - { - "$ref": "#/components/schemas/LibraryListingSourceV1" - }, - { - "$ref": "#/components/schemas/ModelArchiveSourceV1" - } - ], - "title": "Source" + "patch_point": { + "$ref": "#/components/schemas/DeploymentPatchPointWithHashV1", + "description": "The resulting patch point the staged patch produced; matches the pending point a subsequent state read returns." } }, "required": [ - "source" + "patch_point" ], - "title": "CreateModelRequestV1", + "title": "CreateDeploymentPatchResponseV1", "type": "object" }, - "AutoscalingSettingsV1": { - "description": "Autoscaling settings for a deployment.", + "GetDeploymentPatchesStateResponseV1": { + "description": "The patch state of the development deployment.\n\nThe watch client computes its next patch off `pending_patch_point` when present,\nelse `running_patch_point`.", "properties": { - "min_replica": { - "description": "Minimum number of replicas", - "title": "Min Replica", - "type": "integer" - }, - "max_replica": { - "description": "Maximum number of replicas", - "title": "Max Replica", - "type": "integer" + "running_patch_point": { + "$ref": "#/components/schemas/DeploymentPatchPointWithHashV1", + "description": "The patch point the deployment is recorded as running." }, - "autoscaling_window": { + "pending_patch_point": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/DeploymentPatchPointWithHashV1" }, { "type": "null" } ], - "description": "Timeframe of traffic considered for autoscaling decisions", - "title": "Autoscaling Window" - }, - "scale_down_delay": { + "default": null, + "description": "The latest staged-but-unsynced patch point, or null when the deployment is recorded as caught up." + } + }, + "required": [ + "running_patch_point" + ], + "title": "GetDeploymentPatchesStateResponseV1", + "type": "object" + }, + "SyncDeploymentPatchesRequestV1": { + "description": "Triggers a sync of any staged patches to the running deployment. Takes no\nfields: the deployment and its staged patches fully determine the sync.", + "properties": {}, + "title": "SyncDeploymentPatchesRequestV1", + "type": "object" + }, + "SyncDeploymentPatchesResponseV1": { + "description": "The outcome of a sync that ran.\n\nOperational failures (a transient patch failure, an invalid patch sequence)\nare surfaced as HTTP errors rather than fields here, so a 2xx means the sync\nreached a verdict.", + "properties": { + "needs_full_deploy_reason": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "description": "Waiting period before scaling down any active replica", - "title": "Scale Down Delay" - }, - "concurrency_target": { - "description": "Number of requests per replica before scaling up", - "title": "Concurrency Target", - "type": "integer" + "default": null, + "description": "If set, the change cannot be patched and a full push is required; the value explains why. If null, the deployment is now in sync.", + "title": "Needs Full Deploy Reason" + } + }, + "title": "SyncDeploymentPatchesResponseV1", + "type": "object" + }, + "ModelMetricDescriptorV1": { + "description": "Describes one metric. Its position in the response ``metric_descriptors``\nlist is the index used to read that metric out of each value set's ``values``.\n\nA metric may break down into multiple labeled series (e.g. latency quantiles,\nor volume by status). ``label_sets`` enumerates those series in order; each\nvalue set's value for this metric is a list aligned to that order.", + "properties": { + "name": { + "description": "Canonical metric name.", + "title": "Name", + "type": "string" }, - "target_utilization_percentage": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Target utilization percentage for scaling up/down.", - "title": "Target Utilization Percentage" + "unit_hint": { + "$ref": "#/components/schemas/ModelMetricUnitHintV1", + "description": "Advisory unit of the metric's values." }, - "target_in_flight_tokens": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Target number of in-flight tokens for autoscaling decisions. Early access only.", - "title": "Target In Flight Tokens" + "kind": { + "$ref": "#/components/schemas/ModelMetricKindV1", + "description": "Semantic hint for how the metric behaves (GAUGE, COUNTER, HISTOGRAM)." }, - "max_scale_down_rate": { - "anyOf": [ - { - "type": "integer" + "label_sets": { + "description": "The metric's series, in order. Each entry is the set of labels identifying one series; the value at the same index in each value set's ``values`` is that series' value. A plain metric has a single entry with no labels (`{}`). A histogram has one entry per quantile plus an average, e.g. {'quantile': '0.5'} \u2026 {'quantile': '0.99'}, {'stat': 'avg'}. A by-status metric has one entry per status, e.g. {'status': '2xx'}.", + "items": { + "additionalProperties": { + "type": "string" }, - { - "type": "null" - } - ], - "default": null, - "description": "Maximum percentage of replicas that can be removed per autoscaling window (1\u201350). E.g. 20 means at most 20% of replicas are removed per window.", - "title": "Max Scale Down Rate" + "type": "object" + }, + "title": "Label Sets", + "type": "array" } }, "required": [ - "min_replica", - "max_replica", - "autoscaling_window", - "scale_down_delay", - "concurrency_target", - "target_utilization_percentage" + "name", + "unit_hint", + "kind", + "label_sets" ], - "title": "AutoscalingSettingsV1", + "title": "ModelMetricDescriptorV1", "type": "object" }, - "DeploymentStatusV1": { - "description": "The status of a deployment.", + "ModelMetricKindV1": { + "description": "Semantic hint for how a metric behaves, to aid client rendering and\naggregation. It does not describe the value's shape (that is carried by the\ndescriptor's ``label_sets``; a metric may break down into multiple series).\n\n- ``GAUGE``: an instantaneous value (e.g. queue size, running requests).\n- ``COUNTER``: a cumulative total over the step (e.g. tokens, restarts).\n- ``HISTOGRAM``: a distribution, exposed as quantile/average series.", "enum": [ - "BUILDING", - "DEPLOYING", - "DEPLOY_FAILED", - "LOADING_MODEL", - "ACTIVE", - "UNHEALTHY", - "BUILD_FAILED", - "BUILD_STOPPED", - "DEACTIVATING", - "INACTIVE", - "FAILED", - "UPDATING", - "SCALED_TO_ZERO", - "WAKING_UP" + "GAUGE", + "COUNTER", + "HISTOGRAM" ], - "title": "DeploymentStatusV1", + "title": "ModelMetricKindV1", "type": "string" }, - "DeploymentV1": { - "description": "A deployment of a model.", + "ModelMetricModeV1": { + "description": "How metric values are aggregated over the request.", + "enum": [ + "CURRENT", + "SUMMARY", + "SERIES" + ], + "title": "ModelMetricModeV1", + "type": "string" + }, + "ModelMetricUnitHintV1": { + "description": "Advisory unit of a metric's values. Values are reported as scraped, so the\nhint describes the raw value (e.g. GPU memory is reported in mebibytes).\n\n- ``PER_SECOND``: a rate per second.\n- ``SECONDS``: a duration in seconds.\n- ``BYTES``: a size in bytes.\n- ``MEBIBYTES``: a size in mebibytes (MiB).\n- ``COUNT``: a dimensionless tally of discrete things.\n- ``RATIO``: a dimensionless ratio. Usually in ``[0, 1]`` but may exceed 1\n (e.g. CPU usage in cores = cpu-seconds/second).", + "enum": [ + "PER_SECOND", + "SECONDS", + "BYTES", + "MEBIBYTES", + "COUNT", + "RATIO" + ], + "title": "ModelMetricUnitHintV1", + "type": "string" + }, + "ModelMetricValueSetV1": { + "description": "The metric values for one time step. ``values`` is aligned by index to the\nresponse ``metric_descriptors`` list.", "properties": { - "id": { - "description": "Unique identifier of the deployment", - "title": "Id", - "type": "string" - }, - "created_at": { - "description": "Time the deployment was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "name": { - "description": "Name of the deployment", - "title": "Name", - "type": "string" - }, - "model_id": { - "description": "Unique identifier of the model", - "title": "Model Id", - "type": "string" - }, - "is_production": { - "description": "Whether the deployment is the production deployment of the model", - "title": "Is Production", - "type": "boolean" - }, - "is_development": { - "description": "Whether the deployment is the development deployment of the model", - "title": "Is Development", - "type": "boolean" + "start_epoch_millis": { + "description": "Start of the step. The step spans until the next value set's start, or the window end for the last one; a summary has a single value set starting at the window start.", + "title": "Start Epoch Millis", + "type": "integer" }, - "status": { - "$ref": "#/components/schemas/DeploymentStatusV1", - "description": "Status of the deployment" + "values": { + "description": "Metric values aligned to the ``metric_descriptors`` index. Each entry is a list aligned to that descriptor's ``label_sets`` (a single-element list for a plain metric). A series with no data in this step is null.", + "items": { + "items": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "type": "array" + }, + "title": "Values", + "type": "array" + } + }, + "required": [ + "start_epoch_millis", + "values" + ], + "title": "ModelMetricValueSetV1", + "type": "object" + }, + "GetModelMetricsResponseV1": { + "description": "Model metrics over a time window, index-mapped: metric descriptors appear once\nin ``metric_descriptors``; each value set's ``values`` are aligned to that order.", + "properties": { + "start_epoch_millis": { + "description": "Start of the returned window.", + "title": "Start Epoch Millis", + "type": "integer" }, - "active_replica_count": { - "description": "Number of active replicas", - "title": "Active Replica Count", + "end_epoch_millis": { + "description": "End of the returned window.", + "title": "End Epoch Millis", "type": "integer" }, - "autoscaling_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/AutoscalingSettingsV1" - }, - { - "type": "null" - } - ], - "description": "Autoscaling settings for the deployment. If null, the model has not finished deploying" + "mode": { + "$ref": "#/components/schemas/ModelMetricModeV1", + "description": "The aggregation mode used." }, - "instance_type_name": { + "step_seconds": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "description": "Name of the instance type the model deployment is running on", - "title": "Instance Type Name" + "description": "Seconds per step; populated only in SERIES mode, null otherwise.", + "title": "Step Seconds" }, - "environment": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "The environment associated with the deployment", - "title": "Environment" + "metric_descriptors": { + "description": "Descriptors for each metric; position defines the values index.", + "items": { + "$ref": "#/components/schemas/ModelMetricDescriptorV1" + }, + "title": "Metric Descriptors", + "type": "array" }, - "labels": { + "metric_values": { + "description": "Metric values per time step covering the window. In summary mode this always contains exactly one value set spanning the whole window.", + "items": { + "$ref": "#/components/schemas/ModelMetricValueSetV1" + }, + "title": "Metric Values", + "type": "array" + } + }, + "required": [ + "start_epoch_millis", + "end_epoch_millis", + "mode", + "step_seconds", + "metric_descriptors", + "metric_values" + ], + "title": "GetModelMetricsResponseV1", + "type": "object" + }, + "GetDeploymentMetricsRequestV1": { + "description": "Query params for ``GET /v1/models/.../deployments/.../metrics``.", + "properties": { + "mode": { + "$ref": "#/components/schemas/ModelMetricModeV1", + "default": "CURRENT", + "description": "'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." + }, + "start_epoch_millis": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "User-provided key-value labels for the deployment", - "title": "Labels" + "description": "Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", + "title": "Start Epoch Millis" }, - "region": { + "end_epoch_millis": { "anyOf": [ { - "$ref": "#/components/schemas/RegionV1" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "The selected region for the deployment, if any" + "description": "Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", + "title": "End Epoch Millis" }, - "request_backpressure_settings": { - "$ref": "#/components/schemas/RequestBackpressureSettingsV1", - "description": "Effective request backpressure settings for the deployment." + "metrics": { + "description": "Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", + "items": { + "type": "string" + }, + "title": "Metrics", + "type": "array" } }, - "required": [ - "id", - "created_at", - "name", - "model_id", - "is_production", - "is_development", - "status", - "active_replica_count", - "autoscaling_settings", - "instance_type_name", - "environment", - "request_backpressure_settings" - ], - "title": "DeploymentV1", + "title": "GetDeploymentMetricsRequestV1", "type": "object" }, - "RequestBackpressurePolicyV1": { - "enum": [ - "QUEUE_ON_FULL", - "REJECT_ON_FULL" - ], - "title": "RequestBackpressurePolicyV1", - "type": "string" + "TerminateReplicaResponseV1": { + "description": "The response to a request to terminate a replica in a deployment.", + "properties": { + "success": { + "default": true, + "description": "Whether the replica was successfully terminated", + "title": "Success", + "type": "boolean" + } + }, + "title": "TerminateReplicaResponseV1", + "type": "object" }, - "RequestBackpressureSettingsV1": { - "description": "Request backpressure settings for a deployment or environment.", + "SignSSHCertificateRequestV1": { + "description": "Request to sign an SSH certificate for accessing a workload pod.", "properties": { - "policy": { + "public_key": { + "description": "The user's SSH public key (e.g., 'ssh-ed25519 AAAA... user@host').", + "title": "Public Key", + "type": "string" + }, + "replica_id": { "anyOf": [ { - "$ref": "#/components/schemas/RequestBackpressurePolicyV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Backpressure policy. Null when no policy is set." - } - }, - "title": "RequestBackpressureSettingsV1", - "type": "object" - }, - "CreatedModelDeploymentV1": { - "description": "A newly created deployment and its model.", - "properties": { - "model": { - "$ref": "#/components/schemas/ModelV1", - "description": "The model the deployment belongs to. May have been created by this call." - }, - "deployment": { - "$ref": "#/components/schemas/DeploymentV1", - "description": "The newly created deployment." + "description": "The replica to connect to. Required for training jobs (e.g. '0'). Optional for inference (server picks a running replica if omitted).", + "title": "Replica Id" } }, "required": [ - "model", - "deployment" + "public_key" ], - "title": "CreatedModelDeploymentV1", + "title": "SignSSHCertificateRequestV1", "type": "object" }, - "ModelTombstoneV1": { - "description": "A model tombstone.", + "SignSSHCertificateResponseV1": { + "description": "Response containing a signed SSH certificate for proxy authentication.", "properties": { - "id": { - "description": "Unique identifier of the model", - "title": "Id", + "ssh_certificate": { + "description": "The signed SSH certificate in OpenSSH format.", + "title": "Ssh Certificate", "type": "string" }, - "deleted": { - "description": "Whether the model was deleted", - "title": "Deleted", - "type": "boolean" - } - }, - "required": [ - "id", - "deleted" - ], - "title": "ModelTombstoneV1", - "type": "object" - }, - "DeploymentsV1": { - "description": "A list of deployments of a model.", - "properties": { - "deployments": { - "description": "A list of deployments of a model", - "items": { - "$ref": "#/components/schemas/DeploymentV1" - }, - "title": "Deployments", - "type": "array" + "jwt": { + "description": "Signed JWT (ES256) for SSH proxy authorization.", + "title": "Jwt", + "type": "string" + }, + "proxy_address": { + "description": "Address of the SSH proxy to connect to (host:port).", + "title": "Proxy Address", + "type": "string" + }, + "ssh_cert_expires_at": { + "description": "When the certificate expires, in ISO 8601 format.", + "format": "date-time", + "title": "Ssh Cert Expires At", + "type": "string" } }, "required": [ - "deployments" + "ssh_certificate", + "jwt", + "proxy_address", + "ssh_cert_expires_at" ], - "title": "DeploymentsV1", + "title": "SignSSHCertificateResponseV1", "type": "object" }, - "DeploymentsRequestV1": { - "description": "Request parameters for listing a model's deployments.", + "AutoscalingScheduleSettingsV1": { "properties": { - "name": { + "min_replica": { + "description": "Minimum number of replicas", + "title": "Min Replica", + "type": "integer" + }, + "max_replica": { + "description": "Maximum number of replicas", + "title": "Max Replica", + "type": "integer" + }, + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Timeframe of traffic considered for autoscaling decisions. Null inherits the environment value.", + "title": "Autoscaling Window" + }, + "scale_down_delay": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Waiting period before scaling down any active replica. Null inherits the environment value.", + "title": "Scale Down Delay" + }, + "concurrency_target": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "default": null, - "description": "When set, returns only the deployment with this exact name, if any.", - "title": "Name" - } - }, - "title": "DeploymentsRequestV1", - "type": "object" - }, - "DeploymentArchiveSourceV1": { - "description": "Add a deployment from an archive previously uploaded via the credentials\nissued by `POST /v1/prepare_model_upload`.", - "properties": { - "kind": { - "const": "model_archive", - "default": "model_archive", - "title": "Kind", - "type": "string" + "description": "Number of requests per replica before scaling up. Null inherits the environment value.", + "title": "Concurrency Target" }, - "deployment": { - "$ref": "#/components/schemas/DeploymentArchivePayloadV1", - "description": "Deployment-level configuration." + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Target utilization percentage for scaling up/down. Null inherits the environment value.", + "title": "Target Utilization Percentage" }, - "s3_key": { + "target_in_flight_tokens": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "default": null, - "description": "S3 key of the uploaded archive, from the credentials returned by `POST /v1/prepare_model_upload`. Omit for model formats that are not built from an archive (for example, BIS-LLM), where prepare issues no upload target.", - "title": "S3 Key" + "description": "Target number of in-flight tokens for autoscaling decisions. Null inherits the environment value. Early access only.", + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Maximum percentage of replicas that can be removed per autoscaling window. Null inherits the environment value.", + "title": "Max Scale Down Rate" } }, "required": [ - "deployment" + "min_replica", + "max_replica", + "autoscaling_window", + "scale_down_delay", + "concurrency_target", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate" ], - "title": "DeploymentArchiveSourceV1", + "title": "AutoscalingScheduleSettingsV1", "type": "object" }, - "CreateModelDeploymentRequestV1": { - "description": "Body for adding a deployment to an existing model via\n`POST /v1/models/{model_id}/deployments`.", + "AutoscalingScheduleStateV1": { "properties": { - "source": { - "description": "Where the new deployment is created from.", - "discriminator": { - "mapping": { - "model_archive": "#/components/schemas/DeploymentArchiveSourceV1" + "schedule_id": { + "anyOf": [ + { + "type": "string" }, - "propertyName": "kind" - }, - "oneOf": [ { - "$ref": "#/components/schemas/DeploymentArchiveSourceV1" + "type": "null" } ], - "title": "Source" + "description": "Stable schedule identifier, or null when the baseline settings apply", + "title": "Schedule Id" + }, + "autoscaling_settings": { + "$ref": "#/components/schemas/AutoscalingSettingsV1", + "description": "Autoscaling settings on the current serving deployment. In a PATCH response, this snapshot can precede asynchronous schedule reconciliation; poll the GET endpoint for the applied state." } }, "required": [ - "source" + "schedule_id", + "autoscaling_settings" ], - "title": "CreateModelDeploymentRequestV1", + "title": "AutoscalingScheduleStateV1", "type": "object" }, - "DeploymentTombstoneV1": { - "description": "A model deployment tombstone.", + "AutoscalingScheduleV1": { "properties": { "id": { - "description": "Unique identifier of the deployment", + "description": "Stable unique identifier of the schedule", "title": "Id", "type": "string" }, - "deleted": { - "description": "Whether the deployment was deleted", - "title": "Deleted", + "name": { + "description": "Name of the schedule", + "title": "Name", + "type": "string" + }, + "enabled": { + "description": "Whether the schedule is enabled", + "title": "Enabled", "type": "boolean" }, - "model_id": { - "description": "Unique identifier of the model", - "title": "Model Id", + "autoscaling_settings": { + "$ref": "#/components/schemas/AutoscalingScheduleSettingsV1", + "description": "Raw autoscaling overrides applied during the schedule window" + }, + "cadence": { + "description": "Cadence of the schedule. DAILY runs once per selected weekday; HOURLY repeats the minute window every hour on selected weekdays.", + "enum": [ + "DAILY", + "HOURLY" + ], + "title": "Cadence", "type": "string" - } - }, - "required": [ - "id", - "deleted", - "model_id" - ], - "title": "DeploymentTombstoneV1", - "type": "object" - }, - "UpdateDeploymentRequestV1": { - "additionalProperties": false, - "description": "A request to update a deployment.", - "properties": { - "name": { + }, + "weekdays": { + "description": "Weekdays on which the schedule runs", + "items": { + "$ref": "#/components/schemas/AutoscalingScheduleWeekdayV1" + }, + "title": "Weekdays", + "type": "array" + }, + "start_hour": { "anyOf": [ { - "maxLength": 255, - "minLength": 1, - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "New name for the deployment, unique among the model's deployments. Only alphanumeric characters, hyphens, underscores, and periods are allowed.", - "examples": [ - "my-deployment" - ], - "title": "Name" - } - }, - "title": "UpdateDeploymentRequestV1", - "type": "object" - }, - "UpdateAutoscalingSettingsV1": { - "additionalProperties": false, - "description": "A request to update autoscaling settings for a deployment. All fields are optional, and we only update ones passed in.", - "properties": { - "min_replica": { + "description": "Start hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", + "title": "Start Hour" + }, + "start_minute": { + "description": "Start minute of the schedule window", + "title": "Start Minute", + "type": "integer" + }, + "end_hour": { "anyOf": [ { "type": "integer" @@ -15422,256 +20224,220 @@ } ], "default": null, - "description": "Minimum number of replicas", - "examples": [ - 0 - ], - "title": "Min Replica" + "description": "End hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", + "title": "End Hour" }, - "max_replica": { + "end_minute": { + "description": "End minute of the schedule window", + "title": "End Minute", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "enabled", + "autoscaling_settings", + "cadence", + "weekdays", + "start_minute", + "end_minute" + ], + "title": "AutoscalingScheduleV1", + "type": "object" + }, + "AutoscalingScheduleWeekdayV1": { + "enum": [ + "SUNDAY", + "MONDAY", + "TUESDAY", + "WEDNESDAY", + "THURSDAY", + "FRIDAY", + "SATURDAY" + ], + "title": "AutoscalingScheduleWeekdayV1", + "type": "string" + }, + "EnvironmentAutoscalingSchedulesV1": { + "properties": { + "timezone": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Maximum number of replicas", - "examples": [ - 7 - ], - "title": "Max Replica" + "description": "IANA timezone shared by all schedules. Omitted when no schedules exist.", + "title": "Timezone" + }, + "schedules": { + "description": "Autoscaling schedules ordered by creation time and stable identifier", + "items": { + "discriminator": { + "mapping": { + "DAILY": "#/components/schemas/AutoscalingScheduleV1", + "HOURLY": "#/components/schemas/AutoscalingScheduleV1", + "ONE_TIME": "#/components/schemas/OneTimeAutoscalingScheduleV1" + }, + "propertyName": "cadence" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/AutoscalingScheduleV1" + }, + { + "$ref": "#/components/schemas/OneTimeAutoscalingScheduleV1" + } + ] + }, + "title": "Schedules", + "type": "array" }, - "autoscaling_window": { + "applied_state": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/AutoscalingScheduleStateV1" }, { "type": "null" } ], - "default": null, - "description": "Timeframe of traffic considered for autoscaling decisions", - "examples": [ - 600 - ], - "title": "Autoscaling Window" + "description": "Autoscaling state on the current serving deployment, or null when no deployment exists" + } + }, + "required": [ + "schedules", + "applied_state" + ], + "title": "EnvironmentAutoscalingSchedulesV1", + "type": "object" + }, + "EnvironmentV1": { + "description": "Environment for oracles.", + "properties": { + "name": { + "description": "Name of the environment", + "title": "Name", + "type": "string" }, - "scale_down_delay": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Waiting period before scaling down any active replica", - "examples": [ - 120 - ], - "title": "Scale Down Delay" + "created_at": { + "description": "Time the environment was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", + "type": "string" }, - "concurrency_target": { + "model_id": { + "description": "Unique identifier of the model", + "title": "Model Id", + "type": "string" + }, + "current_deployment": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/DeploymentV1" }, { "type": "null" } ], - "default": null, - "description": "Number of requests per replica before scaling up", - "examples": [ - 2 - ], - "title": "Concurrency Target" + "description": "Current deployment of the environment" }, - "target_utilization_percentage": { + "candidate_deployment": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/DeploymentV1" }, { "type": "null" } ], "default": null, - "description": "Target utilization percentage for scaling up/down.", - "examples": [ - 70 - ], - "title": "Target Utilization Percentage" + "description": "Candidate deployment being promoted to the environment, if a promotion is in progress" }, - "target_in_flight_tokens": { + "in_progress_promotion": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/InProgressPromotionV1" }, { "type": "null" } ], "default": null, - "description": "Target number of in-flight tokens for autoscaling decisions. Early access only.", - "examples": [ - 40000 - ], - "title": "Target In Flight Tokens" + "description": "Details of the in-progress promotion, if any" }, - "max_scale_down_rate": { + "autoscaling_settings": { + "$ref": "#/components/schemas/AutoscalingSettingsV1", + "description": "Autoscaling settings for the environment" + }, + "promotion_settings": { + "$ref": "#/components/schemas/PromotionSettingsV1", + "description": "Promotion settings for the environment" + }, + "instance_type": { + "$ref": "#/components/schemas/InstanceTypeV1", + "description": "Instance type for the environment" + }, + "request_backpressure_settings": { + "$ref": "#/components/schemas/RequestBackpressureSettingsV1", + "description": "Request backpressure settings for the environment." + }, + "autoscaling_schedules": { "anyOf": [ { - "maximum": 50, - "minimum": 1, - "type": "integer" + "$ref": "#/components/schemas/EnvironmentAutoscalingSchedulesV1" }, { "type": "null" } ], "default": null, - "description": "Maximum percentage of replicas that can be removed per autoscaling window (1\u201350). E.g. 20 means at most 20% of replicas are removed per window.", - "examples": [ - 20 - ], - "title": "Max Scale Down Rate" + "description": "Autoscaling schedules and their evaluated state" } }, - "title": "UpdateAutoscalingSettingsV1", + "required": [ + "name", + "created_at", + "model_id", + "current_deployment", + "autoscaling_settings", + "promotion_settings", + "instance_type", + "request_backpressure_settings" + ], + "title": "EnvironmentV1", "type": "object" }, - "UpdateAutoscalingSettingsStatusV1": { - "description": "The status of a request to update autoscaling settings.", + "InProgressPromotionStatusV1": { "enum": [ - "ACCEPTED", - "QUEUED", - "UNCHANGED" + "RELEASING", + "RAMPING_UP", + "RAMPING_DOWN", + "PAUSED", + "SUCCEEDED", + "FAILED", + "CANCELED" ], - "title": "UpdateAutoscalingSettingsStatusV1", + "title": "InProgressPromotionStatusV1", "type": "string" }, - "UpdateAutoscalingSettingsResponseV1": { - "description": "The response to a request to update autoscaling settings.", - "properties": { - "status": { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsStatusV1", - "description": "Status of the request to update autoscaling settings" - }, - "message": { - "description": "A message describing the status of the request to update autoscaling settings", - "title": "Message", - "type": "string" - } - }, - "required": [ - "status", - "message" - ], - "title": "UpdateAutoscalingSettingsResponseV1", - "type": "object" - }, - "UpdateRequestBackpressureSettingsV1": { - "additionalProperties": false, - "description": "A request to update request backpressure settings.", - "properties": { - "policy": { - "anyOf": [ - { - "$ref": "#/components/schemas/RequestBackpressurePolicyV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Backpressure policy to apply. Null indicates no policy (on update, clears an existing one).", - "examples": [ - "REJECT_ON_FULL" - ], - "x-null-distinct": true - } - }, - "title": "UpdateRequestBackpressureSettingsV1", - "type": "object" - }, - "PromoteRequestV1": { - "description": "A request to promote a deployment to production.", - "properties": { - "scale_down_previous_production": { - "default": true, - "description": "Whether to scale down the previous production deployment after promoting", - "examples": [ - true - ], - "title": "Scale Down Previous Production", - "type": "boolean" - }, - "preserve_env_instance_type": { - "default": true, - "description": "Whether to use the promoting deployment's instance type or preserve target environment's instance type", - "examples": [ - true - ], - "title": "Preserve Env Instance Type", - "type": "boolean" - } - }, - "title": "PromoteRequestV1", - "type": "object" - }, - "ActivateResponseV1": { - "description": "The response to a request to activate a deployment.", - "properties": { - "success": { - "default": true, - "description": "Whether the deployment was successfully activated", - "title": "Success", - "type": "boolean" - }, - "no_op": { - "default": false, - "description": "Whether the request did nothing because the deployment was already active or on its way to becoming active", - "title": "No Op", - "type": "boolean" - } - }, - "title": "ActivateResponseV1", - "type": "object" - }, - "DeactivateResponseV1": { - "description": "The response to a request to deactivate a deployment.", - "properties": { - "success": { - "default": true, - "description": "Whether the deployment was successfully deactivated", - "title": "Success", - "type": "boolean" - }, - "no_op": { - "default": false, - "description": "Whether the request did nothing because the deployment was already inactive", - "title": "No Op", - "type": "boolean" - } - }, - "title": "DeactivateResponseV1", - "type": "object" - }, - "RetryDeploymentResponseV1": { - "description": "The response to a request to retry a deployment.", - "properties": { - "retried": { - "description": "Whether the retry was successfully initiated", - "title": "Retried", - "type": "boolean" + "InProgressPromotionV1": { + "description": "Details of an in-progress promotion.", + "properties": { + "status": { + "$ref": "#/components/schemas/InProgressPromotionStatusV1", + "description": "Status of the promotion" }, - "reason": { + "percent_traffic_to_new_version": { + "description": "Percentage of traffic routed to the candidate deployment", + "title": "Percent Traffic To New Version", + "type": "integer" + }, + "error_message": { "anyOf": [ { "type": "string" @@ -15681,515 +20447,660 @@ } ], "default": null, - "description": "Explanation of the result. Provided when retried is false to explain why retry was not possible.", - "title": "Reason" + "description": "Error message if promotion failed", + "title": "Error Message" }, - "deployment": { - "$ref": "#/components/schemas/DeploymentV1", - "description": "The deployment that was retried" + "rolling_deploy": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Whether this is a rolling deploy", + "title": "Rolling Deploy" } }, "required": [ - "retried", - "deployment" + "status", + "percent_traffic_to_new_version" ], - "title": "RetryDeploymentResponseV1", + "title": "InProgressPromotionV1", "type": "object" }, - "DownloadDeploymentResponseV1": { - "description": "The response to a request to download a deployment's truss.", + "OneTimeAutoscalingScheduleV1": { "properties": { - "download_url": { - "description": "Presigned URL to download the truss tar file", - "title": "Download Url", + "id": { + "description": "Stable unique identifier of the schedule", + "title": "Id", + "type": "string" + }, + "name": { + "description": "Name of the schedule", + "title": "Name", + "type": "string" + }, + "enabled": { + "description": "Whether the schedule is enabled", + "title": "Enabled", + "type": "boolean" + }, + "autoscaling_settings": { + "$ref": "#/components/schemas/AutoscalingScheduleSettingsV1", + "description": "Raw autoscaling overrides applied during the schedule window" + }, + "cadence": { + "const": "ONE_TIME", + "description": "One-time schedule cadence", + "title": "Cadence", + "type": "string" + }, + "start_at": { + "description": "Inclusive start of the schedule window", + "format": "date-time", + "title": "Start At", + "type": "string" + }, + "end_at": { + "description": "Exclusive end of the schedule window", + "format": "date-time", + "title": "End At", "type": "string" } }, "required": [ - "download_url" + "id", + "name", + "enabled", + "autoscaling_settings", + "cadence", + "start_at", + "end_at" ], - "title": "DownloadDeploymentResponseV1", + "title": "OneTimeAutoscalingScheduleV1", "type": "object" }, - "DeploymentConfigResponseV1": { - "description": "The config of a deployment. Fields are populated per `output_format`.", + "PromotionCleanupStrategyV1": { + "description": "The promotion cleanup strategy.", + "enum": [ + "KEEP", + "SCALE_TO_ZERO", + "DEACTIVATE" + ], + "title": "PromotionCleanupStrategyV1", + "type": "string" + }, + "PromotionSettingsV1": { + "description": "Promotion settings for promoting chains and oracles", "properties": { - "config": { + "redeploy_on_promotion": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "boolean" }, { "type": "null" } ], - "default": null, - "description": "The parsed config of the deployment.", - "title": "Config" + "default": false, + "description": "Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", + "examples": [ + true + ], + "title": "Redeploy On Promotion" }, - "raw_config": { + "rolling_deploy": { "anyOf": [ { - "type": "string" + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Whether the environment should rely on rolling deploy orchestration.", + "examples": [ + true + ], + "title": "Rolling Deploy" + }, + "promotion_cleanup_strategy": { + "anyOf": [ + { + "$ref": "#/components/schemas/PromotionCleanupStrategyV1" + }, + { + "type": "null" + } + ], + "default": "SCALE_TO_ZERO", + "description": "The cleanup strategy to use after a promotion completes.", + "examples": [ + "SCALE_TO_ZERO" + ] + }, + "rolling_deploy_config": { + "anyOf": [ + { + "$ref": "#/components/schemas/RollingDeployConfigV1" }, { "type": "null" } ], "default": null, - "description": "The original config.yaml text \u2014 preserves comments, ordering, formatting.", - "title": "Raw Config" - } - }, - "title": "DeploymentConfigResponseV1", - "type": "object" - }, - "DeploymentConfigOutputFormat": { - "enum": [ - "raw", - "parsed", - "both" - ], - "title": "DeploymentConfigOutputFormat", - "type": "string" - }, - "GetDeploymentConfigRequestV1": { - "description": "Query params for ``GET /v1/models/.../deployments/.../config``.", - "properties": { - "output_format": { - "$ref": "#/components/schemas/DeploymentConfigOutputFormat", - "default": "both", - "description": "'raw': verbatim config.yaml with comments (not available for deployments created before 2026-04-30). 'parsed': dict with server-side defaults applied (always available). 'both': both fields populated." - } - }, - "title": "GetDeploymentConfigRequestV1", - "type": "object" - }, - "LogLevelV1": { - "description": "A log severity level.", - "enum": [ - "DEBUG", - "INFO", - "WARNING", - "ERROR" - ], - "title": "LogLevelV1", - "type": "string" - }, - "LogV1": { - "properties": { - "timestamp": { - "description": "Epoch nanosecond timestamp of the log message.", - "title": "Timestamp", - "type": "string" + "description": "Rolling deploy configuration for promotions" }, - "message": { - "description": "The contents of the log message. When the logger captured an exception, the traceback is appended after the message.", - "title": "Message", - "type": "string" + "ramp_up_while_promoting": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Whether to ramp up traffic while promoting", + "examples": [ + true + ], + "title": "Ramp Up While Promoting" }, - "replica": { + "ramp_up_duration_seconds": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "description": "The replica the log line was emitted from.", - "title": "Replica" + "default": 600, + "description": "Duration of the ramp up in seconds", + "examples": [ + 600 + ], + "title": "Ramp Up Duration Seconds" + } + }, + "title": "PromotionSettingsV1", + "type": "object" + }, + "RollingDeployConfigV1": { + "description": "Rolling deploy config for promoting chains and oracles", + "properties": { + "rolling_deploy_strategy": { + "$ref": "#/components/schemas/RollingDeployStrategyV1", + "default": "REPLICA", + "description": "The rolling deploy strategy to use for promotions.", + "examples": [ + "REPLICA" + ] + }, + "max_surge_percent": { + "default": 25, + "description": "The maximum surge percentage for rolling deploys.", + "examples": [ + 25 + ], + "title": "Max Surge Percent", + "type": "integer" + }, + "max_unavailable_percent": { + "default": 0, + "description": "The maximum unavailable percentage for rolling deploys.", + "examples": [ + 10 + ], + "title": "Max Unavailable Percent", + "type": "integer" }, - "request_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } + "stabilization_time_seconds": { + "default": 0, + "description": "The stabilization time in seconds for rolling deploys.", + "examples": [ + 300 ], - "default": null, - "description": "The request ID associated with an inference request.", - "title": "Request Id" + "title": "Stabilization Time Seconds", + "type": "integer" }, - "level": { - "anyOf": [ - { - "$ref": "#/components/schemas/LogLevelV1" - }, - { - "type": "null" - } + "replica_overhead_percent": { + "default": 0, + "description": "The replica overhead percentage for rolling deploys.", + "examples": [ + 0 ], - "default": null, - "description": "Severity of the log line, if one was detected. null when unknown." + "title": "Replica Overhead Percent", + "type": "integer" } }, - "required": [ - "timestamp", - "message", - "replica" - ], - "title": "LogV1", + "title": "RollingDeployConfigV1", "type": "object" }, - "GetLogsResponseV1": { - "description": "A response to querying logs.", + "RollingDeployStrategyV1": { + "description": "The rolling deploy strategy.", + "enum": [ + "REPLICA" + ], + "title": "RollingDeployStrategyV1", + "type": "string" + }, + "EnvironmentsV1": { + "description": "list of environments", "properties": { - "logs": { - "description": "Logs for a specific entity.", + "environments": { "items": { - "$ref": "#/components/schemas/LogV1" + "$ref": "#/components/schemas/EnvironmentV1" }, - "title": "Logs", + "title": "Environments", "type": "array" } }, "required": [ - "logs" + "environments" ], - "title": "GetLogsResponseV1", + "title": "EnvironmentsV1", "type": "object" }, - "SortOrderV1": { - "enum": [ - "asc", - "desc" - ], - "title": "SortOrderV1", - "type": "string" - }, - "GetDeploymentLogsRequestV1": { - "description": "A request to fetch deployment logs.", + "UpdatePromotionSettingsV1": { + "description": "Promotion settings for model promotion", "properties": { - "start_epoch_millis": { + "redeploy_on_promotion": { "anyOf": [ { - "type": "integer" + "type": "boolean" }, { "type": "null" } ], "default": null, - "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - "title": "Start Epoch Millis" + "description": "Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", + "examples": [ + true + ], + "title": "Redeploy On Promotion" }, - "end_epoch_millis": { + "rolling_deploy": { "anyOf": [ { - "type": "integer" + "type": "boolean" }, { "type": "null" } ], "default": null, - "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - "title": "End Epoch Millis" + "description": "Whether the environment should rely on rolling deploy orchestration.", + "examples": [ + true + ], + "title": "Rolling Deploy" }, - "direction": { + "promotion_cleanup_strategy": { "anyOf": [ { - "$ref": "#/components/schemas/SortOrderV1" + "$ref": "#/components/schemas/PromotionCleanupStrategyV1" }, { "type": "null" } ], "default": null, - "description": "Sort order for logs" + "description": "The cleanup strategy to use after a promotion completes.", + "examples": [ + "SCALE_TO_ZERO" + ] }, - "limit": { + "rolling_deploy_config": { "anyOf": [ { - "maximum": 1000, - "minimum": 1, - "type": "integer" + "$ref": "#/components/schemas/UpdateRollingDeployConfigV1" }, { "type": "null" } ], - "default": 500, - "description": "Limit of logs to fetch in a single request", - "title": "Limit" + "default": null, + "description": "Rolling deploy configuration for promotions" }, - "min_level": { + "ramp_up_while_promoting": { "anyOf": [ { - "$ref": "#/components/schemas/LogLevelV1" + "type": "boolean" }, { "type": "null" } ], "default": null, - "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + "description": "Whether to ramp up traffic while promoting", + "examples": [ + true + ], + "title": "Ramp Up While Promoting" }, - "replica": { + "ramp_up_duration_seconds": { "anyOf": [ { - "maxLength": 256, - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Only return logs emitted by this replica (5-char short ID).", - "title": "Replica" - }, - "request_id": { + "description": "Duration of the ramp up in seconds", + "examples": [ + 600 + ], + "title": "Ramp Up Duration Seconds" + } + }, + "title": "UpdatePromotionSettingsV1", + "type": "object" + }, + "UpdateRollingDeployConfigV1": { + "description": "Rolling deploy config for promoting chains and oracles", + "properties": { + "rolling_deploy_strategy": { "anyOf": [ { - "maxLength": 256, - "type": "string" + "$ref": "#/components/schemas/RollingDeployStrategyV1" }, { "type": "null" } ], "default": null, - "description": "Only return logs tagged with this inference request ID.", - "title": "Request Id" + "description": "The rolling deploy strategy to use for promotions.", + "examples": [ + "REPLICA" + ] }, - "component": { + "max_surge_percent": { "anyOf": [ { - "maxLength": 256, - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Only return logs from this component.", - "title": "Component" + "description": "The maximum surge percentage for rolling deploys.", + "examples": [ + 25 + ], + "title": "Max Surge Percent" }, - "search_pattern": { + "max_unavailable_percent": { "anyOf": [ { - "maxLength": 256, - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", - "title": "Search Pattern" - }, - "includes": { - "description": "Case-sensitive substrings that must all appear in the log message.", - "items": { - "type": "string" - }, - "maxItems": 8, - "title": "Includes", - "type": "array" - }, - "excludes": { - "description": "Case-sensitive substrings; lines containing any of these are dropped.", - "items": { - "type": "string" - }, - "maxItems": 8, - "title": "Excludes", - "type": "array" - } - }, - "title": "GetDeploymentLogsRequestV1", - "type": "object" - }, - "DeploymentPatchActionV1": { - "description": "How a patch op changes its target.", - "enum": [ - "ADD", - "UPDATE", - "REMOVE" - ], - "title": "DeploymentPatchActionV1", - "type": "string" - }, - "DeploymentPatchOpConfigV1": { - "description": "Replace the config when config.yaml changes.\n\nConfig has no action: it is always a full replacement of the parsed config.\nDerived changes (environment variables, external data, requirements) are\nemitted as their own ops alongside this one.", - "properties": { - "type": { - "const": "config", - "default": "config", - "title": "Type", - "type": "string" + "description": "The maximum unavailable percentage for rolling deploys.", + "examples": [ + 10 + ], + "title": "Max Unavailable Percent" }, - "config": { - "additionalProperties": true, - "description": "The full parsed config as a JSON object.", - "title": "Config", - "type": "object" + "stabilization_time_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The stabilization time in seconds for rolling deploys.", + "examples": [ + 300 + ], + "title": "Stabilization Time Seconds" }, - "path": { - "default": "config.yaml", - "description": "Config file path within the source.", - "title": "Path", - "type": "string" + "replica_overhead_percent": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The replica overhead percentage for rolling deploys.", + "examples": [ + 0 + ], + "title": "Replica Overhead Percent" } }, - "required": [ - "config" - ], - "title": "DeploymentPatchOpConfigV1", + "title": "UpdateRollingDeployConfigV1", "type": "object" }, - "DeploymentPatchOpEnvVarV1": { - "description": "Add, update, or remove a single environment variable.", + "CreateEnvironmentRequestV1": { + "description": "A request to create an environment.", "properties": { - "type": { - "const": "environment_variable", - "default": "environment_variable", - "title": "Type", - "type": "string" - }, - "action": { - "$ref": "#/components/schemas/DeploymentPatchActionV1", - "description": "How this op changes the variable." - }, "name": { - "description": "The environment variable name.", + "description": "Name of the environment", + "examples": [ + "staging" + ], "title": "Name", "type": "string" }, - "value": { + "autoscaling_settings": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" }, { "type": "null" } ], "default": null, - "description": "The environment variable value. Required for add and update.", - "title": "Value" + "description": "Autoscaling settings for the environment", + "examples": [ + { + "autoscaling_window": 800, + "concurrency_target": 3, + "max_replica": 2, + "max_scale_down_rate": null, + "min_replica": 1, + "scale_down_delay": 60, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + } + ] + }, + "promotion_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdatePromotionSettingsV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Promotion settings for the environment. New Model environments use rolling promotions by default. Set `rolling_deploy` to `false` to opt out.", + "examples": [ + { + "promotion_cleanup_strategy": null, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": true, + "redeploy_on_promotion": true, + "rolling_deploy": false, + "rolling_deploy_config": null + } + ] + }, + "request_backpressure_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdateRequestBackpressureSettingsV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Request backpressure settings for the environment." } }, "required": [ - "action", "name" ], - "title": "DeploymentPatchOpEnvVarV1", + "title": "CreateEnvironmentRequestV1", "type": "object" }, - "DeploymentPatchOpExternalDataV1": { - "description": "Add, update, or remove a single external data item.\n\nExternal data is referenced by config, not stored in the source. The backend\nonly adds or removes it, where adding re-downloads (overwriting any existing\nfile), so `update` is accepted and treated identically to `add`.", + "EnvironmentTombstoneV1": { + "description": "An environment tombstone.", "properties": { - "type": { - "const": "external_data", - "default": "external_data", - "title": "Type", + "name": { + "description": "Name of the environment", + "title": "Name", "type": "string" }, - "action": { - "$ref": "#/components/schemas/DeploymentPatchActionV1", - "description": "How this op changes the item. `UPDATE` is treated identically to `ADD`." + "model_id": { + "description": "Unique identifier of the model", + "title": "Model Id", + "type": "string" }, - "item": { - "additionalProperties": { - "type": "string" - }, - "description": "The single external data item descriptor.", - "title": "Item", - "type": "object" + "deleted": { + "description": "Whether the environment was deleted", + "title": "Deleted", + "type": "boolean" } }, "required": [ - "action", - "item" + "name", + "model_id", + "deleted" ], - "title": "DeploymentPatchOpExternalDataV1", + "title": "EnvironmentTombstoneV1", "type": "object" }, - "DeploymentPatchOpModelCodeV1": { - "description": "Add, update, or remove a file under the model code directory.", + "AutoscalingScheduleSettingsRequestV1": { + "additionalProperties": false, + "description": "A complete set of raw autoscaling overrides for a schedule.", "properties": { - "type": { - "const": "model_code", - "default": "model_code", - "title": "Type", - "type": "string" + "min_replica": { + "description": "Minimum number of replicas", + "title": "Min Replica", + "type": "integer" }, - "action": { - "$ref": "#/components/schemas/DeploymentPatchActionV1", - "description": "How this op changes the file." + "max_replica": { + "description": "Maximum number of replicas", + "title": "Max Replica", + "type": "integer" }, - "path": { - "description": "File path relative to the model code directory.", - "title": "Path", - "type": "string" + "autoscaling_window": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Timeframe of traffic considered for autoscaling decisions. Null stores no schedule override and follows the current environment value.", + "title": "Autoscaling Window" }, - "content": { + "scale_down_delay": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "default": null, - "description": "UTF-8 file content. Null for removals and binary files.", - "title": "Content" + "description": "Waiting period before scaling down any active replica. Null stores no schedule override and follows the current environment value.", + "title": "Scale Down Delay" }, - "content_bytes": { + "concurrency_target": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "default": null, - "description": "Base64-encoded content for binary files.", - "title": "Content Bytes" + "description": "Number of requests per replica before scaling up. Null stores no schedule override and follows the current environment value.", + "title": "Concurrency Target" }, - "hot_reload": { - "default": false, - "description": "Whether the running server can pick up this change without a restart.", - "title": "Hot Reload", - "type": "boolean" + "target_utilization_percentage": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Target utilization percentage for scaling up/down. Null stores no schedule override and follows the current environment value.", + "title": "Target Utilization Percentage" + }, + "target_in_flight_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Target number of in-flight tokens for autoscaling decisions. Null stores no schedule override and follows the current environment value. Early access only.", + "title": "Target In Flight Tokens" + }, + "max_scale_down_rate": { + "anyOf": [ + { + "maximum": 50, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Maximum percentage of replicas that can be removed per autoscaling window. Null stores no schedule override and follows the current environment value.", + "title": "Max Scale Down Rate" } }, "required": [ - "action", - "path" + "min_replica", + "max_replica", + "autoscaling_window", + "scale_down_delay", + "concurrency_target", + "target_utilization_percentage", + "target_in_flight_tokens", + "max_scale_down_rate" ], - "title": "DeploymentPatchOpModelCodeV1", + "title": "AutoscalingScheduleSettingsRequestV1", "type": "object" }, - "DeploymentPatchOpPackageV1": { - "description": "Add, update, or remove a file under the bundled packages directory.", - "properties": { - "type": { - "const": "package", - "default": "package", - "title": "Type", - "type": "string" - }, - "action": { - "$ref": "#/components/schemas/DeploymentPatchActionV1", - "description": "How this op changes the file." - }, - "path": { - "description": "File path relative to the bundled packages directory.", - "title": "Path", - "type": "string" - }, - "content": { + "AutoscalingScheduleUpsertV1": { + "additionalProperties": false, + "description": "A complete recurring schedule submitted for create or replacement.", + "properties": { + "id": { "anyOf": [ { "type": "string" @@ -16199,250 +21110,155 @@ } ], "default": null, - "description": "UTF-8 file content. Null for removals and binary files.", - "title": "Content" + "description": "Stable schedule identifier. Omit this field to create a schedule.", + "title": "Id" }, - "content_bytes": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Base64-encoded content for binary files.", - "title": "Content Bytes" - } - }, - "required": [ - "action", - "path" - ], - "title": "DeploymentPatchOpPackageV1", - "type": "object" - }, - "DeploymentPatchOpPythonRequirementV1": { - "description": "Add, update, or remove a single Python requirement.", - "properties": { - "type": { - "const": "python_requirement", - "default": "python_requirement", - "title": "Type", + "name": { + "description": "Name of the schedule", + "title": "Name", "type": "string" }, - "action": { - "$ref": "#/components/schemas/DeploymentPatchActionV1", - "description": "How this op changes the requirement." + "enabled": { + "description": "Whether the schedule is enabled", + "title": "Enabled", + "type": "boolean" }, - "requirement": { - "description": "The requirement to apply. For removals this is the package name; otherwise the full requirements.txt-style line.", - "title": "Requirement", - "type": "string" - } - }, - "required": [ - "action", - "requirement" - ], - "title": "DeploymentPatchOpPythonRequirementV1", - "type": "object" - }, - "DeploymentPatchPointV1": { - "description": "A patch point: the source state the next patch is computed against.\n\nThe content hash that identifies a point is derived from this state (see\n`DeploymentPatchPointWithHashV1.hash`), so a request only sends the state and\nthe server stamps the hash. A previous point's hash plus the current local\nsource is enough to compute the next patch, so the watch client reads the\npoint it is patching off of.", - "properties": { - "content_hashes": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "description": "Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", - "title": "Content Hashes", - "type": "object" + "autoscaling_settings": { + "$ref": "#/components/schemas/AutoscalingScheduleSettingsRequestV1", + "description": "Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." }, - "config": { - "description": "The verbatim config.yaml text for this source state.", - "title": "Config", + "cadence": { + "description": "Recurring schedule cadence", + "enum": [ + "DAILY", + "HOURLY" + ], + "title": "Cadence", "type": "string" }, - "requirements": { - "description": "Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", + "weekdays": { + "description": "Weekdays on which the schedule runs", "items": { - "type": "string" + "$ref": "#/components/schemas/AutoscalingScheduleWeekdayV1" }, - "title": "Requirements", + "title": "Weekdays", "type": "array" - } - }, - "required": [ - "content_hashes", - "config" - ], - "title": "DeploymentPatchPointV1", - "type": "object" - }, - "CreateDeploymentPatchRequestV1": { - "description": "A patch to stage against the development deployment.\n\nStaging is durable on its own: the patch is persisted independently of the\nlater sync, so a failed sync does not lose it.", - "properties": { - "prev_patch_hash": { - "description": "Content hash of the patch point this patch is applied on - the link the staged patch must build on. A stale value (the base moved underneath the client) is rejected with a conflict.", - "title": "Prev Patch Hash", - "type": "string" - }, - "next_patch_point": { - "$ref": "#/components/schemas/DeploymentPatchPointV1", - "description": "The source state after this patch. The server derives its content hash from `content_hashes`." }, - "patch_ops": { - "description": "The ordered ops that make up this patch. At least one op is required; a patch that changes nothing is not a valid request. There is no op for a directory: a directory comes into existence when the first file under it is added, and is removed when its last file is removed, so directory creation and deletion happen implicitly through the file ops. Adding or removing an otherwise empty directory therefore produces no ops even though it changes the source hash; do not send a patch request for such a change.", - "items": { - "discriminator": { - "mapping": { - "config": "#/components/schemas/DeploymentPatchOpConfigV1", - "environment_variable": "#/components/schemas/DeploymentPatchOpEnvVarV1", - "external_data": "#/components/schemas/DeploymentPatchOpExternalDataV1", - "model_code": "#/components/schemas/DeploymentPatchOpModelCodeV1", - "package": "#/components/schemas/DeploymentPatchOpPackageV1", - "python_requirement": "#/components/schemas/DeploymentPatchOpPythonRequirementV1" - }, - "propertyName": "type" + "start_hour": { + "anyOf": [ + { + "type": "integer" }, - "oneOf": [ - { - "$ref": "#/components/schemas/DeploymentPatchOpModelCodeV1" - }, - { - "$ref": "#/components/schemas/DeploymentPatchOpPackageV1" - }, - { - "$ref": "#/components/schemas/DeploymentPatchOpConfigV1" - }, - { - "$ref": "#/components/schemas/DeploymentPatchOpPythonRequirementV1" - }, - { - "$ref": "#/components/schemas/DeploymentPatchOpEnvVarV1" - }, - { - "$ref": "#/components/schemas/DeploymentPatchOpExternalDataV1" - } - ] - }, - "minItems": 1, - "title": "Patch Ops", - "type": "array" - } - }, - "required": [ - "prev_patch_hash", - "next_patch_point", - "patch_ops" - ], - "title": "CreateDeploymentPatchRequestV1", - "type": "object" - }, - "DeploymentPatchPointWithHashV1": { - "description": "A patch point plus its server-assigned content hash, returned in responses.\n\nRequests omit the hash (the server derives it from the source state); responses\ninclude it so the watch client can echo it back as the next patch's\n`prev_patch_hash` without having to recompute the fold itself.", - "properties": { - "content_hashes": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "description": "Map of every non-ignored source path, relative and forward-slash, to its content hash: files map to the hex blake3 digest of their bytes, directories map to null. This is the full signature of the source tree and what the content hash is derived from.", - "title": "Content Hashes", - "type": "object" + { + "type": "null" + } + ], + "default": null, + "description": "Start hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", + "title": "Start Hour" }, - "config": { - "description": "The verbatim config.yaml text for this source state.", - "title": "Config", - "type": "string" + "start_minute": { + "description": "Start minute of the schedule window", + "title": "Start Minute", + "type": "integer" }, - "requirements": { - "description": "Requirements resolved from the config's requirements file, when it points at one. Empty when requirements are declared inline in the config.", - "items": { - "type": "string" - }, - "title": "Requirements", - "type": "array" + "end_hour": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "End hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", + "title": "End Hour" }, - "hash": { - "description": "Content hash identifying this exact source state, and the link patches build on. It is derived deterministically from `content_hashes`, so a request need not send it - the server derives it. It is derived by sorting the `content_hashes` keys as paths, splitting each key on '/' into its path components and ordering the keys by comparing those component lists element by element, each component compared by Unicode code point (equivalently UTF-8 byte order). Treating '/' as a path separator this way, rather than as the ordinary character U+002F, means a key that is an ancestor path sorts before a sibling whose name extends the first differing component (so e.g. 'a/b' sorts before 'a.b'). A blake3 hasher is then built, and for each key in that order updated with the blake3 digest (32 raw bytes) of the key encoded as UTF-8, then, when the entry is a file (non-null value), with that file's digest as 32 raw bytes. The stream uses raw digest bytes, but the values in `content_hashes` are those digests hex-encoded (64 hex chars), so decode each value from hex first. Directory entries (null value) contribute only their key digest. The result is the hasher's own hex digest.", - "title": "Hash", - "type": "string" - } - }, - "required": [ - "content_hashes", - "config", - "hash" - ], - "title": "DeploymentPatchPointWithHashV1", - "type": "object" - }, - "CreateDeploymentPatchResponseV1": { - "description": "The created patch, represented by the patch point it produced.", - "properties": { - "patch_point": { - "$ref": "#/components/schemas/DeploymentPatchPointWithHashV1", - "description": "The resulting patch point the staged patch produced; matches the pending point a subsequent state read returns." + "end_minute": { + "description": "End minute of the schedule window", + "title": "End Minute", + "type": "integer" } }, "required": [ - "patch_point" + "name", + "enabled", + "autoscaling_settings", + "cadence", + "weekdays", + "start_minute", + "end_minute" ], - "title": "CreateDeploymentPatchResponseV1", + "title": "AutoscalingScheduleUpsertV1", "type": "object" - }, - "GetDeploymentPatchesStateResponseV1": { - "description": "The patch state of the development deployment.\n\nThe watch client computes its next patch off `pending_patch_point` when present,\nelse `running_patch_point`.", + }, + "OneTimeAutoscalingScheduleUpsertV1": { + "additionalProperties": false, + "description": "A complete one-time schedule submitted for create or replacement.", "properties": { - "running_patch_point": { - "$ref": "#/components/schemas/DeploymentPatchPointWithHashV1", - "description": "The patch point the deployment is recorded as running." - }, - "pending_patch_point": { + "id": { "anyOf": [ { - "$ref": "#/components/schemas/DeploymentPatchPointWithHashV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "The latest staged-but-unsynced patch point, or null when the deployment is recorded as caught up." + "description": "Stable schedule identifier. Omit this field to create a schedule.", + "title": "Id" + }, + "name": { + "description": "Name of the schedule", + "title": "Name", + "type": "string" + }, + "enabled": { + "description": "Whether the schedule is enabled", + "title": "Enabled", + "type": "boolean" + }, + "autoscaling_settings": { + "$ref": "#/components/schemas/AutoscalingScheduleSettingsRequestV1", + "description": "Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." + }, + "cadence": { + "const": "ONE_TIME", + "description": "One-time schedule cadence", + "title": "Cadence", + "type": "string" + }, + "start_at": { + "description": "Inclusive start of the schedule window in ISO 8601 format. New schedules must start in the future.", + "format": "date-time", + "title": "Start At", + "type": "string" + }, + "end_at": { + "description": "Exclusive end of the schedule window in ISO 8601 format", + "format": "date-time", + "title": "End At", + "type": "string" } }, "required": [ - "running_patch_point" + "name", + "enabled", + "autoscaling_settings", + "cadence", + "start_at", + "end_at" ], - "title": "GetDeploymentPatchesStateResponseV1", - "type": "object" - }, - "SyncDeploymentPatchesRequestV1": { - "description": "Triggers a sync of any staged patches to the running deployment. Takes no\nfields: the deployment and its staged patches fully determine the sync.", - "properties": {}, - "title": "SyncDeploymentPatchesRequestV1", + "title": "OneTimeAutoscalingScheduleUpsertV1", "type": "object" }, - "SyncDeploymentPatchesResponseV1": { - "description": "The outcome of a sync that ran.\n\nOperational failures (a transient patch failure, an invalid patch sequence)\nare surfaced as HTTP errors rather than fields here, so a 2xx means the sync\nreached a verdict.", + "UpdateAutoscalingScheduleSettingsV1": { + "additionalProperties": false, + "description": "Partial mutation of an environment's autoscaling schedule collection.", "properties": { - "needs_full_deploy_reason": { + "timezone": { "anyOf": [ { "type": "string" @@ -16452,182 +21268,196 @@ } ], "default": null, - "description": "If set, the change cannot be patched and a full push is required; the value explains why. If null, the deployment is now in sync.", - "title": "Needs Full Deploy Reason" - } - }, - "title": "SyncDeploymentPatchesResponseV1", - "type": "object" - }, - "ModelMetricDescriptorV1": { - "description": "Describes one metric. Its position in the response ``metric_descriptors``\nlist is the index used to read that metric out of each value set's ``values``.\n\nA metric may break down into multiple labeled series (e.g. latency quantiles,\nor volume by status). ``label_sets`` enumerates those series in order; each\nvalue set's value for this metric is a list aligned to that order.", - "properties": { - "name": { - "description": "Canonical metric name.", - "title": "Name", - "type": "string" - }, - "unit_hint": { - "$ref": "#/components/schemas/ModelMetricUnitHintV1", - "description": "Advisory unit of the metric's values." - }, - "kind": { - "$ref": "#/components/schemas/ModelMetricKindV1", - "description": "Semantic hint for how the metric behaves (GAUGE, COUNTER, HISTOGRAM)." + "description": "IANA timezone shared by the resulting collection. Omission preserves the current timezone; null is allowed only when deleting every schedule.", + "title": "Timezone", + "x-null-distinct": true }, - "label_sets": { - "description": "The metric's series, in order. Each entry is the set of labels identifying one series; the value at the same index in each value set's ``values`` is that series' value. A plain metric has a single entry with no labels (`{}`). A histogram has one entry per quantile plus an average, e.g. {'quantile': '0.5'} \u2026 {'quantile': '0.99'}, {'stat': 'avg'}. A by-status metric has one entry per status, e.g. {'status': '2xx'}.", + "schedules": { + "description": "Complete schedules to create or replace. Existing schedules omitted from this list are unchanged.", "items": { - "additionalProperties": { - "type": "string" + "discriminator": { + "mapping": { + "DAILY": "#/components/schemas/AutoscalingScheduleUpsertV1", + "HOURLY": "#/components/schemas/AutoscalingScheduleUpsertV1", + "ONE_TIME": "#/components/schemas/OneTimeAutoscalingScheduleUpsertV1" + }, + "propertyName": "cadence" }, - "type": "object" + "oneOf": [ + { + "$ref": "#/components/schemas/AutoscalingScheduleUpsertV1" + }, + { + "$ref": "#/components/schemas/OneTimeAutoscalingScheduleUpsertV1" + } + ] }, - "title": "Label Sets", + "title": "Schedules", + "type": "array" + }, + "delete_schedules": { + "description": "Stable identifiers of schedules to delete. To clear all schedules, include every existing schedule identifier.", + "items": { + "type": "string" + }, + "title": "Delete Schedules", "type": "array" } }, - "required": [ - "name", - "unit_hint", - "kind", - "label_sets" - ], - "title": "ModelMetricDescriptorV1", + "title": "UpdateAutoscalingScheduleSettingsV1", "type": "object" }, - "ModelMetricKindV1": { - "description": "Semantic hint for how a metric behaves, to aid client rendering and\naggregation. It does not describe the value's shape (that is carried by the\ndescriptor's ``label_sets``; a metric may break down into multiple series).\n\n- ``GAUGE``: an instantaneous value (e.g. queue size, running requests).\n- ``COUNTER``: a cumulative total over the step (e.g. tokens, restarts).\n- ``HISTOGRAM``: a distribution, exposed as quantile/average series.", - "enum": [ - "GAUGE", - "COUNTER", - "HISTOGRAM" - ], - "title": "ModelMetricKindV1", - "type": "string" - }, - "ModelMetricModeV1": { - "description": "How metric values are aggregated over the request.", - "enum": [ - "CURRENT", - "SUMMARY", - "SERIES" - ], - "title": "ModelMetricModeV1", - "type": "string" - }, - "ModelMetricUnitHintV1": { - "description": "Advisory unit of a metric's values. Values are reported as scraped, so the\nhint describes the raw value (e.g. GPU memory is reported in mebibytes).\n\n- ``PER_SECOND``: a rate per second.\n- ``SECONDS``: a duration in seconds.\n- ``BYTES``: a size in bytes.\n- ``MEBIBYTES``: a size in mebibytes (MiB).\n- ``COUNT``: a dimensionless tally of discrete things.\n- ``RATIO``: a dimensionless ratio. Usually in ``[0, 1]`` but may exceed 1\n (e.g. CPU usage in cores = cpu-seconds/second).", - "enum": [ - "PER_SECOND", - "SECONDS", - "BYTES", - "MEBIBYTES", - "COUNT", - "RATIO" - ], - "title": "ModelMetricUnitHintV1", - "type": "string" - }, - "ModelMetricValueSetV1": { - "description": "The metric values for one time step. ``values`` is aligned by index to the\nresponse ``metric_descriptors`` list.", + "UpdateEnvironmentRequestV1": { + "additionalProperties": false, + "description": "A request to update an environment.", "properties": { - "start_epoch_millis": { - "description": "Start of the step. The step spans until the next value set's start, or the window end for the last one; a summary has a single value set starting at the window start.", - "title": "Start Epoch Millis", - "type": "integer" + "autoscaling_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Autoscaling settings for the environment", + "examples": [ + { + "autoscaling_window": 800, + "concurrency_target": 3, + "max_replica": 2, + "max_scale_down_rate": null, + "min_replica": 1, + "scale_down_delay": 60, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + } + ] }, - "values": { - "description": "Metric values aligned to the ``metric_descriptors`` index. Each entry is a list aligned to that descriptor's ``label_sets`` (a single-element list for a plain metric). A series with no data in this step is null.", - "items": { - "items": { - "anyOf": [ - { - "type": "number" - }, + "promotion_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdatePromotionSettingsV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Promotion settings for the environment", + "examples": [ + { + "promotion_cleanup_strategy": null, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": true, + "redeploy_on_promotion": true, + "rolling_deploy": null, + "rolling_deploy_config": null + } + ] + }, + "autoscaling_schedule_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdateAutoscalingScheduleSettingsV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Partial autoscaling schedule collection update. Omitted collection fields and existing schedules are unchanged; each submitted schedule is a complete create or replacement.", + "examples": [ + { + "schedules": [ { - "type": "null" + "autoscaling_settings": { + "autoscaling_window": null, + "concurrency_target": null, + "max_replica": 8, + "max_scale_down_rate": null, + "min_replica": 2, + "scale_down_delay": null, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + }, + "cadence": "DAILY", + "enabled": true, + "end_hour": 10, + "end_minute": 0, + "name": "weekday-peak", + "start_hour": 8, + "start_minute": 0, + "weekdays": [ + "MONDAY", + "TUESDAY", + "WEDNESDAY", + "THURSDAY", + "FRIDAY" + ] } - ] + ], + "timezone": "America/Los_Angeles" }, - "type": "array" - }, - "title": "Values", - "type": "array" - } - }, - "required": [ - "start_epoch_millis", - "values" - ], - "title": "ModelMetricValueSetV1", - "type": "object" - }, - "GetModelMetricsResponseV1": { - "description": "Model metrics over a time window, index-mapped: metric descriptors appear once\nin ``metric_descriptors``; each value set's ``values`` are aligned to that order.", - "properties": { - "start_epoch_millis": { - "description": "Start of the returned window.", - "title": "Start Epoch Millis", - "type": "integer" - }, - "end_epoch_millis": { - "description": "End of the returned window.", - "title": "End Epoch Millis", - "type": "integer" - }, - "mode": { - "$ref": "#/components/schemas/ModelMetricModeV1", - "description": "The aggregation mode used." + { + "delete_schedules": [ + "schedule-id" + ] + } + ] }, - "step_seconds": { + "request_backpressure_settings": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/UpdateRequestBackpressureSettingsV1" }, { "type": "null" } ], - "description": "Seconds per step; populated only in SERIES mode, null otherwise.", - "title": "Step Seconds" + "default": null, + "description": "Request backpressure settings for the environment.", + "examples": [ + { + "policy": "REJECT_ON_FULL" + } + ] + } + }, + "title": "UpdateEnvironmentRequestV1", + "type": "object" + }, + "UpdateEnvironmentResponseV1": { + "description": "The response to a request to update an environment's settings.", + "properties": { + "environment": { + "$ref": "#/components/schemas/EnvironmentV1", + "description": "The environment after the update, matching the shape returned by GET." }, - "metric_descriptors": { - "description": "Descriptors for each metric; position defines the values index.", - "items": { - "$ref": "#/components/schemas/ModelMetricDescriptorV1" - }, - "title": "Metric Descriptors", - "type": "array" + "status": { + "$ref": "#/components/schemas/UpdateAutoscalingSettingsStatusV1", + "deprecated": true, + "description": "Deprecated. Kept for legacy autoscaling-only update operation behavior." }, - "metric_values": { - "description": "Metric values per time step covering the window. In summary mode this always contains exactly one value set spanning the whole window.", - "items": { - "$ref": "#/components/schemas/ModelMetricValueSetV1" - }, - "title": "Metric Values", - "type": "array" + "message": { + "deprecated": true, + "description": "Deprecated. Kept for legacy autoscaling-only update operation behavior.", + "title": "Message", + "type": "string" } }, "required": [ - "start_epoch_millis", - "end_epoch_millis", - "mode", - "step_seconds", - "metric_descriptors", - "metric_values" + "environment", + "status", + "message" ], - "title": "GetModelMetricsResponseV1", + "title": "UpdateEnvironmentResponseV1", "type": "object" }, - "GetDeploymentMetricsRequestV1": { - "description": "Query params for ``GET /v1/models/.../deployments/.../metrics``.", + "GetEnvironmentLogsRequestV1": { + "description": "A request to fetch logs for a model environment.\n\nReturns logs from every deployment that was active on the environment over\nthe requested time range, merged in timestamp order.", "properties": { - "mode": { - "$ref": "#/components/schemas/ModelMetricModeV1", - "default": "CURRENT", - "description": "'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." - }, "start_epoch_millis": { "anyOf": [ { @@ -16638,7 +21468,7 @@ } ], "default": null, - "description": "Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", + "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", "title": "Start Epoch Millis" }, "end_epoch_millis": { @@ -16651,157 +21481,135 @@ } ], "default": null, - "description": "Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", + "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", "title": "End Epoch Millis" }, - "metrics": { - "description": "Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", - "items": { - "type": "string" - }, - "title": "Metrics", - "type": "array" - } - }, - "title": "GetDeploymentMetricsRequestV1", - "type": "object" - }, - "TerminateReplicaResponseV1": { - "description": "The response to a request to terminate a replica in a deployment.", - "properties": { - "success": { - "default": true, - "description": "Whether the replica was successfully terminated", - "title": "Success", - "type": "boolean" - } - }, - "title": "TerminateReplicaResponseV1", - "type": "object" - }, - "SignSSHCertificateRequestV1": { - "description": "Request to sign an SSH certificate for accessing a workload pod.", - "properties": { - "public_key": { - "description": "The user's SSH public key (e.g., 'ssh-ed25519 AAAA... user@host').", - "title": "Public Key", - "type": "string" - }, - "replica_id": { + "direction": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SortOrderV1" }, { "type": "null" } ], "default": null, - "description": "The replica to connect to. Required for training jobs (e.g. '0'). Optional for inference (server picks a running replica if omitted).", - "title": "Replica Id" - } - }, - "required": [ - "public_key" - ], - "title": "SignSSHCertificateRequestV1", - "type": "object" - }, - "SignSSHCertificateResponseV1": { - "description": "Response containing a signed SSH certificate for proxy authentication.", - "properties": { - "ssh_certificate": { - "description": "The signed SSH certificate in OpenSSH format.", - "title": "Ssh Certificate", - "type": "string" - }, - "jwt": { - "description": "Signed JWT (ES256) for SSH proxy authorization.", - "title": "Jwt", - "type": "string" - }, - "proxy_address": { - "description": "Address of the SSH proxy to connect to (host:port).", - "title": "Proxy Address", - "type": "string" + "description": "Sort order for logs" }, - "ssh_cert_expires_at": { - "description": "When the certificate expires, in ISO 8601 format.", - "format": "date-time", - "title": "Ssh Cert Expires At", - "type": "string" - } - }, - "required": [ - "ssh_certificate", - "jwt", - "proxy_address", - "ssh_cert_expires_at" - ], - "title": "SignSSHCertificateResponseV1", - "type": "object" - }, - "AutoscalingScheduleSettingsV1": { - "properties": { - "min_replica": { - "description": "Minimum number of replicas", - "title": "Min Replica", - "type": "integer" + "limit": { + "anyOf": [ + { + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 500, + "description": "Limit of logs to fetch in a single request", + "title": "Limit" }, - "max_replica": { - "description": "Maximum number of replicas", - "title": "Max Replica", - "type": "integer" + "min_level": { + "anyOf": [ + { + "$ref": "#/components/schemas/LogLevelV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." }, - "autoscaling_window": { + "replica": { "anyOf": [ { - "type": "integer" + "maxLength": 256, + "type": "string" }, { "type": "null" } ], - "description": "Timeframe of traffic considered for autoscaling decisions. Null inherits the environment value.", - "title": "Autoscaling Window" + "default": null, + "description": "Only return logs emitted by this replica (5-char short ID).", + "title": "Replica" }, - "scale_down_delay": { + "request_id": { "anyOf": [ { - "type": "integer" + "maxLength": 256, + "type": "string" }, { "type": "null" } ], - "description": "Waiting period before scaling down any active replica. Null inherits the environment value.", - "title": "Scale Down Delay" + "default": null, + "description": "Only return logs tagged with this inference request ID.", + "title": "Request Id" }, - "concurrency_target": { + "component": { "anyOf": [ { - "type": "integer" + "maxLength": 256, + "type": "string" }, { "type": "null" } ], - "description": "Number of requests per replica before scaling up. Null inherits the environment value.", - "title": "Concurrency Target" + "default": null, + "description": "Only return logs from this component.", + "title": "Component" }, - "target_utilization_percentage": { + "search_pattern": { "anyOf": [ { - "type": "integer" + "maxLength": 256, + "type": "string" }, { "type": "null" } ], - "description": "Target utilization percentage for scaling up/down. Null inherits the environment value.", - "title": "Target Utilization Percentage" + "default": null, + "description": "RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", + "title": "Search Pattern" }, - "target_in_flight_tokens": { + "includes": { + "description": "Case-sensitive substrings that must all appear in the log message.", + "items": { + "type": "string" + }, + "maxItems": 8, + "title": "Includes", + "type": "array" + }, + "excludes": { + "description": "Case-sensitive substrings; lines containing any of these are dropped.", + "items": { + "type": "string" + }, + "maxItems": 8, + "title": "Excludes", + "type": "array" + } + }, + "title": "GetEnvironmentLogsRequestV1", + "type": "object" + }, + "GetEnvironmentMetricsRequestV1": { + "description": "Query params for ``GET /v1/models/.../environments/.../metrics``.", + "properties": { + "mode": { + "$ref": "#/components/schemas/ModelMetricModeV1", + "default": "CURRENT", + "description": "'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." + }, + "start_epoch_millis": { "anyOf": [ { "type": "integer" @@ -16810,10 +21618,11 @@ "type": "null" } ], - "description": "Target number of in-flight tokens for autoscaling decisions. Null inherits the environment value. Early access only.", - "title": "Target In Flight Tokens" + "default": null, + "description": "Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", + "title": "Start Epoch Millis" }, - "max_scale_down_rate": { + "end_epoch_millis": { "anyOf": [ { "type": "integer" @@ -16822,804 +21631,661 @@ "type": "null" } ], - "description": "Maximum percentage of replicas that can be removed per autoscaling window. Null inherits the environment value.", - "title": "Max Scale Down Rate" + "default": null, + "description": "Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", + "title": "End Epoch Millis" + }, + "metrics": { + "description": "Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", + "items": { + "type": "string" + }, + "title": "Metrics", + "type": "array" + } + }, + "title": "GetEnvironmentMetricsRequestV1", + "type": "object" + }, + "PromoteToEnvironmentRequestV1": { + "description": "A request to promote a deployment to a environment.", + "properties": { + "scale_down_previous_deployment": { + "default": true, + "description": "Whether to scale down the previous deployment after promoting", + "examples": [ + true + ], + "title": "Scale Down Previous Deployment", + "type": "boolean" + }, + "deployment_id": { + "description": "The id of the deployment to promote", + "title": "Deployment Id", + "type": "string" + }, + "preserve_env_instance_type": { + "default": true, + "description": "Whether to use the promoting deployment's instance type or preserve target environment's instance type", + "examples": [ + true + ], + "title": "Preserve Env Instance Type", + "type": "boolean" } }, "required": [ - "min_replica", - "max_replica", - "autoscaling_window", - "scale_down_delay", - "concurrency_target", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate" + "deployment_id" ], - "title": "AutoscalingScheduleSettingsV1", + "title": "PromoteToEnvironmentRequestV1", "type": "object" }, - "AutoscalingScheduleStateV1": { + "CancelPromotionStatusV1": { + "description": "The status of a request to cancel a promotion.", + "enum": [ + "CANCELED", + "RAMPING_DOWN" + ], + "title": "CancelPromotionStatusV1", + "type": "string" + }, + "CancelPromotionResponseV1": { + "description": "The response to a request to cancel a promotion.", "properties": { - "schedule_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Stable schedule identifier, or null when the baseline settings apply", - "title": "Schedule Id" + "status": { + "$ref": "#/components/schemas/CancelPromotionStatusV1", + "description": "Status of the request to cancel a promotion. Can be CANCELED or RAMPING_DOWN." }, - "autoscaling_settings": { - "$ref": "#/components/schemas/AutoscalingSettingsV1", - "description": "Autoscaling settings on the current serving deployment. In a PATCH response, this snapshot can precede asynchronous schedule reconciliation; poll the GET endpoint for the applied state." + "message": { + "description": "A message describing the status of the request to cancel a promotion", + "title": "Message", + "type": "string" } }, "required": [ - "schedule_id", - "autoscaling_settings" + "status", + "message" ], - "title": "AutoscalingScheduleStateV1", + "title": "CancelPromotionResponseV1", "type": "object" }, - "AutoscalingScheduleV1": { + "SignalPromotionResponseV1": { + "description": "The response to a request to signal a rolling promotion.", + "properties": { + "success": { + "description": "Whether the signal was successfully sent", + "title": "Success", + "type": "boolean" + } + }, + "required": [ + "success" + ], + "title": "SignalPromotionResponseV1", + "type": "object" + }, + "ChainV1": { + "description": "A chain.", "properties": { "id": { - "description": "Stable unique identifier of the schedule", + "description": "Unique identifier of the chain", "title": "Id", "type": "string" }, - "name": { - "description": "Name of the schedule", - "title": "Name", + "created_at": { + "description": "Time the chain was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", "type": "string" }, - "enabled": { - "description": "Whether the schedule is enabled", - "title": "Enabled", - "type": "boolean" - }, - "autoscaling_settings": { - "$ref": "#/components/schemas/AutoscalingScheduleSettingsV1", - "description": "Raw autoscaling overrides applied during the schedule window" - }, - "cadence": { - "description": "Cadence of the schedule. DAILY runs once per selected weekday; HOURLY repeats the minute window every hour on selected weekdays.", - "enum": [ - "DAILY", - "HOURLY" - ], - "title": "Cadence", + "name": { + "description": "Name of the chain", + "title": "Name", "type": "string" }, - "weekdays": { - "description": "Weekdays on which the schedule runs", - "items": { - "$ref": "#/components/schemas/AutoscalingScheduleWeekdayV1" - }, - "title": "Weekdays", - "type": "array" - }, - "start_hour": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Start hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", - "title": "Start Hour" - }, - "start_minute": { - "description": "Start minute of the schedule window", - "title": "Start Minute", + "deployments_count": { + "description": "Number of deployments of the chain", + "title": "Deployments Count", "type": "integer" }, - "end_hour": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "End hour in the environment schedule timezone. Omitted for unrestricted HOURLY schedules.", - "title": "End Hour" - }, - "end_minute": { - "description": "End minute of the schedule window", - "title": "End Minute", - "type": "integer" + "team_name": { + "description": "Name of the team associated with the chain", + "title": "Team Name", + "type": "string" } }, "required": [ "id", + "created_at", "name", - "enabled", - "autoscaling_settings", - "cadence", - "weekdays", - "start_minute", - "end_minute" + "deployments_count", + "team_name" ], - "title": "AutoscalingScheduleV1", + "title": "ChainV1", "type": "object" }, - "AutoscalingScheduleWeekdayV1": { - "enum": [ - "SUNDAY", - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY", - "SATURDAY" - ], - "title": "AutoscalingScheduleWeekdayV1", - "type": "string" - }, - "EnvironmentAutoscalingSchedulesV1": { + "ChainsV1": { + "description": "A list of chains.", "properties": { - "timezone": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "IANA timezone shared by all schedules. Omitted when no schedules exist.", - "title": "Timezone" - }, - "schedules": { - "description": "Autoscaling schedules ordered by creation time and stable identifier", + "chains": { "items": { - "discriminator": { - "mapping": { - "DAILY": "#/components/schemas/AutoscalingScheduleV1", - "HOURLY": "#/components/schemas/AutoscalingScheduleV1", - "ONE_TIME": "#/components/schemas/OneTimeAutoscalingScheduleV1" - }, - "propertyName": "cadence" - }, - "oneOf": [ - { - "$ref": "#/components/schemas/AutoscalingScheduleV1" - }, - { - "$ref": "#/components/schemas/OneTimeAutoscalingScheduleV1" - } - ] + "$ref": "#/components/schemas/ChainV1" }, - "title": "Schedules", + "title": "Chains", "type": "array" + } + }, + "required": [ + "chains" + ], + "title": "ChainsV1", + "type": "object" + }, + "ChainTombstoneV1": { + "description": "A chain tombstone.", + "properties": { + "id": { + "description": "Unique identifier of the chain", + "title": "Id", + "type": "string" }, - "applied_state": { - "anyOf": [ - { - "$ref": "#/components/schemas/AutoscalingScheduleStateV1" - }, - { - "type": "null" - } - ], - "description": "Autoscaling state on the current serving deployment, or null when no deployment exists" + "deleted": { + "description": "Whether the chain was deleted", + "title": "Deleted", + "type": "boolean" } }, "required": [ - "schedules", - "applied_state" + "id", + "deleted" ], - "title": "EnvironmentAutoscalingSchedulesV1", + "title": "ChainTombstoneV1", "type": "object" }, - "EnvironmentV1": { - "description": "Environment for oracles.", + "ChainDeploymentV1": { + "description": "A deployment of a chain.", "properties": { - "name": { - "description": "Name of the environment", - "title": "Name", + "id": { + "description": "Unique identifier of the chain deployment", + "title": "Id", "type": "string" }, "created_at": { - "description": "Time the environment was created in ISO 8601 format", + "description": "Time the chain deployment was created in ISO 8601 format", "format": "date-time", "title": "Created At", "type": "string" }, - "model_id": { - "description": "Unique identifier of the model", - "title": "Model Id", + "chain_id": { + "description": "Unique identifier of the chain", + "title": "Chain Id", "type": "string" }, - "current_deployment": { - "anyOf": [ - { - "$ref": "#/components/schemas/DeploymentV1" - }, - { - "type": "null" - } - ], - "description": "Current deployment of the environment" - }, - "candidate_deployment": { - "anyOf": [ - { - "$ref": "#/components/schemas/DeploymentV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Candidate deployment being promoted to the environment, if a promotion is in progress" - }, - "in_progress_promotion": { + "environment": { "anyOf": [ { - "$ref": "#/components/schemas/InProgressPromotionV1" + "type": "string" }, { "type": "null" } ], - "default": null, - "description": "Details of the in-progress promotion, if any" - }, - "autoscaling_settings": { - "$ref": "#/components/schemas/AutoscalingSettingsV1", - "description": "Autoscaling settings for the environment" - }, - "promotion_settings": { - "$ref": "#/components/schemas/PromotionSettingsV1", - "description": "Promotion settings for the environment" - }, - "instance_type": { - "$ref": "#/components/schemas/InstanceTypeV1", - "description": "Instance type for the environment" + "description": "Environment the chain deployment is deployed in", + "title": "Environment" }, - "request_backpressure_settings": { - "$ref": "#/components/schemas/RequestBackpressureSettingsV1", - "description": "Request backpressure settings for the environment." + "chainlets": { + "description": "Chainlets in the chain deployment", + "items": { + "$ref": "#/components/schemas/ChainletV1" + }, + "title": "Chainlets", + "type": "array" }, - "autoscaling_schedules": { - "anyOf": [ - { - "$ref": "#/components/schemas/EnvironmentAutoscalingSchedulesV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Autoscaling schedules and their evaluated state" + "status": { + "$ref": "#/components/schemas/DeploymentStatusV1", + "description": "Status of the chain deployment" } }, "required": [ - "name", + "id", "created_at", - "model_id", - "current_deployment", - "autoscaling_settings", - "promotion_settings", - "instance_type", - "request_backpressure_settings" + "chain_id", + "environment", + "chainlets", + "status" ], - "title": "EnvironmentV1", + "title": "ChainDeploymentV1", "type": "object" }, - "InProgressPromotionStatusV1": { - "enum": [ - "RELEASING", - "RAMPING_UP", - "RAMPING_DOWN", - "PAUSED", - "SUCCEEDED", - "FAILED", - "CANCELED" - ], - "title": "InProgressPromotionStatusV1", - "type": "string" - }, - "InProgressPromotionV1": { - "description": "Details of an in-progress promotion.", + "ChainletV1": { + "description": "A chainlet in a chain deployment.", "properties": { - "status": { - "$ref": "#/components/schemas/InProgressPromotionStatusV1", - "description": "Status of the promotion" + "id": { + "description": "Unique identifier of the chainlet", + "title": "Id", + "type": "string" }, - "percent_traffic_to_new_version": { - "description": "Percentage of traffic routed to the candidate deployment", - "title": "Percent Traffic To New Version", - "type": "integer" + "name": { + "description": "Name of the chainlet", + "title": "Name", + "type": "string" }, - "error_message": { + "autoscaling_settings": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/AutoscalingSettingsV1" }, { "type": "null" } ], - "default": null, - "description": "Error message if promotion failed", - "title": "Error Message" + "description": "Autoscaling settings for the chainlet. If null, it has not finished deploying" }, - "rolling_deploy": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Whether this is a rolling deploy", - "title": "Rolling Deploy" + "instance_type_name": { + "description": "Name of the instance type the chainlet is deployed on", + "title": "Instance Type Name", + "type": "string" + }, + "active_replica_count": { + "description": "Number of active replicas", + "title": "Active Replica Count", + "type": "integer" + }, + "status": { + "$ref": "#/components/schemas/DeploymentStatusV1", + "description": "Status of the chainlet" + } + }, + "required": [ + "id", + "name", + "autoscaling_settings", + "instance_type_name", + "active_replica_count", + "status" + ], + "title": "ChainletV1", + "type": "object" + }, + "ChainDeploymentsV1": { + "description": "A list of chain deployments.", + "properties": { + "deployments": { + "description": "A list of chain deployments", + "items": { + "$ref": "#/components/schemas/ChainDeploymentV1" + }, + "title": "Deployments", + "type": "array" } }, "required": [ - "status", - "percent_traffic_to_new_version" + "deployments" ], - "title": "InProgressPromotionV1", + "title": "ChainDeploymentsV1", "type": "object" }, - "OneTimeAutoscalingScheduleV1": { + "ChainDeploymentTombstoneV1": { + "description": "A chain deployment tombstone.", "properties": { "id": { - "description": "Stable unique identifier of the schedule", + "description": "Unique identifier of the chain deployment", "title": "Id", "type": "string" }, - "name": { - "description": "Name of the schedule", - "title": "Name", - "type": "string" - }, - "enabled": { - "description": "Whether the schedule is enabled", - "title": "Enabled", + "deleted": { + "description": "Whether the chain deployment was deleted", + "title": "Deleted", "type": "boolean" }, - "autoscaling_settings": { - "$ref": "#/components/schemas/AutoscalingScheduleSettingsV1", - "description": "Raw autoscaling overrides applied during the schedule window" - }, - "cadence": { - "const": "ONE_TIME", - "description": "One-time schedule cadence", - "title": "Cadence", - "type": "string" - }, - "start_at": { - "description": "Inclusive start of the schedule window", - "format": "date-time", - "title": "Start At", - "type": "string" - }, - "end_at": { - "description": "Exclusive end of the schedule window", - "format": "date-time", - "title": "End At", + "chain_id": { + "description": "Unique identifier of the chain", + "title": "Chain Id", "type": "string" } }, "required": [ "id", - "name", - "enabled", - "autoscaling_settings", - "cadence", - "start_at", - "end_at" + "deleted", + "chain_id" ], - "title": "OneTimeAutoscalingScheduleV1", + "title": "ChainDeploymentTombstoneV1", "type": "object" }, - "PromotionCleanupStrategyV1": { - "description": "The promotion cleanup strategy.", - "enum": [ - "KEEP", - "SCALE_TO_ZERO", - "DEACTIVATE" - ], - "title": "PromotionCleanupStrategyV1", - "type": "string" - }, - "PromotionSettingsV1": { - "description": "Promotion settings for promoting chains and oracles", + "ChainletEnvironmentSettingsRequestV1": { + "description": "Request to create environment settings for a chainlet.", "properties": { - "redeploy_on_promotion": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", - "examples": [ - true - ], - "title": "Redeploy On Promotion" - }, - "rolling_deploy": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Whether the environment should rely on rolling deploy orchestration.", + "chainlet_name": { + "description": "Name of the chainlet", "examples": [ - true - ], - "title": "Rolling Deploy" - }, - "promotion_cleanup_strategy": { - "anyOf": [ - { - "$ref": "#/components/schemas/PromotionCleanupStrategyV1" - }, - { - "type": "null" - } + "HelloWorld" ], - "default": "SCALE_TO_ZERO", - "description": "The cleanup strategy to use after a promotion completes.", - "examples": [ - "SCALE_TO_ZERO" - ] + "title": "Chainlet Name", + "type": "string" }, - "rolling_deploy_config": { + "autoscaling_settings": { "anyOf": [ { - "$ref": "#/components/schemas/RollingDeployConfigV1" + "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" }, { "type": "null" } ], "default": null, - "description": "Rolling deploy configuration for promotions" - }, - "ramp_up_while_promoting": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Whether to ramp up traffic while promoting", + "description": "Autoscaling settings for the chainlet", "examples": [ - true - ], - "title": "Ramp Up While Promoting" - }, - "ramp_up_duration_seconds": { - "anyOf": [ { - "type": "integer" - }, - { - "type": "null" + "autoscaling_window": 60, + "concurrency_target": 1, + "max_replica": 1, + "max_scale_down_rate": null, + "min_replica": 0, + "scale_down_delay": 900, + "target_in_flight_tokens": null, + "target_utilization_percentage": 70 } - ], - "default": 600, - "description": "Duration of the ramp up in seconds", - "examples": [ - 600 - ], - "title": "Ramp Up Duration Seconds" - } - }, - "title": "PromotionSettingsV1", - "type": "object" - }, - "RollingDeployConfigV1": { - "description": "Rolling deploy config for promoting chains and oracles", - "properties": { - "rolling_deploy_strategy": { - "$ref": "#/components/schemas/RollingDeployStrategyV1", - "default": "REPLICA", - "description": "The rolling deploy strategy to use for promotions.", - "examples": [ - "REPLICA" ] }, - "max_surge_percent": { - "default": 25, - "description": "The maximum surge percentage for rolling deploys.", - "examples": [ - 25 - ], - "title": "Max Surge Percent", - "type": "integer" - }, - "max_unavailable_percent": { - "default": 0, - "description": "The maximum unavailable percentage for rolling deploys.", - "examples": [ - 10 - ], - "title": "Max Unavailable Percent", - "type": "integer" - }, - "stabilization_time_seconds": { - "default": 0, - "description": "The stabilization time in seconds for rolling deploys.", - "examples": [ - 300 - ], - "title": "Stabilization Time Seconds", - "type": "integer" - }, - "replica_overhead_percent": { - "default": 0, - "description": "The replica overhead percentage for rolling deploys.", + "instance_type_id": { + "default": "1x2", + "description": "ID of the instance type to use for the chainlet", "examples": [ - 0 + "1x4", + "2x8", + "A10G:2x24x96", + "H100:2x52x468" ], - "title": "Replica Overhead Percent", - "type": "integer" - } - }, - "title": "RollingDeployConfigV1", - "type": "object" - }, - "RollingDeployStrategyV1": { - "description": "The rolling deploy strategy.", - "enum": [ - "REPLICA" - ], - "title": "RollingDeployStrategyV1", - "type": "string" - }, - "EnvironmentsV1": { - "description": "list of environments", - "properties": { - "environments": { - "items": { - "$ref": "#/components/schemas/EnvironmentV1" - }, - "title": "Environments", - "type": "array" + "title": "Instance Type Id", + "type": "string" } }, "required": [ - "environments" + "chainlet_name" ], - "title": "EnvironmentsV1", + "title": "ChainletEnvironmentSettingsRequestV1", "type": "object" }, - "UpdatePromotionSettingsV1": { - "description": "Promotion settings for model promotion", + "CreateChainEnvironmentRequestV1": { + "description": "A request to create a custom environment for a chain.", "properties": { - "redeploy_on_promotion": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Whether to deploy on all promotions. Enabling this flag allows model code to safely handle environment-specific logic. When a deployment is promoted, a new deployment will be created with a copy of the image.", + "name": { + "description": "Name of the environment", "examples": [ - true + "staging" ], - "title": "Redeploy On Promotion" + "title": "Name", + "type": "string" }, - "rolling_deploy": { + "promotion_settings": { "anyOf": [ { - "type": "boolean" + "$ref": "#/components/schemas/UpdatePromotionSettingsV1" }, { "type": "null" } ], "default": null, - "description": "Whether the environment should rely on rolling deploy orchestration.", + "description": "Promotion settings for the environment", "examples": [ - true - ], - "title": "Rolling Deploy" - }, - "promotion_cleanup_strategy": { - "anyOf": [ - { - "$ref": "#/components/schemas/PromotionCleanupStrategyV1" - }, { - "type": "null" + "promotion_cleanup_strategy": null, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": true, + "redeploy_on_promotion": true, + "rolling_deploy": null, + "rolling_deploy_config": null } - ], - "default": null, - "description": "The cleanup strategy to use after a promotion completes.", - "examples": [ - "SCALE_TO_ZERO" ] }, - "rolling_deploy_config": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdateRollingDeployConfigV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Rolling deploy configuration for promotions" - }, - "ramp_up_while_promoting": { + "chainlet_settings": { "anyOf": [ { - "type": "boolean" + "items": { + "$ref": "#/components/schemas/ChainletEnvironmentSettingsRequestV1" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "description": "Whether to ramp up traffic while promoting", + "description": "Mapping of chainlet name to the desired chainlet environment settings", "examples": [ - true + [ + { + "autoscaling_settings": { + "autoscaling_window": 800, + "concurrency_target": 4, + "max_replica": 3, + "max_scale_down_rate": null, + "min_replica": 2, + "scale_down_delay": 63, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + }, + "chainlet_name": "HelloWorld", + "instance_type_id": "2x8" + }, + { + "autoscaling_settings": { + "autoscaling_window": null, + "concurrency_target": null, + "max_replica": 3, + "max_scale_down_rate": null, + "min_replica": 3, + "scale_down_delay": null, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + }, + "chainlet_name": "RandInt", + "instance_type_id": "A10Gx8x32" + } + ] ], - "title": "Ramp Up While Promoting" + "title": "Chainlet Settings" + } + }, + "required": [ + "name" + ], + "title": "CreateChainEnvironmentRequestV1", + "type": "object" + }, + "ChainletEnvironmentSettingsV1": { + "description": "Environment settings for a chainlet.", + "properties": { + "chainlet_name": { + "description": "Name of the chainlet", + "title": "Chainlet Name", + "type": "string" }, - "ramp_up_duration_seconds": { + "autoscaling_settings": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/AutoscalingSettingsV1" }, { "type": "null" } ], - "default": null, - "description": "Duration of the ramp up in seconds", - "examples": [ - 600 - ], - "title": "Ramp Up Duration Seconds" + "description": "Autoscaling settings for the chainlet. If null, it has not finished deploying" + }, + "instance_type": { + "$ref": "#/components/schemas/InstanceTypeV1", + "description": "Instance type for the chainlet" } }, - "title": "UpdatePromotionSettingsV1", + "required": [ + "chainlet_name", + "autoscaling_settings", + "instance_type" + ], + "title": "ChainletEnvironmentSettingsV1", "type": "object" }, - "UpdateRollingDeployConfigV1": { - "description": "Rolling deploy config for promoting chains and oracles", + "ChainEnvironmentV1": { + "description": "Environment for oracles.", "properties": { - "rolling_deploy_strategy": { + "name": { + "description": "Name of the environment", + "title": "Name", + "type": "string" + }, + "created_at": { + "description": "Time the environment was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "chain_id": { + "description": "Unique identifier of the chain", + "title": "Chain Id", + "type": "string" + }, + "promotion_settings": { + "$ref": "#/components/schemas/PromotionSettingsV1", + "description": "Promotion settings for the environment" + }, + "chainlet_settings": { + "description": "Environment settings for the chainlets", + "items": { + "$ref": "#/components/schemas/ChainletEnvironmentSettingsV1" + }, + "title": "Chainlet Settings", + "type": "array" + }, + "current_deployment": { "anyOf": [ { - "$ref": "#/components/schemas/RollingDeployStrategyV1" + "$ref": "#/components/schemas/ChainDeploymentV1" }, { "type": "null" } ], - "default": null, - "description": "The rolling deploy strategy to use for promotions.", - "examples": [ - "REPLICA" - ] + "description": "Current chain deployment of the environment" }, - "max_surge_percent": { + "candidate_deployment": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/ChainDeploymentV1" }, { "type": "null" } ], "default": null, - "description": "The maximum surge percentage for rolling deploys.", - "examples": [ - 25 - ], - "title": "Max Surge Percent" + "description": "Candidate chain deployment being promoted to the environment, if a promotion is in progress" }, - "max_unavailable_percent": { + "in_progress_promotion": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/InProgressPromotionV1" }, { "type": "null" } ], "default": null, - "description": "The maximum unavailable percentage for rolling deploys.", - "examples": [ - 10 - ], - "title": "Max Unavailable Percent" - }, - "stabilization_time_seconds": { + "description": "Details of the in-progress promotion, if any" + } + }, + "required": [ + "name", + "created_at", + "chain_id", + "promotion_settings", + "chainlet_settings", + "current_deployment" + ], + "title": "ChainEnvironmentV1", + "type": "object" + }, + "UpdateChainEnvironmentRequestV1": { + "description": "A request to update a chain environment.", + "properties": { + "promotion_settings": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/UpdatePromotionSettingsV1" }, { "type": "null" } ], "default": null, - "description": "The stabilization time in seconds for rolling deploys.", + "description": "Promotion settings for the environment", + "examples": [ + { + "promotion_cleanup_strategy": null, + "ramp_up_duration_seconds": 600, + "ramp_up_while_promoting": true, + "redeploy_on_promotion": null, + "rolling_deploy": null, + "rolling_deploy_config": null + } + ] + } + }, + "title": "UpdateChainEnvironmentRequestV1", + "type": "object" + }, + "UpdateChainEnvironmentResponseV1": { + "description": "A response to update a chain environment.", + "properties": { + "ok": { + "description": "Whether the update was successful", + "title": "Ok", + "type": "boolean" + } + }, + "required": [ + "ok" + ], + "title": "UpdateChainEnvironmentResponseV1", + "type": "object" + }, + "PromoteToChainEnvironmentRequestV1": { + "description": "A request to promote a deployment to a environment.", + "properties": { + "scale_down_previous_deployment": { + "default": true, + "description": "Whether to scale down the previous deployment after promoting", "examples": [ - 300 + true ], - "title": "Stabilization Time Seconds" + "title": "Scale Down Previous Deployment", + "type": "boolean" }, - "replica_overhead_percent": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "The replica overhead percentage for rolling deploys.", - "examples": [ - 0 - ], - "title": "Replica Overhead Percent" + "deployment_id": { + "description": "The id of the chain deployment to promote", + "title": "Deployment Id", + "type": "string" } }, - "title": "UpdateRollingDeployConfigV1", + "required": [ + "deployment_id" + ], + "title": "PromoteToChainEnvironmentRequestV1", "type": "object" }, - "CreateEnvironmentRequestV1": { - "description": "A request to create an environment.", + "ChainletEnvironmentAutoscalingSettingsUpdateV1": { + "description": "The request to update the autoscaling settings for a chainlet.", "properties": { - "name": { - "description": "Name of the environment", + "chainlet_name": { + "description": "Name of the chainlet", "examples": [ - "staging" + "HelloWorld" ], - "title": "Name", + "title": "Chainlet Name", "type": "string" }, "autoscaling_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Autoscaling settings for the environment", + "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1", + "description": "Autoscaling settings for the chainlet", "examples": [ { "autoscaling_window": 800, @@ -17632,279 +22298,422 @@ "target_utilization_percentage": null } ] + } + }, + "required": [ + "chainlet_name", + "autoscaling_settings" + ], + "title": "ChainletEnvironmentAutoscalingSettingsUpdateV1", + "type": "object" + }, + "UpdateChainletEnvironmentAutoscalingSettingsRequestV1": { + "description": "A request to update the autoscaling settings for a multiple chainlets in an environment.\nIf a chainlet name doesn't exist, an error is returned.", + "properties": { + "updates": { + "description": "Mapping of chainlet name to the desired chainlet autoscaling settings. If the chainlet name doesn't exist, an error is returned.", + "examples": [ + [ + { + "autoscaling_settings": { + "autoscaling_window": 800, + "concurrency_target": 4, + "max_replica": 3, + "max_scale_down_rate": null, + "min_replica": 2, + "scale_down_delay": 63, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + }, + "chainlet_name": "HelloWorld" + } + ], + [ + { + "autoscaling_settings": { + "autoscaling_window": null, + "concurrency_target": null, + "max_replica": null, + "max_scale_down_rate": null, + "min_replica": 0, + "scale_down_delay": null, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + }, + "chainlet_name": "HelloWorld" + }, + { + "autoscaling_settings": { + "autoscaling_window": null, + "concurrency_target": null, + "max_replica": null, + "max_scale_down_rate": null, + "min_replica": 0, + "scale_down_delay": null, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + }, + "chainlet_name": "RandInt" + } + ] + ], + "items": { + "$ref": "#/components/schemas/ChainletEnvironmentAutoscalingSettingsUpdateV1" + }, + "title": "Updates", + "type": "array" + } + }, + "required": [ + "updates" + ], + "title": "UpdateChainletEnvironmentAutoscalingSettingsRequestV1", + "type": "object" + }, + "ChainletEnvironmentInstanceTypeUpdateV1": { + "description": "A request to update the environment settings for a chainlet.", + "properties": { + "chainlet_name": { + "description": "Name of the chainlet", + "examples": [ + "HelloWorld" + ], + "title": "Chainlet Name", + "type": "string" }, - "promotion_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdatePromotionSettingsV1" - }, - { - "type": "null" - } + "instance_type_id": { + "description": "Key of the instance type to use for the chainlet", + "examples": [ + "1x4", + "2x8", + "A10G:2x24x96" ], - "default": null, - "description": "Promotion settings for the environment", + "title": "Instance Type Id", + "type": "string" + } + }, + "required": [ + "chainlet_name", + "instance_type_id" + ], + "title": "ChainletEnvironmentInstanceTypeUpdateV1", + "type": "object" + }, + "UpdateChainletEnvironmentInstanceTypeRequestV1": { + "description": "A request to update the instance types for chainlets in an environment. Multiples\nupdates can be made in one request. The updates will be processed in batch and a new deployment\nwill be created, deployed and promoted into the environment.", + "properties": { + "updates": { + "description": "Mapping of chainlet name to the desired chainlet instance type. If the chainlet name doesn't exist, an error is returned.", "examples": [ - { - "promotion_cleanup_strategy": null, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": true, - "redeploy_on_promotion": true, - "rolling_deploy": true, - "rolling_deploy_config": null - } - ] + [ + { + "chainlet_name": "HelloWorld", + "instance_type_id": "1x4" + }, + { + "chainlet_name": "RandInt", + "instance_type_id": "A10G:2x24x96" + } + ] + ], + "items": { + "$ref": "#/components/schemas/ChainletEnvironmentInstanceTypeUpdateV1" + }, + "title": "Updates", + "type": "array" + } + }, + "required": [ + "updates" + ], + "title": "UpdateChainletEnvironmentInstanceTypeRequestV1", + "type": "object" + }, + "UpdateChainletEnvironmentInstanceTypeResponseV1": { + "description": "A response to update the environment settings for a chainlet. If updating the instance type\nresulted in a re-deployment, `requires_redeployment` will be True and the resulting deployment\nwill be returned in the `chain_deployment` field.", + "properties": { + "requires_redeployment": { + "description": "Whether the resource update requires a re-deployment to update the instance type.", + "title": "Requires Redeployment", + "type": "boolean" }, - "request_backpressure_settings": { + "chain_deployment": { "anyOf": [ { - "$ref": "#/components/schemas/UpdateRequestBackpressureSettingsV1" + "$ref": "#/components/schemas/ChainDeploymentV1" }, { "type": "null" } ], - "default": null, - "description": "Request backpressure settings for the environment." + "description": "The chain deployment resulting from the resource update, if any." + }, + "chainlet_environment_settings": { + "description": "The updated chainlet environment settings", + "items": { + "$ref": "#/components/schemas/ChainletEnvironmentSettingsV1" + }, + "title": "Chainlet Environment Settings", + "type": "array" + } + }, + "required": [ + "requires_redeployment", + "chain_deployment", + "chainlet_environment_settings" + ], + "title": "UpdateChainletEnvironmentInstanceTypeResponseV1", + "type": "object" + }, + "UpsertTrainingProjectV1": { + "description": "Fields that can be upserted on a training project.", + "properties": { + "name": { + "description": "Name of the training project.", + "examples": [ + "My Training Project" + ], + "title": "Name", + "type": "string" } }, "required": [ "name" ], - "title": "CreateEnvironmentRequestV1", + "title": "UpsertTrainingProjectV1", "type": "object" }, - "EnvironmentTombstoneV1": { - "description": "An environment tombstone.", + "UpsertTrainingProjectRequestV1": { + "description": "A request to upsert a training project.", "properties": { - "name": { - "description": "Name of the environment", - "title": "Name", - "type": "string" - }, - "model_id": { - "description": "Unique identifier of the model", - "title": "Model Id", - "type": "string" - }, - "deleted": { - "description": "Whether the environment was deleted", - "title": "Deleted", - "type": "boolean" + "training_project": { + "$ref": "#/components/schemas/UpsertTrainingProjectV1", + "description": "The training project to upsert." } }, "required": [ - "name", - "model_id", - "deleted" + "training_project" ], - "title": "EnvironmentTombstoneV1", + "title": "UpsertTrainingProjectRequestV1", "type": "object" }, - "AutoscalingScheduleSettingsRequestV1": { - "additionalProperties": false, - "description": "A complete set of raw autoscaling overrides for a schedule.", + "CheckpointSyncStatus": { + "description": "Lifecycle state for the checkpoint uploader.", + "enum": [ + "SYNCING", + "COMPLETED" + ], + "title": "CheckpointSyncStatus", + "type": "string" + }, + "TrainingJobV1": { "properties": { - "min_replica": { - "description": "Minimum number of replicas", - "title": "Min Replica", - "type": "integer" + "id": { + "description": "Unique identifier of the training job.", + "title": "Id", + "type": "string" }, - "max_replica": { - "description": "Maximum number of replicas", - "title": "Max Replica", - "type": "integer" + "created_at": { + "description": "Time the job was created in ISO 8601 format.", + "format": "date-time", + "title": "Created At", + "type": "string" }, - "autoscaling_window": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Timeframe of traffic considered for autoscaling decisions. Null stores no schedule override and follows the current environment value.", - "title": "Autoscaling Window" + "current_status": { + "description": "Current status of the training job.", + "title": "Current Status", + "type": "string" }, - "scale_down_delay": { + "error_message": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "description": "Waiting period before scaling down any active replica. Null stores no schedule override and follows the current environment value.", - "title": "Scale Down Delay" + "default": null, + "description": "Error message if the training job failed.", + "title": "Error Message" }, - "concurrency_target": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } + "instance_type": { + "$ref": "#/components/schemas/InstanceTypeV1", + "description": "Instance type of the training job." + }, + "node_count": { + "default": 1, + "description": "Number of nodes the job runs on. The instance type describes a single node, so the job's total GPU count is gpu_count multiplied by node_count.", + "examples": [ + 2 ], - "description": "Number of requests per replica before scaling up. Null stores no schedule override and follows the current environment value.", - "title": "Concurrency Target" + "minimum": 1, + "title": "Node Count", + "type": "integer" }, - "target_utilization_percentage": { + "updated_at": { + "description": "Time the job was updated in ISO 8601 format.", + "format": "date-time", + "title": "Updated At", + "type": "string" + }, + "training_project_id": { + "description": "ID of the training project.", + "title": "Training Project Id", + "type": "string" + }, + "training_project": { + "$ref": "#/components/schemas/TrainingProjectSummaryV1", + "description": "Summary of the training project." + }, + "name": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], - "description": "Target utilization percentage for scaling up/down. Null stores no schedule override and follows the current environment value.", - "title": "Target Utilization Percentage" + "default": null, + "description": "Name of the training job.", + "examples": [ + "gpt-oss-job" + ], + "title": "Name" }, - "target_in_flight_tokens": { + "checkpoint_sync_status": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/CheckpointSyncStatus" }, { "type": "null" } ], - "description": "Target number of in-flight tokens for autoscaling decisions. Null stores no schedule override and follows the current environment value. Early access only.", - "title": "Target In Flight Tokens" + "default": null, + "description": "Checkpoint sync status of the training job." }, - "max_scale_down_rate": { + "priority": { + "default": 0, + "description": "Queue priority. Higher values are dequeued first. NULL is treated as 0.", + "title": "Priority", + "type": "integer" + }, + "availability_model": { + "$ref": "#/components/schemas/V1AvailabilityModel", + "default": "dedicated", + "description": "Capacity guarantee for the job. 'dedicated' is non-preemptible on-demand capacity; 'spot' is interruptible." + }, + "user": { "anyOf": [ { - "maximum": 50, - "minimum": 1, - "type": "integer" + "$ref": "#/components/schemas/UserV1" }, { "type": "null" } ], - "description": "Maximum percentage of replicas that can be removed per autoscaling window. Null stores no schedule override and follows the current environment value.", - "title": "Max Scale Down Rate" + "default": null, + "description": "The user who created the training job." } }, "required": [ - "min_replica", - "max_replica", - "autoscaling_window", - "scale_down_delay", - "concurrency_target", - "target_utilization_percentage", - "target_in_flight_tokens", - "max_scale_down_rate" + "id", + "created_at", + "current_status", + "instance_type", + "updated_at", + "training_project_id", + "training_project" ], - "title": "AutoscalingScheduleSettingsRequestV1", + "title": "TrainingJobV1", "type": "object" }, - "AutoscalingScheduleUpsertV1": { - "additionalProperties": false, - "description": "A complete recurring schedule submitted for create or replacement.", + "TrainingProjectSummaryV1": { + "description": "A summary of a training project.", "properties": { "id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Stable schedule identifier. Omit this field to create a schedule.", - "title": "Id" + "description": "Unique identifier of the training project.", + "title": "Id", + "type": "string" }, "name": { - "description": "Name of the schedule", + "description": "Name of the training project.", "title": "Name", "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "title": "TrainingProjectSummaryV1", + "type": "object" + }, + "TrainingProjectV1": { + "properties": { + "id": { + "description": "Unique identifier of the training project", + "title": "Id", + "type": "string" }, - "enabled": { - "description": "Whether the schedule is enabled", - "title": "Enabled", - "type": "boolean" - }, - "autoscaling_settings": { - "$ref": "#/components/schemas/AutoscalingScheduleSettingsRequestV1", - "description": "Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." + "name": { + "description": "Name of the training project.", + "title": "Name", + "type": "string" }, - "cadence": { - "description": "Recurring schedule cadence", - "enum": [ - "DAILY", - "HOURLY" - ], - "title": "Cadence", + "created_at": { + "description": "Time the training project was created in ISO 8601 format.", + "format": "date-time", + "title": "Created At", "type": "string" }, - "weekdays": { - "description": "Weekdays on which the schedule runs", - "items": { - "$ref": "#/components/schemas/AutoscalingScheduleWeekdayV1" - }, - "title": "Weekdays", - "type": "array" + "updated_at": { + "description": "Time the training project was updated in ISO 8601 format.", + "format": "date-time", + "title": "Updated At", + "type": "string" }, - "start_hour": { + "team_name": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Start hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", - "title": "Start Hour" - }, - "start_minute": { - "description": "Start minute of the schedule window", - "title": "Start Minute", - "type": "integer" + "description": "Name of the team associated with the training project.", + "title": "Team Name" }, - "end_hour": { + "latest_job": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/TrainingJobV1" }, { "type": "null" } ], - "default": null, - "description": "End hour in the environment schedule timezone. Omit for unrestricted HOURLY schedules.", - "title": "End Hour" - }, - "end_minute": { - "description": "End minute of the schedule window", - "title": "End Minute", - "type": "integer" + "description": "Most recently created training job for the training project." } }, "required": [ + "id", "name", - "enabled", - "autoscaling_settings", - "cadence", - "weekdays", - "start_minute", - "end_minute" + "created_at", + "updated_at", + "latest_job" ], - "title": "AutoscalingScheduleUpsertV1", + "title": "TrainingProjectV1", "type": "object" }, - "OneTimeAutoscalingScheduleUpsertV1": { - "additionalProperties": false, - "description": "A complete one-time schedule submitted for create or replacement.", + "UserV1": { + "description": "A user.", "properties": { - "id": { + "email": { "anyOf": [ { "type": "string" @@ -17914,368 +22723,304 @@ } ], "default": null, - "description": "Stable schedule identifier. Omit this field to create a schedule.", - "title": "Id" - }, - "name": { - "description": "Name of the schedule", - "title": "Name", - "type": "string" - }, - "enabled": { - "description": "Whether the schedule is enabled", - "title": "Enabled", - "type": "boolean" - }, - "autoscaling_settings": { - "$ref": "#/components/schemas/AutoscalingScheduleSettingsRequestV1", - "description": "Complete raw autoscaling overrides for the schedule. Every field is required; nullable fields store no schedule override and follow the current environment value." - }, - "cadence": { - "const": "ONE_TIME", - "description": "One-time schedule cadence", - "title": "Cadence", - "type": "string" - }, - "start_at": { - "description": "Inclusive start of the schedule window in ISO 8601 format. New schedules must start in the future.", - "format": "date-time", - "title": "Start At", - "type": "string" - }, - "end_at": { - "description": "Exclusive end of the schedule window in ISO 8601 format", - "format": "date-time", - "title": "End At", - "type": "string" + "description": "Email of the user.", + "title": "Email" + } + }, + "title": "UserV1", + "type": "object" + }, + "V1AvailabilityModel": { + "description": "Capacity guarantee under which a training job is scheduled.\n\n``DEDICATED`` is on-demand capacity that is not preempted (the default). ``SPOT`` is\ninterruptible capacity that may be preempted; the user is responsible for checkpointing\ntheir own progress. A managed/resumable model where the platform handles\ncheckpoint/resume on its own is intentionally not defined yet; it is planned for a\nfuture milestone.", + "enum": [ + "dedicated", + "spot" + ], + "title": "V1AvailabilityModel", + "type": "string" + }, + "UpsertTrainingProjectResponseV1": { + "description": "A response to upserting a training project.", + "properties": { + "training_project": { + "$ref": "#/components/schemas/TrainingProjectV1", + "description": "The upserted training project." } }, "required": [ - "name", - "enabled", - "autoscaling_settings", - "cadence", - "start_at", - "end_at" + "training_project" ], - "title": "OneTimeAutoscalingScheduleUpsertV1", + "title": "UpsertTrainingProjectResponseV1", "type": "object" }, - "UpdateAutoscalingScheduleSettingsV1": { - "additionalProperties": false, - "description": "Partial mutation of an environment's autoscaling schedule collection.", + "ListTrainingProjectsResponseV1": { + "description": "A response to list training projects.", "properties": { - "timezone": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "IANA timezone shared by the resulting collection. Omission preserves the current timezone; null is allowed only when deleting every schedule.", - "title": "Timezone", - "x-null-distinct": true - }, - "schedules": { - "description": "Complete schedules to create or replace. Existing schedules omitted from this list are unchanged.", - "items": { - "discriminator": { - "mapping": { - "DAILY": "#/components/schemas/AutoscalingScheduleUpsertV1", - "HOURLY": "#/components/schemas/AutoscalingScheduleUpsertV1", - "ONE_TIME": "#/components/schemas/OneTimeAutoscalingScheduleUpsertV1" - }, - "propertyName": "cadence" - }, - "oneOf": [ - { - "$ref": "#/components/schemas/AutoscalingScheduleUpsertV1" - }, - { - "$ref": "#/components/schemas/OneTimeAutoscalingScheduleUpsertV1" - } - ] - }, - "title": "Schedules", - "type": "array" - }, - "delete_schedules": { - "description": "Stable identifiers of schedules to delete. To clear all schedules, include every existing schedule identifier.", + "training_projects": { + "description": "List of training projects.", "items": { - "type": "string" + "$ref": "#/components/schemas/TrainingProjectV1" }, - "title": "Delete Schedules", + "title": "Training Projects", "type": "array" } }, - "title": "UpdateAutoscalingScheduleSettingsV1", + "required": [ + "training_projects" + ], + "title": "ListTrainingProjectsResponseV1", "type": "object" }, - "UpdateEnvironmentRequestV1": { - "additionalProperties": false, - "description": "A request to update an environment.", + "ListTrainingJobsResponseV1": { + "description": "A response to list training jobs.", "properties": { - "autoscaling_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Autoscaling settings for the environment", - "examples": [ - { - "autoscaling_window": 800, - "concurrency_target": 3, - "max_replica": 2, - "max_scale_down_rate": null, - "min_replica": 1, - "scale_down_delay": 60, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - } - ] - }, - "promotion_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdatePromotionSettingsV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Promotion settings for the environment", - "examples": [ - { - "promotion_cleanup_strategy": null, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": true, - "redeploy_on_promotion": true, - "rolling_deploy": null, - "rolling_deploy_config": null - } - ] - }, - "autoscaling_schedule_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdateAutoscalingScheduleSettingsV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Partial autoscaling schedule collection update. Omitted collection fields and existing schedules are unchanged; each submitted schedule is a complete create or replacement.", - "examples": [ - { - "schedules": [ - { - "autoscaling_settings": { - "autoscaling_window": null, - "concurrency_target": null, - "max_replica": 8, - "max_scale_down_rate": null, - "min_replica": 2, - "scale_down_delay": null, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - }, - "cadence": "DAILY", - "enabled": true, - "end_hour": 10, - "end_minute": 0, - "name": "weekday-peak", - "start_hour": 8, - "start_minute": 0, - "weekdays": [ - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY" - ] - } - ], - "timezone": "America/Los_Angeles" - }, - { - "delete_schedules": [ - "schedule-id" - ] - } - ] + "training_project": { + "$ref": "#/components/schemas/TrainingProjectV1", + "description": "The training project." }, - "request_backpressure_settings": { - "anyOf": [ - { - "$ref": "#/components/schemas/UpdateRequestBackpressureSettingsV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Request backpressure settings for the environment.", - "examples": [ - { - "policy": "REJECT_ON_FULL" - } - ] + "training_jobs": { + "description": "List of training jobs.", + "items": { + "$ref": "#/components/schemas/TrainingJobV1" + }, + "title": "Training Jobs", + "type": "array" } }, - "title": "UpdateEnvironmentRequestV1", + "required": [ + "training_project", + "training_jobs" + ], + "title": "ListTrainingJobsResponseV1", "type": "object" }, - "UpdateEnvironmentResponseV1": { - "description": "The response to a request to update an environment's settings.", + "AuthMethod": { + "enum": [ + "CUSTOM_SECRET", + "AWS_OIDC", + "GCP_OIDC", + "AWS_ASSUME_ROLE" + ], + "title": "AuthMethod", + "type": "string" + }, + "AwsAssumeRoleDockerAuthV1": { + "description": "AWS assume-role details for the registry.", "properties": { - "environment": { - "$ref": "#/components/schemas/EnvironmentV1", - "description": "The environment after the update, matching the shape returned by GET." + "role_arn": { + "description": "AWS IAM role ARN that Baseten assumes to pull from the registry. The role's trust policy must allow Baseten's AWS principal with your Baseten-provided external ID.", + "title": "Role Arn", + "type": "string" }, - "status": { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsStatusV1", - "deprecated": true, - "description": "Deprecated. Kept for legacy autoscaling-only update operation behavior." + "region": { + "description": "AWS region of the registry", + "title": "Region", + "type": "string" + } + }, + "required": [ + "role_arn", + "region" + ], + "title": "AwsAssumeRoleDockerAuthV1", + "type": "object" + }, + "AwsIamDockerAuthV1": { + "description": "AWS details for the registry.", + "properties": { + "access_key_secret_ref": { + "$ref": "#/components/schemas/SecretReferenceV1", + "description": "Name of the access key secret" }, - "message": { - "deprecated": true, - "description": "Deprecated. Kept for legacy autoscaling-only update operation behavior.", - "title": "Message", + "secret_access_key_secret_ref": { + "$ref": "#/components/schemas/SecretReferenceV1", + "description": "Name of the secret key secret" + } + }, + "required": [ + "access_key_secret_ref", + "secret_access_key_secret_ref" + ], + "title": "AwsIamDockerAuthV1", + "type": "object" + }, + "AwsOidcDockerAuthV1": { + "description": "AWS OIDC details for the registry.", + "properties": { + "role_arn": { + "description": "AWS IAM role ARN for OIDC authentication", + "title": "Role Arn", + "type": "string" + }, + "region": { + "description": "AWS region for OIDC authentication", + "title": "Region", "type": "string" } }, "required": [ - "environment", - "status", - "message" + "role_arn", + "region" ], - "title": "UpdateEnvironmentResponseV1", + "title": "AwsOidcDockerAuthV1", "type": "object" }, - "GetEnvironmentLogsRequestV1": { - "description": "A request to fetch logs for a model environment.\n\nReturns logs from every deployment that was active on the environment over\nthe requested time range, merged in timestamp order.", + "BasetenLatestCheckpointConfig": { "properties": { - "start_epoch_millis": { + "project_name": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - "title": "Start Epoch Millis" + "description": "Name of the project to load the checkpoint from", + "title": "Project Name" }, - "end_epoch_millis": { + "job_id": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - "title": "End Epoch Millis" + "description": "ID of the job to load the checkpoint from", + "title": "Job Id" }, - "direction": { + "typ": { + "const": "baseten_latest_checkpoint", + "default": "baseten_latest_checkpoint", + "title": "Typ", + "type": "string" + } + }, + "title": "BasetenLatestCheckpointConfig", + "type": "object" + }, + "BasetenNamedCheckpointConfig": { + "properties": { + "checkpoint_name": { + "description": "Name of the checkpoint to load from", + "title": "Checkpoint Name", + "type": "string" + }, + "project_name": { "anyOf": [ { - "$ref": "#/components/schemas/SortOrderV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Sort order for logs" + "description": "Name of the project to load the checkpoint from", + "title": "Project Name" }, - "limit": { + "job_id": { "anyOf": [ { - "maximum": 1000, - "minimum": 1, - "type": "integer" + "type": "string" }, { "type": "null" } ], - "default": 500, - "description": "Limit of logs to fetch in a single request", - "title": "Limit" + "default": null, + "description": "ID of the job to load the checkpoint from", + "title": "Job Id" }, - "min_level": { - "anyOf": [ - { - "$ref": "#/components/schemas/LogLevelV1" - }, - { - "type": "null" - } + "typ": { + "const": "baseten_named_checkpoint", + "default": "baseten_named_checkpoint", + "title": "Typ", + "type": "string" + } + }, + "required": [ + "checkpoint_name" + ], + "title": "BasetenNamedCheckpointConfig", + "type": "object" + }, + "CreateJobWeightConfigV1": { + "description": "Weight source configuration for MDN (Model Distribution Network).\n\nEnables training jobs to mount external model weights from HuggingFace, S3, GCS, R2,\nor CoreWeave via MDN's caching and CSI mounting infrastructure. Weights are mirrored\nonce and deduplicated across training jobs.", + "properties": { + "source": { + "description": "Weight source URI. Supported formats: hf://, s3://, gs://, r2://, cw://", + "examples": [ + "hf://meta-llama/Llama-3-8B@main", + "s3://my-bucket/models/llama", + "gs://my-bucket/models/llama", + "r2://account_id.bucket/models/llama", + "r2://account_id.eu.bucket/models/llama", + "cw://my-bucket/models/llama" ], - "default": null, - "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + "title": "Source", + "type": "string" }, - "replica": { - "anyOf": [ - { - "maxLength": 256, - "type": "string" - }, - { - "type": "null" - } + "mount_location": { + "description": "Path where weights will be mounted in the container", + "examples": [ + "/app/models/base", + "/models/llama" ], - "default": null, - "description": "Only return logs emitted by this replica (5-char short ID).", - "title": "Replica" + "title": "Mount Location", + "type": "string" }, - "request_id": { + "allow_patterns": { "anyOf": [ { - "maxLength": 256, - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "description": "Only return logs tagged with this inference request ID.", - "title": "Request Id" + "description": "File patterns to include (Unix-style shell patterns)", + "examples": [ + [ + "*.safetensors", + "config.json" + ] + ], + "title": "Allow Patterns" }, - "component": { + "ignore_patterns": { "anyOf": [ { - "maxLength": 256, - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "description": "Only return logs from this component.", - "title": "Component" + "description": "File patterns to exclude (Unix-style shell patterns)", + "examples": [ + [ + "*.bin", + "*.h5" + ] + ], + "title": "Ignore Patterns" }, - "search_pattern": { + "auth_secret_name": { "anyOf": [ { - "maxLength": 256, "type": "string" }, { @@ -18283,943 +23028,882 @@ } ], "default": null, - "description": "RE2 regular expression matched against the log message. Prefer `includes` and `excludes` for plain substring matches.", - "title": "Search Pattern" - }, - "includes": { - "description": "Case-sensitive substrings that must all appear in the log message.", - "items": { - "type": "string" - }, - "maxItems": 8, - "title": "Includes", - "type": "array" - }, - "excludes": { - "description": "Case-sensitive substrings; lines containing any of these are dropped.", - "items": { - "type": "string" - }, - "maxItems": 8, - "title": "Excludes", - "type": "array" - } - }, - "title": "GetEnvironmentLogsRequestV1", - "type": "object" - }, - "GetEnvironmentMetricsRequestV1": { - "description": "Query params for ``GET /v1/models/.../environments/.../metrics``.", - "properties": { - "mode": { - "$ref": "#/components/schemas/ModelMetricModeV1", - "default": "CURRENT", - "description": "'CURRENT': a single instantaneous snapshot at now; start/end must be omitted. 'SUMMARY': a single value set aggregating the whole window. 'SERIES': evenly-spaced value sets across the window, with the step derived from the window duration." + "description": "Name of the workspace secret for authentication (e.g., HuggingFace token)", + "examples": [ + "hf_token", + "aws_credentials" + ], + "title": "Auth Secret Name" }, - "start_epoch_millis": { + "auth": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/TrainingWeightAuthV1" }, { "type": "null" } ], "default": null, - "description": "Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", - "title": "Start Epoch Millis" - }, - "end_epoch_millis": { - "anyOf": [ + "description": "Authentication configuration for the weight source.", + "examples": [ { - "type": "integer" + "auth_method": "CUSTOM_SECRET", + "auth_secret_name": "hf_token" }, { - "type": "null" + "auth_method": "AWS_OIDC", + "aws_oidc_region": "us-east-1", + "aws_oidc_role_arn": "arn:aws:iam::123456789012:role/weights-access" + }, + { + "auth_method": "GCP_OIDC", + "gcp_oidc_service_account": "weights-reader@example.iam.gserviceaccount.com", + "gcp_oidc_workload_id_provider": "projects/123456789/locations/global/workloadIdentityPools/baseten/providers/baseten" + }, + { + "auth_method": "AWS_ASSUME_ROLE", + "aws_assume_role_arn": "arn:aws:iam::123456789012:role/baseten-customer-access", + "aws_assume_role_region": "us-east-1" } - ], - "default": null, - "description": "Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", - "title": "End Epoch Millis" - }, - "metrics": { - "description": "Names of the metrics to return; see https://docs.baseten.co/observability/export-metrics/supported-metrics for the available names. When omitted, a default set is returned: baseten_replicas_active, baseten_inference_requests_total, and baseten_end_to_end_response_time_seconds. Unknown names are rejected; valid names that do not apply are omitted from the response.", - "items": { - "type": "string" - }, - "title": "Metrics", - "type": "array" + ] } }, - "title": "GetEnvironmentMetricsRequestV1", + "required": [ + "source", + "mount_location" + ], + "title": "CreateJobWeightConfigV1", "type": "object" }, - "PromoteToEnvironmentRequestV1": { - "description": "A request to promote a deployment to a environment.", + "CreateTrainingJobAcceleratorV1": { "properties": { - "scale_down_previous_deployment": { - "default": true, - "description": "Whether to scale down the previous deployment after promoting", + "accelerator": { + "description": "GPU type for the training job.", "examples": [ - true + "H100" ], - "title": "Scale Down Previous Deployment", - "type": "boolean" - }, - "deployment_id": { - "description": "The id of the deployment to promote", - "title": "Deployment Id", + "title": "Accelerator", "type": "string" }, - "preserve_env_instance_type": { - "default": true, - "description": "Whether to use the promoting deployment's instance type or preserve target environment's instance type", + "count": { + "description": "GPUs needed for the training job.", "examples": [ - true + 2 ], - "title": "Preserve Env Instance Type", - "type": "boolean" - } - }, - "required": [ - "deployment_id" - ], - "title": "PromoteToEnvironmentRequestV1", - "type": "object" - }, - "CancelPromotionStatusV1": { - "description": "The status of a request to cancel a promotion.", - "enum": [ - "CANCELED", - "RAMPING_DOWN" - ], - "title": "CancelPromotionStatusV1", - "type": "string" - }, - "CancelPromotionResponseV1": { - "description": "The response to a request to cancel a promotion.", - "properties": { - "status": { - "$ref": "#/components/schemas/CancelPromotionStatusV1", - "description": "Status of the request to cancel a promotion. Can be CANCELED or RAMPING_DOWN." - }, - "message": { - "description": "A message describing the status of the request to cancel a promotion", - "title": "Message", - "type": "string" + "title": "Count", + "type": "integer" } }, "required": [ - "status", - "message" + "accelerator", + "count" ], - "title": "CancelPromotionResponseV1", + "title": "CreateTrainingJobAcceleratorV1", "type": "object" }, - "SignalPromotionResponseV1": { - "description": "The response to a request to signal a rolling promotion.", + "CreateTrainingJobCacheConfig": { "properties": { - "success": { - "description": "Whether the signal was successfully sent", - "title": "Success", + "enable_legacy_hf_mount": { + "default": false, + "description": "Whether to enable the legacy Hugging Face cache.", + "examples": [ + true + ], + "title": "Enable Legacy Hf Mount", "type": "boolean" - } - }, - "required": [ - "success" - ], - "title": "SignalPromotionResponseV1", - "type": "object" - }, - "ChainV1": { - "description": "A chain.", - "properties": { - "id": { - "description": "Unique identifier of the chain", - "title": "Id", - "type": "string" }, - "created_at": { - "description": "Time the chain was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "name": { - "description": "Name of the chain", - "title": "Name", - "type": "string" + "enabled": { + "default": false, + "description": "Whether to enable the read-write cache.", + "examples": [ + true + ], + "title": "Enabled", + "type": "boolean" }, - "deployments_count": { - "description": "Number of deployments of the chain", - "title": "Deployments Count", - "type": "integer" + "require_cache_affinity": { + "default": true, + "description": "Whether to require region affinity for the read-write cache. If False, the resulting job is not guaranteed to be deployed alongside the previous cache.", + "examples": [ + true, + false + ], + "title": "Require Cache Affinity", + "type": "boolean" }, - "team_name": { - "description": "Name of the team associated with the chain", - "title": "Team Name", + "mount_base_path": { + "default": "/root/.cache", + "description": "Mount base path for the cache directory. The project cache and team cache will be mounted under this path.", + "examples": [ + "/workspace/.cache", + "/root/.cache" + ], + "title": "Mount Base Path", "type": "string" } }, - "required": [ - "id", - "created_at", - "name", - "deployments_count", - "team_name" - ], - "title": "ChainV1", - "type": "object" - }, - "ChainsV1": { - "description": "A list of chains.", - "properties": { - "chains": { - "items": { - "$ref": "#/components/schemas/ChainV1" - }, - "title": "Chains", - "type": "array" - } - }, - "required": [ - "chains" - ], - "title": "ChainsV1", + "title": "CreateTrainingJobCacheConfig", "type": "object" }, - "ChainTombstoneV1": { - "description": "A chain tombstone.", - "properties": { - "id": { - "description": "Unique identifier of the chain", - "title": "Id", - "type": "string" - }, - "deleted": { - "description": "Whether the chain was deleted", - "title": "Deleted", + "CreateTrainingJobCheckpointingConfig": { + "properties": { + "enabled": { + "default": false, + "description": "Whether checkpointing is enabled.", + "examples": [ + true + ], + "title": "Enabled", "type": "boolean" + }, + "checkpoint_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "path where checkpoints will be saved.", + "examples": [ + "/mnt/ckpts" + ], + "title": "Checkpoint Path" + }, + "volume_size_gib": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Size of the volume in gibibytes. If not provided, the default size will be used", + "examples": [ + 10 + ], + "title": "Volume Size Gib" } }, - "required": [ - "id", - "deleted" - ], - "title": "ChainTombstoneV1", + "title": "CreateTrainingJobCheckpointingConfig", "type": "object" }, - "ChainDeploymentV1": { - "description": "A deployment of a chain.", + "CreateTrainingJobComputeV1": { + "description": "Configuration to specify the compute for a training job.", "properties": { - "id": { - "description": "Unique identifier of the chain deployment", - "title": "Id", - "type": "string" + "node_count": { + "default": 1, + "description": "Number of nodes for the training job.", + "examples": [ + 1 + ], + "title": "Node Count", + "type": "integer" }, - "created_at": { - "description": "Time the chain deployment was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" + "cpu_count": { + "default": 1, + "description": "Number of cpus for the training job.", + "examples": [ + 1 + ], + "title": "Cpu Count", + "type": "integer" }, - "chain_id": { - "description": "Unique identifier of the chain", - "title": "Chain Id", + "memory": { + "default": "2Gi", + "description": "Memory for the training job.", + "examples": [ + "2Gi" + ], + "title": "Memory", "type": "string" }, - "environment": { + "accelerator": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/CreateTrainingJobAcceleratorV1" }, { "type": "null" } ], - "description": "Environment the chain deployment is deployed in", - "title": "Environment" - }, - "chainlets": { - "description": "Chainlets in the chain deployment", - "items": { - "$ref": "#/components/schemas/ChainletV1" - }, - "title": "Chainlets", - "type": "array" + "default": null, + "description": "GPU specification for the training job", + "examples": [ + { + "accelerator": "H100", + "count": 2 + } + ] }, - "status": { - "$ref": "#/components/schemas/DeploymentStatusV1", - "description": "Status of the chain deployment" + "availability_model": { + "$ref": "#/components/schemas/V1AvailabilityModel", + "default": "dedicated", + "description": "Capacity guarantee for the job. 'dedicated' (the default) runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress.", + "examples": [ + "spot" + ] } }, - "required": [ - "id", - "created_at", - "chain_id", - "environment", - "chainlets", - "status" - ], - "title": "ChainDeploymentV1", + "title": "CreateTrainingJobComputeV1", "type": "object" }, - "ChainletV1": { - "description": "A chainlet in a chain deployment.", + "CreateTrainingJobImageV1": { + "description": "Configuration to create a training job image.", "properties": { - "id": { - "description": "Unique identifier of the chainlet", - "title": "Id", - "type": "string" - }, - "name": { - "description": "Name of the chainlet", - "title": "Name", + "base_image": { + "description": "Base image for the training job.", + "examples": [ + "hello-world" + ], + "title": "Base Image", "type": "string" }, - "autoscaling_settings": { + "docker_auth": { "anyOf": [ { - "$ref": "#/components/schemas/AutoscalingSettingsV1" + "$ref": "#/components/schemas/DockerAuthV1" }, { "type": "null" } ], - "description": "Autoscaling settings for the chainlet. If null, it has not finished deploying" - }, - "instance_type_name": { - "description": "Name of the instance type the chainlet is deployed on", - "title": "Instance Type Name", - "type": "string" - }, - "active_replica_count": { - "description": "Number of active replicas", - "title": "Active Replica Count", - "type": "integer" - }, - "status": { - "$ref": "#/components/schemas/DeploymentStatusV1", - "description": "Status of the chainlet" + "default": null, + "description": "Docker authentication credentials" } }, "required": [ - "id", - "name", - "autoscaling_settings", - "instance_type_name", - "active_replica_count", - "status" + "base_image" ], - "title": "ChainletV1", + "title": "CreateTrainingJobImageV1", "type": "object" }, - "ChainDeploymentsV1": { - "description": "A list of chain deployments.", + "CreateTrainingJobRuntimeV1": { + "description": "Configuration to specify the runtime environment for a training job.", "properties": { - "deployments": { - "description": "A list of chain deployments", + "start_commands": { + "description": "Commands to execute when starting the runtime.", + "examples": [ + [ + "python main.py" + ] + ], "items": { - "$ref": "#/components/schemas/ChainDeploymentV1" + "type": "string" }, - "title": "Deployments", + "title": "Start Commands", "type": "array" - } - }, - "required": [ - "deployments" - ], - "title": "ChainDeploymentsV1", - "type": "object" - }, - "ChainDeploymentTombstoneV1": { - "description": "A chain deployment tombstone.", - "properties": { - "id": { - "description": "Unique identifier of the chain deployment", - "title": "Id", - "type": "string" }, - "deleted": { - "description": "Whether the chain deployment was deleted", - "title": "Deleted", - "type": "boolean" + "environment_variables": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/components/schemas/SecretReferenceV1" + } + ] + }, + "description": "Environment variables to set in the runtime.", + "examples": [ + { + "API_KEY": "your_api_key_here", + "PATH": "/usr/bin" + } + ], + "title": "Environment Variables", + "type": "object" }, - "chain_id": { - "description": "Unique identifier of the chain", - "title": "Chain Id", - "type": "string" - } - }, - "required": [ - "id", - "deleted", - "chain_id" - ], - "title": "ChainDeploymentTombstoneV1", - "type": "object" - }, - "ChainletEnvironmentSettingsRequestV1": { - "description": "Request to create environment settings for a chainlet.", - "properties": { - "chainlet_name": { - "description": "Name of the chainlet", + "artifacts": { + "description": "Runtime artifacts for the training job.", + "items": { + "$ref": "#/components/schemas/CreateTrainingJobS3Artifact" + }, + "title": "Artifacts", + "type": "array" + }, + "enable_cache": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Deprecated. Use cache_config instead.", "examples": [ - "HelloWorld" + true ], - "title": "Chainlet Name", - "type": "string" + "title": "Enable Cache" }, - "autoscaling_settings": { + "cache_config": { "anyOf": [ { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" + "$ref": "#/components/schemas/CreateTrainingJobCacheConfig" }, { "type": "null" } ], "default": null, - "description": "Autoscaling settings for the chainlet", + "description": "Configuration for the read-write cache.", "examples": [ { - "autoscaling_window": 60, - "concurrency_target": 1, - "max_replica": 1, - "max_scale_down_rate": null, - "min_replica": 0, - "scale_down_delay": 900, - "target_in_flight_tokens": null, - "target_utilization_percentage": 70 + "enable_legacy_hf_mount": true, + "enabled": true, + "mount_base_path": "/root/.cache", + "require_cache_affinity": true } ] }, - "instance_type_id": { - "default": "1x2", - "description": "ID of the instance type to use for the chainlet", + "checkpointing_config": { + "$ref": "#/components/schemas/CreateTrainingJobCheckpointingConfig", + "description": "Configuration for checkpointing.", "examples": [ - "1x4", - "2x8", - "A10G:2x24x96", - "H100:2x52x468" + { + "checkpoint_path": "/mnt/ckpts", + "enabled": true, + "volume_size_gib": null + } + ] + }, + "load_checkpoint_config": { + "anyOf": [ + { + "$ref": "#/components/schemas/LoadCheckpointConfig" + }, + { + "type": "null" + } ], - "title": "Instance Type Id", + "default": null, + "description": "Configuration for loading checkpoints" + } + }, + "title": "CreateTrainingJobRuntimeV1", + "type": "object" + }, + "CreateTrainingJobS3Artifact": { + "properties": { + "s3_bucket": { + "description": "S3 bucket for the uploaded runtime artifact.", + "examples": [ + "my-s3-bucket" + ], + "title": "S3 Bucket", + "type": "string" + }, + "s3_key": { + "description": "S3 key for the uploaded runtime artifact.", + "examples": [ + "my-s3-key" + ], + "title": "S3 Key", "type": "string" } }, "required": [ - "chainlet_name" + "s3_bucket", + "s3_key" ], - "title": "ChainletEnvironmentSettingsRequestV1", + "title": "CreateTrainingJobS3Artifact", "type": "object" }, - "CreateChainEnvironmentRequestV1": { - "description": "A request to create a custom environment for a chain.", + "CreateTrainingJobV1": { + "description": "Configuration for a training job.", "properties": { - "name": { - "description": "Name of the environment", + "image": { + "$ref": "#/components/schemas/CreateTrainingJobImageV1", "examples": [ - "staging" - ], - "title": "Name", - "type": "string" + { + "base_image": "hello-world", + "docker_auth": null + } + ] }, - "promotion_settings": { + "compute": { + "$ref": "#/components/schemas/CreateTrainingJobComputeV1", + "examples": [ + { + "accelerator": { + "accelerator": "H100", + "count": 2 + }, + "availability_model": "spot", + "cpu_count": 1, + "memory": "2Gi", + "node_count": 1 + } + ] + }, + "runtime": { + "$ref": "#/components/schemas/CreateTrainingJobRuntimeV1", + "description": "Configuration for the runtime environment of the training job.", + "examples": [ + { + "artifacts": [], + "cache_config": null, + "checkpointing_config": { + "checkpoint_path": null, + "enabled": false, + "volume_size_gib": null + }, + "enable_cache": null, + "environment_variables": { + "API_KEY": "your_api_key_here", + "PATH": "/usr/bin" + }, + "load_checkpoint_config": null, + "start_commands": [ + "python main.py" + ] + } + ] + }, + "name": { "anyOf": [ { - "$ref": "#/components/schemas/UpdatePromotionSettingsV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Promotion settings for the environment", + "description": "Name of the training job.", "examples": [ + "gpt-oss-job" + ], + "title": "Name" + }, + "truss_user_env": { + "anyOf": [ { - "promotion_cleanup_strategy": null, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": true, - "redeploy_on_promotion": true, - "rolling_deploy": null, - "rolling_deploy_config": null + "$ref": "#/components/schemas/TrussUserEnv" + }, + { + "type": "null" } - ] + ], + "default": null, + "description": "Truss user environment information" }, - "chainlet_settings": { + "interactive_session": { "anyOf": [ { - "items": { - "$ref": "#/components/schemas/ChainletEnvironmentSettingsRequestV1" - }, - "type": "array" + "$ref": "#/components/schemas/InteractiveSessionConfigV1" }, { "type": "null" } ], "default": null, - "description": "Mapping of chainlet name to the desired chainlet environment settings", + "description": "Configuration for interactive debugging sessions." + }, + "weights": { + "description": "MDN weight sources to mount in the training container. Weights are mirrored and cached for fast startup.", "examples": [ [ { - "autoscaling_settings": { - "autoscaling_window": 800, - "concurrency_target": 4, - "max_replica": 3, - "max_scale_down_rate": null, - "min_replica": 2, - "scale_down_delay": 63, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - }, - "chainlet_name": "HelloWorld", - "instance_type_id": "2x8" - }, - { - "autoscaling_settings": { - "autoscaling_window": null, - "concurrency_target": null, - "max_replica": 3, - "max_scale_down_rate": null, - "min_replica": 3, - "scale_down_delay": null, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - }, - "chainlet_name": "RandInt", - "instance_type_id": "A10Gx8x32" + "allow_patterns": null, + "auth": null, + "auth_secret_name": null, + "ignore_patterns": null, + "mount_location": "/app/models/base", + "source": "hf://meta-llama/Llama-3-8B@main" } ] ], - "title": "Chainlet Settings" - } - }, - "required": [ - "name" - ], - "title": "CreateChainEnvironmentRequestV1", - "type": "object" - }, - "ChainletEnvironmentSettingsV1": { - "description": "Environment settings for a chainlet.", - "properties": { - "chainlet_name": { - "description": "Name of the chainlet", - "title": "Chainlet Name", - "type": "string" + "items": { + "$ref": "#/components/schemas/CreateJobWeightConfigV1" + }, + "title": "Weights", + "type": "array" }, - "autoscaling_settings": { + "enable_baseten_workdir": { + "default": false, + "description": "When enabled, uses /b10/workspace as the working directory instead of the image WORKDIR.", + "examples": [ + false, + true + ], + "title": "Enable Baseten Workdir", + "type": "boolean" + }, + "priority": { "anyOf": [ { - "$ref": "#/components/schemas/AutoscalingSettingsV1" + "type": "integer" }, { "type": "null" } ], - "description": "Autoscaling settings for the chainlet. If null, it has not finished deploying" - }, - "instance_type": { - "$ref": "#/components/schemas/InstanceTypeV1", - "description": "Instance type for the chainlet" + "default": null, + "description": "Queue priority. Higher values are dequeued first. Defaults to 0.", + "examples": [ + 0, + 10, + 100 + ], + "title": "Priority" } }, "required": [ - "chainlet_name", - "autoscaling_settings", - "instance_type" + "image" ], - "title": "ChainletEnvironmentSettingsV1", + "title": "CreateTrainingJobV1", "type": "object" }, - "ChainEnvironmentV1": { - "description": "Environment for oracles.", + "DockerAuthType": { + "enum": [ + "GCP_SERVICE_ACCOUNT_JSON", + "AWS_IAM", + "AWS_OIDC", + "GCP_OIDC", + "REGISTRY_SECRET", + "AWS_ASSUME_ROLE" + ], + "title": "DockerAuthType", + "type": "string" + }, + "DockerAuthV1": { + "description": "Docker authentication credentials.", "properties": { - "name": { - "description": "Name of the environment", - "title": "Name", - "type": "string" - }, - "created_at": { - "description": "Time the environment was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "chain_id": { - "description": "Unique identifier of the chain", - "title": "Chain Id", + "registry": { + "description": "Registry to authenticate with", + "title": "Registry", "type": "string" }, - "promotion_settings": { - "$ref": "#/components/schemas/PromotionSettingsV1", - "description": "Promotion settings for the environment" - }, - "chainlet_settings": { - "description": "Environment settings for the chainlets", - "items": { - "$ref": "#/components/schemas/ChainletEnvironmentSettingsV1" - }, - "title": "Chainlet Settings", - "type": "array" + "auth_method": { + "$ref": "#/components/schemas/DockerAuthType", + "description": "Method to authenticate with the registry", + "examples": [ + "GCP_SERVICE_ACCOUNT_JSON", + "AWS_IAM", + "AWS_OIDC", + "GCP_OIDC", + "REGISTRY_SECRET", + "AWS_ASSUME_ROLE" + ] }, - "current_deployment": { + "gcp_service_account_json_docker_auth": { "anyOf": [ { - "$ref": "#/components/schemas/ChainDeploymentV1" + "$ref": "#/components/schemas/GcpServiceAccountJsonDockerAuthV1" }, { "type": "null" } ], - "description": "Current chain deployment of the environment" + "default": null, + "description": "GCP service account details for the registry" }, - "candidate_deployment": { + "aws_iam_docker_auth": { "anyOf": [ { - "$ref": "#/components/schemas/ChainDeploymentV1" + "$ref": "#/components/schemas/AwsIamDockerAuthV1" }, { "type": "null" } ], "default": null, - "description": "Candidate chain deployment being promoted to the environment, if a promotion is in progress" - } - }, - "required": [ - "name", - "created_at", - "chain_id", - "promotion_settings", - "chainlet_settings", - "current_deployment" - ], - "title": "ChainEnvironmentV1", - "type": "object" - }, - "UpdateChainEnvironmentRequestV1": { - "description": "A request to update a chain environment.", - "properties": { - "promotion_settings": { + "description": "AWS details for the registry" + }, + "aws_oidc_docker_auth": { "anyOf": [ { - "$ref": "#/components/schemas/UpdatePromotionSettingsV1" + "$ref": "#/components/schemas/AwsOidcDockerAuthV1" }, { "type": "null" } ], "default": null, - "description": "Promotion settings for the environment", - "examples": [ + "description": "AWS OIDC details for the registry" + }, + "gcp_oidc_docker_auth": { + "anyOf": [ { - "promotion_cleanup_strategy": null, - "ramp_up_duration_seconds": 600, - "ramp_up_while_promoting": true, - "redeploy_on_promotion": null, - "rolling_deploy": null, - "rolling_deploy_config": null + "$ref": "#/components/schemas/GcpOidcDockerAuthV1" + }, + { + "type": "null" } - ] - } - }, - "title": "UpdateChainEnvironmentRequestV1", - "type": "object" - }, - "UpdateChainEnvironmentResponseV1": { - "description": "A response to update a chain environment.", - "properties": { - "ok": { - "description": "Whether the update was successful", - "title": "Ok", - "type": "boolean" - } - }, - "required": [ - "ok" - ], - "title": "UpdateChainEnvironmentResponseV1", - "type": "object" - }, - "PromoteToChainEnvironmentRequestV1": { - "description": "A request to promote a deployment to a environment.", - "properties": { - "scale_down_previous_deployment": { - "default": true, - "description": "Whether to scale down the previous deployment after promoting", - "examples": [ - true - ], - "title": "Scale Down Previous Deployment", - "type": "boolean" - }, - "deployment_id": { - "description": "The id of the chain deployment to promote", - "title": "Deployment Id", - "type": "string" - } - }, - "required": [ - "deployment_id" - ], - "title": "PromoteToChainEnvironmentRequestV1", - "type": "object" - }, - "ChainletEnvironmentAutoscalingSettingsUpdateV1": { - "description": "The request to update the autoscaling settings for a chainlet.", - "properties": { - "chainlet_name": { - "description": "Name of the chainlet", - "examples": [ - "HelloWorld" ], - "title": "Chainlet Name", - "type": "string" + "default": null, + "description": "GCP OIDC details for the registry" }, - "autoscaling_settings": { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1", - "description": "Autoscaling settings for the chainlet", - "examples": [ + "registry_secret_docker_auth": { + "anyOf": [ { - "autoscaling_window": 800, - "concurrency_target": 3, - "max_replica": 2, - "max_scale_down_rate": null, - "min_replica": 1, - "scale_down_delay": 60, - "target_in_flight_tokens": null, - "target_utilization_percentage": null + "$ref": "#/components/schemas/RegistrySecretDockerAuthV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Required when auth_method is REGISTRY_SECRET. Supports any Docker registry (Docker Hub, GHCR, NGC, etc.) via username:password credentials stored as a Baseten secret." + }, + "aws_assume_role_docker_auth": { + "anyOf": [ + { + "$ref": "#/components/schemas/AwsAssumeRoleDockerAuthV1" + }, + { + "type": "null" } - ] - } - }, - "required": [ - "chainlet_name", - "autoscaling_settings" - ], - "title": "ChainletEnvironmentAutoscalingSettingsUpdateV1", - "type": "object" - }, - "UpdateChainletEnvironmentAutoscalingSettingsRequestV1": { - "description": "A request to update the autoscaling settings for a multiple chainlets in an environment.\nIf a chainlet name doesn't exist, an error is returned.", - "properties": { - "updates": { - "description": "Mapping of chainlet name to the desired chainlet autoscaling settings. If the chainlet name doesn't exist, an error is returned.", - "examples": [ - [ - { - "autoscaling_settings": { - "autoscaling_window": 800, - "concurrency_target": 4, - "max_replica": 3, - "max_scale_down_rate": null, - "min_replica": 2, - "scale_down_delay": 63, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - }, - "chainlet_name": "HelloWorld" - } - ], - [ - { - "autoscaling_settings": { - "autoscaling_window": null, - "concurrency_target": null, - "max_replica": null, - "max_scale_down_rate": null, - "min_replica": 0, - "scale_down_delay": null, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - }, - "chainlet_name": "HelloWorld" - }, - { - "autoscaling_settings": { - "autoscaling_window": null, - "concurrency_target": null, - "max_replica": null, - "max_scale_down_rate": null, - "min_replica": 0, - "scale_down_delay": null, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - }, - "chainlet_name": "RandInt" - } - ] ], - "items": { - "$ref": "#/components/schemas/ChainletEnvironmentAutoscalingSettingsUpdateV1" - }, - "title": "Updates", - "type": "array" + "default": null, + "description": "Required when auth_method is AWS_ASSUME_ROLE. Baseten assumes the given IAM role with its own AWS principal and your organization's external ID, with no OIDC provider registration in your account." } }, "required": [ - "updates" + "registry", + "auth_method" ], - "title": "UpdateChainletEnvironmentAutoscalingSettingsRequestV1", + "title": "DockerAuthV1", "type": "object" }, - "ChainletEnvironmentInstanceTypeUpdateV1": { - "description": "A request to update the environment settings for a chainlet.", + "GcpOidcDockerAuthV1": { + "description": "GCP OIDC details for the registry.", "properties": { - "chainlet_name": { - "description": "Name of the chainlet", - "examples": [ - "HelloWorld" - ], - "title": "Chainlet Name", + "service_account": { + "description": "GCP service account name for OIDC authentication", + "title": "Service Account", "type": "string" }, - "instance_type_id": { - "description": "Key of the instance type to use for the chainlet", - "examples": [ - "1x4", - "2x8", - "A10G:2x24x96" - ], - "title": "Instance Type Id", + "workload_identity_provider": { + "description": "GCP workload identity provider for OIDC authentication", + "title": "Workload Identity Provider", "type": "string" } }, "required": [ - "chainlet_name", - "instance_type_id" + "service_account", + "workload_identity_provider" ], - "title": "ChainletEnvironmentInstanceTypeUpdateV1", + "title": "GcpOidcDockerAuthV1", "type": "object" }, - "UpdateChainletEnvironmentInstanceTypeRequestV1": { - "description": "A request to update the instance types for chainlets in an environment. Multiples\nupdates can be made in one request. The updates will be processed in batch and a new deployment\nwill be created, deployed and promoted into the environment.", + "GcpServiceAccountJsonDockerAuthV1": { + "description": "GCP details for the registry.", "properties": { - "updates": { - "description": "Mapping of chainlet name to the desired chainlet instance type. If the chainlet name doesn't exist, an error is returned.", - "examples": [ - [ - { - "chainlet_name": "HelloWorld", - "instance_type_id": "1x4" - }, - { - "chainlet_name": "RandInt", - "instance_type_id": "A10G:2x24x96" - } - ] - ], - "items": { - "$ref": "#/components/schemas/ChainletEnvironmentInstanceTypeUpdateV1" - }, - "title": "Updates", - "type": "array" + "service_account_json_secret_ref": { + "$ref": "#/components/schemas/SecretReferenceV1", + "description": "Name of the service account secret" } }, "required": [ - "updates" + "service_account_json_secret_ref" ], - "title": "UpdateChainletEnvironmentInstanceTypeRequestV1", + "title": "GcpServiceAccountJsonDockerAuthV1", "type": "object" }, - "UpdateChainletEnvironmentInstanceTypeResponseV1": { - "description": "A response to update the environment settings for a chainlet. If updating the instance type\nresulted in a re-deployment, `requires_redeployment` will be True and the resulting deployment\nwill be returned in the `chain_deployment` field.", + "GitInfo": { "properties": { - "requires_redeployment": { - "description": "Whether the resource update requires a re-deployment to update the instance type.", - "title": "Requires Redeployment", - "type": "boolean" + "latest_commit_sha": { + "title": "Latest Commit Sha", + "type": "string" }, - "chain_deployment": { + "latest_tag": { "anyOf": [ { - "$ref": "#/components/schemas/ChainDeploymentV1" + "type": "string" }, { "type": "null" } ], - "description": "The chain deployment resulting from the resource update, if any." + "title": "Latest Tag" }, - "chainlet_environment_settings": { - "description": "The updated chainlet environment settings", - "items": { - "$ref": "#/components/schemas/ChainletEnvironmentSettingsV1" - }, - "title": "Chainlet Environment Settings", - "type": "array" + "commits_since_tag": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Commits Since Tag" + }, + "has_uncommitted_changes": { + "title": "Has Uncommitted Changes", + "type": "boolean" } }, "required": [ - "requires_redeployment", - "chain_deployment", - "chainlet_environment_settings" + "latest_commit_sha", + "latest_tag", + "commits_since_tag", + "has_uncommitted_changes" ], - "title": "UpdateChainletEnvironmentInstanceTypeResponseV1", + "title": "GitInfo", "type": "object" }, - "UpsertTrainingProjectV1": { - "description": "Fields that can be upserted on a training project.", + "InteractiveSessionConfigV1": { + "description": "Configuration for interactive debugging sessions on training jobs.", "properties": { - "name": { - "description": "Name of the training project.", + "trigger": { + "$ref": "#/components/schemas/V1InteractiveSessionTrigger", + "default": "on_demand", + "description": "When to create the interactive session. 'on_startup' creates on job start, 'on_failure' creates on job failure, 'on_demand' bypasses automatic session creation." + }, + "timeout_minutes": { + "default": 480, + "description": "Number of minutes before the interactive session times out.", "examples": [ - "My Training Project" + 480, + 1440, + 10080 ], - "title": "Name", + "title": "Timeout Minutes", + "type": "integer" + }, + "session_provider": { + "$ref": "#/components/schemas/V1InteractiveSessionProvider", + "default": "vs_code", + "description": "The IDE client for the interactive session." + }, + "auth_provider": { + "$ref": "#/components/schemas/V1InteractiveSessionAuthProvider", + "default": "github", + "description": "The authentication provider for the interactive session." + } + }, + "title": "InteractiveSessionConfigV1", + "type": "object" + }, + "LoadCheckpointConfig": { + "properties": { + "enabled": { + "default": false, + "description": "Whether checkpoint loading is enabled", + "title": "Enabled", + "type": "boolean" + }, + "download_folder": { + "default": "/tmp/loaded_checkpoints", + "description": "Folder where checkpoints will be downloaded", + "title": "Download Folder", + "type": "string" + }, + "checkpoints": { + "description": "List of checkpoint configurations", + "items": { + "discriminator": { + "mapping": { + "baseten_latest_checkpoint": "#/components/schemas/BasetenLatestCheckpointConfig", + "baseten_named_checkpoint": "#/components/schemas/BasetenNamedCheckpointConfig", + "loops_checkpoint": "#/components/schemas/LoopsCheckpointConfig" + }, + "propertyName": "typ" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/BasetenLatestCheckpointConfig" + }, + { + "$ref": "#/components/schemas/BasetenNamedCheckpointConfig" + }, + { + "$ref": "#/components/schemas/LoopsCheckpointConfig" + } + ] + }, + "title": "Checkpoints", + "type": "array" + } + }, + "title": "LoadCheckpointConfig", + "type": "object" + }, + "LoopsCheckpointConfig": { + "properties": { + "run_id": { + "description": "ID of the Loops run to load the checkpoint from", + "title": "Run Id", + "type": "string" + }, + "checkpoint_name": { + "description": "Name of the checkpoint to load", + "title": "Checkpoint Name", + "type": "string" + }, + "target": { + "default": "trainer", + "description": "Which checkpoint target to load: 'trainer' (full training state) or 'sampler' (inference weights)", + "enum": [ + "trainer", + "sampler" + ], + "title": "Target", + "type": "string" + }, + "typ": { + "const": "loops_checkpoint", + "default": "loops_checkpoint", + "title": "Typ", "type": "string" } }, "required": [ - "name" + "run_id", + "checkpoint_name" ], - "title": "UpsertTrainingProjectV1", + "title": "LoopsCheckpointConfig", "type": "object" }, - "UpsertTrainingProjectRequestV1": { - "description": "A request to upsert a training project.", + "RegistrySecretDockerAuthV1": { + "description": "Authentication via a Baseten secret for any Docker registry (Docker Hub, GHCR, NGC, etc.).\nThe referenced secret must contain credentials in the format 'username:password'.\nFor Docker Hub, set registry to 'https://index.docker.io/v1/'. For GHCR, use 'ghcr.io'.", "properties": { - "training_project": { - "$ref": "#/components/schemas/UpsertTrainingProjectV1", - "description": "The training project to upsert." + "secret_ref": { + "$ref": "#/components/schemas/SecretReferenceV1", + "description": "Reference to a Baseten secret containing credentials in the format 'username:password'" + } + }, + "required": [ + "secret_ref" + ], + "title": "RegistrySecretDockerAuthV1", + "type": "object" + }, + "SecretReferenceV1": { + "properties": { + "name": { + "description": "Name of the secret to reference.", + "examples": [ + "hf_token" + ], + "title": "Name", + "type": "string" } }, "required": [ - "training_project" + "name" ], - "title": "UpsertTrainingProjectRequestV1", + "title": "SecretReferenceV1", "type": "object" }, - "CheckpointSyncStatus": { - "description": "Lifecycle state for the checkpoint uploader.", - "enum": [ - "SYNCING", - "COMPLETED" - ], - "title": "CheckpointSyncStatus", - "type": "string" - }, - "TrainingJobV1": { + "TrainingWeightAuthV1": { + "description": "Authentication configuration for a training weight source.", "properties": { - "id": { - "description": "Unique identifier of the training job.", - "title": "Id", - "type": "string" - }, - "created_at": { - "description": "Time the job was created in ISO 8601 format.", - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "current_status": { - "description": "Current status of the training job.", - "title": "Current Status", - "type": "string" + "auth_method": { + "$ref": "#/components/schemas/AuthMethod", + "description": "Method used to authenticate the weight source." }, - "error_message": { + "auth_secret_name": { "anyOf": [ { "type": "string" @@ -19229,39 +23913,23 @@ } ], "default": null, - "description": "Error message if the training job failed.", - "title": "Error Message" - }, - "instance_type": { - "$ref": "#/components/schemas/InstanceTypeV1", - "description": "Instance type of the training job." + "description": "Name of the workspace secret used for custom-secret authentication.", + "title": "Auth Secret Name" }, - "node_count": { - "default": 1, - "description": "Number of nodes the job runs on. The instance type describes a single node, so the job's total GPU count is gpu_count multiplied by node_count.", - "examples": [ - 2 + "aws_oidc_role_arn": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } ], - "minimum": 1, - "title": "Node Count", - "type": "integer" - }, - "updated_at": { - "description": "Time the job was updated in ISO 8601 format.", - "format": "date-time", - "title": "Updated At", - "type": "string" - }, - "training_project_id": { - "description": "ID of the training project.", - "title": "Training Project Id", - "type": "string" - }, - "training_project": { - "$ref": "#/components/schemas/TrainingProjectSummaryV1", - "description": "Summary of the training project." + "default": null, + "description": "AWS IAM role ARN used for OIDC authentication.", + "title": "Aws Oidc Role Arn" }, - "name": { + "aws_oidc_region": { "anyOf": [ { "type": "string" @@ -19271,106 +23939,96 @@ } ], "default": null, - "description": "Name of the training job.", - "examples": [ - "gpt-oss-job" - ], - "title": "Name" + "description": "AWS region used for OIDC authentication.", + "title": "Aws Oidc Region" }, - "checkpoint_sync_status": { + "gcp_oidc_service_account": { "anyOf": [ { - "$ref": "#/components/schemas/CheckpointSyncStatus" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Checkpoint sync status of the training job." - }, - "priority": { - "default": 0, - "description": "Queue priority. Higher values are dequeued first. NULL is treated as 0.", - "title": "Priority", - "type": "integer" + "description": "GCP service account used for OIDC authentication.", + "title": "Gcp Oidc Service Account" }, - "availability_model": { - "$ref": "#/components/schemas/V1AvailabilityModel", - "default": "dedicated", - "description": "Capacity guarantee for the job. 'dedicated' is non-preemptible on-demand capacity; 'spot' is interruptible." + "gcp_oidc_workload_id_provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "GCP workload identity provider used for OIDC authentication.", + "title": "Gcp Oidc Workload Id Provider" }, - "user": { + "aws_assume_role_arn": { "anyOf": [ { - "$ref": "#/components/schemas/UserV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "The user who created the training job." - } - }, - "required": [ - "id", - "created_at", - "current_status", - "instance_type", - "updated_at", - "training_project_id", - "training_project" - ], - "title": "TrainingJobV1", - "type": "object" - }, - "TrainingProjectSummaryV1": { - "description": "A summary of a training project.", - "properties": { - "id": { - "description": "Unique identifier of the training project.", - "title": "Id", - "type": "string" + "description": "AWS IAM role ARN that Baseten assumes to access the weight source.", + "title": "Aws Assume Role Arn" }, - "name": { - "description": "Name of the training project.", - "title": "Name", - "type": "string" + "aws_assume_role_region": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "AWS region used for assume-role authentication.", + "title": "Aws Assume Role Region" } }, "required": [ - "id", - "name" + "auth_method" ], - "title": "TrainingProjectSummaryV1", + "title": "TrainingWeightAuthV1", "type": "object" }, - "TrainingProjectV1": { + "TrussUserEnv": { + "description": "This data models is used to flexibly store info alongside oracle versions.\n\nThere is a corresponding data model in the truss client.\nIn contrast, here all fields are optional for backwards compatibility with old\nclients.", "properties": { - "id": { - "description": "Unique identifier of the training project", - "title": "Id", - "type": "string" - }, - "name": { - "description": "Name of the training project.", - "title": "Name", - "type": "string" - }, - "created_at": { - "description": "Time the training project was created in ISO 8601 format.", - "format": "date-time", - "title": "Created At", - "type": "string" + "truss_client_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Truss Client Version" }, - "updated_at": { - "description": "Time the training project was updated in ISO 8601 format.", - "format": "date-time", - "title": "Updated At", - "type": "string" + "python_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Python Version" }, - "team_name": { + "pydantic_version": { "anyOf": [ { "type": "string" @@ -19380,792 +24038,797 @@ } ], "default": null, - "description": "Name of the team associated with the training project.", - "title": "Team Name" + "title": "Pydantic Version" }, - "latest_job": { + "mypy_version": { "anyOf": [ { - "$ref": "#/components/schemas/TrainingJobV1" + "type": "string" }, { "type": "null" } ], - "description": "Most recently created training job for the training project." - } - }, - "required": [ - "id", - "name", - "created_at", - "updated_at", - "latest_job" - ], - "title": "TrainingProjectV1", - "type": "object" - }, - "UserV1": { - "description": "A user.", - "properties": { - "email": { + "default": null, + "title": "Mypy Version" + }, + "is_library_deployment": { + "default": false, + "title": "Is Library Deployment", + "type": "boolean" + }, + "is_frontend_deployment": { + "default": false, + "title": "Is Frontend Deployment", + "type": "boolean" + }, + "git_info": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/GitInfo" }, { "type": "null" } ], - "default": null, - "description": "Email of the user.", - "title": "Email" + "default": null } }, - "title": "UserV1", + "title": "TrussUserEnv", "type": "object" }, - "V1AvailabilityModel": { - "description": "Capacity guarantee under which a training job is scheduled.\n\n``DEDICATED`` is on-demand capacity that is not preempted (the default). ``SPOT`` is\ninterruptible capacity that may be preempted; the user is responsible for checkpointing\ntheir own progress. A managed/resumable model where the platform handles\ncheckpoint/resume on its own is intentionally not defined yet; it is planned for a\nfuture milestone.", + "V1InteractiveSessionAuthProvider": { "enum": [ - "dedicated", - "spot" + "github", + "microsoft" ], - "title": "V1AvailabilityModel", + "title": "V1InteractiveSessionAuthProvider", "type": "string" }, - "UpsertTrainingProjectResponseV1": { - "description": "A response to upserting a training project.", - "properties": { - "training_project": { - "$ref": "#/components/schemas/TrainingProjectV1", - "description": "The upserted training project." - } - }, - "required": [ - "training_project" + "V1InteractiveSessionProvider": { + "enum": [ + "vs_code", + "cursor", + "ssh" ], - "title": "UpsertTrainingProjectResponseV1", - "type": "object" + "title": "V1InteractiveSessionProvider", + "type": "string" }, - "ListTrainingProjectsResponseV1": { - "description": "A response to list training projects.", - "properties": { - "training_projects": { - "description": "List of training projects.", - "items": { - "$ref": "#/components/schemas/TrainingProjectV1" - }, - "title": "Training Projects", - "type": "array" - } - }, - "required": [ - "training_projects" + "V1InteractiveSessionTrigger": { + "enum": [ + "on_startup", + "on_failure", + "on_demand" ], - "title": "ListTrainingProjectsResponseV1", - "type": "object" + "title": "V1InteractiveSessionTrigger", + "type": "string" }, - "ListTrainingJobsResponseV1": { - "description": "A response to list training jobs.", + "CreateTrainingJobRequestV1": { + "description": "A request to create a training job.", "properties": { - "training_project": { - "$ref": "#/components/schemas/TrainingProjectV1", - "description": "The training project." - }, - "training_jobs": { - "description": "List of training jobs.", - "items": { - "$ref": "#/components/schemas/TrainingJobV1" - }, - "title": "Training Jobs", - "type": "array" + "training_job": { + "$ref": "#/components/schemas/CreateTrainingJobV1", + "description": "The training job to create." } }, "required": [ - "training_project", - "training_jobs" + "training_job" ], - "title": "ListTrainingJobsResponseV1", + "title": "CreateTrainingJobRequestV1", "type": "object" }, - "AuthMethod": { - "enum": [ - "CUSTOM_SECRET", - "AWS_OIDC", - "GCP_OIDC", - "AWS_ASSUME_ROLE" - ], - "title": "AuthMethod", - "type": "string" - }, - "AwsAssumeRoleDockerAuthV1": { - "description": "AWS assume-role details for the registry.", + "CreateTrainingJobResponseV1": { + "description": "A response to creating a training job.", "properties": { - "role_arn": { - "description": "AWS IAM role ARN that Baseten assumes to pull from the registry. The role's trust policy must allow Baseten's AWS principal with your Baseten-provided external ID.", - "title": "Role Arn", - "type": "string" - }, - "region": { - "description": "AWS region of the registry", - "title": "Region", - "type": "string" + "training_job": { + "$ref": "#/components/schemas/TrainingJobV1", + "description": "The created training job." } }, "required": [ - "role_arn", - "region" + "training_job" ], - "title": "AwsAssumeRoleDockerAuthV1", + "title": "CreateTrainingJobResponseV1", "type": "object" }, - "AwsIamDockerAuthV1": { - "description": "AWS details for the registry.", + "TrainingJobTombstoneV1": { + "description": "A training job tombstone.", "properties": { - "access_key_secret_ref": { - "$ref": "#/components/schemas/SecretReferenceV1", - "description": "Name of the access key secret" + "id": { + "description": "Unique identifier of the training job", + "title": "Id", + "type": "string" }, - "secret_access_key_secret_ref": { - "$ref": "#/components/schemas/SecretReferenceV1", - "description": "Name of the secret key secret" + "deleted": { + "description": "Whether the training job was deleted", + "title": "Deleted", + "type": "boolean" + }, + "training_project_id": { + "description": "Unique identifier of the training project", + "title": "Training Project Id", + "type": "string" } }, "required": [ - "access_key_secret_ref", - "secret_access_key_secret_ref" + "id", + "deleted", + "training_project_id" ], - "title": "AwsIamDockerAuthV1", + "title": "TrainingJobTombstoneV1", "type": "object" }, - "AwsOidcDockerAuthV1": { - "description": "AWS OIDC details for the registry.", + "GetTrainingJobResponseV1": { + "description": "A response to fetch a training job.", "properties": { - "role_arn": { - "description": "AWS IAM role ARN for OIDC authentication", - "title": "Role Arn", - "type": "string" + "training_project": { + "$ref": "#/components/schemas/TrainingProjectV1", + "description": "The training project." }, - "region": { - "description": "AWS region for OIDC authentication", - "title": "Region", - "type": "string" + "training_job": { + "$ref": "#/components/schemas/TrainingJobV1", + "description": "The fetched training job." } }, "required": [ - "role_arn", - "region" + "training_project", + "training_job" ], - "title": "AwsOidcDockerAuthV1", + "title": "GetTrainingJobResponseV1", "type": "object" }, - "BasetenLatestCheckpointConfig": { + "UpdateTrainingJobRequestV1": { + "description": "A request to update mutable fields on a training job.\n\nEvery field is optional so a caller can patch one without the other, but at least\none must be provided: an empty body has nothing to apply.", + "minProperties": 1, "properties": { - "project_name": { + "priority": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Name of the project to load the checkpoint from", - "title": "Project Name" + "description": "New queue priority for a PENDING training job. Higher values are dequeued first. Only jobs in the PENDING state can have their priority changed.", + "examples": [ + 0, + 10, + 100 + ], + "title": "Priority" }, - "job_id": { + "availability_model": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/V1AvailabilityModel" }, { "type": "null" } ], "default": null, - "description": "ID of the job to load the checkpoint from", - "title": "Job Id" - }, - "typ": { - "const": "baseten_latest_checkpoint", - "default": "baseten_latest_checkpoint", - "title": "Typ", - "type": "string" + "description": "New capacity guarantee for a PENDING training job. 'dedicated' runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress. Only jobs in the PENDING state can have their availability model changed.", + "examples": [ + "spot" + ] } }, - "title": "BasetenLatestCheckpointConfig", + "title": "UpdateTrainingJobRequestV1", "type": "object" }, - "BasetenNamedCheckpointConfig": { + "UpdateTrainingJobResponseV1": { + "description": "A response to updating a training job.", "properties": { - "checkpoint_name": { - "description": "Name of the checkpoint to load from", - "title": "Checkpoint Name", - "type": "string" - }, - "project_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Name of the project to load the checkpoint from", - "title": "Project Name" - }, - "job_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "ID of the job to load the checkpoint from", - "title": "Job Id" - }, - "typ": { - "const": "baseten_named_checkpoint", - "default": "baseten_named_checkpoint", - "title": "Typ", - "type": "string" + "training_job": { + "$ref": "#/components/schemas/TrainingJobV1", + "description": "The updated training job." + } + }, + "required": [ + "training_job" + ], + "title": "UpdateTrainingJobResponseV1", + "type": "object" + }, + "DownloadTrainingJobResponseV1": { + "description": "A response with presigned URLs for a training job's artifacts.", + "properties": { + "artifact_presigned_urls": { + "description": "Presigned URLs for the job's uploaded artifacts.", + "items": { + "type": "string" + }, + "title": "Artifact Presigned Urls", + "type": "array" } }, "required": [ - "checkpoint_name" + "artifact_presigned_urls" ], - "title": "BasetenNamedCheckpointConfig", + "title": "DownloadTrainingJobResponseV1", "type": "object" }, - "CreateJobWeightConfigV1": { - "description": "Weight source configuration for MDN (Model Distribution Network).\n\nEnables training jobs to mount external model weights from HuggingFace, S3, GCS, R2,\nor CoreWeave via MDN's caching and CSI mounting infrastructure. Weights are mirrored\nonce and deduplicated across training jobs.", + "RecreateTrainingJobResponseV1": { + "description": "A response that sends the new training job", "properties": { - "source": { - "description": "Weight source URI. Supported formats: hf://, s3://, gs://, r2://, cw://", - "examples": [ - "hf://meta-llama/Llama-3-8B@main", - "s3://my-bucket/models/llama", - "gs://my-bucket/models/llama", - "r2://account_id.bucket/models/llama", - "r2://account_id.eu.bucket/models/llama", - "cw://my-bucket/models/llama" - ], - "title": "Source", - "type": "string" - }, - "mount_location": { - "description": "Path where weights will be mounted in the container", - "examples": [ - "/app/models/base", - "/models/llama" - ], - "title": "Mount Location", - "type": "string" - }, - "allow_patterns": { + "training_job": { + "$ref": "#/components/schemas/TrainingJobV1", + "description": "The created training job." + } + }, + "required": [ + "training_job" + ], + "title": "RecreateTrainingJobResponseV1", + "type": "object" + }, + "GetTrainingJobLogsRequestV1": { + "description": "A request to fetch training logs.", + "properties": { + "start_epoch_millis": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "File patterns to include (Unix-style shell patterns)", - "examples": [ - [ - "*.safetensors", - "config.json" - ] - ], - "title": "Allow Patterns" + "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + "title": "Start Epoch Millis" }, - "ignore_patterns": { + "end_epoch_millis": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "File patterns to exclude (Unix-style shell patterns)", - "examples": [ - [ - "*.bin", - "*.h5" - ] - ], - "title": "Ignore Patterns" + "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + "title": "End Epoch Millis" }, - "auth_secret_name": { + "direction": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SortOrderV1" }, { "type": "null" } ], "default": null, - "description": "Name of the workspace secret for authentication (e.g., HuggingFace token)", - "examples": [ - "hf_token", - "aws_credentials" - ], - "title": "Auth Secret Name" + "description": "Sort order for logs" }, - "auth": { + "limit": { "anyOf": [ { - "$ref": "#/components/schemas/TrainingWeightAuthV1" + "maximum": 1000, + "minimum": 1, + "type": "integer" }, { "type": "null" } ], - "default": null, - "description": "Authentication configuration for the weight source.", - "examples": [ - { - "auth_method": "CUSTOM_SECRET", - "auth_secret_name": "hf_token" - }, - { - "auth_method": "AWS_OIDC", - "aws_oidc_region": "us-east-1", - "aws_oidc_role_arn": "arn:aws:iam::123456789012:role/weights-access" - }, + "default": 500, + "description": "Limit of logs to fetch in a single request", + "title": "Limit" + }, + "min_level": { + "anyOf": [ { - "auth_method": "GCP_OIDC", - "gcp_oidc_service_account": "weights-reader@example.iam.gserviceaccount.com", - "gcp_oidc_workload_id_provider": "projects/123456789/locations/global/workloadIdentityPools/baseten/providers/baseten" + "$ref": "#/components/schemas/LogLevelV1" }, { - "auth_method": "AWS_ASSUME_ROLE", - "aws_assume_role_arn": "arn:aws:iam::123456789012:role/baseten-customer-access", - "aws_assume_role_region": "us-east-1" + "type": "null" } - ] + ], + "default": null, + "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + } + }, + "title": "GetTrainingJobLogsRequestV1", + "type": "object" + }, + "StorageMetricsV1": { + "description": "A metric for a training job.", + "properties": { + "usage_bytes": { + "description": "The number of bytes used on the storage entity.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Usage Bytes", + "type": "array" + }, + "utilization": { + "description": "The utilization of the storage entity as a decimal percentage.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Utilization", + "type": "array" } }, "required": [ - "source", - "mount_location" + "usage_bytes", + "utilization" ], - "title": "CreateJobWeightConfigV1", + "title": "StorageMetricsV1", "type": "object" }, - "CreateTrainingJobAcceleratorV1": { + "TrainingJobMetricV1": { + "description": "A metric for a training job.", "properties": { - "accelerator": { - "description": "GPU type for the training job.", - "examples": [ - "H100" - ], - "title": "Accelerator", - "type": "string" + "value": { + "description": "The value of the metric.", + "title": "Value", + "type": "number" }, - "count": { - "description": "GPUs needed for the training job.", - "examples": [ - 2 - ], - "title": "Count", - "type": "integer" + "timestamp": { + "description": "The timestamp of the metric in ISO 8601 format.", + "format": "date-time", + "title": "Timestamp", + "type": "string" } }, "required": [ - "accelerator", - "count" + "value", + "timestamp" ], - "title": "CreateTrainingJobAcceleratorV1", + "title": "TrainingJobMetricV1", "type": "object" }, - "CreateTrainingJobCacheConfig": { + "TrainingJobMetricsV1": { "properties": { - "enable_legacy_hf_mount": { - "default": false, - "description": "Whether to enable the legacy Hugging Face cache.", - "examples": [ - true - ], - "title": "Enable Legacy Hf Mount", - "type": "boolean" + "gpu_memory_usage_bytes": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", + "title": "Gpu Memory Usage Bytes", + "type": "object" }, - "enabled": { - "default": false, - "description": "Whether to enable the read-write cache.", - "examples": [ - true - ], - "title": "Enabled", - "type": "boolean" + "gpu_utilization": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", + "title": "Gpu Utilization", + "type": "object" }, - "require_cache_affinity": { - "default": true, - "description": "Whether to require region affinity for the read-write cache. If False, the resulting job is not guaranteed to be deployed alongside the previous cache.", - "examples": [ - true, - false - ], - "title": "Require Cache Affinity", - "type": "boolean" + "cpu_usage": { + "description": "The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Cpu Usage", + "type": "array" + }, + "cpu_memory_usage_bytes": { + "description": "The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Cpu Memory Usage Bytes", + "type": "array" }, - "mount_base_path": { - "default": "/root/.cache", - "description": "Mount base path for the cache directory. The project cache and team cache will be mounted under this path.", - "examples": [ - "/workspace/.cache", - "/root/.cache" - ], - "title": "Mount Base Path", - "type": "string" + "ephemeral_storage": { + "$ref": "#/components/schemas/StorageMetricsV1", + "description": "The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." } }, - "title": "CreateTrainingJobCacheConfig", + "required": [ + "gpu_memory_usage_bytes", + "gpu_utilization", + "cpu_usage", + "cpu_memory_usage_bytes", + "ephemeral_storage" + ], + "title": "TrainingJobMetricsV1", "type": "object" }, - "CreateTrainingJobCheckpointingConfig": { + "TrainingJobNodeMetricsV1": { + "description": "A set of metrics for a training job node.", "properties": { - "enabled": { - "default": false, - "description": "Whether checkpointing is enabled.", - "examples": [ - true - ], - "title": "Enabled", - "type": "boolean" - }, - "checkpoint_path": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "path where checkpoints will be saved.", - "examples": [ - "/mnt/ckpts" - ], - "title": "Checkpoint Path" + "node_id": { + "description": "The name of the node.", + "title": "Node Id", + "type": "string" }, - "volume_size_gib": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Size of the volume in gibibytes. If not provided, the default size will be used", - "examples": [ - 10 - ], - "title": "Volume Size Gib" + "metrics": { + "$ref": "#/components/schemas/TrainingJobMetricsV1", + "description": "The metrics for the node." } }, - "title": "CreateTrainingJobCheckpointingConfig", + "required": [ + "node_id", + "metrics" + ], + "title": "TrainingJobNodeMetricsV1", "type": "object" }, - "CreateTrainingJobComputeV1": { - "description": "Configuration to specify the compute for a training job.", + "GetTrainingJobMetricsResponseV1": { + "description": "A response to fetch training job metrics. The outer list for each metric represents that metric across time.", "properties": { - "node_count": { - "default": 1, - "description": "Number of nodes for the training job.", - "examples": [ - 1 - ], - "title": "Node Count", - "type": "integer" + "gpu_memory_usage_bytes": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", + "title": "Gpu Memory Usage Bytes", + "type": "object" }, - "cpu_count": { - "default": 1, - "description": "Number of cpus for the training job.", - "examples": [ - 1 - ], - "title": "Cpu Count", - "type": "integer" + "gpu_utilization": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", + "title": "Gpu Utilization", + "type": "object" }, - "memory": { - "default": "2Gi", - "description": "Memory for the training job.", - "examples": [ - "2Gi" - ], - "title": "Memory", - "type": "string" + "cpu_usage": { + "description": "The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Cpu Usage", + "type": "array" }, - "accelerator": { + "cpu_memory_usage_bytes": { + "description": "The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Cpu Memory Usage Bytes", + "type": "array" + }, + "ephemeral_storage": { + "$ref": "#/components/schemas/StorageMetricsV1", + "description": "The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." + }, + "training_job": { + "$ref": "#/components/schemas/TrainingJobV1", + "description": "The training job." + }, + "cache": { "anyOf": [ { - "$ref": "#/components/schemas/CreateTrainingJobAcceleratorV1" + "$ref": "#/components/schemas/StorageMetricsV1" }, { "type": "null" } ], - "default": null, - "description": "GPU specification for the training job", - "examples": [ - { - "accelerator": "H100", - "count": 2 - } - ] + "description": "The storage usage for the read-write cache." }, - "availability_model": { - "$ref": "#/components/schemas/V1AvailabilityModel", - "default": "dedicated", - "description": "Capacity guarantee for the job. 'dedicated' (the default) runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress.", - "examples": [ - "spot" - ] + "per_node_metrics": { + "description": "The metrics for each node in the training job.", + "items": { + "$ref": "#/components/schemas/TrainingJobNodeMetricsV1" + }, + "title": "Per Node Metrics", + "type": "array" } }, - "title": "CreateTrainingJobComputeV1", + "required": [ + "gpu_memory_usage_bytes", + "gpu_utilization", + "cpu_usage", + "cpu_memory_usage_bytes", + "ephemeral_storage", + "training_job", + "cache", + "per_node_metrics" + ], + "title": "GetTrainingJobMetricsResponseV1", "type": "object" }, - "CreateTrainingJobImageV1": { - "description": "Configuration to create a training job image.", + "GetTrainingJobMetricsRequestV1": { + "description": "A request to fetch metrics. Allows the user to request metrics over a period of time.", "properties": { - "base_image": { - "description": "Base image for the training job.", - "examples": [ - "hello-world" - ], - "title": "Base Image", - "type": "string" - }, - "docker_auth": { + "end_epoch_millis": { "anyOf": [ { - "$ref": "#/components/schemas/DockerAuthV1" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Docker authentication credentials" - } - }, - "required": [ - "base_image" - ], - "title": "CreateTrainingJobImageV1", - "type": "object" - }, - "CreateTrainingJobRuntimeV1": { - "description": "Configuration to specify the runtime environment for a training job.", - "properties": { - "start_commands": { - "description": "Commands to execute when starting the runtime.", - "examples": [ - [ - "python main.py" - ] - ], - "items": { - "type": "string" - }, - "title": "Start Commands", - "type": "array" - }, - "environment_variables": { - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/components/schemas/SecretReferenceV1" - } - ] - }, - "description": "Environment variables to set in the runtime.", - "examples": [ - { - "API_KEY": "your_api_key_here", - "PATH": "/usr/bin" - } - ], - "title": "Environment Variables", - "type": "object" - }, - "artifacts": { - "description": "Runtime artifacts for the training job.", - "items": { - "$ref": "#/components/schemas/CreateTrainingJobS3Artifact" - }, - "title": "Artifacts", - "type": "array" + "description": "Epoch millis timestamp to end fetching metrics", + "title": "End Epoch Millis" }, - "enable_cache": { + "start_epoch_millis": { "anyOf": [ { - "type": "boolean" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Deprecated. Use cache_config instead.", - "examples": [ - true - ], - "title": "Enable Cache" + "description": "Epoch millis timestamp to start fetching metrics.", + "title": "Start Epoch Millis" }, - "cache_config": { + "step_seconds": { "anyOf": [ { - "$ref": "#/components/schemas/CreateTrainingJobCacheConfig" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Configuration for the read-write cache.", - "examples": [ + "description": "Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", + "title": "Step Seconds" + } + }, + "title": "GetTrainingJobMetricsRequestV1", + "type": "object" + }, + "StopTrainingJobRequestV1": { + "description": "A request to stop a training job.", + "properties": {}, + "title": "StopTrainingJobRequestV1", + "type": "object" + }, + "StopTrainingJobResponseV1": { + "description": "A response to stopping a training job.", + "properties": { + "training_job": { + "$ref": "#/components/schemas/TrainingJobV1", + "description": "The stopped training job." + } + }, + "required": [ + "training_job" + ], + "title": "StopTrainingJobResponseV1", + "type": "object" + }, + "TrainingJobCheckpointV1": { + "description": "A checkpoint for a training job.", + "properties": { + "checkpoint_id": { + "description": "The ID of the checkpoint.", + "title": "Checkpoint Id", + "type": "string" + }, + "created_at": { + "description": "The timestamp of the checkpoint in ISO 8601 format.", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "checkpoint_type": { + "description": "The type of checkpoint.", + "title": "Checkpoint Type", + "type": "string" + }, + "base_model": { + "anyOf": [ { - "enable_legacy_hf_mount": true, - "enabled": true, - "mount_base_path": "/root/.cache", - "require_cache_affinity": true + "type": "string" + }, + { + "type": "null" } - ] + ], + "description": "The base model of the checkpoint.", + "title": "Base Model" }, - "checkpointing_config": { - "$ref": "#/components/schemas/CreateTrainingJobCheckpointingConfig", - "description": "Configuration for checkpointing.", - "examples": [ + "lora_adapter_config": { + "anyOf": [ { - "checkpoint_path": "/mnt/ckpts", - "enabled": true, - "volume_size_gib": null + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" } - ] + ], + "description": "The adapter config of the checkpoint.", + "title": "Lora Adapter Config" }, - "load_checkpoint_config": { + "size_bytes": { + "description": "The size of the checkpoint in bytes.", + "title": "Size Bytes", + "type": "integer" + }, + "sync_status": { "anyOf": [ { - "$ref": "#/components/schemas/LoadCheckpointConfig" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Configuration for loading checkpoints" + "description": "Sync state of the checkpoint: SYNCING or COMPLETE.", + "title": "Sync Status" + }, + "training_job_id": { + "description": "The ID of the training job.", + "title": "Training Job Id", + "type": "string" } }, - "title": "CreateTrainingJobRuntimeV1", + "required": [ + "checkpoint_id", + "created_at", + "checkpoint_type", + "base_model", + "lora_adapter_config", + "size_bytes", + "training_job_id" + ], + "title": "TrainingJobCheckpointV1", "type": "object" }, - "CreateTrainingJobS3Artifact": { + "GetTrainingJobCheckpointsResponseV1": { + "description": "A response to fetch checkpoints for a training job.", "properties": { - "s3_bucket": { - "description": "S3 bucket for the uploaded runtime artifact.", - "examples": [ - "my-s3-bucket" - ], - "title": "S3 Bucket", + "training_job": { + "$ref": "#/components/schemas/TrainingJobV1", + "description": "The training job." + }, + "checkpoints": { + "description": "The checkpoints for the training job.", + "items": { + "$ref": "#/components/schemas/TrainingJobCheckpointV1" + }, + "title": "Checkpoints", + "type": "array" + } + }, + "required": [ + "training_job", + "checkpoints" + ], + "title": "GetTrainingJobCheckpointsResponseV1", + "type": "object" + }, + "CheckpointFile": { + "properties": { + "url": { + "title": "Url", "type": "string" }, - "s3_key": { - "description": "S3 key for the uploaded runtime artifact.", - "examples": [ - "my-s3-key" - ], - "title": "S3 Key", + "relative_file_name": { + "title": "Relative File Name", + "type": "string" + }, + "node_rank": { + "title": "Node Rank", + "type": "integer" + }, + "size_bytes": { + "title": "Size Bytes", + "type": "integer" + }, + "last_modified": { + "title": "Last Modified", "type": "string" } }, "required": [ - "s3_bucket", - "s3_key" + "url", + "relative_file_name", + "node_rank", + "size_bytes", + "last_modified" ], - "title": "CreateTrainingJobS3Artifact", + "title": "CheckpointFile", "type": "object" }, - "CreateTrainingJobV1": { - "description": "Configuration for a training job.", + "GetTrainingJobCheckpointFilesResponseV1": { + "description": "A response to fetch presigned URLs for checkpoint files of a training job.", "properties": { - "image": { - "$ref": "#/components/schemas/CreateTrainingJobImageV1", - "examples": [ + "presigned_urls": { + "description": "List of presigned URLs for checkpoint files.", + "items": { + "$ref": "#/components/schemas/CheckpointFile" + }, + "title": "Presigned Urls", + "type": "array" + }, + "next_page_token": { + "anyOf": [ { - "base_image": "hello-world", - "docker_auth": null + "type": "integer" + }, + { + "type": "null" } - ] + ], + "default": null, + "description": "Token to use for fetching the next page of results. None when there are no more results.", + "title": "Next Page Token" + }, + "total_count": { + "description": "Total number of checkpoint files available.", + "title": "Total Count", + "type": "integer" + } + }, + "required": [ + "presigned_urls", + "total_count" + ], + "title": "GetTrainingJobCheckpointFilesResponseV1", + "type": "object" + }, + "GetTrainingJobCheckpointFilesRequestV1": { + "description": "Pagination params for ``GET /v1/training_projects/.../checkpoint_files``.", + "properties": { + "page_size": { + "default": 1000, + "description": "Max files per page (default 1000).", + "minimum": 1, + "title": "Page Size", + "type": "integer" + }, + "page_token": { + "default": 0, + "description": "Offset into the file list (default 0).", + "minimum": 0, + "title": "Page Token", + "type": "integer" + } + }, + "title": "GetTrainingJobCheckpointFilesRequestV1", + "type": "object" + }, + "AuthCodeV1": { + "description": "Authentication code for a training job interactive session node.", + "properties": { + "session_id": { + "description": "Unique identifier of the interactive session.", + "title": "Session Id", + "type": "string" }, - "compute": { - "$ref": "#/components/schemas/CreateTrainingJobComputeV1", - "examples": [ - { - "accelerator": { - "accelerator": "H100", - "count": 2 - }, - "availability_model": "spot", - "cpu_count": 1, - "memory": "2Gi", - "node_count": 1 - } - ] + "replica_id": { + "description": "Replica identifier in gXXrY format (e.g., 'g00r0' for group 0, replica 0).", + "title": "Replica Id", + "type": "string" }, - "runtime": { - "$ref": "#/components/schemas/CreateTrainingJobRuntimeV1", - "description": "Configuration for the runtime environment of the training job.", - "examples": [ - { - "artifacts": [], - "cache_config": null, - "checkpointing_config": { - "checkpoint_path": null, - "enabled": false, - "volume_size_gib": null - }, - "enable_cache": null, - "environment_variables": { - "API_KEY": "your_api_key_here", - "PATH": "/usr/bin" - }, - "load_checkpoint_config": null, - "start_commands": [ - "python main.py" - ] - } - ] + "auth_code": { + "description": "The device authentication code (e.g., '4F64-C0D9').", + "title": "Auth Code", + "type": "string" }, - "name": { + "auth_url": { + "description": "URL where the user should enter the auth code (e.g., 'https://github.com/login/device').", + "title": "Auth Url", + "type": "string" + }, + "generated_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { @@ -20173,67 +24836,81 @@ } ], "default": null, - "description": "Name of the training job.", - "examples": [ - "gpt-oss-job" - ], - "title": "Name" + "description": "When the auth code was generated, in ISO 8601 format.", + "title": "Generated At" }, - "truss_user_env": { + "tunnel_name": { "anyOf": [ { - "$ref": "#/components/schemas/TrussUserEnv" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Truss user environment information" + "description": "The name of the tunnel node.", + "title": "Tunnel Name" }, - "interactive_session": { + "expires_at": { "anyOf": [ { - "$ref": "#/components/schemas/InteractiveSessionConfigV1" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Configuration for interactive debugging sessions." + "description": "When the session expires, in ISO 8601 format.", + "title": "Expires At" }, - "weights": { - "description": "MDN weight sources to mount in the training container. Weights are mirrored and cached for fast startup.", - "examples": [ - [ - { - "allow_patterns": null, - "auth": null, - "auth_secret_name": null, - "ignore_patterns": null, - "mount_location": "/app/models/base", - "source": "hf://meta-llama/Llama-3-8B@main" - } - ] + "working_directory": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } ], + "default": null, + "description": "The working directory of the session.", + "title": "Working Directory" + } + }, + "required": [ + "session_id", + "replica_id", + "auth_code", + "auth_url" + ], + "title": "AuthCodeV1", + "type": "object" + }, + "GetAuthCodesResponseV1": { + "description": "Response containing auth codes for all nodes of a training job's interactive sessions.", + "properties": { + "auth_codes": { + "description": "List of auth codes for each node that has an active interactive session.", "items": { - "$ref": "#/components/schemas/CreateJobWeightConfigV1" + "$ref": "#/components/schemas/AuthCodeV1" }, - "title": "Weights", + "title": "Auth Codes", "type": "array" - }, - "enable_baseten_workdir": { - "default": false, - "description": "When enabled, uses /b10/workspace as the working directory instead of the image WORKDIR.", - "examples": [ - false, - true - ], - "title": "Enable Baseten Workdir", - "type": "boolean" - }, - "priority": { + } + }, + "required": [ + "auth_codes" + ], + "title": "GetAuthCodesResponseV1", + "type": "object" + }, + "PatchInteractiveSessionRequestV1": { + "description": "Request to patch an interactive session.\n\nOnly fields that are provided (non-None) will be applied.", + "properties": { + "timeout_minutes": { "anyOf": [ { "type": "integer" @@ -20243,362 +24920,320 @@ } ], "default": null, - "description": "Queue priority. Higher values are dequeued first. Defaults to 0.", - "examples": [ - 0, - 10, - 100 + "description": "For on_startup sessions, minutes to add to the expiration. For on_demand/on_failure sessions, minutes to add to the timeout. Use -1 for infinite timeout (bumps by 10 years).", + "title": "Timeout Minutes" + }, + "trigger": { + "anyOf": [ + { + "$ref": "#/components/schemas/V1InteractiveSessionTrigger" + }, + { + "type": "null" + } ], - "title": "Priority" + "default": null, + "description": "Update when the interactive session is created. Cannot be changed if the session trigger is 'on_startup'." } }, - "required": [ - "image" - ], - "title": "CreateTrainingJobV1", + "title": "PatchInteractiveSessionRequestV1", "type": "object" }, - "DockerAuthType": { - "enum": [ - "GCP_SERVICE_ACCOUNT_JSON", - "AWS_IAM", - "AWS_OIDC", - "GCP_OIDC", - "REGISTRY_SECRET", - "AWS_ASSUME_ROLE" - ], - "title": "DockerAuthType", - "type": "string" - }, - "DockerAuthV1": { - "description": "Docker authentication credentials.", + "InteractiveSessionV1": { + "description": "Representation of a training job interactive session.", "properties": { - "registry": { - "description": "Registry to authenticate with", - "title": "Registry", + "id": { + "description": "Unique identifier of the interactive session.", + "title": "Id", "type": "string" }, - "auth_method": { - "$ref": "#/components/schemas/DockerAuthType", - "description": "Method to authenticate with the registry", - "examples": [ - "GCP_SERVICE_ACCOUNT_JSON", - "AWS_IAM", - "AWS_OIDC", - "GCP_OIDC", - "REGISTRY_SECRET", - "AWS_ASSUME_ROLE" - ] + "trigger": { + "description": "When the interactive session is created.", + "title": "Trigger", + "type": "string" }, - "gcp_service_account_json_docker_auth": { + "timeout_minutes": { + "description": "Minutes before the session times out.", + "title": "Timeout Minutes", + "type": "integer" + }, + "session_provider": { + "description": "The IDE client for the session.", + "title": "Session Provider", + "type": "string" + }, + "auth_provider": { + "description": "The authentication provider for the session.", + "title": "Auth Provider", + "type": "string" + }, + "pod_name": { + "description": "Pod name / node rank for the session.", + "title": "Pod Name", + "type": "string" + }, + "expires_at": { "anyOf": [ { - "$ref": "#/components/schemas/GcpServiceAccountJsonDockerAuthV1" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "GCP service account details for the registry" + "description": "When the session expires, in ISO 8601 format.", + "title": "Expires At" }, - "aws_iam_docker_auth": { + "tunnel_name": { "anyOf": [ { - "$ref": "#/components/schemas/AwsIamDockerAuthV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "AWS details for the registry" + "description": "The tunnel name for the session.", + "title": "Tunnel Name" }, - "aws_oidc_docker_auth": { + "auth_code": { "anyOf": [ { - "$ref": "#/components/schemas/AwsOidcDockerAuthV1" + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The device authentication code.", + "title": "Auth Code" + }, + "auth_url": { + "anyOf": [ + { + "type": "string" }, { "type": "null" } ], "default": null, - "description": "AWS OIDC details for the registry" + "description": "URL where the user should enter the auth code.", + "title": "Auth Url" }, - "gcp_oidc_docker_auth": { + "auth_code_generated_at": { "anyOf": [ { - "$ref": "#/components/schemas/GcpOidcDockerAuthV1" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "GCP OIDC details for the registry" + "description": "When the auth code was generated.", + "title": "Auth Code Generated At" }, - "registry_secret_docker_auth": { + "authenticated_at": { "anyOf": [ { - "$ref": "#/components/schemas/RegistrySecretDockerAuthV1" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Required when auth_method is REGISTRY_SECRET. Supports any Docker registry (Docker Hub, GHCR, NGC, etc.) via username:password credentials stored as a Baseten secret." + "description": "When the session was authenticated.", + "title": "Authenticated At" }, - "aws_assume_role_docker_auth": { + "working_directory": { "anyOf": [ { - "$ref": "#/components/schemas/AwsAssumeRoleDockerAuthV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Required when auth_method is AWS_ASSUME_ROLE. Baseten assumes the given IAM role with its own AWS principal and your organization's external ID, with no OIDC provider registration in your account." + "description": "The working directory of the session.", + "title": "Working Directory" } }, "required": [ - "registry", - "auth_method" + "id", + "trigger", + "timeout_minutes", + "session_provider", + "auth_provider", + "pod_name" ], - "title": "DockerAuthV1", + "title": "InteractiveSessionV1", "type": "object" }, - "GcpOidcDockerAuthV1": { - "description": "GCP OIDC details for the registry.", + "PatchInteractiveSessionResponseV1": { + "description": "Response after patching an interactive session.", "properties": { - "service_account": { - "description": "GCP service account name for OIDC authentication", - "title": "Service Account", - "type": "string" + "interactive_session": { + "$ref": "#/components/schemas/InteractiveSessionV1", + "description": "The updated interactive session." }, - "workload_identity_provider": { - "description": "GCP workload identity provider for OIDC authentication", - "title": "Workload Identity Provider", + "message": { + "description": "Human-readable summary of what was updated.", + "title": "Message", "type": "string" } }, "required": [ - "service_account", - "workload_identity_provider" - ], - "title": "GcpOidcDockerAuthV1", - "type": "object" - }, - "GcpServiceAccountJsonDockerAuthV1": { - "description": "GCP details for the registry.", - "properties": { - "service_account_json_secret_ref": { - "$ref": "#/components/schemas/SecretReferenceV1", - "description": "Name of the service account secret" - } - }, - "required": [ - "service_account_json_secret_ref" + "interactive_session", + "message" ], - "title": "GcpServiceAccountJsonDockerAuthV1", + "title": "PatchInteractiveSessionResponseV1", "type": "object" }, - "GitInfo": { + "FileSummary": { + "description": "Information about a file in the cache.", "properties": { - "latest_commit_sha": { - "title": "Latest Commit Sha", + "path": { + "description": "Relative path of the file in the cache", + "title": "Path", "type": "string" }, - "latest_tag": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Latest Tag" + "size_bytes": { + "description": "Size of the file in bytes", + "title": "Size Bytes", + "type": "integer" }, - "commits_since_tag": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Commits Since Tag" + "modified": { + "description": "Last modification time of the file", + "title": "Modified", + "type": "string" }, - "has_uncommitted_changes": { - "title": "Has Uncommitted Changes", - "type": "boolean" + "file_type": { + "description": "Type of the file", + "title": "File Type", + "type": "string" + }, + "permissions": { + "description": "Permissions of the file", + "title": "Permissions", + "type": "string" } }, "required": [ - "latest_commit_sha", - "latest_tag", - "commits_since_tag", - "has_uncommitted_changes" + "path", + "size_bytes", + "modified", + "file_type", + "permissions" ], - "title": "GitInfo", - "type": "object" - }, - "InteractiveSessionConfigV1": { - "description": "Configuration for interactive debugging sessions on training jobs.", - "properties": { - "trigger": { - "$ref": "#/components/schemas/V1InteractiveSessionTrigger", - "default": "on_demand", - "description": "When to create the interactive session. 'on_startup' creates on job start, 'on_failure' creates on job failure, 'on_demand' bypasses automatic session creation." - }, - "timeout_minutes": { - "default": 480, - "description": "Number of minutes before the interactive session times out.", - "examples": [ - 480, - 1440, - 10080 - ], - "title": "Timeout Minutes", - "type": "integer" - }, - "session_provider": { - "$ref": "#/components/schemas/V1InteractiveSessionProvider", - "default": "vs_code", - "description": "The IDE client for the interactive session." - }, - "auth_provider": { - "$ref": "#/components/schemas/V1InteractiveSessionAuthProvider", - "default": "github", - "description": "The authentication provider for the interactive session." - } - }, - "title": "InteractiveSessionConfigV1", + "title": "FileSummary", "type": "object" }, - "LoadCheckpointConfig": { + "GetCacheSummaryResponseV1": { + "description": "Response for getting cache summary.", "properties": { - "enabled": { - "default": false, - "description": "Whether checkpoint loading is enabled", - "title": "Enabled", - "type": "boolean" + "timestamp": { + "description": "Timestamp when the cache summary was captured", + "title": "Timestamp", + "type": "string" }, - "download_folder": { - "default": "/tmp/loaded_checkpoints", - "description": "Folder where checkpoints will be downloaded", - "title": "Download Folder", + "project_id": { + "description": "Project ID associated with the cache", + "title": "Project Id", "type": "string" }, - "checkpoints": { - "description": "List of checkpoint configurations", + "file_summaries": { + "description": "List of files in the cache", "items": { - "discriminator": { - "mapping": { - "baseten_latest_checkpoint": "#/components/schemas/BasetenLatestCheckpointConfig", - "baseten_named_checkpoint": "#/components/schemas/BasetenNamedCheckpointConfig", - "loops_checkpoint": "#/components/schemas/LoopsCheckpointConfig" - }, - "propertyName": "typ" - }, - "oneOf": [ - { - "$ref": "#/components/schemas/BasetenLatestCheckpointConfig" - }, - { - "$ref": "#/components/schemas/BasetenNamedCheckpointConfig" - }, - { - "$ref": "#/components/schemas/LoopsCheckpointConfig" - } - ] + "$ref": "#/components/schemas/FileSummary" }, - "title": "Checkpoints", + "title": "File Summaries", "type": "array" } }, - "title": "LoadCheckpointConfig", + "required": [ + "timestamp", + "project_id", + "file_summaries" + ], + "title": "GetCacheSummaryResponseV1", "type": "object" }, - "LoopsCheckpointConfig": { + "TrainingProjectTombstoneV1": { + "description": "A training project tombstone.", "properties": { - "run_id": { - "description": "ID of the Loops run to load the checkpoint from", - "title": "Run Id", - "type": "string" - }, - "checkpoint_name": { - "description": "Name of the checkpoint to load", - "title": "Checkpoint Name", - "type": "string" - }, - "target": { - "default": "trainer", - "description": "Which checkpoint target to load: 'trainer' (full training state) or 'sampler' (inference weights)", - "enum": [ - "trainer", - "sampler" - ], - "title": "Target", + "id": { + "description": "Unique identifier of the training project", + "title": "Id", "type": "string" }, - "typ": { - "const": "loops_checkpoint", - "default": "loops_checkpoint", - "title": "Typ", - "type": "string" + "deleted": { + "description": "Whether the training project was deleted", + "title": "Deleted", + "type": "boolean" } }, "required": [ - "run_id", - "checkpoint_name" + "id", + "deleted" ], - "title": "LoopsCheckpointConfig", + "title": "TrainingProjectTombstoneV1", "type": "object" }, - "RegistrySecretDockerAuthV1": { - "description": "Authentication via a Baseten secret for any Docker registry (Docker Hub, GHCR, NGC, etc.).\nThe referenced secret must contain credentials in the format 'username:password'.\nFor Docker Hub, set registry to 'https://index.docker.io/v1/'. For GHCR, use 'ghcr.io'.", + "GetTrainingProjectResponseV1": { + "description": "A response to getting a training project.", "properties": { - "secret_ref": { - "$ref": "#/components/schemas/SecretReferenceV1", - "description": "Reference to a Baseten secret containing credentials in the format 'username:password'" + "training_project": { + "$ref": "#/components/schemas/TrainingProjectV1", + "description": "The training project." } }, "required": [ - "secret_ref" + "training_project" ], - "title": "RegistrySecretDockerAuthV1", + "title": "GetTrainingProjectResponseV1", "type": "object" }, - "SecretReferenceV1": { + "OrderByV1": { + "description": "A request to order training jobs.", "properties": { - "name": { - "description": "Name of the secret to reference.", + "field": { + "description": "The field to order by.", "examples": [ - "hf_token" + "created_at" ], - "title": "Name", + "title": "Field", + "type": "string" + }, + "order": { + "description": "The direction to order by.", + "examples": [ + "asc", + "desc" + ], + "title": "Order", "type": "string" } }, "required": [ - "name" + "field", + "order" ], - "title": "SecretReferenceV1", + "title": "OrderByV1", "type": "object" }, - "TrainingWeightAuthV1": { - "description": "Authentication configuration for a training weight source.", + "SearchTrainingJobsRequestV1": { + "description": "A request to search training jobs.", "properties": { - "auth_method": { - "$ref": "#/components/schemas/AuthMethod", - "description": "Method used to authenticate the weight source." - }, - "auth_secret_name": { + "project_id": { "anyOf": [ { "type": "string" @@ -20608,10 +25243,13 @@ } ], "default": null, - "description": "Name of the workspace secret used for custom-secret authentication.", - "title": "Auth Secret Name" + "description": "Filter the training jobs by project ID.", + "examples": [ + "n4q95w5" + ], + "title": "Project Id" }, - "aws_oidc_role_arn": { + "job_id": { "anyOf": [ { "type": "string" @@ -20621,49 +25259,189 @@ } ], "default": null, - "description": "AWS IAM role ARN used for OIDC authentication.", - "title": "Aws Oidc Role Arn" + "description": "Filter the training jobs by job ID.", + "examples": [ + "p7qr9qv" + ], + "title": "Job Id" }, - "aws_oidc_region": { + "statuses": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "description": "AWS region used for OIDC authentication.", - "title": "Aws Oidc Region" + "description": "Filter the training jobs by status.", + "examples": [ + [ + "TRAINING_JOB_RUNNING", + "TRAINING_JOB_COMPLETED" + ] + ], + "title": "Statuses" }, - "gcp_oidc_service_account": { - "anyOf": [ - { - "type": "string" - }, + "order_by": { + "default": [ { - "type": "null" + "field": "created_at", + "order": "desc" } ], - "default": null, - "description": "GCP service account used for OIDC authentication.", - "title": "Gcp Oidc Service Account" + "description": "Order the training jobs by a field. Currently supports created_at", + "items": { + "$ref": "#/components/schemas/OrderByV1" + }, + "title": "Order By", + "type": "array" + } + }, + "title": "SearchTrainingJobsRequestV1", + "type": "object" + }, + "SearchTrainingJobsResponseV1": { + "description": "A response to search training jobs.", + "properties": { + "training_jobs": { + "description": "List of training jobs.", + "items": { + "$ref": "#/components/schemas/TrainingJobV1" + }, + "title": "Training Jobs", + "type": "array" + } + }, + "required": [ + "training_jobs" + ], + "title": "SearchTrainingJobsResponseV1", + "type": "object" + }, + "EnablementDetailsV1": { + "description": "Why a supported model is not enabled for this workspace.", + "properties": { + "reason": { + "description": "Machine-readable reason the model is not enabled. Currently one of 'needs_approval', 'sequence_length_unsupported' or 'loops_not_enabled'. Deliberately not a closed enum: values are added as the check learns to distinguish cases that call for a different action, so treat an unrecognized value as 'not enabled, reason unknown' rather than an error.", + "examples": [ + "needs_approval" + ], + "title": "Reason", + "type": "string" }, - "gcp_oidc_workload_id_provider": { + "reason_detail": { + "description": "Human-readable explanation of the reason.", + "title": "Reason Detail", + "type": "string" + }, + "remediation": { + "description": "Human-readable next step to enable the model.", + "title": "Remediation", + "type": "string" + } + }, + "required": [ + "reason", + "reason_detail", + "remediation" + ], + "title": "EnablementDetailsV1", + "type": "object" + }, + "SupportedModelV1": { + "description": "A model supported by the Loops server.", + "properties": { + "model_name": { + "description": "The name of the supported model.", + "title": "Model Name", + "type": "string" + }, + "max_seq_len": { + "description": "The longest sequence length Baseten supports for this model. Independent of the caller: see 'max_enabled_seq_len' for what this workspace can actually train at. Named to match the 'max_seq_len' query parameter and the field of the same name on run creation, so one name follows the value through the API.", + "title": "Max Seq Len", + "type": "integer" + }, + "max_enabled_seq_len": { + "default": 0, + "description": "The longest sequence length this workspace can train at. Lower than 'max_seq_len' when the longer configurations need hardware the workspace is not approved for \u2014 a model's longer sequence lengths often need a bigger SKU of the same GPU. Zero when the workspace cannot run the model at all, so a client can compare against a required length without a null case.", + "title": "Max Enabled Seq Len", + "type": "integer" + }, + "max_context_length": { + "deprecated": true, + "description": "Deprecated. Use 'max_seq_len', which carries the same value. Kept so existing clients keep working.", + "title": "Max Context Length", + "type": "integer" + }, + "supports_vision_language": { + "description": "Whether the model accepts image inputs alongside text.", + "title": "Supports Vision Language", + "type": "boolean" + }, + "enabled": { + "default": true, + "description": "Whether this workspace can start a run with this model now. False means Baseten supports it but the workspace cannot use it yet; 'not_enabled' says why. Capacity is resolved when the run is created, so true is not a guarantee that GPUs are free.", + "title": "Enabled", + "type": "boolean" + }, + "enablement_details": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/EnablementDetailsV1" }, { "type": "null" } ], "default": null, - "description": "GCP workload identity provider used for OIDC authentication.", - "title": "Gcp Oidc Workload Id Provider" - }, - "aws_assume_role_arn": { + "description": "Why the model is not enabled, and what would change it. Present only when 'enabled' is false \u2014 an enabled model has nothing to explain. Read 'enabled' for the state; this is the detail behind it." + } + }, + "required": [ + "model_name", + "max_seq_len", + "max_context_length", + "supports_vision_language" + ], + "title": "SupportedModelV1", + "type": "object" + }, + "GetLoopsCapabilitiesResponseV1": { + "description": "Response for ``GET /v1/loops/capabilities``.\n\nA model Baseten does not support has no entry at all, so an empty list for\na single-model request means exactly that.", + "properties": { + "supported_models": { + "description": "Models Baseten supports for this use case, each carrying an 'enabled' flag saying whether this workspace can run it now, and 'enablement_details' when it cannot. Filter on 'enabled' to get the models you can use.", + "items": { + "$ref": "#/components/schemas/SupportedModelV1" + }, + "title": "Supported Models", + "type": "array" + } + }, + "required": [ + "supported_models" + ], + "title": "GetLoopsCapabilitiesResponseV1", + "type": "object" + }, + "LoopsUseCaseV1": { + "description": "What the caller intends to run.\n\nReinforcement learning runs a trainer and a sampler; supervised\nfine-tuning runs a trainer alone. A model can therefore be enabled for one\nand not the other, and the same model can support a longer sequence length\nfor SFT than for RL.", + "enum": [ + "rl", + "sft" + ], + "title": "LoopsUseCaseV1", + "type": "string" + }, + "GetLoopsCapabilitiesQueryParamsV1": { + "description": "Query-string filters for ``GET /v1/loops/capabilities``.", + "properties": { + "model": { "anyOf": [ { "type": "string" @@ -20673,57 +25451,116 @@ } ], "default": null, - "description": "AWS IAM role ARN that Baseten assumes to access the weight source.", - "title": "Aws Assume Role Arn" + "description": "Restrict the response to one model, identified by its HuggingFace repo id. A supported model comes back with its 'enabled' flag and, when false, its 'enablement_details'. An empty list means Baseten does not support that model. Omit to list every supported model.", + "examples": [ + "Qwen/Qwen3-8B" + ], + "title": "Model" }, - "aws_assume_role_region": { + "use_case": { + "$ref": "#/components/schemas/LoopsUseCaseV1", + "default": "rl", + "description": "What the caller intends to run. Defaults to 'rl', the stricter of the two: an RL run needs both a trainer and a sampler, so anything enabled for 'rl' is also enabled for 'sft'.", + "examples": [ + "rl" + ] + }, + "max_seq_len": { "anyOf": [ { - "type": "string" + "minimum": 1, + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "AWS region used for assume-role authentication.", - "title": "Aws Assume Role Region" + "description": "The sequence length the caller intends to train at \u2014 the same value they would pass as 'max_seq_len' when creating the run. Models that cannot serve it are reported as not enabled rather than returned with a ceiling the caller cannot use. Omit for the model's highest enabled sequence length.", + "examples": [ + 32768 + ], + "title": "Max Seq Len" + } + }, + "title": "GetLoopsCapabilitiesQueryParamsV1", + "type": "object" + }, + "LoopsSessionV1": { + "properties": { + "id": { + "title": "Id", + "type": "string" + } + }, + "required": [ + "id" + ], + "title": "LoopsSessionV1", + "type": "object" + }, + "CreateLoopsSessionResponseV1": { + "properties": { + "session": { + "$ref": "#/components/schemas/LoopsSessionV1" + } + }, + "required": [ + "session" + ], + "title": "CreateLoopsSessionResponseV1", + "type": "object" + }, + "GetLoopsSessionResponseV1": { + "description": "Response for ``GET /v1/loops/sessions/``.", + "properties": { + "session": { + "$ref": "#/components/schemas/LoopsSessionV1", + "description": "The Loops session." } }, "required": [ - "auth_method" + "session" ], - "title": "TrainingWeightAuthV1", + "title": "GetLoopsSessionResponseV1", "type": "object" }, - "TrussUserEnv": { - "description": "This data models is used to flexibly store info alongside oracle versions.\n\nThere is a corresponding data model in the truss client.\nIn contrast, here all fields are optional for backwards compatibility with old\nclients.", + "LoopsRunStatusNameV1": { + "description": "A Loops run's lifecycle state: ACTIVE or INACTIVE.", + "enum": [ + "ACTIVE", + "INACTIVE" + ], + "title": "LoopsRunStatusNameV1", + "type": "string" + }, + "LoopsRunStatusV1": { + "description": "The current status of a Loops run.", "properties": { - "truss_client_version": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Truss Client Version" + "name": { + "$ref": "#/components/schemas/LoopsRunStatusNameV1", + "description": "ACTIVE while the run is live; INACTIVE once replaced by a newer run or shut down." + } + }, + "required": [ + "name" + ], + "title": "LoopsRunStatusV1", + "type": "object" + }, + "LoopsRunV1": { + "properties": { + "id": { + "description": "The run ID.", + "title": "Id", + "type": "string" }, - "python_version": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Python Version" + "session_id": { + "description": "The session ID this run belongs to.", + "title": "Session Id", + "type": "string" }, - "pydantic_version": { + "deployment_id": { "anyOf": [ { "type": "string" @@ -20733,236 +25570,250 @@ } ], "default": null, - "title": "Pydantic Version" + "description": "The ID of the Loops deployment the run executes on, if it has one.", + "title": "Deployment Id" }, - "mypy_version": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Mypy Version" + "name": { + "description": "The run's display name.", + "title": "Name", + "type": "string" }, - "is_library_deployment": { - "default": false, - "title": "Is Library Deployment", - "type": "boolean" + "base_model": { + "description": "The HuggingFace base model the run is fine-tuning.", + "title": "Base Model", + "type": "string" }, - "is_frontend_deployment": { - "default": false, - "title": "Is Frontend Deployment", - "type": "boolean" + "base_url": { + "description": "The run's base URL.", + "title": "Base Url", + "type": "string" }, - "git_info": { + "created_at": { + "description": "Time the run was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/LoopsRunStatusV1", + "description": "The run's current status." + }, + "user": { + "$ref": "#/components/schemas/UserV1", + "description": "The user who owns the run." + }, + "sampler": { "anyOf": [ { - "$ref": "#/components/schemas/GitInfo" + "$ref": "#/components/schemas/LoopsSamplerV1" }, { "type": "null" } ], - "default": null - } - }, - "title": "TrussUserEnv", - "type": "object" - }, - "V1InteractiveSessionAuthProvider": { - "enum": [ - "github", - "microsoft" - ], - "title": "V1InteractiveSessionAuthProvider", - "type": "string" - }, - "V1InteractiveSessionProvider": { - "enum": [ - "vs_code", - "cursor", - "ssh" - ], - "title": "V1InteractiveSessionProvider", - "type": "string" - }, - "V1InteractiveSessionTrigger": { - "enum": [ - "on_startup", - "on_failure", - "on_demand" - ], - "title": "V1InteractiveSessionTrigger", - "type": "string" - }, - "CreateTrainingJobRequestV1": { - "description": "A request to create a training job.", - "properties": { - "training_job": { - "$ref": "#/components/schemas/CreateTrainingJobV1", - "description": "The training job to create." + "default": null, + "description": "The sampler bound to this run, or null for a trainer-only run that has not yet created a sampler." } }, "required": [ - "training_job" + "id", + "session_id", + "name", + "base_model", + "base_url", + "created_at", + "status", + "user" ], - "title": "CreateTrainingJobRequestV1", + "title": "LoopsRunV1", "type": "object" }, - "CreateTrainingJobResponseV1": { - "description": "A response to creating a training job.", + "LoopsSamplerStatusV1": { + "description": "The current status of a Loops sampler.", "properties": { - "training_job": { - "$ref": "#/components/schemas/TrainingJobV1", - "description": "The created training job." + "name": { + "$ref": "#/components/schemas/DeploymentStatusV1", + "description": "The current status of the Loops sampler." } }, "required": [ - "training_job" + "name" ], - "title": "CreateTrainingJobResponseV1", + "title": "LoopsSamplerStatusV1", "type": "object" }, - "TrainingJobTombstoneV1": { - "description": "A training job tombstone.", + "LoopsSamplerV1": { "properties": { "id": { - "description": "Unique identifier of the training job", "title": "Id", "type": "string" }, - "deleted": { - "description": "Whether the training job was deleted", - "title": "Deleted", - "type": "boolean" + "base_url": { + "title": "Base Url", + "type": "string" }, - "training_project_id": { - "description": "Unique identifier of the training project", - "title": "Training Project Id", + "base_model": { + "description": "The HuggingFace base model the sampler is serving.", + "title": "Base Model", + "type": "string" + }, + "created_at": { + "description": "Time the sampler was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "model_id": { + "description": "Hashid of the underlying Baseten model.", + "title": "Model Id", + "type": "string" + }, + "deployment_id": { + "description": "Hashid of the specific model deployment (version).", + "title": "Deployment Id", "type": "string" + }, + "status": { + "$ref": "#/components/schemas/LoopsSamplerStatusV1", + "description": "The sampler's current status." + }, + "user": { + "$ref": "#/components/schemas/UserV1", + "description": "The user who owns the sampler." + }, + "instance_type": { + "anyOf": [ + { + "$ref": "#/components/schemas/InstanceTypeV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Instance type serving the sampler." + }, + "node_count": { + "default": 1, + "description": "Number of nodes serving the sampler.", + "title": "Node Count", + "type": "integer" } }, "required": [ "id", - "deleted", - "training_project_id" + "base_url", + "base_model", + "created_at", + "model_id", + "deployment_id", + "status", + "user" ], - "title": "TrainingJobTombstoneV1", + "title": "LoopsSamplerV1", "type": "object" }, - "GetTrainingJobResponseV1": { - "description": "A response to fetch a training job.", + "ListLoopsRunsResponseV1": { + "description": "Runs matching the query filters.", "properties": { - "training_project": { - "$ref": "#/components/schemas/TrainingProjectV1", - "description": "The training project." - }, - "training_job": { - "$ref": "#/components/schemas/TrainingJobV1", - "description": "The fetched training job." + "runs": { + "description": "List of runs.", + "items": { + "$ref": "#/components/schemas/LoopsRunV1" + }, + "title": "Runs", + "type": "array" } }, "required": [ - "training_project", - "training_job" + "runs" ], - "title": "GetTrainingJobResponseV1", + "title": "ListLoopsRunsResponseV1", "type": "object" }, - "UpdateTrainingJobRequestV1": { - "description": "A request to update mutable fields on a training job.\n\nEvery field is optional so a caller can patch one without the other, but at least\none must be provided: an empty body has nothing to apply.", - "minProperties": 1, + "ListLoopsRunsQueryParamsV1": { + "description": "Query-string filters for ``GET /v1/loops/runs``.\n\nAll filters are optional and can be combined; omit them to list the caller's\nown runs. Pass ``scope=org`` to list every run in the caller's organization\ninstead.", "properties": { - "priority": { + "run_id": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "New queue priority for a PENDING training job. Higher values are dequeued first. Only jobs in the PENDING state can have their priority changed.", + "description": "Filter by run ID.", "examples": [ - 0, - 10, - 100 + "k4q95w5" ], - "title": "Priority" + "title": "Run Id" }, - "availability_model": { + "base_model": { "anyOf": [ { - "$ref": "#/components/schemas/V1AvailabilityModel" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "New capacity guarantee for a PENDING training job. 'dedicated' runs on on-demand capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; the user is responsible for checkpointing their own progress. Only jobs in the PENDING state can have their availability model changed.", + "description": "Filter runs by base model name.", "examples": [ - "spot" - ] - } - }, - "title": "UpdateTrainingJobRequestV1", - "type": "object" - }, - "UpdateTrainingJobResponseV1": { - "description": "A response to updating a training job.", - "properties": { - "training_job": { - "$ref": "#/components/schemas/TrainingJobV1", - "description": "The updated training job." - } - }, - "required": [ - "training_job" - ], - "title": "UpdateTrainingJobResponseV1", - "type": "object" - }, - "DownloadTrainingJobResponseV1": { - "description": "A response with presigned URLs for a training job's artifacts.", - "properties": { - "artifact_presigned_urls": { - "description": "Presigned URLs for the job's uploaded artifacts.", - "items": { - "type": "string" - }, - "title": "Artifact Presigned Urls", - "type": "array" - } - }, - "required": [ - "artifact_presigned_urls" - ], - "title": "DownloadTrainingJobResponseV1", - "type": "object" - }, - "RecreateTrainingJobResponseV1": { - "description": "A response that sends the new training job", - "properties": { - "training_job": { - "$ref": "#/components/schemas/TrainingJobV1", - "description": "The created training job." + "Qwen/Qwen3-8B" + ], + "title": "Base Model" + }, + "scope": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Defaults to the caller's own runs; pass 'org' to list every run in the caller's organization.", + "examples": [ + "org" + ], + "title": "Scope" } }, - "required": [ - "training_job" - ], - "title": "RecreateTrainingJobResponseV1", + "title": "ListLoopsRunsQueryParamsV1", "type": "object" }, - "GetTrainingJobLogsRequestV1": { - "description": "A request to fetch training logs.", + "CreateLoopsRunRequestV1": { "properties": { - "start_epoch_millis": { + "session_id": { + "description": "ID of the Loops session this run belongs to.", + "title": "Session Id", + "type": "string" + }, + "base_model": { + "description": "Base model ID (e.g. 'Qwen/Qwen3-8B').", + "title": "Base Model", + "type": "string" + }, + "name": { + "anyOf": [ + { + "maxLength": 255, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional display name for the run. Defaults to the base model name when omitted.", + "title": "Name" + }, + "max_seq_len": { "anyOf": [ { "type": "integer" @@ -20972,10 +25823,17 @@ } ], "default": null, - "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - "title": "Start Epoch Millis" + "description": "Maximum prompt length (in tokens) the run must handle. Set this to the longest training example you plan to send. Defaults to the maximum supported by the model configuration.", + "title": "Max Seq Len" }, - "end_epoch_millis": { + "lora_rank": { + "default": 64, + "description": "LoRA rank.", + "minimum": 1, + "title": "Lora Rank", + "type": "integer" + }, + "seed": { "anyOf": [ { "type": "integer" @@ -20985,262 +25843,221 @@ } ], "default": null, - "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - "title": "End Epoch Millis" + "description": "Random seed for reproducibility.", + "title": "Seed" }, - "direction": { + "scale_down_delay_seconds": { + "default": 900, + "description": "Seconds of inactivity before the run scales to zero. Must be between 1 and 3600 (1 hour). Defaults to 900 (15 minutes).", + "exclusiveMinimum": 0, + "maximum": 3600, + "title": "Scale Down Delay Seconds", + "type": "integer" + }, + "availability_model": { + "$ref": "#/components/schemas/V1AvailabilityModel", + "default": "dedicated", + "description": "Capacity the trainer runs on. 'dedicated' is not preempted. 'spot' runs below inference and reaches idle reserved capacity, but the run is stopped if its GPUs are reclaimed and cannot be resumed.", + "examples": [ + "spot" + ] + }, + "replicas": { + "default": 1, + "description": "Number of data-parallel trainer replicas. Each replica is one full copy of the model's preset node group, so the trainer deployment runs (preset node_count * replicas) nodes (e.g. replicas=4 on a 4-node preset \u2192 16 nodes, 4 DP workers). Must be a positive integer. Defaults to 1.", + "minimum": 1, + "title": "Replicas", + "type": "integer" + }, + "path": { "anyOf": [ { - "$ref": "#/components/schemas/SortOrderV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Sort order for logs" + "description": "Optional bt:// URI of an existing checkpoint to load weights from on startup. Form: bt://loops:/weights/.", + "examples": [ + "bt://loops:k4q95w5/weights/step-100" + ], + "title": "Path" }, - "limit": { + "reuse_from_run_id": { "anyOf": [ { - "maximum": 1000, - "minimum": 1, - "type": "integer" + "type": "string" }, { "type": "null" } ], - "default": 500, - "description": "Limit of logs to fetch in a single request", - "title": "Limit" + "default": null, + "description": "Optional ID of a prior Loops run whose trainer and/or sampler should be reused for this run instead of provisioning fresh. The prior run must use the same base model and belong to the same team.", + "title": "Reuse From Run Id" }, - "min_level": { + "reuse_from_session_id": { "anyOf": [ { - "$ref": "#/components/schemas/LogLevelV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + "description": "Optional ID of a prior Loops session whose trainer and/or sampler should be reused for this run. Deprecated in favor of reuse_from_run_id.", + "title": "Reuse From Session Id" } }, - "title": "GetTrainingJobLogsRequestV1", + "required": [ + "session_id", + "base_model" + ], + "title": "CreateLoopsRunRequestV1", "type": "object" }, - "StorageMetricsV1": { - "description": "A metric for a training job.", + "CreateLoopsRunResponseV1": { "properties": { - "usage_bytes": { - "description": "The number of bytes used on the storage entity.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Usage Bytes", - "type": "array" + "run": { + "$ref": "#/components/schemas/LoopsRunV1" + } + }, + "required": [ + "run" + ], + "title": "CreateLoopsRunResponseV1", + "type": "object" + }, + "DeactivateLoopsRunResponseV1": { + "description": "Response for ``POST /v1/loops/runs//deactivate``.", + "properties": { + "id": { + "description": "The deactivated Loops run ID.", + "title": "Id", + "type": "string" }, - "utilization": { - "description": "The utilization of the storage entity as a decimal percentage.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Utilization", - "type": "array" + "base_model": { + "description": "The base model whose Loops run was deactivated.", + "title": "Base Model", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/UserV1", + "description": "The user who owns the Loops run." } }, "required": [ - "usage_bytes", - "utilization" + "id", + "base_model", + "user" ], - "title": "StorageMetricsV1", + "title": "DeactivateLoopsRunResponseV1", "type": "object" }, - "TrainingJobMetricV1": { - "description": "A metric for a training job.", + "GetLoopsRunResponseV1": { + "description": "Response for ``GET /v1/loops/runs/``.", "properties": { - "value": { - "description": "The value of the metric.", - "title": "Value", - "type": "number" - }, - "timestamp": { - "description": "The timestamp of the metric in ISO 8601 format.", - "format": "date-time", - "title": "Timestamp", - "type": "string" + "run": { + "$ref": "#/components/schemas/LoopsRunV1", + "description": "The Loops run with its associated sampler." } }, "required": [ - "value", - "timestamp" + "run" ], - "title": "TrainingJobMetricV1", + "title": "GetLoopsRunResponseV1", "type": "object" }, - "TrainingJobMetricsV1": { + "ListLoopsSamplersResponseV1": { + "description": "Response for ``GET /v1/loops/samplers``.\n\nReturns the caller's samplers, including those paired to runs and\nstandalone samplers. Ordered newest-first.", "properties": { - "gpu_memory_usage_bytes": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "type": "array" - }, - "description": "A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", - "title": "Gpu Memory Usage Bytes", - "type": "object" - }, - "gpu_utilization": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "type": "array" - }, - "description": "A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", - "title": "Gpu Utilization", - "type": "object" - }, - "cpu_usage": { - "description": "The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Cpu Usage", - "type": "array" - }, - "cpu_memory_usage_bytes": { - "description": "The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", + "samplers": { + "description": "List of samplers.", "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" + "$ref": "#/components/schemas/LoopsSamplerV1" }, - "title": "Cpu Memory Usage Bytes", + "title": "Samplers", "type": "array" - }, - "ephemeral_storage": { - "$ref": "#/components/schemas/StorageMetricsV1", - "description": "The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." } }, "required": [ - "gpu_memory_usage_bytes", - "gpu_utilization", - "cpu_usage", - "cpu_memory_usage_bytes", - "ephemeral_storage" + "samplers" ], - "title": "TrainingJobMetricsV1", + "title": "ListLoopsSamplersResponseV1", "type": "object" }, - "TrainingJobNodeMetricsV1": { - "description": "A set of metrics for a training job node.", + "ListLoopsSamplersRequestV1": { + "description": "Query-string filters for the Loops sampler listing routes.", "properties": { - "node_id": { - "description": "The name of the node.", - "title": "Node Id", - "type": "string" - }, - "metrics": { - "$ref": "#/components/schemas/TrainingJobMetricsV1", - "description": "The metrics for the node." + "scope": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Defaults to the caller's own samplers; pass 'org' to include samplers owned by other users in the caller's organization.", + "examples": [ + "org" + ], + "title": "Scope" } }, - "required": [ - "node_id", - "metrics" - ], - "title": "TrainingJobNodeMetricsV1", + "title": "ListLoopsSamplersRequestV1", "type": "object" }, - "GetTrainingJobMetricsResponseV1": { - "description": "A response to fetch training job metrics. The outer list for each metric represents that metric across time.", + "CreateLoopsSamplerRequestV1": { "properties": { - "gpu_memory_usage_bytes": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "type": "array" - }, - "description": "A map of GPU rank to memory usage for the training job. For multinode jobs, this is the memory usage of the leader unless specified otherwise.", - "title": "Gpu Memory Usage Bytes", - "type": "object" - }, - "gpu_utilization": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" + "availability_model": { + "anyOf": [ + { + "$ref": "#/components/schemas/V1AvailabilityModel" }, - "type": "array" - }, - "description": "A map of GPU rank to fractional GPU utilization. For multinode jobs, this is the GPU utilization of the leader unless specified otherwise.", - "title": "Gpu Utilization", - "type": "object" - }, - "cpu_usage": { - "description": "The CPU usage measured in cores. For multinode jobs, this is the CPU usage of the leader unless specified otherwise.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Cpu Usage", - "type": "array" - }, - "cpu_memory_usage_bytes": { - "description": "The CPU memory usage for the training job. For multinode jobs, this is the CPU memory usage of the leader unless specified otherwise.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Cpu Memory Usage Bytes", - "type": "array" + { + "type": "null" + } + ], + "default": null, + "description": "Capacity the sampler runs on. 'spot' allows preemption when its GPUs are reclaimed. Defaults to 'dedicated' for standalone samplers. Paired samplers inherit their run's availability model; an explicit value must match it." }, - "ephemeral_storage": { - "$ref": "#/components/schemas/StorageMetricsV1", - "description": "The storage usage for the ephemeral storage. For multinode jobs, this is the ephemeral storage usage of the leader unless specified otherwise." + "session_id": { + "description": "ID of the Loops session this sampler belongs to.", + "title": "Session Id", + "type": "string" }, - "training_job": { - "$ref": "#/components/schemas/TrainingJobV1", - "description": "The training job." + "base_model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Base model ID for a standalone sampler (for example, a baseline).", + "title": "Base Model" }, - "cache": { + "run_id": { "anyOf": [ { - "$ref": "#/components/schemas/StorageMetricsV1" + "type": "string" }, { "type": "null" } ], - "description": "The storage usage for the read-write cache." + "default": null, + "description": "ID of an existing run to attach this sampler to. When set, the sampler is paired to the run and weight-syncs from its trainer, and base_model is inherited from the run. Omit to create a standalone sampler.", + "title": "Run Id" }, - "per_node_metrics": { - "description": "The metrics for each node in the training job.", - "items": { - "$ref": "#/components/schemas/TrainingJobNodeMetricsV1" - }, - "title": "Per Node Metrics", - "type": "array" - } - }, - "required": [ - "gpu_memory_usage_bytes", - "gpu_utilization", - "cpu_usage", - "cpu_memory_usage_bytes", - "ephemeral_storage", - "training_job", - "cache", - "per_node_metrics" - ], - "title": "GetTrainingJobMetricsResponseV1", - "type": "object" - }, - "GetTrainingJobMetricsRequestV1": { - "description": "A request to fetch metrics. Allows the user to request metrics over a period of time.", - "properties": { - "end_epoch_millis": { + "max_seq_length": { "anyOf": [ { "type": "integer" @@ -21250,61 +26067,99 @@ } ], "default": null, - "description": "Epoch millis timestamp to end fetching metrics", - "title": "End Epoch Millis" + "description": "Maximum prompt length (in tokens) the sampler must handle. Set this to the longest prompt you plan to send.", + "title": "Max Seq Length" }, - "start_epoch_millis": { + "model_path": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Epoch millis timestamp to start fetching metrics.", - "title": "Start Epoch Millis" + "description": "bt:// URI of an existing sampler checkpoint to serve. Form: bt://loops:/sampler_weights/.", + "examples": [ + "bt://loops:k4q95w5/sampler_weights/step-100" + ], + "title": "Model Path" }, - "step_seconds": { + "reuse_from_session_id": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", - "title": "Step Seconds" + "description": "Optional ID of a prior Loops session to reuse a trainer and/or sampler from. Deprecated.", + "title": "Reuse From Session Id" + } + }, + "required": [ + "session_id" + ], + "title": "CreateLoopsSamplerRequestV1", + "type": "object" + }, + "CreateLoopsSamplerResponseV1": { + "properties": { + "sampler": { + "$ref": "#/components/schemas/LoopsSamplerV1" } }, - "title": "GetTrainingJobMetricsRequestV1", + "required": [ + "sampler" + ], + "title": "CreateLoopsSamplerResponseV1", "type": "object" }, - "StopTrainingJobRequestV1": { - "description": "A request to stop a training job.", - "properties": {}, - "title": "StopTrainingJobRequestV1", + "DeactivateLoopsSamplerResponseV1": { + "description": "Response for ``POST /v1/loops/samplers//deactivate``.", + "properties": { + "id": { + "description": "The deactivated Loops sampler ID.", + "title": "Id", + "type": "string" + }, + "base_model": { + "description": "The base model the deactivated sampler was serving.", + "title": "Base Model", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/UserV1", + "description": "The user who owns the Loops sampler." + } + }, + "required": [ + "id", + "base_model", + "user" + ], + "title": "DeactivateLoopsSamplerResponseV1", "type": "object" }, - "StopTrainingJobResponseV1": { - "description": "A response to stopping a training job.", + "GetLoopsSamplerResponseV1": { + "description": "Response for ``GET /v1/loops/samplers/``.", "properties": { - "training_job": { - "$ref": "#/components/schemas/TrainingJobV1", - "description": "The stopped training job." + "sampler": { + "$ref": "#/components/schemas/LoopsSamplerV1", + "description": "The Loops sampler." } }, "required": [ - "training_job" + "sampler" ], - "title": "StopTrainingJobResponseV1", + "title": "GetLoopsSamplerResponseV1", "type": "object" }, - "TrainingJobCheckpointV1": { - "description": "A checkpoint for a training job.", + "LoopsCheckpointV1": { + "description": "A checkpoint saved by a Loops run.", "properties": { "checkpoint_id": { "description": "The ID of the checkpoint.", @@ -21365,10 +26220,19 @@ "description": "Sync state of the checkpoint: SYNCING or COMPLETE.", "title": "Sync Status" }, - "training_job_id": { - "description": "The ID of the training job.", - "title": "Training Job Id", + "id": { + "description": "The checkpoint ID.", + "title": "Id", + "type": "string" + }, + "run_id": { + "description": "The ID of the run that produced the checkpoint.", + "title": "Run Id", "type": "string" + }, + "target": { + "$ref": "#/components/schemas/TrainerCheckpointTarget", + "description": "Whether this checkpoint is loadable by the sampler or by the run." } }, "required": [ @@ -21378,69 +26242,179 @@ "base_model", "lora_adapter_config", "size_bytes", - "training_job_id" + "id", + "run_id", + "target" ], - "title": "TrainingJobCheckpointV1", + "title": "LoopsCheckpointV1", "type": "object" }, - "GetTrainingJobCheckpointsResponseV1": { - "description": "A response to fetch checkpoints for a training job.", + "TrainerCheckpointTarget": { + "description": "Whether a TrainerServerCheckpoint is loadable by the sampler or the trainer.\n\nSAMPLER checkpoints are consumed by the sampling server for inference;\nTRAINER checkpoints capture full trainer state for resuming training.\nMirrored in the bt:// URI as\n``bt://loops:/(sampler_weights|weights)/``.", + "enum": [ + "sampler", + "trainer" + ], + "title": "TrainerCheckpointTarget", + "type": "string" + }, + "ListLoopsCheckpointsResponseV1": { + "description": "Checkpoints matching the query filter.", "properties": { - "training_job": { - "$ref": "#/components/schemas/TrainingJobV1", - "description": "The training job." - }, "checkpoints": { - "description": "The checkpoints for the training job.", + "description": "Matching checkpoints.", "items": { - "$ref": "#/components/schemas/TrainingJobCheckpointV1" + "$ref": "#/components/schemas/LoopsCheckpointV1" }, "title": "Checkpoints", "type": "array" } }, "required": [ - "training_job", "checkpoints" ], - "title": "GetTrainingJobCheckpointsResponseV1", + "title": "ListLoopsCheckpointsResponseV1", "type": "object" }, - "CheckpointFile": { + "ListLoopsCheckpointsQueryParamsV1": { + "description": "Query-string filters for ``GET /v1/loops/checkpoints``.\n\nProvide exactly one of ``run_id`` (all checkpoints for the run),\n``base_model`` (all checkpoints across the caller's runs of that\nbase model), or ``checkpoint_path`` (the single matching checkpoint).", "properties": { - "url": { - "title": "Url", + "run_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Filter by run ID. Returns all checkpoints saved by the run.", + "examples": [ + "k4q95w5" + ], + "title": "Run Id" + }, + "base_model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Filter by base model. Returns checkpoints across the caller's runs of this base model.", + "examples": [ + "Qwen/Qwen3-8B" + ], + "title": "Base Model" + }, + "checkpoint_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "bt:// URI of a Loops checkpoint. Form: bt://loops:/(weights|sampler_weights)/.", + "examples": [ + "bt://loops:k4q95w5/sampler_weights/step-100" + ], + "title": "Checkpoint Path" + } + }, + "title": "ListLoopsCheckpointsQueryParamsV1", + "type": "object" + }, + "ValidateLoopsCheckpointRequestV1": { + "description": "Request body for ``POST /v1/loops/checkpoints/validate``.", + "properties": { + "checkpoint_path": { + "description": "bt:// URI of a sampler checkpoint. Form: bt://loops:/sampler_weights/.", + "examples": [ + "bt://loops:k4q95w5/sampler_weights/step-100" + ], + "title": "Checkpoint Path", "type": "string" + } + }, + "required": [ + "checkpoint_path" + ], + "title": "ValidateLoopsCheckpointRequestV1", + "type": "object" + }, + "ValidateLoopsCheckpointResponseV1": { + "description": "Response for ``POST /v1/loops/checkpoints/validate``. Empty on success;\ninaccessible or malformed paths raise 400.", + "properties": {}, + "title": "ValidateLoopsCheckpointResponseV1", + "type": "object" + }, + "DeployLoopsCheckpointRequestV1": { + "properties": { + "checkpoint_ids": { + "description": "Sampler checkpoint IDs to deploy together.", + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Checkpoint Ids", + "type": "array" }, - "relative_file_name": { - "title": "Relative File Name", + "model_name": { + "description": "Name for the created model.", + "minLength": 1, + "title": "Model Name", "type": "string" }, - "node_rank": { - "title": "Node Rank", - "type": "integer" + "instance_type_id": { + "description": "Instance type ID for the deployment.", + "title": "Instance Type Id", + "type": "string" }, - "size_bytes": { - "title": "Size Bytes", - "type": "integer" + "hf_secret_name": { + "description": "Name of the team-scoped secret that supplies HF_TOKEN.", + "minLength": 1, + "title": "Hf Secret Name", + "type": "string" + } + }, + "required": [ + "checkpoint_ids", + "model_name", + "instance_type_id", + "hf_secret_name" + ], + "title": "DeployLoopsCheckpointRequestV1", + "type": "object" + }, + "DeployLoopsCheckpointResponseV1": { + "properties": { + "model_id": { + "description": "ID of the created or updated model.", + "title": "Model Id", + "type": "string" }, - "last_modified": { - "title": "Last Modified", + "deployment_id": { + "description": "ID of the created model version deployment.", + "title": "Deployment Id", "type": "string" } }, "required": [ - "url", - "relative_file_name", - "node_rank", - "size_bytes", - "last_modified" + "model_id", + "deployment_id" ], - "title": "CheckpointFile", + "title": "DeployLoopsCheckpointResponseV1", "type": "object" }, - "GetTrainingJobCheckpointFilesResponseV1": { - "description": "A response to fetch presigned URLs for checkpoint files of a training job.", + "LoopsCheckpointFilesResponseV1": { + "description": "Response with presigned URLs for files under a Loops checkpoint.", "properties": { "presigned_urls": { "description": "List of presigned URLs for checkpoint files.", @@ -21473,11 +26447,11 @@ "presigned_urls", "total_count" ], - "title": "GetTrainingJobCheckpointFilesResponseV1", + "title": "LoopsCheckpointFilesResponseV1", "type": "object" }, - "GetTrainingJobCheckpointFilesRequestV1": { - "description": "Pagination params for ``GET /v1/training_projects/.../checkpoint_files``.", + "GetLoopsCheckpointFilesRequestV1": { + "description": "Pagination params for ``GET /v1/loops/checkpoints//files``.", "properties": { "page_size": { "default": 1000, @@ -21494,47 +26468,101 @@ "type": "integer" } }, - "title": "GetTrainingJobCheckpointFilesRequestV1", + "title": "GetLoopsCheckpointFilesRequestV1", "type": "object" }, - "AuthCodeV1": { - "description": "Authentication code for a training job interactive session node.", + "LoopsCheckpointS3SourceV1": { + "description": "The checkpoint's files are fetched as presigned URLs, page by page.", "properties": { - "session_id": { - "description": "Unique identifier of the interactive session.", - "title": "Session Id", - "type": "string" - }, - "replica_id": { - "description": "Replica identifier in gXXrY format (e.g., 'g00r0' for group 0, replica 0).", - "title": "Replica Id", + "kind": { + "const": "s3", + "default": "s3", + "title": "Kind", "type": "string" - }, - "auth_code": { - "description": "The device authentication code (e.g., '4F64-C0D9').", - "title": "Auth Code", + } + }, + "title": "LoopsCheckpointS3SourceV1", + "type": "object" + }, + "LoopsCheckpointVolumeSourceV1": { + "description": "The checkpoint's files are pulled from a Baseten volume.", + "properties": { + "kind": { + "const": "volume", + "default": "volume", + "title": "Kind", "type": "string" }, - "auth_url": { - "description": "URL where the user should enter the auth code (e.g., 'https://github.com/login/device').", - "title": "Auth Url", + "volume_ref": { + "description": "Ref of the volume version holding the checkpoint, as `bdn:/:`.", + "title": "Volume Ref", "type": "string" }, - "generated_at": { - "anyOf": [ + "path": { + "description": "Directory inside that version holding the checkpoint's files.", + "title": "Path", + "type": "string" + } + }, + "required": [ + "volume_ref", + "path" + ], + "title": "LoopsCheckpointVolumeSourceV1", + "type": "object" + }, + "LoopsCheckpointSourceResponseV1": { + "description": "Where a checkpoint's files are fetched from, and how.", + "properties": { + "source": { + "description": "`s3` means the files endpoint serves presigned URLs for this checkpoint; `volume` carries the ref to pull instead.", + "discriminator": { + "mapping": { + "s3": "#/components/schemas/LoopsCheckpointS3SourceV1", + "volume": "#/components/schemas/LoopsCheckpointVolumeSourceV1" + }, + "propertyName": "kind" + }, + "oneOf": [ { - "format": "date-time", - "type": "string" + "$ref": "#/components/schemas/LoopsCheckpointS3SourceV1" }, { - "type": "null" + "$ref": "#/components/schemas/LoopsCheckpointVolumeSourceV1" } ], - "default": null, - "description": "When the auth code was generated, in ISO 8601 format.", - "title": "Generated At" + "title": "Source" + } + }, + "required": [ + "source" + ], + "title": "LoopsCheckpointSourceResponseV1", + "type": "object" + }, + "LoopsDeploymentStatusV1": { + "description": "Latest deployment status for a Loops deployment.", + "properties": { + "name": { + "$ref": "#/components/schemas/Name", + "description": "Latest status of the Loops deployment." + } + }, + "required": [ + "name" + ], + "title": "LoopsDeploymentStatusV1", + "type": "object" + }, + "LoopsDeploymentV1": { + "description": "A Loops deployment \u2014 the long-lived run + sampler pair owned by a user.\n\nThe deployment's current sampler is included inline. The full list of\nsamplers visible to the caller (across all deployments) lives at\n``GET /v1/loops/samplers``.", + "properties": { + "id": { + "description": "The Loops deployment ID.", + "title": "Id", + "type": "string" }, - "tunnel_name": { + "active_run_id": { "anyOf": [ { "type": "string" @@ -21544,13 +26572,12 @@ } ], "default": null, - "description": "The name of the tunnel node.", - "title": "Tunnel Name" + "description": "The ID of the run currently active on this deployment, if any. Null when the deployment's runs have been marked inactive (e.g. scale-to-zero) without a successor.", + "title": "Active Run Id" }, - "expires_at": { + "latest_run_id": { "anyOf": [ { - "format": "date-time", "type": "string" }, { @@ -21558,130 +26585,178 @@ } ], "default": null, - "description": "When the session expires, in ISO 8601 format.", - "title": "Expires At" + "description": "The ID of the most recent run on this deployment, active or not, so idle deployments still expose a usable run handle. Null only if the deployment has no runs.", + "title": "Latest Run Id" }, - "working_directory": { + "base_model": { + "description": "The HuggingFace base model the deployment is fine-tuning.", + "title": "Base Model", + "type": "string" + }, + "base_url": { + "description": "The run's base URL.", + "title": "Base Url", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/LoopsDeploymentStatusV1", + "description": "Latest deployment status." + }, + "user": { + "$ref": "#/components/schemas/UserV1", + "description": "The user who owns the Loops deployment." + }, + "created_at": { + "description": "Time the deployment was created in ISO 8601 format.", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "availability_model": { + "$ref": "#/components/schemas/V1AvailabilityModel", + "default": "dedicated", + "description": "Capacity the trainer was scheduled on." + }, + "instance_type": { + "$ref": "#/components/schemas/InstanceTypeV1", + "description": "Instance type backing the trainer." + }, + "node_count": { + "default": 1, + "description": "Number of nodes backing the trainer.", + "title": "Node Count", + "type": "integer" + }, + "sampler": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/LoopsSamplerV1" }, { "type": "null" } ], "default": null, - "description": "The working directory of the session.", - "title": "Working Directory" + "description": "The sampler bound to this deployment." } }, "required": [ - "session_id", - "replica_id", - "auth_code", - "auth_url" + "id", + "base_model", + "base_url", + "status", + "user", + "created_at", + "instance_type" ], - "title": "AuthCodeV1", + "title": "LoopsDeploymentV1", "type": "object" }, - "GetAuthCodesResponseV1": { - "description": "Response containing auth codes for all nodes of a training job's interactive sessions.", + "Name": { + "enum": [ + "CREATED", + "DEPLOYING", + "RUNNING", + "SCALED_TO_ZERO", + "FAILED", + "STOPPED", + "PREEMPTED" + ], + "title": "LoopsDeploymentStatus", + "type": "string" + }, + "ListLoopsDeploymentsResponseV1": { + "description": "Response for ``GET /v1/loops/deployments``.\n\nDefaults to the caller's own; pass ``?scope=org`` to list every deployment in\nthe caller's organization. Returns every deployment regardless of status;\nclients filter terminal states.", "properties": { - "auth_codes": { - "description": "List of auth codes for each node that has an active interactive session.", + "deployments": { + "description": "Active Loops deployments.", "items": { - "$ref": "#/components/schemas/AuthCodeV1" + "$ref": "#/components/schemas/LoopsDeploymentV1" }, - "title": "Auth Codes", + "title": "Deployments", "type": "array" } }, "required": [ - "auth_codes" + "deployments" ], - "title": "GetAuthCodesResponseV1", + "title": "ListLoopsDeploymentsResponseV1", "type": "object" }, - "PatchInteractiveSessionRequestV1": { - "description": "Request to patch an interactive session.\n\nOnly fields that are provided (non-None) will be applied.", + "ListLoopsDeploymentsRequestV1": { + "description": "Query-string filters for ``GET /v1/loops/deployments``.", "properties": { - "timeout_minutes": { + "scope": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "For on_startup sessions, minutes to add to the expiration. For on_demand/on_failure sessions, minutes to add to the timeout. Use -1 for infinite timeout (bumps by 10 years).", - "title": "Timeout Minutes" - }, - "trigger": { - "anyOf": [ - { - "$ref": "#/components/schemas/V1InteractiveSessionTrigger" - }, - { - "type": "null" - } + "description": "Defaults to the caller's own deployments; pass 'org' to list every deployment in the caller's organization.", + "examples": [ + "org" ], - "default": null, - "description": "Update when the interactive session is created. Cannot be changed if the session trigger is 'on_startup'." + "title": "Scope" } }, - "title": "PatchInteractiveSessionRequestV1", + "title": "ListLoopsDeploymentsRequestV1", "type": "object" }, - "InteractiveSessionV1": { - "description": "Representation of a training job interactive session.", + "DeactivateLoopsDeploymentResponseV1": { + "description": "Response for ``POST /v1/loops/deployments//deactivate``.", "properties": { "id": { - "description": "Unique identifier of the interactive session.", + "description": "The deactivated Loops deployment ID.", "title": "Id", "type": "string" }, - "trigger": { - "description": "When the interactive session is created.", - "title": "Trigger", - "type": "string" - }, - "timeout_minutes": { - "description": "Minutes before the session times out.", - "title": "Timeout Minutes", - "type": "integer" - }, - "session_provider": { - "description": "The IDE client for the session.", - "title": "Session Provider", - "type": "string" - }, - "auth_provider": { - "description": "The authentication provider for the session.", - "title": "Auth Provider", - "type": "string" - }, - "pod_name": { - "description": "Pod name / node rank for the session.", - "title": "Pod Name", + "base_model": { + "description": "The base model whose Loops deployment was deactivated.", + "title": "Base Model", "type": "string" }, - "expires_at": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "When the session expires, in ISO 8601 format.", - "title": "Expires At" + "user": { + "$ref": "#/components/schemas/UserV1", + "description": "The user who owned the Loops deployment." + } + }, + "required": [ + "id", + "base_model", + "user" + ], + "title": "DeactivateLoopsDeploymentResponseV1", + "type": "object" + }, + "GetLoopsDeploymentResponseV1": { + "description": "Response for ``GET /v1/loops/deployments/``.", + "properties": { + "deployment": { + "$ref": "#/components/schemas/LoopsDeploymentV1", + "description": "The Loops deployment." + } + }, + "required": [ + "deployment" + ], + "title": "GetLoopsDeploymentResponseV1", + "type": "object" + }, + "LoopsDebugArchiveFilesResponseV1": { + "description": "Response with presigned URLs for a Loops deployment's debug archive.", + "properties": { + "presigned_urls": { + "items": { + "$ref": "#/components/schemas/CheckpointFile" + }, + "title": "Presigned Urls", + "type": "array" }, - "tunnel_name": { + "next_page_token": { "anyOf": [ { "type": "string" @@ -21691,10 +26766,27 @@ } ], "default": null, - "description": "The tunnel name for the session.", - "title": "Tunnel Name" + "title": "Next Page Token" + } + }, + "required": [ + "presigned_urls" + ], + "title": "LoopsDebugArchiveFilesResponseV1", + "type": "object" + }, + "GetLoopsDebugArchiveFilesRequestV1": { + "description": "Pagination params for a Loops deployment debug archive.", + "properties": { + "page_size": { + "default": 1000, + "description": "Max files per page (default and maximum 1000).", + "maximum": 1000, + "minimum": 1, + "title": "Page Size", + "type": "integer" }, - "auth_code": { + "page_token": { "anyOf": [ { "type": "string" @@ -21704,440 +26796,599 @@ } ], "default": null, - "description": "The device authentication code.", - "title": "Auth Code" - }, - "auth_url": { + "description": "Opaque token for the next page.", + "title": "Page Token" + } + }, + "title": "GetLoopsDebugArchiveFilesRequestV1", + "type": "object" + }, + "GetLoopsDeploymentMetricsRequestV1": { + "description": "Time-range request for trainer deployment metrics.", + "properties": { + "end_epoch_millis": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "URL where the user should enter the auth code.", - "title": "Auth Url" + "description": "Epoch millis to end fetching metrics.", + "title": "End Epoch Millis" }, - "auth_code_generated_at": { + "start_epoch_millis": { "anyOf": [ { - "format": "date-time", - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "When the auth code was generated.", - "title": "Auth Code Generated At" + "description": "Epoch millis to start fetching metrics.", + "title": "Start Epoch Millis" }, - "authenticated_at": { + "step_seconds": { "anyOf": [ { - "format": "date-time", - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "When the session was authenticated.", - "title": "Authenticated At" + "description": "Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", + "title": "Step Seconds" }, - "working_directory": { + "time_divisor_seconds": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "The working directory of the session.", - "title": "Working Directory" + "description": "Unit of time for request-volume metrics, in seconds (e.g. 60 for requests/minute). Defaults to per-second.", + "title": "Time Divisor Seconds" } }, - "required": [ - "id", - "trigger", - "timeout_minutes", - "session_provider", - "auth_provider", - "pod_name" - ], - "title": "InteractiveSessionV1", + "title": "GetLoopsDeploymentMetricsRequestV1", "type": "object" }, - "PatchInteractiveSessionResponseV1": { - "description": "Response after patching an interactive session.", + "InferenceVolumeByStatusDatapointV1": { + "description": "Request rate split by HTTP response code class.", "properties": { - "interactive_session": { - "$ref": "#/components/schemas/InteractiveSessionV1", - "description": "The updated interactive session." - }, - "message": { - "description": "Human-readable summary of what was updated.", - "title": "Message", + "timestamp": { + "description": "ISO 8601 timestamp.", + "format": "date-time", + "title": "Timestamp", "type": "string" + }, + "status_2xx": { + "description": "2xx requests per second.", + "title": "Status 2Xx", + "type": "number" + }, + "status_4xx": { + "description": "4xx requests per second.", + "title": "Status 4Xx", + "type": "number" + }, + "status_5xx": { + "description": "5xx requests per second.", + "title": "Status 5Xx", + "type": "number" } }, "required": [ - "interactive_session", - "message" + "timestamp", + "status_2xx", + "status_4xx", + "status_5xx" ], - "title": "PatchInteractiveSessionResponseV1", + "title": "InferenceVolumeByStatusDatapointV1", "type": "object" }, - "FileSummary": { - "description": "Information about a file in the cache.", + "LoopsDeploymentMetricsV1": { + "description": "Metrics for a trainer (Loops) deployment.\n\nService-level fields summarize HTTP traffic into the trainer pods (the\nKnative queue-proxy is the source). Compute fields are the leader-pod\naggregate; ``per_node_metrics`` carries the full multinode breakdown.", "properties": { - "path": { - "description": "Relative path of the file in the cache", - "title": "Path", - "type": "string" + "inference_volume": { + "description": "Number of inference requests per unit time (requests per second).", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Inference Volume", + "type": "array" }, - "size_bytes": { - "description": "Size of the file in bytes", - "title": "Size Bytes", - "type": "integer" + "concurrent_requests": { + "description": "Number of in-progress concurrent inference requests. Source: the queue-proxy ``revision_queue_depth`` gauge on ``http-usermetric``.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Concurrent Requests", + "type": "array" }, - "modified": { - "description": "Last modification time of the file", - "title": "Modified", - "type": "string" + "response_time_stats": { + "description": "Percentiles of the response time distribution.", + "items": { + "$ref": "#/components/schemas/ResponseTimeDatapointV1" + }, + "title": "Response Time Stats", + "type": "array" }, - "file_type": { - "description": "Type of the file", - "title": "File Type", - "type": "string" + "inference_volume_by_status": { + "description": "Request rate split by response code class.", + "items": { + "$ref": "#/components/schemas/InferenceVolumeByStatusDatapointV1" + }, + "title": "Inference Volume By Status", + "type": "array" }, - "permissions": { - "description": "Permissions of the file", - "title": "Permissions", - "type": "string" + "gpu_memory_usage_bytes": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "Leader-pod GPU memory bytes per GPU rank.", + "title": "Gpu Memory Usage Bytes", + "type": "object" + }, + "gpu_utilization": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "Leader-pod fractional GPU utilization per GPU rank.", + "title": "Gpu Utilization", + "type": "object" + }, + "cpu_usage": { + "description": "Leader-pod CPU usage in cores.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Cpu Usage", + "type": "array" + }, + "cpu_memory_usage_bytes": { + "description": "Leader-pod CPU memory usage bytes.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Cpu Memory Usage Bytes", + "type": "array" + }, + "ephemeral_storage": { + "$ref": "#/components/schemas/StorageMetricsV1", + "description": "Leader-pod ephemeral storage usage." + }, + "per_node_metrics": { + "description": "Per-node compute breakdown for multinode trainer deployments.", + "items": { + "$ref": "#/components/schemas/LoopsDeploymentNodeMetricsV1" + }, + "title": "Per Node Metrics", + "type": "array" } }, "required": [ - "path", - "size_bytes", - "modified", - "file_type", - "permissions" + "inference_volume", + "concurrent_requests", + "response_time_stats", + "inference_volume_by_status", + "gpu_memory_usage_bytes", + "gpu_utilization", + "cpu_usage", + "cpu_memory_usage_bytes", + "ephemeral_storage", + "per_node_metrics" ], - "title": "FileSummary", + "title": "LoopsDeploymentMetricsV1", "type": "object" }, - "GetCacheSummaryResponseV1": { - "description": "Response for getting cache summary.", + "LoopsDeploymentNodeMetricsV1": { + "description": "Per-node compute metrics for a multinode trainer deployment.", "properties": { - "timestamp": { - "description": "Timestamp when the cache summary was captured", - "title": "Timestamp", + "node_id": { + "description": "Identifier for the node.", + "title": "Node Id", "type": "string" }, - "project_id": { - "description": "Project ID associated with the cache", - "title": "Project Id", - "type": "string" + "gpu_memory_usage_bytes": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "GPU memory usage bytes per GPU rank.", + "title": "Gpu Memory Usage Bytes", + "type": "object" }, - "file_summaries": { - "description": "List of files in the cache", + "gpu_utilization": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "type": "array" + }, + "description": "Fractional GPU utilization per GPU rank.", + "title": "Gpu Utilization", + "type": "object" + }, + "cpu_usage": { + "description": "CPU usage in cores.", "items": { - "$ref": "#/components/schemas/FileSummary" + "$ref": "#/components/schemas/TrainingJobMetricV1" }, - "title": "File Summaries", + "title": "Cpu Usage", + "type": "array" + }, + "cpu_memory_usage_bytes": { + "description": "CPU memory usage bytes.", + "items": { + "$ref": "#/components/schemas/TrainingJobMetricV1" + }, + "title": "Cpu Memory Usage Bytes", "type": "array" + }, + "ephemeral_storage": { + "$ref": "#/components/schemas/StorageMetricsV1", + "description": "Ephemeral storage usage." } }, "required": [ - "timestamp", - "project_id", - "file_summaries" + "node_id", + "gpu_memory_usage_bytes", + "gpu_utilization", + "cpu_usage", + "cpu_memory_usage_bytes", + "ephemeral_storage" ], - "title": "GetCacheSummaryResponseV1", + "title": "LoopsDeploymentNodeMetricsV1", "type": "object" }, - "TrainingProjectTombstoneV1": { - "description": "A training project tombstone.", + "ResponseTimeDatapointV1": { + "description": "Latency quantile datapoint. Values are reported in milliseconds.", "properties": { - "id": { - "description": "Unique identifier of the training project", - "title": "Id", + "timestamp": { + "description": "ISO 8601 timestamp.", + "format": "date-time", + "title": "Timestamp", "type": "string" }, - "deleted": { - "description": "Whether the training project was deleted", - "title": "Deleted", - "type": "boolean" - } - }, - "required": [ - "id", - "deleted" - ], - "title": "TrainingProjectTombstoneV1", - "type": "object" - }, - "GetTrainingProjectResponseV1": { - "description": "A response to getting a training project.", - "properties": { - "training_project": { - "$ref": "#/components/schemas/TrainingProjectV1", - "description": "The training project." + "p50": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "50th percentile request latency (milliseconds).", + "title": "P50" + }, + "p95": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "95th percentile request latency (milliseconds).", + "title": "P95" + }, + "p99": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "99th percentile request latency (milliseconds).", + "title": "P99" } }, "required": [ - "training_project" + "timestamp" ], - "title": "GetTrainingProjectResponseV1", + "title": "ResponseTimeDatapointV1", "type": "object" }, - "OrderByV1": { - "description": "A request to order training jobs.", + "GetLoopsDeploymentMetricsResponseV1": { + "description": "Response for ``POST /v1/loops/deployments//metrics``.", "properties": { - "field": { - "description": "The field to order by.", - "examples": [ - "created_at" - ], - "title": "Field", + "deployment_id": { + "description": "The trainer deployment ID.", + "title": "Deployment Id", "type": "string" }, - "order": { - "description": "The direction to order by.", - "examples": [ - "asc", - "desc" - ], - "title": "Order", - "type": "string" + "metrics": { + "$ref": "#/components/schemas/LoopsDeploymentMetricsV1", + "description": "Metrics for the deployment." } }, "required": [ - "field", - "order" + "deployment_id", + "metrics" ], - "title": "OrderByV1", + "title": "GetLoopsDeploymentMetricsResponseV1", "type": "object" }, - "SearchTrainingJobsRequestV1": { - "description": "A request to search training jobs.", + "GetLoopsDeploymentLogsRequestV1": { + "description": "Query parameters for fetching a Loops deployment's logs.", "properties": { - "project_id": { + "start_epoch_millis": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Filter the training jobs by project ID.", - "examples": [ - "n4q95w5" + "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", + "title": "Start Epoch Millis" + }, + "end_epoch_millis": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } ], - "title": "Project Id" + "default": null, + "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", + "title": "End Epoch Millis" }, - "job_id": { + "direction": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SortOrderV1" }, { "type": "null" } ], "default": null, - "description": "Filter the training jobs by job ID.", - "examples": [ - "p7qr9qv" + "description": "Sort order for logs" + }, + "limit": { + "anyOf": [ + { + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } ], - "title": "Job Id" + "default": 500, + "description": "Limit of logs to fetch in a single request", + "title": "Limit" }, - "statuses": { + "min_level": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "$ref": "#/components/schemas/LogLevelV1" }, { "type": "null" } ], "default": null, - "description": "Filter the training jobs by status.", - "examples": [ - [ - "TRAINING_JOB_RUNNING", - "TRAINING_JOB_COMPLETED" - ] - ], - "title": "Statuses" + "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." + } + }, + "title": "GetLoopsDeploymentLogsRequestV1", + "type": "object" + }, + "TeamTrainingGpuCapacityItemV1": { + "description": "Per-team GPU capacity and current usage for one GPU type.", + "properties": { + "team_id": { + "description": "Team identifier", + "title": "Team Id", + "type": "string" + }, + "team_name": { + "description": "Team name", + "title": "Team Name", + "type": "string" + }, + "gpu_type": { + "description": "GPU type identifier (e.g. H100, A100-40GB)", + "title": "Gpu Type", + "type": "string" + }, + "baseline": { + "description": "Baseline GPU allocation for the team. 0 if not configured.", + "title": "Baseline", + "type": "integer" + }, + "limit": { + "description": "Maximum concurrent GPUs of this type for this team", + "title": "Limit", + "type": "integer" }, - "order_by": { - "default": [ - { - "field": "created_at", - "order": "desc" - } - ], - "description": "Order the training jobs by a field. Currently supports created_at", - "items": { - "$ref": "#/components/schemas/OrderByV1" - }, - "title": "Order By", - "type": "array" - } - }, - "title": "SearchTrainingJobsRequestV1", - "type": "object" - }, - "SearchTrainingJobsResponseV1": { - "description": "A response to search training jobs.", - "properties": { - "training_jobs": { - "description": "List of training jobs.", - "items": { - "$ref": "#/components/schemas/TrainingJobV1" - }, - "title": "Training Jobs", - "type": "array" + "usage_count": { + "description": "GPUs currently in use by the team's active training jobs", + "title": "Usage Count", + "type": "integer" + }, + "dedicated_usage_count": { + "default": 0, + "description": "Portion of usage_count from dedicated (on-demand) jobs.", + "title": "Dedicated Usage Count", + "type": "integer" + }, + "spot_usage_count": { + "default": 0, + "description": "Portion of usage_count from spot jobs.", + "title": "Spot Usage Count", + "type": "integer" } }, "required": [ - "training_jobs" + "team_id", + "team_name", + "gpu_type", + "baseline", + "limit", + "usage_count" ], - "title": "SearchTrainingJobsResponseV1", + "title": "TeamTrainingGpuCapacityItemV1", "type": "object" }, - "SupportedModelV1": { - "description": "A model supported by the Loops server.", + "TrainingGpuCapacityItemV1": { + "description": "GPU capacity and current usage for one GPU type.", "properties": { - "model_name": { - "description": "The name of the supported model.", - "title": "Model Name", + "gpu_type": { + "description": "GPU type identifier (e.g. H100, A100-40GB)", + "title": "Gpu Type", "type": "string" }, - "max_context_length": { - "description": "The maximum context length (in tokens) supported by this model.", - "title": "Max Context Length", + "baseline": { + "description": "Baseline GPU allocation; jobs below this threshold are expected to run immediately. 0 if not configured.", + "title": "Baseline", "type": "integer" }, - "supports_vision_language": { - "description": "Whether the model accepts image inputs alongside text.", - "title": "Supports Vision Language", - "type": "boolean" + "limit": { + "description": "Maximum concurrent GPUs of this type for this org", + "title": "Limit", + "type": "integer" + }, + "usage_count": { + "description": "GPUs currently in use by active training jobs", + "title": "Usage Count", + "type": "integer" + }, + "dedicated_usage_count": { + "default": 0, + "description": "Portion of usage_count from dedicated (on-demand) jobs, which run against the baseline.", + "title": "Dedicated Usage Count", + "type": "integer" + }, + "spot_usage_count": { + "default": 0, + "description": "Portion of usage_count from spot jobs, which burst into the peak and may push usage above the limit.", + "title": "Spot Usage Count", + "type": "integer" } }, "required": [ - "model_name", - "max_context_length", - "supports_vision_language" + "gpu_type", + "baseline", + "limit", + "usage_count" ], - "title": "SupportedModelV1", + "title": "TrainingGpuCapacityItemV1", "type": "object" }, - "GetLoopsCapabilitiesResponseV1": { - "description": "Response for ``GET /v1/loops/capabilities``.", + "GetTrainingGpuCapacityResponseV1": { + "description": "Response for the training GPU capacity endpoint.", "properties": { - "supported_models": { - "description": "List of models available on the server.", + "gpu_capacities": { + "description": "Org-level GPU capacity limits and current usage per GPU type", "items": { - "$ref": "#/components/schemas/SupportedModelV1" + "$ref": "#/components/schemas/TrainingGpuCapacityItemV1" }, - "title": "Supported Models", + "title": "Gpu Capacities", + "type": "array" + }, + "team_gpu_capacities": { + "description": "Per-team GPU capacity limits and current usage per GPU type", + "items": { + "$ref": "#/components/schemas/TeamTrainingGpuCapacityItemV1" + }, + "title": "Team Gpu Capacities", "type": "array" } }, "required": [ - "supported_models" + "gpu_capacities" ], - "title": "GetLoopsCapabilitiesResponseV1", + "title": "GetTrainingGpuCapacityResponseV1", "type": "object" }, - "LoopsSessionV1": { + "PatchTeamTrainingGpuCapacityRequestV1": { + "description": "A request to set the GPU capacity ceiling for a (team, gpu_type) pair.\n\nCreates the limit if one doesn't already exist for this team and GPU type,\notherwise updates it in place.", "properties": { - "id": { - "title": "Id", + "team_id": { + "description": "Team identifier", + "title": "Team Id", "type": "string" + }, + "gpu_type": { + "description": "GPU type identifier (e.g. H100, A100-40GB)", + "title": "Gpu Type", + "type": "string" + }, + "max_gpus": { + "description": "Max concurrent GPUs of this type the team may use", + "examples": [ + 8, + 16, + 32 + ], + "title": "Max Gpus", + "type": "integer" } }, "required": [ - "id" - ], - "title": "LoopsSessionV1", - "type": "object" - }, - "CreateLoopsSessionResponseV1": { - "properties": { - "session": { - "$ref": "#/components/schemas/LoopsSessionV1" - } - }, - "required": [ - "session" - ], - "title": "CreateLoopsSessionResponseV1", - "type": "object" - }, - "GetLoopsSessionResponseV1": { - "description": "Response for ``GET /v1/loops/sessions/``.", - "properties": { - "session": { - "$ref": "#/components/schemas/LoopsSessionV1", - "description": "The Loops session." - } - }, - "required": [ - "session" + "team_id", + "gpu_type", + "max_gpus" ], - "title": "GetLoopsSessionResponseV1", + "title": "PatchTeamTrainingGpuCapacityRequestV1", "type": "object" }, - "LoopsRunStatusNameV1": { - "description": "A Loops run's lifecycle state: ACTIVE or INACTIVE.", - "enum": [ - "ACTIVE", - "INACTIVE" - ], - "title": "LoopsRunStatusNameV1", - "type": "string" - }, - "LoopsRunStatusV1": { - "description": "The current status of a Loops run.", + "PatchTeamTrainingGpuCapacityResponseV1": { + "description": "Response for setting a team's GPU capacity ceiling.", "properties": { - "name": { - "$ref": "#/components/schemas/LoopsRunStatusNameV1", - "description": "ACTIVE while the run is live; INACTIVE once replaced by a newer run or shut down." + "team_gpu_capacity": { + "$ref": "#/components/schemas/TeamTrainingGpuCapacityItemV1", + "description": "The updated per-team GPU capacity limit" } }, "required": [ - "name" + "team_gpu_capacity" ], - "title": "LoopsRunStatusV1", + "title": "PatchTeamTrainingGpuCapacityResponseV1", "type": "object" }, - "LoopsRunV1": { + "ActiveJobAtSubmitV1": { + "description": "One other job in the same (org, gpu_type) pool that was holding GPU\ncapacity at the moment the target was submitted.", "properties": { - "id": { - "description": "The run ID.", - "title": "Id", - "type": "string" - }, - "session_id": { - "description": "The session ID this run belongs to.", - "title": "Session Id", + "training_job_id": { + "description": "Hashid of the other training job", + "title": "Training Job Id", "type": "string" }, - "deployment_id": { + "training_job_name": { "anyOf": [ { "type": "string" @@ -22147,171 +27398,150 @@ } ], "default": null, - "description": "The ID of the Loops deployment the run executes on, if it has one.", - "title": "Deployment Id" + "description": "Other job's name", + "title": "Training Job Name" }, - "name": { - "description": "The run's display name.", - "title": "Name", + "instance_type_name": { + "description": "Instance type of the other job", + "title": "Instance Type Name", "type": "string" }, - "base_model": { - "description": "The HuggingFace base model the run is fine-tuning.", - "title": "Base Model", + "total_gpus": { + "description": "gpu_count * effective_node_count", + "title": "Total Gpus", + "type": "integer" + }, + "workload_plane_name": { + "description": "Workload plane the other job was on", + "title": "Workload Plane Name", "type": "string" }, - "base_url": { - "description": "The run's base URL.", - "title": "Base Url", + "status_at_submit": { + "description": "Other job's status as of submitted_at (one of ACTIVE_STATES)", + "title": "Status At Submit", "type": "string" }, - "created_at": { - "description": "Time the run was created in ISO 8601 format", + "status_set_at": { + "description": "When that status was set", "format": "date-time", - "title": "Created At", + "title": "Status Set At", + "type": "string" + } + }, + "required": [ + "training_job_id", + "instance_type_name", + "total_gpus", + "workload_plane_name", + "status_at_submit", + "status_set_at" + ], + "title": "ActiveJobAtSubmitV1", + "type": "object" + }, + "CapacityAtSubmitV1": { + "description": "A GPU capacity row as it stands now, with ``last_modified`` so callers\ncan judge whether the value matches what the dequeue gate saw at submit\ntime. Capacity rows are not historicized: edits overwrite in place. Compare\n``last_modified`` against the response's ``submitted_at`` \u2014 if it's later,\nthe value may have changed.", + "properties": { + "gpu_type": { + "description": "GPU type identifier (e.g. H100, A100-40GB)", + "title": "Gpu Type", "type": "string" }, - "status": { - "$ref": "#/components/schemas/LoopsRunStatusV1", - "description": "The run's current status." - }, - "user": { - "$ref": "#/components/schemas/UserV1", - "description": "The user who owns the run." + "max_gpus": { + "description": "Current max concurrent GPUs of this type", + "title": "Max Gpus", + "type": "integer" }, - "sampler": { + "min_gpus": { "anyOf": [ { - "$ref": "#/components/schemas/LoopsSamplerV1" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "The sampler bound to this run, or null for a trainer-only run that has not yet created a sampler." - } - }, - "required": [ - "id", - "session_id", - "name", - "base_model", - "base_url", - "created_at", - "status", - "user" - ], - "title": "LoopsRunV1", - "type": "object" - }, - "LoopsSamplerStatusV1": { - "description": "The current status of a Loops sampler.", - "properties": { - "name": { - "$ref": "#/components/schemas/DeploymentStatusV1", - "description": "The current status of the Loops sampler." + "description": "Current baseline GPU allocation, if configured", + "title": "Min Gpus" + }, + "last_modified": { + "description": "When the capacity row was last modified", + "format": "date-time", + "title": "Last Modified", + "type": "string" } }, "required": [ - "name" + "gpu_type", + "max_gpus", + "last_modified" ], - "title": "LoopsSamplerStatusV1", + "title": "CapacityAtSubmitV1", "type": "object" }, - "LoopsSamplerV1": { + "PendingJobAheadAtSubmitV1": { + "description": "A PENDING job in the same (org, gpu_type) pool that was ahead of the\ntarget in dequeue FIFO order at submitted_at \u2014 higher priority, or same\npriority and earlier submission.", "properties": { - "id": { - "title": "Id", - "type": "string" - }, - "base_url": { - "title": "Base Url", - "type": "string" - }, - "base_model": { - "description": "The HuggingFace base model the sampler is serving.", - "title": "Base Model", - "type": "string" - }, - "created_at": { - "description": "Time the sampler was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "model_id": { - "description": "Hashid of the underlying Baseten model.", - "title": "Model Id", - "type": "string" - }, - "deployment_id": { - "description": "Hashid of the specific model deployment (version).", - "title": "Deployment Id", + "training_job_id": { + "description": "Hashid of the other training job", + "title": "Training Job Id", "type": "string" }, - "status": { - "$ref": "#/components/schemas/LoopsSamplerStatusV1", - "description": "The sampler's current status." - }, - "user": { - "$ref": "#/components/schemas/UserV1", - "description": "The user who owns the sampler." - }, - "instance_type": { + "training_job_name": { "anyOf": [ { - "$ref": "#/components/schemas/InstanceTypeV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Instance type serving the sampler." + "description": "Other job's name", + "title": "Training Job Name" }, - "node_count": { - "default": 1, - "description": "Number of nodes serving the sampler.", - "title": "Node Count", + "instance_type_name": { + "description": "Instance type of the other job", + "title": "Instance Type Name", + "type": "string" + }, + "requested_gpus": { + "description": "gpu_count * effective_node_count", + "title": "Requested Gpus", "type": "integer" + }, + "priority": { + "description": "Effective priority (NULL coalesced to 0)", + "title": "Priority", + "type": "integer" + }, + "submitted_at": { + "description": "The other job's submission time", + "format": "date-time", + "title": "Submitted At", + "type": "string" } }, "required": [ - "id", - "base_url", - "base_model", - "created_at", - "model_id", - "deployment_id", - "status", - "user" - ], - "title": "LoopsSamplerV1", - "type": "object" - }, - "ListLoopsRunsResponseV1": { - "description": "Runs matching the query filters.", - "properties": { - "runs": { - "description": "List of runs.", - "items": { - "$ref": "#/components/schemas/LoopsRunV1" - }, - "title": "Runs", - "type": "array" - } - }, - "required": [ - "runs" + "training_job_id", + "instance_type_name", + "requested_gpus", + "priority", + "submitted_at" ], - "title": "ListLoopsRunsResponseV1", + "title": "PendingJobAheadAtSubmitV1", "type": "object" }, - "ListLoopsRunsQueryParamsV1": { - "description": "Query-string filters for ``GET /v1/loops/runs``.\n\nAll filters are optional and can be combined; omit them to list the caller's\nown runs. Pass ``scope=org`` to list every run in the caller's organization\ninstead.", + "QueueEventV1": { + "description": "A single ``TrainingJobStatus`` row inside the queue-context window.", "properties": { - "run_id": { + "training_job_id": { + "description": "Hashid of the training job this event is for", + "title": "Training Job Id", + "type": "string" + }, + "training_job_name": { "anyOf": [ { "type": "string" @@ -22321,13 +27551,21 @@ } ], "default": null, - "description": "Filter by run ID.", - "examples": [ - "k4q95w5" - ], - "title": "Run Id" + "description": "Job name", + "title": "Training Job Name" }, - "base_model": { + "status": { + "description": "TrainingJobStatus.Name value", + "title": "Status", + "type": "string" + }, + "created": { + "description": "When the status row was inserted", + "format": "date-time", + "title": "Created", + "type": "string" + }, + "event_message": { "anyOf": [ { "type": "string" @@ -22337,279 +27575,206 @@ } ], "default": null, - "description": "Filter runs by base model name.", - "examples": [ - "Qwen/Qwen3-8B" - ], - "title": "Base Model" + "description": "Human-readable event message from the status metadata", + "title": "Event Message" }, - "scope": { + "exit_code": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Defaults to the caller's own runs; pass 'org' to list every run in the caller's organization.", - "examples": [ - "org" - ], - "title": "Scope" + "description": "Exit code from the status metadata, if any", + "title": "Exit Code" } }, - "title": "ListLoopsRunsQueryParamsV1", + "required": [ + "training_job_id", + "status", + "created" + ], + "title": "QueueEventV1", "type": "object" }, - "CreateLoopsRunRequestV1": { + "GetTrainingJobQueueContextResponseV1": { + "description": "Read-only diagnostic for a training job's PENDING window.\n\nReturns the (org, gpu_type) capacity pool the job was gated by, jobs that\nwere holding GPU capacity in that pool when this job was submitted, and\nevery status event in [submitted_at, released_at] for those jobs (or up to\n\"now\" if the target is still PENDING).", "properties": { - "session_id": { - "description": "ID of the Loops session this run belongs to.", - "title": "Session Id", - "type": "string" - }, - "base_model": { - "description": "Base model ID (e.g. 'Qwen/Qwen3-8B').", - "title": "Base Model", - "type": "string" - }, - "name": { - "anyOf": [ - { - "maxLength": 255, - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Optional display name for the run. Defaults to the base model name when omitted.", - "title": "Name" + "target_job_id": { + "description": "Hashid of the target training job", + "title": "Target Job Id", + "type": "string" }, - "max_seq_len": { + "target_job_name": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Maximum prompt length (in tokens) the run must handle. Set this to the longest training example you plan to send. Defaults to the maximum supported by the model configuration.", - "title": "Max Seq Len" + "description": "Target job's name", + "title": "Target Job Name" }, - "lora_rank": { - "default": 64, - "description": "LoRA rank.", - "minimum": 1, - "title": "Lora Rank", + "gpu_type": { + "description": "GPU type the target requested", + "title": "Gpu Type", + "type": "string" + }, + "requested_gpus": { + "description": "GPUs the target requested (gpu_count * effective_node_count)", + "title": "Requested Gpus", "type": "integer" }, - "seed": { + "submitted_at": { + "description": "When the job row was inserted (= API POST time)", + "format": "date-time", + "title": "Submitted At", + "type": "string" + }, + "released_at": { "anyOf": [ { - "type": "integer" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Random seed for reproducibility.", - "title": "Seed" - }, - "scale_down_delay_seconds": { - "default": 900, - "description": "Seconds of inactivity before the run scales to zero. Must be between 1 and 3600 (1 hour). Defaults to 900 (15 minutes).", - "exclusiveMinimum": 0, - "maximum": 3600, - "title": "Scale Down Delay Seconds", - "type": "integer" - }, - "availability_model": { - "$ref": "#/components/schemas/V1AvailabilityModel", - "default": "dedicated", - "description": "Capacity the trainer runs on. 'dedicated' is not preempted. 'spot' runs below inference and reaches idle reserved capacity, but the run is stopped if its GPUs are reclaimed and cannot be resumed.", - "examples": [ - "spot" - ] - }, - "replicas": { - "default": 1, - "description": "Number of data-parallel trainer replicas. Each replica is one full copy of the model's preset node group, so the trainer deployment runs (preset node_count * replicas) nodes (e.g. replicas=4 on a 4-node preset \u2192 16 nodes, 4 DP workers). Must be a positive integer. Defaults to 1.", - "minimum": 1, - "title": "Replicas", - "type": "integer" + "description": "When the job's TRAINING_JOB_CREATED status was set, i.e. the moment it was released from PENDING. None if still PENDING.", + "title": "Released At" }, - "path": { + "pending_seconds": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Optional bt:// URI of an existing checkpoint to load weights from on startup. Form: bt://loops:/weights/.", - "examples": [ - "bt://loops:k4q95w5/weights/step-100" - ], - "title": "Path" + "description": "released_at - submitted_at in seconds. None if still PENDING.", + "title": "Pending Seconds" }, - "reuse_from_run_id": { + "org_capacity": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/CapacityAtSubmitV1" }, { "type": "null" } ], "default": null, - "description": "Optional ID of a prior Loops run whose trainer and/or sampler should be reused for this run instead of provisioning fresh. The prior run must use the same base model and belong to the same team.", - "title": "Reuse From Run Id" + "description": "Org-level cap for (org, gpu_type). None if no cap is configured." }, - "reuse_from_session_id": { + "team_capacity": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/CapacityAtSubmitV1" }, { "type": "null" } ], "default": null, - "description": "Optional ID of a prior Loops session whose trainer and/or sampler should be reused for this run. Deprecated in favor of reuse_from_run_id.", - "title": "Reuse From Session Id" - } - }, - "required": [ - "session_id", - "base_model" - ], - "title": "CreateLoopsRunRequestV1", - "type": "object" - }, - "CreateLoopsRunResponseV1": { - "properties": { - "run": { - "$ref": "#/components/schemas/LoopsRunV1" - } - }, - "required": [ - "run" - ], - "title": "CreateLoopsRunResponseV1", - "type": "object" - }, - "DeactivateLoopsRunResponseV1": { - "description": "Response for ``POST /v1/loops/runs//deactivate``.", - "properties": { - "id": { - "description": "The deactivated Loops run ID.", - "title": "Id", - "type": "string" + "description": "Team-level cap for (team, gpu_type). None if no team cap is configured." }, - "base_model": { - "description": "The base model whose Loops run was deactivated.", - "title": "Base Model", - "type": "string" + "active_at_submit": { + "description": "Jobs in the same (org, gpu_type) pool that were holding capacity at submitted_at", + "items": { + "$ref": "#/components/schemas/ActiveJobAtSubmitV1" + }, + "title": "Active At Submit", + "type": "array" }, - "user": { - "$ref": "#/components/schemas/UserV1", - "description": "The user who owns the Loops run." - } - }, - "required": [ - "id", - "base_model", - "user" - ], - "title": "DeactivateLoopsRunResponseV1", - "type": "object" - }, - "GetLoopsRunResponseV1": { - "description": "Response for ``GET /v1/loops/runs/``.", - "properties": { - "run": { - "$ref": "#/components/schemas/LoopsRunV1", - "description": "The Loops run with its associated sampler." - } - }, - "required": [ - "run" - ], - "title": "GetLoopsRunResponseV1", - "type": "object" - }, - "ListLoopsSamplersResponseV1": { - "description": "Response for ``GET /v1/loops/samplers``.\n\nReturns the caller's samplers, including those paired to runs and\nstandalone samplers. Ordered newest-first.", - "properties": { - "samplers": { - "description": "List of samplers.", + "pending_ahead_at_submit": { + "description": "PENDING jobs in the same (org, gpu_type) pool that were ahead of the target in dequeue FIFO order at submitted_at (priority DESC then created ASC). These also block the target's release.", "items": { - "$ref": "#/components/schemas/LoopsSamplerV1" + "$ref": "#/components/schemas/PendingJobAheadAtSubmitV1" }, - "title": "Samplers", + "title": "Pending Ahead At Submit", + "type": "array" + }, + "events": { + "description": "Every status event in [submitted_at, events_window_end] for the target job, every job in active_at_submit, and every job in pending_ahead_at_submit, oldest first.", + "items": { + "$ref": "#/components/schemas/QueueEventV1" + }, + "title": "Events", "type": "array" + }, + "events_window_end": { + "description": "released_at if set, else 'now' (events ongoing)", + "format": "date-time", + "title": "Events Window End", + "type": "string" } }, "required": [ - "samplers" + "target_job_id", + "gpu_type", + "requested_gpus", + "submitted_at", + "active_at_submit", + "pending_ahead_at_submit", + "events", + "events_window_end" ], - "title": "ListLoopsSamplersResponseV1", + "title": "GetTrainingJobQueueContextResponseV1", "type": "object" }, - "ListLoopsSamplersRequestV1": { - "description": "Query-string filters for the Loops sampler listing routes.", + "GetBlobCredentialsResponseV1": { + "description": "Response to create a new set of credentials for blob upload.", "properties": { - "scope": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Defaults to the caller's own samplers; pass 'org' to include samplers owned by other users in the caller's organization.", - "examples": [ - "org" - ], - "title": "Scope" + "creds": { + "$ref": "#/components/schemas/AWSCredentialsV1", + "description": "The credentials to upload the blob to" + }, + "s3_key": { + "description": "The S3 key to upload the blob to", + "title": "S3 Key", + "type": "string" + }, + "s3_bucket": { + "description": "The S3 bucket to upload the blob to", + "title": "S3 Bucket", + "type": "string" } }, - "title": "ListLoopsSamplersRequestV1", + "required": [ + "creds", + "s3_key", + "s3_bucket" + ], + "title": "GetBlobCredentialsResponseV1", "type": "object" }, - "CreateLoopsSamplerRequestV1": { - "properties": { - "session_id": { - "description": "ID of the Loops session this sampler belongs to.", - "title": "Session Id", - "type": "string" - }, - "base_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Base model ID for a standalone sampler (for example, a baseline).", - "title": "Base Model" - }, - "run_id": { + "APIKeyCategory": { + "description": "Enum representing the category of an API key.", + "enum": [ + "PERSONAL", + "ROUTES", + "WORKSPACE_MANAGE_ALL", + "WORKSPACE_EXPORT_METRICS", + "WORKSPACE_INVOKE", + "WORKSPACE_MANAGE_API_KEYS" + ], + "title": "APIKeyCategory", + "type": "string" + }, + "CreateAPIKeyRequestV1": { + "description": "Request to create an API key.", + "properties": { + "name": { "anyOf": [ { "type": "string" @@ -22619,41 +27784,49 @@ } ], "default": null, - "description": "ID of an existing run to attach this sampler to. When set, the sampler is paired to the run and weight-syncs from its trainer, and base_model is inherited from the run. Omit to create a standalone sampler.", - "title": "Run Id" - }, - "max_seq_length": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } + "description": "Optional name for the API key", + "examples": [ + "my-api-key" ], - "default": null, - "description": "Maximum prompt length (in tokens) the sampler must handle. Set this to the longest prompt you plan to send.", - "title": "Max Seq Length" + "title": "Name" }, - "model_path": { + "type": { + "$ref": "#/components/schemas/APIKeyCategory", + "description": "Type of the API key.", + "examples": [ + "PERSONAL", + "ROUTES", + "WORKSPACE_MANAGE_API_KEYS", + "WORKSPACE_EXPORT_METRICS", + "WORKSPACE_INVOKE", + "WORKSPACE_MANAGE_ALL" + ] + }, + "model_ids": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "description": "bt:// URI of an existing sampler checkpoint to serve. Form: bt://loops:/sampler_weights/.", + "description": "List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", "examples": [ - "bt://loops:k4q95w5/sampler_weights/step-100" + [ + "aaaaaaaa" + ] ], - "title": "Model Path" + "title": "Model Ids" }, - "reuse_from_session_id": { + "team_id": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -22661,62 +27834,40 @@ } ], "default": null, - "description": "Optional ID of a prior Loops session to reuse a trainer and/or sampler from. Deprecated.", - "title": "Reuse From Session Id" - } - }, - "required": [ - "session_id" - ], - "title": "CreateLoopsSamplerRequestV1", - "type": "object" - }, - "CreateLoopsSamplerResponseV1": { - "properties": { - "sampler": { - "$ref": "#/components/schemas/LoopsSamplerV1" + "description": "Team ID for a team-scoped key. When omitted, uses the team in the URL if present, otherwise your organization's default team. Must match the URL team when both are provided. Not supported for PERSONAL or WORKSPACE_MANAGE_API_KEYS keys.", + "title": "Team Id" } }, "required": [ - "sampler" + "type" ], - "title": "CreateLoopsSamplerResponseV1", + "title": "CreateAPIKeyRequestV1", "type": "object" }, - "GetLoopsSamplerResponseV1": { - "description": "Response for ``GET /v1/loops/samplers/``.", + "APIKeyV1": { + "description": "Represents an API key.", "properties": { - "sampler": { - "$ref": "#/components/schemas/LoopsSamplerV1", - "description": "The Loops sampler." + "api_key": { + "description": "The API key string", + "title": "Api Key", + "type": "string" } }, "required": [ - "sampler" + "api_key" ], - "title": "GetLoopsSamplerResponseV1", + "title": "APIKeyV1", "type": "object" }, - "LoopsCheckpointV1": { - "description": "A checkpoint saved by a Loops run.", + "APIKeyInfoV1": { + "description": "Represents the metadata of an API key.", "properties": { - "checkpoint_id": { - "description": "The ID of the checkpoint.", - "title": "Checkpoint Id", - "type": "string" - }, - "created_at": { - "description": "The timestamp of the checkpoint in ISO 8601 format.", - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "checkpoint_type": { - "description": "The type of checkpoint.", - "title": "Checkpoint Type", + "prefix": { + "description": "The prefix of the API key", + "title": "Prefix", "type": "string" }, - "base_model": { + "name": { "anyOf": [ { "type": "string" @@ -22725,28 +27876,47 @@ "type": "null" } ], - "description": "The base model of the checkpoint.", - "title": "Base Model" + "default": null, + "description": "Optional name for the API key", + "examples": [ + "my-api-key" + ], + "title": "Name" }, - "lora_adapter_config": { + "type": { + "$ref": "#/components/schemas/APIKeyCategory", + "description": "Type of the API key.", + "examples": [ + "PERSONAL", + "ROUTES", + "WORKSPACE_MANAGE_API_KEYS", + "WORKSPACE_EXPORT_METRICS", + "WORKSPACE_INVOKE", + "WORKSPACE_MANAGE_ALL" + ] + }, + "model_ids": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "description": "The adapter config of the checkpoint.", - "title": "Lora Adapter Config" - }, - "size_bytes": { - "description": "The size of the checkpoint in bytes.", - "title": "Size Bytes", - "type": "integer" + "default": null, + "description": "List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", + "examples": [ + [ + "aaaaaaaa" + ] + ], + "title": "Model Ids" }, - "sync_status": { + "team_name": { "anyOf": [ { "type": "string" @@ -22756,71 +27926,19 @@ } ], "default": null, - "description": "Sync state of the checkpoint: SYNCING or COMPLETE.", - "title": "Sync Status" - }, - "id": { - "description": "The checkpoint ID.", - "title": "Id", - "type": "string" + "description": "The name of the team associated with the API key", + "title": "Team Name" }, - "run_id": { - "description": "The ID of the run that produced the checkpoint.", - "title": "Run Id", + "created_at": { + "description": "Creation time in ISO 8601 format", + "format": "date-time", + "title": "Created At", "type": "string" }, - "target": { - "$ref": "#/components/schemas/TrainerCheckpointTarget", - "description": "Whether this checkpoint is loadable by the sampler or by the run." - } - }, - "required": [ - "checkpoint_id", - "created_at", - "checkpoint_type", - "base_model", - "lora_adapter_config", - "size_bytes", - "id", - "run_id", - "target" - ], - "title": "LoopsCheckpointV1", - "type": "object" - }, - "TrainerCheckpointTarget": { - "description": "Whether a TrainerServerCheckpoint is loadable by the sampler or the trainer.\n\nSAMPLER checkpoints are consumed by the sampling server for inference;\nTRAINER checkpoints capture full trainer state for resuming training.\nMirrored in the bt:// URI as\n``bt://loops:/(sampler_weights|weights)/``.", - "enum": [ - "sampler", - "trainer" - ], - "title": "TrainerCheckpointTarget", - "type": "string" - }, - "ListLoopsCheckpointsResponseV1": { - "description": "Checkpoints matching the query filter.", - "properties": { - "checkpoints": { - "description": "Matching checkpoints.", - "items": { - "$ref": "#/components/schemas/LoopsCheckpointV1" - }, - "title": "Checkpoints", - "type": "array" - } - }, - "required": [ - "checkpoints" - ], - "title": "ListLoopsCheckpointsResponseV1", - "type": "object" - }, - "ListLoopsCheckpointsQueryParamsV1": { - "description": "Query-string filters for ``GET /v1/loops/checkpoints``.\n\nProvide exactly one of ``run_id`` (all checkpoints for the run),\n``base_model`` (all checkpoints across the caller's runs of that\nbase model), or ``checkpoint_path`` (the single matching checkpoint).", - "properties": { - "run_id": { + "last_used_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { @@ -22828,13 +27946,39 @@ } ], "default": null, - "description": "Filter by run ID. Returns all checkpoints saved by the run.", - "examples": [ - "k4q95w5" + "description": "Last recorded use in ISO 8601 format, or null if unavailable. Updates may be delayed.", + "title": "Last Used At" + }, + "owner": { + "anyOf": [ + { + "$ref": "#/components/schemas/APIKeyOwnerV1" + }, + { + "type": "null" + } ], - "title": "Run Id" + "default": null, + "description": "The user who owns the API key. Only present for personal API keys." + } + }, + "required": [ + "prefix", + "type", + "created_at" + ], + "title": "APIKeyInfoV1", + "type": "object" + }, + "APIKeyOwnerV1": { + "description": "The user who owns a personal API key.", + "properties": { + "user_id": { + "description": "Unique identifier for the user", + "title": "User Id", + "type": "string" }, - "base_model": { + "email": { "anyOf": [ { "type": "string" @@ -22844,13 +27988,10 @@ } ], "default": null, - "description": "Filter by base model. Returns checkpoints across the caller's runs of this base model.", - "examples": [ - "Qwen/Qwen3-8B" - ], - "title": "Base Model" + "description": "Email address of the user", + "title": "Email" }, - "checkpoint_path": { + "name": { "anyOf": [ { "type": "string" @@ -22860,123 +28001,97 @@ } ], "default": null, - "description": "bt:// URI of a Loops checkpoint. Form: bt://loops:/(weights|sampler_weights)/.", - "examples": [ - "bt://loops:k4q95w5/sampler_weights/step-100" - ], - "title": "Checkpoint Path" + "description": "Display name of the user", + "title": "Name" } }, - "title": "ListLoopsCheckpointsQueryParamsV1", + "required": [ + "user_id" + ], + "title": "APIKeyOwnerV1", "type": "object" }, - "ValidateLoopsCheckpointRequestV1": { - "description": "Request body for ``POST /v1/loops/checkpoints/validate``.", + "APIKeysV1": { + "description": "A list of API keys.", "properties": { - "checkpoint_path": { - "description": "bt:// URI of a sampler checkpoint. Form: bt://loops:/sampler_weights/.", - "examples": [ - "bt://loops:k4q95w5/sampler_weights/step-100" - ], - "title": "Checkpoint Path", - "type": "string" + "keys": { + "description": "A list of API key information", + "items": { + "$ref": "#/components/schemas/APIKeyInfoV1" + }, + "title": "Keys", + "type": "array" } }, "required": [ - "checkpoint_path" + "keys" ], - "title": "ValidateLoopsCheckpointRequestV1", - "type": "object" - }, - "ValidateLoopsCheckpointResponseV1": { - "description": "Response for ``POST /v1/loops/checkpoints/validate``. Empty on success;\ninaccessible or malformed paths raise 400.", - "properties": {}, - "title": "ValidateLoopsCheckpointResponseV1", + "title": "APIKeysV1", "type": "object" }, - "LoopsCheckpointFilesResponseV1": { - "description": "Response with presigned URLs for files under a Loops checkpoint.", + "APIKeysRequestV1": { "properties": { - "presigned_urls": { - "description": "List of presigned URLs for checkpoint files.", - "items": { - "$ref": "#/components/schemas/CheckpointFile" - }, - "title": "Presigned Urls", - "type": "array" - }, - "next_page_token": { + "type": { "anyOf": [ { - "type": "integer" + "$ref": "#/components/schemas/APIKeyCategory" }, { "type": "null" } ], "default": null, - "description": "Token to use for fetching the next page of results. None when there are no more results.", - "title": "Next Page Token" - }, - "total_count": { - "description": "Total number of checkpoint files available.", - "title": "Total Count", - "type": "integer" - } - }, - "required": [ - "presigned_urls", - "total_count" - ], - "title": "LoopsCheckpointFilesResponseV1", - "type": "object" - }, - "GetLoopsCheckpointFilesRequestV1": { - "description": "Pagination params for ``GET /v1/loops/checkpoints//files``.", - "properties": { - "page_size": { - "default": 1000, - "description": "Max files per page (default 1000).", - "minimum": 1, - "title": "Page Size", - "type": "integer" + "description": "Filter by API key type" }, - "page_token": { - "default": 0, - "description": "Offset into the file list (default 0).", - "minimum": 0, - "title": "Page Token", - "type": "integer" + "created_by_me": { + "default": false, + "description": "Return only keys created by the authenticated user", + "title": "Created By Me", + "type": "boolean" } }, - "title": "GetLoopsCheckpointFilesRequestV1", + "title": "APIKeysRequestV1", "type": "object" }, - "LoopsDeploymentStatusV1": { - "description": "Latest deployment status for a Loops deployment.", + "APIKeyTombstoneV1": { + "description": "An API key tombstone.", "properties": { - "name": { - "$ref": "#/components/schemas/Name", - "description": "Latest status of the Loops deployment." + "prefix": { + "description": "Unique prefix of the API key", + "title": "Prefix", + "type": "string" } }, "required": [ - "name" + "prefix" ], - "title": "LoopsDeploymentStatusV1", + "title": "APIKeyTombstoneV1", "type": "object" }, - "LoopsDeploymentV1": { - "description": "A Loops deployment \u2014 the long-lived run + sampler pair owned by a user.\n\nThe deployment's current sampler is included inline. The full list of\nsamplers visible to the caller (across all deployments) lives at\n``GET /v1/loops/samplers``.", + "LimitTypeV1": { + "enum": [ + "REQUEST", + "TOKEN", + "CONCURRENT_REQUEST", + "UNCACHED_INPUT_TOKEN", + "OUTPUT_TOKEN" + ], + "title": "LimitTypeV1", + "type": "string" + }, + "ModelAPIOrgDetailsV1": { + "description": "Workspace-specific state for a Model API.", "properties": { - "id": { - "description": "The Loops deployment ID.", - "title": "Id", + "added_at": { + "description": "When the workspace first added this Model API.", + "format": "date-time", + "title": "Added At", "type": "string" }, - "active_run_id": { + "last_used_at": { "anyOf": [ { + "format": "date-time", "type": "string" }, { @@ -22984,10 +28099,41 @@ } ], "default": null, - "description": "The ID of the run currently active on this deployment, if any. Null when the deployment's runs have been marked inactive (e.g. scale-to-zero) without a successor.", - "title": "Active Run Id" + "description": "When the workspace last invoked this Model API. Null if the workspace has never invoked it.", + "title": "Last Used At" + } + }, + "required": [ + "added_at" + ], + "title": "ModelAPIOrgDetailsV1", + "type": "object" + }, + "ModelAPIV1": { + "description": "A Model API catalog row, optionally enriched with workspace-specific state.", + "properties": { + "name": { + "description": "Identifier of the Model API. Stable, URL-safe slug used as the public identifier.", + "examples": [ + "llama-3-3-70b-instruct" + ], + "title": "Name", + "type": "string" }, - "latest_run_id": { + "display_name": { + "description": "Human-readable name of the Model API.", + "examples": [ + "Llama 3.3 70B Instruct" + ], + "title": "Display Name", + "type": "string" + }, + "description": { + "description": "Description of the Model API.", + "title": "Description", + "type": "string" + }, + "model_family": { "anyOf": [ { "type": "string" @@ -22997,108 +28143,181 @@ } ], "default": null, - "description": "The ID of the most recent run on this deployment, active or not, so idle deployments still expose a usable run handle. Null only if the deployment has no runs.", - "title": "Latest Run Id" + "description": "Family the underlying model belongs to.", + "examples": [ + "Meta", + "DeepSeek", + "Qwen" + ], + "title": "Model Family" }, - "base_model": { - "description": "The HuggingFace base model the deployment is fine-tuning.", - "title": "Base Model", + "release_date": { + "description": "Date the Model API was made available.", + "format": "date", + "title": "Release Date", "type": "string" }, - "base_url": { - "description": "The run's base URL.", - "title": "Base Url", + "invoke_url": { + "description": "Base URL for invoking the Model API. OpenAI-shaped routes (e.g. /v1/chat/completions) live underneath this host.", + "examples": [ + "https://inference.baseten.co" + ], + "title": "Invoke Url", "type": "string" }, - "status": { - "$ref": "#/components/schemas/LoopsDeploymentStatusV1", - "description": "Latest deployment status." - }, - "user": { - "$ref": "#/components/schemas/UserV1", - "description": "The user who owns the Loops deployment." - }, - "created_at": { - "description": "Time the deployment was created in ISO 8601 format.", - "format": "date-time", - "title": "Created At", - "type": "string" + "context_length": { + "description": "The model's context window length, in tokens.", + "examples": [ + 8192 + ], + "title": "Context Length", + "type": "integer" }, - "availability_model": { - "$ref": "#/components/schemas/V1AvailabilityModel", - "default": "dedicated", - "description": "Capacity the trainer was scheduled on." + "cost_per_million_input_tokens": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", + "examples": [ + "0.13" + ], + "title": "Cost Per Million Input Tokens" }, - "instance_type": { - "$ref": "#/components/schemas/InstanceTypeV1", - "description": "Instance type backing the trainer." + "cost_per_million_output_tokens": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", + "examples": [ + "0.50" + ], + "title": "Cost Per Million Output Tokens" }, - "node_count": { - "default": 1, - "description": "Number of nodes backing the trainer.", - "title": "Node Count", - "type": "integer" + "rate_limits": { + "description": "Rate limits in effect for the workspace. Workspace-specific overrides are returned when the workspace has added this Model API and configured them; otherwise the catalog default rate limits are returned.", + "items": { + "$ref": "#/components/schemas/RateLimitV1" + }, + "title": "Rate Limits", + "type": "array" }, - "sampler": { + "org_details": { "anyOf": [ { - "$ref": "#/components/schemas/LoopsSamplerV1" + "$ref": "#/components/schemas/ModelAPIOrgDetailsV1" }, { "type": "null" } ], "default": null, - "description": "The sampler bound to this deployment." + "description": "Workspace-specific state. Null when the workspace has not added this Model API." } }, "required": [ - "id", - "base_model", - "base_url", - "status", - "user", - "created_at", - "instance_type" + "name", + "display_name", + "description", + "release_date", + "invoke_url", + "context_length", + "cost_per_million_input_tokens", + "cost_per_million_output_tokens", + "rate_limits" ], - "title": "LoopsDeploymentV1", + "title": "ModelAPIV1", "type": "object" }, - "Name": { + "RateLimitUnitV1": { "enum": [ - "CREATED", - "DEPLOYING", - "RUNNING", - "SCALED_TO_ZERO", - "FAILED", - "STOPPED", - "PREEMPTED" + "SECOND", + "MINUTE" ], - "title": "LoopsDeploymentStatus", + "title": "RateLimitUnitV1", "type": "string" }, - "ListLoopsDeploymentsResponseV1": { - "description": "Response for ``GET /v1/loops/deployments``.\n\nDefaults to the caller's own; pass ``?scope=org`` to list every deployment in\nthe caller's organization. Returns every deployment regardless of status;\nclients filter terminal states.", + "RateLimitV1": { "properties": { - "deployments": { - "description": "Active Loops deployments.", + "type": { + "$ref": "#/components/schemas/LimitTypeV1", + "description": "The type of the rate limit", + "examples": [ + "TOKEN", + "REQUEST" + ] + }, + "unit": { + "$ref": "#/components/schemas/RateLimitUnitV1", + "description": "The unit of the rate limit", + "examples": [ + "SECOND", + "MINUTE" + ] + }, + "threshold": { + "description": "The threshold for the rate limit", + "examples": [ + 1000, + 50000 + ], + "minimum": 0, + "title": "Threshold", + "type": "integer" + } + }, + "required": [ + "type", + "unit", + "threshold" + ], + "title": "RateLimitV1", + "type": "object" + }, + "ModelAPIsResponseV1": { + "description": "Page of Model APIs visible to the caller.", + "properties": { + "items": { + "description": "Items in this page.", "items": { - "$ref": "#/components/schemas/LoopsDeploymentV1" + "$ref": "#/components/schemas/ModelAPIV1" }, - "title": "Deployments", + "title": "Items", "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "deployments" + "items", + "pagination" ], - "title": "ListLoopsDeploymentsResponseV1", + "title": "ModelAPIsResponseV1", "type": "object" }, - "ListLoopsDeploymentsRequestV1": { - "description": "Query-string filters for ``GET /v1/loops/deployments``.", + "ModelAPIsRequestV1": { + "description": "Query-string filters for ``GET /v1/model_apis``.", "properties": { - "scope": { + "cursor": { "anyOf": [ { "type": "string" @@ -23108,448 +28327,245 @@ } ], "default": null, - "description": "Defaults to the caller's own deployments; pass 'org' to list every deployment in the caller's organization.", - "examples": [ - "org" - ], - "title": "Scope" + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" + }, + "limit": { + "default": 100, + "description": "Maximum number of items to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + }, + "added_only": { + "default": false, + "description": "When true, restrict the result to Model APIs the workspace has added. Defaults to the full visible catalog.", + "title": "Added Only", + "type": "boolean" } }, - "title": "ListLoopsDeploymentsRequestV1", + "title": "ModelAPIsRequestV1", "type": "object" }, - "DeactivateLoopsDeploymentResponseV1": { - "description": "Response for ``POST /v1/loops/deployments//deactivate``.", + "ModelApisUsageBucketV1": { + "description": "One time bucket and the usage recorded in it.", "properties": { - "id": { - "description": "The deactivated Loops deployment ID.", - "title": "Id", + "start_time": { + "description": "Start of the bucket (inclusive), UTC", + "format": "date-time", + "title": "Start Time", "type": "string" }, - "base_model": { - "description": "The base model whose Loops deployment was deactivated.", - "title": "Base Model", + "end_time": { + "description": "End of the bucket (exclusive), UTC", + "format": "date-time", + "title": "End Time", "type": "string" }, - "user": { - "$ref": "#/components/schemas/UserV1", - "description": "The user who owned the Loops deployment." - } - }, - "required": [ - "id", - "base_model", - "user" - ], - "title": "DeactivateLoopsDeploymentResponseV1", - "type": "object" - }, - "GetLoopsDeploymentResponseV1": { - "description": "Response for ``GET /v1/loops/deployments/``.", - "properties": { - "deployment": { - "$ref": "#/components/schemas/LoopsDeploymentV1", - "description": "The Loops deployment." - } - }, - "required": [ - "deployment" - ], - "title": "GetLoopsDeploymentResponseV1", - "type": "object" - }, - "LoopsDebugArchiveFilesResponseV1": { - "description": "Response with presigned URLs for a Loops deployment's debug archive.", - "properties": { - "presigned_urls": { + "results": { + "description": "Usage totals for this bucket, ordered by total tokens descending", "items": { - "$ref": "#/components/schemas/CheckpointFile" + "$ref": "#/components/schemas/ModelApisUsageResultV1" }, - "title": "Presigned Urls", + "title": "Results", "type": "array" - }, - "next_page_token": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Next Page Token" } }, "required": [ - "presigned_urls" + "start_time", + "end_time" ], - "title": "LoopsDebugArchiveFilesResponseV1", - "type": "object" - }, - "GetLoopsDebugArchiveFilesRequestV1": { - "description": "Pagination params for a Loops deployment debug archive.", - "properties": { - "page_size": { - "default": 1000, - "description": "Max files per page (default and maximum 1000).", - "maximum": 1000, - "minimum": 1, - "title": "Page Size", - "type": "integer" - }, - "page_token": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Opaque token for the next page.", - "title": "Page Token" - } - }, - "title": "GetLoopsDebugArchiveFilesRequestV1", + "title": "ModelApisUsageBucketV1", "type": "object" }, - "GetLoopsDeploymentMetricsRequestV1": { - "description": "Time-range request for trainer deployment metrics.", - "properties": { - "end_epoch_millis": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Epoch millis to end fetching metrics.", - "title": "End Epoch Millis" - }, - "start_epoch_millis": { + "ModelApisUsageResultV1": { + "description": "Usage totals for one combination of the requested dimensions, within one bucket.", + "properties": { + "api_key_prefix": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Epoch millis to start fetching metrics.", - "title": "Start Epoch Millis" + "description": "Prefix of the API key the usage is attributed to. Null when not grouping by api_key or when the request was not authenticated with an API key.", + "title": "Api Key Prefix" }, - "step_seconds": { + "user_id": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Resolution of the returned series, in seconds. When omitted, a step is derived from the time range so large windows return fewer points.", - "title": "Step Seconds" + "description": "User the usage is attributed to. Null when not grouping by user or when the credential is not user-scoped.", + "title": "User Id" }, - "time_divisor_seconds": { + "model": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Unit of time for request-volume metrics, in seconds (e.g. 60 for requests/minute). Defaults to per-second.", - "title": "Time Divisor Seconds" - } - }, - "title": "GetLoopsDeploymentMetricsRequestV1", - "type": "object" - }, - "InferenceVolumeByStatusDatapointV1": { - "description": "Request rate split by HTTP response code class.", - "properties": { - "timestamp": { - "description": "ISO 8601 timestamp.", - "format": "date-time", - "title": "Timestamp", - "type": "string" + "description": "Model that served the usage. Null when not grouping by model.", + "title": "Model" }, - "status_2xx": { - "description": "2xx requests per second.", - "title": "Status 2Xx", - "type": "number" + "input_tokens": { + "description": "Total input tokens, cached and uncached combined.", + "title": "Input Tokens", + "type": "integer" }, - "status_4xx": { - "description": "4xx requests per second.", - "title": "Status 4Xx", - "type": "number" + "cached_input_tokens": { + "description": "Input tokens served from the prompt cache.", + "title": "Cached Input Tokens", + "type": "integer" }, - "status_5xx": { - "description": "5xx requests per second.", - "title": "Status 5Xx", - "type": "number" + "uncached_input_tokens": { + "description": "Input tokens not served from the prompt cache.", + "title": "Uncached Input Tokens", + "type": "integer" + }, + "output_tokens": { + "description": "Total output tokens.", + "title": "Output Tokens", + "type": "integer" + }, + "request_count": { + "description": "Total number of requests.", + "title": "Request Count", + "type": "integer" } }, "required": [ - "timestamp", - "status_2xx", - "status_4xx", - "status_5xx" + "input_tokens", + "cached_input_tokens", + "uncached_input_tokens", + "output_tokens", + "request_count" ], - "title": "InferenceVolumeByStatusDatapointV1", + "title": "ModelApisUsageResultV1", "type": "object" }, - "LoopsDeploymentMetricsV1": { - "description": "Metrics for a trainer (Loops) deployment.\n\nService-level fields summarize HTTP traffic into the trainer pods (the\nKnative queue-proxy is the source). Compute fields are the leader-pod\naggregate; ``per_node_metrics`` carries the full multinode breakdown.", + "ModelApisUsageResponseV1": { + "description": "A page of Model APIs token usage: contiguous time buckets, ordered oldest first.", "properties": { - "inference_volume": { - "description": "Number of inference requests per unit time (requests per second).", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Inference Volume", - "type": "array" - }, - "concurrent_requests": { - "description": "Number of in-progress concurrent inference requests. Source: the queue-proxy ``revision_queue_depth`` gauge on ``http-usermetric``.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Concurrent Requests", - "type": "array" - }, - "response_time_stats": { - "description": "Percentiles of the response time distribution.", - "items": { - "$ref": "#/components/schemas/ResponseTimeDatapointV1" - }, - "title": "Response Time Stats", - "type": "array" - }, - "inference_volume_by_status": { - "description": "Request rate split by response code class.", - "items": { - "$ref": "#/components/schemas/InferenceVolumeByStatusDatapointV1" - }, - "title": "Inference Volume By Status", - "type": "array" - }, - "gpu_memory_usage_bytes": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "type": "array" - }, - "description": "Leader-pod GPU memory bytes per GPU rank.", - "title": "Gpu Memory Usage Bytes", - "type": "object" - }, - "gpu_utilization": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "type": "array" - }, - "description": "Leader-pod fractional GPU utilization per GPU rank.", - "title": "Gpu Utilization", - "type": "object" - }, - "cpu_usage": { - "description": "Leader-pod CPU usage in cores.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Cpu Usage", - "type": "array" - }, - "cpu_memory_usage_bytes": { - "description": "Leader-pod CPU memory usage bytes.", + "items": { + "description": "Items in this page.", "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" + "$ref": "#/components/schemas/ModelApisUsageBucketV1" }, - "title": "Cpu Memory Usage Bytes", + "title": "Items", "type": "array" }, - "ephemeral_storage": { - "$ref": "#/components/schemas/StorageMetricsV1", - "description": "Leader-pod ephemeral storage usage." - }, - "per_node_metrics": { - "description": "Per-node compute breakdown for multinode trainer deployments.", - "items": { - "$ref": "#/components/schemas/LoopsDeploymentNodeMetricsV1" - }, - "title": "Per Node Metrics", - "type": "array" + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "inference_volume", - "concurrent_requests", - "response_time_stats", - "inference_volume_by_status", - "gpu_memory_usage_bytes", - "gpu_utilization", - "cpu_usage", - "cpu_memory_usage_bytes", - "ephemeral_storage", - "per_node_metrics" + "items", + "pagination" ], - "title": "LoopsDeploymentMetricsV1", + "title": "ModelApisUsageResponseV1", "type": "object" }, - "LoopsDeploymentNodeMetricsV1": { - "description": "Per-node compute metrics for a multinode trainer deployment.", - "properties": { - "node_id": { - "description": "Identifier for the node.", - "title": "Node Id", - "type": "string" - }, - "gpu_memory_usage_bytes": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "type": "array" - }, - "description": "GPU memory usage bytes per GPU rank.", - "title": "Gpu Memory Usage Bytes", - "type": "object" - }, - "gpu_utilization": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "type": "array" - }, - "description": "Fractional GPU utilization per GPU rank.", - "title": "Gpu Utilization", - "type": "object" - }, - "cpu_usage": { - "description": "CPU usage in cores.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Cpu Usage", - "type": "array" - }, - "cpu_memory_usage_bytes": { - "description": "CPU memory usage bytes.", - "items": { - "$ref": "#/components/schemas/TrainingJobMetricV1" - }, - "title": "Cpu Memory Usage Bytes", - "type": "array" - }, - "ephemeral_storage": { - "$ref": "#/components/schemas/StorageMetricsV1", - "description": "Ephemeral storage usage." - } - }, - "required": [ - "node_id", - "gpu_memory_usage_bytes", - "gpu_utilization", - "cpu_usage", - "cpu_memory_usage_bytes", - "ephemeral_storage" + "BucketWidth": { + "enum": [ + "1m", + "1h", + "1d" + ], + "title": "BucketWidth", + "type": "string" + }, + "UsageDimensionV1": { + "enum": [ + "api_key", + "user", + "model" ], - "title": "LoopsDeploymentNodeMetricsV1", - "type": "object" + "title": "UsageDimensionV1", + "type": "string" }, - "ResponseTimeDatapointV1": { - "description": "Latency quantile datapoint. Values are reported in milliseconds.", + "ModelApisUsageRequestV1": { "properties": { - "timestamp": { - "description": "ISO 8601 timestamp.", - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "p50": { + "start_time": { "anyOf": [ { - "type": "number" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "50th percentile request latency (milliseconds).", - "title": "P50" + "description": "Start of the query range (ISO 8601, UTC), inclusive. Snapped down to the start of its bucket. Required on the first page, and ignored when you pass a cursor.", + "title": "Start Time" }, - "p95": { + "end_time": { "anyOf": [ { - "type": "number" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "95th percentile request latency (milliseconds).", - "title": "P95" + "description": "End of the query range (ISO 8601, UTC), exclusive. Defaults to the current time.", + "title": "End Time" }, - "p99": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": null, - "description": "99th percentile request latency (milliseconds).", - "title": "P99" - } - }, - "required": [ - "timestamp" - ], - "title": "ResponseTimeDatapointV1", - "type": "object" - }, - "GetLoopsDeploymentMetricsResponseV1": { - "description": "Response for ``POST /v1/loops/deployments//metrics``.", - "properties": { - "deployment_id": { - "description": "The trainer deployment ID.", - "title": "Deployment Id", - "type": "string" + "bucket_width": { + "$ref": "#/components/schemas/BucketWidth", + "default": "1d", + "description": "Width of each time bucket: 1m, 1h, or 1d. Defaults to 1d." }, - "metrics": { - "$ref": "#/components/schemas/LoopsDeploymentMetricsV1", - "description": "Metrics for the deployment." - } - }, - "required": [ - "deployment_id", - "metrics" - ], - "title": "GetLoopsDeploymentMetricsResponseV1", - "type": "object" - }, - "GetLoopsDeploymentLogsRequestV1": { - "description": "Query parameters for fetching a Loops deployment's logs.", - "properties": { - "start_epoch_millis": { + "group_by": { + "description": "Dimensions to break usage down by, repeated once per dimension: api_key, user, model. Defaults to model.", + "items": { + "$ref": "#/components/schemas/UsageDimensionV1" + }, + "title": "Group By", + "type": "array" + }, + "api_keys": { + "description": "Return only usage for these API key prefixes, repeated once per prefix.", + "items": { + "type": "string" + }, + "title": "Api Keys", + "type": "array" + }, + "user_ids": { + "description": "Return only usage attributed to these user IDs, repeated once per ID.", + "items": { + "type": "string" + }, + "title": "User Ids", + "type": "array" + }, + "models": { + "description": "Return only usage for these models, repeated once per model.", + "items": { + "type": "string" + }, + "title": "Models", + "type": "array" + }, + "limit": { "anyOf": [ { "type": "integer" @@ -23559,248 +28575,212 @@ } ], "default": null, - "description": "Epoch milliseconds at which to start fetching logs. Defaults to 30 minutes before the end. The window from start to end must not exceed 7 days.", - "title": "Start Epoch Millis" + "description": "Number of time buckets to return. Defaults and maximums depend on bucket_width: 1d defaults to 7 and allows 31, 1h defaults to 24 and allows 168, 1m defaults to 60 and allows 1440.", + "title": "Limit" }, - "end_epoch_millis": { + "cursor": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Epoch milliseconds at which to stop fetching logs. Defaults to the current time.", - "title": "End Epoch Millis" + "description": "Opaque cursor from the pagination.cursor field of a previous response", + "title": "Cursor" + } + }, + "title": "ModelApisUsageRequestV1", + "type": "object" + }, + "CreateLLMModelRequestV1": { + "description": "A request to create a BIS-LLM model", + "properties": { + "resources": { + "additionalProperties": true, + "description": "Resources allocated to the model", + "title": "Resources", + "type": "object" }, - "direction": { + "region": { "anyOf": [ { - "$ref": "#/components/schemas/SortOrderV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Sort order for logs" + "description": "Region in which to deploy the model", + "title": "Region" }, - "limit": { + "llm_version": { "anyOf": [ { - "maximum": 1000, - "minimum": 1, - "type": "integer" + "type": "string" }, { "type": "null" } ], - "default": 500, - "description": "Limit of logs to fetch in a single request", - "title": "Limit" + "default": null, + "description": "Version of the helm chart to use.", + "title": "Llm Version" }, - "min_level": { + "llm_config": { + "additionalProperties": true, + "description": "Configuration specific to the LLM model", + "title": "Llm Config", + "type": "object" + }, + "environment_variables": { + "additionalProperties": true, + "description": "Environment variables for the model", + "title": "Environment Variables", + "type": "object" + }, + "model_metadata": { "anyOf": [ { - "$ref": "#/components/schemas/LogLevelV1" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], "default": null, - "description": "Minimum log severity to include. Omit to return all log lines, including lines that have no level. Any explicit value returns lines at or above that severity and drops lines without a level." - } - }, - "title": "GetLoopsDeploymentLogsRequestV1", - "type": "object" - }, - "TeamTrainingGpuCapacityItemV1": { - "description": "Per-team GPU capacity and current usage for one GPU type.", - "properties": { - "team_id": { - "description": "Team identifier", - "title": "Team Id", - "type": "string" - }, - "team_name": { - "description": "Team name", - "title": "Team Name", - "type": "string" - }, - "gpu_type": { - "description": "GPU type identifier (e.g. H100, A100-40GB)", - "title": "Gpu Type", - "type": "string" - }, - "baseline": { - "description": "Baseline GPU allocation for the team. 0 if not configured.", - "title": "Baseline", - "type": "integer" - }, - "limit": { - "description": "Maximum concurrent GPUs of this type for this team", - "title": "Limit", - "type": "integer" - }, - "usage_count": { - "description": "GPUs currently in use by the team's active training jobs", - "title": "Usage Count", - "type": "integer" - }, - "dedicated_usage_count": { - "default": 0, - "description": "Portion of usage_count from dedicated (on-demand) jobs.", - "title": "Dedicated Usage Count", - "type": "integer" - }, - "spot_usage_count": { - "default": 0, - "description": "Portion of usage_count from spot jobs.", - "title": "Spot Usage Count", - "type": "integer" - } - }, - "required": [ - "team_id", - "team_name", - "gpu_type", - "baseline", - "limit", - "usage_count" - ], - "title": "TeamTrainingGpuCapacityItemV1", - "type": "object" - }, - "TrainingGpuCapacityItemV1": { - "description": "GPU capacity and current usage for one GPU type.", - "properties": { - "gpu_type": { - "description": "GPU type identifier (e.g. H100, A100-40GB)", - "title": "Gpu Type", - "type": "string" - }, - "baseline": { - "description": "Baseline GPU allocation; jobs below this threshold are expected to run immediately. 0 if not configured.", - "title": "Baseline", - "type": "integer" - }, - "limit": { - "description": "Maximum concurrent GPUs of this type for this org", - "title": "Limit", - "type": "integer" + "description": "Model metadata persisted into model_config", + "title": "Model Metadata" }, - "usage_count": { - "description": "GPUs currently in use by active training jobs", - "title": "Usage Count", - "type": "integer" + "autoscaling_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Autoscaling settings for the model", + "examples": [ + { + "autoscaling_window": 600, + "concurrency_target": null, + "max_replica": 5, + "max_scale_down_rate": null, + "min_replica": 1, + "scale_down_delay": 300, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + } + ] }, - "dedicated_usage_count": { - "default": 0, - "description": "Portion of usage_count from dedicated (on-demand) jobs, which run against the baseline.", - "title": "Dedicated Usage Count", - "type": "integer" + "additional_autoscaling_config": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Additional autoscaling configuration (e.g. target in-flight tokens)", + "examples": [ + { + "metrics": [ + { + "name": "in_flight_tokens", + "target": 40000 + } + ] + } + ], + "title": "Additional Autoscaling Config" }, - "spot_usage_count": { - "default": 0, - "description": "Portion of usage_count from spot jobs, which burst into the peak and may push usage above the limit.", - "title": "Spot Usage Count", - "type": "integer" - } - }, - "required": [ - "gpu_type", - "baseline", - "limit", - "usage_count" - ], - "title": "TrainingGpuCapacityItemV1", - "type": "object" - }, - "GetTrainingGpuCapacityResponseV1": { - "description": "Response for the training GPU capacity endpoint.", - "properties": { - "gpu_capacities": { - "description": "Org-level GPU capacity limits and current usage per GPU type", - "items": { - "$ref": "#/components/schemas/TrainingGpuCapacityItemV1" - }, - "title": "Gpu Capacities", - "type": "array" + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "User-defined metadata for the deployment", + "examples": [ + { + "environment": "production", + "git_sha": "abc123" + } + ], + "title": "Metadata" }, - "team_gpu_capacities": { - "description": "Per-team GPU capacity limits and current usage per GPU type", - "items": { - "$ref": "#/components/schemas/TeamTrainingGpuCapacityItemV1" - }, - "title": "Team Gpu Capacities", - "type": "array" + "weights": { + "anyOf": [ + { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Weight configurations for BDN model weight distribution", + "examples": [ + [ + { + "mount_location": "/models/base", + "source": "hf://meta-llama/Llama-3-8B" + } + ] + ], + "title": "Weights" + }, + "name": { + "description": "Name of the model", + "title": "Name", + "type": "string" } }, "required": [ - "gpu_capacities" + "resources", + "name" ], - "title": "GetTrainingGpuCapacityResponseV1", + "title": "CreateLLMModelRequestV1", "type": "object" }, - "PatchTeamTrainingGpuCapacityRequestV1": { - "description": "A request to set the GPU capacity ceiling for a (team, gpu_type) pair.\n\nCreates the limit if one doesn't already exist for this team and GPU type,\notherwise updates it in place.", + "LLMModelHandleV1": { + "description": "Handle for a BIS-LLM model deployment.", "properties": { - "team_id": { - "description": "Team identifier", - "title": "Team Id", + "model_id": { + "description": "Unique identifier of the model", + "title": "Model Id", "type": "string" }, - "gpu_type": { - "description": "GPU type identifier (e.g. H100, A100-40GB)", - "title": "Gpu Type", + "version_id": { + "description": "Unique identifier of the model version", + "title": "Version Id", "type": "string" }, - "max_gpus": { - "description": "Max concurrent GPUs of this type the team may use", - "examples": [ - 8, - 16, - 32 - ], - "title": "Max Gpus", - "type": "integer" - } - }, - "required": [ - "team_id", - "gpu_type", - "max_gpus" - ], - "title": "PatchTeamTrainingGpuCapacityRequestV1", - "type": "object" - }, - "PatchTeamTrainingGpuCapacityResponseV1": { - "description": "Response for setting a team's GPU capacity ceiling.", - "properties": { - "team_gpu_capacity": { - "$ref": "#/components/schemas/TeamTrainingGpuCapacityItemV1", - "description": "The updated per-team GPU capacity limit" - } - }, - "required": [ - "team_gpu_capacity" - ], - "title": "PatchTeamTrainingGpuCapacityResponseV1", - "type": "object" - }, - "ActiveJobAtSubmitV1": { - "description": "One other job in the same (org, gpu_type) pool that was holding GPU\ncapacity at the moment the target was submitted.", - "properties": { - "training_job_id": { - "description": "Hashid of the other training job", - "title": "Training Job Id", + "hostname": { + "description": "Hostname used to invoke the model", + "title": "Hostname", "type": "string" }, - "training_job_name": { + "instance_type_name": { "anyOf": [ { "type": "string" @@ -23810,97 +28790,41 @@ } ], "default": null, - "description": "Other job's name", - "title": "Training Job Name" - }, - "instance_type_name": { - "description": "Instance type of the other job", - "title": "Instance Type Name", - "type": "string" - }, - "total_gpus": { - "description": "gpu_count * effective_node_count", - "title": "Total Gpus", - "type": "integer" - }, - "workload_plane_name": { - "description": "Workload plane the other job was on", - "title": "Workload Plane Name", - "type": "string" - }, - "status_at_submit": { - "description": "Other job's status as of submitted_at (one of ACTIVE_STATES)", - "title": "Status At Submit", - "type": "string" - }, - "status_set_at": { - "description": "When that status was set", - "format": "date-time", - "title": "Status Set At", - "type": "string" + "description": "Name of the instance type the model deployment is running on", + "title": "Instance Type Name" } }, "required": [ - "training_job_id", - "instance_type_name", - "total_gpus", - "workload_plane_name", - "status_at_submit", - "status_set_at" + "model_id", + "version_id", + "hostname" ], - "title": "ActiveJobAtSubmitV1", + "title": "LLMModelHandleV1", "type": "object" }, - "CapacityAtSubmitV1": { - "description": "A GPU capacity row as it stands now, with ``last_modified`` so callers\ncan judge whether the value matches what the dequeue gate saw at submit\ntime. Capacity rows are not historicized: edits overwrite in place. Compare\n``last_modified`` against the response's ``submitted_at`` \u2014 if it's later,\nthe value may have changed.", - "properties": { - "gpu_type": { - "description": "GPU type identifier (e.g. H100, A100-40GB)", - "title": "Gpu Type", - "type": "string" - }, - "max_gpus": { - "description": "Current max concurrent GPUs of this type", - "title": "Max Gpus", - "type": "integer" + "CreateLLMModelVersionRequestV1": { + "description": "A request to create a BIS-LLM model version", + "properties": { + "resources": { + "additionalProperties": true, + "description": "Resources allocated to the model", + "title": "Resources", + "type": "object" }, - "min_gpus": { + "region": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Current baseline GPU allocation, if configured", - "title": "Min Gpus" - }, - "last_modified": { - "description": "When the capacity row was last modified", - "format": "date-time", - "title": "Last Modified", - "type": "string" - } - }, - "required": [ - "gpu_type", - "max_gpus", - "last_modified" - ], - "title": "CapacityAtSubmitV1", - "type": "object" - }, - "PendingJobAheadAtSubmitV1": { - "description": "A PENDING job in the same (org, gpu_type) pool that was ahead of the\ntarget in dequeue FIFO order at submitted_at \u2014 higher priority, or same\npriority and earlier submission.", - "properties": { - "training_job_id": { - "description": "Hashid of the other training job", - "title": "Training Job Id", - "type": "string" + "description": "Region in which to deploy the model", + "title": "Region" }, - "training_job_name": { + "llm_version": { "anyOf": [ { "type": "string" @@ -23910,149 +28834,189 @@ } ], "default": null, - "description": "Other job's name", - "title": "Training Job Name" - }, - "instance_type_name": { - "description": "Instance type of the other job", - "title": "Instance Type Name", - "type": "string" - }, - "requested_gpus": { - "description": "gpu_count * effective_node_count", - "title": "Requested Gpus", - "type": "integer" + "description": "Version of the helm chart to use.", + "title": "Llm Version" }, - "priority": { - "description": "Effective priority (NULL coalesced to 0)", - "title": "Priority", - "type": "integer" + "llm_config": { + "additionalProperties": true, + "description": "Configuration specific to the LLM model", + "title": "Llm Config", + "type": "object" }, - "submitted_at": { - "description": "The other job's submission time", - "format": "date-time", - "title": "Submitted At", - "type": "string" - } - }, - "required": [ - "training_job_id", - "instance_type_name", - "requested_gpus", - "priority", - "submitted_at" - ], - "title": "PendingJobAheadAtSubmitV1", - "type": "object" - }, - "QueueEventV1": { - "description": "A single ``TrainingJobStatus`` row inside the queue-context window.", - "properties": { - "training_job_id": { - "description": "Hashid of the training job this event is for", - "title": "Training Job Id", - "type": "string" + "environment_variables": { + "additionalProperties": true, + "description": "Environment variables for the model", + "title": "Environment Variables", + "type": "object" }, - "training_job_name": { + "model_metadata": { "anyOf": [ { - "type": "string" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], "default": null, - "description": "Job name", - "title": "Training Job Name" + "description": "Model metadata persisted into model_config", + "title": "Model Metadata" }, - "status": { - "description": "TrainingJobStatus.Name value", - "title": "Status", - "type": "string" + "autoscaling_settings": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Autoscaling settings for the model", + "examples": [ + { + "autoscaling_window": 600, + "concurrency_target": null, + "max_replica": 5, + "max_scale_down_rate": null, + "min_replica": 1, + "scale_down_delay": 300, + "target_in_flight_tokens": null, + "target_utilization_percentage": null + } + ] }, - "created": { - "description": "When the status row was inserted", - "format": "date-time", - "title": "Created", - "type": "string" + "additional_autoscaling_config": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Additional autoscaling configuration (e.g. target in-flight tokens)", + "examples": [ + { + "metrics": [ + { + "name": "in_flight_tokens", + "target": 40000 + } + ] + } + ], + "title": "Additional Autoscaling Config" }, - "event_message": { + "metadata": { "anyOf": [ { - "type": "string" + "additionalProperties": true, + "type": "object" }, { "type": "null" } ], "default": null, - "description": "Human-readable event message from the status metadata", - "title": "Event Message" + "description": "User-defined metadata for the deployment", + "examples": [ + { + "environment": "production", + "git_sha": "abc123" + } + ], + "title": "Metadata" }, - "exit_code": { + "weights": { "anyOf": [ { - "type": "integer" + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "description": "Exit code from the status metadata, if any", - "title": "Exit Code" + "description": "Weight configurations for BDN model weight distribution", + "examples": [ + [ + { + "mount_location": "/models/base", + "source": "hf://meta-llama/Llama-3-8B" + } + ] + ], + "title": "Weights" } }, "required": [ - "training_job_id", - "status", - "created" + "resources" ], - "title": "QueueEventV1", + "title": "CreateLLMModelVersionRequestV1", "type": "object" }, - "GetTrainingJobQueueContextResponseV1": { - "description": "Read-only diagnostic for a training job's PENDING window.\n\nReturns the (org, gpu_type) capacity pool the job was gated by, jobs that\nwere holding GPU capacity in that pool when this job was submitted, and\nevery status event in [submitted_at, released_at] for those jobs (or up to\n\"now\" if the target is still PENDING).", + "LibraryListingMetadataV1": { + "additionalProperties": false, "properties": { - "target_job_id": { - "description": "Hashid of the target training job", - "title": "Target Job Id", - "type": "string" + "parameter_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Parameter Count" }, - "target_job_name": { + "context_length": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Target job's name", - "title": "Target Job Name" + "title": "Context Length" }, - "gpu_type": { - "description": "GPU type the target requested", - "title": "Gpu Type", - "type": "string" + "input_modalities": { + "default": [ + "text" + ], + "items": { + "$ref": "#/components/schemas/LibraryListingModality" + }, + "title": "Input Modalities", + "type": "array" }, - "requested_gpus": { - "description": "GPUs the target requested (gpu_count * effective_node_count)", - "title": "Requested Gpus", - "type": "integer" + "output_modalities": { + "default": [ + "text" + ], + "items": { + "$ref": "#/components/schemas/LibraryListingModality" + }, + "title": "Output Modalities", + "type": "array" }, - "submitted_at": { - "description": "When the job row was inserted (= API POST time)", - "format": "date-time", - "title": "Submitted At", + "license": { + "title": "License", "type": "string" }, - "released_at": { + "variant": { "anyOf": [ { - "format": "date-time", "type": "string" }, { @@ -24060,226 +29024,228 @@ } ], "default": null, - "description": "When the job's TRAINING_JOB_CREATED status was set, i.e. the moment it was released from PENDING. None if still PENDING.", - "title": "Released At" + "title": "Variant" }, - "pending_seconds": { + "publisher": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "released_at - submitted_at in seconds. None if still PENDING.", - "title": "Pending Seconds" + "title": "Publisher" }, - "org_capacity": { + "model_api_slug": { "anyOf": [ { - "$ref": "#/components/schemas/CapacityAtSubmitV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Org-level cap for (org, gpu_type). None if no cap is configured." + "title": "Model Api Slug" }, - "team_capacity": { + "release_date": { "anyOf": [ { - "$ref": "#/components/schemas/CapacityAtSubmitV1" + "format": "date", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Team-level cap for (team, gpu_type). None if no team cap is configured." - }, - "active_at_submit": { - "description": "Jobs in the same (org, gpu_type) pool that were holding capacity at submitted_at", - "items": { - "$ref": "#/components/schemas/ActiveJobAtSubmitV1" - }, - "title": "Active At Submit", - "type": "array" - }, - "pending_ahead_at_submit": { - "description": "PENDING jobs in the same (org, gpu_type) pool that were ahead of the target in dequeue FIFO order at submitted_at (priority DESC then created ASC). These also block the target's release.", - "items": { - "$ref": "#/components/schemas/PendingJobAheadAtSubmitV1" - }, - "title": "Pending Ahead At Submit", - "type": "array" - }, - "events": { - "description": "Every status event in [submitted_at, events_window_end] for the target job, every job in active_at_submit, and every job in pending_ahead_at_submit, oldest first.", - "items": { - "$ref": "#/components/schemas/QueueEventV1" - }, - "title": "Events", - "type": "array" - }, - "events_window_end": { - "description": "released_at if set, else 'now' (events ongoing)", - "format": "date-time", - "title": "Events Window End", - "type": "string" - } - }, - "required": [ - "target_job_id", - "gpu_type", - "requested_gpus", - "submitted_at", - "active_at_submit", - "pending_ahead_at_submit", - "events", - "events_window_end" - ], - "title": "GetTrainingJobQueueContextResponseV1", - "type": "object" - }, - "GetBlobCredentialsResponseV1": { - "description": "Response to create a new set of credentials for blob upload.", - "properties": { - "creds": { - "$ref": "#/components/schemas/AWSCredentialsV1", - "description": "The credentials to upload the blob to" + "title": "Release Date" }, - "s3_key": { - "description": "The S3 key to upload the blob to", - "title": "S3 Key", - "type": "string" + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Description" }, - "s3_bucket": { - "description": "The S3 bucket to upload the blob to", - "title": "S3 Bucket", - "type": "string" + "trending": { + "default": false, + "title": "Trending", + "type": "boolean" } }, "required": [ - "creds", - "s3_key", - "s3_bucket" + "license" ], - "title": "GetBlobCredentialsResponseV1", + "title": "LibraryListingMetadataV1", "type": "object" }, - "APIKeyCategory": { - "description": "Enum representing the category of an API key.", + "LibraryListingModality": { "enum": [ - "PERSONAL", - "ROUTES", - "WORKSPACE_MANAGE_ALL", - "WORKSPACE_EXPORT_METRICS", - "WORKSPACE_INVOKE", - "WORKSPACE_MANAGE_API_KEYS" + "text", + "image", + "audio", + "video", + "embedding", + "rerank" ], - "title": "APIKeyCategory", + "title": "LibraryListingModality", "type": "string" }, - "CreateAPIKeyRequestV1": { - "description": "Request to create an API key.", + "LibraryListingV1": { + "description": "A library listing.", "properties": { - "name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Optional name for the API key", - "examples": [ - "my-api-key" - ], - "title": "Name" + "display_name": { + "description": "Display name of the library listing", + "title": "Display Name", + "type": "string" }, - "type": { - "$ref": "#/components/schemas/APIKeyCategory", - "description": "Type of the API key.", - "examples": [ - "PERSONAL", - "ROUTES", - "WORKSPACE_MANAGE_API_KEYS", - "WORKSPACE_EXPORT_METRICS", - "WORKSPACE_INVOKE", - "WORKSPACE_MANAGE_ALL" - ] + "user_defined_id": { + "description": "User-defined identifier of the library listing", + "title": "User Defined Id", + "type": "string" }, - "model_ids": { + "is_public": { + "description": "Whether the listing is publicly accessible", + "title": "Is Public", + "type": "boolean" + }, + "trending": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "boolean" }, { "type": "null" } ], - "default": null, - "description": "List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", - "examples": [ - [ - "aaaaaaaa" - ] - ], - "title": "Model Ids" + "description": "Whether the listing is trending", + "title": "Trending" }, - "team_id": { + "closed_source": { + "description": "Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", + "title": "Closed Source", + "type": "boolean" + }, + "created_at": { + "description": "Time the listing was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "modified_at": { + "description": "Time the listing was last modified", + "format": "date-time", + "title": "Modified At", + "type": "string" + }, + "metadata": { "anyOf": [ { - "minLength": 1, - "type": "string" + "$ref": "#/components/schemas/LibraryListingMetadataV1" }, { "type": "null" } ], "default": null, - "description": "Team ID for a team-scoped key. When omitted, uses the team in the URL if present, otherwise your organization's default team. Must match the URL team when both are provided. Not supported for PERSONAL or WORKSPACE_MANAGE_API_KEYS keys.", - "title": "Team Id" + "description": "Model-level metadata for this listing, if it has been uploaded." + } + }, + "required": [ + "display_name", + "user_defined_id", + "is_public", + "trending", + "closed_source", + "created_at", + "modified_at" + ], + "title": "LibraryListingV1", + "type": "object" + }, + "LibraryListingsV1": { + "description": "A list of library listings.", + "properties": { + "listings": { + "items": { + "$ref": "#/components/schemas/LibraryListingV1" + }, + "title": "Listings", + "type": "array" + } + }, + "required": [ + "listings" + ], + "title": "LibraryListingsV1", + "type": "object" + }, + "CreateLibraryListingRequestV1": { + "description": "Request to create a new library listing.", + "properties": { + "display_name": { + "description": "Display name of the library listing", + "title": "Display Name", + "type": "string" + }, + "user_defined_id": { + "description": "User-defined identifier of the library listing", + "title": "User Defined Id", + "type": "string" + }, + "is_public": { + "default": false, + "description": "Whether the listing is publicly accessible", + "title": "Is Public", + "type": "boolean" + }, + "closed_source": { + "default": false, + "description": "Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", + "title": "Closed Source", + "type": "boolean" } }, "required": [ - "type" + "display_name", + "user_defined_id" ], - "title": "CreateAPIKeyRequestV1", + "title": "CreateLibraryListingRequestV1", "type": "object" }, - "APIKeyV1": { - "description": "Represents an API key.", + "LibraryListingTombstoneV1": { + "description": "A library listing tombstone.", "properties": { - "api_key": { - "description": "The API key string", - "title": "Api Key", + "user_defined_id": { + "description": "User-defined identifier of the library listing", + "title": "User Defined Id", "type": "string" + }, + "deleted": { + "description": "Whether the library listing was deleted", + "title": "Deleted", + "type": "boolean" } }, "required": [ - "api_key" + "user_defined_id", + "deleted" ], - "title": "APIKeyV1", + "title": "LibraryListingTombstoneV1", "type": "object" }, - "APIKeyInfoV1": { - "description": "Represents the metadata of an API key.", + "UpdateLibraryListingRequestV1": { + "description": "Request to update a library listing.", "properties": { - "prefix": { - "description": "The prefix of the API key", - "title": "Prefix", - "type": "string" - }, - "name": { + "display_name": { "anyOf": [ { "type": "string" @@ -24289,584 +29255,383 @@ } ], "default": null, - "description": "Optional name for the API key", - "examples": [ - "my-api-key" - ], - "title": "Name" - }, - "type": { - "$ref": "#/components/schemas/APIKeyCategory", - "description": "Type of the API key.", - "examples": [ - "PERSONAL", - "WORKSPACE_MANAGE_API_KEYS", - "WORKSPACE_EXPORT_METRICS", - "WORKSPACE_INVOKE", - "WORKSPACE_MANAGE_ALL" - ] + "description": "New display name for the library listing", + "title": "Display Name" }, - "model_ids": { + "is_public": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "boolean" }, { "type": "null" } ], "default": null, - "description": "List of model IDs to scope the API key to, only present if type is 'WORKSPACE_EXPORT_METRICS' or 'WORKSPACE_INVOKE'", - "examples": [ - [ - "aaaaaaaa" - ] - ], - "title": "Model Ids" + "description": "Whether the listing is publicly accessible", + "title": "Is Public" }, - "team_name": { + "trending": { "anyOf": [ { - "type": "string" + "type": "boolean" }, { "type": "null" } ], "default": null, - "description": "The name of the team associated with the API key", - "title": "Team Name" + "description": "Whether the listing is trending", + "title": "Trending" }, - "owner": { + "metadata": { "anyOf": [ { - "$ref": "#/components/schemas/APIKeyOwnerV1" + "$ref": "#/components/schemas/LibraryListingMetadataV1" }, { "type": "null" } ], "default": null, - "description": "The user who owns the API key. Only present for personal API keys." + "description": "Model-level metadata for the listing. When provided, replaces the stored metadata. Unknown fields are rejected." } }, - "required": [ - "prefix", - "type" - ], - "title": "APIKeyInfoV1", + "title": "UpdateLibraryListingRequestV1", "type": "object" }, - "APIKeyOwnerV1": { - "description": "The user who owns a personal API key.", + "BenchmarkSnapshotV1": { "properties": { - "user_id": { - "description": "Unique identifier for the user", - "title": "User Id", + "run_id": { + "title": "Run Id", "type": "string" }, - "email": { + "measured_at": { + "format": "date", + "title": "Measured At", + "type": "string" + }, + "llm": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/LLMBenchmarkMetricsV1" }, { "type": "null" } ], - "default": null, - "description": "Email address of the user", - "title": "Email" + "default": null }, - "name": { + "tts": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/TTSBenchmarkMetricsV1" }, { "type": "null" } ], - "default": null, - "description": "Display name of the user", - "title": "Name" - } - }, - "required": [ - "user_id" - ], - "title": "APIKeyOwnerV1", - "type": "object" - }, - "APIKeysV1": { - "description": "A list of API keys.", - "properties": { - "keys": { - "description": "A list of API key information", - "items": { - "$ref": "#/components/schemas/APIKeyInfoV1" - }, - "title": "Keys", - "type": "array" - } - }, - "required": [ - "keys" - ], - "title": "APIKeysV1", - "type": "object" - }, - "APIKeyTombstoneV1": { - "description": "An API key tombstone.", - "properties": { - "prefix": { - "description": "Unique prefix of the API key", - "title": "Prefix", - "type": "string" - } - }, - "required": [ - "prefix" - ], - "title": "APIKeyTombstoneV1", - "type": "object" - }, - "LimitTypeV1": { - "enum": [ - "REQUEST", - "TOKEN" - ], - "title": "LimitTypeV1", - "type": "string" - }, - "ModelAPIOrgDetailsV1": { - "description": "Workspace-specific state for a Model API.", - "properties": { - "added_at": { - "description": "When the workspace first added this Model API.", - "format": "date-time", - "title": "Added At", - "type": "string" + "default": null }, - "last_used_at": { + "embedding": { + "anyOf": [ + { + "$ref": "#/components/schemas/EmbeddingBenchmarkMetricsV1" + }, + { + "type": "null" + } + ], + "default": null + }, + "replicas": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 2, + "title": "Replicas" + }, + "profile": { "anyOf": [ { - "format": "date-time", "type": "string" }, { "type": "null" } ], - "default": null, - "description": "When the workspace last invoked this Model API. Null if the workspace has never invoked it.", - "title": "Last Used At" + "default": "512x256", + "title": "Profile" } }, "required": [ - "added_at" + "run_id", + "measured_at" ], - "title": "ModelAPIOrgDetailsV1", + "title": "BenchmarkSnapshotV1", "type": "object" }, - "ModelAPIV1": { - "description": "A Model API catalog row, optionally enriched with workspace-specific state.", + "EmbeddingBenchmarkMetricsV1": { "properties": { - "name": { - "description": "Identifier of the Model API. Stable, URL-safe slug used as the public identifier.", - "examples": [ - "llama-3-3-70b-instruct" + "e2e_latency_ms_p50": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } ], - "title": "Name", - "type": "string" + "default": null, + "title": "E2E Latency Ms P50" }, - "display_name": { - "description": "Human-readable name of the Model API.", - "examples": [ - "Llama 3.3 70B Instruct" + "e2e_latency_ms_p99": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } ], - "title": "Display Name", - "type": "string" - }, - "description": { - "description": "Description of the Model API.", - "title": "Description", - "type": "string" + "default": null, + "title": "E2E Latency Ms P99" }, - "model_family": { + "input_tokens_per_sec": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Family the underlying model belongs to.", - "examples": [ - "META", - "DEEPSEEK", - "QWEN" - ], - "title": "Model Family" - }, - "release_date": { - "description": "Date the Model API was made available.", - "format": "date", - "title": "Release Date", - "type": "string" - }, - "invoke_url": { - "description": "Base URL for invoking the Model API. OpenAI-shaped routes (e.g. /v1/chat/completions) live underneath this host.", - "examples": [ - "https://inference.baseten.co" - ], - "title": "Invoke Url", - "type": "string" - }, - "context_length": { - "description": "The model's context window length, in tokens.", - "examples": [ - 8192 - ], - "title": "Context Length", - "type": "integer" + "title": "Input Tokens Per Sec" }, - "cost_per_million_input_tokens": { + "requests_per_sec": { "anyOf": [ { "type": "number" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" + } + ], + "default": null, + "title": "Requests Per Sec" + } + }, + "title": "EmbeddingBenchmarkMetricsV1", + "type": "object" + }, + "LLMBenchmarkMetricsV1": { + "properties": { + "ttft_ms_p50": { + "anyOf": [ + { + "type": "number" }, { "type": "null" } ], - "description": "Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", - "examples": [ - "0.13" - ], - "title": "Cost Per Million Input Tokens" + "default": null, + "title": "Ttft Ms P50" }, - "cost_per_million_output_tokens": { + "output_tokens_per_sec_per_user_p50": { "anyOf": [ { "type": "number" }, - { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" - }, { "type": "null" } ], - "description": "Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", - "examples": [ - "0.50" - ], - "title": "Cost Per Million Output Tokens" - }, - "rate_limits": { - "description": "Rate limits in effect for the workspace. Workspace-specific overrides are returned when the workspace has added this Model API and configured them; otherwise the catalog default rate limits are returned.", - "items": { - "$ref": "#/components/schemas/RateLimitV1" - }, - "title": "Rate Limits", - "type": "array" + "default": null, + "title": "Output Tokens Per Sec Per User P50" }, - "org_details": { + "max_concurrent_users_at_50ms_tpot": { "anyOf": [ { - "$ref": "#/components/schemas/ModelAPIOrgDetailsV1" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Workspace-specific state. Null when the workspace has not added this Model API." - } - }, - "required": [ - "name", - "display_name", - "description", - "release_date", - "invoke_url", - "context_length", - "cost_per_million_input_tokens", - "cost_per_million_output_tokens", - "rate_limits" - ], - "title": "ModelAPIV1", - "type": "object" - }, - "RateLimitUnitV1": { - "enum": [ - "SECOND", - "MINUTE" - ], - "title": "RateLimitUnitV1", - "type": "string" - }, - "RateLimitV1": { - "properties": { - "type": { - "$ref": "#/components/schemas/LimitTypeV1", - "description": "The type of the rate limit", - "examples": [ - "TOKEN", - "REQUEST" - ] - }, - "unit": { - "$ref": "#/components/schemas/RateLimitUnitV1", - "description": "The unit of the rate limit", - "examples": [ - "SECOND", - "MINUTE" - ] + "title": "Max Concurrent Users At 50Ms Tpot" }, - "threshold": { - "description": "The threshold for the rate limit", - "examples": [ - 1000, - 50000 + "requests_per_sec_p50": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } ], - "minimum": 0, - "title": "Threshold", - "type": "integer" - } - }, - "required": [ - "type", - "unit", - "threshold" - ], - "title": "RateLimitV1", - "type": "object" - }, - "ModelAPIsResponseV1": { - "description": "Page of Model APIs visible to the caller.", - "properties": { - "items": { - "description": "Items in this page.", - "items": { - "$ref": "#/components/schemas/ModelAPIV1" - }, - "title": "Items", - "type": "array" + "default": null, + "title": "Requests Per Sec P50" }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." - } - }, - "required": [ - "items", - "pagination" - ], - "title": "ModelAPIsResponseV1", - "type": "object" - }, - "ModelAPIsRequestV1": { - "description": "Query-string filters for ``GET /v1/model_apis``.", - "properties": { - "cursor": { + "cost_per_1m_tokens_usd": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", - "title": "Cursor" - }, - "limit": { - "default": 100, - "description": "Maximum number of items to return.", - "maximum": 1000, - "minimum": 1, - "title": "Limit", - "type": "integer" - }, - "added_only": { - "default": false, - "description": "When true, restrict the result to Model APIs the workspace has added. Defaults to the full visible catalog.", - "title": "Added Only", - "type": "boolean" + "title": "Cost Per 1M Tokens Usd" } }, - "title": "ModelAPIsRequestV1", + "title": "LLMBenchmarkMetricsV1", "type": "object" }, - "ModelApisUsageBucketV1": { - "description": "One time bucket and the usage recorded in it.", + "LibraryListingVersionV1": { + "description": "A library listing version.", "properties": { - "start_time": { - "description": "Start of the bucket (inclusive), UTC", + "version_tag": { + "description": "Human-readable tag for this version", + "title": "Version Tag", + "type": "string" + }, + "is_live": { + "description": "Whether this version is the live version", + "title": "Is Live", + "type": "boolean" + }, + "allow_truss_download": { + "description": "Whether users deploying this model can download the Truss", + "title": "Allow Truss Download", + "type": "boolean" + }, + "oracle_version_id": { + "description": "Id of the source model version", + "title": "Oracle Version Id", + "type": "string" + }, + "created_at": { + "description": "Time the version was created in ISO 8601 format", "format": "date-time", - "title": "Start Time", + "title": "Created At", "type": "string" }, - "end_time": { - "description": "End of the bucket (exclusive), UTC", + "modified_at": { + "description": "Time the version was last modified", "format": "date-time", - "title": "End Time", + "title": "Modified At", "type": "string" }, - "results": { - "description": "Usage totals for this bucket, ordered by total tokens descending", - "items": { - "$ref": "#/components/schemas/ModelApisUsageResultV1" - }, - "title": "Results", - "type": "array" + "benchmark": { + "anyOf": [ + { + "$ref": "#/components/schemas/BenchmarkSnapshotV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Benchmark snapshot for this version, if one has been uploaded." } }, "required": [ - "start_time", - "end_time" + "version_tag", + "is_live", + "allow_truss_download", + "oracle_version_id", + "created_at", + "modified_at" ], - "title": "ModelApisUsageBucketV1", + "title": "LibraryListingVersionV1", "type": "object" }, - "ModelApisUsageResultV1": { - "description": "Usage totals for one combination of the requested dimensions, within one bucket.", + "TTSBenchmarkMetricsV1": { "properties": { - "api_key_prefix": { + "ttft_ms_p50": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Prefix of the API key the usage is attributed to. Null when not grouping by api_key or when the request was not authenticated with an API key.", - "title": "Api Key Prefix" + "title": "Ttft Ms P50" }, - "user_id": { + "max_concurrent_streams_at_rtf1": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "User the usage is attributed to. Null when not grouping by user or when the credential is not user-scoped.", - "title": "User Id" + "title": "Max Concurrent Streams At Rtf1" }, - "model": { + "ttft_ms_p50_at_max_concurrency": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Model that served the usage. Null when not grouping by model.", - "title": "Model" - }, - "input_tokens": { - "description": "Total input tokens, cached and uncached combined.", - "title": "Input Tokens", - "type": "integer" - }, - "cached_input_tokens": { - "description": "Input tokens served from the prompt cache.", - "title": "Cached Input Tokens", - "type": "integer" - }, - "uncached_input_tokens": { - "description": "Input tokens not served from the prompt cache.", - "title": "Uncached Input Tokens", - "type": "integer" - }, - "output_tokens": { - "description": "Total output tokens.", - "title": "Output Tokens", - "type": "integer" + "title": "Ttft Ms P50 At Max Concurrency" }, - "request_count": { - "description": "Total number of requests.", - "title": "Request Count", - "type": "integer" + "cost_per_audio_minute_usd": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cost Per Audio Minute Usd" } }, - "required": [ - "input_tokens", - "cached_input_tokens", - "uncached_input_tokens", - "output_tokens", - "request_count" - ], - "title": "ModelApisUsageResultV1", + "title": "TTSBenchmarkMetricsV1", "type": "object" }, - "ModelApisUsageResponseV1": { - "description": "A page of Model APIs token usage: contiguous time buckets, ordered oldest first.", + "LibraryListingVersionsV1": { + "description": "A list of library listing versions.", "properties": { - "items": { - "description": "Items in this page.", + "versions": { "items": { - "$ref": "#/components/schemas/ModelApisUsageBucketV1" + "$ref": "#/components/schemas/LibraryListingVersionV1" }, - "title": "Items", + "title": "Versions", "type": "array" - }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." } }, "required": [ - "items", - "pagination" + "versions" ], - "title": "ModelApisUsageResponseV1", + "title": "LibraryListingVersionsV1", "type": "object" }, - "BucketWidth": { - "enum": [ - "1m", - "1h", - "1d" - ], - "title": "BucketWidth", - "type": "string" - }, - "UsageDimensionV1": { - "enum": [ - "api_key", - "user", - "model" - ], - "title": "UsageDimensionV1", - "type": "string" - }, - "ModelApisUsageRequestV1": { + "CreateLibraryListingVersionRequestV1": { + "description": "Request to create a new library listing version from an existing model version.", "properties": { - "start_time": { + "display_name": { "anyOf": [ { - "format": "date-time", "type": "string" }, { @@ -24874,113 +29639,154 @@ } ], "default": null, - "description": "Start of the query range (ISO 8601, UTC), inclusive. Snapped down to the start of its bucket. Required on the first page, and ignored when you pass a cursor.", - "title": "Start Time" + "description": "Display name of the library listing. Required when creating a new listing.", + "title": "Display Name" }, - "end_time": { + "is_public": { + "default": false, + "description": "Whether the listing is publicly accessible. Only used when creating a new listing.", + "title": "Is Public", + "type": "boolean" + }, + "oracle_version_id": { + "description": "Id of the source model version to publish", + "title": "Oracle Version Id", + "type": "string" + }, + "allow_truss_download": { + "default": false, + "description": "Whether users deploying this model can download the Truss", + "title": "Allow Truss Download", + "type": "boolean" + }, + "closed_source": { + "default": false, + "description": "Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream). Only used when creating a new listing.", + "title": "Closed Source", + "type": "boolean" + }, + "version_tag": { + "description": "Human-readable tag for this version", + "title": "Version Tag", + "type": "string" + } + }, + "required": [ + "oracle_version_id", + "version_tag" + ], + "title": "CreateLibraryListingVersionRequestV1", + "type": "object" + }, + "LibraryListingVersionTombstoneV1": { + "description": "A library listing version tombstone.", + "properties": { + "version_tag": { + "description": "Human-readable tag for this version", + "title": "Version Tag", + "type": "string" + }, + "deleted": { + "description": "Whether the library listing version was deleted", + "title": "Deleted", + "type": "boolean" + } + }, + "required": [ + "version_tag", + "deleted" + ], + "title": "LibraryListingVersionTombstoneV1", + "type": "object" + }, + "UpdateLibraryListingVersionRequestV1": { + "description": "Request to update a library listing version.", + "properties": { + "is_live": { "anyOf": [ { - "format": "date-time", - "type": "string" + "type": "boolean" }, { "type": "null" } ], "default": null, - "description": "End of the query range (ISO 8601, UTC), exclusive. Defaults to the current time.", - "title": "End Time" - }, - "bucket_width": { - "$ref": "#/components/schemas/BucketWidth", - "default": "1d", - "description": "Width of each time bucket: 1m, 1h, or 1d. Defaults to 1d." - }, - "group_by": { - "description": "Dimensions to break usage down by, repeated once per dimension: api_key, user, model. Defaults to model.", - "items": { - "$ref": "#/components/schemas/UsageDimensionV1" - }, - "title": "Group By", - "type": "array" - }, - "api_keys": { - "description": "Return only usage for these API key prefixes, repeated once per prefix.", - "items": { - "type": "string" - }, - "title": "Api Keys", - "type": "array" - }, - "user_ids": { - "description": "Return only usage attributed to these user IDs, repeated once per ID.", - "items": { - "type": "string" - }, - "title": "User Ids", - "type": "array" - }, - "models": { - "description": "Return only usage for these models, repeated once per model.", - "items": { - "type": "string" - }, - "title": "Models", - "type": "array" + "description": "Whether this version should be the live version. Setting to true demotes the current live version.", + "title": "Is Live" }, - "limit": { + "allow_truss_download": { "anyOf": [ { - "type": "integer" + "type": "boolean" }, { "type": "null" } ], "default": null, - "description": "Number of time buckets to return. Defaults and maximums depend on bucket_width: 1d defaults to 7 and allows 31, 1h defaults to 24 and allows 168, 1m defaults to 60 and allows 1440.", - "title": "Limit" + "description": "Whether users deploying this model can download the Truss", + "title": "Allow Truss Download" }, - "cursor": { + "benchmark": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/BenchmarkSnapshotV1" }, { "type": "null" } ], "default": null, - "description": "Opaque cursor from the pagination.cursor field of a previous response", - "title": "Cursor" + "description": "Benchmark snapshot for this version. When provided, replaces the stored benchmark." + } + }, + "title": "UpdateLibraryListingVersionRequestV1", + "type": "object" + }, + "ModelApisCostBucketV1": { + "description": "One daily bucket and the costs attributed to it.", + "properties": { + "date": { + "description": "UTC calendar date for this bucket, from midnight inclusive to the next midnight exclusive.", + "format": "date", + "title": "Date", + "type": "string" + }, + "results": { + "description": "Cost totals for the observed combinations of requested dimensions in this bucket, ordered by those dimensions. Empty when the day has no matching usage.", + "items": { + "$ref": "#/components/schemas/ModelApisCostResultV1" + }, + "title": "Results", + "type": "array" } }, - "title": "ModelApisUsageRequestV1", + "required": [ + "date" + ], + "title": "ModelApisCostBucketV1", "type": "object" }, - "CreateLLMModelRequestV1": { - "description": "A request to create a BIS-LLM model", + "ModelApisCostResultV1": { "properties": { - "resources": { - "additionalProperties": true, - "description": "Resources allocated to the model", - "title": "Resources", - "type": "object" - }, - "region": { + "api_key_prefixes": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], "default": null, - "description": "Region in which to deploy the model", - "title": "Region" + "description": "The single attributed API key prefix for this result. Null when not grouping by api_key_prefix or when attribution is unavailable.", + "title": "Api Key Prefixes" }, - "llm_version": { + "user_id": { "anyOf": [ { "type": "string" @@ -24990,160 +29796,190 @@ } ], "default": null, - "description": "Version of the helm chart to use.", - "title": "Llm Version" - }, - "llm_config": { - "additionalProperties": true, - "description": "Configuration specific to the LLM model", - "title": "Llm Config", - "type": "object" - }, - "environment_variables": { - "additionalProperties": true, - "description": "Environment variables for the model", - "title": "Environment Variables", - "type": "object" + "description": "Attributed user ID. Null when not grouping by user or when attribution is unavailable.", + "title": "User Id" }, - "model_metadata": { + "model": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Model metadata persisted into model_config", - "title": "Model Metadata" + "description": "Model identifier. Null when not grouping by model.", + "title": "Model" }, - "autoscaling_settings": { + "service_tier": { "anyOf": [ { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Autoscaling settings for the model", + "description": "Service tier. Null when not grouping by service_tier or when attribution is unavailable.", + "title": "Service Tier" + }, + "subtotal": { + "description": "Model API cost in USD for this day and grouping combination, returned as an exact decimal string preserving fractional-cent amounts. This amount may differ from finalized invoice amounts.", "examples": [ - { - "autoscaling_window": 600, - "concurrency_target": null, - "max_replica": 5, - "max_scale_down_rate": null, - "min_replica": 1, - "scale_down_delay": 300, - "target_in_flight_tokens": null, - "target_utilization_percentage": null - } - ] + "0.00000123" + ], + "title": "Subtotal", + "type": "string" + } + }, + "required": [ + "subtotal" + ], + "title": "ModelApisCostResultV1", + "type": "object" + }, + "ModelApisCostsResponseV1": { + "description": "One non-overlapping bucket per UTC day, ordered oldest first with no gaps.\n\nDays without matching usage are included with an empty results list.", + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/ModelApisCostBucketV1" + }, + "title": "Items", + "type": "array" }, - "additional_autoscaling_config": { + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "ModelApisCostsResponseV1", + "type": "object" + }, + "ModelApiCostDimensionV1": { + "enum": [ + "api_key_prefix", + "user", + "model", + "service_tier" + ], + "title": "ModelApiCostDimensionV1", + "type": "string" + }, + "ModelApisCostsRequestV1": { + "properties": { + "cursor": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Additional autoscaling configuration (e.g. target in-flight tokens)", - "examples": [ - { - "metrics": [ - { - "name": "in_flight_tokens", - "target": 40000 - } - ] - } - ], - "title": "Additional Autoscaling Config" + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "metadata": { + "limit": { + "default": 7, + "description": "Number of daily cost buckets to return. Defaults to 7; maximum 31.", + "maximum": 31, + "minimum": 1, + "title": "Limit", + "type": "integer" + }, + "start_date": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "format": "date", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "User-defined metadata for the deployment", - "examples": [ - { - "environment": "production", - "git_sha": "abc123" - } - ], - "title": "Metadata" + "description": "Inclusive UTC calendar day at the start of the query range. Defaults to the previous UTC date, cannot be before 2026-08-05, and is ignored when you pass a cursor.", + "title": "Start Date" }, - "weights": { + "end_date": { "anyOf": [ { - "items": { - "additionalProperties": true, - "type": "object" - }, - "type": "array" + "format": "date", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Weight configurations for BDN model weight distribution", - "examples": [ - [ - { - "mount_location": "/models/base", - "source": "hf://meta-llama/Llama-3-8B" - } - ] - ], - "title": "Weights" + "description": "Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included. The date range cannot exceed 90 days.", + "title": "End Date" }, - "name": { - "description": "Name of the model", - "title": "Name", - "type": "string" - } - }, - "required": [ - "resources", - "name" - ], - "title": "CreateLLMModelRequestV1", - "type": "object" - }, - "LLMModelHandleV1": { - "description": "Handle for a BIS-LLM model deployment.", - "properties": { - "model_id": { - "description": "Unique identifier of the model", - "title": "Model Id", - "type": "string" + "group_by": { + "description": "Dimensions to break costs down by, repeated once per dimension: api_key_prefix, user, model, or service_tier. Each result represents one observed combination of the requested dimensions within that day. For example, grouping by api_key_prefix and user returns each API-key and user pair that had usage. Combinations without usage are omitted, so result counts can differ between days. Omit for daily organization totals.", + "items": { + "$ref": "#/components/schemas/ModelApiCostDimensionV1" + }, + "title": "Group By", + "type": "array" }, - "version_id": { - "description": "Unique identifier of the model version", - "title": "Version Id", + "api_key_prefixes": { + "description": "Return only costs for these exact API key prefixes, repeated once per prefix.", + "items": { + "type": "string" + }, + "title": "Api Key Prefixes", + "type": "array" + }, + "user_ids": { + "description": "Return only costs attributed to these exact user IDs, repeated once per ID.", + "items": { + "type": "string" + }, + "title": "User Ids", + "type": "array" + }, + "models": { + "description": "Return only costs for these exact model identifiers, repeated once per model.", + "items": { + "type": "string" + }, + "title": "Models", + "type": "array" + }, + "service_tiers": { + "description": "Return only costs for these exact service tiers, repeated once per tier.", + "items": { + "type": "string" + }, + "title": "Service Tiers", + "type": "array" + } + }, + "title": "ModelApisCostsRequestV1", + "type": "object" + }, + "BillableResourceV1": { + "properties": { + "id": { + "description": "Unique identifier of the resource", + "title": "Id", "type": "string" }, - "hostname": { - "description": "Hostname used to invoke the model", - "title": "Hostname", - "type": "string" + "kind": { + "$ref": "#/components/schemas/ResourceKind", + "description": "Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, or LOOPS_SAMPLER)" }, - "instance_type_name": { + "name": { "anyOf": [ { "type": "string" @@ -25153,28 +29989,10 @@ } ], "default": null, - "description": "Name of the instance type the model deployment is running on", - "title": "Instance Type Name" - } - }, - "required": [ - "model_id", - "version_id", - "hostname" - ], - "title": "LLMModelHandleV1", - "type": "object" - }, - "CreateLLMModelVersionRequestV1": { - "description": "A request to create a BIS-LLM model version", - "properties": { - "resources": { - "additionalProperties": true, - "description": "Resources allocated to the model", - "title": "Resources", - "type": "object" + "description": "Name of the resource", + "title": "Name" }, - "region": { + "model_id": { "anyOf": [ { "type": "string" @@ -25184,10 +30002,10 @@ } ], "default": null, - "description": "Region in which to deploy the model", - "title": "Region" + "description": "Unique identifier of the parent model for model deployments and chainlets", + "title": "Model Id" }, - "llm_version": { + "model_name": { "anyOf": [ { "type": "string" @@ -25197,1165 +30015,1376 @@ } ], "default": null, - "description": "Version of the helm chart to use.", - "title": "Llm Version" + "description": "Name of the parent resource (e.g., model name for model deployments, training project name for training jobs)", + "title": "Model Name" }, - "llm_config": { - "additionalProperties": true, - "description": "Configuration specific to the LLM model", - "title": "Llm Config", - "type": "object" + "is_deleted": { + "description": "Indicates if the resource has been deleted", + "title": "Is Deleted", + "type": "boolean" }, - "environment_variables": { - "additionalProperties": true, - "description": "Environment variables for the model", - "title": "Environment Variables", - "type": "object" + "instance_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Instance type used", + "title": "Instance Type" }, - "model_metadata": { + "base_model": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Model metadata persisted into model_config", - "title": "Model Metadata" + "description": "Base model used by this Loops trainer or sampler", + "title": "Base Model" }, - "autoscaling_settings": { + "environment_name": { "anyOf": [ { - "$ref": "#/components/schemas/UpdateAutoscalingSettingsV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Autoscaling settings for the model", - "examples": [ + "description": "Environment name (e.g., 'production', 'staging')", + "title": "Environment Name" + }, + "chain_metadata": { + "anyOf": [ { - "autoscaling_window": 600, - "concurrency_target": null, - "max_replica": 5, - "max_scale_down_rate": null, - "min_replica": 1, - "scale_down_delay": 300, - "target_in_flight_tokens": null, - "target_utilization_percentage": null + "$ref": "#/components/schemas/ChainMetadataV1" + }, + { + "type": "null" } - ] + ], + "default": null, + "description": "Chain metadata if this is a chainlet deployment" }, - "additional_autoscaling_config": { + "team_id": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Additional autoscaling configuration (e.g. target in-flight tokens)", - "examples": [ + "description": "Unique identifier of the team that owns the resource. Only present for organizations with multiple teams enabled.", + "title": "Team Id" + }, + "team_name": { + "anyOf": [ { - "metrics": [ - { - "name": "in_flight_tokens", - "target": 40000 - } - ] + "type": "string" + }, + { + "type": "null" } ], - "title": "Additional Autoscaling Config" + "default": null, + "description": "Name of the team that owns the resource. Only present for organizations with multiple teams enabled.", + "title": "Team Name" + } + }, + "required": [ + "id", + "kind", + "is_deleted" + ], + "title": "BillableResourceV1", + "type": "object" + }, + "ChainMetadataV1": { + "properties": { + "chain_id": { + "description": "Unique identifier of the chain", + "title": "Chain Id", + "type": "string" }, - "metadata": { + "chain_name": { "anyOf": [ { - "additionalProperties": true, - "type": "object" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "User-defined metadata for the deployment", - "examples": [ + "description": "Name of the chain", + "title": "Chain Name" + }, + "chain_deployment_id": { + "description": "Unique identifier of the chain deployment", + "title": "Chain Deployment Id", + "type": "string" + } + }, + "required": [ + "chain_id", + "chain_deployment_id" + ], + "title": "ChainMetadataV1", + "type": "object" + }, + "DailyDedicatedUsageV1": { + "properties": { + "date": { + "description": "Date of the usage", + "format": "date", + "title": "Date", + "type": "string" + }, + "subtotal": { + "anyOf": [ { - "environment": "production", - "git_sha": "abc123" + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "title": "Metadata" + "description": "Subtotal cost incurred on this date in dollars", + "title": "Subtotal" }, - "weights": { + "compute_cost": { "anyOf": [ { - "items": { - "additionalProperties": true, - "type": "object" - }, - "type": "array" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "description": "Weight configurations for BDN model weight distribution", - "examples": [ - [ - { - "mount_location": "/models/base", - "source": "hf://meta-llama/Llama-3-8B" - } - ] + "description": "Compute cost incurred on this date in dollars", + "title": "Compute Cost" + }, + "surcharge_cost": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + } ], - "title": "Weights" + "description": "Model distribution surcharge incurred on this date in dollars", + "title": "Surcharge Cost" + }, + "minutes": { + "description": "Minutes used on this date", + "title": "Minutes", + "type": "integer" + }, + "inference_requests": { + "description": "Number of inference requests on this date", + "title": "Inference Requests", + "type": "integer" } }, "required": [ - "resources" + "date", + "subtotal", + "compute_cost", + "surcharge_cost", + "minutes", + "inference_requests" ], - "title": "CreateLLMModelVersionRequestV1", + "title": "DailyDedicatedUsageV1", "type": "object" }, - "LibraryListingMetadataV1": { - "additionalProperties": false, + "DailyModelApiUsageV1": { "properties": { - "parameter_count": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Parameter Count" + "date": { + "description": "Date of the usage", + "format": "date", + "title": "Date", + "type": "string" }, - "context_length": { + "subtotal": { "anyOf": [ { - "type": "integer" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "title": "Context Length" + "description": "Subtotal cost incurred on this date in dollars", + "title": "Subtotal" }, - "input_modalities": { - "default": [ - "text" - ], - "items": { - "$ref": "#/components/schemas/LibraryListingModality" - }, - "title": "Input Modalities", - "type": "array" + "input_tokens": { + "description": "Number of input tokens on this date", + "title": "Input Tokens", + "type": "integer" }, - "output_modalities": { - "default": [ - "text" - ], - "items": { - "$ref": "#/components/schemas/LibraryListingModality" - }, - "title": "Output Modalities", - "type": "array" + "output_tokens": { + "description": "Number of output tokens on this date", + "title": "Output Tokens", + "type": "integer" }, - "license": { - "title": "License", + "cached_input_tokens": { + "description": "Number of cached input tokens on this date", + "title": "Cached Input Tokens", + "type": "integer" + } + }, + "required": [ + "date", + "subtotal", + "input_tokens", + "output_tokens", + "cached_input_tokens" + ], + "title": "DailyModelApiUsageV1", + "type": "object" + }, + "DailyTrainingUsageV1": { + "properties": { + "date": { + "description": "Date of the usage", + "format": "date", + "title": "Date", "type": "string" }, - "variant": { + "subtotal": { "anyOf": [ { - "type": "string" + "type": "number" }, { - "type": "null" - } - ], - "default": null, - "title": "Variant" - }, - "publisher": { - "anyOf": [ - { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "type": "string" - }, - { - "type": "null" } ], - "default": null, - "title": "Publisher" + "description": "Subtotal cost incurred on this date in dollars", + "title": "Subtotal" }, - "model_api_slug": { + "minutes": { + "description": "Minutes used on this date", + "title": "Minutes", + "type": "integer" + } + }, + "required": [ + "date", + "subtotal", + "minutes" + ], + "title": "DailyTrainingUsageV1", + "type": "object" + }, + "DedicatedItemV1": { + "properties": { + "billable_resource": { + "$ref": "#/components/schemas/BillableResourceV1", + "description": "The model deployment resource" + }, + "subtotal": { "anyOf": [ { - "type": "string" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "title": "Model Api Slug" + "description": "Subtotal cost in dollars for this billable resource", + "title": "Subtotal" }, - "release_date": { + "compute_cost": { "anyOf": [ { - "format": "date", - "type": "string" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "title": "Release Date" + "description": "Compute cost in dollars for this billable resource", + "title": "Compute Cost" }, - "description": { + "surcharge_cost": { "anyOf": [ { - "type": "string" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "title": "Description" + "description": "Model distribution surcharge in dollars for this billable resource", + "title": "Surcharge Cost" }, - "trending": { - "default": false, - "title": "Trending", - "type": "boolean" + "minutes": { + "description": "Total minutes used for this billable resource", + "title": "Minutes", + "type": "integer" + }, + "inference_requests": { + "description": "Total inference requests for this billable resource", + "title": "Inference Requests", + "type": "integer" + }, + "daily": { + "description": "Daily usage breakdown", + "items": { + "$ref": "#/components/schemas/DailyDedicatedUsageV1" + }, + "title": "Daily", + "type": "array" } }, "required": [ - "license" + "billable_resource", + "subtotal", + "compute_cost", + "surcharge_cost", + "minutes", + "inference_requests" ], - "title": "LibraryListingMetadataV1", + "title": "DedicatedItemV1", "type": "object" }, - "LibraryListingModality": { - "enum": [ - "text", - "image", - "audio", - "video", - "embedding", - "rerank" - ], - "title": "LibraryListingModality", - "type": "string" - }, - "LibraryListingV1": { - "description": "A library listing.", + "DedicatedUsageV1": { "properties": { - "display_name": { - "description": "Display name of the library listing", - "title": "Display Name", - "type": "string" - }, - "user_defined_id": { - "description": "User-defined identifier of the library listing", - "title": "User Defined Id", - "type": "string" - }, - "is_public": { - "description": "Whether the listing is publicly accessible", - "title": "Is Public", - "type": "boolean" - }, - "trending": { + "subtotal": { "anyOf": [ { - "type": "boolean" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "description": "Whether the listing is trending", - "title": "Trending" - }, - "closed_source": { - "description": "Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", - "title": "Closed Source", - "type": "boolean" - }, - "created_at": { - "description": "Time the listing was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" + "description": "Subtotal cost in dollars after applying credits used", + "title": "Subtotal" }, - "modified_at": { - "description": "Time the listing was last modified", - "format": "date-time", - "title": "Modified At", - "type": "string" + "credits_used": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + } + ], + "description": "Credits applied in dollars", + "title": "Credits Used" }, - "metadata": { + "total": { "anyOf": [ { - "$ref": "#/components/schemas/LibraryListingMetadataV1" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "description": "Model-level metadata for this listing, if it has been uploaded." - } - }, - "required": [ - "display_name", - "user_defined_id", - "is_public", - "trending", - "closed_source", - "created_at", - "modified_at" - ], - "title": "LibraryListingV1", - "type": "object" - }, - "LibraryListingsV1": { - "description": "A list of library listings.", - "properties": { - "listings": { + "description": "Total cost in dollars", + "title": "Total" + }, + "minutes": { + "description": "Total minutes used", + "title": "Minutes", + "type": "integer" + }, + "breakdown": { + "description": "Per-deployment usage breakdown", "items": { - "$ref": "#/components/schemas/LibraryListingV1" + "$ref": "#/components/schemas/DedicatedItemV1" }, - "title": "Listings", + "title": "Breakdown", "type": "array" } }, "required": [ - "listings" + "subtotal", + "credits_used", + "total", + "minutes" ], - "title": "LibraryListingsV1", + "title": "DedicatedUsageV1", "type": "object" }, - "CreateLibraryListingRequestV1": { - "description": "Request to create a new library listing.", + "ModelApiItemV1": { "properties": { - "display_name": { - "description": "Display name of the library listing", - "title": "Display Name", + "model_name": { + "description": "Model name", + "title": "Model Name", "type": "string" }, - "user_defined_id": { - "description": "User-defined identifier of the library listing", - "title": "User Defined Id", - "type": "string" + "model_family": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model family (e.g., Meta, DeepSeek)", + "title": "Model Family" }, - "is_public": { - "default": false, - "description": "Whether the listing is publicly accessible", - "title": "Is Public", - "type": "boolean" + "subtotal": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + } + ], + "description": "Subtotal cost in dollars for this model", + "title": "Subtotal" }, - "closed_source": { - "default": false, - "description": "Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream)", - "title": "Closed Source", - "type": "boolean" - } - }, - "required": [ - "display_name", - "user_defined_id" - ], - "title": "CreateLibraryListingRequestV1", - "type": "object" - }, - "LibraryListingTombstoneV1": { - "description": "A library listing tombstone.", - "properties": { - "user_defined_id": { - "description": "User-defined identifier of the library listing", - "title": "User Defined Id", - "type": "string" + "input_tokens": { + "description": "Total input tokens for this model", + "title": "Input Tokens", + "type": "integer" }, - "deleted": { - "description": "Whether the library listing was deleted", - "title": "Deleted", - "type": "boolean" + "output_tokens": { + "description": "Total output tokens for this model", + "title": "Output Tokens", + "type": "integer" + }, + "cached_input_tokens": { + "description": "Total cached input tokens for this model", + "title": "Cached Input Tokens", + "type": "integer" + }, + "daily": { + "description": "Daily usage breakdown", + "items": { + "$ref": "#/components/schemas/DailyModelApiUsageV1" + }, + "title": "Daily", + "type": "array" } }, "required": [ - "user_defined_id", - "deleted" + "model_name", + "subtotal", + "input_tokens", + "output_tokens", + "cached_input_tokens" ], - "title": "LibraryListingTombstoneV1", + "title": "ModelApiItemV1", "type": "object" }, - "UpdateLibraryListingRequestV1": { - "description": "Request to update a library listing.", + "ModelApisUsageV1": { "properties": { - "display_name": { + "subtotal": { "anyOf": [ { - "type": "string" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "description": "New display name for the library listing", - "title": "Display Name" + "description": "Subtotal cost in dollars after applying credits used", + "title": "Subtotal" }, - "is_public": { + "credits_used": { "anyOf": [ { - "type": "boolean" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "description": "Whether the listing is publicly accessible", - "title": "Is Public" + "description": "Credits applied in dollars", + "title": "Credits Used" }, - "trending": { + "total": { "anyOf": [ { - "type": "boolean" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "description": "Whether the listing is trending", - "title": "Trending" + "description": "Total cost in dollars", + "title": "Total" }, - "metadata": { - "anyOf": [ - { - "$ref": "#/components/schemas/LibraryListingMetadataV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Model-level metadata for the listing. When provided, replaces the stored metadata. Unknown fields are rejected." + "breakdown": { + "description": "Per-model usage breakdown", + "items": { + "$ref": "#/components/schemas/ModelApiItemV1" + }, + "title": "Breakdown", + "type": "array" } }, - "title": "UpdateLibraryListingRequestV1", + "required": [ + "subtotal", + "credits_used", + "total" + ], + "title": "ModelApisUsageV1", "type": "object" }, - "BenchmarkSnapshotV1": { + "ResourceKind": { + "enum": [ + "LOOPS_SAMPLER", + "LOOPS_TRAINER", + "MODEL_DEPLOYMENT", + "TRAINING_JOB", + "CHAINLET" + ], + "title": "ResourceKind", + "type": "string" + }, + "TrainingItemV1": { "properties": { - "run_id": { - "title": "Run Id", - "type": "string" - }, - "measured_at": { - "format": "date", - "title": "Measured At", - "type": "string" + "billable_resource": { + "$ref": "#/components/schemas/BillableResourceV1", + "description": "The training job resource" }, - "llm": { + "subtotal": { "anyOf": [ { - "$ref": "#/components/schemas/LLMBenchmarkMetricsV1" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null + "description": "Subtotal cost in dollars for this billable resource", + "title": "Subtotal" }, - "tts": { + "minutes": { + "description": "Total minutes used for this billable resource", + "title": "Minutes", + "type": "integer" + }, + "daily": { + "description": "Daily usage breakdown", + "items": { + "$ref": "#/components/schemas/DailyTrainingUsageV1" + }, + "title": "Daily", + "type": "array" + } + }, + "required": [ + "billable_resource", + "subtotal", + "minutes" + ], + "title": "TrainingItemV1", + "type": "object" + }, + "TrainingUsageV1": { + "properties": { + "subtotal": { "anyOf": [ { - "$ref": "#/components/schemas/TTSBenchmarkMetricsV1" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null + "description": "Subtotal cost in dollars after applying credits used", + "title": "Subtotal" }, - "embedding": { + "credits_used": { "anyOf": [ { - "$ref": "#/components/schemas/EmbeddingBenchmarkMetricsV1" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null + "description": "Credits applied in dollars", + "title": "Credits Used" }, - "replicas": { + "total": { "anyOf": [ { - "type": "integer" + "type": "number" }, { - "type": "null" - } - ], - "default": 2, - "title": "Replicas" - }, - "profile": { - "anyOf": [ - { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", "type": "string" - }, - { - "type": "null" } ], - "default": "512x256", - "title": "Profile" + "description": "Total cost in dollars", + "title": "Total" + }, + "minutes": { + "description": "Total minutes used", + "title": "Minutes", + "type": "integer" + }, + "breakdown": { + "description": "Per-job usage breakdown", + "items": { + "$ref": "#/components/schemas/TrainingItemV1" + }, + "title": "Breakdown", + "type": "array" } }, "required": [ - "run_id", - "measured_at" + "subtotal", + "credits_used", + "total", + "minutes" ], - "title": "BenchmarkSnapshotV1", + "title": "TrainingUsageV1", "type": "object" }, - "EmbeddingBenchmarkMetricsV1": { + "UsageSummaryV1": { + "description": "Billing usage summary for the requested date range.", "properties": { - "e2e_latency_ms_p50": { + "dedicated_usage": { "anyOf": [ { - "type": "number" + "$ref": "#/components/schemas/DedicatedUsageV1" }, { "type": "null" } ], "default": null, - "title": "E2E Latency Ms P50" + "description": "Dedicated model serving usage" }, - "e2e_latency_ms_p99": { + "training_usage": { "anyOf": [ { - "type": "number" + "$ref": "#/components/schemas/TrainingUsageV1" }, { "type": "null" } ], "default": null, - "title": "E2E Latency Ms P99" + "description": "Training usage" }, - "input_tokens_per_sec": { + "model_apis_usage": { "anyOf": [ { - "type": "number" + "$ref": "#/components/schemas/ModelApisUsageV1" }, { "type": "null" } ], "default": null, - "title": "Input Tokens Per Sec" + "description": "Model APIs usage" + } + }, + "title": "UsageSummaryV1", + "type": "object" + }, + "UsageSummaryRequestV1": { + "properties": { + "start_date": { + "description": "Start date (ISO 8601, UTC). Earliest queryable: 2026-01-01.", + "format": "date-time", + "title": "Start Date", + "type": "string" }, - "requests_per_sec": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Requests Per Sec" + "end_date": { + "description": "End date in ISO 8601 format (UTC). Date range cannot exceed 31 days.", + "format": "date-time", + "title": "End Date", + "type": "string" } }, - "title": "EmbeddingBenchmarkMetricsV1", + "required": [ + "start_date", + "end_date" + ], + "title": "UsageSummaryRequestV1", "type": "object" }, - "LLMBenchmarkMetricsV1": { + "ToolCallUsageBucketV1": { + "description": "Server-side tool call usage for one day, provider, charge unit, and model.", "properties": { - "ttft_ms_p50": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Ttft Ms P50" + "date": { + "description": "UTC day the usage was recorded on.", + "format": "date", + "title": "Date", + "type": "string" }, - "output_tokens_per_sec_per_user_p50": { + "provider": { + "description": "Tool provider, such as exa or parallel.", + "title": "Provider", + "type": "string" + }, + "sku": { + "description": "Charge unit, as `/`. The unit is what the provider reported, or the tool name when it reported none. Its meaning varies by provider.", + "title": "Sku", + "type": "string" + }, + "model": { + "description": "Model that made the tool calls.", + "title": "Model", + "type": "string" + }, + "calls": { + "description": "Number of tool calls.", + "title": "Calls", + "type": "integer" + }, + "quantity": { + "description": "Billable quantity in the provider's sku unit, summed over the calls.", + "title": "Quantity", + "type": "number" + } + }, + "required": [ + "date", + "provider", + "sku", + "model", + "calls", + "quantity" + ], + "title": "ToolCallUsageBucketV1", + "type": "object" + }, + "ToolCallUsageResponseV1": { + "description": "Daily server-side tool call usage, ordered by day, provider, sku, and model.", + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/ToolCallUsageBucketV1" + }, + "title": "Items", + "type": "array" + } + }, + "title": "ToolCallUsageResponseV1", + "type": "object" + }, + "ToolCallUsageRequestV1": { + "properties": { + "start_date": { + "description": "Inclusive UTC calendar day at the start of the query range.", + "format": "date", + "title": "Start Date", + "type": "string" + }, + "end_date": { "anyOf": [ { - "type": "number" + "format": "date", + "type": "string" }, { "type": "null" } ], "default": null, - "title": "Output Tokens Per Sec Per User P50" + "description": "Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included. The date range cannot exceed 90 days.", + "title": "End Date" + } + }, + "required": [ + "start_date" + ], + "title": "ToolCallUsageRequestV1", + "type": "object" + }, + "UserInfoV1": { + "description": "A Baseten user.", + "properties": { + "user_id": { + "description": "Unique identifier for the user", + "title": "User Id", + "type": "string" }, - "max_concurrent_users_at_50ms_tpot": { + "email": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "title": "Max Concurrent Users At 50Ms Tpot" + "description": "Email address of the user", + "title": "Email" }, - "requests_per_sec_p50": { + "name": { "anyOf": [ { - "type": "number" + "type": "string" }, { "type": "null" } ], "default": null, - "title": "Requests Per Sec P50" + "description": "Display name of the user", + "title": "Name" }, - "cost_per_1m_tokens_usd": { + "workspace_name": { "anyOf": [ { - "type": "number" + "type": "string" }, { "type": "null" } ], "default": null, - "title": "Cost Per 1M Tokens Usd" + "description": "Name of the user's workspace", + "title": "Workspace Name" } }, - "title": "LLMBenchmarkMetricsV1", + "required": [ + "user_id" + ], + "title": "UserInfoV1", "type": "object" }, - "LibraryListingVersionV1": { - "description": "A library listing version.", - "properties": { - "version_tag": { - "description": "Human-readable tag for this version", - "title": "Version Tag", - "type": "string" - }, - "is_live": { - "description": "Whether this version is the live version", - "title": "Is Live", - "type": "boolean" - }, - "allow_truss_download": { - "description": "Whether users deploying this model can download the Truss", - "title": "Allow Truss Download", - "type": "boolean" - }, - "oracle_version_id": { - "description": "Id of the source model version", - "title": "Oracle Version Id", - "type": "string" - }, - "created_at": { - "description": "Time the version was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "modified_at": { - "description": "Time the version was last modified", - "format": "date-time", - "title": "Modified At", - "type": "string" + "UsersResponseV1": { + "description": "A page of users in the caller's workspace.", + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/UserInfoV1" + }, + "title": "Items", + "type": "array" }, - "benchmark": { - "anyOf": [ - { - "$ref": "#/components/schemas/BenchmarkSnapshotV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Benchmark snapshot for this version, if one has been uploaded." + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "version_tag", - "is_live", - "allow_truss_download", - "oracle_version_id", - "created_at", - "modified_at" + "items", + "pagination" ], - "title": "LibraryListingVersionV1", + "title": "UsersResponseV1", "type": "object" }, - "TTSBenchmarkMetricsV1": { + "UsersRequestV1": { + "description": "Request parameters for listing users.", "properties": { - "ttft_ms_p50": { + "cursor": { "anyOf": [ { - "type": "number" + "type": "string" }, { "type": "null" } ], "default": null, - "title": "Ttft Ms P50" + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "max_concurrent_streams_at_rtf1": { + "limit": { + "default": 100, + "description": "Maximum number of items to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + }, + "email": { "anyOf": [ { - "type": "integer" + "type": "string" }, { "type": "null" } ], "default": null, - "title": "Max Concurrent Streams At Rtf1" + "description": "When set, returns only users with this exact email, if any.", + "title": "Email" + } + }, + "title": "UsersRequestV1", + "type": "object" + }, + "AwsAssumeRoleV1": { + "description": "AWS AssumeRole trust-policy inputs for the organization.", + "properties": { + "baseten_role_arn": { + "description": "Baseten role ARN to allow in an IAM role's trust policy", + "title": "Baseten Role Arn", + "type": "string" }, - "ttft_ms_p50_at_max_concurrency": { + "external_id": { + "description": "sts:ExternalId Baseten presents when assuming the role", + "title": "External Id", + "type": "string" + } + }, + "required": [ + "baseten_role_arn", + "external_id" + ], + "title": "AwsAssumeRoleV1", + "type": "object" + }, + "OrganizationInfoV1": { + "description": "The caller's organization.", + "properties": { + "org_id": { + "description": "Unique identifier for the organization", + "title": "Org Id", + "type": "string" + }, + "name": { "anyOf": [ { - "type": "number" + "type": "string" }, { "type": "null" } ], "default": null, - "title": "Ttft Ms P50 At Max Concurrency" + "description": "Display name of the organization", + "title": "Name" }, - "cost_per_audio_minute_usd": { + "created_at": { + "description": "Time the organization was created in ISO 8601 format", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "aws_assume_role": { "anyOf": [ { - "type": "number" + "$ref": "#/components/schemas/AwsAssumeRoleV1" }, { "type": "null" } ], "default": null, - "title": "Cost Per Audio Minute Usd" + "description": "AWS AssumeRole trust-policy inputs; null while the method is not enabled for the organization" } }, - "title": "TTSBenchmarkMetricsV1", + "required": [ + "org_id", + "created_at" + ], + "title": "OrganizationInfoV1", "type": "object" }, - "LibraryListingVersionsV1": { - "description": "A list of library listing versions.", + "GatewayEventTokensV1": { "properties": { - "versions": { - "items": { - "$ref": "#/components/schemas/LibraryListingVersionV1" - }, - "title": "Versions", - "type": "array" + "inputTokens": { + "description": "Cached and uncached input tokens.", + "title": "Inputtokens", + "type": "integer" + }, + "outputTokens": { + "description": "Output tokens.", + "title": "Outputtokens", + "type": "integer" + }, + "cachedInputTokens": { + "description": "Cached input tokens.", + "title": "Cachedinputtokens", + "type": "integer" } }, "required": [ - "versions" + "inputTokens", + "outputTokens", + "cachedInputTokens" ], - "title": "LibraryListingVersionsV1", + "title": "GatewayEventTokensV1", "type": "object" }, - "CreateLibraryListingVersionRequestV1": { - "description": "Request to create a new library listing version from an existing model version.", + "GatewayEventV1": { "properties": { - "display_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Display name of the library listing. Required when creating a new listing.", - "title": "Display Name" + "type": { + "default": "API_BILLING_USAGE", + "description": "Event type.", + "title": "Type", + "type": "string" }, - "is_public": { - "default": false, - "description": "Whether the listing is publicly accessible. Only used when creating a new listing.", - "title": "Is Public", - "type": "boolean" + "idempotencyKey": { + "description": "Deduplication key.", + "title": "Idempotencykey", + "type": "string" }, - "oracle_version_id": { - "description": "Id of the source model version to publish", - "title": "Oracle Version Id", + "timestamp": { + "description": "Billing event time (ISO 8601, UTC).", + "title": "Timestamp", "type": "string" }, - "allow_truss_download": { - "default": false, - "description": "Whether users deploying this model can download the Truss", - "title": "Allow Truss Download", - "type": "boolean" + "requestId": { + "description": "Inference request ID.", + "title": "Requestid", + "type": "string" }, - "closed_source": { - "default": false, - "description": "Whether the listing is closed source (deployers cannot view or download the Truss, and forks copy mirrored weights instead of re-mirroring from upstream). Only used when creating a new listing.", - "title": "Closed Source", - "type": "boolean" + "modelSlug": { + "description": "Served model.", + "title": "Modelslug", + "type": "string" }, - "version_tag": { - "description": "Human-readable tag for this version", - "title": "Version Tag", + "externalEntityId": { + "description": "Calling group's external ID.", + "title": "Externalentityid", + "type": "string" + }, + "apiKeyPrefix": { + "description": "API key prefix.", + "title": "Apikeyprefix", "type": "string" + }, + "tokens": { + "$ref": "#/components/schemas/GatewayEventTokensV1" } }, "required": [ - "oracle_version_id", - "version_tag" + "idempotencyKey", + "timestamp", + "requestId", + "modelSlug", + "externalEntityId", + "apiKeyPrefix", + "tokens" ], - "title": "CreateLibraryListingVersionRequestV1", + "title": "GatewayEventV1", "type": "object" }, - "LibraryListingVersionTombstoneV1": { - "description": "A library listing version tombstone.", + "GatewayEventsResponseV1": { "properties": { - "version_tag": { - "description": "Human-readable tag for this version", - "title": "Version Tag", - "type": "string" + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/GatewayEventV1" + }, + "title": "Items", + "type": "array" }, - "deleted": { - "description": "Whether the library listing version was deleted", - "title": "Deleted", - "type": "boolean" + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "version_tag", - "deleted" + "items", + "pagination" ], - "title": "LibraryListingVersionTombstoneV1", + "title": "GatewayEventsResponseV1", "type": "object" }, - "UpdateLibraryListingVersionRequestV1": { - "description": "Request to update a library listing version.", + "GatewayEventsRequestV1": { "properties": { - "is_live": { + "start_time": { "anyOf": [ { - "type": "boolean" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Whether this version should be the live version. Setting to true demotes the current live version.", - "title": "Is Live" + "description": "Inclusive start (ISO 8601, UTC). Required without a cursor.", + "title": "Start Time" }, - "allow_truss_download": { + "end_time": { "anyOf": [ { - "type": "boolean" + "format": "date-time", + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Whether users deploying this model can download the Truss", - "title": "Allow Truss Download" + "description": "Exclusive end (ISO 8601, UTC). Defaults to now.", + "title": "End Time" }, - "benchmark": { + "limit": { "anyOf": [ { - "$ref": "#/components/schemas/BenchmarkSnapshotV1" + "maximum": 1000, + "minimum": 1, + "type": "integer" }, { "type": "null" } ], "default": null, - "description": "Benchmark snapshot for this version. When provided, replaces the stored benchmark." - } - }, - "title": "UpdateLibraryListingVersionRequestV1", - "type": "object" - }, - "ModelApisCostBucketV1": { - "description": "One daily bucket and the costs attributed to it.", - "properties": { - "date": { - "description": "UTC calendar date for this bucket, from midnight inclusive to the next midnight exclusive.", - "format": "date", - "title": "Date", - "type": "string" + "description": "Max events. Default 100, max 1000.", + "title": "Limit" }, - "results": { - "description": "Cost totals for the observed combinations of requested dimensions in this bucket, ordered by those dimensions. Empty when the day has no matching usage.", + "api_keys": { + "description": "Return only events for these API key prefixes, repeated once per prefix.", "items": { - "$ref": "#/components/schemas/ModelApisCostResultV1" + "type": "string" }, - "title": "Results", + "title": "Api Keys", + "type": "array" + }, + "external_entity_ids": { + "description": "Return only events for these external entity IDs, repeated once per ID.", + "items": { + "type": "string" + }, + "title": "External Entity Ids", "type": "array" + }, + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Next-page cursor. Other parameters are ignored.", + "title": "Cursor" } }, - "required": [ - "date" - ], - "title": "ModelApisCostBucketV1", + "title": "GatewayEventsRequestV1", "type": "object" }, - "ModelApisCostResultV1": { + "ExploreCostV1": { "properties": { - "api_key_prefixes": { + "input": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "The single attributed API key prefix for this result. Null when not grouping by api_key_prefix or when attribution is unavailable.", - "title": "Api Key Prefixes" + "description": "USD per 1M input tokens, when available.", + "title": "Input" }, - "user_id": { + "output": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Attributed user ID. Null when not grouping by user or when attribution is unavailable.", - "title": "User Id" + "description": "USD per 1M output tokens, when available.", + "title": "Output" }, - "model": { + "cache_read": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Model identifier. Null when not grouping by model.", - "title": "Model" + "description": "USD per 1M input tokens read from cache, when available.", + "title": "Cache Read" }, - "service_tier": { + "cache_write": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Service tier. Null when not grouping by service_tier or when attribution is unavailable.", - "title": "Service Tier" + "description": "USD per 1M input tokens written to cache, when available.", + "title": "Cache Write" }, - "subtotal": { - "description": "Model API cost in USD for this day and grouping combination, returned as an exact decimal string preserving fractional-cent amounts. This amount may differ from finalized invoice amounts.", - "examples": [ - "0.00000123" + "long_context": { + "anyOf": [ + { + "$ref": "#/components/schemas/ExploreCostValuesV1" + }, + { + "type": "null" + } ], - "title": "Subtotal", - "type": "string" - } - }, - "required": [ - "subtotal" - ], - "title": "ModelApisCostResultV1", - "type": "object" - }, - "ModelApisCostsResponseV1": { - "description": "One non-overlapping bucket per UTC day, ordered oldest first with no gaps.\n\nDays without matching usage are included with an empty results list.", - "properties": { - "items": { - "description": "Items in this page.", - "items": { - "$ref": "#/components/schemas/ModelApisCostBucketV1" - }, - "title": "Items", - "type": "array" - }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." + "default": null, + "description": "Prices for long-context requests, when the provider tiers by context length." } }, - "required": [ - "items", - "pagination" - ], - "title": "ModelApisCostsResponseV1", + "title": "ExploreCostV1", "type": "object" }, - "ModelApiCostDimensionV1": { - "enum": [ - "api_key_prefix", - "user", - "model", - "service_tier" - ], - "title": "ModelApiCostDimensionV1", - "type": "string" - }, - "ModelApisCostsRequestV1": { + "ExploreCostValuesV1": { "properties": { - "cursor": { + "input": { "anyOf": [ { - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", - "title": "Cursor" - }, - "limit": { - "default": 7, - "description": "Number of daily cost buckets to return. Defaults to 7; maximum 31.", - "maximum": 31, - "minimum": 1, - "title": "Limit", - "type": "integer" + "description": "USD per 1M input tokens, when available.", + "title": "Input" }, - "start_date": { + "output": { "anyOf": [ { - "format": "date", - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Inclusive UTC calendar day at the start of the query range. Defaults to the previous UTC date, cannot be before 2026-08-05, and is ignored when you pass a cursor.", - "title": "Start Date" + "description": "USD per 1M output tokens, when available.", + "title": "Output" }, - "end_date": { + "cache_read": { "anyOf": [ { - "format": "date", - "type": "string" + "type": "number" }, { "type": "null" } ], "default": null, - "description": "Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included. The date range cannot exceed 90 days.", - "title": "End Date" - }, - "group_by": { - "description": "Dimensions to break costs down by, repeated once per dimension: api_key_prefix, user, model, or service_tier. Each result represents one observed combination of the requested dimensions within that day. For example, grouping by api_key_prefix and user returns each API-key and user pair that had usage. Combinations without usage are omitted, so result counts can differ between days. Omit for daily organization totals.", - "items": { - "$ref": "#/components/schemas/ModelApiCostDimensionV1" - }, - "title": "Group By", - "type": "array" - }, - "api_key_prefixes": { - "description": "Return only costs for these exact API key prefixes, repeated once per prefix.", - "items": { - "type": "string" - }, - "title": "Api Key Prefixes", - "type": "array" + "description": "USD per 1M input tokens read from cache, when available.", + "title": "Cache Read" }, - "user_ids": { - "description": "Return only costs attributed to these exact user IDs, repeated once per ID.", - "items": { - "type": "string" - }, - "title": "User Ids", - "type": "array" + "cache_write": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "USD per 1M input tokens written to cache, when available.", + "title": "Cache Write" + } + }, + "title": "ExploreCostValuesV1", + "type": "object" + }, + "ExploreMetadataAPIFormatsV1": { + "properties": { + "messages": { + "default": false, + "description": "Anthropic Messages API support.", + "title": "Messages", + "type": "boolean" }, - "models": { - "description": "Return only costs for these exact model identifiers, repeated once per model.", - "items": { - "type": "string" - }, - "title": "Models", - "type": "array" + "responses": { + "default": false, + "description": "OpenAI Responses API support.", + "title": "Responses", + "type": "boolean" }, - "service_tiers": { - "description": "Return only costs for these exact service tiers, repeated once per tier.", - "items": { - "type": "string" - }, - "title": "Service Tiers", - "type": "array" + "chat_completions": { + "default": false, + "description": "OpenAI Chat Completions API support.", + "title": "Chat Completions", + "type": "boolean" } }, - "title": "ModelApisCostsRequestV1", + "title": "ExploreMetadataAPIFormatsV1", "type": "object" }, - "BillableResourceV1": { + "ExploreMetadataV1": { "properties": { - "id": { - "description": "Unique identifier of the resource", - "title": "Id", - "type": "string" + "slug": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Metadata slug, e.g. 'anthropic/claude-opus-4'; null for rows without one.", + "title": "Slug" }, - "kind": { - "$ref": "#/components/schemas/ResourceKind", - "description": "Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, or LOOPS_SAMPLER)" + "display_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Model display name, when available.", + "title": "Display Name" }, - "name": { + "release_date": { "anyOf": [ { + "format": "date", "type": "string" }, { "type": "null" } ], - "default": null, - "description": "Name of the resource", - "title": "Name" + "description": "Model release date. Month-only source dates use the first day of that month.", + "title": "Release Date" }, - "model_id": { + "provider": { "anyOf": [ { "type": "string" @@ -26364,445 +31393,628 @@ "type": "null" } ], - "default": null, - "description": "Unique identifier of the parent model for model deployments and chainlets", - "title": "Model Id" + "description": "Provider key derived from the slug prefix, e.g. 'anthropic'; null for unprefixed slugs.", + "title": "Provider" }, - "model_name": { + "context_window": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "default": null, - "description": "Name of the parent resource (e.g., model name for model deployments, training project name for training jobs)", - "title": "Model Name" - }, - "is_deleted": { - "description": "Indicates if the resource has been deleted", - "title": "Is Deleted", - "type": "boolean" + "description": "Total context window in tokens.", + "title": "Context Window" }, - "instance_type": { + "max_output_tokens": { "anyOf": [ { - "type": "string" + "type": "integer" }, { "type": "null" } ], - "default": null, - "description": "Instance type used", - "title": "Instance Type" + "description": "Maximum output tokens per response.", + "title": "Max Output Tokens" }, - "base_model": { + "input_modalities": { + "description": "Accepted input modalities.", + "items": { + "type": "string" + }, + "title": "Input Modalities", + "type": "array" + }, + "tools": { "anyOf": [ { - "type": "string" + "type": "boolean" }, { "type": "null" } ], - "default": null, - "description": "Base model used by this Loops trainer or sampler", - "title": "Base Model" + "description": "Whether the model supports tool calling.", + "title": "Tools" }, - "environment_name": { + "reasoning_effort_levels": { "anyOf": [ { - "type": "string" + "items": { + "type": "string" + }, + "type": "array" }, { "type": "null" } ], - "default": null, - "description": "Environment name (e.g., 'production', 'staging')", - "title": "Environment Name" + "description": "Reasoning effort levels the model supports.", + "title": "Reasoning Effort Levels" }, - "chain_metadata": { + "parallel_tool_calls": { "anyOf": [ { - "$ref": "#/components/schemas/ChainMetadataV1" + "type": "boolean" }, { "type": "null" } ], - "default": null, - "description": "Chain metadata if this is a chainlet deployment" + "description": "Whether the model supports parallel tool calls.", + "title": "Parallel Tool Calls" }, - "team_id": { + "supported_api_formats": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/ExploreMetadataAPIFormatsV1" }, { "type": "null" } ], - "default": null, - "description": "Unique identifier of the team that owns the resource. Only present for organizations with multiple teams enabled.", - "title": "Team Id" + "description": "API formats the model supports." }, - "team_name": { + "cost": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/ExploreCostV1" }, { "type": "null" } ], - "default": null, - "description": "Name of the team that owns the resource. Only present for organizations with multiple teams enabled.", - "title": "Team Name" + "description": "Provider list prices in USD per 1M tokens, when available." } }, "required": [ - "id", - "kind", - "is_deleted" + "slug", + "display_name", + "release_date", + "provider", + "context_window", + "max_output_tokens", + "input_modalities", + "tools", + "reasoning_effort_levels", + "parallel_tool_calls", + "supported_api_formats", + "cost" ], - "title": "BillableResourceV1", + "title": "ExploreMetadataV1", "type": "object" }, - "ChainMetadataV1": { + "ExploreMetadataResponseV1": { "properties": { - "chain_id": { - "description": "Unique identifier of the chain", - "title": "Chain Id", - "type": "string" - }, - "chain_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Name of the chain", - "title": "Chain Name" + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/ExploreMetadataV1" + }, + "title": "Items", + "type": "array" }, - "chain_deployment_id": { - "description": "Unique identifier of the chain deployment", - "title": "Chain Deployment Id", - "type": "string" + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "chain_id", - "chain_deployment_id" + "items", + "pagination" ], - "title": "ChainMetadataV1", + "title": "ExploreMetadataResponseV1", "type": "object" }, - "DailyDedicatedUsageV1": { + "ExploreMetadataRequestV1": { "properties": { - "date": { - "description": "Date of the usage", - "format": "date", - "title": "Date", - "type": "string" - }, - "subtotal": { + "cursor": { "anyOf": [ { - "type": "number" + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Subtotal cost incurred on this date in dollars", - "title": "Subtotal" + "default": null, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "compute_cost": { + "limit": { + "default": 100, + "description": "Maximum number of items to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + }, + "provider": { "anyOf": [ { - "type": "number" + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Compute cost incurred on this date in dollars", - "title": "Compute Cost" + "default": null, + "description": "Filter to a provider by slug prefix, e.g. 'anthropic'. Preserved by the cursor; if repeated, must match the original filter.", + "title": "Provider" }, - "surcharge_cost": { + "q": { "anyOf": [ { - "type": "number" + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Model distribution surcharge incurred on this date in dollars", - "title": "Surcharge Cost" + "default": null, + "description": "Case-insensitive substring search over metadata slugs. Preserved by the cursor; if repeated, must match the original filter.", + "title": "Q" + } + }, + "title": "ExploreMetadataRequestV1", + "type": "object" + }, + "RouteTargetAnthropicV1": { + "additionalProperties": false, + "properties": { + "type": { + "const": "ANTHROPIC", + "description": "Target kind for Anthropic.", + "title": "Type", + "type": "string" }, - "minutes": { - "description": "Minutes used on this date", - "title": "Minutes", - "type": "integer" + "model": { + "description": "Model name sent to the provider.", + "minLength": 1, + "title": "Model", + "type": "string" }, - "inference_requests": { - "description": "Number of inference requests on this date", - "title": "Inference Requests", - "type": "integer" + "secret_name": { + "description": "Name of a credential secret owned by the route's team.", + "minLength": 1, + "title": "Secret Name", + "type": "string" } }, "required": [ - "date", - "subtotal", - "compute_cost", - "surcharge_cost", - "minutes", - "inference_requests" + "type", + "model", + "secret_name" ], - "title": "DailyDedicatedUsageV1", + "title": "RouteTargetAnthropicV1", "type": "object" }, - "DailyModelApiUsageV1": { + "RouteTargetBasetenModelAPIV1": { + "additionalProperties": false, "properties": { - "date": { - "description": "Date of the usage", - "format": "date", - "title": "Date", + "type": { + "const": "BASETEN_MODEL_API", + "description": "Target kind for a Baseten Model API.", + "title": "Type", "type": "string" }, - "subtotal": { - "anyOf": [ - { - "type": "number" - }, - { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" - } - ], - "description": "Subtotal cost incurred on this date in dollars", - "title": "Subtotal" + "model": { + "description": "Name of the target Model API.", + "minLength": 1, + "title": "Model", + "type": "string" + } + }, + "required": [ + "type", + "model" + ], + "title": "RouteTargetBasetenModelAPIV1", + "type": "object" + }, + "RouteTargetOpenAIV1": { + "additionalProperties": false, + "properties": { + "type": { + "const": "OPENAI", + "description": "Target kind for OpenAI.", + "title": "Type", + "type": "string" }, - "input_tokens": { - "description": "Number of input tokens on this date", - "title": "Input Tokens", - "type": "integer" + "model": { + "description": "Model name sent to the provider.", + "minLength": 1, + "title": "Model", + "type": "string" }, - "output_tokens": { - "description": "Number of output tokens on this date", - "title": "Output Tokens", - "type": "integer" + "secret_name": { + "description": "Name of a credential secret owned by the route's team.", + "minLength": 1, + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "type", + "model", + "secret_name" + ], + "title": "RouteTargetOpenAIV1", + "type": "object" + }, + "RouteTargetXAIV1": { + "additionalProperties": false, + "properties": { + "type": { + "const": "XAI", + "description": "Target kind for xAI.", + "title": "Type", + "type": "string" + }, + "model": { + "description": "Model name sent to the provider.", + "minLength": 1, + "title": "Model", + "type": "string" }, - "cached_input_tokens": { - "description": "Number of cached input tokens on this date", - "title": "Cached Input Tokens", - "type": "integer" + "secret_name": { + "description": "Name of a credential secret owned by the route's team.", + "minLength": 1, + "title": "Secret Name", + "type": "string" } }, "required": [ - "date", - "subtotal", - "input_tokens", - "output_tokens", - "cached_input_tokens" + "type", + "model", + "secret_name" ], - "title": "DailyModelApiUsageV1", + "title": "RouteTargetXAIV1", "type": "object" }, - "DailyTrainingUsageV1": { + "RouteV1": { "properties": { - "date": { - "description": "Date of the usage", - "format": "date", - "title": "Date", + "id": { + "description": "Stable route identifier.", + "title": "Id", "type": "string" }, - "subtotal": { + "name": { + "description": "Name to send in the inference request's model field.", + "title": "Name", + "type": "string" + }, + "team_id": { + "description": "Identifier of the owning team.", + "title": "Team Id", + "type": "string" + }, + "team_name": { + "description": "Name of the owning team.", + "title": "Team Name", + "type": "string" + }, + "display_name": { + "description": "Display label, defaulting to the route name.", + "title": "Display Name", + "type": "string" + }, + "description": { + "description": "Short description of the route, empty when unset.", + "title": "Description", + "type": "string" + }, + "target": { + "description": "Configured upstream target.", + "discriminator": { + "mapping": { + "ANTHROPIC": "#/components/schemas/RouteTargetAnthropicV1", + "BASETEN_MODEL_API": "#/components/schemas/RouteTargetBasetenModelAPIV1", + "OPENAI": "#/components/schemas/RouteTargetOpenAIV1", + "XAI": "#/components/schemas/RouteTargetXAIV1" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/RouteTargetBasetenModelAPIV1" + }, + { + "$ref": "#/components/schemas/RouteTargetAnthropicV1" + }, + { + "$ref": "#/components/schemas/RouteTargetOpenAIV1" + }, + { + "$ref": "#/components/schemas/RouteTargetXAIV1" + } + ], + "title": "Target" + }, + "metadata": { "anyOf": [ { - "type": "number" + "$ref": "#/components/schemas/ExploreMetadataV1" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Subtotal cost incurred on this date in dollars", - "title": "Subtotal" + "description": "Resolved model metadata; null when the route has no linked metadata row." }, - "minutes": { - "description": "Minutes used on this date", - "title": "Minutes", - "type": "integer" + "invoke_url": { + "description": "Base URL for inference requests using this route.", + "title": "Invoke Url", + "type": "string" + }, + "created_at": { + "description": "Creation time, ISO 8601.", + "format": "date-time", + "title": "Created At", + "type": "string" } }, "required": [ - "date", - "subtotal", - "minutes" + "id", + "name", + "team_id", + "team_name", + "display_name", + "description", + "target", + "metadata", + "invoke_url", + "created_at" ], - "title": "DailyTrainingUsageV1", + "title": "RouteV1", "type": "object" }, - "DedicatedItemV1": { + "RoutesResponseV1": { "properties": { - "billable_resource": { - "$ref": "#/components/schemas/BillableResourceV1", - "description": "The model deployment resource" + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/RouteV1" + }, + "title": "Items", + "type": "array" }, - "subtotal": { + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "RoutesResponseV1", + "type": "object" + }, + "RoutesRequestV1": { + "properties": { + "cursor": { "anyOf": [ { - "type": "number" + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Subtotal cost in dollars for this billable resource", - "title": "Subtotal" + "default": null, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "compute_cost": { + "limit": { + "default": 100, + "description": "Maximum number of items to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + }, + "team_id": { "anyOf": [ { - "type": "number" + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Compute cost in dollars for this billable resource", - "title": "Compute Cost" + "default": null, + "description": "Filter by owning team ID. Preserved by the cursor; if repeated, must match the original filter.", + "title": "Team Id" }, - "surcharge_cost": { + "name": { "anyOf": [ { - "type": "number" + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Model distribution surcharge in dollars for this billable resource", - "title": "Surcharge Cost" - }, - "minutes": { - "description": "Total minutes used for this billable resource", - "title": "Minutes", - "type": "integer" - }, - "inference_requests": { - "description": "Total inference requests for this billable resource", - "title": "Inference Requests", - "type": "integer" - }, - "daily": { - "description": "Daily usage breakdown", - "items": { - "$ref": "#/components/schemas/DailyDedicatedUsageV1" - }, - "title": "Daily", - "type": "array" + "default": null, + "description": "Filter by exact route name. Preserved by the cursor; if repeated, must match the original filter.", + "title": "Name" } }, - "required": [ - "billable_resource", - "subtotal", - "compute_cost", - "surcharge_cost", - "minutes", - "inference_requests" - ], - "title": "DedicatedItemV1", + "title": "RoutesRequestV1", "type": "object" }, - "DedicatedUsageV1": { + "CreateRouteRequestV1": { + "additionalProperties": false, "properties": { - "subtotal": { + "team_id": { "anyOf": [ { - "type": "number" + "minLength": 1, + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Subtotal cost in dollars after applying credits used", - "title": "Subtotal" + "default": null, + "description": "Identifier of the team that owns the route. When omitted, uses your organization's default team.", + "examples": [ + "abc1234" + ], + "title": "Team Id" }, - "credits_used": { + "display_name": { "anyOf": [ { - "type": "number" + "maxLength": 255, + "minLength": 1, + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Credits applied in dollars", - "title": "Credits Used" + "default": null, + "description": "Display label. Omit to use the route name; null is not accepted.", + "examples": [ + "Assistant" + ], + "title": "Display Name" }, - "total": { - "anyOf": [ + "target": { + "description": "Upstream target for the route.", + "discriminator": { + "mapping": { + "ANTHROPIC": "#/components/schemas/RouteTargetAnthropicV1", + "BASETEN_MODEL_API": "#/components/schemas/RouteTargetBasetenModelAPIV1", + "OPENAI": "#/components/schemas/RouteTargetOpenAIV1", + "XAI": "#/components/schemas/RouteTargetXAIV1" + }, + "propertyName": "type" + }, + "examples": [ { - "type": "number" + "model": "zai-org/GLM-5.3", + "type": "BASETEN_MODEL_API" + } + ], + "oneOf": [ + { + "$ref": "#/components/schemas/RouteTargetBasetenModelAPIV1" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "$ref": "#/components/schemas/RouteTargetAnthropicV1" + }, + { + "$ref": "#/components/schemas/RouteTargetOpenAIV1" + }, + { + "$ref": "#/components/schemas/RouteTargetXAIV1" } ], - "description": "Total cost in dollars", - "title": "Total" + "title": "Target" }, - "minutes": { - "description": "Total minutes used", - "title": "Minutes", - "type": "integer" + "description": { + "anyOf": [ + { + "maxLength": 1000, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Short description of the route. Omit for no description; null is not accepted.", + "examples": [ + "Assistant for code review and debugging." + ], + "title": "Description" + } + }, + "required": [ + "target" + ], + "title": "CreateRouteRequestV1", + "type": "object" + }, + "RouteProviderV1": { + "description": "Upstream provider of a route target, named like the route target types.", + "enum": [ + "BASETEN_MODEL_API", + "OPENAI", + "ANTHROPIC", + "XAI", + "VERTEX", + "OPENAI_COMPATIBLE" + ], + "title": "RouteProviderV1", + "type": "string" + }, + "RoutesUsageBucketV1": { + "properties": { + "date": { + "description": "UTC calendar date for this bucket, from midnight inclusive to the next midnight exclusive.", + "format": "date", + "title": "Date", + "type": "string" }, - "breakdown": { - "description": "Per-deployment usage breakdown", + "results": { + "description": "Usage broken down by the requested dimensions. Empty when there is no usage.", "items": { - "$ref": "#/components/schemas/DedicatedItemV1" + "$ref": "#/components/schemas/RoutesUsageResultV1" }, - "title": "Breakdown", + "title": "Results", "type": "array" } }, "required": [ - "subtotal", - "credits_used", - "total", - "minutes" + "date", + "results" ], - "title": "DedicatedUsageV1", + "title": "RoutesUsageBucketV1", "type": "object" }, - "ModelApiItemV1": { + "RoutesUsageResultV1": { "properties": { - "model_name": { - "description": "Model name", - "title": "Model Name", - "type": "string" + "user_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "ID of the user who created the Routes key. Null when not grouping by USER.", + "title": "User Id" }, - "model_family": { + "model": { "anyOf": [ { "type": "string" @@ -26812,306 +32024,358 @@ } ], "default": null, - "description": "Model family (e.g., llama, mistral)", - "title": "Model Family" + "description": "Model name. For external providers, the model name sent to the provider. Null when not grouping by MODEL.", + "title": "Model" }, - "subtotal": { + "provider": { "anyOf": [ { - "type": "number" + "$ref": "#/components/schemas/RouteProviderV1" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Subtotal cost in dollars for this model", - "title": "Subtotal" + "default": null, + "description": "Provider that served the requests. Null when not grouping by PROVIDER." + }, + "cost_usd": { + "description": "Estimated cost in USD, returned as an exact decimal string. Costs for OpenAI, Anthropic, and xAI estimate what you pay those providers; they are not Baseten charges.", + "examples": [ + "0.00035625" + ], + "title": "Cost Usd", + "type": "string" }, "input_tokens": { - "description": "Total input tokens for this model", + "description": "Input tokens, including cached input tokens.", "title": "Input Tokens", "type": "integer" }, - "output_tokens": { - "description": "Total output tokens for this model", - "title": "Output Tokens", - "type": "integer" - }, "cached_input_tokens": { - "description": "Total cached input tokens for this model", + "description": "Input tokens read from the prompt cache.", "title": "Cached Input Tokens", "type": "integer" }, - "daily": { - "description": "Daily usage breakdown", - "items": { - "$ref": "#/components/schemas/DailyModelApiUsageV1" - }, - "title": "Daily", - "type": "array" + "uncached_input_tokens": { + "description": "Input tokens not read from the prompt cache, including tokens written to the cache.", + "title": "Uncached Input Tokens", + "type": "integer" + }, + "output_tokens": { + "description": "Output tokens.", + "title": "Output Tokens", + "type": "integer" } }, "required": [ - "model_name", - "subtotal", + "cost_usd", "input_tokens", - "output_tokens", - "cached_input_tokens" + "cached_input_tokens", + "uncached_input_tokens", + "output_tokens" ], - "title": "ModelApiItemV1", + "title": "RoutesUsageResultV1", "type": "object" }, - "ModelApisUsageV1": { + "RoutesUsageResponseV1": { "properties": { - "subtotal": { - "anyOf": [ - { - "type": "number" - }, - { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" - } - ], - "description": "Subtotal cost in dollars after applying credits used", - "title": "Subtotal" - }, - "credits_used": { - "anyOf": [ - { - "type": "number" - }, - { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" - } - ], - "description": "Credits applied in dollars", - "title": "Credits Used" - }, - "total": { - "anyOf": [ - { - "type": "number" - }, - { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" - } - ], - "description": "Total cost in dollars", - "title": "Total" - }, - "breakdown": { - "description": "Per-model usage breakdown", + "items": { + "description": "Items in this page.", "items": { - "$ref": "#/components/schemas/ModelApiItemV1" + "$ref": "#/components/schemas/RoutesUsageBucketV1" }, - "title": "Breakdown", + "title": "Items", "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "subtotal", - "credits_used", - "total" + "items", + "pagination" ], - "title": "ModelApisUsageV1", + "title": "RoutesUsageResponseV1", "type": "object" }, - "ResourceKind": { + "RouteUsageDimensionV1": { "enum": [ - "LOOPS_SAMPLER", - "LOOPS_TRAINER", - "MODEL_DEPLOYMENT", - "TRAINING_JOB", - "CHAINLET" + "USER", + "MODEL", + "PROVIDER" ], - "title": "ResourceKind", + "title": "RouteUsageDimensionV1", "type": "string" }, - "TrainingItemV1": { + "RoutesUsageRequestV1": { "properties": { - "billable_resource": { - "$ref": "#/components/schemas/BillableResourceV1", - "description": "The training job resource" - }, - "subtotal": { + "cursor": { "anyOf": [ { - "type": "number" + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Subtotal cost in dollars for this billable resource", - "title": "Subtotal" + "default": null, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" }, - "minutes": { - "description": "Total minutes used for this billable resource", - "title": "Minutes", + "limit": { + "default": 7, + "description": "Number of daily buckets to return. Defaults to 7; maximum 31.", + "maximum": 31, + "minimum": 1, + "title": "Limit", "type": "integer" }, - "daily": { - "description": "Daily usage breakdown", - "items": { - "$ref": "#/components/schemas/DailyTrainingUsageV1" - }, - "title": "Daily", - "type": "array" - } - }, - "required": [ - "billable_resource", - "subtotal", - "minutes" - ], - "title": "TrainingItemV1", - "type": "object" - }, - "TrainingUsageV1": { - "properties": { - "subtotal": { + "start_date": { "anyOf": [ { - "type": "number" - }, - { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "format": "date", "type": "string" - } - ], - "description": "Subtotal cost in dollars after applying credits used", - "title": "Subtotal" - }, - "credits_used": { - "anyOf": [ - { - "type": "number" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Credits applied in dollars", - "title": "Credits Used" + "default": null, + "description": "Inclusive UTC calendar day at the start of the query range. Defaults to the previous UTC date, and is ignored when you pass a cursor.", + "title": "Start Date" }, - "total": { + "end_date": { "anyOf": [ { - "type": "number" + "format": "date", + "type": "string" }, { - "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", - "type": "string" + "type": "null" } ], - "description": "Total cost in dollars", - "title": "Total" + "default": null, + "description": "Exclusive UTC calendar day at the end of the query range. Defaults to the day after the current UTC date so current-day usage is included.", + "title": "End Date" }, - "minutes": { - "description": "Total minutes used", - "title": "Minutes", - "type": "integer" + "group_by": { + "description": "Dimensions to break usage down by, repeated once per dimension: USER, MODEL, or PROVIDER. Each result represents one observed combination of the requested dimensions within that day, and results are sorted by those values. Combinations without usage are omitted, so result counts can differ between days. Defaults to MODEL.", + "items": { + "$ref": "#/components/schemas/RouteUsageDimensionV1" + }, + "title": "Group By", + "type": "array" + }, + "user_ids": { + "description": "Return only usage from Routes keys created by these user IDs, repeated once per ID.", + "items": { + "type": "string" + }, + "title": "User Ids", + "type": "array" }, - "breakdown": { - "description": "Per-job usage breakdown", + "models": { + "description": "Return only usage for these exact model names, repeated once per model.", "items": { - "$ref": "#/components/schemas/TrainingItemV1" + "type": "string" }, - "title": "Breakdown", + "title": "Models", + "type": "array" + }, + "providers": { + "description": "Return only usage for these providers, repeated once per provider.", + "items": { + "$ref": "#/components/schemas/RouteProviderV1" + }, + "title": "Providers", "type": "array" } }, - "required": [ - "subtotal", - "credits_used", - "total", - "minutes" - ], - "title": "TrainingUsageV1", + "title": "RoutesUsageRequestV1", "type": "object" }, - "UsageSummaryV1": { - "description": "Billing usage summary for the requested date range.", + "RouteSpendLimitV1": { "properties": { - "dedicated_usage": { + "user_id": { + "description": "ID of the user.", + "examples": [ + "abc1234" + ], + "title": "User Id", + "type": "string" + }, + "email": { "anyOf": [ { - "$ref": "#/components/schemas/DedicatedUsageV1" + "type": "string" }, { "type": "null" } ], - "default": null, - "description": "Dedicated model serving usage" + "description": "Email address of the user.", + "examples": [ + "dev@example.com" + ], + "title": "Email" }, - "training_usage": { + "monthly_limit_usd": { "anyOf": [ { - "$ref": "#/components/schemas/TrainingUsageV1" + "type": "string" }, { "type": "null" } ], - "default": null, - "description": "Training usage" - }, - "model_apis_usage": { + "description": "Standing spend limit in USD for each UTC calendar month, returned as an exact decimal string. Null when the user has no standing limit.", + "examples": [ + "200" + ], + "title": "Monthly Limit Usd" + } + }, + "required": [ + "user_id", + "email", + "monthly_limit_usd" + ], + "title": "RouteSpendLimitV1", + "type": "object" + }, + "UpdateRouteSpendLimitRequestV1": { + "additionalProperties": false, + "minProperties": 1, + "properties": { + "monthly_limit_usd": { "anyOf": [ { - "$ref": "#/components/schemas/ModelApisUsageV1" + "type": "string" }, { "type": "null" } ], "default": null, - "description": "Model APIs usage" + "description": "Standing spend limit in USD for each UTC calendar month, as a non-negative decimal string with at most 9 decimal places. Send null to remove the limit; omit to leave it unchanged.", + "examples": [ + "200" + ], + "title": "Monthly Limit Usd", + "x-null-distinct": true } }, - "title": "UsageSummaryV1", + "title": "UpdateRouteSpendLimitRequestV1", "type": "object" }, - "UsageSummaryRequestV1": { + "RouteHarness": { + "enum": [ + "claude-code", + "opencode", + "codex" + ], + "title": "RouteHarness", + "type": "string" + }, + "RouteHarnessConfigV1": { "properties": { - "start_date": { - "description": "Start date (ISO 8601, UTC). Earliest queryable: 2026-01-01.", - "format": "date-time", - "title": "Start Date", - "type": "string" + "models": { + "additionalProperties": { + "$ref": "#/components/schemas/RouteHarnessModelV1" + }, + "description": "Route for each model role, keyed by role.", + "propertyNames": { + "$ref": "#/components/schemas/RouteHarnessRole" + }, + "title": "Models", + "type": "object" + } + }, + "required": [ + "models" + ], + "title": "RouteHarnessConfigV1", + "type": "object" + }, + "RouteHarnessModelSource": { + "enum": [ + "team", + "baseten" + ], + "title": "RouteHarnessModelSource", + "type": "string" + }, + "RouteHarnessModelV1": { + "properties": { + "source": { + "$ref": "#/components/schemas/RouteHarnessModelSource", + "description": "Who chose this role's route: `team` if a team admin set it, or `baseten` if it is Baseten's default, chosen from the team's Model API routes." }, - "end_date": { - "description": "End date in ISO 8601 format (UTC). Date range cannot exceed 31 days.", - "format": "date-time", - "title": "End Date", - "type": "string" + "route": { + "$ref": "#/components/schemas/RouteV1", + "description": "Route to use for this role." } }, "required": [ - "start_date", - "end_date" + "source", + "route" ], - "title": "UsageSummaryRequestV1", + "title": "RouteHarnessModelV1", "type": "object" }, - "UserInfoV1": { - "description": "A Baseten user.", + "RouteHarnessRole": { + "enum": [ + "primary", + "background" + ], + "title": "RouteHarnessRole", + "type": "string" + }, + "RouteHarnessConfigsResponseV1": { "properties": { - "user_id": { - "description": "Unique identifier for the user", - "title": "User Id", + "harness_configs": { + "additionalProperties": { + "$ref": "#/components/schemas/RouteHarnessConfigV1" + }, + "description": "Default models for each harness, keyed by harness. A harness is omitted when none of its roles has a route.", + "propertyNames": { + "$ref": "#/components/schemas/RouteHarness" + }, + "title": "Harness Configs", + "type": "object" + } + }, + "required": [ + "harness_configs" + ], + "title": "RouteHarnessConfigsResponseV1", + "type": "object" + }, + "RouteHarnessConfigsRequestV1": { + "properties": { + "team_id": { + "description": "Identifier of the team whose default models to list.", + "minLength": 1, + "title": "Team Id", "type": "string" - }, - "email": { + } + }, + "required": [ + "team_id" + ], + "title": "RouteHarnessConfigsRequestV1", + "type": "object" + }, + "UpdateBackgroundHarnessModelsV1": { + "additionalProperties": false, + "minProperties": 1, + "properties": { + "primary": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -27119,12 +32383,16 @@ } ], "default": null, - "description": "Email address of the user", - "title": "Email" + "description": "Route ID for the primary model, which new sessions use. Omit to keep the current route, or pass null to use Baseten's default.", + "examples": [ + "abc1234" + ], + "title": "Primary" }, - "name": { + "background": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -27132,12 +32400,108 @@ } ], "default": null, - "description": "Display name of the user", - "title": "Name" + "description": "Route ID for background tasks, such as session titles. Omit to keep the current route, or pass null to use Baseten's default.", + "examples": [ + "def5678" + ], + "title": "Background" + } + }, + "title": "UpdateBackgroundHarnessModelsV1", + "type": "object" + }, + "UpdateClaudeCodeHarnessConfigV1": { + "additionalProperties": false, + "properties": { + "team_id": { + "description": "Identifier of the team whose default models to set. Every route must belong to this team.", + "minLength": 1, + "title": "Team Id", + "type": "string" }, - "workspace_name": { + "harness": { + "const": "claude-code", + "description": "Claude Code, which supports the `primary` and `background` roles.", + "title": "Harness", + "type": "string" + }, + "models": { + "$ref": "#/components/schemas/UpdateBackgroundHarnessModelsV1", + "description": "Route IDs for the model roles to change. Roles left out are unchanged." + } + }, + "required": [ + "team_id", + "harness", + "models" + ], + "title": "UpdateClaudeCodeHarnessConfigV1", + "type": "object" + }, + "UpdateCodexHarnessConfigV1": { + "additionalProperties": false, + "properties": { + "team_id": { + "description": "Identifier of the team whose default models to set. Every route must belong to this team.", + "minLength": 1, + "title": "Team Id", + "type": "string" + }, + "harness": { + "const": "codex", + "description": "Codex, which supports only the `primary` role.", + "title": "Harness", + "type": "string" + }, + "models": { + "$ref": "#/components/schemas/UpdatePrimaryHarnessModelsV1", + "description": "Route IDs for the model roles to change. Roles left out are unchanged." + } + }, + "required": [ + "team_id", + "harness", + "models" + ], + "title": "UpdateCodexHarnessConfigV1", + "type": "object" + }, + "UpdateOpenCodeHarnessConfigV1": { + "additionalProperties": false, + "properties": { + "team_id": { + "description": "Identifier of the team whose default models to set. Every route must belong to this team.", + "minLength": 1, + "title": "Team Id", + "type": "string" + }, + "harness": { + "const": "opencode", + "description": "OpenCode, which supports the `primary` and `background` roles.", + "title": "Harness", + "type": "string" + }, + "models": { + "$ref": "#/components/schemas/UpdateBackgroundHarnessModelsV1", + "description": "Route IDs for the model roles to change. Roles left out are unchanged." + } + }, + "required": [ + "team_id", + "harness", + "models" + ], + "title": "UpdateOpenCodeHarnessConfigV1", + "type": "object" + }, + "UpdatePrimaryHarnessModelsV1": { + "additionalProperties": false, + "minProperties": 1, + "properties": { + "primary": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -27145,45 +32509,45 @@ } ], "default": null, - "description": "Name of the user's workspace", - "title": "Workspace Name" + "description": "Route ID for the primary model, which new sessions use. Omit to keep the current route, or pass null to use Baseten's default.", + "examples": [ + "abc1234" + ], + "title": "Primary" } }, - "required": [ - "user_id" - ], - "title": "UserInfoV1", + "title": "UpdatePrimaryHarnessModelsV1", "type": "object" }, - "UsersResponseV1": { - "description": "A page of users in the caller's workspace.", - "properties": { - "items": { - "description": "Items in this page.", - "items": { - "$ref": "#/components/schemas/UserInfoV1" - }, - "title": "Items", - "type": "array" + "UpdateRouteHarnessConfigRequestV1": { + "discriminator": { + "mapping": { + "claude-code": "#/components/schemas/UpdateClaudeCodeHarnessConfigV1", + "codex": "#/components/schemas/UpdateCodexHarnessConfigV1", + "opencode": "#/components/schemas/UpdateOpenCodeHarnessConfigV1" }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." - } + "propertyName": "harness" }, - "required": [ - "items", - "pagination" + "oneOf": [ + { + "$ref": "#/components/schemas/UpdateClaudeCodeHarnessConfigV1" + }, + { + "$ref": "#/components/schemas/UpdateOpenCodeHarnessConfigV1" + }, + { + "$ref": "#/components/schemas/UpdateCodexHarnessConfigV1" + } ], - "title": "UsersResponseV1", - "type": "object" + "title": "UpdateRouteHarnessConfigRequestV1" }, - "UsersRequestV1": { - "description": "Request parameters for listing users.", + "BackgroundHarnessModelsV1": { + "additionalProperties": false, "properties": { - "cursor": { + "primary": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -27191,20 +32555,16 @@ } ], "default": null, - "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", - "title": "Cursor" - }, - "limit": { - "default": 100, - "description": "Maximum number of items to return.", - "maximum": 1000, - "minimum": 1, - "title": "Limit", - "type": "integer" + "description": "Route ID for the primary model, which new sessions use. Omit to use Baseten's default.", + "examples": [ + "abc1234" + ], + "title": "Primary" }, - "email": { + "background": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -27212,45 +32572,23 @@ } ], "default": null, - "description": "When set, returns only users with this exact email, if any.", - "title": "Email" - } - }, - "title": "UsersRequestV1", - "type": "object" - }, - "AwsAssumeRoleV1": { - "description": "AWS AssumeRole trust-policy inputs for the organization.", - "properties": { - "baseten_role_arn": { - "description": "Baseten role ARN to allow in an IAM role's trust policy", - "title": "Baseten Role Arn", - "type": "string" - }, - "external_id": { - "description": "sts:ExternalId Baseten presents when assuming the role", - "title": "External Id", - "type": "string" + "description": "Route ID for background tasks, such as session titles. Omit to use Baseten's default.", + "examples": [ + "def5678" + ], + "title": "Background" } }, - "required": [ - "baseten_role_arn", - "external_id" - ], - "title": "AwsAssumeRoleV1", + "title": "BackgroundHarnessModelsV1", "type": "object" }, - "OrganizationInfoV1": { - "description": "The caller's organization.", + "PrimaryHarnessModelsV1": { + "additionalProperties": false, "properties": { - "org_id": { - "description": "Unique identifier for the organization", - "title": "Org Id", - "type": "string" - }, - "name": { + "primary": { "anyOf": [ { + "minLength": 1, "type": "string" }, { @@ -27258,201 +32596,202 @@ } ], "default": null, - "description": "Display name of the organization", - "title": "Name" + "description": "Route ID for the primary model, which new sessions use. Omit to use Baseten's default.", + "examples": [ + "abc1234" + ], + "title": "Primary" + } + }, + "title": "PrimaryHarnessModelsV1", + "type": "object" + }, + "SetClaudeCodeHarnessConfigV1": { + "additionalProperties": false, + "properties": { + "team_id": { + "description": "Identifier of the team whose default models to set. Every route must belong to this team.", + "minLength": 1, + "title": "Team Id", + "type": "string" }, - "created_at": { - "description": "Time the organization was created in ISO 8601 format", - "format": "date-time", - "title": "Created At", + "harness": { + "const": "claude-code", + "description": "Claude Code, which supports the `primary` and `background` roles.", + "title": "Harness", "type": "string" }, - "aws_assume_role": { - "anyOf": [ - { - "$ref": "#/components/schemas/AwsAssumeRoleV1" - }, - { - "type": "null" - } - ], - "default": null, - "description": "AWS AssumeRole trust-policy inputs; null while the method is not enabled for the organization" + "models": { + "$ref": "#/components/schemas/BackgroundHarnessModelsV1", + "description": "Route ID for each model role. Roles left out use Baseten's defaults." } }, "required": [ - "org_id", - "created_at" + "team_id", + "harness", + "models" ], - "title": "OrganizationInfoV1", + "title": "SetClaudeCodeHarnessConfigV1", "type": "object" }, - "GatewayEventTokensV1": { + "SetCodexHarnessConfigV1": { + "additionalProperties": false, "properties": { - "inputTokens": { - "description": "Cached and uncached input tokens.", - "title": "Inputtokens", - "type": "integer" + "team_id": { + "description": "Identifier of the team whose default models to set. Every route must belong to this team.", + "minLength": 1, + "title": "Team Id", + "type": "string" }, - "outputTokens": { - "description": "Output tokens.", - "title": "Outputtokens", - "type": "integer" + "harness": { + "const": "codex", + "description": "Codex, which supports only the `primary` role.", + "title": "Harness", + "type": "string" }, - "cachedInputTokens": { - "description": "Cached input tokens.", - "title": "Cachedinputtokens", - "type": "integer" + "models": { + "$ref": "#/components/schemas/PrimaryHarnessModelsV1", + "description": "Route ID for each model role. Roles left out use Baseten's defaults." } }, "required": [ - "inputTokens", - "outputTokens", - "cachedInputTokens" + "team_id", + "harness", + "models" ], - "title": "GatewayEventTokensV1", + "title": "SetCodexHarnessConfigV1", "type": "object" }, - "GatewayEventV1": { + "SetOpenCodeHarnessConfigV1": { + "additionalProperties": false, "properties": { - "type": { - "default": "API_BILLING_USAGE", - "description": "Event type.", - "title": "Type", + "team_id": { + "description": "Identifier of the team whose default models to set. Every route must belong to this team.", + "minLength": 1, + "title": "Team Id", "type": "string" }, - "idempotencyKey": { - "description": "Deduplication key.", - "title": "Idempotencykey", + "harness": { + "const": "opencode", + "description": "OpenCode, which supports the `primary` and `background` roles.", + "title": "Harness", "type": "string" }, - "timestamp": { - "description": "Billing event time (ISO 8601, UTC).", - "title": "Timestamp", - "type": "string" + "models": { + "$ref": "#/components/schemas/BackgroundHarnessModelsV1", + "description": "Route ID for each model role. Roles left out use Baseten's defaults." + } + }, + "required": [ + "team_id", + "harness", + "models" + ], + "title": "SetOpenCodeHarnessConfigV1", + "type": "object" + }, + "SetRouteHarnessConfigRequestV1": { + "discriminator": { + "mapping": { + "claude-code": "#/components/schemas/SetClaudeCodeHarnessConfigV1", + "codex": "#/components/schemas/SetCodexHarnessConfigV1", + "opencode": "#/components/schemas/SetOpenCodeHarnessConfigV1" }, - "requestId": { - "description": "Inference request ID.", - "title": "Requestid", - "type": "string" + "propertyName": "harness" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/SetClaudeCodeHarnessConfigV1" }, - "modelSlug": { - "description": "Served model.", - "title": "Modelslug", - "type": "string" + { + "$ref": "#/components/schemas/SetOpenCodeHarnessConfigV1" }, - "externalEntityId": { - "description": "Calling group's external ID.", - "title": "Externalentityid", - "type": "string" + { + "$ref": "#/components/schemas/SetCodexHarnessConfigV1" + } + ], + "title": "SetRouteHarnessConfigRequestV1" + }, + "RouteHarnessConfigTombstoneV1": { + "properties": { + "harness": { + "$ref": "#/components/schemas/RouteHarness", + "description": "Harness whose default models were cleared." }, - "apiKeyPrefix": { - "description": "API key prefix.", - "title": "Apikeyprefix", + "team_id": { + "description": "Identifier of the team whose default models were cleared.", + "title": "Team Id", "type": "string" - }, - "tokens": { - "$ref": "#/components/schemas/GatewayEventTokensV1" } }, "required": [ - "idempotencyKey", - "timestamp", - "requestId", - "modelSlug", - "externalEntityId", - "apiKeyPrefix", - "tokens" + "harness", + "team_id" ], - "title": "GatewayEventV1", + "title": "RouteHarnessConfigTombstoneV1", "type": "object" }, - "GatewayEventsResponseV1": { + "ClearRouteHarnessConfigRequestV1": { "properties": { - "items": { - "description": "Items in this page.", - "items": { - "$ref": "#/components/schemas/GatewayEventV1" - }, - "title": "Items", - "type": "array" - }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." + "team_id": { + "description": "Identifier of the team whose default models to clear.", + "minLength": 1, + "title": "Team Id", + "type": "string" } }, "required": [ - "items", - "pagination" + "team_id" ], - "title": "GatewayEventsResponseV1", + "title": "ClearRouteHarnessConfigRequestV1", "type": "object" }, - "GatewayEventsRequestV1": { + "RouteTombstoneV1": { "properties": { - "start_time": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Inclusive start (ISO 8601, UTC). Required without a cursor.", - "title": "Start Time" - }, - "end_time": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Exclusive end (ISO 8601, UTC). Defaults to now.", - "title": "End Time" - }, - "limit": { - "anyOf": [ - { - "maximum": 1000, - "minimum": 1, - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Max events. Default 100, max 1000.", - "title": "Limit" - }, - "api_keys": { - "description": "Return only events for these API key prefixes, repeated once per prefix.", - "items": { - "type": "string" - }, - "title": "Api Keys", - "type": "array" + "id": { + "description": "Stable identifier of the deleted route.", + "title": "Id", + "type": "string" }, - "external_entity_ids": { - "description": "Return only events for these external entity IDs, repeated once per ID.", - "items": { - "type": "string" - }, - "title": "External Entity Ids", - "type": "array" + "name": { + "description": "Name of the deleted route.", + "title": "Name", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "title": "RouteTombstoneV1", + "type": "object" + }, + "UpdateRouteRequestV1": { + "additionalProperties": false, + "minProperties": 1, + "properties": { + "description": { + "anyOf": [ + { + "maxLength": 1000, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "New description. Omit to keep the current description; use an empty string to clear it. Null is not accepted.", + "examples": [ + "Assistant for code review and debugging." + ], + "title": "Description" }, - "cursor": { + "display_name": { "anyOf": [ { + "maxLength": 255, + "minLength": 1, "type": "string" }, { @@ -27460,11 +32799,14 @@ } ], "default": null, - "description": "Next-page cursor. Other parameters are ignored.", - "title": "Cursor" + "description": "New display label. Omit to keep the current label; null is not accepted.", + "examples": [ + "Assistant" + ], + "title": "Display Name" } }, - "title": "GatewayEventsRequestV1", + "title": "UpdateRouteRequestV1", "type": "object" }, "EndpointTargetV1": { @@ -27611,7 +32953,6 @@ "type": "object" }, "GatewayProvider": { - "description": "Customer-facing provider for an endpoint target.\n\nExternal providers resolve to a fixed upstream host + protocol adapter via\n``external_provider_configs()``; ``BASETEN`` derives its host from the referenced oracle.", "enum": [ "ANTHROPIC", "OPENAI", @@ -27921,7 +33262,245 @@ "title": "UpdateEndpointRequestV1", "type": "object" }, - "EffectiveModelConfigV1": { + "EffectiveModelConfigV1": { + "properties": { + "slug": { + "description": "Shared endpoint slug.", + "title": "Slug", + "type": "string" + }, + "rate_limits": { + "items": { + "$ref": "#/components/schemas/EffectiveRateLimitV1" + }, + "title": "Rate Limits", + "type": "array" + }, + "usage_limits": { + "items": { + "$ref": "#/components/schemas/EffectiveUsageLimitV1" + }, + "title": "Usage Limits", + "type": "array" + } + }, + "required": [ + "slug" + ], + "title": "EffectiveModelConfigV1", + "type": "object" + }, + "EffectiveRateLimitV1": { + "properties": { + "type": { + "$ref": "#/components/schemas/LimitTypeV1", + "description": "The type of the rate limit", + "examples": [ + "TOKEN", + "REQUEST" + ] + }, + "unit": { + "$ref": "#/components/schemas/RateLimitUnitV1", + "description": "The unit of the rate limit", + "examples": [ + "SECOND", + "MINUTE" + ] + }, + "threshold": { + "description": "The threshold for the rate limit", + "examples": [ + 1000, + 50000 + ], + "minimum": 0, + "title": "Threshold", + "type": "integer" + }, + "source_group": { + "description": "ID of the group in the hierarchy this limit is anchored to.", + "examples": [ + "abc123" + ], + "title": "Source Group", + "type": "string" + } + }, + "required": [ + "type", + "unit", + "threshold", + "source_group" + ], + "title": "EffectiveRateLimitV1", + "type": "object" + }, + "EffectiveUsageLimitV1": { + "properties": { + "type": { + "$ref": "#/components/schemas/LimitTypeV1", + "description": "The type of the usage limit", + "examples": [ + "REQUEST", + "TOKEN" + ] + }, + "unit": { + "$ref": "#/components/schemas/UsageLimitUnitV1", + "description": "The unit of the usage limit", + "examples": [ + "DAY" + ] + }, + "threshold": { + "description": "The threshold for the usage limit", + "examples": [ + 10000000 + ], + "minimum": 0, + "title": "Threshold", + "type": "integer" + }, + "source_group": { + "description": "ID of the group in the hierarchy this limit is anchored to.", + "examples": [ + "abc123" + ], + "title": "Source Group", + "type": "string" + } + }, + "required": [ + "type", + "unit", + "threshold", + "source_group" + ], + "title": "EffectiveUsageLimitV1", + "type": "object" + }, + "GroupHierarchyV1": { + "properties": { + "limit_enforcement": { + "$ref": "#/components/schemas/LimitEnforcementV1", + "examples": [ + "CASCADING", + "INDEPENDENT" + ] + }, + "parent_group_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "examples": [ + "abc123" + ], + "title": "Parent Group Id" + } + }, + "required": [ + "limit_enforcement" + ], + "title": "GroupHierarchyV1", + "type": "object" + }, + "GroupMetadataV1": { + "properties": { + "name": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional display name for the group.", + "examples": [ + "Acme prod" + ], + "title": "Name" + }, + "external_entity_id": { + "description": "External-system identifier for this group. Unique within the caller's org.", + "examples": [ + "cust_42" + ], + "maxLength": 255, + "minLength": 1, + "title": "External Entity Id", + "type": "string" + } + }, + "required": [ + "external_entity_id" + ], + "title": "GroupMetadataV1", + "type": "object" + }, + "GroupV1": { + "properties": { + "id": { + "description": "Internal Baseten ID for the group.", + "title": "Id", + "type": "string" + }, + "metadata": { + "$ref": "#/components/schemas/GroupMetadataV1", + "description": "Group identity + display metadata." + }, + "models": { + "items": { + "$ref": "#/components/schemas/ModelConfigV1" + }, + "title": "Models", + "type": "array" + }, + "effective_models": { + "items": { + "$ref": "#/components/schemas/EffectiveModelConfigV1" + }, + "title": "Effective Models", + "type": "array" + }, + "hierarchy": { + "$ref": "#/components/schemas/GroupHierarchyV1", + "description": "Parent linkage and limit enforcement mode. Parent is null for root groups." + }, + "created_at": { + "description": "When this group was created.", + "format": "date-time", + "title": "Created At", + "type": "string" + } + }, + "required": [ + "id", + "metadata", + "hierarchy", + "created_at" + ], + "title": "GroupV1", + "type": "object" + }, + "LimitEnforcementV1": { + "enum": [ + "CASCADING", + "INDEPENDENT" + ], + "title": "LimitEnforcementV1", + "type": "string" + }, + "ModelConfigV1": { "properties": { "slug": { "description": "Shared endpoint slug.", @@ -27930,14 +33509,14 @@ }, "rate_limits": { "items": { - "$ref": "#/components/schemas/EffectiveRateLimitV1" + "$ref": "#/components/schemas/RateLimitV1" }, "title": "Rate Limits", "type": "array" }, "usage_limits": { "items": { - "$ref": "#/components/schemas/EffectiveUsageLimitV1" + "$ref": "#/components/schemas/UsageLimitV1" }, "title": "Usage Limits", "type": "array" @@ -27946,109 +33525,258 @@ "required": [ "slug" ], - "title": "EffectiveModelConfigV1", + "title": "ModelConfigV1", "type": "object" }, - "EffectiveRateLimitV1": { + "UsageLimitUnitV1": { + "enum": [ + "DAY" + ], + "title": "UsageLimitUnitV1", + "type": "string" + }, + "UsageLimitV1": { "properties": { "type": { "$ref": "#/components/schemas/LimitTypeV1", - "description": "The type of the rate limit", + "description": "The type of the usage limit", "examples": [ - "TOKEN", - "REQUEST" + "REQUEST", + "TOKEN" ] }, "unit": { - "$ref": "#/components/schemas/RateLimitUnitV1", - "description": "The unit of the rate limit", + "$ref": "#/components/schemas/UsageLimitUnitV1", + "description": "The unit of the usage limit", "examples": [ - "SECOND", - "MINUTE" + "DAY" ] }, "threshold": { - "description": "The threshold for the rate limit", + "description": "The threshold for the usage limit", "examples": [ - 1000, - 50000 + 10000000 ], "minimum": 0, "title": "Threshold", "type": "integer" - }, - "source_group": { - "description": "ID of the group in the hierarchy this limit is anchored to.", - "examples": [ - "abc123" - ], - "title": "Source Group", - "type": "string" } }, "required": [ "type", "unit", - "threshold", - "source_group" + "threshold" ], - "title": "EffectiveRateLimitV1", + "title": "UsageLimitV1", "type": "object" }, - "EffectiveUsageLimitV1": { + "GroupsResponseV1": { "properties": { - "type": { - "$ref": "#/components/schemas/LimitTypeV1", - "description": "The type of the usage limit", + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/GroupV1" + }, + "title": "Items", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "GroupsResponseV1", + "type": "object" + }, + "CreateGroupHierarchyV1": { + "properties": { + "limit_enforcement": { + "anyOf": [ + { + "$ref": "#/components/schemas/LimitEnforcementV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Limit behavior. Child groups inherit their parent's behavior when omitted; root groups default to Independent for backwards compatibility.", "examples": [ - "REQUEST", - "TOKEN" + "INDEPENDENT" ] }, - "unit": { - "$ref": "#/components/schemas/UsageLimitUnitV1", - "description": "The unit of the usage limit", + "parent_group_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, "examples": [ - "DAY" - ] + "abc123" + ], + "title": "Parent Group Id" + } + }, + "title": "CreateGroupHierarchyV1", + "type": "object" + }, + "CreateGroupRequestV1": { + "properties": { + "metadata": { + "$ref": "#/components/schemas/GroupMetadataV1", + "description": "Group identity + display metadata." }, - "threshold": { - "description": "The threshold for the usage limit", + "models": { + "description": "Per-model rate and usage limit configuration. Defines the group's complete model set. Must be non-empty.", "examples": [ - 10000000 + [ + { + "slug": "my-org/claude" + } + ] ], - "minimum": 0, - "title": "Threshold", - "type": "integer" + "items": { + "$ref": "#/components/schemas/ModelConfigV1" + }, + "minItems": 1, + "title": "Models", + "type": "array" }, - "source_group": { - "description": "ID of the group in the hierarchy this limit is anchored to.", + "hierarchy": { + "$ref": "#/components/schemas/CreateGroupHierarchyV1", + "description": "Parent linkage and limit enforcement mode. Immutable after creation." + } + }, + "required": [ + "metadata", + "models", + "hierarchy" + ], + "title": "CreateGroupRequestV1", + "type": "object" + }, + "UpdateGroupMetadataV1": { + "properties": { + "name": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional display name for the group.", "examples": [ - "abc123" + "Acme prod" ], - "title": "Source Group", + "title": "Name" + } + }, + "title": "UpdateGroupMetadataV1", + "type": "object" + }, + "UpdateGroupRequestV1": { + "properties": { + "metadata": { + "anyOf": [ + { + "$ref": "#/components/schemas/UpdateGroupMetadataV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Mutable group metadata.", + "examples": [ + { + "name": "Acme Prod" + } + ] + }, + "models": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/ModelConfigV1" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Per-model rate and usage limit configuration.", + "title": "Models" + } + }, + "title": "UpdateGroupRequestV1", + "type": "object" + }, + "GatewayKeyInfoV1": { + "properties": { + "prefix": { + "description": "The prefix of the Model API key.", + "title": "Prefix", "type": "string" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional display name.", + "title": "Name" + } + }, + "required": [ + "prefix" + ], + "title": "GatewayKeyInfoV1", + "type": "object" + }, + "KeysForGroupResponseV1": { + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/GatewayKeyInfoV1" + }, + "title": "Items", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "type", - "unit", - "threshold", - "source_group" + "items", + "pagination" ], - "title": "EffectiveUsageLimitV1", + "title": "KeysForGroupResponseV1", "type": "object" }, - "GroupHierarchyV1": { + "CreateApiKeyForGroupRequestV1": { "properties": { - "limit_enforcement": { - "$ref": "#/components/schemas/LimitEnforcementV1", - "examples": [ - "CASCADING", - "INDEPENDENT" - ] - }, - "parent_group_id": { + "name": { "anyOf": [ { "type": "string" @@ -28058,24 +33786,55 @@ } ], "default": null, + "description": "Optional display name for the new key.", "examples": [ - "abc123" + "prod-key-1" ], - "title": "Parent Group Id" + "title": "Name" + } + }, + "title": "CreateApiKeyForGroupRequestV1", + "type": "object" + }, + "CreateApiKeyForGroupResponseV1": { + "properties": { + "api_key": { + "description": "Plaintext key string, returned exactly once.", + "title": "Api Key", + "type": "string" + }, + "prefix": { + "description": "Key prefix (the part before the dot).", + "title": "Prefix", + "type": "string" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Display name of the key.", + "title": "Name" } }, "required": [ - "limit_enforcement" + "api_key", + "prefix" ], - "title": "GroupHierarchyV1", + "title": "CreateApiKeyForGroupResponseV1", "type": "object" }, - "GroupMetadataV1": { + "RegisterAPIKeyRequestV1": { + "description": "Request to register a caller-supplied API key against an existing FederatedGroup.", "properties": { "name": { "anyOf": [ { - "maxLength": 255, "type": "string" }, { @@ -28083,461 +33842,2128 @@ } ], "default": null, - "description": "Optional display name for the group.", + "description": "Optional name for the Model API key", "examples": [ - "Acme prod" + "my-model-api-key" ], "title": "Name" }, - "external_entity_id": { - "description": "External-system identifier for this group. Unique within the caller's org.", + "key": { + "description": "Value of the API key to register", "examples": [ - "cust_42" + "my-secure-api-key-value" ], - "maxLength": 255, - "minLength": 1, - "title": "External Entity Id", + "title": "Key", + "type": "string" + } + }, + "required": [ + "key" + ], + "title": "RegisterAPIKeyRequestV1", + "type": "object" + }, + "RegisterAPIKeyResponseV1": { + "properties": { + "ok": { + "description": "Whether the registration was successful", + "title": "Ok", + "type": "boolean" + } + }, + "required": [ + "ok" + ], + "title": "RegisterAPIKeyResponseV1", + "type": "object" + }, + "ImageBuildLogV1": { + "type": "object", + "required": [ + "timestamp", + "message", + "severity" + ], + "properties": { + "timestamp": { + "type": "string", + "format": "date-time" + }, + "message": { "type": "string" + }, + "severity": { + "type": "integer", + "description": "Numeric OpenTelemetry severity level." + } + } + }, + "ImageBuildLogsResponseV1": { + "type": "object", + "required": [ + "logs", + "total_count" + ], + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageBuildLogV1" + } + }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "Number of matching log entries in the requested time range." + } + } + }, + "SandboxLifecycleV1": { + "type": "object", + "description": "Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", + "properties": { + "expiration_policies": { + "type": "array", + "description": "List of expiration policies. Multiple policies can be combined; whichever condition is met first triggers the action.", + "items": { + "$ref": "#/components/schemas/SandboxExpirationPolicyV1" + }, + "example": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ] + }, + "terminated_retention": { + "type": "string", + "description": "Duration to keep the sandbox record after termination for log access (e.g., '1h', '24h', '7d'). Defaults to 5m. Subject to maximum quota limits.", + "example": "24h" + } + }, + "example": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + } + }, + "SandboxExpirationPolicyV1": { + "description": "Expiration policy. The type determines whether value is a duration or an absolute timestamp.", + "oneOf": [ + { + "$ref": "#/components/schemas/SandboxTTLIdleExpirationPolicyV1" + }, + { + "$ref": "#/components/schemas/SandboxTTLMaxAgeExpirationPolicyV1" + }, + { + "$ref": "#/components/schemas/SandboxDateExpirationPolicyV1" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "TTL_IDLE": "#/components/schemas/SandboxTTLIdleExpirationPolicyV1", + "TTL_MAX_AGE": "#/components/schemas/SandboxTTLMaxAgeExpirationPolicyV1", + "DATE": "#/components/schemas/SandboxDateExpirationPolicyV1" + } + } + }, + "SandboxDurationV1": { + "type": "string", + "description": "Duration using seconds, minutes, hours, or composite durations such as 1h30m. Whole days and weeks are also supported, for example 7d or 2w.", + "pattern": "^[+-]?(0|[0-9]+[dw]|([0-9]+(\\.[0-9]*)?|\\.[0-9]+)(ns|us|\u00b5s|\u03bcs|ms|s|m|h)(([0-9]+(\\.[0-9]*)?|\\.[0-9]+)(ns|us|\u00b5s|\u03bcs|ms|s|m|h))*)$", + "example": "24h" + }, + "SandboxTTLIdleExpirationPolicyV1": { + "type": "object", + "description": "Delete after the specified period of inactivity.", + "required": [ + "action", + "type", + "value" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "DELETE" + ] + }, + "type": { + "type": "string", + "enum": [ + "TTL_IDLE" + ] + }, + "value": { + "$ref": "#/components/schemas/SandboxDurationV1" + } + } + }, + "SandboxTTLMaxAgeExpirationPolicyV1": { + "type": "object", + "description": "Delete after the specified total lifetime.", + "required": [ + "action", + "type", + "value" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "DELETE" + ] + }, + "type": { + "type": "string", + "enum": [ + "TTL_MAX_AGE" + ] + }, + "value": { + "$ref": "#/components/schemas/SandboxDurationV1" + } + } + }, + "SandboxDateExpirationPolicyV1": { + "type": "object", + "description": "Delete at the specified absolute timestamp.", + "required": [ + "action", + "type", + "value" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "DELETE" + ] + }, + "type": { + "type": "string", + "enum": [ + "DATE" + ] + }, + "value": { + "type": "string", + "format": "date-time", + "example": "2026-09-23T21:26:58Z" + } + } + }, + "SandboxNetworkV1": { + "type": "object", + "description": "Network configuration for a sandbox including subnet, domain filtering, and proxy settings", + "properties": { + "proxy": { + "description": "Proxy configuration for routing sandbox HTTP traffic through the platform proxy with MITM inspection and per-destination header/body injection", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxProxyConfigV1" + } + ], + "example": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] + } + }, + "subnet": { + "type": "string", + "description": "Subnet name for the sandbox. Defaults to \"default\" at creation.", + "example": "default" + } + }, + "example": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] + }, + "subnet": "default" + } + }, + "SandboxProxyConfigV1": { + "type": "object", + "description": "Proxy configuration for routing sandbox HTTP traffic through the platform proxy with MITM inspection and per-destination header/body injection", + "properties": { + "allowed_domains": { + "type": "array", + "description": "List of allowed external domains (allowlist). When set, only these domains are reachable. Supports wildcards (e.g. *.storage.example.com).", + "items": { + "type": "string", + "example": "api.openai.com" + }, + "example": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ] + }, + "bypass": { + "type": "array", + "description": "Domains that bypass the proxy entirely via the NO_PROXY directive. Traffic to these destinations goes direct, not through the CONNECT tunnel. Supports wildcards. Note that localhost, private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), 169.254.169.254, .local and .internal are always bypassed by default.", + "items": { + "type": "string", + "example": "registry.npmjs.org" + }, + "example": [ + "registry.npmjs.org" + ] + }, + "forbidden_domains": { + "type": "array", + "description": "List of forbidden external domains (denylist). When set, all domains except these are reachable. Supports wildcards (e.g. *.malware.com). If both allowed_domains and forbidden_domains are set, allowed_domains takes precedence.", + "items": { + "type": "string", + "example": "facebook.com" + }, + "example": [ + "facebook.com", + "*.facebook.com" + ] + }, + "routing": { + "type": "array", + "description": "Per-destination routing rules with header/body injection and secrets. Use destinations [\"*\"] for global rules that apply to all destinations.", + "items": { + "$ref": "#/components/schemas/SandboxProxyTargetV1" + }, + "example": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] } }, - "required": [ - "external_entity_id" - ], - "title": "GroupMetadataV1", - "type": "object" + "example": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] + } }, - "GroupV1": { + "SandboxProxyTargetV1": { + "type": "object", + "description": "Routing rule that injects headers and body fields into requests matching the given destinations. Use destinations [\"*\"] for a global rule that applies to all proxied traffic.", "properties": { - "id": { - "description": "Internal Baseten ID for the group.", - "title": "Id", - "type": "string" - }, - "metadata": { - "$ref": "#/components/schemas/GroupMetadataV1", - "description": "Group identity + display metadata." + "body": { + "type": "object", + "description": "Body fields to inject into matching requests. Values may contain {{SECRET:name}} references resolved from this rule's secrets.", + "additionalProperties": { + "type": "string" + }, + "example": { + "user": "baseten-api-review-0916" + } }, - "models": { + "destinations": { + "type": "array", + "description": "Destination domains this rule applies to. Use [\"*\"] for a global rule that matches all destinations.", "items": { - "$ref": "#/components/schemas/ModelConfigV1" + "type": "string", + "example": "api.openai.com" }, - "title": "Models", - "type": "array" + "example": [ + "api.openai.com" + ] }, - "effective_models": { - "items": { - "$ref": "#/components/schemas/EffectiveModelConfigV1" + "headers": { + "type": "object", + "description": "Headers to inject into matching requests. Values may contain {{SECRET:name}} references resolved from this rule's secrets.", + "additionalProperties": { + "type": "string" }, - "title": "Effective Models", - "type": "array" + "example": { + "Authorization": "Bearer {{SECRET:openai-key}}" + } }, - "hierarchy": { - "$ref": "#/components/schemas/GroupHierarchyV1", - "description": "Parent linkage and limit enforcement mode. Parent is null for root groups." + "secrets": { + "type": "object", + "description": "Named secret values for this routing rule, referenced in headers/body via {{SECRET:name}}. Stored encrypted at rest. Write-only: never returned in API responses.", + "additionalProperties": { + "type": "string" + }, + "example": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + }, + "writeOnly": true + } + }, + "example": { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" }, - "created_at": { - "description": "When this group was created.", - "format": "date-time", - "title": "Created At", - "type": "string" + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + }, + "SandboxEnvV1": { + "type": "object", + "description": "Environment variable with name and value", + "properties": { + "name": { + "type": "string", + "description": "Name of the environment variable", + "example": "NODE_ENV" + }, + "secret": { + "type": "boolean", + "description": "Whether the value is a secret. Defaults to true; secret values are returned as \"****\". Set false explicitly to return the original value.", + "default": true, + "example": false + }, + "value": { + "type": "string", + "description": "Value of the environment variable", + "example": "production" } }, - "required": [ - "id", - "metadata", - "hierarchy", - "created_at" - ], - "title": "GroupV1", - "type": "object" + "example": { + "name": "NODE_ENV", + "secret": false, + "value": "production" + } }, - "LimitEnforcementV1": { - "enum": [ - "CASCADING", - "INDEPENDENT" - ], - "title": "LimitEnforcementV1", - "type": "string" + "SandboxPortsV1": { + "type": "array", + "description": "Set of ports for a resource", + "items": { + "$ref": "#/components/schemas/SandboxPortV1" + }, + "example": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ] }, - "ModelConfigV1": { + "SandboxPortV1": { + "type": "object", + "description": "A port for a resource", "properties": { - "slug": { - "description": "Shared endpoint slug.", - "title": "Slug", - "type": "string" + "name": { + "type": "string", + "description": "The name of the port", + "example": "http" }, - "rate_limits": { - "items": { - "$ref": "#/components/schemas/RateLimitV1" - }, - "title": "Rate Limits", - "type": "array" + "protocol": { + "type": "string", + "description": "The protocol of the port", + "enum": [ + "HTTP", + "TCP", + "UDP", + "TLS" + ], + "example": "HTTP" }, - "usage_limits": { - "items": { - "$ref": "#/components/schemas/UsageLimitV1" - }, - "title": "Usage Limits", - "type": "array" + "target": { + "type": "integer", + "description": "The target port of the port", + "example": 3000, + "minimum": 1, + "maximum": 65535 } }, "required": [ - "slug" + "target" ], - "title": "ModelConfigV1", - "type": "object" + "example": { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } }, - "UsageLimitUnitV1": { - "enum": [ - "DAY" - ], - "title": "UsageLimitUnitV1", - "type": "string" + "SandboxMetadataLabelsV1": { + "type": "object", + "description": "Key-value pairs for organizing and filtering resources. Labels can be used to categorize resources by environment, project, team, or any custom taxonomy.", + "additionalProperties": { + "type": "string" + }, + "example": { + "env": "development", + "project": "api-review", + "team": "engineering" + } }, - "UsageLimitV1": { + "SandboxConfigurationV1": { + "type": "object", + "description": "Writable sandbox configuration. Fields are serialized at the root of the request or resource.", "properties": { - "type": { - "$ref": "#/components/schemas/LimitTypeV1", - "description": "The type of the usage limit", - "examples": [ - "REQUEST", - "TOKEN" + "enabled": { + "type": "boolean", + "description": "When false, the sandbox is disabled and will not accept connections", + "example": true, + "default": true + }, + "lifecycle": { + "description": "Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxLifecycleV1" + } + ], + "example": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + } + }, + "network": { + "description": "Network configuration for a sandbox including subnet, domain filtering, and proxy settings", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxNetworkV1" + } + ], + "example": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] + }, + "subnet": "default" + } + }, + "region": { + "type": "string", + "description": "Region where the sandbox runs (for example us-pdx-1 or eu-lon-1). When omitted at creation, the closest region is selected.", + "example": "us-pdx-1" + }, + "envs": { + "type": "array", + "description": "Environment variables injected into the sandbox.", + "items": { + "$ref": "#/components/schemas/SandboxEnvV1" + }, + "example": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } ] }, - "unit": { - "$ref": "#/components/schemas/UsageLimitUnitV1", - "description": "The unit of the usage limit", - "examples": [ - "DAY" + "image": { + "type": "string", + "description": "Image reference including its tag. Built-in image references are returned in the canonical baseten/ namespace. Use baseten/base-image:latest to get started with the built-in sandbox execution API. This image is available directly without building, pushing, or listing images through GET /v1/sandboxes/images.", + "example": "baseten/base-image:latest" + }, + "memory": { + "type": "integer", + "description": "Memory allocation in megabytes. Also determines CPU allocation (CPU cores = memory in MB / 2048, e.g., 4096MB = 2 CPUs).", + "example": 4096, + "minimum": 1 + }, + "ports": { + "description": "Set of ports for a resource", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxPortsV1" + } + ], + "example": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } ] }, - "threshold": { - "description": "The threshold for the usage limit", - "examples": [ - 10000000 + "external_id": { + "type": "string", + "description": "Caller-owned identifier for external lookups. Max 64 chars, alphanumeric + dash.", + "example": "api-review-20260916-001", + "maxLength": 64, + "pattern": "^[A-Za-z0-9-]+$" + }, + "labels": { + "description": "Key-value pairs for organizing and filtering resources. Labels can be used to categorize resources by environment, project, team, or any custom taxonomy.", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxMetadataLabelsV1" + } ], - "minimum": 0, - "title": "Threshold", - "type": "integer" + "example": { + "env": "development", + "project": "api-review", + "team": "engineering" + } } }, - "required": [ - "type", - "unit", - "threshold" - ], - "title": "UsageLimitV1", - "type": "object" + "example": { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + } + } }, - "GroupsResponseV1": { + "CreateSandboxRequestV1": { + "type": "object", + "description": "Configuration for a new sandbox. The client may provide a name; otherwise the server generates one. The name is immutable after creation.", "properties": { - "items": { - "description": "Items in this page.", + "create_if_not_exists": { + "type": "boolean", + "description": "When true, return the existing live sandbox with this name or recreate it if it is failed, terminated, or being deleted. The server handles concurrent creation and deletion races with a bounded wait; persistent contention returns a conflict. Requires name. Existing configuration is preserved. Defaults to false when omitted." + }, + "name": { + "type": "string", + "description": "Optional unique sandbox name. Generated by the server when omitted; immutable after creation.", + "minLength": 1, + "example": "baseten-api-review-0916" + }, + "lifecycle": { + "description": "Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxLifecycleV1" + } + ], + "example": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + } + }, + "network": { + "description": "Network configuration for a sandbox including subnet, domain filtering, and proxy settings", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxNetworkV1" + } + ], + "example": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] + }, + "subnet": "default" + } + }, + "region": { + "type": "string", + "description": "Region where the sandbox runs (for example us-pdx-1 or eu-lon-1). When omitted at creation, the closest region is selected.", + "example": "us-pdx-1" + }, + "envs": { + "type": "array", + "description": "Environment variables injected into the sandbox.", "items": { - "$ref": "#/components/schemas/GroupV1" + "$ref": "#/components/schemas/SandboxEnvV1" }, - "title": "Items", - "type": "array" - }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." - } - }, - "required": [ - "items", - "pagination" - ], - "title": "GroupsResponseV1", - "type": "object" - }, - "CreateGroupHierarchyV1": { - "properties": { - "limit_enforcement": { - "anyOf": [ + "example": [ { - "$ref": "#/components/schemas/LimitEnforcementV1" + "name": "NODE_ENV", + "secret": false, + "value": "production" }, { - "type": "null" + "name": "PORT", + "secret": false, + "value": "3000" } - ], - "default": null, - "description": "Limit behavior. Child groups inherit their parent's behavior when omitted; root groups default to Independent for backwards compatibility.", - "examples": [ - "INDEPENDENT" ] }, - "parent_group_id": { - "anyOf": [ - { - "type": "string" - }, + "image": { + "type": "string", + "description": "Image reference including its tag. Defaults to baseten/base-image:latest, the built-in sandbox execution API. This image is available directly without building, pushing, or listing images through GET /v1/sandboxes/images.", + "default": "baseten/base-image:latest", + "example": "baseten/base-image:latest" + }, + "memory": { + "type": "integer", + "description": "Memory allocation in megabytes. Also determines CPU allocation (CPU cores = memory in MB / 2048, e.g., 4096MB = 2 CPUs). Defaults to 4096.", + "default": 4096, + "example": 4096, + "minimum": 1 + }, + "ports": { + "description": "Set of ports for a resource", + "allOf": [ { - "type": "null" + "$ref": "#/components/schemas/SandboxPortsV1" } ], - "default": null, - "examples": [ - "abc123" + "example": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ] + }, + "external_id": { + "type": "string", + "description": "Caller-owned identifier for external lookups. Max 64 chars, alphanumeric + dash.", + "example": "api-review-20260916-001", + "maxLength": 64, + "pattern": "^[A-Za-z0-9-]+$" + }, + "labels": { + "description": "Key-value pairs for organizing and filtering resources. Labels can be used to categorize resources by environment, project, team, or any custom taxonomy.", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxMetadataLabelsV1" + } ], - "title": "Parent Group Id" + "example": { + "env": "development", + "project": "api-review", + "team": "engineering" + } } }, - "title": "CreateGroupHierarchyV1", - "type": "object" - }, - "CreateGroupRequestV1": { - "properties": { - "metadata": { - "$ref": "#/components/schemas/GroupMetadataV1", - "description": "Group identity + display metadata." + "example": { + "name": "baseten-api-review-0916", + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" }, - "models": { - "description": "Per-model rate and usage limit configuration. Defines the group's complete model set. Must be non-empty.", - "examples": [ - [ + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ { - "slug": "my-org/claude" + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } } ] - ], - "items": { - "$ref": "#/components/schemas/ModelConfigV1" }, - "minItems": 1, - "title": "Models", - "type": "array" - }, - "hierarchy": { - "$ref": "#/components/schemas/CreateGroupHierarchyV1", - "description": "Parent linkage and limit enforcement mode. Immutable after creation." + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" } - }, - "required": [ - "metadata", - "models", - "hierarchy" - ], - "title": "CreateGroupRequestV1", - "type": "object" + } }, - "UpdateGroupMetadataV1": { + "UpdateSandboxRequestV1": { + "type": "object", + "description": "Partial sandbox update. Omitted fields remain unchanged. Supplied arrays and maps (including labels) replace their previous values; supplied structured objects update only their supplied fields. Null is not accepted. The name, memory, and network configuration are immutable after creation. Supplying memory or network returns 400, including unchanged, empty, or null values.", "properties": { - "name": { - "anyOf": [ + "enabled": { + "type": "boolean", + "description": "When false, the sandbox is disabled and will not accept connections", + "example": true + }, + "lifecycle": { + "description": "Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", + "allOf": [ { - "maxLength": 255, - "type": "string" + "$ref": "#/components/schemas/SandboxLifecycleV1" + } + ], + "example": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + } + }, + "region": { + "type": "string", + "description": "Region where the sandbox runs (for example us-pdx-1 or eu-lon-1). When omitted at creation, the closest region is selected.", + "example": "us-pdx-1" + }, + "envs": { + "type": "array", + "description": "Environment variables injected into the sandbox.", + "items": { + "$ref": "#/components/schemas/SandboxEnvV1" + }, + "example": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" }, { - "type": "null" + "name": "PORT", + "secret": false, + "value": "3000" + } + ] + }, + "image": { + "type": "string", + "description": "Image reference including its tag. Built-in image references are returned in the canonical baseten/ namespace. Use baseten/base-image:latest to get started with the built-in sandbox execution API. This image is available directly without building, pushing, or listing images through GET /v1/sandboxes/images.", + "example": "baseten/base-image:latest" + }, + "ports": { + "description": "Set of ports for a resource", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxPortsV1" } ], - "default": null, - "description": "Optional display name for the group.", - "examples": [ - "Acme prod" + "example": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ] + }, + "external_id": { + "type": "string", + "description": "Caller-owned identifier for external lookups. Max 64 chars, alphanumeric + dash.", + "example": "api-review-20260916-001", + "maxLength": 64, + "pattern": "^[A-Za-z0-9-]+$" + }, + "labels": { + "description": "Key-value pairs for organizing and filtering resources. Labels can be used to categorize resources by environment, project, team, or any custom taxonomy.", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxMetadataLabelsV1" + } ], - "title": "Name" + "example": { + "env": "development", + "project": "api-review", + "team": "engineering", + "revision": "2" + } } }, - "title": "UpdateGroupMetadataV1", - "type": "object" - }, - "UpdateGroupRequestV1": { - "properties": { - "metadata": { - "anyOf": [ + "minProperties": 1, + "example": { + "enabled": true, + "lifecycle": { + "expiration_policies": [ { - "$ref": "#/components/schemas/UpdateGroupMetadataV1" + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" }, { - "type": "null" + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" } ], - "default": null, - "description": "Mutable group metadata.", - "examples": [ + "terminated_retention": "24h" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering", + "revision": "2" + } + } + }, + "SandboxV1": { + "description": "Sandbox resource with configuration and server-managed fields at the root. No metadata, spec, or runtime wrapper.", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxConfigurationV1" + }, + { + "type": "object", + "description": "Server-managed sandbox fields.", + "properties": { + "name": { + "type": "string", + "description": "Immutable sandbox name, provided by the client or generated by the server, used in sandbox_name path parameters.", + "readOnly": true, + "example": "baseten-api-review-0916" + }, + "url": { + "type": "string", + "description": "Base URL of this sandbox's execution API, always present on successful creation. The URL is assigned before deployment completes; inspect status for readiness. Use this exact returned URL; do not reconstruct its hostname. Authenticate requests with your authentication token using Authorization: Bearer . Do not send the Baseten API key directly. No additional routing headers are required. Fetch GET {url}/swagger/doc.json with that header for the API reference served by this sandbox. For example, POST {url}/process with Content-Type: application/json and {\"command\":\"echo hello\",\"waitForCompletion\":true} executes a command and waits for its result. Execution API fields use camelCase, independently of this API's snake_case fields.", + "format": "uri", + "readOnly": true, + "example": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run" + }, + "status": { + "description": "Sandbox deployment status.", + "allOf": [ + { + "$ref": "#/components/schemas/SandboxStatusV1" + } + ], + "example": "DEPLOYED" + }, + "created_at": { + "type": "string", + "description": "Time the sandbox was created.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-16T21:26:58.545765901Z" + }, + "updated_at": { + "type": "string", + "description": "Time the sandbox was last updated.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-16T21:31:13Z" + }, + "created_by": { + "type": "string", + "description": "User or service account that created the sandbox.", + "readOnly": true, + "example": "sandbox-automation" + }, + "updated_by": { + "type": "string", + "description": "User or service account that last updated the sandbox.", + "readOnly": true, + "example": "sandbox-automation" + }, + "last_used_at": { + "type": "string", + "description": "Time the sandbox was last used.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-16T21:31:13Z" + }, + "expires_in": { + "type": "integer", + "description": "Seconds remaining before automatic deletion, when expiration is configured.", + "readOnly": true, + "minimum": 0, + "example": 86400 + } + }, + "required": [ + "name", + "url", + "status", + "created_at" + ], + "example": { + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400 + } + } + ], + "example": { + "enabled": true, + "lifecycle": { + "expiration_policies": [ { - "name": "Acme Prod" + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" } - ] + ], + "terminated_retention": "24h" }, - "models": { - "anyOf": [ + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400 + } + }, + "SandboxStatusV1": { + "type": "string", + "description": "Sandbox deployment status, always uppercase. This tracks provisioning and differs from the execution API state, whose values such as running are lowercase.", + "enum": [ + "DEPLOYING", + "DEPLOYED", + "FAILED", + "DEACTIVATING", + "DEACTIVATED", + "DELETING", + "TERMINATED", + "ARCHIVING", + "ARCHIVED", + "UNARCHIVING", + "BUILDING", + "UPLOADING" + ], + "readOnly": true, + "example": "DEPLOYED" + }, + "SandboxApiPaginationV1": { + "type": "object", + "description": "Cursor pagination information. The cursor is present only when another page is available.", + "properties": { + "has_more": { + "type": "boolean", + "description": "Whether another page is available.", + "example": true + }, + "cursor": { + "type": "string", + "description": "Opaque cursor to pass to the next list request. Keep the same filters.", + "minLength": 1, + "example": "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + } + }, + "required": [ + "has_more" + ], + "example": { + "has_more": true, + "cursor": "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + } + }, + "ListSandboxesResponseV1": { + "type": "object", + "description": "One page of sandboxes.", + "properties": { + "items": { + "type": "array", + "description": "Resources on this page.", + "items": { + "$ref": "#/components/schemas/SandboxV1" + }, + "example": [ { - "items": { - "$ref": "#/components/schemas/ModelConfigV1" + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" }, - "type": "array" - }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400 + } + ] + }, + "pagination": { + "description": "Cursor pagination information. The cursor is present only when another page is available.", + "allOf": [ { - "type": "null" + "$ref": "#/components/schemas/SandboxApiPaginationV1" } ], - "default": null, - "description": "Per-model rate and usage limit configuration.", - "title": "Models" + "example": { + "has_more": true, + "cursor": "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + } } }, - "title": "UpdateGroupRequestV1", - "type": "object" + "required": [ + "items", + "pagination" + ], + "example": { + "items": [ + { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400 + } + ], + "pagination": { + "has_more": true, + "cursor": "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + } + } }, - "GatewayKeyInfoV1": { + "ListImagesResponseV1": { + "type": "object", + "description": "One page of image repository summaries. Fetch tags through the separate tag listing endpoint.", "properties": { - "prefix": { - "description": "The prefix of the Model API key.", - "title": "Prefix", - "type": "string" + "items": { + "type": "array", + "description": "Image repositories on this page.", + "items": { + "$ref": "#/components/schemas/ImageV1" + } }, - "name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Optional display name.", - "title": "Name" + "pagination": { + "$ref": "#/components/schemas/SandboxApiPaginationV1" } }, "required": [ - "prefix" - ], - "title": "GatewayKeyInfoV1", - "type": "object" + "items", + "pagination" + ] }, - "KeysForGroupResponseV1": { + "ListImageTagsResponseV1": { + "type": "object", + "description": "One page of image tags.", "properties": { "items": { - "description": "Items in this page.", + "type": "array", "items": { - "$ref": "#/components/schemas/GatewayKeyInfoV1" - }, - "title": "Items", - "type": "array" + "$ref": "#/components/schemas/ImageTagV1" + } }, "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." + "$ref": "#/components/schemas/SandboxApiPaginationV1" } }, "required": [ "items", "pagination" + ] + }, + "ImageStatusV1": { + "type": "string", + "description": "Image processing status. Only BUILT images are ready to use.", + "enum": [ + "UPLOADING", + "BUILDING", + "BUILT", + "FAILED" ], - "title": "KeysForGroupResponseV1", - "type": "object" + "readOnly": true, + "example": "BUILT" }, - "CreateApiKeyForGroupRequestV1": { + "ImageTagV1": { + "type": "object", + "description": "A tag identifying a version of a sandbox image.", "properties": { "name": { - "anyOf": [ + "type": "string", + "description": "Image tag name.", + "example": "latest" + }, + "created_at": { + "type": "string", + "description": "Time the tag was created.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-16T21:20:00Z" + }, + "updated_at": { + "type": "string", + "description": "Time the tag was last updated.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-16T21:25:00Z" + }, + "size": { + "type": "integer", + "description": "Image size in bytes.", + "format": "int64", + "minimum": 0, + "readOnly": true, + "example": 134217728 + } + }, + "required": [ + "name" + ], + "example": { + "name": "latest", + "created_at": "2026-09-16T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "size": 134217728 + } + }, + "ImageV1": { + "type": "object", + "description": "Sandbox image repository. List and get operations return a summary without embedded tags.", + "properties": { + "name": { + "type": "string", + "description": "Stable repository name supplied when pushing the image.", + "example": "base-image" + }, + "status": { + "description": "Image processing status. Only BUILT images are ready to use.", + "allOf": [ { - "type": "string" + "$ref": "#/components/schemas/ImageStatusV1" + } + ], + "example": "BUILT" + }, + "created_at": { + "type": "string", + "description": "Time the image was created.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-15T21:20:00Z" + }, + "updated_at": { + "type": "string", + "description": "Time the image was last updated.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-16T21:25:00Z" + }, + "last_deployed_at": { + "type": "string", + "description": "Most recent deployment time across all tags, if deployed.", + "format": "date-time", + "readOnly": true, + "example": "2026-09-16T21:26:58.545765901Z" + }, + "size": { + "type": "integer", + "description": "Total repository size in bytes.", + "format": "int64", + "minimum": 0, + "readOnly": true, + "example": 260046848 + }, + "tag_count": { + "type": "integer", + "format": "int64", + "minimum": 0, + "readOnly": true, + "description": "Number of image versions in the repository.", + "example": 2 + }, + "tags": { + "type": "array", + "description": "Empty for list and get summary responses. Use GET /sandboxes/images/{image_name}/tags to retrieve paginated image versions.", + "items": { + "$ref": "#/components/schemas/ImageTagV1" + }, + "example": [ + { + "name": "latest", + "created_at": "2026-09-16T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "size": 134217728 }, { - "type": "null" + "name": "20260915212000", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-15T21:25:00Z", + "size": 125829120 } - ], - "default": null, - "description": "Optional display name for the new key.", - "examples": [ - "prod-key-1" - ], - "title": "Name" + ] } }, - "title": "CreateApiKeyForGroupRequestV1", - "type": "object" + "required": [ + "name", + "status", + "tags" + ], + "example": { + "name": "base-image", + "status": "BUILT", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "last_deployed_at": "2026-09-16T21:26:58.545765901Z", + "size": 260046848, + "tags": [ + { + "name": "latest", + "created_at": "2026-09-16T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "size": 134217728 + }, + { + "name": "20260915212000", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-15T21:25:00Z", + "size": 125829120 + } + ] + } }, - "CreateApiKeyForGroupResponseV1": { + "PushImageRequestV1": { + "type": "object", + "description": "Push a sandbox image from a source archive or an existing registry image.", "properties": { - "api_key": { - "description": "Plaintext key string, returned exactly once.", - "title": "Api Key", - "type": "string" + "name": { + "type": "string", + "description": "Target image repository name. Reusing a name pushes a new version to the existing repository.", + "minLength": 1, + "example": "base-image" }, - "prefix": { - "description": "Key prefix (the part before the dot).", - "title": "Prefix", - "type": "string" + "image": { + "type": "string", + "description": "Optional source registry image reference including a registry hostname. When omitted, the response provides an archive upload URL. The uploaded ZIP archive must not exceed 5 GB.", + "example": "docker.io/b10/base-image:latest" }, + "docker_config": { + "type": "string", + "description": "Optional serialized registry authentication configuration for importing a private image. Used only when image is supplied; never returned.", + "writeOnly": true, + "example": "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"YjEwLXJldmlldzpkZW1vLW5vdC1hLXZhbGlkLXJlZ2lzdHJ5LXRva2Vu\"}}}" + } + }, + "required": [ + "name" + ], + "example": { + "name": "base-image", + "image": "docker.io/b10/base-image:latest", + "docker_config": "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"YjEwLXJldmlldzpkZW1vLW5vdC1hLXZhbGlkLXJlZ2lzdHJ5LXRva2Vu\"}}}" + } + }, + "PushImageResponseV1": { + "type": "object", + "description": "Accepted image push. Acceptance does not imply readiness; poll GET /sandboxes/images/{image_name} until status is BUILT or FAILED.", + "properties": { "name": { - "anyOf": [ - { - "type": "string" - }, + "type": "string", + "description": "Target image repository name.", + "example": "base-image" + }, + "status": { + "description": "Image processing status. Only BUILT images are ready to use.", + "allOf": [ { - "type": "null" + "$ref": "#/components/schemas/ImageStatusV1" } ], - "default": null, - "description": "Display name of the key.", - "title": "Name" + "example": "BUILDING" + }, + "upload_url": { + "type": "string", + "description": "Temporary signed URL for uploading the source ZIP archive with HTTP PUT. Present only when no source image was supplied. The uploaded ZIP archive must not exceed 5 GB. Uploading starts asynchronous processing. This storage upload is separate from the API endpoints.", + "format": "uri", + "example": "https://uploads.b10.run/images/base-image/20260916212658/source.zip?expires=2026-09-16T22%3A26%3A58Z&signature=demo-not-a-valid-upload-signature" + }, + "image": { + "type": "string", + "description": "Registered image reference including its tag, when available. Tags are assigned by the service; GET /sandboxes/images/{image_name} returns the available tags once processing completes.", + "example": "b10/base-image:latest" } }, "required": [ - "api_key", - "prefix" + "name", + "status" ], - "title": "CreateApiKeyForGroupResponseV1", - "type": "object" + "example": { + "name": "base-image", + "status": "BUILDING", + "image": "b10/base-image:latest" + } }, - "RegisterAPIKeyRequestV1": { - "description": "Request to register a caller-supplied API key against an existing FederatedGroup.", + "SandboxLibraryImageVolumeV1": { + "type": "object", + "description": "Volume attachment suggested by a built-in image.", "properties": { "name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Optional name for the Model API key", - "examples": [ - "my-model-api-key" - ], - "title": "Name" + "type": "string", + "description": "Volume name, or an internal identifier for ephemeral volumes.", + "example": "scratch" }, - "key": { - "description": "Value of the API key to register", - "examples": [ - "my-secure-api-key-value" - ], - "title": "Key", - "type": "string" + "mount_path": { + "type": "string", + "description": "Absolute filesystem path where the volume is mounted.", + "example": "/mnt/data" + }, + "type": { + "type": "string", + "description": "Volume type, persistent when empty.", + "example": "ephemeral" + }, + "size_mb": { + "type": "integer", + "description": "Storage capacity in megabytes for ephemeral volumes.", + "example": 10240 + }, + "read_only": { + "type": "boolean", + "description": "Whether the volume is mounted read-only.", + "example": false + } + }, + "required": [ + "name", + "mount_path" + ] + }, + "SandboxLibraryImageCreationOptionsV1": { + "type": "object", + "description": "Optional settings suggested when creating a sandbox from this image.", + "properties": { + "extra_args": { + "type": "object", + "description": "Kernel selection arguments.", + "additionalProperties": { + "type": "string" + } + }, + "volumes": { + "type": "array", + "description": "Volume attachments.", + "items": { + "$ref": "#/components/schemas/SandboxLibraryImageVolumeV1" + } + } + } + }, + "SandboxLibraryImageV1": { + "type": "object", + "description": "Built-in sandbox image usable directly as a sandbox image.", + "properties": { + "name": { + "type": "string", + "description": "Stable identifier of the built-in image.", + "example": "base-image" + }, + "display_name": { + "type": "string", + "description": "Human-readable name.", + "example": "Base Image" + }, + "description": { + "type": "string", + "description": "Short description.", + "example": "A minimal sandbox environment with the sandbox execution API." + }, + "long_description": { + "type": "string", + "description": "Detailed description." + }, + "image": { + "type": "string", + "description": "Image reference including its tag, usable as the image of a sandbox.", + "example": "baseten/base-image:latest" + }, + "memory": { + "type": "integer", + "description": "Recommended memory allocation in megabytes.", + "example": 4096 + }, + "ports": { + "$ref": "#/components/schemas/SandboxPortsV1" + }, + "categories": { + "type": "array", + "description": "Categories of the image.", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "description": "Tags of the image.", + "items": { + "type": "string" + } + }, + "url": { + "type": "string", + "description": "Documentation URL." + }, + "icon": { + "type": "string", + "description": "Icon URL." + }, + "icon_light": { + "type": "string", + "description": "Light-mode icon URL." + }, + "icon_dark": { + "type": "string", + "description": "Dark-mode icon URL." + }, + "enterprise": { + "type": "boolean", + "description": "Whether the image requires an enterprise plan.", + "example": false + }, + "hidden": { + "type": "boolean", + "description": "Whether the image is hidden. Always false in listings.", + "example": false + }, + "coming_soon": { + "type": "boolean", + "description": "Whether the image is not yet available. Always false in listings.", + "example": false + }, + "creation_options": { + "$ref": "#/components/schemas/SandboxLibraryImageCreationOptionsV1" } }, "required": [ - "key" - ], - "title": "RegisterAPIKeyRequestV1", - "type": "object" + "name", + "image" + ] }, - "RegisterAPIKeyResponseV1": { + "ListSandboxLibraryImagesResponseV1": { + "type": "object", + "description": "Built-in sandbox images.", "properties": { - "ok": { - "description": "Whether the registration was successful", - "title": "Ok", - "type": "boolean" + "items": { + "type": "array", + "description": "Built-in images.", + "items": { + "$ref": "#/components/schemas/SandboxLibraryImageV1" + } } }, "required": [ - "ok" + "items" + ] + }, + "CleanupImagesResponseV1": { + "type": "object", + "description": "Result of cleaning up unused sandbox images.", + "properties": { + "deleted": { + "type": "integer", + "description": "Number of image versions removed.", + "minimum": 0, + "example": 3 + }, + "message": { + "type": "string", + "description": "Human-readable cleanup result.", + "example": "Removed 3 unused image versions. Image versions used by active sandboxes were retained." + } + }, + "required": [ + "deleted", + "message" ], - "title": "RegisterAPIKeyResponseV1", - "type": "object" + "example": { + "deleted": 3, + "message": "Removed 3 unused image versions. Image versions used by active sandboxes were retained." + } } }, "parameters": { + "volume_sync_id": { + "schema": { + "type": "string" + }, + "name": "volume_sync_id", + "in": "path", + "required": true + }, "volume_namespace": { "schema": { "type": "string" @@ -28722,6 +36148,22 @@ "in": "path", "required": true }, + "harness": { + "schema": { + "type": "string" + }, + "name": "harness", + "in": "path", + "required": true + }, + "route_id": { + "schema": { + "type": "string" + }, + "name": "route_id", + "in": "path", + "required": true + }, "endpoint_id": { "schema": { "type": "string" @@ -28737,6 +36179,82 @@ "name": "group_id", "in": "path", "required": true + }, + "TeamId": { + "name": "team_id", + "in": "query", + "required": false, + "description": "Optional team ID. Must match X-Team-Id when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + "schema": { + "type": "string", + "minLength": 1 + } + }, + "TeamIdHeader": { + "name": "X-Team-Id", + "in": "header", + "required": false, + "description": "Optional team ID. Must match the team_id query parameter when both are supplied. If neither selector is supplied, defaults to the caller's only accessible team. Callers with multiple accessible teams must select a team. Requests without access to any team are forbidden.", + "schema": { + "type": "string", + "minLength": 1 + } + }, + "SandboxName": { + "name": "sandbox_name", + "in": "path", + "required": true, + "description": "Immutable sandbox name returned by creation.", + "schema": { + "type": "string", + "minLength": 1, + "example": "baseten-api-review-0916" + } + }, + "ImageName": { + "name": "image_name", + "in": "path", + "required": true, + "description": "Image repository name.", + "schema": { + "type": "string", + "minLength": 1, + "example": "base-image" + } + }, + "TagName": { + "name": "tag_name", + "in": "path", + "required": true, + "description": "Image tag name.", + "schema": { + "type": "string", + "minLength": 1, + "example": "20260915212000" + } + }, + "Cursor": { + "name": "cursor", + "in": "query", + "required": false, + "description": "Opaque cursor from the previous page; omit for the first page.", + "schema": { + "type": "string", + "example": "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + } + }, + "Limit": { + "name": "limit", + "in": "query", + "required": false, + "description": "Maximum number of items to return.", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "example": 20 + } } }, "securitySchemes": { @@ -28745,6 +36263,897 @@ "scheme": "bearer", "description": "Send `Authorization: Bearer `. The legacy `Authorization: Api-Key ` scheme is also accepted." } + }, + "responses": { + "SandboxError400": { + "description": "Invalid request. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "INVALID_REQUEST", + "message": "One or more request parameters are invalid.", + "details": { + "request_id": "a3b7c4d2-91e6-4f08-9b5a-2c6d7e8f1043" + } + } + } + } + }, + "SandboxError401": { + "description": "Missing or invalid authentication. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "UNAUTHORIZED", + "message": "Provide a valid authentication token in the Authorization header.", + "details": { + "header": "Authorization" + } + } + } + } + }, + "SandboxError403": { + "description": "Insufficient permissions. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "FORBIDDEN", + "message": "This authentication token does not grant permission to perform this operation.", + "details": { + "request_id": "a3b7c4d2-91e6-4f08-9b5a-2c6d7e8f1043" + } + } + } + } + }, + "SandboxError404": { + "description": "Resource not found. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "NOT_FOUND", + "message": "The requested resource was not found.", + "details": { + "request_id": "a3b7c4d2-91e6-4f08-9b5a-2c6d7e8f1043" + } + } + } + } + }, + "SandboxError409": { + "description": "Resource is currently in use or conflicts with the requested operation. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "RESOURCE_IN_USE", + "message": "The resource is currently in use or conflicts with the requested operation.", + "details": { + "request_id": "a3b7c4d2-91e6-4f08-9b5a-2c6d7e8f1043" + } + } + } + } + }, + "SandboxError429": { + "description": "Request limit exceeded. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "RATE_LIMITED", + "message": "Too many requests. Try again in 30 seconds.", + "details": { + "retry_after_seconds": 30 + } + } + } + } + }, + "SandboxError500": { + "description": "Internal server error. Returns a JSON error with code, message, and optional details.", + "content": { + "application/json": { + "example": { + "code": "INTERNAL_ERROR", + "message": "The request could not be completed. Try again later.", + "details": { + "request_id": "a3b7c4d2-91e6-4f08-9b5a-2c6d7e8f1043" + } + } + } + } + } + }, + "examples": { + "CreateSandboxQuickstart": { + "summary": "Run code with the built-in image", + "description": "Create directly with the built-in image; no image discovery, build, or push is needed. Use the returned url to call the sandbox execution API with your authentication token as a Bearer token, not your Baseten API key.", + "value": { + "image": "baseten/base-image:latest", + "memory": 2048, + "region": "us-was-1" + } + }, + "CreateSandbox": { + "summary": "Create with every supported field", + "value": { + "name": "baseten-api-review-0916", + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + }, + "secrets": { + "openai-key": "sk-proj-demo-not-a-valid-api-key" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + } + }, + "description": "All supported request fields are shown. Credential values are nonfunctional demonstration values." + }, + "UpdateSandbox": { + "summary": "Update every mutable field", + "value": { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering", + "revision": "2" + } + }, + "description": "All mutable request fields are shown. Memory and network configuration are only accepted during creation." + }, + "SandboxReady": { + "summary": "Running sandbox with complete configuration", + "value": { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400 + }, + "description": "Example sandbox URL in the b10.run domain. Write-only proxy secrets are not returned. Other values illustrate a fully configured sandbox." + }, + "SandboxUpdated": { + "summary": "Updated sandbox with complete configuration", + "value": { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering", + "revision": "2" + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:36:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:36:13Z", + "expires_in": 86400 + } + }, + "SandboxDeleting": { + "summary": "Sandbox deletion accepted", + "value": { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DELETING", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:41:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 85800 + } + }, + "SandboxesPage": { + "summary": "Sandbox page with another page available", + "value": { + "items": [ + { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400 + } + ], + "pagination": { + "has_more": true, + "cursor": "eyJ2IjoxLCJsYXN0X2tleSI6ImJhc2V0ZW4tYXBpLXJldmlldy0wOTE2Iiwic29ydCI6ImRlc2MifQ" + } + }, + "description": "The cursor illustrates an opaque pagination token; it is not a reusable live cursor." + }, + "SandboxesLastPage": { + "summary": "Last sandbox page", + "value": { + "items": [ + { + "enabled": true, + "lifecycle": { + "expiration_policies": [ + { + "action": "DELETE", + "type": "TTL_IDLE", + "value": "24h" + }, + { + "action": "DELETE", + "type": "TTL_MAX_AGE", + "value": "7d" + }, + { + "action": "DELETE", + "type": "DATE", + "value": "2026-09-23T21:26:58Z" + } + ], + "terminated_retention": "24h" + }, + "network": { + "proxy": { + "allowed_domains": [ + "api.openai.com", + "pypi.org", + "files.pythonhosted.org", + "registry.npmjs.org" + ], + "bypass": [ + "registry.npmjs.org" + ], + "forbidden_domains": [ + "facebook.com", + "*.facebook.com" + ], + "routing": [ + { + "destinations": [ + "api.openai.com" + ], + "headers": { + "Authorization": "Bearer {{SECRET:openai-key}}" + }, + "body": { + "user": "baseten-api-review-0916" + } + } + ] + }, + "subnet": "default" + }, + "region": "us-pdx-1", + "envs": [ + { + "name": "NODE_ENV", + "secret": false, + "value": "production" + }, + { + "name": "PORT", + "secret": false, + "value": "3000" + } + ], + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "http", + "protocol": "HTTP", + "target": 3000 + } + ], + "external_id": "api-review-20260916-001", + "labels": { + "env": "development", + "project": "api-review", + "team": "engineering" + }, + "name": "baseten-api-review-0916", + "url": "https://sbx-baseten-api-review-0916-esb1qo.us-pdx-1.b10.run", + "status": "DEPLOYED", + "created_at": "2026-09-16T21:26:58.545765901Z", + "updated_at": "2026-09-16T21:31:13Z", + "created_by": "sandbox-automation", + "updated_by": "sandbox-automation", + "last_used_at": "2026-09-16T21:31:13Z", + "expires_in": 86400 + } + ], + "pagination": { + "has_more": false + } + } + }, + "ImageReady": { + "summary": "Built image with all metadata and tags", + "value": { + "name": "base-image", + "status": "BUILT", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "last_deployed_at": "2026-09-16T21:26:58.545765901Z", + "size": 260046848, + "tags": [ + { + "name": "latest", + "created_at": "2026-09-16T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "size": 134217728 + }, + { + "name": "20260915212000", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-15T21:25:00Z", + "size": 125829120 + } + ] + }, + "description": "Dates and byte sizes are representative example data. Image references use the b10 namespace." + }, + "ImageAfterTagDeletion": { + "summary": "Image after deleting its older tag", + "value": { + "name": "base-image", + "status": "BUILT", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-16T21:41:13Z", + "last_deployed_at": "2026-09-16T21:26:58.545765901Z", + "size": 134217728, + "tags": [ + { + "name": "latest", + "created_at": "2026-09-16T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "size": 134217728 + } + ] + } + }, + "ImageSummary": { + "summary": "Image repository summary", + "value": { + "name": "base-image", + "status": "BUILT", + "created_at": "2026-09-15T21:20:00Z", + "size": 260046848, + "tag_count": 2, + "tags": [] + } + }, + "ImagesList": { + "summary": "One page of image repositories", + "value": { + "items": [ + { + "name": "base-image", + "status": "BUILT", + "created_at": "2026-09-15T21:20:00Z", + "updated_at": "2026-09-16T21:25:00Z", + "last_deployed_at": "2026-09-16T21:26:58.545765901Z", + "size": 260046848, + "tag_count": 2, + "tags": [] + } + ], + "pagination": { + "has_more": false + } + } + }, + "PushArchive": { + "summary": "Build an image from an uploaded source archive", + "value": { + "name": "base-image" + }, + "description": "Omit image and docker_config to request an upload URL. Those fields do not apply to source-archive uploads." + }, + "PushRegistry": { + "summary": "Import an image with registry authentication", + "value": { + "name": "base-image", + "image": "docker.io/b10/base-image:latest", + "docker_config": "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"YjEwLXJldmlldzpkZW1vLW5vdC1hLXZhbGlkLXJlZ2lzdHJ5LXRva2Vu\"}}}" + }, + "description": "Shows every request field. docker_config is serialized registry configuration with a deliberately invalid demonstration credential." + }, + "PushArchiveAccepted": { + "summary": "Source upload required", + "value": { + "name": "base-image", + "status": "UPLOADING", + "upload_url": "https://uploads.b10.run/images/base-image/20260916212658/source.zip?expires=2026-09-16T22%3A26%3A58Z&signature=demo-not-a-valid-upload-signature" + }, + "description": "The signed upload URL is illustrative, with a nonfunctional signature. image is unavailable until processing produces a registered image reference." + }, + "PushRegistryAccepted": { + "summary": "Image import accepted", + "value": { + "name": "base-image", + "status": "BUILDING", + "image": "b10/base-image:latest" + }, + "description": "No upload_url is returned for registry imports." + }, + "SandboxLibraryImages": { + "summary": "Built-in sandbox images", + "value": { + "items": [ + { + "name": "base-image", + "display_name": "Base Image", + "description": "A minimal sandbox environment with the sandbox execution API.", + "long_description": "", + "image": "baseten/base-image:latest", + "memory": 4096, + "ports": [ + { + "name": "sandbox-api", + "protocol": "HTTP", + "target": 8080 + } + ], + "categories": [], + "tags": [], + "url": "", + "icon": "https://example.com/base-image.png", + "icon_light": "https://example.com/base-image.png", + "icon_dark": "https://example.com/base-image.png", + "enterprise": false, + "hidden": false, + "coming_soon": false + } + ] + } + }, + "CleanupImages": { + "summary": "Unused image versions removed", + "value": { + "deleted": 3, + "message": "Removed 3 unused image versions. Image versions used by active sandboxes were retained." + } + } } } } \ No newline at end of file diff --git a/scripts/apigen/specs/sandbox.yml b/scripts/apigen/specs/sandbox.yml new file mode 100644 index 0000000..f669352 --- /dev/null +++ b/scripts/apigen/specs/sandbox.yml @@ -0,0 +1,2794 @@ +openapi: 3.0.0 +info: + contact: {} + description: API for manipulating filesystem, processes and network. + title: Sandbox API + version: 0.0.1 +paths: + /archive/export: + post: + description: >- + Archives everything the sandbox changed on top of its base image and streams it, uncompressed, to a presigned S3 PUT URL. The memory of the sandbox is not archived. + + The sandbox is quiesced first: the process list is saved (unless saveProcesses is false), every process is stopped, and the API then refuses the calls that would write to the filesystem. The freeze is not lifted afterwards, since an exported sandbox is meant to be restored elsewhere; call POST /archive/resume to lift it. + + Use dryRun to get the archive's content and exact size without stopping anything and without uploading. + + Set async to start the export and answer immediately, which is what archiving a large filesystem needs: the export then reports itself through GET /archive/status. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ExportOptions" + description: Export options + required: true + responses: + "200": + description: Export result + content: + application/json: + schema: + $ref: "#/components/schemas/ExportResult" + "202": + description: The export was started and runs in the background + content: + application/json: + schema: + $ref: "#/components/schemas/ExportProgress" + "400": + description: Invalid request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "409": + description: An export is already in progress + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Export failed + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Export the filesystem changes to a presigned URL + tags: + - archive + /archive/resume: + post: + description: "Makes the API serve every route again after an export. The processes stopped for the export are not relaunched: this exists so a failed or aborted export does not leave the sandbox unusable." + responses: + "200": + description: Archive status + content: + application/json: + schema: + $ref: "#/components/schemas/QuiesceStatus" + "409": + description: An export or a restore is in progress + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: The root filesystem could not be made writable again + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Lift the archive freeze + tags: + - archive + /archive/status: + get: + description: Reports whether the sandbox is frozen for an archive export, and which processes were stopped for it. + responses: + "200": + description: Archive status + content: + application/json: + schema: + $ref: "#/components/schemas/QuiesceStatus" + summary: Get the archive status + tags: + - archive + "/codegen/fastapply/{path}": + put: + description: >- + Uses the configured LLM provider (Relace or Morph) to apply a code edit to the original content. + + + To use this endpoint as an agent tool, follow these guidelines: + + + Use this tool to make an edit to an existing file. This will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write. + + + When writing the edit, you should specify each edit in sequence, with the special comment "// ... existing code ..." to represent unchanged code in between edited lines. + + + Example format: + + // ... existing code ... + + FIRST_EDIT + + // ... existing code ... + + SECOND_EDIT + + // ... existing code ... + + THIRD_EDIT + + // ... existing code ... + + + You should still bias towards repeating as few lines of the original file as possible to convey the change. But, each edit should contain minimally sufficient context of unchanged lines around the code you're editing to resolve ambiguity. + + + DO NOT omit spans of pre-existing code (or comments) without using the "// ... existing code ..." comment to indicate its absence. If you omit the existing code comment, the model may inadvertently delete these lines. + + + If you plan on deleting a section, you must provide context before and after to delete it. If the initial code is "Block 1\nBlock 2\nBlock 3", and you want to remove Block 2, you would output "// ... existing code ...\nBlock 1\nBlock 3\n// ... existing code ...". + + + Make sure it is clear what the edit should be, and where it should be applied. Make edits to a file in a single edit_file call instead of multiple edit_file calls to the same file. The apply model can handle many distinct edits at once. + parameters: + - description: Path to the file to edit (relative to workspace) + in: path + name: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ApplyEditRequest" + description: Code edit request + required: true + responses: + "200": + description: Code edit applied successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ApplyEditResponse" + "400": + description: Invalid request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity - failed to process the request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: Service unavailable - no provider configured + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Apply code edit + tags: + - fastapply + "/codegen/reranking/{path}": + get: + description: >- + Uses Relace's code reranking model to find the most relevant files for a given query. This is useful as a first pass in agentic exploration to narrow down the search space. + + + Based on: https://docs.relace.ai/docs/code-reranker/agent + + + Query Construction: The query can be a short question or a more detailed conversation with the user request included. For a first pass, use the full conversation; for subsequent calls, use more targeted questions. + + + Token Limit and Score Threshold: For 200k token context models like Claude 4 Sonnet, recommended defaults are scoreThreshold=0.5 and tokenLimit=30000. + + + The response will be a list of file paths and contents ordered from most relevant to least relevant. + parameters: + - description: Path to search in (relative to workspace) + in: path + name: path + required: true + schema: + type: string + - description: Natural language query to search for + in: query + name: query + required: true + schema: + type: string + - description: "Minimum relevance score (default: 0.5)" + in: query + name: scoreThreshold + schema: + type: number + - description: "Maximum tokens to return (default: 30000)" + in: query + name: tokenLimit + schema: + type: integer + - description: Regex pattern to filter files (e.g., .*\\.ts$ for TypeScript files) + in: query + name: filePattern + schema: + type: string + responses: + "200": + description: Relevant files found + content: + application/json: + schema: + $ref: "#/components/schemas/RerankingResponse" + "400": + description: Invalid request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity - failed to process the request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: Service unavailable - Relace not configured + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Code reranking/semantic search + tags: + - codegen + /drives/mount: + get: + description: Returns a list of all currently mounted drives managed by blfs + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/DriveListResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - BearerAuth: [] + summary: List currently mounted drives + tags: + - drive + post: + description: Mounts an agent drive using the blfs binary to a local path, optionally mounting a subpath within the drive. Supports optional UID/GID mapping to remap file ownership between the local sandbox and the filer (always mapped to filer UID/GID 0). Mapping values can be set per-request via uidMap/gidMap fields, or globally via BLFS_UID_MAP/BLFS_GID_MAP environment variables (request values take precedence). + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DriveMountRequest" + description: Drive attachment parameters + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/DriveMountResponse" + "400": + description: Bad Request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "409": + description: Conflict + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - BearerAuth: [] + summary: Attach a drive to a local path + tags: + - drive + "/drives/mount/{mountPath}": + delete: + description: Unmounts a previously mounted drive from the specified local path + parameters: + - description: Mount path to detach (must start with /, e.g. /mnt/test) + in: path + name: mountPath + required: true + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/DriveUnmountResponse" + "400": + description: Bad Request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + security: + - BearerAuth: [] + summary: Detach a drive from a local path + tags: + - drive + /environment/reload: + post: + description: Re-reads /bl/metadata and applies its environment to the sandbox-api process, so this process and every process started afterwards see the current values. Called by the guest init after an environment update; safe to call manually. + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/handler.ReloadResponse" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Reload environment from guest metadata + tags: + - system + "/filesystem-content-search/{path}": + get: + description: Searches for text content inside files using ripgrep. Returns matching lines with context. + parameters: + - description: Directory path to search in + in: path + name: path + required: true + schema: + type: string + - description: Text to search for + in: query + name: query + required: true + schema: + type: string + - description: "Case sensitive search (default: false)" + in: query + name: caseSensitive + schema: + type: boolean + - description: "Maximum number of results to return (default: 100)" + in: query + name: maxResults + schema: + type: integer + - description: File pattern to include (e.g., *.go) + in: query + name: filePattern + schema: + type: string + - description: "Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage)" + in: query + name: excludeDirs + schema: + type: string + responses: + "200": + description: Content search results + content: + application/json: + schema: + $ref: "#/components/schemas/ContentSearchResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Search for text content in files + tags: + - filesystem + "/filesystem-find/{path}": + get: + description: Finds files and directories using the find command. + parameters: + - description: Path to search in (e.g., /home/user/projects) + in: path + name: path + required: true + schema: + type: string + - description: Type of search (file or directory) + in: query + name: type + schema: + type: string + - description: Comma-separated file patterns to include (e.g., *.go,*.js) + in: query + name: patterns + schema: + type: string + - description: "Maximum number of results to return (default: 20). If set to 0, all results will be returned." + in: query + name: maxResults + schema: + type: integer + - description: "Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage). Use empty string to skip no directories." + in: query + name: excludeDirs + schema: + type: string + - description: "Exclude hidden files and directories (default: true)" + in: query + name: excludeHidden + schema: + type: boolean + responses: + "200": + description: Find results + content: + application/json: + schema: + $ref: "#/components/schemas/FindResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Find files and directories + tags: + - filesystem + /filesystem-multipart: + get: + description: List all active multipart uploads + responses: + "200": + description: List of active uploads + content: + application/json: + schema: + $ref: "#/components/schemas/MultipartListUploadsResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: List multipart uploads + tags: + - filesystem + "/filesystem-multipart/{uploadId}/abort": + delete: + description: Abort a multipart upload and clean up all parts + parameters: + - description: Upload ID + in: path + name: uploadId + required: true + schema: + type: string + responses: + "200": + description: Upload aborted + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: Upload not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Abort multipart upload + tags: + - filesystem + "/filesystem-multipart/{uploadId}/complete": + post: + description: Complete a multipart upload by assembling all parts + parameters: + - description: Upload ID + in: path + name: uploadId + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/MultipartCompleteRequest" + description: List of parts + required: true + responses: + "200": + description: Upload completed + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: Upload not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Complete multipart upload + tags: + - filesystem + "/filesystem-multipart/{uploadId}/part": + put: + description: Upload a single part of a multipart upload + parameters: + - description: Upload ID + in: path + name: uploadId + required: true + schema: + type: string + - description: Part number (1-10000) + in: query + name: partNumber + required: true + schema: + type: integer + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: Part data + type: string + format: binary + required: + - file + required: true + responses: + "200": + description: Part uploaded + content: + application/json: + schema: + $ref: "#/components/schemas/MultipartUploadPartResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: Upload not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Upload part + tags: + - filesystem + "/filesystem-multipart/{uploadId}/parts": + get: + description: List all uploaded parts for a multipart upload + parameters: + - description: Upload ID + in: path + name: uploadId + required: true + schema: + type: string + responses: + "200": + description: List of parts + content: + application/json: + schema: + $ref: "#/components/schemas/MultipartListPartsResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: Upload not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: List parts + tags: + - filesystem + "/filesystem-multipart/initiate/{path}": + post: + description: Initiate a multipart upload session for a file + parameters: + - description: File path + in: path + name: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/MultipartInitiateRequest" + description: Optional permissions + responses: + "200": + description: Upload session created + content: + application/json: + schema: + $ref: "#/components/schemas/MultipartInitiateResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Initiate multipart upload + tags: + - filesystem + "/filesystem-search/{path}": + get: + description: Performs fuzzy search on filesystem paths using fuzzy matching algorithm. Optimized alternative to find and grep commands. + parameters: + - description: Path to search in (e.g., /home/user/projects) + in: path + name: path + required: true + schema: + type: string + - description: "Maximum number of results to return (default: 20)" + in: query + name: maxResults + schema: + type: integer + - description: Comma-separated file patterns to include (e.g., *.go,*.js) + in: query + name: patterns + schema: + type: string + - description: "Comma-separated directory names to skip (default: node_modules,vendor,.git,dist,build,target,__pycache__,.venv,.next,coverage). Use empty string to skip no directories." + in: query + name: excludeDirs + schema: + type: string + - description: "Exclude hidden files and directories (default: true)" + in: query + name: excludeHidden + schema: + type: boolean + responses: + "200": + description: Fuzzy search results + content: + application/json: + schema: + $ref: "#/components/schemas/FuzzySearchResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Fuzzy search for files and directories + tags: + - filesystem + "/filesystem/{path}": + delete: + description: Delete a file or directory + parameters: + - description: File or directory path + in: path + name: path + required: true + schema: + type: string + - description: Delete directory recursively + in: query + name: recursive + schema: + type: boolean + responses: + "200": + description: Success message + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "404": + description: File or directory not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Delete file or directory + tags: + - filesystem + get: + description: Get content of a file or listing of a directory. Use Accept header to control response format for files. + parameters: + - description: File or directory path + in: path + name: path + required: true + schema: + type: string + - description: Force download mode for files + in: query + name: download + schema: + type: boolean + responses: + "200": + description: Directory listing + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/Directory" + - $ref: "#/components/schemas/FileWithContent" + - type: string + format: binary + application/octet-stream: + schema: + oneOf: + - $ref: "#/components/schemas/Directory" + - $ref: "#/components/schemas/FileWithContent" + - type: string + format: binary + "404": + description: File or directory not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + application/octet-stream: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + application/octet-stream: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + application/octet-stream: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Get file or directory information + tags: + - filesystem + put: + description: Create or update a file or directory + parameters: + - description: File or directory path + in: path + name: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/FileRequest" + description: File or directory details + required: true + responses: + "200": + description: Success message + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Create or update a file or directory + tags: + - filesystem + "/filesystem/tree/{path}": + delete: + description: Delete a directory tree recursively + parameters: + - description: Root directory path + in: path + name: path + required: true + schema: + type: string + - description: Delete directory recursively + in: query + name: recursive + schema: + type: boolean + responses: + "200": + description: Directory deleted successfully + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Delete directory tree + tags: + - filesystem + get: + description: Get a recursive directory tree structure starting from the specified path + parameters: + - description: Root directory path + in: path + name: path + required: true + schema: + type: string + responses: + "200": + description: Directory tree + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/Directory" + - $ref: "#/components/schemas/FileWithContent" + - type: string + format: binary + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Get directory tree + tags: + - filesystem + put: + description: Create or update multiple files within a directory tree structure + parameters: + - description: Root directory path + in: path + name: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TreeRequest" + description: Map of file paths to content + required: true + responses: + "200": + description: Updated directory tree + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/Directory" + - $ref: "#/components/schemas/FileWithContent" + - type: string + format: binary + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Create or update directory tree + tags: + - filesystem + /health: + get: + description: >- + Returns health status and system information including upgrade count and binary details + + Also includes last upgrade attempt status with detailed error information if available + responses: + "200": + description: Health status + content: + application/json: + schema: + $ref: "#/components/schemas/HealthResponse" + summary: Health check + tags: + - system + "/network/process/{pid}/monitor": + delete: + description: Stop monitoring for new ports opened by a process + parameters: + - description: Process ID + in: path + name: pid + required: true + schema: + type: integer + responses: + "200": + description: Object containing PID and success message + content: + application/json: + schema: + additionalProperties: true + type: object + "400": + description: Invalid process ID + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Stop monitoring ports for a process + tags: + - network + post: + description: Start monitoring for new ports opened by a process + parameters: + - description: Process ID + in: path + name: pid + required: true + schema: + type: integer + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PortMonitorRequest" + description: Port monitor configuration + required: true + responses: + "200": + description: Object containing PID and success message + content: + application/json: + schema: + additionalProperties: true + type: object + "400": + description: Invalid request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Start monitoring ports for a process + tags: + - network + "/network/process/{pid}/ports": + get: + description: Get a list of all open ports for a process + parameters: + - description: Process ID + in: path + name: pid + required: true + schema: + type: integer + responses: + "200": + description: Object containing PID and array of network.PortInfo + content: + application/json: + schema: + additionalProperties: true + type: object + "400": + description: Invalid process ID + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Get open ports for a process + tags: + - network + /network/tunnel: + delete: + description: "Stop the network tunnel and restore the original network configuration. WARNING: After disconnecting, the sandbox will lose all outbound internet connectivity (no egress). Inbound connections to the sandbox will still work. Use PUT /network/tunnel/config to re-establish the tunnel." + responses: + "200": + description: Tunnel disconnected + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "400": + description: No tunnel is running + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Failed to stop tunnel + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Disconnect tunnel + tags: + - network + /network/tunnel/config: + put: + description: Apply a new tunnel configuration on the fly. The existing tunnel is torn down and a new one is established. This endpoint is write-only; there is no corresponding GET to read the config back. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TunnelConfigRequest" + description: Base64-encoded tunnel configuration + required: true + responses: + "200": + description: Configuration applied + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "400": + description: Invalid request body + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Invalid tunnel configuration + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Failed to apply configuration + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Update tunnel configuration + tags: + - network + /process: + get: + description: Get a list of all running and completed processes + responses: + "200": + description: Process list + content: + application/json: + schema: + items: + $ref: "#/components/schemas/ProcessResponse" + type: array + summary: List all processes + tags: + - process + post: + description: Execute a command and return process information. If Accept header is text/event-stream, streams logs in SSE format and returns the process response as a final event. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessRequest" + description: Process execution request + required: true + responses: + "200": + description: Process information + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessResponse" + text/event-stream: + schema: + $ref: "#/components/schemas/ProcessResponse" + "400": + description: Invalid request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + text/event-stream: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + text/event-stream: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + text/event-stream: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Execute a command + tags: + - process + "/process/{identifier}": + delete: + description: Gracefully stop a running process + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + responses: + "200": + description: Process stopped + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "404": + description: Process not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Stop a process + tags: + - process + get: + description: Get information about a process by its PID or name + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + responses: + "200": + description: Process information + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessResponse" + "404": + description: Process not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Get process by identifier + tags: + - process + "/process/{identifier}/kill": + delete: + description: Forcefully kill a running process + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + responses: + "200": + description: Process killed + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "404": + description: Process not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Kill a process + tags: + - process + "/process/{identifier}/logs": + get: + description: Get the stdout and stderr output of a process + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + responses: + "200": + description: Process logs + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessLogs" + "404": + description: Process not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Get process logs + tags: + - process + "/process/{identifier}/logs/stream": + get: + description: Streams the stdout and stderr output of a process in real time, one line per log, prefixed with 'stdout:' or 'stderr:'. Closes when the process exits or the client disconnects. + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + responses: + "200": + description: Stream of process logs, one line per log (prefixed with stdout:/stderr:) + content: + text/plain: + schema: + type: string + "404": + description: Process not found + content: + text/plain: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Unprocessable entity + content: + text/plain: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + text/plain: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Stream process logs in real time + tags: + - process + "/process/{identifier}/stdin": + delete: + description: Send EOF to the process by closing its stdin pipe. Idempotent. For stdio protocols such as MCP this is the clean shutdown path. + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + responses: + "200": + description: Stdin closed + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "404": + description: Process not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "409": + description: Process has no stdin + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Close a process's stdin + tags: + - process + post: + description: 'Write the raw request body to the stdin of a process started with "stdin": true. Bytes are forwarded verbatim, so include the trailing newline your protocol expects. Sequential requests keep their order; each body is written atomically with respect to other writers. The pipe does not survive a sandbox-api restart: once it is gone this returns 409 and the process must be restarted.' + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + requestBody: + content: + application/octet-stream: + schema: + type: string + description: Raw bytes to write + required: true + responses: + "200": + description: Bytes written + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "404": + description: Process not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "409": + description: Process has no stdin, or stdin is closed + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "413": + description: Body over 8 MiB + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Write failed + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "503": + description: Process stopped reading its stdin + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Write to a process's stdin + tags: + - process + /upgrade: + post: + description: >- + Triggers an upgrade of the sandbox-api process. Returns 200 immediately before upgrading. + + The upgrade will: download the specified binary from GitHub releases, validate it, and restart. + + All running processes will be preserved across the upgrade. + + Available versions: "latest" (default, most recent release), "develop", "main", or specific tag like "v1.0.0" + + You can also specify a custom baseUrl for forks (defaults to https://github.com/blaxel-ai/sandbox/releases) + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpgradeRequest" + description: Upgrade options + responses: + "200": + description: Upgrade initiated + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "500": + description: Internal server error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Upgrade the sandbox-api + tags: + - system + "/watch/filesystem/{path}": + get: + description: Streams the path of modified files (one per line) in the given directory. Closes when the client disconnects. + parameters: + - description: Ignore patterns (comma-separated) + in: query + name: ignore + schema: + type: string + - description: Directory path to watch + in: path + name: path + required: true + schema: + type: string + responses: + "200": + description: Stream of modified file paths, one per line + content: + text/plain: + schema: + type: string + "400": + description: Invalid path + content: + text/plain: + schema: + $ref: "#/components/schemas/ErrorResponse" + "500": + description: Internal server error + content: + text/plain: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Stream file modification events in a directory + tags: + - filesystem +servers: + - url: https://sbx-{sandbox_id}-{workspace_id}.{region}.bl.run + variables: + sandbox_id: + default: unknown + workspace_id: + default: unknown + region: + default: unknown +components: + securitySchemes: + BearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + schemas: + ApplyEditRequest: + properties: + codeEdit: + example: |- + // Add world parameter + function hello(world) { + console.log('Hello', world); + } + type: string + model: + example: relace-apply-3 + type: string + required: + - codeEdit + type: object + ApplyEditResponse: + properties: + message: + example: Code edit applied successfully + type: string + originalContent: + example: |- + function hello() { + console.log('Hello'); + } + type: string + path: + example: src/main.js + type: string + provider: + example: Relace + type: string + success: + example: true + type: boolean + updatedContent: + example: |- + function hello(world) { + console.log('Hello', world); + } + type: string + type: object + ArchiveManifest: + properties: + added: + description: Added and Modified count the archive's payload members. + example: 11 + type: integer + apiVersion: + description: APIVersion is the sandbox-api build that produced the archive. + example: v0.1.0 + type: string + createdAt: + type: string + deleted: + description: >- + Deleted are paths the image has and the sandbox deleted. Tar cannot carry + + a deletion, so import applies these from the manifest. + items: + type: string + type: array + excludes: + description: Excludes are the paths left out of the comparison. + items: + type: string + type: array + imageDevice: + description: >- + ImageDevice is the device the pristine image was read from, for the record: + + it says where the sandbox that exported the archive found its image. + example: /dev/vda + type: string + modified: + example: 3 + type: integer + payloadBytes: + description: PayloadBytes is the total content size of the payload members. + example: 3073449 + type: integer + processes: + description: Processes tells whether ProcessesName is present. + example: true + type: boolean + root: + description: Root is the directory the paths are relative to. + example: / + type: string + version: + example: 1 + type: integer + required: + - createdAt + - root + - version + type: object + ContentSearchMatch: + properties: + column: + example: 10 + type: integer + context: + example: |- + previous line + current line + next line + type: string + line: + example: 42 + type: integer + path: + example: src/main.go + type: string + text: + example: const searchText = 'example' + type: string + required: + - column + - line + - path + - text + type: object + ContentSearchResponse: + properties: + matches: + items: + $ref: "#/components/schemas/ContentSearchMatch" + type: array + query: + example: searchText + type: string + total: + example: 5 + type: integer + required: + - matches + - query + - total + type: object + Directory: + properties: + files: + items: + $ref: "#/components/schemas/File" + type: array + name: + type: string + path: + type: string + subdirectories: + description: "@name Subdirectories" + items: + $ref: "#/components/schemas/Subdirectory" + type: array + required: + - files + - name + - path + - subdirectories + type: object + DriveListResponse: + properties: + mounts: + items: + $ref: "#/components/schemas/DriveMountInfo" + type: array + type: object + DriveMountInfo: + properties: + driveName: + type: string + drivePath: + type: string + gidMap: + description: The local GID used for this mount + type: string + mountPath: + type: string + readOnly: + type: boolean + uidMap: + description: The local UID used for this mount + type: string + type: object + DriveMountRequest: + properties: + driveName: + type: string + drivePath: + description: Optional, defaults to "/" + type: string + gidMap: + description: Optional, local GID to map (filer GID is always 0) + type: string + mountPath: + type: string + readOnly: + description: Optional, defaults to false + type: boolean + uidMap: + description: Optional, local UID to map (filer UID is always 0) + type: string + required: + - driveName + - mountPath + type: object + DriveMountResponse: + properties: + driveName: + type: string + drivePath: + type: string + gidMap: + description: The local GID used for this mount + type: string + message: + type: string + mountPath: + type: string + readOnly: + type: boolean + success: + type: boolean + uidMap: + description: The local UID used for this mount + type: string + type: object + DriveUnmountResponse: + properties: + message: + type: string + mountPath: + type: string + success: + type: boolean + type: object + ErrorResponse: + properties: + error: + example: Error message + type: string + required: + - error + type: object + ExportOptions: + properties: + async: + description: >- + Async starts the export and answers immediately, leaving it to run: an + + archive of a large filesystem takes longer than a request may be held + + open. Its progress is reported by /archive/status. + example: false + type: boolean + dryRun: + description: |- + DryRun reports what would be archived, and its exact size, without + stopping anything and without uploading. + example: false + type: boolean + excludes: + description: Excludes are added to the paths excluded by default. + items: + type: string + type: array + headers: + additionalProperties: + type: string + description: >- + Headers are sent with the upload request as given. A presigned URL only + + accepts the headers it was signed for, so these have to match what the + + caller signed: sending one that was not signed, or signing one that is not + + sent, is rejected as a signature mismatch. Typical use is a storage class, + + x-amz-storage-class: GLACIER_IR. + type: object + imageDevice: + description: >- + ImageDevice is the device holding the pristine image. It is found on its + + own, wherever the sandbox booted from attached it, and naming one here + + only overrides that. + example: /dev/vda + type: string + imageMountPoint: + description: >- + ImageMountPoint is a directory where the pristine image is already mounted. + + When set the image device is neither mounted nor unmounted. + example: /mnt/lower + type: string + multipart: + allOf: + - $ref: "#/components/schemas/MultipartUpload" + description: >- + Multipart uploads the archive part by part instead, which is how an + + archive larger than the 5 GB a single PUT accepts is stored. It takes + + precedence over URL. + saveProcesses: + description: |- + SaveProcesses stores the process list in the archive so restore can + relaunch the workload. Defaults to true; set it to false to archive + storage only. + example: true + type: boolean + stopTimeoutSeconds: + description: StopTimeoutSeconds bounds the graceful stop of each process. + example: 30 + type: integer + url: + description: >- + URL is a presigned S3 PUT URL the archive is streamed to. Empty is only + + valid with DryRun, or with Multipart. + example: https://bucket.s3.amazonaws.com/key?... + type: string + type: object + ExportProgress: + properties: + error: + description: Error is why the export failed, without the presigned URL it used. + type: string + finishedAt: + type: string + size: + description: Size is the archive's exact size, known once the filesystem is scanned. + example: 3074211 + type: integer + startedAt: + type: string + state: + allOf: + - $ref: "#/components/schemas/archive.ExportState" + example: running + uploaded: + description: Uploaded reports whether the storage holds the archive. + example: false + type: boolean + type: object + ExportResult: + properties: + changes: + description: |- + Changes lists every path in the archive. Only filled for a dry run, + where it is the point of the call. + items: + $ref: "#/components/schemas/archive.Change" + type: array + duration: + example: 4.2s + type: string + manifest: + $ref: "#/components/schemas/ArchiveManifest" + size: + description: |- + Size is the exact number of bytes uploaded, known before the upload + starts since the archive is not compressed. + example: 3074211 + type: integer + stoppedProcesses: + description: StoppedProcesses are the processes stopped to freeze the filesystem. + items: + type: string + type: array + uploaded: + description: Uploaded is false for a dry run. + example: true + type: boolean + required: + - manifest + type: object + File: + properties: + group: + type: string + lastModified: + type: string + name: + type: string + owner: + type: string + path: + type: string + permissions: + type: string + size: + type: integer + required: + - group + - lastModified + - name + - owner + - path + - permissions + - size + type: object + FileRequest: + properties: + content: + example: file contents here + type: string + isDirectory: + example: false + type: boolean + permissions: + example: "0644" + type: string + type: object + FileWithContent: + properties: + content: + type: string + group: + type: string + lastModified: + type: string + name: + type: string + owner: + type: string + path: + type: string + permissions: + type: string + size: + type: integer + required: + - content + - group + - lastModified + - name + - owner + - path + - permissions + - size + type: object + FindMatch: + properties: + path: + example: src/main.go + type: string + type: + description: '"file" or "directory"' + example: file + type: string + required: + - path + - type + type: object + FindResponse: + properties: + matches: + items: + $ref: "#/components/schemas/FindMatch" + type: array + total: + example: 5 + type: integer + required: + - matches + - total + type: object + FuzzySearchMatch: + properties: + path: + example: src/main.go + type: string + score: + example: 100 + type: integer + type: + description: '"file" or "directory"' + example: file + type: string + required: + - path + - score + - type + type: object + FuzzySearchResponse: + properties: + matches: + items: + $ref: "#/components/schemas/FuzzySearchMatch" + type: array + total: + example: 5 + type: integer + required: + - matches + - total + type: object + HealthResponse: + properties: + arch: + example: amd64 + type: string + buildTime: + example: 2026-01-29T17:36:52Z + type: string + gitCommit: + example: abc123 + type: string + goVersion: + example: go1.25.0 + type: string + lastUpgrade: + $ref: "#/components/schemas/UpgradeStatus" + os: + example: linux + type: string + startedAt: + example: 2026-01-29T18:45:49Z + type: string + status: + example: ok + type: string + upgradeCount: + example: 0 + type: integer + uptime: + example: 1h30m + type: string + uptimeSeconds: + example: 5400.5 + type: number + version: + example: v0.1.0 + type: string + required: + - arch + - buildTime + - gitCommit + - goVersion + - lastUpgrade + - os + - startedAt + - status + - upgradeCount + - uptime + - uptimeSeconds + - version + type: object + MultipartCompleteRequest: + properties: + parts: + items: + $ref: "#/components/schemas/MultipartPartInfo" + type: array + type: object + MultipartInitiateRequest: + properties: + permissions: + example: "0644" + type: string + type: object + MultipartInitiateResponse: + properties: + path: + example: /tmp/largefile.dat + type: string + uploadId: + example: 550e8400-e29b-41d4-a716-446655440000 + type: string + type: object + MultipartListPartsResponse: + properties: + parts: + items: + $ref: "#/components/schemas/filesystem.UploadedPart" + type: array + uploadId: + example: 550e8400-e29b-41d4-a716-446655440000 + type: string + type: object + MultipartListUploadsResponse: + properties: + uploads: + items: + $ref: "#/components/schemas/filesystem.MultipartUpload" + type: array + type: object + MultipartPartInfo: + properties: + etag: + example: 5d41402abc4b2a76b9719d911017c592 + type: string + partNumber: + example: 1 + type: integer + type: object + MultipartUpload: + properties: + abortUrl: + description: >- + AbortURL is a presigned DELETE URL that discards the parts already + + uploaded. Without it a failed export leaves them on the storage until a + + lifecycle rule removes them. + type: string + completeUrl: + description: CompleteURL is a presigned POST URL that assembles the parts. + type: string + partSize: + description: PartSize is the number of bytes sent to every part but the last. + example: 536870912 + type: integer + partUrls: + description: >- + PartURLs are presigned PUT URLs, one per part, in order. Extra ones are + + left unused. + items: + type: string + type: array + type: object + MultipartUploadPartResponse: + properties: + etag: + example: 5d41402abc4b2a76b9719d911017c592 + type: string + partNumber: + example: 1 + type: integer + size: + example: 5242880 + type: integer + type: object + PortMonitorRequest: + properties: + callback: + description: URL to call when a new port is detected + example: http://localhost:3000/callback + type: string + type: object + ProcessLogs: + properties: + logs: + example: logs output + type: string + stderr: + example: stderr output + type: string + stdout: + example: stdout output + type: string + required: + - logs + - stderr + - stdout + type: object + ProcessRequest: + properties: + command: + example: ls -la + type: string + env: + additionalProperties: + type: string + example: + "{\"PORT\"": ' "3000"}' + type: object + keepAlive: + description: Disable scale-to-zero while process runs. Default timeout is 600s (10 minutes). Set timeout to 0 for infinite. + example: false + type: boolean + maxRestarts: + description: Maximum number of restarts on failure. Set to a negative value (e.g. -1) for unlimited restarts. + example: 3 + type: integer + name: + example: my-process + type: string + restartOnFailure: + example: true + type: boolean + stdin: + description: "Open a writable stdin pipe, fed via POST /process/{identifier}/stdin and closed via DELETE. The pipe does not survive a sandbox-api restart: the process then sees EOF." + example: false + type: boolean + timeout: + description: Timeout in seconds. When keepAlive is true, defaults to 600s (10 minutes). Set to 0 for infinite (no auto-kill). + example: 30 + type: integer + waitForCompletion: + example: false + type: boolean + waitForPorts: + example: + - 3000 + - 8080 + items: + type: integer + type: array + workingDir: + example: /home/user + type: string + required: + - command + type: object + ProcessResponse: + properties: + command: + example: ls -la + type: string + completedAt: + example: Wed, 01 Jan 2023 12:01:00 GMT + type: string + exitCode: + example: 0 + type: integer + keepAlive: + description: Whether scale-to-zero is disabled for this process + example: false + type: boolean + logs: + example: logs output + type: string + maxRestarts: + example: 3 + type: integer + name: + example: my-process + type: string + pid: + example: "1234" + type: string + restartCount: + example: 2 + type: integer + restartOnFailure: + example: true + type: boolean + startedAt: + example: Wed, 01 Jan 2023 12:00:00 GMT + type: string + status: + enum: + - failed + - killed + - stopped + - running + - completed + example: running + type: string + stderr: + example: stderr output + type: string + stdin: + description: Whether the process was started with a writable stdin pipe + example: false + type: boolean + stdout: + example: stdout output + type: string + workingDir: + example: /home/user + type: string + required: + - command + - completedAt + - exitCode + - logs + - name + - pid + - startedAt + - status + - stderr + - stdout + - workingDir + type: object + QuiesceStatus: + properties: + export: + allOf: + - $ref: "#/components/schemas/ExportProgress" + description: >- + Export reports the export started asynchronously, if there was one. It is + + how a caller that did not wait for the export learns that the archive is + + on the storage, or why it is not. + readOnlyRoot: + description: >- + ReadOnlyRoot reports whether the root mount was remounted read-only, which + + is what actually stops writes; false means the freeze relies only on the + + API refusing calls, and the reason says why. + example: true + type: boolean + reason: + description: Reason is a human readable explanation of why the sandbox is frozen. + example: archive export + type: string + restore: + allOf: + - $ref: "#/components/schemas/RestoreProgress" + description: |- + Restore reports the archive this sandbox was started from, if it was + started from one: how far its restore has got, and how it ended. + since: + description: Since is when the sandbox left StateActive. + type: string + state: + allOf: + - $ref: "#/components/schemas/archive.QuiesceState" + example: quiesced + stoppedProcesses: + description: StoppedProcesses are the process identifiers stopped while quiescing. + items: + type: string + type: array + required: + - state + type: object + RankedFile: + properties: + content: + type: string + path: + type: string + score: + type: number + type: object + RerankingResponse: + properties: + files: + items: + $ref: "#/components/schemas/RankedFile" + type: array + message: + example: Found 5 relevant files + type: string + success: + example: true + type: boolean + type: object + RestoreProgress: + properties: + deleted: + example: 3 + type: integer + downloaded: + description: Downloaded is how much of the archive has been read so far. + example: 1048576 + type: integer + error: + description: Error is why the restore failed, without the presigned URL it used. + type: string + finishedAt: + type: string + restored: + description: Restored and Deleted count what the archive changed on the filesystem. + example: 1204 + type: integer + size: + description: >- + Size is the archive's size as the storage announced it, and zero when it + + announced none - a client showing a percentage has to allow for that. + example: 3074211 + type: integer + startedAt: + type: string + state: + allOf: + - $ref: "#/components/schemas/archive.RestoreState" + example: extracting + type: object + Subdirectory: + properties: + name: + type: string + path: + type: string + required: + - name + - path + type: object + SuccessResponse: + properties: + message: + example: File created successfully + type: string + path: + example: /path/to/file + type: string + required: + - message + type: object + TreeRequest: + properties: + files: + additionalProperties: + type: string + example: + '"dir/file2.txt"': '"content2"}' + "{\"file1.txt\"": '"content1"' + type: object + type: object + TunnelConfigRequest: + properties: + config: + description: Base64-encoded tunnel config JSON + example: eyJsb2NhbF9pcCI6ICIxMC4wLjAuMS8zMiIsIC4uLn0= + type: string + required: + - config + type: object + UpgradeRequest: + properties: + baseUrl: + description: Base URL for releases (useful for forks) + example: https://github.com/blaxel-ai/sandbox/releases + type: string + version: + description: 'Version to upgrade to: "latest" (default), "develop", "main", or specific tag like "v1.0.0"' + example: latest + type: string + type: object + UpgradeStatus: + properties: + binaryPath: + description: Path to downloaded binary + example: /tmp/sandbox-api-new + type: string + bytesDownloaded: + description: Bytes downloaded + example: 25034936 + type: integer + downloadUrl: + description: URL used for download + example: https://github.com/... + type: string + error: + description: Error message if failed + example: Failed to download binary + type: string + lastAttempt: + description: When the upgrade was attempted + type: string + status: + allOf: + - $ref: "#/components/schemas/process.UpgradeState" + description: Current state (idle, running, completed, failed) + example: running + step: + description: Current/last step (none, starting, download, validate, replace, completed, skipped) + example: download + type: string + version: + description: Version being upgraded to + example: latest + type: string + required: + - status + - step + - version + type: object + archive.Change: + properties: + kind: + allOf: + - $ref: "#/components/schemas/archive.ChangeKind" + example: added + path: + description: Path is relative to the root, without a leading slash. + example: usr/bin/curl + type: string + size: + description: Size is the file content size in bytes, 0 for anything but a regular file. + example: 256216 + type: integer + required: + - kind + - path + type: object + archive.ChangeKind: + enum: + - added + - modified + - deleted + type: string + x-enum-varnames: + - ChangeAdded + - ChangeModified + - ChangeDeleted + archive.ExportState: + enum: + - running + - succeeded + - failed + type: string + x-enum-varnames: + - ExportRunning + - ExportSucceeded + - ExportFailed + archive.QuiesceState: + enum: + - active + - quiescing + - quiesced + - restoring + type: string + x-enum-varnames: + - StateActive + - StateQuiescing + - StateQuiesced + - StateRestoring + archive.RestoreState: + enum: + - downloading + - extracting + - relaunching + - succeeded + - failed + type: string + x-enum-varnames: + - RestoreDownloading + - RestoreExtracting + - RestoreRelaunching + - RestoreSucceeded + - RestoreFailed + filesystem.MultipartUpload: + properties: + initiatedAt: + type: string + parts: + additionalProperties: + $ref: "#/components/schemas/filesystem.UploadedPart" + type: object + path: + example: /tmp/largefile.dat + type: string + permissions: + example: 420 + type: integer + uploadId: + example: 550e8400-e29b-41d4-a716-446655440000 + type: string + type: object + filesystem.UploadedPart: + properties: + etag: + example: 5d41402abc4b2a76b9719d911017c592 + type: string + partNumber: + example: 1 + type: integer + size: + example: 5242880 + type: integer + uploadedAt: + type: string + type: object + handler.ReloadResponse: + properties: + applied: + type: integer + generation: + type: integer + removed: + type: integer + type: object + process.UpgradeState: + enum: + - idle + - running + - completed + - failed + type: string + x-enum-comments: + UpgradeStateCompleted: Upgrade completed successfully + UpgradeStateFailed: Upgrade failed + UpgradeStateIdle: No upgrade in progress + UpgradeStateRunning: Upgrade is currently running + x-enum-descriptions: + - No upgrade in progress + - Upgrade is currently running + - Upgrade completed successfully + - Upgrade failed + x-enum-varnames: + - UpgradeStateIdle + - UpgradeStateRunning + - UpgradeStateCompleted + - UpgradeStateFailed +security: + - BearerAuth: [] diff --git a/scripts/docgen/conf.py b/scripts/docgen/conf.py index b7571ab..3888bd0 100644 --- a/scripts/docgen/conf.py +++ b/scripts/docgen/conf.py @@ -53,6 +53,7 @@ NAV_ONLY = { "baseten.client.managementapi": ["ApiClient", "AsyncApiClient"], "baseten.client.inferenceapi": ["ApiClient", "AsyncApiClient"], + "baseten.client.sandboxapi": ["ApiClient", "AsyncApiClient"], "baseten.client.modelconfig": ["ModelConfig"], } diff --git a/tests/client/test_management.py b/tests/client/test_management.py index 9aff422..5899d2c 100644 --- a/tests/client/test_management.py +++ b/tests/client/test_management.py @@ -84,7 +84,7 @@ def test_get_with_query_params() -> None: client = make_sync_client(fake) client.api.get_model_apis( - request=baseten.client.managementapi.GetModelApisRequest(added_only=True) + params=baseten.client.managementapi.GetModelApisParams(added_only=True) ) path, _, query = fake.capture.path.partition("?") diff --git a/tests/client/test_sandbox.py b/tests/client/test_sandbox.py new file mode 100644 index 0000000..0e7afac --- /dev/null +++ b/tests/client/test_sandbox.py @@ -0,0 +1,226 @@ +from __future__ import annotations + +import json + +import httpx +import pytest + +import baseten.client.sandboxapi +from baseten.client._sandbox import AsyncSandboxClient, SandboxClient +from tests.conftest import FakeTransport + +SANDBOX_URL = "https://sb-123.b10.co" + + +def make_sync_client(fake: FakeTransport) -> SandboxClient: + client = SandboxClient(token="test-token", base_url=SANDBOX_URL) + client.http_client._transport = fake.sync_transport # type: ignore[attr-defined] + return client + + +def make_async_client(fake: FakeTransport) -> AsyncSandboxClient: + client = AsyncSandboxClient(token="test-token", base_url=SANDBOX_URL) + client.http_client._transport = fake.async_transport # type: ignore[attr-defined] + return client + + +def test_bearer_token_sent() -> None: + fake = FakeTransport(200, {"message": "deleted"}) + client = make_sync_client(fake) + + client.api.delete_process(identifier="proc-1") + + assert fake.capture.path == "/process/proc-1" + assert fake.capture.headers["authorization"] == "Bearer test-token" + client.close() + + +def test_empty_token_omits_authorization() -> None: + fake = FakeTransport(200, {"message": "deleted"}) + client = SandboxClient(token="", base_url=SANDBOX_URL) + client.http_client._transport = fake.sync_transport # type: ignore[attr-defined] + + client.api.delete_process(identifier="proc-1") + + assert "authorization" not in fake.capture.headers + client.close() + + +def test_multipart_files_upload() -> None: + fake = FakeTransport(200, {"etag": "abc", "partNumber": 3, "size": 9}) + client = make_sync_client(fake) + + resp = client.api.put_filesystem_multipart_part( + upload_id="upload-1", + params=baseten.client.sandboxapi.PutFilesystemMultipartPartParams(partNumber=3), + files={"file": ("part.bin", b"part data")}, + ) + + assert resp.etag == "abc" + path, _, query = fake.capture.path.partition("?") + assert path == "/filesystem-multipart/upload-1/part" + assert query == "partNumber=3" + # httpx derives the multipart Content-Type, boundary included. + assert fake.capture.headers["content-type"].startswith("multipart/form-data") + assert b"part data" in fake.capture.body_bytes + client.close() + + +def test_octet_stream_body_sent_unmodified() -> None: + fake = FakeTransport(200, {"message": "written"}) + client = make_sync_client(fake) + + client.api.post_process_stdin(identifier="proc-1", content=b"raw stdin") + + assert fake.capture.path == "/process/proc-1/stdin" + assert fake.capture.headers["content-type"] == "application/octet-stream" + assert fake.capture.body_bytes == b"raw stdin" + client.close() + + +def test_raw_returns_response_unread_with_accept() -> None: + fake = FakeTransport( + 200, raw_content=b"file bytes", content_type="application/octet-stream" + ) + client = make_sync_client(fake) + + response = client.api.get_filesystem_raw( + path="file.txt", accept="application/octet-stream" + ) + + assert isinstance(response, httpx.Response) + # MockTransport responses are buffered, so the unread-ness of a streamed + # response (send(stream=True) in the generated _do_raw) is not + # observable here; the caller contract of read + close still holds. + response.read() + assert response.content == b"file bytes" + response.close() + assert fake.capture.headers["accept"] == "application/octet-stream" + client.close() + + +def test_raw_only_stream_keeps_plain_name() -> None: + fake = FakeTransport(200, raw_content=b"log line\n", content_type="text/plain") + client = make_sync_client(fake) + + response = client.api.get_process_logs_stream(identifier="proc-1") + + response.read() + assert response.content == b"log line\n" + response.close() + assert fake.capture.headers["accept"] == "text/plain" + client.close() + + +def test_aliased_field_passed_and_sent_by_api_name() -> None: + fake = FakeTransport( + 200, {"manifest": {"createdAt": "now", "root": "/", "version": 1}} + ) + client = make_sync_client(fake) + + client.api.post_archive_export( + request=baseten.client.sandboxapi.ExportOptions(async_=True) + ) + + # The field renamed for Python (async_) serializes under its API name. + assert json.loads(fake.capture.body) == {"async": True} + client.close() + + +def test_export_narrows_on_status_code() -> None: + fake = FakeTransport( + 200, {"manifest": {"createdAt": "now", "root": "/", "version": 1}, "size": 1024} + ) + client = make_sync_client(fake) + + resp = client.api.post_archive_export( + request=baseten.client.sandboxapi.ExportOptions() + ) + + assert isinstance(resp, baseten.client.sandboxapi.ExportResult) + client.close() + + fake = FakeTransport(202, {}) + client = make_sync_client(fake) + + resp = client.api.post_archive_export( + request=baseten.client.sandboxapi.ExportOptions() + ) + + assert isinstance(resp, baseten.client.sandboxapi.ExportProgress) + client.close() + + +def test_query_params_serialize() -> None: + fake = FakeTransport(200, {"message": "watching"}) + client = make_sync_client(fake) + + client.api.get_watch_filesystem( + path="dir", + params=baseten.client.sandboxapi.GetWatchFilesystemParams(ignore="*.log"), + ) + + path, _, query = fake.capture.path.partition("?") + assert path == "/watch/filesystem/dir" + assert query == "ignore=%2A.log" + client.close() + + +def test_typed_error_keeps_status() -> None: + fake = FakeTransport(400, {"error": "boom"}) + client = make_sync_client(fake) + + with pytest.raises(baseten.client.sandboxapi.ResponseErrorResponse) as exc_info: + client.api.post_process( + request=baseten.client.sandboxapi.ProcessRequest(command="ls") + ) + + assert exc_info.value.status_code == 400 + assert exc_info.value.error_response.error == "boom" + client.close() + + +def test_untyped_error_on_non_schema_body() -> None: + fake = FakeTransport( + 400, raw_content=b"proxy error", content_type="text/html" + ) + client = make_sync_client(fake) + + with pytest.raises(baseten.client.sandboxapi.ResponseError) as exc_info: + client.api.post_process( + request=baseten.client.sandboxapi.ProcessRequest(command="ls") + ) + + assert exc_info.value.status_code == 400 + client.close() + + +@pytest.mark.asyncio +async def test_async_client_round_trip() -> None: + fake = FakeTransport(200, {"message": "deleted"}) + client = make_async_client(fake) + + resp = await client.api.delete_process(identifier="proc-1") + + assert resp.message == "deleted" + assert fake.capture.headers["authorization"] == "Bearer test-token" + await client.close() + + +@pytest.mark.asyncio +async def test_async_raw_sibling() -> None: + fake = FakeTransport( + 200, raw_content=b"event: done", content_type="text/event-stream" + ) + client = make_async_client(fake) + + response = await client.api.post_process_raw( + request=baseten.client.sandboxapi.ProcessRequest(command="ls"), + accept="text/event-stream", + ) + + await response.aread() + assert response.content == b"event: done" + await response.aclose() + assert fake.capture.headers["accept"] == "text/event-stream" + await client.close() diff --git a/tests/conftest.py b/tests/conftest.py index 133a5e7..6ceb3ef 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,14 +13,27 @@ class CapturedRequest: path: str = "" headers: dict[str, str] = field(default_factory=dict) body: str = "" + body_bytes: bytes = b"" class FakeTransport: - """Mock HTTP transport that captures requests and returns fixed responses.""" + """Mock HTTP transport that captures requests and returns fixed responses. - def __init__(self, status_code: int = 200, response: Any = None) -> None: + Set *response* for a JSON body, or *raw_content* (with *content_type*) + for a non-JSON body. + """ + + def __init__( + self, + status_code: int = 200, + response: Any = None, + raw_content: bytes | None = None, + content_type: str = "", + ) -> None: self.status_code = status_code self.response = response + self.raw_content = raw_content + self.content_type = content_type self.capture = CapturedRequest() def _build_response(self, request: httpx.Request) -> httpx.Response: @@ -28,11 +41,16 @@ def _build_response(self, request: httpx.Request) -> httpx.Response: method=request.method, path=str(request.url.raw_path, "ascii"), headers={k: v for k, v in request.headers.items()}, - body=request.content.decode() if request.content else "", + body=request.content.decode(errors="replace") if request.content else "", + body_bytes=request.content, ) body = b"" headers: dict[str, str] = {} - if self.response is not None: + if self.raw_content is not None: + body = self.raw_content + if self.content_type: + headers["content-type"] = self.content_type + elif self.response is not None: body = json.dumps(self.response).encode() headers["content-type"] = "application/json" return httpx.Response( diff --git a/uv.lock b/uv.lock index 0d9b198..9dbab2f 100644 --- a/uv.lock +++ b/uv.lock @@ -84,7 +84,7 @@ wheels = [ [[package]] name = "baseten" -version = "0.11.0" +version = "0.12.0" source = { editable = "." } dependencies = [ { name = "httpx" },