@lvce-editor/chat-view 1.20.0 → 2.1.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 +926 -140
- package/package.json +2 -7
|
@@ -698,7 +698,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
|
|
|
698
698
|
const errorProperty = getErrorProperty(error, prettyError);
|
|
699
699
|
return create$1$1(id, errorProperty);
|
|
700
700
|
};
|
|
701
|
-
const create$
|
|
701
|
+
const create$a = (message, result) => {
|
|
702
702
|
return {
|
|
703
703
|
id: message.id,
|
|
704
704
|
jsonrpc: Two$1,
|
|
@@ -707,7 +707,7 @@ const create$9 = (message, result) => {
|
|
|
707
707
|
};
|
|
708
708
|
const getSuccessResponse = (message, result) => {
|
|
709
709
|
const resultProperty = result ?? null;
|
|
710
|
-
return create$
|
|
710
|
+
return create$a(message, resultProperty);
|
|
711
711
|
};
|
|
712
712
|
const getErrorResponseSimple = (id, error) => {
|
|
713
713
|
return {
|
|
@@ -801,7 +801,7 @@ const handleJsonRpcMessage = async (...args) => {
|
|
|
801
801
|
|
|
802
802
|
const Two = '2.0';
|
|
803
803
|
|
|
804
|
-
const create$
|
|
804
|
+
const create$9 = (method, params) => {
|
|
805
805
|
return {
|
|
806
806
|
jsonrpc: Two,
|
|
807
807
|
method,
|
|
@@ -809,7 +809,7 @@ const create$8 = (method, params) => {
|
|
|
809
809
|
};
|
|
810
810
|
};
|
|
811
811
|
|
|
812
|
-
const create$
|
|
812
|
+
const create$8 = (id, method, params) => {
|
|
813
813
|
const message = {
|
|
814
814
|
id,
|
|
815
815
|
jsonrpc: Two,
|
|
@@ -820,12 +820,12 @@ const create$7 = (id, method, params) => {
|
|
|
820
820
|
};
|
|
821
821
|
|
|
822
822
|
let id$1 = 0;
|
|
823
|
-
const create$
|
|
823
|
+
const create$7 = () => {
|
|
824
824
|
return ++id$1;
|
|
825
825
|
};
|
|
826
826
|
|
|
827
827
|
const registerPromise = map => {
|
|
828
|
-
const id = create$
|
|
828
|
+
const id = create$7();
|
|
829
829
|
const {
|
|
830
830
|
promise,
|
|
831
831
|
resolve
|
|
@@ -842,7 +842,7 @@ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer)
|
|
|
842
842
|
id,
|
|
843
843
|
promise
|
|
844
844
|
} = registerPromise(callbacks);
|
|
845
|
-
const message = create$
|
|
845
|
+
const message = create$8(id, method, params);
|
|
846
846
|
if (useSendAndTransfer && ipc.sendAndTransfer) {
|
|
847
847
|
ipc.sendAndTransfer(message);
|
|
848
848
|
} else {
|
|
@@ -878,7 +878,7 @@ const createRpc = ipc => {
|
|
|
878
878
|
* @deprecated
|
|
879
879
|
*/
|
|
880
880
|
send(method, ...params) {
|
|
881
|
-
const message = create$
|
|
881
|
+
const message = create$9(method, params);
|
|
882
882
|
ipc.send(message);
|
|
883
883
|
}
|
|
884
884
|
};
|
|
@@ -918,7 +918,7 @@ const listen$1 = async (module, options) => {
|
|
|
918
918
|
return ipc;
|
|
919
919
|
};
|
|
920
920
|
|
|
921
|
-
const create$
|
|
921
|
+
const create$6 = async ({
|
|
922
922
|
commandMap,
|
|
923
923
|
isMessagePortOpen = true,
|
|
924
924
|
messagePort
|
|
@@ -936,7 +936,7 @@ const create$5 = async ({
|
|
|
936
936
|
return rpc;
|
|
937
937
|
};
|
|
938
938
|
|
|
939
|
-
const create$
|
|
939
|
+
const create$5 = async ({
|
|
940
940
|
commandMap,
|
|
941
941
|
isMessagePortOpen,
|
|
942
942
|
send
|
|
@@ -946,13 +946,55 @@ const create$4 = async ({
|
|
|
946
946
|
port2
|
|
947
947
|
} = new MessageChannel();
|
|
948
948
|
await send(port1);
|
|
949
|
-
return create$
|
|
949
|
+
return create$6({
|
|
950
950
|
commandMap,
|
|
951
951
|
isMessagePortOpen,
|
|
952
952
|
messagePort: port2
|
|
953
953
|
});
|
|
954
954
|
};
|
|
955
955
|
|
|
956
|
+
const createSharedLazyRpc = factory => {
|
|
957
|
+
let rpcPromise;
|
|
958
|
+
const getOrCreate = () => {
|
|
959
|
+
if (!rpcPromise) {
|
|
960
|
+
rpcPromise = factory();
|
|
961
|
+
}
|
|
962
|
+
return rpcPromise;
|
|
963
|
+
};
|
|
964
|
+
return {
|
|
965
|
+
async dispose() {
|
|
966
|
+
const rpc = await getOrCreate();
|
|
967
|
+
await rpc.dispose();
|
|
968
|
+
},
|
|
969
|
+
async invoke(method, ...params) {
|
|
970
|
+
const rpc = await getOrCreate();
|
|
971
|
+
return rpc.invoke(method, ...params);
|
|
972
|
+
},
|
|
973
|
+
async invokeAndTransfer(method, ...params) {
|
|
974
|
+
const rpc = await getOrCreate();
|
|
975
|
+
return rpc.invokeAndTransfer(method, ...params);
|
|
976
|
+
},
|
|
977
|
+
async send(method, ...params) {
|
|
978
|
+
const rpc = await getOrCreate();
|
|
979
|
+
rpc.send(method, ...params);
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
const create$4 = async ({
|
|
985
|
+
commandMap,
|
|
986
|
+
isMessagePortOpen,
|
|
987
|
+
send
|
|
988
|
+
}) => {
|
|
989
|
+
return createSharedLazyRpc(() => {
|
|
990
|
+
return create$5({
|
|
991
|
+
commandMap,
|
|
992
|
+
isMessagePortOpen,
|
|
993
|
+
send
|
|
994
|
+
});
|
|
995
|
+
});
|
|
996
|
+
};
|
|
997
|
+
|
|
956
998
|
const create$3 = async ({
|
|
957
999
|
commandMap
|
|
958
1000
|
}) => {
|
|
@@ -964,9 +1006,6 @@ const create$3 = async ({
|
|
|
964
1006
|
return rpc;
|
|
965
1007
|
};
|
|
966
1008
|
|
|
967
|
-
const ExtensionHostWorker = 44;
|
|
968
|
-
const RendererWorker = 1;
|
|
969
|
-
|
|
970
1009
|
const createMockRpc = ({
|
|
971
1010
|
commandMap
|
|
972
1011
|
}) => {
|
|
@@ -988,7 +1027,7 @@ const createMockRpc = ({
|
|
|
988
1027
|
};
|
|
989
1028
|
|
|
990
1029
|
const rpcs = Object.create(null);
|
|
991
|
-
const set$
|
|
1030
|
+
const set$4 = (id, rpc) => {
|
|
992
1031
|
rpcs[id] = rpc;
|
|
993
1032
|
};
|
|
994
1033
|
const get$2 = id => {
|
|
@@ -1021,7 +1060,7 @@ const create$2 = rpcId => {
|
|
|
1021
1060
|
const mockRpc = createMockRpc({
|
|
1022
1061
|
commandMap
|
|
1023
1062
|
});
|
|
1024
|
-
set$
|
|
1063
|
+
set$4(rpcId, mockRpc);
|
|
1025
1064
|
// @ts-ignore
|
|
1026
1065
|
mockRpc[Symbol.dispose] = () => {
|
|
1027
1066
|
remove(rpcId);
|
|
@@ -1030,11 +1069,35 @@ const create$2 = rpcId => {
|
|
|
1030
1069
|
return mockRpc;
|
|
1031
1070
|
},
|
|
1032
1071
|
set(rpc) {
|
|
1033
|
-
set$
|
|
1072
|
+
set$4(rpcId, rpc);
|
|
1034
1073
|
}
|
|
1035
1074
|
};
|
|
1036
1075
|
};
|
|
1037
1076
|
|
|
1077
|
+
const {
|
|
1078
|
+
set: set$3
|
|
1079
|
+
} = create$2(6002);
|
|
1080
|
+
|
|
1081
|
+
const ClientX = 'event.clientX';
|
|
1082
|
+
const ClientY = 'event.clientY';
|
|
1083
|
+
const Key = 'event.key';
|
|
1084
|
+
const ShiftKey = 'event.shiftKey';
|
|
1085
|
+
const TargetName = 'event.target.name';
|
|
1086
|
+
const TargetValue = 'event.target.value';
|
|
1087
|
+
|
|
1088
|
+
const ExtensionHostWorker = 44;
|
|
1089
|
+
const RendererWorker = 1;
|
|
1090
|
+
|
|
1091
|
+
const FocusSelector = 'Viewlet.focusSelector';
|
|
1092
|
+
const SetCss = 'Viewlet.setCss';
|
|
1093
|
+
const SetDom2 = 'Viewlet.setDom2';
|
|
1094
|
+
const SetFocusContext = 'Viewlet.setFocusContext';
|
|
1095
|
+
const SetProperty = 'Viewlet.setProperty';
|
|
1096
|
+
const SetValueByName = 'Viewlet.setValueByName';
|
|
1097
|
+
const SetPatches = 'Viewlet.setPatches';
|
|
1098
|
+
|
|
1099
|
+
const FocusChatInput = 8000;
|
|
1100
|
+
|
|
1038
1101
|
const {
|
|
1039
1102
|
invoke: invoke$1,
|
|
1040
1103
|
set: set$2
|
|
@@ -1251,6 +1314,9 @@ const chats = () => {
|
|
|
1251
1314
|
const newChat = () => {
|
|
1252
1315
|
return i18nString('New Chat');
|
|
1253
1316
|
};
|
|
1317
|
+
const debug = () => {
|
|
1318
|
+
return i18nString('Debug');
|
|
1319
|
+
};
|
|
1254
1320
|
const backToChats = () => {
|
|
1255
1321
|
return i18nString('Back to chats');
|
|
1256
1322
|
};
|
|
@@ -1528,23 +1594,6 @@ const diff2 = uid => {
|
|
|
1528
1594
|
return result;
|
|
1529
1595
|
};
|
|
1530
1596
|
|
|
1531
|
-
const ClientX = 'event.clientX';
|
|
1532
|
-
const ClientY = 'event.clientY';
|
|
1533
|
-
const Key = 'event.key';
|
|
1534
|
-
const ShiftKey = 'event.shiftKey';
|
|
1535
|
-
const TargetName = 'event.target.name';
|
|
1536
|
-
const TargetValue = 'event.target.value';
|
|
1537
|
-
|
|
1538
|
-
const FocusSelector = 'Viewlet.focusSelector';
|
|
1539
|
-
const SetCss = 'Viewlet.setCss';
|
|
1540
|
-
const SetDom2 = 'Viewlet.setDom2';
|
|
1541
|
-
const SetFocusContext = 'Viewlet.setFocusContext';
|
|
1542
|
-
const SetProperty = 'Viewlet.setProperty';
|
|
1543
|
-
const SetValueByName = 'Viewlet.setValueByName';
|
|
1544
|
-
const SetPatches = 'Viewlet.setPatches';
|
|
1545
|
-
|
|
1546
|
-
const FocusChatInput = 8000;
|
|
1547
|
-
|
|
1548
1597
|
const Button$2 = 'button';
|
|
1549
1598
|
|
|
1550
1599
|
const Button$1 = 1;
|
|
@@ -1934,29 +1983,6 @@ const requestToPromise = async createRequest => {
|
|
|
1934
1983
|
return promise;
|
|
1935
1984
|
};
|
|
1936
1985
|
|
|
1937
|
-
const openSessionsDatabase = async (databaseName, databaseVersion, storeName) => {
|
|
1938
|
-
const request = indexedDB.open(databaseName, databaseVersion);
|
|
1939
|
-
request.addEventListener('upgradeneeded', () => {
|
|
1940
|
-
const database = request.result;
|
|
1941
|
-
if (!database.objectStoreNames.contains(storeName)) {
|
|
1942
|
-
database.createObjectStore(storeName, {
|
|
1943
|
-
keyPath: 'id'
|
|
1944
|
-
});
|
|
1945
|
-
}
|
|
1946
|
-
});
|
|
1947
|
-
return requestToPromise(() => request);
|
|
1948
|
-
};
|
|
1949
|
-
|
|
1950
|
-
const getDatabase = async (getDatabasePromise, setDatabasePromise, databaseName, databaseVersion, storeName) => {
|
|
1951
|
-
const existingDatabasePromise = getDatabasePromise();
|
|
1952
|
-
if (existingDatabasePromise) {
|
|
1953
|
-
return existingDatabasePromise;
|
|
1954
|
-
}
|
|
1955
|
-
const nextDatabasePromise = openSessionsDatabase(databaseName, databaseVersion, storeName);
|
|
1956
|
-
setDatabasePromise(nextDatabasePromise);
|
|
1957
|
-
return nextDatabasePromise;
|
|
1958
|
-
};
|
|
1959
|
-
|
|
1960
1986
|
const transactionToPromise = async createTransaction => {
|
|
1961
1987
|
const transaction = createTransaction();
|
|
1962
1988
|
const {
|
|
@@ -1976,97 +2002,522 @@ const transactionToPromise = async createTransaction => {
|
|
|
1976
2002
|
return promise;
|
|
1977
2003
|
};
|
|
1978
2004
|
|
|
1979
|
-
const
|
|
1980
|
-
const
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
await transactionToPromise(createTransaction);
|
|
2005
|
+
const toChatViewEvent = event => {
|
|
2006
|
+
const {
|
|
2007
|
+
eventId,
|
|
2008
|
+
...chatViewEvent
|
|
2009
|
+
} = event;
|
|
2010
|
+
return chatViewEvent;
|
|
1986
2011
|
};
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
const database = await getDatabase(getDatabasePromise, setDatabasePromise, databaseName, databaseVersion, storeName);
|
|
1990
|
-
const transaction = database.transaction(storeName, 'readwrite');
|
|
1991
|
-
const createTransaction = () => transaction;
|
|
1992
|
-
const store = transaction.objectStore(storeName);
|
|
1993
|
-
store.delete(id);
|
|
1994
|
-
await transactionToPromise(createTransaction);
|
|
2012
|
+
const now$1 = () => {
|
|
2013
|
+
return new Date().toISOString();
|
|
1995
2014
|
};
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
const database = await getDatabase(getDatabasePromise, setDatabasePromise, databaseName, databaseVersion, storeName);
|
|
1999
|
-
const transaction = database.transaction(storeName, 'readonly');
|
|
2000
|
-
const store = transaction.objectStore(storeName);
|
|
2001
|
-
const result = await requestToPromise(() => store.get(id));
|
|
2002
|
-
return result;
|
|
2015
|
+
const isSameMessage$1 = (a, b) => {
|
|
2016
|
+
return a.id === b.id && a.inProgress === b.inProgress && a.role === b.role && a.text === b.text && a.time === b.time && JSON.stringify(a.toolCalls || []) === JSON.stringify(b.toolCalls || []);
|
|
2003
2017
|
};
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
const result = await requestToPromise(() => store.getAll());
|
|
2010
|
-
return result;
|
|
2018
|
+
const canAppendMessages$1 = (previousMessages, nextMessages) => {
|
|
2019
|
+
if (nextMessages.length < previousMessages.length) {
|
|
2020
|
+
return false;
|
|
2021
|
+
}
|
|
2022
|
+
return previousMessages.every((message, index) => isSameMessage$1(message, nextMessages[index]));
|
|
2011
2023
|
};
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2024
|
+
const canUpdateMessages$1 = (previousMessages, nextMessages) => {
|
|
2025
|
+
if (previousMessages.length !== nextMessages.length) {
|
|
2026
|
+
return false;
|
|
2027
|
+
}
|
|
2028
|
+
for (let i = 0; i < previousMessages.length; i += 1) {
|
|
2029
|
+
const previous = previousMessages[i];
|
|
2030
|
+
const next = nextMessages[i];
|
|
2031
|
+
if (previous.id !== next.id || previous.role !== next.role) {
|
|
2032
|
+
return false;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
return true;
|
|
2036
|
+
};
|
|
2037
|
+
const getMutationEvents$1 = (previous, next) => {
|
|
2038
|
+
const timestamp = now$1();
|
|
2039
|
+
const events = [];
|
|
2040
|
+
if (!previous) {
|
|
2041
|
+
events.push({
|
|
2042
|
+
sessionId: next.id,
|
|
2043
|
+
timestamp,
|
|
2044
|
+
title: next.title,
|
|
2045
|
+
type: 'chat-session-created'
|
|
2046
|
+
});
|
|
2047
|
+
for (const message of next.messages) {
|
|
2048
|
+
events.push({
|
|
2049
|
+
message,
|
|
2050
|
+
sessionId: next.id,
|
|
2051
|
+
timestamp,
|
|
2052
|
+
type: 'chat-message-added'
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
return events;
|
|
2056
|
+
}
|
|
2057
|
+
if (previous.title !== next.title) {
|
|
2058
|
+
events.push({
|
|
2059
|
+
sessionId: next.id,
|
|
2060
|
+
timestamp,
|
|
2061
|
+
title: next.title,
|
|
2062
|
+
type: 'chat-session-title-updated'
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
if (canAppendMessages$1(previous.messages, next.messages)) {
|
|
2066
|
+
for (let i = previous.messages.length; i < next.messages.length; i += 1) {
|
|
2067
|
+
events.push({
|
|
2068
|
+
message: next.messages[i],
|
|
2069
|
+
sessionId: next.id,
|
|
2070
|
+
timestamp,
|
|
2071
|
+
type: 'chat-message-added'
|
|
2072
|
+
});
|
|
2073
|
+
}
|
|
2074
|
+
return events;
|
|
2075
|
+
}
|
|
2076
|
+
if (canUpdateMessages$1(previous.messages, next.messages)) {
|
|
2077
|
+
for (let i = 0; i < previous.messages.length; i += 1) {
|
|
2078
|
+
const previousMessage = previous.messages[i];
|
|
2079
|
+
const nextMessage = next.messages[i];
|
|
2080
|
+
if (!isSameMessage$1(previousMessage, nextMessage)) {
|
|
2081
|
+
events.push({
|
|
2082
|
+
inProgress: nextMessage.inProgress,
|
|
2083
|
+
messageId: nextMessage.id,
|
|
2084
|
+
sessionId: next.id,
|
|
2085
|
+
text: nextMessage.text,
|
|
2086
|
+
time: nextMessage.time,
|
|
2087
|
+
timestamp,
|
|
2088
|
+
toolCalls: nextMessage.toolCalls,
|
|
2089
|
+
type: 'chat-message-updated'
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
return events;
|
|
2094
|
+
}
|
|
2095
|
+
events.push({
|
|
2096
|
+
messages: [...next.messages],
|
|
2097
|
+
sessionId: next.id,
|
|
2098
|
+
timestamp,
|
|
2099
|
+
type: 'chat-session-messages-replaced'
|
|
2100
|
+
});
|
|
2101
|
+
return events;
|
|
2102
|
+
};
|
|
2103
|
+
const replaySession$1 = (id, summary, events) => {
|
|
2104
|
+
let deleted = false;
|
|
2105
|
+
let title = summary?.title || '';
|
|
2106
|
+
let messages = summary?.messages ? [...summary.messages] : [];
|
|
2107
|
+
for (const event of events) {
|
|
2108
|
+
if (event.sessionId !== id) {
|
|
2109
|
+
continue;
|
|
2110
|
+
}
|
|
2111
|
+
if (event.type === 'chat-session-created') {
|
|
2112
|
+
const {
|
|
2113
|
+
title: eventTitle
|
|
2114
|
+
} = event;
|
|
2115
|
+
deleted = false;
|
|
2116
|
+
title = eventTitle;
|
|
2117
|
+
continue;
|
|
2118
|
+
}
|
|
2119
|
+
if (event.type === 'chat-session-deleted') {
|
|
2120
|
+
deleted = true;
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
if (event.type === 'chat-session-title-updated') {
|
|
2124
|
+
const {
|
|
2125
|
+
title: eventTitle
|
|
2126
|
+
} = event;
|
|
2127
|
+
title = eventTitle;
|
|
2128
|
+
continue;
|
|
2129
|
+
}
|
|
2130
|
+
if (event.type === 'chat-message-added') {
|
|
2131
|
+
messages = [...messages, event.message];
|
|
2132
|
+
continue;
|
|
2133
|
+
}
|
|
2134
|
+
if (event.type === 'chat-message-updated') {
|
|
2135
|
+
messages = messages.map(message => {
|
|
2136
|
+
if (message.id !== event.messageId) {
|
|
2137
|
+
return message;
|
|
2138
|
+
}
|
|
2139
|
+
return {
|
|
2140
|
+
...message,
|
|
2141
|
+
inProgress: event.inProgress,
|
|
2142
|
+
text: event.text,
|
|
2143
|
+
time: event.time,
|
|
2144
|
+
toolCalls: event.toolCalls
|
|
2145
|
+
};
|
|
2146
|
+
});
|
|
2147
|
+
continue;
|
|
2148
|
+
}
|
|
2149
|
+
if (event.type === 'chat-session-messages-replaced') {
|
|
2150
|
+
messages = [...event.messages];
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
if (deleted || !title) {
|
|
2154
|
+
return undefined;
|
|
2155
|
+
}
|
|
2156
|
+
return {
|
|
2157
|
+
id,
|
|
2158
|
+
messages,
|
|
2159
|
+
title
|
|
2160
|
+
};
|
|
2020
2161
|
};
|
|
2021
|
-
|
|
2022
2162
|
class IndexedDbChatSessionStorage {
|
|
2023
2163
|
constructor(options = {}) {
|
|
2024
2164
|
this.state = {
|
|
2025
2165
|
databaseName: options.databaseName || 'lvce-chat-view-sessions',
|
|
2026
2166
|
databasePromise: undefined,
|
|
2027
|
-
databaseVersion: options.databaseVersion ||
|
|
2167
|
+
databaseVersion: options.databaseVersion || 2,
|
|
2168
|
+
eventStoreName: options.eventStoreName || 'chat-view-events',
|
|
2028
2169
|
storeName: options.storeName || 'chat-sessions'
|
|
2029
2170
|
};
|
|
2030
2171
|
}
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2172
|
+
openDatabase = async () => {
|
|
2173
|
+
if (this.state.databasePromise) {
|
|
2174
|
+
return this.state.databasePromise;
|
|
2175
|
+
}
|
|
2176
|
+
const request = indexedDB.open(this.state.databaseName, this.state.databaseVersion);
|
|
2177
|
+
request.addEventListener('upgradeneeded', () => {
|
|
2178
|
+
const database = request.result;
|
|
2179
|
+
if (!database.objectStoreNames.contains(this.state.storeName)) {
|
|
2180
|
+
database.createObjectStore(this.state.storeName, {
|
|
2181
|
+
keyPath: 'id'
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
if (database.objectStoreNames.contains(this.state.eventStoreName)) {
|
|
2185
|
+
const {
|
|
2186
|
+
transaction
|
|
2187
|
+
} = request;
|
|
2188
|
+
if (!transaction) {
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2191
|
+
const eventStore = transaction.objectStore(this.state.eventStoreName);
|
|
2192
|
+
if (!eventStore.indexNames.contains('sessionId')) {
|
|
2193
|
+
eventStore.createIndex('sessionId', 'sessionId', {
|
|
2194
|
+
unique: false
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
} else {
|
|
2198
|
+
const eventStore = database.createObjectStore(this.state.eventStoreName, {
|
|
2199
|
+
autoIncrement: true,
|
|
2200
|
+
keyPath: 'eventId'
|
|
2201
|
+
});
|
|
2202
|
+
eventStore.createIndex('sessionId', 'sessionId', {
|
|
2203
|
+
unique: false
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
});
|
|
2207
|
+
const databasePromise = requestToPromise(() => request);
|
|
2035
2208
|
this.state.databasePromise = databasePromise;
|
|
2209
|
+
return databasePromise;
|
|
2210
|
+
};
|
|
2211
|
+
listSummaries = async () => {
|
|
2212
|
+
const database = await this.openDatabase();
|
|
2213
|
+
const transaction = database.transaction(this.state.storeName, 'readonly');
|
|
2214
|
+
const store = transaction.objectStore(this.state.storeName);
|
|
2215
|
+
const summaries = await requestToPromise(() => store.getAll());
|
|
2216
|
+
return summaries;
|
|
2217
|
+
};
|
|
2218
|
+
getSummary = async id => {
|
|
2219
|
+
const database = await this.openDatabase();
|
|
2220
|
+
const transaction = database.transaction(this.state.storeName, 'readonly');
|
|
2221
|
+
const store = transaction.objectStore(this.state.storeName);
|
|
2222
|
+
const summary = await requestToPromise(() => store.get(id));
|
|
2223
|
+
return summary;
|
|
2224
|
+
};
|
|
2225
|
+
getEventsBySessionId = async sessionId => {
|
|
2226
|
+
const database = await this.openDatabase();
|
|
2227
|
+
const transaction = database.transaction(this.state.eventStoreName, 'readonly');
|
|
2228
|
+
const store = transaction.objectStore(this.state.eventStoreName);
|
|
2229
|
+
const index = store.index('sessionId');
|
|
2230
|
+
const events = await requestToPromise(() => index.getAll(IDBKeyRange.only(sessionId)));
|
|
2231
|
+
return events.map(toChatViewEvent);
|
|
2232
|
+
};
|
|
2233
|
+
listEventsInternal = async () => {
|
|
2234
|
+
const database = await this.openDatabase();
|
|
2235
|
+
const transaction = database.transaction(this.state.eventStoreName, 'readonly');
|
|
2236
|
+
const store = transaction.objectStore(this.state.eventStoreName);
|
|
2237
|
+
const events = await requestToPromise(() => store.getAll());
|
|
2238
|
+
return events.map(toChatViewEvent);
|
|
2036
2239
|
};
|
|
2240
|
+
appendEvents = async events => {
|
|
2241
|
+
if (events.length === 0) {
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
const database = await this.openDatabase();
|
|
2245
|
+
const transaction = database.transaction([this.state.storeName, this.state.eventStoreName], 'readwrite');
|
|
2246
|
+
const summaryStore = transaction.objectStore(this.state.storeName);
|
|
2247
|
+
const eventStore = transaction.objectStore(this.state.eventStoreName);
|
|
2248
|
+
for (const event of events) {
|
|
2249
|
+
eventStore.add(event);
|
|
2250
|
+
if (event.type === 'chat-session-created' || event.type === 'chat-session-title-updated') {
|
|
2251
|
+
summaryStore.put({
|
|
2252
|
+
id: event.sessionId,
|
|
2253
|
+
title: event.title
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
if (event.type === 'chat-session-deleted') {
|
|
2257
|
+
summaryStore.delete(event.sessionId);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
await transactionToPromise(() => transaction);
|
|
2261
|
+
};
|
|
2262
|
+
async appendEvent(event) {
|
|
2263
|
+
await this.appendEvents([event]);
|
|
2264
|
+
}
|
|
2037
2265
|
async clear() {
|
|
2038
|
-
|
|
2266
|
+
const database = await this.openDatabase();
|
|
2267
|
+
const transaction = database.transaction([this.state.storeName, this.state.eventStoreName], 'readwrite');
|
|
2268
|
+
transaction.objectStore(this.state.storeName).clear();
|
|
2269
|
+
transaction.objectStore(this.state.eventStoreName).clear();
|
|
2270
|
+
await transactionToPromise(() => transaction);
|
|
2039
2271
|
}
|
|
2040
2272
|
async deleteSession(id) {
|
|
2041
|
-
|
|
2273
|
+
await this.appendEvent({
|
|
2274
|
+
sessionId: id,
|
|
2275
|
+
timestamp: now$1(),
|
|
2276
|
+
type: 'chat-session-deleted'
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
async getEvents(sessionId) {
|
|
2280
|
+
if (sessionId) {
|
|
2281
|
+
return this.getEventsBySessionId(sessionId);
|
|
2282
|
+
}
|
|
2283
|
+
return this.listEventsInternal();
|
|
2042
2284
|
}
|
|
2043
2285
|
async getSession(id) {
|
|
2044
|
-
|
|
2286
|
+
const [summary, events] = await Promise.all([this.getSummary(id), this.getEventsBySessionId(id)]);
|
|
2287
|
+
return replaySession$1(id, summary, events);
|
|
2045
2288
|
}
|
|
2046
2289
|
async listSessions() {
|
|
2047
|
-
|
|
2290
|
+
const summaries = await this.listSummaries();
|
|
2291
|
+
const sessions = [];
|
|
2292
|
+
for (const summary of summaries) {
|
|
2293
|
+
const events = await this.getEventsBySessionId(summary.id);
|
|
2294
|
+
const session = replaySession$1(summary.id, summary, events);
|
|
2295
|
+
if (!session) {
|
|
2296
|
+
continue;
|
|
2297
|
+
}
|
|
2298
|
+
sessions.push(session);
|
|
2299
|
+
}
|
|
2300
|
+
return sessions;
|
|
2048
2301
|
}
|
|
2049
2302
|
async setSession(session) {
|
|
2050
|
-
|
|
2303
|
+
const previous = await this.getSession(session.id);
|
|
2304
|
+
const events = getMutationEvents$1(previous, session);
|
|
2305
|
+
await this.appendEvents(events);
|
|
2306
|
+
if (events.length === 0) {
|
|
2307
|
+
const database = await this.openDatabase();
|
|
2308
|
+
const transaction = database.transaction(this.state.storeName, 'readwrite');
|
|
2309
|
+
const summaryStore = transaction.objectStore(this.state.storeName);
|
|
2310
|
+
summaryStore.put({
|
|
2311
|
+
id: session.id,
|
|
2312
|
+
title: session.title
|
|
2313
|
+
});
|
|
2314
|
+
await transactionToPromise(() => transaction);
|
|
2315
|
+
}
|
|
2051
2316
|
}
|
|
2052
2317
|
}
|
|
2053
2318
|
|
|
2319
|
+
const now = () => {
|
|
2320
|
+
return new Date().toISOString();
|
|
2321
|
+
};
|
|
2322
|
+
const isSameMessage = (a, b) => {
|
|
2323
|
+
return a.id === b.id && a.inProgress === b.inProgress && a.role === b.role && a.text === b.text && a.time === b.time && JSON.stringify(a.toolCalls || []) === JSON.stringify(b.toolCalls || []);
|
|
2324
|
+
};
|
|
2325
|
+
const canAppendMessages = (previousMessages, nextMessages) => {
|
|
2326
|
+
if (nextMessages.length < previousMessages.length) {
|
|
2327
|
+
return false;
|
|
2328
|
+
}
|
|
2329
|
+
return previousMessages.every((message, index) => isSameMessage(message, nextMessages[index]));
|
|
2330
|
+
};
|
|
2331
|
+
const canUpdateMessages = (previousMessages, nextMessages) => {
|
|
2332
|
+
if (previousMessages.length !== nextMessages.length) {
|
|
2333
|
+
return false;
|
|
2334
|
+
}
|
|
2335
|
+
for (let i = 0; i < previousMessages.length; i += 1) {
|
|
2336
|
+
const previous = previousMessages[i];
|
|
2337
|
+
const next = nextMessages[i];
|
|
2338
|
+
if (previous.id !== next.id || previous.role !== next.role) {
|
|
2339
|
+
return false;
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
return true;
|
|
2343
|
+
};
|
|
2344
|
+
const getMutationEvents = (previous, next) => {
|
|
2345
|
+
const timestamp = now();
|
|
2346
|
+
const events = [];
|
|
2347
|
+
if (!previous) {
|
|
2348
|
+
events.push({
|
|
2349
|
+
sessionId: next.id,
|
|
2350
|
+
timestamp,
|
|
2351
|
+
title: next.title,
|
|
2352
|
+
type: 'chat-session-created'
|
|
2353
|
+
});
|
|
2354
|
+
for (const message of next.messages) {
|
|
2355
|
+
events.push({
|
|
2356
|
+
message,
|
|
2357
|
+
sessionId: next.id,
|
|
2358
|
+
timestamp,
|
|
2359
|
+
type: 'chat-message-added'
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
return events;
|
|
2363
|
+
}
|
|
2364
|
+
if (previous.title !== next.title) {
|
|
2365
|
+
events.push({
|
|
2366
|
+
sessionId: next.id,
|
|
2367
|
+
timestamp,
|
|
2368
|
+
title: next.title,
|
|
2369
|
+
type: 'chat-session-title-updated'
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2372
|
+
if (canAppendMessages(previous.messages, next.messages)) {
|
|
2373
|
+
for (let i = previous.messages.length; i < next.messages.length; i += 1) {
|
|
2374
|
+
events.push({
|
|
2375
|
+
message: next.messages[i],
|
|
2376
|
+
sessionId: next.id,
|
|
2377
|
+
timestamp,
|
|
2378
|
+
type: 'chat-message-added'
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
return events;
|
|
2382
|
+
}
|
|
2383
|
+
if (canUpdateMessages(previous.messages, next.messages)) {
|
|
2384
|
+
for (let i = 0; i < previous.messages.length; i += 1) {
|
|
2385
|
+
const previousMessage = previous.messages[i];
|
|
2386
|
+
const nextMessage = next.messages[i];
|
|
2387
|
+
if (!isSameMessage(previousMessage, nextMessage)) {
|
|
2388
|
+
events.push({
|
|
2389
|
+
inProgress: nextMessage.inProgress,
|
|
2390
|
+
messageId: nextMessage.id,
|
|
2391
|
+
sessionId: next.id,
|
|
2392
|
+
text: nextMessage.text,
|
|
2393
|
+
time: nextMessage.time,
|
|
2394
|
+
timestamp,
|
|
2395
|
+
toolCalls: nextMessage.toolCalls,
|
|
2396
|
+
type: 'chat-message-updated'
|
|
2397
|
+
});
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
return events;
|
|
2401
|
+
}
|
|
2402
|
+
events.push({
|
|
2403
|
+
messages: [...next.messages],
|
|
2404
|
+
sessionId: next.id,
|
|
2405
|
+
timestamp,
|
|
2406
|
+
type: 'chat-session-messages-replaced'
|
|
2407
|
+
});
|
|
2408
|
+
return events;
|
|
2409
|
+
};
|
|
2410
|
+
const replaySession = (id, title, events) => {
|
|
2411
|
+
let deleted = false;
|
|
2412
|
+
let currentTitle = title || '';
|
|
2413
|
+
let messages = [];
|
|
2414
|
+
for (const event of events) {
|
|
2415
|
+
if (event.sessionId !== id) {
|
|
2416
|
+
continue;
|
|
2417
|
+
}
|
|
2418
|
+
if (event.type === 'chat-session-created') {
|
|
2419
|
+
deleted = false;
|
|
2420
|
+
currentTitle = event.title;
|
|
2421
|
+
continue;
|
|
2422
|
+
}
|
|
2423
|
+
if (event.type === 'chat-session-deleted') {
|
|
2424
|
+
deleted = true;
|
|
2425
|
+
continue;
|
|
2426
|
+
}
|
|
2427
|
+
if (event.type === 'chat-session-title-updated') {
|
|
2428
|
+
currentTitle = event.title;
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
if (event.type === 'chat-message-added') {
|
|
2432
|
+
messages = [...messages, event.message];
|
|
2433
|
+
continue;
|
|
2434
|
+
}
|
|
2435
|
+
if (event.type === 'chat-message-updated') {
|
|
2436
|
+
messages = messages.map(message => {
|
|
2437
|
+
if (message.id !== event.messageId) {
|
|
2438
|
+
return message;
|
|
2439
|
+
}
|
|
2440
|
+
return {
|
|
2441
|
+
...message,
|
|
2442
|
+
inProgress: event.inProgress,
|
|
2443
|
+
text: event.text,
|
|
2444
|
+
time: event.time,
|
|
2445
|
+
toolCalls: event.toolCalls
|
|
2446
|
+
};
|
|
2447
|
+
});
|
|
2448
|
+
continue;
|
|
2449
|
+
}
|
|
2450
|
+
if (event.type === 'chat-session-messages-replaced') {
|
|
2451
|
+
messages = [...event.messages];
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
if (deleted || !currentTitle) {
|
|
2455
|
+
return undefined;
|
|
2456
|
+
}
|
|
2457
|
+
return {
|
|
2458
|
+
id,
|
|
2459
|
+
messages,
|
|
2460
|
+
title: currentTitle
|
|
2461
|
+
};
|
|
2462
|
+
};
|
|
2054
2463
|
class InMemoryChatSessionStorage {
|
|
2055
|
-
|
|
2464
|
+
events = [];
|
|
2465
|
+
summaries = new Map();
|
|
2466
|
+
async appendEvent(event) {
|
|
2467
|
+
this.events.push(event);
|
|
2468
|
+
if (event.type === 'chat-session-created' || event.type === 'chat-session-title-updated') {
|
|
2469
|
+
this.summaries.set(event.sessionId, event.title);
|
|
2470
|
+
return;
|
|
2471
|
+
}
|
|
2472
|
+
if (event.type === 'chat-session-deleted') {
|
|
2473
|
+
this.summaries.delete(event.sessionId);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2056
2476
|
async clear() {
|
|
2057
|
-
this.
|
|
2477
|
+
this.events.length = 0;
|
|
2478
|
+
this.summaries.clear();
|
|
2058
2479
|
}
|
|
2059
2480
|
async deleteSession(id) {
|
|
2060
|
-
this.
|
|
2481
|
+
await this.appendEvent({
|
|
2482
|
+
sessionId: id,
|
|
2483
|
+
timestamp: now(),
|
|
2484
|
+
type: 'chat-session-deleted'
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2487
|
+
async getEvents(sessionId) {
|
|
2488
|
+
if (!sessionId) {
|
|
2489
|
+
return [...this.events];
|
|
2490
|
+
}
|
|
2491
|
+
return this.events.filter(event => event.sessionId === sessionId);
|
|
2061
2492
|
}
|
|
2062
2493
|
async getSession(id) {
|
|
2063
|
-
return this.
|
|
2494
|
+
return replaySession(id, this.summaries.get(id), this.events);
|
|
2064
2495
|
}
|
|
2065
2496
|
async listSessions() {
|
|
2066
|
-
|
|
2497
|
+
const ids = new Set();
|
|
2498
|
+
for (const id of this.summaries.keys()) {
|
|
2499
|
+
ids.add(id);
|
|
2500
|
+
}
|
|
2501
|
+
for (const event of this.events) {
|
|
2502
|
+
ids.add(event.sessionId);
|
|
2503
|
+
}
|
|
2504
|
+
const sessions = [];
|
|
2505
|
+
for (const id of ids) {
|
|
2506
|
+
const session = replaySession(id, this.summaries.get(id), this.events);
|
|
2507
|
+
if (!session) {
|
|
2508
|
+
continue;
|
|
2509
|
+
}
|
|
2510
|
+
sessions.push(session);
|
|
2511
|
+
}
|
|
2512
|
+
return sessions;
|
|
2067
2513
|
}
|
|
2068
2514
|
async setSession(session) {
|
|
2069
|
-
this.
|
|
2515
|
+
const previous = await this.getSession(session.id);
|
|
2516
|
+
const events = getMutationEvents(previous, session);
|
|
2517
|
+
for (const event of events) {
|
|
2518
|
+
await this.appendEvent(event);
|
|
2519
|
+
}
|
|
2520
|
+
this.summaries.set(session.id, session.title);
|
|
2070
2521
|
}
|
|
2071
2522
|
}
|
|
2072
2523
|
|
|
@@ -2109,6 +2560,9 @@ const deleteChatSession = async id => {
|
|
|
2109
2560
|
const clearChatSessions = async () => {
|
|
2110
2561
|
await chatSessionStorage.clear();
|
|
2111
2562
|
};
|
|
2563
|
+
const appendChatViewEvent = async event => {
|
|
2564
|
+
await chatSessionStorage.appendEvent(event);
|
|
2565
|
+
};
|
|
2112
2566
|
|
|
2113
2567
|
const generateSessionId = () => {
|
|
2114
2568
|
return crypto.randomUUID();
|
|
@@ -2601,6 +3055,20 @@ const getTextContent = content => {
|
|
|
2601
3055
|
return textParts.join('\n');
|
|
2602
3056
|
};
|
|
2603
3057
|
|
|
3058
|
+
const getOpenAiParams = (completionMessages, modelId, stream, includeObfuscation, tools) => {
|
|
3059
|
+
return {
|
|
3060
|
+
messages: completionMessages,
|
|
3061
|
+
model: modelId,
|
|
3062
|
+
...(stream ? {
|
|
3063
|
+
stream: true
|
|
3064
|
+
} : {}),
|
|
3065
|
+
...(includeObfuscation ? {
|
|
3066
|
+
include_obfuscation: true
|
|
3067
|
+
} : {}),
|
|
3068
|
+
tool_choice: 'auto',
|
|
3069
|
+
tools
|
|
3070
|
+
};
|
|
3071
|
+
};
|
|
2604
3072
|
const getStreamChunkText = content => {
|
|
2605
3073
|
if (typeof content === 'string') {
|
|
2606
3074
|
return content;
|
|
@@ -2627,7 +3095,59 @@ const parseSseEvent = eventChunk => {
|
|
|
2627
3095
|
}
|
|
2628
3096
|
return dataLines;
|
|
2629
3097
|
};
|
|
2630
|
-
const
|
|
3098
|
+
const updateToolCallAccumulator = (accumulator, chunk) => {
|
|
3099
|
+
let changed = false;
|
|
3100
|
+
const nextAccumulator = {
|
|
3101
|
+
...accumulator
|
|
3102
|
+
};
|
|
3103
|
+
for (const item of chunk) {
|
|
3104
|
+
if (!item || typeof item !== 'object') {
|
|
3105
|
+
continue;
|
|
3106
|
+
}
|
|
3107
|
+
const index = Reflect.get(item, 'index');
|
|
3108
|
+
if (typeof index !== 'number') {
|
|
3109
|
+
continue;
|
|
3110
|
+
}
|
|
3111
|
+
const current = nextAccumulator[index] || {
|
|
3112
|
+
arguments: '',
|
|
3113
|
+
name: ''
|
|
3114
|
+
};
|
|
3115
|
+
const id = Reflect.get(item, 'id');
|
|
3116
|
+
const toolFunction = Reflect.get(item, 'function');
|
|
3117
|
+
let {
|
|
3118
|
+
name
|
|
3119
|
+
} = current;
|
|
3120
|
+
let args = current.arguments;
|
|
3121
|
+
if (toolFunction && typeof toolFunction === 'object') {
|
|
3122
|
+
const deltaName = Reflect.get(toolFunction, 'name');
|
|
3123
|
+
const deltaArguments = Reflect.get(toolFunction, 'arguments');
|
|
3124
|
+
if (typeof deltaName === 'string' && deltaName) {
|
|
3125
|
+
name = deltaName;
|
|
3126
|
+
}
|
|
3127
|
+
if (typeof deltaArguments === 'string') {
|
|
3128
|
+
args += deltaArguments;
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
const next = {
|
|
3132
|
+
arguments: args,
|
|
3133
|
+
id: typeof id === 'string' ? id : current.id,
|
|
3134
|
+
name
|
|
3135
|
+
};
|
|
3136
|
+
if (JSON.stringify(next) !== JSON.stringify(current)) {
|
|
3137
|
+
nextAccumulator[index] = next;
|
|
3138
|
+
changed = true;
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
if (!changed) {
|
|
3142
|
+
return undefined;
|
|
3143
|
+
}
|
|
3144
|
+
const toolCalls = Object.entries(nextAccumulator).toSorted((a, b) => Number(a[0]) - Number(b[0])).map(entry => entry[1]).filter(toolCall => !!toolCall.name);
|
|
3145
|
+
return {
|
|
3146
|
+
nextAccumulator,
|
|
3147
|
+
toolCalls
|
|
3148
|
+
};
|
|
3149
|
+
};
|
|
3150
|
+
const parseOpenApiStream = async (response, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished) => {
|
|
2631
3151
|
if (!response.body) {
|
|
2632
3152
|
return {
|
|
2633
3153
|
details: 'request-failed',
|
|
@@ -2639,6 +3159,7 @@ const parseOpenApiStream = async (response, onTextChunk) => {
|
|
|
2639
3159
|
let remainder = '';
|
|
2640
3160
|
let text = '';
|
|
2641
3161
|
let done = false;
|
|
3162
|
+
let toolCallAccumulator = {};
|
|
2642
3163
|
while (!done) {
|
|
2643
3164
|
const {
|
|
2644
3165
|
done: streamDone,
|
|
@@ -2664,6 +3185,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
|
|
|
2664
3185
|
}
|
|
2665
3186
|
for (const line of dataLines) {
|
|
2666
3187
|
if (line === '[DONE]') {
|
|
3188
|
+
if (onEventStreamFinished) {
|
|
3189
|
+
await onEventStreamFinished();
|
|
3190
|
+
}
|
|
2667
3191
|
done = true;
|
|
2668
3192
|
break;
|
|
2669
3193
|
}
|
|
@@ -2676,6 +3200,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
|
|
|
2676
3200
|
if (!parsed || typeof parsed !== 'object') {
|
|
2677
3201
|
continue;
|
|
2678
3202
|
}
|
|
3203
|
+
if (onDataEvent) {
|
|
3204
|
+
await onDataEvent(parsed);
|
|
3205
|
+
}
|
|
2679
3206
|
const choices = Reflect.get(parsed, 'choices');
|
|
2680
3207
|
if (!Array.isArray(choices)) {
|
|
2681
3208
|
continue;
|
|
@@ -2688,6 +3215,14 @@ const parseOpenApiStream = async (response, onTextChunk) => {
|
|
|
2688
3215
|
if (!delta || typeof delta !== 'object') {
|
|
2689
3216
|
continue;
|
|
2690
3217
|
}
|
|
3218
|
+
const toolCalls = Reflect.get(delta, 'tool_calls');
|
|
3219
|
+
const updatedToolCallResult = Array.isArray(toolCalls) ? updateToolCallAccumulator(toolCallAccumulator, toolCalls) : undefined;
|
|
3220
|
+
if (updatedToolCallResult) {
|
|
3221
|
+
toolCallAccumulator = updatedToolCallResult.nextAccumulator;
|
|
3222
|
+
}
|
|
3223
|
+
if (updatedToolCallResult && onToolCallsChunk) {
|
|
3224
|
+
await onToolCallsChunk(updatedToolCallResult.toolCalls);
|
|
3225
|
+
}
|
|
2691
3226
|
const content = Reflect.get(delta, 'content');
|
|
2692
3227
|
const chunkText = getStreamChunkText(content);
|
|
2693
3228
|
if (!chunkText) {
|
|
@@ -2704,6 +3239,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
|
|
|
2704
3239
|
const dataLines = parseSseEvent(remainder);
|
|
2705
3240
|
for (const line of dataLines) {
|
|
2706
3241
|
if (line === '[DONE]') {
|
|
3242
|
+
if (onEventStreamFinished) {
|
|
3243
|
+
await onEventStreamFinished();
|
|
3244
|
+
}
|
|
2707
3245
|
continue;
|
|
2708
3246
|
}
|
|
2709
3247
|
let parsed;
|
|
@@ -2715,6 +3253,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
|
|
|
2715
3253
|
if (!parsed || typeof parsed !== 'object') {
|
|
2716
3254
|
continue;
|
|
2717
3255
|
}
|
|
3256
|
+
if (onDataEvent) {
|
|
3257
|
+
await onDataEvent(parsed);
|
|
3258
|
+
}
|
|
2718
3259
|
const choices = Reflect.get(parsed, 'choices');
|
|
2719
3260
|
if (!Array.isArray(choices)) {
|
|
2720
3261
|
continue;
|
|
@@ -2727,6 +3268,14 @@ const parseOpenApiStream = async (response, onTextChunk) => {
|
|
|
2727
3268
|
if (!delta || typeof delta !== 'object') {
|
|
2728
3269
|
continue;
|
|
2729
3270
|
}
|
|
3271
|
+
const toolCalls = Reflect.get(delta, 'tool_calls');
|
|
3272
|
+
const updatedToolCallResult = Array.isArray(toolCalls) ? updateToolCallAccumulator(toolCallAccumulator, toolCalls) : undefined;
|
|
3273
|
+
if (updatedToolCallResult) {
|
|
3274
|
+
toolCallAccumulator = updatedToolCallResult.nextAccumulator;
|
|
3275
|
+
}
|
|
3276
|
+
if (updatedToolCallResult && onToolCallsChunk) {
|
|
3277
|
+
await onToolCallsChunk(updatedToolCallResult.toolCalls);
|
|
3278
|
+
}
|
|
2730
3279
|
const content = Reflect.get(delta, 'content');
|
|
2731
3280
|
const chunkText = getStreamChunkText(content);
|
|
2732
3281
|
if (!chunkText) {
|
|
@@ -2769,7 +3318,10 @@ const getOpenApiErrorDetails = async response => {
|
|
|
2769
3318
|
const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApiApiBaseUrl, assetDir, platform, options) => {
|
|
2770
3319
|
const {
|
|
2771
3320
|
includeObfuscation = false,
|
|
3321
|
+
onDataEvent,
|
|
3322
|
+
onEventStreamFinished,
|
|
2772
3323
|
onTextChunk,
|
|
3324
|
+
onToolCallsChunk,
|
|
2773
3325
|
stream
|
|
2774
3326
|
} = options ?? {
|
|
2775
3327
|
stream: false
|
|
@@ -2784,18 +3336,7 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
2784
3336
|
let response;
|
|
2785
3337
|
try {
|
|
2786
3338
|
response = await fetch(getOpenApiApiEndpoint(openApiApiBaseUrl, stream), {
|
|
2787
|
-
body: JSON.stringify(
|
|
2788
|
-
messages: completionMessages,
|
|
2789
|
-
model: modelId,
|
|
2790
|
-
...(stream ? {
|
|
2791
|
-
stream: true
|
|
2792
|
-
} : {}),
|
|
2793
|
-
...(includeObfuscation ? {
|
|
2794
|
-
include_obfuscation: true
|
|
2795
|
-
} : {}),
|
|
2796
|
-
tool_choice: 'auto',
|
|
2797
|
-
tools
|
|
2798
|
-
}),
|
|
3339
|
+
body: JSON.stringify(getOpenAiParams(completionMessages, modelId, stream, includeObfuscation, tools)),
|
|
2799
3340
|
headers: {
|
|
2800
3341
|
Authorization: `Bearer ${openApiApiKey}`,
|
|
2801
3342
|
'Content-Type': 'application/json',
|
|
@@ -2825,7 +3366,7 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
2825
3366
|
};
|
|
2826
3367
|
}
|
|
2827
3368
|
if (stream) {
|
|
2828
|
-
return parseOpenApiStream(response, onTextChunk);
|
|
3369
|
+
return parseOpenApiStream(response, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished);
|
|
2829
3370
|
}
|
|
2830
3371
|
let parsed;
|
|
2831
3372
|
try {
|
|
@@ -3239,11 +3780,14 @@ const isOpenRouterModel = (selectedModelId, models) => {
|
|
|
3239
3780
|
|
|
3240
3781
|
const getAiResponse = async ({
|
|
3241
3782
|
assetDir,
|
|
3783
|
+
messageId,
|
|
3242
3784
|
messages,
|
|
3243
3785
|
mockApiCommandId,
|
|
3244
3786
|
models,
|
|
3245
|
-
|
|
3787
|
+
onDataEvent,
|
|
3788
|
+
onEventStreamFinished,
|
|
3246
3789
|
onTextChunk,
|
|
3790
|
+
onToolCallsChunk,
|
|
3247
3791
|
openApiApiBaseUrl,
|
|
3248
3792
|
openApiApiKey,
|
|
3249
3793
|
openRouterApiBaseUrl,
|
|
@@ -3272,7 +3816,10 @@ const getAiResponse = async ({
|
|
|
3272
3816
|
} else if (openApiApiKey) {
|
|
3273
3817
|
const result = await getOpenApiAssistantText(messages, getOpenApiModelId(selectedModelId), openApiApiKey, openApiApiBaseUrl, assetDir, platform, {
|
|
3274
3818
|
includeObfuscation: passIncludeObfuscation,
|
|
3819
|
+
onDataEvent,
|
|
3820
|
+
onEventStreamFinished,
|
|
3275
3821
|
onTextChunk,
|
|
3822
|
+
onToolCallsChunk,
|
|
3276
3823
|
stream: streamingEnabled
|
|
3277
3824
|
});
|
|
3278
3825
|
if (result.type === 'success') {
|
|
@@ -3320,7 +3867,7 @@ const getAiResponse = async ({
|
|
|
3320
3867
|
minute: '2-digit'
|
|
3321
3868
|
});
|
|
3322
3869
|
return {
|
|
3323
|
-
id:
|
|
3870
|
+
id: messageId || crypto.randomUUID(),
|
|
3324
3871
|
role: 'assistant',
|
|
3325
3872
|
text,
|
|
3326
3873
|
time: assistantTime
|
|
@@ -3375,7 +3922,6 @@ const handleClickSaveOpenApiApiKey = async state => {
|
|
|
3375
3922
|
messages: retryMessages,
|
|
3376
3923
|
mockApiCommandId: updatedState.mockApiCommandId,
|
|
3377
3924
|
models: updatedState.models,
|
|
3378
|
-
nextMessageId: updatedState.nextMessageId,
|
|
3379
3925
|
openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
|
|
3380
3926
|
openApiApiKey: updatedState.openApiApiKey,
|
|
3381
3927
|
openRouterApiBaseUrl: updatedState.openRouterApiBaseUrl,
|
|
@@ -3455,7 +4001,6 @@ const handleClickSaveOpenRouterApiKey = async state => {
|
|
|
3455
4001
|
messages: retryMessages,
|
|
3456
4002
|
mockApiCommandId: updatedState.mockApiCommandId,
|
|
3457
4003
|
models: updatedState.models,
|
|
3458
|
-
nextMessageId: updatedState.nextMessageId,
|
|
3459
4004
|
openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
|
|
3460
4005
|
openApiApiKey: updatedState.openApiApiKey,
|
|
3461
4006
|
openRouterApiBaseUrl: updatedState.openRouterApiBaseUrl,
|
|
@@ -3512,6 +4057,25 @@ const updateMessageTextInSelectedSession = (sessions, selectedSessionId, message
|
|
|
3512
4057
|
};
|
|
3513
4058
|
});
|
|
3514
4059
|
};
|
|
4060
|
+
const updateMessageToolCallsInSelectedSession = (sessions, selectedSessionId, messageId, toolCalls) => {
|
|
4061
|
+
return sessions.map(session => {
|
|
4062
|
+
if (session.id !== selectedSessionId) {
|
|
4063
|
+
return session;
|
|
4064
|
+
}
|
|
4065
|
+
return {
|
|
4066
|
+
...session,
|
|
4067
|
+
messages: session.messages.map(message => {
|
|
4068
|
+
if (message.id !== messageId) {
|
|
4069
|
+
return message;
|
|
4070
|
+
}
|
|
4071
|
+
return {
|
|
4072
|
+
...message,
|
|
4073
|
+
toolCalls
|
|
4074
|
+
};
|
|
4075
|
+
})
|
|
4076
|
+
};
|
|
4077
|
+
});
|
|
4078
|
+
};
|
|
3515
4079
|
const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTextChunkState) => {
|
|
3516
4080
|
const selectedSession = handleTextChunkState.latestState.sessions.find(session => session.id === handleTextChunkState.latestState.selectedSessionId);
|
|
3517
4081
|
if (!selectedSession) {
|
|
@@ -3527,6 +4091,13 @@ const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTex
|
|
|
3527
4091
|
previousState: handleTextChunkState.previousState
|
|
3528
4092
|
};
|
|
3529
4093
|
}
|
|
4094
|
+
await appendChatViewEvent({
|
|
4095
|
+
content: chunk,
|
|
4096
|
+
messageId: assistantMessageId,
|
|
4097
|
+
sessionId: handleTextChunkState.latestState.selectedSessionId,
|
|
4098
|
+
timestamp: new Date().toISOString(),
|
|
4099
|
+
type: 'handle-response-chunk'
|
|
4100
|
+
});
|
|
3530
4101
|
const updatedText = assistantMessage.text + chunk;
|
|
3531
4102
|
const updatedSessions = updateMessageTextInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, updatedText, true);
|
|
3532
4103
|
const nextState = {
|
|
@@ -3541,6 +4112,34 @@ const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTex
|
|
|
3541
4112
|
previousState: nextState
|
|
3542
4113
|
};
|
|
3543
4114
|
};
|
|
4115
|
+
const handleToolCallsChunkFunction = async (uid, assistantMessageId, toolCalls, handleTextChunkState) => {
|
|
4116
|
+
const selectedSession = handleTextChunkState.latestState.sessions.find(session => session.id === handleTextChunkState.latestState.selectedSessionId);
|
|
4117
|
+
if (!selectedSession) {
|
|
4118
|
+
return {
|
|
4119
|
+
latestState: handleTextChunkState.latestState,
|
|
4120
|
+
previousState: handleTextChunkState.previousState
|
|
4121
|
+
};
|
|
4122
|
+
}
|
|
4123
|
+
const assistantMessage = selectedSession.messages.find(message => message.id === assistantMessageId);
|
|
4124
|
+
if (!assistantMessage) {
|
|
4125
|
+
return {
|
|
4126
|
+
latestState: handleTextChunkState.latestState,
|
|
4127
|
+
previousState: handleTextChunkState.previousState
|
|
4128
|
+
};
|
|
4129
|
+
}
|
|
4130
|
+
const updatedSessions = updateMessageToolCallsInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, toolCalls);
|
|
4131
|
+
const nextState = {
|
|
4132
|
+
...handleTextChunkState.latestState,
|
|
4133
|
+
sessions: updatedSessions
|
|
4134
|
+
};
|
|
4135
|
+
set(uid, handleTextChunkState.previousState, nextState);
|
|
4136
|
+
// @ts-ignore
|
|
4137
|
+
await invoke('Chat.rerender');
|
|
4138
|
+
return {
|
|
4139
|
+
latestState: nextState,
|
|
4140
|
+
previousState: nextState
|
|
4141
|
+
};
|
|
4142
|
+
};
|
|
3544
4143
|
|
|
3545
4144
|
const appendMessageToSelectedSession = (sessions, selectedSessionId, message) => {
|
|
3546
4145
|
return sessions.map(session => {
|
|
@@ -3581,13 +4180,14 @@ const handleSubmit = async state => {
|
|
|
3581
4180
|
hour: '2-digit',
|
|
3582
4181
|
minute: '2-digit'
|
|
3583
4182
|
});
|
|
4183
|
+
const userMessageId = crypto.randomUUID();
|
|
3584
4184
|
const userMessage = {
|
|
3585
|
-
id:
|
|
4185
|
+
id: userMessageId,
|
|
3586
4186
|
role: 'user',
|
|
3587
4187
|
text: userText,
|
|
3588
4188
|
time: userTime
|
|
3589
4189
|
};
|
|
3590
|
-
const assistantMessageId =
|
|
4190
|
+
const assistantMessageId = crypto.randomUUID();
|
|
3591
4191
|
const assistantTime = new Date().toLocaleTimeString([], {
|
|
3592
4192
|
hour: '2-digit',
|
|
3593
4193
|
minute: '2-digit'
|
|
@@ -3614,6 +4214,12 @@ const handleSubmit = async state => {
|
|
|
3614
4214
|
let optimisticState;
|
|
3615
4215
|
if (viewMode === 'list') {
|
|
3616
4216
|
const newSessionId = generateSessionId();
|
|
4217
|
+
await appendChatViewEvent({
|
|
4218
|
+
sessionId: newSessionId,
|
|
4219
|
+
timestamp: new Date().toISOString(),
|
|
4220
|
+
type: 'handle-submit',
|
|
4221
|
+
value: userText
|
|
4222
|
+
});
|
|
3617
4223
|
const newSession = {
|
|
3618
4224
|
id: newSessionId,
|
|
3619
4225
|
messages: streamingEnabled ? [userMessage, inProgressAssistantMessage] : [userMessage],
|
|
@@ -3632,6 +4238,12 @@ const handleSubmit = async state => {
|
|
|
3632
4238
|
viewMode: 'detail'
|
|
3633
4239
|
});
|
|
3634
4240
|
} else {
|
|
4241
|
+
await appendChatViewEvent({
|
|
4242
|
+
sessionId: selectedSessionId,
|
|
4243
|
+
timestamp: new Date().toISOString(),
|
|
4244
|
+
type: 'handle-submit',
|
|
4245
|
+
value: userText
|
|
4246
|
+
});
|
|
3635
4247
|
const updatedWithUser = appendMessageToSelectedSession(workingSessions, selectedSessionId, userMessage);
|
|
3636
4248
|
const updatedSessions = streamingEnabled ? appendMessageToSelectedSession(updatedWithUser, selectedSessionId, inProgressAssistantMessage) : updatedWithUser;
|
|
3637
4249
|
const selectedSession = updatedSessions.find(session => session.id === selectedSessionId);
|
|
@@ -3662,11 +4274,30 @@ const handleSubmit = async state => {
|
|
|
3662
4274
|
} : undefined;
|
|
3663
4275
|
const assistantMessage = await getAiResponse({
|
|
3664
4276
|
assetDir,
|
|
4277
|
+
messageId: assistantMessageId,
|
|
3665
4278
|
messages,
|
|
3666
4279
|
mockApiCommandId,
|
|
3667
4280
|
models,
|
|
3668
|
-
|
|
4281
|
+
onDataEvent: async value => {
|
|
4282
|
+
await appendChatViewEvent({
|
|
4283
|
+
sessionId: optimisticState.selectedSessionId,
|
|
4284
|
+
timestamp: new Date().toISOString(),
|
|
4285
|
+
type: 'data-event',
|
|
4286
|
+
value
|
|
4287
|
+
});
|
|
4288
|
+
},
|
|
4289
|
+
onEventStreamFinished: async () => {
|
|
4290
|
+
await appendChatViewEvent({
|
|
4291
|
+
sessionId: optimisticState.selectedSessionId,
|
|
4292
|
+
timestamp: new Date().toISOString(),
|
|
4293
|
+
type: 'event-stream-finished',
|
|
4294
|
+
value: '[DONE]'
|
|
4295
|
+
});
|
|
4296
|
+
},
|
|
3669
4297
|
onTextChunk: handleTextChunkFunctionRef,
|
|
4298
|
+
onToolCallsChunk: async toolCalls => {
|
|
4299
|
+
handleTextChunkState = await handleToolCallsChunkFunction(state.uid, assistantMessageId, toolCalls, handleTextChunkState);
|
|
4300
|
+
},
|
|
3670
4301
|
openApiApiBaseUrl,
|
|
3671
4302
|
openApiApiKey,
|
|
3672
4303
|
openRouterApiBaseUrl,
|
|
@@ -3712,6 +4343,7 @@ const Send = 'send';
|
|
|
3712
4343
|
const Back = 'back';
|
|
3713
4344
|
const Model = 'model';
|
|
3714
4345
|
const CreateSession = 'create-session';
|
|
4346
|
+
const SessionDebug = 'session-debug';
|
|
3715
4347
|
const Settings = 'settings';
|
|
3716
4348
|
const CloseChat = 'close-chat';
|
|
3717
4349
|
const SessionDelete = 'SessionDelete';
|
|
@@ -3856,6 +4488,11 @@ const handleClickNew = async state => {
|
|
|
3856
4488
|
return createSession(state);
|
|
3857
4489
|
};
|
|
3858
4490
|
|
|
4491
|
+
const handleClickSessionDebug = async state => {
|
|
4492
|
+
await invoke('Main.openUri', `chat-debug://${state.selectedSessionId}`);
|
|
4493
|
+
return state;
|
|
4494
|
+
};
|
|
4495
|
+
|
|
3859
4496
|
const handleClickSettings = async () => {
|
|
3860
4497
|
// TODO
|
|
3861
4498
|
await invoke('Main.openUri', 'app://settings.json');
|
|
@@ -3877,6 +4514,14 @@ const handleInput = async (state, name, value, inputSource = 'user') => {
|
|
|
3877
4514
|
if (name !== Composer) {
|
|
3878
4515
|
return state;
|
|
3879
4516
|
}
|
|
4517
|
+
if (state.selectedSessionId) {
|
|
4518
|
+
await appendChatViewEvent({
|
|
4519
|
+
sessionId: state.selectedSessionId,
|
|
4520
|
+
timestamp: new Date().toISOString(),
|
|
4521
|
+
type: 'handle-input',
|
|
4522
|
+
value
|
|
4523
|
+
});
|
|
4524
|
+
}
|
|
3880
4525
|
const composerHeight = await getComposerHeight(state, value);
|
|
3881
4526
|
return {
|
|
3882
4527
|
...state,
|
|
@@ -3904,7 +4549,7 @@ const handleInputFocus = async (state, name) => {
|
|
|
3904
4549
|
focused: true
|
|
3905
4550
|
};
|
|
3906
4551
|
}
|
|
3907
|
-
if (name === CreateSession || name === Settings || name === CloseChat || name === Back) {
|
|
4552
|
+
if (name === CreateSession || name === SessionDebug || name === Settings || name === CloseChat || name === Back) {
|
|
3908
4553
|
return {
|
|
3909
4554
|
...state,
|
|
3910
4555
|
focus: 'header',
|
|
@@ -4016,7 +4661,7 @@ const sendMessagePortToExtensionHostWorker = async port => {
|
|
|
4016
4661
|
|
|
4017
4662
|
const createExtensionHostRpc = async () => {
|
|
4018
4663
|
try {
|
|
4019
|
-
const rpc = await create$
|
|
4664
|
+
const rpc = await create$5({
|
|
4020
4665
|
commandMap: {},
|
|
4021
4666
|
send: sendMessagePortToExtensionHostWorker
|
|
4022
4667
|
});
|
|
@@ -4393,6 +5038,7 @@ const HandleSubmit = 19;
|
|
|
4393
5038
|
const HandleModelChange = 20;
|
|
4394
5039
|
const HandleChatListScroll = 21;
|
|
4395
5040
|
const HandleMessagesScroll = 22;
|
|
5041
|
+
const HandleClickSessionDebug = 23;
|
|
4396
5042
|
|
|
4397
5043
|
const getModelLabel = model => {
|
|
4398
5044
|
if (model.provider === 'openRouter') {
|
|
@@ -4540,6 +5186,11 @@ const getHeaderActionVirtualDom = item => {
|
|
|
4540
5186
|
|
|
4541
5187
|
const getChatHeaderActionsDom = () => {
|
|
4542
5188
|
const items = [{
|
|
5189
|
+
icon: 'MaskIcon MaskIconDebugPause',
|
|
5190
|
+
name: SessionDebug,
|
|
5191
|
+
onClick: HandleClickSessionDebug,
|
|
5192
|
+
title: debug()
|
|
5193
|
+
}, {
|
|
4543
5194
|
icon: 'MaskIcon MaskIconAdd',
|
|
4544
5195
|
name: CreateSession,
|
|
4545
5196
|
onClick: HandleClickNew,
|
|
@@ -4644,6 +5295,126 @@ const getMissingOpenRouterApiKeyDom = (openRouterApiKeyInput, openRouterApiKeySt
|
|
|
4644
5295
|
});
|
|
4645
5296
|
};
|
|
4646
5297
|
|
|
5298
|
+
const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
|
|
5299
|
+
const parseMessageContent = rawMessage => {
|
|
5300
|
+
if (rawMessage === '') {
|
|
5301
|
+
return [{
|
|
5302
|
+
text: '',
|
|
5303
|
+
type: 'text'
|
|
5304
|
+
}];
|
|
5305
|
+
}
|
|
5306
|
+
const lines = rawMessage.split(/\r?\n/);
|
|
5307
|
+
const nodes = [];
|
|
5308
|
+
let paragraphLines = [];
|
|
5309
|
+
let listItems = [];
|
|
5310
|
+
const flushParagraph = () => {
|
|
5311
|
+
if (paragraphLines.length === 0) {
|
|
5312
|
+
return;
|
|
5313
|
+
}
|
|
5314
|
+
nodes.push({
|
|
5315
|
+
text: paragraphLines.join('\n'),
|
|
5316
|
+
type: 'text'
|
|
5317
|
+
});
|
|
5318
|
+
paragraphLines = [];
|
|
5319
|
+
};
|
|
5320
|
+
const flushList = () => {
|
|
5321
|
+
if (listItems.length === 0) {
|
|
5322
|
+
return;
|
|
5323
|
+
}
|
|
5324
|
+
nodes.push({
|
|
5325
|
+
items: listItems,
|
|
5326
|
+
type: 'list'
|
|
5327
|
+
});
|
|
5328
|
+
listItems = [];
|
|
5329
|
+
};
|
|
5330
|
+
for (const line of lines) {
|
|
5331
|
+
if (!line.trim()) {
|
|
5332
|
+
flushList();
|
|
5333
|
+
flushParagraph();
|
|
5334
|
+
continue;
|
|
5335
|
+
}
|
|
5336
|
+
const match = line.match(orderedListItemRegex);
|
|
5337
|
+
if (match) {
|
|
5338
|
+
flushParagraph();
|
|
5339
|
+
listItems.push({
|
|
5340
|
+
text: match[1],
|
|
5341
|
+
type: 'list-item'
|
|
5342
|
+
});
|
|
5343
|
+
continue;
|
|
5344
|
+
}
|
|
5345
|
+
flushList();
|
|
5346
|
+
paragraphLines.push(line);
|
|
5347
|
+
}
|
|
5348
|
+
flushList();
|
|
5349
|
+
flushParagraph();
|
|
5350
|
+
return nodes.length === 0 ? [{
|
|
5351
|
+
text: '',
|
|
5352
|
+
type: 'text'
|
|
5353
|
+
}] : nodes;
|
|
5354
|
+
};
|
|
5355
|
+
const getMessageContentDom = nodes => {
|
|
5356
|
+
return nodes.flatMap(node => {
|
|
5357
|
+
if (node.type === 'text') {
|
|
5358
|
+
return [{
|
|
5359
|
+
childCount: 1,
|
|
5360
|
+
className: Markdown,
|
|
5361
|
+
type: P
|
|
5362
|
+
}, text(node.text)];
|
|
5363
|
+
}
|
|
5364
|
+
return [{
|
|
5365
|
+
childCount: node.items.length,
|
|
5366
|
+
className: ChatOrderedList,
|
|
5367
|
+
type: Ol
|
|
5368
|
+
}, ...node.items.flatMap(item => {
|
|
5369
|
+
return [{
|
|
5370
|
+
childCount: 1,
|
|
5371
|
+
className: ChatOrderedListItem,
|
|
5372
|
+
type: Li
|
|
5373
|
+
}, text(item.text)];
|
|
5374
|
+
})];
|
|
5375
|
+
});
|
|
5376
|
+
};
|
|
5377
|
+
|
|
5378
|
+
const getToolCallArgumentPreview = rawArguments => {
|
|
5379
|
+
if (!rawArguments.trim()) {
|
|
5380
|
+
return '""';
|
|
5381
|
+
}
|
|
5382
|
+
let parsed;
|
|
5383
|
+
try {
|
|
5384
|
+
parsed = JSON.parse(rawArguments);
|
|
5385
|
+
} catch {
|
|
5386
|
+
return rawArguments;
|
|
5387
|
+
}
|
|
5388
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
5389
|
+
return rawArguments;
|
|
5390
|
+
}
|
|
5391
|
+
const path = Reflect.get(parsed, 'path');
|
|
5392
|
+
if (typeof path === 'string') {
|
|
5393
|
+
return `"${path}"`;
|
|
5394
|
+
}
|
|
5395
|
+
const keys = Object.keys(parsed);
|
|
5396
|
+
if (keys.length === 1) {
|
|
5397
|
+
const value = Reflect.get(parsed, keys[0]);
|
|
5398
|
+
if (typeof value === 'string') {
|
|
5399
|
+
return `"${value}"`;
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
return rawArguments;
|
|
5403
|
+
};
|
|
5404
|
+
const getToolCallsDom = message => {
|
|
5405
|
+
if (message.role !== 'assistant' || !message.toolCalls || message.toolCalls.length === 0) {
|
|
5406
|
+
return [];
|
|
5407
|
+
}
|
|
5408
|
+
return message.toolCalls.flatMap(toolCall => {
|
|
5409
|
+
const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
|
|
5410
|
+
const label = `${toolCall.name} ${argumentPreview}`;
|
|
5411
|
+
return [{
|
|
5412
|
+
childCount: 1,
|
|
5413
|
+
className: Markdown,
|
|
5414
|
+
type: P
|
|
5415
|
+
}, text(label)];
|
|
5416
|
+
});
|
|
5417
|
+
};
|
|
4647
5418
|
const getOpenRouterRequestFailedDom = () => {
|
|
4648
5419
|
return [{
|
|
4649
5420
|
childCount: openRouterRequestFailureReasons.length,
|
|
@@ -4676,7 +5447,10 @@ const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput =
|
|
|
4676
5447
|
const isOpenRouterApiKeyMissingMessage = message.role === 'assistant' && message.text === openRouterApiKeyRequiredMessage;
|
|
4677
5448
|
const isOpenRouterRequestFailedMessage = message.role === 'assistant' && message.text === openRouterRequestFailedMessage;
|
|
4678
5449
|
const isOpenRouterTooManyRequestsMessage = message.role === 'assistant' && message.text.startsWith(openRouterTooManyRequestsMessage);
|
|
4679
|
-
const
|
|
5450
|
+
const messageIntermediate = parseMessageContent(message.text);
|
|
5451
|
+
const messageDom = getMessageContentDom(messageIntermediate);
|
|
5452
|
+
const toolCallsDom = getToolCallsDom(message);
|
|
5453
|
+
const extraChildCount = isOpenApiApiKeyMissingMessage || isOpenRouterApiKeyMissingMessage || isOpenRouterRequestFailedMessage || isOpenRouterTooManyRequestsMessage ? messageIntermediate.length + 1 + toolCallsDom.length : messageIntermediate.length + toolCallsDom.length;
|
|
4680
5454
|
return [{
|
|
4681
5455
|
childCount: 1,
|
|
4682
5456
|
className: mergeClassNames(Message, roleClassName),
|
|
@@ -4685,11 +5459,7 @@ const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput =
|
|
|
4685
5459
|
childCount: extraChildCount,
|
|
4686
5460
|
className: ChatMessageContent,
|
|
4687
5461
|
type: Div
|
|
4688
|
-
},
|
|
4689
|
-
childCount: 1,
|
|
4690
|
-
className: Markdown,
|
|
4691
|
-
type: P
|
|
4692
|
-
}, text(message.text), ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom(openApiApiKeyInput) : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyInput, openRouterApiKeyState) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
|
|
5462
|
+
}, ...messageDom, ...toolCallsDom, ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom(openApiApiKeyInput) : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyInput, openRouterApiKeyState) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
|
|
4693
5463
|
};
|
|
4694
5464
|
|
|
4695
5465
|
const getEmptyMessagesDom = () => {
|
|
@@ -4933,6 +5703,9 @@ const renderEventListeners = () => {
|
|
|
4933
5703
|
}, {
|
|
4934
5704
|
name: HandleClickNew,
|
|
4935
5705
|
params: ['handleClickNew']
|
|
5706
|
+
}, {
|
|
5707
|
+
name: HandleClickSessionDebug,
|
|
5708
|
+
params: ['handleClickSessionDebug']
|
|
4936
5709
|
}, {
|
|
4937
5710
|
name: HandleClickBack,
|
|
4938
5711
|
params: ['handleClickBack']
|
|
@@ -5080,6 +5853,7 @@ const commandMap = {
|
|
|
5080
5853
|
'Chat.handleClickDelete': wrapCommand(handleClickDelete),
|
|
5081
5854
|
'Chat.handleClickList': wrapCommand(handleClickList),
|
|
5082
5855
|
'Chat.handleClickNew': wrapCommand(handleClickNew),
|
|
5856
|
+
'Chat.handleClickSessionDebug': wrapCommand(handleClickSessionDebug),
|
|
5083
5857
|
'Chat.handleClickSettings': handleClickSettings,
|
|
5084
5858
|
'Chat.handleInput': wrapCommand(handleInput),
|
|
5085
5859
|
'Chat.handleInputFocus': wrapCommand(handleInputFocus),
|
|
@@ -5107,12 +5881,24 @@ const commandMap = {
|
|
|
5107
5881
|
'Chat.useMockApi': wrapCommand(useMockApi)
|
|
5108
5882
|
};
|
|
5109
5883
|
|
|
5884
|
+
const send = port => {
|
|
5885
|
+
return invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatNetworkWorker', port, 'HandleMessagePort.handleMessagePort');
|
|
5886
|
+
};
|
|
5887
|
+
const initializeChatNetworkWorker = async () => {
|
|
5888
|
+
const rpc = await create$4({
|
|
5889
|
+
commandMap: {},
|
|
5890
|
+
send
|
|
5891
|
+
});
|
|
5892
|
+
set$3(rpc);
|
|
5893
|
+
};
|
|
5894
|
+
|
|
5110
5895
|
const listen = async () => {
|
|
5111
5896
|
registerCommands(commandMap);
|
|
5112
5897
|
const rpc = await create$3({
|
|
5113
5898
|
commandMap: commandMap
|
|
5114
5899
|
});
|
|
5115
5900
|
set$1(rpc);
|
|
5901
|
+
await initializeChatNetworkWorker();
|
|
5116
5902
|
};
|
|
5117
5903
|
|
|
5118
5904
|
const main = async () => {
|