@lvce-editor/chat-debug-view 4.0.0 → 5.0.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 +1990 -818
- package/package.json +1 -1
|
@@ -955,36 +955,25 @@ const terminate = () => {
|
|
|
955
955
|
globalThis.close();
|
|
956
956
|
};
|
|
957
957
|
|
|
958
|
-
const {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
958
|
+
const createEventCategoryFilterOptions = () => {
|
|
959
|
+
return [{
|
|
960
|
+
label: 'All',
|
|
961
|
+
value: All
|
|
962
|
+
}, {
|
|
963
|
+
label: 'Tools',
|
|
964
|
+
value: Tools
|
|
965
|
+
}, {
|
|
966
|
+
label: 'Network',
|
|
967
|
+
value: Network
|
|
968
|
+
}, {
|
|
969
|
+
label: 'UI',
|
|
970
|
+
value: Ui
|
|
971
|
+
}, {
|
|
972
|
+
label: 'Stream',
|
|
973
|
+
value: Stream
|
|
974
|
+
}];
|
|
975
|
+
};
|
|
966
976
|
|
|
967
|
-
const All = 'all';
|
|
968
|
-
const Tools = 'tools';
|
|
969
|
-
const Network = 'network';
|
|
970
|
-
const Ui = 'ui';
|
|
971
|
-
const Stream = 'stream';
|
|
972
|
-
const options = [{
|
|
973
|
-
label: 'All',
|
|
974
|
-
value: All
|
|
975
|
-
}, {
|
|
976
|
-
label: 'Tools',
|
|
977
|
-
value: Tools
|
|
978
|
-
}, {
|
|
979
|
-
label: 'Network',
|
|
980
|
-
value: Network
|
|
981
|
-
}, {
|
|
982
|
-
label: 'UI',
|
|
983
|
-
value: Ui
|
|
984
|
-
}, {
|
|
985
|
-
label: 'Stream',
|
|
986
|
-
value: Stream
|
|
987
|
-
}];
|
|
988
977
|
const getEventCategoryFilterLabel = eventCategoryFilter => {
|
|
989
978
|
switch (eventCategoryFilter) {
|
|
990
979
|
case Network:
|
|
@@ -1000,6 +989,80 @@ const getEventCategoryFilterLabel = eventCategoryFilter => {
|
|
|
1000
989
|
}
|
|
1001
990
|
};
|
|
1002
991
|
|
|
992
|
+
const All = 'all';
|
|
993
|
+
const Tools = 'tools';
|
|
994
|
+
const Network = 'network';
|
|
995
|
+
const Ui = 'ui';
|
|
996
|
+
const Stream = 'stream';
|
|
997
|
+
|
|
998
|
+
const RE_SPACE = /\s+/;
|
|
999
|
+
const tokenToEventCategoryFilter = new Map([['@tools', Tools], ['@network', Network], ['@ui', Ui], ['@stream', Stream]]);
|
|
1000
|
+
const parseFilterValue = filterValue => {
|
|
1001
|
+
const normalizedFilter = filterValue.trim().toLowerCase();
|
|
1002
|
+
if (!normalizedFilter) {
|
|
1003
|
+
return {
|
|
1004
|
+
eventCategoryFilter: All,
|
|
1005
|
+
filterText: ''
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
const parts = normalizedFilter.split(RE_SPACE);
|
|
1009
|
+
const eventCategoryFilter = parts.map(part => tokenToEventCategoryFilter.get(part)).find(Boolean) || All;
|
|
1010
|
+
const filterText = parts.filter(part => !tokenToEventCategoryFilter.has(part)).join(' ');
|
|
1011
|
+
return {
|
|
1012
|
+
eventCategoryFilter,
|
|
1013
|
+
filterText
|
|
1014
|
+
};
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
const {
|
|
1018
|
+
get,
|
|
1019
|
+
getCommandIds,
|
|
1020
|
+
registerCommands,
|
|
1021
|
+
set,
|
|
1022
|
+
wrapCommand,
|
|
1023
|
+
wrapGetter
|
|
1024
|
+
} = create$1();
|
|
1025
|
+
|
|
1026
|
+
const Response = 'response';
|
|
1027
|
+
const Timing = 'timing';
|
|
1028
|
+
const detailTabs = [Response, Timing];
|
|
1029
|
+
const isDetailTab = value => {
|
|
1030
|
+
return value === Response || value === Timing;
|
|
1031
|
+
};
|
|
1032
|
+
const getDetailTabLabel = value => {
|
|
1033
|
+
if (value === Timing) {
|
|
1034
|
+
return 'Timing';
|
|
1035
|
+
}
|
|
1036
|
+
return 'Response';
|
|
1037
|
+
};
|
|
1038
|
+
|
|
1039
|
+
const defaultTableWidth = 480;
|
|
1040
|
+
const minTableWidth = 240;
|
|
1041
|
+
const minDetailsWidth = 280;
|
|
1042
|
+
const sashWidth = 8;
|
|
1043
|
+
const viewPadding = 8;
|
|
1044
|
+
const timelineHorizontalPadding = 10;
|
|
1045
|
+
const horizontalPadding = viewPadding * 2;
|
|
1046
|
+
const leftPadding = viewPadding;
|
|
1047
|
+
const getMainWidth = width => {
|
|
1048
|
+
return Math.max(0, width - horizontalPadding);
|
|
1049
|
+
};
|
|
1050
|
+
const clampTableWidth = (width, tableWidth) => {
|
|
1051
|
+
const mainWidth = getMainWidth(width);
|
|
1052
|
+
const maxTableWidth = Math.max(0, mainWidth - minDetailsWidth - sashWidth);
|
|
1053
|
+
const minClampedTableWidth = Math.min(minTableWidth, maxTableWidth);
|
|
1054
|
+
return Math.max(minClampedTableWidth, Math.min(tableWidth, maxTableWidth));
|
|
1055
|
+
};
|
|
1056
|
+
const getDetailsWidth = (width, tableWidth) => {
|
|
1057
|
+
const mainWidth = getMainWidth(width);
|
|
1058
|
+
const clampedTableWidth = clampTableWidth(width, tableWidth);
|
|
1059
|
+
return Math.max(0, mainWidth - clampedTableWidth - sashWidth);
|
|
1060
|
+
};
|
|
1061
|
+
const getTableWidthFromClientX = (viewX, width, clientX) => {
|
|
1062
|
+
const nextTableWidth = clientX - viewX - leftPadding;
|
|
1063
|
+
return clampTableWidth(width, nextTableWidth);
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1003
1066
|
const createDefaultState = () => {
|
|
1004
1067
|
return {
|
|
1005
1068
|
assetDir: '',
|
|
@@ -1007,42 +1070,75 @@ const createDefaultState = () => {
|
|
|
1007
1070
|
dataBaseVersion: 2,
|
|
1008
1071
|
errorMessage: '',
|
|
1009
1072
|
eventCategoryFilter: All,
|
|
1073
|
+
eventCategoryFilterOptions: createEventCategoryFilterOptions(),
|
|
1010
1074
|
events: [],
|
|
1011
1075
|
eventStoreName: 'chat-view-events',
|
|
1012
1076
|
filterValue: '',
|
|
1013
1077
|
height: 0,
|
|
1078
|
+
indexedDbSupportOverride: undefined,
|
|
1014
1079
|
initial: false,
|
|
1015
1080
|
platform: 0,
|
|
1081
|
+
selectedDetailTab: Response,
|
|
1082
|
+
selectedEvent: null,
|
|
1083
|
+
selectedEventId: null,
|
|
1016
1084
|
selectedEventIndex: null,
|
|
1017
1085
|
sessionId: '',
|
|
1018
1086
|
sessionIdIndexName: 'sessionId',
|
|
1019
1087
|
showEventStreamFinishedEvents: false,
|
|
1020
1088
|
showInputEvents: false,
|
|
1021
1089
|
showResponsePartEvents: false,
|
|
1090
|
+
tableWidth: defaultTableWidth,
|
|
1022
1091
|
timelineEndSeconds: '',
|
|
1092
|
+
timelineSelectionActive: false,
|
|
1093
|
+
timelineSelectionAnchorSeconds: '',
|
|
1094
|
+
timelineSelectionFocusSeconds: '',
|
|
1023
1095
|
timelineStartSeconds: '',
|
|
1024
1096
|
uid: 0,
|
|
1025
1097
|
uri: '',
|
|
1026
|
-
useDevtoolsLayout:
|
|
1098
|
+
useDevtoolsLayout: true,
|
|
1027
1099
|
width: 0,
|
|
1028
1100
|
x: 0,
|
|
1029
1101
|
y: 0
|
|
1030
1102
|
};
|
|
1031
1103
|
};
|
|
1032
1104
|
|
|
1105
|
+
const validEventCategoryFilters = new Set([All, Network, Stream, Tools, Ui]);
|
|
1106
|
+
const getRestoredEventCategoryFilter = savedState => {
|
|
1107
|
+
if (typeof savedState.eventCategoryFilter === 'string' && validEventCategoryFilters.has(savedState.eventCategoryFilter)) {
|
|
1108
|
+
return savedState.eventCategoryFilter;
|
|
1109
|
+
}
|
|
1110
|
+
if (typeof savedState.filterValue === 'string') {
|
|
1111
|
+
return parseFilterValue(savedState.filterValue).eventCategoryFilter;
|
|
1112
|
+
}
|
|
1113
|
+
return All;
|
|
1114
|
+
};
|
|
1033
1115
|
const create = (uid, uri, x, y, width, height, platform, assetDir, sessionId = '', databaseName = 'lvce-chat-view-sessions', dataBaseVersion = 2, eventStoreName = 'chat-view-events', sessionIdIndexName = 'sessionId', savedState = {}) => {
|
|
1116
|
+
const defaultState = createDefaultState();
|
|
1117
|
+
const {
|
|
1118
|
+
filterValue,
|
|
1119
|
+
selectedEventId,
|
|
1120
|
+
tableWidth,
|
|
1121
|
+
timelineEndSeconds,
|
|
1122
|
+
timelineStartSeconds
|
|
1123
|
+
} = savedState;
|
|
1124
|
+
const restoredEventCategoryFilter = getRestoredEventCategoryFilter(savedState);
|
|
1034
1125
|
const state = {
|
|
1035
|
-
...
|
|
1036
|
-
...savedState,
|
|
1126
|
+
...defaultState,
|
|
1037
1127
|
assetDir,
|
|
1038
1128
|
databaseName,
|
|
1039
1129
|
dataBaseVersion,
|
|
1130
|
+
eventCategoryFilter: restoredEventCategoryFilter,
|
|
1040
1131
|
eventStoreName,
|
|
1132
|
+
filterValue: filterValue ?? defaultState.filterValue,
|
|
1041
1133
|
height,
|
|
1042
1134
|
initial: true,
|
|
1043
1135
|
platform,
|
|
1136
|
+
selectedEventId: selectedEventId ?? defaultState.selectedEventId,
|
|
1044
1137
|
sessionId,
|
|
1045
1138
|
sessionIdIndexName,
|
|
1139
|
+
tableWidth: tableWidth ?? defaultState.tableWidth,
|
|
1140
|
+
timelineEndSeconds: timelineEndSeconds ?? defaultState.timelineEndSeconds,
|
|
1141
|
+
timelineStartSeconds: timelineStartSeconds ?? defaultState.timelineStartSeconds,
|
|
1046
1142
|
uid,
|
|
1047
1143
|
uri,
|
|
1048
1144
|
width,
|
|
@@ -1057,7 +1153,7 @@ const RenderCss = 2;
|
|
|
1057
1153
|
const RenderIncremental = 3;
|
|
1058
1154
|
|
|
1059
1155
|
const diff = (oldState, newState) => {
|
|
1060
|
-
if (oldState.errorMessage !== newState.errorMessage || oldState.eventCategoryFilter !== newState.eventCategoryFilter || oldState.events !== newState.events || oldState.filterValue !== newState.filterValue || oldState.sessionId !== newState.sessionId || oldState.showEventStreamFinishedEvents !== newState.showEventStreamFinishedEvents || oldState.showInputEvents !== newState.showInputEvents || oldState.showResponsePartEvents !== newState.showResponsePartEvents || oldState.timelineEndSeconds !== newState.timelineEndSeconds || oldState.timelineStartSeconds !== newState.timelineStartSeconds || oldState.useDevtoolsLayout !== newState.useDevtoolsLayout || oldState.selectedEventIndex !== newState.selectedEventIndex || oldState.uid !== newState.uid) {
|
|
1156
|
+
if (oldState.errorMessage !== newState.errorMessage || oldState.eventCategoryFilter !== newState.eventCategoryFilter || oldState.events !== newState.events || oldState.filterValue !== newState.filterValue || oldState.sessionId !== newState.sessionId || oldState.showEventStreamFinishedEvents !== newState.showEventStreamFinishedEvents || oldState.showInputEvents !== newState.showInputEvents || oldState.showResponsePartEvents !== newState.showResponsePartEvents || oldState.tableWidth !== newState.tableWidth || oldState.timelineEndSeconds !== newState.timelineEndSeconds || oldState.timelineSelectionActive !== newState.timelineSelectionActive || oldState.timelineSelectionAnchorSeconds !== newState.timelineSelectionAnchorSeconds || oldState.timelineSelectionFocusSeconds !== newState.timelineSelectionFocusSeconds || oldState.timelineStartSeconds !== newState.timelineStartSeconds || oldState.useDevtoolsLayout !== newState.useDevtoolsLayout || oldState.selectedDetailTab !== newState.selectedDetailTab || oldState.selectedEvent !== newState.selectedEvent || oldState.selectedEventIndex !== newState.selectedEventIndex || oldState.width !== newState.width || oldState.uid !== newState.uid) {
|
|
1061
1157
|
return [RenderIncremental, RenderCss];
|
|
1062
1158
|
}
|
|
1063
1159
|
return [];
|
|
@@ -1071,60 +1167,109 @@ const diff2 = uid => {
|
|
|
1071
1167
|
return diff(oldState, newState);
|
|
1072
1168
|
};
|
|
1073
1169
|
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1170
|
+
const hasMatchingToolName$1 = (startedEvent, finishedEvent) => {
|
|
1171
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1172
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1173
|
+
}
|
|
1174
|
+
return true;
|
|
1076
1175
|
};
|
|
1077
1176
|
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1177
|
+
const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
|
|
1178
|
+
return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName$1(startedEvent, finishedEvent);
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
const startedEventType$1 = 'tool-execution-started';
|
|
1182
|
+
const finishedEventType$1 = 'tool-execution-finished';
|
|
1183
|
+
const mergedEventType = 'tool-execution';
|
|
1184
|
+
|
|
1185
|
+
const isToolExecutionFinishedEvent = event => {
|
|
1186
|
+
return event.type === finishedEventType$1;
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
const isToolExecutionStartedEvent = event => {
|
|
1190
|
+
return event.type === startedEventType$1;
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
const getTimestamp$1 = value => {
|
|
1194
|
+
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
const getEndedTimestamp = event => {
|
|
1198
|
+
return getTimestamp$1(event.ended) ?? getTimestamp$1(event.endTime) ?? getTimestamp$1(event.endTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1201
|
+
const eventStableIds = new WeakMap();
|
|
1202
|
+
const eventStableIdState = {
|
|
1203
|
+
nextStableEventId: 1
|
|
1204
|
+
};
|
|
1205
|
+
|
|
1206
|
+
const getOrCreateStableEventId = event => {
|
|
1207
|
+
const existingStableEventId = eventStableIds.get(event);
|
|
1208
|
+
if (existingStableEventId) {
|
|
1209
|
+
return existingStableEventId;
|
|
1087
1210
|
}
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
return {
|
|
1092
|
-
eventCategoryFilter,
|
|
1093
|
-
filterText
|
|
1094
|
-
};
|
|
1211
|
+
const stableEventId = `event-${eventStableIdState.nextStableEventId++}`;
|
|
1212
|
+
eventStableIds.set(event, stableEventId);
|
|
1213
|
+
return stableEventId;
|
|
1095
1214
|
};
|
|
1096
1215
|
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1099
|
-
return event.type.startsWith(toolEventTypePrefix);
|
|
1216
|
+
const getStartedTimestamp = event => {
|
|
1217
|
+
return getTimestamp$1(event.started) ?? getTimestamp$1(event.startTime) ?? getTimestamp$1(event.startTimestamp) ?? getTimestamp$1(event.timestamp);
|
|
1100
1218
|
};
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1219
|
+
|
|
1220
|
+
const setStableEventId = (event, stableEventId) => {
|
|
1221
|
+
eventStableIds.set(event, stableEventId);
|
|
1104
1222
|
};
|
|
1105
|
-
|
|
1106
|
-
|
|
1223
|
+
|
|
1224
|
+
const mergeToolExecutionEvents$1 = (startedEvent, finishedEvent) => {
|
|
1225
|
+
const ended = getEndedTimestamp(finishedEvent);
|
|
1226
|
+
const {
|
|
1227
|
+
eventId
|
|
1228
|
+
} = startedEvent;
|
|
1229
|
+
const started = getStartedTimestamp(startedEvent);
|
|
1230
|
+
const mergedEvent = {
|
|
1231
|
+
...startedEvent,
|
|
1232
|
+
...finishedEvent,
|
|
1233
|
+
...(ended === undefined ? {} : {
|
|
1234
|
+
ended
|
|
1235
|
+
}),
|
|
1236
|
+
...(eventId === undefined ? {} : {
|
|
1237
|
+
eventId
|
|
1238
|
+
}),
|
|
1239
|
+
...(started === undefined ? {} : {
|
|
1240
|
+
started
|
|
1241
|
+
}),
|
|
1242
|
+
type: mergedEventType
|
|
1243
|
+
};
|
|
1244
|
+
const stableEventId = `${getOrCreateStableEventId(startedEvent)}:${getOrCreateStableEventId(finishedEvent)}`;
|
|
1245
|
+
setStableEventId(mergedEvent, stableEventId);
|
|
1246
|
+
return mergedEvent;
|
|
1107
1247
|
};
|
|
1108
|
-
|
|
1109
|
-
|
|
1248
|
+
|
|
1249
|
+
const getStableEventId = event => {
|
|
1250
|
+
return getOrCreateStableEventId(event);
|
|
1110
1251
|
};
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1252
|
+
|
|
1253
|
+
const collapseToolExecutionEvents = events => {
|
|
1254
|
+
const collapsedEvents = [];
|
|
1255
|
+
for (let i = 0; i < events.length; i++) {
|
|
1256
|
+
const event = events[i];
|
|
1257
|
+
if (isToolExecutionStartedEvent(event)) {
|
|
1258
|
+
const nextEvent = events[i + 1];
|
|
1259
|
+
if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
|
|
1260
|
+
collapsedEvents.push(mergeToolExecutionEvents$1(event, nextEvent));
|
|
1261
|
+
i++;
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
collapsedEvents.push(event);
|
|
1123
1266
|
}
|
|
1267
|
+
return collapsedEvents;
|
|
1124
1268
|
};
|
|
1269
|
+
|
|
1125
1270
|
const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1126
1271
|
return events.filter(event => {
|
|
1127
|
-
if (!showInputEvents &&
|
|
1272
|
+
if (!showInputEvents && event.type === 'handle-input') {
|
|
1128
1273
|
return false;
|
|
1129
1274
|
}
|
|
1130
1275
|
if (!showResponsePartEvents && event.type === 'sse-response-part') {
|
|
@@ -1140,11 +1285,46 @@ const getVisibleEvents = (events, showInputEvents, showResponsePartEvents, showE
|
|
|
1140
1285
|
return true;
|
|
1141
1286
|
});
|
|
1142
1287
|
};
|
|
1288
|
+
|
|
1289
|
+
const isNetworkEvent = event => {
|
|
1290
|
+
const normalizedType = event.type.toLowerCase();
|
|
1291
|
+
return normalizedType === 'request' || normalizedType === 'response' || normalizedType === 'handle-response' || normalizedType.includes('fetch') || normalizedType.includes('xhr');
|
|
1292
|
+
};
|
|
1293
|
+
|
|
1294
|
+
const isStreamEvent = event => {
|
|
1295
|
+
return event.type === 'sse-response-part' || event.type === 'event-stream-finished';
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
const toolEventTypePrefix = 'tool-execution';
|
|
1299
|
+
const isToolEvent = event => {
|
|
1300
|
+
return event.type.startsWith(toolEventTypePrefix);
|
|
1301
|
+
};
|
|
1302
|
+
|
|
1303
|
+
const isUiEvent = event => {
|
|
1304
|
+
return event.type.startsWith('handle-') && event.type !== 'handle-response';
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
const matchesEventCategoryFilter = (event, eventCategoryFilter) => {
|
|
1308
|
+
switch (eventCategoryFilter) {
|
|
1309
|
+
case Network:
|
|
1310
|
+
return isNetworkEvent(event);
|
|
1311
|
+
case Stream:
|
|
1312
|
+
return isStreamEvent(event);
|
|
1313
|
+
case Tools:
|
|
1314
|
+
return isToolEvent(event);
|
|
1315
|
+
case Ui:
|
|
1316
|
+
return isUiEvent(event);
|
|
1317
|
+
default:
|
|
1318
|
+
return true;
|
|
1319
|
+
}
|
|
1320
|
+
};
|
|
1321
|
+
|
|
1143
1322
|
const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents) => {
|
|
1144
1323
|
const visibleEvents = getVisibleEvents(events, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
|
|
1324
|
+
const collapsedEvents = collapseToolExecutionEvents(visibleEvents);
|
|
1145
1325
|
const parsedFilter = parseFilterValue(filterValue);
|
|
1146
1326
|
const activeEventCategoryFilter = parsedFilter.eventCategoryFilter === All ? eventCategoryFilter : parsedFilter.eventCategoryFilter;
|
|
1147
|
-
const filteredByCategory =
|
|
1327
|
+
const filteredByCategory = collapsedEvents.filter(event => matchesEventCategoryFilter(event, activeEventCategoryFilter));
|
|
1148
1328
|
const {
|
|
1149
1329
|
filterText
|
|
1150
1330
|
} = parsedFilter;
|
|
@@ -1198,6 +1378,21 @@ const getEventsWithTime = events => {
|
|
|
1198
1378
|
}];
|
|
1199
1379
|
});
|
|
1200
1380
|
};
|
|
1381
|
+
const getTimelineDurationSeconds = events => {
|
|
1382
|
+
const eventsWithTime = getEventsWithTime(events);
|
|
1383
|
+
if (eventsWithTime.length === 0) {
|
|
1384
|
+
return 0;
|
|
1385
|
+
}
|
|
1386
|
+
const baseTime = eventsWithTime[0].time;
|
|
1387
|
+
const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
|
|
1388
|
+
return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
|
|
1389
|
+
};
|
|
1390
|
+
const getSelectionPercent = (value, durationSeconds) => {
|
|
1391
|
+
if (durationSeconds <= 0) {
|
|
1392
|
+
return 0;
|
|
1393
|
+
}
|
|
1394
|
+
return Number((value / durationSeconds * 100).toFixed(3));
|
|
1395
|
+
};
|
|
1201
1396
|
const getNormalizedRange = (durationSeconds, startValue, endValue) => {
|
|
1202
1397
|
const parsedStart = parseTimelineSeconds(startValue);
|
|
1203
1398
|
const parsedEnd = parseTimelineSeconds(endValue);
|
|
@@ -1242,6 +1437,8 @@ const getTimelineInfo = (events, startValue, endValue) => {
|
|
|
1242
1437
|
durationSeconds: 0,
|
|
1243
1438
|
endSeconds: null,
|
|
1244
1439
|
hasSelection: false,
|
|
1440
|
+
selectionEndPercent: null,
|
|
1441
|
+
selectionStartPercent: null,
|
|
1245
1442
|
startSeconds: null
|
|
1246
1443
|
};
|
|
1247
1444
|
}
|
|
@@ -1261,6 +1458,8 @@ const getTimelineInfo = (events, startValue, endValue) => {
|
|
|
1261
1458
|
counts[index] += 1;
|
|
1262
1459
|
}
|
|
1263
1460
|
const maxCount = Math.max(...counts);
|
|
1461
|
+
const selectionStartPercent = range.hasSelection && range.startSeconds !== null ? getSelectionPercent(range.startSeconds, durationSeconds) : null;
|
|
1462
|
+
const selectionEndPercent = range.hasSelection && range.endSeconds !== null ? getSelectionPercent(range.endSeconds, durationSeconds) : null;
|
|
1264
1463
|
const buckets = counts.map((count, index) => {
|
|
1265
1464
|
const bucketStartMs = index * bucketDurationMs;
|
|
1266
1465
|
const bucketEndMs = index === bucketCount - 1 ? durationMs : (index + 1) * bucketDurationMs;
|
|
@@ -1280,231 +1479,87 @@ const getTimelineInfo = (events, startValue, endValue) => {
|
|
|
1280
1479
|
durationSeconds,
|
|
1281
1480
|
endSeconds: range.endSeconds,
|
|
1282
1481
|
hasSelection: range.hasSelection,
|
|
1482
|
+
selectionEndPercent,
|
|
1483
|
+
selectionStartPercent,
|
|
1283
1484
|
startSeconds: range.startSeconds
|
|
1284
1485
|
};
|
|
1285
1486
|
};
|
|
1286
1487
|
|
|
1287
|
-
|
|
1288
|
-
const EventCategoryFilter = 'eventCategoryFilter';
|
|
1289
|
-
const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
|
|
1290
|
-
const ShowInputEvents = 'showInputEvents';
|
|
1291
|
-
const ShowResponsePartEvents = 'showResponsePartEvents';
|
|
1292
|
-
const UseDevtoolsLayout = 'useDevtoolsLayout';
|
|
1293
|
-
const SelectedEventIndex = 'selectedEventIndex';
|
|
1294
|
-
const CloseDetails = 'closeDetails';
|
|
1295
|
-
const TimelineStartSeconds = 'timelineStartSeconds';
|
|
1296
|
-
const TimelineEndSeconds = 'timelineEndSeconds';
|
|
1297
|
-
const TimelineRangePreset = 'timelineRangePreset';
|
|
1488
|
+
// cspell:ignore IDBP
|
|
1298
1489
|
|
|
1299
|
-
const
|
|
1300
|
-
|
|
1301
|
-
|
|
1490
|
+
const startedEventType = 'tool-execution-started';
|
|
1491
|
+
const finishedEventType = 'tool-execution-finished';
|
|
1492
|
+
const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId) => {
|
|
1493
|
+
if (eventId < 1) {
|
|
1494
|
+
return undefined;
|
|
1495
|
+
}
|
|
1496
|
+
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1497
|
+
const index = store.index(sessionIdIndexName);
|
|
1498
|
+
const keys = await index.getAllKeys(sessionId, eventId);
|
|
1499
|
+
if (keys.length < eventId) {
|
|
1500
|
+
return undefined;
|
|
1501
|
+
}
|
|
1502
|
+
const key = keys.at(-1);
|
|
1503
|
+
if (key === undefined) {
|
|
1504
|
+
return undefined;
|
|
1505
|
+
}
|
|
1506
|
+
const event = await store.get(key);
|
|
1507
|
+
return event;
|
|
1508
|
+
}
|
|
1509
|
+
const all = await store.getAll();
|
|
1510
|
+
const events = all.filter(event => event.sessionId === sessionId);
|
|
1511
|
+
return events[eventId - 1];
|
|
1302
1512
|
};
|
|
1303
|
-
const
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1513
|
+
const getTimestamp = value => {
|
|
1514
|
+
return typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
1515
|
+
};
|
|
1516
|
+
const hasMatchingToolName = (startedEvent, finishedEvent) => {
|
|
1517
|
+
if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
|
|
1518
|
+
return startedEvent.toolName === finishedEvent.toolName;
|
|
1309
1519
|
}
|
|
1310
|
-
|
|
1520
|
+
return true;
|
|
1521
|
+
};
|
|
1522
|
+
const mergeToolExecutionEvents = (startedEvent, finishedEvent, eventId) => {
|
|
1523
|
+
const ended = getTimestamp(finishedEvent.ended) ?? getTimestamp(finishedEvent.endTime) ?? getTimestamp(finishedEvent.timestamp);
|
|
1524
|
+
const started = getTimestamp(startedEvent.started) ?? getTimestamp(startedEvent.startTime) ?? getTimestamp(startedEvent.timestamp);
|
|
1311
1525
|
return {
|
|
1312
|
-
|
|
1313
|
-
|
|
1526
|
+
...startedEvent,
|
|
1527
|
+
...finishedEvent,
|
|
1528
|
+
...(ended === undefined ? {} : {
|
|
1529
|
+
ended
|
|
1530
|
+
}),
|
|
1531
|
+
eventId,
|
|
1532
|
+
...(started === undefined ? {} : {
|
|
1533
|
+
started
|
|
1534
|
+
}),
|
|
1535
|
+
type: 'tool-execution'
|
|
1314
1536
|
};
|
|
1315
1537
|
};
|
|
1316
|
-
const
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
if (selectedEventIndex === null) {
|
|
1321
|
-
return null;
|
|
1322
|
-
}
|
|
1323
|
-
const filteredEvents = getCurrentEvents(state);
|
|
1324
|
-
const selectedEvent = filteredEvents[selectedEventIndex];
|
|
1325
|
-
if (!selectedEvent) {
|
|
1326
|
-
return null;
|
|
1327
|
-
}
|
|
1328
|
-
const newIndex = filteredEvents.indexOf(selectedEvent);
|
|
1329
|
-
if (newIndex === -1) {
|
|
1330
|
-
return null;
|
|
1331
|
-
}
|
|
1332
|
-
return newIndex;
|
|
1333
|
-
};
|
|
1334
|
-
const getPreservedSelectedEventIndex = (oldState, newState) => {
|
|
1335
|
-
const {
|
|
1336
|
-
selectedEventIndex
|
|
1337
|
-
} = oldState;
|
|
1338
|
-
if (selectedEventIndex === null) {
|
|
1339
|
-
return null;
|
|
1538
|
+
const getEventDetailsBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId, summaryType) => {
|
|
1539
|
+
const event = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId);
|
|
1540
|
+
if (!event) {
|
|
1541
|
+
return undefined;
|
|
1340
1542
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1543
|
+
if (summaryType !== 'tool-execution') {
|
|
1544
|
+
return {
|
|
1545
|
+
...event,
|
|
1546
|
+
eventId
|
|
1547
|
+
};
|
|
1345
1548
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1549
|
+
if (event.type !== startedEventType) {
|
|
1550
|
+
return {
|
|
1551
|
+
...event,
|
|
1552
|
+
eventId
|
|
1553
|
+
};
|
|
1350
1554
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1555
|
+
const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
|
|
1556
|
+
if (!nextEvent || nextEvent.type !== finishedEventType || nextEvent.sessionId !== sessionId || !hasMatchingToolName(event, nextEvent)) {
|
|
1557
|
+
return {
|
|
1558
|
+
...event,
|
|
1559
|
+
eventId
|
|
1560
|
+
};
|
|
1357
1561
|
}
|
|
1358
|
-
return
|
|
1359
|
-
};
|
|
1360
|
-
const handleInput = (state, name, value, checked) => {
|
|
1361
|
-
if (name === Filter) {
|
|
1362
|
-
const nextState = {
|
|
1363
|
-
...state,
|
|
1364
|
-
filterValue: value
|
|
1365
|
-
};
|
|
1366
|
-
return {
|
|
1367
|
-
...nextState,
|
|
1368
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1369
|
-
};
|
|
1370
|
-
}
|
|
1371
|
-
if (name === EventCategoryFilter) {
|
|
1372
|
-
const nextState = {
|
|
1373
|
-
...state,
|
|
1374
|
-
eventCategoryFilter: value || All
|
|
1375
|
-
};
|
|
1376
|
-
return {
|
|
1377
|
-
...nextState,
|
|
1378
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1379
|
-
};
|
|
1380
|
-
}
|
|
1381
|
-
if (name === ShowEventStreamFinishedEvents) {
|
|
1382
|
-
const nextState = {
|
|
1383
|
-
...state,
|
|
1384
|
-
showEventStreamFinishedEvents: getBoolean(checked)
|
|
1385
|
-
};
|
|
1386
|
-
return {
|
|
1387
|
-
...nextState,
|
|
1388
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1389
|
-
};
|
|
1390
|
-
}
|
|
1391
|
-
if (name === ShowInputEvents) {
|
|
1392
|
-
const nextState = {
|
|
1393
|
-
...state,
|
|
1394
|
-
showInputEvents: getBoolean(checked)
|
|
1395
|
-
};
|
|
1396
|
-
return {
|
|
1397
|
-
...nextState,
|
|
1398
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1399
|
-
};
|
|
1400
|
-
}
|
|
1401
|
-
if (name === ShowResponsePartEvents) {
|
|
1402
|
-
const nextState = {
|
|
1403
|
-
...state,
|
|
1404
|
-
showResponsePartEvents: getBoolean(checked)
|
|
1405
|
-
};
|
|
1406
|
-
return {
|
|
1407
|
-
...nextState,
|
|
1408
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1409
|
-
};
|
|
1410
|
-
}
|
|
1411
|
-
if (name === UseDevtoolsLayout) {
|
|
1412
|
-
const useDevtoolsLayout = getBoolean(checked);
|
|
1413
|
-
return {
|
|
1414
|
-
...state,
|
|
1415
|
-
selectedEventIndex: useDevtoolsLayout ? getSelectedEventIndex(state) : null,
|
|
1416
|
-
useDevtoolsLayout
|
|
1417
|
-
};
|
|
1418
|
-
}
|
|
1419
|
-
if (name === SelectedEventIndex) {
|
|
1420
|
-
return {
|
|
1421
|
-
...state,
|
|
1422
|
-
selectedEventIndex: parseSelectedEventIndex(value)
|
|
1423
|
-
};
|
|
1424
|
-
}
|
|
1425
|
-
if (name === TimelineStartSeconds) {
|
|
1426
|
-
const nextState = {
|
|
1427
|
-
...state,
|
|
1428
|
-
timelineStartSeconds: value
|
|
1429
|
-
};
|
|
1430
|
-
return {
|
|
1431
|
-
...nextState,
|
|
1432
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1433
|
-
};
|
|
1434
|
-
}
|
|
1435
|
-
if (name === TimelineEndSeconds) {
|
|
1436
|
-
const nextState = {
|
|
1437
|
-
...state,
|
|
1438
|
-
timelineEndSeconds: value
|
|
1439
|
-
};
|
|
1440
|
-
return {
|
|
1441
|
-
...nextState,
|
|
1442
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1443
|
-
};
|
|
1444
|
-
}
|
|
1445
|
-
if (name === TimelineRangePreset) {
|
|
1446
|
-
const nextState = {
|
|
1447
|
-
...state,
|
|
1448
|
-
...parseTimelineRangePreset(value)
|
|
1449
|
-
};
|
|
1450
|
-
return {
|
|
1451
|
-
...nextState,
|
|
1452
|
-
selectedEventIndex: getPreservedSelectedEventIndex(state, nextState)
|
|
1453
|
-
};
|
|
1454
|
-
}
|
|
1455
|
-
if (name === CloseDetails) {
|
|
1456
|
-
return {
|
|
1457
|
-
...state,
|
|
1458
|
-
selectedEventIndex: null
|
|
1459
|
-
};
|
|
1460
|
-
}
|
|
1461
|
-
return state;
|
|
1462
|
-
};
|
|
1463
|
-
|
|
1464
|
-
const getFailedToLoadMessage = sessionId => {
|
|
1465
|
-
return `Failed to load chat debug session "${sessionId}". Please try again.`;
|
|
1466
|
-
};
|
|
1467
|
-
|
|
1468
|
-
const ParseChatDebugUriErrorCode = {
|
|
1469
|
-
InvalidSessionId: 'invalid-session-id',
|
|
1470
|
-
InvalidUriEncoding: 'invalid-uri-encoding',
|
|
1471
|
-
InvalidUriFormat: 'invalid-uri-format',
|
|
1472
|
-
MissingUri: 'missing-uri'
|
|
1473
|
-
};
|
|
1474
|
-
|
|
1475
|
-
const getInvalidUriMessage = (uri, code) => {
|
|
1476
|
-
if (code === ParseChatDebugUriErrorCode.MissingUri) {
|
|
1477
|
-
return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
|
|
1478
|
-
}
|
|
1479
|
-
return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
|
|
1480
|
-
};
|
|
1481
|
-
|
|
1482
|
-
const getSessionNotFoundMessage = sessionId => {
|
|
1483
|
-
return `No chat session found for sessionId "${sessionId}".`;
|
|
1484
|
-
};
|
|
1485
|
-
|
|
1486
|
-
const filterEventsBySessionId = (events, sessionId) => {
|
|
1487
|
-
return events.filter(event => event.sessionId === sessionId);
|
|
1488
|
-
};
|
|
1489
|
-
|
|
1490
|
-
// cspell:ignore IDBP
|
|
1491
|
-
|
|
1492
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
1493
|
-
const getAllEvents = async store => {
|
|
1494
|
-
const all = await store.getAll();
|
|
1495
|
-
return all;
|
|
1496
|
-
};
|
|
1497
|
-
|
|
1498
|
-
// cspell:ignore IDBP
|
|
1499
|
-
|
|
1500
|
-
const getEventsBySessionId = async (store, sessionId, sessionIdIndexName) => {
|
|
1501
|
-
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
1502
|
-
const index = store.index(sessionIdIndexName);
|
|
1503
|
-
const events = await index.getAll(sessionId);
|
|
1504
|
-
return filterEventsBySessionId(events, sessionId);
|
|
1505
|
-
}
|
|
1506
|
-
const all = await getAllEvents(store);
|
|
1507
|
-
return filterEventsBySessionId(all, sessionId);
|
|
1562
|
+
return mergeToolExecutionEvents(event, nextEvent, eventId);
|
|
1508
1563
|
};
|
|
1509
1564
|
|
|
1510
1565
|
const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
|
|
@@ -1761,154 +1816,756 @@ replaceTraps(oldTraps => ({
|
|
|
1761
1816
|
}
|
|
1762
1817
|
}));
|
|
1763
1818
|
|
|
1819
|
+
const openDatabaseDependencies = {
|
|
1820
|
+
openDB: openDB
|
|
1821
|
+
};
|
|
1764
1822
|
const openDatabase = async (databaseName, dataBaseVersion) => {
|
|
1765
|
-
return openDB(databaseName, dataBaseVersion);
|
|
1823
|
+
return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
|
|
1766
1824
|
};
|
|
1767
1825
|
|
|
1768
|
-
const
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1826
|
+
const loadSelectedEventDependencies = {
|
|
1827
|
+
getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
|
|
1828
|
+
openDatabase: openDatabase
|
|
1829
|
+
};
|
|
1830
|
+
const loadSelectedEvent = async (databaseName, dataBaseVersion, eventStoreName, sessionId, sessionIdIndexName, eventId, type) => {
|
|
1831
|
+
const database = await loadSelectedEventDependencies.openDatabase(databaseName, dataBaseVersion);
|
|
1773
1832
|
try {
|
|
1774
1833
|
if (!database.objectStoreNames.contains(eventStoreName)) {
|
|
1775
|
-
return
|
|
1834
|
+
return null;
|
|
1776
1835
|
}
|
|
1777
1836
|
const transaction = database.transaction(eventStoreName, 'readonly');
|
|
1778
1837
|
const store = transaction.objectStore(eventStoreName);
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
}
|
|
1782
|
-
return getEventsBySessionId(store, sessionId, sessionIdIndexName);
|
|
1838
|
+
const event = await loadSelectedEventDependencies.getEventDetailsBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId, type);
|
|
1839
|
+
return event ?? null;
|
|
1783
1840
|
} finally {
|
|
1784
1841
|
database.close();
|
|
1785
1842
|
}
|
|
1786
1843
|
};
|
|
1787
1844
|
|
|
1788
|
-
const
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1845
|
+
const handleEventRowClickDependencies = {
|
|
1846
|
+
loadSelectedEvent: loadSelectedEvent
|
|
1847
|
+
};
|
|
1848
|
+
const getCurrentEvents$2 = state => {
|
|
1849
|
+
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1850
|
+
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1851
|
+
};
|
|
1852
|
+
const parseSelectedEventIndex$1 = value => {
|
|
1853
|
+
const parsed = Number.parseInt(value, 10);
|
|
1854
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1855
|
+
return null;
|
|
1797
1856
|
}
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
};
|
|
1857
|
+
return parsed;
|
|
1858
|
+
};
|
|
1859
|
+
const handleEventRowClick = async (state, value) => {
|
|
1860
|
+
const selectedEventIndex = parseSelectedEventIndex$1(value);
|
|
1861
|
+
if (selectedEventIndex === null) {
|
|
1862
|
+
return state;
|
|
1805
1863
|
}
|
|
1806
|
-
const
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
sessionId = decodeURIComponent(encodedSessionId);
|
|
1810
|
-
} catch {
|
|
1864
|
+
const currentEvents = getCurrentEvents$2(state);
|
|
1865
|
+
const selectedEvent = currentEvents[selectedEventIndex];
|
|
1866
|
+
if (!selectedEvent) {
|
|
1811
1867
|
return {
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1868
|
+
...state,
|
|
1869
|
+
selectedEvent: null,
|
|
1870
|
+
selectedEventId: null,
|
|
1871
|
+
selectedEventIndex
|
|
1815
1872
|
};
|
|
1816
1873
|
}
|
|
1817
|
-
if (
|
|
1874
|
+
if (typeof selectedEvent.eventId !== 'number') {
|
|
1818
1875
|
return {
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1876
|
+
...state,
|
|
1877
|
+
selectedEvent,
|
|
1878
|
+
selectedEventId: null,
|
|
1879
|
+
selectedEventIndex
|
|
1822
1880
|
};
|
|
1823
1881
|
}
|
|
1882
|
+
const selectedEventDetails = await handleEventRowClickDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
|
|
1824
1883
|
return {
|
|
1825
|
-
|
|
1826
|
-
|
|
1884
|
+
...state,
|
|
1885
|
+
selectedEvent: selectedEventDetails ?? selectedEvent,
|
|
1886
|
+
selectedEventId: selectedEvent.eventId,
|
|
1887
|
+
selectedEventIndex
|
|
1827
1888
|
};
|
|
1828
1889
|
};
|
|
1829
1890
|
|
|
1830
|
-
const
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
const events = await listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName);
|
|
1854
|
-
if (events.length === 0) {
|
|
1855
|
-
return {
|
|
1856
|
-
...state,
|
|
1857
|
-
errorMessage: getSessionNotFoundMessage(sessionId),
|
|
1858
|
-
events: [],
|
|
1859
|
-
initial: false,
|
|
1860
|
-
selectedEventIndex: null,
|
|
1861
|
-
sessionId
|
|
1862
|
-
};
|
|
1863
|
-
}
|
|
1864
|
-
return {
|
|
1865
|
-
...state,
|
|
1866
|
-
errorMessage: '',
|
|
1867
|
-
events,
|
|
1868
|
-
initial: false,
|
|
1869
|
-
selectedEventIndex: null,
|
|
1870
|
-
sessionId
|
|
1871
|
-
};
|
|
1872
|
-
} catch {
|
|
1891
|
+
const getBoolean = value => {
|
|
1892
|
+
return value === true || value === 'true' || value === 'on' || value === '1';
|
|
1893
|
+
};
|
|
1894
|
+
|
|
1895
|
+
const Filter = 'filter';
|
|
1896
|
+
const EventCategoryFilter = 'eventCategoryFilter';
|
|
1897
|
+
const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
|
|
1898
|
+
const ShowInputEvents = 'showInputEvents';
|
|
1899
|
+
const ShowResponsePartEvents = 'showResponsePartEvents';
|
|
1900
|
+
const UseDevtoolsLayout = 'useDevtoolsLayout';
|
|
1901
|
+
const SelectedEventIndex = 'selectedEventIndex';
|
|
1902
|
+
const CloseDetails = 'closeDetails';
|
|
1903
|
+
const DetailTab = 'detailTab';
|
|
1904
|
+
const TimelineStartSeconds = 'timelineStartSeconds';
|
|
1905
|
+
const TimelineEndSeconds = 'timelineEndSeconds';
|
|
1906
|
+
const TimelineRangePreset = 'timelineRangePreset';
|
|
1907
|
+
|
|
1908
|
+
const getCurrentEvents$1 = state => {
|
|
1909
|
+
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
1910
|
+
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
1911
|
+
};
|
|
1912
|
+
const parseTimelineRangePreset = value => {
|
|
1913
|
+
if (!value) {
|
|
1873
1914
|
return {
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
events: [],
|
|
1877
|
-
initial: false,
|
|
1878
|
-
selectedEventIndex: null,
|
|
1879
|
-
sessionId
|
|
1915
|
+
timelineEndSeconds: '',
|
|
1916
|
+
timelineStartSeconds: ''
|
|
1880
1917
|
};
|
|
1881
1918
|
}
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
const refresh = async state => {
|
|
1885
|
-
const events = await listChatViewEvents(state.sessionId, state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionIdIndexName);
|
|
1919
|
+
const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
|
|
1886
1920
|
return {
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
events,
|
|
1890
|
-
initial: false,
|
|
1891
|
-
selectedEventIndex: null
|
|
1921
|
+
timelineEndSeconds,
|
|
1922
|
+
timelineStartSeconds
|
|
1892
1923
|
};
|
|
1893
1924
|
};
|
|
1925
|
+
const getEventIndexByStableId = (events, event) => {
|
|
1926
|
+
const stableEventId = getStableEventId(event);
|
|
1927
|
+
return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
|
|
1928
|
+
};
|
|
1929
|
+
const getSelectedEventIndex = state => {
|
|
1930
|
+
const {
|
|
1931
|
+
selectedEventIndex
|
|
1932
|
+
} = state;
|
|
1933
|
+
if (selectedEventIndex === null) {
|
|
1934
|
+
return null;
|
|
1935
|
+
}
|
|
1936
|
+
const filteredEvents = getCurrentEvents$1(state);
|
|
1937
|
+
const selectedEvent = filteredEvents[selectedEventIndex];
|
|
1938
|
+
if (!selectedEvent) {
|
|
1939
|
+
return null;
|
|
1940
|
+
}
|
|
1941
|
+
const newIndex = getEventIndexByStableId(filteredEvents, selectedEvent);
|
|
1942
|
+
if (newIndex === -1) {
|
|
1943
|
+
return null;
|
|
1944
|
+
}
|
|
1945
|
+
return newIndex;
|
|
1946
|
+
};
|
|
1947
|
+
const getPreservedSelectedEventIndex = (oldState, newState) => {
|
|
1948
|
+
const {
|
|
1949
|
+
selectedEventIndex
|
|
1950
|
+
} = oldState;
|
|
1951
|
+
if (selectedEventIndex === null) {
|
|
1952
|
+
return null;
|
|
1953
|
+
}
|
|
1954
|
+
const oldFilteredEvents = getCurrentEvents$1(oldState);
|
|
1955
|
+
const selectedEvent = oldFilteredEvents[selectedEventIndex];
|
|
1956
|
+
if (!selectedEvent) {
|
|
1957
|
+
return null;
|
|
1958
|
+
}
|
|
1959
|
+
const newFilteredEvents = getCurrentEvents$1(newState);
|
|
1960
|
+
const newIndex = getEventIndexByStableId(newFilteredEvents, selectedEvent);
|
|
1961
|
+
if (newIndex === -1) {
|
|
1962
|
+
return null;
|
|
1963
|
+
}
|
|
1964
|
+
return newIndex;
|
|
1965
|
+
};
|
|
1966
|
+
const parseSelectedEventIndex = value => {
|
|
1967
|
+
const parsed = Number.parseInt(value, 10);
|
|
1968
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
1969
|
+
return null;
|
|
1970
|
+
}
|
|
1971
|
+
return parsed;
|
|
1972
|
+
};
|
|
1973
|
+
const withPreservedSelection = (state, nextState) => {
|
|
1974
|
+
const selectedEventIndex = getPreservedSelectedEventIndex(state, nextState);
|
|
1975
|
+
return {
|
|
1976
|
+
...nextState,
|
|
1977
|
+
selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
|
|
1978
|
+
selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
|
|
1979
|
+
selectedEventIndex
|
|
1980
|
+
};
|
|
1981
|
+
};
|
|
1982
|
+
const handleInput = (state, name, value, checked) => {
|
|
1983
|
+
if (name === Filter) {
|
|
1984
|
+
const nextState = {
|
|
1985
|
+
...state,
|
|
1986
|
+
filterValue: value
|
|
1987
|
+
};
|
|
1988
|
+
return withPreservedSelection(state, nextState);
|
|
1989
|
+
}
|
|
1990
|
+
if (name === EventCategoryFilter) {
|
|
1991
|
+
const nextState = {
|
|
1992
|
+
...state,
|
|
1993
|
+
eventCategoryFilter: value || All
|
|
1994
|
+
};
|
|
1995
|
+
return withPreservedSelection(state, nextState);
|
|
1996
|
+
}
|
|
1997
|
+
if (name === ShowEventStreamFinishedEvents) {
|
|
1998
|
+
const nextState = {
|
|
1999
|
+
...state,
|
|
2000
|
+
showEventStreamFinishedEvents: getBoolean(checked)
|
|
2001
|
+
};
|
|
2002
|
+
return withPreservedSelection(state, nextState);
|
|
2003
|
+
}
|
|
2004
|
+
if (name === ShowInputEvents) {
|
|
2005
|
+
const nextState = {
|
|
2006
|
+
...state,
|
|
2007
|
+
showInputEvents: getBoolean(checked)
|
|
2008
|
+
};
|
|
2009
|
+
return withPreservedSelection(state, nextState);
|
|
2010
|
+
}
|
|
2011
|
+
if (name === ShowResponsePartEvents) {
|
|
2012
|
+
const nextState = {
|
|
2013
|
+
...state,
|
|
2014
|
+
showResponsePartEvents: getBoolean(checked)
|
|
2015
|
+
};
|
|
2016
|
+
return withPreservedSelection(state, nextState);
|
|
2017
|
+
}
|
|
2018
|
+
if (name === UseDevtoolsLayout) {
|
|
2019
|
+
const useDevtoolsLayout = getBoolean(checked);
|
|
2020
|
+
const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex(state) : null;
|
|
2021
|
+
return {
|
|
2022
|
+
...state,
|
|
2023
|
+
selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
|
|
2024
|
+
selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
|
|
2025
|
+
selectedEventIndex,
|
|
2026
|
+
useDevtoolsLayout
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
if (name === SelectedEventIndex) {
|
|
2030
|
+
const selectedEventIndex = parseSelectedEventIndex(value);
|
|
2031
|
+
return {
|
|
2032
|
+
...state,
|
|
2033
|
+
selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
|
|
2034
|
+
selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
|
|
2035
|
+
selectedEventIndex
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
if (name === TimelineStartSeconds) {
|
|
2039
|
+
const nextState = {
|
|
2040
|
+
...state,
|
|
2041
|
+
timelineStartSeconds: value
|
|
2042
|
+
};
|
|
2043
|
+
return withPreservedSelection(state, nextState);
|
|
2044
|
+
}
|
|
2045
|
+
if (name === TimelineEndSeconds) {
|
|
2046
|
+
const nextState = {
|
|
2047
|
+
...state,
|
|
2048
|
+
timelineEndSeconds: value
|
|
2049
|
+
};
|
|
2050
|
+
return withPreservedSelection(state, nextState);
|
|
2051
|
+
}
|
|
2052
|
+
if (name === TimelineRangePreset) {
|
|
2053
|
+
const nextState = {
|
|
2054
|
+
...state,
|
|
2055
|
+
...parseTimelineRangePreset(value)
|
|
2056
|
+
};
|
|
2057
|
+
return withPreservedSelection(state, nextState);
|
|
2058
|
+
}
|
|
2059
|
+
if (name === CloseDetails) {
|
|
2060
|
+
return {
|
|
2061
|
+
...state,
|
|
2062
|
+
selectedEvent: null,
|
|
2063
|
+
selectedEventId: null,
|
|
2064
|
+
selectedEventIndex: null
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
2067
|
+
if (name === DetailTab) {
|
|
2068
|
+
if (!isDetailTab(value)) {
|
|
2069
|
+
return state;
|
|
2070
|
+
}
|
|
2071
|
+
return {
|
|
2072
|
+
...state,
|
|
2073
|
+
selectedDetailTab: value
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
return state;
|
|
2077
|
+
};
|
|
2078
|
+
|
|
2079
|
+
const handleSashPointerDown = (state, eventX, eventY) => {
|
|
2080
|
+
return state;
|
|
2081
|
+
};
|
|
2082
|
+
|
|
2083
|
+
const handleSashPointerMove = (state, eventX, eventY) => {
|
|
2084
|
+
return {
|
|
2085
|
+
...state,
|
|
2086
|
+
tableWidth: getTableWidthFromClientX(state.x, state.width, eventX)
|
|
2087
|
+
};
|
|
2088
|
+
};
|
|
2089
|
+
|
|
2090
|
+
const handleSashPointerUp = (state, eventX, eventY) => {
|
|
2091
|
+
return state;
|
|
2092
|
+
};
|
|
2093
|
+
|
|
2094
|
+
const handleTableBodyContextMenu = state => {
|
|
2095
|
+
return state;
|
|
2096
|
+
};
|
|
2097
|
+
|
|
2098
|
+
const clearTimelineSelectionState = state => {
|
|
2099
|
+
return {
|
|
2100
|
+
...state,
|
|
2101
|
+
timelineSelectionActive: false,
|
|
2102
|
+
timelineSelectionAnchorSeconds: '',
|
|
2103
|
+
timelineSelectionFocusSeconds: ''
|
|
2104
|
+
};
|
|
2105
|
+
};
|
|
2106
|
+
|
|
2107
|
+
const handleTimelineDoubleClick = state => {
|
|
2108
|
+
const nextState = handleInput(state, TimelineRangePreset, '', false);
|
|
2109
|
+
return clearTimelineSelectionState(nextState);
|
|
2110
|
+
};
|
|
2111
|
+
|
|
2112
|
+
const getTimelineEvents = state => {
|
|
2113
|
+
return getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
const getTimelineLeft = state => {
|
|
2117
|
+
return state.x + viewPadding + timelineHorizontalPadding;
|
|
2118
|
+
};
|
|
2119
|
+
const getTimelineWidth = state => {
|
|
2120
|
+
return Math.max(0, getMainWidth(state.width) - timelineHorizontalPadding * 2);
|
|
2121
|
+
};
|
|
2122
|
+
|
|
2123
|
+
const trailingZeroFractionRegex = /\.0+$/;
|
|
2124
|
+
const trailingFractionZeroRegex = /(\.\d*?)0+$/;
|
|
2125
|
+
const formatTimelinePresetValue = value => {
|
|
2126
|
+
return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
|
|
2127
|
+
};
|
|
2128
|
+
|
|
2129
|
+
const getTimelineSecondsFromClientX = (events, eventX, timelineLeft, timelineWidth) => {
|
|
2130
|
+
if (timelineWidth <= 0) {
|
|
2131
|
+
return undefined;
|
|
2132
|
+
}
|
|
2133
|
+
const durationSeconds = getTimelineDurationSeconds(events);
|
|
2134
|
+
const relativeX = Math.min(Math.max(eventX - timelineLeft, 0), timelineWidth);
|
|
2135
|
+
const ratio = relativeX / timelineWidth;
|
|
2136
|
+
return formatTimelinePresetValue(durationSeconds * ratio);
|
|
2137
|
+
};
|
|
2138
|
+
|
|
2139
|
+
const handleTimelinePointerDown = (state, eventX) => {
|
|
2140
|
+
const timelineEvents = getTimelineEvents(state);
|
|
2141
|
+
const timelineLeft = getTimelineLeft(state);
|
|
2142
|
+
const timelineWidth = getTimelineWidth(state);
|
|
2143
|
+
const clientX = state.x + eventX;
|
|
2144
|
+
const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
|
|
2145
|
+
if (seconds === undefined) {
|
|
2146
|
+
return state;
|
|
2147
|
+
}
|
|
2148
|
+
return {
|
|
2149
|
+
...state,
|
|
2150
|
+
timelineSelectionActive: true,
|
|
2151
|
+
timelineSelectionAnchorSeconds: seconds,
|
|
2152
|
+
timelineSelectionFocusSeconds: seconds
|
|
2153
|
+
};
|
|
2154
|
+
};
|
|
2155
|
+
|
|
2156
|
+
const handleTimelinePointerMove = (state, eventX) => {
|
|
2157
|
+
if (!state.timelineSelectionActive) {
|
|
2158
|
+
return state;
|
|
2159
|
+
}
|
|
2160
|
+
const timelineEvents = getTimelineEvents(state);
|
|
2161
|
+
const timelineLeft = getTimelineLeft(state);
|
|
2162
|
+
const timelineWidth = getTimelineWidth(state);
|
|
2163
|
+
const clientX = state.x + eventX;
|
|
2164
|
+
const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
|
|
2165
|
+
if (seconds === undefined) {
|
|
2166
|
+
return state;
|
|
2167
|
+
}
|
|
2168
|
+
return {
|
|
2169
|
+
...state,
|
|
2170
|
+
timelineSelectionFocusSeconds: seconds
|
|
2171
|
+
};
|
|
2172
|
+
};
|
|
2173
|
+
|
|
2174
|
+
const handleTimelinePointerUp = (state, eventX) => {
|
|
2175
|
+
if (!state.timelineSelectionActive) {
|
|
2176
|
+
return state;
|
|
2177
|
+
}
|
|
2178
|
+
const timelineEvents = getTimelineEvents(state);
|
|
2179
|
+
const timelineLeft = getTimelineLeft(state);
|
|
2180
|
+
const timelineWidth = getTimelineWidth(state);
|
|
2181
|
+
const clientX = state.x + eventX;
|
|
2182
|
+
const focusSeconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
|
|
2183
|
+
if (focusSeconds === undefined) {
|
|
2184
|
+
return clearTimelineSelectionState(state);
|
|
2185
|
+
}
|
|
2186
|
+
const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
|
|
2187
|
+
const focus = Number.parseFloat(focusSeconds);
|
|
2188
|
+
const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
|
|
2189
|
+
const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
|
|
2190
|
+
const nextState = handleInput(state, TimelineRangePreset, `${startSeconds}:${endSeconds}`, false);
|
|
2191
|
+
return clearTimelineSelectionState(nextState);
|
|
2192
|
+
};
|
|
2193
|
+
|
|
2194
|
+
const getFailedToLoadMessage = sessionId => {
|
|
2195
|
+
return `Failed to load chat debug session "${sessionId}". Please try again.`;
|
|
2196
|
+
};
|
|
2197
|
+
|
|
2198
|
+
const getIndexedDbNotSupportedMessage = () => {
|
|
2199
|
+
return 'Unable to load chat debug session: IndexedDB is not supported in this environment.';
|
|
2200
|
+
};
|
|
2201
|
+
|
|
2202
|
+
const ParseChatDebugUriErrorCode = {
|
|
2203
|
+
InvalidSessionId: 'invalid-session-id',
|
|
2204
|
+
InvalidUriEncoding: 'invalid-uri-encoding',
|
|
2205
|
+
InvalidUriFormat: 'invalid-uri-format',
|
|
2206
|
+
MissingUri: 'missing-uri'
|
|
2207
|
+
};
|
|
2208
|
+
|
|
2209
|
+
const getInvalidUriMessage = (uri, code) => {
|
|
2210
|
+
if (code === ParseChatDebugUriErrorCode.MissingUri) {
|
|
2211
|
+
return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
|
|
2212
|
+
}
|
|
2213
|
+
return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
|
|
2214
|
+
};
|
|
2215
|
+
|
|
2216
|
+
const getSessionNotFoundMessage = sessionId => {
|
|
2217
|
+
return `No chat session found for sessionId "${sessionId}".`;
|
|
2218
|
+
};
|
|
2219
|
+
|
|
2220
|
+
const filterEventsBySessionId = (events, sessionId) => {
|
|
2221
|
+
return events.filter(event => event.sessionId === sessionId);
|
|
2222
|
+
};
|
|
2223
|
+
|
|
2224
|
+
// cspell:ignore IDBP
|
|
2225
|
+
|
|
2226
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2227
|
+
const getAllEvents = async store => {
|
|
2228
|
+
const all = await store.getAll();
|
|
2229
|
+
return all;
|
|
2230
|
+
};
|
|
2231
|
+
|
|
2232
|
+
const getEndTime = event => {
|
|
2233
|
+
return event.ended ?? event.endTime ?? event.timestamp;
|
|
2234
|
+
};
|
|
2235
|
+
|
|
2236
|
+
const getStartTime = event => {
|
|
2237
|
+
return event.started ?? event.startTime ?? event.timestamp;
|
|
2238
|
+
};
|
|
2239
|
+
|
|
2240
|
+
const getDuration = event => {
|
|
2241
|
+
const explicitDuration = event.durationMs ?? event.duration;
|
|
2242
|
+
if (typeof explicitDuration === 'number' && Number.isFinite(explicitDuration)) {
|
|
2243
|
+
return explicitDuration;
|
|
2244
|
+
}
|
|
2245
|
+
const start = toTimeNumber(getStartTime(event));
|
|
2246
|
+
const end = toTimeNumber(getEndTime(event));
|
|
2247
|
+
if (start === undefined || end === undefined || !Number.isFinite(start) || !Number.isFinite(end)) {
|
|
2248
|
+
return 0;
|
|
2249
|
+
}
|
|
2250
|
+
return Math.max(0, end - start);
|
|
2251
|
+
};
|
|
2252
|
+
|
|
2253
|
+
const isTimeValue = value => {
|
|
2254
|
+
return typeof value === 'number' || typeof value === 'string';
|
|
2255
|
+
};
|
|
2256
|
+
|
|
2257
|
+
const getLightweightEvent = (event, fallbackEventId) => {
|
|
2258
|
+
const startTime = getStartTime(event);
|
|
2259
|
+
const endTime = getEndTime(event);
|
|
2260
|
+
return {
|
|
2261
|
+
duration: getDuration(event),
|
|
2262
|
+
...(isTimeValue(endTime) ? {
|
|
2263
|
+
endTime
|
|
2264
|
+
} : {}),
|
|
2265
|
+
eventId: typeof event.eventId === 'number' ? event.eventId : fallbackEventId,
|
|
2266
|
+
...(isTimeValue(startTime) ? {
|
|
2267
|
+
startTime
|
|
2268
|
+
} : {}),
|
|
2269
|
+
type: event.type
|
|
2270
|
+
};
|
|
2271
|
+
};
|
|
2272
|
+
|
|
2273
|
+
// cspell:ignore IDBP
|
|
2274
|
+
|
|
2275
|
+
const toLightweightEvents = events => {
|
|
2276
|
+
const eventsWithIds = events.map((event, index) => {
|
|
2277
|
+
return {
|
|
2278
|
+
...event,
|
|
2279
|
+
eventId: index + 1
|
|
2280
|
+
};
|
|
2281
|
+
});
|
|
2282
|
+
return collapseToolExecutionEvents(eventsWithIds).map((event, index) => getLightweightEvent(event, index + 1));
|
|
2283
|
+
};
|
|
2284
|
+
const getEventsBySessionId = async (store, sessionId, sessionIdIndexName) => {
|
|
2285
|
+
if (store.indexNames.contains(sessionIdIndexName)) {
|
|
2286
|
+
const index = store.index(sessionIdIndexName);
|
|
2287
|
+
const events = await index.getAll(sessionId);
|
|
2288
|
+
return toLightweightEvents(filterEventsBySessionId(events, sessionId));
|
|
2289
|
+
}
|
|
2290
|
+
const all = await getAllEvents(store);
|
|
2291
|
+
return toLightweightEvents(filterEventsBySessionId(all, sessionId));
|
|
2292
|
+
};
|
|
2293
|
+
|
|
2294
|
+
let indexedDbSupportOverride;
|
|
2295
|
+
const getIndexedDbSupportOverride = () => {
|
|
2296
|
+
return indexedDbSupportOverride;
|
|
2297
|
+
};
|
|
2298
|
+
const setIndexedDbSupportOverride = supported => {
|
|
2299
|
+
indexedDbSupportOverride = supported;
|
|
2300
|
+
};
|
|
2301
|
+
|
|
2302
|
+
const isIndexedDbSupported = indexedDbSupportOverride => {
|
|
2303
|
+
if (typeof indexedDbSupportOverride === 'boolean') {
|
|
2304
|
+
return indexedDbSupportOverride;
|
|
2305
|
+
}
|
|
2306
|
+
const override = getIndexedDbSupportOverride();
|
|
2307
|
+
if (typeof override === 'boolean') {
|
|
2308
|
+
return override;
|
|
2309
|
+
}
|
|
2310
|
+
return globalThis.indexedDB !== undefined;
|
|
2311
|
+
};
|
|
2312
|
+
|
|
2313
|
+
const listChatViewEventsDependencies = {
|
|
2314
|
+
getEventsBySessionId: getEventsBySessionId,
|
|
2315
|
+
openDatabase: openDatabase
|
|
2316
|
+
};
|
|
2317
|
+
const listChatViewEvents = async (sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName, indexedDbSupportOverride) => {
|
|
2318
|
+
if (!isIndexedDbSupported(indexedDbSupportOverride)) {
|
|
2319
|
+
return {
|
|
2320
|
+
type: 'not-supported'
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
try {
|
|
2324
|
+
const database = await listChatViewEventsDependencies.openDatabase(databaseName, dataBaseVersion);
|
|
2325
|
+
try {
|
|
2326
|
+
if (!database.objectStoreNames.contains(eventStoreName)) {
|
|
2327
|
+
return {
|
|
2328
|
+
events: [],
|
|
2329
|
+
type: 'success'
|
|
2330
|
+
};
|
|
2331
|
+
}
|
|
2332
|
+
const transaction = database.transaction(eventStoreName, 'readonly');
|
|
2333
|
+
const store = transaction.objectStore(eventStoreName);
|
|
2334
|
+
if (!sessionId) {
|
|
2335
|
+
return {
|
|
2336
|
+
events: [],
|
|
2337
|
+
type: 'success'
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
const events = await listChatViewEventsDependencies.getEventsBySessionId(store, sessionId, sessionIdIndexName);
|
|
2341
|
+
return {
|
|
2342
|
+
events,
|
|
2343
|
+
type: 'success'
|
|
2344
|
+
};
|
|
2345
|
+
} finally {
|
|
2346
|
+
database.close();
|
|
2347
|
+
}
|
|
2348
|
+
} catch (error) {
|
|
2349
|
+
return {
|
|
2350
|
+
error,
|
|
2351
|
+
type: 'error'
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
};
|
|
2355
|
+
|
|
2356
|
+
const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
|
|
2357
|
+
const invalidSessionIdPattern = /[/?#]/;
|
|
2358
|
+
const parseChatDebugUri = uri => {
|
|
2359
|
+
if (!uri) {
|
|
2360
|
+
return {
|
|
2361
|
+
code: ParseChatDebugUriErrorCode.MissingUri,
|
|
2362
|
+
message: 'Missing URI',
|
|
2363
|
+
type: 'error'
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
const match = uri.match(chatDebugUriPattern);
|
|
2367
|
+
if (!match) {
|
|
2368
|
+
return {
|
|
2369
|
+
code: ParseChatDebugUriErrorCode.InvalidUriFormat,
|
|
2370
|
+
message: 'Invalid URI format',
|
|
2371
|
+
type: 'error'
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
const encodedSessionId = match[1];
|
|
2375
|
+
let sessionId;
|
|
2376
|
+
try {
|
|
2377
|
+
sessionId = decodeURIComponent(encodedSessionId);
|
|
2378
|
+
} catch {
|
|
2379
|
+
return {
|
|
2380
|
+
code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
|
|
2381
|
+
message: 'Invalid URI encoding',
|
|
2382
|
+
type: 'error'
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
|
|
2386
|
+
return {
|
|
2387
|
+
code: ParseChatDebugUriErrorCode.InvalidSessionId,
|
|
2388
|
+
message: 'Invalid session id',
|
|
2389
|
+
type: 'error'
|
|
2390
|
+
};
|
|
2391
|
+
}
|
|
2392
|
+
return {
|
|
2393
|
+
sessionId,
|
|
2394
|
+
type: 'success'
|
|
2395
|
+
};
|
|
2396
|
+
};
|
|
2397
|
+
|
|
2398
|
+
const loadEventsDependencies = {
|
|
2399
|
+
listChatViewEvents: listChatViewEvents,
|
|
2400
|
+
loadSelectedEvent: loadSelectedEvent
|
|
2401
|
+
};
|
|
2402
|
+
const getCurrentEvents = state => {
|
|
2403
|
+
const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
|
|
2404
|
+
return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
|
|
2405
|
+
};
|
|
2406
|
+
const restoreSelectedEvent = async state => {
|
|
2407
|
+
if (state.selectedEventId === null) {
|
|
2408
|
+
return {
|
|
2409
|
+
...state,
|
|
2410
|
+
selectedEvent: null,
|
|
2411
|
+
selectedEventIndex: null
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
const currentEvents = getCurrentEvents(state);
|
|
2415
|
+
const selectedEventIndex = currentEvents.findIndex(event => event.eventId === state.selectedEventId);
|
|
2416
|
+
if (selectedEventIndex === -1) {
|
|
2417
|
+
return {
|
|
2418
|
+
...state,
|
|
2419
|
+
selectedEvent: null,
|
|
2420
|
+
selectedEventId: null,
|
|
2421
|
+
selectedEventIndex: null
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
const selectedEvent = currentEvents[selectedEventIndex];
|
|
2425
|
+
if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
|
|
2426
|
+
return {
|
|
2427
|
+
...state,
|
|
2428
|
+
selectedEvent: null,
|
|
2429
|
+
selectedEventId: null,
|
|
2430
|
+
selectedEventIndex: null
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
|
|
2434
|
+
return {
|
|
2435
|
+
...state,
|
|
2436
|
+
selectedEvent: selectedEventDetails,
|
|
2437
|
+
selectedEventId: selectedEvent.eventId,
|
|
2438
|
+
selectedEventIndex
|
|
2439
|
+
};
|
|
2440
|
+
};
|
|
2441
|
+
const getStateWithInvalidUri = state => {
|
|
2442
|
+
const parsed = parseChatDebugUri(state.uri);
|
|
2443
|
+
if (parsed.type !== 'error') {
|
|
2444
|
+
return state;
|
|
2445
|
+
}
|
|
2446
|
+
return {
|
|
2447
|
+
...state,
|
|
2448
|
+
errorMessage: getInvalidUriMessage(state.uri, parsed.code),
|
|
2449
|
+
events: [],
|
|
2450
|
+
initial: false,
|
|
2451
|
+
selectedEvent: null,
|
|
2452
|
+
selectedEventId: null,
|
|
2453
|
+
selectedEventIndex: null,
|
|
2454
|
+
sessionId: ''
|
|
2455
|
+
};
|
|
2456
|
+
};
|
|
2457
|
+
const getSessionIdFromUri = state => {
|
|
2458
|
+
const parsed = parseChatDebugUri(state.uri);
|
|
2459
|
+
if (parsed.type === 'error') {
|
|
2460
|
+
return undefined;
|
|
2461
|
+
}
|
|
2462
|
+
return parsed.sessionId;
|
|
2463
|
+
};
|
|
2464
|
+
const loadEventsForSessionId = async (state, sessionId) => {
|
|
2465
|
+
const {
|
|
2466
|
+
databaseName,
|
|
2467
|
+
dataBaseVersion,
|
|
2468
|
+
eventStoreName,
|
|
2469
|
+
indexedDbSupportOverride,
|
|
2470
|
+
sessionIdIndexName
|
|
2471
|
+
} = state;
|
|
2472
|
+
const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName, indexedDbSupportOverride);
|
|
2473
|
+
if (result.type === 'not-supported') {
|
|
2474
|
+
return {
|
|
2475
|
+
...state,
|
|
2476
|
+
errorMessage: getIndexedDbNotSupportedMessage(),
|
|
2477
|
+
events: [],
|
|
2478
|
+
initial: false,
|
|
2479
|
+
selectedEvent: null,
|
|
2480
|
+
selectedEventId: null,
|
|
2481
|
+
selectedEventIndex: null,
|
|
2482
|
+
sessionId
|
|
2483
|
+
};
|
|
2484
|
+
}
|
|
2485
|
+
if (result.type === 'error') {
|
|
2486
|
+
return {
|
|
2487
|
+
...state,
|
|
2488
|
+
errorMessage: getFailedToLoadMessage(sessionId),
|
|
2489
|
+
events: [],
|
|
2490
|
+
initial: false,
|
|
2491
|
+
selectedEvent: null,
|
|
2492
|
+
selectedEventId: null,
|
|
2493
|
+
selectedEventIndex: null,
|
|
2494
|
+
sessionId
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2497
|
+
const {
|
|
2498
|
+
events
|
|
2499
|
+
} = result;
|
|
2500
|
+
if (events.length === 0) {
|
|
2501
|
+
return {
|
|
2502
|
+
...state,
|
|
2503
|
+
errorMessage: getSessionNotFoundMessage(sessionId),
|
|
2504
|
+
events: [],
|
|
2505
|
+
initial: false,
|
|
2506
|
+
selectedEvent: null,
|
|
2507
|
+
selectedEventId: null,
|
|
2508
|
+
selectedEventIndex: null,
|
|
2509
|
+
sessionId
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
const nextState = {
|
|
2513
|
+
...state,
|
|
2514
|
+
errorMessage: '',
|
|
2515
|
+
events,
|
|
2516
|
+
initial: false,
|
|
2517
|
+
sessionId
|
|
2518
|
+
};
|
|
2519
|
+
return restoreSelectedEvent(nextState);
|
|
2520
|
+
};
|
|
2521
|
+
const loadEventsFromUri = async state => {
|
|
2522
|
+
const sessionId = getSessionIdFromUri(state);
|
|
2523
|
+
if (!sessionId) {
|
|
2524
|
+
return getStateWithInvalidUri(state);
|
|
2525
|
+
}
|
|
2526
|
+
return loadEventsForSessionId(state, sessionId);
|
|
2527
|
+
};
|
|
2528
|
+
const refreshEvents = async state => {
|
|
2529
|
+
const sessionId = state.sessionId || getSessionIdFromUri(state);
|
|
2530
|
+
if (!sessionId) {
|
|
2531
|
+
return getStateWithInvalidUri(state);
|
|
2532
|
+
}
|
|
2533
|
+
return loadEventsForSessionId(state, sessionId);
|
|
2534
|
+
};
|
|
2535
|
+
|
|
2536
|
+
const loadContent = async state => {
|
|
2537
|
+
return loadEventsFromUri(state);
|
|
2538
|
+
};
|
|
2539
|
+
|
|
2540
|
+
const refresh = async state => {
|
|
2541
|
+
return refreshEvents(state);
|
|
2542
|
+
};
|
|
2543
|
+
|
|
2544
|
+
const ClientX = 'event.clientX';
|
|
2545
|
+
const ClientY = 'event.clientY';
|
|
2546
|
+
const TargetChecked = 'event.target.checked';
|
|
2547
|
+
const TargetName = 'event.target.name';
|
|
2548
|
+
const TargetValue = 'event.target.value';
|
|
2549
|
+
|
|
2550
|
+
const SetCss = 'Viewlet.setCss';
|
|
2551
|
+
const SetDom2 = 'Viewlet.setDom2';
|
|
2552
|
+
const SetPatches = 'Viewlet.setPatches';
|
|
1894
2553
|
|
|
1895
|
-
const
|
|
1896
|
-
const
|
|
1897
|
-
const
|
|
1898
|
-
|
|
1899
|
-
const SetCss = 'Viewlet.setCss';
|
|
1900
|
-
const SetDom2 = 'Viewlet.setDom2';
|
|
1901
|
-
const SetPatches = 'Viewlet.setPatches';
|
|
1902
|
-
|
|
1903
|
-
const getCss = () => {
|
|
2554
|
+
const getCss = state => {
|
|
2555
|
+
const tableWidth = clampTableWidth(state.width, state.tableWidth);
|
|
2556
|
+
const detailsWidth = getDetailsWidth(state.width, state.tableWidth);
|
|
1904
2557
|
return `
|
|
1905
2558
|
.ChatDebugView {
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
2559
|
+
--ChatDebugViewDetailsWidth: ${detailsWidth}px;
|
|
2560
|
+
--ChatDebugViewSashWidth: ${sashWidth}px;
|
|
2561
|
+
--ChatDebugViewTableWidth: ${tableWidth}px;
|
|
2562
|
+
padding: ${viewPadding}px;
|
|
2563
|
+
display: flex;
|
|
2564
|
+
flex-direction: column;
|
|
1909
2565
|
height: 100%;
|
|
1910
2566
|
box-sizing: border-box;
|
|
1911
2567
|
gap: 8px;
|
|
2568
|
+
contain: strict;
|
|
1912
2569
|
}
|
|
1913
2570
|
|
|
1914
2571
|
.ChatDebugView--devtools {
|
|
@@ -1920,48 +2577,61 @@ const getCss = () => {
|
|
|
1920
2577
|
align-items: center;
|
|
1921
2578
|
gap: 12px;
|
|
1922
2579
|
flex-wrap: wrap;
|
|
2580
|
+
contain: content;
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
.ChatDebugViewTop--devtools {
|
|
2584
|
+
align-items: stretch;
|
|
1923
2585
|
}
|
|
1924
2586
|
|
|
1925
|
-
.
|
|
2587
|
+
.ChatDebugViewFilterInput {
|
|
1926
2588
|
flex: 1;
|
|
2589
|
+
min-width: 0;
|
|
2590
|
+
max-width: 500px;
|
|
2591
|
+
contain: content;
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
.ChatDebugViewFilterInput--devtools {
|
|
2595
|
+
flex: 0 1 80px;
|
|
2596
|
+
width: 100%;
|
|
2597
|
+
max-width: 80px;
|
|
1927
2598
|
}
|
|
1928
2599
|
|
|
1929
|
-
.
|
|
2600
|
+
.ChatDebugViewQuickFilterPill {
|
|
1930
2601
|
display: flex;
|
|
1931
2602
|
align-items: center;
|
|
1932
|
-
|
|
2603
|
+
justify-content: center;
|
|
2604
|
+
min-height: 22px;
|
|
2605
|
+
padding: 0 10px;
|
|
2606
|
+
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2607
|
+
border-radius: 999px;
|
|
2608
|
+
cursor: pointer;
|
|
1933
2609
|
white-space: nowrap;
|
|
2610
|
+
transition:
|
|
2611
|
+
background 120ms ease-out,
|
|
2612
|
+
border-color 120ms ease-out,
|
|
2613
|
+
color 120ms ease-out,
|
|
2614
|
+
transform 120ms ease-out;
|
|
2615
|
+
contain: content;
|
|
1934
2616
|
}
|
|
1935
2617
|
|
|
1936
|
-
.
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2618
|
+
.ChatDebugViewQuickFilterPill:not(.ChatDebugViewQuickFilterPillSelected):hover {
|
|
2619
|
+
border-color: var(--vscode-focusBorder, #007fd4);
|
|
2620
|
+
background: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 82%, transparent 18%);
|
|
2621
|
+
color: var(--vscode-list-hoverForeground, inherit);
|
|
2622
|
+
transform: translateY(-1px);
|
|
1940
2623
|
}
|
|
1941
2624
|
|
|
1942
|
-
.ChatDebugViewEventCount {
|
|
1943
|
-
font-size: 12px;
|
|
1944
|
-
opacity: 0.8;
|
|
1945
|
-
}
|
|
1946
2625
|
|
|
1947
2626
|
.ChatDebugViewQuickFilters {
|
|
1948
2627
|
display: flex;
|
|
1949
|
-
gap: 8px;
|
|
1950
|
-
flex-wrap: wrap;
|
|
1951
|
-
}
|
|
1952
|
-
|
|
1953
|
-
.ChatDebugViewQuickFilterPill {
|
|
1954
|
-
display: inline-flex;
|
|
1955
2628
|
align-items: center;
|
|
2629
|
+
gap: 8px;
|
|
1956
2630
|
justify-content: center;
|
|
1957
2631
|
min-height: 28px;
|
|
1958
|
-
padding: 0 12px;
|
|
1959
|
-
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
1960
|
-
border-radius: 999px;
|
|
1961
|
-
background: var(--vscode-editorWidget-background, transparent);
|
|
1962
|
-
cursor: pointer;
|
|
1963
2632
|
font-size: 12px;
|
|
1964
2633
|
line-height: 1;
|
|
2634
|
+
contain: content;
|
|
1965
2635
|
}
|
|
1966
2636
|
|
|
1967
2637
|
.ChatDebugViewQuickFilterPillSelected {
|
|
@@ -1974,65 +2644,125 @@ const getCss = () => {
|
|
|
1974
2644
|
position: absolute;
|
|
1975
2645
|
opacity: 0;
|
|
1976
2646
|
pointer-events: none;
|
|
2647
|
+
contain: content;
|
|
1977
2648
|
}
|
|
1978
2649
|
|
|
1979
2650
|
.ChatDebugViewEvents {
|
|
1980
|
-
display:
|
|
1981
|
-
|
|
2651
|
+
display: flex;
|
|
2652
|
+
flex-direction: column;
|
|
1982
2653
|
overflow: auto;
|
|
1983
2654
|
min-width: 0;
|
|
1984
2655
|
min-height: 0;
|
|
1985
2656
|
scrollbar-width: thin;
|
|
1986
2657
|
scrollbar-color: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4)) transparent;
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
.ChatDebugViewEvents--timeline {
|
|
1990
|
-
grid-template-rows: auto auto minmax(0, 1fr);
|
|
2658
|
+
contain: strict;
|
|
1991
2659
|
}
|
|
1992
2660
|
|
|
1993
2661
|
.ChatDebugView--devtools .ChatDebugViewEvents {
|
|
1994
|
-
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
1995
2662
|
border-radius: 6px;
|
|
1996
2663
|
margin-bottom: 0;
|
|
2664
|
+
overflow: hidden;
|
|
1997
2665
|
}
|
|
1998
2666
|
|
|
1999
2667
|
.ChatDebugViewEventsFullWidth {
|
|
2000
|
-
|
|
2668
|
+
flex: 1 1 100%;
|
|
2001
2669
|
}
|
|
2002
2670
|
|
|
2003
2671
|
.ChatDebugViewDevtoolsMain {
|
|
2004
|
-
display:
|
|
2005
|
-
|
|
2006
|
-
|
|
2672
|
+
display: flex;
|
|
2673
|
+
flex-direction: column;
|
|
2674
|
+
flex: 1;
|
|
2675
|
+
align-items: stretch;
|
|
2676
|
+
gap: 0;
|
|
2677
|
+
min-width: 0;
|
|
2678
|
+
min-height: 0;
|
|
2679
|
+
contain: strict;
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
.ChatDebugViewDevtoolsMain > .ChatDebugViewTimeline {
|
|
2683
|
+
flex: 0 0 auto;
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
.ChatDebugViewDevtoolsSplit {
|
|
2687
|
+
display: flex;
|
|
2688
|
+
flex: 1;
|
|
2689
|
+
align-items: stretch;
|
|
2690
|
+
gap: 0;
|
|
2007
2691
|
min-width: 0;
|
|
2008
2692
|
min-height: 0;
|
|
2009
2693
|
overflow: hidden;
|
|
2694
|
+
contain: strict;
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
.ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents {
|
|
2698
|
+
flex: 0 1 var(--ChatDebugViewTableWidth);
|
|
2699
|
+
min-width: 0;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
.ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents.ChatDebugViewEventsFullWidth {
|
|
2703
|
+
flex: 1 1 100%;
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
.ChatDebugViewDevtoolsSplit > .ChatDebugViewDetails {
|
|
2707
|
+
border-left: 0;
|
|
2708
|
+
border-top-left-radius: 0;
|
|
2709
|
+
border-bottom-left-radius: 0;
|
|
2710
|
+
flex: 1;
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
.ChatDebugViewSash {
|
|
2714
|
+
flex: 0 0 var(--ChatDebugViewSashWidth);
|
|
2715
|
+
position: relative;
|
|
2716
|
+
cursor: col-resize;
|
|
2717
|
+
display: flex;
|
|
2718
|
+
justify-content: center;
|
|
2719
|
+
min-height: 0;
|
|
2720
|
+
contain: strict;
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
.ChatDebugViewSashLine {
|
|
2724
|
+
width: 1px;
|
|
2725
|
+
height: 100%;
|
|
2726
|
+
background: var(--vscode-editorWidget-border, #454545);
|
|
2727
|
+
pointer-events: none;
|
|
2728
|
+
contain: strict;
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
.ChatDebugViewSash:hover .ChatDebugViewSashLine {
|
|
2732
|
+
background: var(--vscode-focusBorder, #007fd4);
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
.ChatDebugViewTable {
|
|
2736
|
+
display: flex;
|
|
2737
|
+
flex-direction: column;
|
|
2738
|
+
min-height: 0;
|
|
2739
|
+
flex: 1 1 auto;
|
|
2740
|
+
contain: strict;
|
|
2010
2741
|
}
|
|
2011
2742
|
|
|
2012
2743
|
.ChatDebugViewTimeline {
|
|
2013
|
-
display:
|
|
2014
|
-
|
|
2015
|
-
|
|
2744
|
+
display: flex;
|
|
2745
|
+
flex-direction: column;
|
|
2746
|
+
gap: 6px;
|
|
2747
|
+
padding: 6px ${timelineHorizontalPadding}px 8px;
|
|
2016
2748
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2017
2749
|
background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 82%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.12)) 18%);
|
|
2750
|
+
contain: content;
|
|
2018
2751
|
}
|
|
2019
2752
|
|
|
2020
2753
|
.ChatDebugViewTimelineTop {
|
|
2021
2754
|
display: flex;
|
|
2022
|
-
align-items:
|
|
2023
|
-
|
|
2024
|
-
gap: 8px;
|
|
2025
|
-
flex-wrap: wrap;
|
|
2026
|
-
}
|
|
2027
|
-
|
|
2028
|
-
.ChatDebugViewTimelineTitle {
|
|
2029
|
-
font-size: 12px;
|
|
2030
|
-
font-weight: 600;
|
|
2755
|
+
align-items: center;
|
|
2756
|
+
contain: content;
|
|
2031
2757
|
}
|
|
2032
2758
|
|
|
2033
2759
|
.ChatDebugViewTimelineSummary {
|
|
2760
|
+
display: flex;
|
|
2761
|
+
align-items: center;
|
|
2034
2762
|
font-size: 12px;
|
|
2763
|
+
line-height: 16px;
|
|
2035
2764
|
opacity: 0.8;
|
|
2765
|
+
contain: content;
|
|
2036
2766
|
}
|
|
2037
2767
|
|
|
2038
2768
|
.ChatDebugViewTimelineControls {
|
|
@@ -2040,71 +2770,93 @@ const getCss = () => {
|
|
|
2040
2770
|
align-items: center;
|
|
2041
2771
|
gap: 8px;
|
|
2042
2772
|
flex-wrap: wrap;
|
|
2773
|
+
contain: content;
|
|
2043
2774
|
}
|
|
2044
2775
|
|
|
2045
|
-
.
|
|
2046
|
-
display:
|
|
2047
|
-
align-items:
|
|
2048
|
-
gap:
|
|
2049
|
-
|
|
2776
|
+
.ChatDebugViewTimelineBuckets {
|
|
2777
|
+
display: flex;
|
|
2778
|
+
align-items: end;
|
|
2779
|
+
gap: 3px;
|
|
2780
|
+
flex: 1 1 auto;
|
|
2781
|
+
min-height: 52px;
|
|
2782
|
+
pointer-events: none;
|
|
2783
|
+
contain: strict;
|
|
2050
2784
|
}
|
|
2051
2785
|
|
|
2052
|
-
.
|
|
2053
|
-
|
|
2786
|
+
.ChatDebugViewTimelineInteractive {
|
|
2787
|
+
display: flex;
|
|
2788
|
+
position: relative;
|
|
2789
|
+
min-height: 52px;
|
|
2790
|
+
cursor: crosshair;
|
|
2791
|
+
user-select: none;
|
|
2792
|
+
contain: strict;
|
|
2054
2793
|
}
|
|
2055
2794
|
|
|
2056
|
-
.
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
padding: 0 12px;
|
|
2062
|
-
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2063
|
-
border-radius: 999px;
|
|
2064
|
-
cursor: pointer;
|
|
2065
|
-
font-size: 12px;
|
|
2795
|
+
.ChatDebugViewTimelineSelectionOverlay {
|
|
2796
|
+
position: absolute;
|
|
2797
|
+
inset: 0;
|
|
2798
|
+
pointer-events: none;
|
|
2799
|
+
contain: strict;
|
|
2066
2800
|
}
|
|
2067
2801
|
|
|
2068
|
-
.
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2802
|
+
.ChatDebugViewTimelineSelectionRange {
|
|
2803
|
+
position: absolute;
|
|
2804
|
+
top: 0;
|
|
2805
|
+
bottom: 0;
|
|
2806
|
+
background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 20%, transparent 80%);
|
|
2807
|
+
border-left: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
|
|
2808
|
+
border-right: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
|
|
2809
|
+
contain: strict;
|
|
2072
2810
|
}
|
|
2073
2811
|
|
|
2074
|
-
.
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2812
|
+
.ChatDebugViewTimelineSelectionMarker {
|
|
2813
|
+
position: absolute;
|
|
2814
|
+
top: 0;
|
|
2815
|
+
bottom: 0;
|
|
2816
|
+
width: 1px;
|
|
2817
|
+
margin-left: -0.5px;
|
|
2818
|
+
background: var(--vscode-focusBorder, #007fd4);
|
|
2819
|
+
box-shadow: 0 0 0 1px color-mix(in srgb, var(--vscode-focusBorder, #007fd4) 24%, transparent 76%);
|
|
2820
|
+
contain: strict;
|
|
2080
2821
|
}
|
|
2081
2822
|
|
|
2082
2823
|
.ChatDebugViewTimelineBucket {
|
|
2824
|
+
--ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 74%, transparent 26%);
|
|
2825
|
+
--ChatDebugViewTimelineBucketBarBorderColor: transparent;
|
|
2083
2826
|
display: flex;
|
|
2084
2827
|
align-items: stretch;
|
|
2085
|
-
|
|
2086
|
-
|
|
2828
|
+
flex: 1 1 10px;
|
|
2829
|
+
min-width: 10px;
|
|
2830
|
+
min-height: 52px;
|
|
2831
|
+
contain: strict;
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
.ChatDebugViewTimelineBucketSelected {
|
|
2835
|
+
--ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
|
|
2836
|
+
--ChatDebugViewTimelineBucketBarBorderColor: var(--vscode-focusBorder, #007fd4);
|
|
2087
2837
|
}
|
|
2088
2838
|
|
|
2089
2839
|
.ChatDebugViewTimelinePresetInput {
|
|
2090
2840
|
position: absolute;
|
|
2091
2841
|
opacity: 0;
|
|
2092
2842
|
pointer-events: none;
|
|
2843
|
+
contain: content;
|
|
2093
2844
|
}
|
|
2094
2845
|
|
|
2095
2846
|
.ChatDebugViewTimelineBucketBar {
|
|
2096
|
-
width: 100%;
|
|
2097
2847
|
display: flex;
|
|
2098
2848
|
flex-direction: column;
|
|
2099
2849
|
justify-content: flex-end;
|
|
2100
2850
|
gap: 2px;
|
|
2101
|
-
padding:
|
|
2851
|
+
padding: 6px 1px 2px;
|
|
2102
2852
|
border: 1px solid transparent;
|
|
2103
|
-
border-radius:
|
|
2104
|
-
|
|
2853
|
+
border-radius: 2px;
|
|
2854
|
+
width: 100%;
|
|
2855
|
+
background: var(--ChatDebugViewTimelineBucketBarBackground);
|
|
2856
|
+
border-color: var(--ChatDebugViewTimelineBucketBarBorderColor);
|
|
2857
|
+
contain: strict;
|
|
2105
2858
|
}
|
|
2106
2859
|
|
|
2107
|
-
.ChatDebugViewTimelineBucketSelected .ChatDebugViewTimelineBucketBar,
|
|
2108
2860
|
.ChatDebugViewTimelineBucketBarSelected {
|
|
2109
2861
|
background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
|
|
2110
2862
|
border-color: var(--vscode-focusBorder, #007fd4);
|
|
@@ -2115,6 +2867,7 @@ const getCss = () => {
|
|
|
2115
2867
|
height: 4px;
|
|
2116
2868
|
border-radius: 999px;
|
|
2117
2869
|
background: var(--vscode-charts-blue, #75beff);
|
|
2870
|
+
contain: strict;
|
|
2118
2871
|
}
|
|
2119
2872
|
|
|
2120
2873
|
.ChatDebugViewTimelineBucketUnitEmpty {
|
|
@@ -2122,37 +2875,50 @@ const getCss = () => {
|
|
|
2122
2875
|
background: var(--vscode-editorWidget-border, #454545);
|
|
2123
2876
|
}
|
|
2124
2877
|
|
|
2125
|
-
.
|
|
2878
|
+
.ChatDebugViewTableHeaderRow,
|
|
2126
2879
|
.ChatDebugViewEventRow {
|
|
2127
|
-
display:
|
|
2128
|
-
grid-template-columns: minmax(140px, 1fr) minmax(180px, 1fr) minmax(180px, 1fr) 90px 64px;
|
|
2880
|
+
display: flex;
|
|
2129
2881
|
align-items: center;
|
|
2130
2882
|
gap: 8px;
|
|
2883
|
+
contain: content;
|
|
2131
2884
|
}
|
|
2132
2885
|
|
|
2133
2886
|
.ChatDebugViewTableHeader {
|
|
2134
|
-
padding: 8px;
|
|
2887
|
+
padding: 3px 8px;
|
|
2135
2888
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2136
2889
|
background: var(--vscode-editorWidget-background, transparent);
|
|
2137
2890
|
position: sticky;
|
|
2138
2891
|
top: 0;
|
|
2139
2892
|
z-index: 1;
|
|
2893
|
+
contain: content;
|
|
2140
2894
|
}
|
|
2141
2895
|
|
|
2142
2896
|
.ChatDebugViewHeaderCell {
|
|
2897
|
+
display: flex;
|
|
2898
|
+
align-items: center;
|
|
2899
|
+
overflow: hidden;
|
|
2900
|
+
text-overflow: ellipsis;
|
|
2901
|
+
white-space: nowrap;
|
|
2902
|
+
min-width: 0;
|
|
2143
2903
|
font-size: 11px;
|
|
2144
2904
|
text-transform: uppercase;
|
|
2145
2905
|
letter-spacing: 0.04em;
|
|
2146
2906
|
opacity: 0.8;
|
|
2907
|
+
contain: content;
|
|
2147
2908
|
}
|
|
2148
2909
|
|
|
2149
2910
|
.ChatDebugViewTableBody {
|
|
2911
|
+
display: flex;
|
|
2912
|
+
flex-direction: column;
|
|
2150
2913
|
overflow: auto;
|
|
2151
2914
|
min-height: 0;
|
|
2915
|
+
flex: 1 1 auto;
|
|
2916
|
+
contain: strict;
|
|
2152
2917
|
}
|
|
2153
2918
|
|
|
2154
2919
|
.ChatDebugViewEventRowLabel {
|
|
2155
2920
|
display: block;
|
|
2921
|
+
contain: content;
|
|
2156
2922
|
}
|
|
2157
2923
|
|
|
2158
2924
|
.ChatDebugViewEventRowLabelSelected .ChatDebugViewEventRow,
|
|
@@ -2165,29 +2931,49 @@ const getCss = () => {
|
|
|
2165
2931
|
position: absolute;
|
|
2166
2932
|
opacity: 0;
|
|
2167
2933
|
pointer-events: none;
|
|
2934
|
+
contain: content;
|
|
2168
2935
|
}
|
|
2169
2936
|
|
|
2170
2937
|
.ChatDebugViewEventRow {
|
|
2171
|
-
padding: 8px;
|
|
2938
|
+
padding: 2px 8px;
|
|
2172
2939
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2173
2940
|
cursor: pointer;
|
|
2174
2941
|
}
|
|
2175
2942
|
|
|
2176
2943
|
.ChatDebugViewEventRow:hover {
|
|
2177
2944
|
background: var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31));
|
|
2945
|
+
color: var(--vscode-list-hoverForeground, inherit);
|
|
2178
2946
|
}
|
|
2179
2947
|
|
|
2180
2948
|
.ChatDebugViewCell {
|
|
2949
|
+
display: flex;
|
|
2950
|
+
align-items: center;
|
|
2181
2951
|
overflow: hidden;
|
|
2182
2952
|
text-overflow: ellipsis;
|
|
2183
2953
|
white-space: nowrap;
|
|
2954
|
+
min-width: 0;
|
|
2955
|
+
contain: content;
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
.ChatDebugViewCellType {
|
|
2959
|
+
flex: 1 1 140px;
|
|
2960
|
+
min-width: 0;
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
.ChatDebugViewCellTime {
|
|
2964
|
+
flex: 1 1 180px;
|
|
2965
|
+
min-width: 0;
|
|
2184
2966
|
}
|
|
2185
2967
|
|
|
2186
2968
|
.ChatDebugViewCellDuration {
|
|
2969
|
+
flex: 0 0 90px;
|
|
2970
|
+
justify-content: flex-end;
|
|
2187
2971
|
text-align: right;
|
|
2188
2972
|
}
|
|
2189
2973
|
|
|
2190
2974
|
.ChatDebugViewCellStatus {
|
|
2975
|
+
flex: 0 0 64px;
|
|
2976
|
+
justify-content: flex-end;
|
|
2191
2977
|
text-align: right;
|
|
2192
2978
|
}
|
|
2193
2979
|
|
|
@@ -2197,31 +2983,38 @@ const getCss = () => {
|
|
|
2197
2983
|
overflow: hidden;
|
|
2198
2984
|
min-width: 0;
|
|
2199
2985
|
min-height: 0;
|
|
2200
|
-
display:
|
|
2201
|
-
|
|
2986
|
+
display: flex;
|
|
2987
|
+
flex-direction: column;
|
|
2988
|
+
contain: strict;
|
|
2202
2989
|
}
|
|
2203
2990
|
|
|
2204
2991
|
.ChatDebugViewDetailsTop {
|
|
2205
2992
|
display: flex;
|
|
2206
|
-
align-items:
|
|
2207
|
-
justify-content:
|
|
2208
|
-
|
|
2993
|
+
align-items: stretch;
|
|
2994
|
+
justify-content: flex-start;
|
|
2995
|
+
gap: 8px;
|
|
2996
|
+
padding: 0 8px;
|
|
2209
2997
|
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
.ChatDebugViewDetailsTitle {
|
|
2213
|
-
font-size: 12px;
|
|
2214
|
-
font-weight: 600;
|
|
2998
|
+
contain: content;
|
|
2215
2999
|
}
|
|
2216
3000
|
|
|
2217
3001
|
.ChatDebugViewDetailsClose {
|
|
2218
3002
|
width: 18px;
|
|
2219
3003
|
height: 18px;
|
|
2220
3004
|
appearance: none;
|
|
2221
|
-
border:
|
|
3005
|
+
border: none;
|
|
2222
3006
|
border-radius: 4px;
|
|
2223
3007
|
cursor: pointer;
|
|
2224
3008
|
position: relative;
|
|
3009
|
+
color: var(--vscode-foreground, #cccccc);
|
|
3010
|
+
background: transparent;
|
|
3011
|
+
align-self: center;
|
|
3012
|
+
flex: 0 0 auto;
|
|
3013
|
+
contain: strict;
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
.ChatDebugViewDetailsClose:hover {
|
|
3017
|
+
background: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31));
|
|
2225
3018
|
}
|
|
2226
3019
|
|
|
2227
3020
|
.ChatDebugViewDetailsClose::before,
|
|
@@ -2244,8 +3037,61 @@ const getCss = () => {
|
|
|
2244
3037
|
}
|
|
2245
3038
|
|
|
2246
3039
|
.ChatDebugViewDetailsBody {
|
|
3040
|
+
display: flex;
|
|
3041
|
+
flex-direction: column;
|
|
3042
|
+
overflow: hidden;
|
|
3043
|
+
padding: 0;
|
|
3044
|
+
flex: 1 1 auto;
|
|
3045
|
+
min-height: 0;
|
|
3046
|
+
align-items: stretch;
|
|
3047
|
+
contain: strict;
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
.ChatDebugViewDetailsTabs {
|
|
3051
|
+
display: flex;
|
|
3052
|
+
align-items: center;
|
|
3053
|
+
flex: 1 1 auto;
|
|
3054
|
+
gap: 2px;
|
|
3055
|
+
min-width: 0;
|
|
3056
|
+
padding: 0;
|
|
3057
|
+
overflow-x: auto;
|
|
3058
|
+
contain: content;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
.ChatDebugViewDetailsTab {
|
|
3062
|
+
display: flex;
|
|
3063
|
+
align-items: center;
|
|
3064
|
+
justify-content: center;
|
|
3065
|
+
min-height: 32px;
|
|
3066
|
+
padding: 0 10px;
|
|
3067
|
+
appearance: none;
|
|
3068
|
+
background: transparent;
|
|
3069
|
+
border: 0;
|
|
3070
|
+
border-bottom: 2px solid transparent;
|
|
3071
|
+
color: var(--vscode-descriptionForeground, var(--vscode-foreground, #cccccc));
|
|
3072
|
+
cursor: pointer;
|
|
3073
|
+
white-space: nowrap;
|
|
3074
|
+
contain: strict;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
.ChatDebugViewDetailsTab:hover {
|
|
3078
|
+
color: var(--vscode-foreground, #cccccc);
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
.ChatDebugViewDetailsTabSelected {
|
|
3082
|
+
border-bottom-color: var(--vscode-focusBorder, #007fd4);
|
|
3083
|
+
color: var(--vscode-foreground, #cccccc);
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
.ChatDebugViewDetailsPanel {
|
|
3087
|
+
display: flex;
|
|
3088
|
+
flex-direction: column;
|
|
2247
3089
|
overflow: auto;
|
|
2248
3090
|
padding: 8px;
|
|
3091
|
+
flex: 1 1 auto;
|
|
3092
|
+
min-height: 0;
|
|
3093
|
+
align-items: flex-start;
|
|
3094
|
+
contain: strict;
|
|
2249
3095
|
}
|
|
2250
3096
|
|
|
2251
3097
|
.ChatDebugViewEvents::-webkit-scrollbar {
|
|
@@ -2273,25 +3119,101 @@ const getCss = () => {
|
|
|
2273
3119
|
}
|
|
2274
3120
|
|
|
2275
3121
|
.ChatDebugViewEvent {
|
|
3122
|
+
display: flex;
|
|
3123
|
+
flex-direction: column;
|
|
3124
|
+
width: max-content;
|
|
3125
|
+
min-width: 100%;
|
|
2276
3126
|
margin: 0;
|
|
2277
3127
|
padding: 8px;
|
|
2278
3128
|
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
2279
3129
|
border-radius: 6px;
|
|
2280
3130
|
margin-bottom: 8px;
|
|
2281
|
-
white-space:
|
|
2282
|
-
word-break: break-word;
|
|
3131
|
+
white-space: nowrap;
|
|
2283
3132
|
font-family: var(--vscode-editor-font-family, monospace);
|
|
2284
3133
|
font-size: 12px;
|
|
2285
3134
|
user-select: text;
|
|
3135
|
+
contain: content;
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
.row {
|
|
3139
|
+
display: flex;
|
|
3140
|
+
align-items: baseline;
|
|
3141
|
+
min-width: 100%;
|
|
3142
|
+
width: max-content;
|
|
3143
|
+
white-space: nowrap;
|
|
3144
|
+
contain: content;
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
.ChatDebugViewEventLineNumber {
|
|
3148
|
+
display: flex;
|
|
3149
|
+
justify-content: flex-end;
|
|
3150
|
+
flex: 0 0 3ch;
|
|
3151
|
+
margin-right: 12px;
|
|
3152
|
+
opacity: 0.6;
|
|
3153
|
+
user-select: none;
|
|
3154
|
+
contain: content;
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
.ChatDebugViewEventLineContent {
|
|
3158
|
+
display: flex;
|
|
3159
|
+
white-space: pre;
|
|
3160
|
+
contain: content;
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
.ChatDebugViewDetailsPanel > .ChatDebugViewEvent {
|
|
3164
|
+
border: 0;
|
|
3165
|
+
border-radius: 0;
|
|
3166
|
+
margin-bottom: 0;
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
.ChatDebugViewTiming {
|
|
3170
|
+
display: flex;
|
|
3171
|
+
flex-direction: column;
|
|
3172
|
+
width: 100%;
|
|
3173
|
+
border: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
3174
|
+
border-radius: 6px;
|
|
3175
|
+
overflow: hidden;
|
|
3176
|
+
contain: strict;
|
|
3177
|
+
flex: 1;
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
.ChatDebugViewTimingRow {
|
|
3181
|
+
display: flex;
|
|
3182
|
+
align-items: center;
|
|
3183
|
+
justify-content: space-between;
|
|
3184
|
+
gap: 12px;
|
|
3185
|
+
padding: 8px 10px;
|
|
3186
|
+
border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
|
|
3187
|
+
contain: content;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
.ChatDebugViewTimingRow:last-child {
|
|
3191
|
+
border-bottom: 0;
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
.ChatDebugViewTimingLabel {
|
|
3195
|
+
opacity: 0.8;
|
|
3196
|
+
contain: content;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
.ChatDebugViewTimingValue {
|
|
3200
|
+
text-align: right;
|
|
3201
|
+
font-family: var(--vscode-editor-font-family, monospace);
|
|
3202
|
+
contain: content;
|
|
2286
3203
|
}
|
|
2287
3204
|
|
|
2288
3205
|
.ChatDebugViewEmpty {
|
|
3206
|
+
display: flex;
|
|
3207
|
+
align-items: center;
|
|
2289
3208
|
opacity: 0.8;
|
|
3209
|
+
contain: content;
|
|
2290
3210
|
}
|
|
2291
3211
|
|
|
2292
3212
|
.ChatDebugViewError {
|
|
3213
|
+
display: flex;
|
|
2293
3214
|
color: var(--vscode-errorForeground, #f14c4c);
|
|
2294
3215
|
white-space: normal;
|
|
3216
|
+
contain: content;
|
|
2295
3217
|
}
|
|
2296
3218
|
|
|
2297
3219
|
.TokenText {
|
|
@@ -2315,33 +3237,48 @@ const getCss = () => {
|
|
|
2315
3237
|
}
|
|
2316
3238
|
|
|
2317
3239
|
.ChatOrderedList{
|
|
3240
|
+
display:flex;
|
|
3241
|
+
flex-direction:column;
|
|
2318
3242
|
margin:0;
|
|
2319
3243
|
padding:0;
|
|
2320
3244
|
padding-left:10px;
|
|
3245
|
+
contain: content;
|
|
2321
3246
|
}
|
|
2322
3247
|
|
|
2323
3248
|
.ChatOrderedListItem{
|
|
3249
|
+
display:flex;
|
|
2324
3250
|
margin:0;
|
|
2325
3251
|
padding:0;
|
|
3252
|
+
contain: content;
|
|
2326
3253
|
}
|
|
2327
3254
|
|
|
2328
3255
|
.ChatToolCalls{
|
|
3256
|
+
display:flex;
|
|
3257
|
+
flex-direction:column;
|
|
2329
3258
|
margin:0;
|
|
2330
3259
|
padding:0;
|
|
3260
|
+
contain: content;
|
|
2331
3261
|
}
|
|
2332
3262
|
`;
|
|
2333
3263
|
};
|
|
2334
3264
|
|
|
2335
3265
|
const renderCss = (oldState, newState) => {
|
|
2336
|
-
const css = getCss();
|
|
3266
|
+
const css = getCss(newState);
|
|
2337
3267
|
return [SetCss, newState.uid, css];
|
|
2338
3268
|
};
|
|
2339
3269
|
|
|
3270
|
+
const Button = 1;
|
|
2340
3271
|
const Div = 4;
|
|
2341
3272
|
const Input = 6;
|
|
2342
3273
|
const Span = 8;
|
|
3274
|
+
const Table = 9;
|
|
3275
|
+
const TBody = 10;
|
|
3276
|
+
const Td = 11;
|
|
2343
3277
|
const Text = 12;
|
|
2344
|
-
const
|
|
3278
|
+
const Th = 13;
|
|
3279
|
+
const THead = 14;
|
|
3280
|
+
const Tr = 15;
|
|
3281
|
+
const Search = 42;
|
|
2345
3282
|
const Label = 66;
|
|
2346
3283
|
const Reference = 100;
|
|
2347
3284
|
|
|
@@ -2641,9 +3578,65 @@ const diffTree = (oldNodes, newNodes) => {
|
|
|
2641
3578
|
return removeTrailingNavigationPatches(patches);
|
|
2642
3579
|
};
|
|
2643
3580
|
|
|
3581
|
+
const getDebugErrorDom = errorMessage => {
|
|
3582
|
+
return [{
|
|
3583
|
+
childCount: 1,
|
|
3584
|
+
className: 'ChatDebugView',
|
|
3585
|
+
type: Div
|
|
3586
|
+
}, {
|
|
3587
|
+
childCount: 1,
|
|
3588
|
+
className: 'ChatDebugViewError',
|
|
3589
|
+
type: Div
|
|
3590
|
+
}, text(errorMessage)];
|
|
3591
|
+
};
|
|
3592
|
+
|
|
2644
3593
|
const HandleInput = 4;
|
|
2645
3594
|
const HandleFilterInput = 5;
|
|
2646
3595
|
const HandleSimpleInput = 6;
|
|
3596
|
+
const HandleEventRowClick = 7;
|
|
3597
|
+
const HandleSashPointerDown = 8;
|
|
3598
|
+
const HandleSashPointerMove = 9;
|
|
3599
|
+
const HandleSashPointerUp = 10;
|
|
3600
|
+
const HandleTableBodyContextMenu = 11;
|
|
3601
|
+
const HandleTimelinePointerDown = 12;
|
|
3602
|
+
const HandleTimelinePointerMove = 13;
|
|
3603
|
+
const HandleTimelinePointerUp = 14;
|
|
3604
|
+
const HandleTimelineDoubleClick = 15;
|
|
3605
|
+
|
|
3606
|
+
const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
|
|
3607
|
+
if (useDevtoolsLayout) {
|
|
3608
|
+
return [{
|
|
3609
|
+
childCount: 1 + (quickFilterNodes.length > 0 ? 1 : 0),
|
|
3610
|
+
className: 'ChatDebugViewTop ChatDebugViewTop--devtools',
|
|
3611
|
+
type: Search
|
|
3612
|
+
}, {
|
|
3613
|
+
autocomplete: 'off',
|
|
3614
|
+
childCount: 0,
|
|
3615
|
+
className: 'InputBox ChatDebugViewFilterInput ChatDebugViewFilterInput--devtools',
|
|
3616
|
+
inputType: 'search',
|
|
3617
|
+
name: Filter,
|
|
3618
|
+
onInput: HandleFilterInput,
|
|
3619
|
+
placeholder: 'Filter events',
|
|
3620
|
+
type: Input,
|
|
3621
|
+
value: filterValue
|
|
3622
|
+
}, ...quickFilterNodes];
|
|
3623
|
+
}
|
|
3624
|
+
return [{
|
|
3625
|
+
childCount: 1,
|
|
3626
|
+
className: 'ChatDebugViewTop',
|
|
3627
|
+
type: Search
|
|
3628
|
+
}, {
|
|
3629
|
+
autocomplete: 'off',
|
|
3630
|
+
childCount: 0,
|
|
3631
|
+
className: 'InputBox ChatDebugViewFilterInput',
|
|
3632
|
+
inputType: 'search',
|
|
3633
|
+
name: Filter,
|
|
3634
|
+
onInput: HandleFilterInput,
|
|
3635
|
+
placeholder: 'Filter events',
|
|
3636
|
+
type: Input,
|
|
3637
|
+
value: filterValue
|
|
3638
|
+
}];
|
|
3639
|
+
};
|
|
2647
3640
|
|
|
2648
3641
|
const getDurationText = event => {
|
|
2649
3642
|
const explicitDuration = event.durationMs ?? event.duration;
|
|
@@ -2695,6 +3688,129 @@ const getStartText = event => {
|
|
|
2695
3688
|
return getTimestampText(event.started ?? event.startTime ?? event.startTimestamp ?? event.timestamp);
|
|
2696
3689
|
};
|
|
2697
3690
|
|
|
3691
|
+
const getTimingRowDom = (label, value) => {
|
|
3692
|
+
return [{
|
|
3693
|
+
childCount: 2,
|
|
3694
|
+
className: 'ChatDebugViewTimingRow',
|
|
3695
|
+
type: Div
|
|
3696
|
+
}, {
|
|
3697
|
+
childCount: 1,
|
|
3698
|
+
className: 'ChatDebugViewTimingLabel',
|
|
3699
|
+
type: Span
|
|
3700
|
+
}, text(label), {
|
|
3701
|
+
childCount: 1,
|
|
3702
|
+
className: 'ChatDebugViewTimingValue',
|
|
3703
|
+
type: Span
|
|
3704
|
+
}, text(value)];
|
|
3705
|
+
};
|
|
3706
|
+
const getTimingDetailsDom = event => {
|
|
3707
|
+
return [{
|
|
3708
|
+
childCount: 3,
|
|
3709
|
+
className: 'ChatDebugViewTiming',
|
|
3710
|
+
type: Div
|
|
3711
|
+
}, ...getTimingRowDom('Started', getStartText(event)), ...getTimingRowDom('Ended', getEndText(event)), ...getTimingRowDom('Duration', getDurationText(event))];
|
|
3712
|
+
};
|
|
3713
|
+
|
|
3714
|
+
const getTabId = detailTab => {
|
|
3715
|
+
return `ChatDebugViewDetailsTab-${detailTab}`;
|
|
3716
|
+
};
|
|
3717
|
+
const getPanelId = detailTab => {
|
|
3718
|
+
return `ChatDebugViewDetailsPanel-${detailTab}`;
|
|
3719
|
+
};
|
|
3720
|
+
const getTabNodes = selectedDetailTab => {
|
|
3721
|
+
return detailTabs.flatMap(detailTab => {
|
|
3722
|
+
const isSelected = detailTab === selectedDetailTab;
|
|
3723
|
+
return [{
|
|
3724
|
+
'aria-controls': getPanelId(detailTab),
|
|
3725
|
+
'aria-selected': isSelected,
|
|
3726
|
+
childCount: 1,
|
|
3727
|
+
className: isSelected ? 'ChatDebugViewDetailsTab ChatDebugViewDetailsTabSelected' : 'ChatDebugViewDetailsTab',
|
|
3728
|
+
id: getTabId(detailTab),
|
|
3729
|
+
name: DetailTab,
|
|
3730
|
+
onChange: HandleSimpleInput,
|
|
3731
|
+
onClick: HandleSimpleInput,
|
|
3732
|
+
role: 'tab',
|
|
3733
|
+
tabIndex: isSelected ? 0 : -1,
|
|
3734
|
+
type: Button,
|
|
3735
|
+
value: detailTab
|
|
3736
|
+
}, text(getDetailTabLabel(detailTab))];
|
|
3737
|
+
});
|
|
3738
|
+
};
|
|
3739
|
+
const getDetailsDom = (selectedEventNodes, selectedEvent = null, selectedDetailTab = Response) => {
|
|
3740
|
+
if (selectedEventNodes.length === 0) {
|
|
3741
|
+
return [];
|
|
3742
|
+
}
|
|
3743
|
+
const contentNodes = selectedDetailTab === Timing && selectedEvent ? getTimingDetailsDom(selectedEvent) : selectedEventNodes;
|
|
3744
|
+
return [{
|
|
3745
|
+
childCount: 2,
|
|
3746
|
+
className: 'ChatDebugViewDetails',
|
|
3747
|
+
type: Div
|
|
3748
|
+
}, {
|
|
3749
|
+
childCount: 2,
|
|
3750
|
+
className: 'ChatDebugViewDetailsTop',
|
|
3751
|
+
type: Div
|
|
3752
|
+
}, {
|
|
3753
|
+
'aria-label': 'Detail sections',
|
|
3754
|
+
childCount: detailTabs.length,
|
|
3755
|
+
className: 'ChatDebugViewDetailsTabs',
|
|
3756
|
+
role: 'tablist',
|
|
3757
|
+
type: Div
|
|
3758
|
+
}, ...getTabNodes(selectedDetailTab), {
|
|
3759
|
+
'aria-label': 'Close details',
|
|
3760
|
+
childCount: 0,
|
|
3761
|
+
className: 'ChatDebugViewDetailsClose',
|
|
3762
|
+
name: CloseDetails,
|
|
3763
|
+
onChange: HandleSimpleInput,
|
|
3764
|
+
onClick: HandleSimpleInput,
|
|
3765
|
+
type: Button,
|
|
3766
|
+
value: 'close'
|
|
3767
|
+
}, {
|
|
3768
|
+
childCount: 1,
|
|
3769
|
+
className: 'ChatDebugViewDetailsBody',
|
|
3770
|
+
type: Div
|
|
3771
|
+
}, {
|
|
3772
|
+
'aria-labelledby': getTabId(selectedDetailTab),
|
|
3773
|
+
childCount: 1,
|
|
3774
|
+
className: 'ChatDebugViewDetailsPanel',
|
|
3775
|
+
id: getPanelId(selectedDetailTab),
|
|
3776
|
+
role: 'tabpanel',
|
|
3777
|
+
type: Div
|
|
3778
|
+
}, ...contentNodes];
|
|
3779
|
+
};
|
|
3780
|
+
|
|
3781
|
+
const toolExecutionTypePrefix = 'tool-execution';
|
|
3782
|
+
const getToolName = event => {
|
|
3783
|
+
if (typeof event.toolName === 'string' && event.toolName) {
|
|
3784
|
+
return event.toolName;
|
|
3785
|
+
}
|
|
3786
|
+
if (typeof event.name === 'string' && event.name) {
|
|
3787
|
+
return event.name;
|
|
3788
|
+
}
|
|
3789
|
+
const {
|
|
3790
|
+
arguments: toolArguments
|
|
3791
|
+
} = event;
|
|
3792
|
+
if (!toolArguments || typeof toolArguments !== 'object') {
|
|
3793
|
+
return undefined;
|
|
3794
|
+
}
|
|
3795
|
+
const {
|
|
3796
|
+
name
|
|
3797
|
+
} = toolArguments;
|
|
3798
|
+
if (typeof name !== 'string' || !name) {
|
|
3799
|
+
return undefined;
|
|
3800
|
+
}
|
|
3801
|
+
return name;
|
|
3802
|
+
};
|
|
3803
|
+
const getEventTypeLabel = event => {
|
|
3804
|
+
if (!event.type.startsWith(toolExecutionTypePrefix)) {
|
|
3805
|
+
return event.type;
|
|
3806
|
+
}
|
|
3807
|
+
const toolName = getToolName(event);
|
|
3808
|
+
if (!toolName) {
|
|
3809
|
+
return event.type;
|
|
3810
|
+
}
|
|
3811
|
+
return `${event.type}, ${toolName}`;
|
|
3812
|
+
};
|
|
3813
|
+
|
|
2698
3814
|
const hasErrorStatus = event => {
|
|
2699
3815
|
if (event.type === 'error') {
|
|
2700
3816
|
return true;
|
|
@@ -2722,81 +3838,63 @@ const getStatusText = event => {
|
|
|
2722
3838
|
};
|
|
2723
3839
|
|
|
2724
3840
|
const getDevtoolsRows = (events, selectedEventIndex) => {
|
|
2725
|
-
|
|
2726
|
-
return [{
|
|
2727
|
-
childCount: 1,
|
|
2728
|
-
className: 'ChatDebugViewEmpty',
|
|
2729
|
-
type: Div
|
|
2730
|
-
}, text('No events')];
|
|
2731
|
-
}
|
|
2732
|
-
const rows = [];
|
|
2733
|
-
for (let i = 0; i < events.length; i++) {
|
|
2734
|
-
const event = events[i];
|
|
3841
|
+
return events.flatMap((event, i) => {
|
|
2735
3842
|
const isSelected = selectedEventIndex === i;
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
type: Label
|
|
2740
|
-
}, {
|
|
2741
|
-
checked: isSelected,
|
|
2742
|
-
childCount: 0,
|
|
2743
|
-
className: 'ChatDebugViewEventRowInput',
|
|
2744
|
-
inputType: 'radio',
|
|
2745
|
-
name: SelectedEventIndex,
|
|
2746
|
-
onChange: HandleSimpleInput,
|
|
2747
|
-
type: Input,
|
|
2748
|
-
value: String(i)
|
|
2749
|
-
}, {
|
|
2750
|
-
childCount: 5,
|
|
3843
|
+
const rowIndex = String(i);
|
|
3844
|
+
return [{
|
|
3845
|
+
childCount: 3,
|
|
2751
3846
|
className: `ChatDebugViewEventRow${isSelected ? ' ChatDebugViewEventRowSelected' : ''}`,
|
|
2752
|
-
|
|
3847
|
+
'data-index': rowIndex,
|
|
3848
|
+
type: Tr
|
|
2753
3849
|
}, {
|
|
2754
3850
|
childCount: 1,
|
|
2755
3851
|
className: 'ChatDebugViewCell ChatDebugViewCellType',
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
className: 'ChatDebugViewCell',
|
|
2760
|
-
type: Div
|
|
2761
|
-
}, text(getStartText(event)), {
|
|
2762
|
-
childCount: 1,
|
|
2763
|
-
className: 'ChatDebugViewCell',
|
|
2764
|
-
type: Div
|
|
2765
|
-
}, text(getEndText(event)), {
|
|
3852
|
+
'data-index': rowIndex,
|
|
3853
|
+
type: Td
|
|
3854
|
+
}, text(getEventTypeLabel(event)), {
|
|
2766
3855
|
childCount: 1,
|
|
2767
3856
|
className: 'ChatDebugViewCell ChatDebugViewCellDuration',
|
|
2768
|
-
|
|
3857
|
+
'data-index': rowIndex,
|
|
3858
|
+
type: Td
|
|
2769
3859
|
}, text(getDurationText(event)), {
|
|
2770
3860
|
childCount: 1,
|
|
2771
3861
|
className: 'ChatDebugViewCell ChatDebugViewCellStatus',
|
|
2772
|
-
|
|
2773
|
-
|
|
3862
|
+
'data-index': rowIndex,
|
|
3863
|
+
type: Td
|
|
3864
|
+
}, text(getStatusText(event))];
|
|
3865
|
+
});
|
|
3866
|
+
};
|
|
3867
|
+
|
|
3868
|
+
const getEmptyStateDom = emptyMessage => {
|
|
3869
|
+
return [{
|
|
3870
|
+
childCount: 1,
|
|
3871
|
+
className: 'ChatDebugViewEmpty',
|
|
3872
|
+
type: Div
|
|
3873
|
+
}, text(emptyMessage)];
|
|
3874
|
+
};
|
|
3875
|
+
|
|
3876
|
+
const pushToken = (segments, className, value) => {
|
|
3877
|
+
if (!value) {
|
|
3878
|
+
return segments;
|
|
2774
3879
|
}
|
|
2775
|
-
|
|
3880
|
+
const lastSegment = segments.at(-1);
|
|
3881
|
+
if (lastSegment && lastSegment.className === className) {
|
|
3882
|
+
const merged = {
|
|
3883
|
+
className,
|
|
3884
|
+
value: lastSegment.value + value
|
|
3885
|
+
};
|
|
3886
|
+
return [...segments.slice(0, -1), merged];
|
|
3887
|
+
}
|
|
3888
|
+
return [...segments, {
|
|
3889
|
+
className,
|
|
3890
|
+
value
|
|
3891
|
+
}];
|
|
2776
3892
|
};
|
|
2777
3893
|
|
|
2778
3894
|
const numberRegex = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/;
|
|
2779
3895
|
const whitespaceRegex = /\s/u;
|
|
2780
3896
|
const getTokenSegments = json => {
|
|
2781
|
-
|
|
2782
|
-
const pushToken = (className, value) => {
|
|
2783
|
-
if (!value) {
|
|
2784
|
-
return;
|
|
2785
|
-
}
|
|
2786
|
-
const lastSegment = segments.at(-1);
|
|
2787
|
-
if (lastSegment && lastSegment.className === className) {
|
|
2788
|
-
const merged = {
|
|
2789
|
-
className,
|
|
2790
|
-
value: lastSegment.value + value
|
|
2791
|
-
};
|
|
2792
|
-
segments[segments.length - 1] = merged;
|
|
2793
|
-
return;
|
|
2794
|
-
}
|
|
2795
|
-
segments.push({
|
|
2796
|
-
className,
|
|
2797
|
-
value
|
|
2798
|
-
});
|
|
2799
|
-
};
|
|
3897
|
+
let segments = [];
|
|
2800
3898
|
let i = 0;
|
|
2801
3899
|
while (i < json.length) {
|
|
2802
3900
|
const character = json[i];
|
|
@@ -2821,67 +3919,210 @@ const getTokenSegments = json => {
|
|
|
2821
3919
|
lookAheadIndex++;
|
|
2822
3920
|
}
|
|
2823
3921
|
const className = json[lookAheadIndex] === ':' ? 'TokenKey' : 'TokenString';
|
|
2824
|
-
pushToken(className, tokenValue);
|
|
3922
|
+
segments = pushToken(segments, className, tokenValue);
|
|
2825
3923
|
continue;
|
|
2826
3924
|
}
|
|
2827
3925
|
const numberMatch = numberRegex.exec(json.slice(i));
|
|
2828
3926
|
if (numberMatch) {
|
|
2829
|
-
pushToken('TokenNumeric', numberMatch[0]);
|
|
3927
|
+
segments = pushToken(segments, 'TokenNumeric', numberMatch[0]);
|
|
2830
3928
|
i += numberMatch[0].length;
|
|
2831
3929
|
continue;
|
|
2832
3930
|
}
|
|
2833
3931
|
if (json.startsWith('true', i)) {
|
|
2834
|
-
pushToken('TokenBoolean', 'true');
|
|
3932
|
+
segments = pushToken(segments, 'TokenBoolean', 'true');
|
|
2835
3933
|
i += 4;
|
|
2836
3934
|
continue;
|
|
2837
3935
|
}
|
|
2838
3936
|
if (json.startsWith('false', i)) {
|
|
2839
|
-
pushToken('TokenBoolean', 'false');
|
|
3937
|
+
segments = pushToken(segments, 'TokenBoolean', 'false');
|
|
2840
3938
|
i += 5;
|
|
2841
3939
|
continue;
|
|
2842
3940
|
}
|
|
2843
3941
|
if (json.startsWith('null', i)) {
|
|
2844
|
-
pushToken('TokenBoolean', 'null');
|
|
3942
|
+
segments = pushToken(segments, 'TokenBoolean', 'null');
|
|
2845
3943
|
i += 4;
|
|
2846
3944
|
continue;
|
|
2847
3945
|
}
|
|
2848
|
-
pushToken('TokenText', character);
|
|
3946
|
+
segments = pushToken(segments, 'TokenText', character);
|
|
2849
3947
|
i++;
|
|
2850
3948
|
}
|
|
2851
3949
|
return segments;
|
|
2852
3950
|
};
|
|
2853
|
-
|
|
3951
|
+
|
|
3952
|
+
const getJsonLines = value => {
|
|
2854
3953
|
const json = JSON.stringify(value, null, 2);
|
|
2855
3954
|
if (!json) {
|
|
2856
|
-
return [{
|
|
2857
|
-
childCount: 1,
|
|
3955
|
+
return [[{
|
|
2858
3956
|
className: 'TokenText',
|
|
2859
|
-
|
|
2860
|
-
}
|
|
3957
|
+
value: String(json)
|
|
3958
|
+
}]];
|
|
2861
3959
|
}
|
|
2862
3960
|
const segments = getTokenSegments(json);
|
|
2863
|
-
|
|
3961
|
+
const lines = [];
|
|
3962
|
+
let currentLine = [];
|
|
3963
|
+
for (const segment of segments) {
|
|
3964
|
+
const parts = segment.value.split('\n');
|
|
3965
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3966
|
+
const part = parts[i];
|
|
3967
|
+
if (part) {
|
|
3968
|
+
currentLine.push({
|
|
3969
|
+
className: segment.className,
|
|
3970
|
+
value: part
|
|
3971
|
+
});
|
|
3972
|
+
}
|
|
3973
|
+
if (i < parts.length - 1) {
|
|
3974
|
+
lines.push(currentLine);
|
|
3975
|
+
currentLine = [];
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
lines.push(currentLine);
|
|
3980
|
+
return lines;
|
|
3981
|
+
};
|
|
3982
|
+
const getLineContentNodes = line => {
|
|
3983
|
+
return line.flatMap(segment => {
|
|
3984
|
+
return [{
|
|
3985
|
+
childCount: 1,
|
|
3986
|
+
className: segment.className,
|
|
3987
|
+
type: Span
|
|
3988
|
+
}, text(segment.value)];
|
|
3989
|
+
});
|
|
3990
|
+
};
|
|
3991
|
+
const getLineNodes = lines => {
|
|
3992
|
+
return lines.flatMap((line, index) => {
|
|
3993
|
+
const lineContentNodes = getLineContentNodes(line);
|
|
2864
3994
|
return [{
|
|
3995
|
+
childCount: 2,
|
|
3996
|
+
className: 'row',
|
|
3997
|
+
type: Div
|
|
3998
|
+
}, {
|
|
2865
3999
|
childCount: 1,
|
|
2866
|
-
className:
|
|
4000
|
+
className: 'ChatDebugViewEventLineNumber',
|
|
2867
4001
|
type: Span
|
|
2868
|
-
}, text(
|
|
4002
|
+
}, text(String(index + 1)), {
|
|
4003
|
+
childCount: lineContentNodes.length / 2,
|
|
4004
|
+
className: 'ChatDebugViewEventLineContent',
|
|
4005
|
+
type: Span
|
|
4006
|
+
}, ...lineContentNodes];
|
|
2869
4007
|
});
|
|
2870
4008
|
};
|
|
2871
|
-
|
|
2872
4009
|
const getEventNode = event => {
|
|
2873
|
-
const
|
|
4010
|
+
const renderedEvent = {
|
|
4011
|
+
...event,
|
|
4012
|
+
type: getEventTypeLabel(event)
|
|
4013
|
+
};
|
|
4014
|
+
const lines = getJsonLines(renderedEvent);
|
|
4015
|
+
const lineNodes = getLineNodes(lines);
|
|
2874
4016
|
return [{
|
|
2875
|
-
childCount:
|
|
4017
|
+
childCount: lines.length,
|
|
2876
4018
|
className: 'ChatDebugViewEvent',
|
|
2877
|
-
type:
|
|
2878
|
-
}, ...
|
|
4019
|
+
type: Div
|
|
4020
|
+
}, ...lineNodes];
|
|
2879
4021
|
};
|
|
2880
4022
|
|
|
2881
|
-
const
|
|
2882
|
-
const
|
|
2883
|
-
|
|
2884
|
-
|
|
4023
|
+
const getEventsClassName = hasSelectedEvent => {
|
|
4024
|
+
const widthClassName = hasSelectedEvent ? 'ChatDebugViewEvents' : 'ChatDebugViewEvents ChatDebugViewEventsFullWidth';
|
|
4025
|
+
return widthClassName;
|
|
4026
|
+
};
|
|
4027
|
+
|
|
4028
|
+
const getSashNodesDom = hasSelectedEvent => {
|
|
4029
|
+
if (!hasSelectedEvent) {
|
|
4030
|
+
return [];
|
|
4031
|
+
}
|
|
4032
|
+
return [{
|
|
4033
|
+
childCount: 1,
|
|
4034
|
+
className: 'ChatDebugViewSash',
|
|
4035
|
+
onPointerDown: HandleSashPointerDown,
|
|
4036
|
+
type: Div
|
|
4037
|
+
}, {
|
|
4038
|
+
childCount: 0,
|
|
4039
|
+
className: 'ChatDebugViewSashLine',
|
|
4040
|
+
type: Div
|
|
4041
|
+
}];
|
|
4042
|
+
};
|
|
4043
|
+
|
|
4044
|
+
const getTableBodyDom = (rowNodes, eventCount) => {
|
|
4045
|
+
return [{
|
|
4046
|
+
childCount: eventCount === 0 ? 1 : eventCount,
|
|
4047
|
+
className: 'ChatDebugViewTableBody',
|
|
4048
|
+
onContextMenu: HandleTableBodyContextMenu,
|
|
4049
|
+
onPointerDown: HandleEventRowClick,
|
|
4050
|
+
type: TBody
|
|
4051
|
+
}, ...rowNodes];
|
|
4052
|
+
};
|
|
4053
|
+
|
|
4054
|
+
const getTableHeaderDom = () => {
|
|
4055
|
+
return [{
|
|
4056
|
+
childCount: 1,
|
|
4057
|
+
className: 'ChatDebugViewTableHeader',
|
|
4058
|
+
type: THead
|
|
4059
|
+
}, {
|
|
4060
|
+
childCount: 3,
|
|
4061
|
+
className: 'ChatDebugViewTableHeaderRow',
|
|
4062
|
+
type: Tr
|
|
4063
|
+
}, {
|
|
4064
|
+
childCount: 1,
|
|
4065
|
+
className: 'ChatDebugViewHeaderCell ChatDebugViewCellType',
|
|
4066
|
+
scope: 'col',
|
|
4067
|
+
type: Th
|
|
4068
|
+
}, text('Type'), {
|
|
4069
|
+
childCount: 1,
|
|
4070
|
+
className: 'ChatDebugViewHeaderCell ChatDebugViewCellDuration',
|
|
4071
|
+
scope: 'col',
|
|
4072
|
+
type: Th
|
|
4073
|
+
}, text('Duration'), {
|
|
4074
|
+
childCount: 1,
|
|
4075
|
+
className: 'ChatDebugViewHeaderCell ChatDebugViewCellStatus',
|
|
4076
|
+
scope: 'col',
|
|
4077
|
+
type: Th
|
|
4078
|
+
}, text('Status')];
|
|
4079
|
+
};
|
|
4080
|
+
|
|
4081
|
+
const getTableDom = (rowNodes, eventCount) => {
|
|
4082
|
+
return [{
|
|
4083
|
+
childCount: 2,
|
|
4084
|
+
className: 'ChatDebugViewTable',
|
|
4085
|
+
type: Table
|
|
4086
|
+
}, ...getTableHeaderDom(), ...getTableBodyDom(rowNodes, eventCount)];
|
|
4087
|
+
};
|
|
4088
|
+
|
|
4089
|
+
const getBucketUnitDom = unitCount => {
|
|
4090
|
+
if (unitCount === 0) {
|
|
4091
|
+
return [{
|
|
4092
|
+
childCount: 0,
|
|
4093
|
+
className: 'ChatDebugViewTimelineBucketUnit ChatDebugViewTimelineBucketUnitEmpty',
|
|
4094
|
+
type: Div
|
|
4095
|
+
}];
|
|
4096
|
+
}
|
|
4097
|
+
return Array.from({
|
|
4098
|
+
length: unitCount
|
|
4099
|
+
}).fill({
|
|
4100
|
+
childCount: 0,
|
|
4101
|
+
className: 'ChatDebugViewTimelineBucketUnit',
|
|
4102
|
+
type: Div
|
|
4103
|
+
});
|
|
4104
|
+
};
|
|
4105
|
+
|
|
4106
|
+
const getBucketDom = bucket => {
|
|
4107
|
+
const presetValue = `${formatTimelinePresetValue(bucket.startSeconds)}:${formatTimelinePresetValue(bucket.endSeconds)}`;
|
|
4108
|
+
return [{
|
|
4109
|
+
childCount: 2,
|
|
4110
|
+
className: `ChatDebugViewTimelineBucket${bucket.isSelected ? ' ChatDebugViewTimelineBucketSelected' : ''}`,
|
|
4111
|
+
type: Label
|
|
4112
|
+
}, {
|
|
4113
|
+
checked: false,
|
|
4114
|
+
childCount: 0,
|
|
4115
|
+
className: 'ChatDebugViewTimelinePresetInput',
|
|
4116
|
+
inputType: 'radio',
|
|
4117
|
+
name: TimelineRangePreset,
|
|
4118
|
+
onChange: HandleSimpleInput,
|
|
4119
|
+
type: Input,
|
|
4120
|
+
value: presetValue
|
|
4121
|
+
}, {
|
|
4122
|
+
childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
|
|
4123
|
+
className: `ChatDebugViewTimelineBucketBar${bucket.isSelected ? ' ChatDebugViewTimelineBucketBarSelected' : ''}`,
|
|
4124
|
+
type: Div
|
|
4125
|
+
}, ...getBucketUnitDom(bucket.unitCount)];
|
|
2885
4126
|
};
|
|
2886
4127
|
|
|
2887
4128
|
const formatTimelineSeconds = value => {
|
|
@@ -2890,6 +4131,7 @@ const formatTimelineSeconds = value => {
|
|
|
2890
4131
|
}
|
|
2891
4132
|
return `${Number(value.toFixed(1))}s`;
|
|
2892
4133
|
};
|
|
4134
|
+
|
|
2893
4135
|
const getTimelineSummary = (timelineEvents, timelineStartSeconds, timelineEndSeconds) => {
|
|
2894
4136
|
const timelineInfo = getTimelineInfo(timelineEvents, timelineStartSeconds, timelineEndSeconds);
|
|
2895
4137
|
if (timelineInfo.hasSelection && timelineInfo.startSeconds !== null && timelineInfo.endSeconds !== null) {
|
|
@@ -2898,176 +4140,96 @@ const getTimelineSummary = (timelineEvents, timelineStartSeconds, timelineEndSec
|
|
|
2898
4140
|
return `Window 0s-${formatTimelineSeconds(timelineInfo.durationSeconds)} of ${formatTimelineSeconds(timelineInfo.durationSeconds)}`;
|
|
2899
4141
|
};
|
|
2900
4142
|
|
|
2901
|
-
const
|
|
2902
|
-
|
|
4143
|
+
const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
|
|
4144
|
+
if (!timelineSelectionActive) {
|
|
4145
|
+
return {
|
|
4146
|
+
endSeconds: timelineEndSeconds,
|
|
4147
|
+
startSeconds: timelineStartSeconds
|
|
4148
|
+
};
|
|
4149
|
+
}
|
|
4150
|
+
return {
|
|
4151
|
+
endSeconds: timelineSelectionFocusSeconds,
|
|
4152
|
+
startSeconds: timelineSelectionAnchorSeconds
|
|
4153
|
+
};
|
|
4154
|
+
};
|
|
4155
|
+
const formatPercent = value => {
|
|
4156
|
+
return `${Number(value.toFixed(3))}%`;
|
|
4157
|
+
};
|
|
4158
|
+
const getTimelineNodes = (timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '') => {
|
|
4159
|
+
const effectiveRange = getEffectiveTimelineRange(timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
4160
|
+
const timelineInfo = getTimelineInfo(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds);
|
|
2903
4161
|
if (timelineInfo.buckets.length === 0) {
|
|
2904
4162
|
return [];
|
|
2905
4163
|
}
|
|
2906
|
-
|
|
2907
|
-
childCount:
|
|
2908
|
-
className: '
|
|
4164
|
+
const selectionNodes = timelineInfo.hasSelection && timelineInfo.selectionStartPercent !== null && timelineInfo.selectionEndPercent !== null ? [{
|
|
4165
|
+
childCount: 0,
|
|
4166
|
+
className: 'ChatDebugViewTimelineSelectionRange',
|
|
4167
|
+
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};width:${formatPercent(timelineInfo.selectionEndPercent - timelineInfo.selectionStartPercent)};`,
|
|
4168
|
+
type: Div
|
|
4169
|
+
}, {
|
|
4170
|
+
childCount: 0,
|
|
4171
|
+
className: 'ChatDebugViewTimelineSelectionMarker ChatDebugViewTimelineSelectionMarkerStart',
|
|
4172
|
+
style: `left:${formatPercent(timelineInfo.selectionStartPercent)};`,
|
|
2909
4173
|
type: Div
|
|
2910
4174
|
}, {
|
|
4175
|
+
childCount: 0,
|
|
4176
|
+
className: 'ChatDebugViewTimelineSelectionMarker ChatDebugViewTimelineSelectionMarkerEnd',
|
|
4177
|
+
style: `left:${formatPercent(timelineInfo.selectionEndPercent)};`,
|
|
4178
|
+
type: Div
|
|
4179
|
+
}] : [];
|
|
4180
|
+
return [{
|
|
2911
4181
|
childCount: 2,
|
|
2912
|
-
className: '
|
|
4182
|
+
className: 'ChatDebugViewTimeline',
|
|
2913
4183
|
type: Div
|
|
2914
4184
|
}, {
|
|
2915
4185
|
childCount: 1,
|
|
2916
|
-
className: '
|
|
4186
|
+
className: 'ChatDebugViewTimelineTop',
|
|
2917
4187
|
type: Div
|
|
2918
|
-
},
|
|
4188
|
+
}, {
|
|
2919
4189
|
childCount: 1,
|
|
2920
4190
|
className: 'ChatDebugViewTimelineSummary',
|
|
2921
4191
|
type: Div
|
|
2922
|
-
}, text(getTimelineSummary(timelineEvents,
|
|
2923
|
-
childCount: 3,
|
|
2924
|
-
className: 'ChatDebugViewTimelineControls',
|
|
2925
|
-
type: Div
|
|
2926
|
-
}, {
|
|
2927
|
-
childCount: 2,
|
|
2928
|
-
className: 'ChatDebugViewTimelineField',
|
|
2929
|
-
type: Label
|
|
2930
|
-
}, text('From'), {
|
|
2931
|
-
childCount: 0,
|
|
2932
|
-
className: 'InputBox ChatDebugViewTimelineInput',
|
|
2933
|
-
inputType: 'number',
|
|
2934
|
-
name: TimelineStartSeconds,
|
|
2935
|
-
onInput: HandleFilterInput,
|
|
2936
|
-
placeholder: '0',
|
|
2937
|
-
type: Input,
|
|
2938
|
-
value: timelineStartSeconds
|
|
2939
|
-
}, {
|
|
2940
|
-
childCount: 2,
|
|
2941
|
-
className: 'ChatDebugViewTimelineField',
|
|
2942
|
-
type: Label
|
|
2943
|
-
}, text('To'), {
|
|
2944
|
-
childCount: 0,
|
|
2945
|
-
className: 'InputBox ChatDebugViewTimelineInput',
|
|
2946
|
-
inputType: 'number',
|
|
2947
|
-
name: TimelineEndSeconds,
|
|
2948
|
-
onInput: HandleFilterInput,
|
|
2949
|
-
placeholder: formatTimelinePresetValue(timelineInfo.durationSeconds),
|
|
2950
|
-
type: Input,
|
|
2951
|
-
value: timelineEndSeconds
|
|
2952
|
-
}, {
|
|
4192
|
+
}, text(getTimelineSummary(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds)), {
|
|
2953
4193
|
childCount: 2,
|
|
2954
|
-
className:
|
|
2955
|
-
|
|
4194
|
+
className: 'ChatDebugViewTimelineInteractive',
|
|
4195
|
+
onDoubleClick: HandleTimelineDoubleClick,
|
|
4196
|
+
onPointerDown: HandleTimelinePointerDown,
|
|
4197
|
+
type: Div
|
|
2956
4198
|
}, {
|
|
2957
|
-
checked: !timelineInfo.hasSelection,
|
|
2958
|
-
childCount: 0,
|
|
2959
|
-
className: 'ChatDebugViewTimelinePresetInput',
|
|
2960
|
-
inputType: 'radio',
|
|
2961
|
-
name: TimelineRangePreset,
|
|
2962
|
-
onChange: HandleSimpleInput,
|
|
2963
|
-
type: Input,
|
|
2964
|
-
value: ''
|
|
2965
|
-
}, text('All'), {
|
|
2966
4199
|
childCount: timelineInfo.buckets.length,
|
|
2967
4200
|
className: 'ChatDebugViewTimelineBuckets',
|
|
2968
4201
|
type: Div
|
|
2969
|
-
}, ...timelineInfo.buckets.flatMap(
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
type: Label
|
|
2975
|
-
}, {
|
|
2976
|
-
checked: false,
|
|
2977
|
-
childCount: 0,
|
|
2978
|
-
className: 'ChatDebugViewTimelinePresetInput',
|
|
2979
|
-
inputType: 'radio',
|
|
2980
|
-
name: TimelineRangePreset,
|
|
2981
|
-
onChange: HandleSimpleInput,
|
|
2982
|
-
type: Input,
|
|
2983
|
-
value: presetValue
|
|
2984
|
-
}, {
|
|
2985
|
-
childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
|
|
2986
|
-
className: `ChatDebugViewTimelineBucketBar${bucket.isSelected ? ' ChatDebugViewTimelineBucketBarSelected' : ''}`,
|
|
2987
|
-
type: Div
|
|
2988
|
-
}, ...(bucket.unitCount === 0 ? [{
|
|
2989
|
-
childCount: 0,
|
|
2990
|
-
className: 'ChatDebugViewTimelineBucketUnit ChatDebugViewTimelineBucketUnitEmpty',
|
|
2991
|
-
type: Div
|
|
2992
|
-
}] : Array.from({
|
|
2993
|
-
length: bucket.unitCount
|
|
2994
|
-
}).fill({
|
|
2995
|
-
childCount: 0,
|
|
2996
|
-
className: 'ChatDebugViewTimelineBucketUnit',
|
|
2997
|
-
type: Div
|
|
2998
|
-
}))];
|
|
2999
|
-
})];
|
|
4202
|
+
}, ...timelineInfo.buckets.flatMap(getBucketDom), {
|
|
4203
|
+
childCount: selectionNodes.length,
|
|
4204
|
+
className: 'ChatDebugViewTimelineSelectionOverlay',
|
|
4205
|
+
type: Div
|
|
4206
|
+
}, ...selectionNodes];
|
|
3000
4207
|
};
|
|
3001
4208
|
|
|
3002
|
-
const getDevtoolsDom = (events, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds) => {
|
|
4209
|
+
const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage = 'No events have been found', timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', selectedDetailTab = Response) => {
|
|
3003
4210
|
const rowNodes = getDevtoolsRows(events, selectedEventIndex);
|
|
3004
|
-
const timelineNodes = getTimelineNodes(timelineEvents, timelineStartSeconds, timelineEndSeconds);
|
|
3005
|
-
const selectedEvent = selectedEventIndex === null ? undefined : events[selectedEventIndex];
|
|
4211
|
+
const timelineNodes = getTimelineNodes(timelineEvents, timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
|
|
3006
4212
|
const selectedEventNodes = selectedEvent ? getEventNode(selectedEvent) : [];
|
|
3007
4213
|
const hasSelectedEvent = selectedEventNodes.length > 0;
|
|
3008
|
-
const
|
|
3009
|
-
const
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
childCount: 2,
|
|
3015
|
-
className: 'ChatDebugViewDetailsTop',
|
|
3016
|
-
type: Div
|
|
3017
|
-
}, {
|
|
3018
|
-
childCount: 1,
|
|
3019
|
-
className: 'ChatDebugViewDetailsTitle',
|
|
3020
|
-
type: Div
|
|
3021
|
-
}, text('Details'), {
|
|
3022
|
-
childCount: 0,
|
|
3023
|
-
className: 'ChatDebugViewDetailsClose',
|
|
3024
|
-
inputType: 'checkbox',
|
|
3025
|
-
name: CloseDetails,
|
|
3026
|
-
onChange: HandleSimpleInput,
|
|
3027
|
-
type: Input,
|
|
3028
|
-
value: 'close'
|
|
3029
|
-
}, {
|
|
3030
|
-
childCount: selectedEventNodes.length,
|
|
3031
|
-
className: 'ChatDebugViewDetailsBody',
|
|
3032
|
-
type: Div
|
|
3033
|
-
}, ...selectedEventNodes] : [];
|
|
4214
|
+
const tableNodes = events.length === 0 ? getEmptyStateDom(emptyMessage) : getTableDom(rowNodes, events.length);
|
|
4215
|
+
const eventsClassName = getEventsClassName(hasSelectedEvent);
|
|
4216
|
+
const detailsNodes = getDetailsDom(selectedEventNodes, selectedEvent, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response);
|
|
4217
|
+
const sashNodes = getSashNodesDom(hasSelectedEvent);
|
|
4218
|
+
const splitChildCount = hasSelectedEvent ? 3 : 1;
|
|
4219
|
+
const mainChildCount = 1 + (timelineNodes.length > 0 ? 1 : 0);
|
|
3034
4220
|
return [{
|
|
3035
|
-
childCount:
|
|
4221
|
+
childCount: mainChildCount,
|
|
3036
4222
|
className: 'ChatDebugViewDevtoolsMain',
|
|
3037
4223
|
type: Div
|
|
3038
|
-
}, {
|
|
3039
|
-
childCount: timelineNodes.length > 0 ? 3 : 2,
|
|
3040
|
-
className: eventsClassName,
|
|
3041
|
-
type: Div
|
|
3042
4224
|
}, ...timelineNodes, {
|
|
3043
|
-
childCount:
|
|
3044
|
-
className: '
|
|
4225
|
+
childCount: splitChildCount,
|
|
4226
|
+
className: 'ChatDebugViewDevtoolsSplit',
|
|
3045
4227
|
type: Div
|
|
3046
4228
|
}, {
|
|
3047
4229
|
childCount: 1,
|
|
3048
|
-
className:
|
|
3049
|
-
type: Div
|
|
3050
|
-
}, text('Type'), {
|
|
3051
|
-
childCount: 1,
|
|
3052
|
-
className: 'ChatDebugViewHeaderCell',
|
|
3053
|
-
type: Div
|
|
3054
|
-
}, text('Started'), {
|
|
3055
|
-
childCount: 1,
|
|
3056
|
-
className: 'ChatDebugViewHeaderCell',
|
|
3057
|
-
type: Div
|
|
3058
|
-
}, text('Ended'), {
|
|
3059
|
-
childCount: 1,
|
|
3060
|
-
className: 'ChatDebugViewHeaderCell ChatDebugViewCellDuration',
|
|
3061
|
-
type: Div
|
|
3062
|
-
}, text('Duration'), {
|
|
3063
|
-
childCount: 1,
|
|
3064
|
-
className: 'ChatDebugViewHeaderCell ChatDebugViewCellStatus',
|
|
3065
|
-
type: Div
|
|
3066
|
-
}, text('Status'), {
|
|
3067
|
-
childCount: rowNodes.length === 0 ? 1 : rowNodes.length,
|
|
3068
|
-
className: 'ChatDebugViewTableBody',
|
|
4230
|
+
className: eventsClassName,
|
|
3069
4231
|
type: Div
|
|
3070
|
-
}, ...
|
|
4232
|
+
}, ...tableNodes, ...sashNodes, ...detailsNodes];
|
|
3071
4233
|
};
|
|
3072
4234
|
|
|
3073
4235
|
const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
@@ -3081,12 +4243,13 @@ const getLegacyEventsDom = (errorMessage, emptyMessage, eventNodes) => {
|
|
|
3081
4243
|
type: Div
|
|
3082
4244
|
}, text(errorMessage || emptyMessage)] : eventNodes)];
|
|
3083
4245
|
};
|
|
3084
|
-
|
|
4246
|
+
|
|
4247
|
+
const getQuickFilterNodes = (eventCategoryFilter, eventCategoryFilterOptions) => {
|
|
3085
4248
|
return [{
|
|
3086
|
-
childCount:
|
|
4249
|
+
childCount: eventCategoryFilterOptions.length,
|
|
3087
4250
|
className: 'ChatDebugViewQuickFilters',
|
|
3088
4251
|
type: Div
|
|
3089
|
-
}, ...
|
|
4252
|
+
}, ...eventCategoryFilterOptions.flatMap(option => {
|
|
3090
4253
|
const isSelected = option.value === eventCategoryFilter;
|
|
3091
4254
|
return [{
|
|
3092
4255
|
childCount: 2,
|
|
@@ -3104,6 +4267,7 @@ const getQuickFilterNodes = eventCategoryFilter => {
|
|
|
3104
4267
|
}, text(option.label)];
|
|
3105
4268
|
})];
|
|
3106
4269
|
};
|
|
4270
|
+
|
|
3107
4271
|
const getTimelineFilterDescription = (timelineStartSeconds, timelineEndSeconds) => {
|
|
3108
4272
|
const trimmedStart = timelineStartSeconds.trim();
|
|
3109
4273
|
const trimmedEnd = timelineEndSeconds.trim();
|
|
@@ -3118,19 +4282,11 @@ const getTimelineFilterDescription = (timelineStartSeconds, timelineEndSeconds)
|
|
|
3118
4282
|
}
|
|
3119
4283
|
return '';
|
|
3120
4284
|
};
|
|
3121
|
-
|
|
4285
|
+
|
|
4286
|
+
const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, eventCategoryFilterOptions, _showEventStreamFinishedEvents, _showInputEvents, _showResponsePartEvents, useDevtoolsLayout, selectedEvent, selectedEventIndex, timelineStartSeconds, timelineEndSeconds, timelineEvents, events, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', selectedDetailTab = Response) => {
|
|
3122
4287
|
if (errorMessage) {
|
|
3123
|
-
return
|
|
3124
|
-
childCount: 1,
|
|
3125
|
-
className: 'ChatDebugView',
|
|
3126
|
-
type: Div
|
|
3127
|
-
}, {
|
|
3128
|
-
childCount: 1,
|
|
3129
|
-
className: 'ChatDebugViewError',
|
|
3130
|
-
type: Div
|
|
3131
|
-
}, text(errorMessage)];
|
|
4288
|
+
return getDebugErrorDom(errorMessage);
|
|
3132
4289
|
}
|
|
3133
|
-
const eventNodes = events.flatMap(getEventNode);
|
|
3134
4290
|
const trimmedFilterValue = filterValue.trim();
|
|
3135
4291
|
const filterDescriptionParts = [];
|
|
3136
4292
|
if (eventCategoryFilter !== All) {
|
|
@@ -3146,90 +4302,24 @@ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilter, sho
|
|
|
3146
4302
|
const hasFilterValue = filterDescriptionParts.length > 0;
|
|
3147
4303
|
const filterDescription = filterDescriptionParts.join(' ');
|
|
3148
4304
|
const noFilteredEventsMessage = `no events found matching ${filterDescription}`;
|
|
3149
|
-
const
|
|
3150
|
-
const emptyMessage = events.length === 0 && hasFilterValue ? noFilteredEventsMessage : 'No events';
|
|
4305
|
+
const emptyMessage = events.length === 0 && hasFilterValue ? noFilteredEventsMessage : 'No events have been found';
|
|
3151
4306
|
const safeSelectedEventIndex = selectedEventIndex === null || selectedEventIndex < 0 || selectedEventIndex >= events.length ? null : selectedEventIndex;
|
|
3152
|
-
const contentNodes = useDevtoolsLayout ? getDevtoolsDom(events, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds) : getLegacyEventsDom(errorMessage, emptyMessage,
|
|
3153
|
-
const quickFilterNodes = useDevtoolsLayout ? getQuickFilterNodes(eventCategoryFilter) : [];
|
|
3154
|
-
const
|
|
4307
|
+
const contentNodes = useDevtoolsLayout ? getDevtoolsDom(events, selectedEvent, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds, isDetailTab(selectedDetailTab) ? selectedDetailTab : Response) : getLegacyEventsDom(errorMessage, emptyMessage, events.flatMap(getEventNode));
|
|
4308
|
+
const quickFilterNodes = useDevtoolsLayout ? getQuickFilterNodes(eventCategoryFilter, eventCategoryFilterOptions) : [];
|
|
4309
|
+
const debugViewTopDom = getDebugViewTopDom(filterValue, useDevtoolsLayout, quickFilterNodes);
|
|
4310
|
+
const rootChildCount = 2;
|
|
3155
4311
|
return [{
|
|
3156
4312
|
childCount: rootChildCount,
|
|
3157
4313
|
className: useDevtoolsLayout ? 'ChatDebugView ChatDebugView--devtools' : 'ChatDebugView',
|
|
3158
4314
|
type: Div
|
|
3159
|
-
},
|
|
3160
|
-
childCount: 2,
|
|
3161
|
-
className: 'ChatDebugViewTop',
|
|
3162
|
-
type: Div
|
|
3163
|
-
}, {
|
|
3164
|
-
autocomplete: 'off',
|
|
3165
|
-
childCount: 0,
|
|
3166
|
-
className: 'InputBox',
|
|
3167
|
-
inputType: 'search',
|
|
3168
|
-
name: Filter,
|
|
3169
|
-
onInput: HandleFilterInput,
|
|
3170
|
-
placeholder: 'Filter events',
|
|
3171
|
-
type: Input,
|
|
3172
|
-
value: filterValue
|
|
3173
|
-
}, {
|
|
3174
|
-
childCount: 4,
|
|
3175
|
-
className: 'ChatDebugViewToggle',
|
|
3176
|
-
type: Div
|
|
3177
|
-
}, {
|
|
3178
|
-
childCount: 2,
|
|
3179
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3180
|
-
type: Label
|
|
3181
|
-
}, {
|
|
3182
|
-
checked: showEventStreamFinishedEvents,
|
|
3183
|
-
childCount: 0,
|
|
3184
|
-
inputType: 'checkbox',
|
|
3185
|
-
name: ShowEventStreamFinishedEvents,
|
|
3186
|
-
onChange: HandleInput,
|
|
3187
|
-
type: Input
|
|
3188
|
-
}, text('Show event stream finished events'), {
|
|
3189
|
-
childCount: 2,
|
|
3190
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3191
|
-
type: Label
|
|
3192
|
-
}, {
|
|
3193
|
-
checked: showInputEvents,
|
|
3194
|
-
childCount: 0,
|
|
3195
|
-
inputType: 'checkbox',
|
|
3196
|
-
name: ShowInputEvents,
|
|
3197
|
-
onChange: HandleInput,
|
|
3198
|
-
type: Input
|
|
3199
|
-
}, text('Show input events'), {
|
|
3200
|
-
childCount: 2,
|
|
3201
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3202
|
-
type: Label
|
|
3203
|
-
}, {
|
|
3204
|
-
checked: showResponsePartEvents,
|
|
3205
|
-
childCount: 0,
|
|
3206
|
-
inputType: 'checkbox',
|
|
3207
|
-
name: ShowResponsePartEvents,
|
|
3208
|
-
onChange: HandleInput,
|
|
3209
|
-
type: Input
|
|
3210
|
-
}, text('Show response part events'), {
|
|
3211
|
-
childCount: 2,
|
|
3212
|
-
className: 'ChatDebugViewToggleLabel',
|
|
3213
|
-
type: Label
|
|
3214
|
-
}, {
|
|
3215
|
-
checked: useDevtoolsLayout,
|
|
3216
|
-
childCount: 0,
|
|
3217
|
-
inputType: 'checkbox',
|
|
3218
|
-
name: UseDevtoolsLayout,
|
|
3219
|
-
onChange: HandleInput,
|
|
3220
|
-
type: Input
|
|
3221
|
-
}, text('Use devtools layout'), ...quickFilterNodes, {
|
|
3222
|
-
childCount: 1,
|
|
3223
|
-
className: 'ChatDebugViewEventCount',
|
|
3224
|
-
type: Div
|
|
3225
|
-
}, text(eventCountText), ...contentNodes];
|
|
4315
|
+
}, ...debugViewTopDom, ...contentNodes];
|
|
3226
4316
|
};
|
|
3227
4317
|
|
|
3228
4318
|
const withSessionEventIds = events => {
|
|
3229
4319
|
return events.map((event, index) => {
|
|
3230
4320
|
return {
|
|
3231
4321
|
...event,
|
|
3232
|
-
eventId: index + 1
|
|
4322
|
+
eventId: typeof event.eventId === 'number' ? event.eventId : index + 1
|
|
3233
4323
|
};
|
|
3234
4324
|
});
|
|
3235
4325
|
};
|
|
@@ -3237,10 +4327,9 @@ const renderItems = (oldState, newState) => {
|
|
|
3237
4327
|
if (newState.initial) {
|
|
3238
4328
|
return [SetDom2, newState.uid, []];
|
|
3239
4329
|
}
|
|
3240
|
-
const
|
|
3241
|
-
const timelineEvents = getFilteredEvents(eventsWithIds, newState.filterValue, newState.eventCategoryFilter, newState.showInputEvents, newState.showResponsePartEvents, newState.showEventStreamFinishedEvents);
|
|
4330
|
+
const timelineEvents = getTimelineEvents(newState);
|
|
3242
4331
|
const filteredEvents = filterEventsByTimelineRange(timelineEvents, newState.timelineStartSeconds, newState.timelineEndSeconds);
|
|
3243
|
-
const dom = getChatDebugViewDom(newState.errorMessage, newState.filterValue, newState.eventCategoryFilter, newState.showEventStreamFinishedEvents, newState.showInputEvents, newState.showResponsePartEvents, newState.useDevtoolsLayout, newState.selectedEventIndex, newState.timelineStartSeconds, newState.timelineEndSeconds, timelineEvents, filteredEvents);
|
|
4332
|
+
const dom = getChatDebugViewDom(newState.errorMessage, newState.filterValue, newState.eventCategoryFilter, newState.eventCategoryFilterOptions, newState.showEventStreamFinishedEvents, newState.showInputEvents, newState.showResponsePartEvents, newState.useDevtoolsLayout, newState.selectedEvent, newState.selectedEventIndex, newState.timelineStartSeconds, newState.timelineEndSeconds, withSessionEventIds(timelineEvents), withSessionEventIds(filteredEvents), newState.timelineSelectionActive, newState.timelineSelectionAnchorSeconds, newState.timelineSelectionFocusSeconds, newState.selectedDetailTab);
|
|
3244
4333
|
return [SetDom2, newState.uid, dom];
|
|
3245
4334
|
};
|
|
3246
4335
|
|
|
@@ -3287,6 +4376,13 @@ const render2 = (uid, diffResult) => {
|
|
|
3287
4376
|
|
|
3288
4377
|
const renderEventListeners = () => {
|
|
3289
4378
|
return [{
|
|
4379
|
+
name: HandleEventRowClick,
|
|
4380
|
+
params: ['handleEventRowClick', 'event.target.dataset.index']
|
|
4381
|
+
}, {
|
|
4382
|
+
name: HandleTableBodyContextMenu,
|
|
4383
|
+
params: ['handleTableBodyContextMenu'],
|
|
4384
|
+
preventDefault: true
|
|
4385
|
+
}, {
|
|
3290
4386
|
name: HandleFilterInput,
|
|
3291
4387
|
params: ['handleInput', TargetName, TargetValue]
|
|
3292
4388
|
}, {
|
|
@@ -3295,6 +4391,29 @@ const renderEventListeners = () => {
|
|
|
3295
4391
|
}, {
|
|
3296
4392
|
name: HandleSimpleInput,
|
|
3297
4393
|
params: ['handleInput', TargetName, TargetValue]
|
|
4394
|
+
}, {
|
|
4395
|
+
name: HandleSashPointerDown,
|
|
4396
|
+
params: ['handleSashPointerDown', ClientX, ClientY],
|
|
4397
|
+
trackPointerEvents: [HandleSashPointerMove, HandleSashPointerUp]
|
|
4398
|
+
}, {
|
|
4399
|
+
name: HandleSashPointerMove,
|
|
4400
|
+
params: ['handleSashPointerMove', ClientX, ClientY]
|
|
4401
|
+
}, {
|
|
4402
|
+
name: HandleSashPointerUp,
|
|
4403
|
+
params: ['handleSashPointerUp', ClientX, ClientY]
|
|
4404
|
+
}, {
|
|
4405
|
+
name: HandleTimelinePointerDown,
|
|
4406
|
+
params: ['handleTimelinePointerDown', ClientX],
|
|
4407
|
+
trackPointerEvents: [HandleTimelinePointerMove, HandleTimelinePointerUp]
|
|
4408
|
+
}, {
|
|
4409
|
+
name: HandleTimelinePointerMove,
|
|
4410
|
+
params: ['handleTimelinePointerMove', ClientX]
|
|
4411
|
+
}, {
|
|
4412
|
+
name: HandleTimelinePointerUp,
|
|
4413
|
+
params: ['handleTimelinePointerUp', ClientX]
|
|
4414
|
+
}, {
|
|
4415
|
+
name: HandleTimelineDoubleClick,
|
|
4416
|
+
params: ['handleTimelineDoubleClick']
|
|
3298
4417
|
}];
|
|
3299
4418
|
};
|
|
3300
4419
|
|
|
@@ -3302,11 +4421,25 @@ const rerender = state => {
|
|
|
3302
4421
|
return structuredClone(state);
|
|
3303
4422
|
};
|
|
3304
4423
|
|
|
3305
|
-
const
|
|
3306
|
-
|
|
4424
|
+
const handleResize = (state, dimensions) => {
|
|
4425
|
+
const nextState = {
|
|
3307
4426
|
...state,
|
|
3308
4427
|
...dimensions
|
|
3309
4428
|
};
|
|
4429
|
+
return {
|
|
4430
|
+
...nextState,
|
|
4431
|
+
tableWidth: clampTableWidth(nextState.width, state.tableWidth)
|
|
4432
|
+
};
|
|
4433
|
+
};
|
|
4434
|
+
|
|
4435
|
+
const isResizeDimensions = value => {
|
|
4436
|
+
return typeof value === 'object' && value !== null;
|
|
4437
|
+
};
|
|
4438
|
+
const resize = (state, dimensions) => {
|
|
4439
|
+
if (!isResizeDimensions(dimensions)) {
|
|
4440
|
+
return state;
|
|
4441
|
+
}
|
|
4442
|
+
return handleResize(state, dimensions);
|
|
3310
4443
|
};
|
|
3311
4444
|
|
|
3312
4445
|
const saveState = state => {
|
|
@@ -3314,13 +4447,11 @@ const saveState = state => {
|
|
|
3314
4447
|
eventCategoryFilter,
|
|
3315
4448
|
filterValue,
|
|
3316
4449
|
height,
|
|
4450
|
+
selectedEventId,
|
|
3317
4451
|
sessionId,
|
|
3318
|
-
|
|
3319
|
-
showInputEvents,
|
|
3320
|
-
showResponsePartEvents,
|
|
4452
|
+
tableWidth,
|
|
3321
4453
|
timelineEndSeconds,
|
|
3322
4454
|
timelineStartSeconds,
|
|
3323
|
-
useDevtoolsLayout,
|
|
3324
4455
|
width,
|
|
3325
4456
|
x,
|
|
3326
4457
|
y
|
|
@@ -3329,13 +4460,11 @@ const saveState = state => {
|
|
|
3329
4460
|
eventCategoryFilter,
|
|
3330
4461
|
filterValue,
|
|
3331
4462
|
height,
|
|
4463
|
+
selectedEventId,
|
|
3332
4464
|
sessionId,
|
|
3333
|
-
|
|
3334
|
-
showInputEvents,
|
|
3335
|
-
showResponsePartEvents,
|
|
4465
|
+
tableWidth,
|
|
3336
4466
|
timelineEndSeconds,
|
|
3337
4467
|
timelineStartSeconds,
|
|
3338
|
-
useDevtoolsLayout,
|
|
3339
4468
|
width,
|
|
3340
4469
|
x,
|
|
3341
4470
|
y
|
|
@@ -3348,17 +4477,50 @@ const setEvents = (state, events) => {
|
|
|
3348
4477
|
errorMessage: '',
|
|
3349
4478
|
events,
|
|
3350
4479
|
initial: false,
|
|
4480
|
+
selectedEvent: null,
|
|
4481
|
+
selectedEventId: null,
|
|
3351
4482
|
selectedEventIndex: null
|
|
3352
4483
|
};
|
|
3353
4484
|
};
|
|
3354
4485
|
|
|
4486
|
+
const setIndexedDbSupportForTest = supported => {
|
|
4487
|
+
return setIndexedDbSupportOverride(supported);
|
|
4488
|
+
};
|
|
4489
|
+
|
|
3355
4490
|
const setSessionId = async (state, sessionId) => {
|
|
3356
|
-
const
|
|
4491
|
+
const result = await listChatViewEvents(sessionId, state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionIdIndexName);
|
|
4492
|
+
if (result.type === 'not-supported') {
|
|
4493
|
+
return {
|
|
4494
|
+
...state,
|
|
4495
|
+
errorMessage: getIndexedDbNotSupportedMessage(),
|
|
4496
|
+
events: [],
|
|
4497
|
+
initial: false,
|
|
4498
|
+
selectedEvent: null,
|
|
4499
|
+
selectedEventId: null,
|
|
4500
|
+
sessionId
|
|
4501
|
+
};
|
|
4502
|
+
}
|
|
4503
|
+
if (result.type === 'error') {
|
|
4504
|
+
return {
|
|
4505
|
+
...state,
|
|
4506
|
+
errorMessage: getFailedToLoadMessage(sessionId),
|
|
4507
|
+
events: [],
|
|
4508
|
+
initial: false,
|
|
4509
|
+
selectedEvent: null,
|
|
4510
|
+
selectedEventId: null,
|
|
4511
|
+
sessionId
|
|
4512
|
+
};
|
|
4513
|
+
}
|
|
4514
|
+
const {
|
|
4515
|
+
events
|
|
4516
|
+
} = result;
|
|
3357
4517
|
return {
|
|
3358
4518
|
...state,
|
|
3359
4519
|
errorMessage: '',
|
|
3360
4520
|
events,
|
|
3361
4521
|
initial: false,
|
|
4522
|
+
selectedEvent: null,
|
|
4523
|
+
selectedEventId: null,
|
|
3362
4524
|
sessionId
|
|
3363
4525
|
};
|
|
3364
4526
|
};
|
|
@@ -3367,7 +4529,16 @@ const commandMap = {
|
|
|
3367
4529
|
'ChatDebug.create': create,
|
|
3368
4530
|
'ChatDebug.diff2': diff2,
|
|
3369
4531
|
'ChatDebug.getCommandIds': getCommandIds,
|
|
4532
|
+
'ChatDebug.handleEventRowClick': wrapCommand(handleEventRowClick),
|
|
3370
4533
|
'ChatDebug.handleInput': wrapCommand(handleInput),
|
|
4534
|
+
'ChatDebug.handleSashPointerDown': wrapCommand(handleSashPointerDown),
|
|
4535
|
+
'ChatDebug.handleSashPointerMove': wrapCommand(handleSashPointerMove),
|
|
4536
|
+
'ChatDebug.handleSashPointerUp': wrapCommand(handleSashPointerUp),
|
|
4537
|
+
'ChatDebug.handleTableBodyContextMenu': wrapCommand(handleTableBodyContextMenu),
|
|
4538
|
+
'ChatDebug.handleTimelineDoubleClick': wrapCommand(handleTimelineDoubleClick),
|
|
4539
|
+
'ChatDebug.handleTimelinePointerDown': wrapCommand(handleTimelinePointerDown),
|
|
4540
|
+
'ChatDebug.handleTimelinePointerMove': wrapCommand(handleTimelinePointerMove),
|
|
4541
|
+
'ChatDebug.handleTimelinePointerUp': wrapCommand(handleTimelinePointerUp),
|
|
3371
4542
|
'ChatDebug.loadContent': wrapCommand(loadContent),
|
|
3372
4543
|
'ChatDebug.loadContent2': wrapCommand(loadContent),
|
|
3373
4544
|
'ChatDebug.refresh': wrapCommand(refresh),
|
|
@@ -3377,6 +4548,7 @@ const commandMap = {
|
|
|
3377
4548
|
'ChatDebug.resize': wrapCommand(resize),
|
|
3378
4549
|
'ChatDebug.saveState': wrapGetter(saveState),
|
|
3379
4550
|
'ChatDebug.setEvents': wrapCommand(setEvents),
|
|
4551
|
+
'ChatDebug.setIndexedDbSupportForTest': setIndexedDbSupportForTest,
|
|
3380
4552
|
'ChatDebug.setSessionId': wrapCommand(setSessionId),
|
|
3381
4553
|
'ChatDebug.terminate': terminate
|
|
3382
4554
|
};
|