Skip to content

RG-T117 Chatbot fixes - #263

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

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

Conversation

@ucswift

@ucswift ucswift commented Aug 8, 2026

Copy link
Copy Markdown
Member

PR Description

This PR addresses several chatbot (assistant) chat issues and related chat improvements:

  1. Fixed chatbot API response parsing — The chatbot endpoints were assumed to return plain payloads, but they actually use the standard v4 { Data } envelope. The API calls and model interfaces have been corrected to unwrap response.data.Data.

  2. Restricted chatbot conversations to the dedicated screen — Opening or deep-linking to a chatbot channel now redirects to the purpose-built chatbot screen instead of the generic conversation screen, ensuring text-only behavior with no reactions, threads, or deletes.

  3. Added message actions to the chatbot screen — Long-pressing a message now offers a restricted action sheet (copy, edit own, pin for moderators, flag). The MessageActionsSheet gained an assistant prop to hide reactions, reply-in-thread, and delete options in that context.

  4. Hid the urgent toggle in thread replies — The MessageComposer now accepts an allowUrgent prop (defaulting to true) and thread replies pass false, since urgent priority is a channel-level setting only.

  5. Prevented self-acknowledgment of urgent messages — The sender of an urgent message is no longer prompted to acknowledge their own message.

@Resgrid-Bot

This comment has been minimized.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ucswift, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 21 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5d69ee89-95d5-4042-8e18-2a622b2c0b8d

📥 Commits

Reviewing files that changed from the base of the PR and between 783897b and a03e89c.

📒 Files selected for processing (3)
  • src/app/chat/[channelId].tsx
  • src/components/chat/__tests__/chat-utils.test.ts
  • src/components/chat/chat-utils.ts
📝 Walkthrough

Walkthrough

The update aligns chatbot API payload handling with nested Data responses, routes chatbot channels to a dedicated screen, adds assistant message actions and editing, disables urgent controls in thread replies, and filters self-generated acknowledgments.

Changes

Chatbot flow and chat behavior

Layer / File(s) Summary
Chatbot API response contract
src/models/v4/chat/chatbotModels.ts, src/api/chat/chatbot.ts
Chatbot responses now use nullable Data envelopes. API helpers return the nested payload.
Chatbot routing and message actions
src/app/(app)/chat.tsx, src/app/chat/[channelId].tsx, src/app/(app)/chatbot.tsx, src/components/chat/message-actions-sheet.tsx
Chatbot channels open through /chatbot. Long-press actions support copy, edit, flag, and moderator pin behavior. Assistant messages hide unsupported actions.
Chat composer and acknowledgment controls
src/components/chat/message-composer.tsx, src/app/chat/thread/[messageId].tsx, src/stores/chat/store.ts
Urgent controls can be disabled for thread replies. Self-generated acknowledgment events are not queued.

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

Sequence Diagram(s)

sequenceDiagram
  participant openChannel
  participant ChatbotScreen
  participant MessageActionsSheet
  participant ChatbotAPI
  openChannel->>ChatbotScreen: route chatbot channel to /chatbot
  ChatbotScreen->>MessageActionsSheet: open actions for long-pressed message
  MessageActionsSheet->>ChatbotScreen: select copy, edit, flag, or pin
  ChatbotScreen->>ChatbotAPI: submit trimmed edited message
  ChatbotAPI-->>ChatbotScreen: return chatbot message data
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 clearly identifies the pull request as a set of chatbot fixes, matching the primary changes in the files.
✨ Finishing Touches
📝 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

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/components/chat/message-actions-sheet.tsx (1)

31-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use React.FC for MessageActionsSheet.

MessageActionsSheet has typed props but is declared as a function. Declare it as React.FC<MessageActionsSheetProps>.

As per coding guidelines, use React.FC for defining functional components with props.

🤖 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 `@src/components/chat/message-actions-sheet.tsx` at line 31, Update the
MessageActionsSheet component declaration to use
React.FC<MessageActionsSheetProps> while preserving its existing props,
defaults, and implementation behavior.

Source: Coding guidelines

src/app/(app)/chatbot.tsx (1)

153-202: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Extract the assistant action handlers.

