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 d83e0ae63c09..37a1b667b5b7 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"; @@ -531,6 +548,17 @@ public final class APIConstants { public static final String FIRST_NAME = DEFAULT_CARBON_DIALECT + "/givenname"; public static final String LAST_NAME = DEFAULT_CARBON_DIALECT + "/lastname"; + // constants for marketplace assistant + public static final String MARKETPLACE_ASSISTANT = "MarketplaceAssistant"; + public static final String MARKETPLACE_ASSISTANT_ENABLED = "Enabled"; + public static final String MARKETPLACE_ASSISTANT_AUTH_TOKEN = "AuthToken"; + public static final String MARKETPLACE_ASSISTANT_ENDPOINT = "Endpoint"; + public static final String MARKETPLACE_ASSISTANT_CHAT_RESOURCE = "ChatResource"; + public static final String MARKETPLACE_ASSISTANT_PUBLISH_API_RESOURCE = "ApiPublishResource"; + public static final String MARKETPLACE_ASSISTANT_DELETE_API_RESOURCE = "ApiDeleteResource"; + public static final String MARKETPLACE_ASSISTANT_API_COUNT_RESOURCE = "ApiCountResource"; + + //Overview constants for CORS configuration public static final String API_OVERVIEW_CORS_CONFIGURATION = "overview_corsConfiguration"; //Registry lifecycle related info @@ -1678,6 +1706,34 @@ private ConfigParameters() { public static final String API_DATA_URL = "url"; public static final String API_UUID = "apiUUID"; + + public static final String UUID = "uuid"; + public static final String API_SPEC_TYPE = "api_type"; + public static final String API_SPEC_NAME = "api_name"; + public static final String TENANT_DOMAIN = "tenant_domain"; + public static final String QUERY = "query"; + public static final String HISTORY = "history"; + public static final String VERSION = "version"; + public static final String DESCRIPTION = "description"; + + public static final String DEMOTE_TO_CREATED= "Demote to Created"; + public static final String BLOCK = "Block"; + public static final String DEPRECATE = "Deprecate"; + public static final String PUBLISH = "Publish"; + public static final String DEPLOY_AS_A_PROTOTYPE = "Deploy as a Prototype"; + public static final String REPUBLISH = "Re-Publish"; + + public static final String API_SPEC_TYPE_REST = "api_spec"; + public static final String API_SPEC_TYPE_GRAPHQL = "sdl_schema"; + public static final String API_SPEC_TYPE_ASYNC = "async_spec"; + public static final String API_TYPE_HTTP = "HTTP"; + public static final String API_TYPE_WEBHOOK = "WEBHOOK"; + + public static final String API_TYPE_REST = "REST"; + + public static final String API_TYPE_GRAPHQL = "GRAPHQL"; + public static final String API_TYPE_ASYNC = "ASYNC"; + public static final String TRANSPORT_URL_IN = "TransportInURL"; // mock response generation 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/APIManagerConfiguration.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java index 62861606fb0e..b6e289da9843 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java @@ -34,6 +34,7 @@ import org.wso2.carbon.apimgt.api.model.Environment; import org.wso2.carbon.apimgt.api.model.VHost; import org.wso2.carbon.apimgt.common.gateway.configdto.HttpClientConfigurationDTO; +import org.wso2.carbon.apimgt.impl.ai.MarketplaceAssistantConfigurationDto; import org.wso2.carbon.apimgt.common.gateway.dto.ClaimMappingDto; import org.wso2.carbon.apimgt.common.gateway.dto.JWKSConfigurationDTO; import org.wso2.carbon.apimgt.common.gateway.dto.TokenIssuerDto; @@ -116,6 +117,8 @@ public class APIManagerConfiguration { private boolean initialized; private ThrottleProperties throttleProperties = new ThrottleProperties(); private ExtendedJWTConfigurationDto jwtConfigurationDto = new ExtendedJWTConfigurationDto(); + private static MarketplaceAssistantConfigurationDto marketplaceAssistantConfigurationDto = new MarketplaceAssistantConfigurationDto(); + private WorkflowProperties workflowProperties = new WorkflowProperties(); private Map apiGatewayEnvironments = new LinkedHashMap(); private static Properties realtimeNotifierProperties; @@ -160,6 +163,11 @@ public static boolean isTokenRevocationEnabled() { return !tokenRevocationClassName.isEmpty(); } + public MarketplaceAssistantConfigurationDto getMarketplaceAssistantConfigurationDto() { + + return marketplaceAssistantConfigurationDto; + } + private Set externalAPIStores = new HashSet(); private EventHubConfigurationDto eventHubConfigurationDto; private MonetizationConfigurationDto monetizationConfigurationDto = new MonetizationConfigurationDto(); @@ -624,6 +632,8 @@ private void readChildElements(OMElement serverConfig, jsonObject.put(APIConstants.CustomPropertyAttributes.REQUIRED, isRequired); customProperties.add(jsonObject); } + } else if (APIConstants.MARKETPLACE_ASSISTANT.equals(localName)) { + setMarketplaceAssistantConfiguration(element); } readChildElements(element, nameStack); nameStack.pop(); @@ -2326,4 +2336,46 @@ public HttpClientConfigurationDTO getHttpClientConfiguration() { public void setHttpClientConfiguration(HttpClientConfigurationDTO httpClientConfiguration) { this.httpClientConfiguration = httpClientConfiguration; } + + public void setMarketplaceAssistantConfiguration(OMElement omElement){ + OMElement marketplaceAssistantEnableElement = + omElement.getFirstChildWithName(new QName(APIConstants.MARKETPLACE_ASSISTANT_ENABLED)); + if (marketplaceAssistantEnableElement != null) { + marketplaceAssistantConfigurationDto.setEnabled(Boolean.parseBoolean(marketplaceAssistantEnableElement.getText())); + } + if (marketplaceAssistantConfigurationDto.isEnabled()) { + OMElement marketplaceAssistantEndpoint = + omElement.getFirstChildWithName(new QName(APIConstants.MARKETPLACE_ASSISTANT_ENDPOINT)); + if (marketplaceAssistantEndpoint != null) { + marketplaceAssistantConfigurationDto.setEndpoint(marketplaceAssistantEndpoint.getText()); + } + OMElement marketplaceAssistantToken = + omElement.getFirstChildWithName(new QName(APIConstants.MARKETPLACE_ASSISTANT_AUTH_TOKEN)); + + if (marketplaceAssistantToken != null) { + String AccessToken = MiscellaneousUtil.resolve(marketplaceAssistantToken, secretResolver); + marketplaceAssistantConfigurationDto.setAccessToken(AccessToken); + } + OMElement marketplaceAssistantApiCountResource = + omElement.getFirstChildWithName(new QName(APIConstants.MARKETPLACE_ASSISTANT_API_COUNT_RESOURCE)); + if (marketplaceAssistantApiCountResource != null) { + marketplaceAssistantConfigurationDto.setApiCountResource(marketplaceAssistantApiCountResource.getText()); + } + OMElement marketplaceAssistantApiDeleteResource = + omElement.getFirstChildWithName(new QName(APIConstants.MARKETPLACE_ASSISTANT_DELETE_API_RESOURCE)); + if (marketplaceAssistantApiDeleteResource != null) { + marketplaceAssistantConfigurationDto.setApiDeleteResource(marketplaceAssistantApiDeleteResource.getText()); + } + OMElement marketplaceAssistantApiPublishResource = + omElement.getFirstChildWithName(new QName(APIConstants.MARKETPLACE_ASSISTANT_PUBLISH_API_RESOURCE)); + if (marketplaceAssistantApiPublishResource != null) { + marketplaceAssistantConfigurationDto.setApiPublishResource(marketplaceAssistantApiPublishResource.getText()); + } + OMElement marketplaceAssistantChatResource = + omElement.getFirstChildWithName(new QName(APIConstants.MARKETPLACE_ASSISTANT_CHAT_RESOURCE)); + if (marketplaceAssistantChatResource != null) { + marketplaceAssistantConfigurationDto.setChatResource(marketplaceAssistantChatResource.getText()); + } + } + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java index 0a1c430b8ccd..2ff2f27784fa 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java @@ -2336,7 +2336,7 @@ public void deleteAPI(String apiUuid, String organization) throws APIManagementE APIConstants.EventType.API_DELETE.name(), tenantId, organization, api.getId().getApiName(), apiId, api.getUuid(), api.getId().getVersion(), api.getType(), api.getContext(), APIUtil.replaceEmailDomainBack(api.getId().getProviderName()), - api.getStatus(), api.getApiSecurity()); + api.getStatus(), api.getApiSecurity(), api.getStatus(), api.getVisibility()); APIUtil.sendNotification(apiEvent, APIConstants.NotifierType.API.name()); } else { log.debug("Event has not published to gateways due to API id has failed to retrieve from DB for API " diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/ai/MarketplaceAssistantConfigurationDto.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/ai/MarketplaceAssistantConfigurationDto.java new file mode 100644 index 000000000000..841de6f08083 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/ai/MarketplaceAssistantConfigurationDto.java @@ -0,0 +1,72 @@ +package org.wso2.carbon.apimgt.impl.ai; + +public class MarketplaceAssistantConfigurationDto { + + private String AccessToken; + private String Endpoint; + private String ApiPublishResource; + private String ChatResource; + private String ApiDeleteResource; + private String ApiCountResource; + private boolean isEnabled; + + + + public String getAccessToken() { + return AccessToken; + } + + public void setAccessToken(String AccessToken) { + this.AccessToken = AccessToken; + } + + public String getEndpoint() { + return Endpoint; + } + + public void setEndpoint(String Endpoint) { + this.Endpoint = Endpoint; + } + + public String getApiPublishResource() { + return ApiPublishResource; + } + + public void setApiPublishResource(String ApiPublishResource) { + this.ApiPublishResource = ApiPublishResource; + } + + public String getChatResource() { + return ChatResource; + } + + public void setChatResource(String ChatResource) { + this.ChatResource = ChatResource; + } + + public String getApiDeleteResource() { + return ApiDeleteResource; + } + + public void setApiDeleteResource(String ApiDeleteResource) { + this.ApiDeleteResource = ApiDeleteResource; + } + + public String getApiCountResource() { + return ApiCountResource; + } + + public void setApiCountResource(String ApiCountResource) { + this.ApiCountResource = ApiCountResource; + } + + public boolean isEnabled() { + return isEnabled; + } + + public void setEnabled(boolean Enabled) { + this.isEnabled = Enabled; + } + + +} \ No newline at end of file diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java index 6c679cc5acdf..70edf8cf0a47 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java @@ -89,6 +89,7 @@ import org.wso2.carbon.apimgt.impl.notifier.ScopesNotifier; import org.wso2.carbon.apimgt.impl.notifier.SubscriptionsNotifier; import org.wso2.carbon.apimgt.impl.notifier.KeyTemplateNotifier; +import org.wso2.carbon.apimgt.impl.notifier.MarketplaceAssistantApiPublisherNotifier; import org.wso2.carbon.apimgt.impl.observers.APIStatusObserverList; import org.wso2.carbon.apimgt.impl.observers.CommonConfigDeployer; import org.wso2.carbon.apimgt.impl.observers.KeyMgtConfigDeployer; @@ -201,6 +202,8 @@ protected void activate(ComponentContext componentContext) throws Exception { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); configuration.load(filePath); + boolean isMarketplaceAssistantEnabled = configuration.getMarketplaceAssistantConfigurationDto().isEnabled(); + //Registering Notifiers bundleContext.registerService(Notifier.class.getName(), new SubscriptionsNotifier(), null); bundleContext.registerService(Notifier.class.getName(), new ApisNotifier(), null); @@ -216,6 +219,9 @@ protected void activate(ComponentContext componentContext) throws Exception { bundleContext.registerService(Notifier.class.getName(),new KeyTemplateNotifier(), null); bundleContext.registerService(Notifier.class.getName(), new CorrelationConfigNotifier(), null); bundleContext.registerService(Notifier.class.getName(), new GatewayPolicyNotifier(), null); + if (isMarketplaceAssistantEnabled) { + bundleContext.registerService(Notifier.class.getName(), new MarketplaceAssistantApiPublisherNotifier(), null); + } APIManagerConfigurationServiceImpl configurationService = new APIManagerConfigurationServiceImpl(configuration); ServiceReferenceHolder.getInstance().setAPIManagerConfigurationService(configurationService); APIMgtDBUtil.initialize(); @@ -1097,4 +1103,3 @@ protected void unsetWorkflowTaskService(WorkflowTaskService workflowTaskService) ServiceReferenceHolder.getInstance().setWorkflowTaskService(null); } } - diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/notifier/MarketplaceAssistantApiPublisherNotifier.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/notifier/MarketplaceAssistantApiPublisherNotifier.java new file mode 100644 index 000000000000..1e923265f390 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/notifier/MarketplaceAssistantApiPublisherNotifier.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.impl.notifier; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.simple.JSONObject; +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.api.APIProvider; +import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; +import org.wso2.carbon.apimgt.impl.APIManagerFactory; +import org.wso2.carbon.apimgt.impl.ai.MarketplaceAssistantConfigurationDto; +import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; +import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; +import org.wso2.carbon.apimgt.impl.notifier.events.APIEvent; +import org.wso2.carbon.apimgt.impl.notifier.events.Event; +import org.wso2.carbon.apimgt.impl.notifier.exceptions.NotifierException; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.apimgt.impl.utils.APIUtil; + + +/** + * The default API notification service implementation in which API creation, update, delete and LifeCycle change + * events are published to gateway. + */ +public class MarketplaceAssistantApiPublisherNotifier extends ApisNotifier{ + protected ApiMgtDAO apiMgtDAO; + private static final Log log = LogFactory.getLog(MarketplaceAssistantApiPublisherNotifier.class); + private static MarketplaceAssistantConfigurationDto marketplaceAssistantConfigurationDto = new MarketplaceAssistantConfigurationDto(); + + @Override + public boolean publishEvent(Event event) throws NotifierException { + APIManagerConfiguration configuration = ServiceReferenceHolder. + getInstance().getAPIManagerConfigurationService().getAPIManagerConfiguration(); + + if (configuration == null) { + log.error("API Manager configuration is not initialized."); + } else { + marketplaceAssistantConfigurationDto = configuration.getMarketplaceAssistantConfigurationDto(); + + if (marketplaceAssistantConfigurationDto.isEnabled()) { + process(event); + } + } + return true; + } + + /** + * Add or Delete APIs from external DB when life cycle state changes + * + * @param event APIEvent to undeploy APIs from external gateway + * @return + * @throws NotifierException if error occurs + */ + private void process (Event event) throws NotifierException { + APIEvent apiEvent; + apiEvent = (APIEvent) event; + + if (!APIConstants.API_GLOBAL_VISIBILITY.equals(apiEvent.getApiVisibility())) { + return; + } + + if (APIConstants.EventType.API_LIFECYCLE_CHANGE.name().equals(event.getType())) { + String lifecycleEvent = apiEvent.getLifecycleEvent(); + String currentStatus = apiEvent.getCurrentStatus().toUpperCase(); + switch (lifecycleEvent) { + case APIConstants.DEMOTE_TO_CREATED: + case APIConstants.BLOCK: + deleteRequest(apiEvent); + break; + case APIConstants.DEPRECATE: + if (APIConstants.PUBLISHED.equals(currentStatus)){ + deleteRequest(apiEvent); + break; + } + case APIConstants.PUBLISH: + case APIConstants.DEPLOY_AS_A_PROTOTYPE: + if (APIConstants.CREATED.equals(currentStatus)) { + postRequest(apiEvent); + } + break; + case APIConstants.REPUBLISH: + postRequest(apiEvent); + break; + default: + break; + } + } else if (APIConstants.EventType.API_DELETE.name().equals(event.getType())) { + String currentStatus = apiEvent.getApiStatus().toUpperCase(); + switch (currentStatus) { + case APIConstants.PROTOTYPED: + case APIConstants.PUBLISHED: + deleteRequest(apiEvent); + break; + default: + break; + } + } + } + + private void postRequest(APIEvent apiEvent) throws NotifierException { + apiMgtDAO = ApiMgtDAO.getInstance(); + String apiId = apiEvent.getUuid(); + + try { + APIProvider apiProvider = APIManagerFactory.getInstance().getAPIProvider(CarbonContext. + getThreadLocalCarbonContext().getUsername()); + API api = apiProvider.getAPIbyUUID(apiId, apiMgtDAO.getOrganizationByAPIUUID(apiId)); + + + String api_type = api.getType(); + + JSONObject payload = new JSONObject(); + + switch (api_type) { + case APIConstants.API_TYPE_GRAPHQL: + payload.put(APIConstants.API_SPEC_TYPE_GRAPHQL, api.getGraphQLSchema()); + payload.put(APIConstants.API_SPEC_TYPE, APIConstants.API_TYPE_GRAPHQL); + break; + case APIConstants.API_TYPE_ASYNC: + case APIConstants.API_TYPE_WS: + case APIConstants.API_TYPE_WEBSUB: + case APIConstants.API_TYPE_SSE: + case APIConstants.API_TYPE_WEBHOOK: + payload.put(APIConstants.API_SPEC_TYPE_ASYNC, api.getAsyncApiDefinition()); + payload.put(APIConstants.API_SPEC_TYPE, APIConstants.API_TYPE_ASYNC); + break; + case APIConstants.API_TYPE_HTTP: + case APIConstants.API_TYPE_SOAP: + case APIConstants.API_TYPE_SOAPTOREST: + payload.put(APIConstants.API_SPEC_TYPE_REST, api.getSwaggerDefinition()); + payload.put(APIConstants.API_SPEC_TYPE, APIConstants.API_TYPE_REST); + break; + default: + break; + } + + payload.put(APIConstants.UUID, api.getUuid()); + payload.put(APIConstants.DESCRIPTION, api.getDescription()); + payload.put(APIConstants.API_SPEC_NAME, api.getId().getApiName()); + payload.put(APIConstants.TENANT_DOMAIN, apiEvent.getTenantDomain()); + payload.put(APIConstants.VERSION, apiEvent.getApiVersion()); + APIUtil.MarketplaceAssistantPostService(marketplaceAssistantConfigurationDto.getEndpoint(), + marketplaceAssistantConfigurationDto.getAccessToken(), marketplaceAssistantConfigurationDto.getApiPublishResource(), payload.toString()); + } catch (APIManagementException e) { + String errorMessage = "Error encountered while Uploading the API to the vector database" + e.getMessage(); + log.error(errorMessage, e); + } + } + + private void deleteRequest(APIEvent apiEvent) throws NotifierException { + + try { + String uuid = apiEvent.getUuid(); + APIUtil.DeleteApi(marketplaceAssistantConfigurationDto.getEndpoint(), + marketplaceAssistantConfigurationDto.getAccessToken(), marketplaceAssistantConfigurationDto.getApiDeleteResource(), uuid); + } catch (APIManagementException e) { + String errorMessage = "Error encountered while Deleting the API from the vector database"; + log.error(errorMessage); + } + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/notifier/events/APIEvent.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/notifier/events/APIEvent.java index 9c8dd27e395e..39ef0b503a81 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/notifier/events/APIEvent.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/notifier/events/APIEvent.java @@ -40,9 +40,12 @@ public class APIEvent extends Event { private String resourcePath; private APIConstants.EventAction action; private String securityScheme; + private String currentStatus; + private String apiVisibility; + private String lifecycleEvent; public APIEvent(String uuid, String logLevel, String type, String apiContext, String resourceMethod, - String resourcePath) { + String resourcePath) { this.uuid = uuid; this.logLevel = logLevel; this.type = type; @@ -82,6 +85,27 @@ public APIEvent(String eventId, long timestamp, String type, int tenantId, Strin this.securityScheme = securityScheme; } + public APIEvent(String eventId, long timestamp, String type, int tenantId, String tenantDomain, String apiName, + int apiId, String uuid, String apiVersion, String apiType, String apiContext, String apiProvider, + String apiStatus, String securityScheme, String currentStatus, String apiVisibility) { + this.eventId = eventId; + this.timeStamp = timestamp; + this.type = type; + this.tenantId = tenantId; + this.apiId = apiId; + this.uuid = uuid; + this.apiVersion = apiVersion; + this.apiName = apiName; + this.apiType = apiType; + this.apiContext = apiContext; + this.apiProvider = apiProvider; + this.apiStatus = apiStatus; + this.tenantDomain = tenantDomain; + this.securityScheme = securityScheme; + this.currentStatus = currentStatus; + this.apiVisibility = apiVisibility; + } + public APIEvent(String eventId, long timestamp, String type, int tenantId, String tenantDomain, String apiName, int apiId, String uuid, String apiVersion, String apiType, String apiContext, String apiProvider, String apiStatus, APIConstants.EventAction action, String securityScheme) { @@ -102,6 +126,28 @@ public APIEvent(String eventId, long timestamp, String type, int tenantId, Strin this.securityScheme = securityScheme; } + public APIEvent(String eventId, long timestamp, String type, int tenantId, String tenantDomain, String apiName, + int apiId, String uuid, String apiVersion, String apiType, String apiContext, String apiProvider, + String apiStatus, String securityScheme, String action, String currentStatus, String apiVisibility) { + this.eventId = eventId; + this.timeStamp = timestamp; + this.type = type; + this.tenantId = tenantId; + this.apiId = apiId; + this.uuid = uuid; + this.apiVersion = apiVersion; + this.apiName = apiName; + this.apiType = apiType; + this.apiContext = apiContext; + this.apiProvider = apiProvider; + this.apiStatus = apiStatus; + this.tenantDomain = tenantDomain; + this.securityScheme = securityScheme; + this.lifecycleEvent = action; + this.currentStatus = currentStatus; + this.apiVisibility = apiVisibility; + } + @Override public String toString() { @@ -248,4 +294,30 @@ public String getSecurityScheme() { public void setSecurityScheme(String securityScheme) { this.securityScheme = securityScheme; } -} + + public String getCurrentStatus() { + return currentStatus; + } + + public String getLifecycleEvent() { + return lifecycleEvent; + } + + public void setLifecycleEvent(String lifecycleEvent) { + this.lifecycleEvent = lifecycleEvent; + } + + + public void setCurrentStatus(String currentStatus) { + this.currentStatus = currentStatus; + } + + + public String getApiVisibility() { + return apiVisibility; + } + + public void setApiVisibility(String apiVisibility) { + this.apiVisibility = apiVisibility; + } +} \ No newline at end of file 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 a4de89e0841f..40a0f5ceece4 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 @@ -58,9 +58,7 @@ import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.methods.*; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; @@ -10387,4 +10385,163 @@ 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); + } + } + + /** + * This method is used for AI Service health check purposes. This will be utilized by API-Chat feature and + * Marketplace-Assistant feature + * + * @param endpoint Config name to retrieve the AI Service URL + * @param resource Resource that we should forward the request to + * @return CloseableHttpResponse of the GET call + * @throws APIManagementException + */ + public static CloseableHttpResponse getMarketplaceChatApiCount(String endpoint, String resource) + throws APIManagementException { + + try{ + HttpGet apiCountGet = new HttpGet(endpoint + resource); + URL url = new URL(endpoint); + int port = url.getPort(); + String protocol = url.getProtocol(); + HttpClient httpClient = APIUtil.getHttpClient(port, protocol); + return executeHTTPRequest(apiCountGet, httpClient); + } 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); + } + } + + public static String MarketplaceAssistantPostService(String endpoint, String authToken, + String resource, String payload) throws APIManagementException { + + try { + HttpPost preparePost = new HttpPost(endpoint + resource); + preparePost.setHeader(HttpHeaders.AUTHORIZATION, authToken); + preparePost.setHeader(HttpHeaders.CONTENT_TYPE, APIConstants.APPLICATION_JSON_MEDIA_TYPE); + 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) { + return null; + } else { + throw new APIManagementException("Unexpected response detected from the AI service." + responseStr); + } + } 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); + } + } + + + public static void DeleteApi(String endpoint, String authToken, + String resource, String uuid) throws APIManagementException { + + try { + String resourceWithPathParam = endpoint + resource + "/{uuid}"; + resourceWithPathParam = resourceWithPathParam.replace("{uuid}", uuid); + + HttpDelete prepareDelete = new HttpDelete(resourceWithPathParam); + prepareDelete.setHeader(HttpHeaders.AUTHORIZATION, authToken); + + URL url = new URL(endpoint); + int port = url.getPort(); + String protocol = url.getProtocol(); + HttpClient httpClient = APIUtil.getHttpClient(port, protocol); + + CloseableHttpResponse response = executeHTTPRequest(prepareDelete, httpClient); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + if (log.isDebugEnabled()) { + log.debug("Successfully completed the Marketplace Chat API publisher delete call with status code: " + statusCode); + } + } else { + String errorMessage = "Error encountered while Deleting the API from the vector database service to accommodate the " + + "Marketplace assistant"; + log.error(errorMessage); + } + } 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.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java index a0c2bfc6e7dd..33377a0ece13 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java @@ -61,6 +61,7 @@ public static void changeLifecycle(String user, APIProvider apiProvider, String String apiContext = apiTypeWrapper.getContext(); String uuid = apiTypeWrapper.getUuid(); String currentStatus = apiTypeWrapper.getStatus(); + String apiVisibility = apiTypeWrapper.getVisibility(); targetStatus = LCManagerFactory.getInstance().getLCManager().getStateForTransition(action); // Update lifecycle state in the registry @@ -77,7 +78,7 @@ public static void changeLifecycle(String user, APIProvider apiProvider, String // Add LC state change event to the event queue sendLCStateChangeNotification(apiName, apiType, apiContext, apiTypeWrapper.getId().getVersion(), targetStatus, apiTypeWrapper.getId().getProviderName(), apiTypeWrapper.getId().getId(), uuid, orgId, - apiTypeWrapper.getApi() != null ? apiTypeWrapper.getApi().getApiSecurity() : null); + apiTypeWrapper.getApi() != null ? apiTypeWrapper.getApi().getApiSecurity() : null, action, currentStatus, apiVisibility); // Remove revisions and subscriptions after API retire if (!apiTypeWrapper.isAPIProduct()) { @@ -391,14 +392,16 @@ private static void addLCStateChangeInDatabase(String user, ApiTypeWrapper apiTy * @param apiOrApiProductId unique ID of API or API product * @param uuid unique UUID of API or API Product */ - private static void sendLCStateChangeNotification(String apiName, String apiType, String apiContext, String apiVersion, - String targetStatus, String provider, int apiOrApiProductId, - String uuid, String organization, String securityScheme) throws - APIManagementException { + private static void sendLCStateChangeNotification(String apiName, String apiType, String apiContext, + String apiVersion, String targetStatus, String provider, int apiOrApiProductId, String uuid, + String organization, String securityScheme, String action, String currentStatus, String apiVisibility) + throws APIManagementException { APIEvent apiEvent = new APIEvent(UUID.randomUUID().toString(), System.currentTimeMillis(), - APIConstants.EventType.API_LIFECYCLE_CHANGE.name(), APIUtil.getInternalOrganizationId(organization), organization, apiName, apiOrApiProductId, - uuid, apiVersion, apiType, apiContext, APIUtil.replaceEmailDomainBack(provider), targetStatus, securityScheme); + APIConstants.EventType.API_LIFECYCLE_CHANGE.name(), APIUtil.getInternalOrganizationId(organization), + organization, apiName, apiOrApiProductId, uuid, apiVersion, apiType, apiContext, + APIUtil.replaceEmailDomainBack(provider), targetStatus, securityScheme, action, currentStatus, + apiVisibility); APIUtil.sendNotification(apiEvent, APIConstants.NotifierType.API.name()); } @@ -696,4 +699,4 @@ private static void handleException(String msg, Exception e) throws APIManagemen throw new APIManagementException(msg, e); } -} +} \ No newline at end of file diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentImagePermissionTest.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentImagePermissionTest.java index f4af4b012c2e..f15822cb5e89 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentImagePermissionTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentImagePermissionTest.java @@ -25,6 +25,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; +import org.wso2.carbon.apimgt.impl.ai.MarketplaceAssistantConfigurationDto; import org.wso2.carbon.apimgt.impl.utils.APIMgtDBUtil; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.base.MultitenantConstants; @@ -68,6 +69,8 @@ public void setup() throws Exception { Registry registry = Mockito.mock(Registry.class); CarbonContext carbonContext = Mockito.mock(CarbonContext.class); APIManagerConfiguration configuration = Mockito.mock(APIManagerConfiguration.class); + MarketplaceAssistantConfigurationDto marketplaceAssistantConfigurationDto = Mockito.mock( + MarketplaceAssistantConfigurationDto.class); Mockito.when(componentContext.getBundleContext()).thenReturn(bundleContext); Mockito.when(realmService.getTenantUserRealm(MultitenantConstants.SUPER_TENANT_ID)).thenReturn(userRealm); @@ -77,6 +80,8 @@ public void setup() throws Exception { Mockito.when(carbonContext.getRegistry(RegistryType.USER_GOVERNANCE)).thenReturn(registry); Mockito.doNothing().when(configuration).load(Mockito.anyString()); Mockito.when(configuration.getFirstProperty(Mockito.anyString())).thenReturn(""); + Mockito.when(configuration.getMarketplaceAssistantConfigurationDto()) + .thenReturn(marketplaceAssistantConfigurationDto); PowerMockito.when(ServiceReferenceHolder.getInstance()).thenReturn(serviceReferenceHolder); PowerMockito.when(APIUtil.getMountedPath(null, "")).thenReturn(""); PowerMockito.when(RegistryUtils.getAbsolutePath(null, null)).thenReturn(""); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentTest.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentTest.java index 62e6f431fb79..91fcf50cf282 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponentTest.java @@ -30,6 +30,7 @@ import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService; +import org.wso2.carbon.apimgt.impl.ai.MarketplaceAssistantConfigurationDto; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; import org.wso2.carbon.apimgt.impl.dto.EventHubConfigurationDto; import org.wso2.carbon.apimgt.impl.dto.GatewayArtifactSynchronizerProperties; @@ -79,6 +80,8 @@ public void testShouldActivateWhenAllPrerequisitesMet() throws Exception { UserRealm userRealm = Mockito.mock(UserRealm.class); OutputEventAdapterService adapterService = Mockito.mock(OutputEventAdapterService.class); ThrottleProperties throttleProperties = new ThrottleProperties(); + MarketplaceAssistantConfigurationDto marketplaceAssistantConfigurationDto = Mockito.mock( + MarketplaceAssistantConfigurationDto.class); Mockito.doNothing().when(configuration).load(Mockito.anyString()); Mockito.doNothing().when(authManager) @@ -97,6 +100,8 @@ public void testShouldActivateWhenAllPrerequisitesMet() throws Exception { Mockito.when(realmService.getTenantUserRealm(Mockito.anyInt())).thenReturn(userRealm); Mockito.when(userRealm.getAuthorizationManager()).thenReturn(authManager); Mockito.when(configuration.getThrottleProperties()).thenReturn(throttleProperties); + Mockito.when(configuration.getMarketplaceAssistantConfigurationDto()) + .thenReturn(marketplaceAssistantConfigurationDto); PowerMockito.doNothing().when(APIMgtDBUtil.class, "initialize"); PowerMockito.doNothing().when(APIUtil.class, "loadTenantExternalStoreConfig", Mockito.anyString()); PowerMockito.doNothing().when(AuthorizationUtils.class ,"addAuthorizeRoleListener", diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json b/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json index 8040e385bd35..a7fa59630d63 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json @@ -1354,8 +1354,8 @@ "type" : "string", "example" : "EXCHANGED", "description" : "The type of the tokens to be used (exchanged or without exchanged). Accepted values are EXCHANGED, DIRECT or BOTH.", - "default" : "DIRECT", - "enum" : [ "EXCHANGED", "DIRECT", "BOTH" ] + "enum" : [ "EXCHANGED", "DIRECT", "BOTH" ], + "default" : "DIRECT" } } }, 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..ce504bb89217 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 ###################################################### @@ -3608,6 +3651,80 @@ paths: source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/am/devportal/v3/me/change-password"' + + ###################################################### + # The "Marketplace Assistant Feature" resource APIs + ###################################################### + '/marketplace-assistant/api-count': + + #----------------------------------------------------- + # Get No of apis in the VectorDB + #----------------------------------------------------- + get: + summary: API Count endpoint. + description: | + Get the api count of Marketplace Assistant AI service. + operationId: getMarketplaceAssistantApiCount + tags: + - Marketplace Assistant + responses: + 200: + description: | + OK. + Api Count is returned. + content: + application/json: + schema: + $ref: '#/components/schemas/MarketplaceAssistantApiCountResponse' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 500: + description: | + Internal Server Error. + An error occurred while retrieving the API count. + + '/marketplace-assistant/chat': + + #----------------------------------------------------- + # Chat with Marketplace Assistant + #----------------------------------------------------- + post: + summary: Marketplace Assistant Chat Endpoint. + description: | + Send a single query to the service and get the response. + operationId: marketplaceAssistantExecute + requestBody: + description: | + Marketplace Assistant chat request payload. + content: + application/json: + schema: + $ref: '#/components/schemas/MarketplaceAssistantRequest' + tags: + - Marketplace Assistant + responses: + 201: + description: | + Created. + Marketplace Assistant chat response payload. + content: + application/json: + schema: + $ref: '#/components/schemas/MarketplaceAssistantResponse' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 429: + $ref: '#/components/responses/TooManyRequests' + 500: + description: | + Internal Server Error. + An error occurred while executing test using Marketplace Chat service. + + components: schemas: APIList: @@ -5319,6 +5436,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 +5872,227 @@ 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 + ChatMessage: + required: + - content + - role + type: object + properties: + role: + type: string + description: user or assistant role of a chat message. + example: "assistant" + content: + type: string + description: content of the message. + example: "Hi, How can I help you?" + MarketplaceAssistantRequest: + required: + - query + - history + type: object + properties: + query: + type: string + description: natural langugae query given by the user. + example: "Hi" + history: + type: array + items: + $ref: '#/components/schemas/ChatMessage' + MarketplaceAssistantApi: + required: + - apiId + - apiName + - version + type: object + properties: + apiId: + type: string + description: Uuid of the api. + example: "1sbdhsjd-121n-nknsjkd-1213njb" + apiName: + type: string + description: name of the api. + example: "PizzaShackAPI" + version: + type: string + description: version of the api. + example: "1.0.0" + MarketplaceAssistantResponse: + required: + - response + type: object + properties: + response: + type: string + description: natural language response by the llm. + example: "Hi, How can I help you?" + apis: + type: array + items: + $ref: '#/components/schemas/MarketplaceAssistantApi' + MarketplaceAssistantApiCountResponse: + required: + - count + - limit + type: object + properties: + count: + type: integer + description: no of apis stored in the vectordb. + example: "100" + limit: + type: integer + description: maximum no of apis allowed for an org. + example: "1000" + responses: BadRequest: description: Bad Request. Invalid request or validation error. @@ -5848,6 +6194,18 @@ components: description: The entity of the request was not in a supported format moreInfo: "" error: [] + TooManyRequests: + description: Too many requests. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 429 + message: TooManyRequests + description: The user has exceeded the rate limit + moreInfo: "" + error: [ ] parameters: parentCommentID: name: replyTo @@ -6090,6 +6448,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.common/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml index aaf9ca9c34fc..7f13e3215e27 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml @@ -6626,7 +6626,7 @@ paths: x-code-samples: - lang: Curl source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" - "https://127.0.0.1:9443/api/am/publisher/v4/api-products/copy-api-products?newVersion=2.0&defaultVersion=false&apiproductId=2fd14eb8-b828-4013-b448-0739d2e76bf7"' + "https://127.0.0.1:9443/api/am/publisher/v4/api-products/copy-api-products?newVersion=2.0&defaultVersion=false&apiProductId=2fd14eb8-b828-4013-b448-0739d2e76bf7"' operationId: createNewAPIProductVersion /api-products/export: 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/MarketplaceAssistantApi.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/MarketplaceAssistantApi.java new file mode 100644 index 000000000000..993e15fdca4d --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/MarketplaceAssistantApi.java @@ -0,0 +1,69 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1; + +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ErrorDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantApiCountResponseDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantRequestDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantResponseDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.MarketplaceAssistantApiService; +import org.wso2.carbon.apimgt.rest.api.store.v1.impl.MarketplaceAssistantApiServiceImpl; +import org.wso2.carbon.apimgt.api.APIManagementException; + +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import javax.inject.Inject; + +import io.swagger.annotations.*; +import java.io.InputStream; + +import org.apache.cxf.jaxrs.ext.MessageContext; +import org.apache.cxf.jaxrs.ext.multipart.Attachment; +import org.apache.cxf.jaxrs.ext.multipart.Multipart; + +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +@Path("/marketplace-assistant") + +@Api(description = "the marketplace-assistant API") + + + + +public class MarketplaceAssistantApi { + + @Context MessageContext securityContext; + +MarketplaceAssistantApiService delegate = new MarketplaceAssistantApiServiceImpl(); + + + @GET + @Path("/api-count") + + @Produces({ "application/json" }) + @ApiOperation(value = "API Count endpoint.", notes = "Get the api count of Marketplace Assistant AI service. ", response = MarketplaceAssistantApiCountResponseDTO.class, tags={ "Marketplace Assistant", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. Api Count is returned. ", response = MarketplaceAssistantApiCountResponseDTO.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 retrieving the API count. ", response = Void.class) }) + public Response getMarketplaceAssistantApiCount() throws APIManagementException{ + return delegate.getMarketplaceAssistantApiCount(securityContext); + } + + @POST + @Path("/chat") + @Consumes({ "application/json" }) + @Produces({ "application/json" }) + @ApiOperation(value = "Marketplace Assistant Chat Endpoint.", notes = "Send a single query to the service and get the response. ", response = MarketplaceAssistantResponseDTO.class, tags={ "Marketplace Assistant" }) + @ApiResponses(value = { + @ApiResponse(code = 201, message = "Created. Marketplace Assistant chat response payload. ", response = MarketplaceAssistantResponseDTO.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 = 429, message = "Too many requests.", response = ErrorDTO.class), + @ApiResponse(code = 500, message = "Internal Server Error. An error occurred while executing test using Marketplace Chat service. ", response = Void.class) }) + public Response marketplaceAssistantExecute(@ApiParam(value = "Marketplace Assistant chat request payload. " ) MarketplaceAssistantRequestDTO marketplaceAssistantRequestDTO) throws APIManagementException{ + return delegate.marketplaceAssistantExecute(marketplaceAssistantRequestDTO, securityContext); + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/MarketplaceAssistantApiService.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/MarketplaceAssistantApiService.java new file mode 100644 index 000000000000..c9ec95dea707 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/MarketplaceAssistantApiService.java @@ -0,0 +1,28 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1; + +import org.wso2.carbon.apimgt.rest.api.store.v1.*; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.*; + +import org.apache.cxf.jaxrs.ext.MessageContext; +import org.apache.cxf.jaxrs.ext.multipart.Attachment; +import org.apache.cxf.jaxrs.ext.multipart.Multipart; + +import org.wso2.carbon.apimgt.api.APIManagementException; + +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ErrorDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantApiCountResponseDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantRequestDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantResponseDTO; + +import java.util.List; + +import java.io.InputStream; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; + + +public interface MarketplaceAssistantApiService { + public Response getMarketplaceAssistantApiCount(MessageContext messageContext) throws APIManagementException; + public Response marketplaceAssistantExecute(MarketplaceAssistantRequestDTO marketplaceAssistantRequestDTO, 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/ChatMessageDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/ChatMessageDTO.java new file mode 100644 index 000000000000..11934dd05edb --- /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/ChatMessageDTO.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 ChatMessageDTO { + + private String role = null; + private String content = null; + + /** + * user or assistant role of a chat message. + **/ + public ChatMessageDTO role(String role) { + this.role = role; + return this; + } + + + @ApiModelProperty(example = "assistant", required = true, value = "user or assistant role of a chat message.") + @JsonProperty("role") + @NotNull + public String getRole() { + return role; + } + public void setRole(String role) { + this.role = role; + } + + /** + * content of the message. + **/ + public ChatMessageDTO content(String content) { + this.content = content; + return this; + } + + + @ApiModelProperty(example = "Hi, How can I help you?", required = true, value = "content of the message.") + @JsonProperty("content") + @NotNull + public String getContent() { + return content; + } + public void setContent(String content) { + this.content = content; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ChatMessageDTO chatMessage = (ChatMessageDTO) o; + return Objects.equals(role, chatMessage.role) && + Objects.equals(content, chatMessage.content); + } + + @Override + public int hashCode() { + return Objects.hash(role, content); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ChatMessageDTO {\n"); + + sb.append(" role: ").append(toIndentedString(role)).append("\n"); + sb.append(" content: ").append(toIndentedString(content)).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/MarketplaceAssistantApiCountResponseDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/MarketplaceAssistantApiCountResponseDTO.java new file mode 100644 index 000000000000..5d74191a9701 --- /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/MarketplaceAssistantApiCountResponseDTO.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 MarketplaceAssistantApiCountResponseDTO { + + private Integer count = null; + private Integer limit = null; + + /** + * no of apis stored in the vectordb. + **/ + public MarketplaceAssistantApiCountResponseDTO count(Integer count) { + this.count = count; + return this; + } + + + @ApiModelProperty(example = "100", required = true, value = "no of apis stored in the vectordb.") + @JsonProperty("count") + @NotNull + public Integer getCount() { + return count; + } + public void setCount(Integer count) { + this.count = count; + } + + /** + * maximum no of apis allowed for an org. + **/ + public MarketplaceAssistantApiCountResponseDTO limit(Integer limit) { + this.limit = limit; + return this; + } + + + @ApiModelProperty(example = "1000", required = true, value = "maximum no of apis allowed for an org.") + @JsonProperty("limit") + @NotNull + public Integer getLimit() { + return limit; + } + public void setLimit(Integer limit) { + this.limit = limit; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MarketplaceAssistantApiCountResponseDTO marketplaceAssistantApiCountResponse = (MarketplaceAssistantApiCountResponseDTO) o; + return Objects.equals(count, marketplaceAssistantApiCountResponse.count) && + Objects.equals(limit, marketplaceAssistantApiCountResponse.limit); + } + + @Override + public int hashCode() { + return Objects.hash(count, limit); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MarketplaceAssistantApiCountResponseDTO {\n"); + + sb.append(" count: ").append(toIndentedString(count)).append("\n"); + sb.append(" limit: ").append(toIndentedString(limit)).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/MarketplaceAssistantApiDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/MarketplaceAssistantApiDTO.java new file mode 100644 index 000000000000..a1c2e2563f14 --- /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/MarketplaceAssistantApiDTO.java @@ -0,0 +1,127 @@ +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 MarketplaceAssistantApiDTO { + + private String apiId = null; + private String apiName = null; + private String version = null; + + /** + * Uuid of the api. + **/ + public MarketplaceAssistantApiDTO apiId(String apiId) { + this.apiId = apiId; + return this; + } + + + @ApiModelProperty(example = "1sbdhsjd-121n-nknsjkd-1213njb", required = true, value = "Uuid of the api.") + @JsonProperty("apiId") + @NotNull + public String getApiId() { + return apiId; + } + public void setApiId(String apiId) { + this.apiId = apiId; + } + + /** + * name of the api. + **/ + public MarketplaceAssistantApiDTO apiName(String apiName) { + this.apiName = apiName; + return this; + } + + + @ApiModelProperty(example = "PizzaShackAPI", required = true, value = "name of the api.") + @JsonProperty("apiName") + @NotNull + public String getApiName() { + return apiName; + } + public void setApiName(String apiName) { + this.apiName = apiName; + } + + /** + * version of the api. + **/ + public MarketplaceAssistantApiDTO version(String version) { + this.version = version; + return this; + } + + + @ApiModelProperty(example = "1.0.0", required = true, value = "version of the api.") + @JsonProperty("version") + @NotNull + public String getVersion() { + return version; + } + public void setVersion(String version) { + this.version = version; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MarketplaceAssistantApiDTO marketplaceAssistantApi = (MarketplaceAssistantApiDTO) o; + return Objects.equals(apiId, marketplaceAssistantApi.apiId) && + Objects.equals(apiName, marketplaceAssistantApi.apiName) && + Objects.equals(version, marketplaceAssistantApi.version); + } + + @Override + public int hashCode() { + return Objects.hash(apiId, apiName, version); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MarketplaceAssistantApiDTO {\n"); + + sb.append(" apiId: ").append(toIndentedString(apiId)).append("\n"); + sb.append(" apiName: ").append(toIndentedString(apiName)).append("\n"); + sb.append(" version: ").append(toIndentedString(version)).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/MarketplaceAssistantRequestDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/MarketplaceAssistantRequestDTO.java new file mode 100644 index 000000000000..d8165aab24d8 --- /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/MarketplaceAssistantRequestDTO.java @@ -0,0 +1,108 @@ +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.ChatMessageDTO; +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 MarketplaceAssistantRequestDTO { + + private String query = null; + private List history = new ArrayList(); + + /** + * natural langugae query given by the user. + **/ + public MarketplaceAssistantRequestDTO query(String query) { + this.query = query; + return this; + } + + + @ApiModelProperty(example = "Hi", required = true, value = "natural langugae query given by the user.") + @JsonProperty("query") + @NotNull + public String getQuery() { + return query; + } + public void setQuery(String query) { + this.query = query; + } + + /** + **/ + public MarketplaceAssistantRequestDTO history(List history) { + this.history = history; + return this; + } + + + @ApiModelProperty(required = true, value = "") + @Valid + @JsonProperty("history") + @NotNull + public List getHistory() { + return history; + } + public void setHistory(List history) { + this.history = history; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MarketplaceAssistantRequestDTO marketplaceAssistantRequest = (MarketplaceAssistantRequestDTO) o; + return Objects.equals(query, marketplaceAssistantRequest.query) && + Objects.equals(history, marketplaceAssistantRequest.history); + } + + @Override + public int hashCode() { + return Objects.hash(query, history); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MarketplaceAssistantRequestDTO {\n"); + + sb.append(" query: ").append(toIndentedString(query)).append("\n"); + sb.append(" history: ").append(toIndentedString(history)).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/MarketplaceAssistantResponseDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/MarketplaceAssistantResponseDTO.java new file mode 100644 index 000000000000..f438306a7c02 --- /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/MarketplaceAssistantResponseDTO.java @@ -0,0 +1,107 @@ +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.MarketplaceAssistantApiDTO; +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 MarketplaceAssistantResponseDTO { + + private String response = null; + private List apis = new ArrayList(); + + /** + * natural language response by the llm. + **/ + public MarketplaceAssistantResponseDTO response(String response) { + this.response = response; + return this; + } + + + @ApiModelProperty(example = "Hi, How can I help you?", required = true, value = "natural language response by the llm.") + @JsonProperty("response") + @NotNull + public String getResponse() { + return response; + } + public void setResponse(String response) { + this.response = response; + } + + /** + **/ + public MarketplaceAssistantResponseDTO apis(List apis) { + this.apis = apis; + return this; + } + + + @ApiModelProperty(value = "") + @Valid + @JsonProperty("apis") + public List getApis() { + return apis; + } + public void setApis(List apis) { + this.apis = apis; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MarketplaceAssistantResponseDTO marketplaceAssistantResponse = (MarketplaceAssistantResponseDTO) o; + return Objects.equals(response, marketplaceAssistantResponse.response) && + Objects.equals(apis, marketplaceAssistantResponse.apis); + } + + @Override + public int hashCode() { + return Objects.hash(response, apis); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MarketplaceAssistantResponseDTO {\n"); + + sb.append(" response: ").append(toIndentedString(response)).append("\n"); + sb.append(" apis: ").append(toIndentedString(apis)).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..5ea5f7611698 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,14 @@ 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 +271,108 @@ 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. Cause: " + e.getCause().getMessage(); + 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. Cause: " + e.getCause().getMessage(); + 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/impl/MarketplaceAssistantApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/MarketplaceAssistantApiServiceImpl.java new file mode 100644 index 000000000000..5fbb2c74a3ca --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/MarketplaceAssistantApiServiceImpl.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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.carbon.apimgt.rest.api.store.v1.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.util.EntityUtils; +import org.json.simple.JSONObject; +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; +import org.wso2.carbon.apimgt.impl.ai.MarketplaceAssistantConfigurationDto; +import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; +import org.wso2.carbon.apimgt.impl.utils.APIUtil; +import org.wso2.carbon.apimgt.rest.api.store.v1.*; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.*; + +import org.apache.cxf.jaxrs.ext.multipart.Attachment; +import org.apache.cxf.jaxrs.ext.MessageContext; + +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.ErrorDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantApiCountResponseDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantRequestDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.MarketplaceAssistantResponseDTO; +import org.wso2.carbon.apimgt.rest.api.util.utils.RestApiUtil; + +import java.io.IOException; +import java.util.List; + +import java.io.InputStream; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; + + +public class MarketplaceAssistantApiServiceImpl implements MarketplaceAssistantApiService { + + + private static final Log log = LogFactory.getLog(MarketplaceAssistantApiServiceImpl.class); + + private static MarketplaceAssistantConfigurationDto marketplaceAssistantConfigurationDto; + + @Override + public Response marketplaceAssistantExecute(MarketplaceAssistantRequestDTO marketplaceAssistantRequestDTO, + MessageContext messageContext) throws APIManagementException { + APIManagerConfiguration configuration = ServiceReferenceHolder. + getInstance().getAPIManagerConfigurationService().getAPIManagerConfiguration(); + + if (configuration == null) { + log.error("API Manager configuration is not initialized."); + } else { + marketplaceAssistantConfigurationDto = configuration.getMarketplaceAssistantConfigurationDto(); + } + try { + if (marketplaceAssistantConfigurationDto.isEnabled()) { + + boolean isChatQueryEmpty = StringUtils.isEmpty(marketplaceAssistantRequestDTO.getQuery()); + if (isChatQueryEmpty) { + String errorMessage = "Payload is badly formatted. Expected to have 'query'"; + RestApiUtil.handleBadRequest(errorMessage, log); + return null; + } + + String organization = RestApiUtil.getValidatedOrganization(messageContext); + + JSONObject payload = new JSONObject(); + String history = new Gson().toJson(marketplaceAssistantRequestDTO.getHistory()); + + payload.put(APIConstants.QUERY, marketplaceAssistantRequestDTO.getQuery()); + payload.put(APIConstants.HISTORY, history); + payload.put(APIConstants.TENANT_DOMAIN, organization); + + String response = APIUtil. + MarketplaceAssistantPostService(marketplaceAssistantConfigurationDto.getEndpoint(), + marketplaceAssistantConfigurationDto.getAccessToken(), + marketplaceAssistantConfigurationDto.getChatResource(), payload.toString()); + + ObjectMapper objectMapper = new ObjectMapper(); + MarketplaceAssistantResponseDTO executeResponseDTO = objectMapper.readValue(response, + MarketplaceAssistantResponseDTO.class); + return Response.status(Response.Status.CREATED).entity(executeResponseDTO).build(); + } + } catch (APIManagementException | IOException e) { + String errorMessage = "Error encountered while executing the execute statement of Marketplace Assistant service"; + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } + return null; + } + + @Override + public Response getMarketplaceAssistantApiCount(MessageContext messageContext) throws APIManagementException { + APIManagerConfiguration configuration = ServiceReferenceHolder. + getInstance().getAPIManagerConfigurationService().getAPIManagerConfiguration(); + + if (configuration == null) { + log.error("API Manager configuration is not initialized."); + } else { + marketplaceAssistantConfigurationDto = configuration.getMarketplaceAssistantConfigurationDto(); + } + try { + if (marketplaceAssistantConfigurationDto.isEnabled()) { + + CloseableHttpResponse response = APIUtil. + getMarketplaceChatApiCount(marketplaceAssistantConfigurationDto.getEndpoint(), + marketplaceAssistantConfigurationDto.getApiCountResource()); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + String responseStr = EntityUtils.toString(response.getEntity()); + if (log.isDebugEnabled()) { + log.debug("Successfully completed the Marketplace Assistant api count call with status code: " + statusCode); + } + ObjectMapper objectMapper = new ObjectMapper(); + MarketplaceAssistantApiCountResponseDTO executeResponseDTO = objectMapper.readValue(responseStr, + MarketplaceAssistantApiCountResponseDTO.class); + return Response.status(Response.Status.OK).entity(executeResponseDTO).build(); + } else { + String errorMessage = "Error encountered while executing the Marketplace Assistant service to accomodate the " + + "specified testing requirement"; + log.error(errorMessage); + RestApiUtil.handleInternalServerError(errorMessage, log); + } + } + } catch (APIManagementException | IOException e) { + String errorMessage = "Error encountered while executing the execute statement of Marketplace Assistant service"; + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } + return null; + } +} 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..ce504bb89217 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 ###################################################### @@ -3608,6 +3651,80 @@ paths: source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/am/devportal/v3/me/change-password"' + + ###################################################### + # The "Marketplace Assistant Feature" resource APIs + ###################################################### + '/marketplace-assistant/api-count': + + #----------------------------------------------------- + # Get No of apis in the VectorDB + #----------------------------------------------------- + get: + summary: API Count endpoint. + description: | + Get the api count of Marketplace Assistant AI service. + operationId: getMarketplaceAssistantApiCount + tags: + - Marketplace Assistant + responses: + 200: + description: | + OK. + Api Count is returned. + content: + application/json: + schema: + $ref: '#/components/schemas/MarketplaceAssistantApiCountResponse' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 500: + description: | + Internal Server Error. + An error occurred while retrieving the API count. + + '/marketplace-assistant/chat': + + #----------------------------------------------------- + # Chat with Marketplace Assistant + #----------------------------------------------------- + post: + summary: Marketplace Assistant Chat Endpoint. + description: | + Send a single query to the service and get the response. + operationId: marketplaceAssistantExecute + requestBody: + description: | + Marketplace Assistant chat request payload. + content: + application/json: + schema: + $ref: '#/components/schemas/MarketplaceAssistantRequest' + tags: + - Marketplace Assistant + responses: + 201: + description: | + Created. + Marketplace Assistant chat response payload. + content: + application/json: + schema: + $ref: '#/components/schemas/MarketplaceAssistantResponse' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 429: + $ref: '#/components/responses/TooManyRequests' + 500: + description: | + Internal Server Error. + An error occurred while executing test using Marketplace Chat service. + + components: schemas: APIList: @@ -5319,6 +5436,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 +5872,227 @@ 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 + ChatMessage: + required: + - content + - role + type: object + properties: + role: + type: string + description: user or assistant role of a chat message. + example: "assistant" + content: + type: string + description: content of the message. + example: "Hi, How can I help you?" + MarketplaceAssistantRequest: + required: + - query + - history + type: object + properties: + query: + type: string + description: natural langugae query given by the user. + example: "Hi" + history: + type: array + items: + $ref: '#/components/schemas/ChatMessage' + MarketplaceAssistantApi: + required: + - apiId + - apiName + - version + type: object + properties: + apiId: + type: string + description: Uuid of the api. + example: "1sbdhsjd-121n-nknsjkd-1213njb" + apiName: + type: string + description: name of the api. + example: "PizzaShackAPI" + version: + type: string + description: version of the api. + example: "1.0.0" + MarketplaceAssistantResponse: + required: + - response + type: object + properties: + response: + type: string + description: natural language response by the llm. + example: "Hi, How can I help you?" + apis: + type: array + items: + $ref: '#/components/schemas/MarketplaceAssistantApi' + MarketplaceAssistantApiCountResponse: + required: + - count + - limit + type: object + properties: + count: + type: integer + description: no of apis stored in the vectordb. + example: "100" + limit: + type: integer + description: maximum no of apis allowed for an org. + example: "1000" + responses: BadRequest: description: Bad Request. Invalid request or validation error. @@ -5848,6 +6194,18 @@ components: description: The entity of the request was not in a supported format moreInfo: "" error: [] + TooManyRequests: + description: Too many requests. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 429 + message: TooManyRequests + description: The user has exceeded the rate limit + moreInfo: "" + error: [ ] parameters: parentCommentID: name: replyTo @@ -6090,6 +6448,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.store.v1/src/main/webapp/WEB-INF/beans.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/webapp/WEB-INF/beans.xml index 16f95295ab6c..071c143fd1b5 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/webapp/WEB-INF/beans.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/webapp/WEB-INF/beans.xml @@ -29,6 +29,7 @@ + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/webapp/WEB-INF/web.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/webapp/WEB-INF/web.xml index 704f87cb8b17..a82b26da74e6 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/webapp/WEB-INF/web.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/webapp/WEB-INF/web.xml @@ -48,7 +48,8 @@ org.wso2.carbon.apimgt.rest.api.store.v1.RecommendationsApi, org.wso2.carbon.apimgt.rest.api.store.v1.KeyManagersApi, org.wso2.carbon.apimgt.rest.api.store.v1.MeApi, - org.wso2.carbon.apimgt.rest.api.store.v1.WebhooksApi + org.wso2.carbon.apimgt.rest.api.store.v1.WebhooksApi, + org.wso2.carbon.apimgt.rest.api.store.v1.MarketplaceAssistantApi diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json index 585fd7d161e8..26d436826223 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json @@ -43,6 +43,13 @@ "apim.cache.restapi_token.expiry_time" : "300s", "apim.cache.restapi_cache_control_headers.max_age" : "86400s", "apim.analytics.enable": false, + "apim.ai.enable": false, + "apim.ai.token": "abc", + "apim.ai.endpoint": "http://test.com", + "apim.ai.marketplace_assistant_chat_resource": "/ai/marketplace-assistant/chat", + "apim.ai.marketplace_assistant_publish_api_resource": "/ai/spec-populator/publish-api", + "apim.ai.marketplace_assistant_remove_api_resource": "/ai/spec-populator/remove-api", + "apim.ai.marketplace_assistant_api_count_resource": "/ai/spec-populator/api-count", "apim.api_quota_limit.enable": false, "apim.http_client.max_total": "100", "apim.http_client.default_max_per_route": "50", 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 3b95d7839494..dea7d9fa0f07 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}} + + + + + + {{apim.ai.enable}} + + {{apim.ai.token}} + + {{apim.ai.endpoint}} + + {{apim.ai.marketplace_assistant_chat_resource}} + + {{apim.ai.marketplace_assistant_publish_api_resource}} + + {{apim.ai.marketplace_assistant_remove_api_resource}} + + {{apim.ai.marketplace_assistant_api_count_resource}} + + + + + + true + + + + http://localhost:9090 + + + + + + + true + + + + http://localhost:9090 + + + + + + true + + abc + + https://test.com + + /AI/marketplace-assistant/chat + + /AI/spec-populator/publish-api + + /AI/spec-populator/remove-api + + /AI/spec-populator/api-count + + + diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog.feature/src/main/resources/runtimes/cxf3/snakeyaml-2.2.jar b/features/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog.feature/src/main/resources/runtimes/cxf3/snakeyaml-2.2.jar new file mode 100644 index 000000000000..275dd5700a38 Binary files /dev/null and b/features/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog.feature/src/main/resources/runtimes/cxf3/snakeyaml-2.2.jar differ