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