These inline callbacks are recreated on every ChatbotScreen render. Define named callbacks for copy, edit, flag, pin, and save, then pass stable references to the action sheet and button.

As per coding guidelines, avoid anonymous functions in renderItem or event handlers to prevent re-renders.

🤖 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 `@src/app/`(app)/chatbot.tsx around lines 153 - 202, Extract the inline copy,
edit, flag, pin, and edit-save handlers from ChatbotScreen into named callbacks,
using the existing state and store operations. Pass those callbacks directly to
MessageActionsSheet and the save Button, preserving current behavior and
guarding channel/message availability as currently implemented.

Source: Coding guidelines

src/components/chat/message-composer.tsx (1)

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

Use React.FC<MessageComposerProps> for this updated component.

The changed public component still uses a function declaration. Convert it to the required typed functional-component form.

As per coding guidelines, utilize React.FC for defining functional components with props.

🤖 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 `@src/components/chat/message-composer.tsx` at line 32, Convert the
MessageComposer function declaration to a React.FC<MessageComposerProps>
component while preserving its existing props, defaults, and behavior.

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 `@src/api/chat/chatbot.ts`:
- Around line 8-10: Update getChatbotChannel and the other affected chatbot
helpers to use the required createApiEndpoint or createCachedApiEndpoint wrapper
instead of calling api.get directly, while preserving their typed
ChatbotChannelResponse handling, abort signal support, and existing response
values.

In `@src/app/`(app)/chatbot.tsx:
- Line 75: Update the MessageBubble usage in renderItem to explicitly disable
reactions for assistant messages, using the component’s existing assistant or
disableReactions prop so reaction controls are hidden. Replace the inline no-op
onToggleReaction callback with the appropriate stable handler or omit it when
reactions are disabled, avoiding anonymous functions in renderItem.

In `@src/app/chat/`[channelId].tsx:
- Around line 260-264: Update the channel resolution flow before the generic
conversation render so a missing channel is fetched or resolved using channelId
before evaluating the ChatChannelType.Chatbot redirect. Ensure chatbot deep
links redirect to /chatbot on the initial render, and only render the generic
conversation after confirming the resolved channel is not a chatbot.

In `@src/components/chat/message-composer.tsx`:
- Around line 28-32: Enforce allowUrgent across MessageComposer’s send handlers:
pass allowUrgent && urgent to the callbacks in handleSend, handlePickImage, and
handleShareLocation, and reset urgent whenever allowUrgent changes to false so
hidden controls cannot send urgent messages.

---

Nitpick comments:
In `@src/app/`(app)/chatbot.tsx:
- Around line 153-202: Extract the inline copy, edit, flag, pin, and edit-save
handlers from ChatbotScreen into named callbacks, using the existing state and
store operations. Pass those callbacks directly to MessageActionsSheet and the
save Button, preserving current behavior and guarding channel/message
availability as currently implemented.

In `@src/components/chat/message-actions-sheet.tsx`:
- Line 31: Update the MessageActionsSheet component declaration to use
React.FC<MessageActionsSheetProps> while preserving its existing props,
defaults, and implementation behavior.

In `@src/components/chat/message-composer.tsx`:
- Line 32: Convert the MessageComposer function declaration to a
React.FC<MessageComposerProps> component while preserving its existing props,
defaults, and behavior.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 55401197-cbcc-409c-97b9-330d9e429e37

📥 Commits

Reviewing files that changed from the base of the PR and between c93a060 and 783897b.

📒 Files selected for processing (9)
  • src/api/chat/chatbot.ts
  • src/app/(app)/chat.tsx
  • src/app/(app)/chatbot.tsx
  • src/app/chat/[channelId].tsx
  • src/app/chat/thread/[messageId].tsx
  • src/components/chat/message-actions-sheet.tsx
  • src/components/chat/message-composer.tsx
  • src/models/v4/chat/chatbotModels.ts
  • src/stores/chat/store.ts

