From 07422d5dc7df55251009a4cddcfc0866580d665f Mon Sep 17 00:00:00 2001 From: Rashmika998 Date: Wed, 11 Feb 2026 18:40:21 +0530 Subject: [PATCH 1/6] Add AI chat agent --- .../customer-portal/backend/config.toml.local | 8 ++ .../modules/ai_chat_agent/ai_chat_agent.bal | 25 +++++++ .../backend/modules/ai_chat_agent/client.bal | 37 ++++++++++ .../backend/modules/ai_chat_agent/types.bal | 73 +++++++++++++++++++ apps/customer-portal/backend/service.bal | 39 ++++++++++ apps/customer-portal/backend/types.bal | 14 ++++ 6 files changed, 196 insertions(+) create mode 100644 apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal create mode 100644 apps/customer-portal/backend/modules/ai_chat_agent/client.bal create mode 100644 apps/customer-portal/backend/modules/ai_chat_agent/types.bal diff --git a/apps/customer-portal/backend/config.toml.local b/apps/customer-portal/backend/config.toml.local index be064f470e..a85c0e09a6 100644 --- a/apps/customer-portal/backend/config.toml.local +++ b/apps/customer-portal/backend/config.toml.local @@ -24,3 +24,11 @@ updatesServiceUrl = "" clientId = "" clientSecret = "" scopes = [""] + +[customer_portal.ai_chat_agent] +aiChatAgentBaseUrl = "" +[customer_portal.updates.clientCredentialsOauth2Config] + tokenUrl = "" + clientId = "" + clientSecret = "" + scopes = [""] \ No newline at end of file diff --git a/apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal b/apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal new file mode 100644 index 0000000000..150e48d073 --- /dev/null +++ b/apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal @@ -0,0 +1,25 @@ +// Copyright (c) 2026 WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +# Get case classification for the given payload. +# +# + payload - Case classification payload +# + return - Case classification response or error +public isolated function createCaseClassification(CaseClassificationPayload payload) + returns CaseClassificationResponse|error { + + return aiChatAgentClient->/case_classification.post(payload); +} diff --git a/apps/customer-portal/backend/modules/ai_chat_agent/client.bal b/apps/customer-portal/backend/modules/ai_chat_agent/client.bal new file mode 100644 index 0000000000..13c44376a8 --- /dev/null +++ b/apps/customer-portal/backend/modules/ai_chat_agent/client.bal @@ -0,0 +1,37 @@ +// Copyright (c) 2026 WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +import ballerina/http; + +configurable string aiChatAgentBaseUrl = ?; +configurable ClientCredentialsOauth2Config clientCredentialsOauth2Config = ?; + +final http:Client aiChatAgentClient = check new (aiChatAgentBaseUrl, { + auth: { + ...clientCredentialsOauth2Config + }, + httpVersion: http:HTTP_1_1, + http1Settings: {keepAlive: http:KEEPALIVE_NEVER}, + timeout: 300.0, + retryConfig: { + count: 3, + interval: 2.0, + statusCodes: [ + http:STATUS_BAD_GATEWAY, + http:STATUS_SERVICE_UNAVAILABLE, + http:STATUS_GATEWAY_TIMEOUT + ] + } +}); diff --git a/apps/customer-portal/backend/modules/ai_chat_agent/types.bal b/apps/customer-portal/backend/modules/ai_chat_agent/types.bal new file mode 100644 index 0000000000..3c895a3232 --- /dev/null +++ b/apps/customer-portal/backend/modules/ai_chat_agent/types.bal @@ -0,0 +1,73 @@ +// Copyright (c) 2026 WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +import ballerina/data.jsondata; + +# [Configurable] Client credentials grant type oauth2 configuration. +type ClientCredentialsOauth2Config record {| + # OAuth2 token endpoint + string tokenUrl; + # OAuth2 client ID + string clientId; + # OAuth2 client secret + string clientSecret; + # OAuth2 scopes + string[] scopes = []; +|}; + +# Case classification payload. +public type CaseClassificationPayload record {| + # Chat history + string chat_history; + # Product details + string[] productDetails; + # Environments + string[] environments; + # Region + string region; + # Tier + string tier; +|}; + +# Case classification response. +public type CaseClassificationResponse record {| + # Issue type + string issueType; + # Case information + @jsondata:Name {value: "case_info"} + ChatCaseInfo caseInfo; + # Severity level + string severityLevel; + json...; +|}; + +# Chat case information. +public type ChatCaseInfo record {| + # Description + string description; + # Short description + string shortDescription; + # Product name + string productName; + # Product version + string productVersion; + # Environment + string environment; + # Tier + string tier; + # Region + string region; + json...; +|}; diff --git a/apps/customer-portal/backend/service.bal b/apps/customer-portal/backend/service.bal index 8ff9cb0910..1897d3d8a5 100644 --- a/apps/customer-portal/backend/service.bal +++ b/apps/customer-portal/backend/service.bal @@ -14,6 +14,7 @@ // specific language governing permissions and limitations // under the License. +import customer_portal.ai_chat_agent; import customer_portal.authorization; import customer_portal.entity; import customer_portal.scim; @@ -829,6 +830,44 @@ service http:InterceptableService / on new http:Listener(9090) { return getCaseFilters(caseMetadata); } + # Classify the case using AI chat agent. + # + # + payload - case classification payload + # + return - Case classification response or an error + resource function post cases/classification(http:RequestContext ctx, CaseClassificationPayload payload) + returns ai_chat_agent:CaseClassificationResponse|http:InternalServerError { + + authorization:UserInfoPayload|error userInfo = ctx.getWithType(authorization:HEADER_USER_INFO); + if userInfo is error { + return { + body: { + message: ERR_MSG_USER_INFO_HEADER_NOT_FOUND + } + }; + } + + // TODO: Need to persist the chat history + ai_chat_agent:CaseClassificationResponse|error classificationResponse = + ai_chat_agent:createCaseClassification( + { + chat_history: payload.chatHistory, + productDetails: payload.productDetails, + environments: payload.environments, + region: payload.region, + tier: payload.tier + }); + if classificationResponse is error { + string customError = "Failed to classify chat message."; + log:printError(customError, classificationResponse); + return { + body: { + message: customError + } + }; + } + return classificationResponse; + } + # Get comments for a specific case. # # + id - ID of the case diff --git a/apps/customer-portal/backend/types.bal b/apps/customer-portal/backend/types.bal index bdaaae548d..3a45b10669 100644 --- a/apps/customer-portal/backend/types.bal +++ b/apps/customer-portal/backend/types.bal @@ -309,3 +309,17 @@ public type AttachmentPayload record {| # Base 64 encoded content string content; |}; + +# Case classification payload. +public type CaseClassificationPayload record {| + # Chat history + string chatHistory; + # Product details + string[] productDetails; + # Environments + string[] environments; + # Region + string region; + # Tier + string tier; +|}; From 20ef037dfa42a1ad506de4e0d06de332701a982d Mon Sep 17 00:00:00 2001 From: Rashmika998 Date: Wed, 11 Feb 2026 18:48:49 +0530 Subject: [PATCH 2/6] format config.toml.local --- apps/customer-portal/backend/config.toml.local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/customer-portal/backend/config.toml.local b/apps/customer-portal/backend/config.toml.local index a85c0e09a6..93493577c1 100644 --- a/apps/customer-portal/backend/config.toml.local +++ b/apps/customer-portal/backend/config.toml.local @@ -31,4 +31,4 @@ aiChatAgentBaseUrl = "" tokenUrl = "" clientId = "" clientSecret = "" - scopes = [""] \ No newline at end of file + scopes = [""] From d57647263844943f7ddbe733f73aaa265f9adeb7 Mon Sep 17 00:00:00 2001 From: Rashmika998 Date: Wed, 11 Feb 2026 18:50:46 +0530 Subject: [PATCH 3/6] Update documentation --- .../backend/modules/ai_chat_agent/ai_chat_agent.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal b/apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal index 150e48d073..d0488b771f 100644 --- a/apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal +++ b/apps/customer-portal/backend/modules/ai_chat_agent/ai_chat_agent.bal @@ -14,7 +14,7 @@ // specific language governing permissions and limitations // under the License. -# Get case classification for the given payload. +# Create case classification for the given payload. # # + payload - Case classification payload # + return - Case classification response or error From 7bdb09f5e54ed4cc5656874811adcbb52fc4ca15 Mon Sep 17 00:00:00 2001 From: Rashmika998 Date: Wed, 11 Feb 2026 18:57:57 +0530 Subject: [PATCH 4/6] Update config.toml.local --- apps/customer-portal/backend/config.toml.local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/customer-portal/backend/config.toml.local b/apps/customer-portal/backend/config.toml.local index 93493577c1..49f22e2bf0 100644 --- a/apps/customer-portal/backend/config.toml.local +++ b/apps/customer-portal/backend/config.toml.local @@ -27,7 +27,7 @@ updatesServiceUrl = "" [customer_portal.ai_chat_agent] aiChatAgentBaseUrl = "" -[customer_portal.updates.clientCredentialsOauth2Config] +[customer_portal.ai_chat_agent.clientCredentialsOauth2Config] tokenUrl = "" clientId = "" clientSecret = "" From 8a00846ce86f6c3d5a8142fbcd0ff9ddcefc53c6 Mon Sep 17 00:00:00 2001 From: Rashmika998 Date: Wed, 11 Feb 2026 19:46:15 +0530 Subject: [PATCH 5/6] pdate reource name --- apps/customer-portal/backend/service.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/customer-portal/backend/service.bal b/apps/customer-portal/backend/service.bal index 1897d3d8a5..4d0aa8fde5 100644 --- a/apps/customer-portal/backend/service.bal +++ b/apps/customer-portal/backend/service.bal @@ -834,7 +834,7 @@ service http:InterceptableService / on new http:Listener(9090) { # # + payload - case classification payload # + return - Case classification response or an error - resource function post cases/classification(http:RequestContext ctx, CaseClassificationPayload payload) + resource function post cases/classify(http:RequestContext ctx, CaseClassificationPayload payload) returns ai_chat_agent:CaseClassificationResponse|http:InternalServerError { authorization:UserInfoPayload|error userInfo = ctx.getWithType(authorization:HEADER_USER_INFO); From b652817b7e13c412f34c3307415022dc8c33fa4c Mon Sep 17 00:00:00 2001 From: Rashmika998 Date: Wed, 11 Feb 2026 19:47:10 +0530 Subject: [PATCH 6/6] Updae documentation --- apps/customer-portal/backend/service.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/customer-portal/backend/service.bal b/apps/customer-portal/backend/service.bal index 4d0aa8fde5..5d16d02dc6 100644 --- a/apps/customer-portal/backend/service.bal +++ b/apps/customer-portal/backend/service.bal @@ -832,7 +832,7 @@ service http:InterceptableService / on new http:Listener(9090) { # Classify the case using AI chat agent. # - # + payload - case classification payload + # + payload - Case classification payload # + return - Case classification response or an error resource function post cases/classify(http:RequestContext ctx, CaseClassificationPayload payload) returns ai_chat_agent:CaseClassificationResponse|http:InternalServerError {