@agentiffai/design 1.3.11 → 1.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -332,6 +332,8 @@ interface UserMessageProps {
332
332
  isStreaming?: boolean;
333
333
  /** Action buttons to display below the message */
334
334
  actions?: ActionButtonType[];
335
+ /** Whether to enable markdown rendering */
336
+ enableMarkdown?: boolean;
335
337
  }
336
338
  /**
337
339
  * UserMessage component displays a user's message in a chat interface.
@@ -345,7 +347,7 @@ interface UserMessageProps {
345
347
  * - Action buttons support
346
348
  * - Avatar display
347
349
  */
348
- declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
350
+ declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, enableMarkdown, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
349
351
 
350
352
  interface ResponseProps {
351
353
  /** Loading state - shows animated dots */
@@ -407,6 +409,7 @@ declare const StreamErrorMessage: React__default.FC<StreamErrorMessageProps>;
407
409
  * StreamingText Component
408
410
  *
409
411
  * Provides typewriter animation for streaming AI responses.
412
+ * Supports basic markdown rendering (bold, italic, code, links).
410
413
  *
411
414
  * @see specs/015-restyle-ai-chat/spec.md:FR-031, FR-042
412
415
  * @see UI_COMPONENTS_SSE.md:548-595
@@ -332,6 +332,8 @@ interface UserMessageProps {
332
332
  isStreaming?: boolean;
333
333
  /** Action buttons to display below the message */
334
334
  actions?: ActionButtonType[];
335
+ /** Whether to enable markdown rendering */
336
+ enableMarkdown?: boolean;
335
337
  }
336
338
  /**
337
339
  * UserMessage component displays a user's message in a chat interface.
@@ -345,7 +347,7 @@ interface UserMessageProps {
345
347
  * - Action buttons support
346
348
  * - Avatar display
347
349
  */
348
- declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
350
+ declare const UserMessage: ({ content, timestamp, className, avatarUrl, username, isStreaming, actions, enableMarkdown, }: UserMessageProps) => react_jsx_runtime.JSX.Element;
349
351
 
350
352
  interface ResponseProps {
351
353
  /** Loading state - shows animated dots */
@@ -407,6 +409,7 @@ declare const StreamErrorMessage: React__default.FC<StreamErrorMessageProps>;
407
409
  * StreamingText Component
408
410
  *
409
411
  * Provides typewriter animation for streaming AI responses.
412
+ * Supports basic markdown rendering (bold, italic, code, links).
410
413
  *
411
414
  * @see specs/015-restyle-ai-chat/spec.md:FR-031, FR-042
412
415
  * @see UI_COMPONENTS_SSE.md:548-595
@@ -110,7 +110,9 @@ var tokens = {
110
110
  fontWeight: {
111
111
  regular: 400,
112
112
  medium: 500,
113
- semibold: 600},
113
+ semibold: 600,
114
+ bold: 700
115
+ },
114
116
  lineHeight: {
115
117
  tight: 1.25,
116
118
  normal: 1.5}
@@ -828,6 +830,59 @@ function AssistantThinking({
828
830
  );
829
831
  }
830
832
  AssistantThinking.displayName = "AssistantThinking";
833
+ function parseMarkdown(text) {
834
+ if (!text) return [];
835
+ const elements = [];
836
+ let key = 0;
837
+ const paragraphs = text.split(/\n\n+/);
838
+ paragraphs.forEach((paragraph, pIndex) => {
839
+ if (pIndex > 0) {
840
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("br", {}, key++));
841
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("br", {}, key++));
842
+ }
843
+ const lines = paragraph.split("\n");
844
+ lines.forEach((line, lineIndex) => {
845
+ if (lineIndex > 0) {
846
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("br", {}, key++));
847
+ }
848
+ const parsed = parseInlineMarkdown(line, key);
849
+ elements.push(...parsed.elements);
850
+ key = parsed.nextKey;
851
+ });
852
+ });
853
+ return elements;
854
+ }
855
+ function parseInlineMarkdown(text, startKey) {
856
+ const elements = [];
857
+ let key = startKey;
858
+ const inlineRegex = /(\*\*(.+?)\*\*)|(\*(.+?)\*)|(`([^`]+)`)|(\[([^\]]+)\]\(([^)]+)\))/g;
859
+ let lastIndex = 0;
860
+ let match;
861
+ while ((match = inlineRegex.exec(text)) !== null) {
862
+ if (match.index > lastIndex) {
863
+ elements.push(text.slice(lastIndex, match.index));
864
+ }
865
+ if (match[1]) {
866
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("strong", { children: match[2] }, key++));
867
+ } else if (match[3]) {
868
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("em", { children: match[4] }, key++));
869
+ } else if (match[5]) {
870
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("code", { children: match[6] }, key++));
871
+ } else if (match[7]) {
872
+ elements.push(
873
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: match[9], target: "_blank", rel: "noopener noreferrer", children: match[8] }, key++)
874
+ );
875
+ }
876
+ lastIndex = match.index + match[0].length;
877
+ }
878
+ if (lastIndex < text.length) {
879
+ elements.push(text.slice(lastIndex));
880
+ }
881
+ if (elements.length === 0) {
882
+ elements.push(text);
883
+ }
884
+ return { elements, nextKey: key };
885
+ }
831
886
  var Container3 = styled8__default.default.div`
