@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.
@@ -1210,6 +1210,37 @@ var formatPollResponse = (question, selectedOptions, otherText) => {
1210
1210
  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.`;
1211
1211
  };
1212
1212
 
1213
+ // src/react/utils/sessionCache.ts
1214
+ var buildCacheKey = (storageKey, sessionId) => `${storageKey}_cache_${sessionId}`;
1215
+ var writeSessionCache = (storageKey, session) => {
1216
+ if (typeof window === "undefined") return;
1217
+ try {
1218
+ const key = buildCacheKey(storageKey, session.id);
1219
+ localStorage.setItem(key, JSON.stringify(session));
1220
+ } catch (error) {
1221
+ console.warn("[sessionCache] Failed to write cache:", error);
1222
+ }
1223
+ };
1224
+ var readSessionCache = (storageKey, sessionId) => {
1225
+ if (typeof window === "undefined") return null;
1226
+ try {
1227
+ const key = buildCacheKey(storageKey, sessionId);
1228
+ const data = localStorage.getItem(key);
1229
+ if (!data) return null;
1230
+ return JSON.parse(data);
1231
+ } catch {
1232
+ return null;
1233
+ }
1234
+ };
1235
+ var removeSessionCache = (storageKey, sessionId) => {
1236
+ if (typeof window === "undefined") return;
1237
+ try {
1238
+ const key = buildCacheKey(storageKey, sessionId);
1239
+ localStorage.removeItem(key);
1240
+ } catch {
1241
+ }
1242
+ };
1243
+
1213
1244
  // src/react/hooks/useChatUI.ts
1214
1245
  var DEFAULT_STORAGE_KEY = "chatllm_sessions";
1215
1246
  var DEFAULT_COMPRESSION_THRESHOLD = 20;
@@ -1281,6 +1312,10 @@ var useChatUI = (options) => {
1281
1312
  const [deepResearchProgress, setDeepResearchProgress] = (0, import_react4.useState)(
1282
1313
  null
1283
1314
  );
1315
+ const sessionsRef = (0, import_react4.useRef)(sessions);
1316
+ (0, import_react4.useEffect)(() => {
1317
+ sessionsRef.current = sessions;
1318
+ }, [sessions]);
1284
1319
  const abortControllerRef = (0, import_react4.useRef)(null);
1285
1320
  const skipNextPollParsingRef = (0, import_react4.useRef)(false);
1286
1321
  const skipNextSkillParsingRef = (0, import_react4.useRef)(false);
@@ -1610,7 +1645,7 @@ ${newConversation}
1610
1645
  setIsSessionLoading(true);
1611
1646
  try {
1612
1647
  const sessionDetail = await onLoadSession(id);
1613
- const loadedMessages = sessionDetail.messages.map((m, idx) => ({
1648
+ let loadedMessages = sessionDetail.messages.map((m, idx) => ({
1614
1649
  id: m.id || generateId2("msg"),
1615
1650
  role: typeof m.role === "string" ? m.role.toLowerCase() : m.role,
1616
1651
  // API는 message 필드, 내부는 content 필드 사용
@@ -1620,18 +1655,54 @@ ${newConversation}
1620
1655
  alternatives: m.alternatives,
1621
1656
  sources: m.sources
1622
1657
  }));
1658
+ let resolvedTitle = sessionDetail.title;
1659
+ if (loadedMessages.length === 0) {
1660
+ const cached = readSessionCache(storageKey, id);
1661
+ if (cached && cached.messages.length > 0) {
1662
+ console.warn("[useChatUI] Server returned empty messages, using localStorage cache");
1663
+ loadedMessages = cached.messages;
1664
+ if (!resolvedTitle && cached.title) {
1665
+ resolvedTitle = cached.title;
1666
+ }
1667
+ }
1668
+ }
1623
1669
  setSessions(
1624
1670
  (prev) => prev.map(
1625
- (s) => s.id === id ? { ...s, title: sessionDetail.title, messages: loadedMessages, updatedAt: Date.now() } : s
1671
+ (s) => s.id === id ? { ...s, title: resolvedTitle, messages: loadedMessages, updatedAt: Date.now() } : s
1626
1672
  )
1627
1673
  );
1628
1674
  setCurrentSessionId(id);
1675
+ if (loadedMessages.length > 0) {
1676
+ const existingSession2 = sessions.find((s) => s.id === id);
1677
+ writeSessionCache(storageKey, {
1678
+ id,
1679
+ title: resolvedTitle,
1680
+ messages: loadedMessages,
1681
+ model: existingSession2?.model || initialModel || models[0]?.id || "",
1682
+ createdAt: existingSession2?.createdAt || Date.now(),
1683
+ updatedAt: Date.now()
1684
+ });
1685
+ }
1629
1686
  const existingSession = sessions.find((s) => s.id === id);
1630
1687
  if (existingSession) {
1631
1688
  setSelectedModel(existingSession.model);
1632
1689
  }
1633
1690
  } catch (error) {
1634
1691
  onError?.(error instanceof Error ? error : new Error("Failed to load session"));
1692
+ const cached = readSessionCache(storageKey, id);
1693
+ if (cached && cached.messages.length > 0) {
1694
+ console.warn("[useChatUI] onLoadSession failed, using localStorage cache");
1695
+ setSessions(
1696
+ (prev) => prev.map(
1697
+ (s) => s.id === id ? { ...s, title: cached.title || s.title, messages: cached.messages, updatedAt: Date.now() } : s
1698
+ )
1699
+ );
1700
+ setCurrentSessionId(id);
1701
+ const existingSession = sessions.find((s) => s.id === id);
1702
+ if (existingSession) {
1703
+ setSelectedModel(existingSession.model);
1704
+ }
1705
+ }
1635
1706
  } finally {
1636
1707
  setIsSessionLoading(false);
1637
1708
  }
@@ -1642,11 +1713,12 @@ ${newConversation}
1642
1713
  setCurrentSessionId(id);
1643
1714
  setSelectedModel(session.model);
1644
1715
  }
1645
- }, [sessions, useExternalStorage, onLoadSession, onError]);
1716
+ }, [sessions, useExternalStorage, onLoadSession, onError, storageKey, initialModel, models]);
1646
1717
  const deleteSession = (0, import_react4.useCallback)(async (id) => {
1647
1718
  if (useExternalStorage && onDeleteSessionCallback) {
1648
1719
  try {
1649
1720
  await onDeleteSessionCallback(id);
1721
+ removeSessionCache(storageKey, id);
1650
1722
  setSessions((prev) => {
1651
1723
  const filtered = prev.filter((s) => s.id !== id);
1652
1724
  if (currentSessionId === id) {
@@ -2137,20 +2209,23 @@ ${result.content}
2137
2209
  };
2138
2210
  })
2139
2211
  );
2140
- if (useExternalStorage && onSaveMessages && capturedSessionId) {
2141
- const updatedSession = sessions.find((s) => s.id === capturedSessionId);
2142
- const assistantContent = updatedSession?.messages.find(
2143
- (m) => m.id === assistantMessageId
2144
- )?.content || "";
2145
- if (assistantContent) {
2212
+ if (useExternalStorage && capturedSessionId) {
2213
+ const assistantContentForSave = accumulatedContent;
2214
+ if (assistantContentForSave && onSaveMessages) {
2146
2215
  const messagesToSave = [
2147
2216
  { role: "USER", message: finalContent },
2148
- { role: "ASSISTANT", message: assistantContent }
2217
+ { role: "ASSISTANT", message: assistantContentForSave }
2149
2218
  ];
2150
2219
  onSaveMessages(capturedSessionId, messagesToSave).catch((saveError) => {
2151
2220
  console.error("[useChatUI] Failed to save messages:", saveError);
2152
2221
  });
2153
2222
  }
2223
+ queueMicrotask(() => {
2224
+ const sessionToCache = sessionsRef.current.find((s) => s.id === capturedSessionId);
2225
+ if (sessionToCache && sessionToCache.messages.length > 0) {
2226
+ writeSessionCache(storageKey, sessionToCache);
2227
+ }
2228
+ });
2154
2229
  }
2155
2230
  if (enableAutoExtraction && globalMemory) {
2156
2231
  const currentMsgCount = existingMessages.length + 2;
@@ -6086,7 +6161,7 @@ var MessageBubble = ({
6086
6161
  display: "flex",
6087
6162
  flexDirection: "column",
6088
6163
  alignItems: "flex-end",
6089
- padding: "8px 24px"
6164
+ padding: "4px 24px"
6090
6165
  },
6091
6166
  onMouseEnter: () => setShowActions(true),
6092
6167
  onMouseLeave: () => setShowActions(false),
@@ -6152,7 +6227,7 @@ var MessageBubble = ({
6152
6227
  display: "flex",
6153
6228
  flexDirection: "column",
6154
6229
  alignItems: "flex-start",
6155
- padding: "8px 24px"
6230
+ padding: "4px 24px"
6156
6231
  },
6157
6232
  onMouseEnter: () => setShowActions(true),
6158
6233
  onMouseLeave: () => setShowActions(false),
@@ -6164,25 +6239,25 @@ var MessageBubble = ({
6164
6239
  className: "chatllm-sheet",
6165
6240
  style: {
6166
6241
  width: "100%",
6167
- padding: "24px",
6242
+ padding: "16px",
6168
6243
  display: "flex",
6169
- gap: "16px"
6244
+ gap: "12px"
6170
6245
  },
6171
6246
  children: [
6172
6247
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6173
6248
  "div",
6174
6249
  {
6175
6250
  style: {
6176
- width: "40px",
6177
- height: "40px",
6178
- borderRadius: "12px",
6251
+ width: "32px",
6252
+ height: "32px",
6253
+ borderRadius: "10px",
6179
6254
  backgroundColor: "var(--chatllm-primary-light)",
6180
6255
  display: "flex",
6181
6256
  alignItems: "center",
6182
6257
  justifyContent: "center",
6183
6258
  color: "var(--chatllm-primary)"
6184
6259
  },
6185
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconSvg, { name: "magic-line", size: 24 })
6260
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconSvg, { name: "magic-line", size: 20 })
6186
6261
  }
6187
6262
  ) }),
6188
6263
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
@@ -6193,7 +6268,7 @@ var MessageBubble = ({
6193
6268
  display: "flex",
6194
6269
  alignItems: "center",
6195
6270
  gap: "8px",
6196
- marginBottom: "16px"
6271
+ marginBottom: "8px"
6197
6272
  },
6198
6273
  children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6199
6274
  "span",
@@ -6443,7 +6518,7 @@ var MessageBubble = ({
6443
6518
  display: "flex",
6444
6519
  gap: "2px",
6445
6520
  marginTop: "4px",
6446
- marginLeft: "56px",
6521
+ marginLeft: "44px",
6447
6522
  height: "24px",
6448
6523
  opacity: showActions ? 1 : 0,
6449
6524
  transition: "opacity 0.15s ease"