Skip to content

feat: implement AI Adapter layer, State Machines for Auth/Input, and Contextual AI Features#1168

Open
vivekyadav-3 wants to merge 36 commits intoRocketChat:developfrom
vivekyadav-3:feature/ai-adapter-complete
Open

feat: implement AI Adapter layer, State Machines for Auth/Input, and Contextual AI Features#1168
vivekyadav-3 wants to merge 36 commits intoRocketChat:developfrom
vivekyadav-3:feature/ai-adapter-complete

Conversation

@vivekyadav-3
Copy link

@vivekyadav-3 vivekyadav-3 commented Feb 25, 2026

Pull Request: AI Adapter Layer & Architecture Improvements
Overview

This PR introduces a major architectural update focused on stability and AI integration, aligned with the GSoC 2026 goals.

It adds a pluggable AI adapter system and restructures core authentication and message input handling using Finite State Machines (FSM) to improve reliability.

What’s Included

  1. AI Adapter System

Pluggable AI Interface
A new IAiAdapter interface allows integration with any AI service without modifying core logic.

Centralized AI State Management
Added a dynamic AI store to manage replies, summaries, and loading states.

AI Features

Smart Replies: Suggested responses displayed above the input field.

Message Translation: Translation option available in the message action menu.

Conversation Summary Modal: A dedicated AiSummaryModal for generating and viewing summaries of long threads.

  1. Architecture & Stability Improvements

Authentication State Machine
Auth transitions are now centrally managed in RocketChatAuth.ts. This prevents inconsistent states and resolves infinite loading issues.

Message Input State Machine
Introduced clear states (DRAFTING, SENDING, ERROR) to prevent race conditions and double message submissions.

Media Resource Cleanup
Updated useMediaRecorder.js to ensure camera and microphone streams are always properly released.

  1. Accessibility Enhancements

Improved ARIA labels and states for the main chat input.

Ensures better compatibility with screen readers and improves WCAG compliance.

How to Test
AI Features

Enable MockAiAdapter in EmbeddedChat.js.

Open a thread and click “Summarize Thread” in the header.

Use “Translate” from the message toolbox.

Observe Smart Replies appearing when new messages arrive.

State Machines

Trigger a login failure to confirm transition to the ERROR state and automatic reset to UNAUTHENTICATED.

Send a delayed message and observe the SENDING state on the action button.

Accessibility

Use Chrome Vox or VoiceOver to navigate the chat input and verify ARIA labels are correctly announced.

