@lvce-editor/chat-storage-worker 1.0.0 → 1.2.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/chatStorageWorkerMain.js +632 -0
- package/package.json +1 -1
|
@@ -888,6 +888,631 @@ const create = async ({
|
|
|
888
888
|
return rpc;
|
|
889
889
|
};
|
|
890
890
|
|
|
891
|
+
const toError = error => {
|
|
892
|
+
if (error instanceof Error) {
|
|
893
|
+
return error;
|
|
894
|
+
}
|
|
895
|
+
return new Error('IndexedDB request failed');
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
const requestToPromise = async createRequest => {
|
|
899
|
+
const request = createRequest();
|
|
900
|
+
const {
|
|
901
|
+
promise,
|
|
902
|
+
reject,
|
|
903
|
+
resolve
|
|
904
|
+
} = Promise.withResolvers();
|
|
905
|
+
request.addEventListener('success', () => {
|
|
906
|
+
resolve(request.result);
|
|
907
|
+
});
|
|
908
|
+
request.addEventListener('error', () => {
|
|
909
|
+
reject(toError(request.error));
|
|
910
|
+
});
|
|
911
|
+
return promise;
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
const transactionToPromise = async createTransaction => {
|
|
915
|
+
const transaction = createTransaction();
|
|
916
|
+
const {
|
|
917
|
+
promise,
|
|
918
|
+
reject,
|
|
919
|
+
resolve
|
|
920
|
+
} = Promise.withResolvers();
|
|
921
|
+
transaction.addEventListener('complete', () => {
|
|
922
|
+
resolve();
|
|
923
|
+
});
|
|
924
|
+
transaction.addEventListener('error', () => {
|
|
925
|
+
reject(toError(transaction.error));
|
|
926
|
+
});
|
|
927
|
+
transaction.addEventListener('abort', () => {
|
|
928
|
+
reject(toError(transaction.error));
|
|
929
|
+
});
|
|
930
|
+
return promise;
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
const toChatViewEvent = event => {
|
|
934
|
+
const {
|
|
935
|
+
eventId,
|
|
936
|
+
...chatViewEvent
|
|
937
|
+
} = event;
|
|
938
|
+
return chatViewEvent;
|
|
939
|
+
};
|
|
940
|
+
const now$1 = () => {
|
|
941
|
+
return new Date().toISOString();
|
|
942
|
+
};
|
|
943
|
+
const isSameMessage$1 = (a, b) => {
|
|
944
|
+
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 || []);
|
|
945
|
+
};
|
|
946
|
+
const canAppendMessages$1 = (previousMessages, nextMessages) => {
|
|
947
|
+
if (nextMessages.length < previousMessages.length) {
|
|
948
|
+
return false;
|
|
949
|
+
}
|
|
950
|
+
return previousMessages.every((message, index) => isSameMessage$1(message, nextMessages[index]));
|
|
951
|
+
};
|
|
952
|
+
const canUpdateMessages$1 = (previousMessages, nextMessages) => {
|
|
953
|
+
if (previousMessages.length !== nextMessages.length) {
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
for (let i = 0; i < previousMessages.length; i += 1) {
|
|
957
|
+
const previous = previousMessages[i];
|
|
958
|
+
const next = nextMessages[i];
|
|
959
|
+
if (previous.id !== next.id || previous.role !== next.role) {
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return true;
|
|
964
|
+
};
|
|
965
|
+
const getMutationEvents$1 = (previous, next) => {
|
|
966
|
+
const timestamp = now$1();
|
|
967
|
+
const events = [];
|
|
968
|
+
if (!previous) {
|
|
969
|
+
events.push({
|
|
970
|
+
sessionId: next.id,
|
|
971
|
+
timestamp,
|
|
972
|
+
title: next.title,
|
|
973
|
+
type: 'chat-session-created'
|
|
974
|
+
});
|
|
975
|
+
for (const message of next.messages) {
|
|
976
|
+
events.push({
|
|
977
|
+
message,
|
|
978
|
+
sessionId: next.id,
|
|
979
|
+
timestamp,
|
|
980
|
+
type: 'chat-message-added'
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
return events;
|
|
984
|
+
}
|
|
985
|
+
if (previous.title !== next.title) {
|
|
986
|
+
events.push({
|
|
987
|
+
sessionId: next.id,
|
|
988
|
+
timestamp,
|
|
989
|
+
title: next.title,
|
|
990
|
+
type: 'chat-session-title-updated'
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
if (canAppendMessages$1(previous.messages, next.messages)) {
|
|
994
|
+
for (let i = previous.messages.length; i < next.messages.length; i += 1) {
|
|
995
|
+
events.push({
|
|
996
|
+
message: next.messages[i],
|
|
997
|
+
sessionId: next.id,
|
|
998
|
+
timestamp,
|
|
999
|
+
type: 'chat-message-added'
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
return events;
|
|
1003
|
+
}
|
|
1004
|
+
if (canUpdateMessages$1(previous.messages, next.messages)) {
|
|
1005
|
+
for (let i = 0; i < previous.messages.length; i += 1) {
|
|
1006
|
+
const previousMessage = previous.messages[i];
|
|
1007
|
+
const nextMessage = next.messages[i];
|
|
1008
|
+
if (!isSameMessage$1(previousMessage, nextMessage)) {
|
|
1009
|
+
events.push({
|
|
1010
|
+
inProgress: nextMessage.inProgress,
|
|
1011
|
+
messageId: nextMessage.id,
|
|
1012
|
+
sessionId: next.id,
|
|
1013
|
+
text: nextMessage.text,
|
|
1014
|
+
time: nextMessage.time,
|
|
1015
|
+
timestamp,
|
|
1016
|
+
toolCalls: nextMessage.toolCalls,
|
|
1017
|
+
type: 'chat-message-updated'
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return events;
|
|
1022
|
+
}
|
|
1023
|
+
events.push({
|
|
1024
|
+
messages: [...next.messages],
|
|
1025
|
+
sessionId: next.id,
|
|
1026
|
+
timestamp,
|
|
1027
|
+
type: 'chat-session-messages-replaced'
|
|
1028
|
+
});
|
|
1029
|
+
return events;
|
|
1030
|
+
};
|
|
1031
|
+
const replaySession$1 = (id, summary, events) => {
|
|
1032
|
+
let deleted = false;
|
|
1033
|
+
let title = summary?.title || '';
|
|
1034
|
+
let messages = summary?.messages ? [...summary.messages] : [];
|
|
1035
|
+
for (const event of events) {
|
|
1036
|
+
if (event.sessionId !== id) {
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
if (event.type === 'chat-session-created') {
|
|
1040
|
+
const {
|
|
1041
|
+
title: eventTitle
|
|
1042
|
+
} = event;
|
|
1043
|
+
deleted = false;
|
|
1044
|
+
title = eventTitle;
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
if (event.type === 'chat-session-deleted') {
|
|
1048
|
+
deleted = true;
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
if (event.type === 'chat-session-title-updated') {
|
|
1052
|
+
const {
|
|
1053
|
+
title: eventTitle
|
|
1054
|
+
} = event;
|
|
1055
|
+
title = eventTitle;
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
if (event.type === 'chat-message-added') {
|
|
1059
|
+
messages = [...messages, event.message];
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
if (event.type === 'chat-message-updated') {
|
|
1063
|
+
messages = messages.map(message => {
|
|
1064
|
+
if (message.id !== event.messageId) {
|
|
1065
|
+
return message;
|
|
1066
|
+
}
|
|
1067
|
+
return {
|
|
1068
|
+
...message,
|
|
1069
|
+
...(event.inProgress === undefined ? {} : {
|
|
1070
|
+
inProgress: event.inProgress
|
|
1071
|
+
}),
|
|
1072
|
+
text: event.text,
|
|
1073
|
+
time: event.time,
|
|
1074
|
+
...(event.toolCalls === undefined ? {} : {
|
|
1075
|
+
toolCalls: event.toolCalls
|
|
1076
|
+
})
|
|
1077
|
+
};
|
|
1078
|
+
});
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
1081
|
+
if (event.type === 'chat-session-messages-replaced') {
|
|
1082
|
+
messages = [...event.messages];
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
if (deleted || !title) {
|
|
1086
|
+
return undefined;
|
|
1087
|
+
}
|
|
1088
|
+
return {
|
|
1089
|
+
id,
|
|
1090
|
+
messages,
|
|
1091
|
+
title
|
|
1092
|
+
};
|
|
1093
|
+
};
|
|
1094
|
+
class IndexedDbChatSessionStorage {
|
|
1095
|
+
constructor(options = {}) {
|
|
1096
|
+
this.state = {
|
|
1097
|
+
databaseName: options.databaseName || 'lvce-chat-view-sessions',
|
|
1098
|
+
databasePromise: undefined,
|
|
1099
|
+
databaseVersion: options.databaseVersion || 2,
|
|
1100
|
+
eventStoreName: options.eventStoreName || 'chat-view-events',
|
|
1101
|
+
storeName: options.storeName || 'chat-sessions'
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
openDatabase = async () => {
|
|
1105
|
+
if (this.state.databasePromise) {
|
|
1106
|
+
return this.state.databasePromise;
|
|
1107
|
+
}
|
|
1108
|
+
const request = indexedDB.open(this.state.databaseName, this.state.databaseVersion);
|
|
1109
|
+
request.addEventListener('upgradeneeded', () => {
|
|
1110
|
+
const database = request.result;
|
|
1111
|
+
if (!database.objectStoreNames.contains(this.state.storeName)) {
|
|
1112
|
+
database.createObjectStore(this.state.storeName, {
|
|
1113
|
+
keyPath: 'id'
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
if (database.objectStoreNames.contains(this.state.eventStoreName)) {
|
|
1117
|
+
const {
|
|
1118
|
+
transaction
|
|
1119
|
+
} = request;
|
|
1120
|
+
if (!transaction) {
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
const eventStore = transaction.objectStore(this.state.eventStoreName);
|
|
1124
|
+
if (!eventStore.indexNames.contains('sessionId')) {
|
|
1125
|
+
eventStore.createIndex('sessionId', 'sessionId', {
|
|
1126
|
+
unique: false
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
} else {
|
|
1130
|
+
const eventStore = database.createObjectStore(this.state.eventStoreName, {
|
|
1131
|
+
autoIncrement: true,
|
|
1132
|
+
keyPath: 'eventId'
|
|
1133
|
+
});
|
|
1134
|
+
eventStore.createIndex('sessionId', 'sessionId', {
|
|
1135
|
+
unique: false
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
const databasePromise = requestToPromise(() => request);
|
|
1140
|
+
this.state.databasePromise = databasePromise;
|
|
1141
|
+
return databasePromise;
|
|
1142
|
+
};
|
|
1143
|
+
listSummaries = async () => {
|
|
1144
|
+
const database = await this.openDatabase();
|
|
1145
|
+
const transaction = database.transaction(this.state.storeName, 'readonly');
|
|
1146
|
+
const store = transaction.objectStore(this.state.storeName);
|
|
1147
|
+
const summaries = await requestToPromise(() => store.getAll());
|
|
1148
|
+
return summaries;
|
|
1149
|
+
};
|
|
1150
|
+
getSummary = async id => {
|
|
1151
|
+
const database = await this.openDatabase();
|
|
1152
|
+
const transaction = database.transaction(this.state.storeName, 'readonly');
|
|
1153
|
+
const store = transaction.objectStore(this.state.storeName);
|
|
1154
|
+
const summary = await requestToPromise(() => store.get(id));
|
|
1155
|
+
return summary;
|
|
1156
|
+
};
|
|
1157
|
+
getEventsBySessionId = async sessionId => {
|
|
1158
|
+
const database = await this.openDatabase();
|
|
1159
|
+
const transaction = database.transaction(this.state.eventStoreName, 'readonly');
|
|
1160
|
+
const store = transaction.objectStore(this.state.eventStoreName);
|
|
1161
|
+
const index = store.index('sessionId');
|
|
1162
|
+
const events = await requestToPromise(() => index.getAll(IDBKeyRange.only(sessionId)));
|
|
1163
|
+
return events.map(toChatViewEvent);
|
|
1164
|
+
};
|
|
1165
|
+
listEventsInternal = async () => {
|
|
1166
|
+
const database = await this.openDatabase();
|
|
1167
|
+
const transaction = database.transaction(this.state.eventStoreName, 'readonly');
|
|
1168
|
+
const store = transaction.objectStore(this.state.eventStoreName);
|
|
1169
|
+
const events = await requestToPromise(() => store.getAll());
|
|
1170
|
+
return events.map(toChatViewEvent);
|
|
1171
|
+
};
|
|
1172
|
+
appendEvents = async events => {
|
|
1173
|
+
if (events.length === 0) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
const database = await this.openDatabase();
|
|
1177
|
+
const transaction = database.transaction([this.state.storeName, this.state.eventStoreName], 'readwrite');
|
|
1178
|
+
const summaryStore = transaction.objectStore(this.state.storeName);
|
|
1179
|
+
const eventStore = transaction.objectStore(this.state.eventStoreName);
|
|
1180
|
+
for (const event of events) {
|
|
1181
|
+
eventStore.add(event);
|
|
1182
|
+
if (event.type === 'chat-session-created' || event.type === 'chat-session-title-updated') {
|
|
1183
|
+
summaryStore.put({
|
|
1184
|
+
id: event.sessionId,
|
|
1185
|
+
title: event.title
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
if (event.type === 'chat-session-deleted') {
|
|
1189
|
+
summaryStore.delete(event.sessionId);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
await transactionToPromise(() => transaction);
|
|
1193
|
+
};
|
|
1194
|
+
async appendEvent(event) {
|
|
1195
|
+
await this.appendEvents([event]);
|
|
1196
|
+
}
|
|
1197
|
+
async clear() {
|
|
1198
|
+
const database = await this.openDatabase();
|
|
1199
|
+
const transaction = database.transaction([this.state.storeName, this.state.eventStoreName], 'readwrite');
|
|
1200
|
+
transaction.objectStore(this.state.storeName).clear();
|
|
1201
|
+
transaction.objectStore(this.state.eventStoreName).clear();
|
|
1202
|
+
await transactionToPromise(() => transaction);
|
|
1203
|
+
}
|
|
1204
|
+
async deleteSession(id) {
|
|
1205
|
+
await this.appendEvent({
|
|
1206
|
+
sessionId: id,
|
|
1207
|
+
timestamp: now$1(),
|
|
1208
|
+
type: 'chat-session-deleted'
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
async getEvents(sessionId) {
|
|
1212
|
+
if (sessionId) {
|
|
1213
|
+
return this.getEventsBySessionId(sessionId);
|
|
1214
|
+
}
|
|
1215
|
+
return this.listEventsInternal();
|
|
1216
|
+
}
|
|
1217
|
+
async getSession(id) {
|
|
1218
|
+
const [summary, events] = await Promise.all([this.getSummary(id), this.getEventsBySessionId(id)]);
|
|
1219
|
+
return replaySession$1(id, summary, events);
|
|
1220
|
+
}
|
|
1221
|
+
async listSessions() {
|
|
1222
|
+
const summaries = await this.listSummaries();
|
|
1223
|
+
const sessions = [];
|
|
1224
|
+
for (const summary of summaries) {
|
|
1225
|
+
const events = await this.getEventsBySessionId(summary.id);
|
|
1226
|
+
const session = replaySession$1(summary.id, summary, events);
|
|
1227
|
+
if (!session) {
|
|
1228
|
+
continue;
|
|
1229
|
+
}
|
|
1230
|
+
sessions.push(session);
|
|
1231
|
+
}
|
|
1232
|
+
return sessions;
|
|
1233
|
+
}
|
|
1234
|
+
async setSession(session) {
|
|
1235
|
+
const previous = await this.getSession(session.id);
|
|
1236
|
+
const events = getMutationEvents$1(previous, session);
|
|
1237
|
+
await this.appendEvents(events);
|
|
1238
|
+
if (events.length === 0) {
|
|
1239
|
+
const database = await this.openDatabase();
|
|
1240
|
+
const transaction = database.transaction(this.state.storeName, 'readwrite');
|
|
1241
|
+
const summaryStore = transaction.objectStore(this.state.storeName);
|
|
1242
|
+
summaryStore.put({
|
|
1243
|
+
id: session.id,
|
|
1244
|
+
title: session.title
|
|
1245
|
+
});
|
|
1246
|
+
await transactionToPromise(() => transaction);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
const now = () => {
|
|
1252
|
+
return new Date().toISOString();
|
|
1253
|
+
};
|
|
1254
|
+
const isSameMessage = (a, b) => {
|
|
1255
|
+
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 || []);
|
|
1256
|
+
};
|
|
1257
|
+
const canAppendMessages = (previousMessages, nextMessages) => {
|
|
1258
|
+
if (nextMessages.length < previousMessages.length) {
|
|
1259
|
+
return false;
|
|
1260
|
+
}
|
|
1261
|
+
return previousMessages.every((message, index) => isSameMessage(message, nextMessages[index]));
|
|
1262
|
+
};
|
|
1263
|
+
const canUpdateMessages = (previousMessages, nextMessages) => {
|
|
1264
|
+
if (previousMessages.length !== nextMessages.length) {
|
|
1265
|
+
return false;
|
|
1266
|
+
}
|
|
1267
|
+
for (let i = 0; i < previousMessages.length; i += 1) {
|
|
1268
|
+
const previous = previousMessages[i];
|
|
1269
|
+
const next = nextMessages[i];
|
|
1270
|
+
if (previous.id !== next.id || previous.role !== next.role) {
|
|
1271
|
+
return false;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
return true;
|
|
1275
|
+
};
|
|
1276
|
+
const getMutationEvents = (previous, next) => {
|
|
1277
|
+
const timestamp = now();
|
|
1278
|
+
const events = [];
|
|
1279
|
+
if (!previous) {
|
|
1280
|
+
events.push({
|
|
1281
|
+
sessionId: next.id,
|
|
1282
|
+
timestamp,
|
|
1283
|
+
title: next.title,
|
|
1284
|
+
type: 'chat-session-created'
|
|
1285
|
+
});
|
|
1286
|
+
for (const message of next.messages) {
|
|
1287
|
+
events.push({
|
|
1288
|
+
message,
|
|
1289
|
+
sessionId: next.id,
|
|
1290
|
+
timestamp,
|
|
1291
|
+
type: 'chat-message-added'
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
return events;
|
|
1295
|
+
}
|
|
1296
|
+
if (previous.title !== next.title) {
|
|
1297
|
+
events.push({
|
|
1298
|
+
sessionId: next.id,
|
|
1299
|
+
timestamp,
|
|
1300
|
+
title: next.title,
|
|
1301
|
+
type: 'chat-session-title-updated'
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
if (canAppendMessages(previous.messages, next.messages)) {
|
|
1305
|
+
for (let i = previous.messages.length; i < next.messages.length; i += 1) {
|
|
1306
|
+
events.push({
|
|
1307
|
+
message: next.messages[i],
|
|
1308
|
+
sessionId: next.id,
|
|
1309
|
+
timestamp,
|
|
1310
|
+
type: 'chat-message-added'
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
return events;
|
|
1314
|
+
}
|
|
1315
|
+
if (canUpdateMessages(previous.messages, next.messages)) {
|
|
1316
|
+
for (let i = 0; i < previous.messages.length; i += 1) {
|
|
1317
|
+
const previousMessage = previous.messages[i];
|
|
1318
|
+
const nextMessage = next.messages[i];
|
|
1319
|
+
if (!isSameMessage(previousMessage, nextMessage)) {
|
|
1320
|
+
events.push({
|
|
1321
|
+
inProgress: nextMessage.inProgress,
|
|
1322
|
+
messageId: nextMessage.id,
|
|
1323
|
+
sessionId: next.id,
|
|
1324
|
+
text: nextMessage.text,
|
|
1325
|
+
time: nextMessage.time,
|
|
1326
|
+
timestamp,
|
|
1327
|
+
toolCalls: nextMessage.toolCalls,
|
|
1328
|
+
type: 'chat-message-updated'
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
return events;
|
|
1333
|
+
}
|
|
1334
|
+
events.push({
|
|
1335
|
+
messages: [...next.messages],
|
|
1336
|
+
sessionId: next.id,
|
|
1337
|
+
timestamp,
|
|
1338
|
+
type: 'chat-session-messages-replaced'
|
|
1339
|
+
});
|
|
1340
|
+
return events;
|
|
1341
|
+
};
|
|
1342
|
+
const replaySession = (id, title, events) => {
|
|
1343
|
+
let deleted = false;
|
|
1344
|
+
let currentTitle = title || '';
|
|
1345
|
+
let messages = [];
|
|
1346
|
+
for (const event of events) {
|
|
1347
|
+
if (event.sessionId !== id) {
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
if (event.type === 'chat-session-created') {
|
|
1351
|
+
deleted = false;
|
|
1352
|
+
currentTitle = event.title;
|
|
1353
|
+
continue;
|
|
1354
|
+
}
|
|
1355
|
+
if (event.type === 'chat-session-deleted') {
|
|
1356
|
+
deleted = true;
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
if (event.type === 'chat-session-title-updated') {
|
|
1360
|
+
currentTitle = event.title;
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
if (event.type === 'chat-message-added') {
|
|
1364
|
+
messages = [...messages, event.message];
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
if (event.type === 'chat-message-updated') {
|
|
1368
|
+
messages = messages.map(message => {
|
|
1369
|
+
if (message.id !== event.messageId) {
|
|
1370
|
+
return message;
|
|
1371
|
+
}
|
|
1372
|
+
return {
|
|
1373
|
+
...message,
|
|
1374
|
+
...(event.inProgress === undefined ? {} : {
|
|
1375
|
+
inProgress: event.inProgress
|
|
1376
|
+
}),
|
|
1377
|
+
text: event.text,
|
|
1378
|
+
time: event.time,
|
|
1379
|
+
...(event.toolCalls === undefined ? {} : {
|
|
1380
|
+
toolCalls: event.toolCalls
|
|
1381
|
+
})
|
|
1382
|
+
};
|
|
1383
|
+
});
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
if (event.type === 'chat-session-messages-replaced') {
|
|
1387
|
+
messages = [...event.messages];
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
if (deleted || !currentTitle) {
|
|
1391
|
+
return undefined;
|
|
1392
|
+
}
|
|
1393
|
+
return {
|
|
1394
|
+
id,
|
|
1395
|
+
messages,
|
|
1396
|
+
title: currentTitle
|
|
1397
|
+
};
|
|
1398
|
+
};
|
|
1399
|
+
class InMemoryChatSessionStorage {
|
|
1400
|
+
events = [];
|
|
1401
|
+
summaries = new Map();
|
|
1402
|
+
async appendEvent(event) {
|
|
1403
|
+
this.events.push(event);
|
|
1404
|
+
if (event.type === 'chat-session-created' || event.type === 'chat-session-title-updated') {
|
|
1405
|
+
this.summaries.set(event.sessionId, event.title);
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
if (event.type === 'chat-session-deleted') {
|
|
1409
|
+
this.summaries.delete(event.sessionId);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
async clear() {
|
|
1413
|
+
this.events.length = 0;
|
|
1414
|
+
this.summaries.clear();
|
|
1415
|
+
}
|
|
1416
|
+
async deleteSession(id) {
|
|
1417
|
+
await this.appendEvent({
|
|
1418
|
+
sessionId: id,
|
|
1419
|
+
timestamp: now(),
|
|
1420
|
+
type: 'chat-session-deleted'
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
async getEvents(sessionId) {
|
|
1424
|
+
if (!sessionId) {
|
|
1425
|
+
return [...this.events];
|
|
1426
|
+
}
|
|
1427
|
+
return this.events.filter(event => event.sessionId === sessionId);
|
|
1428
|
+
}
|
|
1429
|
+
async getSession(id) {
|
|
1430
|
+
return replaySession(id, this.summaries.get(id), this.events);
|
|
1431
|
+
}
|
|
1432
|
+
async listSessions() {
|
|
1433
|
+
const ids = new Set();
|
|
1434
|
+
for (const id of this.summaries.keys()) {
|
|
1435
|
+
ids.add(id);
|
|
1436
|
+
}
|
|
1437
|
+
for (const event of this.events) {
|
|
1438
|
+
ids.add(event.sessionId);
|
|
1439
|
+
}
|
|
1440
|
+
const sessions = [];
|
|
1441
|
+
for (const id of ids) {
|
|
1442
|
+
const session = replaySession(id, this.summaries.get(id), this.events);
|
|
1443
|
+
if (!session) {
|
|
1444
|
+
continue;
|
|
1445
|
+
}
|
|
1446
|
+
sessions.push(session);
|
|
1447
|
+
}
|
|
1448
|
+
return sessions;
|
|
1449
|
+
}
|
|
1450
|
+
async setSession(session) {
|
|
1451
|
+
const previous = await this.getSession(session.id);
|
|
1452
|
+
const events = getMutationEvents(previous, session);
|
|
1453
|
+
for (const event of events) {
|
|
1454
|
+
await this.appendEvent(event);
|
|
1455
|
+
}
|
|
1456
|
+
this.summaries.set(session.id, session.title);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
const createDefaultStorage = () => {
|
|
1461
|
+
if (typeof indexedDB === 'undefined') {
|
|
1462
|
+
return new InMemoryChatSessionStorage();
|
|
1463
|
+
}
|
|
1464
|
+
return new IndexedDbChatSessionStorage();
|
|
1465
|
+
};
|
|
1466
|
+
let chatSessionStorage = createDefaultStorage();
|
|
1467
|
+
const setSession = async session => {
|
|
1468
|
+
await chatSessionStorage.setSession(session);
|
|
1469
|
+
};
|
|
1470
|
+
const listChatSessions = async () => {
|
|
1471
|
+
const sessions = await chatSessionStorage.listSessions();
|
|
1472
|
+
return sessions.map(session => {
|
|
1473
|
+
const summary = {
|
|
1474
|
+
id: session.id,
|
|
1475
|
+
messages: [],
|
|
1476
|
+
title: session.title
|
|
1477
|
+
};
|
|
1478
|
+
if (!session.projectId) {
|
|
1479
|
+
return summary;
|
|
1480
|
+
}
|
|
1481
|
+
return {
|
|
1482
|
+
...summary,
|
|
1483
|
+
projectId: session.projectId
|
|
1484
|
+
};
|
|
1485
|
+
});
|
|
1486
|
+
};
|
|
1487
|
+
const getChatSession = async id => {
|
|
1488
|
+
const session = await chatSessionStorage.getSession(id);
|
|
1489
|
+
if (!session) {
|
|
1490
|
+
return undefined;
|
|
1491
|
+
}
|
|
1492
|
+
const resultBase = {
|
|
1493
|
+
id: session.id,
|
|
1494
|
+
messages: [...session.messages],
|
|
1495
|
+
title: session.title
|
|
1496
|
+
};
|
|
1497
|
+
const result = session.projectId ? {
|
|
1498
|
+
...resultBase,
|
|
1499
|
+
projectId: session.projectId
|
|
1500
|
+
} : resultBase;
|
|
1501
|
+
return result;
|
|
1502
|
+
};
|
|
1503
|
+
const deleteChatSession = async id => {
|
|
1504
|
+
await chatSessionStorage.deleteSession(id);
|
|
1505
|
+
};
|
|
1506
|
+
const clearChatSessions = async () => {
|
|
1507
|
+
await chatSessionStorage.clear();
|
|
1508
|
+
};
|
|
1509
|
+
const appendChatViewEvent = async event => {
|
|
1510
|
+
await chatSessionStorage.appendEvent(event);
|
|
1511
|
+
};
|
|
1512
|
+
const getChatViewEvents = async sessionId => {
|
|
1513
|
+
return chatSessionStorage.getEvents(sessionId);
|
|
1514
|
+
};
|
|
1515
|
+
|
|
891
1516
|
const handleMessagePort = async port => {
|
|
892
1517
|
await create$1({
|
|
893
1518
|
commandMap: commandMap,
|
|
@@ -896,6 +1521,13 @@ const handleMessagePort = async port => {
|
|
|
896
1521
|
};
|
|
897
1522
|
|
|
898
1523
|
const commandMap = {
|
|
1524
|
+
'ChatStorage.appendEvent': appendChatViewEvent,
|
|
1525
|
+
'ChatStorage.clear': clearChatSessions,
|
|
1526
|
+
'ChatStorage.deleteSession': deleteChatSession,
|
|
1527
|
+
'ChatStorage.getEvents': getChatViewEvents,
|
|
1528
|
+
'ChatStorage.getSession': getChatSession,
|
|
1529
|
+
'ChatStorage.listSessions': listChatSessions,
|
|
1530
|
+
'ChatStorage.setSession': setSession,
|
|
899
1531
|
'HandleMessagePort.handleMessagePort': handleMessagePort
|
|
900
1532
|
};
|
|
901
1533
|
|