Comment thread src/api/chat/chatbot.ts
Comment on lines 8 to +10
export const getChatbotChannel = async (signal?: AbortSignal) => {
const response = await api.get<ChatbotChannelResponse>(`${CHATBOT}/GetChatChannel`, { signal });
return response.data;
return response.data?.Data ?? null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Use the required API endpoint wrapper.

These helpers call the Axios client directly. Route them through createApiEndpoint or createCachedApiEndpoint to follow the required API-module boundary.

As per coding guidelines, always use createApiEndpoint or createCachedApiEndpoint for API endpoints with typed response generics.

Also applies to: 17-22

🤖 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 `@src/api/chat/chatbot.ts` around lines 8 - 10, Update getChatbotChannel and
the other affected chatbot helpers to use the required createApiEndpoint or
createCachedApiEndpoint wrapper instead of calling api.get directly, while
preserving their typed ChatbotChannelResponse handling, abort signal support,
and existing response values.

Source: Coding guidelines

Comment thread src/app/(app)/chatbot.tsx
const renderItem = useCallback(
({ item }: { item: ChatMessageResultData }) => (
<MessageBubble message={item} isOwn={!!item.SenderUserId && item.SenderUserId === currentUserId} showSender={false} currentUserId={currentUserId} onLongPress={() => undefined} onToggleReaction={() => undefined} />
<MessageBubble message={item} isOwn={!!item.SenderUserId && item.SenderUserId === currentUserId} showSender={false} currentUserId={currentUserId} onLongPress={setActionsMessage} onToggleReaction={() => undefined} />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Hide reaction controls in assistant messages.

If an assistant message has existing reactions, MessageBubble renders pressable reaction controls and invokes this no-op callback. The user can tap a visible control that does nothing.

Pass an explicit assistant or disableReactions prop to MessageBubble and hide those controls in assistant mode.

As per coding guidelines, avoid anonymous functions in renderItem or event handlers to prevent re-renders.

🤖 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 `@src/app/`(app)/chatbot.tsx at line 75, Update the MessageBubble usage in
renderItem to explicitly disable reactions for assistant messages, using the
component’s existing assistant or disableReactions prop so reaction controls are
hidden. Replace the inline no-op onToggleReaction callback with the appropriate
stable handler or omit it when reactions are disabled, avoiding anonymous
functions in renderItem.

Source: Coding guidelines

Comment thread src/app/chat/[channelId].tsx
Comment on lines +28 to +32
/** Urgent priority is channel-level only; thread replies pass false to hide the toggle. */
allowUrgent?: boolean;
}

export function MessageComposer({ onSendText, onSendImage, onSendLocation, onOpenGif, onTyping, disabled, placeholder }: MessageComposerProps) {
export function MessageComposer({ onSendText, onSendImage, onSendLocation, onOpenGif, onTyping, disabled, placeholder, allowUrgent = true }: MessageComposerProps) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Enforce allowUrgent on every send path.

The new prop only changes rendering. If urgent is already true when allowUrgent changes to false, handleSend, handlePickImage, and handleShareLocation still pass true to their callbacks. A hidden control can therefore still send an urgent message. Derive the callback value from allowUrgent && urgent and clear urgent when allowUrgent becomes false.

🤖 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 `@src/components/chat/message-composer.tsx` around lines 28 - 32, Enforce
allowUrgent across MessageComposer’s send handlers: pass allowUrgent && urgent
to the callbacks in handleSend, handlePickImage, and handleShareLocation, and
reset urgent whenever allowUrgent changes to false so hidden controls cannot
send urgent messages.

Comment thread src/app/(app)/chat.tsx
// (text only, no reactions/threads/deletes) instead of the generic conversation.
const channel = useChatStore.getState().channels.find((c) => c.ChatChannelId === channelId);
if (channel?.ChannelType === ChatChannelType.Chatbot) {
router.push('/chatbot' as Href);

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 low

Magic string vulnerability caused by hardcoding the route path '/chatbot' as a raw string literal. Define a centralized routes module (e.g., export const Routes = { Chatbot: '/chatbot' } as const) and reference it here to ensure refactor safety.

Kody rule violation: Centralize string constants

Prompt for LLM

File src/app/(app)/chat.tsx:

Line 110:

Magic string vulnerability caused by hardcoding the route path '/chatbot' as a raw string literal. Define a centralized routes module (e.g., `export const Routes = { Chatbot: '/chatbot' } as const`) and reference it here to ensure refactor safety.

Talk to Kody by mentioning @kody

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

Comment thread src/app/(app)/chatbot.tsx
const renderItem = useCallback(
({ item }: { item: ChatMessageResultData }) => (
<MessageBubble message={item} isOwn={!!item.SenderUserId && item.SenderUserId === currentUserId} showSender={false} currentUserId={currentUserId} onLongPress={() => undefined} onToggleReaction={() => undefined} />
<MessageBubble message={item} isOwn={!!item.SenderUserId && item.SenderUserId === currentUserId} showSender={false} currentUserId={currentUserId} onLongPress={setActionsMessage} onToggleReaction={() => undefined} />

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

Performance regression caused by inline arrow functions in JSX props, which create new function instances on every render. Move these function definitions outside the render method to prevent unnecessary re-renders.

Kody rule violation: Avoid using .bind() or arrow functions in JSX props

Prompt for LLM

File src/app/(app)/chatbot.tsx:

Line 75:

Performance regression caused by inline arrow functions in JSX props, which create new function instances on every render. Move these function definitions outside the render method to prevent unnecessary re-renders.

Talk to Kody by mentioning @kody

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

Comment thread src/app/(app)/chatbot.tsx
setEditText(m.Body ?? '');
}}
onDelete={() => undefined}
onFlag={(m, reason) => useChatStore.getState().flagMessage(m.ChatMessageId, reason)}

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

Unhandled promise rejection occurs because the flagMessage store action lacks a .catch() handler when invoked by the UI event handler. Append .catch(() => useToastStore.getState().showToast('error', t('chat.flag_failed'))) to the useChatStore.getState().flagMessage call to display an error toast on failure.

Kody rule violation: Handle async operations with proper error handling

Prompt for LLM

File src/app/(app)/chatbot.tsx:

Line 172:

Unhandled promise rejection occurs because the `flagMessage` store action lacks a `.catch()` handler when invoked by the UI event handler. Append `.catch(() => useToastStore.getState().showToast('error', t('chat.flag_failed')))` to the `useChatStore.getState().flagMessage` call to display an error toast on failure.

Talk to Kody by mentioning @kody

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

@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.

Comment on lines +79 to +82
void useChatStore
.getState()
.fetchChannels()
.finally(() => setResolveAttempted(true));

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

Unhandled promise rejection occurs because the fetchChannels() promise chains .finally() without a .catch() handler, risking app crashes and leaving resolveAttempted unset. Add a .catch() block to log the error context before executing .finally(() => setResolveAttempted(true)).

Kody rule violation: Handle async operations with proper error handling

Prompt for LLM

File src/app/chat/[channelId].tsx:

Line 79 to 82:

Unhandled promise rejection occurs because the `fetchChannels()` promise chains `.finally()` without a `.catch()` handler, risking app crashes and leaving `resolveAttempted` unset. Add a `.catch()` block to log the error context before executing `.finally(() => setResolveAttempted(true))`.

Talk to Kody by mentioning @kody

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

Comment on lines +123 to 127
try {
return await Clipboard.setStringAsync(text);
} catch {
return false;
}

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 high

Void return mismatch causes a successful native copy to evaluate as falsy, triggering the 'copy_unavailable' toast in [channelId].tsx:362 and chatbot.tsx:164 because Clipboard.setStringAsync resolves void instead of a boolean. Explicitly return true after the awaited call and update the test's .mockResolvedValue(true) to match the library.

try {
  await Clipboard.setStringAsync(text);
  return true;
} catch {
  return false;
}
Prompt for LLM

File src/components/chat/chat-utils.ts:

Line 123 to 127:

Void return mismatch causes a successful native copy to evaluate as falsy, triggering the 'copy_unavailable' toast in `[channelId].tsx:362` and `chatbot.tsx:164` because `Clipboard.setStringAsync` resolves `void` instead of a boolean. Explicitly return `true` after the awaited call and update the test's `.mockResolvedValue(true)` to match the library.

Suggested Code:

  try {
    await Clipboard.setStringAsync(text);
    return true;
  } catch {
    return false;
  }

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 6f0e170 into master Aug 8, 2026
19 of 20 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 10, 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