vivekyadav-3 and others added 30 commits January 25, 2026 22:02
… authentication, commands, and message tools
- Added encodeURIComponent() to properly encode user input before appending to URL query string
- Prevents special characters (&, ?, #, %) from breaking query parameters
- Fixes issue RocketChat#1149
- Changed typing status timeout from 15000ms to 10000ms
- Makes typing indicator more responsive and updates faster
- Improves real-time chat experience
- Added defensive check to ensure selectedItem exists before accessing properties
- Prevents TypeError when user types commands not in the filtered list
- Fixes issue RocketChat#1144
…icated

- Added default empty string values in destructuring pattern
- Fixes all 37 API methods that were sending literal 'undefined' as header values
- Headers now send empty strings instead of 'undefined' when user is not logged in
- Fixes issue RocketChat#1133
Summary of changes:
- Replaced legacy DDP method calls (getUserRoles, rooms:get) with modern REST API endpoints for better server compatibility.
- Fixed critical busy-wait loop in handleTypingEvent that caused application freezes.
- URL-encoded search and filter parameters in API calls to prevent HTTP Parameter Pollution.
- Added a 50,000-character safety guard in sendMessage to prevent crashes from excessively large messages.
- Cleaned up unused variables and imports across several components.
- Prevented crash on unknown slash commands in CommandsList\n- Improved command list visibility logic in useShowCommands\n- Fixed session state leaks by resetting user store on logout in EmbeddedChat\n- Removed hardcoded default emoji preview in EmojiPicker
Copilot AI review requested due to automatic review settings February 25, 2026 16:23
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ vivekyadav-3
❌ vivekyadav1207vy-sudo
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an AI integration layer (adapter + UI entry points) and adds more deterministic UI/auth/input behaviors, alongside a set of cleanup and reliability changes across the React SDK and API/auth packages.

Changes:

  • Add AI adapter contract + mock adapter, wire AI actions into UI (smart replies, translate, summary modal).
  • Add auth “state” propagation and update React to reflect auth/connection states more explicitly.
  • Improve stability/cleanup patterns (listeners/intervals/media recorder cleanup), plus performance-oriented memoization and filtering updates.

Reviewed changes

Copilot reviewed 47 out of 48 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
test_simple.js Adds a simple console log script (appears unrelated to PR goals).
temp_lerna_index.js Adds a large process-spawn helper (appears unrelated to PR goals).
packages/react/src/views/TypingUsers/TypingUsers.js Fixes listener cleanup by using a stable handler function.
packages/react/src/views/ReportMessage/MessageReportWindow.js Removes unused theme hook import.
packages/react/src/views/MessageList/MessageList.js Memoizes filtered/reported messages; adjusts day-boundary logic and propTypes.
packages/react/src/views/MessageAggregators/common/MessageAggregator.js Refactors aggregator rendering/memoization; changes export shape; adds propTypes.
packages/react/src/views/MessageAggregators/StarredMessages.js Minor import cleanup (but still imports aggregator as named export).
packages/react/src/views/Message/MessageToolbox.js Adds translate option and refactors permission checks; formatting/style changes.
packages/react/src/views/Message/MessageMetrics.js Removes unused formatDistance import.
packages/react/src/views/Message/Message.js Adds memoized role sets; adds optimistic star/pin; adds translate handler hookup.
packages/react/src/views/LoginForm/LoginForm.js Adds PropTypes and improves password-toggle button semantics.
packages/react/src/views/FileMessage/FileMessage.js Simplifies component signature; removes unused props; keeps internal fetch state setters.
packages/react/src/views/EmojiPicker/EmojiPicker.js Removes defaultEmoji from preview config.
packages/react/src/views/EmbeddedChat.js Wires in Mock AI adapter; adds auth memoization and auto-login toast behavior; adjusts auth listener cleanup.
packages/react/src/views/DynamicHeader/DynamicHeader.js Adds actions slot to header UI.
packages/react/src/views/CommandList/CommandsList.js Adds guards for null command/messageRef; makes list keys more resilient.
packages/react/src/views/ChatLayout/ChatLayout.js Removes unused starredMessages store selector.
packages/react/src/views/ChatInput/VideoMessageRecoder.js Cleans up interval on unmount; toggles recording state in store; theme hook cleanup.
packages/react/src/views/ChatInput/SmartReplies.js New smart-replies UI component reading from AI store.
packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js Improves emoji insertion at cursor + triggers upstream updates after formatting actions.
packages/react/src/views/ChatInput/ChatInput.js Adds input FSM states; smart replies fetching/listener; improves typing timer cleanup and send error handling; adds ARIA attributes.
packages/react/src/views/ChatInput/AudioMessageRecorder.js Fixes typo in store action; adds interval cleanup on unmount.
packages/react/src/views/ChatHeader/ChatHeader.js Improves logout token cleanup; swaps avatar rendering; adds thread “Summarize” action.
packages/react/src/views/ChatBody/ChatBody.js Consolidates auth-change listener management; improves scroll-to-bottom behavior; adds auth-state messaging; stabilizes UiKitModal key; adds summary modal.
packages/react/src/views/ChatBody/AiSummaryModal.js New modal to display and copy AI-generated summaries.
packages/react/src/views/ChannelState/ChannelState.js Adds PropTypes.
packages/react/src/views/AttachmentHandler/TextAttachment.js Removes unused author prop.
packages/react/src/store/userStore.js Adds authState and setter.
packages/react/src/store/messageStore.js Renames toogleRecordingMessage to toggleRecordingMessage.
packages/react/src/store/index.js Re-exports useAiStore.
packages/react/src/store/aiStore.js New Zustand store for AI state (replies/loading/summary modal).
packages/react/src/lib/emoji.js Changes emoji parsing to replace all :shortname: occurrences.
packages/react/src/hooks/useShowCommands.js Avoids showing empty command list when no matches.
packages/react/src/hooks/useRCAuth.js Subscribes to auth state changes; improves login error handling and messaging.
packages/react/src/hooks/useMediaRecorder.js Avoids stopping non-recording recorder; adds unmount cleanup.
packages/react/src/hooks/useFetchChatData.js Stores raw permissions to avoid unnecessary re-apply; minor role mapping refactor.
packages/react/lint_report.txt Adds lint report artifact.
packages/auth/src/index.ts Exports AuthState.
packages/auth/src/RocketChatAuth.ts Adds auth state machine + listeners; updates login flows to set state.
packages/api/src/index.ts Exports AI adapter types and mock adapter.
packages/api/src/MockAiAdapter.ts Adds mock AI adapter implementation.
packages/api/src/IAiAdapter.ts Adds AI adapter interface contract.
packages/api/src/EmbeddedChatApi.ts Adds AI adapter plumbing + AI feature methods; improves typing lock; URL-encodes query params; changes several REST endpoints/return shapes; adds message length guard.
UPDATED_PR_DESCRIPTION.md Adds updated narrative PR description.
RFC_CHAT_INPUT_REFACTOR.md Adds ChatInput refactor proposal doc.
PULL_REQUEST_GUIDE.md Adds guide text for PR context/testing.
PR_SUMMARY.md Adds summary doc for addressed issues/testing.
GSOC_2026_PROPOSAL_EmbeddedChat.md Adds proposal document.
Comments suppressed due to low confidence (1)

packages/auth/src/RocketChatAuth.ts:60

  • onAuthChange is async and currently returns nothing. Several React components in this PR treat it like it returns an unsubscribe function, which results in leaked listeners. Consider making onAuthChange return a synchronous unsubscribe (e.g., a function that calls removeAuthListener) and make removeAuthListener non-async since it’s purely synchronous array mutation.
  async onAuthChange(callback: (user: object | null) => void) {
    this.authListeners.push(callback);
    const user = await this.getCurrentUser();
    callback(user);
  }

  async removeAuthListener(callback: (user: object | null) => void) {
    this.authListeners = this.authListeners.filter((cb) => cb !== callback);
  }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

<Modal.Close onClick={() => setSummaryModalOpen(false)} />
</Modal.Header>
<Modal.Content style={{ padding: '1.5rem', maxHeight: '60vh', overflowY: 'auto' }}>
<Markdown body={summaryContent} />
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

Markdown in this codebase renders only when both body and md token props are provided; passing just a string body will render nothing. As a result, the summary content won’t be displayed. Either render summaryContent as plain text, or convert it to the token format expected by Markup/Markdown and pass it via the md prop.

Suggested change
<Markdown body={summaryContent} />
<div>{summaryContent}</div>

Copilot uses AI. Check for mistakes.
Comment on lines 91 to 93
const setIsLoginIn = useLoginStore((state) => state.setIsLoginIn);
const dispatchToastMessage = useToastBarDispatch();
if (isClosable && !setClosableState) {
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

useToastBarDispatch() is called in EmbeddedChat before a ToastBarProvider exists in the render tree. Since useToastBarDispatch destructures from ToastContext, this will throw at runtime (context is undefined). Move the ToastBarProvider higher (wrapping the component that calls the hook) or relocate the auto-login error toast into a child component rendered under the provider.

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +194
const unsubscribe = RCInstance.auth.onAuthChange((user) => {
if (user) {
// Clear old listeners before adding new ones to avoid duplicates
removeAllListeners();
RCInstance.addMessageListener(addMessage);
RCInstance.addMessageDeleteListener(removeMessage);
RCInstance.addActionTriggeredListener(onActionTriggerResponse);
RCInstance.addUiInteractionListener(onActionTriggerResponse);

getMessagesAndRoles();
setHasMoreMessages(true);
} else {
getMessagesAndRoles(anonymousMode);
}
});
}, [RCInstance, anonymousMode, getMessagesAndRoles]);

