@lvce-editor/chat-view 1.8.0 → 1.9.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.
@@ -1201,7 +1201,7 @@ const assistant = i18nString('Assistant');
1201
1201
  const composePlaceholder = i18nString('Type your message. Enter to send, Shift+Enter for newline.');
1202
1202
  const sendMessage = i18nString('Send message');
1203
1203
  const send = i18nString('Send');
1204
- const deleteChatSession = i18nString('Delete chat session');
1204
+ const deleteChatSession$1 = i18nString('Delete chat session');
1205
1205
  const defaultSessionTitle = i18nString('Chat 1');
1206
1206
  const dummyChatA = i18nString('Dummy Chat A');
1207
1207
  const dummyChatB = i18nString('Dummy Chat B');
@@ -1209,6 +1209,7 @@ const dummyChatC = i18nString('Dummy Chat C');
1209
1209
 
1210
1210
  const createDefaultState = () => {
1211
1211
  const defaultSessionId = 'session-1';
1212
+ const defaultModelId = 'test';
1212
1213
  return {
1213
1214
  assetDir: '',
1214
1215
  composerValue: '',
@@ -1221,9 +1222,23 @@ const createDefaultState = () => {
1221
1222
  inputSource: 'script',
1222
1223
  lastSubmittedSessionId: '',
1223
1224
  listItemHeight: 40,
1225
+ models: [{
1226
+ id: defaultModelId,
1227
+ name: 'test'
1228
+ }, {
1229
+ id: 'codex-5.3',
1230
+ name: 'Codex 5.3'
1231
+ }, {
1232
+ id: 'claude-code',
1233
+ name: 'Claude Code'
1234
+ }, {
1235
+ id: 'claude-haiku',
1236
+ name: 'Claude Haiku'
1237
+ }],
1224
1238
  nextMessageId: 1,
1225
1239
  platform: 0,
1226
1240
  renamingSessionId: '',
1241
+ selectedModelId: defaultModelId,
1227
1242
  selectedSessionId: defaultSessionId,
1228
1243
  sessions: [{
1229
1244
  id: defaultSessionId,
@@ -1274,7 +1289,7 @@ const diffFocus = (oldState, newState) => {
1274
1289
  };
1275
1290
 
1276
1291
  const isEqual = (oldState, newState) => {
1277
- return oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.viewMode === newState.viewMode;
1292
+ return oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.viewMode === newState.viewMode;
1278
1293
  };
1279
1294
 
1280
1295
  const RenderItems = 4;
@@ -1338,6 +1353,8 @@ const Span = 8;
1338
1353
  const Text = 12;
1339
1354
  const P = 50;
1340
1355
  const TextArea = 62;
1356
+ const Select$1 = 63;
1357
+ const Option$1 = 64;
1341
1358
  const Reference = 100;
1342
1359
 
1343
1360
  const Enter = 3;
@@ -1667,17 +1684,170 @@ const handleChatListContextMenu = async (name, x, y) => {
1667
1684
  await invoke('ContextMenu.show', x, y, CHAT_LIST_ITEM_CONTEXT_MENU, sessionId);
1668
1685
  };
1669
1686
 
1687
+ const LVCE_CHAT_SESSIONS_DB_NAME = 'lvce-chat-view-sessions';
1688
+ const LVCE_CHAT_SESSIONS_DB_VERSION = 1;
1689
+ const LVCE_CHAT_SESSIONS_STORE = 'chat-sessions';
1690
+ const toError = error => {
1691
+ if (error instanceof Error) {
1692
+ return error;
1693
+ }
1694
+ return new Error('IndexedDB request failed');
1695
+ };
1696
+ const requestToPromise = async createRequest => {
1697
+ const request = createRequest();
1698
+ return new Promise((resolve, reject) => {
1699
+ request.addEventListener('success', () => {
1700
+ resolve(request.result);
1701
+ });
1702
+ request.addEventListener('error', () => {
1703
+ reject(toError(request.error));
1704
+ });
1705
+ });
1706
+ };
1707
+ const transactionToPromise = async createTransaction => {
1708
+ const transaction = createTransaction();
1709
+ return new Promise((resolve, reject) => {
1710
+ transaction.addEventListener('complete', () => {
1711
+ resolve();
1712
+ });
1713
+ transaction.addEventListener('error', () => {
1714
+ reject(toError(transaction.error));
1715
+ });
1716
+ transaction.addEventListener('abort', () => {
1717
+ reject(toError(transaction.error));
1718
+ });
1719
+ });
1720
+ };
1721
+ const openSessionsDatabase = async () => {
1722
+ const request = indexedDB.open(LVCE_CHAT_SESSIONS_DB_NAME, LVCE_CHAT_SESSIONS_DB_VERSION);
1723
+ request.addEventListener('upgradeneeded', () => {
1724
+ const database = request.result;
1725
+ if (!database.objectStoreNames.contains(LVCE_CHAT_SESSIONS_STORE)) {
1726
+ database.createObjectStore(LVCE_CHAT_SESSIONS_STORE, {
1727
+ keyPath: 'id'
1728
+ });
1729
+ }
1730
+ });
1731
+ return requestToPromise(() => request);
1732
+ };
1733
+ class IndexedDbChatSessionStorage {
1734
+ async getDatabase() {
1735
+ if (!this.databasePromise) {
1736
+ this.databasePromise = openSessionsDatabase();
1737
+ }
1738
+ return this.databasePromise;
1739
+ }
1740
+ async clear() {
1741
+ const database = await this.getDatabase();
1742
+ const transaction = database.transaction(LVCE_CHAT_SESSIONS_STORE, 'readwrite');
1743
+ const createTransaction = () => transaction;
1744
+ const store = transaction.objectStore(LVCE_CHAT_SESSIONS_STORE);
1745
+ store.clear();
1746
+ await transactionToPromise(createTransaction);
1747
+ }
1748
+ async deleteSession(id) {
1749
+ const database = await this.getDatabase();
1750
+ const transaction = database.transaction(LVCE_CHAT_SESSIONS_STORE, 'readwrite');
1751
+ const createTransaction = () => transaction;
1752
+ const store = transaction.objectStore(LVCE_CHAT_SESSIONS_STORE);
1753
+ store.delete(id);
1754
+ await transactionToPromise(createTransaction);
1755
+ }
1756
+ async getSession(id) {
1757
+ const database = await this.getDatabase();
1758
+ const transaction = database.transaction(LVCE_CHAT_SESSIONS_STORE, 'readonly');
1759
+ const store = transaction.objectStore(LVCE_CHAT_SESSIONS_STORE);
1760
+ const result = await requestToPromise(() => store.get(id));
1761
+ return result;
1762
+ }
1763
+ async listSessions() {
1764
+ const database = await this.getDatabase();
1765
+ const transaction = database.transaction(LVCE_CHAT_SESSIONS_STORE, 'readonly');
1766
+ const store = transaction.objectStore(LVCE_CHAT_SESSIONS_STORE);
1767
+ const result = await requestToPromise(() => store.getAll());
1768
+ return result;
1769
+ }
1770
+ async setSession(session) {
1771
+ const database = await this.getDatabase();
1772
+ const transaction = database.transaction(LVCE_CHAT_SESSIONS_STORE, 'readwrite');
1773
+ const createTransaction = () => transaction;
1774
+ const store = transaction.objectStore(LVCE_CHAT_SESSIONS_STORE);
1775
+ store.put(session);
1776
+ await transactionToPromise(createTransaction);
1777
+ }
1778
+ }
1779
+
1780
+ class InMemoryChatSessionStorage {
1781
+ sessions = new Map();
1782
+ async clear() {
1783
+ this.sessions.clear();
1784
+ }
1785
+ async deleteSession(id) {
1786
+ this.sessions.delete(id);
1787
+ }
1788
+ async getSession(id) {
1789
+ return this.sessions.get(id);
1790
+ }
1791
+ async listSessions() {
1792
+ return [...this.sessions.values()];
1793
+ }
1794
+ async setSession(session) {
1795
+ this.sessions.set(session.id, session);
1796
+ }
1797
+ }
1798
+
1799
+ const createDefaultStorage = () => {
1800
+ if (typeof indexedDB === 'undefined') {
1801
+ return new InMemoryChatSessionStorage();
1802
+ }
1803
+ return new IndexedDbChatSessionStorage();
1804
+ };
1805
+ let chatSessionStorage = createDefaultStorage();
1806
+ const listChatSessions = async () => {
1807
+ const sessions = await chatSessionStorage.listSessions();
1808
+ return sessions.map(session => ({
1809
+ id: session.id,
1810
+ messages: [],
1811
+ title: session.title
1812
+ }));
1813
+ };
1814
+ const getChatSession = async id => {
1815
+ const session = await chatSessionStorage.getSession(id);
1816
+ if (!session) {
1817
+ return undefined;
1818
+ }
1819
+ return {
1820
+ id: session.id,
1821
+ messages: [...session.messages],
1822
+ title: session.title
1823
+ };
1824
+ };
1825
+ const saveChatSession = async session => {
1826
+ await chatSessionStorage.setSession({
1827
+ id: session.id,
1828
+ messages: [...session.messages],
1829
+ title: session.title
1830
+ });
1831
+ };
1832
+ const deleteChatSession = async id => {
1833
+ await chatSessionStorage.deleteSession(id);
1834
+ };
1835
+ const clearChatSessions = async () => {
1836
+ await chatSessionStorage.clear();
1837
+ };
1838
+
1670
1839
  const generateSessionId = () => {
1671
1840
  return crypto.randomUUID();
1672
1841
  };
1673
1842
 
1674
- const createSession = state => {
1843
+ const createSession = async state => {
1675
1844
  const id = generateSessionId();
1676
1845
  const session = {
1677
1846
  id,
1678
1847
  messages: [],
1679
1848
  title: `Chat ${state.sessions.length + 1}`
1680
1849
  };
1850
+ await saveChatSession(session);
1681
1851
  return {
1682
1852
  ...state,
1683
1853
  renamingSessionId: '',
@@ -1698,7 +1868,7 @@ const getNextSelectedSessionId = (sessions, deletedId) => {
1698
1868
  return sessions[nextIndex].id;
1699
1869
  };
1700
1870
 
1701
- const deleteSession = (state, id) => {
1871
+ const deleteSession = async (state, id) => {
1702
1872
  const {
1703
1873
  renamingSessionId,
1704
1874
  sessions
@@ -1707,6 +1877,7 @@ const deleteSession = (state, id) => {
1707
1877
  if (filtered.length === sessions.length) {
1708
1878
  return state;
1709
1879
  }
1880
+ await deleteChatSession(id);
1710
1881
  if (filtered.length === 0) {
1711
1882
  return {
1712
1883
  ...state,
@@ -1716,11 +1887,22 @@ const deleteSession = (state, id) => {
1716
1887
  viewMode: 'list'
1717
1888
  };
1718
1889
  }
1890
+ const nextSelectedSessionId = getNextSelectedSessionId(filtered, id);
1891
+ const loadedSession = await getChatSession(nextSelectedSessionId);
1892
+ const hydratedSessions = filtered.map(session => {
1893
+ if (session.id !== nextSelectedSessionId) {
1894
+ return session;
1895
+ }
1896
+ if (!loadedSession) {
1897
+ return session;
1898
+ }
1899
+ return loadedSession;
1900
+ });
1719
1901
  return {
1720
1902
  ...state,
1721
1903
  renamingSessionId: renamingSessionId === id ? '' : renamingSessionId,
1722
- selectedSessionId: getNextSelectedSessionId(filtered, id),
1723
- sessions: filtered
1904
+ selectedSessionId: nextSelectedSessionId,
1905
+ sessions: hydratedSessions
1724
1906
  };
1725
1907
  };
1726
1908
 
@@ -1774,14 +1956,27 @@ const handleSubmit = async state => {
1774
1956
  text: userText,
1775
1957
  time: userTime
1776
1958
  };
1959
+ let workingSessions = sessions;
1960
+ if (viewMode === 'detail') {
1961
+ const loadedSession = await getChatSession(selectedSessionId);
1962
+ if (loadedSession) {
1963
+ workingSessions = sessions.map(session => {
1964
+ if (session.id !== selectedSessionId) {
1965
+ return session;
1966
+ }
1967
+ return loadedSession;
1968
+ });
1969
+ }
1970
+ }
1777
1971
  let optimisticState;
1778
1972
  if (viewMode === 'list') {
1779
1973
  const newSessionId = generateSessionId();
1780
1974
  const newSession = {
1781
1975
  id: newSessionId,
1782
1976
  messages: [userMessage],
1783
- title: `Chat ${sessions.length + 1}`
1977
+ title: `Chat ${workingSessions.length + 1}`
1784
1978
  };
1979
+ await saveChatSession(newSession);
1785
1980
  optimisticState = focusInput({
1786
1981
  ...state,
1787
1982
  composerValue: '',
@@ -1789,11 +1984,11 @@ const handleSubmit = async state => {
1789
1984
  lastSubmittedSessionId: newSessionId,
1790
1985
  nextMessageId: nextMessageId + 1,
1791
1986
  selectedSessionId: newSessionId,
1792
- sessions: [...sessions, newSession],
1987
+ sessions: [...workingSessions, newSession],
1793
1988
  viewMode: 'detail'
1794
1989
  });
1795
1990
  } else {
1796
- const updatedSessions = sessions.map(session => {
1991
+ const updatedSessions = workingSessions.map(session => {
1797
1992
  if (session.id !== selectedSessionId) {
1798
1993
  return session;
1799
1994
  }
@@ -1802,6 +1997,10 @@ const handleSubmit = async state => {
1802
1997
  messages: [...session.messages, userMessage]
1803
1998
  };
1804
1999
  });
2000
+ const selectedSession = updatedSessions.find(session => session.id === selectedSessionId);
2001
+ if (selectedSession) {
2002
+ await saveChatSession(selectedSession);
2003
+ }
1805
2004
  optimisticState = focusInput({
1806
2005
  ...state,
1807
2006
  composerValue: '',
@@ -1824,6 +2023,10 @@ const handleSubmit = async state => {
1824
2023
  messages: [...session.messages, assistantMessage]
1825
2024
  };
1826
2025
  });
2026
+ const selectedSession = updatedSessions.find(session => session.id === optimisticState.selectedSessionId);
2027
+ if (selectedSession) {
2028
+ await saveChatSession(selectedSession);
2029
+ }
1827
2030
  return focusInput({
1828
2031
  ...optimisticState,
1829
2032
  nextMessageId: optimisticState.nextMessageId + 1,
@@ -1845,15 +2048,26 @@ const handleClickSend = async state => {
1845
2048
  return handleSubmit(submitState);
1846
2049
  };
1847
2050
 
1848
- const selectSession = (state, id) => {
2051
+ const selectSession = async (state, id) => {
1849
2052
  const exists = state.sessions.some(session => session.id === id);
1850
2053
  if (!exists) {
1851
2054
  return state;
1852
2055
  }
2056
+ const loadedSession = await getChatSession(id);
2057
+ const sessions = state.sessions.map(session => {
2058
+ if (session.id !== id) {
2059
+ return session;
2060
+ }
2061
+ if (!loadedSession) {
2062
+ return session;
2063
+ }
2064
+ return loadedSession;
2065
+ });
1853
2066
  return {
1854
2067
  ...state,
1855
2068
  renamingSessionId: '',
1856
2069
  selectedSessionId: id,
2070
+ sessions,
1857
2071
  viewMode: 'detail'
1858
2072
  };
1859
2073
  };
@@ -2007,7 +2221,7 @@ const handleInputFocus = async (state, name) => {
2007
2221
  };
2008
2222
  };
2009
2223
 
2010
- const submitRename = state => {
2224
+ const submitRename = async state => {
2011
2225
  const {
2012
2226
  composerValue,
2013
2227
  renamingSessionId,
@@ -2029,6 +2243,10 @@ const submitRename = state => {
2029
2243
  title
2030
2244
  };
2031
2245
  });
2246
+ const renamedSession = updatedSessions.find(session => session.id === renamingSessionId);
2247
+ if (renamedSession) {
2248
+ await saveChatSession(renamedSession);
2249
+ }
2032
2250
  return {
2033
2251
  ...state,
2034
2252
  composerValue: '',
@@ -2061,6 +2279,13 @@ const handleKeyDown = async (state, key, shiftKey) => {
2061
2279
  return handleSubmit(submitState);
2062
2280
  };
2063
2281
 
2282
+ const handleModelChange = async (state, value) => {
2283
+ return {
2284
+ ...state,
2285
+ selectedModelId: value
2286
+ };
2287
+ };
2288
+
2064
2289
  const handleNewline = async state => {
2065
2290
  return handleInput(state, `${state.composerValue}\n`);
2066
2291
  };
@@ -2121,6 +2346,19 @@ const getSavedBounds = savedState => {
2121
2346
  };
2122
2347
  };
2123
2348
 
2349
+ const getSavedSelectedModelId = savedState => {
2350
+ if (!isObject(savedState)) {
2351
+ return undefined;
2352
+ }
2353
+ const {
2354
+ selectedModelId
2355
+ } = savedState;
2356
+ if (typeof selectedModelId !== 'string') {
2357
+ return undefined;
2358
+ }
2359
+ return selectedModelId;
2360
+ };
2361
+
2124
2362
  const getSavedSelectedSessionId = savedState => {
2125
2363
  if (!isObject(savedState)) {
2126
2364
  return undefined;
@@ -2147,23 +2385,79 @@ const getSavedSessions = savedState => {
2147
2385
  return sessions;
2148
2386
  };
2149
2387
 
2388
+ const getSavedViewMode = savedState => {
2389
+ if (!isObject(savedState)) {
2390
+ return undefined;
2391
+ }
2392
+ const {
2393
+ viewMode
2394
+ } = savedState;
2395
+ if (viewMode !== 'list' && viewMode !== 'detail') {
2396
+ return undefined;
2397
+ }
2398
+ return viewMode;
2399
+ };
2400
+
2401
+ const toSummarySession = session => {
2402
+ return {
2403
+ id: session.id,
2404
+ messages: [],
2405
+ title: session.title
2406
+ };
2407
+ };
2408
+ const loadSelectedSessionMessages = async (sessions, selectedSessionId) => {
2409
+ if (!selectedSessionId) {
2410
+ return sessions;
2411
+ }
2412
+ const loadedSession = await getChatSession(selectedSessionId);
2413
+ if (!loadedSession) {
2414
+ return sessions;
2415
+ }
2416
+ return sessions.map(session => {
2417
+ if (session.id !== selectedSessionId) {
2418
+ return session;
2419
+ }
2420
+ return loadedSession;
2421
+ });
2422
+ };
2150
2423
  const loadContent = async (state, savedState) => {
2151
2424
  const savedBounds = getSavedBounds(savedState);
2152
- const sessions = getSavedSessions(savedState) || state.sessions;
2425
+ const savedSelectedModelId = getSavedSelectedModelId(savedState);
2426
+ const savedViewMode = getSavedViewMode(savedState);
2427
+ const legacySavedSessions = getSavedSessions(savedState);
2428
+ const storedSessions = await listChatSessions();
2429
+ let sessions = storedSessions;
2430
+ if (sessions.length === 0 && legacySavedSessions && legacySavedSessions.length > 0) {
2431
+ for (const session of legacySavedSessions) {
2432
+ await saveChatSession(session);
2433
+ }
2434
+ sessions = legacySavedSessions.map(toSummarySession);
2435
+ }
2436
+ if (sessions.length === 0 && state.sessions.length > 0) {
2437
+ for (const session of state.sessions) {
2438
+ await saveChatSession(session);
2439
+ }
2440
+ sessions = state.sessions.map(toSummarySession);
2441
+ }
2153
2442
  const preferredSessionId = getSavedSelectedSessionId(savedState) || state.selectedSessionId;
2443
+ const preferredModelId = savedSelectedModelId || state.selectedModelId;
2444
+ const selectedModelId = state.models.some(model => model.id === preferredModelId) ? preferredModelId : state.models[0]?.id || '';
2154
2445
  const selectedSessionId = sessions.some(session => session.id === preferredSessionId) ? preferredSessionId : sessions[0]?.id || '';
2155
- const viewMode = sessions.length === 0 ? 'list' : state.viewMode === 'detail' ? 'detail' : 'list';
2446
+ sessions = await loadSelectedSessionMessages(sessions, selectedSessionId);
2447
+ const preferredViewMode = savedViewMode || state.viewMode;
2448
+ const viewMode = sessions.length === 0 || !selectedSessionId ? 'list' : preferredViewMode === 'detail' ? 'detail' : 'list';
2156
2449
  return {
2157
2450
  ...state,
2158
2451
  ...savedBounds,
2159
2452
  initial: false,
2453
+ selectedModelId,
2160
2454
  selectedSessionId,
2161
2455
  sessions,
2162
2456
  viewMode
2163
2457
  };
2164
2458
  };
2165
2459
 
2166
- const openMockSession = (state, mockSessionId, mockChatMessages) => {
2460
+ const openMockSession = async (state, mockSessionId, mockChatMessages) => {
2167
2461
  if (!mockSessionId) {
2168
2462
  return state;
2169
2463
  }
@@ -2181,6 +2475,10 @@ const openMockSession = (state, mockSessionId, mockChatMessages) => {
2181
2475
  messages: mockChatMessages,
2182
2476
  title: mockSessionId
2183
2477
  }];
2478
+ const selectedSession = sessions.find(session => session.id === mockSessionId);
2479
+ if (selectedSession) {
2480
+ await saveChatSession(selectedSession);
2481
+ }
2184
2482
  return {
2185
2483
  ...state,
2186
2484
  renamingSessionId: '',
@@ -2226,6 +2524,8 @@ const renderFocusContext = (oldState, newState) => {
2226
2524
  const ChatActions = 'ChatActions';
2227
2525
  const ChatName = 'ChatName';
2228
2526
  const ChatSendArea = 'ChatSendArea';
2527
+ const ChatSendAreaBottom = 'ChatSendAreaBottom';
2528
+ const ChatSendAreaContent = 'ChatSendAreaContent';
2229
2529
  const Chat = 'Chat';
2230
2530
  const ChatHeader = 'ChatHeader';
2231
2531
  const Button = 'Button';
@@ -2234,11 +2534,16 @@ const ButtonPrimary = 'ButtonPrimary';
2234
2534
  const IconButton = 'IconButton';
2235
2535
  const Label = 'Label';
2236
2536
  const ChatList = 'ChatList';
2537
+ const ChatListEmpty = 'ChatListEmpty';
2237
2538
  const ChatListItem = 'ChatListItem';
2238
2539
  const ChatListItemLabel = 'ChatListItemLabel';
2239
2540
  const Markdown = 'Markdown';
2240
2541
  const Message = 'Message';
2542
+ const MessageUser = 'MessageUser';
2543
+ const MessageAssistant = 'MessageAssistant';
2241
2544
  const MultilineInputBox = 'MultilineInputBox';
2545
+ const Option = 'Option';
2546
+ const Select = 'Select';
2242
2547
  const Viewlet = 'Viewlet';
2243
2548
  const ChatWelcomeMessage = 'ChatWelcomeMessage';
2244
2549
 
@@ -2254,14 +2559,28 @@ const HandleClickBack = 16;
2254
2559
  const HandleClickList = 17;
2255
2560
  const HandleClickDelete = 18;
2256
2561
  const HandleSubmit = 19;
2562
+ const HandleModelChange = 20;
2257
2563
 
2258
- const getChatSendAreaDom = composerValue => {
2564
+ const getChatSendAreaDom = (composerValue, models, selectedModelId) => {
2259
2565
  const isSendDisabled = composerValue.trim() === '';
2260
2566
  const sendButtonClassName = isSendDisabled ? `${Button} ${ButtonPrimary} ${ButtonDisabled}` : `${Button} ${ButtonPrimary}`;
2567
+ const modelOptions = models.flatMap(model => {
2568
+ return [{
2569
+ childCount: 1,
2570
+ className: Option,
2571
+ selected: model.id === selectedModelId,
2572
+ type: Option$1,
2573
+ value: model.id
2574
+ }, text(model.name)];
2575
+ });
2261
2576
  return [{
2262
- childCount: 2,
2577
+ childCount: 1,
2263
2578
  className: ChatSendArea,
2264
2579
  type: Div
2580
+ }, {
2581
+ childCount: 2,
2582
+ className: ChatSendAreaContent,
2583
+ type: Div
2265
2584
  }, {
2266
2585
  childCount: 0,
2267
2586
  className: MultilineInputBox,
@@ -2272,6 +2591,17 @@ const getChatSendAreaDom = composerValue => {
2272
2591
  type: TextArea,
2273
2592
  value: composerValue
2274
2593
  }, {
2594
+ childCount: 2,
2595
+ className: ChatSendAreaBottom,
2596
+ type: Div
2597
+ }, {
2598
+ childCount: models.length,
2599
+ className: Select,
2600
+ name: 'model',
2601
+ onInput: HandleModelChange,
2602
+ type: Select$1,
2603
+ value: selectedModelId
2604
+ }, ...modelOptions, {
2275
2605
  childCount: 1,
2276
2606
  className: sendButtonClassName,
2277
2607
  disabled: isSendDisabled,
@@ -2348,9 +2678,10 @@ const getChatHeaderDomDetailMode = selectedSessionTitle => {
2348
2678
  };
2349
2679
 
2350
2680
  const getChatMessageDom = message => {
2681
+ const roleClassName = message.role === 'user' ? MessageUser : MessageAssistant;
2351
2682
  return [{
2352
2683
  childCount: 2,
2353
- className: Message,
2684
+ className: mergeClassNames(Message, roleClassName),
2354
2685
  type: Div
2355
2686
  }, {
2356
2687
  childCount: 1,
@@ -2378,7 +2709,7 @@ const getMessagesDom = messages => {
2378
2709
  }, ...messages.flatMap(getChatMessageDom)];
2379
2710
  };
2380
2711
 
2381
- const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue) => {
2712
+ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId) => {
2382
2713
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
2383
2714
  const selectedSessionTitle = selectedSession?.title || chatTitle;
2384
2715
  const messages = selectedSession ? selectedSession.messages : [];
@@ -2386,7 +2717,7 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue)
2386
2717
  childCount: 3,
2387
2718
  className: mergeClassNames(Viewlet, Chat),
2388
2719
  type: Div
2389
- }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages), ...getChatSendAreaDom(composerValue)];
2720
+ }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages), ...getChatSendAreaDom(composerValue, models, selectedModelId)];
2390
2721
  };
2391
2722
 
2392
2723
  const getChatHeaderListModeDom = () => {
@@ -2404,7 +2735,7 @@ const getChatHeaderListModeDom = () => {
2404
2735
  const getEmptyChatSessionsDom = () => {
2405
2736
  return [{
2406
2737
  childCount: 1,
2407
- className: ChatList,
2738
+ className: ChatListEmpty,
2408
2739
  type: Div
2409
2740
  }, {
2410
2741
  childCount: 1,
@@ -2438,7 +2769,7 @@ const getSessionDom = session => {
2438
2769
  onClick: HandleClickDelete,
2439
2770
  role: Button$2,
2440
2771
  tabIndex: 0,
2441
- title: deleteChatSession,
2772
+ title: deleteChatSession$1,
2442
2773
  type: Button$1
2443
2774
  }, text('🗑')];
2444
2775
  };
@@ -2455,12 +2786,12 @@ const getChatListDom = (sessions, selectedSessionId) => {
2455
2786
  }, ...sessions.flatMap(getSessionDom)];
2456
2787
  };
2457
2788
 
2458
- const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue) => {
2789
+ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId) => {
2459
2790
  return [{
2460
2791
  childCount: 3,
2461
2792
  className: mergeClassNames(Viewlet, Chat),
2462
2793
  type: Div
2463
- }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions), ...getChatSendAreaDom(composerValue)];
2794
+ }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions), ...getChatSendAreaDom(composerValue, models, selectedModelId)];
2464
2795
  };
2465
2796
 
2466
2797
  const getChatModeUnsupportedVirtualDom = () => {
@@ -2470,12 +2801,12 @@ const getChatModeUnsupportedVirtualDom = () => {
2470
2801
  }, text('Unknown view mode')];
2471
2802
  };
2472
2803
 
2473
- const getChatVirtualDom = (sessions, selectedSessionId, composerValue, viewMode) => {
2804
+ const getChatVirtualDom = (sessions, selectedSessionId, composerValue, viewMode, models, selectedModelId) => {
2474
2805
  switch (viewMode) {
2475
2806
  case 'detail':
2476
- return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue);
2807
+ return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId);
2477
2808
  case 'list':
2478
- return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue);
2809
+ return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId);
2479
2810
  default:
2480
2811
  return getChatModeUnsupportedVirtualDom();
2481
2812
  }
@@ -2485,6 +2816,8 @@ const renderItems = (oldState, newState) => {
2485
2816
  const {
2486
2817
  composerValue,
2487
2818
  initial,
2819
+ models,
2820
+ selectedModelId,
2488
2821
  selectedSessionId,
2489
2822
  sessions,
2490
2823
  uid,
@@ -2493,7 +2826,7 @@ const renderItems = (oldState, newState) => {
2493
2826
  if (initial) {
2494
2827
  return [SetDom2, uid, []];
2495
2828
  }
2496
- const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, viewMode);
2829
+ const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, viewMode, models, selectedModelId);
2497
2830
  return [SetDom2, uid, dom];
2498
2831
  };
2499
2832
 
@@ -2581,6 +2914,9 @@ const renderEventListeners = () => {
2581
2914
  }, {
2582
2915
  name: HandleInput,
2583
2916
  params: ['handleInput', TargetValue]
2917
+ }, {
2918
+ name: HandleModelChange,
2919
+ params: ['handleModelChange', TargetValue]
2584
2920
  }, {
2585
2921
  name: HandleFocus,
2586
2922
  params: ['handleInputFocus', TargetName]
@@ -2598,6 +2934,7 @@ const rerender = state => {
2598
2934
  };
2599
2935
 
2600
2936
  const reset = async state => {
2937
+ await clearChatSessions();
2601
2938
  return {
2602
2939
  ...state,
2603
2940
  composerValue: '',
@@ -2620,8 +2957,8 @@ const saveState = state => {
2620
2957
  height,
2621
2958
  nextMessageId,
2622
2959
  renamingSessionId,
2960
+ selectedModelId,
2623
2961
  selectedSessionId,
2624
- sessions,
2625
2962
  viewMode,
2626
2963
  width,
2627
2964
  x,
@@ -2632,8 +2969,8 @@ const saveState = state => {
2632
2969
  height,
2633
2970
  nextMessageId,
2634
2971
  renamingSessionId,
2972
+ selectedModelId,
2635
2973
  selectedSessionId,
2636
- sessions,
2637
2974
  viewMode,
2638
2975
  width,
2639
2976
  x,
@@ -2681,6 +3018,7 @@ const commandMap = {
2681
3018
  'Chat.handleInput': wrapCommand(handleInput),
2682
3019
  'Chat.handleInputFocus': wrapCommand(handleInputFocus),
2683
3020
  'Chat.handleKeyDown': wrapCommand(handleKeyDown),
3021
+ 'Chat.handleModelChange': wrapCommand(handleModelChange),
2684
3022
  'Chat.handleSubmit': wrapCommand(handleSubmit),
2685
3023
  'Chat.initialize': initialize,
2686
3024
  'Chat.loadContent': wrapCommand(loadContent),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",