Skip to content

Commit dbbbd29

Browse files
authored
fix: improve custom widget AI assistant feedback (#42095)
## Summary - render Custom Widget AI assistant responses with the existing shared Ask AI Markdown renderer while keeping user messages as plain text - expose the existing CE Markdown renderer through the edition-aware GPT barrel so CE and EE reuse one implementation - animate the Generating loader icon - add regression coverage for the assistant/user rendering boundary ## Testing - CE: 29 Custom Widget AI Assistant tests pass - CE: ESLint passes with no new errors - CE: TypeScript check passes - EE sync simulation: final net patch applies cleanly onto latest appsmith-ee release - EE sync simulation: no PR-related TypeScript failures - git diff validation and CE pre-push edition guard pass ## Linear https://linear.app/appsmith/issue/APP-15735/replace-internal-appsmith-app-with-native-co-pilot-component ## Automation /ok-to-test tags="@tag.All" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/31082751527> > Commit: 61a8087 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=31082751527&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Thu, 06 Aug 2026 09:11:50 UTC <!-- end of auto-generated comment: Cypress test results --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * AI assistant responses now support formatted Markdown rendering. * User messages continue to display as plain text for clear distinction. * Added a rotating loading indicator while the assistant is processing. * **Tests** * Added coverage confirming Markdown formatting for assistant responses and plain-text rendering for user messages. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent adc82dd commit dbbbd29

3 files changed

Lines changed: 47 additions & 2 deletions

File tree

app/client/src/ce/components/editorComponents/GPT/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { AISidePanel } from "./AISidePanel";
1111

1212
// Re-export the new components
1313
export { AISidePanel } from "./AISidePanel";
14+
export { AIMarkdownRenderer } from "./shared";
1415

1516
export type AIEditorContext = Partial<{
1617
functionName: string;

app/client/src/pages/Editor/CustomWidgetBuilder/Editor/AIAssistant/index.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ jest.mock("ee/utils/AnalyticsUtil", () => ({
3030
default: { logEvent: jest.fn() },
3131
}));
3232

33+
jest.mock("ee/components/editorComponents/GPT", () => ({
34+
AIMarkdownRenderer: ({ content }: { content: string }) => (
35+
<div data-testid="t--custom-widget-ai-markdown">{content}</div>
36+
),
37+
}));
38+
3339
const mockStore = configureStore();
3440

3541
const SRC_DOC = {
@@ -178,6 +184,26 @@ describe("CustomWidgetBuilder AIAssistant", () => {
178184
expect(screen.queryByText(/color: red/)).not.toBeInTheDocument();
179185
});
180186

187+
it("uses the markdown renderer for assistant responses and keeps user messages plain", () => {
188+
renderAssistant({
189+
aiAssistant: {
190+
messages: [
191+
{ role: "user", content: "**Keep this literal**", timestamp: 1 },
192+
{
193+
role: "assistant",
194+
content: "## Features\n\n**Inline editing**",
195+
timestamp: 2,
196+
},
197+
],
198+
},
199+
});
200+
201+
expect(
202+
screen.getByTestId("t--custom-widget-ai-markdown"),
203+
).toHaveTextContent("## Features **Inline editing**");
204+
expect(screen.getByText("**Keep this literal**")).toBeInTheDocument();
205+
});
206+
181207
it("does not re-apply older assistant messages", () => {
182208
const bulkUpdate = jest.fn();
183209

app/client/src/pages/Editor/CustomWidgetBuilder/Editor/AIAssistant/index.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
Text,
2121
Tooltip,
2222
} from "@appsmith/ads";
23+
import { AIMarkdownRenderer } from "ee/components/editorComponents/GPT";
2324
import type { ContentProps } from "pages/Editor/CustomWidgetBuilder/Editor/CodeEditors/types";
2425
import { CustomWidgetBuilderContext } from "pages/Editor/CustomWidgetBuilder";
2526
import {
@@ -95,6 +96,19 @@ const fadeIn = keyframes`
9596
}
9697
`;
9798

99+
const rotate = keyframes`
100+
from {
101+
transform: rotate(0deg);
102+
}
103+
to {
104+
transform: rotate(360deg);
105+
}
106+
`;
107+
108+
const LoadingIcon = styled(Icon)`
109+
animation: ${rotate} 1s linear infinite;
110+
`;
111+
98112
const EmptyState = styled.div`
99113
display: flex;
100114
flex-direction: column;
@@ -565,7 +579,11 @@ export function AIAssistant(props: ContentProps) {
565579
? createMessage(CUSTOM_WIDGET_AI_ASSISTANT.USER_LABEL)
566580
: createMessage(CUSTOM_WIDGET_AI_ASSISTANT.ASSISTANT_LABEL)}
567581
</MessageHeader>
568-
<UserMessageContent>{message.content}</UserMessageContent>
582+
{message.role === "user" ? (
583+
<UserMessageContent>{message.content}</UserMessageContent>
584+
) : (
585+
<AIMarkdownRenderer content={message.content} />
586+
)}
569587
{message.appliedFiles.length > 0 && (
570588
<AppliedUpdates>
571589
<Text color="var(--ads-v2-color-fg-muted)" kind="body-s">
@@ -589,7 +607,7 @@ export function AIAssistant(props: ContentProps) {
589607
{isLoading && (
590608
<LoadingState>
591609
<LoadingText>
592-
<Icon name="loader-line" size="sm" />
610+
<LoadingIcon name="loader-line" size="sm" />
593611
{createMessage(CUSTOM_WIDGET_AI_ASSISTANT.THINKING)}
594612
</LoadingText>
595613
</LoadingState>

0 commit comments

Comments
 (0)