useEffect(() => {
RCInstance.auth.onAuthChange((user) => {
if (user) {
fetchAndSetPermissions();
} else {
removeAllListeners();
getMessagesAndRoles(anonymousMode);
permissionsRef.current = null;
}
});
}, []);

return () => {
if (typeof unsubscribe === 'function') unsubscribe();
removeAllListeners();
};
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

RCInstance.auth.onAuthChange(...) does not return an unsubscribe function; unsubscribe here won’t be callable so the auth-change listener isn’t removed on unmount. This can lead to duplicated listeners and repeated getMessagesAndRoles() / permission fetches after re-mounts. Use removeAuthListener in cleanup or change onAuthChange to return an unsubscribe.

Copilot uses AI. Check for mistakes.
import React, { useCallback } from 'react';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
import { useStarredMessageStore, useUserStore } from '../../store';
import { MessageAggregator } from './common/MessageAggregator';
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

MessageAggregator is now exported as default from ./common/MessageAggregator, but this file still imports it as a named export ({ MessageAggregator }). This will fail to import at runtime; switch to a default import (or restore the named export).

Copilot uses AI. Check for mistakes.
Comment on lines +566 to 569
if (result.success) {
return result.room;
}
return null;
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

getRoomInfo() changed to return result.room (a room object) instead of the previous method-call response shape. At least one consumer expects roomInfo.result[...] (e.g., ChatHeader’s archived-room path), which will now throw. Either preserve the previous return shape or update all callers to the new return type.

