@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.
- package/dist/chatViewWorkerMain.js +367 -29
- package/package.json +1 -1
|
@@ -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:
|
|
1723
|
-
sessions:
|
|
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 ${
|
|
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: [...
|
|
1987
|
+
sessions: [...workingSessions, newSession],
|
|
1793
1988
|
viewMode: 'detail'
|
|
1794
1989
|
});
|
|
1795
1990
|
} else {
|
|
1796
|
-
const updatedSessions =
|
|
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
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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),
|