@gendive/chatllm 0.12.1 → 0.12.3

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.
@@ -1154,6 +1154,37 @@ var formatPollResponse = (question, selectedOptions, otherText) => {
1154
1154
  return `${selectedLabels.join(", ")}\uC744(\uB97C) \uC120\uD0DD\uD588\uC2B5\uB2C8\uB2E4. \uC774 \uC120\uD0DD\uC744 \uBC14\uD0D5\uC73C\uB85C \uC9C4\uD589\uD574\uC8FC\uC138\uC694.`;
1155
1155
  };
1156
1156
 
1157
+ // src/react/utils/sessionCache.ts
1158
+ var buildCacheKey = (storageKey, sessionId) => `${storageKey}_cache_${sessionId}`;
1159
+ var writeSessionCache = (storageKey, session) => {
1160
+ if (typeof window === "undefined") return;
1161
+ try {
1162
+ const key = buildCacheKey(storageKey, session.id);
1163
+ localStorage.setItem(key, JSON.stringify(session));
1164
+ } catch (error) {
1165
+ console.warn("[sessionCache] Failed to write cache:", error);
1166
+ }
1167
+ };
1168
+ var readSessionCache = (storageKey, sessionId) => {
1169
+ if (typeof window === "undefined") return null;
1170
+ try {
1171
+ const key = buildCacheKey(storageKey, sessionId);
1172
+ const data = localStorage.getItem(key);
1173
+ if (!data) return null;
1174
+ return JSON.parse(data);
1175
+ } catch {
1176
+ return null;
1177
+ }
1178
+ };
1179
+ var removeSessionCache = (storageKey, sessionId) => {
1180
+ if (typeof window === "undefined") return;
1181
+ try {
1182
+ const key = buildCacheKey(storageKey, sessionId);
1183
+ localStorage.removeItem(key);
1184
+ } catch {
1185
+ }
1186
+ };
1187
+
1157
1188
  // src/react/hooks/useChatUI.ts
1158
1189
  var DEFAULT_STORAGE_KEY = "chatllm_sessions";
1159
1190
  var DEFAULT_COMPRESSION_THRESHOLD = 20;
@@ -1225,6 +1256,10 @@ var useChatUI = (options) => {
1225
1256
  const [deepResearchProgress, setDeepResearchProgress] = useState4(
1226
1257
  null
1227
1258
  );
1259
+ const sessionsRef = useRef3(sessions);
1260
+ useEffect2(() => {
1261
+ sessionsRef.current = sessions;
1262
+ }, [sessions]);
1228
1263
  const abortControllerRef = useRef3(null);
1229
1264
  const skipNextPollParsingRef = useRef3(false);
1230
1265
  const skipNextSkillParsingRef = useRef3(false);
@@ -1554,7 +1589,7 @@ ${newConversation}
1554
1589
  setIsSessionLoading(true);
1555
1590
  try {
1556
1591
  const sessionDetail = await onLoadSession(id);
1557
- const loadedMessages = sessionDetail.messages.map((m, idx) => ({
1592
+ let loadedMessages = sessionDetail.messages.map((m, idx) => ({
1558
1593
  id: m.id || generateId2("msg"),
1559
1594
  role: typeof m.role === "string" ? m.role.toLowerCase() : m.role,
1560
1595
  // API는 message 필드, 내부는 content 필드 사용
@@ -1564,18 +1599,54 @@ ${newConversation}
1564
1599
  alternatives: m.alternatives,
1565
1600
  sources: m.sources
1566
1601
  }));
1602
+ let resolvedTitle = sessionDetail.title;
1603
+ if (loadedMessages.length === 0) {
1604
+ const cached = readSessionCache(storageKey, id);
1605
+ if (cached && cached.messages.length > 0) {
1606
+ console.warn("[useChatUI] Server returned empty messages, using localStorage cache");
1607
+ loadedMessages = cached.messages;
1608
+ if (!resolvedTitle && cached.title) {
1609
+ resolvedTitle = cached.title;
1610
+ }
1611
+ }
1612
+ }
1567
1613
  setSessions(
1568
1614
  (prev) => prev.map(
1569
- (s) => s.id === id ? { ...s, title: sessionDetail.title, messages: loadedMessages, updatedAt: Date.now() } : s
1615
+ (s) => s.id === id ? { ...s, title: resolvedTitle, messages: loadedMessages, updatedAt: Date.now() } : s
1570
1616
  )
1571
1617
  );
1572
1618
  setCurrentSessionId(id);
1619
+ if (loadedMessages.length > 0) {
1620
+ const existingSession2 = sessions.find((s) => s.id === id);
1621
+ writeSessionCache(storageKey, {
1622
+ id,
1623
+ title: resolvedTitle,
1624
+ messages: loadedMessages,
1625
+ model: existingSession2?.model || initialModel || models[0]?.id || "",
1626
+ createdAt: existingSession2?.createdAt || Date.now(),
1627
+ updatedAt: Date.now()
1628
+ });
1629
+ }
1573
1630
  const existingSession = sessions.find((s) => s.id === id);
1574
1631
  if (existingSession) {
1575
1632
  setSelectedModel(existingSession.model);
1576
1633
  }
1577
1634
  } catch (error) {
1578
1635
  onError?.(error instanceof Error ? error : new Error("Failed to load session"));
1636
+ const cached = readSessionCache(storageKey, id);
1637
+ if (cached && cached.messages.length > 0) {
1638
+ console.warn("[useChatUI] onLoadSession failed, using localStorage cache");
1639
+ setSessions(
1640
+ (prev) => prev.map(
1641
+ (s) => s.id === id ? { ...s, title: cached.title || s.title, messages: cached.messages, updatedAt: Date.now() } : s
1642
+ )
1643
+ );
1644
+ setCurrentSessionId(id);
1645
+ const existingSession = sessions.find((s) => s.id === id);
1646
+ if (existingSession) {
1647
+ setSelectedModel(existingSession.model);
1648
+ }
1649
+ }
1579
1650
  } finally {
1580
1651
  setIsSessionLoading(false);
1581
1652
  }
@@ -1586,11 +1657,12 @@ ${newConversation}
1586
1657
  setCurrentSessionId(id);
1587
1658
  setSelectedModel(session.model);
1588
1659
  }
1589
- }, [sessions, useExternalStorage, onLoadSession, onError]);
1660
+ }, [sessions, useExternalStorage, onLoadSession, onError, storageKey, initialModel, models]);
1590
1661
  const deleteSession = useCallback4(async (id) => {
1591
1662
  if (useExternalStorage && onDeleteSessionCallback) {
1592
1663
  try {
1593
1664
  await onDeleteSessionCallback(id);
1665
+ removeSessionCache(storageKey, id);
1594
1666
  setSessions((prev) => {
1595
1667
  const filtered = prev.filter((s) => s.id !== id);
1596
1668
  if (currentSessionId === id) {
@@ -2081,20 +2153,23 @@ ${result.content}
2081
2153
  };
2082
2154
  })
2083
2155
  );
2084
- if (useExternalStorage && onSaveMessages && capturedSessionId) {
2085
- const updatedSession = sessions.find((s) => s.id === capturedSessionId);
2086
- const assistantContent = updatedSession?.messages.find(
2087
- (m) => m.id === assistantMessageId
2088
- )?.content || "";
2089
- if (assistantContent) {
2156
+ if (useExternalStorage && capturedSessionId) {
2157
+ const assistantContentForSave = accumulatedContent;
2158
+ if (assistantContentForSave && onSaveMessages) {
2090
2159
  const messagesToSave = [
2091
2160
  { role: "USER", message: finalContent },
2092
- { role: "ASSISTANT", message: assistantContent }
2161
+ { role: "ASSISTANT", message: assistantContentForSave }
2093
2162
  ];
2094
2163
  onSaveMessages(capturedSessionId, messagesToSave).catch((saveError) => {
2095
2164
  console.error("[useChatUI] Failed to save messages:", saveError);
2096
2165
  });
2097
2166
  }
2167
+ queueMicrotask(() => {
2168
+ const sessionToCache = sessionsRef.current.find((s) => s.id === capturedSessionId);
2169
+ if (sessionToCache && sessionToCache.messages.length > 0) {
2170
+ writeSessionCache(storageKey, sessionToCache);
2171
+ }
2172
+ });
2098
2173
  }
2099
2174
  if (enableAutoExtraction && globalMemory) {
2100
2175
  const currentMsgCount = existingMessages.length + 2;
@@ -6030,7 +6105,7 @@ var MessageBubble = ({
6030
6105
  display: "flex",
6031
6106
  flexDirection: "column",
6032
6107
  alignItems: "flex-end",
6033
- padding: "8px 24px"
6108
+ padding: "4px 24px"
6034
6109
  },
6035
6110
  onMouseEnter: () => setShowActions(true),
6036
6111
  onMouseLeave: () => setShowActions(false),
@@ -6096,7 +6171,7 @@ var MessageBubble = ({
6096
6171
  display: "flex",
6097
6172
  flexDirection: "column",
6098
6173
  alignItems: "flex-start",
6099
- padding: "8px 24px"
6174
+ padding: "4px 24px"
6100
6175
  },
6101
6176
  onMouseEnter: () => setShowActions(true),
6102
6177
  onMouseLeave: () => setShowActions(false),
@@ -6108,25 +6183,25 @@ var MessageBubble = ({
6108
6183
  className: "chatllm-sheet",
6109
6184
  style: {
6110
6185
  width: "100%",
6111
- padding: "24px",
6186
+ padding: "16px",
6112
6187
  display: "flex",
6113
- gap: "16px"
6188
+ gap: "12px"
6114
6189
  },
6115
6190
  children: [
6116
6191
  /* @__PURE__ */ jsx10("div", { style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx10(
6117
6192
  "div",
6118
6193
  {
6119
6194
  style: {
6120
- width: "40px",
6121
- height: "40px",
6122
- borderRadius: "12px",
6195
+ width: "32px",
6196
+ height: "32px",
6197
+ borderRadius: "10px",
6123
6198
  backgroundColor: "var(--chatllm-primary-light)",
6124
6199
  display: "flex",
6125
6200
  alignItems: "center",
6126
6201
  justifyContent: "center",
6127
6202
  color: "var(--chatllm-primary)"
6128
6203
  },
6129
- children: /* @__PURE__ */ jsx10(IconSvg, { name: "magic-line", size: 24 })
6204
+ children: /* @__PURE__ */ jsx10(IconSvg, { name: "magic-line", size: 20 })
6130
6205
  }
6131
6206
  ) }),
6132
6207
  /* @__PURE__ */ jsxs9("div", { style: { flex: 1, minWidth: 0 }, children: [
@@ -6137,7 +6212,7 @@ var MessageBubble = ({
6137
6212
  display: "flex",
6138
6213
  alignItems: "center",
6139
6214
  gap: "8px",
6140
- marginBottom: "16px"
6215
+ marginBottom: "8px"
6141
6216
  },
6142
6217
  children: /* @__PURE__ */ jsx10(
6143
6218
  "span",
@@ -6387,7 +6462,7 @@ var MessageBubble = ({
6387
6462
  display: "flex",
6388
6463
  gap: "2px",
6389
6464
  marginTop: "4px",
6390
- marginLeft: "56px",
6465
+ marginLeft: "44px",
6391
6466
  height: "24px",
6392
6467
  opacity: showActions ? 1 : 0,
6393
6468
  transition: "opacity 0.15s ease"