Skip to content

RG-T117 Chatbot fixes - #452

Merged
ucswift merged 2 commits into
masterfrom
develop
Aug 8, 2026
Merged

RG-T117 Chatbot fixes#452
ucswift merged 2 commits into
masterfrom
develop

Conversation

@ucswift

@ucswift ucswift commented Aug 8, 2026

Copy link
Copy Markdown
Member

PR Description

This pull request addresses several fixes and improvements for the chatbot feature (now referred to as "Assistant"):

1. Rebranding "Chatbot" to "Assistant"

Updates all user-facing text strings across the chatbot handlers, ingress services, and localization files (English, Arabic, German, Spanish, French, Italian, Polish, Swedish, Ukrainian) to replace the term "Chatbot" with "Assistant." This includes error messages, help text, system messages, department settings labels, and profile security PIN descriptions.

2. Fix: Assistant channel messages from regular chat now trigger the chatbot pipeline

When a user sends a message to the assistant (Chatbot-type) channel through the generic chat SendMessage endpoint (e.g., from the regular chat page), the message is now also enqueued to the chatbot processing pipeline. Previously, only the dedicated ChatbotController endpoint fed the pipeline, meaning messages sent from the standard chat UI to the assistant channel were not processed. A typing indicator is also sent to the user's devices while the pipeline runs.

3. Fix: Assistant chat now respects the department-level Assistant enable/disable toggle

The ChatbotChatEnabledAsync check in ChatbotController now additionally evaluates the DepartmentConfig.IsEnabled setting (from Department Settings > Assistant). Previously, it only checked the chat-specific ChatbotEnabled setting, allowing the assistant to remain accessible even when an administrator had disabled it at the department level.

4. Fix: Proper handling of v4 API envelope in chat API client

The getChatbotChannel function in the frontend chat API now correctly unwraps the response payload nested under the Data property of the v4 API envelope, while maintaining backward compatibility with flat payloads. This fixes issues where the assistant channel could not be properly resolved from the API response.

@Resgrid-Bot

Resgrid-Bot commented Aug 8, 2026

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Business Logic

Access your configuration settings here.

@request-info

request-info Bot commented Aug 8, 2026

Copy link
Copy Markdown

Thanks for opening this, but we'd appreciate a little more information. Could you update it with more details?

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR queues chatbot-channel messages, validates department chat availability, supports wrapped and differently cased channel responses, and changes user-facing terminology from “chatbot” to “assistant.”

Changes

Chatbot assistant flow

Layer / File(s) Summary
Queue chatbot channel messages
Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs
ChatController injects IQueueService. Non-empty chatbot-channel messages are queued with WebChat metadata. Enqueue failures return HTTP 500. Successful enqueueing publishes a typing event.
Chat availability and channel response contracts
Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs, Web/Resgrid.Web/Areas/User/Apps/src/components/chat/chatApi.ts
Chatbot access checks global settings, department settings, and optional chatbot configuration. getChatbotChannel accepts wrapped or flat responses and both casing conventions.
Assistant-facing response terminology
Core/Resgrid.Chatbot/Handlers/*, Core/Resgrid.Chatbot/Services/*
User-facing chatbot text, help branding, message subjects, poll fallback names, and linking responses now use “assistant” terminology.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ChatController
  participant IQueueService
  participant SenderDevices
  ChatController->>IQueueService: Enqueue WebChat chatbot message
  IQueueService-->>ChatController: Return enqueue result
  ChatController->>SenderDevices: Publish chatbot typing event
Loading

Possibly related PRs

  • Resgrid/Core#425: Prepares ChatbotMessageQueueItem for queue serialization used by this PR.
  • Resgrid/Core#427: Introduces the restricted-mode flow whose messaging this PR updates.
  • Resgrid/Core#451: Also modifies chatbot configuration behavior in ChatbotController.

Suggested reviewers: github-actions

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately identifies the pull request as fixes to chatbot functionality and terminology.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs (1)

68-83: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Resolve IQueueService with the required service locator.

The added constructor parameter uses constructor injection. Resolve IQueueService with Bootstrapper.GetKernel().Resolve<IQueueService>() in the constructor, then remove the parameter.

As per coding guidelines, use Bootstrapper.GetKernel().Resolve<T>() rather than constructor injection.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs` around lines 68 -
83, The ChatController constructor currently injects IQueueService directly;
remove the queueService parameter and initialize _queueService by resolving
IQueueService through Bootstrapper.GetKernel().Resolve<IQueueService>() within
the constructor, while leaving the existing field assignment and other
dependencies unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs`:
- Around line 829-846: The chat endpoint must handle the boolean result from
EnqueueChatbotMessageAsync before emitting ChatbotTyping or returning Created.
Update the surrounding method to capture the enqueue result, return the same
failure response used by ChatbotController.SendChatMessage when it is false, and
only send the typing event and success response after queueing succeeds.

---

Nitpick comments:
In `@Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs`:
- Around line 68-83: The ChatController constructor currently injects
IQueueService directly; remove the queueService parameter and initialize
_queueService by resolving IQueueService through
Bootstrapper.GetKernel().Resolve<IQueueService>() within the constructor, while
leaving the existing field assignment and other dependencies unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fb4b76fe-bf32-4e18-ac07-45aff8ba03d9

📥 Commits

Reviewing files that changed from the base of the PR and between 7f7fb06 and 95c5403.

⛔ Files ignored due to path filters (19)
  • Core/Resgrid.Localization/Areas/User/Department/Department.ar.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.de.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.en.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.es.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.fr.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.it.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.pl.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.sv.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Department/Department.uk.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.ar.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.de.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.en.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.es.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.fr.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.it.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.pl.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.sv.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Home/EditProfile.uk.resx is excluded by !**/*.resx