832
887
  font-family: ${(props) => props.$variant === "code" ? tokens.typography.fontFamily.monospace : tokens.typography.fontFamily.primary};
833
888
  white-space: pre-wrap;
@@ -836,6 +891,33 @@ var Container3 = styled8__default.default.div`
836
891
  /* Performance optimizations for streaming text */
837
892
  text-rendering: optimizeSpeed;
838
893
  contain: content;
894
+
895
+ /* Markdown element styles */
896
+ strong {
897
+ font-weight: ${tokens.typography.fontWeight.bold};
898
+ color: ${tokens.colors.text.primary};
899
+ }
900
+
901
+ em {
902
+ font-style: italic;
903
+ }
904
+
905
+ code {
906
+ font-family: ${tokens.typography.fontFamily.monospace};
907
+ background: ${tokens.colors.surface.overlay};
908
+ padding: 0.15em 0.4em;
909
+ border-radius: ${tokens.borderRadius.sm};
910
+ font-size: 0.9em;
911
+ }
912
+
913
+ a {
914
+ color: ${tokens.colors.primary};
915
+ text-decoration: none;
916
+
917
+ &:hover {
918
+ text-decoration: underline;
919
+ }
920
+ }
839
921
  `;
840
922
  var Cursor = styled8__default.default.span`
841
923
  display: inline-block;
@@ -880,8 +962,14 @@ var StreamingTextBase = ({
880
962
  wasStreamingRef.current = isStreaming;
881
963
  }, [isStreaming, onStreamComplete]);
882
964
  const showCursor = isStreaming && cursor;
965
+ const renderedContent = react.useMemo(() => {
966
+ if (variant === "markdown") {
967
+ return parseMarkdown(content);
968
+ }
969
+ return content;
970
+ }, [content, variant]);
883
971
  return /* @__PURE__ */ jsxRuntime.jsxs(Container3, { $variant: variant, className, children: [
884
- content,
972
+ renderedContent,
885
973
  showCursor && /* @__PURE__ */ jsxRuntime.jsx(Cursor, {})
886
974
  ] });
887
975
  };
@@ -1313,20 +1401,30 @@ var AssistantMessageAdapterBase = ({
1313
1401
  // markdownTagRenderers,
1314
1402
  // ImageRenderer,
1315
1403
  }) => {
1316
- if (isLoading || isGenerating && !message?.content) {
1317
- return /* @__PURE__ */ jsxRuntime.jsx(AssistantThinking, { message: "Thinking..." });
1318
- }
1404
+ const lastGenerativeUIRef = react.useRef(null);
1319
1405
  const rawContent = message?.content || "";
1320
1406
  const content = stripToolCallMarkers(rawContent);
1321
1407
  let generativeUIOutput = null;
1322
1408
  const msgWithUI = message;
1323
1409
  if (msgWithUI && typeof msgWithUI.generativeUI === "function") {
1324
1410
  try {
1325
- generativeUIOutput = msgWithUI.generativeUI();
1411
+ const newOutput = msgWithUI.generativeUI();
1412
+ if (newOutput !== null && newOutput !== void 0) {
1413
+ generativeUIOutput = newOutput;
1414
+ lastGenerativeUIRef.current = newOutput;
1415
+ }
1326
1416
  } catch (e) {
1327
1417
  console.warn("[AssistantMessageAdapter] Error rendering generativeUI:", e);
1328
1418
  }
1329
1419
  }
1420
+ if (!generativeUIOutput && lastGenerativeUIRef.current) {
1421
+ generativeUIOutput = lastGenerativeUIRef.current;
1422
+ }
1423
+ const hasGenerativeUI = generativeUIOutput !== null;
1424
+ const showThinking = (isLoading || isGenerating && !content) && !hasGenerativeUI;
1425
+ if (showThinking) {
1426
+ return /* @__PURE__ */ jsxRuntime.jsx(AssistantThinking, { message: "Thinking..." });
1427
+ }
1330
1428
  const attachments = [];
1331
1429
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1332
1430
  generativeUIOutput && /* @__PURE__ */ jsxRuntime.jsx(GenerativeUIContainer, { children: generativeUIOutput }),
@@ -1345,35 +1443,39 @@ var AssistantMessageAdapterBase = ({
1345
1443
  };
1346
1444
  var AssistantMessageAdapter = react.memo(AssistantMessageAdapterBase);
1347
1445
  AssistantMessageAdapter.displayName = "AssistantMessageAdapter";
1348
- function createAssistantMessageAdapter(ThinkingIndicator, ToolCallsComponent) {
1446
+ function createAssistantMessageAdapter(ThinkingIndicator, _ToolCallsComponent) {
1349
1447
  const CustomAssistantMessageAdapter = ({
1350
1448
  message,
1351
1449
  isLoading,
1352
- isGenerating,
1353
- isCurrentMessage
1450
+ isGenerating
1451
+ // isCurrentMessage and ToolCallsComponent are no longer used but kept for backwards compat
1354
1452
  }) => {
1355
- const showThinking = isLoading || isGenerating && !message?.content;
1356
- const shouldShowToolCalls = isCurrentMessage && ToolCallsComponent;
1453
+ const lastGenerativeUIRef = react.useRef(null);
1357
1454
  const rawContent = message?.content || "";
1358
1455
  const content = stripToolCallMarkers(rawContent);
1359
1456
  let generativeUIOutput = null;
1360
1457
  const msgWithUI = message;
1361
1458
  if (msgWithUI && typeof msgWithUI.generativeUI === "function") {
1362
1459
  try {
1363
- generativeUIOutput = msgWithUI.generativeUI();
1460
+ const newOutput = msgWithUI.generativeUI();
1461
+ if (newOutput !== null && newOutput !== void 0) {
1462
+ generativeUIOutput = newOutput;
1463
+ lastGenerativeUIRef.current = newOutput;
1464
+ }
1364
1465
  } catch (e) {
1365
1466
  console.warn("[AssistantMessageAdapter] Error rendering generativeUI:", e);
1366
1467
  }
1367
1468
  }
1469
+ if (!generativeUIOutput && lastGenerativeUIRef.current) {
1470
+ generativeUIOutput = lastGenerativeUIRef.current;
1471
+ }
1368
1472
  const attachments = [];
1473
+ const hasGenerativeUI = generativeUIOutput !== null;
1474
+ const showThinking = (isLoading || isGenerating && !content) && !hasGenerativeUI;
1369
1475
  if (showThinking) {
1370
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1371
- ThinkingIndicator ? /* @__PURE__ */ jsxRuntime.jsx(ThinkingIndicator, { isLoading, isGenerating }) : /* @__PURE__ */ jsxRuntime.jsx(AssistantThinking, { message: "Thinking..." }),
1372
- shouldShowToolCalls && /* @__PURE__ */ jsxRuntime.jsx(ToolCallsComponent, {})
1373
- ] });
1476
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: ThinkingIndicator ? /* @__PURE__ */ jsxRuntime.jsx(ThinkingIndicator, { isLoading, isGenerating }) : /* @__PURE__ */ jsxRuntime.jsx(AssistantThinking, { message: "Thinking..." }) });
1374
1477
  }
1375
1478
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1376
- shouldShowToolCalls && /* @__PURE__ */ jsxRuntime.jsx(ToolCallsComponent, {}),
1377
1479
  generativeUIOutput && /* @__PURE__ */ jsxRuntime.jsx(GenerativeUIContainer, { children: generativeUIOutput }),
1378
1480
  content && /* @__PURE__ */ jsxRuntime.jsx(
1379
1481
  AssistantMessage,
@@ -1391,16 +1493,15 @@ function createAssistantMessageAdapter(ThinkingIndicator, ToolCallsComponent) {
1391
1493
  CustomAssistantMessageAdapter.displayName = "CustomAssistantMessageAdapter";
1392
1494
  return react.memo(CustomAssistantMessageAdapter);
1393
1495
  }
1394
- function createAssistantMessageAdapterWithErrorReporting(onReportIssue, ThinkingIndicator, ToolCallsComponent) {
1496
+ function createAssistantMessageAdapterWithErrorReporting(onReportIssue, ThinkingIndicator, _ToolCallsComponent) {
1395
1497
  const ErrorReportingAssistantMessageAdapter = ({
1396
1498
  message,
1397
1499
  isLoading,
1398
- isGenerating,
1399
- isCurrentMessage
1500
+ isGenerating
1501
+ // isCurrentMessage and ToolCallsComponent are no longer used but kept for backwards compat
1400
1502
  }) => {
1503
+ const lastGenerativeUIRef = react.useRef(null);
1401
1504
  const { visibleMessages } = reactCore.useCopilotChat();
1402
- const showThinking = isLoading || isGenerating && !message?.content;
1403
- const shouldShowToolCalls = isCurrentMessage && ToolCallsComponent;
1404
1505
  const rawContent = message?.content || "";
1405
1506
  const content = stripToolCallMarkers(rawContent);
1406
1507
  const errorContext = react.useMemo(() => detectErrorInMessage(content), [content]);
@@ -1448,20 +1549,25 @@ function createAssistantMessageAdapterWithErrorReporting(onReportIssue, Thinking
1448
1549
  const msgWithUI = message;
1449
1550
  if (msgWithUI && typeof msgWithUI.generativeUI === "function") {
1450
1551
  try {
1451
- generativeUIOutput = msgWithUI.generativeUI();
1552
+ const newOutput = msgWithUI.generativeUI();
1553
+ if (newOutput !== null && newOutput !== void 0) {
1554
+ generativeUIOutput = newOutput;
1555
+ lastGenerativeUIRef.current = newOutput;
1556
+ }
1452
1557
  } catch (e) {
1453
1558
  console.warn("[AssistantMessageAdapter] Error rendering generativeUI:", e);
1454
1559
  }
1455
1560
  }
1561
+ if (!generativeUIOutput && lastGenerativeUIRef.current) {
1562
+ generativeUIOutput = lastGenerativeUIRef.current;
1563
+ }
1456
1564
  const attachments = [];
1565
+ const hasGenerativeUI = generativeUIOutput !== null;
1566
+ const showThinking = (isLoading || isGenerating && !content) && !hasGenerativeUI;
1457
1567
  if (showThinking) {
1458
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1459
- ThinkingIndicator ? /* @__PURE__ */ jsxRuntime.jsx(ThinkingIndicator, { isLoading, isGenerating }) : /* @__PURE__ */ jsxRuntime.jsx(AssistantThinking, { message: "Thinking..." }),
1460
- shouldShowToolCalls && /* @__PURE__ */ jsxRuntime.jsx(ToolCallsComponent, {})
1461
- ] });
1568
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: ThinkingIndicator ? /* @__PURE__ */ jsxRuntime.jsx(ThinkingIndicator, { isLoading, isGenerating }) : /* @__PURE__ */ jsxRuntime.jsx(AssistantThinking, { message: "Thinking..." }) });
1462
1569
  }
1463
1570
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1464
- shouldShowToolCalls && /* @__PURE__ */ jsxRuntime.jsx(ToolCallsComponent, {}),
1465
1571
  generativeUIOutput && /* @__PURE__ */ jsxRuntime.jsx(GenerativeUIContainer, { children: generativeUIOutput }),
1466
1572
  content && /* @__PURE__ */ jsxRuntime.jsx(
1467
1573
  AssistantMessage,
@@ -3090,7 +3196,7 @@ function CustomCopilotSidebar2({
3090
3196
  [disabled, disabledReason, onSetOpen]
3091
3197
  );
3092
3198
  const AssistantMessageAdapterMemo = react.useMemo(
3093
- () => onReportIssue ? createAssistantMessageAdapterWithErrorReporting(onReportIssue, ThinkingIndicator, ToolCallsComponent) : ThinkingIndicator || ToolCallsComponent ? createAssistantMessageAdapter(ThinkingIndicator, ToolCallsComponent) : AssistantMessageAdapter,
3199
+ () => onReportIssue ? createAssistantMessageAdapterWithErrorReporting(onReportIssue, ThinkingIndicator) : ThinkingIndicator || ToolCallsComponent ? createAssistantMessageAdapter(ThinkingIndicator) : AssistantMessageAdapter,
3094
3200
  [ThinkingIndicator, ToolCallsComponent, onReportIssue]
3095
3201
  );
3096
3202
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -3646,27 +3752,6 @@ var ActionsContainer3 = styled8__default.default.div`
3646
3752
  gap: ${tokens.spacing.xs};
