diff --git a/workspaces/lightspeed/.changeset/tasty-pumpkins-design.md b/workspaces/lightspeed/.changeset/tasty-pumpkins-design.md
new file mode 100644
index 0000000000..ff9eb3de7b
--- /dev/null
+++ b/workspaces/lightspeed/.changeset/tasty-pumpkins-design.md
@@ -0,0 +1,5 @@
+---
+'@red-hat-developer-hub/backstage-plugin-lightspeed': patch
+---
+
+Render new lines in deepThinking component
diff --git a/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedChatBox.tsx b/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedChatBox.tsx
index 072ccf8b48..7d4195a8a1 100644
--- a/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedChatBox.tsx
+++ b/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedChatBox.tsx
@@ -17,6 +17,7 @@
import {
ForwardedRef,
forwardRef,
+ Fragment,
useEffect,
useImperativeHandle,
useRef,
@@ -247,9 +248,18 @@ export const LightspeedChatBox = forwardRef(
})();
if (reasoningContent) {
+ const reasoningBody = reasoningContent
+ .split('\n')
+ .map((line, lineIndex, array) => (
+
+ {line}
+ {lineIndex < array.length - 1 &&
}
+
+ ));
+
deepThinking = {
toggleContent: t('reasoning.thinking'),
- body: reasoningContent,
+ body: reasoningBody,
expandableSectionProps: {},
};
extraContentParts.beforeMainContent = (
diff --git a/workspaces/lightspeed/plugins/lightspeed/src/components/__tests__/LightspeedChatBox.test.tsx b/workspaces/lightspeed/plugins/lightspeed/src/components/__tests__/LightspeedChatBox.test.tsx
new file mode 100644
index 0000000000..33f3808fe9
--- /dev/null
+++ b/workspaces/lightspeed/plugins/lightspeed/src/components/__tests__/LightspeedChatBox.test.tsx
@@ -0,0 +1,176 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { ChatbotDisplayMode } from '@patternfly/chatbot';
+import { render, screen } from '@testing-library/react';
+
+import { mockUseTranslation } from '../../test-utils/mockTranslations';
+import { LightspeedChatBox } from '../LightspeedChatBox';
+
+jest.mock('../../hooks/useTranslation', () => ({
+ useTranslation: jest.fn(() => mockUseTranslation()),
+}));
+
+jest.mock('../../hooks/useAutoScroll', () => ({
+ useAutoScroll: jest.fn(() => ({
+ autoScroll: true,
+ resumeAutoScroll: jest.fn(),
+ stopAutoScroll: jest.fn(),
+ scrollToBottom: jest.fn(),
+ scrollToTop: jest.fn(),
+ })),
+}));
+
+jest.mock('../../hooks/useBufferedMessages', () => ({
+ useBufferedMessages: jest.fn(messages => {
+ return messages || [];
+ }),
+}));
+
+jest.mock('../../hooks/useFeedbackActions', () => ({
+ useFeedbackActions: jest.fn(messages => {
+ return messages || [];
+ }),
+}));
+
+jest.mock('@patternfly/chatbot', () => {
+ const actual = jest.requireActual('@patternfly/chatbot');
+ return {
+ ...actual,
+ DeepThinking: ({ body }: { body: React.ReactNode }) => (
+
{body}
+ ),
+ MessageBox: ({ children }: { children: React.ReactNode }) => (
+ {children}
+ ),
+ Message: (props: any) => (
+
+ {props.extraContent?.beforeMainContent}
+ {props.content}
+ {props.extraContent?.afterMainContent}
+
+ ),
+ };
+});
+
+describe('LightspeedChatBox', () => {
+ const defaultProps = {
+ userName: 'user:test',
+ messages: [],
+ announcement: undefined,
+ conversationId: 'test-conversation-id',
+ profileLoading: false,
+ welcomePrompts: [],
+ isStreaming: false,
+ topicRestrictionEnabled: false,
+ displayMode: ChatbotDisplayMode.embedded,
+ };
+
+ it('should render reasoning content with newlines as line breaks', () => {
+ const messagesWithReasoning = [
+ {
+ role: 'bot' as const,
+ content: 'Line 1\nLine 2\nLine 3Main response content',
+ timestamp: '2026-01-22T00:00:00Z',
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ const deepThinking = screen.getByTestId('deep-thinking');
+ expect(deepThinking).toBeInTheDocument();
+
+ // Check that the reasoning body contains line breaks
+ const reasoningContent = deepThinking.textContent;
+ expect(reasoningContent).toContain('Line 1');
+ expect(reasoningContent).toContain('Line 2');
+ expect(reasoningContent).toContain('Line 3');
+
+ const brElements = deepThinking.querySelectorAll('br');
+ expect(brElements.length).toBe(2);
+ });
+
+ it('should handle reasoning content without newlines', () => {
+ const messagesWithReasoning = [
+ {
+ role: 'bot' as const,
+ content: 'Single line reasoningMain response',
+ name: 'assistant',
+ timestamp: '2024-01-01T00:00:00Z',
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ const deepThinking = screen.getByTestId('deep-thinking');
+ expect(deepThinking).toBeInTheDocument();
+ expect(deepThinking).toHaveTextContent('Single line reasoning');
+
+ const brElements = deepThinking.querySelectorAll('br');
+ expect(brElements.length).toBe(0);
+ });
+
+ it('should handle reasoning in progress with newlines', () => {
+ const messagesWithReasoningInProgress = [
+ {
+ role: 'bot' as const,
+ content: 'Line 1\nLine 2\nLine 3',
+ timestamp: '2024-01-01T00:00:00Z',
+ name: 'assistant',
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ const deepThinking = screen.getByTestId('deep-thinking');
+ expect(deepThinking).toBeInTheDocument();
+
+ const brElements = deepThinking.querySelectorAll('br');
+ expect(brElements.length).toBe(2);
+ });
+
+ it('should handle reasoning content with multiple newlines', () => {
+ const messagesWithReasoningInProgress = [
+ {
+ role: 'bot' as const,
+ content: 'Line 1\n\n\nLine 2\nLine 3',
+ timestamp: '2024-01-01T00:00:00Z',
+ name: 'assistant',
+ },
+ ];
+
+ render(
+ ,
+ );
+
+ const deepThinking = screen.getByTestId('deep-thinking');
+ expect(deepThinking).toBeInTheDocument();
+
+ const brElements = deepThinking.querySelectorAll('br');
+ expect(brElements.length).toBe(4);
+ });
+});