From 9a9c6a5bb539f1c08daa63516b7015d378dea6cf Mon Sep 17 00:00:00 2001 From: SasmithaDilshan Date: Fri, 24 Apr 2026 16:46:07 +0530 Subject: [PATCH 1/2] Enrich conversations/search response with chatbot stats Append messagesExchanged, troubleshootingAttempts, and kbArticlesReviewed from the AI chat agent summary endpoint to each conversation in the POST /projects/{id}/conversations/search response. Stats default to 0 when unavailable. Co-Authored-By: Claude Sonnet 4.6 --- .../modules/ai_chat_agent/ai_chat_agent.bal | 2 +- .../backend/modules/types/types.bal | 6 +++++ apps/customer-portal/backend/service.bal | 27 +++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) 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 ed1b9d821..583a57b25 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 @@ -79,7 +79,7 @@ public isolated function getRecommendation(RecommendationRequest payload) return } # Get summary for a conversation. -# +# # + projectId - Project ID # + conversationId - Conversation ID # + return - Summary response or error diff --git a/apps/customer-portal/backend/modules/types/types.bal b/apps/customer-portal/backend/modules/types/types.bal index f445117d6..d875112b3 100644 --- a/apps/customer-portal/backend/modules/types/types.bal +++ b/apps/customer-portal/backend/modules/types/types.bal @@ -1043,6 +1043,12 @@ public type Conversation record {| ReferenceItem? case; # State information ReferenceItem? state; + # Total messages exchanged in the chatbot conversation + int messagesExchanged?; + # Number of troubleshooting tool invocations in the chatbot conversation + int troubleshootingAttempts?; + # Number of unique KB articles surfaced in the chatbot conversation + int kbArticlesReviewed?; json...; |}; diff --git a/apps/customer-portal/backend/service.bal b/apps/customer-portal/backend/service.bal index c925bfea9..1d6c0bc5f 100644 --- a/apps/customer-portal/backend/service.bal +++ b/apps/customer-portal/backend/service.bal @@ -83,7 +83,6 @@ service http:InterceptableService / on new http:Listener(9090, listenerConf) { log:printInfo("Customer Portal backend started."); } - # Fetch metadata information for the customer portal. # # + return - Metadata information or error response resource function get metadata(http:RequestContext ctx) @@ -1370,8 +1369,32 @@ service http:InterceptableService / on new http:Listener(9090, listenerConf) { }; } + types:ConversationSearchResponse baseResponse = mapConversationSearchResponse(conversationResponse); + + // Enrich each conversation with chatbot stats from the AI chat agent. + types:Conversation[] enrichedConversations = []; + foreach types:Conversation conv in baseResponse.conversations { + types:Conversation enriched = conv.clone(); + ai_chat_agent:ConversationSummaryResponse|error summary = ai_chat_agent:getSummary(id, conv.id); + if summary is ai_chat_agent:ConversationSummaryResponse { + enriched.messagesExchanged = summary.messagesExchanged; + enriched.troubleshootingAttempts = summary.troubleshootingAttempts; + enriched.kbArticlesReviewed = summary.kbArticlesReviewed; + } else { + enriched.messagesExchanged = 0; + enriched.troubleshootingAttempts = 0; + enriched.kbArticlesReviewed = 0; + } + enrichedConversations.push(enriched); + } + return { - body: mapConversationSearchResponse(conversationResponse) + body: { + conversations: enrichedConversations, + totalRecords: baseResponse.totalRecords, + 'limit: baseResponse.'limit, + offset: baseResponse.offset + } }; } From 4d37eb60dd89524024bbc124018c4e4f694da8cd Mon Sep 17 00:00:00 2001 From: SasmithaDilshan Date: Fri, 24 Apr 2026 20:12:16 +0530 Subject: [PATCH 2/2] Change ws query path param --- .../backend/modules/ai_chat_agent/client.bal | 2 +- apps/customer-portal/backend/service.bal | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/customer-portal/backend/modules/ai_chat_agent/client.bal b/apps/customer-portal/backend/modules/ai_chat_agent/client.bal index b831cd3e1..a669c45d0 100644 --- a/apps/customer-portal/backend/modules/ai_chat_agent/client.bal +++ b/apps/customer-portal/backend/modules/ai_chat_agent/client.bal @@ -40,7 +40,7 @@ final http:Client aiChatAgentClient = check new (aiChatAgentBaseUrl, { }); isolated function createAiChatAgentWsClient(string sessionId) returns websocket:Client|error { - return new (string `${aiChatAgentWsBaseUrl}/ws?sessionId=${sessionId}`, { + return new (string `${aiChatAgentWsBaseUrl}/ws/${sessionId}`, { auth: { ...clientCredentialsOauth2ConfigWs } diff --git a/apps/customer-portal/backend/service.bal b/apps/customer-portal/backend/service.bal index 1d6c0bc5f..cebd4a304 100644 --- a/apps/customer-portal/backend/service.bal +++ b/apps/customer-portal/backend/service.bal @@ -1371,11 +1371,18 @@ service http:InterceptableService / on new http:Listener(9090, listenerConf) { types:ConversationSearchResponse baseResponse = mapConversationSearchResponse(conversationResponse); - // Enrich each conversation with chatbot stats from the AI chat agent. - types:Conversation[] enrichedConversations = []; + // Fan-out: fire all summary calls in parallel to avoid N serial round-trips. + future[] summaryFutures = []; foreach types:Conversation conv in baseResponse.conversations { - types:Conversation enriched = conv.clone(); - ai_chat_agent:ConversationSummaryResponse|error summary = ai_chat_agent:getSummary(id, conv.id); + future f = start ai_chat_agent:getSummary(id, conv.id); + summaryFutures.push(f); + } + + // Fan-in: collect results and enrich each conversation. + types:Conversation[] enrichedConversations = []; + foreach int i in 0 ..< baseResponse.conversations.length() { + types:Conversation enriched = baseResponse.conversations[i].clone(); + ai_chat_agent:ConversationSummaryResponse|error summary = wait summaryFutures[i]; if summary is ai_chat_agent:ConversationSummaryResponse { enriched.messagesExchanged = summary.messagesExchanged; enriched.troubleshootingAttempts = summary.troubleshootingAttempts;