diff --git a/baseten/client/managementapi/__init__.py b/baseten/client/managementapi/__init__.py index 643f009..73a864c 100644 --- a/baseten/client/managementapi/__init__.py +++ b/baseten/client/managementapi/__init__.py @@ -23,6 +23,7 @@ AuditLogEntry, AuditLogEventApiKeyCreated, AuditLogEventApiKeyDeleted, + AuditLogEventApiKeyLifetimeLimitsUpdated, AuditLogEventAutoscalingScheduleChange, AuditLogEventAutoscalingScheduleOperations, AuditLogEventAutoscalingScheduleSettings, @@ -47,6 +48,9 @@ AuditLogEventGatewayEndpointCreated, AuditLogEventGatewayEndpointDeleted, AuditLogEventGatewayEndpointUpdated, + AuditLogEventGridMachineUserCreated, + AuditLogEventGridMachineUserDeleted, + AuditLogEventGridMachineUserUpdated, AuditLogEventModelDeleted, AuditLogEventModelDeployed, AuditLogEventModelDeploymentActivated, @@ -126,19 +130,26 @@ ComputeCost, ComputeCost1, CorrelationId, + CostPerMillionCachedInputTokens, CostPerMillionInputTokens, + CostPerMillionInputTokens1, CostPerMillionOutputTokens, + CostPerMillionOutputTokens1, CreateApiKeyForGroupRequest, CreateApiKeyForGroupResponse, CreateAPIKeyRequest, CreateChainEnvironmentRequest, CreateDeploymentPatchRequest, CreateDeploymentPatchResponse, + CreatedGridMachineUser, CreatedModelDeployment, CreateEndpointRequest, CreateEnvironmentRequest, CreateGridConnectionRequest, + CreateGridMachineUserAPIKeyRequest, + CreateGridMachineUserRequest, CreateGridRouteRequest, + CreateGridTokenRequest, CreateGroupHierarchy, CreateGroupRequest, CreateJobWeightConfig, @@ -178,6 +189,7 @@ CreateVolumeTokenResponse, CreditsUsed, DailyDedicatedUsage, + DailyLoopsUsage, DailyModelApiUsage, DailyTrainingUsage, DeactivateLoopsDeploymentResponse, @@ -275,6 +287,8 @@ GetGatewayEventsParams, GetGridClassifiersParams, GetGridConnectionsParams, + GetGridMachineUsersParams, + GetGridRouteClassifiersParams, GetGridRoutesParams, GetGridRoutesUsageParams, GetGridTeamSettingsParams, @@ -299,9 +313,11 @@ GetLoopsSamplersParams, GetLoopsSessionResponse, GetLoopsUserConfigResponse, + GetMetricsResponse, + GetModelApisMetricsParams, + GetModelApisModelApiNameParams, GetModelApisParams, GetModelApisUsageParams, - GetModelMetricsResponse, GetModelsAuditLogsParams, GetModelsDeploymentsConfigParams, GetModelsDeploymentsLogsParams, @@ -336,6 +352,7 @@ GetTrainingProjectsJobsCheckpointFilesParams, GetTrainingProjectsJobsLogsParams, GetTrainingProjectsJobsMetricsParams, + GetTrainingProjectsParams, GetUsersParams, GetVolumesNamespacesParams, GetVolumesParams, @@ -346,21 +363,30 @@ GridClassifier, GridClassifiersResponse, GridConnection, + GridConnectionBedrockAccessKeysAuth, + GridConnectionBedrockApiKeyAuth, GridConnectionConfigAnthropic, + GridConnectionConfigBedrock, GridConnectionConfigOpenAI, + GridConnectionConfigVertex, GridConnectionConfigXAI, GridConnectionsResponse, GridConnectionTombstone, GridEffectiveSpendLimit, GridHarnessDefaults, GridHarnessModel, - GridPrimaryHarnessDefaults, + GridMachineUser, + GridMachineUsersResponse, + GridMachineUserTombstone, GridRoute, + GridRouteClassifier, + GridRouteClassifiersResponse, GridRouteRef, GridRoutesResponse, GridRouteTargetBasetenModelAPI, GridRouteTargetClassifier, GridRouteTargetConnection, + GridRouteTargetIntelligent, GridRouteTombstone, GridRouteUsageBucket, GridRouteUsageResponse, @@ -371,6 +397,7 @@ GridTeamSpendLimitSetting, GridTeamUserSettings, GridTeamUserSettingsList, + GridToken, Group, GroupHierarchy, GroupMetadata, @@ -393,8 +420,10 @@ LibraryListingVersions, LibraryListingVersionTombstone, Limit, - Limit5, + Limit3, + Limit4, Limit6, + Limit7, ListAuditLogsResponse, ListImagesParams, ListImageTagsParams, @@ -423,6 +452,7 @@ LLMRuntime, LoadCheckpointConfig, Log, + LoopsBaseModelItem, LoopsCheckpoint, LoopsCheckpointConfig, LoopsCheckpointFilesResponse, @@ -435,20 +465,26 @@ LoopsDeploymentNodeMetrics, LoopsDeploymentStatus, LoopsLoRAConfig, + LoopsMeterUsage, + LoopsResourceItem, LoopsRun, LoopsRunStatus, LoopsSampler, LoopsSamplerStatus, LoopsSession, + LoopsUsage, LoopsUserConfig, MaxScaleDownRate, MaxScaleDownRate1, MaxSeqLen, + MetricDescriptor, + MetricValueSet, MinDurationMs, Model, ModelAPI, ModelApiItem, ModelAPIOrgDetails, + ModelAPIRateLimit, ModelApisCostBucket, ModelApisCostResult, ModelApisCostsResponse, @@ -457,10 +493,9 @@ ModelApisUsageBucket, ModelApisUsageResponse, ModelApisUsageResult, + ModelAPITeamDetails, ModelArchiveSource, ModelConfig, - ModelMetricDescriptor, - ModelMetricValueSet, ModelPromotionSettings, Models, ModelTombstone, @@ -468,6 +503,8 @@ Name2, Name3, Name5, + Name6, + Name7, NumReplicas, OneTimeAutoscalingSchedule, OneTimeAutoscalingScheduleUpsert, @@ -566,12 +603,18 @@ StopTrainingJobResponse, StorageMetrics, Subtotal, - Subtotal3, + Subtotal1, + Subtotal2, Subtotal4, Subtotal5, Subtotal6, Subtotal7, Subtotal8, + Subtotal9, + Subtotal10, + Subtotal11, + Subtotal12, + Subtotal13, SupportedModel, SurchargeCost, SurchargeCost1, @@ -585,6 +628,8 @@ TeamId3, TeamId4, TeamId5, + TeamId6, + TeamId7, Teams, TeamTrainingGpuCapacityItem, TerminateReplicaResponse, @@ -628,7 +673,7 @@ UpdateGridBackgroundHarnessModels, UpdateGridConnectionRequest, UpdateGridHarnessDefaults, - UpdateGridPrimaryHarnessModels, + UpdateGridMachineUserRequest, UpdateGridRouteRequest, UpdateGridSpendLimitSetting, UpdateGridTeamSettingsRequest, @@ -652,8 +697,12 @@ UpdateTrafficRoutingSettings, UpdateTrainingJobRequest, UpdateTrainingJobResponse, + UpsertGridConnectionBedrockAccessKeysAuth, + UpsertGridConnectionBedrockApiKeyAuth, UpsertGridConnectionConfigAnthropic, + UpsertGridConnectionConfigBedrock, UpsertGridConnectionConfigOpenAI, + UpsertGridConnectionConfigVertex, UpsertGridConnectionConfigXAI, UpsertGridRouteTargetBasetenModelAPI, UpsertGridRouteTargetClassifier, @@ -676,6 +725,7 @@ VolumeSyncAuthenticationAWSAssumeRole, VolumeSyncAuthenticationAWSOIDC, VolumeSyncAuthenticationGCPOIDC, + VolumeSyncAuthenticationHuggingFaceOIDC, VolumeSyncDestination, VolumeSyncError, VolumeSyncs, @@ -707,6 +757,7 @@ "AuditLogEntry", "AuditLogEventApiKeyCreated", "AuditLogEventApiKeyDeleted", + "AuditLogEventApiKeyLifetimeLimitsUpdated", "AuditLogEventAutoscalingScheduleChange", "AuditLogEventAutoscalingScheduleOperations", "AuditLogEventAutoscalingScheduleSettings", @@ -731,6 +782,9 @@ "AuditLogEventGatewayEndpointCreated", "AuditLogEventGatewayEndpointDeleted", "AuditLogEventGatewayEndpointUpdated", + "AuditLogEventGridMachineUserCreated", + "AuditLogEventGridMachineUserDeleted", + "AuditLogEventGridMachineUserUpdated", "AuditLogEventModelDeleted", "AuditLogEventModelDeployed", "AuditLogEventModelDeploymentActivated", @@ -809,8 +863,11 @@ "ComputeCost", "ComputeCost1", "CorrelationId", + "CostPerMillionCachedInputTokens", "CostPerMillionInputTokens", + "CostPerMillionInputTokens1", "CostPerMillionOutputTokens", + "CostPerMillionOutputTokens1", "CreateAPIKeyRequest", "CreateApiKeyForGroupRequest", "CreateApiKeyForGroupResponse", @@ -820,7 +877,10 @@ "CreateEndpointRequest", "CreateEnvironmentRequest", "CreateGridConnectionRequest", + "CreateGridMachineUserAPIKeyRequest", + "CreateGridMachineUserRequest", "CreateGridRouteRequest", + "CreateGridTokenRequest", "CreateGroupHierarchy", "CreateGroupRequest", "CreateJobWeightConfig", @@ -858,9 +918,11 @@ "CreateVolumeSyncRequest", "CreateVolumeTokenRequest", "CreateVolumeTokenResponse", + "CreatedGridMachineUser", "CreatedModelDeployment", "CreditsUsed", "DailyDedicatedUsage", + "DailyLoopsUsage", "DailyModelApiUsage", "DailyTrainingUsage", "DeactivateLoopsDeploymentResponse", @@ -958,6 +1020,8 @@ "GetGatewayEventsParams", "GetGridClassifiersParams", "GetGridConnectionsParams", + "GetGridMachineUsersParams", + "GetGridRouteClassifiersParams", "GetGridRoutesParams", "GetGridRoutesUsageParams", "GetGridTeamSettingsParams", @@ -982,9 +1046,11 @@ "GetLoopsSamplersParams", "GetLoopsSessionResponse", "GetLoopsUserConfigResponse", + "GetMetricsResponse", + "GetModelApisMetricsParams", + "GetModelApisModelApiNameParams", "GetModelApisParams", "GetModelApisUsageParams", - "GetModelMetricsResponse", "GetModelsAuditLogsParams", "GetModelsDeploymentsConfigParams", "GetModelsDeploymentsLogsParams", @@ -1019,6 +1085,7 @@ "GetTrainingProjectsJobsCheckpointFilesParams", "GetTrainingProjectsJobsLogsParams", "GetTrainingProjectsJobsMetricsParams", + "GetTrainingProjectsParams", "GetUsersParams", "GetVolumesNamespacesParams", "GetVolumesParams", @@ -1029,20 +1096,29 @@ "GridClassifier", "GridClassifiersResponse", "GridConnection", + "GridConnectionBedrockAccessKeysAuth", + "GridConnectionBedrockApiKeyAuth", "GridConnectionConfigAnthropic", + "GridConnectionConfigBedrock", "GridConnectionConfigOpenAI", + "GridConnectionConfigVertex", "GridConnectionConfigXAI", "GridConnectionTombstone", "GridConnectionsResponse", "GridEffectiveSpendLimit", "GridHarnessDefaults", "GridHarnessModel", - "GridPrimaryHarnessDefaults", + "GridMachineUser", + "GridMachineUserTombstone", + "GridMachineUsersResponse", "GridRoute", + "GridRouteClassifier", + "GridRouteClassifiersResponse", "GridRouteRef", "GridRouteTargetBasetenModelAPI", "GridRouteTargetClassifier", "GridRouteTargetConnection", + "GridRouteTargetIntelligent", "GridRouteTombstone", "GridRouteUsageBucket", "GridRouteUsageResponse", @@ -1054,6 +1130,7 @@ "GridTeamSpendLimitSetting", "GridTeamUserSettings", "GridTeamUserSettingsList", + "GridToken", "Group", "GroupHierarchy", "GroupMetadata", @@ -1079,8 +1156,10 @@ "LibraryListingVersions", "LibraryListings", "Limit", - "Limit5", + "Limit3", + "Limit4", "Limit6", + "Limit7", "ListAuditLogsResponse", "ListImageTagsParams", "ListImagesParams", @@ -1106,6 +1185,7 @@ "ListVolumesResponse", "LoadCheckpointConfig", "Log", + "LoopsBaseModelItem", "LoopsCheckpoint", "LoopsCheckpointConfig", "LoopsCheckpointFilesResponse", @@ -1118,19 +1198,26 @@ "LoopsDeploymentNodeMetrics", "LoopsDeploymentStatus", "LoopsLoRAConfig", + "LoopsMeterUsage", + "LoopsResourceItem", "LoopsRun", "LoopsRunStatus", "LoopsSampler", "LoopsSamplerStatus", "LoopsSession", + "LoopsUsage", "LoopsUserConfig", "MaxScaleDownRate", "MaxScaleDownRate1", "MaxSeqLen", + "MetricDescriptor", + "MetricValueSet", "MinDurationMs", "Model", "ModelAPI", "ModelAPIOrgDetails", + "ModelAPIRateLimit", + "ModelAPITeamDetails", "ModelAPIsResponse", "ModelApiItem", "ModelApisCostBucket", @@ -1142,8 +1229,6 @@ "ModelApisUsageResult", "ModelArchiveSource", "ModelConfig", - "ModelMetricDescriptor", - "ModelMetricValueSet", "ModelPromotionSettings", "ModelTombstone", "Models", @@ -1151,6 +1236,8 @@ "Name2", "Name3", "Name5", + "Name6", + "Name7", "NumReplicas", "OneTimeAutoscalingSchedule", "OneTimeAutoscalingScheduleUpsert", @@ -1250,12 +1337,18 @@ "StopTrainingJobResponse", "StorageMetrics", "Subtotal", - "Subtotal3", + "Subtotal1", + "Subtotal2", "Subtotal4", "Subtotal5", "Subtotal6", "Subtotal7", "Subtotal8", + "Subtotal9", + "Subtotal10", + "Subtotal11", + "Subtotal12", + "Subtotal13", "SupportedModel", "SurchargeCost", "SurchargeCost1", @@ -1270,6 +1363,8 @@ "TeamId3", "TeamId4", "TeamId5", + "TeamId6", + "TeamId7", "TeamTrainingGpuCapacityItem", "Teams", "TerminateReplicaResponse", @@ -1312,7 +1407,7 @@ "UpdateGridBackgroundHarnessModels", "UpdateGridConnectionRequest", "UpdateGridHarnessDefaults", - "UpdateGridPrimaryHarnessModels", + "UpdateGridMachineUserRequest", "UpdateGridRouteRequest", "UpdateGridSpendLimitSetting", "UpdateGridTeamSettingsRequest", @@ -1336,8 +1431,12 @@ "UpdateTrafficRoutingSettings", "UpdateTrainingJobRequest", "UpdateTrainingJobResponse", + "UpsertGridConnectionBedrockAccessKeysAuth", + "UpsertGridConnectionBedrockApiKeyAuth", "UpsertGridConnectionConfigAnthropic", + "UpsertGridConnectionConfigBedrock", "UpsertGridConnectionConfigOpenAI", + "UpsertGridConnectionConfigVertex", "UpsertGridConnectionConfigXAI", "UpsertGridRouteTargetBasetenModelAPI", "UpsertGridRouteTargetClassifier", @@ -1360,6 +1459,7 @@ "VolumeSyncAuthenticationAWSAssumeRole", "VolumeSyncAuthenticationAWSOIDC", "VolumeSyncAuthenticationGCPOIDC", + "VolumeSyncAuthenticationHuggingFaceOIDC", "VolumeSyncDestination", "VolumeSyncError", "VolumeSyncSourceAzure", diff --git a/baseten/client/managementapi/_client.py b/baseten/client/managementapi/_client.py index 1c5ec94..145cd1e 100644 --- a/baseten/client/managementapi/_client.py +++ b/baseten/client/managementapi/_client.py @@ -31,11 +31,15 @@ CreateChainEnvironmentRequest, CreateDeploymentPatchRequest, CreateDeploymentPatchResponse, + CreatedGridMachineUser, CreatedModelDeployment, CreateEndpointRequest, CreateEnvironmentRequest, CreateGridConnectionRequest, + CreateGridMachineUserAPIKeyRequest, + CreateGridMachineUserRequest, CreateGridRouteRequest, + CreateGridTokenRequest, CreateGroupRequest, CreateLibraryListingRequest, CreateLibraryListingVersionRequest, @@ -114,6 +118,8 @@ GetGatewayEventsParams, GetGridClassifiersParams, GetGridConnectionsParams, + GetGridMachineUsersParams, + GetGridRouteClassifiersParams, GetGridRoutesParams, GetGridRoutesUsageParams, GetGridTeamSettingsParams, @@ -138,9 +144,11 @@ GetLoopsSamplersParams, GetLoopsSessionResponse, GetLoopsUserConfigResponse, + GetMetricsResponse, + GetModelApisMetricsParams, + GetModelApisModelApiNameParams, GetModelApisParams, GetModelApisUsageParams, - GetModelMetricsResponse, GetModelsAuditLogsParams, GetModelsDeploymentsConfigParams, GetModelsDeploymentsLogsParams, @@ -175,6 +183,7 @@ GetTrainingProjectsJobsCheckpointFilesParams, GetTrainingProjectsJobsLogsParams, GetTrainingProjectsJobsMetricsParams, + GetTrainingProjectsParams, GetUsersParams, GetVolumesNamespacesParams, GetVolumesParams, @@ -185,13 +194,19 @@ GridConnection, GridConnectionsResponse, GridConnectionTombstone, + GridMachineUser, + GridMachineUsersResponse, + GridMachineUserTombstone, GridRoute, + GridRouteClassifier, + GridRouteClassifiersResponse, GridRoutesResponse, GridRouteTombstone, GridRouteUsageResponse, GridTeamSettings, GridTeamUserSettings, GridTeamUserSettingsList, + GridToken, Group, GroupsResponse, InstanceTypePrices, @@ -306,6 +321,7 @@ UpdateEnvironmentRequest, UpdateEnvironmentResponse, UpdateGridConnectionRequest, + UpdateGridMachineUserRequest, UpdateGridRouteRequest, UpdateGridTeamSettingsRequest, UpdateGridUserSettingsRequest, @@ -574,6 +590,40 @@ def delete_grid_connections(self, *, connection_id: str) -> GridConnectionTombst ), ) + def delete_grid_machine_users( + self, *, machine_user_id: str + ) -> GridMachineUserTombstone: + """Deletes a machine user""" + return self._do_json( + GridMachineUserTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/grid/machine_users/{}", + path_args=[machine_user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def delete_grid_machine_users_api_keys( + self, *, machine_user_id: str, api_key_prefix: str + ) -> APIKeyTombstone: + """Revokes a machine user's API key""" + return self._do_json( + APIKeyTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/grid/machine_users/{}/api_keys/{}", + path_args=[machine_user_id, api_key_prefix], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + def delete_grid_routes(self, *, route_id: str) -> GridRouteTombstone: """Deletes a route""" return self._do_json( @@ -1383,6 +1433,106 @@ def get_grid_connections( ), ) + def get_grid_connections_connection_id( + self, *, connection_id: str + ) -> GridConnection: + """Gets a connection""" + return self._do_json( + GridConnection, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/connections/{}", + path_args=[connection_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_grid_machine_users( + self, *, params: GetGridMachineUsersParams | None = None + ) -> GridMachineUsersResponse: + """Lists machine users""" + return self._do_json( + GridMachineUsersResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/machine_users", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_grid_machine_users_api_keys(self, *, machine_user_id: str) -> APIKeys: + """Lists a machine user's API keys""" + return self._do_json( + APIKeys, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/machine_users/{}/api_keys", + path_args=[machine_user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_grid_machine_users_machine_user_id( + self, *, machine_user_id: str + ) -> GridMachineUser: + """Gets a machine user""" + return self._do_json( + GridMachineUser, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/machine_users/{}", + path_args=[machine_user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def get_grid_route_classifiers( + self, *, params: GetGridRouteClassifiersParams | None = None + ) -> GridRouteClassifiersResponse: + """Lists route classifiers available for intelligent routes""" + return self._do_json( + GridRouteClassifiersResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/route_classifiers", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_grid_route_classifiers_route_classifier_id( + self, *, route_classifier_id: str + ) -> GridRouteClassifier: + """Gets a route classifier available for intelligent routes""" + return self._do_json( + GridRouteClassifier, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/route_classifiers/{}", + path_args=[route_classifier_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + def get_grid_routes( self, *, params: GetGridRoutesParams | None = None ) -> GridRoutesResponse: @@ -1871,7 +2021,29 @@ def get_model_apis( ), ) - def get_model_apis_model_api_name(self, *, model_api_name: str) -> ModelAPI: + def get_model_apis_metrics( + self, *, model_api_name: str, params: GetModelApisMetricsParams | None = None + ) -> GetMetricsResponse: + """Gets the metrics for a Model API""" + return self._do_json( + GetMetricsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/model_apis/{}/metrics", + path_args=[model_api_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + def get_model_apis_model_api_name( + self, + *, + model_api_name: str, + params: GetModelApisModelApiNameParams | None = None, + ) -> ModelAPI: """Gets a Model API""" return self._do_json( ModelAPI, @@ -1880,7 +2052,7 @@ def get_model_apis_model_api_name(self, *, model_api_name: str) -> ModelAPI: path_fmt="/v1/model_apis/{}", path_args=[model_api_name], body=None, - query=None, + query=params, success_codes=[200], error_codes=None, ), @@ -2049,10 +2221,10 @@ def get_models_deployments_metrics( model_id: str, deployment_id: str, params: GetModelsDeploymentsMetricsParams | None = None, - ) -> GetModelMetricsResponse: + ) -> GetMetricsResponse: """Gets the metrics for a model deployment""" return self._do_json( - GetModelMetricsResponse, + GetMetricsResponse, _ApiRequest( method="GET", path_fmt="/v1/models/{}/deployments/{}/metrics", @@ -2197,10 +2369,10 @@ def get_models_environments_metrics( model_id: str, env_name: str, params: GetModelsEnvironmentsMetricsParams | None = None, - ) -> GetModelMetricsResponse: + ) -> GetMetricsResponse: """Gets the metrics for a model environment.""" return self._do_json( - GetModelMetricsResponse, + GetMetricsResponse, _ApiRequest( method="GET", path_fmt="/v1/models/{}/environments/{}/metrics", @@ -2593,7 +2765,9 @@ def get_training_jobs_queue_context( ), ) - def get_training_projects(self) -> ListTrainingProjectsResponse: + def get_training_projects( + self, *, params: GetTrainingProjectsParams | None = None + ) -> ListTrainingProjectsResponse: """Lists training projects""" return self._do_json( ListTrainingProjectsResponse, @@ -2602,7 +2776,7 @@ def get_training_projects(self) -> ListTrainingProjectsResponse: path_fmt="/v1/training_projects", path_args=[], body=None, - query=None, + query=params, success_codes=[200], error_codes=None, ), @@ -3181,6 +3355,23 @@ def patch_grid_connections( ), ) + def patch_grid_machine_users( + self, *, machine_user_id: str, request: UpdateGridMachineUserRequest + ) -> GridMachineUser: + """Updates a machine user""" + return self._do_json( + GridMachineUser, + _ApiRequest( + method="PATCH", + path_fmt="/v1/grid/machine_users/{}", + path_args=[machine_user_id], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + def patch_grid_routes( self, *, route_id: str, request: UpdateGridRouteRequest ) -> GridRoute: @@ -3670,6 +3861,40 @@ def post_grid_connections( ), ) + def post_grid_machine_users( + self, *, request: CreateGridMachineUserRequest + ) -> CreatedGridMachineUser: + """Creates a machine user""" + return self._do_json( + CreatedGridMachineUser, + _ApiRequest( + method="POST", + path_fmt="/v1/grid/machine_users", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + def post_grid_machine_users_api_keys( + self, *, machine_user_id: str, request: CreateGridMachineUserAPIKeyRequest + ) -> APIKey: + """Creates an API key for a machine user""" + return self._do_json( + APIKey, + _ApiRequest( + method="POST", + path_fmt="/v1/grid/machine_users/{}/api_keys", + path_args=[machine_user_id], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + def post_grid_routes(self, *, request: CreateGridRouteRequest) -> GridRoute: """Creates a route""" return self._do_json( @@ -3685,6 +3910,21 @@ def post_grid_routes(self, *, request: CreateGridRouteRequest) -> GridRoute: ), ) + def post_grid_token(self, *, request: CreateGridTokenRequest) -> GridToken: + """Creates a Grid access token""" + return self._do_json( + GridToken, + _ApiRequest( + method="POST", + path_fmt="/v1/grid/token", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + def post_library_listings( self, *, request: CreateLibraryListingRequest ) -> LibraryListing: @@ -5174,6 +5414,40 @@ async def delete_grid_connections( ), ) + async def delete_grid_machine_users( + self, *, machine_user_id: str + ) -> GridMachineUserTombstone: + """Deletes a machine user""" + return await self._do_json( + GridMachineUserTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/grid/machine_users/{}", + path_args=[machine_user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def delete_grid_machine_users_api_keys( + self, *, machine_user_id: str, api_key_prefix: str + ) -> APIKeyTombstone: + """Revokes a machine user's API key""" + return await self._do_json( + APIKeyTombstone, + _ApiRequest( + method="DELETE", + path_fmt="/v1/grid/machine_users/{}/api_keys/{}", + path_args=[machine_user_id, api_key_prefix], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + async def delete_grid_routes(self, *, route_id: str) -> GridRouteTombstone: """Deletes a route""" return await self._do_json( @@ -5987,6 +6261,106 @@ async def get_grid_connections( ), ) + async def get_grid_connections_connection_id( + self, *, connection_id: str + ) -> GridConnection: + """Gets a connection""" + return await self._do_json( + GridConnection, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/connections/{}", + path_args=[connection_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_grid_machine_users( + self, *, params: GetGridMachineUsersParams | None = None + ) -> GridMachineUsersResponse: + """Lists machine users""" + return await self._do_json( + GridMachineUsersResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/machine_users", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_grid_machine_users_api_keys(self, *, machine_user_id: str) -> APIKeys: + """Lists a machine user's API keys""" + return await self._do_json( + APIKeys, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/machine_users/{}/api_keys", + path_args=[machine_user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_grid_machine_users_machine_user_id( + self, *, machine_user_id: str + ) -> GridMachineUser: + """Gets a machine user""" + return await self._do_json( + GridMachineUser, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/machine_users/{}", + path_args=[machine_user_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_grid_route_classifiers( + self, *, params: GetGridRouteClassifiersParams | None = None + ) -> GridRouteClassifiersResponse: + """Lists route classifiers available for intelligent routes""" + return await self._do_json( + GridRouteClassifiersResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/route_classifiers", + path_args=[], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_grid_route_classifiers_route_classifier_id( + self, *, route_classifier_id: str + ) -> GridRouteClassifier: + """Gets a route classifier available for intelligent routes""" + return await self._do_json( + GridRouteClassifier, + _ApiRequest( + method="GET", + path_fmt="/v1/grid/route_classifiers/{}", + path_args=[route_classifier_id], + body=None, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + async def get_grid_routes( self, *, params: GetGridRoutesParams | None = None ) -> GridRoutesResponse: @@ -6475,7 +6849,29 @@ async def get_model_apis( ), ) - async def get_model_apis_model_api_name(self, *, model_api_name: str) -> ModelAPI: + async def get_model_apis_metrics( + self, *, model_api_name: str, params: GetModelApisMetricsParams | None = None + ) -> GetMetricsResponse: + """Gets the metrics for a Model API""" + return await self._do_json( + GetMetricsResponse, + _ApiRequest( + method="GET", + path_fmt="/v1/model_apis/{}/metrics", + path_args=[model_api_name], + body=None, + query=params, + success_codes=[200], + error_codes=None, + ), + ) + + async def get_model_apis_model_api_name( + self, + *, + model_api_name: str, + params: GetModelApisModelApiNameParams | None = None, + ) -> ModelAPI: """Gets a Model API""" return await self._do_json( ModelAPI, @@ -6484,7 +6880,7 @@ async def get_model_apis_model_api_name(self, *, model_api_name: str) -> ModelAP path_fmt="/v1/model_apis/{}", path_args=[model_api_name], body=None, - query=None, + query=params, success_codes=[200], error_codes=None, ), @@ -6653,10 +7049,10 @@ async def get_models_deployments_metrics( model_id: str, deployment_id: str, params: GetModelsDeploymentsMetricsParams | None = None, - ) -> GetModelMetricsResponse: + ) -> GetMetricsResponse: """Gets the metrics for a model deployment""" return await self._do_json( - GetModelMetricsResponse, + GetMetricsResponse, _ApiRequest( method="GET", path_fmt="/v1/models/{}/deployments/{}/metrics", @@ -6801,10 +7197,10 @@ async def get_models_environments_metrics( model_id: str, env_name: str, params: GetModelsEnvironmentsMetricsParams | None = None, - ) -> GetModelMetricsResponse: + ) -> GetMetricsResponse: """Gets the metrics for a model environment.""" return await self._do_json( - GetModelMetricsResponse, + GetMetricsResponse, _ApiRequest( method="GET", path_fmt="/v1/models/{}/environments/{}/metrics", @@ -7197,7 +7593,9 @@ async def get_training_jobs_queue_context( ), ) - async def get_training_projects(self) -> ListTrainingProjectsResponse: + async def get_training_projects( + self, *, params: GetTrainingProjectsParams | None = None + ) -> ListTrainingProjectsResponse: """Lists training projects""" return await self._do_json( ListTrainingProjectsResponse, @@ -7206,7 +7604,7 @@ async def get_training_projects(self) -> ListTrainingProjectsResponse: path_fmt="/v1/training_projects", path_args=[], body=None, - query=None, + query=params, success_codes=[200], error_codes=None, ), @@ -7787,6 +8185,23 @@ async def patch_grid_connections( ), ) + async def patch_grid_machine_users( + self, *, machine_user_id: str, request: UpdateGridMachineUserRequest + ) -> GridMachineUser: + """Updates a machine user""" + return await self._do_json( + GridMachineUser, + _ApiRequest( + method="PATCH", + path_fmt="/v1/grid/machine_users/{}", + path_args=[machine_user_id], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + async def patch_grid_routes( self, *, route_id: str, request: UpdateGridRouteRequest ) -> GridRoute: @@ -8280,6 +8695,40 @@ async def post_grid_connections( ), ) + async def post_grid_machine_users( + self, *, request: CreateGridMachineUserRequest + ) -> CreatedGridMachineUser: + """Creates a machine user""" + return await self._do_json( + CreatedGridMachineUser, + _ApiRequest( + method="POST", + path_fmt="/v1/grid/machine_users", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + + async def post_grid_machine_users_api_keys( + self, *, machine_user_id: str, request: CreateGridMachineUserAPIKeyRequest + ) -> APIKey: + """Creates an API key for a machine user""" + return await self._do_json( + APIKey, + _ApiRequest( + method="POST", + path_fmt="/v1/grid/machine_users/{}/api_keys", + path_args=[machine_user_id], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + async def post_grid_routes(self, *, request: CreateGridRouteRequest) -> GridRoute: """Creates a route""" return await self._do_json( @@ -8295,6 +8744,21 @@ async def post_grid_routes(self, *, request: CreateGridRouteRequest) -> GridRout ), ) + async def post_grid_token(self, *, request: CreateGridTokenRequest) -> GridToken: + """Creates a Grid access token""" + return await self._do_json( + GridToken, + _ApiRequest( + method="POST", + path_fmt="/v1/grid/token", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes=None, + ), + ) + async def post_library_listings( self, *, request: CreateLibraryListingRequest ) -> LibraryListing: diff --git a/baseten/client/managementapi/_models.py b/baseten/client/managementapi/_models.py index f1d1936..fa8dbfa 100644 --- a/baseten/client/managementapi/_models.py +++ b/baseten/client/managementapi/_models.py @@ -82,6 +82,14 @@ class CreateTrainingJobCacheConfig(BaseModel): title="Mount Base Path", ), ] = "/root/.cache" + persistent_home: Annotated[ + bool, + Field( + description="Whether to keep `$HOME` in a per-job directory on the project cache, so its contents outlive the job. Requires `enabled`.", + examples=[True, False], + title="Persistent Home", + ), + ] = False class CreateTrainingJobCheckpointingConfig(BaseModel): @@ -440,6 +448,53 @@ class GetModelsEnvironmentsStartupsSummaryParams(BaseModel): ] = None +class Limit3(RootModel[int]): + root: Annotated[ + int | None, + Field( + description="Maximum number of projects to return, up to 1000.", + ge=1, + le=1000, + title="Limit", + ), + ] = None + + +class GetTrainingProjectsParams(BaseModel): + name: Annotated[ + str | None, + Field( + description="Return only the project with this exact name.", title="Name" + ), + ] = None + cursor: Annotated[ + str | None, + Field( + description="Opaque cursor from the pagination.cursor field of a previous response. Omit both cursor and limit to get every project in one response.", + title="Cursor", + ), + ] = None + limit: Annotated[ + Limit3 | None, + Field( + description="Maximum number of projects to return, up to 1000.", + title="Limit", + ), + ] = None + + +class Limit4(RootModel[int]): + root: Annotated[ + int, + Field( + description="Limit of logs to fetch in a single request", + ge=1, + le=1000, + title="Limit", + ), + ] = 500 + + class GetTrainingProjectsJobsMetricsParams(BaseModel): end_epoch_millis: Annotated[ int | None, @@ -506,6 +561,14 @@ class GetLoopsRunsParams(BaseModel): title="Base Model", ), ] = None + session_id: Annotated[ + str | None, + Field( + description="Filter runs by the session that created them. An unknown or inaccessible session returns an empty list.", + examples=["k4q95w5"], + title="Session Id", + ), + ] = None scope: Annotated[ str | None, Field( @@ -517,6 +580,14 @@ class GetLoopsRunsParams(BaseModel): class GetLoopsSamplersParams(BaseModel): + session_id: Annotated[ + str | None, + Field( + description="Filter samplers by the session that created them. An unknown or inaccessible session returns an empty list.", + examples=["k4q95w5"], + title="Session Id", + ), + ] = None scope: Annotated[ str | None, Field( @@ -611,6 +682,14 @@ class GetTeamsLoopsRunsParams(BaseModel): title="Base Model", ), ] = None + session_id: Annotated[ + str | None, + Field( + description="Filter runs by the session that created them. An unknown or inaccessible session returns an empty list.", + examples=["k4q95w5"], + title="Session Id", + ), + ] = None scope: Annotated[ str | None, Field( @@ -622,6 +701,14 @@ class GetTeamsLoopsRunsParams(BaseModel): class GetTeamsLoopsSamplersParams(BaseModel): + session_id: Annotated[ + str | None, + Field( + description="Filter samplers by the session that created them. An unknown or inaccessible session returns an empty list.", + examples=["k4q95w5"], + title="Session Id", + ), + ] = None scope: Annotated[ str | None, Field( @@ -636,7 +723,7 @@ class GetApiKeysParams(BaseModel): type: Annotated[ Literal[ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_ALL", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -672,15 +759,32 @@ class GetModelApisParams(BaseModel): title="Limit", ), ] = 100 + team_ids: Annotated[ + list[str] | None, + Field( + description="Select teams for added-model details, filtering, and ordering, repeated once per team. Defaults to all teams where you can invoke Model APIs. Any unauthorized team causes a 403.", + title="Team Ids", + ), + ] = None added_only: Annotated[ bool, Field( - description="When true, restrict the result to Model APIs the workspace has added. Defaults to the full visible catalog.", + description="When true, restrict the result to Model APIs added by any team where you can invoke Model APIs. Explicit team_ids narrow this to the selected teams. Defaults to the full visible catalog.", title="Added Only", ), ] = False +class GetModelApisModelApiNameParams(BaseModel): + team_ids: Annotated[ + list[str] | None, + Field( + description="Select teams for added-model details, repeated once per team. Defaults to all teams where you can invoke Model APIs. Any unauthorized team causes a 403.", + title="Team Ids", + ), + ] = None + + class GetBillingUsageSummaryParams(BaseModel): start_date: Annotated[ AwareDatetime, @@ -698,23 +802,6 @@ class GetBillingUsageSummaryParams(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, @@ -741,7 +828,7 @@ class GetUsersParams(BaseModel): ] = None -class Limit5(RootModel[int]): +class Limit6(RootModel[int]): root: Annotated[ int | None, Field( @@ -769,7 +856,7 @@ class GetGatewayEventsParams(BaseModel): ), ] = None limit: Annotated[ - Limit5 | None, + Limit6 | None, Field(description="Max events. Default 100, max 1000.", title="Limit"), ] = None api_keys: Annotated[ @@ -998,6 +1085,51 @@ class GetGridClassifiersParams(BaseModel): ] = 100 +class GetGridRouteClassifiersParams(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 + + +class GetGridMachineUsersParams(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 + team_id: Annotated[ + str | None, + Field( + description="Limit machine users to this team. Without it, every team you administer.", + title="Team Id", + ), + ] = None + + class GetSandboxLogsParams(BaseModel): team_id: Annotated[ str | None, @@ -1661,6 +1793,18 @@ class VolumeSyncAuthenticationGCPOIDC(BaseModel): ] +class VolumeSyncAuthenticationHuggingFaceOIDC(BaseModel): + resource: Annotated[ + str, + Field( + description="Hugging Face username for an account CI/CD identity, or namespace/repository for a repository trusted publisher. Configure trust in Hugging Face before starting the sync.", + examples=["hf-user", "organization/private-model"], + pattern="^[A-Za-z0-9][A-Za-z0-9_.-]*(/[A-Za-z0-9_][A-Za-z0-9_.-]*)?$", + title="Resource", + ), + ] + + class VolumeSyncDestination(BaseModel): ref: Annotated[ str, @@ -1836,6 +1980,12 @@ class VolumeSyncSourceHuggingFace(BaseModel): Literal["HUGGING_FACE"], Field(description="Hugging Face source type.", title="Type"), ] + hf_oidc: Annotated[ + VolumeSyncAuthenticationHuggingFaceOIDC | None, + Field( + description="Hugging Face OIDC authentication for this source. Cannot be combined with auth_secret_name." + ), + ] = None class VolumeSyncSourceR2(BaseModel): @@ -3264,6 +3414,23 @@ class AuditLogEventApiKeyDeleted(BaseModel): revocation_reason: Literal["INACTIVITY"] | str | None = None +class AuditLogEventApiKeyLifetimeLimitsUpdated(BaseModel): + event_type: Annotated[ + Literal["API_KEY_LIFETIME_LIMITS_UPDATED"], Field(title="Event Type") + ] + organization_id: Annotated[str, Field(title="Organization Id")] + previous_personal_limit_days: Annotated[ + int | None, Field(title="Previous Personal Limit Days") + ] + new_personal_limit_days: Annotated[ + int | None, Field(title="New Personal Limit Days") + ] + previous_team_limit_days: Annotated[ + int | None, Field(title="Previous Team Limit Days") + ] + new_team_limit_days: Annotated[int | None, Field(title="New Team Limit Days")] + + class AuditLogEventAutoscalingScheduleSettings(BaseModel): min_replica: Annotated[int, Field(title="Min Replica")] max_replica: Annotated[int, Field(title="Max Replica")] @@ -3610,22 +3777,43 @@ class AuditLogEventGatewayEndpointUpdated(BaseModel): previous_slug: Annotated[str | None, Field(title="Previous Slug")] -class AuditLogEventModelDeleted(BaseModel): - 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 AuditLogEventGridMachineUserCreated(BaseModel): + event_type: Annotated[ + Literal["GRID_MACHINE_USER_CREATED"], Field(title="Event Type") + ] + machine_user_id: Annotated[str, Field(title="Machine User Id")] + machine_user_name: Annotated[str, Field(title="Machine User Name")] + team_id: Annotated[str, Field(title="Team Id")] + team_name: Annotated[str, Field(title="Team Name")] -class AuditLogEventModelDeployed(BaseModel): - event_type: Annotated[Literal["MODEL_DEPLOYED"], Field(title="Event Type")] +class AuditLogEventGridMachineUserDeleted(BaseModel): + event_type: Annotated[ + Literal["GRID_MACHINE_USER_DELETED"], Field(title="Event Type") + ] + machine_user_id: Annotated[str, Field(title="Machine User Id")] + machine_user_name: Annotated[str, Field(title="Machine User Name")] + team_id: Annotated[str, Field(title="Team Id")] + team_name: Annotated[str, Field(title="Team Name")] + + +class AuditLogEventGridMachineUserUpdated(BaseModel): + event_type: Annotated[ + Literal["GRID_MACHINE_USER_UPDATED"], Field(title="Event Type") + ] + machine_user_id: Annotated[str, Field(title="Machine User Id")] + machine_user_name: Annotated[str, Field(title="Machine User Name")] + previous_machine_user_name: Annotated[ + str, Field(title="Previous Machine User Name") + ] + team_id: Annotated[str, Field(title="Team Id")] + team_name: Annotated[str, Field(title="Team Name")] + + +class AuditLogEventModelDeleted(BaseModel): + 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")] - 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): @@ -4256,7 +4444,7 @@ class GetLogsResponse(BaseModel): ] -class Limit6(RootModel[int]): +class Limit7(RootModel[int]): root: Annotated[ int, Field( @@ -4287,13 +4475,13 @@ class GetDeploymentLogsRequest(BaseModel): Literal["asc", "desc"] | str | None, Field(description="Sort order for logs") ] = None limit: Annotated[ - Limit6 | None, + Limit7 | None, Field( description="Limit of logs to fetch in a single request", title="Limit", validate_default=True, ), - ] = Limit6.model_validate(500) + ] = Limit7.model_validate(500) min_level: Annotated[ Literal["DEBUG", "INFO", "WARNING", "ERROR"] | str | None, Field( @@ -4609,7 +4797,7 @@ class SyncDeploymentPatchesResponse(BaseModel): ] = None -class ModelMetricValueSet(BaseModel): +class MetricValueSet(BaseModel): start_epoch_millis: Annotated[ int, Field( @@ -5484,6 +5672,14 @@ class UpsertTrainingProject(BaseModel): title="Name", ), ] + project_accelerator: Annotated[ + str | None, + Field( + description="Optional default GPU type for cache-enabled CPU job placement, such as H100. GPU jobs use their requested GPU type; uncached CPU jobs use normal CPU routing. Omitting this field preserves the stored default; providing a value updates it. Existing cache-affinity requirements still apply.", + examples=["H100"], + title="Project Accelerator", + ), + ] = None class UpsertTrainingProjectRequest(BaseModel): @@ -5578,13 +5774,13 @@ class CreateTrainingJobCompute(BaseModel): ), ] = None availability_model: Annotated[ - Literal["dedicated", "spot"] | str, + Literal["standard", "spot"] | str, 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.", + description="Capacity guarantee for the job. Defaults to 'standard'. 'standard' runs on capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; you are responsible for checkpointing your own progress.", examples=["spot"], - title="V1AvailabilityModel", + title="AvailabilityModelV1", ), - ] = "dedicated" + ] = "standard" class GcpOidcDockerAuth(BaseModel): @@ -5649,7 +5845,14 @@ class SecretReference(BaseModel): class TrainingWeightAuth(BaseModel): auth_method: Annotated[ - Literal["CUSTOM_SECRET", "AWS_OIDC", "GCP_OIDC", "AWS_ASSUME_ROLE"] | str, + Literal[ + "CUSTOM_SECRET", + "AWS_OIDC", + "GCP_OIDC", + "HUGGING_FACE_OIDC", + "AWS_ASSUME_ROLE", + ] + | str, Field( description="Method used to authenticate the weight source.", title="AuthMethod", @@ -5732,9 +5935,9 @@ class UpdateTrainingJobRequest(BaseModel): ), ] = None availability_model: Annotated[ - Literal["dedicated", "spot"] | str | None, + Literal["standard", "spot"] | str | 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.", + description="New capacity guarantee for a PENDING training job. 'standard' runs on capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; you are responsible for checkpointing your own progress. Only jobs in the PENDING state can have their availability model changed.", examples=["spot"], ), ] = None @@ -5769,13 +5972,13 @@ class GetTrainingJobLogsRequest(BaseModel): Literal["asc", "desc"] | str | None, Field(description="Sort order for logs") ] = None limit: Annotated[ - Limit6 | None, + Limit7 | None, Field( description="Limit of logs to fetch in a single request", title="Limit", validate_default=True, ), - ] = Limit6.model_validate(500) + ] = Limit7.model_validate(500) min_level: Annotated[ Literal["DEBUG", "INFO", "WARNING", "ERROR"] | str | None, Field( @@ -6104,6 +6307,22 @@ class OrderBy(BaseModel): class SearchTrainingJobsRequest(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", + ), + ] = 1000 project_id: Annotated[ str | None, Field( @@ -6222,7 +6441,7 @@ class GetLoopsCapabilitiesResponse(BaseModel): supported_models: Annotated[ list[SupportedModel], Field( - 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.", + 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. Models this workspace can run come first, then the rest, each group sorted by name.", title="Supported Models", ), ] @@ -6278,6 +6497,12 @@ class LoopsSamplerStatus(BaseModel): class LoopsSampler(BaseModel): id: Annotated[str, Field(title="Id")] + session_id: Annotated[ + str, + Field( + description="The session ID this sampler belongs to.", title="Session Id" + ), + ] base_url: Annotated[str, Field(title="Base Url")] base_model: Annotated[ str, @@ -6392,13 +6617,13 @@ class CreateLoopsRunRequest(BaseModel): ), ] = 900 availability_model: Annotated[ - Literal["dedicated", "spot"] | str, + Literal["standard", "spot"] | str, 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.", + description="Capacity the trainer runs on. 'standard' 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"], - title="V1AvailabilityModel", + title="AvailabilityModelV1", ), - ] = "dedicated" + ] = "standard" replicas: Annotated[ int, Field( @@ -6499,13 +6724,13 @@ class CreateLoopsTrainerRequest(BaseModel): ), ] = 900 availability_model: Annotated[ - Literal["dedicated", "spot"] | str, + Literal["standard", "spot"] | str, 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.", + description="Capacity the trainer runs on. 'standard' 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"], - title="V1AvailabilityModel", + title="AvailabilityModelV1", ), - ] = "dedicated" + ] = "standard" replicas: Annotated[ int, Field( @@ -6543,6 +6768,13 @@ class CreateLoopsTrainerRequest(BaseModel): title="Base Checkpoint", ), ] = None + scope: Annotated[ + Literal["default", "serverless", "dedicated"] | str, + Field( + description="Choose where this runs. 'default' lets Baseten choose. 'serverless' runs on Baseten's shared capacity, and fails instead of falling back when shared capacity can't serve the request. 'dedicated' gives it its own deployment, which you size and pay for.", + title="LoopsPlacementScopeV1", + ), + ] = "default" class ListLoopsSamplersResponse(BaseModel): @@ -6564,9 +6796,9 @@ class NumReplicas(RootModel[int]): class CreateLoopsSamplerRequest(BaseModel): availability_model: Annotated[ - Literal["dedicated", "spot"] | str | None, + Literal["standard", "spot"] | str | 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." + description="Capacity the sampler runs on. 'spot' allows preemption when its GPUs are reclaimed. Defaults to 'standard' for standalone samplers. Paired samplers inherit their run's availability model; an explicit value must match it." ), ] = None session_id: Annotated[ @@ -6619,6 +6851,13 @@ class CreateLoopsSamplerRequest(BaseModel): title="Num Replicas", ), ] = None + scope: Annotated[ + Literal["default", "serverless", "dedicated"] | str, + Field( + description="Choose where this runs. 'default' lets Baseten choose. 'serverless' runs on Baseten's shared capacity, and fails instead of falling back when shared capacity can't serve the request. 'dedicated' gives it its own deployment, which you size and pay for. Standalone samplers only: a run's sampler runs where its run does.", + title="LoopsPlacementScopeV1", + ), + ] = "default" class CreateLoopsSamplerResponse(BaseModel): @@ -6769,7 +7008,7 @@ class LoopsCheckpointVolumeSource(BaseModel): path: Annotated[ str, Field( - description="Directory inside that version holding the checkpoint's files.", + description="Directory inside that version holding the checkpoint's files. Empty when the checkpoint is the whole version.", title="Path", ), ] @@ -6852,12 +7091,12 @@ class LoopsDeployment(BaseModel): ), ] availability_model: Annotated[ - Literal["dedicated", "spot"] | str, + Literal["standard", "spot"] | str, Field( description="Capacity the trainer was scheduled on.", - title="V1AvailabilityModel", + title="AvailabilityModelV1", ), - ] = "dedicated" + ] = "standard" instance_type: Annotated[ InstanceType, Field(description="Instance type backing the trainer.") ] @@ -7003,7 +7242,7 @@ class TeamTrainingGpuCapacityItem(BaseModel): dedicated_usage_count: Annotated[ int, Field( - description="Portion of usage_count from dedicated (on-demand) jobs.", + description="Portion of usage_count from standard (non-spot) jobs.", title="Dedicated Usage Count", ), ] = 0 @@ -7047,7 +7286,7 @@ class TrainingGpuCapacityItem(BaseModel): dedicated_usage_count: Annotated[ int, Field( - description="Portion of usage_count from dedicated (on-demand) jobs, which run against the baseline.", + description="Portion of usage_count from standard (non-spot) jobs, which run against the baseline.", title="Dedicated Usage Count", ), ] = 0 @@ -7338,7 +7577,7 @@ class CreateAPIKeyRequest(BaseModel): type: Annotated[ Literal[ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_ALL", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -7349,7 +7588,7 @@ class CreateAPIKeyRequest(BaseModel): description="Type of the API key.", examples=[ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_API_KEYS", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -7366,6 +7605,14 @@ class CreateAPIKeyRequest(BaseModel): title="Model Ids", ), ] = None + expires_at: Annotated[ + AwareDatetime | None, + Field( + description="Expiration time in UTC. Must be in the future. Personal keys must expire within 90 days, or sooner if your organization sets a lower limit. Team and organization keys require an expiration within your organization's limit when one is set; otherwise they may omit it or use null. Organization lifetime limits do not apply to Grid keys.", + examples=["2027-01-01T00:00:00Z"], + title="Expires At", + ), + ] = None team_id: Annotated[ TeamId3 | None, Field( @@ -7401,14 +7648,13 @@ class ModelAPIOrgDetails(BaseModel): added_at: Annotated[ AwareDatetime, Field( - description="When the workspace first added this Model API.", - title="Added At", + description="When the team first added this Model API.", title="Added At" ), ] last_used_at: Annotated[ AwareDatetime | None, Field( - description="When the workspace last invoked this Model API. Null if the workspace has never invoked it.", + description="When the team last invoked this Model API. Null if the team has never invoked it.", title="Last Used At", ), ] = None @@ -7421,8 +7667,7 @@ class CostPerMillionInputTokens(RootModel[str]): root: Annotated[ str, Field( - description="Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", - examples=["0.13"], + description="Effective cost per million input tokens, in dollars. Null if unavailable.", pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", title="Cost Per Million Input Tokens", ), @@ -7436,45 +7681,56 @@ class CostPerMillionOutputTokens(RootModel[str]): root: Annotated[ str, Field( - description="Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", - examples=["0.50"], + description="Effective cost per million output tokens, in dollars. Null if unavailable.", pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", title="Cost Per Million Output Tokens", ), ] -class RateLimit(BaseModel): - type: Annotated[ - Literal[ - "REQUEST", - "TOKEN", - "CONCURRENT_REQUEST", - "UNCACHED_INPUT_TOKEN", - "OUTPUT_TOKEN", - ] - | str, - Field( - description="The type of the rate limit", - examples=["TOKEN", "REQUEST"], - title="LimitTypeV1", +class CostPerMillionInputTokens1(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + deprecated=True, + description="Deprecated and will be removed in a future version. Legacy effective input-token price. Use team_details pricing instead. Retained during migration; null when pricing is unavailable.", + examples=["0.13"], + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Cost Per Million Input Tokens", ), ] - unit: Annotated[ - Literal["SECOND", "MINUTE"] | str, + + +class CostPerMillionCachedInputTokens(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="The unit of the rate limit", - examples=["SECOND", "MINUTE"], - title="RateLimitUnitV1", + description="Effective cost per million cached input tokens, in dollars. Null when pricing is unavailable or the Model API has no cached input price.", + examples=["0.03"], + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Cost Per Million Cached Input Tokens", ), ] - threshold: Annotated[ - int, + + +class CostPerMillionOutputTokens1(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, Field( - description="The threshold for the rate limit", - examples=[1000, 50000], - ge=0, - title="Threshold", + deprecated=True, + description="Deprecated and will be removed in a future version. Legacy effective output-token price. Use team_details pricing instead. Retained during migration; null when pricing is unavailable.", + examples=["0.50"], + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Cost Per Million Output Tokens", ), ] @@ -7564,6 +7820,13 @@ class RuntimeOidc(BaseModel): title="Enabled", ), ] = None + byok: Annotated[ + dict[str, Any] | None, + Field( + description="BYOK configuration for envelope-encrypted BDN weights in BIS-LLM deployments. Requires runtime.oidc.enabled to be true.", + title="Byok", + ), + ] = None class LLMModelHandle(BaseModel): @@ -7609,6 +7872,7 @@ class LibraryListingMetadata(BaseModel): ] = ["text"] license: Annotated[str, Field(title="License")] variant: Annotated[str | None, Field(title="Variant")] = None + base_model: Annotated[str | None, Field(title="Base Model")] = 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 @@ -7897,6 +8161,13 @@ class ModelApisCostResult(BaseModel): title="Service Tier", ), ] = None + team_id: Annotated[ + str | None, + Field( + description="Team the cost is attributed to. Null when not grouping by team or when team attribution is unavailable.", + title="Team Id", + ), + ] = None subtotal: Annotated[ str, Field( @@ -8000,10 +8271,38 @@ class DailyDedicatedUsage(BaseModel): ] +class Subtotal1(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + description="Cost in dollars across all four meters", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", + ), + ] + + +class Subtotal2(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + description="Subtotal cost incurred on this date in dollars", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", + ), + ] + + class DailyModelApiUsage(BaseModel): date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] subtotal: Annotated[ - float | Subtotal, + float | Subtotal2, Field( description="Subtotal cost incurred on this date in dollars", title="Subtotal", @@ -8031,7 +8330,7 @@ class DailyModelApiUsage(BaseModel): class DailyTrainingUsage(BaseModel): date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] subtotal: Annotated[ - float | Subtotal, + float | Subtotal2, Field( description="Subtotal cost incurred on this date in dollars", title="Subtotal", @@ -8042,7 +8341,7 @@ class DailyTrainingUsage(BaseModel): ] -class Subtotal3(RootModel[str]): +class Subtotal4(RootModel[str]): model_config = ConfigDict( regex_engine="python-re", ) @@ -8084,7 +8383,7 @@ class SurchargeCost1(RootModel[str]): ] -class Subtotal4(RootModel[str]): +class Subtotal5(RootModel[str]): model_config = ConfigDict( regex_engine="python-re", ) @@ -8126,7 +8425,73 @@ class Total(RootModel[str]): ] -class Subtotal5(RootModel[str]): +class Subtotal6(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + description="Cost in dollars across all four meters", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", + ), + ] + + +class Subtotal7(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + description="Cost of those tokens in dollars", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", + ), + ] + + +class LoopsMeterUsage(BaseModel): + tokens: Annotated[ + int, Field(description="Tokens billed on this meter", title="Tokens") + ] + subtotal: Annotated[ + float | Subtotal7, + Field(description="Cost of those tokens in dollars", title="Subtotal"), + ] + + +class Subtotal8(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + description="Cost in dollars across all four meters", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", + ), + ] + + +class Subtotal9(RootModel[str]): + model_config = ConfigDict( + regex_engine="python-re", + ) + root: Annotated[ + str, + Field( + description="Cost in dollars before credits", + pattern="^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + title="Subtotal", + ), + ] + + +class Subtotal10(RootModel[str]): model_config = ConfigDict( regex_engine="python-re", ) @@ -8147,7 +8512,7 @@ class ModelApiItem(BaseModel): Field(description="Model family (e.g., Meta, DeepSeek)", title="Model Family"), ] = None subtotal: Annotated[ - float | Subtotal5, + float | Subtotal10, Field(description="Subtotal cost in dollars for this model", title="Subtotal"), ] input_tokens: Annotated[ @@ -8171,7 +8536,7 @@ class ModelApiItem(BaseModel): ] = None -class Subtotal6(RootModel[str]): +class Subtotal11(RootModel[str]): model_config = ConfigDict( regex_engine="python-re", ) @@ -8187,7 +8552,7 @@ class Subtotal6(RootModel[str]): class ModelApisUsage(BaseModel): subtotal: Annotated[ - float | Subtotal6, + float | Subtotal11, Field( description="Subtotal cost in dollars after applying credits used", title="Subtotal", @@ -8206,7 +8571,7 @@ class ModelApisUsage(BaseModel): ] = None -class Subtotal7(RootModel[str]): +class Subtotal12(RootModel[str]): model_config = ConfigDict( regex_engine="python-re", ) @@ -8220,7 +8585,7 @@ class Subtotal7(RootModel[str]): ] -class Subtotal8(RootModel[str]): +class Subtotal13(RootModel[str]): model_config = ConfigDict( regex_engine="python-re", ) @@ -8261,6 +8626,13 @@ class ToolCallUsageBucket(BaseModel): title="Quantity", ), ] + team_id: Annotated[ + str | None, + Field( + description="Team attributed to the usage. Null when not grouping by team or when historical team attribution is unavailable.", + title="Team Id", + ), + ] = None class ToolCallUsageResponse(BaseModel): @@ -8415,6 +8787,62 @@ class ExploreMetadataAPIFormats(BaseModel): ] = False +class TeamId4(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="ID of the team. When omitted, the team you belong to; required when you belong to several.", + examples=["abc1234"], + min_length=1, + title="Team Id", + ), + ] = None + + +class CreateGridTokenRequest(BaseModel): + team_id: Annotated[ + TeamId4 | None, + Field( + description="ID of the team. When omitted, the team you belong to; required when you belong to several.", + examples=["abc1234"], + title="Team Id", + ), + ] = None + + +class GridToken(BaseModel): + token: Annotated[ + str, + Field( + description="Short-lived bearer token for the Grid gateway, scoped to you and the team. Send it as Authorization: Bearer .", + title="Token", + ), + ] + expires_at: Annotated[ + AwareDatetime, + Field( + description="Token expiry in ISO 8601 format. Tokens cannot be renewed; request a new one.", + title="Expires At", + ), + ] + team_id: Annotated[ + str, + Field( + description="ID of the team the token invokes Grid routes in.", + examples=["abc1234"], + title="Team Id", + ), + ] + team_name: Annotated[ + str, + Field( + description="Name of that team.", + examples=["Engineering"], + title="Team Name", + ), + ] + + class GridClassifier(BaseModel): id: Annotated[ str, @@ -8434,6 +8862,40 @@ class GridClassifier(BaseModel): ] +class GridRouteClassifier(BaseModel): + id: Annotated[ + str, + Field( + description="Stable route classifier identifier.", + examples=["general-v1"], + title="Id", + ), + ] + name: Annotated[ + str, + Field( + description="Display name of the route classifier.", + examples=["General"], + title="Name", + ), + ] + supported_tradeoffs: Annotated[ + list[Literal["cost", "balanced", "intelligence"] | str], + Field( + description="Tradeoffs the route classifier supports. Empty when it supports all of them.", + title="Supported Tradeoffs", + ), + ] + decidable_models: Annotated[ + list[str], + Field( + description="Model identities the route classifier picks from.", + examples=[["zai-org/GLM-5.3", "anthropic/claude-opus-5-5"]], + title="Decidable Models", + ), + ] + + class GridRouteRef(BaseModel): id: Annotated[str, Field(description="Stable route identifier.", title="Id")] slug: Annotated[ @@ -8502,6 +8964,26 @@ class GridRouteTargetConnection(BaseModel): ] +class GridRouteTargetIntelligent(BaseModel): + type: Annotated[ + Literal["INTELLIGENT"], + Field( + description="Target kind for an intelligent route: Baseten picks the model per request.", + title="Type", + ), + ] + route_classifier: Annotated[ + GridRouteClassifier, Field(description="Route classifier that picks the model.") + ] + tradeoff: Annotated[ + Literal["cost", "balanced", "intelligence"] | str, + Field( + description="How the classifier weighs cost against quality.", + title="GridRouteTradeoffV1", + ), + ] + + class UpsertGridRouteTargetBasetenModelAPI(BaseModel): model_config = ConfigDict( extra="forbid", @@ -8579,7 +9061,7 @@ class UpsertGridRouteTargetConnection(BaseModel): ] -class TeamId4(RootModel[str]): +class TeamId5(RootModel[str]): root: Annotated[ str | None, Field( @@ -8621,7 +9103,7 @@ class CreateGridRouteRequest(BaseModel): extra="forbid", ) team_id: Annotated[ - TeamId4 | None, + TeamId5 | None, Field( description="Identifier of the team that owns the route.", examples=["abc1234"], @@ -8698,6 +9180,7 @@ class GridRouteUsageResult(BaseModel): "XAI", "VERTEX", "OPENAI_COMPATIBLE", + "BEDROCK", ] | str | None, @@ -8712,6 +9195,12 @@ class GridRouteUsageResult(BaseModel): title="Router Id", ), ] = None + harness: Annotated[ + Literal["CLAUDE_CODE", "OPENCODE", "CODEX", "PI"] | str | None, + Field( + description="Coding harness. Null when not grouping by HARNESS, when no harness was recorded (including usage from before harness tracking), or when the recorded harness is not recognized by this API version." + ), + ] = None cost_usd: Annotated[ str, Field( @@ -8882,23 +9371,39 @@ class UpdateGridBackgroundHarnessModels(BaseModel): ] = None -class UpdateGridPrimaryHarnessModels(BaseModel): +class UpdateGridHarnessDefaults(BaseModel): model_config = ConfigDict( extra="forbid", ) - primary: Annotated[ - Primary | None, + claude_code: Annotated[ + UpdateGridBackgroundHarnessModels | None, Field( - description="Route ID for the primary model, which new sessions use. Omit to keep the current route, or pass null to use the team's default.", - examples=["abc1234"], - title="Primary", + description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." ), ] = None - - -class UpdateGridTeamSpendLimitSetting(BaseModel): - model_config = ConfigDict( - extra="forbid", + opencode: Annotated[ + UpdateGridBackgroundHarnessModels | None, + Field( + description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." + ), + ] = None + codex: Annotated[ + UpdateGridBackgroundHarnessModels | None, + Field( + description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." + ), + ] = None + pi: Annotated[ + UpdateGridBackgroundHarnessModels | None, + Field( + description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." + ), + ] = None + + +class UpdateGridTeamSpendLimitSetting(BaseModel): + model_config = ConfigDict( + extra="forbid", ) per_member_monthly_limit_usd: Annotated[ str | None, @@ -8918,6 +9423,32 @@ class UpdateGridTeamSpendLimitSetting(BaseModel): ] = None +class UpdateGridTeamSettingsRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + harness_defaults: Annotated[ + UpdateGridHarnessDefaults | None, + Field( + description="Harnesses to change; harnesses left out are unchanged. Pass null to clear every harness, so each role uses the team's default." + ), + ] = None + spend_limit: Annotated[ + UpdateGridTeamSpendLimitSetting | None, + Field( + description="Spend limit fields to change. Pass null to remove the team's limits; omit to leave them unchanged." + ), + ] = None + team_id: Annotated[ + str | None, + Field( + description="ID of the team. When omitted, the team you belong to; required when you belong to several.", + examples=["abc1234"], + title="Team Id", + ), + ] = None + + class GridEffectiveSpendLimit(BaseModel): monthly_limit_usd: Annotated[ str | None, @@ -9002,6 +9533,26 @@ class UpdateGridUserSettingsRequest(BaseModel): ] = None +class GridConnectionBedrockAccessKeysAuth(BaseModel): + method: Annotated[ + Literal["access_keys"], + Field( + description='The secret holds the access keys of an IAM user, as the base64-encoded JSON object `{"AccessKeyId": "...", "SecretAccessKey": "..."}`', + title="Method", + ), + ] + + +class GridConnectionBedrockApiKeyAuth(BaseModel): + method: Annotated[ + Literal["api_key"], + Field( + description="The secret holds a long-term Amazon Bedrock API key.", + title="Method", + ), + ] + + class GridConnectionConfigAnthropic(BaseModel): provider: Annotated[ Literal["ANTHROPIC"], @@ -9023,6 +9574,43 @@ class GridConnectionConfigAnthropic(BaseModel): ] +class GridConnectionConfigBedrock(BaseModel): + provider: Annotated[ + Literal["BEDROCK"], + Field(description="Provider kind for Amazon Bedrock.", title="Provider"), + ] + secret_id: Annotated[ + str, + Field( + description="Identifier of the team secret holding the provider API key.", + title="Secret Id", + ), + ] + secret_name: Annotated[ + str, + Field( + description="Name of the team secret holding the provider API key.", + title="Secret Name", + ), + ] + region: Annotated[ + str, + Field(description="AWS Region of the Amazon Bedrock endpoint.", title="Region"), + ] + auth: Annotated[ + Annotated[ + GridConnectionBedrockApiKeyAuth | GridConnectionBedrockAccessKeysAuth, + Field( + description="How the connection's secret authenticates with Amazon Bedrock.", + discriminator="method", + title="Auth", + ), + ] + | dict[str, Any], + Field(union_mode="left_to_right"), + ] + + class GridConnectionConfigOpenAI(BaseModel): provider: Annotated[ Literal["OPENAI"], @@ -9044,6 +9632,41 @@ class GridConnectionConfigOpenAI(BaseModel): ] +class GridConnectionConfigVertex(BaseModel): + provider: Annotated[ + Literal["VERTEX"], + Field(description="Provider kind for Google Vertex.", title="Provider"), + ] + secret_id: Annotated[ + str, + Field( + description="Identifier of the team secret holding the provider API key.", + title="Secret Id", + ), + ] + secret_name: Annotated[ + str, + Field( + description="Name of the team secret holding the provider API key.", + title="Secret Name", + ), + ] + project_id: Annotated[ + str, + Field( + description="Google Cloud project ID or number of a project with Vertex AI enabled.", + title="Project Id", + ), + ] + location: Annotated[ + str, + Field( + description="Google Cloud region that serves the Vertex AI models, for example `us-central1`.", + title="Location", + ), + ] + + class GridConnectionConfigXAI(BaseModel): provider: Annotated[ Literal["XAI"], Field(description="Provider kind for xAI.", title="Provider") @@ -9083,7 +9706,9 @@ class GridConnection(BaseModel): Annotated[ GridConnectionConfigAnthropic | GridConnectionConfigOpenAI - | GridConnectionConfigXAI, + | GridConnectionConfigXAI + | GridConnectionConfigVertex + | GridConnectionConfigBedrock, Field( description="Provider the connection authenticates with, and the team secret holding its API key.", discriminator="provider", @@ -9111,6 +9736,32 @@ class GridConnectionsResponse(BaseModel): ] +class UpsertGridConnectionBedrockAccessKeysAuth(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + method: Annotated[ + Literal["access_keys"], + Field( + description='The secret holds the access keys of an IAM user, as the base64-encoded JSON object `{"AccessKeyId": "...", "SecretAccessKey": "..."}`', + title="Method", + ), + ] + + +class UpsertGridConnectionBedrockApiKeyAuth(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + method: Annotated[ + Literal["api_key"], + Field( + description="The secret holds a long-term Amazon Bedrock API key.", + title="Method", + ), + ] + + class UpsertGridConnectionConfigAnthropic(BaseModel): model_config = ConfigDict( extra="forbid", @@ -9130,6 +9781,50 @@ class UpsertGridConnectionConfigAnthropic(BaseModel): ] +class UpsertGridConnectionConfigBedrock(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + provider: Annotated[ + Literal["BEDROCK"], + Field( + description="Provider kind for Amazon Bedrock. Claude models (`anthropic.*`) use the Anthropic Messages API, and other models use the OpenAI-compatible APIs.", + title="Provider", + ), + ] + secret_name: Annotated[ + str, + Field( + description="Name of an existing secret, owned by the same team, that holds the provider API key.", + examples=["anthropic-key"], + min_length=1, + title="Secret Name", + ), + ] + region: Annotated[ + str, + Field( + description="AWS Region of the Amazon Bedrock endpoint, for example `us-east-1`.", + examples=["us-east-1"], + min_length=1, + title="Region", + ), + ] + auth: Annotated[ + Annotated[ + UpsertGridConnectionBedrockApiKeyAuth + | UpsertGridConnectionBedrockAccessKeysAuth, + Field( + description="How the connection's secret authenticates with Amazon Bedrock.", + discriminator="method", + title="Auth", + ), + ] + | dict[str, Any], + Field(union_mode="left_to_right"), + ] + + class UpsertGridConnectionConfigOpenAI(BaseModel): model_config = ConfigDict( extra="forbid", @@ -9149,6 +9844,43 @@ class UpsertGridConnectionConfigOpenAI(BaseModel): ] +class UpsertGridConnectionConfigVertex(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + provider: Annotated[ + Literal["VERTEX"], + Field(description="Provider kind for Google Vertex.", title="Provider"), + ] + secret_name: Annotated[ + str, + Field( + description="Name of an existing secret, owned by the same team, that holds the provider API key.", + examples=["anthropic-key"], + min_length=1, + title="Secret Name", + ), + ] + project_id: Annotated[ + str, + Field( + description="Google Cloud project ID or number of a project with Vertex AI enabled.", + examples=["my-gcp-project"], + min_length=1, + title="Project Id", + ), + ] + location: Annotated[ + str, + Field( + description="Google Cloud region that serves the Vertex AI models, for example `us-central1`.", + examples=["us-central1"], + min_length=1, + title="Location", + ), + ] + + class UpsertGridConnectionConfigXAI(BaseModel): model_config = ConfigDict( extra="forbid", @@ -9167,7 +9899,7 @@ class UpsertGridConnectionConfigXAI(BaseModel): ] -class TeamId5(RootModel[str]): +class TeamId6(RootModel[str]): root: Annotated[ str | None, Field( @@ -9184,7 +9916,7 @@ class CreateGridConnectionRequest(BaseModel): extra="forbid", ) team_id: Annotated[ - TeamId5 | None, + TeamId6 | None, Field( description="Identifier of the team that owns the connection.", examples=["abc1234"], @@ -9195,7 +9927,9 @@ class CreateGridConnectionRequest(BaseModel): Annotated[ UpsertGridConnectionConfigAnthropic | UpsertGridConnectionConfigOpenAI - | UpsertGridConnectionConfigXAI, + | UpsertGridConnectionConfigXAI + | UpsertGridConnectionConfigVertex + | UpsertGridConnectionConfigBedrock, Field( description="Provider the connection authenticates with, and the team secret holding its API key.", discriminator="provider", @@ -9223,7 +9957,9 @@ class UpdateGridConnectionRequest(BaseModel): Annotated[ UpsertGridConnectionConfigAnthropic | UpsertGridConnectionConfigOpenAI - | UpsertGridConnectionConfigXAI, + | UpsertGridConnectionConfigXAI + | UpsertGridConnectionConfigVertex + | UpsertGridConnectionConfigBedrock, Field( description="Complete new connection configuration, replacing the current one. The provider must match the connection and is immutable.", discriminator="provider", @@ -9236,13 +9972,220 @@ class UpdateGridConnectionRequest(BaseModel): ] -class GridClassifiersResponse(BaseModel): - items: Annotated[ - list[GridClassifier], Field(description="Items in this page.", title="Items") - ] - pagination: Annotated[ - PaginationResponse, Field(description="Pagination metadata for the page.") - ] +class GridClassifiersResponse(BaseModel): + items: Annotated[ + list[GridClassifier], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class GridRouteClassifiersResponse(BaseModel): + items: Annotated[ + list[GridRouteClassifier], + Field(description="Items in this page.", title="Items"), + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class GridMachineUser(BaseModel): + id: Annotated[ + str, + Field( + description="Stable machine user identifier. Grid usage and settings identify the machine user by this ID as its `user_id`.", + title="Id", + ), + ] + name: Annotated[ + str, + Field( + description="Name of the machine user, unique within its team.", + title="Name", + ), + ] + team_id: Annotated[ + str, + Field( + description="Identifier of the team that owns the machine user.", + title="Team Id", + ), + ] + team_name: Annotated[ + str, + Field( + description="Name of the team that owns the machine user.", + title="Team Name", + ), + ] + created_by: Annotated[ + str | None, + Field( + description="ID of the user who created the machine user. Null when unknown.", + title="Created By", + ), + ] = None + created_at: Annotated[ + AwareDatetime, Field(description="Creation time, ISO 8601.", title="Created At") + ] + + +class GridMachineUsersResponse(BaseModel): + items: Annotated[ + list[GridMachineUser], Field(description="Items in this page.", title="Items") + ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] + + +class Name5(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="Name of the API key: lowercase letters, numbers, and hyphens, at most 255 characters, and unique among the machine user's active keys. Defaults to a name derived from the machine user's.", + examples=["production"], + max_length=255, + min_length=1, + title="Name", + ), + ] = None + + +class CreateGridMachineUserAPIKeyRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + name: Annotated[ + Name5 | None, + Field( + description="Name of the API key: lowercase letters, numbers, and hyphens, at most 255 characters, and unique among the machine user's active keys. Defaults to a name derived from the machine user's.", + examples=["production"], + title="Name", + ), + ] = None + + +class TeamId7(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="Identifier of the team that owns the machine user. Defaults to your only team, if you belong to exactly one.", + examples=["abc1234"], + min_length=1, + title="Team Id", + ), + ] = None + + +class CreateGridMachineUserRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + team_id: Annotated[ + TeamId7 | None, + Field( + description="Identifier of the team that owns the machine user. Defaults to your only team, if you belong to exactly one.", + examples=["abc1234"], + title="Team Id", + ), + ] = None + name: Annotated[ + str, + Field( + description="Name of the machine user, unique within the team. At most 255 characters.", + examples=["night-shift"], + max_length=255, + min_length=1, + title="Name", + ), + ] + api_key: Annotated[ + CreateGridMachineUserAPIKeyRequest | None, + Field(description="When set, also creates the machine user's first API key."), + ] = None + + +class CreatedGridMachineUser(BaseModel): + id: Annotated[ + str, + Field( + description="Stable machine user identifier. Grid usage and settings identify the machine user by this ID as its `user_id`.", + title="Id", + ), + ] + name: Annotated[ + str, + Field( + description="Name of the machine user, unique within its team.", + title="Name", + ), + ] + team_id: Annotated[ + str, + Field( + description="Identifier of the team that owns the machine user.", + title="Team Id", + ), + ] + team_name: Annotated[ + str, + Field( + description="Name of the team that owns the machine user.", + title="Team Name", + ), + ] + created_by: Annotated[ + str | None, + Field( + description="ID of the user who created the machine user. Null when unknown.", + title="Created By", + ), + ] = None + created_at: Annotated[ + AwareDatetime, Field(description="Creation time, ISO 8601.", title="Created At") + ] + api_key: Annotated[ + str | None, + Field( + description="The first API key, returned only once. Null unless the request set `api_key`.", + title="Api Key", + ), + ] = None + + +class GridMachineUserTombstone(BaseModel): + id: Annotated[ + str, + Field(description="Stable identifier of the deleted machine user.", title="Id"), + ] + + +class Name6(RootModel[str]): + root: Annotated[ + str | None, + Field( + description="Name of the machine user, unique within its team. At most 255 characters. Omit to keep it.", + max_length=255, + min_length=1, + title="Name", + ), + ] = None + + +class UpdateGridMachineUserRequest(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + name: Annotated[ + Name6 | None, + Field( + description="Name of the machine user, unique within its team. At most 255 characters. Omit to keep it.", + title="Name", + ), + ] = None class VertexTargetConfig(BaseModel): @@ -9277,7 +10220,7 @@ class EndpointTargetRequest(BaseModel): Field( description="Upstream provider for this target.", examples=["ANTHROPIC", "OPENAI", "OPENAI_COMPATIBLE", "BASETEN"], - title="GatewayProvider", + title="GatewayEndpointProviderV1", ), ] secret_id: Annotated[ @@ -9503,7 +10446,7 @@ class EffectiveRateLimit(BaseModel): ] -class Name5(RootModel[str]): +class Name7(RootModel[str]): root: Annotated[ str | None, Field( @@ -9517,7 +10460,7 @@ class Name5(RootModel[str]): class GroupMetadata(BaseModel): name: Annotated[ - Name5 | None, + Name7 | None, Field( description="Optional display name for the group.", examples=["Acme prod"], @@ -9536,6 +10479,41 @@ class GroupMetadata(BaseModel): ] +class RateLimit(BaseModel): + type: Annotated[ + Literal[ + "REQUEST", + "TOKEN", + "CONCURRENT_REQUEST", + "UNCACHED_INPUT_TOKEN", + "OUTPUT_TOKEN", + ] + | str, + Field( + description="The type of the rate limit", + examples=["TOKEN", "REQUEST"], + title="LimitTypeV1", + ), + ] + unit: Annotated[ + Literal["SECOND", "MINUTE"] | str, + Field( + description="The unit of the rate limit", + examples=["SECOND", "MINUTE"], + title="RateLimitUnitV1", + ), + ] + threshold: Annotated[ + int, + Field( + description="The threshold for the rate limit", + examples=[1000, 50000], + ge=0, + title="Threshold", + ), + ] + + class UsageLimit(BaseModel): type: Annotated[ Literal[ @@ -9586,7 +10564,7 @@ class CreateGroupHierarchy(BaseModel): class UpdateGroupMetadata(BaseModel): name: Annotated[ - Name5 | None, + Name7 | None, Field( description="Optional display name for the group.", examples=["Acme prod"], @@ -10472,7 +11450,7 @@ class GetAuditLogsParams(BaseModel): "SECRETS", "API_KEYS", "GATEWAY", - "CODE", + "GRID", "WEBHOOK_SIGNING_SECRETS", "USER_MANAGEMENT", "DIRECTORY_GROUP_MANAGEMENT", @@ -10585,7 +11563,7 @@ class GetModelsAuditLogsParams(BaseModel): "SECRETS", "API_KEYS", "GATEWAY", - "CODE", + "GRID", "WEBHOOK_SIGNING_SECRETS", "USER_MANAGEMENT", "DIRECTORY_GROUP_MANAGEMENT", @@ -10731,7 +11709,7 @@ class GetModelsDeploymentsMetricsParams(BaseModel): Literal["CURRENT", "SUMMARY", "SERIES"] | str, 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.", - title="ModelMetricModeV1", + title="MetricModeV1", ), ] = "CURRENT" start_epoch_millis: Annotated[ @@ -10914,7 +11892,7 @@ class GetModelsEnvironmentsMetricsParams(BaseModel): Literal["CURRENT", "SUMMARY", "SERIES"] | str, 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.", - title="ModelMetricModeV1", + title="MetricModeV1", ), ] = "CURRENT" start_epoch_millis: Annotated[ @@ -11064,7 +12042,7 @@ class GetChainsAuditLogsParams(BaseModel): "SECRETS", "API_KEYS", "GATEWAY", - "CODE", + "GRID", "WEBHOOK_SIGNING_SECRETS", "USER_MANAGEMENT", "DIRECTORY_GROUP_MANAGEMENT", @@ -11224,13 +12202,13 @@ class GetTrainingProjectsJobsLogsParams(BaseModel): Literal["asc", "desc"] | str | None, Field(description="Sort order for logs") ] = None limit: Annotated[ - Limit | None, + Limit4 | None, Field( description="Limit of logs to fetch in a single request", title="Limit", validate_default=True, ), - ] = Limit.model_validate(500) + ] = Limit4.model_validate(500) min_level: Annotated[ Literal["DEBUG", "INFO", "WARNING", "ERROR"] | str | None, Field( @@ -11243,7 +12221,7 @@ class GetLoopsCapabilitiesParams(BaseModel): model: Annotated[ str | None, Field( - 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.", + 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'. Without 'enabled', an empty list means Baseten does not support that model. Omit to list every supported model.", examples=["Qwen/Qwen3-8B"], title="Model", ), @@ -11264,6 +12242,14 @@ class GetLoopsCapabilitiesParams(BaseModel): title="Max Seq Len", ), ] = None + enabled: Annotated[ + bool | None, + Field( + description="Pass true to list only the models this workspace can run now, or false for only the ones it cannot. Omit to list both. With 'model', an empty list can also mean the model is supported but filtered out.", + examples=[True], + title="Enabled", + ), + ] = None class GetLoopsDeploymentsLogsParams(BaseModel): @@ -11285,13 +12271,13 @@ class GetLoopsDeploymentsLogsParams(BaseModel): Literal["asc", "desc"] | str | None, Field(description="Sort order for logs") ] = None limit: Annotated[ - Limit | None, + Limit4 | None, Field( description="Limit of logs to fetch in a single request", title="Limit", validate_default=True, ), - ] = Limit.model_validate(500) + ] = Limit4.model_validate(500) min_level: Annotated[ Literal["DEBUG", "INFO", "WARNING", "ERROR"] | str | None, Field( @@ -11373,6 +12359,37 @@ class GetModelApisUsageParams(BaseModel): ] = None +class GetModelApisMetricsParams(BaseModel): + mode: Annotated[ + Literal["CURRENT", "SUMMARY", "SERIES"] | str, + 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.", + title="MetricModeV1", + ), + ] = "CURRENT" + start_epoch_millis: Annotated[ + int | None, + Field( + description="Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", + title="Start Epoch Millis", + ), + ] = None + end_epoch_millis: Annotated[ + int | 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", + ), + ] = None + metrics: Annotated[ + list[str] | 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_model_api_inference_requests_total, baseten_model_api_incoming_inference_requests_total, and baseten_model_api_tokens_total. Unknown names are rejected; valid names that are not enabled for your organization are omitted from the response.", + title="Metrics", + ), + ] = None + + class GetBillingModelApisParams(BaseModel): cursor: Annotated[ str | None, @@ -11405,9 +12422,10 @@ class GetBillingModelApisParams(BaseModel): ), ] = None group_by: Annotated[ - list[Literal["api_key_prefix", "user", "model", "service_tier"] | str] | None, + list[Literal["api_key_prefix", "user", "model", "service_tier", "team"] | str] + | 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.", + description="Dimensions to break costs down by, repeated once per dimension: api_key_prefix, user, model, service_tier, or team. 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 totals across all teams you can manage.", title="Group By", ), ] = None @@ -11439,6 +12457,44 @@ class GetBillingModelApisParams(BaseModel): title="Service Tiers", ), ] = None + team_ids: Annotated[ + list[str] | None, + Field( + description="Return only costs attributed to these teams, repeated once per team. Defaults to all teams you can manage.", + title="Team Ids", + ), + ] = None + + +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 + team_ids: Annotated[ + list[str] | None, + Field( + description="Return only usage for these teams, repeated once per team. Defaults to all teams you can manage. An unauthorized team ID causes a 403 response.", + title="Team Ids", + ), + ] = None + group_by: Annotated[ + list[Literal["TEAM"] | str] | None, + Field( + description="Pass TEAM to split daily rows by team. Defaults to aggregating across teams.", + title="Group By", + ), + ] = None class GetGridRoutesUsageParams(BaseModel): @@ -11480,9 +12536,10 @@ class GetGridRoutesUsageParams(BaseModel): ), ] = None group_by: Annotated[ - list[Literal["USER", "TEAM", "MODEL", "PROVIDER", "ROUTER"] | str] | None, + list[Literal["USER", "TEAM", "MODEL", "PROVIDER", "ROUTER", "HARNESS"] | str] + | None, Field( - description="Dimensions to break usage down by, repeated once per dimension: USER, TEAM, MODEL, PROVIDER, or ROUTER. 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. ROUTER returns only usage sent through an intelligent router, one row per router, or per router and model with MODEL. Router rows repeat usage already counted in other groupings, so don't add them to model totals. Defaults to MODEL.", + description="Dimensions to break usage down by, repeated once per dimension: USER, TEAM, MODEL, PROVIDER, ROUTER, or HARNESS. 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. ROUTER returns only usage sent through an intelligent router, one row per router, or per router and model with MODEL. Router rows repeat usage already counted in other groupings, so don't add them to model totals. HARNESS includes usage with no recorded harness as a null group. Defaults to MODEL.", title="Group By", ), ] = None @@ -11509,6 +12566,7 @@ class GetGridRoutesUsageParams(BaseModel): "XAI", "VERTEX", "OPENAI_COMPATIBLE", + "BEDROCK", ] | str ] @@ -11518,6 +12576,13 @@ class GetGridRoutesUsageParams(BaseModel): title="Providers", ), ] = None + harnesses: Annotated[ + list[Literal["CLAUDE_CODE", "OPENCODE", "CODEX", "PI"] | str] | None, + Field( + description="Return only usage for these harnesses, repeated once per harness. Omit to include all usage, including usage with no recorded harness.", + title="Harnesses", + ), + ] = None class GetSandboxMetricsParams(BaseModel): @@ -11989,6 +13054,30 @@ class AuditLogEventEnvironmentUpdated(BaseModel): previous_settings: AuditLogEventEnvironmentSettings | None +class AuditLogEventModelDeployed(BaseModel): + 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")] + region_update: Annotated[str | None, Field(title="Region Update")] + instance_type_id_update: Annotated[ + str | None, Field(title="Instance Type Id Update") + ] + promotion_settings_override: AuditLogEventPromotionSettingsOverride | None + autoscaling_settings_update: AuditLogEventAutoscalingSettingsUpdate | None + request_backpressure_settings_update: ( + AuditLogEventRequestBackpressureSettingsUpdate | None + ) + autoscaling_schedule_settings_update: ( + AuditLogEventAutoscalingScheduleOperations | None + ) + + class AuditLogEventModelDeploymentAutoscalingSettingsChanged(BaseModel): schedules: Annotated[ list[AuditLogEventAutoscalingScheduleChange] | None, Field(title="Schedules") @@ -12265,7 +13354,7 @@ class RetryDeploymentResponse(BaseModel): ] -class ModelMetricDescriptor(BaseModel): +class MetricDescriptor(BaseModel): name: Annotated[str, Field(description="Canonical metric name.", title="Name")] unit_hint: Annotated[ Literal[ @@ -12281,26 +13370,26 @@ class ModelMetricDescriptor(BaseModel): | str, Field( description="Advisory unit of the metric's values.", - title="ModelMetricUnitHintV1", + title="MetricUnitHintV1", ), ] kind: Annotated[ Literal["GAUGE", "COUNTER", "HISTOGRAM"] | str, Field( description="Semantic hint for how the metric behaves (GAUGE, COUNTER, HISTOGRAM).", - title="ModelMetricKindV1", + title="MetricKindV1", ), ] label_sets: Annotated[ list[dict[str, str]], 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'}.", + 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'}.", title="Label Sets", ), ] -class GetModelMetricsResponse(BaseModel): +class GetMetricsResponse(BaseModel): start_epoch_millis: Annotated[ int, Field(description="Start of the returned window.", title="Start Epoch Millis"), @@ -12310,7 +13399,7 @@ class GetModelMetricsResponse(BaseModel): ] mode: Annotated[ Literal["CURRENT", "SUMMARY", "SERIES"] | str, - Field(description="The aggregation mode used.", title="ModelMetricModeV1"), + Field(description="The aggregation mode used.", title="MetricModeV1"), ] step_seconds: Annotated[ int | None, @@ -12320,14 +13409,14 @@ class GetModelMetricsResponse(BaseModel): ), ] metric_descriptors: Annotated[ - list[ModelMetricDescriptor], + list[MetricDescriptor], Field( description="Descriptors for each metric; position defines the values index.", title="Metric Descriptors", ), ] metric_values: Annotated[ - list[ModelMetricValueSet], + list[MetricValueSet], 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", @@ -12980,12 +14069,12 @@ class TrainingJob(BaseModel): ), ] = 0 availability_model: Annotated[ - Literal["dedicated", "spot"] | str, + Literal["standard", "spot"] | str, Field( - description="Capacity guarantee for the job. 'dedicated' is non-preemptible on-demand capacity; 'spot' is interruptible.", - title="V1AvailabilityModel", + description="Capacity guarantee for the job. 'standard' runs on capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; you are responsible for checkpointing your own progress.", + title="AvailabilityModelV1", ), - ] = "dedicated" + ] = "standard" user: Annotated[ User | None, Field(description="The user who created the training job.") ] = None @@ -12998,6 +14087,13 @@ class TrainingProject(BaseModel): name: Annotated[ str, Field(description="Name of the training project.", title="Name") ] + project_accelerator: Annotated[ + str | None, + Field( + description="Default GPU type for cache-enabled CPU job placement.", + title="Project Accelerator", + ), + ] = None created_at: Annotated[ AwareDatetime, Field( @@ -13038,6 +14134,9 @@ class ListTrainingProjectsResponse(BaseModel): list[TrainingProject], Field(description="List of training projects.", title="Training Projects"), ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] class ListTrainingJobsResponse(BaseModel): @@ -13171,6 +14270,7 @@ class CreateTrainingJobRuntime(BaseModel): "enable_legacy_hf_mount": True, "enabled": True, "mount_base_path": "/root/.cache", + "persistent_home": False, "require_cache_affinity": True, } ], @@ -13362,6 +14462,9 @@ class SearchTrainingJobsResponse(BaseModel): list[TrainingJob], Field(description="List of training jobs.", title="Training Jobs"), ] + pagination: Annotated[ + PaginationResponse, Field(description="Pagination metadata for the page.") + ] class LoopsRun(BaseModel): @@ -13543,7 +14646,7 @@ class APIKeyInfo(BaseModel): type: Annotated[ Literal[ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_ALL", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -13554,7 +14657,7 @@ class APIKeyInfo(BaseModel): description="Type of the API key.", examples=[ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_API_KEYS", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -13566,41 +14669,157 @@ class APIKeyInfo(BaseModel): 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", + 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_name: Annotated[ + str | None, + Field( + description="The name of the team associated with the API key", + title="Team Name", + ), + ] = None + created_at: Annotated[ + AwareDatetime, + Field(description="Creation time in ISO 8601 format", title="Created At"), + ] + expires_at: Annotated[ + AwareDatetime | None, + Field( + description="Expiry time in ISO 8601 format, or null if the key never expires.", + title="Expires At", + ), + ] = None + last_used_at: Annotated[ + AwareDatetime | None, + Field( + description="Last recorded use in ISO 8601 format, or null if unavailable. Updates may be delayed.", + title="Last Used At", + ), + ] = None + owner: Annotated[ + APIKeyOwner | None, + Field( + description="The user who owns the API key. Only present for personal API keys." + ), + ] = None + + +class APIKeys(BaseModel): + keys: Annotated[ + list[APIKeyInfo], + Field(description="A list of API key information", title="Keys"), + ] + + +class ModelAPIRateLimit(BaseModel): + type: Annotated[ + Literal[ + "REQUEST", + "TOKEN", + "CONCURRENT_REQUEST", + "UNCACHED_INPUT_TOKEN", + "OUTPUT_TOKEN", + ] + | str, + Field( + description="The type of the rate limit", + examples=["TOKEN", "REQUEST"], + title="LimitTypeV1", + ), + ] + unit: Annotated[ + Literal["SECOND", "MINUTE"] | str, + Field( + description="The unit of the rate limit", + examples=["SECOND", "MINUTE"], + title="RateLimitUnitV1", + ), + ] + threshold: Annotated[ + int, + Field( + description="The threshold for the rate limit", + examples=[1000, 50000], + ge=0, + title="Threshold", + ), + ] + is_pooled: Annotated[ + bool, + Field( + description="Whether this limit uses the organization-wide pool. The threshold is the effective limit, including any adaptive grant.", + title="Is Pooled", + ), + ] + service_tier: Annotated[ + Literal["DEFAULT", "FLEX", "PRIORITY"] | str, + Field( + description="Service tier the rate limit applies to.", + examples=["DEFAULT", "FLEX"], + title="ModelAPIServiceTierV1", + ), + ] + baseline_threshold: Annotated[ + int, + Field( + description="Configured baseline threshold for the rate limit, before any adaptive increase. Equal to `threshold` when no adaptive increase is in effect.", + examples=[1000, 50000], + ge=0, + title="Baseline Threshold", ), - ] = None + ] + + +class ModelAPITeamDetails(BaseModel): + id: Annotated[ + str, Field(description="Organization Shared Endpoint ID.", title="Id") + ] + team_id: Annotated[ + str, Field(description="Team that has added this Model API.", title="Team Id") + ] team_name: Annotated[ - str | None, + str, Field( - description="The name of the team associated with the API key", + description="Name of the team that has added this Model API.", title="Team Name", ), - ] = None - created_at: Annotated[ + ] + added_at: Annotated[ AwareDatetime, - Field(description="Creation time in ISO 8601 format", title="Created At"), + Field( + description="When the team first added this Model API.", title="Added At" + ), ] last_used_at: Annotated[ AwareDatetime | None, Field( - description="Last recorded use in ISO 8601 format, or null if unavailable. Updates may be delayed.", + description="When the team last invoked this Model API. Null if never invoked.", title="Last Used At", ), - ] = None - owner: Annotated[ - APIKeyOwner | None, + ] + rate_limits: Annotated[ + list[ModelAPIRateLimit], Field( - description="The user who owns the API key. Only present for personal API keys." + description="Effective rate limits for this team's Model API, at most one per type, unit, and service tier.", + title="Rate Limits", + ), + ] + cost_per_million_input_tokens: Annotated[ + float | CostPerMillionInputTokens | None, + Field( + description="Effective cost per million input tokens, in dollars. Null if unavailable.", + 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 if unavailable.", + title="Cost Per Million Output Tokens", ), - ] = None - - -class APIKeys(BaseModel): - keys: Annotated[ - list[APIKeyInfo], - Field(description="A list of API key information", title="Keys"), ] @@ -13655,32 +14874,51 @@ class ModelAPI(BaseModel): ), ] cost_per_million_input_tokens: Annotated[ - float | CostPerMillionInputTokens | None, + float | CostPerMillionInputTokens1 | None, Field( - description="Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", + deprecated=True, + description="Deprecated and will be removed in a future version. Legacy effective input-token price. Use team_details pricing instead. Retained during migration; null when pricing is unavailable.", examples=["0.13"], title="Cost Per Million Input Tokens", ), ] + cost_per_million_cached_input_tokens: Annotated[ + float | CostPerMillionCachedInputTokens | None, + Field( + description="Effective cost per million cached input tokens, in dollars. Null when pricing is unavailable or the Model API has no cached input price.", + examples=["0.03"], + title="Cost Per Million Cached Input Tokens", + ), + ] cost_per_million_output_tokens: Annotated[ - float | CostPerMillionOutputTokens | None, + float | CostPerMillionOutputTokens1 | None, Field( - description="Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", + deprecated=True, + description="Deprecated and will be removed in a future version. Legacy effective output-token price. Use team_details pricing instead. Retained during migration; null when pricing is unavailable.", examples=["0.50"], title="Cost Per Million Output Tokens", ), ] rate_limits: Annotated[ - list[RateLimit], + list[ModelAPIRateLimit], 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.", + deprecated=True, + description="Deprecated and will be removed in a future version. Legacy Default Team effective limits, independent of team_ids, or catalog defaults when not added or unauthorized. Use team_details for team limits; this field is not the org-pool limit view.", title="Rate Limits", ), ] org_details: Annotated[ ModelAPIOrgDetails | None, Field( - description="Workspace-specific state. Null when the workspace has not added this Model API." + deprecated=True, + description="Deprecated and will be removed in a future version. Legacy Default Team state, independent of team_ids. Use team_details instead. Null when not added or unauthorized.", + ), + ] = None + team_details: Annotated[ + list[ModelAPITeamDetails] | None, + Field( + description="Added Model API details for authorized teams, ordered by team ID. Empty when no team in the selected scope has added this Model API.", + title="Team Details", ), ] = None @@ -13734,6 +14972,13 @@ class CreateLLMModelRequest(BaseModel): dict[str, Any], Field(description="Resources allocated to the model", title="Resources"), ] + deployment_name: Annotated[ + str | None, + Field( + description="Name of the deployment, unique within the model. Use only A-Z, a-z, 0-9, '-', '_', and '.'. The name 'development' is reserved. If omitted or empty, a name is generated automatically.", + title="Deployment Name", + ), + ] = None region: Annotated[ str | None, Field(description="Region in which to deploy the model", title="Region"), @@ -13811,6 +15056,13 @@ class CreateLLMModelRequest(BaseModel): title="Weights", ), ] = None + bdn: Annotated[ + dict[str, Any] | None, + Field( + description="BDN configuration for read-only sealed volume mounts; supports mounts only", + title="Bdn", + ), + ] = None egress_restrictions: Annotated[ EgressRestrictions | None, Field( @@ -13828,6 +15080,13 @@ class CreateLLMModelVersionRequest(BaseModel): dict[str, Any], Field(description="Resources allocated to the model", title="Resources"), ] + deployment_name: Annotated[ + str | None, + Field( + description="Name of the deployment, unique within the model. Use only A-Z, a-z, 0-9, '-', '_', and '.'. The name 'development' is reserved. If omitted or empty, a name is generated automatically.", + title="Deployment Name", + ), + ] = None region: Annotated[ str | None, Field(description="Region in which to deploy the model", title="Region"), @@ -13905,6 +15164,13 @@ class CreateLLMModelVersionRequest(BaseModel): title="Weights", ), ] = None + bdn: Annotated[ + dict[str, Any] | None, + Field( + description="BDN configuration for read-only sealed volume mounts; supports mounts only", + title="Bdn", + ), + ] = None egress_restrictions: Annotated[ EgressRestrictions | None, Field( @@ -14025,6 +15291,7 @@ class BillableResource(BaseModel): ] kind: Annotated[ Literal[ + "LOOPS_RUN", "LOOPS_SAMPLER", "LOOPS_TRAINER", "MODEL_DEPLOYMENT", @@ -14033,7 +15300,7 @@ class BillableResource(BaseModel): ] | str, Field( - description="Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, or LOOPS_SAMPLER)", + description="Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, LOOPS_SAMPLER, or LOOPS_RUN)", title="ResourceKind", ), ] @@ -14066,7 +15333,7 @@ class BillableResource(BaseModel): base_model: Annotated[ str | None, Field( - description="Base model used by this Loops trainer or sampler", + description="Base model used by this Loops run, trainer, or sampler", title="Base Model", ), ] = None @@ -14097,12 +15364,35 @@ class BillableResource(BaseModel): ] = None +class DailyLoopsUsage(BaseModel): + subtotal: Annotated[ + float | Subtotal1, + Field(description="Cost in dollars across all four meters", title="Subtotal"), + ] + uncached_prefill: Annotated[ + LoopsMeterUsage, Field(description="Prompt tokens that missed the prefix cache") + ] + cached_prefill: Annotated[ + LoopsMeterUsage, Field(description="Prompt tokens served from the prefix cache") + ] + sample: Annotated[ + LoopsMeterUsage, Field(description="Tokens generated by sampling") + ] + train: Annotated[ + LoopsMeterUsage, + Field( + description="Tokens processed by forward and forward-backward training calls" + ), + ] + date: Annotated[date_aliased, Field(description="Date of the usage", title="Date")] + + class DedicatedItem(BaseModel): billable_resource: Annotated[ BillableResource, Field(description="The model deployment resource") ] subtotal: Annotated[ - float | Subtotal3, + float | Subtotal4, Field( description="Subtotal cost in dollars for this billable resource", title="Subtotal", @@ -14143,7 +15433,7 @@ class DedicatedItem(BaseModel): class DedicatedUsage(BaseModel): subtotal: Annotated[ - float | Subtotal4, + float | Subtotal5, Field( description="Subtotal cost in dollars after applying credits used", title="Subtotal", @@ -14163,12 +15453,44 @@ class DedicatedUsage(BaseModel): ] = None +class LoopsResourceItem(BaseModel): + subtotal: Annotated[ + float | Subtotal8, + Field(description="Cost in dollars across all four meters", title="Subtotal"), + ] + uncached_prefill: Annotated[ + LoopsMeterUsage, Field(description="Prompt tokens that missed the prefix cache") + ] + cached_prefill: Annotated[ + LoopsMeterUsage, Field(description="Prompt tokens served from the prefix cache") + ] + sample: Annotated[ + LoopsMeterUsage, Field(description="Tokens generated by sampling") + ] + train: Annotated[ + LoopsMeterUsage, + Field( + description="Tokens processed by forward and forward-backward training calls" + ), + ] + billable_resource: Annotated[ + BillableResource, + Field( + description="The Loops run (LOOPS_RUN) or standalone sampler (LOOPS_SAMPLER). A resource that no longer exists has only its ID and kind set." + ), + ] + daily: Annotated[ + list[DailyLoopsUsage] | None, + Field(description="Daily usage breakdown", title="Daily"), + ] = None + + class TrainingItem(BaseModel): billable_resource: Annotated[ BillableResource, Field(description="The training job resource") ] subtotal: Annotated[ - float | Subtotal7, + float | Subtotal12, Field( description="Subtotal cost in dollars for this billable resource", title="Subtotal", @@ -14188,7 +15510,7 @@ class TrainingItem(BaseModel): class TrainingUsage(BaseModel): subtotal: Annotated[ - float | Subtotal8, + float | Subtotal13, Field( description="Subtotal cost in dollars after applying credits used", title="Subtotal", @@ -14208,18 +15530,6 @@ class TrainingUsage(BaseModel): ] = 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, @@ -14361,7 +15671,8 @@ class GridRoute(BaseModel): Annotated[ GridRouteTargetBasetenModelAPI | GridRouteTargetConnection - | GridRouteTargetClassifier, + | GridRouteTargetClassifier + | GridRouteTargetIntelligent, Field( description="Configured upstream target.", discriminator="type", @@ -14436,71 +15747,6 @@ class GridHarnessModel(BaseModel): route: Annotated[GridRoute, Field(description="Route to use for this role.")] -class GridPrimaryHarnessDefaults(BaseModel): - primary: Annotated[ - GridHarnessModel | None, - Field( - description="Route for the primary model, which new sessions use. Null when the team has no route to use." - ), - ] - - -class UpdateGridHarnessDefaults(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - claude_code: Annotated[ - UpdateGridBackgroundHarnessModels | None, - Field( - description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." - ), - ] = None - opencode: Annotated[ - UpdateGridBackgroundHarnessModels | None, - Field( - description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." - ), - ] = None - codex: Annotated[ - UpdateGridPrimaryHarnessModels | None, - Field( - description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." - ), - ] = None - pi: Annotated[ - UpdateGridPrimaryHarnessModels | None, - Field( - description="Route IDs for the model roles to change; roles left out are unchanged. Every route must belong to the team. Pass null to clear every role, or omit to leave the harness unchanged." - ), - ] = None - - -class UpdateGridTeamSettingsRequest(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - harness_defaults: Annotated[ - UpdateGridHarnessDefaults | None, - Field( - description="Harnesses to change; harnesses left out are unchanged. Pass null to clear every harness, so each role uses the team's default." - ), - ] = None - spend_limit: Annotated[ - UpdateGridTeamSpendLimitSetting | None, - Field( - description="Spend limit fields to change. Pass null to remove the team's limits; omit to leave them unchanged." - ), - ] = None - team_id: Annotated[ - str | None, - Field( - description="ID of the team. When omitted, the team you belong to; required when you belong to several.", - examples=["abc1234"], - title="Team Id", - ), - ] = None - - class GridSpendLimitSetting(BaseModel): user_monthly_limit_usd: Annotated[ str | None, @@ -14610,7 +15856,11 @@ class EndpointTarget(BaseModel): "OPENAI_COMPATIBLE", ] | str, - Field(description="Upstream provider.", title="GatewayProvider"), + Field( + description="Upstream provider.", + examples=["ANTHROPIC", "OPENAI_COMPATIBLE"], + title="GatewayEndpointProviderV1", + ), ] secret_id: Annotated[ str | None, Field(description="Referenced secret, if any.", title="Secret Id") @@ -15035,7 +16285,7 @@ class DeploymentArchivePayload(BaseModel): autoscaling_settings: Annotated[ UpdateAutoscalingSettings | None, Field( - description="Autoscaling settings for the new deployment. With `environment_name`, the new deployment starts from the environment's settings with these changes applied, and the environment keeps the result when the promotion completes. Without it, they apply to the new deployment only.", + description="Autoscaling settings for the new deployment. The new deployment starts from the settings of the environment named by `environment_name` with these changes applied, and the environment keeps the result when the promotion completes. Requires `environment_name`.", examples=[{"max_replica": 4, "min_replica": 2}], ), ] = None @@ -15062,7 +16312,7 @@ class DeploymentArchivePayload(BaseModel): instance_type_id: Annotated[ str | None, Field( - description="Instance type for the new deployment, from `GET /v1/instance_types`, in place of the one in `config`. With `environment_name`, the environment takes it when the promotion completes. Without it, it applies to the new deployment only. Cannot be set with `preserve_env_instance_type: true`.", + description="Instance type for the new deployment, from `GET /v1/instance_types`, in place of the one in `config`. The environment named by `environment_name` takes it when the promotion completes. Requires `environment_name`. Cannot be set with `preserve_env_instance_type: true`.", title="Instance Type Id", ), ] = None @@ -15142,12 +16392,16 @@ class AuditLogEntry(BaseModel): "SECRET_DELETED", "API_KEY_CREATED", "API_KEY_DELETED", + "API_KEY_LIFETIME_LIMITS_UPDATED", "GATEWAY_ENDPOINT_CREATED", "GATEWAY_ENDPOINT_UPDATED", "GATEWAY_ENDPOINT_DELETED", "PROVIDER_CONNECTION_CREATED", "PROVIDER_CONNECTION_UPDATED", "PROVIDER_CONNECTION_DELETED", + "GRID_MACHINE_USER_CREATED", + "GRID_MACHINE_USER_UPDATED", + "GRID_MACHINE_USER_DELETED", "USER_INVITED", "USER_JOINED_ORGANIZATION", "WEBHOOK_SIGNING_SECRET_CREATED", @@ -15206,12 +16460,16 @@ class AuditLogEntry(BaseModel): | AuditLogEventSecretDeleted | AuditLogEventApiKeyCreated | AuditLogEventApiKeyDeleted + | AuditLogEventApiKeyLifetimeLimitsUpdated | AuditLogEventGatewayEndpointCreated | AuditLogEventGatewayEndpointUpdated | AuditLogEventGatewayEndpointDeleted | AuditLogEventProviderConnectionCreated | AuditLogEventProviderConnectionUpdated | AuditLogEventProviderConnectionDeleted + | AuditLogEventGridMachineUserCreated + | AuditLogEventGridMachineUserUpdated + | AuditLogEventGridMachineUserDeleted | AuditLogEventUserInvited | AuditLogEventUserJoinedOrganization | AuditLogEventWebhookSigningSecretCreated @@ -15641,6 +16899,78 @@ class GetLoopsDeploymentMetricsResponse(BaseModel): ] +class LoopsBaseModelItem(BaseModel): + subtotal: Annotated[ + float | Subtotal6, + Field(description="Cost in dollars across all four meters", title="Subtotal"), + ] + uncached_prefill: Annotated[ + LoopsMeterUsage, Field(description="Prompt tokens that missed the prefix cache") + ] + cached_prefill: Annotated[ + LoopsMeterUsage, Field(description="Prompt tokens served from the prefix cache") + ] + sample: Annotated[ + LoopsMeterUsage, Field(description="Tokens generated by sampling") + ] + train: Annotated[ + LoopsMeterUsage, + Field( + description="Tokens processed by forward and forward-backward training calls" + ), + ] + base_model: Annotated[ + str, Field(description="Base model the usage is priced by", title="Base Model") + ] + daily: Annotated[ + list[DailyLoopsUsage] | None, + Field(description="Daily usage breakdown", title="Daily"), + ] = None + breakdown: Annotated[ + list[LoopsResourceItem] | None, + Field( + description="Usage per run and standalone sampler on this base model", + title="Breakdown", + ), + ] = None + + +class LoopsUsage(BaseModel): + subtotal: Annotated[ + float | Subtotal9, + Field(description="Cost in dollars before credits", 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") + ] + breakdown: Annotated[ + list[LoopsBaseModelItem] | None, + Field(description="Per-base-model 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 + loops_usage: Annotated[ + LoopsUsage | None, + Field( + description="Serverless Loops usage, billed per token. Loops usage on dedicated trainers and samplers is billed by the minute and is part of training usage." + ), + ] = None + + class GridBackgroundHarnessDefaults(BaseModel): primary: Annotated[ GridHarnessModel | None, @@ -15665,10 +16995,10 @@ class GridHarnessDefaults(BaseModel): GridBackgroundHarnessDefaults, Field(description="Default models for OpenCode.") ] codex: Annotated[ - GridPrimaryHarnessDefaults, Field(description="Default models for Codex.") + GridBackgroundHarnessDefaults, Field(description="Default models for Codex.") ] pi: Annotated[ - GridPrimaryHarnessDefaults, Field(description="Default models for Pi.") + GridBackgroundHarnessDefaults, Field(description="Default models for Pi.") ] @@ -15901,12 +17231,21 @@ class SandboxConfiguration(BaseModel): memory: Annotated[ int | None, Field( - description="Memory allocation in megabytes. Also determines CPU allocation (CPU cores = memory in MB / 2048, e.g., 4096MB = 2 CPUs). Must be between 1024 and 262144.", + description="Memory allocation in megabytes. Must be between 1024 and 262144. When cpu is not set at creation, memory also determines the CPU allocation (by default 2048 MB = 1 vCPU, 4096 MB = 2, 8192 MB = 4, 16384 MB = 6, 32768 MB = 8, 65536 MB = 16, 131072 MB or more = 32).", examples=[4096], ge=512, le=262144, ), ] = None + cpu: Annotated[ + int | None, + Field( + description="Number of vCPUs the sandbox runs with. Always returned, including for sandboxes created without cpu, whose CPU allocation was derived from memory. Set at creation only.", + examples=[2], + ge=1, + le=32, + ), + ] = None filesystem: Annotated[ SandboxFilesystem | None, Field( @@ -16043,14 +17382,23 @@ class CreateSandboxRequest(BaseModel): ), ] = "baseten/base-image:latest" memory: Annotated[ - int, + int | None, Field( - description="Memory allocation in megabytes. Also determines CPU allocation (CPU cores = memory in MB / 2048, e.g., 4096MB = 2 CPUs). Defaults to 4096. Must be between 1024 and 262144.", + description="Memory allocation in megabytes. Must be between 1024 and 262144. Defaults to 4096, or to 8192 MB per vCPU (a 1:8 ratio) when only cpu is set, capped at the account's memory quota. When cpu is omitted, memory also determines the CPU allocation (by default 2048 MB = 1 vCPU, 4096 MB = 2, 8192 MB = 4, 16384 MB = 6, 32768 MB = 8, 65536 MB = 16, 131072 MB or more = 32).", examples=[4096], ge=512, le=262144, ), - ] = 4096 + ] = None + cpu: Annotated[ + int | None, + Field( + description="Optional number of vCPUs, a whole number between 1 and 32. When omitted, the CPU allocation is derived from memory. When set, memory must be between 1024 and 8192 megabytes per vCPU (a ratio from 1:1 to 1:8), and cpu must not exceed the account's per-sandbox cpu quota. A value equal to the allocation memory alone would give is always accepted. When memory is omitted, it defaults to 8192 MB per vCPU, capped at the account's memory quota. Immutable after creation.", + examples=[2], + ge=1, + le=32, + ), + ] = None filesystem: Annotated[ SandboxFilesystem | None, Field( @@ -16289,6 +17637,7 @@ class ListSandboxesResponse(BaseModel): ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [{"name": "http", "protocol": "HTTP", "target": 3000}], "external_id": "api-review-20260916-001", "labels": { diff --git a/baseten/client/sandboxapi/__init__.py b/baseten/client/sandboxapi/__init__.py index 92b1685..06275bb 100644 --- a/baseten/client/sandboxapi/__init__.py +++ b/baseten/client/sandboxapi/__init__.py @@ -18,6 +18,8 @@ ArchiveManifest, ContentSearchMatch, ContentSearchResponse, + CopyRequest, + CopyResponse, DeleteFilesystemParams, DeleteFilesystemTreeParams, DeleteNetworkProcessMonitorResponse, @@ -49,6 +51,7 @@ GetFilesystemTreeParams, GetNetworkProcessPortsResponse, GetProcessResponse, + GetProcessWaitParams, GetWatchFilesystemParams, HandlerReloadResponse, HealthResponse, @@ -87,6 +90,8 @@ "AsyncApiClient", "ContentSearchMatch", "ContentSearchResponse", + "CopyRequest", + "CopyResponse", "DeleteFilesystemParams", "DeleteFilesystemTreeParams", "DeleteNetworkProcessMonitorResponse", @@ -118,6 +123,7 @@ "GetFilesystemTreeParams", "GetNetworkProcessPortsResponse", "GetProcessResponse", + "GetProcessWaitParams", "GetWatchFilesystemParams", "HandlerReloadResponse", "HealthResponse", diff --git a/baseten/client/sandboxapi/_client.py b/baseten/client/sandboxapi/_client.py index 2e2f049..9b60fed 100644 --- a/baseten/client/sandboxapi/_client.py +++ b/baseten/client/sandboxapi/_client.py @@ -15,6 +15,8 @@ ApplyEditRequest, ApplyEditResponse, ContentSearchResponse, + CopyRequest, + CopyResponse, DeleteFilesystemParams, DeleteFilesystemTreeParams, DeleteNetworkProcessMonitorResponse, @@ -39,6 +41,7 @@ GetFilesystemTreeParams, GetNetworkProcessPortsResponse, GetProcessResponse, + GetProcessWaitParams, GetWatchFilesystemParams, HandlerReloadResponse, HealthResponse, @@ -628,6 +631,23 @@ def get_process_logs_stream( ) ) + def get_process_wait( + self, *, identifier: str, params: GetProcessWaitParams | None = None + ) -> ProcessResponse: + """Wait for a process to finish""" + return self._do_json( + ProcessResponse, + _ApiRequest( + method="GET", + path_fmt="/process/{}/wait", + path_args=[identifier], + body=None, + query=params, + success_codes=[200], + error_codes={400: "ErrorResponse", 404: "ErrorResponse"}, + ), + ) + def get_watch_filesystem( self, *, path: str, params: GetWatchFilesystemParams | None = None ) -> httpx.Response: @@ -731,6 +751,25 @@ def post_environment_reload(self) -> HandlerReloadResponse: ), ) + def post_filesystem_copy(self, *, request: CopyRequest) -> CopyResponse: + """Copy a file or directory""" + return self._do_json( + CopyResponse, + _ApiRequest( + method="POST", + path_fmt="/filesystem-copy", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 409: "ErrorResponse", + 422: "ErrorResponse", + }, + ), + ) + def post_filesystem_multipart_complete( self, *, upload_id: str, request: MultipartCompleteRequest ) -> SuccessResponse: @@ -868,7 +907,7 @@ def post_upgrade(self, *, request: UpgradeRequest) -> SuccessResponse: body=request, query=None, success_codes=[200], - error_codes={500: "ErrorResponse"}, + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, ), ) @@ -1632,6 +1671,23 @@ async def get_process_logs_stream( ) ) + async def get_process_wait( + self, *, identifier: str, params: GetProcessWaitParams | None = None + ) -> ProcessResponse: + """Wait for a process to finish""" + return await self._do_json( + ProcessResponse, + _ApiRequest( + method="GET", + path_fmt="/process/{}/wait", + path_args=[identifier], + body=None, + query=params, + success_codes=[200], + error_codes={400: "ErrorResponse", 404: "ErrorResponse"}, + ), + ) + async def get_watch_filesystem( self, *, path: str, params: GetWatchFilesystemParams | None = None ) -> httpx.Response: @@ -1737,6 +1793,25 @@ async def post_environment_reload(self) -> HandlerReloadResponse: ), ) + async def post_filesystem_copy(self, *, request: CopyRequest) -> CopyResponse: + """Copy a file or directory""" + return await self._do_json( + CopyResponse, + _ApiRequest( + method="POST", + path_fmt="/filesystem-copy", + path_args=[], + body=request, + query=None, + success_codes=[200], + error_codes={ + 400: "ErrorResponse", + 409: "ErrorResponse", + 422: "ErrorResponse", + }, + ), + ) + async def post_filesystem_multipart_complete( self, *, upload_id: str, request: MultipartCompleteRequest ) -> SuccessResponse: @@ -1874,7 +1949,7 @@ async def post_upgrade(self, *, request: UpgradeRequest) -> SuccessResponse: body=request, query=None, success_codes=[200], - error_codes={500: "ErrorResponse"}, + error_codes={400: "ErrorResponse", 500: "ErrorResponse"}, ), ) diff --git a/baseten/client/sandboxapi/_models.py b/baseten/client/sandboxapi/_models.py index 5b631b6..c9b0ffa 100644 --- a/baseten/client/sandboxapi/_models.py +++ b/baseten/client/sandboxapi/_models.py @@ -114,6 +114,18 @@ class ContentSearchResponse(BaseModel): total: Annotated[int, Field(examples=[5])] +class CopyRequest(BaseModel): + destination: Annotated[str, Field(examples=["/app/destination"])] + noOverwrite: Annotated[bool, Field(examples=[False])] = False + source: Annotated[str, Field(examples=["/app/source"])] + + +class CopyResponse(BaseModel): + destination: str + message: str + source: str + + class DriveMountInfo(BaseModel): driveName: str | None = None drivePath: str | None = None @@ -168,6 +180,7 @@ class DriveUnmountResponse(BaseModel): class ErrorResponse(BaseModel): + code: Annotated[str | None, Field(examples=["FILE_ALREADY_EXISTS"])] = None error: Annotated[str, Field(examples=["Error message"])] @@ -302,6 +315,20 @@ class ProcessLogs(BaseModel): class ProcessRequest(BaseModel): + callbackSecret: Annotated[ + str | None, + Field( + description="Key the webhook is signed with (HMAC-SHA256, X-Blaxel-Signature header). At least 32 characters; required with callbackUrl. Never returned by the API.", + examples=["a-random-secret-of-at-least-32-chars"], + ), + ] = None + callbackUrl: Annotated[ + str | None, + Field( + description="URL that receives a signed process.exited webhook when the process ends for good (not on auto-restart). Requires callbackSecret.", + examples=["https://example.com/hooks/process"], + ), + ] = None command: Annotated[str, Field(examples=["ls -la"])] env: Annotated[dict[str, str] | None, Field(examples=[{'{"PORT"': ' "3000"}'}])] = ( None @@ -431,15 +458,12 @@ class TunnelConfigRequest(BaseModel): class UpgradeRequest(BaseModel): baseUrl: Annotated[ str | None, - Field( - description="Base URL for releases (useful for forks)", - examples=["https://github.com/blaxel-ai/sandbox/releases"], - ), + Field(description="Deprecated: custom binary sources are not accepted"), ] = None version: Annotated[ str | None, Field( - description='Version to upgrade to: "latest" (default), "develop", "main", or specific tag like "v1.0.0"', + description='Version to upgrade to: "latest" (default), "develop", "main", or a release tag like "v1.0.0"', examples=["latest"], ), ] = None @@ -609,6 +633,15 @@ class GetFilesystemTreeParams(BaseModel): ] = None +class GetProcessWaitParams(BaseModel): + timeout: Annotated[ + int | None, + Field( + description="Seconds to wait (default and max 119; larger values are capped)" + ), + ] = None + + class GetWatchFilesystemParams(BaseModel): ignore: Annotated[ str | None, diff --git a/baseten/sandbox/_client.py b/baseten/sandbox/_client.py index abb7b90..e8cfc0f 100644 --- a/baseten/sandbox/_client.py +++ b/baseten/sandbox/_client.py @@ -296,6 +296,7 @@ def create( create_if_not_exists: bool | None = None, image: str | None = None, memory: int | None = None, + cpu: int | None = None, region: str | None = None, envs: Mapping[str, SandboxEnvValue] | None = None, labels: Mapping[str, str] | None = None, @@ -317,8 +318,11 @@ def create( preserved. image: Image reference including its tag. Defaults to ``baseten/base-image:latest``. - memory: Memory in megabytes, which also sets the CPU allocation. - Defaults to 4096. + memory: Memory in megabytes. Defaults to 4096, or to 8192 per vCPU + when only *cpu* is set. When *cpu* is ``None``, it also sets + the CPU allocation. + cpu: Number of vCPUs, from 1 to 32. ``None`` derives the CPU + allocation from *memory*. region: Region to run in. ``None`` picks the closest one. envs: Environment variables, by name. labels: Labels, by key. @@ -344,6 +348,7 @@ def create( create_if_not_exists=create_if_not_exists, image=image, memory=memory, + cpu=cpu, region=region, envs=None if envs is None else envs_to_api(envs), labels=None if labels is None else dict(labels), @@ -700,6 +705,7 @@ async def create( create_if_not_exists: bool | None = None, image: str | None = None, memory: int | None = None, + cpu: int | None = None, region: str | None = None, envs: Mapping[str, SandboxEnvValue] | None = None, labels: Mapping[str, str] | None = None, @@ -722,6 +728,7 @@ async def create( create_if_not_exists=create_if_not_exists, image=image, memory=memory, + cpu=cpu, region=region, envs=None if envs is None else envs_to_api(envs), labels=None if labels is None else dict(labels), diff --git a/baseten/sandbox/_errors.py b/baseten/sandbox/_errors.py index b641dd5..f692871 100644 --- a/baseten/sandbox/_errors.py +++ b/baseten/sandbox/_errors.py @@ -218,7 +218,7 @@ def api_error_from( """Convert an error a generated client raised for an error response.""" body: Any if isinstance(err, baseten.client.sandboxapi.ResponseErrorResponse): - body = err.error_response.model_dump(mode="json") + body = err.error_response.model_dump(mode="json", exclude_unset=True) else: try: body = json.loads(err.body) diff --git a/baseten/sandbox/_info.py b/baseten/sandbox/_info.py index 4171adb..6c62acf 100644 --- a/baseten/sandbox/_info.py +++ b/baseten/sandbox/_info.py @@ -247,7 +247,10 @@ class SandboxInfo: """Image reference, including its tag.""" memory: int | None - """Memory in megabytes, which also sets the CPU allocation.""" + """Memory in megabytes.""" + + cpu: int | None + """Number of vCPUs the sandbox runs with.""" region: str | None @@ -296,6 +299,7 @@ def sandbox_info_from_api(sandbox: baseten.client.managementapi.Sandbox) -> Sand status=sandbox.status, image=sandbox.image, memory=sandbox.memory, + cpu=sandbox.cpu, region=sandbox.region, envs=_envs_from_api(sandbox.envs), labels=dict(sandbox.labels or {}), diff --git a/scripts/apigen/specs/management.json b/scripts/apigen/specs/management.json index 8972135..540f7d5 100644 --- a/scripts/apigen/specs/management.json +++ b/scripts/apigen/specs/management.json @@ -3485,7 +3485,7 @@ "required": false, "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.", "schema": { - "$ref": "#/components/schemas/ModelMetricModeV1", + "$ref": "#/components/schemas/MetricModeV1", "default": "CURRENT" } }, @@ -3545,7 +3545,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetModelMetricsResponseV1" + "$ref": "#/components/schemas/GetMetricsResponseV1" } } } @@ -4336,7 +4336,7 @@ "required": false, "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.", "schema": { - "$ref": "#/components/schemas/ModelMetricModeV1", + "$ref": "#/components/schemas/MetricModeV1", "default": "CURRENT" } }, @@ -4396,7 +4396,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetModelMetricsResponseV1" + "$ref": "#/components/schemas/GetMetricsResponseV1" } } } @@ -5920,11 +5920,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/training_projects \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"training_project\": {\n \"name\": \"My Training Project\"\n }\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/training_projects \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"training_project\": {\n \"name\": \"My Training Project\",\n \"project_accelerator\": \"H100\"\n }\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}/training_projects\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'training_project': {'name': 'My Training Project'}}\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}/training_projects\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'training_project': {'name': 'My Training Project', 'project_accelerator': 'H100'}}\n)\n\nprint(response.text)" } ], "description": "Upserts a training project with the specified metadata for a team.", @@ -5967,10 +5967,68 @@ }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_projects\"\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/training_projects\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'name': None, 'cursor': None, 'limit': None}\n)\n\nprint(response.text)" + } + ], + "description": "Lists the organization's training projects, newest first.", + "parameters": [ + { + "name": "name", + "in": "query", + "required": false, + "description": "Return only the project with this exact name.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "description": "Opaque cursor from the pagination.cursor field of a previous response. Omit both cursor and limit to get every project in one response.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cursor" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "description": "Maximum number of projects to return, up to 1000.", + "schema": { + "anyOf": [ + { + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Limit" + } } ], - "description": "Lists all training projects for the organization.", "responses": { "200": { "description": "", @@ -5989,11 +6047,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/training_projects \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"training_project\": {\n \"name\": \"My Training Project\"\n }\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/training_projects \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"training_project\": {\n \"name\": \"My Training Project\",\n \"project_accelerator\": \"H100\"\n }\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_projects\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'training_project': {'name': 'My Training Project'}}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_projects\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'training_project': {'name': 'My Training Project', 'project_accelerator': 'H100'}}\n)\n\nprint(response.text)" } ], "description": "Upserts a training project with the specified metadata.", @@ -6058,11 +6116,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/training_projects/{training_project_id}/jobs \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"training_job\": {\n \"image\": {\n \"base_image\": \"hello-world\",\n \"docker_auth\": null\n },\n \"compute\": {\n \"node_count\": 1,\n \"cpu_count\": 1,\n \"memory\": \"2Gi\",\n \"accelerator\": {\n \"accelerator\": \"H100\",\n \"count\": 2\n },\n \"availability_model\": \"spot\"\n },\n \"runtime\": {\n \"start_commands\": [\n \"python main.py\"\n ],\n \"environment_variables\": {\n \"API_KEY\": \"your_api_key_here\",\n \"PATH\": \"/usr/bin\"\n },\n \"enable_cache\": true,\n \"cache_config\": {\n \"enable_legacy_hf_mount\": true,\n \"enabled\": true,\n \"mount_base_path\": \"/root/.cache\",\n \"require_cache_affinity\": true\n },\n \"checkpointing_config\": {\n \"enabled\": true,\n \"checkpoint_path\": \"/mnt/ckpts\",\n \"volume_size_gib\": 10\n },\n \"load_checkpoint_config\": null\n },\n \"name\": \"gpt-oss-job\",\n \"truss_user_env\": null,\n \"interactive_session\": null,\n \"weights\": [\n {\n \"allow_patterns\": null,\n \"auth\": null,\n \"auth_secret_name\": null,\n \"ignore_patterns\": null,\n \"mount_location\": \"/app/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B@main\"\n }\n ],\n \"enable_baseten_workdir\": false,\n \"priority\": 0\n }\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/training_projects/{training_project_id}/jobs \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"training_job\": {\n \"image\": {\n \"base_image\": \"hello-world\",\n \"docker_auth\": null\n },\n \"compute\": {\n \"node_count\": 1,\n \"cpu_count\": 1,\n \"memory\": \"2Gi\",\n \"accelerator\": {\n \"accelerator\": \"H100\",\n \"count\": 2\n },\n \"availability_model\": \"spot\"\n },\n \"runtime\": {\n \"start_commands\": [\n \"python main.py\"\n ],\n \"environment_variables\": {\n \"API_KEY\": \"your_api_key_here\",\n \"PATH\": \"/usr/bin\"\n },\n \"enable_cache\": true,\n \"cache_config\": {\n \"enable_legacy_hf_mount\": true,\n \"enabled\": true,\n \"mount_base_path\": \"/root/.cache\",\n \"persistent_home\": false,\n \"require_cache_affinity\": true\n },\n \"checkpointing_config\": {\n \"enabled\": true,\n \"checkpoint_path\": \"/mnt/ckpts\",\n \"volume_size_gib\": 10\n },\n \"load_checkpoint_config\": null\n },\n \"name\": \"gpt-oss-job\",\n \"truss_user_env\": null,\n \"interactive_session\": null,\n \"weights\": [\n {\n \"allow_patterns\": null,\n \"auth\": null,\n \"auth_secret_name\": null,\n \"ignore_patterns\": null,\n \"mount_location\": \"/app/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B@main\"\n }\n ],\n \"enable_baseten_workdir\": false,\n \"priority\": 0\n }\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_projects/{training_project_id}/jobs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'training_job': {'image': {'base_image': 'hello-world', 'docker_auth': None}, 'compute': {'node_count': 1, 'cpu_count': 1, 'memory': '2Gi', 'accelerator': {'accelerator': 'H100', 'count': 2}, 'availability_model': 'spot'}, 'runtime': {'start_commands': ['python main.py'], 'environment_variables': {'API_KEY': 'your_api_key_here', 'PATH': '/usr/bin'}, 'enable_cache': True, 'cache_config': {'enable_legacy_hf_mount': True, 'enabled': True, 'mount_base_path': '/root/.cache', 'require_cache_affinity': True}, 'checkpointing_config': {'enabled': True, 'checkpoint_path': '/mnt/ckpts', 'volume_size_gib': 10}, 'load_checkpoint_config': None}, 'name': 'gpt-oss-job', 'truss_user_env': None, 'interactive_session': None, 'weights': [{'allow_patterns': None, 'auth': None, 'auth_secret_name': None, 'ignore_patterns': None, 'mount_location': '/app/models/base', 'source': 'hf://meta-llama/Llama-3-8B@main'}], 'enable_baseten_workdir': False, 'priority': 0}}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_projects/{training_project_id}/jobs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'training_job': {'image': {'base_image': 'hello-world', 'docker_auth': None}, 'compute': {'node_count': 1, 'cpu_count': 1, 'memory': '2Gi', 'accelerator': {'accelerator': 'H100', 'count': 2}, 'availability_model': 'spot'}, 'runtime': {'start_commands': ['python main.py'], 'environment_variables': {'API_KEY': 'your_api_key_here', 'PATH': '/usr/bin'}, 'enable_cache': True, 'cache_config': {'enable_legacy_hf_mount': True, 'enabled': True, 'mount_base_path': '/root/.cache', 'persistent_home': False, 'require_cache_affinity': True}, 'checkpointing_config': {'enabled': True, 'checkpoint_path': '/mnt/ckpts', 'volume_size_gib': 10}, 'load_checkpoint_config': None}, 'name': 'gpt-oss-job', 'truss_user_env': None, 'interactive_session': None, 'weights': [{'allow_patterns': None, 'auth': None, 'auth_secret_name': None, 'ignore_patterns': None, 'mount_location': '/app/models/base', 'source': 'hf://meta-llama/Llama-3-8B@main'}], 'enable_baseten_workdir': False, 'priority': 0}}\n)\n\nprint(response.text)" } ], "description": "Creates a training job with the specified configuration.", @@ -6163,7 +6221,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_projects/{training_project_id}/jobs/{training_job_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'priority': 0, 'availability_model': 'spot'}\n)\n\nprint(response.text)" } ], - "description": "Updates mutable fields on a PENDING training job: the queue priority (higher priorities are dequeued first) and the availability model (dedicated or spot capacity). Changes take effect on the next queue evaluation, which is triggered immediately.", + "description": "Updates mutable fields on a PENDING training job: the queue priority (higher priorities are dequeued first) and the availability model (standard or spot capacity). Changes take effect on the next queue evaluation, which is triggered immediately.", "requestBody": { "content": { "application/json": { @@ -6929,14 +6987,14 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/training_jobs/search \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"project_id\": \"n4q95w5\",\n \"job_id\": \"p7qr9qv\",\n \"statuses\": [\n \"TRAINING_JOB_RUNNING\",\n \"TRAINING_JOB_COMPLETED\"\n ]\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/training_jobs/search \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"cursor\": null,\n \"project_id\": \"n4q95w5\",\n \"job_id\": \"p7qr9qv\",\n \"statuses\": [\n \"TRAINING_JOB_RUNNING\",\n \"TRAINING_JOB_COMPLETED\"\n ]\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_jobs/search\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'project_id': 'n4q95w5', 'job_id': 'p7qr9qv', 'statuses': ['TRAINING_JOB_RUNNING', 'TRAINING_JOB_COMPLETED']}\n)\n\nprint(response.text)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/training_jobs/search\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'cursor': None, 'project_id': 'n4q95w5', 'job_id': 'p7qr9qv', 'statuses': ['TRAINING_JOB_RUNNING', 'TRAINING_JOB_COMPLETED']}\n)\n\nprint(response.text)" } ], - "description": "Searches training jobs for the organization.", + "description": "Searches training jobs for the organization. Send the same filters with every page.", "requestBody": { "content": { "application/json": { @@ -6971,16 +7029,16 @@ }, { "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 params={'model': 'Qwen/Qwen3-8B', 'use_case': 'rl', 'max_seq_len': 32768}\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, 'enabled': True}\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. 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.", + "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. Models this workspace can run come first. Capacity is resolved when the run is created, not here. Pass ?enabled=true for only the models you can use. Pass ?model= to ask about one model \u2014 without ?enabled=, 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.", + "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'. Without 'enabled', an empty list means Baseten does not support that model. Omit to list every supported model.", "schema": { "anyOf": [ { @@ -7031,6 +7089,27 @@ ], "title": "Max Seq Len" } + }, + { + "name": "enabled", + "in": "query", + "required": false, + "description": "Pass true to list only the models this workspace can run now, or false for only the ones it cannot. Omit to list both. With 'model', an empty list can also mean the model is supported but filtered out.", + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "examples": [ + true + ], + "title": "Enabled" + } } ], "responses": { @@ -7118,10 +7197,10 @@ }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/runs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'run_id': 'k4q95w5', 'base_model': 'Qwen/Qwen3-8B', 'scope': 'org'}\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/runs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'run_id': 'k4q95w5', 'base_model': 'Qwen/Qwen3-8B', 'session_id': 'k4q95w5', 'scope': 'org'}\n)\n\nprint(response.text)" } ], - "description": "Lists Loops runs visible to the requesting user, optionally filtered by run id and/or base model. Defaults to the caller's own runs; pass ?scope=org to list every run in the caller's organization.", + "description": "Lists Loops runs visible to the requesting user, optionally filtered by run id, base model, and/or session. Defaults to the caller's own runs; pass ?scope=org to list every run in the caller's organization.", "parameters": [ { "name": "run_id", @@ -7165,6 +7244,27 @@ "title": "Base Model" } }, + { + "name": "session_id", + "in": "query", + "required": false, + "description": "Filter runs by the session that created them. An unknown or inaccessible session returns an empty list.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "examples": [ + "k4q95w5" + ], + "title": "Session Id" + } + }, { "name": "scope", "in": "query", @@ -7309,11 +7409,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/trainers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"session_id\": null,\n \"base_model\": null,\n \"name\": null,\n \"max_seq_len\": null,\n \"seed\": null,\n \"availability_model\": \"spot\",\n \"path\": \"bt://loops:k4q95w5/weights/step-100\",\n \"reuse_from_run_id\": null,\n \"reuse_from_session_id\": null,\n \"base_checkpoint\": null\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/loops/trainers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"session_id\": null,\n \"base_model\": null,\n \"name\": null,\n \"max_seq_len\": null,\n \"seed\": null,\n \"availability_model\": \"spot\",\n \"path\": \"bt://loops:k4q95w5/weights/step-100\",\n \"reuse_from_run_id\": null,\n \"reuse_from_session_id\": null,\n \"base_checkpoint\": null,\n \"scope\": \"default\"\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/loops/trainers\"\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, 'name': None, 'max_seq_len': None, 'seed': None, 'availability_model': 'spot', 'path': 'bt://loops:k4q95w5/weights/step-100', 'reuse_from_run_id': None, 'reuse_from_session_id': None, 'base_checkpoint': 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/trainers\"\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, 'name': None, 'max_seq_len': None, 'seed': None, 'availability_model': 'spot', 'path': 'bt://loops:k4q95w5/weights/step-100', 'reuse_from_run_id': None, 'reuse_from_session_id': None, 'base_checkpoint': None, 'scope': 'default'}\n)\n\nprint(response.text)" } ], "description": "Creates a trainer-only Loops run in the given session, without a sampler. To sample from it, create a sampler with POST /v1/loops/samplers and pass this run's ID as run_id to pair the two. List and read the trainer through the /v1/loops/runs endpoints.", @@ -7351,11 +7451,32 @@ }, { "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 \"GET\",\n url,\n headers=headers,\n params={'scope': 'org'}\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 \"GET\",\n url,\n headers=headers,\n params={'session_id': 'k4q95w5', 'scope': 'org'}\n)\n\nprint(response.text)" } ], - "description": "Lists Loops samplers (paired and standalone). Defaults to the caller's own; pass ?scope=org to list every sampler in the caller's organization.", + "description": "Lists Loops samplers (paired and standalone), optionally filtered by session. Defaults to the caller's own; pass ?scope=org to list every sampler in the caller's organization.", "parameters": [ + { + "name": "session_id", + "in": "query", + "required": false, + "description": "Filter samplers by the session that created them. An unknown or inaccessible session returns an empty list.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "examples": [ + "k4q95w5" + ], + "title": "Session Id" + } + }, { "name": "scope", "in": "query", @@ -7396,11 +7517,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 \"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 \"num_replicas\": 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 \"num_replicas\": null,\n \"scope\": \"default\"\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={'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, 'num_replicas': 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, 'num_replicas': None, 'scope': 'default'}\n)\n\nprint(response.text)" } ], "description": "Creates a standalone Loops sampler not linked to a run.", @@ -8149,10 +8270,10 @@ }, { "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/runs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'run_id': 'k4q95w5', 'base_model': 'Qwen/Qwen3-8B', 'scope': 'org'}\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/runs\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'run_id': 'k4q95w5', 'base_model': 'Qwen/Qwen3-8B', 'session_id': 'k4q95w5', 'scope': 'org'}\n)\n\nprint(response.text)" } ], - "description": "Lists Loops runs in the given team, visible to the requesting user, optionally filtered by run id and/or base model.", + "description": "Lists Loops runs in the given team, visible to the requesting user, optionally filtered by run id, base model, and/or session.", "parameters": [ { "name": "run_id", @@ -8196,6 +8317,27 @@ "title": "Base Model" } }, + { + "name": "session_id", + "in": "query", + "required": false, + "description": "Filter runs by the session that created them. An unknown or inaccessible session returns an empty list.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "examples": [ + "k4q95w5" + ], + "title": "Session Id" + } + }, { "name": "scope", "in": "query", @@ -8279,11 +8421,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/loops/trainers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"session_id\": null,\n \"base_model\": null,\n \"name\": null,\n \"max_seq_len\": null,\n \"seed\": null,\n \"availability_model\": \"spot\",\n \"path\": \"bt://loops:k4q95w5/weights/step-100\",\n \"reuse_from_run_id\": null,\n \"reuse_from_session_id\": null,\n \"base_checkpoint\": null\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/loops/trainers \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"session_id\": null,\n \"base_model\": null,\n \"name\": null,\n \"max_seq_len\": null,\n \"seed\": null,\n \"availability_model\": \"spot\",\n \"path\": \"bt://loops:k4q95w5/weights/step-100\",\n \"reuse_from_run_id\": null,\n \"reuse_from_session_id\": null,\n \"base_checkpoint\": null,\n \"scope\": \"default\"\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/trainers\"\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, 'name': None, 'max_seq_len': None, 'seed': None, 'availability_model': 'spot', 'path': 'bt://loops:k4q95w5/weights/step-100', 'reuse_from_run_id': None, 'reuse_from_session_id': None, 'base_checkpoint': 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/trainers\"\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, 'name': None, 'max_seq_len': None, 'seed': None, 'availability_model': 'spot', 'path': 'bt://loops:k4q95w5/weights/step-100', 'reuse_from_run_id': None, 'reuse_from_session_id': None, 'base_checkpoint': None, 'scope': 'default'}\n)\n\nprint(response.text)" } ], "description": "Creates a trainer-only Loops run in the given session, without a sampler. To sample from it, create a sampler with POST /v1/loops/samplers and pass this run's ID as run_id to pair the two. List and read the trainer through the /v1/loops/runs endpoints.", @@ -8326,11 +8468,32 @@ }, { "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 \"GET\",\n url,\n headers=headers,\n params={'scope': 'org'}\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 \"GET\",\n url,\n headers=headers,\n params={'session_id': 'k4q95w5', 'scope': 'org'}\n)\n\nprint(response.text)" } ], - "description": "Lists Loops samplers (paired and standalone) in the given team, visible to the requesting user. Defaults to the caller's own; pass ?scope=org to list every sampler in the team.", + "description": "Lists Loops samplers (paired and standalone) in the given team, visible to the requesting user, optionally filtered by session. Defaults to the caller's own; pass ?scope=org to list every sampler in the team.", "parameters": [ + { + "name": "session_id", + "in": "query", + "required": false, + "description": "Filter samplers by the session that created them. An unknown or inaccessible session returns an empty list.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "examples": [ + "k4q95w5" + ], + "title": "Session Id" + } + }, { "name": "scope", "in": "query", @@ -8376,11 +8539,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 \"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 \"num_replicas\": 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 \"num_replicas\": null,\n \"scope\": \"default\"\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={'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, 'num_replicas': 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, 'num_replicas': None, 'scope': 'default'}\n)\n\nprint(response.text)" } ], "description": "Creates a standalone Loops sampler not linked to a run; the sampler belongs to the given team.", @@ -8743,7 +8906,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/model_apis\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None}\n)\n\nprint(response.text)" } ], - "description": "Lists Model APIs visible to the caller. By default returns the full catalog; pass `added_only=true` to restrict to Model APIs the workspace has added.", + "description": "Lists model metadata with added-model details for teams where you can invoke Model APIs. Legacy Default Team fields remain deprecated but unchanged. Pass team_ids to narrow team details; unauthorized teams cause a 403. added_only=true returns models added by any team in scope. Models added in scope sort first, by their latest addition. Pagination is by model; cursor filters are preserved and reauthorized on every page.", "parameters": [ { "name": "cursor", @@ -8776,11 +8939,24 @@ "type": "integer" } }, + { + "name": "team_ids", + "in": "query", + "required": false, + "description": "Select teams for added-model details, filtering, and ordering, repeated once per team. Defaults to all teams where you can invoke Model APIs. Any unauthorized team causes a 403.", + "schema": { + "items": { + "type": "string" + }, + "title": "Team Ids", + "type": "array" + } + }, { "name": "added_only", "in": "query", "required": false, - "description": "When true, restrict the result to Model APIs the workspace has added. Defaults to the full visible catalog.", + "description": "When true, restrict the result to Model APIs added by any team where you can invoke Model APIs. Explicit team_ids narrow this to the selected teams. Defaults to the full visible catalog.", "schema": { "default": false, "title": "Added Only", @@ -8981,32 +9157,94 @@ } } }, - "/v1/model_apis/{model_api_name}": { + "/v1/model_apis/{model_api_name}/metrics": { "get": { - "summary": "Gets a Model API", + "summary": "Gets the metrics for a Model API", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/model_apis/{model_api_name} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/model_apis/{model_api_name}/metrics \\\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/model_apis/{model_api_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)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/model_apis/{model_api_name}/metrics\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'mode': 'CURRENT', 'start_epoch_millis': None, 'end_epoch_millis': None}\n)\n\nprint(response.text)" + } + ], + "description": "Gets the metrics for a Model API in the given time range.", + "parameters": [ + { + "name": "mode", + "in": "query", + "required": false, + "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.", + "schema": { + "$ref": "#/components/schemas/MetricModeV1", + "default": "CURRENT" + } + }, + { + "name": "start_epoch_millis", + "in": "query", + "required": false, + "description": "Epoch millis timestamp to start fetching metrics. Defaults to one hour before the end.", + "schema": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start Epoch Millis" + } + }, + { + "name": "end_epoch_millis", + "in": "query", + "required": false, + "description": "Epoch millis timestamp to end fetching metrics. Defaults to the current time. The window between start and end must not exceed 7 days.", + "schema": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End Epoch Millis" + } + }, + { + "name": "metrics", + "in": "query", + "required": false, + "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_model_api_inference_requests_total, baseten_model_api_incoming_inference_requests_total, and baseten_model_api_tokens_total. Unknown names are rejected; valid names that are not enabled for your organization are omitted from the response.", + "schema": { + "items": { + "type": "string" + }, + "title": "Metrics", + "type": "array" + } } ], - "description": "Fetches a Model API by name, with workspace overlay when added.", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ModelAPIV1" + "$ref": "#/components/schemas/GetMetricsResponseV1" } } } } - } + }, + "x-stability": "unstable" }, "parameters": [ { @@ -9014,54 +9252,102 @@ } ] }, - "/v1/llm_models": { - "post": { - "summary": "Creates a new BIS-LLM deployment", + "/v1/model_apis/{model_api_name}": { + "get": { + "summary": "Gets a Model API", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/llm_models \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"resources\": null,\n \"region\": null,\n \"llm_version\": null,\n \"model_metadata\": null,\n \"autoscaling_settings\": {\n \"autoscaling_window\": 600,\n \"concurrency_target\": null,\n \"max_replica\": 5,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 300,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"additional_autoscaling_config\": {\n \"metrics\": [\n {\n \"name\": \"in_flight_tokens\",\n \"target\": 40000\n }\n ]\n },\n \"metadata\": {\n \"environment\": \"production\",\n \"git_sha\": \"abc123\"\n },\n \"weights\": [\n {\n \"mount_location\": \"/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B\"\n }\n ],\n \"egress_restrictions\": null,\n \"runtime\": null,\n \"name\": null\n}'" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/model_apis/{model_api_name} \\\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/llm_models\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'resources': None, 'region': None, 'llm_version': None, 'model_metadata': None, 'autoscaling_settings': {'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}, 'additional_autoscaling_config': {'metrics': [{'name': 'in_flight_tokens', 'target': 40000}]}, 'metadata': {'environment': 'production', 'git_sha': 'abc123'}, 'weights': [{'mount_location': '/models/base', 'source': 'hf://meta-llama/Llama-3-8B'}], 'egress_restrictions': None, 'runtime': None, 'name': 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/model_apis/{model_api_name}\"\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)" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateLLMModelRequestV1" - } + "description": "Returns model metadata with added-model details for teams where you can invoke Model APIs. Legacy Default Team fields remain deprecated but unchanged. Pass team_ids to narrow team details; unauthorized teams cause a 403.", + "parameters": [ + { + "name": "team_ids", + "in": "query", + "required": false, + "description": "Select teams for added-model details, repeated once per team. Defaults to all teams where you can invoke Model APIs. Any unauthorized team causes a 403.", + "schema": { + "items": { + "type": "string" + }, + "title": "Team Ids", + "type": "array" } - }, - "required": true - }, + } + ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/LLMModelHandleV1" + "$ref": "#/components/schemas/ModelAPIV1" } } } } } - } + }, + "parameters": [ + { + "$ref": "#/components/parameters/model_api_name" + } + ] }, - "/v1/teams/{team_id}/llm_models": { + "/v1/llm_models": { "post": { "summary": "Creates a new BIS-LLM deployment", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/llm_models \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"resources\": null,\n \"region\": null,\n \"llm_version\": null,\n \"model_metadata\": null,\n \"autoscaling_settings\": {\n \"autoscaling_window\": 600,\n \"concurrency_target\": null,\n \"max_replica\": 5,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 300,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"additional_autoscaling_config\": {\n \"metrics\": [\n {\n \"name\": \"in_flight_tokens\",\n \"target\": 40000\n }\n ]\n },\n \"metadata\": {\n \"environment\": \"production\",\n \"git_sha\": \"abc123\"\n },\n \"weights\": [\n {\n \"mount_location\": \"/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B\"\n }\n ],\n \"egress_restrictions\": null,\n \"runtime\": null,\n \"name\": null\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/llm_models \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"resources\": null,\n \"deployment_name\": null,\n \"region\": null,\n \"llm_version\": null,\n \"model_metadata\": null,\n \"autoscaling_settings\": {\n \"autoscaling_window\": 600,\n \"concurrency_target\": null,\n \"max_replica\": 5,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 300,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"additional_autoscaling_config\": {\n \"metrics\": [\n {\n \"name\": \"in_flight_tokens\",\n \"target\": 40000\n }\n ]\n },\n \"metadata\": {\n \"environment\": \"production\",\n \"git_sha\": \"abc123\"\n },\n \"weights\": [\n {\n \"mount_location\": \"/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B\"\n }\n ],\n \"bdn\": null,\n \"egress_restrictions\": null,\n \"runtime\": null,\n \"name\": 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}/llm_models\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'resources': None, 'region': None, 'llm_version': None, 'model_metadata': None, 'autoscaling_settings': {'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}, 'additional_autoscaling_config': {'metrics': [{'name': 'in_flight_tokens', 'target': 40000}]}, 'metadata': {'environment': 'production', 'git_sha': 'abc123'}, 'weights': [{'mount_location': '/models/base', 'source': 'hf://meta-llama/Llama-3-8B'}], 'egress_restrictions': None, 'runtime': None, 'name': 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/llm_models\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'resources': None, 'deployment_name': None, 'region': None, 'llm_version': None, 'model_metadata': None, 'autoscaling_settings': {'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}, 'additional_autoscaling_config': {'metrics': [{'name': 'in_flight_tokens', 'target': 40000}]}, 'metadata': {'environment': 'production', 'git_sha': 'abc123'}, 'weights': [{'mount_location': '/models/base', 'source': 'hf://meta-llama/Llama-3-8B'}], 'bdn': None, 'egress_restrictions': None, 'runtime': None, 'name': None}\n)\n\nprint(response.text)" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateLLMModelRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LLMModelHandleV1" + } + } + } + } + } + } + }, + "/v1/teams/{team_id}/llm_models": { + "post": { + "summary": "Creates a new BIS-LLM deployment", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/teams/{team_id}/llm_models \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"resources\": null,\n \"deployment_name\": null,\n \"region\": null,\n \"llm_version\": null,\n \"model_metadata\": null,\n \"autoscaling_settings\": {\n \"autoscaling_window\": 600,\n \"concurrency_target\": null,\n \"max_replica\": 5,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 300,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"additional_autoscaling_config\": {\n \"metrics\": [\n {\n \"name\": \"in_flight_tokens\",\n \"target\": 40000\n }\n ]\n },\n \"metadata\": {\n \"environment\": \"production\",\n \"git_sha\": \"abc123\"\n },\n \"weights\": [\n {\n \"mount_location\": \"/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B\"\n }\n ],\n \"bdn\": null,\n \"egress_restrictions\": null,\n \"runtime\": null,\n \"name\": 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}/llm_models\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'resources': None, 'deployment_name': None, 'region': None, 'llm_version': None, 'model_metadata': None, 'autoscaling_settings': {'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}, 'additional_autoscaling_config': {'metrics': [{'name': 'in_flight_tokens', 'target': 40000}]}, 'metadata': {'environment': 'production', 'git_sha': 'abc123'}, 'weights': [{'mount_location': '/models/base', 'source': 'hf://meta-llama/Llama-3-8B'}], 'bdn': None, 'egress_restrictions': None, 'runtime': None, 'name': None}\n)\n\nprint(response.text)" } ], "requestBody": { @@ -9099,11 +9385,11 @@ "x-codeSamples": [ { "lang": "bash", - "source": "curl --request POST \\\n--url https://api.baseten.co/v1/llm_models/{model_id}/deployments \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"resources\": null,\n \"region\": null,\n \"llm_version\": null,\n \"model_metadata\": null,\n \"autoscaling_settings\": {\n \"autoscaling_window\": 600,\n \"concurrency_target\": null,\n \"max_replica\": 5,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 300,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"additional_autoscaling_config\": {\n \"metrics\": [\n {\n \"name\": \"in_flight_tokens\",\n \"target\": 40000\n }\n ]\n },\n \"metadata\": {\n \"environment\": \"production\",\n \"git_sha\": \"abc123\"\n },\n \"weights\": [\n {\n \"mount_location\": \"/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B\"\n }\n ],\n \"egress_restrictions\": null,\n \"runtime\": null\n}'" + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/llm_models/{model_id}/deployments \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"resources\": null,\n \"deployment_name\": null,\n \"region\": null,\n \"llm_version\": null,\n \"model_metadata\": null,\n \"autoscaling_settings\": {\n \"autoscaling_window\": 600,\n \"concurrency_target\": null,\n \"max_replica\": 5,\n \"max_scale_down_rate\": null,\n \"min_replica\": 1,\n \"scale_down_delay\": 300,\n \"target_in_flight_tokens\": null,\n \"target_utilization_percentage\": null\n },\n \"additional_autoscaling_config\": {\n \"metrics\": [\n {\n \"name\": \"in_flight_tokens\",\n \"target\": 40000\n }\n ]\n },\n \"metadata\": {\n \"environment\": \"production\",\n \"git_sha\": \"abc123\"\n },\n \"weights\": [\n {\n \"mount_location\": \"/models/base\",\n \"source\": \"hf://meta-llama/Llama-3-8B\"\n }\n ],\n \"bdn\": null,\n \"egress_restrictions\": null,\n \"runtime\": null\n}'" }, { "lang": "python", - "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/llm_models/{model_id}/deployments\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'resources': None, 'region': None, 'llm_version': None, 'model_metadata': None, 'autoscaling_settings': {'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}, 'additional_autoscaling_config': {'metrics': [{'name': 'in_flight_tokens', 'target': 40000}]}, 'metadata': {'environment': 'production', 'git_sha': 'abc123'}, 'weights': [{'mount_location': '/models/base', 'source': 'hf://meta-llama/Llama-3-8B'}], 'egress_restrictions': None, 'runtime': 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/llm_models/{model_id}/deployments\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'resources': None, 'deployment_name': None, 'region': None, 'llm_version': None, 'model_metadata': None, 'autoscaling_settings': {'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}, 'additional_autoscaling_config': {'metrics': [{'name': 'in_flight_tokens', 'target': 40000}]}, 'metadata': {'environment': 'production', 'git_sha': 'abc123'}, 'weights': [{'mount_location': '/models/base', 'source': 'hf://meta-llama/Llama-3-8B'}], 'bdn': None, 'egress_restrictions': None, 'runtime': None}\n)\n\nprint(response.text)" } ], "requestBody": { @@ -9474,7 +9760,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/billing/model_apis\"\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)" } ], - "description": "Returns daily Model API costs in USD for your organization, with optional filtering and grouping by API key, user, model, and service tier. Results may differ from finalized invoice amounts. Cost history is available from August 5, 2026 at 20:45 UTC. August 5 is a partial day; earlier dates are unavailable.", + "description": "Returns daily Model API costs in USD for the teams you can manage, with optional filtering and grouping by API key, user, model, service tier, and team. Organization admins receive organization-wide totals by default; other callers may receive lower totals than callers with management access to more teams. Results may differ from finalized invoice amounts. Cost history is available from August 5, 2026 at 20:45 UTC. August 5 is a partial day; earlier dates are unavailable. Team attribution began on October 12, 2026 at 21:54 UTC, with no historical backfill. October 12 is a partial day for team-scoped queries. Only unfiltered organization-admin queries include older unattributed usage.", "parameters": [ { "name": "cursor", @@ -9549,7 +9835,7 @@ "name": "group_by", "in": "query", "required": false, - "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.", + "description": "Dimensions to break costs down by, repeated once per dimension: api_key_prefix, user, model, service_tier, or team. 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 totals across all teams you can manage.", "schema": { "items": { "$ref": "#/components/schemas/ModelApiCostDimensionV1" @@ -9609,6 +9895,19 @@ "title": "Service Tiers", "type": "array" } + }, + { + "name": "team_ids", + "in": "query", + "required": false, + "description": "Return only costs attributed to these teams, repeated once per team. Defaults to all teams you can manage.", + "schema": { + "items": { + "type": "string" + }, + "title": "Team Ids", + "type": "array" + } } ], "responses": { @@ -9690,7 +9989,7 @@ "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.", + "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. Defaults to teams you can manage; org admins include all organization history. Use team_ids to narrow the scope and group_by=TEAM for per-team rows. An unauthorized team filter causes a 403 response.", "parameters": [ { "name": "start_date", @@ -9721,309 +10020,32 @@ "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", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/users \\\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/users\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'email': None}\n)\n\nprint(response.text)" - } - ], - "description": "Returns the workspace's members. Only actual joined members are returned; service accounts, invited users, and pending join requests are excluded.", - "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": "email", - "in": "query", - "required": false, - "description": "When set, returns only users with this exact email, if any.", - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Email" - } - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersResponseV1" - } - } - } - } - }, - "x-stability": "unstable" - } - }, - "/v1/users/me": { - "get": { - "summary": "Gets the authenticated user", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/users/me \\\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/users/me\"\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 info about the user making the request.", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserInfoV1" - } - } - } - } - }, - "x-stability": "unstable" - } - }, - "/v1/users/{user_id}": { - "get": { - "summary": "Gets a user by ID", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/users/{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/users/{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": "Returns info about a user in the caller's workspace.", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserInfoV1" - } - } - } - } - }, - "x-stability": "unstable" - }, - "parameters": [ - { - "$ref": "#/components/parameters/user_id" - } - ] - }, - "/v1/organizations/me": { - "get": { - "summary": "Gets the authenticated organization", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/organizations/me \\\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/organizations/me\"\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 info about the organization of the user making the request.", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrganizationInfoV1" - } - } - } - } - }, - "x-stability": "unstable" - } - }, - "/v1/gateway/events": { - "get": { - "summary": "Lists gateway events", - "x-codeSamples": [ - { - "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/events \\\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/events\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'start_time': None, 'end_time': None, 'limit': None, 'cursor': None}\n)\n\nprint(response.text)" - } - ], - "parameters": [ - { - "name": "start_time", - "in": "query", - "required": false, - "description": "Inclusive start (ISO 8601, UTC). Required without a cursor.", - "schema": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Start Time" - } - }, - { - "name": "end_time", - "in": "query", - "required": false, - "description": "Exclusive end (ISO 8601, UTC). Defaults to now.", - "schema": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "End Time" - } - }, - { - "name": "limit", - "in": "query", - "required": false, - "description": "Max events. Default 100, max 1000.", - "schema": { - "anyOf": [ - { - "maximum": 1000, - "minimum": 1, - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Limit" - } - }, - { - "name": "api_keys", + "name": "team_ids", "in": "query", "required": false, - "description": "Return only events for these API key prefixes, repeated once per prefix.", + "description": "Return only usage for these teams, repeated once per team. Defaults to all teams you can manage. An unauthorized team ID causes a 403 response.", "schema": { "items": { "type": "string" }, - "title": "Api Keys", + "title": "Team Ids", "type": "array" } }, { - "name": "external_entity_ids", + "name": "group_by", "in": "query", "required": false, - "description": "Return only events for these external entity IDs, repeated once per ID.", + "description": "Pass TEAM to split daily rows by team. Defaults to aggregating across teams.", "schema": { "items": { - "type": "string" + "$ref": "#/components/schemas/ToolCallUsageDimensionV1" }, - "title": "External Entity Ids", + "title": "Group By", "type": "array" } - }, - { - "name": "cursor", - "in": "query", - "required": false, - "description": "Next-page cursor. Other parameters are ignored.", - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Cursor" - } } ], "responses": { @@ -10032,7 +10054,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GatewayEventsResponseV1" + "$ref": "#/components/schemas/ToolCallUsageResponseV1" } } } @@ -10040,20 +10062,323 @@ } } }, - "/v1/explore/metadata": { + "/v1/users": { "get": { - "summary": "Lists model metadata", + "summary": "Lists users in the workspace", "x-codeSamples": [ { "lang": "bash", - "source": "curl --request GET \\\n--url https://api.baseten.co/v1/explore/metadata \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\"\n" + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/users \\\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/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)" + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/users\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'email': None}\n)\n\nprint(response.text)" } ], - "description": "Lists all live model metadata rows, e.g. for model pickers.", + "description": "Returns the workspace's members. Only actual joined members are returned; service accounts, invited users, and pending join requests are excluded.", + "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": "email", + "in": "query", + "required": false, + "description": "When set, returns only users with this exact email, if any.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Email" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersResponseV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/users/me": { + "get": { + "summary": "Gets the authenticated user", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/users/me \\\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/users/me\"\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 info about the user making the request.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserInfoV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/users/{user_id}": { + "get": { + "summary": "Gets a user by ID", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/users/{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/users/{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": "Returns info about a user in the caller's workspace.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserInfoV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "parameters": [ + { + "$ref": "#/components/parameters/user_id" + } + ] + }, + "/v1/organizations/me": { + "get": { + "summary": "Gets the authenticated organization", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/organizations/me \\\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/organizations/me\"\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 info about the organization of the user making the request.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationInfoV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/gateway/events": { + "get": { + "summary": "Lists gateway events", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/gateway/events \\\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/events\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'start_time': None, 'end_time': None, 'limit': None, 'cursor': None}\n)\n\nprint(response.text)" + } + ], + "parameters": [ + { + "name": "start_time", + "in": "query", + "required": false, + "description": "Inclusive start (ISO 8601, UTC). Required without a cursor.", + "schema": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start Time" + } + }, + { + "name": "end_time", + "in": "query", + "required": false, + "description": "Exclusive end (ISO 8601, UTC). Defaults to now.", + "schema": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End Time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "description": "Max events. Default 100, max 1000.", + "schema": { + "anyOf": [ + { + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Limit" + } + }, + { + "name": "api_keys", + "in": "query", + "required": false, + "description": "Return only events for these API key prefixes, repeated once per prefix.", + "schema": { + "items": { + "type": "string" + }, + "title": "Api Keys", + "type": "array" + } + }, + { + "name": "external_entity_ids", + "in": "query", + "required": false, + "description": "Return only events for these external entity IDs, repeated once per ID.", + "schema": { + "items": { + "type": "string" + }, + "title": "External Entity Ids", + "type": "array" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "description": "Next-page cursor. Other parameters are ignored.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cursor" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GatewayEventsResponseV1" + } + } + } + } + } + } + }, + "/v1/explore/metadata": { + "get": { + "summary": "Lists model metadata", + "x-codeSamples": [ + { + "lang": "bash", + "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/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)" + } + ], + "description": "Lists all live model metadata rows, e.g. for model pickers.", "parameters": [ { "name": "cursor", @@ -10138,6 +10463,45 @@ "x-stability": "unstable" } }, + "/v1/grid/token": { + "post": { + "summary": "Creates a Grid access token", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/grid/token \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"team_id\": \"abc1234\"\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/grid/token\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'team_id': 'abc1234'}\n)\n\nprint(response.text)" + } + ], + "description": "Exchanges your Baseten credentials for a short-lived token that authenticates against the Grid gateway as you, in the given team. Tokens expire after four hours and cannot be renewed; request a new one when needed. Routes keys cannot create tokens.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGridTokenRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GridTokenV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, "/v1/grid/routes": { "get": { "summary": "Lists routes", @@ -10390,7 +10754,7 @@ "name": "group_by", "in": "query", "required": false, - "description": "Dimensions to break usage down by, repeated once per dimension: USER, TEAM, MODEL, PROVIDER, or ROUTER. 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. ROUTER returns only usage sent through an intelligent router, one row per router, or per router and model with MODEL. Router rows repeat usage already counted in other groupings, so don't add them to model totals. Defaults to MODEL.", + "description": "Dimensions to break usage down by, repeated once per dimension: USER, TEAM, MODEL, PROVIDER, ROUTER, or HARNESS. 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. ROUTER returns only usage sent through an intelligent router, one row per router, or per router and model with MODEL. Router rows repeat usage already counted in other groupings, so don't add them to model totals. HARNESS includes usage with no recorded harness as a null group. Defaults to MODEL.", "schema": { "items": { "$ref": "#/components/schemas/GridRouteUsageDimensionV1" @@ -10437,6 +10801,19 @@ "title": "Providers", "type": "array" } + }, + { + "name": "harnesses", + "in": "query", + "required": false, + "description": "Return only usage for these harnesses, repeated once per harness. Omit to include all usage, including usage with no recorded harness.", + "schema": { + "items": { + "$ref": "#/components/schemas/GridRouteUsageHarnessV1" + }, + "title": "Harnesses", + "type": "array" + } } ], "responses": { @@ -10653,7 +11030,7 @@ "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/grid/team_settings/users\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None, 'team_id': 'abc1234'}\n)\n\nprint(response.text)" } ], - "description": "Returns each member's settings in each team, including organization admins and Grid service accounts, one row per team membership. With `team_id`, one team, which requires team admin for it or organization admin; without it, every team you administer.", + "description": "Returns each member's settings in each team, including organization admins and Grid service accounts, one row per team membership. With `team_id`, one team, which requires team admin for it or organization admin; without it, every team you administer, which is none for members.", "parameters": [ { "name": "cursor", @@ -10969,6 +11346,32 @@ "$ref": "#/components/parameters/connection_id" } ], + "get": { + "summary": "Gets a connection", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/grid/connections/{connection_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/grid/connections/{connection_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/GridConnectionV1" + } + } + } + } + }, + "x-stability": "unstable" + }, "patch": { "summary": "Updates a connection", "x-codeSamples": [ @@ -11102,6 +11505,424 @@ } ] }, + "/v1/grid/route_classifiers": { + "get": { + "summary": "Lists route classifiers available for intelligent routes", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/grid/route_classifiers \\\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/grid/route_classifiers\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"GET\",\n url,\n headers=headers,\n params={'cursor': None}\n)\n\nprint(response.text)" + } + ], + "description": "Returns Baseten-managed route classifiers available to your organization, ordered by identifier. Route classifiers cannot be created or modified through this API.", + "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" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GridRouteClassifiersResponseV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/grid/route_classifiers/{route_classifier_id}": { + "get": { + "summary": "Gets a route classifier available for intelligent routes", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/grid/route_classifiers/{route_classifier_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/grid/route_classifiers/{route_classifier_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/GridRouteClassifierV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "parameters": [ + { + "$ref": "#/components/parameters/route_classifier_id" + } + ] + }, + "/v1/grid/machine_users": { + "get": { + "summary": "Lists machine users", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/grid/machine_users \\\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/grid/machine_users\"\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}\n)\n\nprint(response.text)" + } + ], + "description": "Lists machine users, newest first: the team's with `team_id`, which requires team admin for it, else those of every team you administer.", + "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": "team_id", + "in": "query", + "required": false, + "description": "Limit machine users to this team. Without it, every team you administer.", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Team Id" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GridMachineUsersResponseV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "post": { + "summary": "Creates a machine user", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/grid/machine_users \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"team_id\": \"abc1234\",\n \"name\": \"night-shift\",\n \"api_key\": null\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/grid/machine_users\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'team_id': 'abc1234', 'name': 'night-shift', 'api_key': None}\n)\n\nprint(response.text)" + } + ], + "description": "Creates a team-owned identity for an application, with its own Grid budget. Set `api_key` to also create its first API key, which the response returns only once. Set the machine user's spend limit with the user settings endpoint, using its `id` as the user ID. Requires team admin.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGridMachineUserRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatedGridMachineUserV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/grid/machine_users/{machine_user_id}": { + "delete": { + "summary": "Deletes a machine user", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request DELETE \\\n--url https://api.baseten.co/v1/grid/machine_users/{machine_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/grid/machine_users/{machine_user_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)" + } + ], + "description": "Revokes the machine user's API keys and deletes it. Its usage history remains. Requires team admin for the machine user's team.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GridMachineUserTombstoneV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "parameters": [ + { + "$ref": "#/components/parameters/machine_user_id" + } + ], + "get": { + "summary": "Gets a machine user", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/grid/machine_users/{machine_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/grid/machine_users/{machine_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": "Requires team admin for the machine user's team.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GridMachineUserV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "patch": { + "summary": "Updates a machine user", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request PATCH \\\n--url https://api.baseten.co/v1/grid/machine_users/{machine_user_id} \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": null\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/grid/machine_users/{machine_user_id}\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"PATCH\",\n url,\n headers=headers,\n json={'name': None}\n)\n\nprint(response.text)" + } + ], + "description": "Changes only the fields in the request. Requires team admin for the machine user's team.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateGridMachineUserRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GridMachineUserV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/grid/machine_users/{machine_user_id}/api_keys": { + "get": { + "summary": "Lists a machine user's API keys", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request GET \\\n--url https://api.baseten.co/v1/grid/machine_users/{machine_user_id}/api_keys \\\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/grid/machine_users/{machine_user_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)" + } + ], + "description": "Lists the machine user's active API keys, newest first. Requires team admin for the machine user's team.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeysV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "parameters": [ + { + "$ref": "#/components/parameters/machine_user_id" + } + ], + "post": { + "summary": "Creates an API key for a machine user", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request POST \\\n--url https://api.baseten.co/v1/grid/machine_users/{machine_user_id}/api_keys \\\n--header \"Authorization: Bearer $BASETEN_API_KEY\" \\\n--data '{\n \"name\": \"production\"\n}'" + }, + { + "lang": "python", + "source": "import requests\nimport os\nAPI_KEY = os.environ.get(\"BASETEN_API_KEY\", \"\")\nurl = \"https://api.baseten.co/v1/grid/machine_users/{machine_user_id}/api_keys\"\n\nheaders = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\nresponse = requests.request(\n \"POST\",\n url,\n headers=headers,\n json={'name': 'production'}\n)\n\nprint(response.text)" + } + ], + "description": "The machine user's other API keys stay active. Requires team admin for the machine user's team.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGridMachineUserAPIKeyRequestV1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyV1" + } + } + } + } + }, + "x-stability": "unstable" + } + }, + "/v1/grid/machine_users/{machine_user_id}/api_keys/{api_key_prefix}": { + "delete": { + "summary": "Revokes a machine user's API key", + "x-codeSamples": [ + { + "lang": "bash", + "source": "curl --request DELETE \\\n--url https://api.baseten.co/v1/grid/machine_users/{machine_user_id}/api_keys/{api_key_prefix} \\\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/grid/machine_users/{machine_user_id}/api_keys/{api_key_prefix}\"\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)" + } + ], + "description": "The machine user's other API keys stay active. Requires team admin for the machine user's team.", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyTombstoneV1" + } + } + } + } + }, + "x-stability": "unstable" + }, + "parameters": [ + { + "$ref": "#/components/parameters/machine_user_id" + }, + { + "$ref": "#/components/parameters/api_key_prefix" + } + ] + }, "/v1/gateway/endpoints": { "get": { "summary": "Lists Gateway endpoints", @@ -14065,6 +14886,26 @@ "title": "VolumeSyncAuthenticationGCPOIDCV1", "type": "object" }, + "VolumeSyncAuthenticationHuggingFaceOIDCV1": { + "description": "Authentication using a Hugging Face trusted publisher and Baseten workload identity.", + "properties": { + "resource": { + "description": "Hugging Face username for an account CI/CD identity, or namespace/repository for a repository trusted publisher. Configure trust in Hugging Face before starting the sync.", + "examples": [ + "hf-user", + "organization/private-model" + ], + "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]*(/[A-Za-z0-9_][A-Za-z0-9_.-]*)?$", + "title": "Resource", + "type": "string" + } + }, + "required": [ + "resource" + ], + "title": "VolumeSyncAuthenticationHuggingFaceOIDCV1", + "type": "object" + }, "VolumeSyncDestinationV1": { "description": "BDN destination for a volume sync.", "properties": { @@ -14350,6 +15191,18 @@ "description": "Hugging Face source type.", "title": "Type", "type": "string" + }, + "hf_oidc": { + "anyOf": [ + { + "$ref": "#/components/schemas/VolumeSyncAuthenticationHuggingFaceOIDCV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Hugging Face OIDC authentication for this source. Cannot be combined with auth_secret_name." } }, "required": [ @@ -16543,7 +17396,7 @@ } ], "default": null, - "description": "Autoscaling settings for the new deployment. With `environment_name`, the new deployment starts from the environment's settings with these changes applied, and the environment keeps the result when the promotion completes. Without it, they apply to the new deployment only.", + "description": "Autoscaling settings for the new deployment. The new deployment starts from the settings of the environment named by `environment_name` with these changes applied, and the environment keeps the result when the promotion completes. Requires `environment_name`.", "examples": [ { "max_replica": 4, @@ -16609,7 +17462,7 @@ } ], "default": null, - "description": "Instance type for the new deployment, from `GET /v1/instance_types`, in place of the one in `config`. With `environment_name`, the environment takes it when the promotion completes. Without it, it applies to the new deployment only. Cannot be set with `preserve_env_instance_type: true`.", + "description": "Instance type for the new deployment, from `GET /v1/instance_types`, in place of the one in `config`. The environment named by `environment_name` takes it when the promotion completes. Requires `environment_name`. Cannot be set with `preserve_env_instance_type: true`.", "title": "Instance Type Id" } }, @@ -17364,6 +18217,7 @@ "mapping": { "API_KEY_CREATED": "#/components/schemas/AuditLogEventApiKeyCreatedV1", "API_KEY_DELETED": "#/components/schemas/AuditLogEventApiKeyDeletedV1", + "API_KEY_LIFETIME_LIMITS_UPDATED": "#/components/schemas/AuditLogEventApiKeyLifetimeLimitsUpdatedV1", "CHAINLET_AUTOSCALING_SETTINGS_CHANGED": "#/components/schemas/AuditLogEventChainletAutoscalingSettingsChangedV1", "CHAINLET_INSTANCE_TYPE_CHANGED": "#/components/schemas/AuditLogEventChainletInstanceTypeChangedV1", "CHAIN_DELETED": "#/components/schemas/AuditLogEventChainDeletedV1", @@ -17381,6 +18235,9 @@ "GATEWAY_ENDPOINT_CREATED": "#/components/schemas/AuditLogEventGatewayEndpointCreatedV1", "GATEWAY_ENDPOINT_DELETED": "#/components/schemas/AuditLogEventGatewayEndpointDeletedV1", "GATEWAY_ENDPOINT_UPDATED": "#/components/schemas/AuditLogEventGatewayEndpointUpdatedV1", + "GRID_MACHINE_USER_CREATED": "#/components/schemas/AuditLogEventGridMachineUserCreatedV1", + "GRID_MACHINE_USER_DELETED": "#/components/schemas/AuditLogEventGridMachineUserDeletedV1", + "GRID_MACHINE_USER_UPDATED": "#/components/schemas/AuditLogEventGridMachineUserUpdatedV1", "MODEL_DELETED": "#/components/schemas/AuditLogEventModelDeletedV1", "MODEL_DEPLOYED": "#/components/schemas/AuditLogEventModelDeployedV1", "MODEL_DEPLOYMENT_ACTIVATED": "#/components/schemas/AuditLogEventModelDeploymentActivatedV1", @@ -17497,6 +18354,9 @@ { "$ref": "#/components/schemas/AuditLogEventApiKeyDeletedV1" }, + { + "$ref": "#/components/schemas/AuditLogEventApiKeyLifetimeLimitsUpdatedV1" + }, { "$ref": "#/components/schemas/AuditLogEventGatewayEndpointCreatedV1" }, @@ -17515,6 +18375,15 @@ { "$ref": "#/components/schemas/AuditLogEventProviderConnectionDeletedV1" }, + { + "$ref": "#/components/schemas/AuditLogEventGridMachineUserCreatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventGridMachineUserUpdatedV1" + }, + { + "$ref": "#/components/schemas/AuditLogEventGridMachineUserDeletedV1" + }, { "$ref": "#/components/schemas/AuditLogEventUserInvitedV1" }, @@ -17728,6 +18597,74 @@ "title": "AuditLogEventApiKeyDeletedV1", "type": "object" }, + "AuditLogEventApiKeyLifetimeLimitsUpdatedV1": { + "description": "An administrator updated the organization's API key lifetime limits.", + "properties": { + "event_type": { + "const": "API_KEY_LIFETIME_LIMITS_UPDATED", + "title": "Event Type", + "type": "string" + }, + "organization_id": { + "title": "Organization Id", + "type": "string" + }, + "previous_personal_limit_days": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Previous Personal Limit Days" + }, + "new_personal_limit_days": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "New Personal Limit Days" + }, + "previous_team_limit_days": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Previous Team Limit Days" + }, + "new_team_limit_days": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "New Team Limit Days" + } + }, + "required": [ + "event_type", + "organization_id", + "previous_personal_limit_days", + "new_personal_limit_days", + "previous_team_limit_days", + "new_team_limit_days" + ], + "title": "AuditLogEventApiKeyLifetimeLimitsUpdatedV1", + "type": "object" + }, "AuditLogEventAutoscalingScheduleActionV1": { "description": "What an autoscaling change did to one schedule.", "enum": [ @@ -19975,6 +20912,116 @@ "title": "AuditLogEventGatewayEndpointUpdatedV1", "type": "object" }, + "AuditLogEventGridMachineUserCreatedV1": { + "description": "A Grid machine user was created.", + "properties": { + "event_type": { + "const": "GRID_MACHINE_USER_CREATED", + "title": "Event Type", + "type": "string" + }, + "machine_user_id": { + "title": "Machine User Id", + "type": "string" + }, + "machine_user_name": { + "title": "Machine User Name", + "type": "string" + }, + "team_id": { + "title": "Team Id", + "type": "string" + }, + "team_name": { + "title": "Team Name", + "type": "string" + } + }, + "required": [ + "event_type", + "machine_user_id", + "machine_user_name", + "team_id", + "team_name" + ], + "title": "AuditLogEventGridMachineUserCreatedV1", + "type": "object" + }, + "AuditLogEventGridMachineUserDeletedV1": { + "description": "A Grid machine user was deleted, revoking its API keys.", + "properties": { + "event_type": { + "const": "GRID_MACHINE_USER_DELETED", + "title": "Event Type", + "type": "string" + }, + "machine_user_id": { + "title": "Machine User Id", + "type": "string" + }, + "machine_user_name": { + "title": "Machine User Name", + "type": "string" + }, + "team_id": { + "title": "Team Id", + "type": "string" + }, + "team_name": { + "title": "Team Name", + "type": "string" + } + }, + "required": [ + "event_type", + "machine_user_id", + "machine_user_name", + "team_id", + "team_name" + ], + "title": "AuditLogEventGridMachineUserDeletedV1", + "type": "object" + }, + "AuditLogEventGridMachineUserUpdatedV1": { + "description": "A Grid machine user was renamed.", + "properties": { + "event_type": { + "const": "GRID_MACHINE_USER_UPDATED", + "title": "Event Type", + "type": "string" + }, + "machine_user_id": { + "title": "Machine User Id", + "type": "string" + }, + "machine_user_name": { + "title": "Machine User Name", + "type": "string" + }, + "previous_machine_user_name": { + "title": "Previous Machine User Name", + "type": "string" + }, + "team_id": { + "title": "Team Id", + "type": "string" + }, + "team_name": { + "title": "Team Name", + "type": "string" + } + }, + "required": [ + "event_type", + "machine_user_id", + "machine_user_name", + "previous_machine_user_name", + "team_id", + "team_name" + ], + "title": "AuditLogEventGridMachineUserUpdatedV1", + "type": "object" + }, "AuditLogEventModelDeletedV1": { "description": "A model was deleted.", "properties": { @@ -20046,6 +21093,68 @@ } ], "title": "Environment Name" + }, + "region_update": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Region Update" + }, + "instance_type_id_update": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Instance Type Id Update" + }, + "promotion_settings_override": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventPromotionSettingsOverrideV1" + }, + { + "type": "null" + } + ] + }, + "autoscaling_settings_update": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventAutoscalingSettingsUpdateV1" + }, + { + "type": "null" + } + ] + }, + "request_backpressure_settings_update": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventRequestBackpressureSettingsUpdateV1" + }, + { + "type": "null" + } + ] + }, + "autoscaling_schedule_settings_update": { + "anyOf": [ + { + "$ref": "#/components/schemas/AuditLogEventAutoscalingScheduleOperationsV1" + }, + { + "type": "null" + } + ] } }, "required": [ @@ -20057,7 +21166,13 @@ "scale_previous_to_zero", "trusted", "publish", - "environment_name" + "environment_name", + "region_update", + "instance_type_id_update", + "promotion_settings_override", + "autoscaling_settings_update", + "request_backpressure_settings_update", + "autoscaling_schedule_settings_update" ], "title": "AuditLogEventModelDeployedV1", "type": "object" @@ -21147,12 +22262,16 @@ "SECRET_DELETED", "API_KEY_CREATED", "API_KEY_DELETED", + "API_KEY_LIFETIME_LIMITS_UPDATED", "GATEWAY_ENDPOINT_CREATED", "GATEWAY_ENDPOINT_UPDATED", "GATEWAY_ENDPOINT_DELETED", "PROVIDER_CONNECTION_CREATED", "PROVIDER_CONNECTION_UPDATED", "PROVIDER_CONNECTION_DELETED", + "GRID_MACHINE_USER_CREATED", + "GRID_MACHINE_USER_UPDATED", + "GRID_MACHINE_USER_DELETED", "USER_INVITED", "USER_JOINED_ORGANIZATION", "WEBHOOK_SIGNING_SECRET_CREATED", @@ -21666,7 +22785,7 @@ "SECRETS", "API_KEYS", "GATEWAY", - "CODE", + "GRID", "WEBHOOK_SIGNING_SECRETS", "USER_MANAGEMENT", "DIRECTORY_GROUP_MANAGEMENT", @@ -23510,7 +24629,7 @@ "title": "SyncDeploymentPatchesResponseV1", "type": "object" }, - "ModelMetricDescriptorV1": { + "MetricDescriptorV1": { "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": { @@ -23519,15 +24638,15 @@ "type": "string" }, "unit_hint": { - "$ref": "#/components/schemas/ModelMetricUnitHintV1", + "$ref": "#/components/schemas/MetricUnitHintV1", "description": "Advisory unit of the metric's values." }, "kind": { - "$ref": "#/components/schemas/ModelMetricKindV1", + "$ref": "#/components/schemas/MetricKindV1", "description": "Semantic hint for how the metric behaves (GAUGE, COUNTER, HISTOGRAM)." }, "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'}.", + "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'}.", "items": { "additionalProperties": { "type": "string" @@ -23544,30 +24663,30 @@ "kind", "label_sets" ], - "title": "ModelMetricDescriptorV1", + "title": "MetricDescriptorV1", "type": "object" }, - "ModelMetricKindV1": { + "MetricKindV1": { "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", + "title": "MetricKindV1", "type": "string" }, - "ModelMetricModeV1": { + "MetricModeV1": { "description": "How metric values are aggregated over the request.", "enum": [ "CURRENT", "SUMMARY", "SERIES" ], - "title": "ModelMetricModeV1", + "title": "MetricModeV1", "type": "string" }, - "ModelMetricUnitHintV1": { + "MetricUnitHintV1": { "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).\n- ``CELSIUS``: a temperature in degrees Celsius.\n- ``WATTS``: power draw in watts.", "enum": [ "PER_SECOND", @@ -23579,10 +24698,10 @@ "CELSIUS", "WATTS" ], - "title": "ModelMetricUnitHintV1", + "title": "MetricUnitHintV1", "type": "string" }, - "ModelMetricValueSetV1": { + "MetricValueSetV1": { "description": "The metric values for one time step. ``values`` is aligned by index to the\nresponse ``metric_descriptors`` list.", "properties": { "start_epoch_millis": { @@ -23613,10 +24732,10 @@ "start_epoch_millis", "values" ], - "title": "ModelMetricValueSetV1", + "title": "MetricValueSetV1", "type": "object" }, - "GetModelMetricsResponseV1": { + "GetMetricsResponseV1": { "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": { @@ -23630,7 +24749,7 @@ "type": "integer" }, "mode": { - "$ref": "#/components/schemas/ModelMetricModeV1", + "$ref": "#/components/schemas/MetricModeV1", "description": "The aggregation mode used." }, "step_seconds": { @@ -23648,7 +24767,7 @@ "metric_descriptors": { "description": "Descriptors for each metric; position defines the values index.", "items": { - "$ref": "#/components/schemas/ModelMetricDescriptorV1" + "$ref": "#/components/schemas/MetricDescriptorV1" }, "title": "Metric Descriptors", "type": "array" @@ -23656,7 +24775,7 @@ "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" + "$ref": "#/components/schemas/MetricValueSetV1" }, "title": "Metric Values", "type": "array" @@ -23670,14 +24789,14 @@ "metric_descriptors", "metric_values" ], - "title": "GetModelMetricsResponseV1", + "title": "GetMetricsResponseV1", "type": "object" }, "GetDeploymentMetricsRequestV1": { "description": "Query params for ``GET /v1/models/.../deployments/.../metrics``.", "properties": { "mode": { - "$ref": "#/components/schemas/ModelMetricModeV1", + "$ref": "#/components/schemas/MetricModeV1", "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." }, @@ -25711,7 +26830,7 @@ "description": "Query params for ``GET /v1/models/.../environments/.../metrics``.", "properties": { "mode": { - "$ref": "#/components/schemas/ModelMetricModeV1", + "$ref": "#/components/schemas/MetricModeV1", "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." }, @@ -26718,6 +27837,22 @@ ], "title": "Name", "type": "string" + }, + "project_accelerator": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional default GPU type for cache-enabled CPU job placement, such as H100. GPU jobs use their requested GPU type; uncached CPU jobs use normal CPU routing. Omitting this field preserves the stored default; providing a value updates it. Existing cache-affinity requirements still apply.", + "examples": [ + "H100" + ], + "title": "Project Accelerator" } }, "required": [ @@ -26740,6 +27875,15 @@ "title": "UpsertTrainingProjectRequestV1", "type": "object" }, + "AvailabilityModelV1": { + "description": "Capacity a training job or Loops trainer runs on.", + "enum": [ + "standard", + "spot" + ], + "title": "AvailabilityModelV1", + "type": "string" + }, "CheckpointSyncStatus": { "description": "Lifecycle state for the checkpoint uploader.", "enum": [ @@ -26844,9 +27988,9 @@ "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." + "$ref": "#/components/schemas/AvailabilityModelV1", + "default": "standard", + "description": "Capacity guarantee for the job. 'standard' runs on capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; you are responsible for checkpointing your own progress." }, "user": { "anyOf": [ @@ -26906,6 +28050,19 @@ "title": "Name", "type": "string" }, + "project_accelerator": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Default GPU type for cache-enabled CPU job placement.", + "title": "Project Accelerator" + }, "created_at": { "description": "Time the training project was created in ISO 8601 format.", "format": "date-time", @@ -26973,15 +28130,6 @@ "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": { @@ -27006,14 +28154,67 @@ }, "title": "Training Projects", "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "training_projects" + "training_projects", + "pagination" ], "title": "ListTrainingProjectsResponseV1", "type": "object" }, + "ListTrainingProjectsRequestV1": { + "description": "A request to list training projects.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Return only the project with this exact name.", + "title": "Name" + }, + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Opaque cursor from the pagination.cursor field of a previous response. Omit both cursor and limit to get every project in one response.", + "title": "Cursor" + }, + "limit": { + "anyOf": [ + { + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Maximum number of projects to return, up to 1000.", + "title": "Limit" + } + }, + "title": "ListTrainingProjectsRequestV1", + "type": "object" + }, "ListTrainingJobsResponseV1": { "description": "A response to list training jobs.", "properties": { @@ -27042,6 +28243,7 @@ "CUSTOM_SECRET", "AWS_OIDC", "GCP_OIDC", + "HUGGING_FACE_OIDC", "AWS_ASSUME_ROLE" ], "title": "AuthMethod", @@ -27384,6 +28586,16 @@ ], "title": "Mount Base Path", "type": "string" + }, + "persistent_home": { + "default": false, + "description": "Whether to keep `$HOME` in a per-job directory on the project cache, so its contents outlive the job. Requires `enabled`.", + "examples": [ + true, + false + ], + "title": "Persistent Home", + "type": "boolean" } }, "title": "CreateTrainingJobCacheConfig", @@ -27485,9 +28697,9 @@ ] }, "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.", + "$ref": "#/components/schemas/AvailabilityModelV1", + "default": "standard", + "description": "Capacity guarantee for the job. Defaults to 'standard'. 'standard' runs on capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; you are responsible for checkpointing your own progress.", "examples": [ "spot" ] @@ -27603,6 +28815,7 @@ "enable_legacy_hf_mount": true, "enabled": true, "mount_base_path": "/root/.cache", + "persistent_home": false, "require_cache_affinity": true } ] @@ -28445,14 +29658,14 @@ "availability_model": { "anyOf": [ { - "$ref": "#/components/schemas/V1AvailabilityModel" + "$ref": "#/components/schemas/AvailabilityModelV1" }, { "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": "New capacity guarantee for a PENDING training job. 'standard' runs on capacity that is not preempted. 'spot' runs on interruptible capacity that may be preempted; you are responsible for checkpointing your own progress. Only jobs in the PENDING state can have their availability model changed.", "examples": [ "spot" ] @@ -29476,6 +30689,27 @@ "SearchTrainingJobsRequestV1": { "description": "A request to search training jobs.", "properties": { + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Opaque cursor returned by a previous page. Omit to fetch the first page.", + "title": "Cursor" + }, + "limit": { + "default": 1000, + "description": "Maximum number of items to return.", + "maximum": 1000, + "minimum": 1, + "title": "Limit", + "type": "integer" + }, "project_id": { "anyOf": [ { @@ -29558,10 +30792,15 @@ }, "title": "Training Jobs", "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." } }, "required": [ - "training_jobs" + "training_jobs", + "pagination" ], "title": "SearchTrainingJobsResponseV1", "type": "object" @@ -29668,10 +30907,10 @@ "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.", + "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 without ``enabled`` 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.", + "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. Models this workspace can run come first, then the rest, each group sorted by name.", "items": { "$ref": "#/components/schemas/SupportedModelV1" }, @@ -29707,7 +30946,7 @@ } ], "default": null, - "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.", + "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'. Without 'enabled', an empty list means Baseten does not support that model. Omit to list every supported model.", "examples": [ "Qwen/Qwen3-8B" ], @@ -29737,6 +30976,22 @@ 32768 ], "title": "Max Seq Len" + }, + "enabled": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Pass true to list only the models this workspace can run now, or false for only the ones it cannot. Omit to list both. With 'model', an empty list can also mean the model is supported but filtered out.", + "examples": [ + true + ], + "title": "Enabled" } }, "title": "GetLoopsCapabilitiesQueryParamsV1", @@ -29930,6 +31185,11 @@ "title": "Id", "type": "string" }, + "session_id": { + "description": "The session ID this sampler belongs to.", + "title": "Session Id", + "type": "string" + }, "base_url": { "title": "Base Url", "type": "string" @@ -30013,6 +31273,7 @@ }, "required": [ "id", + "session_id", "base_url", "base_model", "created_at", @@ -30075,6 +31336,22 @@ ], "title": "Base Model" }, + "session_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Filter runs by the session that created them. An unknown or inaccessible session returns an empty list.", + "examples": [ + "k4q95w5" + ], + "title": "Session Id" + }, "scope": { "anyOf": [ { @@ -30165,9 +31442,9 @@ "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.", + "$ref": "#/components/schemas/AvailabilityModelV1", + "default": "standard", + "description": "Capacity the trainer runs on. 'standard' 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" ] @@ -30308,6 +31585,16 @@ "title": "GetLoopsRunResponseV1", "type": "object" }, + "LoopsPlacementScopeV1": { + "description": "Where a Loops run's trainer or a standalone sampler runs.", + "enum": [ + "default", + "serverless", + "dedicated" + ], + "title": "LoopsPlacementScopeV1", + "type": "string" + }, "CreateLoopsTrainerRequestV1": { "properties": { "session_id": { @@ -30377,9 +31664,9 @@ "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.", + "$ref": "#/components/schemas/AvailabilityModelV1", + "default": "standard", + "description": "Capacity the trainer runs on. 'standard' 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" ] @@ -30445,6 +31732,11 @@ "default": null, "description": "Optional Hugging Face checkpoint to start training from instead of the base model's weights. Form: hf:///[@]. It must be a complete, merged checkpoint in safetensors format with the same architecture as base_model, which still selects the hardware and training configuration. It must include its tokenizer files: the run's sampler and the SDK load the tokenizer and chat template from the checkpoint. A private or gated repository needs a Hugging Face token in the team secret hf_access_token. The revision is pinned to a commit when the run is created. Cannot be combined with path, reuse_from_run_id, or reuse_from_session_id.", "title": "Base Checkpoint" + }, + "scope": { + "$ref": "#/components/schemas/LoopsPlacementScopeV1", + "default": "default", + "description": "Choose where this runs. 'default' lets Baseten choose. 'serverless' runs on Baseten's shared capacity, and fails instead of falling back when shared capacity can't serve the request. 'dedicated' gives it its own deployment, which you size and pay for." } }, "required": [ @@ -30475,6 +31767,22 @@ "ListLoopsSamplersRequestV1": { "description": "Query-string filters for the Loops sampler listing routes.", "properties": { + "session_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Filter samplers by the session that created them. An unknown or inaccessible session returns an empty list.", + "examples": [ + "k4q95w5" + ], + "title": "Session Id" + }, "scope": { "anyOf": [ { @@ -30500,14 +31808,14 @@ "availability_model": { "anyOf": [ { - "$ref": "#/components/schemas/V1AvailabilityModel" + "$ref": "#/components/schemas/AvailabilityModelV1" }, { "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." + "description": "Capacity the sampler runs on. 'spot' allows preemption when its GPUs are reclaimed. Defaults to 'standard' for standalone samplers. Paired samplers inherit their run's availability model; an explicit value must match it." }, "session_id": { "description": "ID of the Loops session this sampler belongs to.", @@ -30595,6 +31903,11 @@ "default": null, "description": "Number of replicas the sampler runs, applied as both its minimum and maximum. Must be at least 1. If omitted, a new sampler uses the platform defaults and a paired sampler reused from an earlier run keeps its settings. A run that already has a sampler keeps it unchanged, and when a run ends, its sampler is scaled down.", "title": "Num Replicas" + }, + "scope": { + "$ref": "#/components/schemas/LoopsPlacementScopeV1", + "default": "default", + "description": "Choose where this runs. 'default' lets Baseten choose. 'serverless' runs on Baseten's shared capacity, and fails instead of falling back when shared capacity can't serve the request. 'dedicated' gives it its own deployment, which you size and pay for. Standalone samplers only: a run's sampler runs where its run does." } }, "required": [ @@ -31066,7 +32379,7 @@ "type": "string" }, "path": { - "description": "Directory inside that version holding the checkpoint's files.", + "description": "Directory inside that version holding the checkpoint's files. Empty when the checkpoint is the whole version.", "title": "Path", "type": "string" } @@ -31193,8 +32506,8 @@ "type": "string" }, "availability_model": { - "$ref": "#/components/schemas/V1AvailabilityModel", - "default": "dedicated", + "$ref": "#/components/schemas/AvailabilityModelV1", + "default": "standard", "description": "Capacity the trainer was scheduled on." }, "instance_type": { @@ -31821,7 +33134,7 @@ }, "dedicated_usage_count": { "default": 0, - "description": "Portion of usage_count from dedicated (on-demand) jobs.", + "description": "Portion of usage_count from standard (non-spot) jobs.", "title": "Dedicated Usage Count", "type": "integer" }, @@ -31868,7 +33181,7 @@ }, "dedicated_usage_count": { "default": 0, - "description": "Portion of usage_count from dedicated (on-demand) jobs, which run against the baseline.", + "description": "Portion of usage_count from standard (non-spot) jobs, which run against the baseline.", "title": "Dedicated Usage Count", "type": "integer" }, @@ -32342,7 +33655,7 @@ "description": "Enum representing the category of an API key.", "enum": [ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_ALL", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -32375,7 +33688,7 @@ "description": "Type of the API key.", "examples": [ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_API_KEYS", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -32403,6 +33716,23 @@ ], "title": "Model Ids" }, + "expires_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Expiration time in UTC. Must be in the future. Personal keys must expire within 90 days, or sooner if your organization sets a lower limit. Team and organization keys require an expiration within your organization's limit when one is set; otherwise they may omit it or use null. Organization lifetime limits do not apply to Grid keys.", + "examples": [ + "2027-01-01T00:00:00Z" + ], + "title": "Expires At" + }, "team_id": { "anyOf": [ { @@ -32468,7 +33798,7 @@ "description": "Type of the API key.", "examples": [ "PERSONAL", - "ROUTES", + "GRID", "WORKSPACE_MANAGE_API_KEYS", "WORKSPACE_EXPORT_METRICS", "WORKSPACE_INVOKE", @@ -32515,6 +33845,20 @@ "title": "Created At", "type": "string" }, + "expires_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Expiry time in ISO 8601 format, or null if the key never expires.", + "title": "Expires At" + }, "last_used_at": { "anyOf": [ { @@ -32660,10 +34004,10 @@ "type": "string" }, "ModelAPIOrgDetailsV1": { - "description": "Workspace-specific state for a Model API.", + "description": "Team-specific state for an added Model API.", "properties": { "added_at": { - "description": "When the workspace first added this Model API.", + "description": "When the team first added this Model API.", "format": "date-time", "title": "Added At", "type": "string" @@ -32679,7 +34023,7 @@ } ], "default": null, - "description": "When the workspace last invoked this Model API. Null if the workspace has never invoked it.", + "description": "When the team last invoked this Model API. Null if the team has never invoked it.", "title": "Last Used At" } }, @@ -32689,8 +34033,170 @@ "title": "ModelAPIOrgDetailsV1", "type": "object" }, + "ModelAPIRateLimitV1": { + "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" + }, + "is_pooled": { + "description": "Whether this limit uses the organization-wide pool. The threshold is the effective limit, including any adaptive grant.", + "title": "Is Pooled", + "type": "boolean" + }, + "service_tier": { + "$ref": "#/components/schemas/ModelAPIServiceTierV1", + "description": "Service tier the rate limit applies to.", + "examples": [ + "DEFAULT", + "FLEX" + ] + }, + "baseline_threshold": { + "description": "Configured baseline threshold for the rate limit, before any adaptive increase. Equal to `threshold` when no adaptive increase is in effect.", + "examples": [ + 1000, + 50000 + ], + "minimum": 0, + "title": "Baseline Threshold", + "type": "integer" + } + }, + "required": [ + "type", + "unit", + "threshold", + "is_pooled", + "service_tier", + "baseline_threshold" + ], + "title": "ModelAPIRateLimitV1", + "type": "object" + }, + "ModelAPIServiceTierV1": { + "enum": [ + "DEFAULT", + "FLEX", + "PRIORITY" + ], + "title": "ModelAPIServiceTierV1", + "type": "string" + }, + "ModelAPITeamDetailsV1": { + "properties": { + "id": { + "description": "Organization Shared Endpoint ID.", + "title": "Id", + "type": "string" + }, + "team_id": { + "description": "Team that has added this Model API.", + "title": "Team Id", + "type": "string" + }, + "team_name": { + "description": "Name of the team that has added this Model API.", + "title": "Team Name", + "type": "string" + }, + "added_at": { + "description": "When the team first added this Model API.", + "format": "date-time", + "title": "Added At", + "type": "string" + }, + "last_used_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "When the team last invoked this Model API. Null if never invoked.", + "title": "Last Used At" + }, + "rate_limits": { + "description": "Effective rate limits for this team's Model API, at most one per type, unit, and service tier.", + "items": { + "$ref": "#/components/schemas/ModelAPIRateLimitV1" + }, + "title": "Rate Limits", + "type": "array" + }, + "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 if unavailable.", + "title": "Cost Per Million Input Tokens" + }, + "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 if unavailable.", + "title": "Cost Per Million Output Tokens" + } + }, + "required": [ + "id", + "team_id", + "team_name", + "added_at", + "last_used_at", + "rate_limits", + "cost_per_million_input_tokens", + "cost_per_million_output_tokens" + ], + "title": "ModelAPITeamDetailsV1", + "type": "object" + }, "ModelAPIV1": { - "description": "A Model API catalog row, optionally enriched with workspace-specific state.", + "description": "Model metadata and authorized team details, with retained legacy fields.", "properties": { "name": { "description": "Identifier of the Model API. Stable, URL-safe slug used as the public identifier.", @@ -32766,12 +34272,32 @@ "type": "null" } ], - "description": "Effective cost per million input tokens, in dollars. Null when pricing is unavailable.", + "deprecated": true, + "description": "Deprecated and will be removed in a future version. Legacy effective input-token price. Use team_details pricing instead. Retained during migration; null when pricing is unavailable.", "examples": [ "0.13" ], "title": "Cost Per Million Input Tokens" }, + "cost_per_million_cached_input_tokens": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Effective cost per million cached input tokens, in dollars. Null when pricing is unavailable or the Model API has no cached input price.", + "examples": [ + "0.03" + ], + "title": "Cost Per Million Cached Input Tokens" + }, "cost_per_million_output_tokens": { "anyOf": [ { @@ -32785,16 +34311,18 @@ "type": "null" } ], - "description": "Effective cost per million output tokens, in dollars. Null when pricing is unavailable.", + "deprecated": true, + "description": "Deprecated and will be removed in a future version. Legacy effective output-token price. Use team_details pricing instead. Retained during migration; 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.", + "deprecated": true, + "description": "Deprecated and will be removed in a future version. Legacy Default Team effective limits, independent of team_ids, or catalog defaults when not added or unauthorized. Use team_details for team limits; this field is not the org-pool limit view.", "items": { - "$ref": "#/components/schemas/RateLimitV1" + "$ref": "#/components/schemas/ModelAPIRateLimitV1" }, "title": "Rate Limits", "type": "array" @@ -32809,7 +34337,16 @@ } ], "default": null, - "description": "Workspace-specific state. Null when the workspace has not added this Model API." + "deprecated": true, + "description": "Deprecated and will be removed in a future version. Legacy Default Team state, independent of team_ids. Use team_details instead. Null when not added or unauthorized." + }, + "team_details": { + "description": "Added Model API details for authorized teams, ordered by team ID. Empty when no team in the selected scope has added this Model API.", + "items": { + "$ref": "#/components/schemas/ModelAPITeamDetailsV1" + }, + "title": "Team Details", + "type": "array" } }, "required": [ @@ -32820,6 +34357,7 @@ "invoke_url", "context_length", "cost_per_million_input_tokens", + "cost_per_million_cached_input_tokens", "cost_per_million_output_tokens", "rate_limits" ], @@ -32834,43 +34372,6 @@ "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" - ] - }, - "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": { @@ -32918,9 +34419,17 @@ "title": "Limit", "type": "integer" }, + "team_ids": { + "description": "Select teams for added-model details, filtering, and ordering, repeated once per team. Defaults to all teams where you can invoke Model APIs. Any unauthorized team causes a 403.", + "items": { + "type": "string" + }, + "title": "Team Ids", + "type": "array" + }, "added_only": { "default": false, - "description": "When true, restrict the result to Model APIs the workspace has added. Defaults to the full visible catalog.", + "description": "When true, restrict the result to Model APIs added by any team where you can invoke Model APIs. Explicit team_ids narrow this to the selected teams. Defaults to the full visible catalog.", "title": "Added Only", "type": "boolean" } @@ -33197,6 +34706,67 @@ "title": "ModelApisUsageRequestV1", "type": "object" }, + "GetModelAPIMetricsRequestV1": { + "description": "Query params for ``GET /v1/model_apis/.../metrics``.", + "properties": { + "mode": { + "$ref": "#/components/schemas/MetricModeV1", + "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" + }, + { + "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": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "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_model_api_inference_requests_total, baseten_model_api_incoming_inference_requests_total, and baseten_model_api_tokens_total. Unknown names are rejected; valid names that are not enabled for your organization are omitted from the response.", + "items": { + "type": "string" + }, + "title": "Metrics", + "type": "array" + } + }, + "title": "GetModelAPIMetricsRequestV1", + "type": "object" + }, + "ModelAPIRequestV1": { + "description": "Query-string filters for ``GET /v1/model_apis/{model_api_name}``.", + "properties": { + "team_ids": { + "description": "Select teams for added-model details, repeated once per team. Defaults to all teams where you can invoke Model APIs. Any unauthorized team causes a 403.", + "items": { + "type": "string" + }, + "title": "Team Ids", + "type": "array" + } + }, + "title": "ModelAPIRequestV1", + "type": "object" + }, "EgressRestrictionsV1": { "properties": { "fqdn_allow_list": { @@ -33277,6 +34847,20 @@ "default": null, "description": "If true, mounts an OIDC bearer token for the deployment to access at runtime. If unset, the platform default applies.", "title": "Enabled" + }, + "byok": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "BYOK configuration for envelope-encrypted BDN weights in BIS-LLM deployments. Requires runtime.oidc.enabled to be true.", + "title": "Byok" } }, "title": "RuntimeOidcV1", @@ -33291,6 +34875,19 @@ "title": "Resources", "type": "object" }, + "deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Name of the deployment, unique within the model. Use only A-Z, a-z, 0-9, '-', '_', and '.'. The name 'development' is reserved. If omitted or empty, a name is generated automatically.", + "title": "Deployment Name" + }, "region": { "anyOf": [ { @@ -33436,6 +35033,20 @@ ], "title": "Weights" }, + "bdn": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "BDN configuration for read-only sealed volume mounts; supports mounts only", + "title": "Bdn" + }, "egress_restrictions": { "anyOf": [ { @@ -33522,6 +35133,19 @@ "title": "Resources", "type": "object" }, + "deployment_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Name of the deployment, unique within the model. Use only A-Z, a-z, 0-9, '-', '_', and '.'. The name 'development' is reserved. If omitted or empty, a name is generated automatically.", + "title": "Deployment Name" + }, "region": { "anyOf": [ { @@ -33667,6 +35291,20 @@ ], "title": "Weights" }, + "bdn": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "BDN configuration for read-only sealed volume mounts; supports mounts only", + "title": "Bdn" + }, "egress_restrictions": { "anyOf": [ { @@ -33760,6 +35398,18 @@ "default": null, "title": "Variant" }, + "base_model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Base Model" + }, "publisher": { "anyOf": [ { @@ -34609,6 +36259,19 @@ "description": "Service tier. Null when not grouping by service_tier or when attribution is unavailable.", "title": "Service Tier" }, + "team_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Team the cost is attributed to. Null when not grouping by team or when team attribution is unavailable.", + "title": "Team Id" + }, "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": [ @@ -34652,7 +36315,8 @@ "api_key_prefix", "user", "model", - "service_tier" + "service_tier", + "team" ], "title": "ModelApiCostDimensionV1", "type": "string" @@ -34709,7 +36373,7 @@ "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.", + "description": "Dimensions to break costs down by, repeated once per dimension: api_key_prefix, user, model, service_tier, or team. 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 totals across all teams you can manage.", "items": { "$ref": "#/components/schemas/ModelApiCostDimensionV1" }, @@ -34747,6 +36411,14 @@ }, "title": "Service Tiers", "type": "array" + }, + "team_ids": { + "description": "Return only costs attributed to these teams, repeated once per team. Defaults to all teams you can manage.", + "items": { + "type": "string" + }, + "title": "Team Ids", + "type": "array" } }, "title": "ModelApisCostsRequestV1", @@ -34761,7 +36433,7 @@ }, "kind": { "$ref": "#/components/schemas/ResourceKind", - "description": "Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, or LOOPS_SAMPLER)" + "description": "Resource kind (MODEL_DEPLOYMENT, CHAINLET, TRAINING_JOB, LOOPS_TRAINER, LOOPS_SAMPLER, or LOOPS_RUN)" }, "name": { "anyOf": [ @@ -34830,7 +36502,7 @@ } ], "default": null, - "description": "Base model used by this Loops trainer or sampler", + "description": "Base model used by this Loops run, trainer, or sampler", "title": "Base Model" }, "environment_name": { @@ -34995,6 +36667,55 @@ "title": "DailyDedicatedUsageV1", "type": "object" }, + "DailyLoopsUsageV1": { + "properties": { + "subtotal": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + } + ], + "description": "Cost in dollars across all four meters", + "title": "Subtotal" + }, + "uncached_prefill": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Prompt tokens that missed the prefix cache" + }, + "cached_prefill": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Prompt tokens served from the prefix cache" + }, + "sample": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Tokens generated by sampling" + }, + "train": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Tokens processed by forward and forward-backward training calls" + }, + "date": { + "description": "Date of the usage", + "format": "date", + "title": "Date", + "type": "string" + } + }, + "required": [ + "subtotal", + "uncached_prefill", + "cached_prefill", + "sample", + "train", + "date" + ], + "title": "DailyLoopsUsageV1", + "type": "object" + }, "DailyModelApiUsageV1": { "properties": { "date": { @@ -35216,26 +36937,100 @@ "title": "DedicatedUsageV1", "type": "object" }, - "ModelApiItemV1": { + "LoopsBaseModelItemV1": { "properties": { - "model_name": { - "description": "Model name", - "title": "Model Name", + "subtotal": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + } + ], + "description": "Cost in dollars across all four meters", + "title": "Subtotal" + }, + "uncached_prefill": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Prompt tokens that missed the prefix cache" + }, + "cached_prefill": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Prompt tokens served from the prefix cache" + }, + "sample": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Tokens generated by sampling" + }, + "train": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Tokens processed by forward and forward-backward training calls" + }, + "base_model": { + "description": "Base model the usage is priced by", + "title": "Base Model", "type": "string" }, - "model_family": { + "daily": { + "description": "Daily usage breakdown", + "items": { + "$ref": "#/components/schemas/DailyLoopsUsageV1" + }, + "title": "Daily", + "type": "array" + }, + "breakdown": { + "description": "Usage per run and standalone sampler on this base model", + "items": { + "$ref": "#/components/schemas/LoopsResourceItemV1" + }, + "title": "Breakdown", + "type": "array" + } + }, + "required": [ + "subtotal", + "uncached_prefill", + "cached_prefill", + "sample", + "train", + "base_model" + ], + "title": "LoopsBaseModelItemV1", + "type": "object" + }, + "LoopsMeterUsageV1": { + "properties": { + "tokens": { + "description": "Tokens billed on this meter", + "title": "Tokens", + "type": "integer" + }, + "subtotal": { "anyOf": [ { - "type": "string" + "type": "number" }, { - "type": "null" + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" } ], - "default": null, - "description": "Model family (e.g., Meta, DeepSeek)", - "title": "Model Family" - }, + "description": "Cost of those tokens in dollars", + "title": "Subtotal" + } + }, + "required": [ + "tokens", + "subtotal" + ], + "title": "LoopsMeterUsageV1", + "type": "object" + }, + "LoopsResourceItemV1": { + "properties": { "subtotal": { "anyOf": [ { @@ -35246,44 +37041,50 @@ "type": "string" } ], - "description": "Subtotal cost in dollars for this model", + "description": "Cost in dollars across all four meters", "title": "Subtotal" }, - "input_tokens": { - "description": "Total input tokens for this model", - "title": "Input Tokens", - "type": "integer" + "uncached_prefill": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Prompt tokens that missed the prefix cache" }, - "output_tokens": { - "description": "Total output tokens for this model", - "title": "Output Tokens", - "type": "integer" + "cached_prefill": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Prompt tokens served from the prefix cache" }, - "cached_input_tokens": { - "description": "Total cached input tokens for this model", - "title": "Cached Input Tokens", - "type": "integer" + "sample": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Tokens generated by sampling" + }, + "train": { + "$ref": "#/components/schemas/LoopsMeterUsageV1", + "description": "Tokens processed by forward and forward-backward training calls" + }, + "billable_resource": { + "$ref": "#/components/schemas/BillableResourceV1", + "description": "The Loops run (LOOPS_RUN) or standalone sampler (LOOPS_SAMPLER). A resource that no longer exists has only its ID and kind set." }, "daily": { "description": "Daily usage breakdown", "items": { - "$ref": "#/components/schemas/DailyModelApiUsageV1" + "$ref": "#/components/schemas/DailyLoopsUsageV1" }, "title": "Daily", "type": "array" } }, "required": [ - "model_name", "subtotal", - "input_tokens", - "output_tokens", - "cached_input_tokens" + "uncached_prefill", + "cached_prefill", + "sample", + "train", + "billable_resource" ], - "title": "ModelApiItemV1", + "title": "LoopsResourceItemV1", "type": "object" }, - "ModelApisUsageV1": { + "LoopsUsageV1": { "properties": { "subtotal": { "anyOf": [ @@ -35295,7 +37096,132 @@ "type": "string" } ], - "description": "Subtotal cost in dollars after applying credits used", + "description": "Cost in dollars before credits", + "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-base-model usage breakdown", + "items": { + "$ref": "#/components/schemas/LoopsBaseModelItemV1" + }, + "title": "Breakdown", + "type": "array" + } + }, + "required": [ + "subtotal", + "credits_used", + "total" + ], + "title": "LoopsUsageV1", + "type": "object" + }, + "ModelApiItemV1": { + "properties": { + "model_name": { + "description": "Model name", + "title": "Model Name", + "type": "string" + }, + "model_family": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model family (e.g., Meta, DeepSeek)", + "title": "Model Family" + }, + "subtotal": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + } + ], + "description": "Subtotal cost in dollars for this model", + "title": "Subtotal" + }, + "input_tokens": { + "description": "Total input tokens for this model", + "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", + "title": "Cached Input Tokens", + "type": "integer" + }, + "daily": { + "description": "Daily usage breakdown", + "items": { + "$ref": "#/components/schemas/DailyModelApiUsageV1" + }, + "title": "Daily", + "type": "array" + } + }, + "required": [ + "model_name", + "subtotal", + "input_tokens", + "output_tokens", + "cached_input_tokens" + ], + "title": "ModelApiItemV1", + "type": "object" + }, + "ModelApisUsageV1": { + "properties": { + "subtotal": { + "anyOf": [ + { + "type": "number" + }, + { + "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$", + "type": "string" + } + ], + "description": "Subtotal cost in dollars after applying credits used", "title": "Subtotal" }, "credits_used": { @@ -35343,6 +37269,7 @@ }, "ResourceKind": { "enum": [ + "LOOPS_RUN", "LOOPS_SAMPLER", "LOOPS_TRAINER", "MODEL_DEPLOYMENT", @@ -35495,6 +37422,18 @@ ], "default": null, "description": "Model APIs usage" + }, + "loops_usage": { + "anyOf": [ + { + "$ref": "#/components/schemas/LoopsUsageV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Serverless Loops usage, billed per token. Loops usage on dedicated trainers and samplers is billed by the minute and is part of training usage." } }, "title": "UsageSummaryV1", @@ -35555,6 +37494,19 @@ "description": "Billable quantity in the provider's sku unit, summed over the calls.", "title": "Quantity", "type": "number" + }, + "team_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Team attributed to the usage. Null when not grouping by team or when historical team attribution is unavailable.", + "title": "Team Id" } }, "required": [ @@ -35582,6 +37534,13 @@ "title": "ToolCallUsageResponseV1", "type": "object" }, + "ToolCallUsageDimensionV1": { + "enum": [ + "TEAM" + ], + "title": "ToolCallUsageDimensionV1", + "type": "string" + }, "ToolCallUsageRequestV1": { "properties": { "start_date": { @@ -35603,6 +37562,22 @@ "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" + }, + "team_ids": { + "description": "Return only usage for these teams, repeated once per team. Defaults to all teams you can manage. An unauthorized team ID causes a 403 response.", + "items": { + "type": "string" + }, + "title": "Team Ids", + "type": "array" + }, + "group_by": { + "description": "Pass TEAM to split daily rows by team. Defaults to aggregating across teams.", + "items": { + "$ref": "#/components/schemas/ToolCallUsageDimensionV1" + }, + "title": "Group By", + "type": "array" } }, "required": [ @@ -36366,6 +38341,68 @@ "title": "ExploreMetadataRequestV1", "type": "object" }, + "CreateGridTokenRequestV1": { + "properties": { + "team_id": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "ID of the team. When omitted, the team you belong to; required when you belong to several.", + "examples": [ + "abc1234" + ], + "title": "Team Id" + } + }, + "title": "CreateGridTokenRequestV1", + "type": "object" + }, + "GridTokenV1": { + "properties": { + "token": { + "description": "Short-lived bearer token for the Grid gateway, scoped to you and the team. Send it as Authorization: Bearer .", + "title": "Token", + "type": "string" + }, + "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" + }, + "team_id": { + "description": "ID of the team the token invokes Grid routes in.", + "examples": [ + "abc1234" + ], + "title": "Team Id", + "type": "string" + }, + "team_name": { + "description": "Name of that team.", + "examples": [ + "Engineering" + ], + "title": "Team Name", + "type": "string" + } + }, + "required": [ + "token", + "expires_at", + "team_id", + "team_name" + ], + "title": "GridTokenV1", + "type": "object" + }, "GridClassifierV1": { "properties": { "id": { @@ -36392,6 +38429,62 @@ "title": "GridClassifierV1", "type": "object" }, + "GridRouteClassifierV1": { + "properties": { + "id": { + "description": "Stable route classifier identifier.", + "examples": [ + "general-v1" + ], + "title": "Id", + "type": "string" + }, + "name": { + "description": "Display name of the route classifier.", + "examples": [ + "General" + ], + "title": "Name", + "type": "string" + }, + "supported_tradeoffs": { + "description": "Tradeoffs the route classifier supports. Empty when it supports all of them.", + "items": { + "enum": [ + "cost", + "balanced", + "intelligence" + ], + "title": "GridRouteTradeoffV1", + "type": "string" + }, + "title": "Supported Tradeoffs", + "type": "array" + }, + "decidable_models": { + "description": "Model identities the route classifier picks from.", + "examples": [ + [ + "zai-org/GLM-5.3", + "anthropic/claude-opus-5-5" + ] + ], + "items": { + "type": "string" + }, + "title": "Decidable Models", + "type": "array" + } + }, + "required": [ + "id", + "name", + "supported_tradeoffs", + "decidable_models" + ], + "title": "GridRouteClassifierV1", + "type": "object" + }, "GridRouteRefV1": { "properties": { "id": { @@ -36503,6 +38596,37 @@ "title": "GridRouteTargetConnectionV1", "type": "object" }, + "GridRouteTargetIntelligentV1": { + "properties": { + "type": { + "const": "INTELLIGENT", + "description": "Target kind for an intelligent route: Baseten picks the model per request.", + "title": "Type", + "type": "string" + }, + "route_classifier": { + "$ref": "#/components/schemas/GridRouteClassifierV1", + "description": "Route classifier that picks the model." + }, + "tradeoff": { + "description": "How the classifier weighs cost against quality.", + "enum": [ + "cost", + "balanced", + "intelligence" + ], + "title": "GridRouteTradeoffV1", + "type": "string" + } + }, + "required": [ + "type", + "route_classifier", + "tradeoff" + ], + "title": "GridRouteTargetIntelligentV1", + "type": "object" + }, "GridRouteV1": { "properties": { "id": { @@ -36541,7 +38665,8 @@ "mapping": { "BASETEN_MODEL_API": "#/components/schemas/GridRouteTargetBasetenModelAPIV1", "CLASSIFIER": "#/components/schemas/GridRouteTargetClassifierV1", - "CONNECTION": "#/components/schemas/GridRouteTargetConnectionV1" + "CONNECTION": "#/components/schemas/GridRouteTargetConnectionV1", + "INTELLIGENT": "#/components/schemas/GridRouteTargetIntelligentV1" }, "propertyName": "type" }, @@ -36554,6 +38679,9 @@ }, { "$ref": "#/components/schemas/GridRouteTargetClassifierV1" + }, + { + "$ref": "#/components/schemas/GridRouteTargetIntelligentV1" } ], "title": "Target" @@ -36882,7 +39010,8 @@ "ANTHROPIC", "XAI", "VERTEX", - "OPENAI_COMPATIBLE" + "OPENAI_COMPATIBLE", + "BEDROCK" ], "title": "GridProviderV1", "type": "string" @@ -36911,6 +39040,16 @@ "title": "GridRouteUsageBucketV1", "type": "object" }, + "GridRouteUsageHarnessV1": { + "enum": [ + "CLAUDE_CODE", + "OPENCODE", + "CODEX", + "PI" + ], + "title": "GridRouteUsageHarnessV1", + "type": "string" + }, "GridRouteUsageResultV1": { "properties": { "user_id": { @@ -36990,6 +39129,18 @@ "description": "Slug of the intelligent router, matching its name in `GET /v1/grid/routes`. Null when not grouping by ROUTER.", "title": "Router Id" }, + "harness": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridRouteUsageHarnessV1" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Coding harness. Null when not grouping by HARNESS, when no harness was recorded (including usage from before harness tracking), or when the recorded harness is not recognized by this API version." + }, "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": [ @@ -37063,7 +39214,8 @@ "TEAM", "MODEL", "PROVIDER", - "ROUTER" + "ROUTER", + "HARNESS" ], "title": "GridRouteUsageDimensionV1", "type": "string" @@ -37133,7 +39285,7 @@ "title": "End Date" }, "group_by": { - "description": "Dimensions to break usage down by, repeated once per dimension: USER, TEAM, MODEL, PROVIDER, or ROUTER. 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. ROUTER returns only usage sent through an intelligent router, one row per router, or per router and model with MODEL. Router rows repeat usage already counted in other groupings, so don't add them to model totals. Defaults to MODEL.", + "description": "Dimensions to break usage down by, repeated once per dimension: USER, TEAM, MODEL, PROVIDER, ROUTER, or HARNESS. 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. ROUTER returns only usage sent through an intelligent router, one row per router, or per router and model with MODEL. Router rows repeat usage already counted in other groupings, so don't add them to model totals. HARNESS includes usage with no recorded harness as a null group. Defaults to MODEL.", "items": { "$ref": "#/components/schemas/GridRouteUsageDimensionV1" }, @@ -37163,6 +39315,14 @@ }, "title": "Providers", "type": "array" + }, + "harnesses": { + "description": "Return only usage for these harnesses, repeated once per harness. Omit to include all usage, including usage with no recorded harness.", + "items": { + "$ref": "#/components/schemas/GridRouteUsageHarnessV1" + }, + "title": "Harnesses", + "type": "array" } }, "title": "GridRouteUsageRequestV1", @@ -37305,11 +39465,11 @@ "description": "Default models for OpenCode." }, "codex": { - "$ref": "#/components/schemas/GridPrimaryHarnessDefaultsV1", + "$ref": "#/components/schemas/GridBackgroundHarnessDefaultsV1", "description": "Default models for Codex." }, "pi": { - "$ref": "#/components/schemas/GridPrimaryHarnessDefaultsV1", + "$ref": "#/components/schemas/GridBackgroundHarnessDefaultsV1", "description": "Default models for Pi." } }, @@ -37340,26 +39500,6 @@ "title": "GridHarnessModelV1", "type": "object" }, - "GridPrimaryHarnessDefaultsV1": { - "properties": { - "primary": { - "anyOf": [ - { - "$ref": "#/components/schemas/GridHarnessModelV1" - }, - { - "type": "null" - } - ], - "description": "Route for the primary model, which new sessions use. Null when the team has no route to use." - } - }, - "required": [ - "primary" - ], - "title": "GridPrimaryHarnessDefaultsV1", - "type": "object" - }, "GridSettingSourceV1": { "enum": [ "user", @@ -37544,7 +39684,7 @@ "codex": { "anyOf": [ { - "$ref": "#/components/schemas/UpdateGridPrimaryHarnessModelsV1" + "$ref": "#/components/schemas/UpdateGridBackgroundHarnessModelsV1" }, { "type": "null" @@ -37557,7 +39697,7 @@ "pi": { "anyOf": [ { - "$ref": "#/components/schemas/UpdateGridPrimaryHarnessModelsV1" + "$ref": "#/components/schemas/UpdateGridBackgroundHarnessModelsV1" }, { "type": "null" @@ -37571,32 +39711,6 @@ "title": "UpdateGridHarnessDefaultsV1", "type": "object" }, - "UpdateGridPrimaryHarnessModelsV1": { - "additionalProperties": false, - "minProperties": 1, - "properties": { - "primary": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Route ID for the primary model, which new sessions use. Omit to keep the current route, or pass null to use the team's default.", - "examples": [ - "abc1234" - ], - "title": "Primary", - "x-null-distinct": true - } - }, - "title": "UpdateGridPrimaryHarnessModelsV1", - "type": "object" - }, "UpdateGridTeamSpendLimitSettingV1": { "additionalProperties": false, "minProperties": 1, @@ -38069,6 +40183,36 @@ "title": "UpdateGridUserSettingsRequestV1", "type": "object" }, + "GridConnectionBedrockAccessKeysAuthV1": { + "properties": { + "method": { + "const": "access_keys", + "description": "The secret holds the access keys of an IAM user, as the base64-encoded JSON object `{\"AccessKeyId\": \"...\", \"SecretAccessKey\": \"...\"}`", + "title": "Method", + "type": "string" + } + }, + "required": [ + "method" + ], + "title": "GridConnectionBedrockAccessKeysAuthV1", + "type": "object" + }, + "GridConnectionBedrockApiKeyAuthV1": { + "properties": { + "method": { + "const": "api_key", + "description": "The secret holds a long-term Amazon Bedrock API key.", + "title": "Method", + "type": "string" + } + }, + "required": [ + "method" + ], + "title": "GridConnectionBedrockApiKeyAuthV1", + "type": "object" + }, "GridConnectionConfigAnthropicV1": { "properties": { "provider": { @@ -38096,6 +40240,59 @@ "title": "GridConnectionConfigAnthropicV1", "type": "object" }, + "GridConnectionConfigBedrockV1": { + "properties": { + "provider": { + "const": "BEDROCK", + "description": "Provider kind for Amazon Bedrock.", + "title": "Provider", + "type": "string" + }, + "secret_id": { + "description": "Identifier of the team secret holding the provider API key.", + "title": "Secret Id", + "type": "string" + }, + "secret_name": { + "description": "Name of the team secret holding the provider API key.", + "title": "Secret Name", + "type": "string" + }, + "region": { + "description": "AWS Region of the Amazon Bedrock endpoint.", + "title": "Region", + "type": "string" + }, + "auth": { + "description": "How the connection's secret authenticates with Amazon Bedrock.", + "discriminator": { + "mapping": { + "access_keys": "#/components/schemas/GridConnectionBedrockAccessKeysAuthV1", + "api_key": "#/components/schemas/GridConnectionBedrockApiKeyAuthV1" + }, + "propertyName": "method" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/GridConnectionBedrockApiKeyAuthV1" + }, + { + "$ref": "#/components/schemas/GridConnectionBedrockAccessKeysAuthV1" + } + ], + "title": "Auth" + } + }, + "required": [ + "provider", + "secret_id", + "secret_name", + "region", + "auth" + ], + "title": "GridConnectionConfigBedrockV1", + "type": "object" + }, "GridConnectionConfigOpenAIV1": { "properties": { "provider": { @@ -38123,6 +40320,45 @@ "title": "GridConnectionConfigOpenAIV1", "type": "object" }, + "GridConnectionConfigVertexV1": { + "properties": { + "provider": { + "const": "VERTEX", + "description": "Provider kind for Google Vertex.", + "title": "Provider", + "type": "string" + }, + "secret_id": { + "description": "Identifier of the team secret holding the provider API key.", + "title": "Secret Id", + "type": "string" + }, + "secret_name": { + "description": "Name of the team secret holding the provider API key.", + "title": "Secret Name", + "type": "string" + }, + "project_id": { + "description": "Google Cloud project ID or number of a project with Vertex AI enabled.", + "title": "Project Id", + "type": "string" + }, + "location": { + "description": "Google Cloud region that serves the Vertex AI models, for example `us-central1`.", + "title": "Location", + "type": "string" + } + }, + "required": [ + "provider", + "secret_id", + "secret_name", + "project_id", + "location" + ], + "title": "GridConnectionConfigVertexV1", + "type": "object" + }, "GridConnectionConfigXAIV1": { "properties": { "provider": { @@ -38172,7 +40408,9 @@ "discriminator": { "mapping": { "ANTHROPIC": "#/components/schemas/GridConnectionConfigAnthropicV1", + "BEDROCK": "#/components/schemas/GridConnectionConfigBedrockV1", "OPENAI": "#/components/schemas/GridConnectionConfigOpenAIV1", + "VERTEX": "#/components/schemas/GridConnectionConfigVertexV1", "XAI": "#/components/schemas/GridConnectionConfigXAIV1" }, "propertyName": "provider" @@ -38186,6 +40424,12 @@ }, { "$ref": "#/components/schemas/GridConnectionConfigXAIV1" + }, + { + "$ref": "#/components/schemas/GridConnectionConfigVertexV1" + }, + { + "$ref": "#/components/schemas/GridConnectionConfigBedrockV1" } ], "title": "Config" @@ -38269,92 +40513,588 @@ } ], "default": null, - "description": "Limit connections to this team. Without it, connections from every team where you can invoke routes.", + "description": "Limit connections to this team. Without it, connections from every team where you can invoke routes.", + "title": "Team Id" + } + }, + "title": "GridConnectionsRequestV1", + "type": "object" + }, + "UpsertGridConnectionBedrockAccessKeysAuthV1": { + "additionalProperties": false, + "properties": { + "method": { + "const": "access_keys", + "description": "The secret holds the access keys of an IAM user, as the base64-encoded JSON object `{\"AccessKeyId\": \"...\", \"SecretAccessKey\": \"...\"}`", + "title": "Method", + "type": "string" + } + }, + "required": [ + "method" + ], + "title": "UpsertGridConnectionBedrockAccessKeysAuthV1", + "type": "object" + }, + "UpsertGridConnectionBedrockApiKeyAuthV1": { + "additionalProperties": false, + "properties": { + "method": { + "const": "api_key", + "description": "The secret holds a long-term Amazon Bedrock API key.", + "title": "Method", + "type": "string" + } + }, + "required": [ + "method" + ], + "title": "UpsertGridConnectionBedrockApiKeyAuthV1", + "type": "object" + }, + "UpsertGridConnectionConfigAnthropicV1": { + "additionalProperties": false, + "properties": { + "provider": { + "const": "ANTHROPIC", + "description": "Provider kind for Anthropic.", + "title": "Provider", + "type": "string" + }, + "secret_name": { + "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", + "examples": [ + "anthropic-key" + ], + "minLength": 1, + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "provider", + "secret_name" + ], + "title": "UpsertGridConnectionConfigAnthropicV1", + "type": "object" + }, + "UpsertGridConnectionConfigBedrockV1": { + "additionalProperties": false, + "properties": { + "provider": { + "const": "BEDROCK", + "description": "Provider kind for Amazon Bedrock. Claude models (`anthropic.*`) use the Anthropic Messages API, and other models use the OpenAI-compatible APIs.", + "title": "Provider", + "type": "string" + }, + "secret_name": { + "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", + "examples": [ + "anthropic-key" + ], + "minLength": 1, + "title": "Secret Name", + "type": "string" + }, + "region": { + "description": "AWS Region of the Amazon Bedrock endpoint, for example `us-east-1`.", + "examples": [ + "us-east-1" + ], + "minLength": 1, + "title": "Region", + "type": "string" + }, + "auth": { + "description": "How the connection's secret authenticates with Amazon Bedrock.", + "discriminator": { + "mapping": { + "access_keys": "#/components/schemas/UpsertGridConnectionBedrockAccessKeysAuthV1", + "api_key": "#/components/schemas/UpsertGridConnectionBedrockApiKeyAuthV1" + }, + "propertyName": "method" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/UpsertGridConnectionBedrockApiKeyAuthV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionBedrockAccessKeysAuthV1" + } + ], + "title": "Auth" + } + }, + "required": [ + "provider", + "secret_name", + "region", + "auth" + ], + "title": "UpsertGridConnectionConfigBedrockV1", + "type": "object" + }, + "UpsertGridConnectionConfigOpenAIV1": { + "additionalProperties": false, + "properties": { + "provider": { + "const": "OPENAI", + "description": "Provider kind for OpenAI.", + "title": "Provider", + "type": "string" + }, + "secret_name": { + "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", + "examples": [ + "anthropic-key" + ], + "minLength": 1, + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "provider", + "secret_name" + ], + "title": "UpsertGridConnectionConfigOpenAIV1", + "type": "object" + }, + "UpsertGridConnectionConfigVertexV1": { + "additionalProperties": false, + "properties": { + "provider": { + "const": "VERTEX", + "description": "Provider kind for Google Vertex.", + "title": "Provider", + "type": "string" + }, + "secret_name": { + "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", + "examples": [ + "anthropic-key" + ], + "minLength": 1, + "title": "Secret Name", + "type": "string" + }, + "project_id": { + "description": "Google Cloud project ID or number of a project with Vertex AI enabled.", + "examples": [ + "my-gcp-project" + ], + "minLength": 1, + "title": "Project Id", + "type": "string" + }, + "location": { + "description": "Google Cloud region that serves the Vertex AI models, for example `us-central1`.", + "examples": [ + "us-central1" + ], + "minLength": 1, + "title": "Location", + "type": "string" + } + }, + "required": [ + "provider", + "secret_name", + "project_id", + "location" + ], + "title": "UpsertGridConnectionConfigVertexV1", + "type": "object" + }, + "UpsertGridConnectionConfigXAIV1": { + "additionalProperties": false, + "properties": { + "provider": { + "const": "XAI", + "description": "Provider kind for xAI.", + "title": "Provider", + "type": "string" + }, + "secret_name": { + "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", + "examples": [ + "anthropic-key" + ], + "minLength": 1, + "title": "Secret Name", + "type": "string" + } + }, + "required": [ + "provider", + "secret_name" + ], + "title": "UpsertGridConnectionConfigXAIV1", + "type": "object" + }, + "CreateGridConnectionRequestV1": { + "additionalProperties": false, + "properties": { + "team_id": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Identifier of the team that owns the connection.", + "examples": [ + "abc1234" + ], + "title": "Team Id" + }, + "config": { + "description": "Provider the connection authenticates with, and the team secret holding its API key.", + "discriminator": { + "mapping": { + "ANTHROPIC": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1", + "BEDROCK": "#/components/schemas/UpsertGridConnectionConfigBedrockV1", + "OPENAI": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1", + "VERTEX": "#/components/schemas/UpsertGridConnectionConfigVertexV1", + "XAI": "#/components/schemas/UpsertGridConnectionConfigXAIV1" + }, + "propertyName": "provider" + }, + "examples": [ + { + "provider": "ANTHROPIC", + "secret_name": "anthropic-key" + } + ], + "oneOf": [ + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigXAIV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigVertexV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigBedrockV1" + } + ], + "title": "Config" + } + }, + "required": [ + "config" + ], + "title": "CreateGridConnectionRequestV1", + "type": "object" + }, + "GridConnectionTombstoneV1": { + "properties": { + "id": { + "description": "Stable identifier of the deleted connection.", + "title": "Id", + "type": "string" + } + }, + "required": [ + "id" + ], + "title": "GridConnectionTombstoneV1", + "type": "object" + }, + "UpdateGridConnectionRequestV1": { + "additionalProperties": false, + "properties": { + "config": { + "description": "Complete new connection configuration, replacing the current one. The provider must match the connection and is immutable.", + "discriminator": { + "mapping": { + "ANTHROPIC": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1", + "BEDROCK": "#/components/schemas/UpsertGridConnectionConfigBedrockV1", + "OPENAI": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1", + "VERTEX": "#/components/schemas/UpsertGridConnectionConfigVertexV1", + "XAI": "#/components/schemas/UpsertGridConnectionConfigXAIV1" + }, + "propertyName": "provider" + }, + "examples": [ + { + "provider": "ANTHROPIC", + "secret_name": "anthropic-key" + } + ], + "oneOf": [ + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigXAIV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigVertexV1" + }, + { + "$ref": "#/components/schemas/UpsertGridConnectionConfigBedrockV1" + } + ], + "title": "Config" + } + }, + "required": [ + "config" + ], + "title": "UpdateGridConnectionRequestV1", + "type": "object" + }, + "GridClassifiersResponseV1": { + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/GridClassifierV1" + }, + "title": "Items", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "GridClassifiersResponseV1", + "type": "object" + }, + "GridClassifiersRequestV1": { + "properties": { + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "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" + } + }, + "title": "GridClassifiersRequestV1", + "type": "object" + }, + "GridRouteClassifiersResponseV1": { + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/GridRouteClassifierV1" + }, + "title": "Items", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "GridRouteClassifiersResponseV1", + "type": "object" + }, + "GridRouteClassifiersRequestV1": { + "properties": { + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "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" + } + }, + "title": "GridRouteClassifiersRequestV1", + "type": "object" + }, + "GridMachineUserV1": { + "properties": { + "id": { + "description": "Stable machine user identifier. Grid usage and settings identify the machine user by this ID as its `user_id`.", + "title": "Id", + "type": "string" + }, + "name": { + "description": "Name of the machine user, unique within its team.", + "title": "Name", + "type": "string" + }, + "team_id": { + "description": "Identifier of the team that owns the machine user.", + "title": "Team Id", + "type": "string" + }, + "team_name": { + "description": "Name of the team that owns the machine user.", + "title": "Team Name", + "type": "string" + }, + "created_by": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "ID of the user who created the machine user. Null when unknown.", + "title": "Created By" + }, + "created_at": { + "description": "Creation time, ISO 8601.", + "format": "date-time", + "title": "Created At", + "type": "string" + } + }, + "required": [ + "id", + "name", + "team_id", + "team_name", + "created_at" + ], + "title": "GridMachineUserV1", + "type": "object" + }, + "GridMachineUsersResponseV1": { + "properties": { + "items": { + "description": "Items in this page.", + "items": { + "$ref": "#/components/schemas/GridMachineUserV1" + }, + "title": "Items", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationResponseV1", + "description": "Pagination metadata for the page." + } + }, + "required": [ + "items", + "pagination" + ], + "title": "GridMachineUsersResponseV1", + "type": "object" + }, + "GridMachineUsersRequestV1": { + "properties": { + "cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "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" + }, + "team_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Limit machine users to this team. Without it, every team you administer.", "title": "Team Id" } }, - "title": "GridConnectionsRequestV1", - "type": "object" - }, - "UpsertGridConnectionConfigAnthropicV1": { - "additionalProperties": false, - "properties": { - "provider": { - "const": "ANTHROPIC", - "description": "Provider kind for Anthropic.", - "title": "Provider", - "type": "string" - }, - "secret_name": { - "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", - "examples": [ - "anthropic-key" - ], - "minLength": 1, - "title": "Secret Name", - "type": "string" - } - }, - "required": [ - "provider", - "secret_name" - ], - "title": "UpsertGridConnectionConfigAnthropicV1", + "title": "GridMachineUsersRequestV1", "type": "object" }, - "UpsertGridConnectionConfigOpenAIV1": { + "CreateGridMachineUserAPIKeyRequestV1": { "additionalProperties": false, "properties": { - "provider": { - "const": "OPENAI", - "description": "Provider kind for OpenAI.", - "title": "Provider", - "type": "string" - }, - "secret_name": { - "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", - "examples": [ - "anthropic-key" + "name": { + "anyOf": [ + { + "maxLength": 255, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } ], - "minLength": 1, - "title": "Secret Name", - "type": "string" - } - }, - "required": [ - "provider", - "secret_name" - ], - "title": "UpsertGridConnectionConfigOpenAIV1", - "type": "object" - }, - "UpsertGridConnectionConfigXAIV1": { - "additionalProperties": false, - "properties": { - "provider": { - "const": "XAI", - "description": "Provider kind for xAI.", - "title": "Provider", - "type": "string" - }, - "secret_name": { - "description": "Name of an existing secret, owned by the same team, that holds the provider API key.", + "default": null, + "description": "Name of the API key: lowercase letters, numbers, and hyphens, at most 255 characters, and unique among the machine user's active keys. Defaults to a name derived from the machine user's.", "examples": [ - "anthropic-key" + "production" ], - "minLength": 1, - "title": "Secret Name", - "type": "string" + "title": "Name" } }, - "required": [ - "provider", - "secret_name" - ], - "title": "UpsertGridConnectionConfigXAIV1", + "title": "CreateGridMachineUserAPIKeyRequestV1", "type": "object" }, - "CreateGridConnectionRequestV1": { + "CreateGridMachineUserRequestV1": { "additionalProperties": false, "properties": { "team_id": { @@ -38368,128 +41108,128 @@ } ], "default": null, - "description": "Identifier of the team that owns the connection.", + "description": "Identifier of the team that owns the machine user. Defaults to your only team, if you belong to exactly one.", "examples": [ "abc1234" ], "title": "Team Id" }, - "config": { - "description": "Provider the connection authenticates with, and the team secret holding its API key.", - "discriminator": { - "mapping": { - "ANTHROPIC": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1", - "OPENAI": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1", - "XAI": "#/components/schemas/UpsertGridConnectionConfigXAIV1" - }, - "propertyName": "provider" - }, + "name": { + "description": "Name of the machine user, unique within the team. At most 255 characters.", "examples": [ - { - "provider": "ANTHROPIC", - "secret_name": "anthropic-key" - } + "night-shift" ], - "oneOf": [ - { - "$ref": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1" - }, + "maxLength": 255, + "minLength": 1, + "title": "Name", + "type": "string" + }, + "api_key": { + "anyOf": [ { - "$ref": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1" + "$ref": "#/components/schemas/CreateGridMachineUserAPIKeyRequestV1" }, { - "$ref": "#/components/schemas/UpsertGridConnectionConfigXAIV1" + "type": "null" } ], - "title": "Config" + "default": null, + "description": "When set, also creates the machine user's first API key." } }, "required": [ - "config" + "name" ], - "title": "CreateGridConnectionRequestV1", + "title": "CreateGridMachineUserRequestV1", "type": "object" }, - "GridConnectionTombstoneV1": { + "CreatedGridMachineUserV1": { "properties": { "id": { - "description": "Stable identifier of the deleted connection.", + "description": "Stable machine user identifier. Grid usage and settings identify the machine user by this ID as its `user_id`.", "title": "Id", "type": "string" - } - }, - "required": [ - "id" - ], - "title": "GridConnectionTombstoneV1", - "type": "object" - }, - "UpdateGridConnectionRequestV1": { - "additionalProperties": false, - "properties": { - "config": { - "description": "Complete new connection configuration, replacing the current one. The provider must match the connection and is immutable.", - "discriminator": { - "mapping": { - "ANTHROPIC": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1", - "OPENAI": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1", - "XAI": "#/components/schemas/UpsertGridConnectionConfigXAIV1" + }, + "name": { + "description": "Name of the machine user, unique within its team.", + "title": "Name", + "type": "string" + }, + "team_id": { + "description": "Identifier of the team that owns the machine user.", + "title": "Team Id", + "type": "string" + }, + "team_name": { + "description": "Name of the team that owns the machine user.", + "title": "Team Name", + "type": "string" + }, + "created_by": { + "anyOf": [ + { + "type": "string" }, - "propertyName": "provider" - }, - "examples": [ { - "provider": "ANTHROPIC", - "secret_name": "anthropic-key" + "type": "null" } ], - "oneOf": [ - { - "$ref": "#/components/schemas/UpsertGridConnectionConfigAnthropicV1" - }, + "default": null, + "description": "ID of the user who created the machine user. Null when unknown.", + "title": "Created By" + }, + "created_at": { + "description": "Creation time, ISO 8601.", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "api_key": { + "anyOf": [ { - "$ref": "#/components/schemas/UpsertGridConnectionConfigOpenAIV1" + "type": "string" }, { - "$ref": "#/components/schemas/UpsertGridConnectionConfigXAIV1" + "type": "null" } ], - "title": "Config" + "default": null, + "description": "The first API key, returned only once. Null unless the request set `api_key`.", + "title": "Api Key" } }, "required": [ - "config" + "id", + "name", + "team_id", + "team_name", + "created_at" ], - "title": "UpdateGridConnectionRequestV1", + "title": "CreatedGridMachineUserV1", "type": "object" }, - "GridClassifiersResponseV1": { + "GridMachineUserTombstoneV1": { "properties": { - "items": { - "description": "Items in this page.", - "items": { - "$ref": "#/components/schemas/GridClassifierV1" - }, - "title": "Items", - "type": "array" - }, - "pagination": { - "$ref": "#/components/schemas/PaginationResponseV1", - "description": "Pagination metadata for the page." + "id": { + "description": "Stable identifier of the deleted machine user.", + "title": "Id", + "type": "string" } }, "required": [ - "items", - "pagination" + "id" ], - "title": "GridClassifiersResponseV1", + "title": "GridMachineUserTombstoneV1", "type": "object" }, - "GridClassifiersRequestV1": { + "UpdateGridMachineUserRequestV1": { + "additionalProperties": false, "properties": { - "cursor": { + "name": { "anyOf": [ { + "maxLength": 255, + "minLength": 1, "type": "string" }, { @@ -38497,27 +41237,23 @@ } ], "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": "Name of the machine user, unique within its team. At most 255 characters. Omit to keep it.", + "title": "Name" } }, - "title": "GridClassifiersRequestV1", + "title": "UpdateGridMachineUserRequestV1", "type": "object" }, "EndpointTargetV1": { "description": "One configured upstream target of an endpoint.", "properties": { "provider": { - "$ref": "#/components/schemas/GatewayProvider", - "description": "Upstream provider." + "$ref": "#/components/schemas/GatewayEndpointProviderV1", + "description": "Upstream provider.", + "examples": [ + "ANTHROPIC", + "OPENAI_COMPATIBLE" + ] }, "secret_id": { "anyOf": [ @@ -38655,7 +41391,7 @@ "title": "EndpointV1", "type": "object" }, - "GatewayProvider": { + "GatewayEndpointProviderV1": { "enum": [ "ANTHROPIC", "OPENAI", @@ -38665,7 +41401,7 @@ "VERTEX", "OPENAI_COMPATIBLE" ], - "title": "GatewayProvider", + "title": "GatewayEndpointProviderV1", "type": "string" }, "SharedEndpointRegionV1": { @@ -38729,7 +41465,7 @@ "description": "One desired upstream target. The customer picks a provider; Baseten owns the\nupstream host and protocol adapter.", "properties": { "provider": { - "$ref": "#/components/schemas/GatewayProvider", + "$ref": "#/components/schemas/GatewayEndpointProviderV1", "description": "Upstream provider for this target.", "examples": [ "ANTHROPIC", @@ -39231,6 +41967,43 @@ "title": "ModelConfigV1", "type": "object" }, + "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" + ] + }, + "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" + }, "UsageLimitUnitV1": { "enum": [ "DAY" @@ -40514,11 +43287,18 @@ }, "memory": { "type": "integer", - "description": "Memory allocation in megabytes. Also determines CPU allocation (CPU cores = memory in MB / 2048, e.g., 4096MB = 2 CPUs). Must be between 1024 and 262144.", + "description": "Memory allocation in megabytes. Must be between 1024 and 262144. When cpu is not set at creation, memory also determines the CPU allocation (by default 2048 MB = 1 vCPU, 4096 MB = 2, 8192 MB = 4, 16384 MB = 6, 32768 MB = 8, 65536 MB = 16, 131072 MB or more = 32).", "example": 4096, "minimum": 512, "maximum": 262144 }, + "cpu": { + "type": "integer", + "description": "Number of vCPUs the sandbox runs with. Always returned, including for sandboxes created without cpu, whose CPU allocation was derived from memory. Set at creation only.", + "example": 2, + "minimum": 1, + "maximum": 32 + }, "filesystem": { "description": "Filesystem configuration. Set at creation only.", "allOf": [ @@ -40644,6 +43424,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -40775,12 +43556,18 @@ }, "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. Must be between 1024 and 262144.", - "default": 4096, + "description": "Memory allocation in megabytes. Must be between 1024 and 262144. Defaults to 4096, or to 8192 MB per vCPU (a 1:8 ratio) when only cpu is set, capped at the account's memory quota. When cpu is omitted, memory also determines the CPU allocation (by default 2048 MB = 1 vCPU, 4096 MB = 2, 8192 MB = 4, 16384 MB = 6, 32768 MB = 8, 65536 MB = 16, 131072 MB or more = 32).", "example": 4096, "minimum": 512, "maximum": 262144 }, + "cpu": { + "type": "integer", + "description": "Optional number of vCPUs, a whole number between 1 and 32. When omitted, the CPU allocation is derived from memory. When set, memory must be between 1024 and 8192 megabytes per vCPU (a ratio from 1:1 to 1:8), and cpu must not exceed the account's per-sandbox cpu quota. A value equal to the allocation memory alone would give is always accepted. When memory is omitted, it defaults to 8192 MB per vCPU, capped at the account's memory quota. Immutable after creation.", + "example": 2, + "minimum": 1, + "maximum": 32 + }, "filesystem": { "description": "Filesystem configuration. Set at creation only.", "allOf": [ @@ -40907,6 +43694,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -40924,7 +43712,7 @@ }, "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, network, region, image, ports, filesystem, and volumes are immutable after creation. Supplying any of these fields returns 400, including unchanged, empty, or null values.", + "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, cpu, network, region, image, ports, filesystem, and volumes are immutable after creation. Supplying any of these fields returns 400, including unchanged, empty, or null values.", "properties": { "lifecycle": { "description": "Lifecycle configuration controlling automatic sandbox deletion based on idle time, max age, or specific dates", @@ -41197,6 +43985,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -41343,6 +44132,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -41454,6 +44244,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -42640,6 +45431,22 @@ "in": "path", "required": true }, + "route_classifier_id": { + "schema": { + "type": "string" + }, + "name": "route_classifier_id", + "in": "path", + "required": true + }, + "machine_user_id": { + "schema": { + "type": "string" + }, + "name": "machine_user_id", + "in": "path", + "required": true + }, "endpoint_id": { "schema": { "type": "string" @@ -43000,6 +45807,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -43130,6 +45938,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -43224,6 +46033,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -43318,6 +46128,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -43413,6 +46224,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", @@ -43515,6 +46327,7 @@ ], "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "ports": [ { "name": "http", diff --git a/scripts/apigen/specs/sandbox.yml b/scripts/apigen/specs/sandbox.yml index 1a0e0dd..c0d2692 100644 --- a/scripts/apigen/specs/sandbox.yml +++ b/scripts/apigen/specs/sandbox.yml @@ -458,6 +458,48 @@ paths: summary: Search for text content in files tags: - filesystem + /filesystem-copy: + post: + description: >- + Recursively copy a file or directory in one request, placed like `cp -r`: when destination is an existing directory (or a symlink to one), the copy goes inside it, named after source; otherwise destination is the copy's path. Relative paths use the filesystem working directory. Source symlinks are copied as symlinks; special files are refused. By default existing files are overwritten and existing directories merged. + + + With noOverwrite=true, every entry is created exclusively (O_EXCL, mkdir, symlink), with no check-then-write race: an existing final target, including an empty directory or a dangling symlink, returns 409 with code FILE_ALREADY_EXISTS and is left unchanged. A copy is not a transaction: on a later failure, entries it already created remain. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CopyRequest" + description: Source, destination, and optional noOverwrite flag + required: true + responses: + "200": + description: Files copied + content: + application/json: + schema: + $ref: "#/components/schemas/CopyResponse" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "409": + description: Destination exists (FILE_ALREADY_EXISTS) + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "422": + description: Copy failed + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Copy a file or directory + tags: + - filesystem "/filesystem-find/{path}": get: description: Finds files and directories using the find command. @@ -1755,6 +1797,43 @@ paths: summary: Write to a process's stdin tags: - process + "/process/{identifier}/wait": + get: + description: "Hold the request until the process is over for good (no restart to come) or the timeout expires, then return the process like GET /process/{identifier}. A process still running after the timeout comes back with status running: call again. Replaces polling GET /process/{identifier}." + parameters: + - description: Process identifier (PID or name) + in: path + name: identifier + required: true + schema: + type: string + - description: Seconds to wait (default and max 119; larger values are capped) + in: query + name: timeout + schema: + type: integer + responses: + "200": + description: Process information + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessResponse" + "400": + description: Invalid timeout + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: Process not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + summary: Wait for a process to finish + tags: + - process /upgrade: post: description: >- @@ -1766,7 +1845,9 @@ paths: 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) + Binaries are downloaded from https://github.com/blaxel-ai/sandbox/releases; requests with a baseUrl are rejected. + + Releases that still accepted a baseUrl are refused, and the refusal is reported in the health endpoint's lastUpgrade. requestBody: content: application/json: @@ -1780,6 +1861,12 @@ paths: application/json: schema: $ref: "#/components/schemas/SuccessResponse" + "400": + description: Invalid version or baseUrl + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" "500": description: Internal server error content: @@ -1989,6 +2076,35 @@ components: - query - total type: object + CopyRequest: + properties: + destination: + example: /app/destination + type: string + noOverwrite: + default: false + example: false + type: boolean + source: + example: /app/source + type: string + required: + - destination + - source + type: object + CopyResponse: + properties: + destination: + type: string + message: + type: string + source: + type: string + required: + - destination + - message + - source + type: object Directory: properties: files: @@ -2096,6 +2212,9 @@ components: type: object ErrorResponse: properties: + code: + example: FILE_ALREADY_EXISTS + type: string error: example: Error message type: string @@ -2525,6 +2644,14 @@ components: type: object ProcessRequest: properties: + callbackSecret: + description: Key the webhook is signed with (HMAC-SHA256, X-Blaxel-Signature header). At least 32 characters; required with callbackUrl. Never returned by the API. + example: a-random-secret-of-at-least-32-chars + type: string + callbackUrl: + description: URL that receives a signed process.exited webhook when the process ends for good (not on auto-restart). Requires callbackSecret. + example: https://example.com/hooks/process + type: string command: example: ls -la type: string @@ -2787,11 +2914,10 @@ components: UpgradeRequest: properties: baseUrl: - description: Base URL for releases (useful for forks) - example: https://github.com/blaxel-ai/sandbox/releases + description: "Deprecated: custom binary sources are not accepted" type: string version: - description: 'Version to upgrade to: "latest" (default), "develop", "main", or specific tag like "v1.0.0"' + description: 'Version to upgrade to: "latest" (default), "develop", "main", or a release tag like "v1.0.0"' example: latest type: string type: object diff --git a/tests/client/test_e2e.py b/tests/client/test_e2e.py index b7599ce..c40502b 100644 --- a/tests/client/test_e2e.py +++ b/tests/client/test_e2e.py @@ -17,6 +17,7 @@ import os import uuid from collections.abc import Callable +from datetime import UTC, datetime, timedelta from typing import Any import pytest @@ -150,6 +151,7 @@ async def test_api_key_crud() -> None: request=baseten.client.managementapi.CreateAPIKeyRequest( name=key_name, type="PERSONAL", + expires_at=datetime.now(UTC) + timedelta(days=1), ), ) assert created.api_key diff --git a/tests/sandbox/test_client.py b/tests/sandbox/test_client.py index c724002..eabe711 100644 --- a/tests/sandbox/test_client.py +++ b/tests/sandbox/test_client.py @@ -136,6 +136,7 @@ def test_creates_with_every_field_mapped(self) -> None: create_if_not_exists=True, image="img:1", memory=2048, + cpu=1, region="us-was-1", envs={"A": SandboxEnvValue(value="1", secret=False)}, labels={"team": "infra"}, @@ -155,6 +156,7 @@ def test_creates_with_every_field_mapped(self) -> None: "create_if_not_exists": True, "image": "img:1", "memory": 2048, + "cpu": 1, "region": "us-was-1", "envs": [{"name": "A", "value": "1", "secret": False}], "labels": {"team": "infra"}, @@ -479,6 +481,7 @@ def _info() -> SandboxInfo: status="DEPLOYED", image=None, memory=None, + cpu=None, region=None, envs={}, labels={}, diff --git a/tests/sandbox/test_info.py b/tests/sandbox/test_info.py index ba7804d..847275f 100644 --- a/tests/sandbox/test_info.py +++ b/tests/sandbox/test_info.py @@ -32,6 +32,7 @@ "status": "DEPLOYED", "image": "baseten/base-image:latest", "memory": 4096, + "cpu": 2, "region": "us-was-1", "envs": [ {"name": "PLAIN", "value": "shown", "secret": False}, @@ -74,9 +75,10 @@ def test_maps_sandbox_record() -> None: assert info.name == "sbx" assert info.url == "https://sbx.example.dev/" assert info.status == "DEPLOYED" - assert (info.image, info.memory, info.region) == ( + assert (info.image, info.memory, info.cpu, info.region) == ( "baseten/base-image:latest", 4096, + 2, "us-was-1", ) # An env without a name is left out. diff --git a/tests/sandbox/test_parity.py b/tests/sandbox/test_parity.py index fc6a5c9..f17f752 100644 --- a/tests/sandbox/test_parity.py +++ b/tests/sandbox/test_parity.py @@ -133,6 +133,10 @@ def _kwargs(method: Callable[..., Any]) -> set[str]: "waitForCompletion": "wait_for_completion", "waitForPorts": "wait_for_ports", } +_PROCESS_REQUEST_UNSUPPORTED = { + "callbackUrl": "process exit webhooks not supported yet", + "callbackSecret": "process exit webhooks not supported yet", +} _POLICY_RENAMES = {"value": "after"} _POLICY_TYPE = {"type": "set by which policy class is used"} @@ -233,12 +237,16 @@ def _kwargs(method: Callable[..., Any]) -> set[str]: ours=_kwargs(SandboxProcess.exec), generated=baseten.client.sandboxapi.ProcessRequest, renamed=_PROCESS_REQUEST_RENAMES, + generated_only=_PROCESS_REQUEST_UNSUPPORTED, ), "SandboxProcess.exec_stream": _Parity( ours=_kwargs(SandboxProcess.exec_stream), generated=baseten.client.sandboxapi.ProcessRequest, renamed=_PROCESS_REQUEST_RENAMES, - generated_only={"waitForCompletion": "always sent true, to stream"}, + generated_only={ + **_PROCESS_REQUEST_UNSUPPORTED, + "waitForCompletion": "always sent true, to stream", + }, ), "SandboxFileSystemDirectory": _Parity( ours=_dataclass_fields(SandboxFileSystemDirectory),