@lvce-editor/chat-debug-view 5.1.0 → 5.3.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 +687 -486
- package/package.json +1 -1
|
@@ -1026,7 +1026,7 @@ const {
|
|
|
1026
1026
|
const Response = 'response';
|
|
1027
1027
|
const Preview = 'preview';
|
|
1028
1028
|
const Timing = 'timing';
|
|
1029
|
-
const detailTabs = [
|
|
1029
|
+
const detailTabs = [Preview, Response, Timing];
|
|
1030
1030
|
const isDetailTab = value => {
|
|
1031
1031
|
return value === Response || value === Preview || value === Timing;
|
|
1032
1032
|
};
|
|
@@ -1171,328 +1171,14 @@ const diff2 = uid => {
|
|
|
1171
1171
|
return diff(oldState, newState);
|
|
1172
1172
|
};
|
|
1173
1173
|
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
return startedEvent.toolName === finishedEvent.toolName;
|
|
1177
|
-
}
|
|
1178
|
-
return true;
|
|
1179
|
-
};
|
|
1180
|
-
|
|
1181
|
-
const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
|
|
1182
|
-
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName$1(startedEvent, finishedEvent);
|
|
1183
|
-
};
|
|
1184
|
-
|
|
1185
|
-
const startedEventType$1 = 'tool-execution-started';
|
|
1186
|
-
const finishedEventType$1 = 'tool-execution-finished';
|
|
1187
|
-
const mergedEventType = 'tool-execution';
|
|
1188
|
-
|
|
1189
|
-
const isToolExecutionFinishedEvent = event => {
|
|
1190
|
-
return event.type === finishedEventType$1;
|
|
1191
|
-
};
|
|
1192
|
-
|
|
1193
|
-
const isToolExecutionStartedEvent = event => {
|
|
1194
|
-
return event.type === startedEventType$1;
|
|
1195
|
-
};
|
|
1196
|
-
|
|
1197
|
-
const getTimestamp$1 = value => {
|
|
1198
|
-
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1199
|
-
};
|
|
1200
|
-
|
|
1201
|
-
const getEndedTimestamp = event => {
|
|
1202
|
-
return getTimestamp$1(event.ended) ?? getTimestamp$1(event.endTime) ?? getTimestamp$1(event.endTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
const eventStableIds = new WeakMap();
|
|
1206
|
-
const eventStableIdState = {
|
|
1207
|
-
nextStableEventId: 1
|
|
1208
|
-
};
|
|
1209
|
-
|
|
1210
|
-
const getOrCreateStableEventId = event => {
|
|
1211
|
-
const existingStableEventId = eventStableIds.get(event);
|
|
1212
|
-
if (existingStableEventId) {
|
|
1213
|
-
return existingStableEventId;
|
|
1214
|
-
}
|
|
1215
|
-
const stableEventId = `event-${eventStableIdState.nextStableEventId++}`;
|
|
1216
|
-
eventStableIds.set(event, stableEventId);
|
|
1217
|
-
return stableEventId;
|
|
1218
|
-
};
|
|
1219
|
-
|
|
1220
|
-
const getStartedTimestamp = event => {
|
|
1221
|
-
return getTimestamp$1(event.started) ?? getTimestamp$1(event.startTime) ?? getTimestamp$1(event.startTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1222
|
-
};
|
|
1223
|
-
|
|
1224
|
-
const setStableEventId = (event, stableEventId) => {
|
|
1225
|
-
eventStableIds.set(event, stableEventId);
|
|
1226
|
-
};
|
|
1227
|
-
|
|
1228
|
-
const mergeToolExecutionEvents$1 = (startedEvent, finishedEvent) => {
|
|
1229
|
-
const ended = getEndedTimestamp(finishedEvent);
|
|
1230
|
-
const {
|
|
1231
|
-
eventId
|
|
1232
|
-
} = startedEvent;
|
|
1233
|
-
const started = getStartedTimestamp(startedEvent);
|
|
1234
|
-
const mergedEvent = {
|
|
1235
|
-
...startedEvent,
|
|
1236
|
-
...finishedEvent,
|
|
1237
|
-
...(ended === undefined ? {} : {
|
|
1238
|
-
ended
|
|
1239
|
-
}),
|
|
1240
|
-
...(eventId === undefined ? {} : {
|
|
1241
|
-
eventId
|
|
1242
|
-
}),
|
|
1243
|
-
...(started === undefined ? {} : {
|
|
1244
|
-
started
|
|
1245
|
-
}),
|
|
1246
|
-
type: mergedEventType
|
|
1247
|
-
};
|
|
1248
|
-
const stableEventId = `${getOrCreateStableEventId(startedEvent)}:${getOrCreateStableEventId(finishedEvent)}`;
|
|
1249
|
-
setStableEventId(mergedEvent, stableEventId);
|
|
1250
|
-
return mergedEvent;
|
|
1251
|
-
};
|
|
1252
|
-
|
|
1253
|
-
const getStableEventId = event => {
|
|
1254
|
-
return getOrCreateStableEventId(event);
|
|
1255
|
-
};
|
|
1256
|
-
|
|
1257
|
-
const collapseToolExecutionEvents = events => {
|
|
1258
|
-
const collapsedEvents = [];
|
|
1259
|
-
for (let i = 0; i < events.length; i++) {
|
|
1260
|
-
const event = events[i];
|
|
1261
|
-
if (isToolExecutionStartedEvent(event)) {
|
|
1262
|
-
const nextEvent = events[i + 1];
|
|
1263
|
-
if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
|
|
1264
|
-
collapsedEvents.push(mergeToolExecutionEvents$1(event, nextEvent));
|
|
1265
|
-
i++;
|
|
1266
|
-
continue;
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
collapsedEvents.push(event);
|
|
1270
|
-
}
|
|
1271
|
-
return collapsedEvents;
|
|
1272
|
-
};
|
|
1273
|
-
|
|
1274
|
-
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1275
|
-
return events.filter(event => {
|
|
1276
|
-
if (!showInputEvents && event.type === 'handle-input') {
|
|
1277
|
-
return false;
|
|
1278
|
-
}
|
|
1279
|
-
if (!showResponsePartEvents && event.type === 'sse-response-part') {
|
|
1280
|
-
return false;
|
|
1281
|
-
}
|
|
1282
|
-
if (!showEventStreamFinishedEvents && event.type === 'event-stream-finished') {
|
|
1283
|
-
return false;
|
|
1284
|
-
}
|
|
1285
|
-
// hide session creation events by default — not useful in the debug view
|
|
1286
|
-
if (event.type === 'chat-session-created') {
|
|
1287
|
-
return false;
|
|
1288
|
-
}
|
|
1289
|
-
return true;
|
|
1290
|
-
});
|
|
1291
|
-
};
|
|
1292
|
-
|
|
1293
|
-
const isNetworkEvent = event => {
|
|
1294
|
-
const normalizedType = event.type.toLowerCase();
|
|
1295
|
-
return normalizedType === 'request' || normalizedType === 'response' || normalizedType === 'handle-response' || normalizedType.includes('fetch') || normalizedType.includes('xhr');
|
|
1296
|
-
};
|
|
1297
|
-
|
|
1298
|
-
const isStreamEvent = event => {
|
|
1299
|
-
return event.type === 'sse-response-part' || event.type === 'event-stream-finished';
|
|
1300
|
-
};
|
|
1301
|
-
|
|
1302
|
-
const toolEventTypePrefix = 'tool-execution';
|
|
1303
|
-
const isToolEvent = event => {
|
|
1304
|
-
return event.type.startsWith(toolEventTypePrefix);
|
|
1305
|
-
};
|
|
1306
|
-
|
|
1307
|
-
const isUiEvent = event => {
|
|
1308
|
-
return event.type.startsWith('handle-') && event.type !== 'handle-response';
|
|
1309
|
-
};
|
|
1310
|
-
|
|
1311
|
-
const matchesEventCategoryFilter = (event, eventCategoryFilter) => {
|
|
1312
|
-
switch (eventCategoryFilter) {
|
|
1313
|
-
case Network:
|
|
1314
|
-
return isNetworkEvent(event);
|
|
1315
|
-
case Stream:
|
|
1316
|
-
return isStreamEvent(event);
|
|
1317
|
-
case Tools:
|
|
1318
|
-
return isToolEvent(event);
|
|
1319
|
-
case Ui:
|
|
1320
|
-
return isUiEvent(event);
|
|
1321
|
-
default:
|
|
1322
|
-
return true;
|
|
1323
|
-
}
|
|
1324
|
-
};
|
|
1325
|
-
|
|
1326
|
-
const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1327
|
-
const visibleEvents = getVisibleEvents(events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
1328
|
-
const collapsedEvents = collapseToolExecutionEvents(visibleEvents);
|
|
1329
|
-
const parsedFilter = parseFilterValue(filterValue);
|
|
1330
|
-
const activeEventCategoryFilter = parsedFilter.eventCategoryFilter === All ? eventCategoryFilter : parsedFilter.eventCategoryFilter;
|
|
1331
|
-
const filteredByCategory = collapsedEvents.filter(event => matchesEventCategoryFilter(event, activeEventCategoryFilter));
|
|
1332
|
-
const {
|
|
1333
|
-
filterText
|
|
1334
|
-
} = parsedFilter;
|
|
1335
|
-
if (!filterText) {
|
|
1336
|
-
return filteredByCategory;
|
|
1337
|
-
}
|
|
1338
|
-
return filteredByCategory.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
|
|
1339
|
-
};
|
|
1340
|
-
|
|
1341
|
-
const toTimeNumber = value => {
|
|
1342
|
-
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1343
|
-
return value;
|
|
1344
|
-
}
|
|
1345
|
-
if (typeof value === 'string') {
|
|
1346
|
-
const timestamp = Date.parse(value);
|
|
1347
|
-
if (!Number.isNaN(timestamp)) {
|
|
1348
|
-
return timestamp;
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
return undefined;
|
|
1352
|
-
};
|
|
1353
|
-
|
|
1354
|
-
const getEventTime = event => {
|
|
1355
|
-
return toTimeNumber(event.started ?? event.startTime ?? event.startTimestamp ?? event.timestamp);
|
|
1356
|
-
};
|
|
1357
|
-
|
|
1358
|
-
const maxBarUnits = 8;
|
|
1359
|
-
const parseTimelineSeconds = value => {
|
|
1360
|
-
const trimmed = value.trim();
|
|
1361
|
-
if (!trimmed) {
|
|
1362
|
-
return undefined;
|
|
1363
|
-
}
|
|
1364
|
-
const parsed = Number.parseFloat(trimmed);
|
|
1365
|
-
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
1366
|
-
return undefined;
|
|
1367
|
-
}
|
|
1368
|
-
return parsed;
|
|
1369
|
-
};
|
|
1370
|
-
const roundSeconds = value => {
|
|
1371
|
-
return Number(value.toFixed(3));
|
|
1372
|
-
};
|
|
1373
|
-
const getEventsWithTime = events => {
|
|
1374
|
-
return events.flatMap(event => {
|
|
1375
|
-
const time = getEventTime(event);
|
|
1376
|
-
if (time === undefined) {
|
|
1377
|
-
return [];
|
|
1378
|
-
}
|
|
1379
|
-
return [{
|
|
1380
|
-
event,
|
|
1381
|
-
time
|
|
1382
|
-
}];
|
|
1383
|
-
});
|
|
1384
|
-
};
|
|
1385
|
-
const getTimelineDurationSeconds = events => {
|
|
1386
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1387
|
-
if (eventsWithTime.length === 0) {
|
|
1388
|
-
return 0;
|
|
1389
|
-
}
|
|
1390
|
-
const baseTime = eventsWithTime[0].time;
|
|
1391
|
-
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1392
|
-
return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1393
|
-
};
|
|
1394
|
-
const getSelectionPercent = (value, durationSeconds) => {
|
|
1395
|
-
if (durationSeconds <= 0) {
|
|
1396
|
-
return 0;
|
|
1397
|
-
}
|
|
1398
|
-
return Number((value / durationSeconds * 100).toFixed(3));
|
|
1399
|
-
};
|
|
1400
|
-
const getNormalizedRange = (durationSeconds, startValue, endValue) => {
|
|
1401
|
-
const parsedStart = parseTimelineSeconds(startValue);
|
|
1402
|
-
const parsedEnd = parseTimelineSeconds(endValue);
|
|
1403
|
-
if (parsedStart === undefined && parsedEnd === undefined) {
|
|
1404
|
-
return {
|
|
1405
|
-
endSeconds: null,
|
|
1406
|
-
hasSelection: false,
|
|
1407
|
-
startSeconds: null
|
|
1408
|
-
};
|
|
1409
|
-
}
|
|
1410
|
-
const rawStart = parsedStart ?? 0;
|
|
1411
|
-
const rawEnd = parsedEnd ?? durationSeconds;
|
|
1412
|
-
const normalizedStart = Math.max(0, Math.min(durationSeconds, Math.min(rawStart, rawEnd)));
|
|
1413
|
-
const normalizedEnd = Math.max(0, Math.min(durationSeconds, Math.max(rawStart, rawEnd)));
|
|
1414
|
-
return {
|
|
1415
|
-
endSeconds: roundSeconds(normalizedEnd),
|
|
1416
|
-
hasSelection: true,
|
|
1417
|
-
startSeconds: roundSeconds(normalizedStart)
|
|
1418
|
-
};
|
|
1419
|
-
};
|
|
1420
|
-
const filterEventsByTimelineRange = (events, startValue, endValue) => {
|
|
1421
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1422
|
-
if (eventsWithTime.length === 0) {
|
|
1423
|
-
return events;
|
|
1424
|
-
}
|
|
1425
|
-
const baseTime = eventsWithTime[0].time;
|
|
1426
|
-
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1427
|
-
const durationSeconds = roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1428
|
-
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1429
|
-
if (!range.hasSelection || range.startSeconds === null || range.endSeconds === null) {
|
|
1430
|
-
return events;
|
|
1431
|
-
}
|
|
1432
|
-
const startTime = baseTime + range.startSeconds * 1000;
|
|
1433
|
-
const endTime = baseTime + range.endSeconds * 1000;
|
|
1434
|
-
return eventsWithTime.filter(item => item.time >= startTime && item.time <= endTime).map(item => item.event);
|
|
1435
|
-
};
|
|
1436
|
-
const getTimelineInfo = (events, startValue, endValue) => {
|
|
1437
|
-
const eventsWithTime = getEventsWithTime(events);
|
|
1438
|
-
if (eventsWithTime.length === 0) {
|
|
1439
|
-
return {
|
|
1440
|
-
buckets: [],
|
|
1441
|
-
durationSeconds: 0,
|
|
1442
|
-
endSeconds: null,
|
|
1443
|
-
hasSelection: false,
|
|
1444
|
-
selectionEndPercent: null,
|
|
1445
|
-
selectionStartPercent: null,
|
|
1446
|
-
startSeconds: null
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
|
-
const baseTime = eventsWithTime[0].time;
|
|
1450
|
-
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1451
|
-
const durationMs = Math.max(0, lastTime - baseTime);
|
|
1452
|
-
const durationSeconds = roundSeconds(durationMs / 1000);
|
|
1453
|
-
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1454
|
-
const bucketCount = durationSeconds === 0 ? 1 : Math.max(12, Math.min(48, Math.ceil(durationSeconds)));
|
|
1455
|
-
const bucketDurationMs = durationMs === 0 ? 1000 : durationMs / bucketCount;
|
|
1456
|
-
const counts = Array.from({
|
|
1457
|
-
length: bucketCount
|
|
1458
|
-
}).fill(0);
|
|
1459
|
-
for (const item of eventsWithTime) {
|
|
1460
|
-
const offsetMs = item.time - baseTime;
|
|
1461
|
-
const index = durationMs === 0 ? 0 : Math.min(bucketCount - 1, Math.floor(offsetMs / durationMs * bucketCount));
|
|
1462
|
-
counts[index] += 1;
|
|
1463
|
-
}
|
|
1464
|
-
const maxCount = Math.max(...counts);
|
|
1465
|
-
const selectionStartPercent = range.hasSelection && range.startSeconds !== null ? getSelectionPercent(range.startSeconds, durationSeconds) : null;
|
|
1466
|
-
const selectionEndPercent = range.hasSelection && range.endSeconds !== null ? getSelectionPercent(range.endSeconds, durationSeconds) : null;
|
|
1467
|
-
const buckets = counts.map((count, index) => {
|
|
1468
|
-
const bucketStartMs = index * bucketDurationMs;
|
|
1469
|
-
const bucketEndMs = index === bucketCount - 1 ? durationMs : (index + 1) * bucketDurationMs;
|
|
1470
|
-
const hasSelection = range.hasSelection && range.startSeconds !== null && range.endSeconds !== null;
|
|
1471
|
-
const selectionStartMs = hasSelection ? range.startSeconds * 1000 : 0;
|
|
1472
|
-
const selectionEndMs = hasSelection ? range.endSeconds * 1000 : 0;
|
|
1473
|
-
return {
|
|
1474
|
-
count,
|
|
1475
|
-
endSeconds: roundSeconds(bucketEndMs / 1000),
|
|
1476
|
-
isSelected: hasSelection && bucketEndMs >= selectionStartMs && bucketStartMs <= selectionEndMs,
|
|
1477
|
-
startSeconds: roundSeconds(bucketStartMs / 1000),
|
|
1478
|
-
unitCount: count === 0 ? 0 : Math.max(1, Math.round(count / maxCount * maxBarUnits))
|
|
1479
|
-
};
|
|
1480
|
-
});
|
|
1481
|
-
return {
|
|
1482
|
-
buckets,
|
|
1483
|
-
durationSeconds,
|
|
1484
|
-
endSeconds: range.endSeconds,
|
|
1485
|
-
hasSelection: range.hasSelection,
|
|
1486
|
-
selectionEndPercent,
|
|
1487
|
-
selectionStartPercent,
|
|
1488
|
-
startSeconds: range.startSeconds
|
|
1489
|
-
};
|
|
1174
|
+
const handleDetailsContextMenu = state => {
|
|
1175
|
+
return state;
|
|
1490
1176
|
};
|
|
1491
1177
|
|
|
1492
1178
|
// cspell:ignore IDBP
|
|
1493
1179
|
|
|
1494
|
-
const startedEventType = 'tool-execution-started';
|
|
1495
|
-
const finishedEventType = 'tool-execution-finished';
|
|
1180
|
+
const startedEventType$1 = 'tool-execution-started';
|
|
1181
|
+
const finishedEventType$1 = 'tool-execution-finished';
|
|
1496
1182
|
const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId) => {
|
|
1497
1183
|
if (eventId < 1) {
|
|
1498
1184
|
return undefined;
|
|
@@ -1514,18 +1200,18 @@ const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndex
|
|
|
1514
1200
|
const events = all.filter(event => event.sessionId === sessionId);
|
|
1515
1201
|
return events[eventId - 1];
|
|
1516
1202
|
};
|
|
1517
|
-
const getTimestamp = value => {
|
|
1203
|
+
const getTimestamp$1 = value => {
|
|
1518
1204
|
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1519
1205
|
};
|
|
1520
|
-
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1206
|
+
const hasMatchingToolName$1 = (startedEvent, finishedEvent) => {
|
|
1521
1207
|
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1522
1208
|
return startedEvent.toolName === finishedEvent.toolName;
|
|
1523
1209
|
}
|
|
1524
1210
|
return true;
|
|
1525
1211
|
};
|
|
1526
|
-
const mergeToolExecutionEvents = (startedEvent, finishedEvent, eventId) => {
|
|
1527
|
-
const ended = getTimestamp(finishedEvent.ended) ?? getTimestamp(finishedEvent.endTime) ?? getTimestamp(finishedEvent.timestamp);
|
|
1528
|
-
const started = getTimestamp(startedEvent.started) ?? getTimestamp(startedEvent.startTime) ?? getTimestamp(startedEvent.timestamp);
|
|
1212
|
+
const mergeToolExecutionEvents$1 = (startedEvent, finishedEvent, eventId) => {
|
|
1213
|
+
const ended = getTimestamp$1(finishedEvent.ended) ?? getTimestamp$1(finishedEvent.endTime) ?? getTimestamp$1(finishedEvent.timestamp);
|
|
1214
|
+
const started = getTimestamp$1(startedEvent.started) ?? getTimestamp$1(startedEvent.startTime) ?? getTimestamp$1(startedEvent.timestamp);
|
|
1529
1215
|
return {
|
|
1530
1216
|
...startedEvent,
|
|
1531
1217
|
...finishedEvent,
|
|
@@ -1550,20 +1236,20 @@ const getEventDetailsBySessionIdAndEventId = async (store, sessionId, sessionIdI
|
|
|
1550
1236
|
eventId
|
|
1551
1237
|
};
|
|
1552
1238
|
}
|
|
1553
|
-
if (event.type !== startedEventType) {
|
|
1239
|
+
if (event.type !== startedEventType$1) {
|
|
1554
1240
|
return {
|
|
1555
1241
|
...event,
|
|
1556
1242
|
eventId
|
|
1557
1243
|
};
|
|
1558
1244
|
}
|
|
1559
1245
|
const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
|
|
1560
|
-
if (!nextEvent || nextEvent.type !== finishedEventType || nextEvent.sessionId !== sessionId || !hasMatchingToolName(event, nextEvent)) {
|
|
1246
|
+
if (!nextEvent || nextEvent.type !== finishedEventType$1 || nextEvent.sessionId !== sessionId || !hasMatchingToolName$1(event, nextEvent)) {
|
|
1561
1247
|
return {
|
|
1562
1248
|
...event,
|
|
1563
1249
|
eventId
|
|
1564
1250
|
};
|
|
1565
1251
|
}
|
|
1566
|
-
return mergeToolExecutionEvents(event, nextEvent, eventId);
|
|
1252
|
+
return mergeToolExecutionEvents$1(event, nextEvent, eventId);
|
|
1567
1253
|
};
|
|
1568
1254
|
|
|
1569
1255
|
const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
|
|
@@ -1826,45 +1512,349 @@ const openDatabaseDependencies = {
|
|
|
1826
1512
|
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1827
1513
|
return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
|
|
1828
1514
|
};
|
|
1829
|
-
|
|
1830
|
-
const loadSelectedEventDependencies = {
|
|
1831
|
-
getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
|
|
1832
|
-
openDatabase: openDatabase
|
|
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;
|
|
1633
|
+
};
|
|
1634
|
+
|
|
1635
|
+
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1636
|
+
return events.filter(event => {
|
|
1637
|
+
if (!showInputEvents && event.type === 'handle-input') {
|
|
1638
|
+
return false;
|
|
1639
|
+
}
|
|
1640
|
+
if (!showResponsePartEvents && event.type === 'sse-response-part') {
|
|
1641
|
+
return false;
|
|
1642
|
+
}
|
|
1643
|
+
if (!showEventStreamFinishedEvents && event.type === 'event-stream-finished') {
|
|
1644
|
+
return false;
|
|
1645
|
+
}
|
|
1646
|
+
// hide session creation events by default — not useful in the debug view
|
|
1647
|
+
if (event.type === 'chat-session-created') {
|
|
1648
|
+
return false;
|
|
1649
|
+
}
|
|
1650
|
+
return true;
|
|
1651
|
+
});
|
|
1652
|
+
};
|
|
1653
|
+
|
|
1654
|
+
const isNetworkEvent = event => {
|
|
1655
|
+
const normalizedType = event.type.toLowerCase();
|
|
1656
|
+
return normalizedType === 'request' || normalizedType === 'response' || normalizedType === 'handle-response' || normalizedType.includes('fetch') || normalizedType.includes('xhr');
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
const isStreamEvent = event => {
|
|
1660
|
+
return event.type === 'sse-response-part' || event.type === 'event-stream-finished';
|
|
1661
|
+
};
|
|
1662
|
+
|
|
1663
|
+
const toolEventTypePrefix = 'tool-execution';
|
|
1664
|
+
const isToolEvent = event => {
|
|
1665
|
+
return event.type.startsWith(toolEventTypePrefix);
|
|
1666
|
+
};
|
|
1667
|
+
|
|
1668
|
+
const isUiEvent = event => {
|
|
1669
|
+
return event.type.startsWith('handle-') && event.type !== 'handle-response';
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
const matchesEventCategoryFilter = (event, eventCategoryFilter) => {
|
|
1673
|
+
switch (eventCategoryFilter) {
|
|
1674
|
+
case Network:
|
|
1675
|
+
return isNetworkEvent(event);
|
|
1676
|
+
case Stream:
|
|
1677
|
+
return isStreamEvent(event);
|
|
1678
|
+
case Tools:
|
|
1679
|
+
return isToolEvent(event);
|
|
1680
|
+
case Ui:
|
|
1681
|
+
return isUiEvent(event);
|
|
1682
|
+
default:
|
|
1683
|
+
return true;
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
|
|
1687
|
+
const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1688
|
+
const visibleEvents = getVisibleEvents(events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
1689
|
+
const collapsedEvents = collapseToolExecutionEvents(visibleEvents);
|
|
1690
|
+
const parsedFilter = parseFilterValue(filterValue);
|
|
1691
|
+
const activeEventCategoryFilter = parsedFilter.eventCategoryFilter === All ? eventCategoryFilter : parsedFilter.eventCategoryFilter;
|
|
1692
|
+
const filteredByCategory = collapsedEvents.filter(event => matchesEventCategoryFilter(event, activeEventCategoryFilter));
|
|
1693
|
+
const {
|
|
1694
|
+
filterText
|
|
1695
|
+
} = parsedFilter;
|
|
1696
|
+
if (!filterText) {
|
|
1697
|
+
return filteredByCategory;
|
|
1698
|
+
}
|
|
1699
|
+
return filteredByCategory.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
|
|
1700
|
+
};
|
|
1701
|
+
|
|
1702
|
+
const toTimeNumber = value => {
|
|
1703
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1704
|
+
return value;
|
|
1705
|
+
}
|
|
1706
|
+
if (typeof value === 'string') {
|
|
1707
|
+
const timestamp = Date.parse(value);
|
|
1708
|
+
if (!Number.isNaN(timestamp)) {
|
|
1709
|
+
return timestamp;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return undefined;
|
|
1713
|
+
};
|
|
1714
|
+
|
|
1715
|
+
const getEventTime = event => {
|
|
1716
|
+
return toTimeNumber(event.started ?? event.startTime ?? event.startTimestamp ?? event.timestamp);
|
|
1717
|
+
};
|
|
1718
|
+
|
|
1719
|
+
const maxBarUnits = 8;
|
|
1720
|
+
const parseTimelineSeconds = value => {
|
|
1721
|
+
const trimmed = value.trim();
|
|
1722
|
+
if (!trimmed) {
|
|
1723
|
+
return undefined;
|
|
1724
|
+
}
|
|
1725
|
+
const parsed = Number.parseFloat(trimmed);
|
|
1726
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
1727
|
+
return undefined;
|
|
1728
|
+
}
|
|
1729
|
+
return parsed;
|
|
1730
|
+
};
|
|
1731
|
+
const roundSeconds = value => {
|
|
1732
|
+
return Number(value.toFixed(3));
|
|
1733
|
+
};
|
|
1734
|
+
const getEventsWithTime = events => {
|
|
1735
|
+
return events.flatMap(event => {
|
|
1736
|
+
const time = getEventTime(event);
|
|
1737
|
+
if (time === undefined) {
|
|
1738
|
+
return [];
|
|
1739
|
+
}
|
|
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;
|
|
1758
|
+
}
|
|
1759
|
+
return Number((value / durationSeconds * 100).toFixed(3));
|
|
1760
|
+
};
|
|
1761
|
+
const getNormalizedRange = (durationSeconds, startValue, endValue) => {
|
|
1762
|
+
const parsedStart = parseTimelineSeconds(startValue);
|
|
1763
|
+
const parsedEnd = parseTimelineSeconds(endValue);
|
|
1764
|
+
if (parsedStart === undefined && parsedEnd === undefined) {
|
|
1765
|
+
return {
|
|
1766
|
+
endSeconds: null,
|
|
1767
|
+
hasSelection: false,
|
|
1768
|
+
startSeconds: null
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
const rawStart = parsedStart ?? 0;
|
|
1772
|
+
const rawEnd = parsedEnd ?? durationSeconds;
|
|
1773
|
+
const normalizedStart = Math.max(0, Math.min(durationSeconds, Math.min(rawStart, rawEnd)));
|
|
1774
|
+
const normalizedEnd = Math.max(0, Math.min(durationSeconds, Math.max(rawStart, rawEnd)));
|
|
1775
|
+
return {
|
|
1776
|
+
endSeconds: roundSeconds(normalizedEnd),
|
|
1777
|
+
hasSelection: true,
|
|
1778
|
+
startSeconds: roundSeconds(normalizedStart)
|
|
1779
|
+
};
|
|
1780
|
+
};
|
|
1781
|
+
const filterEventsByTimelineRange = (events, startValue, endValue) => {
|
|
1782
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1783
|
+
if (eventsWithTime.length === 0) {
|
|
1784
|
+
return events;
|
|
1785
|
+
}
|
|
1786
|
+
const baseTime = eventsWithTime[0].time;
|
|
1787
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1788
|
+
const durationSeconds = roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1789
|
+
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1790
|
+
if (!range.hasSelection || range.startSeconds === null || range.endSeconds === null) {
|
|
1791
|
+
return events;
|
|
1792
|
+
}
|
|
1793
|
+
const startTime = baseTime + range.startSeconds * 1000;
|
|
1794
|
+
const endTime = baseTime + range.endSeconds * 1000;
|
|
1795
|
+
return eventsWithTime.filter(item => item.time >= startTime && item.time <= endTime).map(item => item.event);
|
|
1833
1796
|
};
|
|
1834
|
-
const
|
|
1835
|
-
const
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1797
|
+
const getTimelineInfo = (events, startValue, endValue) => {
|
|
1798
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1799
|
+
if (eventsWithTime.length === 0) {
|
|
1800
|
+
return {
|
|
1801
|
+
buckets: [],
|
|
1802
|
+
durationSeconds: 0,
|
|
1803
|
+
endSeconds: null,
|
|
1804
|
+
hasSelection: false,
|
|
1805
|
+
selectionEndPercent: null,
|
|
1806
|
+
selectionStartPercent: null,
|
|
1807
|
+
startSeconds: null
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
const baseTime = eventsWithTime[0].time;
|
|
1811
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1812
|
+
const durationMs = Math.max(0, lastTime - baseTime);
|
|
1813
|
+
const durationSeconds = roundSeconds(durationMs / 1000);
|
|
1814
|
+
const range = getNormalizedRange(durationSeconds, startValue, endValue);
|
|
1815
|
+
const bucketCount = durationSeconds === 0 ? 1 : Math.max(12, Math.min(48, Math.ceil(durationSeconds)));
|
|
1816
|
+
const bucketDurationMs = durationMs === 0 ? 1000 : durationMs / bucketCount;
|
|
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;
|
|
1846
1824
|
}
|
|
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
|
+
};
|
|
1847
1851
|
};
|
|
1848
1852
|
|
|
1849
|
-
const handleEventRowClickDependencies = {
|
|
1850
|
-
loadSelectedEvent: loadSelectedEvent
|
|
1851
|
-
};
|
|
1852
1853
|
const getCurrentEvents$2 = state => {
|
|
1853
1854
|
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1854
1855
|
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1855
1856
|
};
|
|
1856
|
-
const
|
|
1857
|
-
const parsed = Number.parseInt(value, 10);
|
|
1858
|
-
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1859
|
-
return null;
|
|
1860
|
-
}
|
|
1861
|
-
return parsed;
|
|
1862
|
-
};
|
|
1863
|
-
const handleEventRowClick = async (state, value) => {
|
|
1864
|
-
const selectedEventIndex = parseSelectedEventIndex$1(value);
|
|
1865
|
-
if (selectedEventIndex === null) {
|
|
1866
|
-
return state;
|
|
1867
|
-
}
|
|
1857
|
+
const selectEventAtIndex = async (state, selectedEventIndex, dependencies) => {
|
|
1868
1858
|
const currentEvents = getCurrentEvents$2(state);
|
|
1869
1859
|
const selectedEvent = currentEvents[selectedEventIndex];
|
|
1870
1860
|
if (!selectedEvent) {
|
|
@@ -1883,7 +1873,7 @@ const handleEventRowClick = async (state, value) => {
|
|
|
1883
1873
|
selectedEventIndex
|
|
1884
1874
|
};
|
|
1885
1875
|
}
|
|
1886
|
-
const selectedEventDetails = await
|
|
1876
|
+
const selectedEventDetails = await dependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
|
|
1887
1877
|
return {
|
|
1888
1878
|
...state,
|
|
1889
1879
|
selectedEvent: selectedEventDetails ?? selectedEvent,
|
|
@@ -1892,6 +1882,34 @@ const handleEventRowClick = async (state, value) => {
|
|
|
1892
1882
|
};
|
|
1893
1883
|
};
|
|
1894
1884
|
|
|
1885
|
+
const handleEventRowClickDependencies = {
|
|
1886
|
+
loadSelectedEvent: loadSelectedEvent
|
|
1887
|
+
};
|
|
1888
|
+
const isPrimaryButton = button => {
|
|
1889
|
+
return button === 0;
|
|
1890
|
+
};
|
|
1891
|
+
const parseSelectedEventIndex$1 = value => {
|
|
1892
|
+
const parsed = Number.parseInt(value, 10);
|
|
1893
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1894
|
+
return null;
|
|
1895
|
+
}
|
|
1896
|
+
return parsed;
|
|
1897
|
+
};
|
|
1898
|
+
const handleEventRowClick = async (state, value, button) => {
|
|
1899
|
+
if (!isPrimaryButton(button)) {
|
|
1900
|
+
return state;
|
|
1901
|
+
}
|
|
1902
|
+
const selectedEventIndex = parseSelectedEventIndex$1(value);
|
|
1903
|
+
if (selectedEventIndex === null) {
|
|
1904
|
+
return state;
|
|
1905
|
+
}
|
|
1906
|
+
return selectEventAtIndex(state, selectedEventIndex, handleEventRowClickDependencies);
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
const handleHeaderContextMenu = state => {
|
|
1910
|
+
return state;
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1895
1913
|
const getBoolean = value => {
|
|
1896
1914
|
return value === true || value === 'true' || value === 'on' || value === '1';
|
|
1897
1915
|
};
|
|
@@ -2114,7 +2132,15 @@ const handleTimelineDoubleClick = state => {
|
|
|
2114
2132
|
};
|
|
2115
2133
|
|
|
2116
2134
|
const getTimelineEvents = state => {
|
|
2117
|
-
|
|
2135
|
+
const {
|
|
2136
|
+
eventCategoryFilter,
|
|
2137
|
+
events,
|
|
2138
|
+
filterValue,
|
|
2139
|
+
showEventStreamFinishedEvents,
|
|
2140
|
+
showInputEvents,
|
|
2141
|
+
showResponsePartEvents
|
|
2142
|
+
} = state;
|
|
2143
|
+
return getFilteredEvents(events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
2118
2144
|
};
|
|
2119
2145
|
|
|
2120
2146
|
const getTimelineLeft = state => {
|
|
@@ -2545,6 +2571,21 @@ const refresh = async state => {
|
|
|
2545
2571
|
return refreshEvents(state);
|
|
2546
2572
|
};
|
|
2547
2573
|
|
|
2574
|
+
const Button = 1;
|
|
2575
|
+
const Div = 4;
|
|
2576
|
+
const Input = 6;
|
|
2577
|
+
const Span = 8;
|
|
2578
|
+
const Table = 9;
|
|
2579
|
+
const TBody = 10;
|
|
2580
|
+
const Td = 11;
|
|
2581
|
+
const Text = 12;
|
|
2582
|
+
const Th = 13;
|
|
2583
|
+
const THead = 14;
|
|
2584
|
+
const Tr = 15;
|
|
2585
|
+
const Search = 42;
|
|
2586
|
+
const Label = 66;
|
|
2587
|
+
const Reference = 100;
|
|
2588
|
+
|
|
2548
2589
|
const ClientX = 'event.clientX';
|
|
2549
2590
|
const ClientY = 'event.clientY';
|
|
2550
2591
|
const TargetChecked = 'event.target.checked';
|
|
@@ -2910,6 +2951,21 @@ const getCss = state => {
|
|
|
2910
2951
|
contain: content;
|
|
2911
2952
|
}
|
|
2912
2953
|
|
|
2954
|
+
.ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(1) {
|
|
2955
|
+
flex: 1 1 140px;
|
|
2956
|
+
min-width: 0;
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
.ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(2) {
|
|
2960
|
+
flex: 0 0 90px;
|
|
2961
|
+
justify-content: flex-end;
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
.ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(3) {
|
|
2965
|
+
flex: 0 0 96px;
|
|
2966
|
+
justify-content: flex-end;
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2913
2969
|
.ChatDebugViewTableBody {
|
|
2914
2970
|
display: flex;
|
|
2915
2971
|
flex-direction: column;
|
|
@@ -2939,8 +2995,12 @@ const getCss = state => {
|
|
|
2939
2995
|
|
|
2940
2996
|
.ChatDebugViewEventRow {
|
|
2941
2997
|
padding: 2px 8px;
|
|
2942
|
-
|
|
2943
|
-
cursor:
|
|
2998
|
+
background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 92%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 8%);
|
|
2999
|
+
cursor: default;
|
|
3000
|
+
}
|
|
3001
|
+
|
|
3002
|
+
.ChatDebugViewTableBody > .ChatDebugViewEventRow:nth-child(even) {
|
|
3003
|
+
background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 84%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 16%);
|
|
2944
3004
|
}
|
|
2945
3005
|
|
|
2946
3006
|
.ChatDebugViewEventRow:hover {
|
|
@@ -2955,6 +3015,7 @@ const getCss = state => {
|
|
|
2955
3015
|
text-overflow: ellipsis;
|
|
2956
3016
|
white-space: nowrap;
|
|
2957
3017
|
min-width: 0;
|
|
3018
|
+
pointer-events: none;
|
|
2958
3019
|
contain: content;
|
|
2959
3020
|
}
|
|
2960
3021
|
|
|
@@ -3273,21 +3334,6 @@ const renderCss = (oldState, newState) => {
|
|
|
3273
3334
|
return [SetCss, newState.uid, css];
|
|
3274
3335
|
};
|
|
3275
3336
|
|
|
3276
|
-
const Button = 1;
|
|
3277
|
-
const Div = 4;
|
|
3278
|
-
const Input = 6;
|
|
3279
|
-
const Span = 8;
|
|
3280
|
-
const Table = 9;
|
|
3281
|
-
const TBody = 10;
|
|
3282
|
-
const Td = 11;
|
|
3283
|
-
const Text = 12;
|
|
3284
|
-
const Th = 13;
|
|
3285
|
-
const THead = 14;
|
|
3286
|
-
const Tr = 15;
|
|
3287
|
-
const Search = 42;
|
|
3288
|
-
const Label = 66;
|
|
3289
|
-
const Reference = 100;
|
|
3290
|
-
|
|
3291
3337
|
const text = data => {
|
|
3292
3338
|
return {
|
|
3293
3339
|
childCount: 0,
|
|
@@ -3584,14 +3630,87 @@ const diffTree = (oldNodes, newNodes) => {
|
|
|
3584
3630
|
return removeTrailingNavigationPatches(patches);
|
|
3585
3631
|
};
|
|
3586
3632
|
|
|
3633
|
+
const ChatDebugView = 'ChatDebugView';
|
|
3634
|
+
const ChatDebugViewDevtools = 'ChatDebugView--devtools';
|
|
3635
|
+
const ChatDebugViewDetails = 'ChatDebugViewDetails';
|
|
3636
|
+
const ChatDebugViewDetailsBody = 'ChatDebugViewDetailsBody';
|
|
3637
|
+
const ChatDebugViewDetailsClose = 'ChatDebugViewDetailsClose';
|
|
3638
|
+
const ChatDebugViewDetailsPanel = 'ChatDebugViewDetailsPanel';
|
|
3639
|
+
const ChatDebugViewDetailsTab = 'ChatDebugViewDetailsTab';
|
|
3640
|
+
const ChatDebugViewDetailsTabSelected = 'ChatDebugViewDetailsTabSelected';
|
|
3641
|
+
const ChatDebugViewDetailsTabs = 'ChatDebugViewDetailsTabs';
|
|
3642
|
+
const ChatDebugViewDetailsTop = 'ChatDebugViewDetailsTop';
|
|
3643
|
+
const ChatDebugViewDevtoolsMain = 'ChatDebugViewDevtoolsMain';
|
|
3644
|
+
const ChatDebugViewDevtoolsSplit = 'ChatDebugViewDevtoolsSplit';
|
|
3645
|
+
const ChatDebugViewEmpty = 'ChatDebugViewEmpty';
|
|
3646
|
+
const ChatDebugViewError = 'ChatDebugViewError';
|
|
3647
|
+
const ChatDebugViewEvent = 'ChatDebugViewEvent';
|
|
3648
|
+
const ChatDebugViewEventLineContent = 'ChatDebugViewEventLineContent';
|
|
3649
|
+
const ChatDebugViewEventLineNumber = 'ChatDebugViewEventLineNumber';
|
|
3650
|
+
const ChatDebugViewEventRow = 'ChatDebugViewEventRow';
|
|
3651
|
+
const ChatDebugViewEventRowSelected = 'ChatDebugViewEventRowSelected';
|
|
3652
|
+
const ChatDebugViewEvents = 'ChatDebugViewEvents';
|
|
3653
|
+
const ChatDebugViewEventsFullWidth = 'ChatDebugViewEventsFullWidth';
|
|
3654
|
+
const ChatDebugViewFilterInput = 'ChatDebugViewFilterInput';
|
|
3655
|
+
const ChatDebugViewFilterInputDevtools = 'ChatDebugViewFilterInput--devtools';
|
|
3656
|
+
const ChatDebugViewHeaderCell = 'ChatDebugViewHeaderCell';
|
|
3657
|
+
const ChatDebugViewQuickFilterInput = 'ChatDebugViewQuickFilterInput';
|
|
3658
|
+
const ChatDebugViewQuickFilterPill = 'ChatDebugViewQuickFilterPill';
|
|
3659
|
+
const ChatDebugViewQuickFilterPillSelected = 'ChatDebugViewQuickFilterPillSelected';
|
|
3660
|
+
const ChatDebugViewQuickFilters = 'ChatDebugViewQuickFilters';
|
|
3661
|
+
const ChatDebugViewSash = 'ChatDebugViewSash';
|
|
3662
|
+
const ChatDebugViewSashLine = 'ChatDebugViewSashLine';
|
|
3663
|
+
const ChatDebugViewTable = 'ChatDebugViewTable';
|
|
3664
|
+
const ChatDebugViewTableBody = 'ChatDebugViewTableBody';
|
|
3665
|
+
const ChatDebugViewTableHeader = 'ChatDebugViewTableHeader';
|
|
3666
|
+
const ChatDebugViewTableHeaderRow = 'ChatDebugViewTableHeaderRow';
|
|
3667
|
+
const ChatDebugViewTimeline = 'ChatDebugViewTimeline';
|
|
3668
|
+
const ChatDebugViewTimelineBucket = 'ChatDebugViewTimelineBucket';
|
|
3669
|
+
const ChatDebugViewTimelineBucketBar = 'ChatDebugViewTimelineBucketBar';
|
|
3670
|
+
const ChatDebugViewTimelineBucketBarSelected = 'ChatDebugViewTimelineBucketBarSelected';
|
|
3671
|
+
const ChatDebugViewTimelineBucketSelected = 'ChatDebugViewTimelineBucketSelected';
|
|
3672
|
+
const ChatDebugViewTimelineBucketUnit = 'ChatDebugViewTimelineBucketUnit';
|
|
3673
|
+
const ChatDebugViewTimelineBucketUnitEmpty = 'ChatDebugViewTimelineBucketUnitEmpty';
|
|
3674
|
+
const ChatDebugViewTimelineBuckets = 'ChatDebugViewTimelineBuckets';
|
|
3675
|
+
const ChatDebugViewTimelineInteractive = 'ChatDebugViewTimelineInteractive';
|
|
3676
|
+
const ChatDebugViewTimelinePresetInput = 'ChatDebugViewTimelinePresetInput';
|
|
3677
|
+
const ChatDebugViewTimelineSelectionMarker = 'ChatDebugViewTimelineSelectionMarker';
|
|
3678
|
+
const ChatDebugViewTimelineSelectionMarkerEnd = 'ChatDebugViewTimelineSelectionMarkerEnd';
|
|
3679
|
+
const ChatDebugViewTimelineSelectionMarkerStart = 'ChatDebugViewTimelineSelectionMarkerStart';
|
|
3680
|
+
const ChatDebugViewTimelineSelectionOverlay = 'ChatDebugViewTimelineSelectionOverlay';
|
|
3681
|
+
const ChatDebugViewTimelineSelectionRange = 'ChatDebugViewTimelineSelectionRange';
|
|
3682
|
+
const ChatDebugViewTimelineSummary = 'ChatDebugViewTimelineSummary';
|
|
3683
|
+
const ChatDebugViewTimelineTop = 'ChatDebugViewTimelineTop';
|
|
3684
|
+
const ChatDebugViewTiming = 'ChatDebugViewTiming';
|
|
3685
|
+
const ChatDebugViewTimingLabel = 'ChatDebugViewTimingLabel';
|
|
3686
|
+
const ChatDebugViewTimingRow = 'ChatDebugViewTimingRow';
|
|
3687
|
+
const ChatDebugViewTimingValue = 'ChatDebugViewTimingValue';
|
|
3688
|
+
const ChatDebugViewTop = 'ChatDebugViewTop';
|
|
3689
|
+
const ChatDebugViewTopDevtools = 'ChatDebugViewTop--devtools';
|
|
3690
|
+
const ChatDebugViewCell = 'ChatDebugViewCell';
|
|
3691
|
+
const ChatDebugViewCellDuration = 'ChatDebugViewCellDuration';
|
|
3692
|
+
const ChatDebugViewCellStatus = 'ChatDebugViewCellStatus';
|
|
3693
|
+
const ChatDebugViewCellStatusError = 'ChatDebugViewCellStatusError';
|
|
3694
|
+
const ChatDebugViewCellType = 'ChatDebugViewCellType';
|
|
3695
|
+
const InputBox = 'InputBox';
|
|
3696
|
+
const Row = 'row';
|
|
3697
|
+
const TokenBoolean = 'TokenBoolean';
|
|
3698
|
+
const TokenKey = 'TokenKey';
|
|
3699
|
+
const TokenNumeric = 'TokenNumeric';
|
|
3700
|
+
const TokenString = 'TokenString';
|
|
3701
|
+
const TokenText = 'TokenText';
|
|
3702
|
+
const joinClassNames = (...classNames) => {
|
|
3703
|
+
return classNames.filter(Boolean).join(' ');
|
|
3704
|
+
};
|
|
3705
|
+
|
|
3587
3706
|
const getDebugErrorDom = errorMessage => {
|
|
3588
3707
|
return [{
|
|
3589
3708
|
childCount: 1,
|
|
3590
|
-
className:
|
|
3709
|
+
className: ChatDebugView,
|
|
3591
3710
|
type: Div
|
|
3592
3711
|
}, {
|
|
3593
3712
|
childCount: 1,
|
|
3594
|
-
className:
|
|
3713
|
+
className: ChatDebugViewError,
|
|
3595
3714
|
type: Div
|
|
3596
3715
|
}, text(errorMessage)];
|
|
3597
3716
|
};
|
|
@@ -3600,25 +3719,29 @@ const HandleInput = 4;
|
|
|
3600
3719
|
const HandleFilterInput = 5;
|
|
3601
3720
|
const HandleSimpleInput = 6;
|
|
3602
3721
|
const HandleEventRowClick = 7;
|
|
3603
|
-
const
|
|
3604
|
-
const
|
|
3605
|
-
const
|
|
3606
|
-
const
|
|
3607
|
-
const
|
|
3608
|
-
const
|
|
3609
|
-
const
|
|
3610
|
-
const
|
|
3722
|
+
const HandleHeaderContextMenu = 8;
|
|
3723
|
+
const HandleSashPointerDown = 9;
|
|
3724
|
+
const HandleSashPointerMove = 10;
|
|
3725
|
+
const HandleSashPointerUp = 11;
|
|
3726
|
+
const HandleTableBodyContextMenu = 12;
|
|
3727
|
+
const HandleDetailsContextMenu = 13;
|
|
3728
|
+
const HandleTimelinePointerDown = 14;
|
|
3729
|
+
const HandleTimelinePointerMove = 15;
|
|
3730
|
+
const HandleTimelinePointerUp = 16;
|
|
3731
|
+
const HandleTimelineDoubleClick = 17;
|
|
3732
|
+
const HandleTableKeyDown = 18;
|
|
3611
3733
|
|
|
3612
3734
|
const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
|
|
3613
3735
|
if (useDevtoolsLayout) {
|
|
3614
3736
|
return [{
|
|
3615
3737
|
childCount: 1 + (quickFilterNodes.length > 0 ? 1 : 0),
|
|
3616
|
-
className:
|
|
3738
|
+
className: joinClassNames(ChatDebugViewTop, ChatDebugViewTopDevtools),
|
|
3739
|
+
onContextMenu: HandleHeaderContextMenu,
|
|
3617
3740
|
type: Search
|
|
3618
3741
|
}, {
|
|
3619
3742
|
autocomplete: 'off',
|
|
3620
3743
|
childCount: 0,
|
|
3621
|
-
className:
|
|
3744
|
+
className: joinClassNames(InputBox, ChatDebugViewFilterInput, ChatDebugViewFilterInputDevtools),
|
|
3622
3745
|
inputType: 'search',
|
|
3623
3746
|
name: Filter,
|
|
3624
3747
|
onInput: HandleFilterInput,
|
|
@@ -3629,12 +3752,13 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
|
|
|
3629
3752
|
}
|
|
3630
3753
|
return [{
|
|
3631
3754
|
childCount: 1,
|
|
3632
|
-
className:
|
|
3755
|
+
className: ChatDebugViewTop,
|
|
3756
|
+
onContextMenu: HandleHeaderContextMenu,
|
|
3633
3757
|
type: Search
|
|
3634
3758
|
}, {
|
|
3635
3759
|
autocomplete: 'off',
|
|
3636
3760
|
childCount: 0,
|
|
3637
|
-
className:
|
|
3761
|
+
className: joinClassNames(InputBox, ChatDebugViewFilterInput),
|
|
3638
3762
|
inputType: 'search',
|
|
3639
3763
|
name: Filter,
|
|
3640
3764
|
onInput: HandleFilterInput,
|
|
@@ -3697,22 +3821,22 @@ const getStartText = event => {
|
|
|
3697
3821
|
const getTimingRowDom = (label, value) => {
|
|
3698
3822
|
return [{
|
|
3699
3823
|
childCount: 2,
|
|
3700
|
-
className:
|
|
3824
|
+
className: ChatDebugViewTimingRow,
|
|
3701
3825
|
type: Div
|
|
3702
3826
|
}, {
|
|
3703
3827
|
childCount: 1,
|
|
3704
|
-
className:
|
|
3828
|
+
className: ChatDebugViewTimingLabel,
|
|
3705
3829
|
type: Span
|
|
3706
3830
|
}, text(label), {
|
|
3707
3831
|
childCount: 1,
|
|
3708
|
-
className:
|
|
3832
|
+
className: ChatDebugViewTimingValue,
|
|
3709
3833
|
type: Span
|
|
3710
3834
|
}, text(value)];
|
|
3711
3835
|
};
|
|
3712
3836
|
const getTimingDetailsDom = event => {
|
|
3713
3837
|
return [{
|
|
3714
3838
|
childCount: 3,
|
|
3715
|
-
className:
|
|
3839
|
+
className: ChatDebugViewTiming,
|
|
3716
3840
|
type: Div
|
|
3717
3841
|
}, ...getTimingRowDom('Started', getStartText(event)), ...getTimingRowDom('Ended', getEndText(event)), ...getTimingRowDom('Duration', getDurationText(event))];
|
|
3718
3842
|
};
|
|
@@ -3730,7 +3854,7 @@ const getTabNodes = selectedDetailTab => {
|
|
|
3730
3854
|
'aria-controls': getPanelId(detailTab),
|
|
3731
3855
|
'aria-selected': isSelected,
|
|
3732
3856
|
childCount: 1,
|
|
3733
|
-
className: isSelected
|
|
3857
|
+
className: joinClassNames(ChatDebugViewDetailsTab, isSelected && ChatDebugViewDetailsTabSelected),
|
|
3734
3858
|
id: getTabId(detailTab),
|
|
3735
3859
|
name: DetailTab,
|
|
3736
3860
|
onChange: HandleSimpleInput,
|
|
@@ -3742,23 +3866,23 @@ const getTabNodes = selectedDetailTab => {
|
|
|
3742
3866
|
}, text(getDetailTabLabel(detailTab))];
|
|
3743
3867
|
});
|
|
3744
3868
|
};
|
|
3745
|
-
const getDetailsDom = (
|
|
3746
|
-
if (
|
|
3869
|
+
const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes, selectedEvent = null, selectedDetailTab = Response) => {
|
|
3870
|
+
if (previewEventNodes.length === 0 && responseEventNodes.length === 0) {
|
|
3747
3871
|
return [];
|
|
3748
3872
|
}
|
|
3749
|
-
const contentNodes = selectedDetailTab === Timing && selectedEvent ? getTimingDetailsDom(selectedEvent) :
|
|
3873
|
+
const contentNodes = selectedDetailTab === Timing && selectedEvent ? getTimingDetailsDom(selectedEvent) : selectedDetailTab === Preview ? previewEventNodes : responseEventNodes;
|
|
3750
3874
|
return [{
|
|
3751
3875
|
childCount: 2,
|
|
3752
|
-
className:
|
|
3876
|
+
className: ChatDebugViewDetails,
|
|
3753
3877
|
type: Div
|
|
3754
3878
|
}, {
|
|
3755
3879
|
childCount: 2,
|
|
3756
|
-
className:
|
|
3880
|
+
className: ChatDebugViewDetailsTop,
|
|
3757
3881
|
type: Div
|
|
3758
3882
|
}, {
|
|
3759
3883
|
'aria-label': 'Close details',
|
|
3760
3884
|
childCount: 0,
|
|
3761
|
-
className:
|
|
3885
|
+
className: ChatDebugViewDetailsClose,
|
|
3762
3886
|
name: CloseDetails,
|
|
3763
3887
|
onChange: HandleSimpleInput,
|
|
3764
3888
|
onClick: HandleSimpleInput,
|
|
@@ -3767,19 +3891,20 @@ const getDetailsDom = (selectedEventNodes, selectedEvent = null, selectedDetailT
|
|
|
3767
3891
|
}, {
|
|
3768
3892
|
'aria-label': 'Detail sections',
|
|
3769
3893
|
childCount: detailTabs.length,
|
|
3770
|
-
className:
|
|
3894
|
+
className: ChatDebugViewDetailsTabs,
|
|
3771
3895
|
role: 'tablist',
|
|
3772
3896
|
type: Div
|
|
3773
3897
|
}, ...getTabNodes(selectedDetailTab), {
|
|
3774
3898
|
childCount: 1,
|
|
3775
|
-
className:
|
|
3899
|
+
className: ChatDebugViewDetailsBody,
|
|
3776
3900
|
role: 'document',
|
|
3777
3901
|
type: Div
|
|
3778
3902
|
}, {
|
|
3779
3903
|
'aria-labelledby': getTabId(selectedDetailTab),
|
|
3780
3904
|
childCount: 1,
|
|
3781
|
-
className:
|
|
3905
|
+
className: ChatDebugViewDetailsPanel,
|
|
3782
3906
|
id: getPanelId(selectedDetailTab),
|
|
3907
|
+
onContextMenu: HandleDetailsContextMenu,
|
|
3783
3908
|
role: 'tabpanel',
|
|
3784
3909
|
type: Div
|
|
3785
3910
|
}, ...contentNodes];
|
|
@@ -3818,6 +3943,19 @@ const getEventTypeLabel = event => {
|
|
|
3818
3943
|
return `${event.type}, ${toolName}`;
|
|
3819
3944
|
};
|
|
3820
3945
|
|
|
3946
|
+
const isRecord = value => {
|
|
3947
|
+
return typeof value === 'object' && value !== null;
|
|
3948
|
+
};
|
|
3949
|
+
const isErrorStatusCode = value => {
|
|
3950
|
+
if (typeof value === 'number') {
|
|
3951
|
+
return value >= 400;
|
|
3952
|
+
}
|
|
3953
|
+
if (typeof value === 'string') {
|
|
3954
|
+
const parsedStatus = Number(value);
|
|
3955
|
+
return Number.isFinite(parsedStatus) && parsedStatus >= 400;
|
|
3956
|
+
}
|
|
3957
|
+
return false;
|
|
3958
|
+
};
|
|
3821
3959
|
const hasErrorStatus = event => {
|
|
3822
3960
|
if (event.type === 'error') {
|
|
3823
3961
|
return true;
|
|
@@ -3828,12 +3966,17 @@ const hasErrorStatus = event => {
|
|
|
3828
3966
|
const {
|
|
3829
3967
|
status
|
|
3830
3968
|
} = event;
|
|
3831
|
-
if (
|
|
3969
|
+
if (isErrorStatusCode(status)) {
|
|
3832
3970
|
return true;
|
|
3833
3971
|
}
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3972
|
+
const {
|
|
3973
|
+
result
|
|
3974
|
+
} = event;
|
|
3975
|
+
if (isRecord(result)) {
|
|
3976
|
+
if (isErrorStatusCode(result.status)) {
|
|
3977
|
+
return true;
|
|
3978
|
+
}
|
|
3979
|
+
if (typeof result.error === 'string' || typeof result.errorMessage === 'string' || typeof result.exception === 'string') {
|
|
3837
3980
|
return true;
|
|
3838
3981
|
}
|
|
3839
3982
|
}
|
|
@@ -3851,23 +3994,20 @@ const getDevtoolsRows = (events, selectedEventIndex) => {
|
|
|
3851
3994
|
const rowIndex = String(i);
|
|
3852
3995
|
return [{
|
|
3853
3996
|
childCount: 3,
|
|
3854
|
-
className:
|
|
3997
|
+
className: joinClassNames(ChatDebugViewEventRow, isSelected && ChatDebugViewEventRowSelected),
|
|
3855
3998
|
'data-index': rowIndex,
|
|
3856
3999
|
type: Tr
|
|
3857
4000
|
}, {
|
|
3858
4001
|
childCount: 1,
|
|
3859
|
-
className:
|
|
3860
|
-
'data-index': rowIndex,
|
|
4002
|
+
className: joinClassNames(ChatDebugViewCell, ChatDebugViewCellType),
|
|
3861
4003
|
type: Td
|
|
3862
4004
|
}, text(getEventTypeLabel(event)), {
|
|
3863
4005
|
childCount: 1,
|
|
3864
|
-
className:
|
|
3865
|
-
'data-index': rowIndex,
|
|
4006
|
+
className: joinClassNames(ChatDebugViewCell, ChatDebugViewCellDuration),
|
|
3866
4007
|
type: Td
|
|
3867
4008
|
}, text(getDurationText(event)), {
|
|
3868
4009
|
childCount: 1,
|
|
3869
|
-
className:
|
|
3870
|
-
'data-index': rowIndex,
|
|
4010
|
+
className: joinClassNames(ChatDebugViewCell, ChatDebugViewCellStatus, isErrorStatus && ChatDebugViewCellStatusError),
|
|
3871
4011
|
type: Td
|
|
3872
4012
|
}, text(getStatusText(event))];
|
|
3873
4013
|
});
|
|
@@ -3876,7 +4016,7 @@ const getDevtoolsRows = (events, selectedEventIndex) => {
|
|
|
3876
4016
|
const getEmptyStateDom = emptyMessage => {
|
|
3877
4017
|
return [{
|
|
3878
4018
|
childCount: 1,
|
|
3879
|
-
className:
|
|
4019
|
+
className: ChatDebugViewEmpty,
|
|
3880
4020
|
type: Div
|
|
3881
4021
|
}, text(emptyMessage)];
|
|
3882
4022
|
};
|
|
@@ -3926,32 +4066,32 @@ const getTokenSegments = json => {
|
|
|
3926
4066
|
while (lookAheadIndex < json.length && whitespaceRegex.test(json[lookAheadIndex])) {
|
|
3927
4067
|
lookAheadIndex++;
|
|
3928
4068
|
}
|
|
3929
|
-
const className = json[lookAheadIndex] === ':' ?
|
|
4069
|
+
const className = json[lookAheadIndex] === ':' ? TokenKey : TokenString;
|
|
3930
4070
|
segments = pushToken(segments, className, tokenValue);
|
|
3931
4071
|
continue;
|
|
3932
4072
|
}
|
|
3933
4073
|
const numberMatch = numberRegex.exec(json.slice(i));
|
|
3934
4074
|
if (numberMatch) {
|
|
3935
|
-
segments = pushToken(segments,
|
|
4075
|
+
segments = pushToken(segments, TokenNumeric, numberMatch[0]);
|
|
3936
4076
|
i += numberMatch[0].length;
|
|
3937
4077
|
continue;
|
|
3938
4078
|
}
|
|
3939
4079
|
if (json.startsWith('true', i)) {
|
|
3940
|
-
segments = pushToken(segments,
|
|
4080
|
+
segments = pushToken(segments, TokenBoolean, 'true');
|
|
3941
4081
|
i += 4;
|
|
3942
4082
|
continue;
|
|
3943
4083
|
}
|
|
3944
4084
|
if (json.startsWith('false', i)) {
|
|
3945
|
-
segments = pushToken(segments,
|
|
4085
|
+
segments = pushToken(segments, TokenBoolean, 'false');
|
|
3946
4086
|
i += 5;
|
|
3947
4087
|
continue;
|
|
3948
4088
|
}
|
|
3949
4089
|
if (json.startsWith('null', i)) {
|
|
3950
|
-
segments = pushToken(segments,
|
|
4090
|
+
segments = pushToken(segments, TokenBoolean, 'null');
|
|
3951
4091
|
i += 4;
|
|
3952
4092
|
continue;
|
|
3953
4093
|
}
|
|
3954
|
-
segments = pushToken(segments,
|
|
4094
|
+
segments = pushToken(segments, TokenText, character);
|
|
3955
4095
|
i++;
|
|
3956
4096
|
}
|
|
3957
4097
|
return segments;
|
|
@@ -3961,7 +4101,7 @@ const getJsonLines = value => {
|
|
|
3961
4101
|
const json = JSON.stringify(value, null, 2);
|
|
3962
4102
|
if (!json) {
|
|
3963
4103
|
return [[{
|
|
3964
|
-
className:
|
|
4104
|
+
className: TokenText,
|
|
3965
4105
|
value: String(json)
|
|
3966
4106
|
}]];
|
|
3967
4107
|
}
|
|
@@ -4001,50 +4141,99 @@ const getLineNodes = lines => {
|
|
|
4001
4141
|
const lineContentNodes = getLineContentNodes(line);
|
|
4002
4142
|
return [{
|
|
4003
4143
|
childCount: 2,
|
|
4004
|
-
className:
|
|
4144
|
+
className: Row,
|
|
4005
4145
|
type: Div
|
|
4006
4146
|
}, {
|
|
4007
4147
|
childCount: 1,
|
|
4008
|
-
className:
|
|
4148
|
+
className: ChatDebugViewEventLineNumber,
|
|
4009
4149
|
type: Span
|
|
4010
4150
|
}, text(String(index + 1)), {
|
|
4011
4151
|
childCount: lineContentNodes.length / 2,
|
|
4012
|
-
className:
|
|
4152
|
+
className: ChatDebugViewEventLineContent,
|
|
4013
4153
|
type: Span
|
|
4014
4154
|
}, ...lineContentNodes];
|
|
4015
4155
|
});
|
|
4016
4156
|
};
|
|
4017
|
-
const
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4157
|
+
const isChatViewEvent = value => {
|
|
4158
|
+
return typeof value === 'object' && value !== null && typeof value.type === 'string';
|
|
4159
|
+
};
|
|
4160
|
+
const getEventNode = value => {
|
|
4161
|
+
const renderedValue = isChatViewEvent(value) ? {
|
|
4162
|
+
...value,
|
|
4163
|
+
type: getEventTypeLabel(value)
|
|
4164
|
+
} : value;
|
|
4165
|
+
const lines = getJsonLines(renderedValue);
|
|
4023
4166
|
const lineNodes = getLineNodes(lines);
|
|
4024
4167
|
return [{
|
|
4025
4168
|
childCount: lines.length,
|
|
4026
|
-
className:
|
|
4169
|
+
className: ChatDebugViewEvent,
|
|
4027
4170
|
type: Div
|
|
4028
4171
|
}, ...lineNodes];
|
|
4029
4172
|
};
|
|
4030
4173
|
|
|
4031
4174
|
const getEventsClassName = hasSelectedEvent => {
|
|
4032
|
-
const widthClassName =
|
|
4175
|
+
const widthClassName = joinClassNames(ChatDebugViewEvents, !hasSelectedEvent && ChatDebugViewEventsFullWidth);
|
|
4033
4176
|
return widthClassName;
|
|
4034
4177
|
};
|
|
4035
4178
|
|
|
4179
|
+
const hasOwn = (event, key) => {
|
|
4180
|
+
return Object.hasOwn(event, key);
|
|
4181
|
+
};
|
|
4182
|
+
const isChatMessageUpdatedEvent = event => {
|
|
4183
|
+
return event.type === 'chat-message-updated';
|
|
4184
|
+
};
|
|
4185
|
+
const getPreviewName = event => {
|
|
4186
|
+
if (typeof event.name === 'string' && event.name) {
|
|
4187
|
+
return event.name;
|
|
4188
|
+
}
|
|
4189
|
+
if (typeof event.toolName === 'string' && event.toolName) {
|
|
4190
|
+
return event.toolName;
|
|
4191
|
+
}
|
|
4192
|
+
return undefined;
|
|
4193
|
+
};
|
|
4194
|
+
const shouldIncludeArguments = (event, name) => {
|
|
4195
|
+
if (!hasOwn(event, 'arguments')) {
|
|
4196
|
+
return false;
|
|
4197
|
+
}
|
|
4198
|
+
if (name === 'getWorkspaceUri') {
|
|
4199
|
+
return false;
|
|
4200
|
+
}
|
|
4201
|
+
return true;
|
|
4202
|
+
};
|
|
4203
|
+
const getPreviewEvent = event => {
|
|
4204
|
+
if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
|
|
4205
|
+
return event.text;
|
|
4206
|
+
}
|
|
4207
|
+
const name = getPreviewName(event);
|
|
4208
|
+
const previewEvent = {
|
|
4209
|
+
...(name === undefined ? {} : {
|
|
4210
|
+
name
|
|
4211
|
+
}),
|
|
4212
|
+
...(shouldIncludeArguments(event, name) ? {
|
|
4213
|
+
arguments: event.arguments
|
|
4214
|
+
} : {}),
|
|
4215
|
+
...(hasOwn(event, 'result') ? {
|
|
4216
|
+
result: event.result
|
|
4217
|
+
} : {})
|
|
4218
|
+
};
|
|
4219
|
+
if (Object.keys(previewEvent).length > 0) {
|
|
4220
|
+
return previewEvent;
|
|
4221
|
+
}
|
|
4222
|
+
return event;
|
|
4223
|
+
};
|
|
4224
|
+
|
|
4036
4225
|
const getSashNodesDom = hasSelectedEvent => {
|
|
4037
4226
|
if (!hasSelectedEvent) {
|
|
4038
4227
|
return [];
|
|
4039
4228
|
}
|
|
4040
4229
|
return [{
|
|
4041
4230
|
childCount: 1,
|
|
4042
|
-
className:
|
|
4231
|
+
className: ChatDebugViewSash,
|
|
4043
4232
|
onPointerDown: HandleSashPointerDown,
|
|
4044
4233
|
type: Div
|
|
4045
4234
|
}, {
|
|
4046
4235
|
childCount: 0,
|
|
4047
|
-
className:
|
|
4236
|
+
className: ChatDebugViewSashLine,
|
|
4048
4237
|
type: Div
|
|
4049
4238
|
}];
|
|
4050
4239
|
};
|
|
@@ -4052,7 +4241,7 @@ const getSashNodesDom = hasSelectedEvent => {
|
|
|
4052
4241
|
const getTableBodyDom = (rowNodes, eventCount) => {
|
|
4053
4242
|
return [{
|
|
4054
4243
|
childCount: eventCount === 0 ? 1 : eventCount,
|
|
4055
|
-
className:
|
|
4244
|
+
className: ChatDebugViewTableBody,
|
|
4056
4245
|
onContextMenu: HandleTableBodyContextMenu,
|
|
4057
4246
|
onPointerDown: HandleEventRowClick,
|
|
4058
4247
|
type: TBody
|
|
@@ -4062,25 +4251,25 @@ const getTableBodyDom = (rowNodes, eventCount) => {
|
|
|
4062
4251
|
const getTableHeaderDom = () => {
|
|
4063
4252
|
return [{
|
|
4064
4253
|
childCount: 1,
|
|
4065
|
-
className:
|
|
4254
|
+
className: ChatDebugViewTableHeader,
|
|
4066
4255
|
type: THead
|
|
4067
4256
|
}, {
|
|
4068
4257
|
childCount: 3,
|
|
4069
|
-
className:
|
|
4258
|
+
className: ChatDebugViewTableHeaderRow,
|
|
4070
4259
|
type: Tr
|
|
4071
4260
|
}, {
|
|
4072
4261
|
childCount: 1,
|
|
4073
|
-
className:
|
|
4262
|
+
className: ChatDebugViewHeaderCell,
|
|
4074
4263
|
scope: 'col',
|
|
4075
4264
|
type: Th
|
|
4076
4265
|
}, text('Type'), {
|
|
4077
4266
|
childCount: 1,
|
|
4078
|
-
className:
|
|
4267
|
+
className: ChatDebugViewHeaderCell,
|
|
4079
4268
|
scope: 'col',
|
|
4080
4269
|
type: Th
|
|
4081
4270
|
}, text('Duration'), {
|
|
4082
4271
|
childCount: 1,
|
|
4083
|
-
className:
|
|
4272
|
+
className: ChatDebugViewHeaderCell,
|
|
4084
4273
|
scope: 'col',
|
|
4085
4274
|
type: Th
|
|
4086
4275
|
}, text('Status')];
|
|
@@ -4089,16 +4278,20 @@ const getTableHeaderDom = () => {
|
|
|
4089
4278
|
const getTableDom = (rowNodes, eventCount) => {
|
|
4090
4279
|
return [{
|
|
4091
4280
|
childCount: 2,
|
|
4092
|
-
className:
|
|
4281
|
+
className: ChatDebugViewTable,
|
|
4093
4282
|
type: Table
|
|
4094
4283
|
}, ...getTableHeaderDom(), ...getTableBodyDom(rowNodes, eventCount)];
|
|
4095
4284
|
};
|
|
4096
4285
|
|
|
4286
|
+
const formatPercent = value => {
|
|
4287
|
+
return `${Number(value.toFixed(3))}%`;
|
|
4288
|
+
};
|
|
4289
|
+
|
|
4097
4290
|
const getBucketUnitDom = unitCount => {
|
|
4098
4291
|
if (unitCount === 0) {
|
|
4099
4292
|
return [{
|
|
4100
4293
|
childCount: 0,
|
|
4101
|
-
className:
|
|
4294
|
+
className: joinClassNames(ChatDebugViewTimelineBucketUnit, ChatDebugViewTimelineBucketUnitEmpty),
|
|
4102
4295
|
type: Div
|
|
4103
4296
|
}];
|
|
4104
4297
|
}
|
|
@@ -4106,7 +4299,7 @@ const getBucketUnitDom = unitCount => {
|
|
|
4106
4299
|
length: unitCount
|
|
4107
4300
|
}).fill({
|
|
4108
4301
|
childCount: 0,
|
|
4109
|
-
className:
|
|
4302
|
+
className: ChatDebugViewTimelineBucketUnit,
|
|
4110
4303
|
type: Div
|
|
4111
4304
|
});
|
|
4112
4305
|
};
|
|
@@ -4115,12 +4308,12 @@ const getBucketDom = bucket => {
|
|
|
4115
4308
|
const presetValue = `${formatTimelinePresetValue(bucket.startSeconds)}:${formatTimelinePresetValue(bucket.endSeconds)}`;
|
|
4116
4309
|
return [{
|
|
4117
4310
|
childCount: 2,
|
|
4118
|
-
className:
|
|
4311
|
+
className: joinClassNames(ChatDebugViewTimelineBucket, bucket.isSelected && ChatDebugViewTimelineBucketSelected),
|
|
4119
4312
|
type: Label
|
|
4120
4313
|
}, {
|
|
4121
4314
|
checked: false,
|
|
4122
4315
|
childCount: 0,
|
|
4123
|
-
className:
|
|
4316
|
+
className: ChatDebugViewTimelinePresetInput,
|
|
4124
4317
|
inputType: 'radio',
|
|
4125
4318
|
name: TimelineRangePreset,
|
|
4126
4319
|
onChange: HandleSimpleInput,
|
|
@@ -4128,11 +4321,24 @@ const getBucketDom = bucket => {
|
|
|
4128
4321
|
value: presetValue
|
|
4129
4322
|
}, {
|
|
4130
4323
|
childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
|
|
4131
|
-
className:
|
|
4324
|
+
className: joinClassNames(ChatDebugViewTimelineBucketBar, bucket.isSelected && ChatDebugViewTimelineBucketBarSelected),
|
|
4132
4325
|
type: Div
|
|
4133
4326
|
}, ...getBucketUnitDom(bucket.unitCount)];
|
|
4134
4327
|
};
|
|
4135
4328
|
|
|
4329
|
+
const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
|
|
4330
|
+
if (!timelineSelectionActive) {
|
|
4331
|
+
return {
|
|
4332
|
+
endSeconds: timelineEndSeconds,
|
|
4333
|
+
startSeconds: timelineStartSeconds
|
|
4334
|
+
};
|
|
4335
|
+
}
|
|
4336
|
+
return {
|
|
4337
|
+
endSeconds: timelineSelectionFocusSeconds,
|
|
4338
|
+
startSeconds: timelineSelectionAnchorSeconds
|
|
4339
|
+
};
|
|
4340
|
+
};
|
|
4341
|
+
|
|
4136
4342
|
const formatTimelineSeconds = value => {
|
|
4137
4343
|
if (Number.isInteger(value)) {
|
|
4138
4344
|
return `${value}s`;
|
|
@@ -4148,21 +4354,6 @@ const getTimelineSummary = (timelineEvents, timelineStartSeconds, timelineEndSec
|
|
|
4148
4354
|
return `Window 0s-${formatTimelineSeconds(timelineInfo.durationSeconds)} of ${formatTimelineSeconds(timelineInfo.durationSeconds)}`;
|
|
4149
4355
|
};
|
|
4150
4356
|
|
|
4151
|
-
const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
|
|
4152
|
-
if (!timelineSelectionActive) {
|
|
4153
|
-
return {
|
|
4154
|
-
endSeconds: timelineEndSeconds,
|
|
4155
|
-
startSeconds: timelineStartSeconds
|
|
4156
|
-
};
|
|
4157
|
-
}
|
|
4158
|
-
return {
|
|
4159
|
-
endSeconds: timelineSelectionFocusSeconds,
|
|
4160
|
-
startSeconds: timelineSelectionAnchorSeconds
|
|
4161
|
-
};
|
|
4162
|
-
};
|
|
4163
|
-
const formatPercent = value => {
|
|
4164
|
-
return `${Number(value.toFixed(3))}%`;
|
|
4165
|
-
};
|
|
4166
4357
|
const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '') => {
|
|
4167
4358
|
const effectiveRange = getEffectiveTimelineRange(timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
4168
4359
|
const timelineInfo = getTimelineInfo(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds);
|
|
@@ -4171,45 +4362,45 @@ const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSecon
|
|
|
4171
4362
|
}
|
|
4172
4363
|
const selectionNodes = timelineInfo.hasSelection && timelineInfo.selectionStartPercent !== null && timelineInfo.selectionEndPercent !== null ? [{
|
|
4173
4364
|
childCount: 0,
|
|
4174
|
-
className:
|
|
4365
|
+
className: ChatDebugViewTimelineSelectionRange,
|
|
4175
4366
|
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};width:${formatPercent(timelineInfo.selectionEndPercent - timelineInfo.selectionStartPercent)};`,
|
|
4176
4367
|
type: Div
|
|
4177
4368
|
}, {
|
|
4178
4369
|
childCount: 0,
|
|
4179
|
-
className:
|
|
4370
|
+
className: joinClassNames(ChatDebugViewTimelineSelectionMarker, ChatDebugViewTimelineSelectionMarkerStart),
|
|
4180
4371
|
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};`,
|
|
4181
4372
|
type: Div
|
|
4182
4373
|
}, {
|
|
4183
4374
|
childCount: 0,
|
|
4184
|
-
className:
|
|
4375
|
+
className: joinClassNames(ChatDebugViewTimelineSelectionMarker, ChatDebugViewTimelineSelectionMarkerEnd),
|
|
4185
4376
|
style: `left:${formatPercent(timelineInfo.selectionEndPercent)};`,
|
|
4186
4377
|
type: Div
|
|
4187
4378
|
}] : [];
|
|
4188
4379
|
return [{
|
|
4189
4380
|
childCount: 2,
|
|
4190
|
-
className:
|
|
4381
|
+
className: ChatDebugViewTimeline,
|
|
4191
4382
|
type: Div
|
|
4192
4383
|
}, {
|
|
4193
4384
|
childCount: 1,
|
|
4194
|
-
className:
|
|
4385
|
+
className: ChatDebugViewTimelineTop,
|
|
4195
4386
|
type: Div
|
|
4196
4387
|
}, {
|
|
4197
4388
|
childCount: 1,
|
|
4198
|
-
className:
|
|
4389
|
+
className: ChatDebugViewTimelineSummary,
|
|
4199
4390
|
type: Div
|
|
4200
4391
|
}, text(getTimelineSummary(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds)), {
|
|
4201
4392
|
childCount: 2,
|
|
4202
|
-
className:
|
|
4393
|
+
className: ChatDebugViewTimelineInteractive,
|
|
4203
4394
|
onDoubleClick: HandleTimelineDoubleClick,
|
|
4204
4395
|
onPointerDown: HandleTimelinePointerDown,
|
|
4205
4396
|
type: Div
|
|
4206
4397
|
}, {
|
|
4207
4398
|
childCount: timelineInfo.buckets.length,
|
|
4208
|
-
className:
|
|
4399
|
+
className: ChatDebugViewTimelineBuckets,
|
|
4209
4400
|
type: Div
|
|
4210
4401
|
}, ...timelineInfo.buckets.flatMap(getBucketDom), {
|
|
4211
4402
|
childCount: selectionNodes.length,
|
|
4212
|
-
className:
|
|
4403
|
+
className: ChatDebugViewTimelineSelectionOverlay,
|
|
4213
4404
|
type: Div
|
|
4214
4405
|
}, ...selectionNodes];
|
|
4215
4406
|
};
|
|
@@ -4217,25 +4408,29 @@ const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSecon
|
|
|
4217
4408
|
const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage = 'No events have been found', timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', selectedDetailTab = Response) => {
|
|
4218
4409
|
const rowNodes = getDevtoolsRows(events, selectedEventIndex);
|
|
4219
4410
|
const timelineNodes = getTimelineNodes(timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
4220
|
-
const
|
|
4221
|
-
const
|
|
4411
|
+
const previewEventNodes = selectedEvent ? getEventNode(getPreviewEvent(selectedEvent)) : [];
|
|
4412
|
+
const responseEventNodes = selectedEvent ? getEventNode(selectedEvent) : [];
|
|
4413
|
+
const hasSelectedEvent = responseEventNodes.length > 0;
|
|
4222
4414
|
const tableNodes = events.length === 0 ? getEmptyStateDom(emptyMessage) : getTableDom(rowNodes, events.length);
|
|
4223
4415
|
const eventsClassName = getEventsClassName(hasSelectedEvent);
|
|
4224
|
-
const detailsNodes = getDetailsDom(
|
|
4416
|
+
const detailsNodes = getDetailsDom(previewEventNodes, responseEventNodes, selectedEvent, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response);
|
|
4225
4417
|
const sashNodes = getSashNodesDom(hasSelectedEvent);
|
|
4226
4418
|
const splitChildCount = hasSelectedEvent ? 3 : 1;
|
|
4227
4419
|
const mainChildCount = 1 + (timelineNodes.length > 0 ? 1 : 0);
|
|
4228
4420
|
return [{
|
|
4229
4421
|
childCount: mainChildCount,
|
|
4230
|
-
className:
|
|
4422
|
+
className: ChatDebugViewDevtoolsMain,
|
|
4231
4423
|
type: Div
|
|
4232
4424
|
}, ...timelineNodes, {
|
|
4233
4425
|
childCount: splitChildCount,
|
|
4234
|
-
className:
|
|
4426
|
+
className: ChatDebugViewDevtoolsSplit,
|
|
4235
4427
|
type: Div
|
|
4236
4428
|
}, {
|
|
4237
4429
|
childCount: 1,
|
|
4238
4430
|
className: eventsClassName,
|
|
4431
|
+
onKeyDown: HandleTableKeyDown,
|
|
4432
|
+
role: 'application',
|
|
4433
|
+
tabIndex: 0,
|
|
4239
4434
|
type: Div
|
|
4240
4435
|
}, ...tableNodes, ...sashNodes, ...detailsNodes];
|
|
4241
4436
|
};
|
|
@@ -4243,11 +4438,13 @@ const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvent
|
|
|
4243
4438
|
const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
4244
4439
|
return [{
|
|
4245
4440
|
childCount: eventNodes.length === 0 ? 1 : eventNodes.length,
|
|
4246
|
-
className:
|
|
4441
|
+
className: ChatDebugViewEvents,
|
|
4442
|
+
role: 'application',
|
|
4443
|
+
tabIndex: 0,
|
|
4247
4444
|
type: Div
|
|
4248
4445
|
}, ...(eventNodes.length === 0 ? [{
|
|
4249
4446
|
childCount: 1,
|
|
4250
|
-
className: errorMessage ?
|
|
4447
|
+
className: errorMessage ? ChatDebugViewError : ChatDebugViewEmpty,
|
|
4251
4448
|
type: Div
|
|
4252
4449
|
}, text(errorMessage || emptyMessage)] : eventNodes)];
|
|
4253
4450
|
};
|
|
@@ -4255,18 +4452,18 @@ const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
|
4255
4452
|
const getQuickFilterNodes = (eventCategoryFilter, eventCategoryFilterOptions) => {
|
|
4256
4453
|
return [{
|
|
4257
4454
|
childCount: eventCategoryFilterOptions.length,
|
|
4258
|
-
className:
|
|
4455
|
+
className: ChatDebugViewQuickFilters,
|
|
4259
4456
|
type: Div
|
|
4260
4457
|
}, ...eventCategoryFilterOptions.flatMap(option => {
|
|
4261
4458
|
const isSelected = option.value === eventCategoryFilter;
|
|
4262
4459
|
return [{
|
|
4263
4460
|
childCount: 2,
|
|
4264
|
-
className:
|
|
4461
|
+
className: joinClassNames(ChatDebugViewQuickFilterPill, isSelected && ChatDebugViewQuickFilterPillSelected),
|
|
4265
4462
|
type: Label
|
|
4266
4463
|
}, {
|
|
4267
4464
|
checked: isSelected,
|
|
4268
4465
|
childCount: 0,
|
|
4269
|
-
className:
|
|
4466
|
+
className: ChatDebugViewQuickFilterInput,
|
|
4270
4467
|
inputType: 'radio',
|
|
4271
4468
|
name: EventCategoryFilter,
|
|
4272
4469
|
onChange: HandleInput,
|
|
@@ -4307,10 +4504,12 @@ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, eve
|
|
|
4307
4504
|
if (timelineFilterDescription) {
|
|
4308
4505
|
filterDescriptionParts.push(timelineFilterDescription);
|
|
4309
4506
|
}
|
|
4507
|
+
const hasTimelineFilter = Boolean(timelineFilterDescription);
|
|
4310
4508
|
const hasFilterValue = filterDescriptionParts.length > 0;
|
|
4311
4509
|
const filterDescription = filterDescriptionParts.join(' ');
|
|
4312
4510
|
const noFilteredEventsMessage = `no events found matching ${filterDescription}`;
|
|
4313
|
-
const
|
|
4511
|
+
const useNoToolCallEventsMessage = eventCategoryFilter === Tools && !trimmedFilterValue && !hasTimelineFilter;
|
|
4512
|
+
const emptyMessage = events.length === 0 && hasFilterValue ? useNoToolCallEventsMessage ? 'No tool call events.' : noFilteredEventsMessage : 'No events have been found';
|
|
4314
4513
|
const safeSelectedEventIndex = selectedEventIndex === null || selectedEventIndex < 0 || selectedEventIndex >= events.length ? null : selectedEventIndex;
|
|
4315
4514
|
const contentNodes = useDevtoolsLayout ? getDevtoolsDom(events, selectedEvent, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response) : getLegacyEventsDom(errorMessage, emptyMessage, events.flatMap(getEventNode));
|
|
4316
4515
|
const quickFilterNodes = useDevtoolsLayout ? getQuickFilterNodes(eventCategoryFilter, eventCategoryFilterOptions) : [];
|
|
@@ -4318,7 +4517,7 @@ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, eve
|
|
|
4318
4517
|
const rootChildCount = 2;
|
|
4319
4518
|
return [{
|
|
4320
4519
|
childCount: rootChildCount,
|
|
4321
|
-
className:
|
|
4520
|
+
className: joinClassNames(ChatDebugView, useDevtoolsLayout && ChatDebugViewDevtools),
|
|
4322
4521
|
type: Div
|
|
4323
4522
|
}, ...debugViewTopDom, ...contentNodes];
|
|
4324
4523
|
};
|
|
@@ -4385,7 +4584,7 @@ const render2 = (uid, diffResult) => {
|
|
|
4385
4584
|
const renderEventListeners = () => {
|
|
4386
4585
|
return [{
|
|
4387
4586
|
name: HandleEventRowClick,
|
|
4388
|
-
params: ['handleEventRowClick', 'event.target.dataset.index']
|
|
4587
|
+
params: ['handleEventRowClick', 'event.target.dataset.index', 'event.button']
|
|
4389
4588
|
}, {
|
|
4390
4589
|
name: HandleTableBodyContextMenu,
|
|
4391
4590
|
params: ['handleTableBodyContextMenu'],
|
|
@@ -4537,7 +4736,9 @@ const commandMap = {
|
|
|
4537
4736
|
'ChatDebug.create': create,
|
|
4538
4737
|
'ChatDebug.diff2': diff2,
|
|
4539
4738
|
'ChatDebug.getCommandIds': getCommandIds,
|
|
4739
|
+
'ChatDebug.handleDetailsContextMenu': wrapCommand(handleDetailsContextMenu),
|
|
4540
4740
|
'ChatDebug.handleEventRowClick': wrapCommand(handleEventRowClick),
|
|
4741
|
+
'ChatDebug.handleHeaderContextMenu': wrapCommand(handleHeaderContextMenu),
|
|
4541
4742
|
'ChatDebug.handleInput': wrapCommand(handleInput),
|
|
4542
4743
|
'ChatDebug.handleSashPointerDown': wrapCommand(handleSashPointerDown),
|
|
4543
4744
|
'ChatDebug.handleSashPointerMove': wrapCommand(handleSashPointerMove),
|