Suggested change
if (result.success) {
return result.room;
}
return null;
return result;

Copilot uses AI. Check for mistakes.
Comment on lines 183 to 200
@@ -157,6 +194,14 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
.catch(console.error);
}
});

return () => {
if (typeof unsubscribe === 'function') unsubscribe();
if (timerRef.current) clearTimeout(timerRef.current);
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

Same issue as elsewhere: RCInstance.auth.onAuthChange(...) does not return an unsubscribe function, so the cleanup here won’t remove the auth listener. Use RCInstance.auth.removeAuthListener (or change onAuthChange to return an unsubscribe) to avoid listener leaks and duplicated fetches.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to 26
const MessageAggregator = ({
title,
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

MessageAggregator was changed from a named export to a default export, but multiple existing views still import it as { MessageAggregator } (e.g., StarredMessages, PinnedMessages, MentionedMessages, etc.). This will cause runtime/import errors. Either keep the named export for backward compatibility or update all import sites to use the default export.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 17
@@ -8,16 +8,16 @@ import {
useComponentOverrides,
appendClassNames,
useTheme,
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import { EmojiPicker } from '../EmojiPicker';
import { getMessageToolboxStyles } from './Message.styles';
import SurfaceMenu from '../SurfaceMenu/SurfaceMenu';
import { Markdown } from '../Markdown';
import Attachment from '../AttachmentHandler/Attachment';
} from "@embeddedchat/ui-elements";
import RCContext from "../../context/RCInstance";
import { EmojiPicker } from "../EmojiPicker";
import { getMessageToolboxStyles } from "./Message.styles";
import SurfaceMenu from "../SurfaceMenu/SurfaceMenu";
import { Markdown } from "../Markdown";
import Attachment from "../AttachmentHandler/Attachment";
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

This file was switched to double quotes, but the repo’s Prettier config for packages/react enforces singleQuote: true and ESLint treats Prettier violations as errors. Reformat this file to match the project’s Prettier settings (or run the formatter) to avoid lint/build failures.

Copilot uses AI. Check for mistakes.
Comment on lines +215 to 222
translate: {
label: "Translate",
id: "translate",
onClick: () => handleTranslateMessage(message),
iconName: "language",
visible: RCInstance.getAiAdapter()?.enabled,
},
}),
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

options is memoized but reads RCInstance.getAiAdapter()?.enabled without including RCInstance (or a stable aiEnabled value) in the dependency list. If the adapter is set/changed at runtime, the Translate option visibility can become stale. Include a stable dependency or derive aiEnabled outside the memo.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,61 @@
import React from 'react';
import { Box, Button, useTheme, lighten, darken } from '@embeddedchat/ui-elements';
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

Button is imported but never used, which triggers lint warnings in this package. Remove the unused import (or switch the reply chips to actual Buttons if that was the intent).

Suggested change
import { Box, Button, useTheme, lighten, darken } from '@embeddedchat/ui-elements';
import { Box, useTheme, lighten, darken } from '@embeddedchat/ui-elements';

Copilot uses AI. Check for mistakes.
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.

4 participants