@gendive/chatllm 0.8.1 → 0.10.0
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.
- package/dist/react/index.d.mts +148 -0
- package/dist/react/index.d.ts +148 -0
- package/dist/react/index.js +325 -21
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +325 -21
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -568,7 +568,15 @@ var useChatUI = (options) => {
|
|
|
568
568
|
// Memory options
|
|
569
569
|
useGlobalMemoryEnabled = true,
|
|
570
570
|
globalMemoryConfig,
|
|
571
|
-
enableAutoExtraction = true
|
|
571
|
+
enableAutoExtraction = true,
|
|
572
|
+
// External storage options
|
|
573
|
+
useExternalStorage = false,
|
|
574
|
+
onLoadSessions,
|
|
575
|
+
onCreateSession,
|
|
576
|
+
onLoadSession,
|
|
577
|
+
onDeleteSession: onDeleteSessionCallback,
|
|
578
|
+
onUpdateSessionTitle,
|
|
579
|
+
onSaveMessages
|
|
572
580
|
} = options;
|
|
573
581
|
const [sessions, setSessions] = (0, import_react3.useState)([]);
|
|
574
582
|
const [currentSessionId, setCurrentSessionId] = (0, import_react3.useState)(null);
|
|
@@ -586,6 +594,8 @@ var useChatUI = (options) => {
|
|
|
586
594
|
...initialPersonalization
|
|
587
595
|
});
|
|
588
596
|
const [activeAlternatives, setActiveAlternatives] = (0, import_react3.useState)({});
|
|
597
|
+
const [isSessionsLoading, setIsSessionsLoading] = (0, import_react3.useState)(false);
|
|
598
|
+
const [isSessionLoading, setIsSessionLoading] = (0, import_react3.useState)(false);
|
|
589
599
|
const abortControllerRef = (0, import_react3.useRef)(null);
|
|
590
600
|
const memoryOptions = (0, import_react3.useMemo)(
|
|
591
601
|
() => ({
|
|
@@ -609,6 +619,36 @@ var useChatUI = (options) => {
|
|
|
609
619
|
const compressionState = currentSession?.compressionState || null;
|
|
610
620
|
(0, import_react3.useEffect)(() => {
|
|
611
621
|
if (typeof window === "undefined") return;
|
|
622
|
+
if (useExternalStorage && onLoadSessions) {
|
|
623
|
+
setIsSessionsLoading(true);
|
|
624
|
+
onLoadSessions().then((sessionList) => {
|
|
625
|
+
const sessionsWithoutMessages = sessionList.map((s) => ({
|
|
626
|
+
id: s.id,
|
|
627
|
+
title: s.title,
|
|
628
|
+
messages: [],
|
|
629
|
+
// 메시지는 세션 선택 시 로드
|
|
630
|
+
model: initialModel || models[0]?.id || "",
|
|
631
|
+
createdAt: Date.now(),
|
|
632
|
+
updatedAt: Date.now()
|
|
633
|
+
}));
|
|
634
|
+
setSessions(sessionsWithoutMessages);
|
|
635
|
+
if (sessionsWithoutMessages.length > 0) {
|
|
636
|
+
setCurrentSessionId(sessionsWithoutMessages[0].id);
|
|
637
|
+
}
|
|
638
|
+
}).catch((error) => {
|
|
639
|
+
onError?.(error instanceof Error ? error : new Error("Failed to load sessions"));
|
|
640
|
+
}).finally(() => {
|
|
641
|
+
setIsSessionsLoading(false);
|
|
642
|
+
});
|
|
643
|
+
const savedPersonalization2 = localStorage.getItem(`${storageKey}_personalization`);
|
|
644
|
+
if (savedPersonalization2) {
|
|
645
|
+
try {
|
|
646
|
+
setPersonalization(JSON.parse(savedPersonalization2));
|
|
647
|
+
} catch {
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
612
652
|
const saved = localStorage.getItem(storageKey);
|
|
613
653
|
if (saved) {
|
|
614
654
|
try {
|
|
@@ -628,13 +668,14 @@ var useChatUI = (options) => {
|
|
|
628
668
|
} catch {
|
|
629
669
|
}
|
|
630
670
|
}
|
|
631
|
-
}, [storageKey]);
|
|
671
|
+
}, [storageKey, useExternalStorage, onLoadSessions, initialModel, models, onError]);
|
|
632
672
|
(0, import_react3.useEffect)(() => {
|
|
633
673
|
if (typeof window === "undefined") return;
|
|
674
|
+
if (useExternalStorage) return;
|
|
634
675
|
if (sessions.length > 0) {
|
|
635
676
|
localStorage.setItem(storageKey, JSON.stringify(sessions));
|
|
636
677
|
}
|
|
637
|
-
}, [sessions, storageKey]);
|
|
678
|
+
}, [sessions, storageKey, useExternalStorage]);
|
|
638
679
|
(0, import_react3.useEffect)(() => {
|
|
639
680
|
if (typeof window === "undefined") return;
|
|
640
681
|
localStorage.setItem(`${storageKey}_personalization`, JSON.stringify(personalization));
|
|
@@ -787,7 +828,29 @@ ${newConversation}
|
|
|
787
828
|
const estimateTokens = (0, import_react3.useCallback)((messages2) => {
|
|
788
829
|
return messages2.reduce((sum, m) => sum + Math.ceil(m.content.length / 4), 0);
|
|
789
830
|
}, []);
|
|
790
|
-
const newSession = (0, import_react3.useCallback)(() => {
|
|
831
|
+
const newSession = (0, import_react3.useCallback)(async () => {
|
|
832
|
+
if (useExternalStorage && onCreateSession) {
|
|
833
|
+
setIsSessionLoading(true);
|
|
834
|
+
try {
|
|
835
|
+
const created = await onCreateSession();
|
|
836
|
+
const now2 = Date.now();
|
|
837
|
+
const newSess2 = {
|
|
838
|
+
id: created.id,
|
|
839
|
+
title: created.title,
|
|
840
|
+
messages: [],
|
|
841
|
+
model: selectedModel,
|
|
842
|
+
createdAt: now2,
|
|
843
|
+
updatedAt: now2
|
|
844
|
+
};
|
|
845
|
+
setSessions((prev) => [newSess2, ...prev]);
|
|
846
|
+
setCurrentSessionId(newSess2.id);
|
|
847
|
+
} catch (error) {
|
|
848
|
+
onError?.(error instanceof Error ? error : new Error("Failed to create session"));
|
|
849
|
+
} finally {
|
|
850
|
+
setIsSessionLoading(false);
|
|
851
|
+
}
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
791
854
|
const now = Date.now();
|
|
792
855
|
const newSess = {
|
|
793
856
|
id: generateId("session"),
|
|
@@ -799,15 +862,60 @@ ${newConversation}
|
|
|
799
862
|
};
|
|
800
863
|
setSessions((prev) => [newSess, ...prev]);
|
|
801
864
|
setCurrentSessionId(newSess.id);
|
|
802
|
-
}, [selectedModel]);
|
|
803
|
-
const selectSession = (0, import_react3.useCallback)((id) => {
|
|
865
|
+
}, [selectedModel, useExternalStorage, onCreateSession, onError]);
|
|
866
|
+
const selectSession = (0, import_react3.useCallback)(async (id) => {
|
|
867
|
+
if (useExternalStorage && onLoadSession) {
|
|
868
|
+
setIsSessionLoading(true);
|
|
869
|
+
try {
|
|
870
|
+
const sessionDetail = await onLoadSession(id);
|
|
871
|
+
const loadedMessages = sessionDetail.messages.map((m, idx) => ({
|
|
872
|
+
id: m.id || generateId("msg"),
|
|
873
|
+
role: typeof m.role === "string" ? m.role.toLowerCase() : m.role,
|
|
874
|
+
content: m.content,
|
|
875
|
+
timestamp: m.timestamp || Date.now() - (sessionDetail.messages.length - idx) * 1e3,
|
|
876
|
+
model: m.model,
|
|
877
|
+
alternatives: m.alternatives,
|
|
878
|
+
sources: m.sources
|
|
879
|
+
}));
|
|
880
|
+
setSessions(
|
|
881
|
+
(prev) => prev.map(
|
|
882
|
+
(s) => s.id === id ? { ...s, title: sessionDetail.title, messages: loadedMessages, updatedAt: Date.now() } : s
|
|
883
|
+
)
|
|
884
|
+
);
|
|
885
|
+
setCurrentSessionId(id);
|
|
886
|
+
const existingSession = sessions.find((s) => s.id === id);
|
|
887
|
+
if (existingSession) {
|
|
888
|
+
setSelectedModel(existingSession.model);
|
|
889
|
+
}
|
|
890
|
+
} catch (error) {
|
|
891
|
+
onError?.(error instanceof Error ? error : new Error("Failed to load session"));
|
|
892
|
+
} finally {
|
|
893
|
+
setIsSessionLoading(false);
|
|
894
|
+
}
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
804
897
|
const session = sessions.find((s) => s.id === id);
|
|
805
898
|
if (session) {
|
|
806
899
|
setCurrentSessionId(id);
|
|
807
900
|
setSelectedModel(session.model);
|
|
808
901
|
}
|
|
809
|
-
}, [sessions]);
|
|
810
|
-
const deleteSession = (0, import_react3.useCallback)((id) => {
|
|
902
|
+
}, [sessions, useExternalStorage, onLoadSession, onError]);
|
|
903
|
+
const deleteSession = (0, import_react3.useCallback)(async (id) => {
|
|
904
|
+
if (useExternalStorage && onDeleteSessionCallback) {
|
|
905
|
+
try {
|
|
906
|
+
await onDeleteSessionCallback(id);
|
|
907
|
+
setSessions((prev) => {
|
|
908
|
+
const filtered = prev.filter((s) => s.id !== id);
|
|
909
|
+
if (currentSessionId === id) {
|
|
910
|
+
setCurrentSessionId(filtered.length > 0 ? filtered[0].id : null);
|
|
911
|
+
}
|
|
912
|
+
return filtered;
|
|
913
|
+
});
|
|
914
|
+
} catch (error) {
|
|
915
|
+
onError?.(error instanceof Error ? error : new Error("Failed to delete session"));
|
|
916
|
+
}
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
811
919
|
setSessions((prev) => {
|
|
812
920
|
const filtered = prev.filter((s) => s.id !== id);
|
|
813
921
|
if (currentSessionId === id) {
|
|
@@ -818,16 +926,30 @@ ${newConversation}
|
|
|
818
926
|
}
|
|
819
927
|
return filtered;
|
|
820
928
|
});
|
|
821
|
-
}, [currentSessionId, storageKey]);
|
|
822
|
-
const renameSession = (0, import_react3.useCallback)((id, newTitle) => {
|
|
929
|
+
}, [currentSessionId, storageKey, useExternalStorage, onDeleteSessionCallback, onError]);
|
|
930
|
+
const renameSession = (0, import_react3.useCallback)(async (id, newTitle) => {
|
|
823
931
|
if (!newTitle.trim()) return;
|
|
932
|
+
if (useExternalStorage && onUpdateSessionTitle) {
|
|
933
|
+
try {
|
|
934
|
+
await onUpdateSessionTitle(id, newTitle.trim());
|
|
935
|
+
setSessions(
|
|
936
|
+
(prev) => prev.map(
|
|
937
|
+
(s) => s.id === id ? { ...s, title: newTitle.trim(), updatedAt: Date.now() } : s
|
|
938
|
+
)
|
|
939
|
+
);
|
|
940
|
+
onTitleChange?.(id, newTitle.trim());
|
|
941
|
+
} catch (error) {
|
|
942
|
+
onError?.(error instanceof Error ? error : new Error("Failed to update session title"));
|
|
943
|
+
}
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
824
946
|
setSessions(
|
|
825
947
|
(prev) => prev.map(
|
|
826
948
|
(s) => s.id === id ? { ...s, title: newTitle.trim(), updatedAt: Date.now() } : s
|
|
827
949
|
)
|
|
828
950
|
);
|
|
829
951
|
onTitleChange?.(id, newTitle.trim());
|
|
830
|
-
}, [onTitleChange]);
|
|
952
|
+
}, [onTitleChange, useExternalStorage, onUpdateSessionTitle, onError]);
|
|
831
953
|
const setModel = (0, import_react3.useCallback)((model) => {
|
|
832
954
|
setSelectedModel(model);
|
|
833
955
|
if (currentSessionId) {
|
|
@@ -1095,6 +1217,21 @@ ${contextSummary}` },
|
|
|
1095
1217
|
}
|
|
1096
1218
|
}
|
|
1097
1219
|
}
|
|
1220
|
+
if (useExternalStorage && onSaveMessages && capturedSessionId) {
|
|
1221
|
+
const updatedSession = sessions.find((s) => s.id === capturedSessionId);
|
|
1222
|
+
const assistantContent = updatedSession?.messages.find(
|
|
1223
|
+
(m) => m.id === assistantMessageId
|
|
1224
|
+
)?.content || "";
|
|
1225
|
+
if (assistantContent) {
|
|
1226
|
+
const messagesToSave = [
|
|
1227
|
+
{ role: "USER", message: finalContent },
|
|
1228
|
+
{ role: "ASSISTANT", message: assistantContent }
|
|
1229
|
+
];
|
|
1230
|
+
onSaveMessages(capturedSessionId, messagesToSave).catch((saveError) => {
|
|
1231
|
+
console.error("[useChatUI] Failed to save messages:", saveError);
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1098
1235
|
} catch (error) {
|
|
1099
1236
|
if (error instanceof Error && error.name === "AbortError") {
|
|
1100
1237
|
return;
|
|
@@ -1136,7 +1273,9 @@ ${contextSummary}` },
|
|
|
1136
1273
|
onSendMessage,
|
|
1137
1274
|
onError,
|
|
1138
1275
|
generateTitleCallback,
|
|
1139
|
-
onTitleChange
|
|
1276
|
+
onTitleChange,
|
|
1277
|
+
useExternalStorage,
|
|
1278
|
+
onSaveMessages
|
|
1140
1279
|
]);
|
|
1141
1280
|
const saveEdit = (0, import_react3.useCallback)(async (content) => {
|
|
1142
1281
|
if (!editingMessageId || !currentSession || !currentSessionId) return;
|
|
@@ -1389,7 +1528,18 @@ ${currentSession.contextSummary}` },
|
|
|
1389
1528
|
content: m.content
|
|
1390
1529
|
}));
|
|
1391
1530
|
await infoExtraction.extractInfo(recentMessages);
|
|
1392
|
-
}
|
|
1531
|
+
},
|
|
1532
|
+
// External Storage Loading States
|
|
1533
|
+
/**
|
|
1534
|
+
* @description 세션 목록 로딩 상태
|
|
1535
|
+
* @Todo vibecode - 외부 스토리지 사용 시
|
|
1536
|
+
*/
|
|
1537
|
+
isSessionsLoading,
|
|
1538
|
+
/**
|
|
1539
|
+
* @description 단일 세션 로딩 상태
|
|
1540
|
+
* @Todo vibecode - 외부 스토리지 사용 시
|
|
1541
|
+
*/
|
|
1542
|
+
isSessionLoading
|
|
1393
1543
|
};
|
|
1394
1544
|
};
|
|
1395
1545
|
|
|
@@ -2547,6 +2697,9 @@ var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((?:(?<!!)\[`?[^\]]+`?\]\(
|
|
|
2547
2697
|
var INLINE_CHOICE_PATTERN = /\[(\d+)\]\s*([^\[\n]+?)(?=\s*\[\d+\]|$)/g;
|
|
2548
2698
|
var INLINE_CHOICE_LINE_PATTERN = /^(.+?)?\s*(\[\d+\][^\[]+(?:\[\d+\][^\[]+)+)$/;
|
|
2549
2699
|
var CODE_BLOCK_REGEX = /```(\w*)\n?([\s\S]*?)```/g;
|
|
2700
|
+
var THINKING_TAG_REGEX = /<thinking>([\s\S]*?)<\/thinking>/gi;
|
|
2701
|
+
var THINKING_CODEBLOCK_REGEX = /```thinking\n?([\s\S]*?)```/gi;
|
|
2702
|
+
var THINKING_TEXT_REGEX = /^Thinking:\s*\n([\s\S]*?)(?=\n\n|$)/gim;
|
|
2550
2703
|
var INLINE_CODE_REGEX = /`([^`]+)`/g;
|
|
2551
2704
|
var BOLD_REGEX = /\*\*([^*]+)\*\*/g;
|
|
2552
2705
|
var ITALIC_REGEX = /(?<!\*)\*([^*]+)\*(?!\*)/g;
|
|
@@ -2724,6 +2877,80 @@ var MarkdownTable = ({ data }) => {
|
|
|
2724
2877
|
}
|
|
2725
2878
|
);
|
|
2726
2879
|
};
|
|
2880
|
+
var ThinkingBlock = ({ content, defaultOpen = false }) => {
|
|
2881
|
+
const [isOpen, setIsOpen] = import_react8.default.useState(defaultOpen);
|
|
2882
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2883
|
+
"details",
|
|
2884
|
+
{
|
|
2885
|
+
open: isOpen,
|
|
2886
|
+
className: "chatllm-thinking",
|
|
2887
|
+
style: {
|
|
2888
|
+
margin: "12px 0",
|
|
2889
|
+
borderRadius: "8px",
|
|
2890
|
+
border: "1px solid var(--chatllm-border, #e5e7eb)",
|
|
2891
|
+
background: "var(--chatllm-bg-secondary, #f9fafb)",
|
|
2892
|
+
overflow: "hidden"
|
|
2893
|
+
},
|
|
2894
|
+
children: [
|
|
2895
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2896
|
+
"summary",
|
|
2897
|
+
{
|
|
2898
|
+
onClick: (e) => {
|
|
2899
|
+
e.preventDefault();
|
|
2900
|
+
setIsOpen(!isOpen);
|
|
2901
|
+
},
|
|
2902
|
+
style: {
|
|
2903
|
+
padding: "10px 14px",
|
|
2904
|
+
cursor: "pointer",
|
|
2905
|
+
fontSize: "13px",
|
|
2906
|
+
color: "var(--chatllm-text-secondary, #6b7280)",
|
|
2907
|
+
userSelect: "none",
|
|
2908
|
+
listStyle: "none",
|
|
2909
|
+
display: "flex",
|
|
2910
|
+
alignItems: "center",
|
|
2911
|
+
gap: "6px"
|
|
2912
|
+
},
|
|
2913
|
+
children: [
|
|
2914
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: "14px" }, children: "\u{1F4AD}" }),
|
|
2915
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
2916
|
+
"Thinking",
|
|
2917
|
+
isOpen ? "" : "..."
|
|
2918
|
+
] }),
|
|
2919
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2920
|
+
"span",
|
|
2921
|
+
{
|
|
2922
|
+
style: {
|
|
2923
|
+
marginLeft: "auto",
|
|
2924
|
+
fontSize: "10px",
|
|
2925
|
+
transition: "transform 0.2s",
|
|
2926
|
+
transform: isOpen ? "rotate(180deg)" : "rotate(0deg)"
|
|
2927
|
+
},
|
|
2928
|
+
children: "\u25BC"
|
|
2929
|
+
}
|
|
2930
|
+
)
|
|
2931
|
+
]
|
|
2932
|
+
}
|
|
2933
|
+
),
|
|
2934
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2935
|
+
"div",
|
|
2936
|
+
{
|
|
2937
|
+
className: "chatllm-thinking-content",
|
|
2938
|
+
style: {
|
|
2939
|
+
padding: "12px 14px",
|
|
2940
|
+
borderTop: "1px solid var(--chatllm-border, #e5e7eb)",
|
|
2941
|
+
fontSize: "13px",
|
|
2942
|
+
color: "var(--chatllm-text-secondary, #6b7280)",
|
|
2943
|
+
whiteSpace: "pre-wrap",
|
|
2944
|
+
lineHeight: "1.6",
|
|
2945
|
+
background: "var(--chatllm-bg, #ffffff)"
|
|
2946
|
+
},
|
|
2947
|
+
children: content.trim()
|
|
2948
|
+
}
|
|
2949
|
+
)
|
|
2950
|
+
]
|
|
2951
|
+
}
|
|
2952
|
+
);
|
|
2953
|
+
};
|
|
2727
2954
|
var CodeBlock = ({ language, code }) => {
|
|
2728
2955
|
const [copied, setCopied] = import_react8.default.useState(false);
|
|
2729
2956
|
const handleCopy = async () => {
|
|
@@ -3148,10 +3375,35 @@ var SourceLinksSection = ({ links, label }) => {
|
|
|
3148
3375
|
}
|
|
3149
3376
|
);
|
|
3150
3377
|
};
|
|
3151
|
-
var MarkdownRenderer = ({
|
|
3378
|
+
var MarkdownRenderer = ({
|
|
3379
|
+
content,
|
|
3380
|
+
className,
|
|
3381
|
+
onChoiceClick,
|
|
3382
|
+
showThinking = true,
|
|
3383
|
+
thinkingDefaultOpen = false
|
|
3384
|
+
}) => {
|
|
3152
3385
|
const rendered = (0, import_react8.useMemo)(() => {
|
|
3153
3386
|
const elements = [];
|
|
3154
3387
|
let processedContent = content;
|
|
3388
|
+
const thinkingBlocks = [];
|
|
3389
|
+
if (showThinking) {
|
|
3390
|
+
processedContent = processedContent.replace(THINKING_TAG_REGEX, (_, thinkContent) => {
|
|
3391
|
+
thinkingBlocks.push(thinkContent);
|
|
3392
|
+
return `\xA7THINKING\xA7${thinkingBlocks.length - 1}\xA7/THINKING\xA7`;
|
|
3393
|
+
});
|
|
3394
|
+
processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, (_, thinkContent) => {
|
|
3395
|
+
thinkingBlocks.push(thinkContent);
|
|
3396
|
+
return `\xA7THINKING\xA7${thinkingBlocks.length - 1}\xA7/THINKING\xA7`;
|
|
3397
|
+
});
|
|
3398
|
+
processedContent = processedContent.replace(THINKING_TEXT_REGEX, (_, thinkContent) => {
|
|
3399
|
+
thinkingBlocks.push(thinkContent);
|
|
3400
|
+
return `\xA7THINKING\xA7${thinkingBlocks.length - 1}\xA7/THINKING\xA7`;
|
|
3401
|
+
});
|
|
3402
|
+
} else {
|
|
3403
|
+
processedContent = processedContent.replace(THINKING_TAG_REGEX, "");
|
|
3404
|
+
processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, "");
|
|
3405
|
+
processedContent = processedContent.replace(THINKING_TEXT_REGEX, "");
|
|
3406
|
+
}
|
|
3155
3407
|
const codeBlocks = [];
|
|
3156
3408
|
processedContent = processedContent.replace(CODE_BLOCK_REGEX, (_, lang, code) => {
|
|
3157
3409
|
codeBlocks.push({ language: lang || "", code });
|
|
@@ -3259,6 +3511,23 @@ var MarkdownRenderer = ({ content, className, onChoiceClick }) => {
|
|
|
3259
3511
|
}
|
|
3260
3512
|
};
|
|
3261
3513
|
lines.forEach((line, lineIndex) => {
|
|
3514
|
+
const thinkingMatch = line.match(/§THINKING§(\d+)§\/THINKING§/);
|
|
3515
|
+
if (thinkingMatch) {
|
|
3516
|
+
flushList();
|
|
3517
|
+
flushBlockquote();
|
|
3518
|
+
const index = parseInt(thinkingMatch[1]);
|
|
3519
|
+
elements.push(
|
|
3520
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3521
|
+
ThinkingBlock,
|
|
3522
|
+
{
|
|
3523
|
+
content: thinkingBlocks[index],
|
|
3524
|
+
defaultOpen: thinkingDefaultOpen
|
|
3525
|
+
},
|
|
3526
|
+
`thinking-${lineIndex}`
|
|
3527
|
+
)
|
|
3528
|
+
);
|
|
3529
|
+
return;
|
|
3530
|
+
}
|
|
3262
3531
|
const codeBlockMatch = line.match(/§CODEBLOCK§(\d+)§\/CODEBLOCK§/);
|
|
3263
3532
|
if (codeBlockMatch) {
|
|
3264
3533
|
flushList();
|
|
@@ -3447,7 +3716,9 @@ var MessageBubble = ({
|
|
|
3447
3716
|
activeAlternativeIndex = 0,
|
|
3448
3717
|
onAlternativeChange,
|
|
3449
3718
|
nextAssistantMessage,
|
|
3450
|
-
onChoiceClick
|
|
3719
|
+
onChoiceClick,
|
|
3720
|
+
showThinking = true,
|
|
3721
|
+
thinkingDefaultOpen = false
|
|
3451
3722
|
}) => {
|
|
3452
3723
|
const [showActions, setShowActions] = (0, import_react9.useState)(false);
|
|
3453
3724
|
const [showModelMenu, setShowModelMenu] = (0, import_react9.useState)(false);
|
|
@@ -3551,7 +3822,15 @@ var MessageBubble = ({
|
|
|
3551
3822
|
children: [
|
|
3552
3823
|
isAssistant ? (
|
|
3553
3824
|
// AI 메시지는 마크다운 렌더링
|
|
3554
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3825
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3826
|
+
MarkdownRenderer,
|
|
3827
|
+
{
|
|
3828
|
+
content: displayContent,
|
|
3829
|
+
onChoiceClick,
|
|
3830
|
+
showThinking,
|
|
3831
|
+
thinkingDefaultOpen
|
|
3832
|
+
}
|
|
3833
|
+
)
|
|
3555
3834
|
) : (
|
|
3556
3835
|
// 사용자 메시지는 일반 텍스트
|
|
3557
3836
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -3841,7 +4120,9 @@ var MessageList = ({
|
|
|
3841
4120
|
models,
|
|
3842
4121
|
copiedId,
|
|
3843
4122
|
editingId,
|
|
3844
|
-
onChoiceClick
|
|
4123
|
+
onChoiceClick,
|
|
4124
|
+
showThinking = true,
|
|
4125
|
+
thinkingDefaultOpen = false
|
|
3845
4126
|
}) => {
|
|
3846
4127
|
const messagesEndRef = (0, import_react10.useRef)(null);
|
|
3847
4128
|
const containerRef = (0, import_react10.useRef)(null);
|
|
@@ -3914,7 +4195,9 @@ var MessageList = ({
|
|
|
3914
4195
|
onAlternativeChange: message.role === "user" && assistantForAlts && onSetActiveAlternative ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx) : message.role === "assistant" && onSetActiveAlternative ? (idx) => onSetActiveAlternative(message.id, idx) : void 0,
|
|
3915
4196
|
models,
|
|
3916
4197
|
alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives,
|
|
3917
|
-
onChoiceClick: message.role === "assistant" ? onChoiceClick : void 0
|
|
4198
|
+
onChoiceClick: message.role === "assistant" ? onChoiceClick : void 0,
|
|
4199
|
+
showThinking,
|
|
4200
|
+
thinkingDefaultOpen
|
|
3918
4201
|
},
|
|
3919
4202
|
message.id
|
|
3920
4203
|
);
|
|
@@ -5202,7 +5485,18 @@ var ChatUI = ({
|
|
|
5202
5485
|
onSessionChange,
|
|
5203
5486
|
onError,
|
|
5204
5487
|
onTitleChange,
|
|
5205
|
-
generateTitle: generateTitle2
|
|
5488
|
+
generateTitle: generateTitle2,
|
|
5489
|
+
// External Storage Props
|
|
5490
|
+
useExternalStorage = false,
|
|
5491
|
+
onLoadSessions,
|
|
5492
|
+
onCreateSession,
|
|
5493
|
+
onLoadSession,
|
|
5494
|
+
onDeleteSession,
|
|
5495
|
+
onUpdateSessionTitle,
|
|
5496
|
+
onSaveMessages,
|
|
5497
|
+
// Thinking Block Props
|
|
5498
|
+
showThinking = true,
|
|
5499
|
+
thinkingDefaultOpen = false
|
|
5206
5500
|
}) => {
|
|
5207
5501
|
import_react13.default.useEffect(() => {
|
|
5208
5502
|
injectStyles();
|
|
@@ -5221,7 +5515,15 @@ var ChatUI = ({
|
|
|
5221
5515
|
onSessionChange,
|
|
5222
5516
|
onError,
|
|
5223
5517
|
onTitleChange,
|
|
5224
|
-
generateTitle: generateTitle2
|
|
5518
|
+
generateTitle: generateTitle2,
|
|
5519
|
+
// External Storage Options
|
|
5520
|
+
useExternalStorage,
|
|
5521
|
+
onLoadSessions,
|
|
5522
|
+
onCreateSession,
|
|
5523
|
+
onLoadSession,
|
|
5524
|
+
onDeleteSession,
|
|
5525
|
+
onUpdateSessionTitle,
|
|
5526
|
+
onSaveMessages
|
|
5225
5527
|
};
|
|
5226
5528
|
const {
|
|
5227
5529
|
sessions,
|
|
@@ -5390,7 +5692,9 @@ var ChatUI = ({
|
|
|
5390
5692
|
models: hookModels,
|
|
5391
5693
|
copiedId: copiedMessageId,
|
|
5392
5694
|
editingId: editingMessageId,
|
|
5393
|
-
onChoiceClick: handleChoiceClick
|
|
5695
|
+
onChoiceClick: handleChoiceClick,
|
|
5696
|
+
showThinking,
|
|
5697
|
+
thinkingDefaultOpen
|
|
5394
5698
|
}
|
|
5395
5699
|
),
|
|
5396
5700
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|