@lvce-editor/chat-debug-view 3.2.0 → 3.4.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/chatDebugViewWorkerMain.js +343 -75
- package/package.json +1 -1
|
@@ -1067,52 +1067,310 @@ const handleInput = (state, name, value, checked) => {
|
|
|
1067
1067
|
return state;
|
|
1068
1068
|
};
|
|
1069
1069
|
|
|
1070
|
-
const
|
|
1071
|
-
|
|
1072
|
-
const {
|
|
1073
|
-
promise,
|
|
1074
|
-
reject,
|
|
1075
|
-
resolve
|
|
1076
|
-
} = Promise.withResolvers();
|
|
1077
|
-
const onSuccess = () => {
|
|
1078
|
-
cleanup();
|
|
1079
|
-
resolve(request.result);
|
|
1080
|
-
};
|
|
1081
|
-
const onError = () => {
|
|
1082
|
-
cleanup();
|
|
1083
|
-
reject(request.error || new Error('IndexedDB request failed'));
|
|
1084
|
-
};
|
|
1085
|
-
const cleanup = () => {
|
|
1086
|
-
request.removeEventListener('success', onSuccess);
|
|
1087
|
-
request.removeEventListener('error', onError);
|
|
1088
|
-
};
|
|
1089
|
-
request.addEventListener('success', onSuccess);
|
|
1090
|
-
request.addEventListener('error', onError);
|
|
1091
|
-
return promise;
|
|
1070
|
+
const getFailedToLoadMessage = sessionId => {
|
|
1071
|
+
return `Failed to load chat debug session "${sessionId}". Please try again.`;
|
|
1092
1072
|
};
|
|
1093
1073
|
|
|
1094
|
-
|
|
1074
|
+
const ParseChatDebugUriErrorCode = {
|
|
1075
|
+
InvalidSessionId: 'invalid-session-id',
|
|
1076
|
+
InvalidUriEncoding: 'invalid-uri-encoding',
|
|
1077
|
+
InvalidUriFormat: 'invalid-uri-format',
|
|
1078
|
+
MissingUri: 'missing-uri'
|
|
1079
|
+
};
|
|
1095
1080
|
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1081
|
+
const getInvalidUriMessage = (uri, code) => {
|
|
1082
|
+
if (code === ParseChatDebugUriErrorCode.MissingUri) {
|
|
1083
|
+
return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
|
|
1084
|
+
}
|
|
1085
|
+
return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
|
|
1099
1086
|
};
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
return
|
|
1087
|
+
|
|
1088
|
+
const getSessionNotFoundMessage = sessionId => {
|
|
1089
|
+
return `No chat session found for sessionId "${sessionId}".`;
|
|
1103
1090
|
};
|
|
1091
|
+
|
|
1104
1092
|
const filterEventsBySessionId = (events, sessionId) => {
|
|
1105
1093
|
return events.filter(event => event.sessionId === sessionId);
|
|
1106
1094
|
};
|
|
1095
|
+
|
|
1096
|
+
// cspell:ignore IDBP
|
|
1097
|
+
|
|
1098
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1099
|
+
const getAllEvents = async store => {
|
|
1100
|
+
const all = await store.getAll();
|
|
1101
|
+
return all;
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
// cspell:ignore IDBP
|
|
1105
|
+
|
|
1107
1106
|
const getEventsBySessionId = async (store, sessionId, sessionIdIndexName) => {
|
|
1108
1107
|
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1109
1108
|
const index = store.index(sessionIdIndexName);
|
|
1110
|
-
const events = await
|
|
1109
|
+
const events = await index.getAll(sessionId);
|
|
1111
1110
|
return filterEventsBySessionId(events, sessionId);
|
|
1112
1111
|
}
|
|
1113
1112
|
const all = await getAllEvents(store);
|
|
1114
1113
|
return filterEventsBySessionId(all, sessionId);
|
|
1115
1114
|
};
|
|
1115
|
+
|
|
1116
|
+
const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
|
|
1117
|
+
let idbProxyableTypes;
|
|
1118
|
+
let cursorAdvanceMethods;
|
|
1119
|
+
// This is a function to prevent it throwing up in node environments.
|
|
1120
|
+
function getIdbProxyableTypes() {
|
|
1121
|
+
return idbProxyableTypes || (idbProxyableTypes = [IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction]);
|
|
1122
|
+
}
|
|
1123
|
+
// This is a function to prevent it throwing up in node environments.
|
|
1124
|
+
function getCursorAdvanceMethods() {
|
|
1125
|
+
return cursorAdvanceMethods || (cursorAdvanceMethods = [IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey]);
|
|
1126
|
+
}
|
|
1127
|
+
const transactionDoneMap = new WeakMap();
|
|
1128
|
+
const transformCache = new WeakMap();
|
|
1129
|
+
const reverseTransformCache = new WeakMap();
|
|
1130
|
+
function promisifyRequest(request) {
|
|
1131
|
+
const promise = new Promise((resolve, reject) => {
|
|
1132
|
+
const unlisten = () => {
|
|
1133
|
+
request.removeEventListener('success', success);
|
|
1134
|
+
request.removeEventListener('error', error);
|
|
1135
|
+
};
|
|
1136
|
+
const success = () => {
|
|
1137
|
+
resolve(wrap(request.result));
|
|
1138
|
+
unlisten();
|
|
1139
|
+
};
|
|
1140
|
+
const error = () => {
|
|
1141
|
+
reject(request.error);
|
|
1142
|
+
unlisten();
|
|
1143
|
+
};
|
|
1144
|
+
request.addEventListener('success', success);
|
|
1145
|
+
request.addEventListener('error', error);
|
|
1146
|
+
});
|
|
1147
|
+
// This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
|
|
1148
|
+
// is because we create many promises from a single IDBRequest.
|
|
1149
|
+
reverseTransformCache.set(promise, request);
|
|
1150
|
+
return promise;
|
|
1151
|
+
}
|
|
1152
|
+
function cacheDonePromiseForTransaction(tx) {
|
|
1153
|
+
// Early bail if we've already created a done promise for this transaction.
|
|
1154
|
+
if (transactionDoneMap.has(tx)) return;
|
|
1155
|
+
const done = new Promise((resolve, reject) => {
|
|
1156
|
+
const unlisten = () => {
|
|
1157
|
+
tx.removeEventListener('complete', complete);
|
|
1158
|
+
tx.removeEventListener('error', error);
|
|
1159
|
+
tx.removeEventListener('abort', error);
|
|
1160
|
+
};
|
|
1161
|
+
const complete = () => {
|
|
1162
|
+
resolve();
|
|
1163
|
+
unlisten();
|
|
1164
|
+
};
|
|
1165
|
+
const error = () => {
|
|
1166
|
+
reject(tx.error || new DOMException('AbortError', 'AbortError'));
|
|
1167
|
+
unlisten();
|
|
1168
|
+
};
|
|
1169
|
+
tx.addEventListener('complete', complete);
|
|
1170
|
+
tx.addEventListener('error', error);
|
|
1171
|
+
tx.addEventListener('abort', error);
|
|
1172
|
+
});
|
|
1173
|
+
// Cache it for later retrieval.
|
|
1174
|
+
transactionDoneMap.set(tx, done);
|
|
1175
|
+
}
|
|
1176
|
+
let idbProxyTraps = {
|
|
1177
|
+
get(target, prop, receiver) {
|
|
1178
|
+
if (target instanceof IDBTransaction) {
|
|
1179
|
+
// Special handling for transaction.done.
|
|
1180
|
+
if (prop === 'done') return transactionDoneMap.get(target);
|
|
1181
|
+
// Make tx.store return the only store in the transaction, or undefined if there are many.
|
|
1182
|
+
if (prop === 'store') {
|
|
1183
|
+
return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
// Else transform whatever we get back.
|
|
1187
|
+
return wrap(target[prop]);
|
|
1188
|
+
},
|
|
1189
|
+
set(target, prop, value) {
|
|
1190
|
+
target[prop] = value;
|
|
1191
|
+
return true;
|
|
1192
|
+
},
|
|
1193
|
+
has(target, prop) {
|
|
1194
|
+
if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) {
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
return prop in target;
|
|
1198
|
+
}
|
|
1199
|
+
};
|
|
1200
|
+
function replaceTraps(callback) {
|
|
1201
|
+
idbProxyTraps = callback(idbProxyTraps);
|
|
1202
|
+
}
|
|
1203
|
+
function wrapFunction(func) {
|
|
1204
|
+
// Due to expected object equality (which is enforced by the caching in `wrap`), we
|
|
1205
|
+
// only create one new func per func.
|
|
1206
|
+
// Cursor methods are special, as the behaviour is a little more different to standard IDB. In
|
|
1207
|
+
// IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
|
|
1208
|
+
// cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
|
|
1209
|
+
// with real promises, so each advance methods returns a new promise for the cursor object, or
|
|
1210
|
+
// undefined if the end of the cursor has been reached.
|
|
1211
|
+
if (getCursorAdvanceMethods().includes(func)) {
|
|
1212
|
+
return function (...args) {
|
|
1213
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
1214
|
+
// the original object.
|
|
1215
|
+
func.apply(unwrap(this), args);
|
|
1216
|
+
return wrap(this.request);
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
return function (...args) {
|
|
1220
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
1221
|
+
// the original object.
|
|
1222
|
+
return wrap(func.apply(unwrap(this), args));
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function transformCachableValue(value) {
|
|
1226
|
+
if (typeof value === 'function') return wrapFunction(value);
|
|
1227
|
+
// This doesn't return, it just creates a 'done' promise for the transaction,
|
|
1228
|
+
// which is later returned for transaction.done (see idbObjectHandler).
|
|
1229
|
+
if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value);
|
|
1230
|
+
if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps);
|
|
1231
|
+
// Return the same value back if we're not going to transform it.
|
|
1232
|
+
return value;
|
|
1233
|
+
}
|
|
1234
|
+
function wrap(value) {
|
|
1235
|
+
// We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
|
|
1236
|
+
// IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
|
|
1237
|
+
if (value instanceof IDBRequest) return promisifyRequest(value);
|
|
1238
|
+
// If we've already transformed this value before, reuse the transformed value.
|
|
1239
|
+
// This is faster, but it also provides object equality.
|
|
1240
|
+
if (transformCache.has(value)) return transformCache.get(value);
|
|
1241
|
+
const newValue = transformCachableValue(value);
|
|
1242
|
+
// Not all types are transformed.
|
|
1243
|
+
// These may be primitive types, so they can't be WeakMap keys.
|
|
1244
|
+
if (newValue !== value) {
|
|
1245
|
+
transformCache.set(value, newValue);
|
|
1246
|
+
reverseTransformCache.set(newValue, value);
|
|
1247
|
+
}
|
|
1248
|
+
return newValue;
|
|
1249
|
+
}
|
|
1250
|
+
const unwrap = value => reverseTransformCache.get(value);
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* Open a database.
|
|
1254
|
+
*
|
|
1255
|
+
* @param name Name of the database.
|
|
1256
|
+
* @param version Schema version.
|
|
1257
|
+
* @param callbacks Additional callbacks.
|
|
1258
|
+
*/
|
|
1259
|
+
function openDB(name, version, {
|
|
1260
|
+
blocked,
|
|
1261
|
+
upgrade,
|
|
1262
|
+
blocking,
|
|
1263
|
+
terminated
|
|
1264
|
+
} = {}) {
|
|
1265
|
+
const request = indexedDB.open(name, version);
|
|
1266
|
+
const openPromise = wrap(request);
|
|
1267
|
+
if (upgrade) {
|
|
1268
|
+
request.addEventListener('upgradeneeded', event => {
|
|
1269
|
+
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
if (blocked) {
|
|
1273
|
+
request.addEventListener('blocked', event => blocked(
|
|
1274
|
+
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
|
|
1275
|
+
event.oldVersion, event.newVersion, event));
|
|
1276
|
+
}
|
|
1277
|
+
openPromise.then(db => {
|
|
1278
|
+
if (terminated) db.addEventListener('close', () => terminated());
|
|
1279
|
+
if (blocking) {
|
|
1280
|
+
db.addEventListener('versionchange', event => blocking(event.oldVersion, event.newVersion, event));
|
|
1281
|
+
}
|
|
1282
|
+
}).catch(() => {});
|
|
1283
|
+
return openPromise;
|
|
1284
|
+
}
|
|
1285
|
+
const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
|
|
1286
|
+
const writeMethods = ['put', 'add', 'delete', 'clear'];
|
|
1287
|
+
const cachedMethods = new Map();
|
|
1288
|
+
function getMethod(target, prop) {
|
|
1289
|
+
if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) {
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (cachedMethods.get(prop)) return cachedMethods.get(prop);
|
|
1293
|
+
const targetFuncName = prop.replace(/FromIndex$/, '');
|
|
1294
|
+
const useIndex = prop !== targetFuncName;
|
|
1295
|
+
const isWrite = writeMethods.includes(targetFuncName);
|
|
1296
|
+
if (
|
|
1297
|
+
// Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
|
|
1298
|
+
!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) {
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
const method = async function (storeName, ...args) {
|
|
1302
|
+
// isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
|
|
1303
|
+
const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
|
|
1304
|
+
let target = tx.store;
|
|
1305
|
+
if (useIndex) target = target.index(args.shift());
|
|
1306
|
+
// Must reject if op rejects.
|
|
1307
|
+
// If it's a write operation, must reject if tx.done rejects.
|
|
1308
|
+
// Must reject with op rejection first.
|
|
1309
|
+
// Must resolve with op value.
|
|
1310
|
+
// Must handle both promises (no unhandled rejections)
|
|
1311
|
+
return (await Promise.all([target[targetFuncName](...args), isWrite && tx.done]))[0];
|
|
1312
|
+
};
|
|
1313
|
+
cachedMethods.set(prop, method);
|
|
1314
|
+
return method;
|
|
1315
|
+
}
|
|
1316
|
+
replaceTraps(oldTraps => ({
|
|
1317
|
+
...oldTraps,
|
|
1318
|
+
get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
|
|
1319
|
+
has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)
|
|
1320
|
+
}));
|
|
1321
|
+
const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
|
|
1322
|
+
const methodMap = {};
|
|
1323
|
+
const advanceResults = new WeakMap();
|
|
1324
|
+
const ittrProxiedCursorToOriginalProxy = new WeakMap();
|
|
1325
|
+
const cursorIteratorTraps = {
|
|
1326
|
+
get(target, prop) {
|
|
1327
|
+
if (!advanceMethodProps.includes(prop)) return target[prop];
|
|
1328
|
+
let cachedFunc = methodMap[prop];
|
|
1329
|
+
if (!cachedFunc) {
|
|
1330
|
+
cachedFunc = methodMap[prop] = function (...args) {
|
|
1331
|
+
advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
return cachedFunc;
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
async function* iterate(...args) {
|
|
1338
|
+
// tslint:disable-next-line:no-this-assignment
|
|
1339
|
+
let cursor = this;
|
|
1340
|
+
if (!(cursor instanceof IDBCursor)) {
|
|
1341
|
+
cursor = await cursor.openCursor(...args);
|
|
1342
|
+
}
|
|
1343
|
+
if (!cursor) return;
|
|
1344
|
+
cursor = cursor;
|
|
1345
|
+
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
1346
|
+
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
1347
|
+
// Map this double-proxy back to the original, so other cursor methods work.
|
|
1348
|
+
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
1349
|
+
while (cursor) {
|
|
1350
|
+
yield proxiedCursor;
|
|
1351
|
+
// If one of the advancing methods was not called, call continue().
|
|
1352
|
+
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
1353
|
+
advanceResults.delete(proxiedCursor);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
function isIteratorProp(target, prop) {
|
|
1357
|
+
return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
|
|
1358
|
+
}
|
|
1359
|
+
replaceTraps(oldTraps => ({
|
|
1360
|
+
...oldTraps,
|
|
1361
|
+
get(target, prop, receiver) {
|
|
1362
|
+
if (isIteratorProp(target, prop)) return iterate;
|
|
1363
|
+
return oldTraps.get(target, prop, receiver);
|
|
1364
|
+
},
|
|
1365
|
+
has(target, prop) {
|
|
1366
|
+
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
1367
|
+
}
|
|
1368
|
+
}));
|
|
1369
|
+
|
|
1370
|
+
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1371
|
+
return openDB(databaseName, dataBaseVersion);
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1116
1374
|
const listChatViewEvents = async (sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName) => {
|
|
1117
1375
|
if (typeof indexedDB === 'undefined') {
|
|
1118
1376
|
return [];
|
|
@@ -1135,36 +1393,39 @@ const listChatViewEvents = async (sessionId, databaseName, dataBaseVersion, even
|
|
|
1135
1393
|
|
|
1136
1394
|
const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
|
|
1137
1395
|
const invalidSessionIdPattern = /[/?#]/;
|
|
1138
|
-
const ParseChatDebugUriErrorCode = {
|
|
1139
|
-
InvalidSessionId: 'invalid-session-id',
|
|
1140
|
-
InvalidUriEncoding: 'invalid-uri-encoding',
|
|
1141
|
-
InvalidUriFormat: 'invalid-uri-format',
|
|
1142
|
-
MissingUri: 'missing-uri'
|
|
1143
|
-
};
|
|
1144
|
-
const createErrorResult = (code, message) => {
|
|
1145
|
-
return {
|
|
1146
|
-
code,
|
|
1147
|
-
message,
|
|
1148
|
-
type: 'error'
|
|
1149
|
-
};
|
|
1150
|
-
};
|
|
1151
1396
|
const parseChatDebugUri = uri => {
|
|
1152
1397
|
if (!uri) {
|
|
1153
|
-
return
|
|
1398
|
+
return {
|
|
1399
|
+
code: ParseChatDebugUriErrorCode.MissingUri,
|
|
1400
|
+
message: 'Missing URI',
|
|
1401
|
+
type: 'error'
|
|
1402
|
+
};
|
|
1154
1403
|
}
|
|
1155
1404
|
const match = uri.match(chatDebugUriPattern);
|
|
1156
1405
|
if (!match) {
|
|
1157
|
-
return
|
|
1406
|
+
return {
|
|
1407
|
+
code: ParseChatDebugUriErrorCode.InvalidUriFormat,
|
|
1408
|
+
message: 'Invalid URI format',
|
|
1409
|
+
type: 'error'
|
|
1410
|
+
};
|
|
1158
1411
|
}
|
|
1159
1412
|
const encodedSessionId = match[1];
|
|
1160
1413
|
let sessionId;
|
|
1161
1414
|
try {
|
|
1162
1415
|
sessionId = decodeURIComponent(encodedSessionId);
|
|
1163
1416
|
} catch {
|
|
1164
|
-
return
|
|
1417
|
+
return {
|
|
1418
|
+
code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
|
|
1419
|
+
message: 'Invalid URI encoding',
|
|
1420
|
+
type: 'error'
|
|
1421
|
+
};
|
|
1165
1422
|
}
|
|
1166
1423
|
if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
|
|
1167
|
-
return
|
|
1424
|
+
return {
|
|
1425
|
+
code: ParseChatDebugUriErrorCode.InvalidSessionId,
|
|
1426
|
+
message: 'Invalid session id',
|
|
1427
|
+
type: 'error'
|
|
1428
|
+
};
|
|
1168
1429
|
}
|
|
1169
1430
|
return {
|
|
1170
1431
|
sessionId,
|
|
@@ -1172,18 +1433,6 @@ const parseChatDebugUri = uri => {
|
|
|
1172
1433
|
};
|
|
1173
1434
|
};
|
|
1174
1435
|
|
|
1175
|
-
const getInvalidUriMessage = (uri, code) => {
|
|
1176
|
-
if (code === ParseChatDebugUriErrorCode.MissingUri) {
|
|
1177
|
-
return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
|
|
1178
|
-
}
|
|
1179
|
-
return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
|
|
1180
|
-
};
|
|
1181
|
-
const getSessionNotFoundMessage = sessionId => {
|
|
1182
|
-
return `No chat session found for sessionId "${sessionId}".`;
|
|
1183
|
-
};
|
|
1184
|
-
const getFailedToLoadMessage = sessionId => {
|
|
1185
|
-
return `Failed to load chat debug session "${sessionId}". Please try again.`;
|
|
1186
|
-
};
|
|
1187
1436
|
const loadContent = async state => {
|
|
1188
1437
|
const {
|
|
1189
1438
|
databaseName,
|
|
@@ -1285,11 +1534,6 @@ const getCss = () => {
|
|
|
1285
1534
|
gap: 4px;
|
|
1286
1535
|
}
|
|
1287
1536
|
|
|
1288
|
-
.ChatDebugViewSession {
|
|
1289
|
-
font-size: 12px;
|
|
1290
|
-
opacity: 0.8;
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
1537
|
.ChatDebugViewEventCount {
|
|
1294
1538
|
font-size: 12px;
|
|
1295
1539
|
opacity: 0.8;
|
|
@@ -1510,7 +1754,8 @@ const getEventNode = event => {
|
|
|
1510
1754
|
type: Pre
|
|
1511
1755
|
}, ...tokenNodes];
|
|
1512
1756
|
};
|
|
1513
|
-
|
|
1757
|
+
|
|
1758
|
+
const getChatDebugViewDom = (errorMessage, filterValue, showEventStreamFinishedEvents, showInputEvents, showResponsePartEvents, events) => {
|
|
1514
1759
|
if (errorMessage) {
|
|
1515
1760
|
return [{
|
|
1516
1761
|
childCount: 1,
|
|
@@ -1529,7 +1774,7 @@ const getChatDebugViewDom = (sessionId, errorMessage, filterValue, showEventStre
|
|
|
1529
1774
|
const eventCountText = events.length === 0 && hasFilterValue ? noFilteredEventsMessage : `${events.length} event${events.length === 1 ? '' : 's'}`;
|
|
1530
1775
|
const emptyMessage = events.length === 0 && hasFilterValue ? noFilteredEventsMessage : 'No events';
|
|
1531
1776
|
return [{
|
|
1532
|
-
childCount:
|
|
1777
|
+
childCount: 3,
|
|
1533
1778
|
className: 'ChatDebugView',
|
|
1534
1779
|
type: Div
|
|
1535
1780
|
}, {
|
|
@@ -1537,6 +1782,7 @@ const getChatDebugViewDom = (sessionId, errorMessage, filterValue, showEventStre
|
|
|
1537
1782
|
className: 'ChatDebugViewTop',
|
|
1538
1783
|
type: Div
|
|
1539
1784
|
}, {
|
|
1785
|
+
autocomplete: 'off',
|
|
1540
1786
|
childCount: 0,
|
|
1541
1787
|
className: 'InputBox',
|
|
1542
1788
|
inputType: 'search',
|
|
@@ -1587,10 +1833,6 @@ const getChatDebugViewDom = (sessionId, errorMessage, filterValue, showEventStre
|
|
|
1587
1833
|
className: 'ChatDebugViewEventCount',
|
|
1588
1834
|
type: Div
|
|
1589
1835
|
}, text(eventCountText), {
|
|
1590
|
-
childCount: 1,
|
|
1591
|
-
className: 'ChatDebugViewSession',
|
|
1592
|
-
type: Div
|
|
1593
|
-
}, text(`sessionId: ${sessionId || '(none)'}`), {
|
|
1594
1836
|
childCount: eventNodes.length === 0 ? 1 : eventNodes.length,
|
|
1595
1837
|
className: 'ChatDebugViewEvents',
|
|
1596
1838
|
type: Div
|
|
@@ -1601,6 +1843,28 @@ const getChatDebugViewDom = (sessionId, errorMessage, filterValue, showEventStre
|
|
|
1601
1843
|
}, text(errorMessage || emptyMessage)] : eventNodes)];
|
|
1602
1844
|
};
|
|
1603
1845
|
|
|
1846
|
+
const RE_SPACE = /\s+/;
|
|
1847
|
+
const parseFilterValue = filterValue => {
|
|
1848
|
+
const normalizedFilter = filterValue.trim().toLowerCase();
|
|
1849
|
+
if (!normalizedFilter) {
|
|
1850
|
+
return {
|
|
1851
|
+
filterText: '',
|
|
1852
|
+
toolsOnly: false
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
const parts = normalizedFilter.split(RE_SPACE);
|
|
1856
|
+
const toolsOnly = parts.includes('@tools');
|
|
1857
|
+
const filterText = parts.filter(part => part !== '@tools').join(' ');
|
|
1858
|
+
return {
|
|
1859
|
+
filterText,
|
|
1860
|
+
toolsOnly
|
|
1861
|
+
};
|
|
1862
|
+
};
|
|
1863
|
+
|
|
1864
|
+
const toolEventTypePrefix = 'tool-execution-';
|
|
1865
|
+
const isToolEvent = event => {
|
|
1866
|
+
return event.type.startsWith(toolEventTypePrefix);
|
|
1867
|
+
};
|
|
1604
1868
|
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1605
1869
|
return events.filter(event => {
|
|
1606
1870
|
if (!showInputEvents && (event.type === 'handle-input' || event.type === 'handle-submit')) {
|
|
@@ -1621,11 +1885,15 @@ const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showE
|
|
|
1621
1885
|
};
|
|
1622
1886
|
const getFilteredEvents = (events, filterValue, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1623
1887
|
const visibleEvents = getVisibleEvents(events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
1624
|
-
const
|
|
1625
|
-
|
|
1626
|
-
|
|
1888
|
+
const {
|
|
1889
|
+
filterText,
|
|
1890
|
+
toolsOnly
|
|
1891
|
+
} = parseFilterValue(filterValue);
|
|
1892
|
+
const filteredBySyntax = toolsOnly ? visibleEvents.filter(isToolEvent) : visibleEvents;
|
|
1893
|
+
if (!filterText) {
|
|
1894
|
+
return filteredBySyntax;
|
|
1627
1895
|
}
|
|
1628
|
-
return
|
|
1896
|
+
return filteredBySyntax.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
|
|
1629
1897
|
};
|
|
1630
1898
|
|
|
1631
1899
|
const withSessionEventIds = events => {
|
|
@@ -1639,7 +1907,7 @@ const withSessionEventIds = events => {
|
|
|
1639
1907
|
const renderItems = (oldState, newState) => {
|
|
1640
1908
|
const eventsWithIds = withSessionEventIds(newState.events);
|
|
1641
1909
|
const filteredEvents = getFilteredEvents(eventsWithIds, newState.filterValue, newState.showInputEvents, newState.showResponsePartEvents, newState.showEventStreamFinishedEvents);
|
|
1642
|
-
const dom = getChatDebugViewDom(newState.
|
|
1910
|
+
const dom = getChatDebugViewDom(newState.errorMessage, newState.filterValue, newState.showEventStreamFinishedEvents, newState.showInputEvents, newState.showResponsePartEvents, filteredEvents);
|
|
1643
1911
|
return [SetDom2, newState.uid, dom];
|
|
1644
1912
|
};
|
|
1645
1913
|
|