📒 Files selected for processing (9)
  • Core/Resgrid.Chatbot/Handlers/DispatchCallHandler.cs
  • Core/Resgrid.Chatbot/Handlers/HelpActionHandler.cs
  • Core/Resgrid.Chatbot/Handlers/MessageSendHandler.cs
  • Core/Resgrid.Chatbot/Handlers/PollCreateHandler.cs
  • Core/Resgrid.Chatbot/Services/ChatbotIngressService.cs
  • Core/Resgrid.Chatbot/Services/CodeLinkingService.cs
  • Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs
  • Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs
  • Web/Resgrid.Web/Areas/User/Apps/src/components/chat/chatApi.ts

Comment thread Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs (1)

54-54: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Resolve IQueueService through the required Service Locator.

Line 69 adds constructor injection for IQueueService. Remove this parameter. Resolve the dependency in the constructor with Bootstrapper.GetKernel().Resolve<IQueueService>().

As per coding guidelines, use “Service Locator pattern via Bootstrapper.GetKernel().Resolve<T>() to resolve dependencies explicitly in constructors, rather than constructor injection”.

Proposed fix
 			IFeatureToggleService featureToggleService,
 			IAuthorizationService authorizationService,
 			ICacheProvider cacheProvider,
-			IEventAggregator eventAggregator,
-			IQueueService queueService)
+			IEventAggregator eventAggregator)
@@
 			_cacheProvider = cacheProvider;
 			_eventAggregator = eventAggregator;
-			_queueService = queueService;
+			_queueService = Bootstrapper.GetKernel().Resolve<IQueueService>();

Also applies to: 68-83

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs` at line 54, Update
the ChatController constructor to remove the injected IQueueService parameter
and initialize the existing _queueService field by resolving IQueueService
through Bootstrapper.GetKernel().Resolve<IQueueService>(). Preserve the field
and all other constructor dependencies unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs`:
- Line 54: Update the ChatController constructor to remove the injected
IQueueService parameter and initialize the existing _queueService field by
resolving IQueueService through
Bootstrapper.GetKernel().Resolve<IQueueService>(). Preserve the field and all
other constructor dependencies unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3e00a484-189c-4d5f-a9f8-ab819daabbdb

📥 Commits

Reviewing files that changed from the base of the PR and between 95c5403 and 950e140.

📒 Files selected for processing (1)
  • Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs

Comment on lines +829 to +836
var queued = await _queueService.EnqueueChatbotMessageAsync(new Resgrid.Model.Queue.ChatbotMessageQueueItem
{
DepartmentId = DepartmentId,
From = UserId,
Body = message.Body,
MessageId = message.ChatMessageId,
Platform = (int)Resgrid.Chatbot.Models.ChatbotPlatform.WebChat
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Kody Rules high

Unguarded external I/O call in _queueService.EnqueueChatbotMessageAsync violates Rule [27], which requires external calls to be wrapped with error context and mapped to application-level errors. Wrap the enqueue in try/catch with structured logging context (channelId, DepartmentId, UserId), deciding whether the chatbot pipeline is best-effort or should surface a typed application error. Also found in ChatbotController.cs:478.

Kody rule violation: Add try-catch blocks for external calls

Prompt for LLM

File Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs:

Line 829 to 836:

Unguarded external I/O call in _queueService.EnqueueChatbotMessageAsync violates Rule [27], which requires external calls to be wrapped with error context and mapped to application-level errors. Wrap the enqueue in try/catch with structured logging context (channelId, DepartmentId, UserId), deciding whether the chatbot pipeline is best-effort or should surface a typed application error. Also found in ChatbotController.cs:478.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

// The assistant channel is also reachable from the regular chat page, so sends that arrive
// through this generic endpoint must still feed the chatbot pipeline (the dedicated
// ChatbotController.SendChatMessage does the same for the assistant panel).
var channel = await _chatChannelService.GetChannelByIdAsync(channelId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Bug medium

Unhandled exception risk in the chatbot-enqueue block (lines 826-847) which sits outside the try-catch handling SendMessageAsync errors, allowing exceptions from EnqueueChatbotMessageAsync or _eventAggregator.SendMessage to propagate unhandled after the message is already persisted. Wrap the enqueue block in a try-catch that logs the exception and continues returning the already-saved message, matching the pattern in ChatbotController.SendChatMessage (lines 365-413).

if (message == null)
    return BadRequest();

// The assistant channel is also reachable from the regular chat page, so sends that arrive
// through this generic endpoint must still feed the chatbot pipeline (the dedicated
// ChatbotController.SendChatMessage does the same for the assistant panel).
try
{
    var channel = await _chatChannelService.GetChannelByIdAsync(channelId);
    if (channel != null && channel.ChannelType == (int)ChatChannelType.Chatbot && !String.IsNullOrWhiteSpace(message.Body))
    {
        await _queueService.EnqueueChatbotMessageAsync(new Resgrid.Model.Queue.ChatbotMessageQueueItem
        {
            DepartmentId = DepartmentId,
            From = UserId,
            Body = message.Body,
            MessageId = message.ChatMessageId,
            Platform = (int)Resgrid.Chatbot.Models.ChatbotPlatform.WebChat
        });

        // Typing indicator to the user's devices while the worker runs the pipeline.
        _eventAggregator.SendMessage<ChatEventRaised>(new ChatEventRaised
        {
            DepartmentId = DepartmentId,
            ChatChannelId = channel.ChatChannelId,
            Kind = ChatEventKinds.ChatbotTyping,
            TargetUserId = UserId,
            PayloadJson = Newtonsoft.Json.JsonConvert.SerializeObject(new { channel.ChatChannelId, IsTyping = true })
        });
    }
}
catch (Exception ex)
{
    Framework.Logging.LogException(ex, "Failed to enqueue chatbot message from generic SendMessage.");
}
Prompt for LLM

File Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs:

Line 826:

Unhandled exception risk in the chatbot-enqueue block (lines 826-847) which sits outside the try-catch handling SendMessageAsync errors, allowing exceptions from EnqueueChatbotMessageAsync or _eventAggregator.SendMessage to propagate unhandled after the message is already persisted. Wrap the enqueue block in a try-catch that logs the exception and continues returning the already-saved message, matching the pattern in ChatbotController.SendChatMessage (lines 365-413).

Suggested Code:

if (message == null)
    return BadRequest();

// The assistant channel is also reachable from the regular chat page, so sends that arrive
// through this generic endpoint must still feed the chatbot pipeline (the dedicated
// ChatbotController.SendChatMessage does the same for the assistant panel).
try
{
    var channel = await _chatChannelService.GetChannelByIdAsync(channelId);
    if (channel != null && channel.ChannelType == (int)ChatChannelType.Chatbot && !String.IsNullOrWhiteSpace(message.Body))
    {
        await _queueService.EnqueueChatbotMessageAsync(new Resgrid.Model.Queue.ChatbotMessageQueueItem
        {
            DepartmentId = DepartmentId,
            From = UserId,
            Body = message.Body,
            MessageId = message.ChatMessageId,
            Platform = (int)Resgrid.Chatbot.Models.ChatbotPlatform.WebChat
        });

        // Typing indicator to the user's devices while the worker runs the pipeline.
        _eventAggregator.SendMessage<ChatEventRaised>(new ChatEventRaised
        {
            DepartmentId = DepartmentId,
            ChatChannelId = channel.ChatChannelId,
            Kind = ChatEventKinds.ChatbotTyping,
            TargetUserId = UserId,
            PayloadJson = Newtonsoft.Json.JsonConvert.SerializeObject(new { channel.ChatChannelId, IsTyping = true })
        });
    }
}
catch (Exception ex)
{
    Framework.Logging.LogException(ex, "Failed to enqueue chatbot message from generic SendMessage.");
}

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.


// Honor the admin toggle from Department Settings > Assistant. Matching the ingress
// pipeline's semantics, a missing config row means enabled.
var config = await _departmentConfigService.GetConfigAsync(DepartmentId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kody code-review Kody Rules high

Unguarded awaited async operation in _departmentConfigService.GetConfigAsync violates Rule [1], which requires every awaited async operation to be wrapped in try/catch. Wrap the await in a try/catch block that logs with DepartmentId and operation context, returning a safe default (e.g., false) or rethrowing as appropriate.

Kody rule violation: Handle async operations with proper error handling

Prompt for LLM

File Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs:

Line 478:

Unguarded awaited async operation in _departmentConfigService.GetConfigAsync violates Rule [1], which requires every awaited async operation to be wrapped in try/catch. Wrap the await in a try/catch block that logs with DepartmentId and operation context, returning a safe default (e.g., false) or rethrowing as appropriate.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

@ucswift

ucswift commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

Approve

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is approved.

@ucswift
ucswift merged commit 407ba70 into master Aug 8, 2026
18 of 19 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants