@gendive/chatllm 0.17.18 → 0.17.20

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.
@@ -647,6 +647,8 @@ interface ChatUIProps {
647
647
  sidebarRenderFooter?: () => React.ReactNode;
648
648
  /** 설정 버튼 표시 여부 */
649
649
  showSettings?: boolean;
650
+ /** @description 설정 모달에서 메모리 탭 표시 여부 (기본: true) @Todo vibecode */
651
+ showMemoryTab?: boolean;
650
652
  /** 모델 선택기 표시 여부 */
651
653
  showModelSelector?: boolean;
652
654
  /** 초기 시스템 프롬프트 */
@@ -1790,6 +1792,8 @@ interface SettingsModalProps {
1790
1792
  enableProjects?: boolean;
1791
1793
  /** @description 현재 프로젝트 이름 @Todo vibecode */
1792
1794
  currentProjectTitle?: string;
1795
+ /** @description 메모리 탭 표시 여부 (기본: true) @Todo vibecode */
1796
+ showMemoryTab?: boolean;
1793
1797
  }
1794
1798
  declare const SettingsModal: React$1.FC<SettingsModalProps>;
1795
1799
 
@@ -647,6 +647,8 @@ interface ChatUIProps {
647
647
  sidebarRenderFooter?: () => React.ReactNode;
648
648
  /** 설정 버튼 표시 여부 */
649
649
  showSettings?: boolean;
650
+ /** @description 설정 모달에서 메모리 탭 표시 여부 (기본: true) @Todo vibecode */
651
+ showMemoryTab?: boolean;
650
652
  /** 모델 선택기 표시 여부 */
651
653
  showModelSelector?: boolean;
652
654
  /** 초기 시스템 프롬프트 */
@@ -1790,6 +1792,8 @@ interface SettingsModalProps {
1790
1792
  enableProjects?: boolean;
1791
1793
  /** @description 현재 프로젝트 이름 @Todo vibecode */
1792
1794
  currentProjectTitle?: string;
1795
+ /** @description 메모리 탭 표시 여부 (기본: true) @Todo vibecode */
1796
+ showMemoryTab?: boolean;
1793
1797
  }
1794
1798
  declare const SettingsModal: React$1.FC<SettingsModalProps>;
1795
1799
 
@@ -483,7 +483,7 @@ var parseExtractionResult = (text) => {
483
483
  function useInfoExtraction(options) {
484
484
  const [isExtracting, setIsExtracting] = (0, import_react2.useState)(false);
485
485
  const [lastExtraction, setLastExtraction] = (0, import_react2.useState)(null);
486
- const { apiEndpoint, model, minConfidence = 0.8, globalMemory } = options;
486
+ const { apiEndpoint, model, minConfidence = 0.8, globalMemory, onCallLLM } = options;
487
487
  const extractInfo = (0, import_react2.useCallback)(
488
488
  async (messages) => {
489
489
  if (messages.length === 0) {
@@ -492,41 +492,44 @@ function useInfoExtraction(options) {
492
492
  setIsExtracting(true);
493
493
  try {
494
494
  const prompt = buildExtractionPrompt(messages);
495
- const response = await fetch(apiEndpoint, {
496
- method: "POST",
497
- headers: { "Content-Type": "application/json" },
498
- body: JSON.stringify({
499
- messages: [{ role: "user", content: prompt }],
500
- model: model || "default"
501
- })
502
- });
503
- if (!response.ok) {
504
- throw new Error(`API error: ${response.status}`);
505
- }
506
- const reader = response.body?.getReader();
507
- if (!reader) {
508
- return [];
509
- }
510
- const decoder = new TextDecoder();
511
- let buffer = "";
512
- let fullResponse = "";
513
- while (true) {
514
- const { done, value } = await reader.read();
515
- if (done) break;
516
- buffer += decoder.decode(value, { stream: true });
517
- const lines = buffer.split("\n");
518
- buffer = lines.pop() || "";
519
- for (const line of lines) {
520
- if (line.startsWith("data: ")) {
521
- const data = line.slice(6);
522
- if (data === "[DONE]") continue;
523
- try {
524
- const parsed = JSON.parse(data);
525
- {
495
+ let fullResponse;
496
+ if (onCallLLM) {
497
+ fullResponse = await onCallLLM(prompt, model || "default");
498
+ } else {
499
+ const response = await fetch(apiEndpoint, {
500
+ method: "POST",
501
+ headers: { "Content-Type": "application/json" },
502
+ body: JSON.stringify({
503
+ messages: [{ role: "user", content: prompt }],
504
+ model: model || "default"
505
+ })
506
+ });
507
+ if (!response.ok) {
508
+ throw new Error(`API error: ${response.status}`);
509
+ }
510
+ const reader = response.body?.getReader();
511
+ if (!reader) {
512
+ return [];
513
+ }
514
+ const decoder = new TextDecoder();
515
+ let buffer = "";
516
+ fullResponse = "";
517
+ while (true) {
518
+ const { done, value } = await reader.read();
519
+ if (done) break;
520
+ buffer += decoder.decode(value, { stream: true });
521
+ const lines = buffer.split("\n");
522
+ buffer = lines.pop() || "";
523
+ for (const line of lines) {
524
+ if (line.startsWith("data: ")) {
525
+ const data = line.slice(6);
526
+ if (data === "[DONE]") continue;
527
+ try {
528
+ const parsed = JSON.parse(data);
526
529
  const chunk = parsed.content ?? parsed.text ?? "";
527
530
  if (chunk) fullResponse += chunk;
531
+ } catch {
528
532
  }
529
- } catch {
530
533
  }
531
534
  }
532
535
  }
@@ -553,7 +556,7 @@ function useInfoExtraction(options) {
553
556
  setIsExtracting(false);
554
557
  }
555
558
  },
556
- [apiEndpoint, model, minConfidence, globalMemory]
559
+ [apiEndpoint, model, minConfidence, globalMemory, onCallLLM]
557
560
  );
558
561
  return {
559
562
  extractInfo,
@@ -1609,6 +1612,33 @@ var removeSessionCache = (storageKey, sessionId) => {
1609
1612
  };
1610
1613
 
1611
1614
  // src/react/hooks/useChatUI.ts
1615
+ var parseSSEResponse = async (response) => {
1616
+ const reader = response.body?.getReader();
1617
+ if (!reader) return "";
1618
+ const decoder = new TextDecoder();
1619
+ let buffer = "";
1620
+ let result = "";
1621
+ while (true) {
1622
+ const { done, value } = await reader.read();
1623
+ if (done) break;
1624
+ buffer += decoder.decode(value, { stream: true });
1625
+ const lines = buffer.split("\n");
1626
+ buffer = lines.pop() || "";
1627
+ for (const line of lines) {
1628
+ if (line.startsWith("data: ")) {
1629
+ const data = line.slice(6);
1630
+ if (data === "[DONE]") continue;
1631
+ try {
1632
+ const parsed = JSON.parse(data);
1633
+ const chunk = parsed.content ?? parsed.text ?? "";
1634
+ if (chunk) result += chunk;
1635
+ } catch {
1636
+ }
1637
+ }
1638
+ }
1639
+ }
1640
+ return result;
1641
+ };
1612
1642
  var DEFAULT_STORAGE_KEY = "chatllm_sessions";
1613
1643
  var DEFAULT_COMPRESSION_THRESHOLD = 20;
1614
1644
  var DEFAULT_KEEP_RECENT = 6;
@@ -1814,11 +1844,37 @@ var useChatUI = (options) => {
1814
1844
  );
1815
1845
  const projectMemoryRaw = useGlobalMemory(projectMemoryOptions);
1816
1846
  const projectMemory = enableProjects ? projectMemoryRaw : null;
1847
+ const callInternalLLM = (0, import_react5.useCallback)(async (prompt, model) => {
1848
+ if (onSendMessageRef.current) {
1849
+ const modelConfig = models.find((m) => m.id === model);
1850
+ const provider = modelConfig?.provider || "ollama";
1851
+ const result = await onSendMessageRef.current({
1852
+ messages: [{ role: "user", content: prompt }],
1853
+ model,
1854
+ provider,
1855
+ apiKey
1856
+ });
1857
+ if (typeof result === "string") return result;
1858
+ if (typeof result === "object" && "content" in result) return result.content;
1859
+ return parseSSEResponse(new Response(result));
1860
+ }
1861
+ const response = await fetch(apiEndpoint, {
1862
+ method: "POST",
1863
+ headers: { "Content-Type": "application/json" },
1864
+ body: JSON.stringify({
1865
+ messages: [{ role: "user", content: prompt }],
1866
+ model
1867
+ })
1868
+ });
1869
+ if (!response.ok) return "";
1870
+ return parseSSEResponse(response);
1871
+ }, [apiEndpoint, apiKey, models]);
1817
1872
  const infoExtraction = useInfoExtraction({
1818
1873
  apiEndpoint,
1819
1874
  model: selectedModel,
1820
1875
  minConfidence: 0.8,
1821
- globalMemory
1876
+ globalMemory,
1877
+ onCallLLM: callInternalLLM
1822
1878
  });
1823
1879
  const currentSession = sessions.find((s) => s.id === currentSessionId) || null;
1824
1880
  const messages = currentSession?.messages.filter((m) => !m.hidden) || [];
@@ -2016,46 +2072,11 @@ ${conversationText}
2016
2072
 
2017
2073
  \uC694\uC57D:`;
2018
2074
  try {
2019
- const response = await fetch(apiEndpoint, {
2020
- method: "POST",
2021
- headers: { "Content-Type": "application/json" },
2022
- body: JSON.stringify({
2023
- messages: [{ role: "user", content: summaryPrompt }],
2024
- model
2025
- })
2026
- });
2027
- if (!response.ok) return "";
2028
- const reader = response.body?.getReader();
2029
- if (!reader) return "";
2030
- const decoder = new TextDecoder();
2031
- let buffer = "";
2032
- let summary = "";
2033
- while (true) {
2034
- const { done, value } = await reader.read();
2035
- if (done) break;
2036
- buffer += decoder.decode(value, { stream: true });
2037
- const lines = buffer.split("\n");
2038
- buffer = lines.pop() || "";
2039
- for (const line of lines) {
2040
- if (line.startsWith("data: ")) {
2041
- const data = line.slice(6);
2042
- if (data === "[DONE]") continue;
2043
- try {
2044
- const parsed = JSON.parse(data);
2045
- {
2046
- const chunk = parsed.content ?? parsed.text ?? "";
2047
- if (chunk) summary += chunk;
2048
- }
2049
- } catch {
2050
- }
2051
- }
2052
- }
2053
- }
2054
- return summary;
2075
+ return await callInternalLLM(summaryPrompt, model);
2055
2076
  } catch {
2056
2077
  return "";
2057
2078
  }
2058
- }, [apiEndpoint]);
2079
+ }, [callInternalLLM]);
2059
2080
  const incrementalCompressContext = (0, import_react5.useCallback)(
2060
2081
  async (existingSummary, newMessages, model) => {
2061
2082
  const newConversation = newMessages.map((m) => `${m.role === "user" ? "\uC0AC\uC6A9\uC790" : "AI"}: ${m.content}`).join("\n\n");
@@ -2075,47 +2096,13 @@ ${newConversation}
2075
2096
 
2076
2097
  \uD1B5\uD569 \uC694\uC57D:`;
2077
2098
  try {
2078
- const response = await fetch(apiEndpoint, {
2079
- method: "POST",
2080
- headers: { "Content-Type": "application/json" },
2081
- body: JSON.stringify({
2082
- messages: [{ role: "user", content: mergePrompt }],
2083
- model
2084
- })
2085
- });
2086
- if (!response.ok) return existingSummary;
2087
- const reader = response.body?.getReader();
2088
- if (!reader) return existingSummary;
2089
- const decoder = new TextDecoder();
2090
- let buffer = "";
2091
- let summary = "";
2092
- while (true) {
2093
- const { done, value } = await reader.read();
2094
- if (done) break;
2095
- buffer += decoder.decode(value, { stream: true });
2096
- const lines = buffer.split("\n");
2097
- buffer = lines.pop() || "";
2098
- for (const line of lines) {
2099
- if (line.startsWith("data: ")) {
2100
- const data = line.slice(6);
2101
- if (data === "[DONE]") continue;
2102
- try {
2103
- const parsed = JSON.parse(data);
2104
- {
2105
- const chunk = parsed.content ?? parsed.text ?? "";
2106
- if (chunk) summary += chunk;
2107
- }
2108
- } catch {
2109
- }
2110
- }
2111
- }
2112
- }
2099
+ const summary = await callInternalLLM(mergePrompt, model);
2113
2100
  return summary || existingSummary;
2114
2101
  } catch {
2115
2102
  return existingSummary;
2116
2103
  }
2117
2104
  },
2118
- [apiEndpoint]
2105
+ [callInternalLLM]
2119
2106
  );
2120
2107
  const estimateTokens = (0, import_react5.useCallback)((messages2) => {
2121
2108
  return messages2.reduce((sum, m) => sum + Math.ceil(m.content.length / 4), 0);
@@ -9234,7 +9221,8 @@ var SettingsModal = ({
9234
9221
  onDeleteProjectMemory,
9235
9222
  onClearProjectMemory,
9236
9223
  enableProjects = false,
9237
- currentProjectTitle
9224
+ currentProjectTitle,
9225
+ showMemoryTab = true
9238
9226
  }) => {
9239
9227
  const [activeTab, setActiveTab] = (0, import_react18.useState)("general");
9240
9228
  const [localApiKey, setLocalApiKey] = (0, import_react18.useState)(apiKey);
@@ -9340,7 +9328,7 @@ var SettingsModal = ({
9340
9328
  label: "\uAC1C\uC778 \uB9DE\uCDA4 \uC124\uC815"
9341
9329
  }
9342
9330
  ),
9343
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9331
+ showMemoryTab && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9344
9332
  TabButton,
9345
9333
  {
9346
9334
  active: activeTab === "memory",
@@ -9349,7 +9337,7 @@ var SettingsModal = ({
9349
9337
  label: "AI \uBA54\uBAA8\uB9AC"
9350
9338
  }
9351
9339
  ),
9352
- enableProjects && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9340
+ showMemoryTab && enableProjects && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9353
9341
  TabButton,
9354
9342
  {
9355
9343
  active: activeTab === "project-memory",
@@ -9536,7 +9524,7 @@ var SettingsModal = ({
9536
9524
  }
9537
9525
  ) })
9538
9526
  ] }),
9539
- activeTab === "memory" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9527
+ activeTab === "memory" && showMemoryTab && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9540
9528
  MemoryTabContent,
9541
9529
  {
9542
9530
  items: memoryItems,
@@ -9545,7 +9533,7 @@ var SettingsModal = ({
9545
9533
  onClearAll: onClearMemory
9546
9534
  }
9547
9535
  ),
9548
- activeTab === "project-memory" && enableProjects && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9536
+ activeTab === "project-memory" && showMemoryTab && enableProjects && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
9549
9537
  MemoryTabContent,
9550
9538
  {
9551
9539
  items: projectMemoryItems,
@@ -10731,6 +10719,7 @@ var ChatUIView = ({
10731
10719
  sidebarRenderAfterHeader,
10732
10720
  sidebarRenderFooter,
10733
10721
  showSettings,
10722
+ showMemoryTab,
10734
10723
  showModelSelector,
10735
10724
  showThinking,
10736
10725
  thinkingDefaultOpen,
@@ -10999,6 +10988,7 @@ var ChatUIView = ({
10999
10988
  onDeleteMemory: globalMemory ? (key) => globalMemory.remove(key) : void 0,
11000
10989
  onClearMemory: globalMemory ? () => globalMemory.clear() : void 0,
11001
10990
  onSave: savePersonalization,
10991
+ showMemoryTab,
11002
10992
  enableProjects: projects.length > 0,
11003
10993
  projectMemoryItems,
11004
10994
  onDeleteProjectMemory: projectMemory ? (key) => projectMemory.remove(key) : void 0,
@@ -11039,6 +11029,7 @@ var ChatUIWithHook = ({
11039
11029
  sidebarRenderAfterHeader,
11040
11030
  sidebarRenderFooter,
11041
11031
  showSettings = true,
11032
+ showMemoryTab = true,
11042
11033
  showModelSelector = true,
11043
11034
  systemPrompt,
11044
11035
  contextCompressionThreshold = 20,
@@ -11131,6 +11122,7 @@ var ChatUIWithHook = ({
11131
11122
  sidebarRenderAfterHeader,
11132
11123
  sidebarRenderFooter,
11133
11124
  showSettings,
11125
+ showMemoryTab,
11134
11126
  showModelSelector,
11135
11127
  showThinking,
11136
11128
  thinkingDefaultOpen,
@@ -11154,6 +11146,7 @@ var ChatUI = (props) => {
11154
11146
  sidebarRenderAfterHeader,
11155
11147
  sidebarRenderFooter,
11156
11148
  showSettings = true,
11149
+ showMemoryTab: chatStateShowMemoryTab = true,
11157
11150
  showModelSelector = true,
11158
11151
  showThinking = true,
11159
11152
  thinkingDefaultOpen = false,
@@ -11175,6 +11168,7 @@ var ChatUI = (props) => {
11175
11168
  sidebarRenderAfterHeader,
11176
11169
  sidebarRenderFooter,
11177
11170
  showSettings,
11171
+ showMemoryTab: chatStateShowMemoryTab,
11178
11172
  showModelSelector,
11179
11173
  showThinking,
11180
11174
  thinkingDefaultOpen,