@lvce-editor/chat-debug-view 5.2.0 → 5.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 +752 -570
- package/package.json +1 -1
|
@@ -1171,465 +1171,127 @@ const diff2 = uid => {
|
|
|
1171
1171
|
return diff(oldState, newState);
|
|
1172
1172
|
};
|
|
1173
1173
|
|
|
1174
|
+
const handleCloseDetails = state => {
|
|
1175
|
+
return {
|
|
1176
|
+
...state,
|
|
1177
|
+
selectedEvent: null,
|
|
1178
|
+
selectedEventId: null,
|
|
1179
|
+
selectedEventIndex: null
|
|
1180
|
+
};
|
|
1181
|
+
};
|
|
1182
|
+
|
|
1174
1183
|
const handleDetailsContextMenu = state => {
|
|
1175
1184
|
return state;
|
|
1176
1185
|
};
|
|
1177
1186
|
|
|
1178
|
-
|
|
1187
|
+
const handleDetailTab = (state, value) => {
|
|
1188
|
+
if (!isDetailTab(value)) {
|
|
1189
|
+
return state;
|
|
1190
|
+
}
|
|
1191
|
+
return {
|
|
1192
|
+
...state,
|
|
1193
|
+
selectedDetailTab: value
|
|
1194
|
+
};
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
const hasMatchingToolName$1 = (startedEvent, finishedEvent) => {
|
|
1198
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1199
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1200
|
+
}
|
|
1201
|
+
return true;
|
|
1202
|
+
};
|
|
1203
|
+
|
|
1204
|
+
const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
|
|
1205
|
+
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName$1(startedEvent, finishedEvent);
|
|
1206
|
+
};
|
|
1179
1207
|
|
|
1180
1208
|
const startedEventType$1 = 'tool-execution-started';
|
|
1181
1209
|
const finishedEventType$1 = 'tool-execution-finished';
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1187
|
-
const index = store.index(sessionIdIndexName);
|
|
1188
|
-
const keys = await index.getAllKeys(sessionId, eventId);
|
|
1189
|
-
if (keys.length < eventId) {
|
|
1190
|
-
return undefined;
|
|
1191
|
-
}
|
|
1192
|
-
const key = keys.at(-1);
|
|
1193
|
-
if (key === undefined) {
|
|
1194
|
-
return undefined;
|
|
1195
|
-
}
|
|
1196
|
-
const event = await store.get(key);
|
|
1197
|
-
return event;
|
|
1198
|
-
}
|
|
1199
|
-
const all = await store.getAll();
|
|
1200
|
-
const events = all.filter(event => event.sessionId === sessionId);
|
|
1201
|
-
return events[eventId - 1];
|
|
1210
|
+
const mergedEventType = 'tool-execution';
|
|
1211
|
+
|
|
1212
|
+
const isToolExecutionFinishedEvent = event => {
|
|
1213
|
+
return event.type === finishedEventType$1;
|
|
1202
1214
|
};
|
|
1215
|
+
|
|
1216
|
+
const isToolExecutionStartedEvent = event => {
|
|
1217
|
+
return event.type === startedEventType$1;
|
|
1218
|
+
};
|
|
1219
|
+
|
|
1203
1220
|
const getTimestamp$1 = value => {
|
|
1204
1221
|
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1205
1222
|
};
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1223
|
+
|
|
1224
|
+
const getEndedTimestamp = event => {
|
|
1225
|
+
return getTimestamp$1(event.ended) ?? getTimestamp$1(event.endTime) ?? getTimestamp$1(event.endTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
const eventStableIds = new WeakMap();
|
|
1229
|
+
const eventStableIdState = {
|
|
1230
|
+
nextStableEventId: 1
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
const getOrCreateStableEventId = event => {
|
|
1234
|
+
const existingStableEventId = eventStableIds.get(event);
|
|
1235
|
+
if (existingStableEventId) {
|
|
1236
|
+
return existingStableEventId;
|
|
1209
1237
|
}
|
|
1210
|
-
|
|
1238
|
+
const stableEventId = `event-${eventStableIdState.nextStableEventId++}`;
|
|
1239
|
+
eventStableIds.set(event, stableEventId);
|
|
1240
|
+
return stableEventId;
|
|
1211
1241
|
};
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1242
|
+
|
|
1243
|
+
const getStartedTimestamp = event => {
|
|
1244
|
+
return getTimestamp$1(event.started) ?? getTimestamp$1(event.startTime) ?? getTimestamp$1(event.startTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1245
|
+
};
|
|
1246
|
+
|
|
1247
|
+
const setStableEventId = (event, stableEventId) => {
|
|
1248
|
+
eventStableIds.set(event, stableEventId);
|
|
1249
|
+
};
|
|
1250
|
+
|
|
1251
|
+
const mergeToolExecutionEvents$1 = (startedEvent, finishedEvent) => {
|
|
1252
|
+
const ended = getEndedTimestamp(finishedEvent);
|
|
1253
|
+
const {
|
|
1254
|
+
eventId
|
|
1255
|
+
} = startedEvent;
|
|
1256
|
+
const started = getStartedTimestamp(startedEvent);
|
|
1257
|
+
const mergedEvent = {
|
|
1216
1258
|
...startedEvent,
|
|
1217
1259
|
...finishedEvent,
|
|
1218
1260
|
...(ended === undefined ? {} : {
|
|
1219
1261
|
ended
|
|
1220
1262
|
}),
|
|
1221
|
-
eventId
|
|
1263
|
+
...(eventId === undefined ? {} : {
|
|
1264
|
+
eventId
|
|
1265
|
+
}),
|
|
1222
1266
|
...(started === undefined ? {} : {
|
|
1223
1267
|
started
|
|
1224
1268
|
}),
|
|
1225
|
-
type:
|
|
1269
|
+
type: mergedEventType
|
|
1226
1270
|
};
|
|
1271
|
+
const stableEventId = `${getOrCreateStableEventId(startedEvent)}:${getOrCreateStableEventId(finishedEvent)}`;
|
|
1272
|
+
setStableEventId(mergedEvent, stableEventId);
|
|
1273
|
+
return mergedEvent;
|
|
1227
1274
|
};
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
return undefined;
|
|
1232
|
-
}
|
|
1233
|
-
if (summaryType !== 'tool-execution') {
|
|
1234
|
-
return {
|
|
1235
|
-
...event,
|
|
1236
|
-
eventId
|
|
1237
|
-
};
|
|
1238
|
-
}
|
|
1239
|
-
if (event.type !== startedEventType$1) {
|
|
1240
|
-
return {
|
|
1241
|
-
...event,
|
|
1242
|
-
eventId
|
|
1243
|
-
};
|
|
1244
|
-
}
|
|
1245
|
-
const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
|
|
1246
|
-
if (!nextEvent || nextEvent.type !== finishedEventType$1 || nextEvent.sessionId !== sessionId || !hasMatchingToolName$1(event, nextEvent)) {
|
|
1247
|
-
return {
|
|
1248
|
-
...event,
|
|
1249
|
-
eventId
|
|
1250
|
-
};
|
|
1251
|
-
}
|
|
1252
|
-
return mergeToolExecutionEvents$1(event, nextEvent, eventId);
|
|
1275
|
+
|
|
1276
|
+
const getStableEventId = event => {
|
|
1277
|
+
return getOrCreateStableEventId(event);
|
|
1253
1278
|
};
|
|
1254
1279
|
|
|
1255
|
-
const
|
|
1256
|
-
|
|
1257
|
-
let
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
}
|
|
1266
|
-
const transactionDoneMap = new WeakMap();
|
|
1267
|
-
const transformCache = new WeakMap();
|
|
1268
|
-
const reverseTransformCache = new WeakMap();
|
|
1269
|
-
function promisifyRequest(request) {
|
|
1270
|
-
const promise = new Promise((resolve, reject) => {
|
|
1271
|
-
const unlisten = () => {
|
|
1272
|
-
request.removeEventListener('success', success);
|
|
1273
|
-
request.removeEventListener('error', error);
|
|
1274
|
-
};
|
|
1275
|
-
const success = () => {
|
|
1276
|
-
resolve(wrap(request.result));
|
|
1277
|
-
unlisten();
|
|
1278
|
-
};
|
|
1279
|
-
const error = () => {
|
|
1280
|
-
reject(request.error);
|
|
1281
|
-
unlisten();
|
|
1282
|
-
};
|
|
1283
|
-
request.addEventListener('success', success);
|
|
1284
|
-
request.addEventListener('error', error);
|
|
1285
|
-
});
|
|
1286
|
-
// This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
|
|
1287
|
-
// is because we create many promises from a single IDBRequest.
|
|
1288
|
-
reverseTransformCache.set(promise, request);
|
|
1289
|
-
return promise;
|
|
1290
|
-
}
|
|
1291
|
-
function cacheDonePromiseForTransaction(tx) {
|
|
1292
|
-
// Early bail if we've already created a done promise for this transaction.
|
|
1293
|
-
if (transactionDoneMap.has(tx)) return;
|
|
1294
|
-
const done = new Promise((resolve, reject) => {
|
|
1295
|
-
const unlisten = () => {
|
|
1296
|
-
tx.removeEventListener('complete', complete);
|
|
1297
|
-
tx.removeEventListener('error', error);
|
|
1298
|
-
tx.removeEventListener('abort', error);
|
|
1299
|
-
};
|
|
1300
|
-
const complete = () => {
|
|
1301
|
-
resolve();
|
|
1302
|
-
unlisten();
|
|
1303
|
-
};
|
|
1304
|
-
const error = () => {
|
|
1305
|
-
reject(tx.error || new DOMException('AbortError', 'AbortError'));
|
|
1306
|
-
unlisten();
|
|
1307
|
-
};
|
|
1308
|
-
tx.addEventListener('complete', complete);
|
|
1309
|
-
tx.addEventListener('error', error);
|
|
1310
|
-
tx.addEventListener('abort', error);
|
|
1311
|
-
});
|
|
1312
|
-
// Cache it for later retrieval.
|
|
1313
|
-
transactionDoneMap.set(tx, done);
|
|
1314
|
-
}
|
|
1315
|
-
let idbProxyTraps = {
|
|
1316
|
-
get(target, prop, receiver) {
|
|
1317
|
-
if (target instanceof IDBTransaction) {
|
|
1318
|
-
// Special handling for transaction.done.
|
|
1319
|
-
if (prop === 'done') return transactionDoneMap.get(target);
|
|
1320
|
-
// Make tx.store return the only store in the transaction, or undefined if there are many.
|
|
1321
|
-
if (prop === 'store') {
|
|
1322
|
-
return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]);
|
|
1280
|
+
const collapseToolExecutionEvents = events => {
|
|
1281
|
+
const collapsedEvents = [];
|
|
1282
|
+
for (let i = 0; i < events.length; i++) {
|
|
1283
|
+
const event = events[i];
|
|
1284
|
+
if (isToolExecutionStartedEvent(event)) {
|
|
1285
|
+
const nextEvent = events[i + 1];
|
|
1286
|
+
if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
|
|
1287
|
+
collapsedEvents.push(mergeToolExecutionEvents$1(event, nextEvent));
|
|
1288
|
+
i++;
|
|
1289
|
+
continue;
|
|
1323
1290
|
}
|
|
1324
1291
|
}
|
|
1325
|
-
|
|
1326
|
-
return wrap(target[prop]);
|
|
1327
|
-
},
|
|
1328
|
-
set(target, prop, value) {
|
|
1329
|
-
target[prop] = value;
|
|
1330
|
-
return true;
|
|
1331
|
-
},
|
|
1332
|
-
has(target, prop) {
|
|
1333
|
-
if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) {
|
|
1334
|
-
return true;
|
|
1335
|
-
}
|
|
1336
|
-
return prop in target;
|
|
1292
|
+
collapsedEvents.push(event);
|
|
1337
1293
|
}
|
|
1338
|
-
|
|
1339
|
-
function replaceTraps(callback) {
|
|
1340
|
-
idbProxyTraps = callback(idbProxyTraps);
|
|
1341
|
-
}
|
|
1342
|
-
function wrapFunction(func) {
|
|
1343
|
-
// Due to expected object equality (which is enforced by the caching in `wrap`), we
|
|
1344
|
-
// only create one new func per func.
|
|
1345
|
-
// Cursor methods are special, as the behaviour is a little more different to standard IDB. In
|
|
1346
|
-
// IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
|
|
1347
|
-
// cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
|
|
1348
|
-
// with real promises, so each advance methods returns a new promise for the cursor object, or
|
|
1349
|
-
// undefined if the end of the cursor has been reached.
|
|
1350
|
-
if (getCursorAdvanceMethods().includes(func)) {
|
|
1351
|
-
return function (...args) {
|
|
1352
|
-
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
1353
|
-
// the original object.
|
|
1354
|
-
func.apply(unwrap(this), args);
|
|
1355
|
-
return wrap(this.request);
|
|
1356
|
-
};
|
|
1357
|
-
}
|
|
1358
|
-
return function (...args) {
|
|
1359
|
-
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
1360
|
-
// the original object.
|
|
1361
|
-
return wrap(func.apply(unwrap(this), args));
|
|
1362
|
-
};
|
|
1363
|
-
}
|
|
1364
|
-
function transformCachableValue(value) {
|
|
1365
|
-
if (typeof value === 'function') return wrapFunction(value);
|
|
1366
|
-
// This doesn't return, it just creates a 'done' promise for the transaction,
|
|
1367
|
-
// which is later returned for transaction.done (see idbObjectHandler).
|
|
1368
|
-
if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value);
|
|
1369
|
-
if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps);
|
|
1370
|
-
// Return the same value back if we're not going to transform it.
|
|
1371
|
-
return value;
|
|
1372
|
-
}
|
|
1373
|
-
function wrap(value) {
|
|
1374
|
-
// We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
|
|
1375
|
-
// IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
|
|
1376
|
-
if (value instanceof IDBRequest) return promisifyRequest(value);
|
|
1377
|
-
// If we've already transformed this value before, reuse the transformed value.
|
|
1378
|
-
// This is faster, but it also provides object equality.
|
|
1379
|
-
if (transformCache.has(value)) return transformCache.get(value);
|
|
1380
|
-
const newValue = transformCachableValue(value);
|
|
1381
|
-
// Not all types are transformed.
|
|
1382
|
-
// These may be primitive types, so they can't be WeakMap keys.
|
|
1383
|
-
if (newValue !== value) {
|
|
1384
|
-
transformCache.set(value, newValue);
|
|
1385
|
-
reverseTransformCache.set(newValue, value);
|
|
1386
|
-
}
|
|
1387
|
-
return newValue;
|
|
1388
|
-
}
|
|
1389
|
-
const unwrap = value => reverseTransformCache.get(value);
|
|
1390
|
-
|
|
1391
|
-
/**
|
|
1392
|
-
* Open a database.
|
|
1393
|
-
*
|
|
1394
|
-
* @param name Name of the database.
|
|
1395
|
-
* @param version Schema version.
|
|
1396
|
-
* @param callbacks Additional callbacks.
|
|
1397
|
-
*/
|
|
1398
|
-
function openDB(name, version, {
|
|
1399
|
-
blocked,
|
|
1400
|
-
upgrade,
|
|
1401
|
-
blocking,
|
|
1402
|
-
terminated
|
|
1403
|
-
} = {}) {
|
|
1404
|
-
const request = indexedDB.open(name, version);
|
|
1405
|
-
const openPromise = wrap(request);
|
|
1406
|
-
if (upgrade) {
|
|
1407
|
-
request.addEventListener('upgradeneeded', event => {
|
|
1408
|
-
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
|
|
1409
|
-
});
|
|
1410
|
-
}
|
|
1411
|
-
if (blocked) {
|
|
1412
|
-
request.addEventListener('blocked', event => blocked(
|
|
1413
|
-
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
|
|
1414
|
-
event.oldVersion, event.newVersion, event));
|
|
1415
|
-
}
|
|
1416
|
-
openPromise.then(db => {
|
|
1417
|
-
if (terminated) db.addEventListener('close', () => terminated());
|
|
1418
|
-
if (blocking) {
|
|
1419
|
-
db.addEventListener('versionchange', event => blocking(event.oldVersion, event.newVersion, event));
|
|
1420
|
-
}
|
|
1421
|
-
}).catch(() => {});
|
|
1422
|
-
return openPromise;
|
|
1423
|
-
}
|
|
1424
|
-
const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
|
|
1425
|
-
const writeMethods = ['put', 'add', 'delete', 'clear'];
|
|
1426
|
-
const cachedMethods = new Map();
|
|
1427
|
-
function getMethod(target, prop) {
|
|
1428
|
-
if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) {
|
|
1429
|
-
return;
|
|
1430
|
-
}
|
|
1431
|
-
if (cachedMethods.get(prop)) return cachedMethods.get(prop);
|
|
1432
|
-
const targetFuncName = prop.replace(/FromIndex$/, '');
|
|
1433
|
-
const useIndex = prop !== targetFuncName;
|
|
1434
|
-
const isWrite = writeMethods.includes(targetFuncName);
|
|
1435
|
-
if (
|
|
1436
|
-
// Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
|
|
1437
|
-
!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) {
|
|
1438
|
-
return;
|
|
1439
|
-
}
|
|
1440
|
-
const method = async function (storeName, ...args) {
|
|
1441
|
-
// isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
|
|
1442
|
-
const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
|
|
1443
|
-
let target = tx.store;
|
|
1444
|
-
if (useIndex) target = target.index(args.shift());
|
|
1445
|
-
// Must reject if op rejects.
|
|
1446
|
-
// If it's a write operation, must reject if tx.done rejects.
|
|
1447
|
-
// Must reject with op rejection first.
|
|
1448
|
-
// Must resolve with op value.
|
|
1449
|
-
// Must handle both promises (no unhandled rejections)
|
|
1450
|
-
return (await Promise.all([target[targetFuncName](...args), isWrite && tx.done]))[0];
|
|
1451
|
-
};
|
|
1452
|
-
cachedMethods.set(prop, method);
|
|
1453
|
-
return method;
|
|
1454
|
-
}
|
|
1455
|
-
replaceTraps(oldTraps => ({
|
|
1456
|
-
...oldTraps,
|
|
1457
|
-
get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
|
|
1458
|
-
has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)
|
|
1459
|
-
}));
|
|
1460
|
-
const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
|
|
1461
|
-
const methodMap = {};
|
|
1462
|
-
const advanceResults = new WeakMap();
|
|
1463
|
-
const ittrProxiedCursorToOriginalProxy = new WeakMap();
|
|
1464
|
-
const cursorIteratorTraps = {
|
|
1465
|
-
get(target, prop) {
|
|
1466
|
-
if (!advanceMethodProps.includes(prop)) return target[prop];
|
|
1467
|
-
let cachedFunc = methodMap[prop];
|
|
1468
|
-
if (!cachedFunc) {
|
|
1469
|
-
cachedFunc = methodMap[prop] = function (...args) {
|
|
1470
|
-
advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
|
|
1471
|
-
};
|
|
1472
|
-
}
|
|
1473
|
-
return cachedFunc;
|
|
1474
|
-
}
|
|
1475
|
-
};
|
|
1476
|
-
async function* iterate(...args) {
|
|
1477
|
-
// tslint:disable-next-line:no-this-assignment
|
|
1478
|
-
let cursor = this;
|
|
1479
|
-
if (!(cursor instanceof IDBCursor)) {
|
|
1480
|
-
cursor = await cursor.openCursor(...args);
|
|
1481
|
-
}
|
|
1482
|
-
if (!cursor) return;
|
|
1483
|
-
cursor = cursor;
|
|
1484
|
-
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
1485
|
-
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
1486
|
-
// Map this double-proxy back to the original, so other cursor methods work.
|
|
1487
|
-
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
1488
|
-
while (cursor) {
|
|
1489
|
-
yield proxiedCursor;
|
|
1490
|
-
// If one of the advancing methods was not called, call continue().
|
|
1491
|
-
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
1492
|
-
advanceResults.delete(proxiedCursor);
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
function isIteratorProp(target, prop) {
|
|
1496
|
-
return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
|
|
1497
|
-
}
|
|
1498
|
-
replaceTraps(oldTraps => ({
|
|
1499
|
-
...oldTraps,
|
|
1500
|
-
get(target, prop, receiver) {
|
|
1501
|
-
if (isIteratorProp(target, prop)) return iterate;
|
|
1502
|
-
return oldTraps.get(target, prop, receiver);
|
|
1503
|
-
},
|
|
1504
|
-
has(target, prop) {
|
|
1505
|
-
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
1506
|
-
}
|
|
1507
|
-
}));
|
|
1508
|
-
|
|
1509
|
-
const openDatabaseDependencies = {
|
|
1510
|
-
openDB: openDB
|
|
1511
|
-
};
|
|
1512
|
-
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1513
|
-
return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
|
|
1514
|
-
};
|
|
1515
|
-
|
|
1516
|
-
const loadSelectedEventDependencies = {
|
|
1517
|
-
getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
|
|
1518
|
-
openDatabase: openDatabase
|
|
1519
|
-
};
|
|
1520
|
-
const loadSelectedEvent = async (databaseName, dataBaseVersion, eventStoreName, sessionId, sessionIdIndexName, eventId, type) => {
|
|
1521
|
-
const database = await loadSelectedEventDependencies.openDatabase(databaseName, dataBaseVersion);
|
|
1522
|
-
try {
|
|
1523
|
-
if (!database.objectStoreNames.contains(eventStoreName)) {
|
|
1524
|
-
return null;
|
|
1525
|
-
}
|
|
1526
|
-
const transaction = database.transaction(eventStoreName, 'readonly');
|
|
1527
|
-
const store = transaction.objectStore(eventStoreName);
|
|
1528
|
-
const event = await loadSelectedEventDependencies.getEventDetailsBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId, type);
|
|
1529
|
-
return event ?? null;
|
|
1530
|
-
} finally {
|
|
1531
|
-
database.close();
|
|
1532
|
-
}
|
|
1533
|
-
};
|
|
1534
|
-
|
|
1535
|
-
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1536
|
-
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1537
|
-
return startedEvent.toolName === finishedEvent.toolName;
|
|
1538
|
-
}
|
|
1539
|
-
return true;
|
|
1540
|
-
};
|
|
1541
|
-
|
|
1542
|
-
const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
|
|
1543
|
-
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName(startedEvent, finishedEvent);
|
|
1544
|
-
};
|
|
1545
|
-
|
|
1546
|
-
const startedEventType = 'tool-execution-started';
|
|
1547
|
-
const finishedEventType = 'tool-execution-finished';
|
|
1548
|
-
const mergedEventType = 'tool-execution';
|
|
1549
|
-
|
|
1550
|
-
const isToolExecutionFinishedEvent = event => {
|
|
1551
|
-
return event.type === finishedEventType;
|
|
1552
|
-
};
|
|
1553
|
-
|
|
1554
|
-
const isToolExecutionStartedEvent = event => {
|
|
1555
|
-
return event.type === startedEventType;
|
|
1556
|
-
};
|
|
1557
|
-
|
|
1558
|
-
const getTimestamp = value => {
|
|
1559
|
-
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1560
|
-
};
|
|
1561
|
-
|
|
1562
|
-
const getEndedTimestamp = event => {
|
|
1563
|
-
return getTimestamp(event.ended) ?? getTimestamp(event.endTime) ?? getTimestamp(event.endTimestamp) ?? getTimestamp(event.timestamp);
|
|
1564
|
-
};
|
|
1565
|
-
|
|
1566
|
-
const eventStableIds = new WeakMap();
|
|
1567
|
-
const eventStableIdState = {
|
|
1568
|
-
nextStableEventId: 1
|
|
1569
|
-
};
|
|
1570
|
-
|
|
1571
|
-
const getOrCreateStableEventId = event => {
|
|
1572
|
-
const existingStableEventId = eventStableIds.get(event);
|
|
1573
|
-
if (existingStableEventId) {
|
|
1574
|
-
return existingStableEventId;
|
|
1575
|
-
}
|
|
1576
|
-
const stableEventId = `event-${eventStableIdState.nextStableEventId++}`;
|
|
1577
|
-
eventStableIds.set(event, stableEventId);
|
|
1578
|
-
return stableEventId;
|
|
1579
|
-
};
|
|
1580
|
-
|
|
1581
|
-
const getStartedTimestamp = event => {
|
|
1582
|
-
return getTimestamp(event.started) ?? getTimestamp(event.startTime) ?? getTimestamp(event.startTimestamp) ?? getTimestamp(event.timestamp);
|
|
1583
|
-
};
|
|
1584
|
-
|
|
1585
|
-
const setStableEventId = (event, stableEventId) => {
|
|
1586
|
-
eventStableIds.set(event, stableEventId);
|
|
1587
|
-
};
|
|
1588
|
-
|
|
1589
|
-
const mergeToolExecutionEvents = (startedEvent, finishedEvent) => {
|
|
1590
|
-
const ended = getEndedTimestamp(finishedEvent);
|
|
1591
|
-
const {
|
|
1592
|
-
eventId
|
|
1593
|
-
} = startedEvent;
|
|
1594
|
-
const started = getStartedTimestamp(startedEvent);
|
|
1595
|
-
const mergedEvent = {
|
|
1596
|
-
...startedEvent,
|
|
1597
|
-
...finishedEvent,
|
|
1598
|
-
...(ended === undefined ? {} : {
|
|
1599
|
-
ended
|
|
1600
|
-
}),
|
|
1601
|
-
...(eventId === undefined ? {} : {
|
|
1602
|
-
eventId
|
|
1603
|
-
}),
|
|
1604
|
-
...(started === undefined ? {} : {
|
|
1605
|
-
started
|
|
1606
|
-
}),
|
|
1607
|
-
type: mergedEventType
|
|
1608
|
-
};
|
|
1609
|
-
const stableEventId = `${getOrCreateStableEventId(startedEvent)}:${getOrCreateStableEventId(finishedEvent)}`;
|
|
1610
|
-
setStableEventId(mergedEvent, stableEventId);
|
|
1611
|
-
return mergedEvent;
|
|
1612
|
-
};
|
|
1613
|
-
|
|
1614
|
-
const getStableEventId = event => {
|
|
1615
|
-
return getOrCreateStableEventId(event);
|
|
1616
|
-
};
|
|
1617
|
-
|
|
1618
|
-
const collapseToolExecutionEvents = events => {
|
|
1619
|
-
const collapsedEvents = [];
|
|
1620
|
-
for (let i = 0; i < events.length; i++) {
|
|
1621
|
-
const event = events[i];
|
|
1622
|
-
if (isToolExecutionStartedEvent(event)) {
|
|
1623
|
-
const nextEvent = events[i + 1];
|
|
1624
|
-
if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
|
|
1625
|
-
collapsedEvents.push(mergeToolExecutionEvents(event, nextEvent));
|
|
1626
|
-
i++;
|
|
1627
|
-
continue;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
collapsedEvents.push(event);
|
|
1631
|
-
}
|
|
1632
|
-
return collapsedEvents;
|
|
1294
|
+
return collapsedEvents;
|
|
1633
1295
|
};
|
|
1634
1296
|
|
|
1635
1297
|
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
@@ -1737,117 +1399,537 @@ const getEventsWithTime = events => {
|
|
|
1737
1399
|
if (time === undefined) {
|
|
1738
1400
|
return [];
|
|
1739
1401
|
}
|
|
1740
|
-
return [{
|
|
1741
|
-
event,
|
|
1742
|
-
time
|
|
1743
|
-
}];
|
|
1744
|
-
});
|
|
1745
|
-
};
|
|
1746
|
-
const getTimelineDurationSeconds = events => {
|
|
1747
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1748
|
-
if (eventsWithTime.length === 0) {
|
|
1749
|
-
return 0;
|
|
1750
|
-
}
|
|
1751
|
-
const baseTime = eventsWithTime[0].time;
|
|
1752
|
-
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1753
|
-
return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1754
|
-
};
|
|
1755
|
-
const getSelectionPercent = (value, durationSeconds) => {
|
|
1756
|
-
if (durationSeconds <= 0) {
|
|
1757
|
-
return 0;
|
|
1402
|
+
return [{
|
|
1403
|
+
event,
|
|
1404
|
+
time
|
|
1405
|
+
}];
|
|
1406
|
+
});
|
|
1407
|
+
};
|
|
1408
|
+
const getTimelineDurationSeconds = events => {
|
|
1409
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1410
|
+
if (eventsWithTime.length === 0) {
|
|
1411
|
+
return 0;
|
|
1412
|
+
}
|
|
1413
|
+
const baseTime = eventsWithTime[0].time;
|
|
1414
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1415
|
+
return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1416
|
+
};
|
|
1417
|
+
const getSelectionPercent = (value, durationSeconds) => {
|
|
1418
|
+
if (durationSeconds <= 0) {
|
|
1419
|
+
return 0;
|
|
1420
|
+
}
|
|
1421
|
+
return Number((value / durationSeconds * 100).toFixed(3));
|
|
1422
|
+
};
|
|
1423
|
+
const getNormalizedRange = (durationSeconds, startValue, endValue) => {
|
|
1424
|
+
const parsedStart = parseTimelineSeconds(startValue);
|
|
1425
|
+
const parsedEnd = parseTimelineSeconds(endValue);
|
|
1426
|
+
if (parsedStart === undefined && parsedEnd === undefined) {
|
|
1427
|
+
return {
|
|
1428
|
+
endSeconds: null,
|
|
1429
|
+
hasSelection: false,
|
|
1430
|
+
startSeconds: null
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
const rawStart = parsedStart ?? 0;
|
|
1434
|
+
const rawEnd = parsedEnd ?? durationSeconds;
|
|
1435
|
+
const normalizedStart = Math.max(0, Math.min(durationSeconds, Math.min(rawStart, rawEnd)));
|
|
1436
|
+
const normalizedEnd = Math.max(0, Math.min(durationSeconds, Math.max(rawStart, rawEnd)));
|
|
1437
|
+
return {
|
|
1438
|
+
endSeconds: roundSeconds(normalizedEnd),
|
|
1439
|
+
hasSelection: true,
|
|
1440
|
+
startSeconds: roundSeconds(normalizedStart)
|
|
1441
|
+
};
|
|
1442
|
+
};
|
|
1443
|
+
const filterEventsByTimelineRange = (events, startValue, endValue) => {
|
|
1444
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1445
|
+
if (eventsWithTime.length === 0) {
|
|
1446
|
+
return events;
|
|
1447
|
+
}
|
|
1448
|
+
const baseTime = eventsWithTime[0].time;
|
|
1449
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1450
|
+
const durationSeconds = roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1451
|
+
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1452
|
+
if (!range.hasSelection || range.startSeconds === null || range.endSeconds === null) {
|
|
1453
|
+
return events;
|
|
1454
|
+
}
|
|
1455
|
+
const startTime = baseTime + range.startSeconds * 1000;
|
|
1456
|
+
const endTime = baseTime + range.endSeconds * 1000;
|
|
1457
|
+
return eventsWithTime.filter(item => item.time >= startTime && item.time <= endTime).map(item => item.event);
|
|
1458
|
+
};
|
|
1459
|
+
const getTimelineInfo = (events, startValue, endValue) => {
|
|
1460
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1461
|
+
if (eventsWithTime.length === 0) {
|
|
1462
|
+
return {
|
|
1463
|
+
buckets: [],
|
|
1464
|
+
durationSeconds: 0,
|
|
1465
|
+
endSeconds: null,
|
|
1466
|
+
hasSelection: false,
|
|
1467
|
+
selectionEndPercent: null,
|
|
1468
|
+
selectionStartPercent: null,
|
|
1469
|
+
startSeconds: null
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
const baseTime = eventsWithTime[0].time;
|
|
1473
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1474
|
+
const durationMs = Math.max(0, lastTime - baseTime);
|
|
1475
|
+
const durationSeconds = roundSeconds(durationMs / 1000);
|
|
1476
|
+
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1477
|
+
const bucketCount = durationSeconds === 0 ? 1 : Math.max(12, Math.min(48, Math.ceil(durationSeconds)));
|
|
1478
|
+
const bucketDurationMs = durationMs === 0 ? 1000 : durationMs / bucketCount;
|
|
1479
|
+
const counts = Array.from({
|
|
1480
|
+
length: bucketCount
|
|
1481
|
+
}).fill(0);
|
|
1482
|
+
for (const item of eventsWithTime) {
|
|
1483
|
+
const offsetMs = item.time - baseTime;
|
|
1484
|
+
const index = durationMs === 0 ? 0 : Math.min(bucketCount - 1, Math.floor(offsetMs / durationMs * bucketCount));
|
|
1485
|
+
counts[index] += 1;
|
|
1486
|
+
}
|
|
1487
|
+
const maxCount = Math.max(...counts);
|
|
1488
|
+
const selectionStartPercent = range.hasSelection && range.startSeconds !== null ? getSelectionPercent(range.startSeconds, durationSeconds) : null;
|
|
1489
|
+
const selectionEndPercent = range.hasSelection && range.endSeconds !== null ? getSelectionPercent(range.endSeconds, durationSeconds) : null;
|
|
1490
|
+
const buckets = counts.map((count, index) => {
|
|
1491
|
+
const bucketStartMs = index * bucketDurationMs;
|
|
1492
|
+
const bucketEndMs = index === bucketCount - 1 ? durationMs : (index + 1) * bucketDurationMs;
|
|
1493
|
+
const hasSelection = range.hasSelection && range.startSeconds !== null && range.endSeconds !== null;
|
|
1494
|
+
const selectionStartMs = hasSelection ? range.startSeconds * 1000 : 0;
|
|
1495
|
+
const selectionEndMs = hasSelection ? range.endSeconds * 1000 : 0;
|
|
1496
|
+
return {
|
|
1497
|
+
count,
|
|
1498
|
+
endSeconds: roundSeconds(bucketEndMs / 1000),
|
|
1499
|
+
isSelected: hasSelection && bucketEndMs >= selectionStartMs && bucketStartMs <= selectionEndMs,
|
|
1500
|
+
startSeconds: roundSeconds(bucketStartMs / 1000),
|
|
1501
|
+
unitCount: count === 0 ? 0 : Math.max(1, Math.round(count / maxCount * maxBarUnits))
|
|
1502
|
+
};
|
|
1503
|
+
});
|
|
1504
|
+
return {
|
|
1505
|
+
buckets,
|
|
1506
|
+
durationSeconds,
|
|
1507
|
+
endSeconds: range.endSeconds,
|
|
1508
|
+
hasSelection: range.hasSelection,
|
|
1509
|
+
selectionEndPercent,
|
|
1510
|
+
selectionStartPercent,
|
|
1511
|
+
startSeconds: range.startSeconds
|
|
1512
|
+
};
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
const getCurrentEvents$3 = state => {
|
|
1516
|
+
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1517
|
+
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1518
|
+
};
|
|
1519
|
+
const getEventIndexByStableId$1 = (events, event) => {
|
|
1520
|
+
const stableEventId = getStableEventId(event);
|
|
1521
|
+
return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
|
|
1522
|
+
};
|
|
1523
|
+
const getSelectedEventIndex$1 = state => {
|
|
1524
|
+
const {
|
|
1525
|
+
selectedEventIndex
|
|
1526
|
+
} = state;
|
|
1527
|
+
if (selectedEventIndex === null) {
|
|
1528
|
+
return null;
|
|
1529
|
+
}
|
|
1530
|
+
const filteredEvents = getCurrentEvents$3(state);
|
|
1531
|
+
const selectedEvent = filteredEvents[selectedEventIndex];
|
|
1532
|
+
if (!selectedEvent) {
|
|
1533
|
+
return null;
|
|
1534
|
+
}
|
|
1535
|
+
const newIndex = getEventIndexByStableId$1(filteredEvents, selectedEvent);
|
|
1536
|
+
if (newIndex === -1) {
|
|
1537
|
+
return null;
|
|
1538
|
+
}
|
|
1539
|
+
return newIndex;
|
|
1540
|
+
};
|
|
1541
|
+
const getPreservedSelectedEventIndex$1 = (oldState, newState) => {
|
|
1542
|
+
const {
|
|
1543
|
+
selectedEventIndex
|
|
1544
|
+
} = oldState;
|
|
1545
|
+
if (selectedEventIndex === null) {
|
|
1546
|
+
return null;
|
|
1547
|
+
}
|
|
1548
|
+
const oldFilteredEvents = getCurrentEvents$3(oldState);
|
|
1549
|
+
const selectedEvent = oldFilteredEvents[selectedEventIndex];
|
|
1550
|
+
if (!selectedEvent) {
|
|
1551
|
+
return null;
|
|
1552
|
+
}
|
|
1553
|
+
const newFilteredEvents = getCurrentEvents$3(newState);
|
|
1554
|
+
const newIndex = getEventIndexByStableId$1(newFilteredEvents, selectedEvent);
|
|
1555
|
+
if (newIndex === -1) {
|
|
1556
|
+
return null;
|
|
1557
|
+
}
|
|
1558
|
+
return newIndex;
|
|
1559
|
+
};
|
|
1560
|
+
const withPreservedSelection$1 = (state, nextState) => {
|
|
1561
|
+
const selectedEventIndex = getPreservedSelectedEventIndex$1(state, nextState);
|
|
1562
|
+
return {
|
|
1563
|
+
...nextState,
|
|
1564
|
+
selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
|
|
1565
|
+
selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
|
|
1566
|
+
selectedEventIndex
|
|
1567
|
+
};
|
|
1568
|
+
};
|
|
1569
|
+
|
|
1570
|
+
const handleEventCategoryFilter = (state, value) => {
|
|
1571
|
+
const nextState = {
|
|
1572
|
+
...state,
|
|
1573
|
+
eventCategoryFilter: value || All
|
|
1574
|
+
};
|
|
1575
|
+
return withPreservedSelection$1(state, nextState);
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
// cspell:ignore IDBP
|
|
1579
|
+
|
|
1580
|
+
const startedEventType = 'tool-execution-started';
|
|
1581
|
+
const finishedEventType = 'tool-execution-finished';
|
|
1582
|
+
const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId) => {
|
|
1583
|
+
if (eventId < 1) {
|
|
1584
|
+
return undefined;
|
|
1585
|
+
}
|
|
1586
|
+
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1587
|
+
const index = store.index(sessionIdIndexName);
|
|
1588
|
+
const keys = await index.getAllKeys(sessionId, eventId);
|
|
1589
|
+
if (keys.length < eventId) {
|
|
1590
|
+
return undefined;
|
|
1591
|
+
}
|
|
1592
|
+
const key = keys.at(-1);
|
|
1593
|
+
if (key === undefined) {
|
|
1594
|
+
return undefined;
|
|
1595
|
+
}
|
|
1596
|
+
const event = await store.get(key);
|
|
1597
|
+
return event;
|
|
1598
|
+
}
|
|
1599
|
+
const all = await store.getAll();
|
|
1600
|
+
const events = all.filter(event => event.sessionId === sessionId);
|
|
1601
|
+
return events[eventId - 1];
|
|
1602
|
+
};
|
|
1603
|
+
const getTimestamp = value => {
|
|
1604
|
+
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1605
|
+
};
|
|
1606
|
+
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1607
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1608
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1609
|
+
}
|
|
1610
|
+
return true;
|
|
1611
|
+
};
|
|
1612
|
+
const mergeToolExecutionEvents = (startedEvent, finishedEvent, eventId) => {
|
|
1613
|
+
const ended = getTimestamp(finishedEvent.ended) ?? getTimestamp(finishedEvent.endTime) ?? getTimestamp(finishedEvent.timestamp);
|
|
1614
|
+
const started = getTimestamp(startedEvent.started) ?? getTimestamp(startedEvent.startTime) ?? getTimestamp(startedEvent.timestamp);
|
|
1615
|
+
return {
|
|
1616
|
+
...startedEvent,
|
|
1617
|
+
...finishedEvent,
|
|
1618
|
+
...(ended === undefined ? {} : {
|
|
1619
|
+
ended
|
|
1620
|
+
}),
|
|
1621
|
+
eventId,
|
|
1622
|
+
...(started === undefined ? {} : {
|
|
1623
|
+
started
|
|
1624
|
+
}),
|
|
1625
|
+
type: 'tool-execution'
|
|
1626
|
+
};
|
|
1627
|
+
};
|
|
1628
|
+
const getEventDetailsBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId, summaryType) => {
|
|
1629
|
+
const event = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId);
|
|
1630
|
+
if (!event) {
|
|
1631
|
+
return undefined;
|
|
1632
|
+
}
|
|
1633
|
+
if (summaryType !== 'tool-execution') {
|
|
1634
|
+
return {
|
|
1635
|
+
...event,
|
|
1636
|
+
eventId
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
if (event.type !== startedEventType) {
|
|
1640
|
+
return {
|
|
1641
|
+
...event,
|
|
1642
|
+
eventId
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
|
|
1646
|
+
if (!nextEvent || nextEvent.type !== finishedEventType || nextEvent.sessionId !== sessionId || !hasMatchingToolName(event, nextEvent)) {
|
|
1647
|
+
return {
|
|
1648
|
+
...event,
|
|
1649
|
+
eventId
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
return mergeToolExecutionEvents(event, nextEvent, eventId);
|
|
1653
|
+
};
|
|
1654
|
+
|
|
1655
|
+
const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
|
|
1656
|
+
let idbProxyableTypes;
|
|
1657
|
+
let cursorAdvanceMethods;
|
|
1658
|
+
// This is a function to prevent it throwing up in node environments.
|
|
1659
|
+
function getIdbProxyableTypes() {
|
|
1660
|
+
return idbProxyableTypes || (idbProxyableTypes = [IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction]);
|
|
1661
|
+
}
|
|
1662
|
+
// This is a function to prevent it throwing up in node environments.
|
|
1663
|
+
function getCursorAdvanceMethods() {
|
|
1664
|
+
return cursorAdvanceMethods || (cursorAdvanceMethods = [IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey]);
|
|
1665
|
+
}
|
|
1666
|
+
const transactionDoneMap = new WeakMap();
|
|
1667
|
+
const transformCache = new WeakMap();
|
|
1668
|
+
const reverseTransformCache = new WeakMap();
|
|
1669
|
+
function promisifyRequest(request) {
|
|
1670
|
+
const promise = new Promise((resolve, reject) => {
|
|
1671
|
+
const unlisten = () => {
|
|
1672
|
+
request.removeEventListener('success', success);
|
|
1673
|
+
request.removeEventListener('error', error);
|
|
1674
|
+
};
|
|
1675
|
+
const success = () => {
|
|
1676
|
+
resolve(wrap(request.result));
|
|
1677
|
+
unlisten();
|
|
1678
|
+
};
|
|
1679
|
+
const error = () => {
|
|
1680
|
+
reject(request.error);
|
|
1681
|
+
unlisten();
|
|
1682
|
+
};
|
|
1683
|
+
request.addEventListener('success', success);
|
|
1684
|
+
request.addEventListener('error', error);
|
|
1685
|
+
});
|
|
1686
|
+
// This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
|
|
1687
|
+
// is because we create many promises from a single IDBRequest.
|
|
1688
|
+
reverseTransformCache.set(promise, request);
|
|
1689
|
+
return promise;
|
|
1690
|
+
}
|
|
1691
|
+
function cacheDonePromiseForTransaction(tx) {
|
|
1692
|
+
// Early bail if we've already created a done promise for this transaction.
|
|
1693
|
+
if (transactionDoneMap.has(tx)) return;
|
|
1694
|
+
const done = new Promise((resolve, reject) => {
|
|
1695
|
+
const unlisten = () => {
|
|
1696
|
+
tx.removeEventListener('complete', complete);
|
|
1697
|
+
tx.removeEventListener('error', error);
|
|
1698
|
+
tx.removeEventListener('abort', error);
|
|
1699
|
+
};
|
|
1700
|
+
const complete = () => {
|
|
1701
|
+
resolve();
|
|
1702
|
+
unlisten();
|
|
1703
|
+
};
|
|
1704
|
+
const error = () => {
|
|
1705
|
+
reject(tx.error || new DOMException('AbortError', 'AbortError'));
|
|
1706
|
+
unlisten();
|
|
1707
|
+
};
|
|
1708
|
+
tx.addEventListener('complete', complete);
|
|
1709
|
+
tx.addEventListener('error', error);
|
|
1710
|
+
tx.addEventListener('abort', error);
|
|
1711
|
+
});
|
|
1712
|
+
// Cache it for later retrieval.
|
|
1713
|
+
transactionDoneMap.set(tx, done);
|
|
1714
|
+
}
|
|
1715
|
+
let idbProxyTraps = {
|
|
1716
|
+
get(target, prop, receiver) {
|
|
1717
|
+
if (target instanceof IDBTransaction) {
|
|
1718
|
+
// Special handling for transaction.done.
|
|
1719
|
+
if (prop === 'done') return transactionDoneMap.get(target);
|
|
1720
|
+
// Make tx.store return the only store in the transaction, or undefined if there are many.
|
|
1721
|
+
if (prop === 'store') {
|
|
1722
|
+
return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
// Else transform whatever we get back.
|
|
1726
|
+
return wrap(target[prop]);
|
|
1727
|
+
},
|
|
1728
|
+
set(target, prop, value) {
|
|
1729
|
+
target[prop] = value;
|
|
1730
|
+
return true;
|
|
1731
|
+
},
|
|
1732
|
+
has(target, prop) {
|
|
1733
|
+
if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) {
|
|
1734
|
+
return true;
|
|
1735
|
+
}
|
|
1736
|
+
return prop in target;
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
function replaceTraps(callback) {
|
|
1740
|
+
idbProxyTraps = callback(idbProxyTraps);
|
|
1741
|
+
}
|
|
1742
|
+
function wrapFunction(func) {
|
|
1743
|
+
// Due to expected object equality (which is enforced by the caching in `wrap`), we
|
|
1744
|
+
// only create one new func per func.
|
|
1745
|
+
// Cursor methods are special, as the behaviour is a little more different to standard IDB. In
|
|
1746
|
+
// IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
|
|
1747
|
+
// cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
|
|
1748
|
+
// with real promises, so each advance methods returns a new promise for the cursor object, or
|
|
1749
|
+
// undefined if the end of the cursor has been reached.
|
|
1750
|
+
if (getCursorAdvanceMethods().includes(func)) {
|
|
1751
|
+
return function (...args) {
|
|
1752
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
1753
|
+
// the original object.
|
|
1754
|
+
func.apply(unwrap(this), args);
|
|
1755
|
+
return wrap(this.request);
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
return function (...args) {
|
|
1759
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
1760
|
+
// the original object.
|
|
1761
|
+
return wrap(func.apply(unwrap(this), args));
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
function transformCachableValue(value) {
|
|
1765
|
+
if (typeof value === 'function') return wrapFunction(value);
|
|
1766
|
+
// This doesn't return, it just creates a 'done' promise for the transaction,
|
|
1767
|
+
// which is later returned for transaction.done (see idbObjectHandler).
|
|
1768
|
+
if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value);
|
|
1769
|
+
if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps);
|
|
1770
|
+
// Return the same value back if we're not going to transform it.
|
|
1771
|
+
return value;
|
|
1772
|
+
}
|
|
1773
|
+
function wrap(value) {
|
|
1774
|
+
// We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
|
|
1775
|
+
// IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
|
|
1776
|
+
if (value instanceof IDBRequest) return promisifyRequest(value);
|
|
1777
|
+
// If we've already transformed this value before, reuse the transformed value.
|
|
1778
|
+
// This is faster, but it also provides object equality.
|
|
1779
|
+
if (transformCache.has(value)) return transformCache.get(value);
|
|
1780
|
+
const newValue = transformCachableValue(value);
|
|
1781
|
+
// Not all types are transformed.
|
|
1782
|
+
// These may be primitive types, so they can't be WeakMap keys.
|
|
1783
|
+
if (newValue !== value) {
|
|
1784
|
+
transformCache.set(value, newValue);
|
|
1785
|
+
reverseTransformCache.set(newValue, value);
|
|
1786
|
+
}
|
|
1787
|
+
return newValue;
|
|
1788
|
+
}
|
|
1789
|
+
const unwrap = value => reverseTransformCache.get(value);
|
|
1790
|
+
|
|
1791
|
+
/**
|
|
1792
|
+
* Open a database.
|
|
1793
|
+
*
|
|
1794
|
+
* @param name Name of the database.
|
|
1795
|
+
* @param version Schema version.
|
|
1796
|
+
* @param callbacks Additional callbacks.
|
|
1797
|
+
*/
|
|
1798
|
+
function openDB(name, version, {
|
|
1799
|
+
blocked,
|
|
1800
|
+
upgrade,
|
|
1801
|
+
blocking,
|
|
1802
|
+
terminated
|
|
1803
|
+
} = {}) {
|
|
1804
|
+
const request = indexedDB.open(name, version);
|
|
1805
|
+
const openPromise = wrap(request);
|
|
1806
|
+
if (upgrade) {
|
|
1807
|
+
request.addEventListener('upgradeneeded', event => {
|
|
1808
|
+
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
|
|
1809
|
+
});
|
|
1810
|
+
}
|
|
1811
|
+
if (blocked) {
|
|
1812
|
+
request.addEventListener('blocked', event => blocked(
|
|
1813
|
+
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
|
|
1814
|
+
event.oldVersion, event.newVersion, event));
|
|
1815
|
+
}
|
|
1816
|
+
openPromise.then(db => {
|
|
1817
|
+
if (terminated) db.addEventListener('close', () => terminated());
|
|
1818
|
+
if (blocking) {
|
|
1819
|
+
db.addEventListener('versionchange', event => blocking(event.oldVersion, event.newVersion, event));
|
|
1820
|
+
}
|
|
1821
|
+
}).catch(() => {});
|
|
1822
|
+
return openPromise;
|
|
1823
|
+
}
|
|
1824
|
+
const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
|
|
1825
|
+
const writeMethods = ['put', 'add', 'delete', 'clear'];
|
|
1826
|
+
const cachedMethods = new Map();
|
|
1827
|
+
function getMethod(target, prop) {
|
|
1828
|
+
if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) {
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
if (cachedMethods.get(prop)) return cachedMethods.get(prop);
|
|
1832
|
+
const targetFuncName = prop.replace(/FromIndex$/, '');
|
|
1833
|
+
const useIndex = prop !== targetFuncName;
|
|
1834
|
+
const isWrite = writeMethods.includes(targetFuncName);
|
|
1835
|
+
if (
|
|
1836
|
+
// Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
|
|
1837
|
+
!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) {
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
const method = async function (storeName, ...args) {
|
|
1841
|
+
// isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
|
|
1842
|
+
const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
|
|
1843
|
+
let target = tx.store;
|
|
1844
|
+
if (useIndex) target = target.index(args.shift());
|
|
1845
|
+
// Must reject if op rejects.
|
|
1846
|
+
// If it's a write operation, must reject if tx.done rejects.
|
|
1847
|
+
// Must reject with op rejection first.
|
|
1848
|
+
// Must resolve with op value.
|
|
1849
|
+
// Must handle both promises (no unhandled rejections)
|
|
1850
|
+
return (await Promise.all([target[targetFuncName](...args), isWrite && tx.done]))[0];
|
|
1851
|
+
};
|
|
1852
|
+
cachedMethods.set(prop, method);
|
|
1853
|
+
return method;
|
|
1854
|
+
}
|
|
1855
|
+
replaceTraps(oldTraps => ({
|
|
1856
|
+
...oldTraps,
|
|
1857
|
+
get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
|
|
1858
|
+
has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)
|
|
1859
|
+
}));
|
|
1860
|
+
const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
|
|
1861
|
+
const methodMap = {};
|
|
1862
|
+
const advanceResults = new WeakMap();
|
|
1863
|
+
const ittrProxiedCursorToOriginalProxy = new WeakMap();
|
|
1864
|
+
const cursorIteratorTraps = {
|
|
1865
|
+
get(target, prop) {
|
|
1866
|
+
if (!advanceMethodProps.includes(prop)) return target[prop];
|
|
1867
|
+
let cachedFunc = methodMap[prop];
|
|
1868
|
+
if (!cachedFunc) {
|
|
1869
|
+
cachedFunc = methodMap[prop] = function (...args) {
|
|
1870
|
+
advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
return cachedFunc;
|
|
1758
1874
|
}
|
|
1759
|
-
return Number((value / durationSeconds * 100).toFixed(3));
|
|
1760
1875
|
};
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
if (
|
|
1765
|
-
|
|
1766
|
-
endSeconds: null,
|
|
1767
|
-
hasSelection: false,
|
|
1768
|
-
startSeconds: null
|
|
1769
|
-
};
|
|
1876
|
+
async function* iterate(...args) {
|
|
1877
|
+
// tslint:disable-next-line:no-this-assignment
|
|
1878
|
+
let cursor = this;
|
|
1879
|
+
if (!(cursor instanceof IDBCursor)) {
|
|
1880
|
+
cursor = await cursor.openCursor(...args);
|
|
1770
1881
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
const
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1783
|
-
if (eventsWithTime.length === 0) {
|
|
1784
|
-
return events;
|
|
1882
|
+
if (!cursor) return;
|
|
1883
|
+
cursor = cursor;
|
|
1884
|
+
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
1885
|
+
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
1886
|
+
// Map this double-proxy back to the original, so other cursor methods work.
|
|
1887
|
+
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
1888
|
+
while (cursor) {
|
|
1889
|
+
yield proxiedCursor;
|
|
1890
|
+
// If one of the advancing methods was not called, call continue().
|
|
1891
|
+
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
1892
|
+
advanceResults.delete(proxiedCursor);
|
|
1785
1893
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1894
|
+
}
|
|
1895
|
+
function isIteratorProp(target, prop) {
|
|
1896
|
+
return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
|
|
1897
|
+
}
|
|
1898
|
+
replaceTraps(oldTraps => ({
|
|
1899
|
+
...oldTraps,
|
|
1900
|
+
get(target, prop, receiver) {
|
|
1901
|
+
if (isIteratorProp(target, prop)) return iterate;
|
|
1902
|
+
return oldTraps.get(target, prop, receiver);
|
|
1903
|
+
},
|
|
1904
|
+
has(target, prop) {
|
|
1905
|
+
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
1792
1906
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1907
|
+
}));
|
|
1908
|
+
|
|
1909
|
+
const openDatabaseDependencies = {
|
|
1910
|
+
openDB: openDB
|
|
1796
1911
|
};
|
|
1797
|
-
const
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
const counts = Array.from({
|
|
1818
|
-
length: bucketCount
|
|
1819
|
-
}).fill(0);
|
|
1820
|
-
for (const item of eventsWithTime) {
|
|
1821
|
-
const offsetMs = item.time - baseTime;
|
|
1822
|
-
const index = durationMs === 0 ? 0 : Math.min(bucketCount - 1, Math.floor(offsetMs / durationMs * bucketCount));
|
|
1823
|
-
counts[index] += 1;
|
|
1912
|
+
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1913
|
+
return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
|
|
1914
|
+
};
|
|
1915
|
+
|
|
1916
|
+
const loadSelectedEventDependencies = {
|
|
1917
|
+
getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
|
|
1918
|
+
openDatabase: openDatabase
|
|
1919
|
+
};
|
|
1920
|
+
const loadSelectedEvent = async (databaseName, dataBaseVersion, eventStoreName, sessionId, sessionIdIndexName, eventId, type) => {
|
|
1921
|
+
const database = await loadSelectedEventDependencies.openDatabase(databaseName, dataBaseVersion);
|
|
1922
|
+
try {
|
|
1923
|
+
if (!database.objectStoreNames.contains(eventStoreName)) {
|
|
1924
|
+
return null;
|
|
1925
|
+
}
|
|
1926
|
+
const transaction = database.transaction(eventStoreName, 'readonly');
|
|
1927
|
+
const store = transaction.objectStore(eventStoreName);
|
|
1928
|
+
const event = await loadSelectedEventDependencies.getEventDetailsBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId, type);
|
|
1929
|
+
return event ?? null;
|
|
1930
|
+
} finally {
|
|
1931
|
+
database.close();
|
|
1824
1932
|
}
|
|
1825
|
-
const maxCount = Math.max(...counts);
|
|
1826
|
-
const selectionStartPercent = range.hasSelection && range.startSeconds !== null ? getSelectionPercent(range.startSeconds, durationSeconds) : null;
|
|
1827
|
-
const selectionEndPercent = range.hasSelection && range.endSeconds !== null ? getSelectionPercent(range.endSeconds, durationSeconds) : null;
|
|
1828
|
-
const buckets = counts.map((count, index) => {
|
|
1829
|
-
const bucketStartMs = index * bucketDurationMs;
|
|
1830
|
-
const bucketEndMs = index === bucketCount - 1 ? durationMs : (index + 1) * bucketDurationMs;
|
|
1831
|
-
const hasSelection = range.hasSelection && range.startSeconds !== null && range.endSeconds !== null;
|
|
1832
|
-
const selectionStartMs = hasSelection ? range.startSeconds * 1000 : 0;
|
|
1833
|
-
const selectionEndMs = hasSelection ? range.endSeconds * 1000 : 0;
|
|
1834
|
-
return {
|
|
1835
|
-
count,
|
|
1836
|
-
endSeconds: roundSeconds(bucketEndMs / 1000),
|
|
1837
|
-
isSelected: hasSelection && bucketEndMs >= selectionStartMs && bucketStartMs <= selectionEndMs,
|
|
1838
|
-
startSeconds: roundSeconds(bucketStartMs / 1000),
|
|
1839
|
-
unitCount: count === 0 ? 0 : Math.max(1, Math.round(count / maxCount * maxBarUnits))
|
|
1840
|
-
};
|
|
1841
|
-
});
|
|
1842
|
-
return {
|
|
1843
|
-
buckets,
|
|
1844
|
-
durationSeconds,
|
|
1845
|
-
endSeconds: range.endSeconds,
|
|
1846
|
-
hasSelection: range.hasSelection,
|
|
1847
|
-
selectionEndPercent,
|
|
1848
|
-
selectionStartPercent,
|
|
1849
|
-
startSeconds: range.startSeconds
|
|
1850
|
-
};
|
|
1851
1933
|
};
|
|
1852
1934
|
|
|
1853
1935
|
const getCurrentEvents$2 = state => {
|
|
@@ -1895,7 +1977,7 @@ const parseSelectedEventIndex$1 = value => {
|
|
|
1895
1977
|
}
|
|
1896
1978
|
return parsed;
|
|
1897
1979
|
};
|
|
1898
|
-
const handleEventRowClick = async (state, value, button) => {
|
|
1980
|
+
const handleEventRowClick = async (state, value, button = 0) => {
|
|
1899
1981
|
if (!isPrimaryButton(button)) {
|
|
1900
1982
|
return state;
|
|
1901
1983
|
}
|
|
@@ -1931,7 +2013,7 @@ const getCurrentEvents$1 = state => {
|
|
|
1931
2013
|
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1932
2014
|
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1933
2015
|
};
|
|
1934
|
-
const parseTimelineRangePreset = value => {
|
|
2016
|
+
const parseTimelineRangePreset$1 = value => {
|
|
1935
2017
|
if (!value) {
|
|
1936
2018
|
return {
|
|
1937
2019
|
timelineEndSeconds: '',
|
|
@@ -2074,7 +2156,7 @@ const handleInput = (state, name, value, checked) => {
|
|
|
2074
2156
|
if (name === TimelineRangePreset) {
|
|
2075
2157
|
const nextState = {
|
|
2076
2158
|
...state,
|
|
2077
|
-
...parseTimelineRangePreset(value)
|
|
2159
|
+
...parseTimelineRangePreset$1(value)
|
|
2078
2160
|
};
|
|
2079
2161
|
return withPreservedSelection(state, nextState);
|
|
2080
2162
|
}
|
|
@@ -2126,8 +2208,43 @@ const clearTimelineSelectionState = state => {
|
|
|
2126
2208
|
};
|
|
2127
2209
|
};
|
|
2128
2210
|
|
|
2211
|
+
const parseTimelineRangePreset = value => {
|
|
2212
|
+
if (!value) {
|
|
2213
|
+
return {
|
|
2214
|
+
timelineEndSeconds: '',
|
|
2215
|
+
timelineStartSeconds: ''
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
|
|
2219
|
+
return {
|
|
2220
|
+
timelineEndSeconds,
|
|
2221
|
+
timelineStartSeconds
|
|
2222
|
+
};
|
|
2223
|
+
};
|
|
2224
|
+
const handleTimelineStartSeconds = (state, value) => {
|
|
2225
|
+
const nextState = {
|
|
2226
|
+
...state,
|
|
2227
|
+
timelineStartSeconds: value
|
|
2228
|
+
};
|
|
2229
|
+
return withPreservedSelection$1(state, nextState);
|
|
2230
|
+
};
|
|
2231
|
+
const handleTimelineEndSeconds = (state, value) => {
|
|
2232
|
+
const nextState = {
|
|
2233
|
+
...state,
|
|
2234
|
+
timelineEndSeconds: value
|
|
2235
|
+
};
|
|
2236
|
+
return withPreservedSelection$1(state, nextState);
|
|
2237
|
+
};
|
|
2238
|
+
const handleTimelineRangePreset = (state, value) => {
|
|
2239
|
+
const nextState = {
|
|
2240
|
+
...state,
|
|
2241
|
+
...parseTimelineRangePreset(value)
|
|
2242
|
+
};
|
|
2243
|
+
return withPreservedSelection$1(state, nextState);
|
|
2244
|
+
};
|
|
2245
|
+
|
|
2129
2246
|
const handleTimelineDoubleClick = state => {
|
|
2130
|
-
const nextState =
|
|
2247
|
+
const nextState = handleTimelineRangePreset(state, '');
|
|
2131
2248
|
return clearTimelineSelectionState(nextState);
|
|
2132
2249
|
};
|
|
2133
2250
|
|
|
@@ -2217,10 +2334,44 @@ const handleTimelinePointerUp = (state, eventX) => {
|
|
|
2217
2334
|
const focus = Number.parseFloat(focusSeconds);
|
|
2218
2335
|
const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
|
|
2219
2336
|
const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
|
|
2220
|
-
const nextState =
|
|
2337
|
+
const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
|
|
2221
2338
|
return clearTimelineSelectionState(nextState);
|
|
2222
2339
|
};
|
|
2223
2340
|
|
|
2341
|
+
const handleUseDevtoolsLayout = (state, checked) => {
|
|
2342
|
+
const useDevtoolsLayout = getBoolean(checked);
|
|
2343
|
+
const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
|
|
2344
|
+
return {
|
|
2345
|
+
...state,
|
|
2346
|
+
selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
|
|
2347
|
+
selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
|
|
2348
|
+
selectedEventIndex,
|
|
2349
|
+
useDevtoolsLayout
|
|
2350
|
+
};
|
|
2351
|
+
};
|
|
2352
|
+
|
|
2353
|
+
const handleShowEventStreamFinishedEvents = (state, checked) => {
|
|
2354
|
+
const nextState = {
|
|
2355
|
+
...state,
|
|
2356
|
+
showEventStreamFinishedEvents: getBoolean(checked)
|
|
2357
|
+
};
|
|
2358
|
+
return withPreservedSelection$1(state, nextState);
|
|
2359
|
+
};
|
|
2360
|
+
const handleShowInputEvents = (state, checked) => {
|
|
2361
|
+
const nextState = {
|
|
2362
|
+
...state,
|
|
2363
|
+
showInputEvents: getBoolean(checked)
|
|
2364
|
+
};
|
|
2365
|
+
return withPreservedSelection$1(state, nextState);
|
|
2366
|
+
};
|
|
2367
|
+
const handleShowResponsePartEvents = (state, checked) => {
|
|
2368
|
+
const nextState = {
|
|
2369
|
+
...state,
|
|
2370
|
+
showResponsePartEvents: getBoolean(checked)
|
|
2371
|
+
};
|
|
2372
|
+
return withPreservedSelection$1(state, nextState);
|
|
2373
|
+
};
|
|
2374
|
+
|
|
2224
2375
|
const getFailedToLoadMessage = sessionId => {
|
|
2225
2376
|
return `Failed to load chat debug session "${sessionId}". Please try again.`;
|
|
2226
2377
|
};
|
|
@@ -2571,9 +2722,23 @@ const refresh = async state => {
|
|
|
2571
2722
|
return refreshEvents(state);
|
|
2572
2723
|
};
|
|
2573
2724
|
|
|
2725
|
+
const Button = 1;
|
|
2726
|
+
const Div = 4;
|
|
2727
|
+
const Input = 6;
|
|
2728
|
+
const Span = 8;
|
|
2729
|
+
const Table = 9;
|
|
2730
|
+
const TBody = 10;
|
|
2731
|
+
const Td = 11;
|
|
2732
|
+
const Text = 12;
|
|
2733
|
+
const Th = 13;
|
|
2734
|
+
const THead = 14;
|
|
2735
|
+
const Tr = 15;
|
|
2736
|
+
const Search = 42;
|
|
2737
|
+
const Label = 66;
|
|
2738
|
+
const Reference = 100;
|
|
2739
|
+
|
|
2574
2740
|
const ClientX = 'event.clientX';
|
|
2575
2741
|
const ClientY = 'event.clientY';
|
|
2576
|
-
const TargetChecked = 'event.target.checked';
|
|
2577
2742
|
const TargetName = 'event.target.name';
|
|
2578
2743
|
const TargetValue = 'event.target.value';
|
|
2579
2744
|
|
|
@@ -3319,21 +3484,6 @@ const renderCss = (oldState, newState) => {
|
|
|
3319
3484
|
return [SetCss, newState.uid, css];
|
|
3320
3485
|
};
|
|
3321
3486
|
|
|
3322
|
-
const Button = 1;
|
|
3323
|
-
const Div = 4;
|
|
3324
|
-
const Input = 6;
|
|
3325
|
-
const Span = 8;
|
|
3326
|
-
const Table = 9;
|
|
3327
|
-
const TBody = 10;
|
|
3328
|
-
const Td = 11;
|
|
3329
|
-
const Text = 12;
|
|
3330
|
-
const Th = 13;
|
|
3331
|
-
const THead = 14;
|
|
3332
|
-
const Tr = 15;
|
|
3333
|
-
const Search = 42;
|
|
3334
|
-
const Label = 66;
|
|
3335
|
-
const Reference = 100;
|
|
3336
|
-
|
|
3337
3487
|
const text = data => {
|
|
3338
3488
|
return {
|
|
3339
3489
|
childCount: 0,
|
|
@@ -3715,9 +3865,9 @@ const getDebugErrorDom = errorMessage => {
|
|
|
3715
3865
|
}, text(errorMessage)];
|
|
3716
3866
|
};
|
|
3717
3867
|
|
|
3718
|
-
const
|
|
3868
|
+
const HandleEventCategoryFilter = 4;
|
|
3719
3869
|
const HandleFilterInput = 5;
|
|
3720
|
-
const
|
|
3870
|
+
const HandleDetailTab = 6;
|
|
3721
3871
|
const HandleEventRowClick = 7;
|
|
3722
3872
|
const HandleHeaderContextMenu = 8;
|
|
3723
3873
|
const HandleSashPointerDown = 9;
|
|
@@ -3730,6 +3880,8 @@ const HandleTimelinePointerMove = 15;
|
|
|
3730
3880
|
const HandleTimelinePointerUp = 16;
|
|
3731
3881
|
const HandleTimelineDoubleClick = 17;
|
|
3732
3882
|
const HandleTableKeyDown = 18;
|
|
3883
|
+
const HandleTimelineRangePreset = 19;
|
|
3884
|
+
const HandleCloseDetails = 20;
|
|
3733
3885
|
|
|
3734
3886
|
const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
|
|
3735
3887
|
if (useDevtoolsLayout) {
|
|
@@ -3857,8 +4009,8 @@ const getTabNodes = selectedDetailTab => {
|
|
|
3857
4009
|
className: joinClassNames(ChatDebugViewDetailsTab, isSelected && ChatDebugViewDetailsTabSelected),
|
|
3858
4010
|
id: getTabId(detailTab),
|
|
3859
4011
|
name: DetailTab,
|
|
3860
|
-
onChange:
|
|
3861
|
-
onClick:
|
|
4012
|
+
onChange: HandleDetailTab,
|
|
4013
|
+
onClick: HandleDetailTab,
|
|
3862
4014
|
role: 'tab',
|
|
3863
4015
|
tabIndex: isSelected ? 0 : -1,
|
|
3864
4016
|
type: Button,
|
|
@@ -3884,8 +4036,8 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
|
|
|
3884
4036
|
childCount: 0,
|
|
3885
4037
|
className: ChatDebugViewDetailsClose,
|
|
3886
4038
|
name: CloseDetails,
|
|
3887
|
-
onChange:
|
|
3888
|
-
onClick:
|
|
4039
|
+
onChange: HandleCloseDetails,
|
|
4040
|
+
onClick: HandleCloseDetails,
|
|
3889
4041
|
type: Button,
|
|
3890
4042
|
value: 'close'
|
|
3891
4043
|
}, {
|
|
@@ -4179,6 +4331,9 @@ const getEventsClassName = hasSelectedEvent => {
|
|
|
4179
4331
|
const hasOwn = (event, key) => {
|
|
4180
4332
|
return Object.hasOwn(event, key);
|
|
4181
4333
|
};
|
|
4334
|
+
const isChatMessageUpdatedEvent = event => {
|
|
4335
|
+
return event.type === 'chat-message-updated';
|
|
4336
|
+
};
|
|
4182
4337
|
const getPreviewName = event => {
|
|
4183
4338
|
if (typeof event.name === 'string' && event.name) {
|
|
4184
4339
|
return event.name;
|
|
@@ -4198,6 +4353,9 @@ const shouldIncludeArguments = (event, name) => {
|
|
|
4198
4353
|
return true;
|
|
4199
4354
|
};
|
|
4200
4355
|
const getPreviewEvent = event => {
|
|
4356
|
+
if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
|
|
4357
|
+
return event.text;
|
|
4358
|
+
}
|
|
4201
4359
|
const name = getPreviewName(event);
|
|
4202
4360
|
const previewEvent = {
|
|
4203
4361
|
...(name === undefined ? {} : {
|
|
@@ -4310,7 +4468,7 @@ const getBucketDom = bucket => {
|
|
|
4310
4468
|
className: ChatDebugViewTimelinePresetInput,
|
|
4311
4469
|
inputType: 'radio',
|
|
4312
4470
|
name: TimelineRangePreset,
|
|
4313
|
-
onChange:
|
|
4471
|
+
onChange: HandleTimelineRangePreset,
|
|
4314
4472
|
type: Input,
|
|
4315
4473
|
value: presetValue
|
|
4316
4474
|
}, {
|
|
@@ -4460,7 +4618,7 @@ const getQuickFilterNodes = (eventCategoryFilter, eventCategoryFilterOptions) =>
|
|
|
4460
4618
|
className: ChatDebugViewQuickFilterInput,
|
|
4461
4619
|
inputType: 'radio',
|
|
4462
4620
|
name: EventCategoryFilter,
|
|
4463
|
-
onChange:
|
|
4621
|
+
onChange: HandleEventCategoryFilter,
|
|
4464
4622
|
type: Input,
|
|
4465
4623
|
value: option.value
|
|
4466
4624
|
}, text(option.label)];
|
|
@@ -4498,10 +4656,12 @@ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, eve
|
|
|
4498
4656
|
if (timelineFilterDescription) {
|
|
4499
4657
|
filterDescriptionParts.push(timelineFilterDescription);
|
|
4500
4658
|
}
|
|
4659
|
+
const hasTimelineFilter = Boolean(timelineFilterDescription);
|
|
4501
4660
|
const hasFilterValue = filterDescriptionParts.length > 0;
|
|
4502
4661
|
const filterDescription = filterDescriptionParts.join(' ');
|
|
4503
4662
|
const noFilteredEventsMessage = `no events found matching ${filterDescription}`;
|
|
4504
|
-
const
|
|
4663
|
+
const useNoToolCallEventsMessage = eventCategoryFilter === Tools && !trimmedFilterValue && !hasTimelineFilter;
|
|
4664
|
+
const emptyMessage = events.length === 0 && hasFilterValue ? useNoToolCallEventsMessage ? 'No tool call events.' : noFilteredEventsMessage : 'No events have been found';
|
|
4505
4665
|
const safeSelectedEventIndex = selectedEventIndex === null || selectedEventIndex < 0 || selectedEventIndex >= events.length ? null : selectedEventIndex;
|
|
4506
4666
|
const contentNodes = useDevtoolsLayout ? getDevtoolsDom(events, selectedEvent, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response) : getLegacyEventsDom(errorMessage, emptyMessage, events.flatMap(getEventNode));
|
|
4507
4667
|
const quickFilterNodes = useDevtoolsLayout ? getQuickFilterNodes(eventCategoryFilter, eventCategoryFilterOptions) : [];
|
|
@@ -4585,11 +4745,17 @@ const renderEventListeners = () => {
|
|
|
4585
4745
|
name: HandleFilterInput,
|
|
4586
4746
|
params: ['handleInput', TargetName, TargetValue]
|
|
4587
4747
|
}, {
|
|
4588
|
-
name:
|
|
4589
|
-
params: ['
|
|
4748
|
+
name: HandleEventCategoryFilter,
|
|
4749
|
+
params: ['handleEventCategoryFilter', TargetValue]
|
|
4590
4750
|
}, {
|
|
4591
|
-
name:
|
|
4592
|
-
params: ['
|
|
4751
|
+
name: HandleDetailTab,
|
|
4752
|
+
params: ['handleDetailTab', TargetValue]
|
|
4753
|
+
}, {
|
|
4754
|
+
name: HandleTimelineRangePreset,
|
|
4755
|
+
params: ['handleTimelineRangePreset', TargetValue]
|
|
4756
|
+
}, {
|
|
4757
|
+
name: HandleCloseDetails,
|
|
4758
|
+
params: ['handleCloseDetails']
|
|
4593
4759
|
}, {
|
|
4594
4760
|
name: HandleSashPointerDown,
|
|
4595
4761
|
params: ['handleSashPointerDown', ClientX, ClientY],
|
|
@@ -4686,8 +4852,11 @@ const setIndexedDbSupportForTest = supported => {
|
|
|
4686
4852
|
return setIndexedDbSupportOverride(supported);
|
|
4687
4853
|
};
|
|
4688
4854
|
|
|
4855
|
+
const setSessionIdDependencies = {
|
|
4856
|
+
listChatViewEvents: listChatViewEvents
|
|
4857
|
+
};
|
|
4689
4858
|
const setSessionId = async (state, sessionId) => {
|
|
4690
|
-
const result = await listChatViewEvents(sessionId, state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionIdIndexName);
|
|
4859
|
+
const result = await setSessionIdDependencies.listChatViewEvents(sessionId, state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionIdIndexName, state.indexedDbSupportOverride);
|
|
4691
4860
|
if (result.type === 'not-supported') {
|
|
4692
4861
|
return {
|
|
4693
4862
|
...state,
|
|
@@ -4696,6 +4865,7 @@ const setSessionId = async (state, sessionId) => {
|
|
|
4696
4865
|
initial: false,
|
|
4697
4866
|
selectedEvent: null,
|
|
4698
4867
|
selectedEventId: null,
|
|
4868
|
+
selectedEventIndex: null,
|
|
4699
4869
|
sessionId
|
|
4700
4870
|
};
|
|
4701
4871
|
}
|
|
@@ -4707,6 +4877,7 @@ const setSessionId = async (state, sessionId) => {
|
|
|
4707
4877
|
initial: false,
|
|
4708
4878
|
selectedEvent: null,
|
|
4709
4879
|
selectedEventId: null,
|
|
4880
|
+
selectedEventIndex: null,
|
|
4710
4881
|
sessionId
|
|
4711
4882
|
};
|
|
4712
4883
|
}
|
|
@@ -4720,6 +4891,7 @@ const setSessionId = async (state, sessionId) => {
|
|
|
4720
4891
|
initial: false,
|
|
4721
4892
|
selectedEvent: null,
|
|
4722
4893
|
selectedEventId: null,
|
|
4894
|
+
selectedEventIndex: null,
|
|
4723
4895
|
sessionId
|
|
4724
4896
|
};
|
|
4725
4897
|
};
|
|
@@ -4728,18 +4900,28 @@ const commandMap = {
|
|
|
4728
4900
|
'ChatDebug.create': create,
|
|
4729
4901
|
'ChatDebug.diff2': diff2,
|
|
4730
4902
|
'ChatDebug.getCommandIds': getCommandIds,
|
|
4903
|
+
'ChatDebug.handleCloseDetails': wrapCommand(handleCloseDetails),
|
|
4731
4904
|
'ChatDebug.handleDetailsContextMenu': wrapCommand(handleDetailsContextMenu),
|
|
4905
|
+
'ChatDebug.handleDetailTab': wrapCommand(handleDetailTab),
|
|
4906
|
+
'ChatDebug.handleEventCategoryFilter': wrapCommand(handleEventCategoryFilter),
|
|
4732
4907
|
'ChatDebug.handleEventRowClick': wrapCommand(handleEventRowClick),
|
|
4733
4908
|
'ChatDebug.handleHeaderContextMenu': wrapCommand(handleHeaderContextMenu),
|
|
4734
4909
|
'ChatDebug.handleInput': wrapCommand(handleInput),
|
|
4735
4910
|
'ChatDebug.handleSashPointerDown': wrapCommand(handleSashPointerDown),
|
|
4736
4911
|
'ChatDebug.handleSashPointerMove': wrapCommand(handleSashPointerMove),
|
|
4737
4912
|
'ChatDebug.handleSashPointerUp': wrapCommand(handleSashPointerUp),
|
|
4913
|
+
'ChatDebug.handleShowEventStreamFinishedEvents': wrapCommand(handleShowEventStreamFinishedEvents),
|
|
4914
|
+
'ChatDebug.handleShowInputEvents': wrapCommand(handleShowInputEvents),
|
|
4915
|
+
'ChatDebug.handleShowResponsePartEvents': wrapCommand(handleShowResponsePartEvents),
|
|
4738
4916
|
'ChatDebug.handleTableBodyContextMenu': wrapCommand(handleTableBodyContextMenu),
|
|
4739
4917
|
'ChatDebug.handleTimelineDoubleClick': wrapCommand(handleTimelineDoubleClick),
|
|
4918
|
+
'ChatDebug.handleTimelineEndSeconds': wrapCommand(handleTimelineEndSeconds),
|
|
4740
4919
|
'ChatDebug.handleTimelinePointerDown': wrapCommand(handleTimelinePointerDown),
|
|
4741
4920
|
'ChatDebug.handleTimelinePointerMove': wrapCommand(handleTimelinePointerMove),
|
|
4742
4921
|
'ChatDebug.handleTimelinePointerUp': wrapCommand(handleTimelinePointerUp),
|
|
4922
|
+
'ChatDebug.handleTimelineRangePreset': wrapCommand(handleTimelineRangePreset),
|
|
4923
|
+
'ChatDebug.handleTimelineStartSeconds': wrapCommand(handleTimelineStartSeconds),
|
|
4924
|
+
'ChatDebug.handleUseDevtoolsLayout': wrapCommand(handleUseDevtoolsLayout),
|
|
4743
4925
|
'ChatDebug.loadContent': wrapCommand(loadContent),
|
|
4744
4926
|
'ChatDebug.loadContent2': wrapCommand(loadContent),
|
|
4745
4927
|
'ChatDebug.refresh': wrapCommand(refresh),
|