From b4c4bd362565c0ed89d131d7da4be4b4bfab5aca Mon Sep 17 00:00:00 2001 From: pasant9 Date: Thu, 19 Sep 2024 19:28:06 +0530 Subject: [PATCH 1/6] Copy api_definitions to pack --- .../distribution/product/src/main/assembly/bin.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/distribution/product/src/main/assembly/bin.xml b/modules/distribution/product/src/main/assembly/bin.xml index 97277ea1f6..d08e90bcd8 100644 --- a/modules/distribution/product/src/main/assembly/bin.xml +++ b/modules/distribution/product/src/main/assembly/bin.xml @@ -425,6 +425,17 @@ **/**.xml + + + + ../../p2-profile/product/target/wso2carbon-core-${carbon.kernel.version}/repository/resources/api_definitions + + wso2am-${pom.version}/repository/resources/api_definitions + + **/**.yaml + + + src/main/conf/governance wso2am-${pom.version}/repository/resources From 6d18d210c3f6871c3d3afcec9ce69dd048a84868 Mon Sep 17 00:00:00 2001 From: Avishka-Shamendra Date: Wed, 25 Sep 2024 12:04:02 +0530 Subject: [PATCH 2/6] Copy api_def to pack --- modules/distribution/product/src/main/assembly/bin.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/distribution/product/src/main/assembly/bin.xml b/modules/distribution/product/src/main/assembly/bin.xml index 97277ea1f6..6a4d29bd72 100644 --- a/modules/distribution/product/src/main/assembly/bin.xml +++ b/modules/distribution/product/src/main/assembly/bin.xml @@ -425,6 +425,15 @@ **/**.xml + + + ../../p2-profile/product/target/wso2carbon-core-${carbon.kernel.version}/repository/resources/api_definitions + + wso2am-${pom.version}/repository/resources/api_definitions + + **/**.yaml + + src/main/conf/governance wso2am-${pom.version}/repository/resources From 12b60989b9f3e395411b56d58d26dbd5edfec142 Mon Sep 17 00:00:00 2001 From: Avishka-Shamendra Date: Thu, 26 Sep 2024 11:15:41 +0530 Subject: [PATCH 3/6] Add AI API Integration Test --- .../tests/aiapi/AIAPITestCase.java | 264 ++ .../resources/ai-api/mistral-add-props.json | 59 + .../test/resources/ai-api/mistral-def.json | 4055 +++++++++++++++++ .../resources/ai-api/mistral-payload.json | 4 + .../resources/ai-api/mistral-response.json | 23 + .../src/test/resources/testng.xml | 7 + 6 files changed, 4412 insertions(+) create mode 100644 modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java create mode 100644 modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-add-props.json create mode 100644 modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-def.json create mode 100644 modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-payload.json create mode 100644 modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-response.json diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java new file mode 100644 index 0000000000..cd4ff520f7 --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.am.integration.tests.aiapi; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONObject; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.APIKeyDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyGenerateRequestDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.SubscriptionDTO; +import org.wso2.am.integration.test.utils.base.APIMIntegrationBaseTest; +import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants; +import org.wso2.am.integration.test.utils.bean.APIThrottlingTier; +import org.wso2.am.integration.test.utils.http.HTTPSClientUtils; +import org.wso2.carbon.automation.engine.annotations.ExecutionEnvironment; +import org.wso2.carbon.automation.engine.annotations.SetEnvironment; +import org.wso2.carbon.automation.engine.context.TestUserMode; +import org.wso2.carbon.automation.test.utils.common.TestConfigurationProvider; +import org.wso2.carbon.automation.test.utils.http.client.HttpResponse; + +import javax.ws.rs.core.Response; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + * AI API Test Case + */ +@SetEnvironment(executionEnvironments = { ExecutionEnvironment.STANDALONE }) +public class AIAPITestCase extends APIMIntegrationBaseTest { + + private static final Log log = LogFactory.getLog(AIAPITestCase.class); + + // Variables related to mistral AI API + private static final String mistralAPIName = "mistralAPI"; + private static final String mistralAPIVersion = "1.0.0"; + private static final String mistralAPIContext = "mistralAPI"; + private static final String mistralAPIEndpoint = "/mistral"; + private static final String mistralAPIResource = "/v1/chat/completions"; + private String mistralAPIId; + private String mistralResponse; + + // Application and API related common details + private static final String apiProvider = "admin"; + private static final String applicationName = "AI-API-Application"; + private String applicationId; + + // Other variables + private String resourcePath; + private WireMockServer wireMockServer; + private int endpointPort; + private String endpointHost = "http://localhost"; + private int lowerPortLimit = 9950; + private int upperPortLimit = 9999; + + + @Factory(dataProvider = "userModeDataProvider") + public AIAPITestCase(TestUserMode userMode) { + this.userMode = userMode; + } + + @DataProvider + public static Object[][] userModeDataProvider() { + return new Object[][]{ + {TestUserMode.SUPER_TENANT_ADMIN}, + {TestUserMode.TENANT_ADMIN}, + }; + } + + @BeforeClass(alwaysRun = true) + public void setEnvironment() throws Exception { + super.init(userMode); + + // Add application + ApplicationDTO applicationDTO = restAPIStore.addApplication(applicationName, + APIThrottlingTier.UNLIMITED.getState(), "", "this-is-test"); + applicationId = applicationDTO.getApplicationId(); + Assert.assertNotNull(applicationId); + + resourcePath = TestConfigurationProvider.getResourceLocation() + "ai-api" + File.separator; + mistralResponse = readFile(resourcePath + "mistral-response.json"); + + // Start WireMock server + startWiremockServer(); + } + + /** + * Test Mistral AI API creation, deployment, and publishing + */ + @Test(groups = { "wso2.am" }, description = "Test Mistral AI API creation, deployment and publishing") + public void testMistralAIAPICreationAndPublish() throws Exception { + String originalDefinition = readFile(resourcePath + "mistral-def.json"); + String additionalProperties = readFile(resourcePath + "mistral-add-props.json"); + JSONObject additionalPropertiesObj = new JSONObject(additionalProperties); + + // Update production endpoint + JSONObject endpointConfig = additionalPropertiesObj.getJSONObject("endpointConfig"); + JSONObject productionEndpoints = new JSONObject(); + productionEndpoints.put("url", endpointHost + ":" + endpointPort + mistralAPIEndpoint); + endpointConfig.put("production_endpoints", productionEndpoints); + additionalPropertiesObj.put("endpointConfig", endpointConfig); + + // Create API + File file = getTempFileWithContent(originalDefinition); + APIDTO apidto = restAPIPublisher.importOASDefinition(file, additionalPropertiesObj.toString()); + mistralAPIId = apidto.getId(); + + HttpResponse createdApiResponse = restAPIPublisher.getAPI(mistralAPIId); + assertEquals(Response.Status.OK.getStatusCode(), + createdApiResponse.getResponseCode(), mistralAPIId + " AI API creation failed"); + + // Deploy API + String revisionUUID = createAPIRevisionAndDeployUsingRest(mistralAPIId, restAPIPublisher); + Assert.assertNotNull(revisionUUID); + + // Publish API + HttpResponse lifecycleResponse = restAPIPublisher + .changeAPILifeCycleStatusToPublish(mistralAPIId, false); + assertEquals(lifecycleResponse.getResponseCode(), HttpStatus.SC_OK); + + waitForAPIDeploymentSync(apidto.getProvider(), + apidto.getName(), apidto.getVersion(), APIMIntegrationConstants.IS_API_EXISTS); + } + + /** + * Test Mistral AI API invocation + */ + @Test(groups = { "wso2.am" }, description = "Test AI API invocation", + dependsOnMethods = "testMistralAIAPICreationAndPublish") + public void testMistralAIApiInvocation() throws Exception { + SubscriptionDTO subscriptionDTO = restAPIStore. + subscribeToAPI(mistralAPIId, applicationId, APIMIntegrationConstants.API_TIER.UNLIMITED); + assertNotNull(subscriptionDTO, "Mistral AI API Subscription failed"); + + APIKeyDTO apiKeyDTO = restAPIStore. + generateAPIKeys(applicationId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION.toString(), + -1, null, null); + assertNotNull(apiKeyDTO, "Mistral AI API Key generation failed"); + String apiKey = apiKeyDTO.getApikey(); + + Map requestHeaders = new HashMap<>(); + requestHeaders.put("ApiKey", apiKey); + String invokeURL = getAPIInvocationURLHttp(mistralAPIContext, mistralAPIVersion) + + mistralAPIResource; + + String mistralPayload = readFile(resourcePath + "mistral-payload.json"); + HttpResponse serviceResponse = HTTPSClientUtils. + doPost(invokeURL, requestHeaders, mistralPayload); + + assertEquals(HttpStatus.SC_OK, serviceResponse.getResponseCode(), "Failed to invoke Mistral AI API"); + assertEquals(mistralResponse, serviceResponse.getData(), "Mistral AI API response mismatch"); + } + + @AfterClass(alwaysRun = true) + public void destroyAPIs() throws Exception { + if (wireMockServer != null) { + wireMockServer.stop(); + } + restAPIStore.removeAPISubscriptionByName(mistralAPIName, mistralAPIVersion, apiProvider, applicationName); + restAPIStore.deleteApplication(applicationId); + restAPIPublisher.deleteAPI(mistralAPIId); + super.cleanUp(); + } + + private File getTempFileWithContent(String content) throws IOException { + File temp = File.createTempFile("swagger", ".json"); + try (BufferedWriter out = new BufferedWriter(new FileWriter(temp))) { + out.write(content); + } + temp.deleteOnExit(); + return temp; + } + + private void startWiremockServer() throws Exception { + endpointPort = getAvailablePort(); + wireMockServer = new WireMockServer(options().port(endpointPort)); + + wireMockServer.stubFor(WireMock.post(urlEqualTo(mistralAPIEndpoint + mistralAPIResource)) + .willReturn(aResponse().withStatus(200). + withHeader("Content-Type", "application/json").withBody(mistralResponse))); + + wireMockServer.start(); + log.info("Wiremock server started on port " + endpointPort); + } + + + /** + * Find a free port to start backend WebSocket server in given port range + * + * @return Available Port Number + */ + private int getAvailablePort() { + while (lowerPortLimit < upperPortLimit) { + if (isPortFree(lowerPortLimit)) { + return lowerPortLimit; + } + lowerPortLimit++; + } + return -1; + } + + /** + * Check whether give port is available + * + * @param port Port Number + * @return status + */ + private boolean isPortFree(int port) { + Socket s = null; + try { + s = new Socket(endpointHost, port); + // something is using the port and has responded. + return false; + } catch (IOException e) { + // port available + return true; + } finally { + if (s != null) { + try { + s.close(); + } catch (IOException e) { + throw new RuntimeException("Unable to close connection ", e); + } + } + } + } +} diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-add-props.json b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-add-props.json new file mode 100644 index 0000000000..3059d64246 --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-add-props.json @@ -0,0 +1,59 @@ +{ + "name": "mistralAPI", + "version": "1.0.0", + "context": "mistralAPI", + "gatewayType": "wso2/synapse", + "policies": ["Unlimited"], + "endpointConfig": { + "endpoint_type": "http", + "endpoint_security": { + "production": { + "enabled": true, + "type": "apikey", + "apiKeyIdentifier": "Authorization", + "apiKeyValue": "Bearer 123", + "username": "", + "password": "", + "grantType": "", + "tokenUrl": "", + "clientId": null, + "clientSecret": null, + "customParameters": "{}" + }, + "sandbox": { + "enabled": true, + "type": "apikey", + "apiKeyIdentifier": "Authorization", + "apiKeyValue": "123", + "username": "", + "password": null, + "grantType": "", + "tokenUrl": "", + "clientId": null, + "clientSecret": null, + "customParameters": "{}" + } + } + }, + "aiConfiguration": { + "llmProviderName": "MistralAI", + "llmProviderApiVersion": "1.0.0" + }, + "maxTps": { + "production": 1000, + "sandbox": 1000, + "productionTimeUnit": "MINUTE", + "sandboxTimeUnit": "MINUTE", + "tokenBasedThrottlingConfiguration": { + "productionMaxPromptTokenCount": 1234, + "productionMaxCompletionTokenCount": 2345, + "productionMaxTotalTokenCount": 3456, + "sandboxMaxPromptTokenCount": 4567, + "sandboxMaxCompletionTokenCount": 5678, + "sandboxMaxTotalTokenCount": 6789, + "isTokenBasedThrottlingEnabled": true + } + }, + "securityScheme":["api_key"], + "egress":true +} \ No newline at end of file diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-def.json b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-def.json new file mode 100644 index 0000000000..bf4d6f871c --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-def.json @@ -0,0 +1,4055 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Mistral AI API", + "description": "Our Chat Completion and Embeddings APIs specification. Create your account on [La Plateforme](https://console.mistral.ai) to get access and read the [docs](https://docs.mistral.ai) to learn how to use it.", + "version": "0.0.2" + }, + "paths": { + "/v1/models": { + "get": { + "summary": "List Models", + "description": "List all models available to the user.", + "operationId": "list_models_v1_models_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelList" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "tags": [ + "models" + ] + } + }, + "/v1/models/{model_id}": { + "get": { + "summary": "Retrieve Model", + "description": "Retrieve a model information.", + "operationId": "retrieve_model_v1_models__model_id__get", + "parameters": [ + { + "name": "model_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Model Id" + }, + "example": "ft:open-mistral-7b:587a6b29:20240514:7e773925", + "description": "The ID of the model to retrieve." + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelCard" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "tags": [ + "models" + ] + }, + "delete": { + "summary": "Delete Model", + "description": "Delete a fine-tuned model.", + "operationId": "delete_model_v1_models__model_id__delete", + "parameters": [ + { + "name": "model_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Model Id" + }, + "example": "ft:open-mistral-7b:587a6b29:20240514:7e773925", + "description": "The ID of the model to delete." + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteModelOut" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "tags": [ + "models" + ] + } + }, + "/v1/files": { + "post": { + "operationId": "files_api_routes_upload_file", + "summary": "Upload File", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadFileOut" + } + } + } + } + }, + "description": "Upload a file that can be used across various endpoints.\n\nThe size of individual files can be a maximum of 512 MB. The Fine-tuning API only supports .jsonl files.\n\nPlease contact us if you need to increase these storage limits.", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "title": "MultiPartBodyParams", + "type": "object", + "properties": { + "purpose": { + "const": "fine-tune", + "default": "fine-tune", + "enum": [ + "fine-tune" + ], + "title": "Purpose", + "type": "string" + }, + "file": { + "format": "binary", + "title": "File", + "type": "string", + "description": "The File object (not file name) to be uploaded.\n To upload a file and specify a custom file name you should format your request as such:\n ```bash\n file=@path/to/your/file.jsonl;filename=custom_name.jsonl\n ```\n Otherwise, you can just keep the original file name:\n ```bash\n file=@path/to/your/file.jsonl\n ```" + } + }, + "required": [ + "file" + ] + } + } + }, + "required": true + }, + "tags": [ + "files" + ] + }, + "get": { + "operationId": "files_api_routes_list_files", + "summary": "List Files", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListFilesOut" + } + } + } + } + }, + "description": "Returns a list of files that belong to the user's organization.", + "tags": [ + "files" + ] + } + }, + "/v1/files/{file_id}": { + "get": { + "operationId": "files_api_routes_retrieve_file", + "summary": "Retrieve File", + "parameters": [ + { + "in": "path", + "name": "file_id", + "schema": { + "title": "File Id", + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetrieveFileOut" + } + } + } + } + }, + "description": "Returns information about a specific file.", + "tags": [ + "files" + ] + }, + "delete": { + "operationId": "files_api_routes_delete_file", + "summary": "Delete File", + "parameters": [ + { + "in": "path", + "name": "file_id", + "schema": { + "title": "File Id", + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteFileOut" + } + } + } + } + }, + "description": "Delete a file.", + "tags": [ + "files" + ] + } + }, + "/v1/fine_tuning/jobs": { + "get": { + "operationId": "jobs_api_routes_fine_tuning_get_fine_tuning_jobs", + "summary": "Get Fine Tuning Jobs", + "parameters": [ + { + "in": "query", + "name": "page", + "schema": { + "default": 0, + "title": "Page", + "type": "integer" + }, + "required": false, + "description": "The page number of the results to be returned." + }, + { + "in": "query", + "name": "page_size", + "schema": { + "default": 100, + "title": "Page Size", + "type": "integer" + }, + "required": false, + "description": "The number of items to return per page." + }, + { + "in": "query", + "name": "model", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Model" + }, + "required": false, + "description": "The model name used for fine-tuning to filter on. When set, the other results are not displayed." + }, + { + "in": "query", + "name": "created_after", + "schema": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created After" + }, + "required": false, + "description": "The date/time to filter on. When set, the results for previous creation times are not displayed." + }, + { + "in": "query", + "name": "created_by_me", + "schema": { + "default": false, + "title": "Created By Me", + "type": "boolean" + }, + "required": false, + "description": "When set, only return results for jobs created by the API caller. Other results are not displayed." + }, + { + "in": "query", + "name": "status", + "schema": { + "anyOf": [ + { + "enum": [ + "QUEUED", + "STARTED", + "VALIDATING", + "VALIDATED", + "RUNNING", + "FAILED_VALIDATION", + "FAILED", + "SUCCESS", + "CANCELLED", + "CANCELLATION_REQUESTED" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Status" + }, + "required": false, + "description": "The current job state to filter on. When set, the other results are not displayed." + }, + { + "in": "query", + "name": "wandb_project", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wandb Project" + }, + "required": false, + "description": "The Weights and Biases project to filter on. When set, the other results are not displayed." + }, + { + "in": "query", + "name": "wandb_name", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Wandb Name" + }, + "required": false, + "description": "The Weight and Biases run name to filter on. When set, the other results are not displayed." + }, + { + "in": "query", + "name": "suffix", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Suffix" + }, + "required": false, + "description": "The model suffix to filter on. When set, the other results are not displayed." + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobsOut" + } + } + } + } + }, + "description": "Get a list of fine-tuning jobs for your organization and user.", + "tags": [ + "fine-tuning" + ] + }, + "post": { + "operationId": "jobs_api_routes_fine_tuning_create_fine_tuning_job", + "summary": "Create Fine Tuning Job", + "parameters": [ + { + "in": "query", + "name": "dry_run", + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Dry Run" + }, + "required": false, + "description": "* If `true` the job is not spawned, instead the query returns a handful of useful metadata\n for the user to perform sanity checks (see `LegacyJobMetadataOut` response).\n* Otherwise, the job is started and the query returns the job ID along with some of the\n input parameters (see `JobOut` response).\n" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/JobOut" + }, + { + "$ref": "#/components/schemas/LegacyJobMetadataOut" + } + ], + "title": "Response" + } + } + } + } + }, + "description": "Create a new fine-tuning job, it will be queued for processing.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobIn" + } + } + }, + "required": true + }, + "tags": [ + "fine-tuning" + ] + } + }, + "/v1/fine_tuning/jobs/{job_id}": { + "get": { + "operationId": "jobs_api_routes_fine_tuning_get_fine_tuning_job", + "summary": "Get Fine Tuning Job", + "parameters": [ + { + "in": "path", + "name": "job_id", + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + }, + "required": true, + "description": "The ID of the job to analyse." + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DetailedJobOut" + } + } + } + } + }, + "description": "Get a fine-tuned job details by its UUID.", + "tags": [ + "fine-tuning" + ] + } + }, + "/v1/fine_tuning/jobs/{job_id}/cancel": { + "post": { + "operationId": "jobs_api_routes_fine_tuning_cancel_fine_tuning_job", + "summary": "Cancel Fine Tuning Job", + "parameters": [ + { + "in": "path", + "name": "job_id", + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + }, + "required": true, + "description": "The ID of the job to cancel." + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DetailedJobOut" + } + } + } + } + }, + "description": "Request the cancellation of a fine tuning job.", + "tags": [ + "fine-tuning" + ] + } + }, + "/v1/fine_tuning/jobs/{job_id}/start": { + "post": { + "operationId": "jobs_api_routes_fine_tuning_start_fine_tuning_job", + "summary": "Start Fine Tuning Job", + "parameters": [ + { + "in": "path", + "name": "job_id", + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DetailedJobOut" + } + } + } + } + }, + "description": "Request the start of a validated fine tuning job.", + "tags": [ + "fine-tuning" + ] + } + }, + "/v1/fine_tuning/models/{model_id}": { + "patch": { + "operationId": "jobs_api_routes_fine_tuning_update_fine_tuned_model", + "summary": "Update Fine Tuned Model", + "parameters": [ + { + "in": "path", + "name": "model_id", + "schema": { + "title": "Model Id", + "type": "string" + }, + "required": true, + "example": "ft:open-mistral-7b:587a6b29:20240514:7e773925", + "description": "The ID of the model to update." + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FTModelOut" + } + } + } + } + }, + "description": "Update a model name or description.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateFTModelIn" + } + } + }, + "required": true + }, + "tags": [ + "models" + ] + } + }, + "/v1/fine_tuning/models/{model_id}/archive": { + "post": { + "operationId": "jobs_api_routes_fine_tuning_archive_fine_tuned_model", + "summary": "Archive Fine Tuned Model", + "parameters": [ + { + "in": "path", + "name": "model_id", + "schema": { + "title": "Model Id", + "type": "string" + }, + "required": true, + "example": "ft:open-mistral-7b:587a6b29:20240514:7e773925", + "description": "The ID of the model to archive." + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArchiveFTModelOut" + } + } + } + } + }, + "description": "Archive a fine-tuned model.", + "tags": [ + "models" + ] + }, + "delete": { + "operationId": "jobs_api_routes_fine_tuning_unarchive_fine_tuned_model", + "summary": "Unarchive Fine Tuned Model", + "parameters": [ + { + "in": "path", + "name": "model_id", + "schema": { + "title": "Model Id", + "type": "string" + }, + "required": true, + "example": "ft:open-mistral-7b:587a6b29:20240514:7e773925", + "description": "The ID of the model to unarchive." + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnarchiveFTModelOut" + } + } + } + } + }, + "description": "Un-archive a fine-tuned model.", + "tags": [ + "models" + ] + } + }, + "/v1/chat/completions": { + "post": { + "summary": "Chat Completion", + "operationId": "chat_completion_v1_chat_completions_post", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionResponse" + } + }, + "text/event-stream": { + "schema": { + "$ref": "#/components/schemas/CompletionEvent" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "tags": [ + "chat" + ] + } + }, + "/v1/fim/completions": { + "post": { + "summary": "Fim Completion", + "description": "FIM completion.", + "operationId": "fim_completion_v1_fim_completions_post", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FIMCompletionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FIMCompletionResponse" + } + }, + "text/event-stream": { + "schema": { + "$ref": "#/components/schemas/CompletionEvent" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "tags": [ + "fim" + ] + } + }, + "/v1/agents/completions": { + "post": { + "summary": "Agents Completion", + "operationId": "agents_completion_v1_agents_completions_post", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentsCompletionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "tags": [ + "agents" + ] + } + }, + "/v1/embeddings": { + "post": { + "summary": "Embeddings", + "description": "Embeddings", + "operationId": "embeddings_v1_embeddings_post", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddingResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "tags": [ + "embeddings" + ] + } + } + }, + "components": { + "schemas": { + "DeleteModelOut": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "The ID of the deleted model.", + "examples": [ + "ft:open-mistral-7b:587a6b29:20240514:7e773925" + ] + }, + "object": { + "type": "string", + "title": "Object", + "default": "model", + "description": "The object type that was deleted" + }, + "deleted": { + "type": "boolean", + "title": "Deleted", + "default": true, + "description": "The deletion status", + "examples": [ + true + ] + } + }, + "type": "object", + "required": [ + "id" + ], + "title": "DeleteModelOut" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail" + } + }, + "type": "object", + "title": "HTTPValidationError" + }, + "ModelCapabilities": { + "properties": { + "completion_chat": { + "type": "boolean", + "title": "Completion Chat", + "default": true + }, + "completion_fim": { + "type": "boolean", + "title": "Completion Fim", + "default": false + }, + "function_calling": { + "type": "boolean", + "title": "Function Calling", + "default": true + }, + "fine_tuning": { + "type": "boolean", + "title": "Fine Tuning", + "default": false + } + }, + "type": "object", + "title": "ModelCapabilities" + }, + "ModelCard": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "object": { + "type": "string", + "title": "Object", + "default": "model" + }, + "created": { + "type": "integer", + "title": "Created" + }, + "owned_by": { + "type": "string", + "title": "Owned By", + "default": "mistralai" + }, + "root": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Root" + }, + "archived": { + "type": "boolean", + "title": "Archived", + "default": false + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "capabilities": { + "$ref": "#/components/schemas/ModelCapabilities" + }, + "max_context_length": { + "type": "integer", + "title": "Max Context Length", + "default": 32768 + }, + "aliases": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Aliases", + "default": [] + }, + "deprecation": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Deprecation" + } + }, + "type": "object", + "required": [ + "id", + "capabilities" + ], + "title": "ModelCard" + }, + "ModelList": { + "properties": { + "object": { + "type": "string", + "title": "Object", + "default": "list" + }, + "data": { + "items": { + "$ref": "#/components/schemas/ModelCard" + }, + "type": "array", + "title": "Data" + } + }, + "type": "object", + "title": "ModelList" + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "type": "array", + "title": "Location" + }, + "msg": { + "type": "string", + "title": "Message" + }, + "type": { + "type": "string", + "title": "Error Type" + } + }, + "type": "object", + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError" + }, + "SampleType": { + "enum": [ + "pretrain", + "instruct" + ], + "title": "SampleType", + "type": "string" + }, + "Source": { + "enum": [ + "upload", + "repository" + ], + "title": "Source", + "type": "string" + }, + "UploadFileOut": { + "properties": { + "id": { + "format": "uuid", + "title": "Id", + "type": "string", + "description": "The unique identifier of the file.", + "examples": [ + "497f6eca-6276-4993-bfeb-53cbbbba6f09" + ] + }, + "object": { + "title": "Object", + "type": "string", + "description": "The object type, which is always \"file\".", + "examples": [ + "file" + ] + }, + "bytes": { + "title": "Bytes", + "type": "integer", + "description": "The size of the file, in bytes.", + "examples": [ + 13000 + ] + }, + "created_at": { + "title": "Created At", + "type": "integer", + "description": "The UNIX timestamp (in seconds) of the event.", + "examples": [ + 1716963433 + ] + }, + "filename": { + "title": "Filename", + "type": "string", + "description": "The name of the uploaded file.", + "examples": [ + "files_upload.jsonl" + ] + }, + "purpose": { + "const": "fine-tune", + "enum": [ + "fine-tune" + ], + "title": "Purpose", + "type": "string", + "description": "The intended purpose of the uploaded file. Only accepts fine-tuning (`fine-tune`) for now.", + "examples": [ + "fine-tune" + ] + }, + "sample_type": { + "$ref": "#/components/schemas/SampleType" + }, + "num_lines": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Num Lines" + }, + "source": { + "$ref": "#/components/schemas/Source" + } + }, + "required": [ + "id", + "object", + "bytes", + "created_at", + "filename", + "purpose", + "sample_type", + "source" + ], + "title": "UploadFileOut", + "type": "object" + }, + "FileSchema": { + "properties": { + "id": { + "format": "uuid", + "title": "Id", + "type": "string", + "description": "The unique identifier of the file.", + "examples": [ + "497f6eca-6276-4993-bfeb-53cbbbba6f09" + ] + }, + "object": { + "title": "Object", + "type": "string", + "description": "The object type, which is always \"file\".", + "examples": [ + "file" + ] + }, + "bytes": { + "title": "Bytes", + "type": "integer", + "description": "The size of the file, in bytes.", + "examples": [ + 13000 + ] + }, + "created_at": { + "title": "Created At", + "type": "integer", + "description": "The UNIX timestamp (in seconds) of the event.", + "examples": [ + 1716963433 + ] + }, + "filename": { + "title": "Filename", + "type": "string", + "description": "The name of the uploaded file.", + "examples": [ + "files_upload.jsonl" + ] + }, + "purpose": { + "const": "fine-tune", + "enum": [ + "fine-tune" + ], + "title": "Purpose", + "type": "string", + "description": "The intended purpose of the uploaded file. Only accepts fine-tuning (`fine-tune`) for now.", + "examples": [ + "fine-tune" + ] + }, + "sample_type": { + "$ref": "#/components/schemas/SampleType" + }, + "num_lines": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Num Lines" + }, + "source": { + "$ref": "#/components/schemas/Source" + } + }, + "required": [ + "id", + "object", + "bytes", + "created_at", + "filename", + "purpose", + "sample_type", + "source" + ], + "title": "FileSchema", + "type": "object" + }, + "ListFilesOut": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/FileSchema" + }, + "title": "Data", + "type": "array" + }, + "object": { + "title": "Object", + "type": "string" + } + }, + "required": [ + "data", + "object" + ], + "title": "ListFilesOut", + "type": "object" + }, + "RetrieveFileOut": { + "properties": { + "id": { + "format": "uuid", + "title": "Id", + "type": "string", + "description": "The unique identifier of the file.", + "examples": [ + "497f6eca-6276-4993-bfeb-53cbbbba6f09" + ] + }, + "object": { + "title": "Object", + "type": "string", + "description": "The object type, which is always \"file\".", + "examples": [ + "file" + ] + }, + "bytes": { + "title": "Bytes", + "type": "integer", + "description": "The size of the file, in bytes.", + "examples": [ + 13000 + ] + }, + "created_at": { + "title": "Created At", + "type": "integer", + "description": "The UNIX timestamp (in seconds) of the event.", + "examples": [ + 1716963433 + ] + }, + "filename": { + "title": "Filename", + "type": "string", + "description": "The name of the uploaded file.", + "examples": [ + "files_upload.jsonl" + ] + }, + "purpose": { + "const": "fine-tune", + "enum": [ + "fine-tune" + ], + "title": "Purpose", + "type": "string", + "description": "The intended purpose of the uploaded file. Only accepts fine-tuning (`fine-tune`) for now.", + "examples": [ + "fine-tune" + ] + }, + "sample_type": { + "$ref": "#/components/schemas/SampleType" + }, + "num_lines": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Num Lines" + }, + "source": { + "$ref": "#/components/schemas/Source" + } + }, + "required": [ + "id", + "object", + "bytes", + "created_at", + "filename", + "purpose", + "sample_type", + "source" + ], + "title": "RetrieveFileOut", + "type": "object" + }, + "DeleteFileOut": { + "properties": { + "id": { + "format": "uuid", + "title": "Id", + "type": "string", + "description": "The ID of the deleted file.", + "examples": [ + "497f6eca-6276-4993-bfeb-53cbbbba6f09" + ] + }, + "object": { + "title": "Object", + "type": "string", + "description": "The object type that was deleted", + "examples": [ + "file" + ] + }, + "deleted": { + "title": "Deleted", + "type": "boolean", + "description": "The deletion status.", + "examples": [ + false + ] + } + }, + "required": [ + "id", + "object", + "deleted" + ], + "title": "DeleteFileOut", + "type": "object" + }, + "FineTuneableModel": { + "enum": [ + "open-mistral-7b", + "mistral-small-latest", + "codestral-latest", + "mistral-large-latest", + "open-mistral-nemo" + ], + "title": "FineTuneableModel", + "type": "string", + "description": "The name of the model to fine-tune." + }, + "GithubRepositoryOut": { + "properties": { + "type": { + "const": "github", + "default": "github", + "enum": [ + "github" + ], + "title": "Type", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "owner": { + "title": "Owner", + "type": "string" + }, + "ref": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Ref" + }, + "weight": { + "default": 1, + "exclusiveMinimum": 0, + "title": "Weight", + "type": "number" + }, + "commit_id": { + "maxLength": 40, + "minLength": 40, + "title": "Commit Id", + "type": "string" + } + }, + "required": [ + "name", + "owner", + "commit_id" + ], + "title": "GithubRepositoryOut", + "type": "object" + }, + "JobMetadataOut": { + "properties": { + "expected_duration_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Expected Duration Seconds" + }, + "cost": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Cost" + }, + "cost_currency": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cost Currency" + }, + "train_tokens_per_step": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Train Tokens Per Step" + }, + "train_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Train Tokens" + }, + "data_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Data Tokens" + }, + "estimated_start_time": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Estimated Start Time" + } + }, + "title": "JobMetadataOut", + "type": "object" + }, + "JobOut": { + "properties": { + "id": { + "format": "uuid", + "title": "Id", + "type": "string", + "description": "The ID of the job." + }, + "auto_start": { + "title": "Auto Start", + "type": "boolean" + }, + "hyperparameters": { + "$ref": "#/components/schemas/TrainingParameters" + }, + "model": { + "$ref": "#/components/schemas/FineTuneableModel" + }, + "status": { + "enum": [ + "QUEUED", + "STARTED", + "VALIDATING", + "VALIDATED", + "RUNNING", + "FAILED_VALIDATION", + "FAILED", + "SUCCESS", + "CANCELLED", + "CANCELLATION_REQUESTED" + ], + "title": "Status", + "type": "string", + "description": "The current status of the fine-tuning job." + }, + "job_type": { + "title": "Job Type", + "type": "string", + "description": "The type of job (`FT` for fine-tuning)." + }, + "created_at": { + "title": "Created At", + "type": "integer", + "description": "The UNIX timestamp (in seconds) for when the fine-tuning job was created." + }, + "modified_at": { + "title": "Modified At", + "type": "integer", + "description": "The UNIX timestamp (in seconds) for when the fine-tuning job was last modified." + }, + "training_files": { + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Training Files", + "type": "array", + "description": "A list containing the IDs of uploaded files that contain training data." + }, + "validation_files": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": [], + "title": "Validation Files", + "description": "A list containing the IDs of uploaded files that contain validation data." + }, + "object": { + "const": "job", + "default": "job", + "enum": [ + "job" + ], + "title": "Object", + "type": "string", + "description": "The object type of the fine-tuning job." + }, + "fine_tuned_model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Fine Tuned Model", + "description": "The name of the fine-tuned model that is being created. The value will be `null` if the fine-tuning job is still running." + }, + "suffix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Suffix", + "description": "Optional text/code that adds more context for the model. When given a `prompt` and a `suffix` the model will fill what is between them. When `suffix` is not provided, the model will simply execute completion starting with `prompt`." + }, + "integrations": { + "anyOf": [ + { + "items": { + "discriminator": { + "mapping": { + "wandb": "#/components/schemas/WandbIntegrationOut" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/WandbIntegrationOut" + } + ] + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Integrations", + "description": "A list of integrations enabled for your fine-tuning job." + }, + "trained_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Trained Tokens", + "description": "Total number of tokens trained." + }, + "repositories": { + "default": [], + "items": { + "discriminator": { + "mapping": { + "github": "#/components/schemas/GithubRepositoryOut" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/GithubRepositoryOut" + } + ] + }, + "maxItems": 20, + "title": "Repositories", + "type": "array" + }, + "metadata": { + "anyOf": [ + { + "$ref": "#/components/schemas/JobMetadataOut" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "id", + "auto_start", + "hyperparameters", + "model", + "status", + "job_type", + "created_at", + "modified_at", + "training_files" + ], + "title": "JobOut", + "type": "object" + }, + "JobsOut": { + "properties": { + "data": { + "default": [], + "items": { + "$ref": "#/components/schemas/JobOut" + }, + "title": "Data", + "type": "array" + }, + "object": { + "const": "list", + "default": "list", + "enum": [ + "list" + ], + "title": "Object", + "type": "string" + }, + "total": { + "title": "Total", + "type": "integer" + } + }, + "required": [ + "total" + ], + "title": "JobsOut", + "type": "object" + }, + "TrainingParameters": { + "properties": { + "training_steps": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Training Steps" + }, + "learning_rate": { + "default": 0.0001, + "maximum": 1, + "minimum": 1e-8, + "title": "Learning Rate", + "type": "number" + }, + "weight_decay": { + "anyOf": [ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 0.1, + "title": "Weight Decay" + }, + "warmup_fraction": { + "anyOf": [ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 0.05, + "title": "Warmup Fraction" + }, + "epochs": { + "anyOf": [ + { + "minimum": 0.01, + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Epochs" + }, + "fim_ratio": { + "anyOf": [ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 0.9, + "title": "Fim Ratio" + } + }, + "title": "TrainingParameters", + "type": "object" + }, + "WandbIntegrationOut": { + "properties": { + "type": { + "const": "wandb", + "default": "wandb", + "enum": [ + "wandb" + ], + "title": "Type", + "type": "string" + }, + "project": { + "title": "Project", + "type": "string", + "description": "The name of the project that the new run will be created under." + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name", + "description": "A display name to set for the run. If not set, will use the job ID as the name." + }, + "run_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Run Name" + } + }, + "required": [ + "project" + ], + "title": "WandbIntegrationOut", + "type": "object" + }, + "LegacyJobMetadataOut": { + "properties": { + "expected_duration_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Expected Duration Seconds", + "description": "The approximated time (in seconds) for the fine-tuning process to complete.", + "examples": [ + 220 + ] + }, + "cost": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Cost", + "description": "The cost of the fine-tuning job.", + "examples": [ + 10 + ] + }, + "cost_currency": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cost Currency", + "description": "The currency used for the fine-tuning job cost.", + "examples": [ + "EUR" + ] + }, + "train_tokens_per_step": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Train Tokens Per Step", + "description": "The number of tokens consumed by one training step.", + "examples": [ + 131072 + ] + }, + "train_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Train Tokens", + "description": "The total number of tokens used during the fine-tuning process.", + "examples": [ + 1310720 + ] + }, + "data_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Data Tokens", + "description": "The total number of tokens in the training dataset.", + "examples": [ + 305375 + ] + }, + "estimated_start_time": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Estimated Start Time" + }, + "deprecated": { + "default": true, + "title": "Deprecated", + "type": "boolean" + }, + "details": { + "title": "Details", + "type": "string" + }, + "epochs": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Epochs", + "description": "The number of complete passes through the entire training dataset.", + "examples": [ + 4.2922 + ] + }, + "training_steps": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Training Steps", + "description": "The number of training steps to perform. A training step refers to a single update of the model weights during the fine-tuning process. This update is typically calculated using a batch of samples from the training dataset.", + "examples": [ + 10 + ] + }, + "object": { + "const": "job.metadata", + "default": "job.metadata", + "enum": [ + "job.metadata" + ], + "title": "Object", + "type": "string" + } + }, + "required": [ + "details" + ], + "title": "LegacyJobMetadataOut", + "type": "object" + }, + "GithubRepositoryIn": { + "properties": { + "type": { + "const": "github", + "default": "github", + "enum": [ + "github" + ], + "title": "Type", + "type": "string" + }, + "name": { + "title": "Name", + "type": "string" + }, + "owner": { + "title": "Owner", + "type": "string" + }, + "ref": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Ref" + }, + "weight": { + "default": 1, + "exclusiveMinimum": 0, + "title": "Weight", + "type": "number" + }, + "token": { + "title": "Token", + "type": "string" + } + }, + "required": [ + "name", + "owner", + "token" + ], + "title": "GithubRepositoryIn", + "type": "object" + }, + "JobIn": { + "properties": { + "model": { + "$ref": "#/components/schemas/FineTuneableModel" + }, + "training_files": { + "default": [], + "items": { + "$ref": "#/components/schemas/TrainingFile" + }, + "title": "Training Files", + "type": "array" + }, + "validation_files": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Validation Files", + "description": "A list containing the IDs of uploaded files that contain validation data. If you provide these files, the data is used to generate validation metrics periodically during fine-tuning. These metrics can be viewed in `checkpoints` when getting the status of a running fine-tuning job. The same data should not be present in both train and validation files." + }, + "hyperparameters": { + "$ref": "#/components/schemas/TrainingParametersIn" + }, + "suffix": { + "anyOf": [ + { + "maxLength": 18, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Suffix", + "description": "A string that will be added to your fine-tuning model name. For example, a suffix of \"my-great-model\" would produce a model name like `ft:open-mistral-7b:my-great-model:xxx...`" + }, + "integrations": { + "anyOf": [ + { + "items": { + "discriminator": { + "mapping": { + "wandb": "#/components/schemas/WandbIntegration" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/WandbIntegration" + } + ] + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Integrations", + "description": "A list of integrations to enable for your fine-tuning job." + }, + "repositories": { + "default": [], + "items": { + "discriminator": { + "mapping": { + "github": "#/components/schemas/GithubRepositoryIn" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/GithubRepositoryIn" + } + ] + }, + "title": "Repositories", + "type": "array" + }, + "auto_start": { + "description": "This field will be required in a future release.", + "title": "Auto Start", + "type": "boolean" + } + }, + "required": [ + "model", + "hyperparameters" + ], + "title": "JobIn", + "type": "object" + }, + "TrainingFile": { + "properties": { + "file_id": { + "format": "uuid", + "title": "File Id", + "type": "string" + }, + "weight": { + "default": 1, + "exclusiveMinimum": 0, + "title": "Weight", + "type": "number" + } + }, + "required": [ + "file_id" + ], + "title": "TrainingFile", + "type": "object" + }, + "TrainingParametersIn": { + "properties": { + "training_steps": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Training Steps", + "description": "The number of training steps to perform. A training step refers to a single update of the model weights during the fine-tuning process. This update is typically calculated using a batch of samples from the training dataset." + }, + "learning_rate": { + "default": 0.0001, + "maximum": 1, + "minimum": 1e-8, + "title": "Learning Rate", + "type": "number", + "description": "A parameter describing how much to adjust the pre-trained model's weights in response to the estimated error each time the weights are updated during the fine-tuning process." + }, + "weight_decay": { + "anyOf": [ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 0.1, + "title": "Weight Decay", + "description": "(Advanced Usage) Weight decay adds a term to the loss function that is proportional to the sum of the squared weights. This term reduces the magnitude of the weights and prevents them from growing too large." + }, + "warmup_fraction": { + "anyOf": [ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 0.05, + "title": "Warmup Fraction", + "description": "(Advanced Usage) A parameter that specifies the percentage of the total training steps at which the learning rate warm-up phase ends. During this phase, the learning rate gradually increases from a small value to the initial learning rate, helping to stabilize the training process and improve convergence. Similar to `pct_start` in [mistral-finetune](https://github.com/mistralai/mistral-finetune)" + }, + "epochs": { + "anyOf": [ + { + "minimum": 0.01, + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Epochs" + }, + "fim_ratio": { + "anyOf": [ + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": 0.9, + "title": "Fim Ratio" + } + }, + "title": "TrainingParametersIn", + "type": "object", + "description": "The fine-tuning hyperparameter settings used in a fine-tune job." + }, + "WandbIntegration": { + "properties": { + "type": { + "const": "wandb", + "default": "wandb", + "enum": [ + "wandb" + ], + "title": "Type", + "type": "string" + }, + "project": { + "title": "Project", + "type": "string", + "description": "The name of the project that the new run will be created under." + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name", + "description": "A display name to set for the run. If not set, will use the job ID as the name." + }, + "api_key": { + "maxLength": 40, + "minLength": 40, + "title": "Api Key", + "type": "string", + "description": "The WandB API key to use for authentication." + }, + "run_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Run Name" + } + }, + "required": [ + "project", + "api_key" + ], + "title": "WandbIntegration", + "type": "object" + }, + "CheckpointOut": { + "properties": { + "metrics": { + "$ref": "#/components/schemas/MetricOut" + }, + "step_number": { + "title": "Step Number", + "type": "integer", + "description": "The step number that the checkpoint was created at." + }, + "created_at": { + "title": "Created At", + "type": "integer", + "description": "The UNIX timestamp (in seconds) for when the checkpoint was created.", + "examples": [ + 1716963433 + ] + } + }, + "required": [ + "metrics", + "step_number", + "created_at" + ], + "title": "CheckpointOut", + "type": "object" + }, + "DetailedJobOut": { + "properties": { + "id": { + "format": "uuid", + "title": "Id", + "type": "string" + }, + "auto_start": { + "title": "Auto Start", + "type": "boolean" + }, + "hyperparameters": { + "$ref": "#/components/schemas/TrainingParameters" + }, + "model": { + "$ref": "#/components/schemas/FineTuneableModel" + }, + "status": { + "enum": [ + "QUEUED", + "STARTED", + "VALIDATING", + "VALIDATED", + "RUNNING", + "FAILED_VALIDATION", + "FAILED", + "SUCCESS", + "CANCELLED", + "CANCELLATION_REQUESTED" + ], + "title": "Status", + "type": "string" + }, + "job_type": { + "title": "Job Type", + "type": "string" + }, + "created_at": { + "title": "Created At", + "type": "integer" + }, + "modified_at": { + "title": "Modified At", + "type": "integer" + }, + "training_files": { + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Training Files", + "type": "array" + }, + "validation_files": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": [], + "title": "Validation Files" + }, + "object": { + "const": "job", + "default": "job", + "enum": [ + "job" + ], + "title": "Object", + "type": "string" + }, + "fine_tuned_model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Fine Tuned Model" + }, + "suffix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Suffix" + }, + "integrations": { + "anyOf": [ + { + "items": { + "discriminator": { + "mapping": { + "wandb": "#/components/schemas/WandbIntegrationOut" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/WandbIntegrationOut" + } + ] + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Integrations" + }, + "trained_tokens": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Trained Tokens" + }, + "repositories": { + "default": [], + "items": { + "discriminator": { + "mapping": { + "github": "#/components/schemas/GithubRepositoryOut" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/GithubRepositoryOut" + } + ] + }, + "maxItems": 20, + "title": "Repositories", + "type": "array" + }, + "metadata": { + "anyOf": [ + { + "$ref": "#/components/schemas/JobMetadataOut" + }, + { + "type": "null" + } + ] + }, + "events": { + "default": [], + "items": { + "$ref": "#/components/schemas/EventOut" + }, + "title": "Events", + "type": "array", + "description": "Event items are created every time the status of a fine-tuning job changes. The timestamped list of all events is accessible here." + }, + "checkpoints": { + "default": [], + "items": { + "$ref": "#/components/schemas/CheckpointOut" + }, + "title": "Checkpoints", + "type": "array" + } + }, + "required": [ + "id", + "auto_start", + "hyperparameters", + "model", + "status", + "job_type", + "created_at", + "modified_at", + "training_files" + ], + "title": "DetailedJobOut", + "type": "object" + }, + "EventOut": { + "properties": { + "name": { + "title": "Name", + "type": "string", + "description": "The name of the event." + }, + "data": { + "anyOf": [ + { + "type": "object", + "additionalProperties": true + }, + { + "type": "null" + } + ], + "title": "Data" + }, + "created_at": { + "title": "Created At", + "type": "integer", + "description": "The UNIX timestamp (in seconds) of the event." + } + }, + "required": [ + "name", + "created_at" + ], + "title": "EventOut", + "type": "object" + }, + "MetricOut": { + "properties": { + "train_loss": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Train Loss" + }, + "valid_loss": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Valid Loss" + }, + "valid_mean_token_accuracy": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Valid Mean Token Accuracy" + } + }, + "title": "MetricOut", + "type": "object", + "description": "Metrics at the step number during the fine-tuning job. Use these metrics to assess if the training is going smoothly (loss should decrease, token accuracy should increase)." + }, + "FTModelCapabilitiesOut": { + "properties": { + "completion_chat": { + "default": true, + "title": "Completion Chat", + "type": "boolean" + }, + "completion_fim": { + "default": false, + "title": "Completion Fim", + "type": "boolean" + }, + "function_calling": { + "default": false, + "title": "Function Calling", + "type": "boolean" + }, + "fine_tuning": { + "default": false, + "title": "Fine Tuning", + "type": "boolean" + } + }, + "title": "FTModelCapabilitiesOut", + "type": "object" + }, + "FTModelOut": { + "properties": { + "id": { + "title": "Id", + "type": "string" + }, + "object": { + "const": "model", + "default": "model", + "enum": [ + "model" + ], + "title": "Object", + "type": "string" + }, + "created": { + "title": "Created", + "type": "integer" + }, + "owned_by": { + "title": "Owned By", + "type": "string" + }, + "root": { + "title": "Root", + "type": "string" + }, + "archived": { + "title": "Archived", + "type": "boolean" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "capabilities": { + "$ref": "#/components/schemas/FTModelCapabilitiesOut" + }, + "max_context_length": { + "default": 32768, + "title": "Max Context Length", + "type": "integer" + }, + "aliases": { + "default": [], + "items": { + "type": "string" + }, + "title": "Aliases", + "type": "array" + }, + "job": { + "format": "uuid", + "title": "Job", + "type": "string" + } + }, + "required": [ + "id", + "created", + "owned_by", + "root", + "archived", + "capabilities", + "job" + ], + "title": "FTModelOut", + "type": "object" + }, + "UpdateFTModelIn": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + } + }, + "title": "UpdateFTModelIn", + "type": "object" + }, + "ArchiveFTModelOut": { + "properties": { + "id": { + "title": "Id", + "type": "string" + }, + "object": { + "const": "model", + "default": "model", + "enum": [ + "model" + ], + "title": "Object", + "type": "string" + }, + "archived": { + "default": true, + "title": "Archived", + "type": "boolean" + } + }, + "required": [ + "id" + ], + "title": "ArchiveFTModelOut", + "type": "object" + }, + "UnarchiveFTModelOut": { + "properties": { + "id": { + "title": "Id", + "type": "string" + }, + "object": { + "const": "model", + "default": "model", + "enum": [ + "model" + ], + "title": "Object", + "type": "string" + }, + "archived": { + "default": false, + "title": "Archived", + "type": "boolean" + } + }, + "required": [ + "id" + ], + "title": "UnarchiveFTModelOut", + "type": "object" + }, + "AssistantMessage": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Content" + }, + "tool_calls": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/ToolCall" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Tool Calls" + }, + "prefix": { + "type": "boolean", + "title": "Prefix", + "default": false, + "description": "Set this to `true` when adding an assistant message as prefix to condition the model response. The role of the prefix message is to force the model to start its answer by the content of the message." + }, + "role": { + "type": "string", + "default": "assistant", + "title": "Role", + "enum": [ + "assistant" + ] + } + }, + "additionalProperties": false, + "type": "object", + "title": "AssistantMessage" + }, + "ChatCompletionRequest": { + "properties": { + "model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Model", + "description": "ID of the model to use. You can use the [List Available Models](/api/#tag/models/operation/list_models_v1_models_get) API to see all of your available models, or see our [Model overview](/models) for model descriptions.", + "examples": [ + "mistral-small-latest" + ] + }, + "temperature": { + "type": "number", + "maximum": 1.5, + "minimum": 0, + "title": "Temperature", + "default": 0.7, + "description": "What sampling temperature to use, between 0.0 and 1.0. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but not both." + }, + "top_p": { + "type": "number", + "maximum": 1, + "minimum": 0, + "title": "Top P", + "default": 1, + "description": "Nucleus sampling, where the model considers the results of the tokens with `top_p` probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We generally recommend altering this or `temperature` but not both." + }, + "max_tokens": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Max Tokens", + "description": "The maximum number of tokens to generate in the completion. The token count of your prompt plus `max_tokens` cannot exceed the model's context length." + }, + "min_tokens": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Min Tokens", + "description": "The minimum number of tokens to generate in the completion." + }, + "stream": { + "type": "boolean", + "title": "Stream", + "default": false, + "description": "Whether to stream back partial progress. If set, tokens will be sent as data-only server-side events as they become available, with the stream terminated by a data: [DONE] message. Otherwise, the server will hold the request open until the timeout or until completion, with the response containing the full result as JSON." + }, + "stop": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "title": "Stop", + "description": "Stop generation if this token is detected. Or if one of these tokens is detected when providing an array" + }, + "random_seed": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Random Seed", + "description": "The seed to use for random sampling. If set, different calls will generate deterministic results." + }, + "messages": { + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemMessage" + }, + { + "$ref": "#/components/schemas/UserMessage" + }, + { + "$ref": "#/components/schemas/AssistantMessage" + }, + { + "$ref": "#/components/schemas/ToolMessage" + } + ], + "discriminator": { + "propertyName": "role", + "mapping": { + "assistant": "#/components/schemas/AssistantMessage", + "system": "#/components/schemas/SystemMessage", + "tool": "#/components/schemas/ToolMessage", + "user": "#/components/schemas/UserMessage" + } + } + }, + "type": "array", + "title": "Messages", + "description": "The prompt(s) to generate completions for, encoded as a list of dict with role and content.", + "examples": [ + [ + { + "role": "user", + "content": "Who is the best French painter? Answer in one short sentence." + } + ] + ] + }, + "response_format": { + "$ref": "#/components/schemas/ResponseFormat" + }, + "tools": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/Tool" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Tools" + }, + "tool_choice": { + "allOf": [ + { + "$ref": "#/components/schemas/ToolChoice" + } + ], + "default": "auto" + }, + "safe_prompt": { + "type": "boolean", + "description": "Whether to inject a safety prompt before all conversations.", + "default": false + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "messages", + "model" + ], + "title": "ChatCompletionRequest" + }, + "ChunkTypes": { + "type": "string", + "const": "text", + "title": "ChunkTypes" + }, + "ContentChunk": { + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/ChunkTypes" + } + ], + "default": "text" + }, + "text": { + "type": "string", + "title": "Text" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "text" + ], + "title": "ContentChunk" + }, + "FIMCompletionRequest": { + "properties": { + "model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Model", + "default": "codestral-2405", + "description": "ID of the model to use. Only compatible for now with:\n - `codestral-2405`\n - `codestral-latest`", + "examples": [ + "codestral-2405" + ] + }, + "temperature": { + "type": "number", + "maximum": 1.5, + "minimum": 0, + "title": "Temperature", + "default": 0.7, + "description": "What sampling temperature to use, between 0.0 and 1.0. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but not both." + }, + "top_p": { + "type": "number", + "maximum": 1, + "minimum": 0, + "title": "Top P", + "default": 1, + "description": "Nucleus sampling, where the model considers the results of the tokens with `top_p` probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We generally recommend altering this or `temperature` but not both." + }, + "max_tokens": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Max Tokens", + "description": "The maximum number of tokens to generate in the completion. The token count of your prompt plus `max_tokens` cannot exceed the model's context length." + }, + "min_tokens": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Min Tokens", + "description": "The minimum number of tokens to generate in the completion." + }, + "stream": { + "type": "boolean", + "title": "Stream", + "default": false, + "description": "Whether to stream back partial progress. If set, tokens will be sent as data-only server-side events as they become available, with the stream terminated by a data: [DONE] message. Otherwise, the server will hold the request open until the timeout or until completion, with the response containing the full result as JSON." + }, + "stop": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "title": "Stop", + "description": "Stop generation if this token is detected. Or if one of these tokens is detected when providing an array" + }, + "random_seed": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Random Seed", + "description": "The seed to use for random sampling. If set, different calls will generate deterministic results." + }, + "prompt": { + "type": "string", + "title": "Prompt", + "description": "The text/code to complete.", + "examples": [ + "def" + ] + }, + "suffix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Suffix", + "default": "", + "description": "Optional text/code that adds more context for the model. When given a `prompt` and a `suffix` the model will fill what is between them. When `suffix` is not provided, the model will simply execute completion starting with `prompt`.", + "examples": [ + "return a+b" + ] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "prompt", + "model" + ], + "title": "FIMCompletionRequest" + }, + "Function": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "description": { + "type": "string", + "title": "Description", + "default": "" + }, + "parameters": { + "type": "object", + "title": "Parameters", + "additionalProperties": true + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name", + "parameters" + ], + "title": "Function" + }, + "FunctionCall": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "arguments": { + "title": "Arguments", + "anyOf": [ + { + "type": "object", + "additionalProperties": true + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name", + "arguments" + ], + "title": "FunctionCall" + }, + "ResponseFormat": { + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/ResponseFormats" + } + ], + "default": "text" + } + }, + "additionalProperties": false, + "type": "object", + "title": "ResponseFormat" + }, + "ResponseFormats": { + "type": "string", + "enum": [ + "text", + "json_object" + ], + "title": "ResponseFormats", + "description": "An object specifying the format that the model must output. Setting to `{ \"type\": \"json_object\" }` enables JSON mode, which guarantees the message the model generates is in JSON. When using JSON mode you MUST also instruct the model to produce JSON yourself with a system or a user message." + }, + "SystemMessage": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/components/schemas/ContentChunk" + }, + "type": "array" + } + ], + "title": "Content" + }, + "role": { + "type": "string", + "default": "system", + "enum": [ + "system" + ] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "content" + ], + "title": "SystemMessage" + }, + "TextChunk": { + "properties": { + "type": { + "const": "text", + "title": "Type", + "default": "text" + }, + "text": { + "type": "string", + "title": "Text" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "text" + ], + "title": "TextChunk" + }, + "Tool": { + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/ToolTypes" + } + ], + "default": "function" + }, + "function": { + "$ref": "#/components/schemas/Function" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "function" + ], + "title": "Tool" + }, + "ToolCall": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "default": "null" + }, + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/ToolTypes" + } + ], + "default": "function" + }, + "function": { + "$ref": "#/components/schemas/FunctionCall" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "function" + ], + "title": "ToolCall" + }, + "ToolChoice": { + "type": "string", + "enum": [ + "auto", + "none", + "any" + ], + "title": "ToolChoice" + }, + "ToolMessage": { + "properties": { + "content": { + "type": "string", + "title": "Content" + }, + "tool_call_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Tool Call Id" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "role": { + "type": "string", + "default": "tool", + "enum": [ + "tool" + ] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "content" + ], + "title": "ToolMessage" + }, + "ToolTypes": { + "type": "string", + "const": "function", + "title": "ToolTypes" + }, + "UserMessage": { + "properties": { + "content": { + "title": "Content", + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/components/schemas/TextChunk" + }, + "type": "array" + } + ] + }, + "role": { + "type": "string", + "default": "user", + "enum": [ + "user" + ] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "content" + ], + "title": "UserMessage" + }, + "AgentsCompletionRequest": { + "properties": { + "max_tokens": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Max Tokens", + "description": "The maximum number of tokens to generate in the completion. The token count of your prompt plus `max_tokens` cannot exceed the model's context length." + }, + "min_tokens": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Min Tokens", + "description": "The minimum number of tokens to generate in the completion." + }, + "stream": { + "type": "boolean", + "title": "Stream", + "default": false, + "description": "Whether to stream back partial progress. If set, tokens will be sent as data-only server-side events as they become available, with the stream terminated by a data: [DONE] message. Otherwise, the server will hold the request open until the timeout or until completion, with the response containing the full result as JSON." + }, + "stop": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "title": "Stop", + "description": "Stop generation if this token is detected. Or if one of these tokens is detected when providing an array" + }, + "random_seed": { + "anyOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "null" + } + ], + "title": "Random Seed", + "description": "The seed to use for random sampling. If set, different calls will generate deterministic results." + }, + "messages": { + "type": "array", + "title": "Messages", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/UserMessage" + }, + { + "$ref": "#/components/schemas/AssistantMessage" + }, + { + "$ref": "#/components/schemas/ToolMessage" + } + ], + "discriminator": { + "propertyName": "role", + "mapping": { + "assistant": "#/components/schemas/AssistantMessage", + "tool": "#/components/schemas/ToolMessage", + "user": "#/components/schemas/UserMessage" + } + } + }, + "description": "The prompt(s) to generate completions for, encoded as a list of dict with role and content.", + "examples": [ + [ + { + "role": "user", + "content": "Who is the best French painter? Answer in one short sentence." + } + ] + ] + }, + "response_format": { + "$ref": "#/components/schemas/ResponseFormat" + }, + "tools": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/Tool" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Tools" + }, + "tool_choice": { + "allOf": [ + { + "$ref": "#/components/schemas/ToolChoice" + } + ], + "default": "auto" + }, + "agent_id": { + "type": "string", + "description": "The ID of the agent to use for this completion." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "messages", + "agent_id" + ], + "title": "AgentsCompletionRequest" + }, + "EmbeddingRequest": { + "properties": { + "input": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "title": "Input", + "description": "Text to embed." + }, + "model": { + "type": "string", + "title": "Model", + "description": "ID of the model to use." + }, + "encoding_format": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Encoding Format", + "description": "The format to return the embeddings in.", + "default": "float" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "input", + "model" + ], + "title": "EmbeddingRequest" + }, + "UsageInfo": { + "title": "UsageInfo", + "type": "object", + "properties": { + "prompt_tokens": { + "type": "integer", + "example": 16 + }, + "completion_tokens": { + "type": "integer", + "example": 34 + }, + "total_tokens": { + "type": "integer", + "example": 50 + } + }, + "required": [ + "prompt_tokens", + "completion_tokens", + "total_tokens" + ] + }, + "ResponseBase": { + "type": "object", + "title": "ResponseBase", + "properties": { + "id": { + "type": "string", + "example": "cmpl-e5cc70bb28c444948073e77776eb30ef" + }, + "object": { + "type": "string", + "example": "chat.completion" + }, + "model": { + "type": "string", + "example": "mistral-small-latest" + }, + "usage": { + "$ref": "#/components/schemas/UsageInfo" + } + } + }, + "ChatCompletionChoice": { + "title": "ChatCompletionChoice", + "type": "object", + "required": [ + "index", + "finish_reason", + "message" + ], + "properties": { + "index": { + "type": "integer", + "example": 0 + }, + "message": { + "$ref": "#/components/schemas/AssistantMessage" + }, + "finish_reason": { + "type": "string", + "enum": [ + "stop", + "length", + "model_length", + "error", + "tool_calls" + ], + "example": "stop" + } + } + }, + "ChatCompletionResponseBase": { + "allOf": [ + { + "$ref": "#/components/schemas/ResponseBase" + }, + { + "type": "object", + "title": "ChatCompletionResponseBase", + "properties": { + "created": { + "type": "integer", + "example": 1702256327 + } + } + } + ] + }, + "ChatCompletionResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/ChatCompletionResponseBase" + }, + { + "type": "object", + "title": "ChatCompletionResponse", + "properties": { + "choices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatCompletionChoice" + } + } + }, + "required": [ + "id", + "object", + "data", + "model", + "usage" + ] + } + ] + }, + "FIMCompletionResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/ChatCompletionResponse" + }, + { + "type": "object", + "properties": { + "model": { + "type": "string", + "example": "codestral-latest" + } + } + } + ] + }, + "EmbeddingResponseData": { + "title": "EmbeddingResponseData", + "type": "object", + "properties": { + "object": { + "type": "string", + "example": "embedding" + }, + "embedding": { + "type": "array", + "items": { + "type": "number" + }, + "examples": [ + 0.1, + 0.2, + 0.3 + ] + }, + "index": { + "type": "integer", + "example": 0 + } + }, + "examples": [ + { + "object": "embedding", + "embedding": [ + 0.1, + 0.2, + 0.3 + ], + "index": 0 + }, + { + "object": "embedding", + "embedding": [ + 0.4, + 0.5, + 0.6 + ], + "index": 1 + } + ] + }, + "EmbeddingResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/ResponseBase" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmbeddingResponseData" + } + } + }, + "required": [ + "id", + "object", + "data", + "model", + "usage" + ] + } + ] + }, + "CompletionEvent": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/CompletionChunk" + } + } + }, + "CompletionChunk": { + "type": "object", + "required": [ + "id", + "model", + "choices" + ], + "properties": { + "id": { + "type": "string" + }, + "object": { + "type": "string" + }, + "created": { + "type": "integer" + }, + "model": { + "type": "string" + }, + "usage": { + "$ref": "#/components/schemas/UsageInfo" + }, + "choices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompletionResponseStreamChoice" + } + } + } + }, + "CompletionResponseStreamChoice": { + "type": "object", + "required": [ + "index", + "delta", + "finish_reason" + ], + "properties": { + "index": { + "type": "integer" + }, + "delta": { + "$ref": "#/components/schemas/DeltaMessage" + }, + "finish_reason": { + "type": [ + "string", + "null" + ], + "enum": [ + "stop", + "length", + "error", + "tool_calls", + null + ] + } + } + }, + "DeltaMessage": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "tool_calls": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/ToolCall" + } + } + ] + } + } + } + }, + "securitySchemes": { + "ApiKey": { + "type": "http", + "scheme": "bearer" + } + } + }, + "tags": [ + { + "name": "chat", + "x-displayName": "Chat", + "description": "Chat Completion API." + }, + { + "name": "fim", + "x-displayName": "FIM", + "description": "Fill-in-the-middle API." + }, + { + "name": "agents", + "x-displayName": "Agents", + "description": "Agents API." + }, + { + "name": "embeddings", + "x-displayName": "Embeddings", + "description": "Embeddings API." + }, + { + "name": "files", + "x-displayName": "Files", + "description": "Files API" + }, + { + "name": "fine-tuning", + "x-displayName": "Fine Tuning", + "description": "Fine-tuning API" + }, + { + "name": "models", + "x-displayName": "Models", + "description": "Model Management API" + } + ], + "security": [ + { + "ApiKey": [] + } + ], + "servers": [ + { + "url": "https://api.mistral.ai", + "description": "Production server" + } + ] +} \ No newline at end of file diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-payload.json b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-payload.json new file mode 100644 index 0000000000..8b68988e59 --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-payload.json @@ -0,0 +1,4 @@ +{ + "model": "mistral-large-latest", + "messages": [{"role": "user", "content": "Who is the most renowned French painter?"}] +} \ No newline at end of file diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-response.json b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-response.json new file mode 100644 index 0000000000..24dfac720f --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/ai-api/mistral-response.json @@ -0,0 +1,23 @@ +{ + "id": "f821a1dd4df2492382ec9676b59ddcd3", + "object": "chat.completion", + "created": 1727259070, + "model": "mistral-large-latest", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Determining the \"most renowned\" French painter can be subjective and depends on personal preferences, as France has produced many influential and famous artists. However, some of the most celebrated French painters include:\n\n1. **Claude Monet**: Often considered one of the most famous French painters, Monet is a founder of French Impressionist painting. His works, such as \"Impression, Sunrise\" and the \"Water Lilies\" series, are iconic.\n\n2. **Pierre-Auguste Renoir**: Another leading figure of the Impressionist movement, Renoir is known for his vibrant and sensual paintings, like \"Luncheon of the Boating Party.\"\n\n3. **Paul Cézanne**: Often referred to as the \"father of modern art,\" Cézanne's work bridged the gap between Impressionism and the modern art movements of the 20th century. His paintings, such as \"The Card Players,\" are highly influential.\n\n4. **Henri Matisse**: A leading figure of the Fauvist movement, Matisse is celebrated for his use of color and innovative style. Works like \"The Dance\" and \"The Green Stripe\" are among his most famous.\n\n5. **Edgar Degas**: Known for his works in painting, sculpture, printmaking, and drawing, Degas is particularly renowned for his depictions of dancers, such as \"The Dance Class.\"\n\nEach of these artists has made significant contributions to the world of art, and their renown can vary based on different criteria and personal tastes.", + "tool_calls": null + }, + "finish_reason": "stop", + "logprobs": null + } + ], + "usage": { + "prompt_tokens": 12, + "total_tokens": 358, + "completion_tokens": 346 + } +} \ No newline at end of file diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml index e63d3f2eee..bfe2d0b7cc 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml @@ -293,6 +293,13 @@ + + + + + + + From 460b6947ca02eb92fa374bc0deb278fe3c68d1ae Mon Sep 17 00:00:00 2001 From: Avishka-Shamendra Date: Thu, 26 Sep 2024 11:19:56 +0530 Subject: [PATCH 4/6] Add developer comments --- .../org/wso2/am/integration/tests/aiapi/AIAPITestCase.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java index cd4ff520f7..9edd09bd17 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/aiapi/AIAPITestCase.java @@ -165,21 +165,24 @@ public void testMistralAIAPICreationAndPublish() throws Exception { @Test(groups = { "wso2.am" }, description = "Test AI API invocation", dependsOnMethods = "testMistralAIAPICreationAndPublish") public void testMistralAIApiInvocation() throws Exception { + + // Subscribe to API SubscriptionDTO subscriptionDTO = restAPIStore. subscribeToAPI(mistralAPIId, applicationId, APIMIntegrationConstants.API_TIER.UNLIMITED); assertNotNull(subscriptionDTO, "Mistral AI API Subscription failed"); + // Get API Key APIKeyDTO apiKeyDTO = restAPIStore. generateAPIKeys(applicationId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION.toString(), -1, null, null); assertNotNull(apiKeyDTO, "Mistral AI API Key generation failed"); String apiKey = apiKeyDTO.getApikey(); + // Invoke API Map requestHeaders = new HashMap<>(); requestHeaders.put("ApiKey", apiKey); String invokeURL = getAPIInvocationURLHttp(mistralAPIContext, mistralAPIVersion) + mistralAPIResource; - String mistralPayload = readFile(resourcePath + "mistral-payload.json"); HttpResponse serviceResponse = HTTPSClientUtils. doPost(invokeURL, requestHeaders, mistralPayload); From 8c6195363de1ee50322ae9f2d3d9da024e56747c Mon Sep 17 00:00:00 2001 From: Avishka-Shamendra Date: Thu, 26 Sep 2024 11:30:02 +0530 Subject: [PATCH 5/6] Move AI API testcase --- .../tests-backend/src/test/resources/testng.xml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml index bfe2d0b7cc..4eb4426f59 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml @@ -37,6 +37,7 @@ + @@ -293,13 +294,6 @@ - - - - - - - From 32518367ae53c79358a3ac134ae1d0c9cb255a6b Mon Sep 17 00:00:00 2001 From: AnuGayan Date: Fri, 27 Sep 2024 12:06:00 +0530 Subject: [PATCH 6/6] Fix integration test failures due to AI APIs --- .../clients/admin/api/openapi.yaml | 40 +++++++++++++++-- .../admin/api/dto/ThrottleLimitDTO.java | 44 ++++++++++++++++--- .../admin/src/main/resources/admin-api.yaml | 38 ++++++++++++++-- 3 files changed, 109 insertions(+), 13 deletions(-) diff --git a/modules/integration/tests-common/clients/admin/api/openapi.yaml b/modules/integration/tests-common/clients/admin/api/openapi.yaml index 47ea98940a..ebff2ebbd3 100644 --- a/modules/integration/tests-common/clients/admin/api/openapi.yaml +++ b/modules/integration/tests-common/clients/admin/api/openapi.yaml @@ -8139,14 +8139,15 @@ components: ThrottleLimit: properties: type: - description: | - Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". - Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in - Definitions section. + description: "Type of the throttling limit. Allowed values are \"REQUESTCOUNTLIMIT\"\ + , \"BANDWIDTHLIMIT\", \"EVENTCOUNTLIMIT\"\nand \"AIAPIQUOTALIMIT\".\n\ + Please see schemas of \"RequestCountLimit\", \"BandwidthLimit\", \"EventCountLimit\"\ + \ and \"AIAPIQuotaLimit\" \nthrottling limit types in Definitions section.\n" enum: - REQUESTCOUNTLIMIT - BANDWIDTHLIMIT - EVENTCOUNTLIMIT + - AIAPIQUOTALIMIT example: REQUESTCOUNTLIMIT type: string requestCount: @@ -8155,6 +8156,8 @@ components: $ref: '#/components/schemas/BandwidthLimit' eventCount: $ref: '#/components/schemas/EventCountLimit' + aiApiQuota: + $ref: '#/components/schemas/AIAPIQuotaLimit' required: - type title: Throttle Limit @@ -8200,6 +8203,11 @@ components: - $ref: '#/components/schemas/ThrottleLimitBase' - $ref: '#/components/schemas/RequestCountLimit_allOf' title: Request Count Limit object + AIAPIQuotaLimit: + allOf: + - $ref: '#/components/schemas/ThrottleLimitBase' + - $ref: '#/components/schemas/AIAPIQuotaLimit_allOf' + title: AI API Quota Limit object EventCountLimit: allOf: - $ref: '#/components/schemas/ThrottleLimitBase' @@ -10025,6 +10033,30 @@ components: type: integer required: - requestCount + AIAPIQuotaLimit_allOf: + properties: + requestCount: + description: Maximum number of requests allowed + example: 300 + format: int64 + type: integer + totalTokenCount: + description: Maximum number of total tokens allowed + example: 800 + format: int64 + type: integer + promptTokenCount: + description: Maximum number of prompt tokens allowed + example: 400 + format: int64 + type: integer + completionTokenCount: + description: Maximum number of completion tokens allowed + example: 500 + format: int64 + type: integer + required: + - requestCount EventCountLimit_allOf: properties: eventCount: diff --git a/modules/integration/tests-common/clients/admin/src/gen/java/org/wso2/am/integration/clients/admin/api/dto/ThrottleLimitDTO.java b/modules/integration/tests-common/clients/admin/src/gen/java/org/wso2/am/integration/clients/admin/api/dto/ThrottleLimitDTO.java index 518b8e8085..c5969fc7a6 100644 --- a/modules/integration/tests-common/clients/admin/src/gen/java/org/wso2/am/integration/clients/admin/api/dto/ThrottleLimitDTO.java +++ b/modules/integration/tests-common/clients/admin/src/gen/java/org/wso2/am/integration/clients/admin/api/dto/ThrottleLimitDTO.java @@ -23,6 +23,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.IOException; +import org.wso2.am.integration.clients.admin.api.dto.AIAPIQuotaLimitDTO; import org.wso2.am.integration.clients.admin.api.dto.BandwidthLimitDTO; import org.wso2.am.integration.clients.admin.api.dto.EventCountLimitDTO; import org.wso2.am.integration.clients.admin.api.dto.RequestCountLimitDTO; @@ -33,7 +34,7 @@ public class ThrottleLimitDTO { /** -* Type of the throttling limit. Allowed values are \"REQUESTCOUNTLIMIT\" and \"BANDWIDTHLIMIT\". Please see schemas of \"RequestCountLimit\" and \"BandwidthLimit\" throttling limit types in Definitions section. +* Type of the throttling limit. Allowed values are \"REQUESTCOUNTLIMIT\", \"BANDWIDTHLIMIT\", \"EVENTCOUNTLIMIT\" and \"AIAPIQUOTALIMIT\". Please see schemas of \"RequestCountLimit\", \"BandwidthLimit\", \"EventCountLimit\" and \"AIAPIQuotaLimit\" throttling limit types in Definitions section. */ @JsonAdapter(TypeEnum.Adapter.class) public enum TypeEnum { @@ -41,7 +42,9 @@ public enum TypeEnum { BANDWIDTHLIMIT("BANDWIDTHLIMIT"), - EVENTCOUNTLIMIT("EVENTCOUNTLIMIT"); + EVENTCOUNTLIMIT("EVENTCOUNTLIMIT"), + + AIAPIQUOTALIMIT("AIAPIQUOTALIMIT"); private String value; @@ -97,6 +100,10 @@ public TypeEnum read(final JsonReader jsonReader) throws IOException { @SerializedName(SERIALIZED_NAME_EVENT_COUNT) private EventCountLimitDTO eventCount = null; + public static final String SERIALIZED_NAME_AI_API_QUOTA = "aiApiQuota"; + @SerializedName(SERIALIZED_NAME_AI_API_QUOTA) + private AIAPIQuotaLimitDTO aiApiQuota = null; + public ThrottleLimitDTO type(TypeEnum type) { @@ -105,10 +112,10 @@ public ThrottleLimitDTO type(TypeEnum type) { } /** - * Type of the throttling limit. Allowed values are \"REQUESTCOUNTLIMIT\" and \"BANDWIDTHLIMIT\". Please see schemas of \"RequestCountLimit\" and \"BandwidthLimit\" throttling limit types in Definitions section. + * Type of the throttling limit. Allowed values are \"REQUESTCOUNTLIMIT\", \"BANDWIDTHLIMIT\", \"EVENTCOUNTLIMIT\" and \"AIAPIQUOTALIMIT\". Please see schemas of \"RequestCountLimit\", \"BandwidthLimit\", \"EventCountLimit\" and \"AIAPIQuotaLimit\" throttling limit types in Definitions section. * @return type **/ - @ApiModelProperty(example = "REQUESTCOUNTLIMIT", required = true, value = "Type of the throttling limit. Allowed values are \"REQUESTCOUNTLIMIT\" and \"BANDWIDTHLIMIT\". Please see schemas of \"RequestCountLimit\" and \"BandwidthLimit\" throttling limit types in Definitions section. ") + @ApiModelProperty(example = "REQUESTCOUNTLIMIT", required = true, value = "Type of the throttling limit. Allowed values are \"REQUESTCOUNTLIMIT\", \"BANDWIDTHLIMIT\", \"EVENTCOUNTLIMIT\" and \"AIAPIQUOTALIMIT\". Please see schemas of \"RequestCountLimit\", \"BandwidthLimit\", \"EventCountLimit\" and \"AIAPIQuotaLimit\" throttling limit types in Definitions section. ") public TypeEnum getType() { return type; @@ -189,6 +196,29 @@ public void setEventCount(EventCountLimitDTO eventCount) { } + public ThrottleLimitDTO aiApiQuota(AIAPIQuotaLimitDTO aiApiQuota) { + + this.aiApiQuota = aiApiQuota; + return this; + } + + /** + * Get aiApiQuota + * @return aiApiQuota + **/ + @javax.annotation.Nullable + @ApiModelProperty(value = "") + + public AIAPIQuotaLimitDTO getAiApiQuota() { + return aiApiQuota; + } + + + public void setAiApiQuota(AIAPIQuotaLimitDTO aiApiQuota) { + this.aiApiQuota = aiApiQuota; + } + + @Override public boolean equals(Object o) { if (this == o) { @@ -201,12 +231,13 @@ public boolean equals(Object o) { return Objects.equals(this.type, throttleLimit.type) && Objects.equals(this.requestCount, throttleLimit.requestCount) && Objects.equals(this.bandwidth, throttleLimit.bandwidth) && - Objects.equals(this.eventCount, throttleLimit.eventCount); + Objects.equals(this.eventCount, throttleLimit.eventCount) && + Objects.equals(this.aiApiQuota, throttleLimit.aiApiQuota); } @Override public int hashCode() { - return Objects.hash(type, requestCount, bandwidth, eventCount); + return Objects.hash(type, requestCount, bandwidth, eventCount, aiApiQuota); } @@ -218,6 +249,7 @@ public String toString() { sb.append(" requestCount: ").append(toIndentedString(requestCount)).append("\n"); sb.append(" bandwidth: ").append(toIndentedString(bandwidth)).append("\n"); sb.append(" eventCount: ").append(toIndentedString(eventCount)).append("\n"); + sb.append(" aiApiQuota: ").append(toIndentedString(aiApiQuota)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/modules/integration/tests-common/clients/admin/src/main/resources/admin-api.yaml b/modules/integration/tests-common/clients/admin/src/main/resources/admin-api.yaml index d8466dfc96..1e34da2414 100644 --- a/modules/integration/tests-common/clients/admin/src/main/resources/admin-api.yaml +++ b/modules/integration/tests-common/clients/admin/src/main/resources/admin-api.yaml @@ -4886,20 +4886,24 @@ components: type: type: string description: | - Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". - Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in - Definitions section. + Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT", "BANDWIDTHLIMIT", "EVENTCOUNTLIMIT" + and "AIAPIQUOTALIMIT". + Please see schemas of "RequestCountLimit", "BandwidthLimit", "EventCountLimit" and "AIAPIQuotaLimit" + throttling limit types in Definitions section. example: REQUESTCOUNTLIMIT enum: - REQUESTCOUNTLIMIT - BANDWIDTHLIMIT - EVENTCOUNTLIMIT + - AIAPIQUOTALIMIT requestCount: $ref: '#/components/schemas/RequestCountLimit' bandwidth: $ref: '#/components/schemas/BandwidthLimit' eventCount: $ref: '#/components/schemas/EventCountLimit' + aiApiQuota: + $ref: '#/components/schemas/AIAPIQuotaLimit' BurstLimit: title: Burst Limit object type: object @@ -4963,6 +4967,34 @@ components: description: Maximum number of requests allowed format: int64 example: 30 + AIAPIQuotaLimit: + title: AI API Quota Limit object + allOf: + - $ref: '#/components/schemas/ThrottleLimitBase' + - required: + - requestCount + type: object + properties: + requestCount: + type: integer + description: Maximum number of requests allowed + format: int64 + example: 300 + totalTokenCount: + type: integer + description: Maximum number of total tokens allowed + format: int64 + example: 800 + promptTokenCount: + type: integer + description: Maximum number of prompt tokens allowed + format: int64 + example: 400 + completionTokenCount: + type: integer + description: Maximum number of completion tokens allowed + format: int64 + example: 500 EventCountLimit: title: Event Count Limit object allOf: