diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java index b6fcef707870..7df9c706bd3b 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIConsumer.java @@ -799,6 +799,28 @@ Set getPaginatedSubscribedAPIsByApplication(Application applicati */ Tier getThrottlePolicyByName(String name, int policyType, String organization) throws APIManagementException; + /** + * Returns the API Chat execute call response as a string + * + * @param apiChatRequestId Request UUID + * @param requestPayload Request payload to be used for the AI service execute call + * @return execution response as a string + * @throws APIManagementException if execute call failed + */ + String invokeApiChatExecute(String apiChatRequestId, String requestPayload) throws APIManagementException; + + /** + * Returns the API Chat prepare call response as a string + * + * @param apiId ID of the API + * @param apiChatRequestId Request UUID + * @param organization Identifier of an organization + * @return prepare response + * @throws APIManagementException if prepare call failed + */ + String invokeApiChatPrepare(String apiId, String apiChatRequestId, String organization) + throws APIManagementException; + /** * This method used to retrieve key manager configurations for tenant * @param organization organization of the key manager diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java index 5b9d2ff2859d..ef13a401622d 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java @@ -548,7 +548,11 @@ public enum ExceptionCodes implements ErrorHandler { KEY_MANAGER_RESTRICTED_FOR_USER(902013, "Unauthorized Access to Key Manager", 403, "Key Manager is Restricted for this user"), // Admin portal get apis and api provider change related errors CHANGE_API_PROVIDER_FAILED(903011, "Error while changing the API provider", 500, "Error while changing the API provider in the registry or DB"), - GET_SEARCH_APIS_IN_ADMIN_FAILED(903012, "Error while getting the apis", 500, "Error while getting/searching the apis from registry"); + GET_SEARCH_APIS_IN_ADMIN_FAILED(903012, "Error while getting the apis", 500, "Error while getting/searching the apis from registry"), + + // AI service invocation related exceptions + AI_SERVICE_INVALID_RESPONSE(903100, "Invalid response from AI service", 500, "Error while invoking AI service. %s", false), + AI_SERVICE_INVALID_ACCESS_TOKEN(900906, "Invalid access token provided for AI service", 401, "Invalid access token provided for AI service"); private final long errorCode; private final String errorMessage; diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatAPISpec.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatAPISpec.java new file mode 100644 index 000000000000..8bf07147e778 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatAPISpec.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.carbon.apimgt.api.model; + +import org.json.simple.JSONArray; + +public class APIChatAPISpec { + private String serviceUrl = null; + private JSONArray tools; + + public String getServiceUrl() { + return serviceUrl; + } + + public void setServiceUrl(String serviceUrl) { + this.serviceUrl = serviceUrl; + } + + public JSONArray getTools() { + return tools; + } + + public void setTools(JSONArray tools) { + this.tools = tools; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatExecutionResponse.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatExecutionResponse.java new file mode 100644 index 000000000000..2200536a04bc --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatExecutionResponse.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.carbon.apimgt.api.model; + +public class APIChatExecutionResponse { + private Integer code = null; + private String path = null; + private Object headers = null; + private Object body = null; + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Object getHeaders() { + return headers; + } + + public void setHeaders(Object headers) { + this.headers = headers; + } + + public Object getBody() { + return body; + } + + public void setBody(Object body) { + this.body = body; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatTestExecutionInfo.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatTestExecutionInfo.java new file mode 100644 index 000000000000..f03831d6b849 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatTestExecutionInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.carbon.apimgt.api.model; + +/** + * Details related to API Chat test execution + */ +public class APIChatTestExecutionInfo { + private APIChatExecutionResponse response = null; + + public APIChatExecutionResponse getResponse() { + return response; + } + + public void setResponse(APIChatExecutionResponse response) { + this.response = response; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatTestInitializerInfo.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatTestInitializerInfo.java new file mode 100644 index 000000000000..6a3ac5f8b17d --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIChatTestInitializerInfo.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.carbon.apimgt.api.model; + +import org.json.simple.JSONObject; + +/** + * Details related to API Chat test initialization + */ +public class APIChatTestInitializerInfo { + private String command = null; + private APIChatAPISpec apiSpec = null; + + public String getCommand() { + return command; + } + + public void setCommand(String command) { + this.command = command; + } + + public APIChatAPISpec getApiSpec() { + return apiSpec; + } + + public void setApiSpec(APIChatAPISpec apiSpec) { + this.apiSpec = apiSpec; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java index 54025328e251..adf627aa26d6 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java @@ -501,6 +501,23 @@ public final class APIConstants { public static final String DIGEST = "x5t#S256"; public static final String CNF = "cnf"; + // Constants related to AI features: API chat and Marketplace Assistant + public static class AI { + + public static final String API_CHAT = "APIChat."; + public static final String API_CHAT_ENABLED = API_CHAT + "Enabled"; + public static final String API_CHAT_AUTH_TOKEN = API_CHAT + "AuthToken"; + public static final String API_CHAT_ENDPOINT = API_CHAT + "Endpoint"; + public static final String API_CHAT_PREPARE_RESOURCE = "/prepare"; + public static final String API_CHAT_EXECUTE_RESOURCE = "/chat"; + public static final String API_CHAT_ACTION_PREPARE = "PREPARE"; + public static final String API_CHAT_ACTION_EXECUTE = "EXECUTE"; + + private AI() { + + } + } + //documentation rxt public static final String DOC_NAME = "overview_name"; diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java index bf6acb99dbda..6531ad4207d9 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java @@ -3308,6 +3308,24 @@ public String getOpenAPIDefinition(String apiId, String organization) throws API return APIUtil.removeXMediationScriptsFromSwagger(definition); } + @Override + public String invokeApiChatExecute(String apiChatRequestId, String requestPayload) throws APIManagementException { + return APIUtil.invokeAIService(APIConstants.AI.API_CHAT_ENDPOINT, + APIConstants.AI.API_CHAT_AUTH_TOKEN, APIConstants.AI.API_CHAT_EXECUTE_RESOURCE, requestPayload, + apiChatRequestId); + } + + @Override + public String invokeApiChatPrepare(String apiId, String apiChatRequestId, String organization) + throws APIManagementException { + String swaggerDefinition = getOpenAPIDefinition(apiId, organization); + String payload = "{\"openapi\": " + swaggerDefinition + "}"; + String prepareResponse = APIUtil.invokeAIService(APIConstants.AI.API_CHAT_ENDPOINT, + APIConstants.AI.API_CHAT_AUTH_TOKEN, APIConstants.AI.API_CHAT_PREPARE_RESOURCE, payload, + apiChatRequestId); + return prepareResponse; + } + @Override public String getOpenAPIDefinitionForEnvironment(API api, String environmentName) throws APIManagementException { diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java index 6a43f7b4444d..f993c4701583 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java @@ -10371,4 +10371,71 @@ public static String getScopesAsString(Set scopes) { } return scopesStringBuilder.toString().trim(); } + + /** + * Check whether API Chat feature is enabled + * + * @return returns true if API Chat feature is enabled, false if disabled. + */ + public static boolean isApiChatEnabled() { + APIManagerConfiguration config = ServiceReferenceHolder.getInstance(). + getAPIManagerConfigurationService().getAPIManagerConfiguration(); + String isApiChatEnabled = config.getFirstProperty(APIConstants.AI.API_CHAT_ENABLED); + return Boolean.parseBoolean(isApiChatEnabled); + } + + /** + * Checks whether an auth token is provided for AI features to use. This token is utilized for authentication and + * throttling purposes. + * + * @return returns true if a valid auth token is found, false otherwise. + */ + public static boolean isAuthTokenProvidedForAIFeatures() { + APIManagerConfiguration config = ServiceReferenceHolder.getInstance(). + getAPIManagerConfigurationService().getAPIManagerConfiguration(); + String authToken = config.getFirstProperty(APIConstants.AI.API_CHAT_AUTH_TOKEN); + if (StringUtils.isEmpty(authToken)) { + return false; + } + return true; + } + + public static String invokeAIService(String endpointConfigName, String authTokenConfigName, + String resource, String payload, String requestId) throws APIManagementException { + + APIManagerConfiguration config = ServiceReferenceHolder.getInstance(). + getAPIManagerConfigurationService().getAPIManagerConfiguration(); + String endpoint = config.getFirstProperty(endpointConfigName); + String authToken = config.getFirstProperty(authTokenConfigName); + try { + HttpPost preparePost = new HttpPost(endpoint + resource); + preparePost.setHeader(HttpHeaders.AUTHORIZATION, APIConstants.AUTHORIZATION_BEARER + authToken); + preparePost.setHeader(HttpHeaders.CONTENT_TYPE, APIConstants.APPLICATION_JSON_MEDIA_TYPE); + preparePost.setHeader("x-request-id", requestId); + StringEntity requestEntity = new StringEntity(payload, ContentType.APPLICATION_JSON); + preparePost.setEntity(requestEntity); + + URL url = new URL(endpoint); + int port = url.getPort(); + String protocol = url.getProtocol(); + HttpClient httpClient = APIUtil.getHttpClient(port, protocol); + + CloseableHttpResponse response = executeHTTPRequest(preparePost, httpClient); + int statusCode = response.getStatusLine().getStatusCode(); + String responseStr = EntityUtils.toString(response.getEntity()); + if (statusCode == HttpStatus.SC_CREATED) { + return responseStr; + } else if (statusCode == HttpStatus.SC_UNAUTHORIZED) { + throw new APIManagementException("Unexpected response detected from the AI service." + responseStr, + ExceptionCodes.AI_SERVICE_INVALID_ACCESS_TOKEN); + } else { + throw new APIManagementException("Unexpected response detected from the AI service." + responseStr, + ExceptionCodes.AI_SERVICE_INVALID_RESPONSE); + } + } catch (MalformedURLException e) { + throw new APIManagementException("Invalid/malformed URL encountered. URL: " + endpoint, e); + } catch (APIManagementException | IOException e) { + throw new APIManagementException("Error encountered while connecting to service", e); + } + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml index 26019f4337fe..93b071249bc4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml @@ -3575,6 +3575,49 @@ paths: - lang: Curl source: curl -k "https://localhost:9443/api/am/devportal/v3/apis/e93fb282-b456-48fc-8981-003fb89086ae/graphql-policies/complexity/types" + ###################################################### + # The "API Chat Feature" resource API + ###################################################### + /apis/{apiId}/api-chat: + post: + security: + - OAuth2Security: + - apim:subscribe + summary: Test API using a natural language query + description: | + Executes a test scenario against an API; which iteratively provide resources that need to be + invoked alongside the inputs such as parameters, payloads, etc. while caching the progress. + operationId: apiChatPost + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/action' + requestBody: + description: | + API Chat request body + content: + application/json: + schema: + $ref: '#/components/schemas/ApiChatRequest' + tags: + - API Chat + responses: + 201: + description: | + Created. + API Chat action completed. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiChatResponse' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 500: + description: | + Internal Server Error. + An error occurred while invoking the API Chat service. + ###################################################### # User resource APIs ###################################################### @@ -5319,6 +5362,14 @@ components: properties too will affect the maximum password length allowed and an intersection of all conditions will be considered finally to validate the password. + apiChatEnabled: + type: boolean + description: Specifies whether API Chat feature is enabled. + default: true + aiAuthTokenProvided: + type: boolean + description: Checks if the auth token is provided for AI service usage. + default: false ApplicationAttribute: title: Application attributes type: object @@ -5747,6 +5798,152 @@ components: type: array items: type: string + ApiChatRequest: + title: API Chat request + properties: + apiChatRequestId: + type: string + description: | + Request UUID + example: "faae5fcc-cbae-40c4-bf43-89931630d313" + command: + type: string + description: | + User specified testcase to be tested against the API + example: "Get pet with id 123" + apiSpec: + type: object + properties: + serviceUrl: + type: string + description: Service URL of API if any + example: "https://localhost:8243/pizzashack/1.0.0" + tools: + type: array + description: Extracted Http tools from the OpenAPI specification + items: + type: object + example: + name: "GET-order_orderId" + description: "Get details of an Order by providing Order Id. This tool invokes a HTTP GET resource" + method: "GET" + path: "/order/{orderId}" + parameters: + orderId: + location: "path" + description: "Order Id" + required: true + style: "simple" + explode: false + schema: + type: "string" + format: "string" + response: + type: object + properties: + code: + type: integer + description: HTTP status code of the response + example: 201 + path: + type: string + description: HTTP path url with encoded parameters + example: "/order/123" + headers: + type: object + description: Response headers + example: + contentType: "application/json" + body: + type: object + description: Response payload + example: + orderId: "300ada62-81bd-4c89-bdfa-983de3cadd77" + pizzaType: "Pepperoni" + quantity: 2 + customerName: "John Doe" + creditCardNumber: "1234567890123456" + address: "123 Main St" + delivered: false + ApiChatResponse: + title: API Chat response + properties: + apiSpec: + type: object + title: Enriched API spec + required: + - tools + properties: + serviceUrl: + type: string + description: Extracted service URL from the OpenAPI specification if there is any + example: "https://localhost:8243/pizzashack/1.0.0" + tools: + type: array + description: Extracted Http tools from the OpenAPI specification + items: + type: object + example: + name: "GET-order_orderId" + description: "Get details of an Order by providing Order Id. This tool invokes a HTTP GET resource" + method: "GET" + path: "/order/{orderId}" + parameters: + orderId: + location: "path" + description: "Order Id" + required: true + style: "simple" + explode: false + schema: + type: "string" + format: "string" + taskStatus: + type: string + description: Task status (IN_PROGRESS, TERMINATED or COMPLETED) + enum: + - IN_PROGRESS + - TERMINATED + - COMPLETED + example: COMPLETED + resource: + type: object + properties: + method: + type: string + description: HTTP method of the resource + example: "GET" + path: + type: string + description: Path of the resource + example: "/order/{orderId}" + inputs: + type: object + description: Input parameters for the resource + example: + parameters: + orderId: "123" + result: + type: string + description: completion result + example: "The pet with ID 123 is available. Here are the details: - ID: 123 - Name: asd - Status: available" + queries: + type: array + description: list of sample queries + items: + $ref: '#/components/schemas/SampleQuery' + SampleQuery: + title: API Chat sample query record + required: + - scenario + - query + properties: + scenario: + type: string + description: scenario + query: + type: string + description: generated query responses: BadRequest: description: Bad Request. Invalid request or validation error. @@ -6090,6 +6287,16 @@ components: required: true schema: type: string + action: + name: apiChatAction + in: query + description: | + Action to be performed on API Chat AI Agent. Specifies whether 'prepare' or 'execute' + schema: + type: string + enum: + - PREPARE + - EXECUTE securitySchemes: OAuth2Security: type: oauth2 diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java index 88c06e182eaf..fef871764b3a 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java @@ -462,7 +462,8 @@ public Response deleteAPIRevision(@ApiParam(value = "**API ID** consisting of th @ApiOperation(value = "Delete Pending Revision Deployment Workflow Tasks", notes = "This operation can be used to remove pending revision deployment requests that are in pending state ", response = Void.class, authorizations = { @Authorization(value = "OAuth2Security", scopes = { @AuthorizationScope(scope = "apim:api_publish", description = "Publish API"), - @AuthorizationScope(scope = "apim:api_manage", description = "Manage all API related operations") + @AuthorizationScope(scope = "apim:api_manage", description = "Manage all API related operations"), + @AuthorizationScope(scope = "apim:api_create", description = "Create API") }) }, tags={ "API Revisions", }) @ApiResponses(value = { diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApi.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApi.java index 0d4f45982881..bfdd5285cb3f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApi.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApi.java @@ -2,6 +2,8 @@ import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIListDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApiChatRequestDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApiChatResponseDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.CommentDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.CommentListDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.DocumentDTO; @@ -69,6 +71,24 @@ public Response addCommentToAPI(@ApiParam(value = "**API ID** consisting of the return delegate.addCommentToAPI(apiId, postRequestBodyDTO, replyTo, securityContext); } + @POST + @Path("/{apiId}/api-chat") + @Consumes({ "application/json" }) + @Produces({ "application/json" }) + @ApiOperation(value = "Test API using a natural language query", notes = "Executes a test scenario against an API; which iteratively provide resources that need to be invoked alongside the inputs such as parameters, payloads, etc. while caching the progress. ", response = ApiChatResponseDTO.class, authorizations = { + @Authorization(value = "OAuth2Security", scopes = { + @AuthorizationScope(scope = "apim:subscribe", description = "Subscribe API") + }) + }, tags={ "API Chat", }) + @ApiResponses(value = { + @ApiResponse(code = 201, message = "Created. API Chat action completed. ", response = ApiChatResponseDTO.class), + @ApiResponse(code = 400, message = "Bad Request. Invalid request or validation error.", response = ErrorDTO.class), + @ApiResponse(code = 401, message = "Unauthorized. The user is not authorized.", response = ErrorDTO.class), + @ApiResponse(code = 500, message = "Internal Server Error. An error occurred while invoking the API Chat service. ", response = Void.class) }) + public Response apiChatPost(@ApiParam(value = "**API ID** consisting of the **UUID** of the API. ",required=true) @PathParam("apiId") String apiId, @ApiParam(value = "Action to be performed on API Chat AI Agent. Specifies whether 'prepare' or 'execute' ", allowableValues="PREPARE, EXECUTE") @QueryParam("apiChatAction") String apiChatAction, @ApiParam(value = "API Chat request body " ) ApiChatRequestDTO apiChatRequestDTO) throws APIManagementException{ + return delegate.apiChatPost(apiId, apiChatAction, apiChatRequestDTO, securityContext); + } + @GET @Path("/{apiId}/async-api-specification") diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApiService.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApiService.java index ca91af87db9e..f50b9477dbb6 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApiService.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/ApisApiService.java @@ -11,6 +11,8 @@ import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIListDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApiChatRequestDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApiChatResponseDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.CommentDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.CommentListDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.DocumentDTO; @@ -35,6 +37,7 @@ public interface ApisApiService { public Response addCommentToAPI(String apiId, PostRequestBodyDTO postRequestBodyDTO, String replyTo, MessageContext messageContext) throws APIManagementException; + public Response apiChatPost(String apiId, String apiChatAction, ApiChatRequestDTO apiChatRequestDTO, MessageContext messageContext) throws APIManagementException; public Response apisApiIdAsyncApiSpecificationGet(String apiId, String environmentName, String ifNoneMatch, String xWSO2Tenant, MessageContext messageContext) throws APIManagementException; public Response apisApiIdDocumentsDocumentIdContentGet(String apiId, String documentId, String xWSO2Tenant, String ifNoneMatch, MessageContext messageContext) throws APIManagementException; public Response apisApiIdDocumentsDocumentIdGet(String apiId, String documentId, String xWSO2Tenant, String ifNoneMatch, MessageContext messageContext) throws APIManagementException; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestApiSpecDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestApiSpecDTO.java new file mode 100644 index 000000000000..11d600eb1a60 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestApiSpecDTO.java @@ -0,0 +1,105 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.List; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class ApiChatRequestApiSpecDTO { + + private String serviceUrl = null; + private List tools = new ArrayList(); + + /** + * Service URL of API if any + **/ + public ApiChatRequestApiSpecDTO serviceUrl(String serviceUrl) { + this.serviceUrl = serviceUrl; + return this; + } + + + @ApiModelProperty(example = "https://localhost:8243/pizzashack/1.0.0", value = "Service URL of API if any") + @JsonProperty("serviceUrl") + public String getServiceUrl() { + return serviceUrl; + } + public void setServiceUrl(String serviceUrl) { + this.serviceUrl = serviceUrl; + } + + /** + * Extracted Http tools from the OpenAPI specification + **/ + public ApiChatRequestApiSpecDTO tools(List tools) { + this.tools = tools; + return this; + } + + + @ApiModelProperty(value = "Extracted Http tools from the OpenAPI specification") + @JsonProperty("tools") + public List getTools() { + return tools; + } + public void setTools(List tools) { + this.tools = tools; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ApiChatRequestApiSpecDTO apiChatRequestApiSpec = (ApiChatRequestApiSpecDTO) o; + return Objects.equals(serviceUrl, apiChatRequestApiSpec.serviceUrl) && + Objects.equals(tools, apiChatRequestApiSpec.tools); + } + + @Override + public int hashCode() { + return Objects.hash(serviceUrl, tools); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ApiChatRequestApiSpecDTO {\n"); + + sb.append(" serviceUrl: ").append(toIndentedString(serviceUrl)).append("\n"); + sb.append(" tools: ").append(toIndentedString(tools)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestDTO.java new file mode 100644 index 000000000000..82fa1b929c2f --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestDTO.java @@ -0,0 +1,147 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApiChatRequestApiSpecDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApiChatRequestResponseDTO; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class ApiChatRequestDTO { + + private String apiChatRequestId = null; + private String command = null; + private ApiChatRequestApiSpecDTO apiSpec = null; + private ApiChatRequestResponseDTO response = null; + + /** + * Request UUID + **/ + public ApiChatRequestDTO apiChatRequestId(String apiChatRequestId) { + this.apiChatRequestId = apiChatRequestId; + return this; + } + + + @ApiModelProperty(example = "faae5fcc-cbae-40c4-bf43-89931630d313", value = "Request UUID ") + @JsonProperty("apiChatRequestId") + public String getApiChatRequestId() { + return apiChatRequestId; + } + public void setApiChatRequestId(String apiChatRequestId) { + this.apiChatRequestId = apiChatRequestId; + } + + /** + * User specified testcase to be tested against the API + **/ + public ApiChatRequestDTO command(String command) { + this.command = command; + return this; + } + + + @ApiModelProperty(example = "Get pet with id 123", value = "User specified testcase to be tested against the API ") + @JsonProperty("command") + public String getCommand() { + return command; + } + public void setCommand(String command) { + this.command = command; + } + + /** + **/ + public ApiChatRequestDTO apiSpec(ApiChatRequestApiSpecDTO apiSpec) { + this.apiSpec = apiSpec; + return this; + } + + + @ApiModelProperty(value = "") + @Valid + @JsonProperty("apiSpec") + public ApiChatRequestApiSpecDTO getApiSpec() { + return apiSpec; + } + public void setApiSpec(ApiChatRequestApiSpecDTO apiSpec) { + this.apiSpec = apiSpec; + } + + /** + **/ + public ApiChatRequestDTO response(ApiChatRequestResponseDTO response) { + this.response = response; + return this; + } + + + @ApiModelProperty(value = "") + @Valid + @JsonProperty("response") + public ApiChatRequestResponseDTO getResponse() { + return response; + } + public void setResponse(ApiChatRequestResponseDTO response) { + this.response = response; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ApiChatRequestDTO apiChatRequest = (ApiChatRequestDTO) o; + return Objects.equals(apiChatRequestId, apiChatRequest.apiChatRequestId) && + Objects.equals(command, apiChatRequest.command) && + Objects.equals(apiSpec, apiChatRequest.apiSpec) && + Objects.equals(response, apiChatRequest.response); + } + + @Override + public int hashCode() { + return Objects.hash(apiChatRequestId, command, apiSpec, response); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ApiChatRequestDTO {\n"); + + sb.append(" apiChatRequestId: ").append(toIndentedString(apiChatRequestId)).append("\n"); + sb.append(" command: ").append(toIndentedString(command)).append("\n"); + sb.append(" apiSpec: ").append(toIndentedString(apiSpec)).append("\n"); + sb.append(" response: ").append(toIndentedString(response)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestResponseDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestResponseDTO.java new file mode 100644 index 000000000000..381507d16efe --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatRequestResponseDTO.java @@ -0,0 +1,147 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class ApiChatRequestResponseDTO { + + private Integer code = null; + private String path = null; + private Object headers = null; + private Object body = null; + + /** + * HTTP status code of the response + **/ + public ApiChatRequestResponseDTO code(Integer code) { + this.code = code; + return this; + } + + + @ApiModelProperty(example = "201", value = "HTTP status code of the response") + @JsonProperty("code") + public Integer getCode() { + return code; + } + public void setCode(Integer code) { + this.code = code; + } + + /** + * HTTP path url with encoded parameters + **/ + public ApiChatRequestResponseDTO path(String path) { + this.path = path; + return this; + } + + + @ApiModelProperty(example = "/order/123", value = "HTTP path url with encoded parameters") + @JsonProperty("path") + public String getPath() { + return path; + } + public void setPath(String path) { + this.path = path; + } + + /** + * Response headers + **/ + public ApiChatRequestResponseDTO headers(Object headers) { + this.headers = headers; + return this; + } + + + @ApiModelProperty(example = "{\"contentType\":\"application/json\"}", value = "Response headers") + @Valid + @JsonProperty("headers") + public Object getHeaders() { + return headers; + } + public void setHeaders(Object headers) { + this.headers = headers; + } + + /** + * Response payload + **/ + public ApiChatRequestResponseDTO body(Object body) { + this.body = body; + return this; + } + + + @ApiModelProperty(example = "{\"orderId\":\"300ada62-81bd-4c89-bdfa-983de3cadd77\",\"pizzaType\":\"Pepperoni\",\"quantity\":2,\"customerName\":\"John Doe\",\"creditCardNumber\":\"1234567890123456\",\"address\":\"123 Main St\",\"delivered\":false}", value = "Response payload") + @Valid + @JsonProperty("body") + public Object getBody() { + return body; + } + public void setBody(Object body) { + this.body = body; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ApiChatRequestResponseDTO apiChatRequestResponse = (ApiChatRequestResponseDTO) o; + return Objects.equals(code, apiChatRequestResponse.code) && + Objects.equals(path, apiChatRequestResponse.path) && + Objects.equals(headers, apiChatRequestResponse.headers) && + Objects.equals(body, apiChatRequestResponse.body); + } + + @Override + public int hashCode() { + return Objects.hash(code, path, headers, body); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ApiChatRequestResponseDTO {\n"); + + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" path: ").append(toIndentedString(path)).append("\n"); + sb.append(" headers: ").append(toIndentedString(headers)).append("\n"); + sb.append(" body: ").append(toIndentedString(body)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatResponseDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatResponseDTO.java new file mode 100644 index 000000000000..6b4f9e5cb9ba --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatResponseDTO.java @@ -0,0 +1,204 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.List; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ApiChatResponseResourceDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.EnrichedAPISpecDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.SampleQueryDTO; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class ApiChatResponseDTO { + + private EnrichedAPISpecDTO apiSpec = null; + + @XmlType(name="TaskStatusEnum") + @XmlEnum(String.class) + public enum TaskStatusEnum { + IN_PROGRESS("IN_PROGRESS"), + TERMINATED("TERMINATED"), + COMPLETED("COMPLETED"); + private String value; + + TaskStatusEnum (String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TaskStatusEnum fromValue(String v) { + for (TaskStatusEnum b : TaskStatusEnum.values()) { + if (String.valueOf(b.value).equals(v)) { + return b; + } + } +return null; + } + } + private TaskStatusEnum taskStatus = null; + private ApiChatResponseResourceDTO resource = null; + private String result = null; + private List queries = new ArrayList(); + + /** + **/ + public ApiChatResponseDTO apiSpec(EnrichedAPISpecDTO apiSpec) { + this.apiSpec = apiSpec; + return this; + } + + + @ApiModelProperty(value = "") + @Valid + @JsonProperty("apiSpec") + public EnrichedAPISpecDTO getApiSpec() { + return apiSpec; + } + public void setApiSpec(EnrichedAPISpecDTO apiSpec) { + this.apiSpec = apiSpec; + } + + /** + * Task status (IN_PROGRESS, TERMINATED or COMPLETED) + **/ + public ApiChatResponseDTO taskStatus(TaskStatusEnum taskStatus) { + this.taskStatus = taskStatus; + return this; + } + + + @ApiModelProperty(example = "COMPLETED", value = "Task status (IN_PROGRESS, TERMINATED or COMPLETED)") + @JsonProperty("taskStatus") + public TaskStatusEnum getTaskStatus() { + return taskStatus; + } + public void setTaskStatus(TaskStatusEnum taskStatus) { + this.taskStatus = taskStatus; + } + + /** + **/ + public ApiChatResponseDTO resource(ApiChatResponseResourceDTO resource) { + this.resource = resource; + return this; + } + + + @ApiModelProperty(value = "") + @Valid + @JsonProperty("resource") + public ApiChatResponseResourceDTO getResource() { + return resource; + } + public void setResource(ApiChatResponseResourceDTO resource) { + this.resource = resource; + } + + /** + * completion result + **/ + public ApiChatResponseDTO result(String result) { + this.result = result; + return this; + } + + + @ApiModelProperty(example = "The pet with ID 123 is available. Here are the details: - ID: 123 - Name: asd - Status: available", value = "completion result") + @JsonProperty("result") + public String getResult() { + return result; + } + public void setResult(String result) { + this.result = result; + } + + /** + * list of sample queries + **/ + public ApiChatResponseDTO queries(List queries) { + this.queries = queries; + return this; + } + + + @ApiModelProperty(value = "list of sample queries") + @Valid + @JsonProperty("queries") + public List getQueries() { + return queries; + } + public void setQueries(List queries) { + this.queries = queries; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ApiChatResponseDTO apiChatResponse = (ApiChatResponseDTO) o; + return Objects.equals(apiSpec, apiChatResponse.apiSpec) && + Objects.equals(taskStatus, apiChatResponse.taskStatus) && + Objects.equals(resource, apiChatResponse.resource) && + Objects.equals(result, apiChatResponse.result) && + Objects.equals(queries, apiChatResponse.queries); + } + + @Override + public int hashCode() { + return Objects.hash(apiSpec, taskStatus, resource, result, queries); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ApiChatResponseDTO {\n"); + + sb.append(" apiSpec: ").append(toIndentedString(apiSpec)).append("\n"); + sb.append(" taskStatus: ").append(toIndentedString(taskStatus)).append("\n"); + sb.append(" resource: ").append(toIndentedString(resource)).append("\n"); + sb.append(" result: ").append(toIndentedString(result)).append("\n"); + sb.append(" queries: ").append(toIndentedString(queries)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatResponseResourceDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatResponseResourceDTO.java new file mode 100644 index 000000000000..44a6e667e76c --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ApiChatResponseResourceDTO.java @@ -0,0 +1,125 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class ApiChatResponseResourceDTO { + + private String method = null; + private String path = null; + private Object inputs = null; + + /** + * HTTP method of the resource + **/ + public ApiChatResponseResourceDTO method(String method) { + this.method = method; + return this; + } + + + @ApiModelProperty(example = "GET", value = "HTTP method of the resource") + @JsonProperty("method") + public String getMethod() { + return method; + } + public void setMethod(String method) { + this.method = method; + } + + /** + * Path of the resource + **/ + public ApiChatResponseResourceDTO path(String path) { + this.path = path; + return this; + } + + + @ApiModelProperty(example = "/order/{orderId}", value = "Path of the resource") + @JsonProperty("path") + public String getPath() { + return path; + } + public void setPath(String path) { + this.path = path; + } + + /** + * Input parameters for the resource + **/ + public ApiChatResponseResourceDTO inputs(Object inputs) { + this.inputs = inputs; + return this; + } + + + @ApiModelProperty(example = "{\"parameters\":{\"orderId\":\"123\"}}", value = "Input parameters for the resource") + @Valid + @JsonProperty("inputs") + public Object getInputs() { + return inputs; + } + public void setInputs(Object inputs) { + this.inputs = inputs; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ApiChatResponseResourceDTO apiChatResponseResource = (ApiChatResponseResourceDTO) o; + return Objects.equals(method, apiChatResponseResource.method) && + Objects.equals(path, apiChatResponseResource.path) && + Objects.equals(inputs, apiChatResponseResource.inputs); + } + + @Override + public int hashCode() { + return Objects.hash(method, path, inputs); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ApiChatResponseResourceDTO {\n"); + + sb.append(" method: ").append(toIndentedString(method)).append("\n"); + sb.append(" path: ").append(toIndentedString(path)).append("\n"); + sb.append(" inputs: ").append(toIndentedString(inputs)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/EnrichedAPISpecDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/EnrichedAPISpecDTO.java new file mode 100644 index 000000000000..613fae85ea58 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/EnrichedAPISpecDTO.java @@ -0,0 +1,106 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.List; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class EnrichedAPISpecDTO { + + private String serviceUrl = null; + private List tools = new ArrayList(); + + /** + * Extracted service URL from the OpenAPI specification if there is any + **/ + public EnrichedAPISpecDTO serviceUrl(String serviceUrl) { + this.serviceUrl = serviceUrl; + return this; + } + + + @ApiModelProperty(example = "https://localhost:8243/pizzashack/1.0.0", value = "Extracted service URL from the OpenAPI specification if there is any") + @JsonProperty("serviceUrl") + public String getServiceUrl() { + return serviceUrl; + } + public void setServiceUrl(String serviceUrl) { + this.serviceUrl = serviceUrl; + } + + /** + * Extracted Http tools from the OpenAPI specification + **/ + public EnrichedAPISpecDTO tools(List tools) { + this.tools = tools; + return this; + } + + + @ApiModelProperty(required = true, value = "Extracted Http tools from the OpenAPI specification") + @JsonProperty("tools") + @NotNull + public List getTools() { + return tools; + } + public void setTools(List tools) { + this.tools = tools; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EnrichedAPISpecDTO enrichedAPISpec = (EnrichedAPISpecDTO) o; + return Objects.equals(serviceUrl, enrichedAPISpec.serviceUrl) && + Objects.equals(tools, enrichedAPISpec.tools); + } + + @Override + public int hashCode() { + return Objects.hash(serviceUrl, tools); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class EnrichedAPISpecDTO {\n"); + + sb.append(" serviceUrl: ").append(toIndentedString(serviceUrl)).append("\n"); + sb.append(" tools: ").append(toIndentedString(tools)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SampleQueryDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SampleQueryDTO.java new file mode 100644 index 000000000000..dcda2162199d --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SampleQueryDTO.java @@ -0,0 +1,105 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class SampleQueryDTO { + + private String scenario = null; + private String query = null; + + /** + * scenario + **/ + public SampleQueryDTO scenario(String scenario) { + this.scenario = scenario; + return this; + } + + + @ApiModelProperty(required = true, value = "scenario") + @JsonProperty("scenario") + @NotNull + public String getScenario() { + return scenario; + } + public void setScenario(String scenario) { + this.scenario = scenario; + } + + /** + * generated query + **/ + public SampleQueryDTO query(String query) { + this.query = query; + return this; + } + + + @ApiModelProperty(required = true, value = "generated query") + @JsonProperty("query") + @NotNull + public String getQuery() { + return query; + } + public void setQuery(String query) { + this.query = query; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SampleQueryDTO sampleQuery = (SampleQueryDTO) o; + return Objects.equals(scenario, sampleQuery.scenario) && + Objects.equals(query, sampleQuery.query); + } + + @Override + public int hashCode() { + return Objects.hash(scenario, query); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SampleQueryDTO {\n"); + + sb.append(" scenario: ").append(toIndentedString(scenario)).append("\n"); + sb.append(" query: ").append(toIndentedString(query)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java index a5a69be8330b..342de83ed67a 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SettingsDTO.java @@ -39,6 +39,8 @@ public class SettingsDTO { private String passwordPolicyPattern = null; private Integer passwordPolicyMinLength = null; private Integer passwordPolicyMaxLength = null; + private Boolean apiChatEnabled = true; + private Boolean aiAuthTokenProvided = false; /** **/ @@ -317,6 +319,42 @@ public void setPasswordPolicyMaxLength(Integer passwordPolicyMaxLength) { this.passwordPolicyMaxLength = passwordPolicyMaxLength; } + /** + * Specifies whether API Chat feature is enabled. + **/ + public SettingsDTO apiChatEnabled(Boolean apiChatEnabled) { + this.apiChatEnabled = apiChatEnabled; + return this; + } + + + @ApiModelProperty(value = "Specifies whether API Chat feature is enabled.") + @JsonProperty("apiChatEnabled") + public Boolean isApiChatEnabled() { + return apiChatEnabled; + } + public void setApiChatEnabled(Boolean apiChatEnabled) { + this.apiChatEnabled = apiChatEnabled; + } + + /** + * Checks if the auth token is provided for AI service usage. + **/ + public SettingsDTO aiAuthTokenProvided(Boolean aiAuthTokenProvided) { + this.aiAuthTokenProvided = aiAuthTokenProvided; + return this; + } + + + @ApiModelProperty(value = "Checks if the auth token is provided for AI service usage.") + @JsonProperty("aiAuthTokenProvided") + public Boolean isAiAuthTokenProvided() { + return aiAuthTokenProvided; + } + public void setAiAuthTokenProvided(Boolean aiAuthTokenProvided) { + this.aiAuthTokenProvided = aiAuthTokenProvided; + } + @Override public boolean equals(java.lang.Object o) { @@ -342,12 +380,14 @@ public boolean equals(java.lang.Object o) { Objects.equals(userStorePasswordPattern, settings.userStorePasswordPattern) && Objects.equals(passwordPolicyPattern, settings.passwordPolicyPattern) && Objects.equals(passwordPolicyMinLength, settings.passwordPolicyMinLength) && - Objects.equals(passwordPolicyMaxLength, settings.passwordPolicyMaxLength); + Objects.equals(passwordPolicyMaxLength, settings.passwordPolicyMaxLength) && + Objects.equals(apiChatEnabled, settings.apiChatEnabled) && + Objects.equals(aiAuthTokenProvided, settings.aiAuthTokenProvided); } @Override public int hashCode() { - return Objects.hash(grantTypes, scopes, applicationSharingEnabled, mapExistingAuthApps, apiGatewayEndpoint, monetizationEnabled, recommendationEnabled, isUnlimitedTierPaid, identityProvider, isAnonymousModeEnabled, isPasswordChangeEnabled, isJWTEnabledForLoginTokens, userStorePasswordPattern, passwordPolicyPattern, passwordPolicyMinLength, passwordPolicyMaxLength); + return Objects.hash(grantTypes, scopes, applicationSharingEnabled, mapExistingAuthApps, apiGatewayEndpoint, monetizationEnabled, recommendationEnabled, isUnlimitedTierPaid, identityProvider, isAnonymousModeEnabled, isPasswordChangeEnabled, isJWTEnabledForLoginTokens, userStorePasswordPattern, passwordPolicyPattern, passwordPolicyMinLength, passwordPolicyMaxLength, apiChatEnabled, aiAuthTokenProvided); } @Override @@ -371,6 +411,8 @@ public String toString() { sb.append(" passwordPolicyPattern: ").append(toIndentedString(passwordPolicyPattern)).append("\n"); sb.append(" passwordPolicyMinLength: ").append(toIndentedString(passwordPolicyMinLength)).append("\n"); sb.append(" passwordPolicyMaxLength: ").append(toIndentedString(passwordPolicyMaxLength)).append("\n"); + sb.append(" apiChatEnabled: ").append(toIndentedString(apiChatEnabled)).append("\n"); + sb.append(" aiAuthTokenProvided: ").append(toIndentedString(aiAuthTokenProvided)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java index 1b73b466d5cd..a266766547b4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/ApisApiServiceImpl.java @@ -29,6 +29,10 @@ import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.ExceptionCodes; import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIChatAPISpec; +import org.wso2.carbon.apimgt.api.model.APIChatExecutionResponse; +import org.wso2.carbon.apimgt.api.model.APIChatTestExecutionInfo; +import org.wso2.carbon.apimgt.api.model.APIChatTestInitializerInfo; import org.wso2.carbon.apimgt.api.model.APIIdentifier; import org.wso2.carbon.apimgt.api.model.APIRating; import org.wso2.carbon.apimgt.api.model.ApiTypeWrapper; @@ -36,6 +40,7 @@ import org.wso2.carbon.apimgt.api.model.CommentList; import org.wso2.carbon.apimgt.api.model.Documentation; import org.wso2.carbon.apimgt.api.model.DocumentationContent; +import org.wso2.carbon.apimgt.api.model.Environment; import org.wso2.carbon.apimgt.api.model.ResourceFile; import org.wso2.carbon.apimgt.api.model.Tier; import org.wso2.carbon.apimgt.api.model.graphql.queryanalysis.GraphqlComplexityInfo; @@ -45,13 +50,13 @@ import org.wso2.carbon.apimgt.impl.APIClientGenerationManager; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.definitions.GraphQLSchemaDefinition; -import org.wso2.carbon.apimgt.api.model.Environment; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiCommonUtil; import org.wso2.carbon.apimgt.rest.api.store.v1.ApisApiService; - +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -265,6 +270,107 @@ public Response addCommentToAPI(String apiId, PostRequestBodyDTO postRequestBody return null; } + @Override + public Response apiChatPost(String apiId, String apiChatAction, ApiChatRequestDTO apiChatRequestDTO, + MessageContext messageContext) throws APIManagementException { + if (APIUtil.isApiChatEnabled()) { + // Check the action + if (apiChatAction.equals(APIConstants.AI.API_CHAT_ACTION_PREPARE)) { + // Determine whether the request body is valid. Request body should have a request UUID. + if (StringUtils.isEmpty(apiId) || StringUtils.isEmpty(apiChatRequestDTO.getApiChatRequestId())) { + String errorMessage = "Error while executing the prepare statement as request is badly formatted"; + RestApiUtil.handleBadRequest(errorMessage, log); + return null; + } + + try { + String organization = RestApiUtil.getValidatedOrganization(messageContext); + APIConsumer apiConsumer = RestApiCommonUtil.getLoggedInUserConsumer(); + String prepareResponse = apiConsumer.invokeApiChatPrepare(apiId, + apiChatRequestDTO.getApiChatRequestId(), organization); + ObjectMapper objectMapper = new ObjectMapper(); + ApiChatResponseDTO preparationResponseDTO = objectMapper.readValue(prepareResponse, + ApiChatResponseDTO.class); + return Response.status(Response.Status.CREATED).entity(preparationResponseDTO).build(); + } catch (APIManagementException | IOException e) { + String errorMessage = "Error encountered while executing the prepare statement of API Chat service"; + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } + + } else if (apiChatAction.equals(APIConstants.AI.API_CHAT_ACTION_EXECUTE)) { + // Determine whether the request body is valid. + + // Request body should have a request UUID + if (StringUtils.isEmpty(apiChatRequestDTO.getApiChatRequestId())) { + String errorMessage = "Error executing the API Chat service. Payload is missing apiChatRequestId " + + "value"; + RestApiUtil.handleBadRequest(errorMessage, log); + return null; + } + + try { + APIConsumer apiConsumer = RestApiCommonUtil.getLoggedInUserConsumer(); + String apiChatRequestId = apiChatRequestDTO.getApiChatRequestId(); + boolean isTestInitializationRequest = !StringUtils.isEmpty( + apiChatRequestDTO.getCommand()) && apiChatRequestDTO.getApiSpec() != null; + boolean isTestExecutionRequest = apiChatRequestDTO.getResponse() != null; + String requestPayload = ""; // Request payload for Choreo deployed API Chat Agent + + if (isTestInitializationRequest) { + ApiChatRequestApiSpecDTO specDTO = apiChatRequestDTO.getApiSpec(); + APIChatAPISpec apiSpec = new APIChatAPISpec(); + apiSpec.setServiceUrl(specDTO.getServiceUrl()); + JSONArray jsonArray = new JSONArray(); + jsonArray.addAll(specDTO.getTools()); + apiSpec.setTools(jsonArray); + + APIChatTestInitializerInfo initializerInfo = new APIChatTestInitializerInfo(); + initializerInfo.setCommand(apiChatRequestDTO.getCommand()); + initializerInfo.setApiSpec(apiSpec); + + // Generate the payload for Choreo deployed API Chat Agent + ObjectMapper payloadMapper = new ObjectMapper(); + requestPayload = payloadMapper.writeValueAsString(initializerInfo); + } else if (isTestExecutionRequest) { + ApiChatRequestResponseDTO responseDTO = apiChatRequestDTO.getResponse(); + APIChatExecutionResponse responseInfo = new APIChatExecutionResponse(); + APIChatTestExecutionInfo executionInfo = new APIChatTestExecutionInfo(); + + responseInfo.setCode(responseDTO.getCode()); + responseInfo.setPath(responseDTO.getPath()); + responseInfo.setHeaders(responseDTO.getHeaders()); + responseInfo.setBody(responseDTO.getBody()); + executionInfo.setResponse(responseInfo); + + // Generate the payload for Choreo deployed API Chat Agent + ObjectMapper payloadMapper = new ObjectMapper(); + requestPayload = payloadMapper.writeValueAsString(executionInfo); + } else { + // Request should either initialize test or provide test execution progress + String errorMessage = "Payload is badly formatted. Expected to have either 'command' and " + + "'apiSpec' or 'response'"; + RestApiUtil.handleBadRequest(errorMessage, log); + return null; + } + + String executionResponse = apiConsumer.invokeApiChatExecute(apiChatRequestId, requestPayload); + ObjectMapper responseMapper = new ObjectMapper(); + ApiChatResponseDTO responseDTO = responseMapper.readValue(executionResponse, + ApiChatResponseDTO.class); + return Response.status(Response.Status.CREATED).entity(responseDTO).build(); + } catch (APIManagementException | IOException e) { + String errorMessage = "Error encountered while executing the API Chat service to accommodate the " + + "specified testing requirement"; + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } + } else { + String errorMessage = "Invalid action detected. Action is expected to be either 'PREPARE' or 'EXECUTE'"; + RestApiUtil.handleBadRequest(errorMessage, log); + } + } + return null; + } + /** * Retrieves the async api specification document of an API * diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java index b8b2febfa20f..6fcd6230f43b 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SettingsMappingUtil.java @@ -125,6 +125,8 @@ public SettingsDTO fromSettingstoDTO(Boolean isUserAvailable, Boolean moneatizat settingsDTO.setPasswordPolicyPattern(passwordPolicyPattern); settingsDTO.setPasswordPolicyMinLength(passwordPolicyMinLength); settingsDTO.setPasswordPolicyMaxLength(passwordPolicyMaxLength); + settingsDTO.setApiChatEnabled(APIUtil.isApiChatEnabled()); + settingsDTO.setAiAuthTokenProvided(APIUtil.isAuthTokenProvidedForAIFeatures()); if (isUserAvailable) { settingsDTO.setGrantTypes(APIUtil.getGrantTypes()); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml index 26019f4337fe..93b071249bc4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml @@ -3575,6 +3575,49 @@ paths: - lang: Curl source: curl -k "https://localhost:9443/api/am/devportal/v3/apis/e93fb282-b456-48fc-8981-003fb89086ae/graphql-policies/complexity/types" + ###################################################### + # The "API Chat Feature" resource API + ###################################################### + /apis/{apiId}/api-chat: + post: + security: + - OAuth2Security: + - apim:subscribe + summary: Test API using a natural language query + description: | + Executes a test scenario against an API; which iteratively provide resources that need to be + invoked alongside the inputs such as parameters, payloads, etc. while caching the progress. + operationId: apiChatPost + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/action' + requestBody: + description: | + API Chat request body + content: + application/json: + schema: + $ref: '#/components/schemas/ApiChatRequest' + tags: + - API Chat + responses: + 201: + description: | + Created. + API Chat action completed. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiChatResponse' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 500: + description: | + Internal Server Error. + An error occurred while invoking the API Chat service. + ###################################################### # User resource APIs ###################################################### @@ -5319,6 +5362,14 @@ components: properties too will affect the maximum password length allowed and an intersection of all conditions will be considered finally to validate the password. + apiChatEnabled: + type: boolean + description: Specifies whether API Chat feature is enabled. + default: true + aiAuthTokenProvided: + type: boolean + description: Checks if the auth token is provided for AI service usage. + default: false ApplicationAttribute: title: Application attributes type: object @@ -5747,6 +5798,152 @@ components: type: array items: type: string + ApiChatRequest: + title: API Chat request + properties: + apiChatRequestId: + type: string + description: | + Request UUID + example: "faae5fcc-cbae-40c4-bf43-89931630d313" + command: + type: string + description: | + User specified testcase to be tested against the API + example: "Get pet with id 123" + apiSpec: + type: object + properties: + serviceUrl: + type: string + description: Service URL of API if any + example: "https://localhost:8243/pizzashack/1.0.0" + tools: + type: array + description: Extracted Http tools from the OpenAPI specification + items: + type: object + example: + name: "GET-order_orderId" + description: "Get details of an Order by providing Order Id. This tool invokes a HTTP GET resource" + method: "GET" + path: "/order/{orderId}" + parameters: + orderId: + location: "path" + description: "Order Id" + required: true + style: "simple" + explode: false + schema: + type: "string" + format: "string" + response: + type: object + properties: + code: + type: integer + description: HTTP status code of the response + example: 201 + path: + type: string + description: HTTP path url with encoded parameters + example: "/order/123" + headers: + type: object + description: Response headers + example: + contentType: "application/json" + body: + type: object + description: Response payload + example: + orderId: "300ada62-81bd-4c89-bdfa-983de3cadd77" + pizzaType: "Pepperoni" + quantity: 2 + customerName: "John Doe" + creditCardNumber: "1234567890123456" + address: "123 Main St" + delivered: false + ApiChatResponse: + title: API Chat response + properties: + apiSpec: + type: object + title: Enriched API spec + required: + - tools + properties: + serviceUrl: + type: string + description: Extracted service URL from the OpenAPI specification if there is any + example: "https://localhost:8243/pizzashack/1.0.0" + tools: + type: array + description: Extracted Http tools from the OpenAPI specification + items: + type: object + example: + name: "GET-order_orderId" + description: "Get details of an Order by providing Order Id. This tool invokes a HTTP GET resource" + method: "GET" + path: "/order/{orderId}" + parameters: + orderId: + location: "path" + description: "Order Id" + required: true + style: "simple" + explode: false + schema: + type: "string" + format: "string" + taskStatus: + type: string + description: Task status (IN_PROGRESS, TERMINATED or COMPLETED) + enum: + - IN_PROGRESS + - TERMINATED + - COMPLETED + example: COMPLETED + resource: + type: object + properties: + method: + type: string + description: HTTP method of the resource + example: "GET" + path: + type: string + description: Path of the resource + example: "/order/{orderId}" + inputs: + type: object + description: Input parameters for the resource + example: + parameters: + orderId: "123" + result: + type: string + description: completion result + example: "The pet with ID 123 is available. Here are the details: - ID: 123 - Name: asd - Status: available" + queries: + type: array + description: list of sample queries + items: + $ref: '#/components/schemas/SampleQuery' + SampleQuery: + title: API Chat sample query record + required: + - scenario + - query + properties: + scenario: + type: string + description: scenario + query: + type: string + description: generated query responses: BadRequest: description: Bad Request. Invalid request or validation error. @@ -6090,6 +6287,16 @@ components: required: true schema: type: string + action: + name: apiChatAction + in: query + description: | + Action to be performed on API Chat AI Agent. Specifies whether 'prepare' or 'execute' + schema: + type: string + enum: + - PREPARE + - EXECUTE securitySchemes: OAuth2Security: type: oauth2 diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 index 11248a7067b8..d8fcc2d3f512 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 @@ -353,6 +353,34 @@ + + + + {{apim.ai.enable}} + + {{apim.ai.token}} + + {{apim.ai.endpoint}} + + + + + + + {{apim.ai.enable}} + + {{apim.ai.token}} + + {{apim.ai.endpoint}} + + + + + + true + + + + http://localhost:9090 + + + + + + + true + + + + http://localhost:9090 + + +