3647
3753
  flex-wrap: wrap;
3648
3754
  `;
3649
- var StreamingIndicator2 = styled8__default.default.span`
3650
- display: inline-block;
3651
- width: ${tokens.spacing.xs};
3652
- height: ${tokens.spacing.xs};
3653
- margin-left: ${tokens.spacing.xs};
3654
- background-color: ${tokens.colors.text.tertiary};
3655
- border-radius: ${tokens.borderRadius.full};
3656
- animation: pulse 1.5s ease-in-out infinite;
3657
-
3658
- @keyframes pulse {
3659
- 0%,
3660
- 100% {
3661
- opacity: 0.3;
3662
- transform: scale(0.8);
3663
- }
3664
- 50% {
3665
- opacity: 1;
3666
- transform: scale(1.2);
3667
- }
3668
- }
3669
- `;
3670
3755
  var Avatar3 = styled8__default.default.img`
3671
3756
  width: ${tokens.spacing.xl};
3672
3757
  height: ${tokens.spacing.xl};
@@ -3682,15 +3767,21 @@ var UserMessage2 = ({
3682
3767
  avatarUrl,
3683
3768
  username,
3684
3769
  isStreaming = false,
3685
- actions = []
3770
+ actions = [],
3771
+ enableMarkdown = true
3686
3772
  }) => {
3687
3773
  return /* @__PURE__ */ jsxRuntime.jsxs(StyledUserMessage2, { className, children: [
3688
3774
  /* @__PURE__ */ jsxRuntime.jsxs(MessageBubble, { children: [
3689
3775
  username && /* @__PURE__ */ jsxRuntime.jsx("strong", { children: username }),
3690
- /* @__PURE__ */ jsxRuntime.jsxs(MessageContent2, { children: [
3691
- content,
3692
- isStreaming && /* @__PURE__ */ jsxRuntime.jsx(StreamingIndicator2, {})
3693
- ] }),
3776
+ /* @__PURE__ */ jsxRuntime.jsx(MessageContent2, { children: /* @__PURE__ */ jsxRuntime.jsx(
3777
+ StreamingText2,
3778
+ {
3779
+ content,
3780
+ isStreaming,
3781
+ variant: enableMarkdown ? "markdown" : "default",
3782
+ cursor: false
3783
+ }
3784
+ ) }),
3694
3785
  timestamp && /* @__PURE__ */ jsxRuntime.jsx(MessageTime2, { children: timestamp }),
3695
3786
  actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ActionsContainer3, { children: actions.map((action, index) => /* @__PURE__ */ jsxRuntime.jsxs(ActionButton3, { onClick: action.onClick, children: [
3696
3787
  action.icon,