@gendive/chatllm 0.2.0 → 0.3.1

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.
@@ -1,5 +1,5 @@
1
1
  // src/react/ChatUI.tsx
2
- import React6, { useState as useState7 } from "react";
2
+ import React9, { useState as useState9 } from "react";
3
3
 
4
4
  // src/react/hooks/useChatUI.ts
5
5
  import { useState, useRef, useCallback, useEffect } from "react";
@@ -563,6 +563,7 @@ var IconSvg = ({
563
563
  size = 20,
564
564
  color = "currentColor",
565
565
  className = "",
566
+ style,
566
567
  onClick,
567
568
  "aria-label": ariaLabel
568
569
  }) => {
@@ -594,7 +595,11 @@ var IconSvg = ({
594
595
  "user-3-line": /* @__PURE__ */ jsx("path", { d: "M20 22h-2v-2a3 3 0 0 0-3-3H9a3 3 0 0 0-3 3v2H4v-2a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5v2zm-8-9a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" }),
595
596
  "sun-line": /* @__PURE__ */ jsx("path", { d: "M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z" }),
596
597
  "moon-line": /* @__PURE__ */ jsx("path", { d: "M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z" }),
597
- "key-line": /* @__PURE__ */ jsx("path", { d: "M12.917 13A6.002 6.002 0 0 1 1 12a6 6 0 0 1 11.917-1H23v6h-2v-4h-2v4h-2v-4h-4.083zM7 10a2 2 0 1 0 0 4 2 2 0 0 0 0-4z" })
598
+ "key-line": /* @__PURE__ */ jsx("path", { d: "M12.917 13A6.002 6.002 0 0 1 1 12a6 6 0 0 1 11.917-1H23v6h-2v-4h-2v4h-2v-4h-4.083zM7 10a2 2 0 1 0 0 4 2 2 0 0 0 0-4z" }),
599
+ "links-line": /* @__PURE__ */ jsx("path", { d: "M17.657 14.828l-1.414-1.414L17.657 12A4 4 0 1 0 12 6.343l-1.414 1.414-1.414-1.414 1.414-1.414a6 6 0 0 1 8.485 8.485l-1.414 1.414zm-2.829 2.829l-1.414 1.414a6 6 0 1 1-8.485-8.485l1.414-1.414 1.414 1.414L6.343 12A4 4 0 1 0 12 17.657l1.414-1.414 1.414 1.414zm0-9.9l1.415 1.415-7.071 7.07-1.415-1.414 7.071-7.07z" }),
600
+ "external-link-line": /* @__PURE__ */ jsx("path", { d: "M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h6zm11-3v8h-2V6.413l-7.793 7.794-1.414-1.414L17.585 5H13V3h8z" }),
601
+ "arrow-left-line": /* @__PURE__ */ jsx("path", { d: "M7.828 11H20v2H7.828l5.364 5.364-1.414 1.414L4 12l7.778-7.778 1.414 1.414z" }),
602
+ "arrow-right-line": /* @__PURE__ */ jsx("path", { d: "M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z" })
598
603
  };
599
604
  const iconPath = icons[name];
600
605
  return /* @__PURE__ */ jsx(
@@ -609,7 +614,7 @@ var IconSvg = ({
609
614
  "aria-label": ariaLabel,
610
615
  role: onClick ? "button" : "img",
611
616
  tabIndex: onClick ? 0 : void 0,
612
- style: { display: "inline-block", verticalAlign: "middle" },
617
+ style: { display: "inline-block", verticalAlign: "middle", ...style },
613
618
  children: iconPath || /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" })
614
619
  }
615
620
  );
@@ -1408,11 +1413,568 @@ var ChatInput = ({
1408
1413
  };
1409
1414
 
1410
1415
  // src/react/components/MessageList.tsx
1411
- import { useRef as useRef3, useEffect as useEffect3, useCallback as useCallback2, useState as useState5 } from "react";
1416
+ import { useRef as useRef3, useEffect as useEffect3, useCallback as useCallback2, useState as useState6 } from "react";
1412
1417
 
1413
1418
  // src/react/components/MessageBubble.tsx
1419
+ import { useState as useState5 } from "react";
1420
+
1421
+ // src/react/components/MarkdownRenderer.tsx
1422
+ import React4, { useMemo } from "react";
1423
+
1424
+ // src/react/components/LinkChip.tsx
1414
1425
  import { useState as useState4 } from "react";
1415
1426
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1427
+ var getDomain = (url) => {
1428
+ try {
1429
+ const urlObj = new URL(url);
1430
+ return urlObj.hostname.replace("www.", "");
1431
+ } catch {
1432
+ return url;
1433
+ }
1434
+ };
1435
+ var getShortName = (domain) => {
1436
+ const parts = domain.split(".");
1437
+ if (parts.length >= 2) {
1438
+ return parts[parts.length - 2];
1439
+ }
1440
+ return domain;
1441
+ };
1442
+ var getDomainColor = (domain) => {
1443
+ const lowerDomain = domain.toLowerCase();
1444
+ const colorMap = {
1445
+ "google": "#4285f4",
1446
+ "wikipedia": "#000000",
1447
+ "github": "#24292e",
1448
+ "stackoverflow": "#f48024",
1449
+ "medium": "#00ab6c",
1450
+ "youtube": "#ff0000",
1451
+ "twitter": "#1da1f2",
1452
+ "naver": "#03c75a",
1453
+ "namu": "#00a495",
1454
+ "tistory": "#eb531f",
1455
+ "velog": "#20c997",
1456
+ "brave": "#fb542b",
1457
+ "mk": "#0066cc",
1458
+ "ko": "#3366cc"
1459
+ };
1460
+ for (const [key, color] of Object.entries(colorMap)) {
1461
+ if (lowerDomain.includes(key)) {
1462
+ return color;
1463
+ }
1464
+ }
1465
+ let hash = 0;
1466
+ for (let i = 0; i < domain.length; i++) {
1467
+ hash = domain.charCodeAt(i) + ((hash << 5) - hash);
1468
+ }
1469
+ const hue = hash % 360;
1470
+ return `hsl(${hue}, 60%, 45%)`;
1471
+ };
1472
+ var LinkChip = ({
1473
+ text,
1474
+ url,
1475
+ showFavicon = true,
1476
+ index,
1477
+ style
1478
+ }) => {
1479
+ const [isHovered, setIsHovered] = useState4(false);
1480
+ const domain = getDomain(url);
1481
+ const shortName = getShortName(domain);
1482
+ const domainColor = getDomainColor(domain);
1483
+ const parseText = (t) => {
1484
+ const match = t.match(/^(\d+)\.\s*(.+)$/);
1485
+ if (match) {
1486
+ return { number: match[1], label: match[2] };
1487
+ }
1488
+ return { label: t };
1489
+ };
1490
+ const parsed = parseText(text);
1491
+ const displayNumber = index !== void 0 ? String(index + 1) : parsed.number;
1492
+ const displayLabel = parsed.label;
1493
+ return /* @__PURE__ */ jsxs4(
1494
+ "a",
1495
+ {
1496
+ href: url,
1497
+ target: "_blank",
1498
+ rel: "noopener noreferrer",
1499
+ onMouseEnter: () => setIsHovered(true),
1500
+ onMouseLeave: () => setIsHovered(false),
1501
+ style: {
1502
+ display: "inline-flex",
1503
+ alignItems: "center",
1504
+ gap: "6px",
1505
+ padding: "4px 10px",
1506
+ backgroundColor: isHovered ? "var(--chatllm-chip-bg-hover, #e2e8f0)" : "var(--chatllm-chip-bg, #f1f5f9)",
1507
+ border: "1px solid var(--chatllm-chip-border, #e2e8f0)",
1508
+ borderRadius: "16px",
1509
+ textDecoration: "none",
1510
+ fontSize: "13px",
1511
+ fontWeight: 500,
1512
+ color: "var(--chatllm-chip-text, #475569)",
1513
+ transition: "all 0.15s ease",
1514
+ cursor: "pointer",
1515
+ maxWidth: "180px",
1516
+ ...style
1517
+ },
1518
+ title: `${displayLabel} - ${domain}`,
1519
+ children: [
1520
+ displayNumber && /* @__PURE__ */ jsx5(
1521
+ "span",
1522
+ {
1523
+ style: {
1524
+ display: "flex",
1525
+ alignItems: "center",
1526
+ justifyContent: "center",
1527
+ width: "18px",
1528
+ height: "18px",
1529
+ borderRadius: "50%",
1530
+ backgroundColor: domainColor,
1531
+ color: "#ffffff",
1532
+ fontSize: "11px",
1533
+ fontWeight: 600,
1534
+ flexShrink: 0
1535
+ },
1536
+ children: displayNumber
1537
+ }
1538
+ ),
1539
+ showFavicon && !displayNumber && /* @__PURE__ */ jsx5(
1540
+ "span",
1541
+ {
1542
+ style: {
1543
+ width: "16px",
1544
+ height: "16px",
1545
+ display: "flex",
1546
+ alignItems: "center",
1547
+ justifyContent: "center",
1548
+ flexShrink: 0
1549
+ },
1550
+ children: /* @__PURE__ */ jsx5(
1551
+ IconSvg,
1552
+ {
1553
+ name: "links-line",
1554
+ size: 14,
1555
+ color: domainColor
1556
+ }
1557
+ )
1558
+ }
1559
+ ),
1560
+ /* @__PURE__ */ jsx5(
1561
+ "span",
1562
+ {
1563
+ style: {
1564
+ overflow: "hidden",
1565
+ textOverflow: "ellipsis",
1566
+ whiteSpace: "nowrap"
1567
+ },
1568
+ children: displayLabel
1569
+ }
1570
+ ),
1571
+ /* @__PURE__ */ jsx5(
1572
+ IconSvg,
1573
+ {
1574
+ name: "external-link-line",
1575
+ size: 12,
1576
+ color: "var(--chatllm-text-muted, #94a3b8)",
1577
+ style: {
1578
+ opacity: isHovered ? 1 : 0.6,
1579
+ flexShrink: 0
1580
+ }
1581
+ }
1582
+ )
1583
+ ]
1584
+ }
1585
+ );
1586
+ };
1587
+
1588
+ // src/react/components/MarkdownRenderer.tsx
1589
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1590
+ var LINK_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
1591
+ var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((?:\[`?[^\]]+`?\]\([^)]+\)\s*)+)/gi;
1592
+ var CODE_BLOCK_REGEX = /```(\w*)\n?([\s\S]*?)```/g;
1593
+ var INLINE_CODE_REGEX = /`([^`]+)`/g;
1594
+ var BOLD_REGEX = /\*\*([^*]+)\*\*/g;
1595
+ var ITALIC_REGEX = /(?<!\*)\*([^*]+)\*(?!\*)/g;
1596
+ var HR_REGEX = /^---+$/gm;
1597
+ var parseSourceLinks = (text) => {
1598
+ const links = [];
1599
+ let match;
1600
+ const linkRegex = /\[`?([^\]`]+)`?\]\(([^)]+)\)/g;
1601
+ while ((match = linkRegex.exec(text)) !== null) {
1602
+ links.push({
1603
+ text: match[1],
1604
+ url: match[2]
1605
+ });
1606
+ }
1607
+ return links;
1608
+ };
1609
+ var parseInlineElements = (text, key) => {
1610
+ const elements = [];
1611
+ let lastIndex = 0;
1612
+ let currentText = text;
1613
+ currentText = currentText.replace(INLINE_CODE_REGEX, "\xA7CODE\xA7$1\xA7/CODE\xA7");
1614
+ currentText = currentText.replace(BOLD_REGEX, "\xA7BOLD\xA7$1\xA7/BOLD\xA7");
1615
+ currentText = currentText.replace(ITALIC_REGEX, "\xA7ITALIC\xA7$1\xA7/ITALIC\xA7");
1616
+ currentText = currentText.replace(LINK_REGEX, "\xA7LINK\xA7$1\xA7URL\xA7$2\xA7/LINK\xA7");
1617
+ const parts = currentText.split(/(§CODE§.*?§\/CODE§|§BOLD§.*?§\/BOLD§|§ITALIC§.*?§\/ITALIC§|§LINK§.*?§\/LINK§)/);
1618
+ parts.forEach((part, index) => {
1619
+ if (part.startsWith("\xA7CODE\xA7")) {
1620
+ const content = part.replace("\xA7CODE\xA7", "").replace("\xA7/CODE\xA7", "");
1621
+ elements.push(
1622
+ /* @__PURE__ */ jsx6(
1623
+ "code",
1624
+ {
1625
+ style: {
1626
+ backgroundColor: "var(--chatllm-code-bg, #f3f4f6)",
1627
+ padding: "2px 6px",
1628
+ borderRadius: "4px",
1629
+ fontSize: "0.9em",
1630
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
1631
+ color: "var(--chatllm-code-text, #e11d48)"
1632
+ },
1633
+ children: content
1634
+ },
1635
+ `${key}-code-${index}`
1636
+ )
1637
+ );
1638
+ } else if (part.startsWith("\xA7BOLD\xA7")) {
1639
+ const content = part.replace("\xA7BOLD\xA7", "").replace("\xA7/BOLD\xA7", "");
1640
+ elements.push(/* @__PURE__ */ jsx6("strong", { children: content }, `${key}-bold-${index}`));
1641
+ } else if (part.startsWith("\xA7ITALIC\xA7")) {
1642
+ const content = part.replace("\xA7ITALIC\xA7", "").replace("\xA7/ITALIC\xA7", "");
1643
+ elements.push(/* @__PURE__ */ jsx6("em", { children: content }, `${key}-italic-${index}`));
1644
+ } else if (part.startsWith("\xA7LINK\xA7")) {
1645
+ const match = part.match(/§LINK§(.+?)§URL§(.+?)§\/LINK§/);
1646
+ if (match) {
1647
+ elements.push(
1648
+ /* @__PURE__ */ jsx6(
1649
+ "a",
1650
+ {
1651
+ href: match[2],
1652
+ target: "_blank",
1653
+ rel: "noopener noreferrer",
1654
+ style: {
1655
+ color: "var(--chatllm-link, #3b82f6)",
1656
+ textDecoration: "none"
1657
+ },
1658
+ children: match[1]
1659
+ },
1660
+ `${key}-link-${index}`
1661
+ )
1662
+ );
1663
+ }
1664
+ } else if (part) {
1665
+ elements.push(part);
1666
+ }
1667
+ });
1668
+ return elements;
1669
+ };
1670
+ var CodeBlock = ({ language, code }) => {
1671
+ const [copied, setCopied] = React4.useState(false);
1672
+ const handleCopy = async () => {
1673
+ try {
1674
+ await navigator.clipboard.writeText(code);
1675
+ setCopied(true);
1676
+ setTimeout(() => setCopied(false), 2e3);
1677
+ } catch (e) {
1678
+ console.error("Failed to copy");
1679
+ }
1680
+ };
1681
+ return /* @__PURE__ */ jsxs5(
1682
+ "div",
1683
+ {
1684
+ style: {
1685
+ position: "relative",
1686
+ margin: "12px 0",
1687
+ borderRadius: "8px",
1688
+ overflow: "hidden",
1689
+ backgroundColor: "var(--chatllm-code-block-bg, #1f2937)"
1690
+ },
1691
+ children: [
1692
+ /* @__PURE__ */ jsxs5(
1693
+ "div",
1694
+ {
1695
+ style: {
1696
+ display: "flex",
1697
+ justifyContent: "space-between",
1698
+ alignItems: "center",
1699
+ padding: "8px 12px",
1700
+ backgroundColor: "var(--chatllm-code-block-header, #374151)",
1701
+ borderBottom: "1px solid var(--chatllm-code-block-border, #4b5563)"
1702
+ },
1703
+ children: [
1704
+ /* @__PURE__ */ jsx6(
1705
+ "span",
1706
+ {
1707
+ style: {
1708
+ fontSize: "12px",
1709
+ color: "var(--chatllm-code-block-lang, #9ca3af)",
1710
+ textTransform: "lowercase"
1711
+ },
1712
+ children: language || "code"
1713
+ }
1714
+ ),
1715
+ /* @__PURE__ */ jsx6(
1716
+ "button",
1717
+ {
1718
+ onClick: handleCopy,
1719
+ style: {
1720
+ padding: "4px 8px",
1721
+ fontSize: "12px",
1722
+ backgroundColor: "transparent",
1723
+ border: "1px solid var(--chatllm-code-block-border, #4b5563)",
1724
+ borderRadius: "4px",
1725
+ color: "var(--chatllm-code-block-text, #e5e7eb)",
1726
+ cursor: "pointer"
1727
+ },
1728
+ children: copied ? "\uBCF5\uC0AC\uB428!" : "\uBCF5\uC0AC"
1729
+ }
1730
+ )
1731
+ ]
1732
+ }
1733
+ ),
1734
+ /* @__PURE__ */ jsx6(
1735
+ "pre",
1736
+ {
1737
+ style: {
1738
+ margin: 0,
1739
+ padding: "16px",
1740
+ overflow: "auto",
1741
+ fontSize: "13px",
1742
+ lineHeight: "1.6",
1743
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
1744
+ color: "var(--chatllm-code-block-text, #e5e7eb)"
1745
+ },
1746
+ children: /* @__PURE__ */ jsx6("code", { children: code.trim() })
1747
+ }
1748
+ )
1749
+ ]
1750
+ }
1751
+ );
1752
+ };
1753
+ var SourceLinksSection = ({ links, label }) => {
1754
+ return /* @__PURE__ */ jsxs5(
1755
+ "div",
1756
+ {
1757
+ style: {
1758
+ display: "flex",
1759
+ flexWrap: "wrap",
1760
+ alignItems: "center",
1761
+ gap: "8px",
1762
+ margin: "12px 0",
1763
+ padding: "12px",
1764
+ backgroundColor: "var(--chatllm-source-bg, #f8fafc)",
1765
+ borderRadius: "8px",
1766
+ border: "1px solid var(--chatllm-border-light, #e2e8f0)"
1767
+ },
1768
+ children: [
1769
+ label && /* @__PURE__ */ jsx6(
1770
+ "span",
1771
+ {
1772
+ style: {
1773
+ fontSize: "13px",
1774
+ fontWeight: 500,
1775
+ color: "var(--chatllm-text-muted, #64748b)",
1776
+ marginRight: "4px"
1777
+ },
1778
+ children: label
1779
+ }
1780
+ ),
1781
+ links.map((link, index) => /* @__PURE__ */ jsx6(LinkChip, { text: link.text, url: link.url }, index))
1782
+ ]
1783
+ }
1784
+ );
1785
+ };
1786
+ var MarkdownRenderer = ({ content, className }) => {
1787
+ const rendered = useMemo(() => {
1788
+ const elements = [];
1789
+ let processedContent = content;
1790
+ const codeBlocks = [];
1791
+ processedContent = processedContent.replace(CODE_BLOCK_REGEX, (_, lang, code) => {
1792
+ codeBlocks.push({ language: lang || "", code });
1793
+ return `\xA7CODEBLOCK\xA7${codeBlocks.length - 1}\xA7/CODEBLOCK\xA7`;
1794
+ });
1795
+ const sourceSections = [];
1796
+ processedContent = processedContent.replace(SOURCE_LINKS_REGEX, (match, label, linksText) => {
1797
+ const links = parseSourceLinks(linksText);
1798
+ if (links.length > 0) {
1799
+ sourceSections.push({ label: label?.replace(/\*+/g, "").trim() || "\uCD9C\uCC98", links });
1800
+ return `\xA7SOURCES\xA7${sourceSections.length - 1}\xA7/SOURCES\xA7`;
1801
+ }
1802
+ return match;
1803
+ });
1804
+ const lines = processedContent.split("\n");
1805
+ let currentList = null;
1806
+ let blockquoteLines = [];
1807
+ const flushList = () => {
1808
+ if (currentList) {
1809
+ if (currentList.type === "ul") {
1810
+ elements.push(
1811
+ /* @__PURE__ */ jsx6("ul", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ul-${elements.length}`)
1812
+ );
1813
+ } else {
1814
+ elements.push(
1815
+ /* @__PURE__ */ jsx6("ol", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ol-${elements.length}`)
1816
+ );
1817
+ }
1818
+ currentList = null;
1819
+ }
1820
+ };
1821
+ const flushBlockquote = () => {
1822
+ if (blockquoteLines.length > 0) {
1823
+ elements.push(
1824
+ /* @__PURE__ */ jsx6(
1825
+ "blockquote",
1826
+ {
1827
+ style: {
1828
+ margin: "12px 0",
1829
+ padding: "12px 16px",
1830
+ borderLeft: "4px solid var(--chatllm-primary, #3b82f6)",
1831
+ backgroundColor: "var(--chatllm-bg-secondary, #f9fafb)",
1832
+ borderRadius: "0 8px 8px 0",
1833
+ color: "var(--chatllm-text, #374151)"
1834
+ },
1835
+ children: blockquoteLines.map((line, i) => /* @__PURE__ */ jsxs5(React4.Fragment, { children: [
1836
+ parseInlineElements(line, `bq-line-${i}`),
1837
+ i < blockquoteLines.length - 1 && /* @__PURE__ */ jsx6("br", {})
1838
+ ] }, i))
1839
+ },
1840
+ `bq-${elements.length}`
1841
+ )
1842
+ );
1843
+ blockquoteLines = [];
1844
+ }
1845
+ };
1846
+ lines.forEach((line, lineIndex) => {
1847
+ const codeBlockMatch = line.match(/§CODEBLOCK§(\d+)§\/CODEBLOCK§/);
1848
+ if (codeBlockMatch) {
1849
+ flushList();
1850
+ flushBlockquote();
1851
+ const index = parseInt(codeBlockMatch[1]);
1852
+ elements.push(
1853
+ /* @__PURE__ */ jsx6(CodeBlock, { ...codeBlocks[index] }, `codeblock-${lineIndex}`)
1854
+ );
1855
+ return;
1856
+ }
1857
+ const sourcesMatch = line.match(/§SOURCES§(\d+)§\/SOURCES§/);
1858
+ if (sourcesMatch) {
1859
+ flushList();
1860
+ flushBlockquote();
1861
+ const index = parseInt(sourcesMatch[1]);
1862
+ elements.push(
1863
+ /* @__PURE__ */ jsx6(SourceLinksSection, { ...sourceSections[index] }, `sources-${lineIndex}`)
1864
+ );
1865
+ return;
1866
+ }
1867
+ if (HR_REGEX.test(line)) {
1868
+ flushList();
1869
+ flushBlockquote();
1870
+ elements.push(
1871
+ /* @__PURE__ */ jsx6(
1872
+ "hr",
1873
+ {
1874
+ style: {
1875
+ margin: "16px 0",
1876
+ border: "none",
1877
+ borderTop: "1px solid var(--chatllm-border, #e5e7eb)"
1878
+ }
1879
+ },
1880
+ `hr-${lineIndex}`
1881
+ )
1882
+ );
1883
+ return;
1884
+ }
1885
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
1886
+ if (headingMatch) {
1887
+ flushList();
1888
+ flushBlockquote();
1889
+ const level = headingMatch[1].length;
1890
+ const text = headingMatch[2];
1891
+ const HeadingTag = `h${level}`;
1892
+ const sizes = {
1893
+ 1: "1.5em",
1894
+ 2: "1.3em",
1895
+ 3: "1.15em",
1896
+ 4: "1.05em",
1897
+ 5: "1em",
1898
+ 6: "0.95em"
1899
+ };
1900
+ elements.push(
1901
+ /* @__PURE__ */ jsx6(
1902
+ HeadingTag,
1903
+ {
1904
+ style: {
1905
+ fontSize: sizes[level],
1906
+ fontWeight: level <= 2 ? 600 : 500,
1907
+ margin: "16px 0 8px",
1908
+ color: "var(--chatllm-text, #1f2937)"
1909
+ },
1910
+ children: parseInlineElements(text, `heading-${lineIndex}`)
1911
+ },
1912
+ `heading-${lineIndex}`
1913
+ )
1914
+ );
1915
+ return;
1916
+ }
1917
+ const blockquoteMatch = line.match(/^>\s*(.*)$/);
1918
+ if (blockquoteMatch) {
1919
+ flushList();
1920
+ blockquoteLines.push(blockquoteMatch[1]);
1921
+ return;
1922
+ } else {
1923
+ flushBlockquote();
1924
+ }
1925
+ const ulMatch = line.match(/^[\-\*]\s+(.+)$/);
1926
+ if (ulMatch) {
1927
+ flushBlockquote();
1928
+ if (!currentList || currentList.type !== "ul") {
1929
+ flushList();
1930
+ currentList = { type: "ul", items: [] };
1931
+ }
1932
+ currentList.items.push(
1933
+ /* @__PURE__ */ jsx6("li", { style: { margin: "4px 0" }, children: parseInlineElements(ulMatch[1], `li-${lineIndex}`) }, `li-${lineIndex}`)
1934
+ );
1935
+ return;
1936
+ }
1937
+ const olMatch = line.match(/^(\d+)\.\s+(.+)$/);
1938
+ if (olMatch) {
1939
+ flushBlockquote();
1940
+ if (!currentList || currentList.type !== "ol") {
1941
+ flushList();
1942
+ currentList = { type: "ol", items: [] };
1943
+ }
1944
+ currentList.items.push(
1945
+ /* @__PURE__ */ jsx6("li", { style: { margin: "4px 0" }, children: parseInlineElements(olMatch[2], `li-${lineIndex}`) }, `li-${lineIndex}`)
1946
+ );
1947
+ return;
1948
+ }
1949
+ flushList();
1950
+ if (!line.trim()) {
1951
+ elements.push(/* @__PURE__ */ jsx6("br", {}, `br-${lineIndex}`));
1952
+ return;
1953
+ }
1954
+ elements.push(
1955
+ /* @__PURE__ */ jsx6("p", { style: { margin: "4px 0" }, children: parseInlineElements(line, `p-${lineIndex}`) }, `p-${lineIndex}`)
1956
+ );
1957
+ });
1958
+ flushList();
1959
+ flushBlockquote();
1960
+ return elements;
1961
+ }, [content]);
1962
+ return /* @__PURE__ */ jsx6(
1963
+ "div",
1964
+ {
1965
+ className: `chatllm-markdown ${className || ""}`,
1966
+ style: {
1967
+ fontSize: "15px",
1968
+ lineHeight: "1.7",
1969
+ color: "var(--chatllm-text, #374151)"
1970
+ },
1971
+ children: rendered
1972
+ }
1973
+ );
1974
+ };
1975
+
1976
+ // src/react/components/MessageBubble.tsx
1977
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1416
1978
  var MessageBubble = ({
1417
1979
  message,
1418
1980
  isLoading,
@@ -1426,7 +1988,7 @@ var MessageBubble = ({
1426
1988
  activeAlternativeIndex = 0,
1427
1989
  onAlternativeChange
1428
1990
  }) => {
1429
- const [showActions, setShowActions] = useState4(false);
1991
+ const [showActions, setShowActions] = useState5(false);
1430
1992
  const isUser = message.role === "user";
1431
1993
  const isAssistant = message.role === "assistant";
1432
1994
  const displayContent = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.content || message.content : message.content;
@@ -1438,7 +2000,7 @@ var MessageBubble = ({
1438
2000
  if (text && text.length > 0) {
1439
2001
  }
1440
2002
  };
1441
- return /* @__PURE__ */ jsxs4(
2003
+ return /* @__PURE__ */ jsxs6(
1442
2004
  "div",
1443
2005
  {
1444
2006
  className: `chatllm-message chatllm-message--${message.role}`,
@@ -1452,7 +2014,7 @@ var MessageBubble = ({
1452
2014
  onMouseLeave: () => setShowActions(false),
1453
2015
  onMouseUp: handleMouseUp,
1454
2016
  children: [
1455
- /* @__PURE__ */ jsx5(
2017
+ /* @__PURE__ */ jsx7(
1456
2018
  "div",
1457
2019
  {
1458
2020
  style: {
@@ -1465,7 +2027,7 @@ var MessageBubble = ({
1465
2027
  justifyContent: "center",
1466
2028
  flexShrink: 0
1467
2029
  },
1468
- children: /* @__PURE__ */ jsx5(
2030
+ children: /* @__PURE__ */ jsx7(
1469
2031
  IconSvg,
1470
2032
  {
1471
2033
  name: isUser ? "user-3-line" : "robot-line",
@@ -1475,8 +2037,8 @@ var MessageBubble = ({
1475
2037
  )
1476
2038
  }
1477
2039
  ),
1478
- /* @__PURE__ */ jsxs4("div", { style: { flex: 1, minWidth: 0 }, children: [
1479
- /* @__PURE__ */ jsxs4(
2040
+ /* @__PURE__ */ jsxs6("div", { style: { flex: 1, minWidth: 0 }, children: [
2041
+ /* @__PURE__ */ jsxs6(
1480
2042
  "div",
1481
2043
  {
1482
2044
  style: {
@@ -1486,7 +2048,7 @@ var MessageBubble = ({
1486
2048
  marginBottom: "8px"
1487
2049
  },
1488
2050
  children: [
1489
- /* @__PURE__ */ jsx5(
2051
+ /* @__PURE__ */ jsx7(
1490
2052
  "span",
1491
2053
  {
1492
2054
  style: {
@@ -1497,7 +2059,7 @@ var MessageBubble = ({
1497
2059
  children: isUser ? "\uB098" : "AI"
1498
2060
  }
1499
2061
  ),
1500
- displayModel && /* @__PURE__ */ jsx5(
2062
+ displayModel && /* @__PURE__ */ jsx7(
1501
2063
  "span",
1502
2064
  {
1503
2065
  style: {
@@ -1513,19 +2075,32 @@ var MessageBubble = ({
1513
2075
  ]
1514
2076
  }
1515
2077
  ),
1516
- /* @__PURE__ */ jsxs4(
2078
+ /* @__PURE__ */ jsxs6(
1517
2079
  "div",
1518
2080
  {
1519
2081
  style: {
1520
- fontSize: "15px",
1521
- lineHeight: "1.7",
1522
- color: "var(--chatllm-text, #374151)",
1523
- whiteSpace: "pre-wrap",
1524
2082
  wordBreak: "break-word"
1525
2083
  },
1526
2084
  children: [
1527
- displayContent,
1528
- isLoading && isAssistant && !displayContent && /* @__PURE__ */ jsxs4(
2085
+ isAssistant ? (
2086
+ // AI 메시지는 마크다운 렌더링
2087
+ /* @__PURE__ */ jsx7(MarkdownRenderer, { content: displayContent })
2088
+ ) : (
2089
+ // 사용자 메시지는 일반 텍스트
2090
+ /* @__PURE__ */ jsx7(
2091
+ "div",
2092
+ {
2093
+ style: {
2094
+ fontSize: "15px",
2095
+ lineHeight: "1.7",
2096
+ color: "var(--chatllm-text, #374151)",
2097
+ whiteSpace: "pre-wrap"
2098
+ },
2099
+ children: displayContent
2100
+ }
2101
+ )
2102
+ ),
2103
+ isLoading && isAssistant && !displayContent && /* @__PURE__ */ jsxs6(
1529
2104
  "span",
1530
2105
  {
1531
2106
  style: {
@@ -1533,16 +2108,16 @@ var MessageBubble = ({
1533
2108
  gap: "4px"
1534
2109
  },
1535
2110
  children: [
1536
- /* @__PURE__ */ jsx5("span", { className: "chatllm-typing-dot", style: dotStyle }),
1537
- /* @__PURE__ */ jsx5("span", { className: "chatllm-typing-dot", style: { ...dotStyle, animationDelay: "0.2s" } }),
1538
- /* @__PURE__ */ jsx5("span", { className: "chatllm-typing-dot", style: { ...dotStyle, animationDelay: "0.4s" } })
2111
+ /* @__PURE__ */ jsx7("span", { className: "chatllm-typing-dot", style: dotStyle }),
2112
+ /* @__PURE__ */ jsx7("span", { className: "chatllm-typing-dot", style: { ...dotStyle, animationDelay: "0.2s" } }),
2113
+ /* @__PURE__ */ jsx7("span", { className: "chatllm-typing-dot", style: { ...dotStyle, animationDelay: "0.4s" } })
1539
2114
  ]
1540
2115
  }
1541
2116
  )
1542
2117
  ]
1543
2118
  }
1544
2119
  ),
1545
- alternatives && alternatives.length > 0 && /* @__PURE__ */ jsxs4(
2120
+ alternatives && alternatives.length > 0 && /* @__PURE__ */ jsxs6(
1546
2121
  "div",
1547
2122
  {
1548
2123
  style: {
@@ -1554,7 +2129,7 @@ var MessageBubble = ({
1554
2129
  borderTop: "1px solid var(--chatllm-border-light, #f3f4f6)"
1555
2130
  },
1556
2131
  children: [
1557
- /* @__PURE__ */ jsx5(
2132
+ /* @__PURE__ */ jsx7(
1558
2133
  "button",
1559
2134
  {
1560
2135
  onClick: () => onAlternativeChange?.(Math.max(0, activeAlternativeIndex - 1)),
@@ -1564,15 +2139,15 @@ var MessageBubble = ({
1564
2139
  opacity: activeAlternativeIndex === 0 ? 0.5 : 1,
1565
2140
  cursor: activeAlternativeIndex === 0 ? "not-allowed" : "pointer"
1566
2141
  },
1567
- children: /* @__PURE__ */ jsx5(IconSvg, { name: "arrow-left-line", size: 14 })
2142
+ children: /* @__PURE__ */ jsx7(IconSvg, { name: "arrow-left-line", size: 14 })
1568
2143
  }
1569
2144
  ),
1570
- /* @__PURE__ */ jsxs4("span", { style: { fontSize: "12px", color: "var(--chatllm-text-muted, #9ca3af)" }, children: [
2145
+ /* @__PURE__ */ jsxs6("span", { style: { fontSize: "12px", color: "var(--chatllm-text-muted, #9ca3af)" }, children: [
1571
2146
  activeAlternativeIndex + 1,
1572
2147
  " / ",
1573
2148
  alternatives.length + 1
1574
2149
  ] }),
1575
- /* @__PURE__ */ jsx5(
2150
+ /* @__PURE__ */ jsx7(
1576
2151
  "button",
1577
2152
  {
1578
2153
  onClick: () => onAlternativeChange?.(Math.min(alternatives.length, activeAlternativeIndex + 1)),
@@ -1582,13 +2157,13 @@ var MessageBubble = ({
1582
2157
  opacity: activeAlternativeIndex === alternatives.length ? 0.5 : 1,
1583
2158
  cursor: activeAlternativeIndex === alternatives.length ? "not-allowed" : "pointer"
1584
2159
  },
1585
- children: /* @__PURE__ */ jsx5(IconSvg, { name: "arrow-right-line", size: 14 })
2160
+ children: /* @__PURE__ */ jsx7(IconSvg, { name: "arrow-right-line", size: 14 })
1586
2161
  }
1587
2162
  )
1588
2163
  ]
1589
2164
  }
1590
2165
  ),
1591
- showActions && !isLoading && /* @__PURE__ */ jsxs4(
2166
+ showActions && !isLoading && /* @__PURE__ */ jsxs6(
1592
2167
  "div",
1593
2168
  {
1594
2169
  style: {
@@ -1597,7 +2172,7 @@ var MessageBubble = ({
1597
2172
  marginTop: "12px"
1598
2173
  },
1599
2174
  children: [
1600
- /* @__PURE__ */ jsx5("button", { onClick: onCopy, style: actionButtonStyle, title: "\uBCF5\uC0AC", children: /* @__PURE__ */ jsx5(
2175
+ /* @__PURE__ */ jsx7("button", { onClick: onCopy, style: actionButtonStyle, title: "\uBCF5\uC0AC", children: /* @__PURE__ */ jsx7(
1601
2176
  IconSvg,
1602
2177
  {
1603
2178
  name: isCopied ? "check-line" : "file-copy-line",
@@ -1605,8 +2180,8 @@ var MessageBubble = ({
1605
2180
  color: isCopied ? "var(--chatllm-success, #22c55e)" : "var(--chatllm-text-muted, #9ca3af)"
1606
2181
  }
1607
2182
  ) }),
1608
- isUser && /* @__PURE__ */ jsx5("button", { onClick: onEdit, style: actionButtonStyle, title: "\uC218\uC815", children: /* @__PURE__ */ jsx5(IconSvg, { name: "edit-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
1609
- isAssistant && onRegenerate && /* @__PURE__ */ jsx5("button", { onClick: onRegenerate, style: actionButtonStyle, title: "\uB2E4\uC2DC \uC0DD\uC131", children: /* @__PURE__ */ jsx5(IconSvg, { name: "refresh-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) })
2183
+ isUser && /* @__PURE__ */ jsx7("button", { onClick: onEdit, style: actionButtonStyle, title: "\uC218\uC815", children: /* @__PURE__ */ jsx7(IconSvg, { name: "edit-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
2184
+ isAssistant && onRegenerate && /* @__PURE__ */ jsx7("button", { onClick: onRegenerate, style: actionButtonStyle, title: "\uB2E4\uC2DC \uC0DD\uC131", children: /* @__PURE__ */ jsx7(IconSvg, { name: "refresh-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) })
1610
2185
  ]
1611
2186
  }
1612
2187
  )
@@ -1645,7 +2220,7 @@ var navButtonStyle = {
1645
2220
  };
1646
2221
 
1647
2222
  // src/react/components/MessageList.tsx
1648
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
2223
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1649
2224
  var MessageList = ({
1650
2225
  messages,
1651
2226
  isLoading,
@@ -1658,8 +2233,8 @@ var MessageList = ({
1658
2233
  }) => {
1659
2234
  const messagesEndRef = useRef3(null);
1660
2235
  const containerRef = useRef3(null);
1661
- const [selectedText, setSelectedText] = useState5("");
1662
- const [selectionPosition, setSelectionPosition] = useState5(null);
2236
+ const [selectedText, setSelectedText] = useState6("");
2237
+ const [selectionPosition, setSelectionPosition] = useState6(null);
1663
2238
  useEffect3(() => {
1664
2239
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1665
2240
  }, [messages]);
@@ -1694,7 +2269,7 @@ var MessageList = ({
1694
2269
  window.getSelection()?.removeAllRanges();
1695
2270
  }
1696
2271
  };
1697
- return /* @__PURE__ */ jsxs5(
2272
+ return /* @__PURE__ */ jsxs7(
1698
2273
  "div",
1699
2274
  {
1700
2275
  ref: containerRef,
@@ -1706,7 +2281,7 @@ var MessageList = ({
1706
2281
  },
1707
2282
  onMouseUp: handleMouseUp,
1708
2283
  children: [
1709
- messages.map((message, index) => /* @__PURE__ */ jsx6(
2284
+ messages.map((message, index) => /* @__PURE__ */ jsx8(
1710
2285
  MessageBubble,
1711
2286
  {
1712
2287
  message,
@@ -1721,7 +2296,7 @@ var MessageList = ({
1721
2296
  },
1722
2297
  message.id
1723
2298
  )),
1724
- selectionPosition && /* @__PURE__ */ jsxs5(
2299
+ selectionPosition && /* @__PURE__ */ jsxs7(
1725
2300
  "div",
1726
2301
  {
1727
2302
  style: {
@@ -1732,7 +2307,7 @@ var MessageList = ({
1732
2307
  zIndex: 50
1733
2308
  },
1734
2309
  children: [
1735
- /* @__PURE__ */ jsxs5(
2310
+ /* @__PURE__ */ jsxs7(
1736
2311
  "button",
1737
2312
  {
1738
2313
  onClick: handleQuote,
@@ -1751,12 +2326,12 @@ var MessageList = ({
1751
2326
  boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)"
1752
2327
  },
1753
2328
  children: [
1754
- /* @__PURE__ */ jsx6(IconSvg, { name: "double-quotes-l", size: 14, color: "#ffffff" }),
2329
+ /* @__PURE__ */ jsx8(IconSvg, { name: "double-quotes-l", size: 14, color: "#ffffff" }),
1755
2330
  "\uC778\uC6A9\uD558\uAE30"
1756
2331
  ]
1757
2332
  }
1758
2333
  ),
1759
- /* @__PURE__ */ jsx6(
2334
+ /* @__PURE__ */ jsx8(
1760
2335
  "div",
1761
2336
  {
1762
2337
  style: {
@@ -1775,14 +2350,14 @@ var MessageList = ({
1775
2350
  ]
1776
2351
  }
1777
2352
  ),
1778
- /* @__PURE__ */ jsx6("div", { ref: messagesEndRef })
2353
+ /* @__PURE__ */ jsx8("div", { ref: messagesEndRef })
1779
2354
  ]
1780
2355
  }
1781
2356
  );
1782
2357
  };
1783
2358
 
1784
2359
  // src/react/components/EmptyState.tsx
1785
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
2360
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1786
2361
  var EmptyState = ({
1787
2362
  greeting,
1788
2363
  templates = [],
@@ -1799,7 +2374,7 @@ var EmptyState = ({
1799
2374
  };
1800
2375
  return iconMap[icon] || "sparkling-line";
1801
2376
  };
1802
- return /* @__PURE__ */ jsxs6(
2377
+ return /* @__PURE__ */ jsxs8(
1803
2378
  "div",
1804
2379
  {
1805
2380
  className: "chatllm-empty-state",
@@ -1813,7 +2388,7 @@ var EmptyState = ({
1813
2388
  textAlign: "center"
1814
2389
  },
1815
2390
  children: [
1816
- /* @__PURE__ */ jsx7(
2391
+ /* @__PURE__ */ jsx9(
1817
2392
  "div",
1818
2393
  {
1819
2394
  style: {
@@ -1827,10 +2402,10 @@ var EmptyState = ({
1827
2402
  marginBottom: "24px",
1828
2403
  boxShadow: "0 8px 32px rgba(59, 130, 246, 0.25)"
1829
2404
  },
1830
- children: /* @__PURE__ */ jsx7(IconSvg, { name: "sparkling-line", size: 32, color: "#ffffff" })
2405
+ children: /* @__PURE__ */ jsx9(IconSvg, { name: "sparkling-line", size: 32, color: "#ffffff" })
1831
2406
  }
1832
2407
  ),
1833
- /* @__PURE__ */ jsx7(
2408
+ /* @__PURE__ */ jsx9(
1834
2409
  "h1",
1835
2410
  {
1836
2411
  style: {
@@ -1842,7 +2417,7 @@ var EmptyState = ({
1842
2417
  children: greeting
1843
2418
  }
1844
2419
  ),
1845
- /* @__PURE__ */ jsx7(
2420
+ /* @__PURE__ */ jsx9(
1846
2421
  "p",
1847
2422
  {
1848
2423
  style: {
@@ -1853,7 +2428,7 @@ var EmptyState = ({
1853
2428
  children: "\uBB34\uC5C7\uC744 \uB3C4\uC640\uB4DC\uB9B4\uAE4C\uC694?"
1854
2429
  }
1855
2430
  ),
1856
- actions.length > 0 && /* @__PURE__ */ jsx7(
2431
+ actions.length > 0 && /* @__PURE__ */ jsx9(
1857
2432
  "div",
1858
2433
  {
1859
2434
  style: {
@@ -1864,7 +2439,7 @@ var EmptyState = ({
1864
2439
  maxWidth: "600px",
1865
2440
  marginBottom: "32px"
1866
2441
  },
1867
- children: actions.map((action) => /* @__PURE__ */ jsxs6(
2442
+ children: actions.map((action) => /* @__PURE__ */ jsxs8(
1868
2443
  "button",
1869
2444
  {
1870
2445
  onClick: () => onActionSelect?.(action),
@@ -1889,7 +2464,7 @@ var EmptyState = ({
1889
2464
  e.currentTarget.style.boxShadow = "none";
1890
2465
  },
1891
2466
  children: [
1892
- /* @__PURE__ */ jsx7(
2467
+ /* @__PURE__ */ jsx9(
1893
2468
  "div",
1894
2469
  {
1895
2470
  style: {
@@ -1901,7 +2476,7 @@ var EmptyState = ({
1901
2476
  alignItems: "center",
1902
2477
  justifyContent: "center"
1903
2478
  },
1904
- children: /* @__PURE__ */ jsx7(
2479
+ children: /* @__PURE__ */ jsx9(
1905
2480
  IconSvg,
1906
2481
  {
1907
2482
  name: getActionIcon(action.icon),
@@ -1911,7 +2486,7 @@ var EmptyState = ({
1911
2486
  )
1912
2487
  }
1913
2488
  ),
1914
- /* @__PURE__ */ jsx7("div", { children: /* @__PURE__ */ jsx7(
2489
+ /* @__PURE__ */ jsx9("div", { children: /* @__PURE__ */ jsx9(
1915
2490
  "div",
1916
2491
  {
1917
2492
  style: {
@@ -1928,8 +2503,8 @@ var EmptyState = ({
1928
2503
  ))
1929
2504
  }
1930
2505
  ),
1931
- templates.length > 0 && /* @__PURE__ */ jsxs6("div", { style: { width: "100%", maxWidth: "600px" }, children: [
1932
- /* @__PURE__ */ jsx7(
2506
+ templates.length > 0 && /* @__PURE__ */ jsxs8("div", { style: { width: "100%", maxWidth: "600px" }, children: [
2507
+ /* @__PURE__ */ jsx9(
1933
2508
  "h3",
1934
2509
  {
1935
2510
  style: {
@@ -1942,7 +2517,7 @@ var EmptyState = ({
1942
2517
  children: "\uCD94\uCC9C \uD504\uB86C\uD504\uD2B8"
1943
2518
  }
1944
2519
  ),
1945
- /* @__PURE__ */ jsx7(
2520
+ /* @__PURE__ */ jsx9(
1946
2521
  "div",
1947
2522
  {
1948
2523
  style: {
@@ -1950,7 +2525,7 @@ var EmptyState = ({
1950
2525
  flexDirection: "column",
1951
2526
  gap: "8px"
1952
2527
  },
1953
- children: templates.map((template) => /* @__PURE__ */ jsxs6(
2528
+ children: templates.map((template) => /* @__PURE__ */ jsxs8(
1954
2529
  "button",
1955
2530
  {
1956
2531
  onClick: () => onTemplateClick(template),
@@ -1973,7 +2548,7 @@ var EmptyState = ({
1973
2548
  e.currentTarget.style.backgroundColor = "var(--chatllm-bg, #ffffff)";
1974
2549
  },
1975
2550
  children: [
1976
- /* @__PURE__ */ jsx7(
2551
+ /* @__PURE__ */ jsx9(
1977
2552
  "div",
1978
2553
  {
1979
2554
  style: {
@@ -1986,11 +2561,11 @@ var EmptyState = ({
1986
2561
  justifyContent: "center",
1987
2562
  flexShrink: 0
1988
2563
  },
1989
- children: /* @__PURE__ */ jsx7(IconSvg, { name: "file-text-line", size: 18, color: "var(--chatllm-text-muted, #6b7280)" })
2564
+ children: /* @__PURE__ */ jsx9(IconSvg, { name: "file-text-line", size: 18, color: "var(--chatllm-text-muted, #6b7280)" })
1990
2565
  }
1991
2566
  ),
1992
- /* @__PURE__ */ jsxs6("div", { style: { flex: 1, minWidth: 0 }, children: [
1993
- /* @__PURE__ */ jsx7(
2567
+ /* @__PURE__ */ jsxs8("div", { style: { flex: 1, minWidth: 0 }, children: [
2568
+ /* @__PURE__ */ jsx9(
1994
2569
  "div",
1995
2570
  {
1996
2571
  style: {
@@ -2001,7 +2576,7 @@ var EmptyState = ({
2001
2576
  children: template.title
2002
2577
  }
2003
2578
  ),
2004
- /* @__PURE__ */ jsx7(
2579
+ /* @__PURE__ */ jsx9(
2005
2580
  "div",
2006
2581
  {
2007
2582
  style: {
@@ -2015,7 +2590,7 @@ var EmptyState = ({
2015
2590
  }
2016
2591
  )
2017
2592
  ] }),
2018
- /* @__PURE__ */ jsx7(IconSvg, { name: "arrow-right-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" })
2593
+ /* @__PURE__ */ jsx9(IconSvg, { name: "arrow-right-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" })
2019
2594
  ]
2020
2595
  },
2021
2596
  template.id
@@ -2029,8 +2604,8 @@ var EmptyState = ({
2029
2604
  };
2030
2605
 
2031
2606
  // src/react/components/MemoryPanel.tsx
2032
- import { useState as useState6 } from "react";
2033
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2607
+ import { useState as useState7 } from "react";
2608
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2034
2609
  var categoryLabels = {
2035
2610
  context: "\uB300\uD654 \uCEE8\uD14D\uC2A4\uD2B8",
2036
2611
  preference: "\uC0AC\uC6A9\uC790 \uC120\uD638",
@@ -2051,8 +2626,8 @@ var MemoryPanel = ({
2051
2626
  isOpen,
2052
2627
  onToggle
2053
2628
  }) => {
2054
- const [expandedId, setExpandedId] = useState6(null);
2055
- const [activeTab, setActiveTab] = useState6("all");
2629
+ const [expandedId, setExpandedId] = useState7(null);
2630
+ const [activeTab, setActiveTab] = useState7("all");
2056
2631
  const filteredItems = activeTab === "all" ? items : items.filter((item) => item.category === activeTab);
2057
2632
  const formatDate2 = (timestamp) => {
2058
2633
  const date = new Date(timestamp);
@@ -2064,7 +2639,7 @@ var MemoryPanel = ({
2064
2639
  });
2065
2640
  };
2066
2641
  if (!isOpen) {
2067
- return /* @__PURE__ */ jsx8(
2642
+ return /* @__PURE__ */ jsx10(
2068
2643
  "button",
2069
2644
  {
2070
2645
  onClick: onToggle,
@@ -2084,11 +2659,11 @@ var MemoryPanel = ({
2084
2659
  justifyContent: "center",
2085
2660
  zIndex: 100
2086
2661
  },
2087
- children: /* @__PURE__ */ jsx8(IconSvg, { name: "robot-line", size: 24, color: "#ffffff" })
2662
+ children: /* @__PURE__ */ jsx10(IconSvg, { name: "robot-line", size: 24, color: "#ffffff" })
2088
2663
  }
2089
2664
  );
2090
2665
  }
2091
- return /* @__PURE__ */ jsxs7(
2666
+ return /* @__PURE__ */ jsxs9(
2092
2667
  "div",
2093
2668
  {
2094
2669
  className: "chatllm-memory-panel",
@@ -2108,7 +2683,7 @@ var MemoryPanel = ({
2108
2683
  zIndex: 100
2109
2684
  },
2110
2685
  children: [
2111
- /* @__PURE__ */ jsxs7(
2686
+ /* @__PURE__ */ jsxs9(
2112
2687
  "div",
2113
2688
  {
2114
2689
  style: {
@@ -2119,8 +2694,8 @@ var MemoryPanel = ({
2119
2694
  borderBottom: "1px solid var(--chatllm-border, #e5e7eb)"
2120
2695
  },
2121
2696
  children: [
2122
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [
2123
- /* @__PURE__ */ jsx8(
2697
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [
2698
+ /* @__PURE__ */ jsx10(
2124
2699
  "div",
2125
2700
  {
2126
2701
  style: {
@@ -2132,19 +2707,19 @@ var MemoryPanel = ({
2132
2707
  alignItems: "center",
2133
2708
  justifyContent: "center"
2134
2709
  },
2135
- children: /* @__PURE__ */ jsx8(IconSvg, { name: "robot-line", size: 18, color: "var(--chatllm-primary, #3b82f6)" })
2710
+ children: /* @__PURE__ */ jsx10(IconSvg, { name: "robot-line", size: 18, color: "var(--chatllm-primary, #3b82f6)" })
2136
2711
  }
2137
2712
  ),
2138
- /* @__PURE__ */ jsxs7("div", { children: [
2139
- /* @__PURE__ */ jsx8("div", { style: { fontSize: "15px", fontWeight: 600, color: "var(--chatllm-text, #1f2937)" }, children: "AI \uBA54\uBAA8\uB9AC" }),
2140
- /* @__PURE__ */ jsxs7("div", { style: { fontSize: "12px", color: "var(--chatllm-text-muted, #9ca3af)" }, children: [
2713
+ /* @__PURE__ */ jsxs9("div", { children: [
2714
+ /* @__PURE__ */ jsx10("div", { style: { fontSize: "15px", fontWeight: 600, color: "var(--chatllm-text, #1f2937)" }, children: "AI \uBA54\uBAA8\uB9AC" }),
2715
+ /* @__PURE__ */ jsxs9("div", { style: { fontSize: "12px", color: "var(--chatllm-text-muted, #9ca3af)" }, children: [
2141
2716
  items.length,
2142
2717
  "\uAC1C \uD56D\uBAA9"
2143
2718
  ] })
2144
2719
  ] })
2145
2720
  ] }),
2146
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: "4px" }, children: [
2147
- onClearAll && items.length > 0 && /* @__PURE__ */ jsx8(
2721
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", gap: "4px" }, children: [
2722
+ onClearAll && items.length > 0 && /* @__PURE__ */ jsx10(
2148
2723
  "button",
2149
2724
  {
2150
2725
  onClick: onClearAll,
@@ -2156,10 +2731,10 @@ var MemoryPanel = ({
2156
2731
  cursor: "pointer"
2157
2732
  },
2158
2733
  title: "\uC804\uCCB4 \uC0AD\uC81C",
2159
- children: /* @__PURE__ */ jsx8(IconSvg, { name: "delete-bin-line", size: 18, color: "var(--chatllm-text-muted, #9ca3af)" })
2734
+ children: /* @__PURE__ */ jsx10(IconSvg, { name: "delete-bin-line", size: 18, color: "var(--chatllm-text-muted, #9ca3af)" })
2160
2735
  }
2161
2736
  ),
2162
- /* @__PURE__ */ jsx8(
2737
+ /* @__PURE__ */ jsx10(
2163
2738
  "button",
2164
2739
  {
2165
2740
  onClick: onToggle,
@@ -2170,14 +2745,14 @@ var MemoryPanel = ({
2170
2745
  borderRadius: "8px",
2171
2746
  cursor: "pointer"
2172
2747
  },
2173
- children: /* @__PURE__ */ jsx8(IconSvg, { name: "close-line", size: 18, color: "var(--chatllm-text-muted, #9ca3af)" })
2748
+ children: /* @__PURE__ */ jsx10(IconSvg, { name: "close-line", size: 18, color: "var(--chatllm-text-muted, #9ca3af)" })
2174
2749
  }
2175
2750
  )
2176
2751
  ] })
2177
2752
  ]
2178
2753
  }
2179
2754
  ),
2180
- /* @__PURE__ */ jsx8(
2755
+ /* @__PURE__ */ jsx10(
2181
2756
  "div",
2182
2757
  {
2183
2758
  style: {
@@ -2187,7 +2762,7 @@ var MemoryPanel = ({
2187
2762
  borderBottom: "1px solid var(--chatllm-border-light, #f3f4f6)",
2188
2763
  overflowX: "auto"
2189
2764
  },
2190
- children: ["all", "context", "preference", "skill", "fact"].map((tab) => /* @__PURE__ */ jsx8(
2765
+ children: ["all", "context", "preference", "skill", "fact"].map((tab) => /* @__PURE__ */ jsx10(
2191
2766
  "button",
2192
2767
  {
2193
2768
  onClick: () => setActiveTab(tab),
@@ -2208,8 +2783,8 @@ var MemoryPanel = ({
2208
2783
  ))
2209
2784
  }
2210
2785
  ),
2211
- /* @__PURE__ */ jsxs7("div", { style: { flex: 1, overflow: "auto", padding: "12px" }, children: [
2212
- contextSummary && activeTab === "all" && /* @__PURE__ */ jsxs7(
2786
+ /* @__PURE__ */ jsxs9("div", { style: { flex: 1, overflow: "auto", padding: "12px" }, children: [
2787
+ contextSummary && activeTab === "all" && /* @__PURE__ */ jsxs9(
2213
2788
  "div",
2214
2789
  {
2215
2790
  style: {
@@ -2220,7 +2795,7 @@ var MemoryPanel = ({
2220
2795
  borderLeft: "3px solid var(--chatllm-primary, #3b82f6)"
2221
2796
  },
2222
2797
  children: [
2223
- /* @__PURE__ */ jsxs7(
2798
+ /* @__PURE__ */ jsxs9(
2224
2799
  "div",
2225
2800
  {
2226
2801
  style: {
@@ -2230,12 +2805,12 @@ var MemoryPanel = ({
2230
2805
  marginBottom: "8px"
2231
2806
  },
2232
2807
  children: [
2233
- /* @__PURE__ */ jsx8(IconSvg, { name: "file-text-line", size: 14, color: "var(--chatllm-primary, #3b82f6)" }),
2234
- /* @__PURE__ */ jsx8("span", { style: { fontSize: "12px", fontWeight: 500, color: "var(--chatllm-primary, #3b82f6)" }, children: "\uB300\uD654 \uC694\uC57D" })
2808
+ /* @__PURE__ */ jsx10(IconSvg, { name: "file-text-line", size: 14, color: "var(--chatllm-primary, #3b82f6)" }),
2809
+ /* @__PURE__ */ jsx10("span", { style: { fontSize: "12px", fontWeight: 500, color: "var(--chatllm-primary, #3b82f6)" }, children: "\uB300\uD654 \uC694\uC57D" })
2235
2810
  ]
2236
2811
  }
2237
2812
  ),
2238
- /* @__PURE__ */ jsx8(
2813
+ /* @__PURE__ */ jsx10(
2239
2814
  "p",
2240
2815
  {
2241
2816
  style: {
@@ -2250,7 +2825,7 @@ var MemoryPanel = ({
2250
2825
  ]
2251
2826
  }
2252
2827
  ),
2253
- filteredItems.length === 0 ? /* @__PURE__ */ jsxs7(
2828
+ filteredItems.length === 0 ? /* @__PURE__ */ jsxs9(
2254
2829
  "div",
2255
2830
  {
2256
2831
  style: {
@@ -2259,11 +2834,11 @@ var MemoryPanel = ({
2259
2834
  color: "var(--chatllm-text-muted, #9ca3af)"
2260
2835
  },
2261
2836
  children: [
2262
- /* @__PURE__ */ jsx8(IconSvg, { name: "robot-line", size: 32, color: "var(--chatllm-text-muted, #d1d5db)" }),
2263
- /* @__PURE__ */ jsx8("p", { style: { fontSize: "14px", marginTop: "12px" }, children: "\uC800\uC7A5\uB41C \uBA54\uBAA8\uB9AC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" })
2837
+ /* @__PURE__ */ jsx10(IconSvg, { name: "robot-line", size: 32, color: "var(--chatllm-text-muted, #d1d5db)" }),
2838
+ /* @__PURE__ */ jsx10("p", { style: { fontSize: "14px", marginTop: "12px" }, children: "\uC800\uC7A5\uB41C \uBA54\uBAA8\uB9AC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" })
2264
2839
  ]
2265
2840
  }
2266
- ) : /* @__PURE__ */ jsx8("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: filteredItems.map((item) => /* @__PURE__ */ jsxs7(
2841
+ ) : /* @__PURE__ */ jsx10("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: filteredItems.map((item) => /* @__PURE__ */ jsxs9(
2267
2842
  "div",
2268
2843
  {
2269
2844
  style: {
@@ -2276,10 +2851,10 @@ var MemoryPanel = ({
2276
2851
  },
2277
2852
  onClick: () => setExpandedId(expandedId === item.id ? null : item.id),
2278
2853
  children: [
2279
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between" }, children: [
2280
- /* @__PURE__ */ jsxs7("div", { style: { flex: 1, minWidth: 0 }, children: [
2281
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "4px" }, children: [
2282
- item.category && /* @__PURE__ */ jsx8(
2854
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between" }, children: [
2855
+ /* @__PURE__ */ jsxs9("div", { style: { flex: 1, minWidth: 0 }, children: [
2856
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "4px" }, children: [
2857
+ item.category && /* @__PURE__ */ jsx10(
2283
2858
  "span",
2284
2859
  {
2285
2860
  style: {
@@ -2293,9 +2868,9 @@ var MemoryPanel = ({
2293
2868
  children: categoryLabels[item.category]
2294
2869
  }
2295
2870
  ),
2296
- /* @__PURE__ */ jsx8("span", { style: { fontSize: "11px", color: "var(--chatllm-text-muted, #9ca3af)" }, children: formatDate2(item.timestamp) })
2871
+ /* @__PURE__ */ jsx10("span", { style: { fontSize: "11px", color: "var(--chatllm-text-muted, #9ca3af)" }, children: formatDate2(item.timestamp) })
2297
2872
  ] }),
2298
- /* @__PURE__ */ jsx8(
2873
+ /* @__PURE__ */ jsx10(
2299
2874
  "div",
2300
2875
  {
2301
2876
  style: {
@@ -2307,8 +2882,8 @@ var MemoryPanel = ({
2307
2882
  }
2308
2883
  )
2309
2884
  ] }),
2310
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
2311
- onDelete && /* @__PURE__ */ jsx8(
2885
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
2886
+ onDelete && /* @__PURE__ */ jsx10(
2312
2887
  "button",
2313
2888
  {
2314
2889
  onClick: (e) => {
@@ -2323,10 +2898,10 @@ var MemoryPanel = ({
2323
2898
  cursor: "pointer",
2324
2899
  opacity: 0.5
2325
2900
  },
2326
- children: /* @__PURE__ */ jsx8(IconSvg, { name: "delete-bin-line", size: 14, color: "var(--chatllm-text-muted, #9ca3af)" })
2901
+ children: /* @__PURE__ */ jsx10(IconSvg, { name: "delete-bin-line", size: 14, color: "var(--chatllm-text-muted, #9ca3af)" })
2327
2902
  }
2328
2903
  ),
2329
- /* @__PURE__ */ jsx8(
2904
+ /* @__PURE__ */ jsx10(
2330
2905
  IconSvg,
2331
2906
  {
2332
2907
  name: expandedId === item.id ? "arrow-up-s-line" : "arrow-down-s-line",
@@ -2336,7 +2911,7 @@ var MemoryPanel = ({
2336
2911
  )
2337
2912
  ] })
2338
2913
  ] }),
2339
- expandedId === item.id && /* @__PURE__ */ jsx8(
2914
+ expandedId === item.id && /* @__PURE__ */ jsx10(
2340
2915
  "div",
2341
2916
  {
2342
2917
  style: {
@@ -2344,7 +2919,7 @@ var MemoryPanel = ({
2344
2919
  paddingTop: "12px",
2345
2920
  borderTop: "1px solid var(--chatllm-border-light, #f3f4f6)"
2346
2921
  },
2347
- children: /* @__PURE__ */ jsx8(
2922
+ children: /* @__PURE__ */ jsx10(
2348
2923
  "p",
2349
2924
  {
2350
2925
  style: {
@@ -2369,8 +2944,439 @@ var MemoryPanel = ({
2369
2944
  );
2370
2945
  };
2371
2946
 
2947
+ // src/react/components/SettingsModal.tsx
2948
+ import { useState as useState8 } from "react";
2949
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2950
+ var DEFAULT_PERSONALIZATION2 = {
2951
+ responseStyle: {
2952
+ warmth: "medium",
2953
+ enthusiasm: "medium",
2954
+ emojiUsage: "low",
2955
+ formatting: "default",
2956
+ verbosity: "balanced"
2957
+ },
2958
+ userProfile: {},
2959
+ useMemory: true,
2960
+ language: "auto"
2961
+ };
2962
+ var SettingsModal = ({
2963
+ isOpen,
2964
+ onClose,
2965
+ personalization,
2966
+ onPersonalizationChange,
2967
+ apiKey = "",
2968
+ onApiKeyChange,
2969
+ onClearAllData,
2970
+ apiKeyLabel = "API Key",
2971
+ apiKeyDescription = "Cloud \uBAA8\uB378 \uC0AC\uC6A9\uC5D0 \uD544\uC694\uD569\uB2C8\uB2E4"
2972
+ }) => {
2973
+ const [activeTab, setActiveTab] = useState8("general");
2974
+ const [localApiKey, setLocalApiKey] = useState8(apiKey);
2975
+ if (!isOpen) return null;
2976
+ const updateResponseStyle = (key, value) => {
2977
+ onPersonalizationChange({
2978
+ ...personalization,
2979
+ responseStyle: {
2980
+ ...personalization.responseStyle,
2981
+ [key]: value
2982
+ }
2983
+ });
2984
+ };
2985
+ const updateUserProfile = (key, value) => {
2986
+ onPersonalizationChange({
2987
+ ...personalization,
2988
+ userProfile: {
2989
+ ...personalization.userProfile,
2990
+ [key]: value
2991
+ }
2992
+ });
2993
+ };
2994
+ const handleApiKeyChange = (value) => {
2995
+ setLocalApiKey(value);
2996
+ onApiKeyChange?.(value);
2997
+ };
2998
+ return /* @__PURE__ */ jsx11(
2999
+ "div",
3000
+ {
3001
+ className: "chatllm-settings-overlay",
3002
+ style: {
3003
+ position: "fixed",
3004
+ inset: 0,
3005
+ backgroundColor: "rgba(0, 0, 0, 0.3)",
3006
+ display: "flex",
3007
+ alignItems: "center",
3008
+ justifyContent: "center",
3009
+ zIndex: 1e3
3010
+ },
3011
+ onClick: onClose,
3012
+ children: /* @__PURE__ */ jsxs10(
3013
+ "div",
3014
+ {
3015
+ className: "chatllm-settings-modal",
3016
+ style: {
3017
+ backgroundColor: "var(--chatllm-bg, #ffffff)",
3018
+ borderRadius: "16px",
3019
+ width: "100%",
3020
+ maxWidth: "800px",
3021
+ height: "80vh",
3022
+ maxHeight: "600px",
3023
+ margin: "16px",
3024
+ boxShadow: "0 20px 60px rgba(0, 0, 0, 0.15)",
3025
+ display: "flex",
3026
+ overflow: "hidden"
3027
+ },
3028
+ onClick: (e) => e.stopPropagation(),
3029
+ children: [
3030
+ /* @__PURE__ */ jsxs10(
3031
+ "div",
3032
+ {
3033
+ style: {
3034
+ width: "200px",
3035
+ backgroundColor: "var(--chatllm-bg-secondary, #f9fafb)",
3036
+ borderRight: "1px solid var(--chatllm-border, #e5e7eb)",
3037
+ display: "flex",
3038
+ flexDirection: "column"
3039
+ },
3040
+ children: [
3041
+ /* @__PURE__ */ jsx11("div", { style: { padding: "16px", borderBottom: "1px solid var(--chatllm-border, #e5e7eb)" }, children: /* @__PURE__ */ jsx11(
3042
+ "button",
3043
+ {
3044
+ onClick: onClose,
3045
+ style: {
3046
+ padding: "8px",
3047
+ backgroundColor: "transparent",
3048
+ border: "none",
3049
+ borderRadius: "8px",
3050
+ cursor: "pointer",
3051
+ display: "flex",
3052
+ alignItems: "center",
3053
+ justifyContent: "center"
3054
+ },
3055
+ children: /* @__PURE__ */ jsx11(IconSvg, { name: "close-line", size: 20, color: "var(--chatllm-text-muted, #6b7280)" })
3056
+ }
3057
+ ) }),
3058
+ /* @__PURE__ */ jsxs10("nav", { style: { flex: 1, padding: "8px" }, children: [
3059
+ /* @__PURE__ */ jsx11(
3060
+ TabButton,
3061
+ {
3062
+ active: activeTab === "general",
3063
+ onClick: () => setActiveTab("general"),
3064
+ icon: "settings-3-line",
3065
+ label: "\uC77C\uBC18"
3066
+ }
3067
+ ),
3068
+ /* @__PURE__ */ jsx11(
3069
+ TabButton,
3070
+ {
3071
+ active: activeTab === "personalization",
3072
+ onClick: () => setActiveTab("personalization"),
3073
+ icon: "user-3-line",
3074
+ label: "\uAC1C\uC778 \uB9DE\uCDA4 \uC124\uC815"
3075
+ }
3076
+ ),
3077
+ /* @__PURE__ */ jsx11(
3078
+ TabButton,
3079
+ {
3080
+ active: activeTab === "data",
3081
+ onClick: () => setActiveTab("data"),
3082
+ icon: "delete-bin-line",
3083
+ label: "\uB370\uC774\uD130 \uC81C\uC5B4"
3084
+ }
3085
+ )
3086
+ ] })
3087
+ ]
3088
+ }
3089
+ ),
3090
+ /* @__PURE__ */ jsxs10("div", { style: { flex: 1, overflow: "auto", padding: "24px" }, children: [
3091
+ activeTab === "general" && /* @__PURE__ */ jsxs10("div", { children: [
3092
+ /* @__PURE__ */ jsx11("h2", { style: { fontSize: "20px", fontWeight: 600, marginBottom: "24px", color: "var(--chatllm-text, #1f2937)" }, children: "\uC77C\uBC18" }),
3093
+ /* @__PURE__ */ jsx11(SettingRow, { label: "\uC5B8\uC5B4", children: /* @__PURE__ */ jsxs10(
3094
+ "select",
3095
+ {
3096
+ value: personalization.language,
3097
+ onChange: (e) => onPersonalizationChange({ ...personalization, language: e.target.value }),
3098
+ style: selectStyle,
3099
+ children: [
3100
+ /* @__PURE__ */ jsx11("option", { value: "auto", children: "\uC790\uB3D9 \uD0D0\uC9C0" }),
3101
+ /* @__PURE__ */ jsx11("option", { value: "ko", children: "\uD55C\uAD6D\uC5B4" }),
3102
+ /* @__PURE__ */ jsx11("option", { value: "en", children: "English" }),
3103
+ /* @__PURE__ */ jsx11("option", { value: "ja", children: "\u65E5\u672C\u8A9E" })
3104
+ ]
3105
+ }
3106
+ ) }),
3107
+ /* @__PURE__ */ jsx11(SettingRow, { label: "\uAE30\uBCF8\uAC12\uC73C\uB85C \uCD08\uAE30\uD654", description: "\uBAA8\uB4E0 \uC124\uC815\uC744 \uCD08\uAE30 \uC0C1\uD0DC\uB85C \uB418\uB3CC\uB9BD\uB2C8\uB2E4", children: /* @__PURE__ */ jsx11(
3108
+ "button",
3109
+ {
3110
+ onClick: () => onPersonalizationChange(DEFAULT_PERSONALIZATION2),
3111
+ style: buttonSecondaryStyle,
3112
+ children: "\uCD08\uAE30\uD654"
3113
+ }
3114
+ ) }),
3115
+ onApiKeyChange && /* @__PURE__ */ jsxs10("div", { style: { marginTop: "32px", paddingTop: "24px", borderTop: "1px solid var(--chatllm-border, #e5e7eb)" }, children: [
3116
+ /* @__PURE__ */ jsx11("h3", { style: { fontSize: "16px", fontWeight: 500, marginBottom: "16px", color: "var(--chatllm-text, #1f2937)" }, children: "API \uC124\uC815" }),
3117
+ /* @__PURE__ */ jsxs10("div", { children: [
3118
+ /* @__PURE__ */ jsx11("label", { style: { display: "block", fontSize: "14px", marginBottom: "8px", color: "var(--chatllm-text, #374151)" }, children: apiKeyLabel }),
3119
+ /* @__PURE__ */ jsx11(
3120
+ "input",
3121
+ {
3122
+ type: "password",
3123
+ value: localApiKey,
3124
+ onChange: (e) => handleApiKeyChange(e.target.value),
3125
+ placeholder: "API \uD0A4\uB97C \uC785\uB825\uD558\uC138\uC694",
3126
+ style: inputStyle
3127
+ }
3128
+ ),
3129
+ /* @__PURE__ */ jsx11("p", { style: { fontSize: "12px", color: "var(--chatllm-text-muted, #9ca3af)", marginTop: "4px" }, children: apiKeyDescription })
3130
+ ] })
3131
+ ] })
3132
+ ] }),
3133
+ activeTab === "personalization" && /* @__PURE__ */ jsxs10("div", { children: [
3134
+ /* @__PURE__ */ jsx11("h2", { style: { fontSize: "20px", fontWeight: 600, marginBottom: "24px", color: "var(--chatllm-text, #1f2937)" }, children: "\uAC1C\uC778 \uB9DE\uCDA4 \uC124\uC815" }),
3135
+ /* @__PURE__ */ jsxs10("section", { style: { marginBottom: "32px" }, children: [
3136
+ /* @__PURE__ */ jsx11("h3", { style: { fontSize: "14px", fontWeight: 500, color: "var(--chatllm-text-muted, #6b7280)", marginBottom: "16px" }, children: "\uC0AC\uC6A9\uC790 \uD504\uB85C\uD544" }),
3137
+ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
3138
+ /* @__PURE__ */ jsxs10("div", { children: [
3139
+ /* @__PURE__ */ jsx11("label", { style: labelStyle, children: "\uB2C9\uB124\uC784" }),
3140
+ /* @__PURE__ */ jsx11(
3141
+ "input",
3142
+ {
3143
+ type: "text",
3144
+ value: personalization.userProfile.nickname || "",
3145
+ onChange: (e) => updateUserProfile("nickname", e.target.value),
3146
+ placeholder: "\uC5B4\uB5BB\uAC8C \uBD88\uB7EC\uB4DC\uB9B4\uAE4C\uC694?",
3147
+ style: inputStyle
3148
+ }
3149
+ )
3150
+ ] }),
3151
+ /* @__PURE__ */ jsxs10("div", { children: [
3152
+ /* @__PURE__ */ jsx11("label", { style: labelStyle, children: "\uC9C1\uC5C5" }),
3153
+ /* @__PURE__ */ jsx11(
3154
+ "input",
3155
+ {
3156
+ type: "text",
3157
+ value: personalization.userProfile.occupation || "",
3158
+ onChange: (e) => updateUserProfile("occupation", e.target.value),
3159
+ placeholder: "\uC608: \uC18C\uD504\uD2B8\uC6E8\uC5B4 \uAC1C\uBC1C\uC790",
3160
+ style: inputStyle
3161
+ }
3162
+ )
3163
+ ] }),
3164
+ /* @__PURE__ */ jsxs10("div", { children: [
3165
+ /* @__PURE__ */ jsx11("label", { style: labelStyle, children: "\uCD94\uAC00 \uC815\uBCF4" }),
3166
+ /* @__PURE__ */ jsx11(
3167
+ "textarea",
3168
+ {
3169
+ value: personalization.userProfile.additionalInfo || "",
3170
+ onChange: (e) => updateUserProfile("additionalInfo", e.target.value),
3171
+ placeholder: "\uAD00\uC2EC\uC0AC, \uC120\uD638 \uC0AC\uD56D \uB4F1",
3172
+ rows: 3,
3173
+ style: { ...inputStyle, resize: "none" }
3174
+ }
3175
+ )
3176
+ ] })
3177
+ ] })
3178
+ ] }),
3179
+ /* @__PURE__ */ jsxs10("section", { children: [
3180
+ /* @__PURE__ */ jsx11("h3", { style: { fontSize: "14px", fontWeight: 500, color: "var(--chatllm-text-muted, #6b7280)", marginBottom: "16px" }, children: "\uC751\uB2F5 \uC2A4\uD0C0\uC77C" }),
3181
+ /* @__PURE__ */ jsx11(SettingRow, { label: "\uB530\uB73B\uD568", children: /* @__PURE__ */ jsxs10(
3182
+ "select",
3183
+ {
3184
+ value: personalization.responseStyle.warmth,
3185
+ onChange: (e) => updateResponseStyle("warmth", e.target.value),
3186
+ style: selectStyle,
3187
+ children: [
3188
+ /* @__PURE__ */ jsx11("option", { value: "high", children: "\uB192\uC74C - \uCE5C\uADFC\uD558\uACE0 \uB530\uB73B\uD558\uAC8C" }),
3189
+ /* @__PURE__ */ jsx11("option", { value: "medium", children: "\uAE30\uBCF8\uAC12" }),
3190
+ /* @__PURE__ */ jsx11("option", { value: "low", children: "\uB0AE\uC74C - \uAC04\uACB0\uD558\uACE0 \uC0AC\uBB34\uC801\uC73C\uB85C" })
3191
+ ]
3192
+ }
3193
+ ) }),
3194
+ /* @__PURE__ */ jsx11(SettingRow, { label: "\uC5F4\uC815\uC801", children: /* @__PURE__ */ jsxs10(
3195
+ "select",
3196
+ {
3197
+ value: personalization.responseStyle.enthusiasm,
3198
+ onChange: (e) => updateResponseStyle("enthusiasm", e.target.value),
3199
+ style: selectStyle,
3200
+ children: [
3201
+ /* @__PURE__ */ jsx11("option", { value: "high", children: "\uB192\uC74C - \uC801\uADF9\uC801\uC774\uACE0 \uD65C\uBC1C\uD558\uAC8C" }),
3202
+ /* @__PURE__ */ jsx11("option", { value: "medium", children: "\uAE30\uBCF8\uAC12" }),
3203
+ /* @__PURE__ */ jsx11("option", { value: "low", children: "\uB0AE\uC74C - \uCC28\uBD84\uD558\uACE0 \uC808\uC81C\uC788\uAC8C" })
3204
+ ]
3205
+ }
3206
+ ) }),
3207
+ /* @__PURE__ */ jsx11(SettingRow, { label: "\uC774\uBAA8\uC9C0 \uC0AC\uC6A9", children: /* @__PURE__ */ jsxs10(
3208
+ "select",
3209
+ {
3210
+ value: personalization.responseStyle.emojiUsage,
3211
+ onChange: (e) => updateResponseStyle("emojiUsage", e.target.value),
3212
+ style: selectStyle,
3213
+ children: [
3214
+ /* @__PURE__ */ jsx11("option", { value: "high", children: "\uB192\uC74C - \uC790\uC8FC \uC0AC\uC6A9" }),
3215
+ /* @__PURE__ */ jsx11("option", { value: "medium", children: "\uAE30\uBCF8\uAC12" }),
3216
+ /* @__PURE__ */ jsx11("option", { value: "low", children: "\uB0AE\uC74C - \uAC70\uC758 \uC0AC\uC6A9 \uC548 \uD568" })
3217
+ ]
3218
+ }
3219
+ ) }),
3220
+ /* @__PURE__ */ jsx11(SettingRow, { label: "\uC751\uB2F5 \uAE38\uC774", children: /* @__PURE__ */ jsxs10(
3221
+ "select",
3222
+ {
3223
+ value: personalization.responseStyle.verbosity,
3224
+ onChange: (e) => updateResponseStyle("verbosity", e.target.value),
3225
+ style: selectStyle,
3226
+ children: [
3227
+ /* @__PURE__ */ jsx11("option", { value: "detailed", children: "\uC0C1\uC138 - \uC790\uC138\uD558\uAC8C \uC124\uBA85" }),
3228
+ /* @__PURE__ */ jsx11("option", { value: "balanced", children: "\uAE30\uBCF8\uAC12" }),
3229
+ /* @__PURE__ */ jsx11("option", { value: "concise", children: "\uAC04\uACB0 - \uD575\uC2EC\uB9CC \uC694\uC57D" })
3230
+ ]
3231
+ }
3232
+ ) })
3233
+ ] })
3234
+ ] }),
3235
+ activeTab === "data" && /* @__PURE__ */ jsxs10("div", { children: [
3236
+ /* @__PURE__ */ jsx11("h2", { style: { fontSize: "20px", fontWeight: 600, marginBottom: "24px", color: "var(--chatllm-text, #1f2937)" }, children: "\uB370\uC774\uD130 \uC81C\uC5B4" }),
3237
+ /* @__PURE__ */ jsx11(SettingRow, { label: "\uBA54\uBAA8\uB9AC \uC0AC\uC6A9", description: "\uB300\uD654 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uAE30\uC5B5\uD569\uB2C8\uB2E4", children: /* @__PURE__ */ jsx11(
3238
+ "button",
3239
+ {
3240
+ onClick: () => onPersonalizationChange({ ...personalization, useMemory: !personalization.useMemory }),
3241
+ style: {
3242
+ width: "48px",
3243
+ height: "28px",
3244
+ borderRadius: "14px",
3245
+ backgroundColor: personalization.useMemory ? "var(--chatllm-primary, #3b82f6)" : "var(--chatllm-text-muted, #d1d5db)",
3246
+ border: "none",
3247
+ cursor: "pointer",
3248
+ position: "relative",
3249
+ transition: "background-color 0.2s"
3250
+ },
3251
+ children: /* @__PURE__ */ jsx11(
3252
+ "div",
3253
+ {
3254
+ style: {
3255
+ width: "22px",
3256
+ height: "22px",
3257
+ borderRadius: "50%",
3258
+ backgroundColor: "#ffffff",
3259
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)",
3260
+ position: "absolute",
3261
+ top: "3px",
3262
+ left: personalization.useMemory ? "23px" : "3px",
3263
+ transition: "left 0.2s"
3264
+ }
3265
+ }
3266
+ )
3267
+ }
3268
+ ) }),
3269
+ onClearAllData && /* @__PURE__ */ jsx11(SettingRow, { label: "\uB300\uD654 \uAE30\uB85D \uC0AD\uC81C", description: "\uBAA8\uB4E0 \uB300\uD654 \uAE30\uB85D\uC744 \uC0AD\uC81C\uD569\uB2C8\uB2E4", children: /* @__PURE__ */ jsx11(
3270
+ "button",
3271
+ {
3272
+ onClick: () => {
3273
+ if (window.confirm("\uBAA8\uB4E0 \uB300\uD654 \uAE30\uB85D\uC744 \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?")) {
3274
+ onClearAllData();
3275
+ }
3276
+ },
3277
+ style: buttonDangerStyle,
3278
+ children: "\uC0AD\uC81C"
3279
+ }
3280
+ ) })
3281
+ ] })
3282
+ ] })
3283
+ ]
3284
+ }
3285
+ )
3286
+ }
3287
+ );
3288
+ };
3289
+ var TabButton = ({ active, onClick, icon, label }) => /* @__PURE__ */ jsxs10(
3290
+ "button",
3291
+ {
3292
+ onClick,
3293
+ style: {
3294
+ width: "100%",
3295
+ display: "flex",
3296
+ alignItems: "center",
3297
+ gap: "12px",
3298
+ padding: "10px 12px",
3299
+ borderRadius: "10px",
3300
+ border: "none",
3301
+ backgroundColor: active ? "var(--chatllm-bg, #ffffff)" : "transparent",
3302
+ boxShadow: active ? "0 1px 3px rgba(0, 0, 0, 0.08)" : "none",
3303
+ color: active ? "var(--chatllm-primary, #3b82f6)" : "var(--chatllm-text-muted, #6b7280)",
3304
+ fontSize: "14px",
3305
+ cursor: "pointer",
3306
+ textAlign: "left",
3307
+ marginBottom: "4px"
3308
+ },
3309
+ children: [
3310
+ /* @__PURE__ */ jsx11(IconSvg, { name: icon, size: 20 }),
3311
+ label
3312
+ ]
3313
+ }
3314
+ );
3315
+ var SettingRow = ({ label, description, children }) => /* @__PURE__ */ jsxs10(
3316
+ "div",
3317
+ {
3318
+ style: {
3319
+ display: "flex",
3320
+ alignItems: "center",
3321
+ justifyContent: "space-between",
3322
+ padding: "12px 0",
3323
+ borderBottom: "1px solid var(--chatllm-border-light, #f3f4f6)"
3324
+ },
3325
+ children: [
3326
+ /* @__PURE__ */ jsxs10("div", { children: [
3327
+ /* @__PURE__ */ jsx11("span", { style: { fontSize: "14px", color: "var(--chatllm-text, #374151)" }, children: label }),
3328
+ description && /* @__PURE__ */ jsx11("p", { style: { fontSize: "12px", color: "var(--chatllm-text-muted, #9ca3af)", marginTop: "2px" }, children: description })
3329
+ ] }),
3330
+ children
3331
+ ]
3332
+ }
3333
+ );
3334
+ var selectStyle = {
3335
+ padding: "8px 12px",
3336
+ backgroundColor: "var(--chatllm-bg-secondary, #f9fafb)",
3337
+ border: "1px solid var(--chatllm-border, #e5e7eb)",
3338
+ borderRadius: "8px",
3339
+ fontSize: "14px",
3340
+ color: "var(--chatllm-text, #374151)",
3341
+ minWidth: "200px",
3342
+ cursor: "pointer"
3343
+ };
3344
+ var inputStyle = {
3345
+ width: "100%",
3346
+ padding: "10px 12px",
3347
+ backgroundColor: "var(--chatllm-bg-secondary, #f9fafb)",
3348
+ border: "1px solid var(--chatllm-border, #e5e7eb)",
3349
+ borderRadius: "8px",
3350
+ fontSize: "14px",
3351
+ color: "var(--chatllm-text, #374151)"
3352
+ };
3353
+ var labelStyle = {
3354
+ display: "block",
3355
+ fontSize: "12px",
3356
+ color: "var(--chatllm-text-muted, #6b7280)",
3357
+ marginBottom: "6px"
3358
+ };
3359
+ var buttonSecondaryStyle = {
3360
+ padding: "8px 16px",
3361
+ backgroundColor: "var(--chatllm-bg-secondary, #f3f4f6)",
3362
+ border: "none",
3363
+ borderRadius: "8px",
3364
+ fontSize: "14px",
3365
+ color: "var(--chatllm-text, #374151)",
3366
+ cursor: "pointer"
3367
+ };
3368
+ var buttonDangerStyle = {
3369
+ padding: "8px 16px",
3370
+ backgroundColor: "var(--chatllm-danger-bg, #fef2f2)",
3371
+ border: "none",
3372
+ borderRadius: "8px",
3373
+ fontSize: "14px",
3374
+ color: "var(--chatllm-danger, #dc2626)",
3375
+ cursor: "pointer"
3376
+ };
3377
+
2372
3378
  // src/react/ChatUI.tsx
2373
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3379
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2374
3380
  var DEFAULT_ACTIONS = [
2375
3381
  {
2376
3382
  id: "webSearch",
@@ -2525,6 +3531,7 @@ var ChatUI = ({
2525
3531
  templates = DEFAULT_TEMPLATES,
2526
3532
  personalization,
2527
3533
  apiKey,
3534
+ onApiKeyChange,
2528
3535
  apiEndpoint = "/api/chat",
2529
3536
  theme,
2530
3537
  showSidebar = true,
@@ -2539,7 +3546,7 @@ var ChatUI = ({
2539
3546
  onSessionChange,
2540
3547
  onError
2541
3548
  }) => {
2542
- React6.useEffect(() => {
3549
+ React9.useEffect(() => {
2543
3550
  injectStyles();
2544
3551
  }, []);
2545
3552
  const hookOptions = {
@@ -2600,8 +3607,8 @@ var ChatUI = ({
2600
3607
  const handleSubmit = () => {
2601
3608
  sendMessage();
2602
3609
  };
2603
- const [memoryPanelOpen, setMemoryPanelOpen] = useState7(false);
2604
- const memoryItems = React6.useMemo(() => {
3610
+ const [memoryPanelOpen, setMemoryPanelOpen] = useState9(false);
3611
+ const memoryItems = React9.useMemo(() => {
2605
3612
  const items = [];
2606
3613
  if (currentSession?.contextSummary) {
2607
3614
  items.push({
@@ -2642,7 +3649,7 @@ var ChatUI = ({
2642
3649
  return items;
2643
3650
  }, [currentSession, currentPersonalization]);
2644
3651
  const themeClass = theme?.mode === "dark" ? "chatllm-dark" : "";
2645
- return /* @__PURE__ */ jsxs8(
3652
+ return /* @__PURE__ */ jsxs11(
2646
3653
  "div",
2647
3654
  {
2648
3655
  className: `chatllm-root ${themeClass} ${className}`,
@@ -2653,7 +3660,7 @@ var ChatUI = ({
2653
3660
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'
2654
3661
  },
2655
3662
  children: [
2656
- showSidebar && /* @__PURE__ */ jsx9(
3663
+ showSidebar && /* @__PURE__ */ jsx12(
2657
3664
  ChatSidebar,
2658
3665
  {
2659
3666
  sessions,
@@ -2665,7 +3672,7 @@ var ChatUI = ({
2665
3672
  onToggle: toggleSidebar
2666
3673
  }
2667
3674
  ),
2668
- /* @__PURE__ */ jsxs8(
3675
+ /* @__PURE__ */ jsxs11(
2669
3676
  "main",
2670
3677
  {
2671
3678
  style: {
@@ -2676,7 +3683,7 @@ var ChatUI = ({
2676
3683
  minWidth: 0
2677
3684
  },
2678
3685
  children: [
2679
- /* @__PURE__ */ jsx9(
3686
+ /* @__PURE__ */ jsx12(
2680
3687
  ChatHeader,
2681
3688
  {
2682
3689
  title: currentSession?.title || "\uC0C8 \uB300\uD654",
@@ -2688,7 +3695,7 @@ var ChatUI = ({
2688
3695
  sidebarOpen
2689
3696
  }
2690
3697
  ),
2691
- messages.length === 0 ? /* @__PURE__ */ jsx9(
3698
+ messages.length === 0 ? /* @__PURE__ */ jsx12(
2692
3699
  EmptyState,
2693
3700
  {
2694
3701
  greeting,
@@ -2697,7 +3704,7 @@ var ChatUI = ({
2697
3704
  actions,
2698
3705
  onActionSelect: handleActionSelect
2699
3706
  }
2700
- ) : /* @__PURE__ */ jsx9(
3707
+ ) : /* @__PURE__ */ jsx12(
2701
3708
  MessageList,
2702
3709
  {
2703
3710
  messages,
@@ -2710,7 +3717,7 @@ var ChatUI = ({
2710
3717
  editingId: editingMessageId
2711
3718
  }
2712
3719
  ),
2713
- /* @__PURE__ */ jsx9(
3720
+ /* @__PURE__ */ jsx12(
2714
3721
  ChatInput,
2715
3722
  {
2716
3723
  value: input,
@@ -2730,7 +3737,7 @@ var ChatUI = ({
2730
3737
  ]
2731
3738
  }
2732
3739
  ),
2733
- /* @__PURE__ */ jsx9(
3740
+ /* @__PURE__ */ jsx12(
2734
3741
  MemoryPanel,
2735
3742
  {
2736
3743
  items: memoryItems,
@@ -2738,6 +3745,22 @@ var ChatUI = ({
2738
3745
  isOpen: memoryPanelOpen,
2739
3746
  onToggle: () => setMemoryPanelOpen(!memoryPanelOpen)
2740
3747
  }
3748
+ ),
3749
+ showSettings && /* @__PURE__ */ jsx12(
3750
+ SettingsModal,
3751
+ {
3752
+ isOpen: settingsOpen,
3753
+ onClose: closeSettings,
3754
+ personalization: currentPersonalization,
3755
+ onPersonalizationChange: updatePersonalization,
3756
+ apiKey,
3757
+ onApiKeyChange,
3758
+ onClearAllData: () => {
3759
+ sessions.forEach((s) => deleteSession(s.id));
3760
+ },
3761
+ apiKeyLabel: "API Key",
3762
+ apiKeyDescription: "Cloud \uBAA8\uB378 \uC0AC\uC6A9\uC5D0 \uD544\uC694\uD569\uB2C8\uB2E4"
3763
+ }
2741
3764
  )
2742
3765
  ]
2743
3766
  }
@@ -2751,9 +3774,12 @@ export {
2751
3774
  EmptyState,
2752
3775
  Icon,
2753
3776
  IconSvg,
3777
+ LinkChip,
3778
+ MarkdownRenderer,
2754
3779
  MemoryPanel,
2755
3780
  MessageBubble,
2756
3781
  MessageList,
3782
+ SettingsModal,
2757
3783
  useChatUI
2758
3784
  };
2759
3785
  //# sourceMappingURL=index.mjs.map