@lvce-editor/chat-debug-view 5.5.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,6 +54,49 @@ class VError extends Error {
54
54
  }
55
55
  }
56
56
 
57
+ class AssertionError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'AssertionError';
61
+ }
62
+ }
63
+ const Object$1 = 1;
64
+ const Number$1 = 2;
65
+ const Array$1 = 3;
66
+ const String$1 = 4;
67
+ const Boolean$1 = 5;
68
+ const Function = 6;
69
+ const Null = 7;
70
+ const Unknown = 8;
71
+ const getType = value => {
72
+ switch (typeof value) {
73
+ case 'number':
74
+ return Number$1;
75
+ case 'function':
76
+ return Function;
77
+ case 'string':
78
+ return String$1;
79
+ case 'object':
80
+ if (value === null) {
81
+ return Null;
82
+ }
83
+ if (Array.isArray(value)) {
84
+ return Array$1;
85
+ }
86
+ return Object$1;
87
+ case 'boolean':
88
+ return Boolean$1;
89
+ default:
90
+ return Unknown;
91
+ }
92
+ };
93
+ const number = value => {
94
+ const type = getType(value);
95
+ if (type !== Number$1) {
96
+ throw new AssertionError('expected value to be of type number');
97
+ }
98
+ };
99
+
57
100
  const isMessagePort = value => {
58
101
  return value && value instanceof MessagePort;
59
102
  };
@@ -368,6 +411,100 @@ const IpcChildWithModuleWorkerAndMessagePort$1 = {
368
411
  listen: listen$6,
369
412
  wrap: wrap$e
370
413
  };
414
+ const addListener = (emitter, type, callback) => {
415
+ if ('addEventListener' in emitter) {
416
+ emitter.addEventListener(type, callback);
417
+ } else {
418
+ emitter.on(type, callback);
419
+ }
420
+ };
421
+ const removeListener = (emitter, type, callback) => {
422
+ if ('removeEventListener' in emitter) {
423
+ emitter.removeEventListener(type, callback);
424
+ } else {
425
+ emitter.off(type, callback);
426
+ }
427
+ };
428
+ const getFirstEvent = (eventEmitter, eventMap) => {
429
+ const {
430
+ promise,
431
+ resolve
432
+ } = Promise.withResolvers();
433
+ const listenerMap = Object.create(null);
434
+ const cleanup = value => {
435
+ for (const event of Object.keys(eventMap)) {
436
+ removeListener(eventEmitter, event, listenerMap[event]);
437
+ }
438
+ resolve(value);
439
+ };
440
+ for (const [event, type] of Object.entries(eventMap)) {
441
+ const listener = event => {
442
+ cleanup({
443
+ event,
444
+ type
445
+ });
446
+ };
447
+ addListener(eventEmitter, event, listener);
448
+ listenerMap[event] = listener;
449
+ }
450
+ return promise;
451
+ };
452
+ const Message$1 = 3;
453
+ const create$5$1 = async ({
454
+ isMessagePortOpen,
455
+ messagePort
456
+ }) => {
457
+ if (!isMessagePort(messagePort)) {
458
+ throw new IpcError('port must be of type MessagePort');
459
+ }
460
+ if (isMessagePortOpen) {
461
+ return messagePort;
462
+ }
463
+ const eventPromise = getFirstEvent(messagePort, {
464
+ message: Message$1
465
+ });
466
+ messagePort.start();
467
+ const {
468
+ event,
469
+ type
470
+ } = await eventPromise;
471
+ if (type !== Message$1) {
472
+ throw new IpcError('Failed to wait for ipc message');
473
+ }
474
+ if (event.data !== readyMessage) {
475
+ throw new IpcError('unexpected first message');
476
+ }
477
+ return messagePort;
478
+ };
479
+ const signal$1 = messagePort => {
480
+ messagePort.start();
481
+ };
482
+ class IpcParentWithMessagePort extends Ipc {
483
+ getData = getData$2;
484
+ send(message) {
485
+ this._rawIpc.postMessage(message);
486
+ }
487
+ sendAndTransfer(message) {
488
+ const transfer = getTransferrables(message);
489
+ this._rawIpc.postMessage(message, transfer);
490
+ }
491
+ dispose() {
492
+ this._rawIpc.close();
493
+ }
494
+ onMessage(callback) {
495
+ this._rawIpc.addEventListener('message', callback);
496
+ }
497
+ onClose(callback) {}
498
+ }
499
+ const wrap$5 = messagePort => {
500
+ return new IpcParentWithMessagePort(messagePort);
501
+ };
502
+ const IpcParentWithMessagePort$1 = {
503
+ __proto__: null,
504
+ create: create$5$1,
505
+ signal: signal$1,
506
+ wrap: wrap$5
507
+ };
371
508
 
372
509
  class CommandNotFoundError extends Error {
373
510
  constructor(command) {
@@ -392,10 +529,10 @@ const execute = (command, ...args) => {
392
529
 
393
530
  const Two$1 = '2.0';
394
531
  const callbacks = Object.create(null);
395
- const get$1 = id => {
532
+ const get$2 = id => {
396
533
  return callbacks[id];
397
534
  };
398
- const remove = id => {
535
+ const remove$1 = id => {
399
536
  delete callbacks[id];
400
537
  };
401
538
  class JsonRpcError extends Error {
@@ -541,14 +678,14 @@ const warn = (...args) => {
541
678
  console.warn(...args);
542
679
  };
543
680
  const resolve = (id, response) => {
544
- const fn = get$1(id);
681
+ const fn = get$2(id);
545
682
  if (!fn) {
546
683
  console.log(response);
547
684
  warn(`callback ${id} may already be disposed`);
548
685
  return;
549
686
  }
550
687
  fn(response);
551
- remove(id);
688
+ remove$1(id);
552
689
  };
553
690
  const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND';
554
691
  const getErrorType = prettyError => {
@@ -604,7 +741,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
604
741
  const errorProperty = getErrorProperty(error, prettyError);
605
742
  return create$1$1(id, errorProperty);
606
743
  };
607
- const create$6 = (message, result) => {
744
+ const create$a = (message, result) => {
608
745
  return {
609
746
  id: message.id,
610
747
  jsonrpc: Two$1,
@@ -613,7 +750,7 @@ const create$6 = (message, result) => {
613
750
  };
614
751
  const getSuccessResponse = (message, result) => {
615
752
  const resultProperty = result ?? null;
616
- return create$6(message, resultProperty);
753
+ return create$a(message, resultProperty);
617
754
  };
618
755
  const getErrorResponseSimple = (id, error) => {
619
756
  return {
@@ -707,7 +844,7 @@ const handleJsonRpcMessage = async (...args) => {
707
844
 
708
845
  const Two = '2.0';
709
846
 
710
- const create$5 = (method, params) => {
847
+ const create$9 = (method, params) => {
711
848
  return {
712
849
  jsonrpc: Two,
713
850
  method,
@@ -715,7 +852,7 @@ const create$5 = (method, params) => {
715
852
  };
716
853
  };
717
854
 
718
- const create$4 = (id, method, params) => {
855
+ const create$8 = (id, method, params) => {
719
856
  const message = {
720
857
  id,
721
858
  jsonrpc: Two,
@@ -726,12 +863,12 @@ const create$4 = (id, method, params) => {
726
863
  };
727
864
 
728
865
  let id = 0;
729
- const create$3 = () => {
866
+ const create$7 = () => {
730
867
  return ++id;
731
868
  };
732
869
 
733
870
  const registerPromise = map => {
734
- const id = create$3();
871
+ const id = create$7();
735
872
  const {
736
873
  promise,
737
874
  resolve
@@ -748,7 +885,7 @@ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer)
748
885
  id,
749
886
  promise
750
887
  } = registerPromise(callbacks);
751
- const message = create$4(id, method, params);
888
+ const message = create$8(id, method, params);
752
889
  if (useSendAndTransfer && ipc.sendAndTransfer) {
753
890
  ipc.sendAndTransfer(message);
754
891
  } else {
@@ -784,7 +921,7 @@ const createRpc = ipc => {
784
921
  * @deprecated
785
922
  */
786
923
  send(method, ...params) {
787
- const message = create$5(method, params);
924
+ const message = create$9(method, params);
788
925
  ipc.send(message);
789
926
  }
790
927
  };
@@ -824,7 +961,84 @@ const listen$1 = async (module, options) => {
824
961
  return ipc;
825
962
  };
826
963
 
827
- const create$2 = async ({
964
+ const create$6 = async ({
965
+ commandMap,
966
+ isMessagePortOpen = true,
967
+ messagePort
968
+ }) => {
969
+ // TODO create a commandMap per rpc instance
970
+ register(commandMap);
971
+ const rawIpc = await IpcParentWithMessagePort$1.create({
972
+ isMessagePortOpen,
973
+ messagePort
974
+ });
975
+ const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
976
+ handleIpc(ipc);
977
+ const rpc = createRpc(ipc);
978
+ messagePort.start();
979
+ return rpc;
980
+ };
981
+
982
+ const create$5 = async ({
983
+ commandMap,
984
+ isMessagePortOpen,
985
+ send
986
+ }) => {
987
+ const {
988
+ port1,
989
+ port2
990
+ } = new MessageChannel();
991
+ await send(port1);
992
+ return create$6({
993
+ commandMap,
994
+ isMessagePortOpen,
995
+ messagePort: port2
996
+ });
997
+ };
998
+
999
+ const createSharedLazyRpc = factory => {
1000
+ let rpcPromise;
1001
+ const getOrCreate = () => {
1002
+ if (!rpcPromise) {
1003
+ rpcPromise = factory();
1004
+ }
1005
+ return rpcPromise;
1006
+ };
1007
+ return {
1008
+ async dispose() {
1009
+ const rpc = await getOrCreate();
1010
+ await rpc.dispose();
1011
+ },
1012
+ async invoke(method, ...params) {
1013
+ const rpc = await getOrCreate();
1014
+ return rpc.invoke(method, ...params);
1015
+ },
1016
+ async invokeAndTransfer(method, ...params) {
1017
+ const rpc = await getOrCreate();
1018
+ return rpc.invokeAndTransfer(method, ...params);
1019
+ },
1020
+ async send(method, ...params) {
1021
+ const rpc = await getOrCreate();
1022
+ rpc.send(method, ...params);
1023
+ }
1024
+ };
1025
+ };
1026
+
1027
+ const create$4 = async ({
1028
+ commandMap,
1029
+ isMessagePortOpen,
1030
+ send
1031
+ }) => {
1032
+ return createSharedLazyRpc(() => {
1033
+ return create$5({
1034
+ commandMap,
1035
+ isMessagePortOpen,
1036
+ send
1037
+ });
1038
+ });
1039
+ };
1040
+
1041
+ const create$3 = async ({
828
1042
  commandMap
829
1043
  }) => {
830
1044
  // TODO create a commandMap per rpc instance
@@ -835,6 +1049,123 @@ const create$2 = async ({
835
1049
  return rpc;
836
1050
  };
837
1051
 
1052
+ const createMockRpc = ({
1053
+ commandMap
1054
+ }) => {
1055
+ const invocations = [];
1056
+ const invoke = (method, ...params) => {
1057
+ invocations.push([method, ...params]);
1058
+ const command = commandMap[method];
1059
+ if (!command) {
1060
+ throw new Error(`command ${method} not found`);
1061
+ }
1062
+ return command(...params);
1063
+ };
1064
+ const mockRpc = {
1065
+ invocations,
1066
+ invoke,
1067
+ invokeAndTransfer: invoke
1068
+ };
1069
+ return mockRpc;
1070
+ };
1071
+
1072
+ const rpcs = Object.create(null);
1073
+ const set$3 = (id, rpc) => {
1074
+ rpcs[id] = rpc;
1075
+ };
1076
+ const get$1 = id => {
1077
+ return rpcs[id];
1078
+ };
1079
+ const remove = id => {
1080
+ delete rpcs[id];
1081
+ };
1082
+
1083
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
1084
+ const create$2 = rpcId => {
1085
+ return {
1086
+ async dispose() {
1087
+ const rpc = get$1(rpcId);
1088
+ await rpc.dispose();
1089
+ },
1090
+ // @ts-ignore
1091
+ invoke(method, ...params) {
1092
+ const rpc = get$1(rpcId);
1093
+ // @ts-ignore
1094
+ return rpc.invoke(method, ...params);
1095
+ },
1096
+ // @ts-ignore
1097
+ invokeAndTransfer(method, ...params) {
1098
+ const rpc = get$1(rpcId);
1099
+ // @ts-ignore
1100
+ return rpc.invokeAndTransfer(method, ...params);
1101
+ },
1102
+ registerMockRpc(commandMap) {
1103
+ const mockRpc = createMockRpc({
1104
+ commandMap
1105
+ });
1106
+ set$3(rpcId, mockRpc);
1107
+ // @ts-ignore
1108
+ mockRpc[Symbol.dispose] = () => {
1109
+ remove(rpcId);
1110
+ };
1111
+ // @ts-ignore
1112
+ return mockRpc;
1113
+ },
1114
+ set(rpc) {
1115
+ set$3(rpcId, rpc);
1116
+ }
1117
+ };
1118
+ };
1119
+
1120
+ const Button$1 = 1;
1121
+ const Div = 4;
1122
+ const Input = 6;
1123
+ const Span = 8;
1124
+ const Table = 9;
1125
+ const TBody = 10;
1126
+ const Td = 11;
1127
+ const Text = 12;
1128
+ const Th = 13;
1129
+ const THead = 14;
1130
+ const Tr = 15;
1131
+ const Search = 42;
1132
+ const Label = 66;
1133
+ const Reference = 100;
1134
+
1135
+ const Button = 'event.button';
1136
+ const ClientX = 'event.clientX';
1137
+ const ClientY = 'event.clientY';
1138
+ const TargetName = 'event.target.name';
1139
+ const TargetValue = 'event.target.value';
1140
+
1141
+ const ChatStorageWorker = 6003;
1142
+ const RendererWorker = 1;
1143
+
1144
+ const SetCss = 'Viewlet.setCss';
1145
+ const SetDom2 = 'Viewlet.setDom2';
1146
+ const SetPatches = 'Viewlet.setPatches';
1147
+
1148
+ const {
1149
+ invoke: invoke$1,
1150
+ set: set$2
1151
+ } = create$2(ChatStorageWorker);
1152
+
1153
+ const {
1154
+ invoke,
1155
+ invokeAndTransfer,
1156
+ set: set$1
1157
+ } = create$2(RendererWorker);
1158
+ const showContextMenu2 = async (uid, menuId, x, y, args) => {
1159
+ number(uid);
1160
+ number(menuId);
1161
+ number(x);
1162
+ number(y);
1163
+ await invoke('ContextMenu.show2', uid, menuId, x, y, args);
1164
+ };
1165
+ const sendMessagePortToChatStorageWorker$1 = async port => {
1166
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatStorageWorker', port, 'HandleMessagePort.handleMessagePort');
1167
+ };
1168
+
838
1169
  const toCommandId = key => {
839
1170
  const dotIndex = key.indexOf('.');
840
1171
  return key.slice(dotIndex + 1);
@@ -1079,7 +1410,6 @@ const createDefaultState = () => {
1079
1410
  eventStoreName: 'chat-view-events',
1080
1411
  filterValue: '',
1081
1412
  height: 0,
1082
- indexedDbSupportOverride: undefined,
1083
1413
  initial: false,
1084
1414
  platform: 0,
1085
1415
  selectedDetailTab: Response,
@@ -1171,30 +1501,31 @@ const diff2 = uid => {
1171
1501
  return diff(oldState, newState);
1172
1502
  };
1173
1503
 
1174
- const handleCloseDetails = state => {
1175
- return {
1176
- ...state,
1177
- selectedEvent: null,
1178
- selectedEventId: null,
1179
- selectedEventIndex: null
1180
- };
1504
+ const getMenuIds = () => {
1505
+ return [555, 556, 557];
1181
1506
  };
1182
1507
 
1183
- const handleDetailsContextMenu = state => {
1184
- return state;
1508
+ const getErrorMessage = error => {
1509
+ if (error instanceof Error) {
1510
+ return error.message;
1511
+ }
1512
+ if (typeof error === 'string') {
1513
+ return error;
1514
+ }
1515
+ if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {
1516
+ return error.message;
1517
+ }
1518
+ return undefined;
1185
1519
  };
1186
-
1187
- const handleDetailTab = (state, value) => {
1188
- if (!isDetailTab(value)) {
1189
- return state;
1520
+ const getFailedToLoadMessage = (sessionId, error) => {
1521
+ const errorMessage = getErrorMessage(error);
1522
+ if (errorMessage) {
1523
+ return `Failed to load chat debug session "${sessionId}": ${errorMessage}`;
1190
1524
  }
1191
- return {
1192
- ...state,
1193
- selectedDetailTab: value
1194
- };
1525
+ return `Failed to load chat debug session "${sessionId}". Please try again.`;
1195
1526
  };
1196
1527
 
1197
- const hasMatchingToolName$1 = (startedEvent, finishedEvent) => {
1528
+ const hasMatchingToolName = (startedEvent, finishedEvent) => {
1198
1529
  if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
1199
1530
  return startedEvent.toolName === finishedEvent.toolName;
1200
1531
  }
@@ -1202,27 +1533,27 @@ const hasMatchingToolName$1 = (startedEvent, finishedEvent) => {
1202
1533
  };
1203
1534
 
1204
1535
  const isMatchingToolExecutionPair = (startedEvent, finishedEvent) => {
1205
- return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName$1(startedEvent, finishedEvent);
1536
+ return startedEvent.sessionId === finishedEvent.sessionId && hasMatchingToolName(startedEvent, finishedEvent);
1206
1537
  };
1207
1538
 
1208
- const startedEventType$1 = 'tool-execution-started';
1209
- const finishedEventType$1 = 'tool-execution-finished';
1539
+ const startedEventType = 'tool-execution-started';
1540
+ const finishedEventType = 'tool-execution-finished';
1210
1541
  const mergedEventType = 'tool-execution';
1211
1542
 
1212
1543
  const isToolExecutionFinishedEvent = event => {
1213
- return event.type === finishedEventType$1;
1544
+ return event.type === finishedEventType;
1214
1545
  };
1215
1546
 
1216
1547
  const isToolExecutionStartedEvent = event => {
1217
- return event.type === startedEventType$1;
1548
+ return event.type === startedEventType;
1218
1549
  };
1219
1550
 
1220
- const getTimestamp$1 = value => {
1551
+ const getTimestamp = value => {
1221
1552
  return typeof value === 'string' || typeof value === 'number' ? value : undefined;
1222
1553
  };
1223
1554
 
1224
1555
  const getEndedTimestamp = event => {
1225
- return getTimestamp$1(event.ended) ?? getTimestamp$1(event.endTime) ?? getTimestamp$1(event.endTimestamp) ?? getTimestamp$1(event.timestamp);
1556
+ return getTimestamp(event.ended) ?? getTimestamp(event.endTime) ?? getTimestamp(event.endTimestamp) ?? getTimestamp(event.timestamp);
1226
1557
  };
1227
1558
 
1228
1559
  const eventStableIds = new WeakMap();
@@ -1241,14 +1572,14 @@ const getOrCreateStableEventId = event => {
1241
1572
  };
1242
1573
 
1243
1574
  const getStartedTimestamp = event => {
1244
- return getTimestamp$1(event.started) ?? getTimestamp$1(event.startTime) ?? getTimestamp$1(event.startTimestamp) ?? getTimestamp$1(event.timestamp);
1575
+ return getTimestamp(event.started) ?? getTimestamp(event.startTime) ?? getTimestamp(event.startTimestamp) ?? getTimestamp(event.timestamp);
1245
1576
  };
1246
1577
 
1247
1578
  const setStableEventId = (event, stableEventId) => {
1248
1579
  eventStableIds.set(event, stableEventId);
1249
1580
  };
1250
1581
 
1251
- const mergeToolExecutionEvents$1 = (startedEvent, finishedEvent) => {
1582
+ const mergeToolExecutionEvents = (startedEvent, finishedEvent) => {
1252
1583
  const ended = getEndedTimestamp(finishedEvent);
1253
1584
  const {
1254
1585
  eventId
@@ -1284,7 +1615,7 @@ const collapseToolExecutionEvents = events => {
1284
1615
  if (isToolExecutionStartedEvent(event)) {
1285
1616
  const nextEvent = events[i + 1];
1286
1617
  if (nextEvent && isToolExecutionFinishedEvent(nextEvent) && isMatchingToolExecutionPair(event, nextEvent)) {
1287
- collapsedEvents.push(mergeToolExecutionEvents$1(event, nextEvent));
1618
+ collapsedEvents.push(mergeToolExecutionEvents(event, nextEvent));
1288
1619
  i++;
1289
1620
  continue;
1290
1621
  }
@@ -1361,6 +1692,24 @@ const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEv
1361
1692
  return filteredByCategory.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
1362
1693
  };
1363
1694
 
1695
+ const ParseChatDebugUriErrorCode = {
1696
+ InvalidSessionId: 'invalid-session-id',
1697
+ InvalidUriEncoding: 'invalid-uri-encoding',
1698
+ InvalidUriFormat: 'invalid-uri-format',
1699
+ MissingUri: 'missing-uri'
1700
+ };
1701
+
1702
+ const getInvalidUriMessage = (uri, code) => {
1703
+ if (code === ParseChatDebugUriErrorCode.MissingUri) {
1704
+ return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
1705
+ }
1706
+ return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
1707
+ };
1708
+
1709
+ const getSessionNotFoundMessage = sessionId => {
1710
+ return `No chat session found for sessionId "${sessionId}".`;
1711
+ };
1712
+
1364
1713
  const toTimeNumber = value => {
1365
1714
  if (typeof value === 'number' && Number.isFinite(value)) {
1366
1715
  return value;
@@ -1512,558 +1861,409 @@ const getTimelineInfo = (events, startValue, endValue) => {
1512
1861
  };
1513
1862
  };
1514
1863
 
1515
- const getCurrentEvents$3 = state => {
1516
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1517
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1864
+ const listChatViewEvents$1 = async sessionId => {
1865
+ return invoke$1('ChatStorage.listChatViewEvents', sessionId);
1518
1866
  };
1519
- const getEventIndexByStableId$1 = (events, event) => {
1520
- const stableEventId = getStableEventId(event);
1521
- return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
1867
+ const loadSelectedEvent$1 = async (sessionId, eventId, type) => {
1868
+ return invoke$1('ChatStorage.loadSelectedEvent', sessionId, eventId, type);
1522
1869
  };
1523
- const getSelectedEventIndex$1 = state => {
1524
- const {
1525
- selectedEventIndex
1526
- } = state;
1527
- if (selectedEventIndex === null) {
1528
- return null;
1529
- }
1530
- const filteredEvents = getCurrentEvents$3(state);
1531
- const selectedEvent = filteredEvents[selectedEventIndex];
1532
- if (!selectedEvent) {
1533
- return null;
1534
- }
1535
- const newIndex = getEventIndexByStableId$1(filteredEvents, selectedEvent);
1536
- if (newIndex === -1) {
1537
- return null;
1538
- }
1539
- return newIndex;
1870
+
1871
+ const listChatViewEventsDependencies = {
1872
+ listChatViewEventsFromWorker: listChatViewEvents$1
1540
1873
  };
1541
- const getPreservedSelectedEventIndex$1 = (oldState, newState) => {
1542
- const {
1543
- selectedEventIndex
1544
- } = oldState;
1545
- if (selectedEventIndex === null) {
1546
- return null;
1547
- }
1548
- const oldFilteredEvents = getCurrentEvents$3(oldState);
1549
- const selectedEvent = oldFilteredEvents[selectedEventIndex];
1550
- if (!selectedEvent) {
1551
- return null;
1552
- }
1553
- const newFilteredEvents = getCurrentEvents$3(newState);
1554
- const newIndex = getEventIndexByStableId$1(newFilteredEvents, selectedEvent);
1555
- if (newIndex === -1) {
1556
- return null;
1874
+ const listChatViewEvents = async (sessionId, _databaseName, _dataBaseVersion, _eventStoreName, _sessionIdIndexName) => {
1875
+ try {
1876
+ return await listChatViewEventsDependencies.listChatViewEventsFromWorker(sessionId);
1877
+ } catch (error) {
1878
+ return {
1879
+ error,
1880
+ type: 'error'
1881
+ };
1557
1882
  }
1558
- return newIndex;
1559
1883
  };
1560
- const withPreservedSelection$1 = (state, nextState) => {
1561
- const selectedEventIndex = getPreservedSelectedEventIndex$1(state, nextState);
1562
- return {
1563
- ...nextState,
1564
- selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
1565
- selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
1566
- selectedEventIndex
1567
- };
1884
+
1885
+ const loadSelectedEventDependencies = {
1886
+ loadSelectedEventFromWorker: loadSelectedEvent$1
1887
+ };
1888
+ const loadSelectedEvent = async (_databaseName, _dataBaseVersion, _eventStoreName, sessionId, _sessionIdIndexName, eventId, type) => {
1889
+ return loadSelectedEventDependencies.loadSelectedEventFromWorker(sessionId, eventId, type);
1568
1890
  };
1569
1891
 
1570
- const handleEventCategoryFilter = (state, value) => {
1571
- const nextState = {
1572
- ...state,
1573
- eventCategoryFilter: value || All
1574
- };
1575
- return withPreservedSelection$1(state, nextState);
1576
- };
1577
-
1578
- let workerRpc;
1579
- const setWorkerRpc = value => {
1580
- workerRpc = value;
1581
- };
1582
- const invoke = async (method, ...params) => {
1583
- if (!workerRpc) {
1584
- throw new Error('worker rpc is not initialized');
1585
- }
1586
- return workerRpc.invoke(method, ...params);
1587
- };
1588
-
1589
- const chatStorageWorkerClientDependencies = {
1590
- invoke: invoke
1591
- };
1592
- const listChatViewEvents$1 = async sessionId => {
1593
- return chatStorageWorkerClientDependencies.invoke('ChatStorage.listChatViewEvents', sessionId);
1594
- };
1595
- const loadSelectedEvent$1 = async (sessionId, eventId, type) => {
1596
- return chatStorageWorkerClientDependencies.invoke('ChatStorage.loadSelectedEvent', sessionId, eventId, type);
1597
- };
1598
-
1599
- // cspell:ignore IDBP
1600
-
1601
- const startedEventType = 'tool-execution-started';
1602
- const finishedEventType = 'tool-execution-finished';
1603
- const getRawEventBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId) => {
1604
- if (eventId < 1) {
1605
- return undefined;
1606
- }
1607
- if (store.indexNames.contains(sessionIdIndexName)) {
1608
- const index = store.index(sessionIdIndexName);
1609
- const keys = await index.getAllKeys(sessionId, eventId);
1610
- if (keys.length < eventId) {
1611
- return undefined;
1612
- }
1613
- const key = keys.at(-1);
1614
- if (key === undefined) {
1615
- return undefined;
1616
- }
1617
- const event = await store.get(key);
1618
- return event;
1619
- }
1620
- const all = await store.getAll();
1621
- const events = all.filter(event => event.sessionId === sessionId);
1622
- return events[eventId - 1];
1623
- };
1624
- const getTimestamp = value => {
1625
- return typeof value === 'string' || typeof value === 'number' ? value : undefined;
1626
- };
1627
- const hasMatchingToolName = (startedEvent, finishedEvent) => {
1628
- if (typeof startedEvent.toolName === 'string' && typeof finishedEvent.toolName === 'string') {
1629
- return startedEvent.toolName === finishedEvent.toolName;
1630
- }
1631
- return true;
1632
- };
1633
- const mergeToolExecutionEvents = (startedEvent, finishedEvent, eventId) => {
1634
- const ended = getTimestamp(finishedEvent.ended) ?? getTimestamp(finishedEvent.endTime) ?? getTimestamp(finishedEvent.timestamp);
1635
- const started = getTimestamp(startedEvent.started) ?? getTimestamp(startedEvent.startTime) ?? getTimestamp(startedEvent.timestamp);
1636
- return {
1637
- ...startedEvent,
1638
- ...finishedEvent,
1639
- ...(ended === undefined ? {} : {
1640
- ended
1641
- }),
1642
- eventId,
1643
- ...(started === undefined ? {} : {
1644
- started
1645
- }),
1646
- type: 'tool-execution'
1647
- };
1648
- };
1649
- const getEventDetailsBySessionIdAndEventId = async (store, sessionId, sessionIdIndexName, eventId, summaryType) => {
1650
- const event = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId);
1651
- if (!event) {
1652
- return undefined;
1653
- }
1654
- if (summaryType !== 'tool-execution') {
1892
+ const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
1893
+ const invalidSessionIdPattern = /[/?#]/;
1894
+ const parseChatDebugUri = uri => {
1895
+ if (!uri) {
1655
1896
  return {
1656
- ...event,
1657
- eventId
1897
+ code: ParseChatDebugUriErrorCode.MissingUri,
1898
+ message: 'Missing URI',
1899
+ type: 'error'
1658
1900
  };
1659
1901
  }
1660
- if (event.type !== startedEventType) {
1902
+ const match = uri.match(chatDebugUriPattern);
1903
+ if (!match) {
1661
1904
  return {
1662
- ...event,
1663
- eventId
1905
+ code: ParseChatDebugUriErrorCode.InvalidUriFormat,
1906
+ message: 'Invalid URI format',
1907
+ type: 'error'
1664
1908
  };
1665
1909
  }
1666
- const nextEvent = await getRawEventBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId + 1);
1667
- if (!nextEvent || nextEvent.type !== finishedEventType || nextEvent.sessionId !== sessionId || !hasMatchingToolName(event, nextEvent)) {
1910
+ const encodedSessionId = match[1];
1911
+ let sessionId;
1912
+ try {
1913
+ sessionId = decodeURIComponent(encodedSessionId);
1914
+ } catch {
1668
1915
  return {
1669
- ...event,
1670
- eventId
1671
- };
1672
- }
1673
- return mergeToolExecutionEvents(event, nextEvent, eventId);
1674
- };
1675
-
1676
- const instanceOfAny = (object, constructors) => constructors.some(c => object instanceof c);
1677
- let idbProxyableTypes;
1678
- let cursorAdvanceMethods;
1679
- // This is a function to prevent it throwing up in node environments.
1680
- function getIdbProxyableTypes() {
1681
- return idbProxyableTypes || (idbProxyableTypes = [IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction]);
1682
- }
1683
- // This is a function to prevent it throwing up in node environments.
1684
- function getCursorAdvanceMethods() {
1685
- return cursorAdvanceMethods || (cursorAdvanceMethods = [IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey]);
1686
- }
1687
- const transactionDoneMap = new WeakMap();
1688
- const transformCache = new WeakMap();
1689
- const reverseTransformCache = new WeakMap();
1690
- function promisifyRequest(request) {
1691
- const promise = new Promise((resolve, reject) => {
1692
- const unlisten = () => {
1693
- request.removeEventListener('success', success);
1694
- request.removeEventListener('error', error);
1695
- };
1696
- const success = () => {
1697
- resolve(wrap(request.result));
1698
- unlisten();
1699
- };
1700
- const error = () => {
1701
- reject(request.error);
1702
- unlisten();
1703
- };
1704
- request.addEventListener('success', success);
1705
- request.addEventListener('error', error);
1706
- });
1707
- // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
1708
- // is because we create many promises from a single IDBRequest.
1709
- reverseTransformCache.set(promise, request);
1710
- return promise;
1711
- }
1712
- function cacheDonePromiseForTransaction(tx) {
1713
- // Early bail if we've already created a done promise for this transaction.
1714
- if (transactionDoneMap.has(tx)) return;
1715
- const done = new Promise((resolve, reject) => {
1716
- const unlisten = () => {
1717
- tx.removeEventListener('complete', complete);
1718
- tx.removeEventListener('error', error);
1719
- tx.removeEventListener('abort', error);
1720
- };
1721
- const complete = () => {
1722
- resolve();
1723
- unlisten();
1724
- };
1725
- const error = () => {
1726
- reject(tx.error || new DOMException('AbortError', 'AbortError'));
1727
- unlisten();
1916
+ code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
1917
+ message: 'Invalid URI encoding',
1918
+ type: 'error'
1728
1919
  };
1729
- tx.addEventListener('complete', complete);
1730
- tx.addEventListener('error', error);
1731
- tx.addEventListener('abort', error);
1732
- });
1733
- // Cache it for later retrieval.
1734
- transactionDoneMap.set(tx, done);
1735
- }
1736
- let idbProxyTraps = {
1737
- get(target, prop, receiver) {
1738
- if (target instanceof IDBTransaction) {
1739
- // Special handling for transaction.done.
1740
- if (prop === 'done') return transactionDoneMap.get(target);
1741
- // Make tx.store return the only store in the transaction, or undefined if there are many.
1742
- if (prop === 'store') {
1743
- return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]);
1744
- }
1745
- }
1746
- // Else transform whatever we get back.
1747
- return wrap(target[prop]);
1748
- },
1749
- set(target, prop, value) {
1750
- target[prop] = value;
1751
- return true;
1752
- },
1753
- has(target, prop) {
1754
- if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) {
1755
- return true;
1756
- }
1757
- return prop in target;
1758
1920
  }
1759
- };
1760
- function replaceTraps(callback) {
1761
- idbProxyTraps = callback(idbProxyTraps);
1762
- }
1763
- function wrapFunction(func) {
1764
- // Due to expected object equality (which is enforced by the caching in `wrap`), we
1765
- // only create one new func per func.
1766
- // Cursor methods are special, as the behaviour is a little more different to standard IDB. In
1767
- // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
1768
- // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
1769
- // with real promises, so each advance methods returns a new promise for the cursor object, or
1770
- // undefined if the end of the cursor has been reached.
1771
- if (getCursorAdvanceMethods().includes(func)) {
1772
- return function (...args) {
1773
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
1774
- // the original object.
1775
- func.apply(unwrap(this), args);
1776
- return wrap(this.request);
1921
+ if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
1922
+ return {
1923
+ code: ParseChatDebugUriErrorCode.InvalidSessionId,
1924
+ message: 'Invalid session id',
1925
+ type: 'error'
1777
1926
  };
1778
1927
  }
1779
- return function (...args) {
1780
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
1781
- // the original object.
1782
- return wrap(func.apply(unwrap(this), args));
1783
- };
1784
- }
1785
- function transformCachableValue(value) {
1786
- if (typeof value === 'function') return wrapFunction(value);
1787
- // This doesn't return, it just creates a 'done' promise for the transaction,
1788
- // which is later returned for transaction.done (see idbObjectHandler).
1789
- if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value);
1790
- if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps);
1791
- // Return the same value back if we're not going to transform it.
1792
- return value;
1793
- }
1794
- function wrap(value) {
1795
- // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
1796
- // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
1797
- if (value instanceof IDBRequest) return promisifyRequest(value);
1798
- // If we've already transformed this value before, reuse the transformed value.
1799
- // This is faster, but it also provides object equality.
1800
- if (transformCache.has(value)) return transformCache.get(value);
1801
- const newValue = transformCachableValue(value);
1802
- // Not all types are transformed.
1803
- // These may be primitive types, so they can't be WeakMap keys.
1804
- if (newValue !== value) {
1805
- transformCache.set(value, newValue);
1806
- reverseTransformCache.set(newValue, value);
1807
- }
1808
- return newValue;
1809
- }
1810
- const unwrap = value => reverseTransformCache.get(value);
1811
-
1812
- /**
1813
- * Open a database.
1814
- *
1815
- * @param name Name of the database.
1816
- * @param version Schema version.
1817
- * @param callbacks Additional callbacks.
1818
- */
1819
- function openDB(name, version, {
1820
- blocked,
1821
- upgrade,
1822
- blocking,
1823
- terminated
1824
- } = {}) {
1825
- const request = indexedDB.open(name, version);
1826
- const openPromise = wrap(request);
1827
- if (upgrade) {
1828
- request.addEventListener('upgradeneeded', event => {
1829
- upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
1830
- });
1831
- }
1832
- if (blocked) {
1833
- request.addEventListener('blocked', event => blocked(
1834
- // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
1835
- event.oldVersion, event.newVersion, event));
1836
- }
1837
- openPromise.then(db => {
1838
- if (terminated) db.addEventListener('close', () => terminated());
1839
- if (blocking) {
1840
- db.addEventListener('versionchange', event => blocking(event.oldVersion, event.newVersion, event));
1841
- }
1842
- }).catch(() => {});
1843
- return openPromise;
1844
- }
1845
- const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
1846
- const writeMethods = ['put', 'add', 'delete', 'clear'];
1847
- const cachedMethods = new Map();
1848
- function getMethod(target, prop) {
1849
- if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) {
1850
- return;
1851
- }
1852
- if (cachedMethods.get(prop)) return cachedMethods.get(prop);
1853
- const targetFuncName = prop.replace(/FromIndex$/, '');
1854
- const useIndex = prop !== targetFuncName;
1855
- const isWrite = writeMethods.includes(targetFuncName);
1856
- if (
1857
- // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
1858
- !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) {
1859
- return;
1860
- }
1861
- const method = async function (storeName, ...args) {
1862
- // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
1863
- const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
1864
- let target = tx.store;
1865
- if (useIndex) target = target.index(args.shift());
1866
- // Must reject if op rejects.
1867
- // If it's a write operation, must reject if tx.done rejects.
1868
- // Must reject with op rejection first.
1869
- // Must resolve with op value.
1870
- // Must handle both promises (no unhandled rejections)
1871
- return (await Promise.all([target[targetFuncName](...args), isWrite && tx.done]))[0];
1928
+ return {
1929
+ sessionId,
1930
+ type: 'success'
1872
1931
  };
1873
- cachedMethods.set(prop, method);
1874
- return method;
1875
- }
1876
- replaceTraps(oldTraps => ({
1877
- ...oldTraps,
1878
- get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
1879
- has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop)
1880
- }));
1881
- const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
1882
- const methodMap = {};
1883
- const advanceResults = new WeakMap();
1884
- const ittrProxiedCursorToOriginalProxy = new WeakMap();
1885
- const cursorIteratorTraps = {
1886
- get(target, prop) {
1887
- if (!advanceMethodProps.includes(prop)) return target[prop];
1888
- let cachedFunc = methodMap[prop];
1889
- if (!cachedFunc) {
1890
- cachedFunc = methodMap[prop] = function (...args) {
1891
- advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
1892
- };
1893
- }
1894
- return cachedFunc;
1895
- }
1896
- };
1897
- async function* iterate(...args) {
1898
- // tslint:disable-next-line:no-this-assignment
1899
- let cursor = this;
1900
- if (!(cursor instanceof IDBCursor)) {
1901
- cursor = await cursor.openCursor(...args);
1902
- }
1903
- if (!cursor) return;
1904
- cursor = cursor;
1905
- const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
1906
- ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
1907
- // Map this double-proxy back to the original, so other cursor methods work.
1908
- reverseTransformCache.set(proxiedCursor, unwrap(cursor));
1909
- while (cursor) {
1910
- yield proxiedCursor;
1911
- // If one of the advancing methods was not called, call continue().
1912
- cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
1913
- advanceResults.delete(proxiedCursor);
1914
- }
1915
- }
1916
- function isIteratorProp(target, prop) {
1917
- return prop === Symbol.asyncIterator && instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor]) || prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore]);
1918
- }
1919
- replaceTraps(oldTraps => ({
1920
- ...oldTraps,
1921
- get(target, prop, receiver) {
1922
- if (isIteratorProp(target, prop)) return iterate;
1923
- return oldTraps.get(target, prop, receiver);
1924
- },
1925
- has(target, prop) {
1926
- return isIteratorProp(target, prop) || oldTraps.has(target, prop);
1927
- }
1928
- }));
1929
-
1930
- const openDatabaseDependencies = {
1931
- openDB: openDB
1932
- };
1933
- const openDatabase = async (databaseName, dataBaseVersion) => {
1934
- return openDatabaseDependencies.openDB(databaseName, dataBaseVersion);
1935
1932
  };
1936
1933
 
1937
- const loadSelectedEventDependencies = {
1938
- getEventDetailsBySessionIdAndEventId: getEventDetailsBySessionIdAndEventId,
1939
- loadSelectedEventFromWorker: loadSelectedEvent$1,
1940
- openDatabase: openDatabase
1941
- };
1942
- const loadSelectedEvent = async (databaseName, dataBaseVersion, eventStoreName, sessionId, sessionIdIndexName, eventId, type) => {
1943
- const database = await loadSelectedEventDependencies.openDatabase(databaseName, dataBaseVersion);
1944
- try {
1945
- if (!database.objectStoreNames.contains(eventStoreName)) {
1946
- return null;
1947
- }
1948
- const transaction = database.transaction(eventStoreName, 'readonly');
1949
- const store = transaction.objectStore(eventStoreName);
1950
- const event = await loadSelectedEventDependencies.getEventDetailsBySessionIdAndEventId(store, sessionId, sessionIdIndexName, eventId, type);
1951
- return event ?? null;
1952
- } finally {
1953
- database.close();
1954
- }
1934
+ const loadEventsDependencies = {
1935
+ listChatViewEvents: listChatViewEvents,
1936
+ loadSelectedEvent: loadSelectedEvent
1955
1937
  };
1956
-
1957
- const getCurrentEvents$2 = state => {
1938
+ const getCurrentEvents$3 = state => {
1958
1939
  const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1959
1940
  return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1960
1941
  };
1961
- const selectEventAtIndex = async (state, selectedEventIndex, dependencies) => {
1962
- const currentEvents = getCurrentEvents$2(state);
1963
- const selectedEvent = currentEvents[selectedEventIndex];
1964
- if (!selectedEvent) {
1942
+ const restoreSelectedEvent = async state => {
1943
+ if (state.selectedEventId === null) {
1944
+ return {
1945
+ ...state,
1946
+ selectedEvent: null,
1947
+ selectedEventIndex: null
1948
+ };
1949
+ }
1950
+ const currentEvents = getCurrentEvents$3(state);
1951
+ const selectedEventIndex = currentEvents.findIndex(event => event.eventId === state.selectedEventId);
1952
+ if (selectedEventIndex === -1) {
1965
1953
  return {
1966
1954
  ...state,
1967
1955
  selectedEvent: null,
1968
1956
  selectedEventId: null,
1969
- selectedEventIndex
1957
+ selectedEventIndex: null
1970
1958
  };
1971
1959
  }
1972
- if (typeof selectedEvent.eventId !== 'number') {
1960
+ const selectedEvent = currentEvents[selectedEventIndex];
1961
+ if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
1973
1962
  return {
1974
1963
  ...state,
1975
- selectedEvent,
1964
+ selectedEvent: null,
1976
1965
  selectedEventId: null,
1977
- selectedEventIndex
1966
+ selectedEventIndex: null
1978
1967
  };
1979
1968
  }
1980
- const selectedEventDetails = await dependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
1969
+ const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
1981
1970
  return {
1982
1971
  ...state,
1983
- selectedEvent: selectedEventDetails ?? selectedEvent,
1972
+ selectedEvent: selectedEventDetails,
1984
1973
  selectedEventId: selectedEvent.eventId,
1985
1974
  selectedEventIndex
1986
1975
  };
1987
1976
  };
1988
-
1989
- const handleEventRowClickDependencies = {
1990
- loadSelectedEvent: loadSelectedEvent
1991
- };
1992
- const isPrimaryButton = button => {
1993
- return button === 0;
1994
- };
1995
- const parseSelectedEventIndex$1 = value => {
1996
- const parsed = Number.parseInt(value, 10);
1997
- if (Number.isNaN(parsed) || parsed < 0) {
1998
- return null;
1999
- }
2000
- return parsed;
2001
- };
2002
- const handleEventRowClick = async (state, value, button = 0) => {
2003
- if (!isPrimaryButton(button)) {
2004
- return state;
2005
- }
2006
- const selectedEventIndex = parseSelectedEventIndex$1(value);
2007
- if (selectedEventIndex === null) {
1977
+ const getStateWithInvalidUri = state => {
1978
+ const parsed = parseChatDebugUri(state.uri);
1979
+ if (parsed.type !== 'error') {
2008
1980
  return state;
2009
1981
  }
2010
- return selectEventAtIndex(state, selectedEventIndex, handleEventRowClickDependencies);
2011
- };
2012
-
2013
- const handleHeaderContextMenu = state => {
2014
- return state;
2015
- };
2016
-
2017
- const getBoolean = value => {
2018
- return value === true || value === 'true' || value === 'on' || value === '1';
2019
- };
2020
-
2021
- const Filter = 'filter';
2022
- const EventCategoryFilter = 'eventCategoryFilter';
2023
- const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
2024
- const ShowInputEvents = 'showInputEvents';
2025
- const ShowResponsePartEvents = 'showResponsePartEvents';
2026
- const UseDevtoolsLayout = 'useDevtoolsLayout';
2027
- const SelectedEventIndex = 'selectedEventIndex';
2028
- const CloseDetails = 'closeDetails';
2029
- const DetailTab = 'detailTab';
2030
- const TimelineStartSeconds = 'timelineStartSeconds';
2031
- const TimelineEndSeconds = 'timelineEndSeconds';
2032
- const TimelineRangePreset = 'timelineRangePreset';
2033
-
2034
- const getCurrentEvents$1 = state => {
2035
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2036
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2037
- };
2038
- const parseTimelineRangePreset$1 = value => {
2039
- if (!value) {
2040
- return {
2041
- timelineEndSeconds: '',
2042
- timelineStartSeconds: ''
2043
- };
2044
- }
2045
- const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
2046
1982
  return {
2047
- timelineEndSeconds,
2048
- timelineStartSeconds
1983
+ ...state,
1984
+ errorMessage: getInvalidUriMessage(state.uri, parsed.code),
1985
+ events: [],
1986
+ initial: false,
1987
+ selectedEvent: null,
1988
+ selectedEventId: null,
1989
+ selectedEventIndex: null,
1990
+ sessionId: ''
2049
1991
  };
2050
1992
  };
2051
- const getEventIndexByStableId = (events, event) => {
2052
- const stableEventId = getStableEventId(event);
2053
- return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
1993
+ const getSessionIdFromUri = state => {
1994
+ const parsed = parseChatDebugUri(state.uri);
1995
+ if (parsed.type === 'error') {
1996
+ return undefined;
1997
+ }
1998
+ return parsed.sessionId;
2054
1999
  };
2055
- const getSelectedEventIndex = state => {
2000
+ const loadEventsForSessionId = async (state, sessionId) => {
2056
2001
  const {
2057
- selectedEventIndex
2002
+ databaseName,
2003
+ dataBaseVersion,
2004
+ eventStoreName,
2005
+ sessionIdIndexName
2058
2006
  } = state;
2059
- if (selectedEventIndex === null) {
2060
- return null;
2061
- }
2062
- const filteredEvents = getCurrentEvents$1(state);
2063
- const selectedEvent = filteredEvents[selectedEventIndex];
2064
- if (!selectedEvent) {
2065
- return null;
2066
- }
2007
+ const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName);
2008
+ if (result.type === 'error') {
2009
+ return {
2010
+ ...state,
2011
+ errorMessage: getFailedToLoadMessage(sessionId, result.error),
2012
+ events: [],
2013
+ initial: false,
2014
+ selectedEvent: null,
2015
+ selectedEventId: null,
2016
+ selectedEventIndex: null,
2017
+ sessionId
2018
+ };
2019
+ }
2020
+ const {
2021
+ events
2022
+ } = result;
2023
+ if (events.length === 0) {
2024
+ return {
2025
+ ...state,
2026
+ errorMessage: getSessionNotFoundMessage(sessionId),
2027
+ events: [],
2028
+ initial: false,
2029
+ selectedEvent: null,
2030
+ selectedEventId: null,
2031
+ selectedEventIndex: null,
2032
+ sessionId
2033
+ };
2034
+ }
2035
+ const nextState = {
2036
+ ...state,
2037
+ errorMessage: '',
2038
+ events,
2039
+ initial: false,
2040
+ sessionId
2041
+ };
2042
+ return restoreSelectedEvent(nextState);
2043
+ };
2044
+ const loadEventsFromUri = async state => {
2045
+ const sessionId = getSessionIdFromUri(state);
2046
+ if (!sessionId) {
2047
+ return getStateWithInvalidUri(state);
2048
+ }
2049
+ return loadEventsForSessionId(state, sessionId);
2050
+ };
2051
+ const refreshEvents = async state => {
2052
+ const sessionId = state.sessionId || getSessionIdFromUri(state);
2053
+ if (!sessionId) {
2054
+ return getStateWithInvalidUri(state);
2055
+ }
2056
+ return loadEventsForSessionId(state, sessionId);
2057
+ };
2058
+
2059
+ const refresh = async state => {
2060
+ return refreshEvents(state);
2061
+ };
2062
+
2063
+ const handleClickRefreshDependencies = {
2064
+ refresh: refresh
2065
+ };
2066
+ const handleClickRefresh = async state => {
2067
+ return handleClickRefreshDependencies.refresh(state);
2068
+ };
2069
+
2070
+ const handleCloseDetails = state => {
2071
+ return {
2072
+ ...state,
2073
+ selectedEvent: null,
2074
+ selectedEventId: null,
2075
+ selectedEventIndex: null
2076
+ };
2077
+ };
2078
+
2079
+ const handleDetailsContextMenu = state => {
2080
+ return state;
2081
+ };
2082
+
2083
+ const handleDetailTab = (state, value) => {
2084
+ if (!isDetailTab(value)) {
2085
+ return state;
2086
+ }
2087
+ return {
2088
+ ...state,
2089
+ selectedDetailTab: value
2090
+ };
2091
+ };
2092
+
2093
+ const getCurrentEvents$2 = state => {
2094
+ const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2095
+ return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2096
+ };
2097
+ const getEventIndexByStableId$1 = (events, event) => {
2098
+ const stableEventId = getStableEventId(event);
2099
+ return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
2100
+ };
2101
+ const getSelectedEventIndex$1 = state => {
2102
+ const {
2103
+ selectedEventIndex
2104
+ } = state;
2105
+ if (selectedEventIndex === null) {
2106
+ return null;
2107
+ }
2108
+ const filteredEvents = getCurrentEvents$2(state);
2109
+ const selectedEvent = filteredEvents[selectedEventIndex];
2110
+ if (!selectedEvent) {
2111
+ return null;
2112
+ }
2113
+ const newIndex = getEventIndexByStableId$1(filteredEvents, selectedEvent);
2114
+ if (newIndex === -1) {
2115
+ return null;
2116
+ }
2117
+ return newIndex;
2118
+ };
2119
+ const getPreservedSelectedEventIndex$1 = (oldState, newState) => {
2120
+ const {
2121
+ selectedEventIndex
2122
+ } = oldState;
2123
+ if (selectedEventIndex === null) {
2124
+ return null;
2125
+ }
2126
+ const oldFilteredEvents = getCurrentEvents$2(oldState);
2127
+ const selectedEvent = oldFilteredEvents[selectedEventIndex];
2128
+ if (!selectedEvent) {
2129
+ return null;
2130
+ }
2131
+ const newFilteredEvents = getCurrentEvents$2(newState);
2132
+ const newIndex = getEventIndexByStableId$1(newFilteredEvents, selectedEvent);
2133
+ if (newIndex === -1) {
2134
+ return null;
2135
+ }
2136
+ return newIndex;
2137
+ };
2138
+ const withPreservedSelection$1 = (state, nextState) => {
2139
+ const selectedEventIndex = getPreservedSelectedEventIndex$1(state, nextState);
2140
+ return {
2141
+ ...nextState,
2142
+ selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
2143
+ selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
2144
+ selectedEventIndex
2145
+ };
2146
+ };
2147
+
2148
+ const handleEventCategoryFilter = (state, value) => {
2149
+ const nextState = {
2150
+ ...state,
2151
+ eventCategoryFilter: value || All
2152
+ };
2153
+ return withPreservedSelection$1(state, nextState);
2154
+ };
2155
+
2156
+ const getCurrentEvents$1 = state => {
2157
+ const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2158
+ return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2159
+ };
2160
+ const selectEventAtIndex = async (state, selectedEventIndex, dependencies) => {
2161
+ const currentEvents = getCurrentEvents$1(state);
2162
+ const selectedEvent = currentEvents[selectedEventIndex];
2163
+ if (!selectedEvent) {
2164
+ return {
2165
+ ...state,
2166
+ selectedEvent: null,
2167
+ selectedEventId: null,
2168
+ selectedEventIndex
2169
+ };
2170
+ }
2171
+ if (typeof selectedEvent.eventId !== 'number') {
2172
+ return {
2173
+ ...state,
2174
+ selectedEvent,
2175
+ selectedEventId: null,
2176
+ selectedEventIndex
2177
+ };
2178
+ }
2179
+ const selectedEventDetails = await dependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
2180
+ return {
2181
+ ...state,
2182
+ selectedEvent: selectedEventDetails ?? selectedEvent,
2183
+ selectedEventId: selectedEvent.eventId,
2184
+ selectedEventIndex
2185
+ };
2186
+ };
2187
+
2188
+ const handleEventRowClickDependencies = {
2189
+ loadSelectedEvent: loadSelectedEvent
2190
+ };
2191
+ const isPrimaryButton = button => {
2192
+ return button === 0;
2193
+ };
2194
+ const parseSelectedEventIndex$1 = value => {
2195
+ const parsed = Number.parseInt(value, 10);
2196
+ if (Number.isNaN(parsed) || parsed < 0) {
2197
+ return null;
2198
+ }
2199
+ return parsed;
2200
+ };
2201
+ const handleEventRowClick = async (state, value, button = 0) => {
2202
+ if (!isPrimaryButton(button)) {
2203
+ return state;
2204
+ }
2205
+ const selectedEventIndex = parseSelectedEventIndex$1(value);
2206
+ if (selectedEventIndex === null) {
2207
+ return state;
2208
+ }
2209
+ return selectEventAtIndex(state, selectedEventIndex, handleEventRowClickDependencies);
2210
+ };
2211
+
2212
+ const handleHeaderContextMenu = state => {
2213
+ return state;
2214
+ };
2215
+
2216
+ const getBoolean = value => {
2217
+ return value === true || value === 'true' || value === 'on' || value === '1';
2218
+ };
2219
+
2220
+ const Filter = 'filter';
2221
+ const EventCategoryFilter = 'eventCategoryFilter';
2222
+ const ShowEventStreamFinishedEvents = 'showEventStreamFinishedEvents';
2223
+ const ShowInputEvents = 'showInputEvents';
2224
+ const ShowResponsePartEvents = 'showResponsePartEvents';
2225
+ const UseDevtoolsLayout = 'useDevtoolsLayout';
2226
+ const SelectedEventIndex = 'selectedEventIndex';
2227
+ const CloseDetails = 'closeDetails';
2228
+ const DetailTab = 'detailTab';
2229
+ const TimelineStartSeconds = 'timelineStartSeconds';
2230
+ const TimelineEndSeconds = 'timelineEndSeconds';
2231
+ const TimelineRangePreset = 'timelineRangePreset';
2232
+ const Refresh = 'refresh';
2233
+
2234
+ const getCurrentEvents = state => {
2235
+ const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2236
+ return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2237
+ };
2238
+ const parseTimelineRangePreset$1 = value => {
2239
+ if (!value) {
2240
+ return {
2241
+ timelineEndSeconds: '',
2242
+ timelineStartSeconds: ''
2243
+ };
2244
+ }
2245
+ const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
2246
+ return {
2247
+ timelineEndSeconds,
2248
+ timelineStartSeconds
2249
+ };
2250
+ };
2251
+ const getEventIndexByStableId = (events, event) => {
2252
+ const stableEventId = getStableEventId(event);
2253
+ return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
2254
+ };
2255
+ const getSelectedEventIndex = state => {
2256
+ const {
2257
+ selectedEventIndex
2258
+ } = state;
2259
+ if (selectedEventIndex === null) {
2260
+ return null;
2261
+ }
2262
+ const filteredEvents = getCurrentEvents(state);
2263
+ const selectedEvent = filteredEvents[selectedEventIndex];
2264
+ if (!selectedEvent) {
2265
+ return null;
2266
+ }
2067
2267
  const newIndex = getEventIndexByStableId(filteredEvents, selectedEvent);
2068
2268
  if (newIndex === -1) {
2069
2269
  return null;
@@ -2077,12 +2277,12 @@ const getPreservedSelectedEventIndex = (oldState, newState) => {
2077
2277
  if (selectedEventIndex === null) {
2078
2278
  return null;
2079
2279
  }
2080
- const oldFilteredEvents = getCurrentEvents$1(oldState);
2280
+ const oldFilteredEvents = getCurrentEvents(oldState);
2081
2281
  const selectedEvent = oldFilteredEvents[selectedEventIndex];
2082
2282
  if (!selectedEvent) {
2083
2283
  return null;
2084
2284
  }
2085
- const newFilteredEvents = getCurrentEvents$1(newState);
2285
+ const newFilteredEvents = getCurrentEvents(newState);
2086
2286
  const newIndex = getEventIndexByStableId(newFilteredEvents, selectedEvent);
2087
2287
  if (newIndex === -1) {
2088
2288
  return null;
@@ -2217,7 +2417,44 @@ const handleSashPointerUp = (state, eventX, eventY) => {
2217
2417
  return state;
2218
2418
  };
2219
2419
 
2220
- const handleTableBodyContextMenu = state => {
2420
+ const devtoolsRootGap = 4;
2421
+ const devtoolsTopHeight = 28;
2422
+ const devtoolsTimelineHeight = 88;
2423
+ const devtoolsTableHeaderHeight = 24;
2424
+ const devtoolsTableRowHeight = 24;
2425
+ const MenuChatDebugTableBody = 2190;
2426
+ const getTableBodyY = (state, hasTimeline) => {
2427
+ return state.y + viewPadding + devtoolsTopHeight + devtoolsRootGap + (hasTimeline ? devtoolsTimelineHeight : 0) + devtoolsTableHeaderHeight;
2428
+ };
2429
+ const getTableBodyEventIndex = (state, eventX, eventY) => {
2430
+ if (!state.useDevtoolsLayout) {
2431
+ return -1;
2432
+ }
2433
+ const currentEvents = getCurrentEvents$1(state);
2434
+ if (currentEvents.length === 0) {
2435
+ return -1;
2436
+ }
2437
+ const tableX = state.x + leftPadding;
2438
+ const tableWidth = clampTableWidth(state.width, state.tableWidth);
2439
+ const hasTimeline = currentEvents.length > 0;
2440
+ const tableBodyY = getTableBodyY(state, hasTimeline);
2441
+ const relativeX = eventX - tableX;
2442
+ const relativeY = eventY - tableBodyY;
2443
+ if (relativeX < 0 || relativeX >= tableWidth || relativeY < 0) {
2444
+ return -1;
2445
+ }
2446
+ const eventIndex = Math.floor(relativeY / devtoolsTableRowHeight);
2447
+ if (eventIndex < 0 || eventIndex >= currentEvents.length) {
2448
+ return -1;
2449
+ }
2450
+ return eventIndex;
2451
+ };
2452
+ const handleTableBodyContextMenu = async (state, eventX, eventY) => {
2453
+ const eventIndex = getTableBodyEventIndex(state, eventX, eventY);
2454
+ await showContextMenu2(state.uid, MenuChatDebugTableBody, eventX, eventY, {
2455
+ eventIndex,
2456
+ menuId: MenuChatDebugTableBody
2457
+ });
2221
2458
  return state;
2222
2459
  };
2223
2460
 
@@ -2246,1258 +2483,181 @@ const parseTimelineRangePreset = value => {
2246
2483
  const handleTimelineStartSeconds = (state, value) => {
2247
2484
  const nextState = {
2248
2485
  ...state,
2249
- timelineStartSeconds: value
2250
- };
2251
- return withPreservedSelection$1(state, nextState);
2252
- };
2253
- const handleTimelineEndSeconds = (state, value) => {
2254
- const nextState = {
2255
- ...state,
2256
- timelineEndSeconds: value
2257
- };
2258
- return withPreservedSelection$1(state, nextState);
2259
- };
2260
- const handleTimelineRangePreset = (state, value) => {
2261
- const nextState = {
2262
- ...state,
2263
- ...parseTimelineRangePreset(value)
2264
- };
2265
- return withPreservedSelection$1(state, nextState);
2266
- };
2267
-
2268
- const handleTimelineDoubleClick = state => {
2269
- const nextState = handleTimelineRangePreset(state, '');
2270
- return clearTimelineSelectionState(nextState);
2271
- };
2272
-
2273
- const getTimelineEvents = state => {
2274
- const {
2275
- eventCategoryFilter,
2276
- events,
2277
- filterValue,
2278
- showEventStreamFinishedEvents,
2279
- showInputEvents,
2280
- showResponsePartEvents
2281
- } = state;
2282
- return getFilteredEvents(events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
2283
- };
2284
-
2285
- const getTimelineLeft = state => {
2286
- return state.x + viewPadding + timelineHorizontalPadding;
2287
- };
2288
- const getTimelineWidth = state => {
2289
- return Math.max(0, getMainWidth(state.width) - timelineHorizontalPadding * 2);
2290
- };
2291
-
2292
- const trailingZeroFractionRegex = /\.0+$/;
2293
- const trailingFractionZeroRegex = /(\.\d*?)0+$/;
2294
- const formatTimelinePresetValue = value => {
2295
- return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
2296
- };
2297
-
2298
- const getTimelineSecondsFromClientX = (events, eventX, timelineLeft, timelineWidth) => {
2299
- if (timelineWidth <= 0) {
2300
- return undefined;
2301
- }
2302
- const durationSeconds = getTimelineDurationSeconds(events);
2303
- const relativeX = Math.min(Math.max(eventX - timelineLeft, 0), timelineWidth);
2304
- const ratio = relativeX / timelineWidth;
2305
- return formatTimelinePresetValue(durationSeconds * ratio);
2306
- };
2307
-
2308
- const handleTimelinePointerDown = (state, eventX) => {
2309
- const timelineEvents = getTimelineEvents(state);
2310
- const timelineLeft = getTimelineLeft(state);
2311
- const timelineWidth = getTimelineWidth(state);
2312
- const clientX = state.x + eventX;
2313
- const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2314
- if (seconds === undefined) {
2315
- return state;
2316
- }
2317
- return {
2318
- ...state,
2319
- timelineSelectionActive: true,
2320
- timelineSelectionAnchorSeconds: seconds,
2321
- timelineSelectionFocusSeconds: seconds
2322
- };
2323
- };
2324
-
2325
- const handleTimelinePointerMove = (state, eventX) => {
2326
- if (!state.timelineSelectionActive) {
2327
- return state;
2328
- }
2329
- const timelineEvents = getTimelineEvents(state);
2330
- const timelineLeft = getTimelineLeft(state);
2331
- const timelineWidth = getTimelineWidth(state);
2332
- const clientX = state.x + eventX;
2333
- const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2334
- if (seconds === undefined) {
2335
- return state;
2336
- }
2337
- return {
2338
- ...state,
2339
- timelineSelectionFocusSeconds: seconds
2340
- };
2341
- };
2342
-
2343
- const handleTimelinePointerUp = (state, eventX) => {
2344
- if (!state.timelineSelectionActive) {
2345
- return state;
2346
- }
2347
- const timelineEvents = getTimelineEvents(state);
2348
- const timelineLeft = getTimelineLeft(state);
2349
- const timelineWidth = getTimelineWidth(state);
2350
- const clientX = state.x + eventX;
2351
- const focusSeconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2352
- if (focusSeconds === undefined) {
2353
- return clearTimelineSelectionState(state);
2354
- }
2355
- const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
2356
- const focus = Number.parseFloat(focusSeconds);
2357
- const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
2358
- const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
2359
- const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
2360
- return clearTimelineSelectionState(nextState);
2361
- };
2362
-
2363
- const handleUseDevtoolsLayout = (state, checked) => {
2364
- const useDevtoolsLayout = getBoolean(checked);
2365
- const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
2366
- return {
2367
- ...state,
2368
- selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
2369
- selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
2370
- selectedEventIndex,
2371
- useDevtoolsLayout
2372
- };
2373
- };
2374
-
2375
- const handleShowEventStreamFinishedEvents = (state, checked) => {
2376
- const nextState = {
2377
- ...state,
2378
- showEventStreamFinishedEvents: getBoolean(checked)
2379
- };
2380
- return withPreservedSelection$1(state, nextState);
2381
- };
2382
- const handleShowInputEvents = (state, checked) => {
2383
- const nextState = {
2384
- ...state,
2385
- showInputEvents: getBoolean(checked)
2386
- };
2387
- return withPreservedSelection$1(state, nextState);
2388
- };
2389
- const handleShowResponsePartEvents = (state, checked) => {
2390
- const nextState = {
2391
- ...state,
2392
- showResponsePartEvents: getBoolean(checked)
2393
- };
2394
- return withPreservedSelection$1(state, nextState);
2395
- };
2396
-
2397
- const getFailedToLoadMessage = sessionId => {
2398
- return `Failed to load chat debug session "${sessionId}". Please try again.`;
2399
- };
2400
-
2401
- const getIndexedDbNotSupportedMessage = () => {
2402
- return 'Unable to load chat debug session: IndexedDB is not supported in this environment.';
2403
- };
2404
-
2405
- const ParseChatDebugUriErrorCode = {
2406
- InvalidSessionId: 'invalid-session-id',
2407
- InvalidUriEncoding: 'invalid-uri-encoding',
2408
- InvalidUriFormat: 'invalid-uri-format',
2409
- MissingUri: 'missing-uri'
2410
- };
2411
-
2412
- const getInvalidUriMessage = (uri, code) => {
2413
- if (code === ParseChatDebugUriErrorCode.MissingUri) {
2414
- return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
2415
- }
2416
- return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
2417
- };
2418
-
2419
- const getSessionNotFoundMessage = sessionId => {
2420
- return `No chat session found for sessionId "${sessionId}".`;
2421
- };
2422
-
2423
- const filterEventsBySessionId = (events, sessionId) => {
2424
- return events.filter(event => event.sessionId === sessionId);
2425
- };
2426
-
2427
- // cspell:ignore IDBP
2428
-
2429
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
2430
- const getAllEvents = async store => {
2431
- const all = await store.getAll();
2432
- return all;
2433
- };
2434
-
2435
- const getEndTime = event => {
2436
- return event.ended ?? event.endTime ?? event.timestamp;
2437
- };
2438
-
2439
- const getStartTime = event => {
2440
- return event.started ?? event.startTime ?? event.timestamp;
2441
- };
2442
-
2443
- const getDuration = event => {
2444
- const explicitDuration = event.durationMs ?? event.duration;
2445
- if (typeof explicitDuration === 'number' && Number.isFinite(explicitDuration)) {
2446
- return explicitDuration;
2447
- }
2448
- const start = toTimeNumber(getStartTime(event));
2449
- const end = toTimeNumber(getEndTime(event));
2450
- if (start === undefined || end === undefined || !Number.isFinite(start) || !Number.isFinite(end)) {
2451
- return 0;
2452
- }
2453
- return Math.max(0, end - start);
2454
- };
2455
-
2456
- const isTimeValue = value => {
2457
- return typeof value === 'number' || typeof value === 'string';
2458
- };
2459
-
2460
- const getLightweightEvent = (event, fallbackEventId) => {
2461
- const startTime = getStartTime(event);
2462
- const endTime = getEndTime(event);
2463
- return {
2464
- duration: getDuration(event),
2465
- ...(isTimeValue(endTime) ? {
2466
- endTime
2467
- } : {}),
2468
- eventId: typeof event.eventId === 'number' ? event.eventId : fallbackEventId,
2469
- ...(isTimeValue(startTime) ? {
2470
- startTime
2471
- } : {}),
2472
- type: event.type
2473
- };
2474
- };
2475
-
2476
- // cspell:ignore IDBP
2477
-
2478
- const toLightweightEvents = events => {
2479
- const eventsWithIds = events.map((event, index) => {
2480
- return {
2481
- ...event,
2482
- eventId: index + 1
2483
- };
2484
- });
2485
- return collapseToolExecutionEvents(eventsWithIds).map((event, index) => getLightweightEvent(event, index + 1));
2486
- };
2487
- const getEventsBySessionId = async (store, sessionId, sessionIdIndexName) => {
2488
- if (store.indexNames.contains(sessionIdIndexName)) {
2489
- const index = store.index(sessionIdIndexName);
2490
- const events = await index.getAll(sessionId);
2491
- return toLightweightEvents(filterEventsBySessionId(events, sessionId));
2492
- }
2493
- const all = await getAllEvents(store);
2494
- return toLightweightEvents(filterEventsBySessionId(all, sessionId));
2495
- };
2496
-
2497
- let indexedDbSupportOverride;
2498
- const getIndexedDbSupportOverride = () => {
2499
- return indexedDbSupportOverride;
2500
- };
2501
- const setIndexedDbSupportOverride = supported => {
2502
- indexedDbSupportOverride = supported;
2503
- };
2504
-
2505
- const isIndexedDbSupported = indexedDbSupportOverride => {
2506
- if (typeof indexedDbSupportOverride === 'boolean') {
2507
- return indexedDbSupportOverride;
2508
- }
2509
- const override = getIndexedDbSupportOverride();
2510
- if (typeof override === 'boolean') {
2511
- return override;
2512
- }
2513
- return globalThis.indexedDB !== undefined;
2514
- };
2515
-
2516
- const listChatViewEventsDependencies = {
2517
- getEventsBySessionId: getEventsBySessionId,
2518
- listChatViewEventsFromWorker: listChatViewEvents$1,
2519
- openDatabase: openDatabase
2520
- };
2521
- const listChatViewEvents = async (sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName, indexedDbSupportOverride) => {
2522
- if (!isIndexedDbSupported(indexedDbSupportOverride)) {
2523
- return {
2524
- type: 'not-supported'
2525
- };
2526
- }
2527
- try {
2528
- const database = await listChatViewEventsDependencies.openDatabase(databaseName, dataBaseVersion);
2529
- try {
2530
- if (!database.objectStoreNames.contains(eventStoreName)) {
2531
- return {
2532
- events: [],
2533
- type: 'success'
2534
- };
2535
- }
2536
- const transaction = database.transaction(eventStoreName, 'readonly');
2537
- const store = transaction.objectStore(eventStoreName);
2538
- if (!sessionId) {
2539
- return {
2540
- events: [],
2541
- type: 'success'
2542
- };
2543
- }
2544
- const events = await listChatViewEventsDependencies.getEventsBySessionId(store, sessionId, sessionIdIndexName);
2545
- return {
2546
- events,
2547
- type: 'success'
2548
- };
2549
- } finally {
2550
- database.close();
2551
- }
2552
- } catch (error) {
2553
- return {
2554
- error,
2555
- type: 'error'
2556
- };
2557
- }
2558
- };
2559
-
2560
- const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
2561
- const invalidSessionIdPattern = /[/?#]/;
2562
- const parseChatDebugUri = uri => {
2563
- if (!uri) {
2564
- return {
2565
- code: ParseChatDebugUriErrorCode.MissingUri,
2566
- message: 'Missing URI',
2567
- type: 'error'
2568
- };
2569
- }
2570
- const match = uri.match(chatDebugUriPattern);
2571
- if (!match) {
2572
- return {
2573
- code: ParseChatDebugUriErrorCode.InvalidUriFormat,
2574
- message: 'Invalid URI format',
2575
- type: 'error'
2576
- };
2577
- }
2578
- const encodedSessionId = match[1];
2579
- let sessionId;
2580
- try {
2581
- sessionId = decodeURIComponent(encodedSessionId);
2582
- } catch {
2583
- return {
2584
- code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
2585
- message: 'Invalid URI encoding',
2586
- type: 'error'
2587
- };
2588
- }
2589
- if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
2590
- return {
2591
- code: ParseChatDebugUriErrorCode.InvalidSessionId,
2592
- message: 'Invalid session id',
2593
- type: 'error'
2594
- };
2595
- }
2596
- return {
2597
- sessionId,
2598
- type: 'success'
2599
- };
2600
- };
2601
-
2602
- const loadEventsDependencies = {
2603
- listChatViewEvents: listChatViewEvents,
2604
- loadSelectedEvent: loadSelectedEvent
2605
- };
2606
- const getCurrentEvents = state => {
2607
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2608
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2609
- };
2610
- const restoreSelectedEvent = async state => {
2611
- if (state.selectedEventId === null) {
2612
- return {
2613
- ...state,
2614
- selectedEvent: null,
2615
- selectedEventIndex: null
2616
- };
2617
- }
2618
- const currentEvents = getCurrentEvents(state);
2619
- const selectedEventIndex = currentEvents.findIndex(event => event.eventId === state.selectedEventId);
2620
- if (selectedEventIndex === -1) {
2621
- return {
2622
- ...state,
2623
- selectedEvent: null,
2624
- selectedEventId: null,
2625
- selectedEventIndex: null
2626
- };
2627
- }
2628
- const selectedEvent = currentEvents[selectedEventIndex];
2629
- if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
2630
- return {
2631
- ...state,
2632
- selectedEvent: null,
2633
- selectedEventId: null,
2634
- selectedEventIndex: null
2635
- };
2636
- }
2637
- const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
2638
- return {
2639
- ...state,
2640
- selectedEvent: selectedEventDetails,
2641
- selectedEventId: selectedEvent.eventId,
2642
- selectedEventIndex
2643
- };
2644
- };
2645
- const getStateWithInvalidUri = state => {
2646
- const parsed = parseChatDebugUri(state.uri);
2647
- if (parsed.type !== 'error') {
2648
- return state;
2649
- }
2650
- return {
2651
- ...state,
2652
- errorMessage: getInvalidUriMessage(state.uri, parsed.code),
2653
- events: [],
2654
- initial: false,
2655
- selectedEvent: null,
2656
- selectedEventId: null,
2657
- selectedEventIndex: null,
2658
- sessionId: ''
2659
- };
2660
- };
2661
- const getSessionIdFromUri = state => {
2662
- const parsed = parseChatDebugUri(state.uri);
2663
- if (parsed.type === 'error') {
2664
- return undefined;
2665
- }
2666
- return parsed.sessionId;
2667
- };
2668
- const loadEventsForSessionId = async (state, sessionId) => {
2669
- const {
2670
- databaseName,
2671
- dataBaseVersion,
2672
- eventStoreName,
2673
- indexedDbSupportOverride,
2674
- sessionIdIndexName
2675
- } = state;
2676
- const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName, indexedDbSupportOverride);
2677
- if (result.type === 'not-supported') {
2678
- return {
2679
- ...state,
2680
- errorMessage: getIndexedDbNotSupportedMessage(),
2681
- events: [],
2682
- initial: false,
2683
- selectedEvent: null,
2684
- selectedEventId: null,
2685
- selectedEventIndex: null,
2686
- sessionId
2687
- };
2688
- }
2689
- if (result.type === 'error') {
2690
- return {
2691
- ...state,
2692
- errorMessage: getFailedToLoadMessage(sessionId),
2693
- events: [],
2694
- initial: false,
2695
- selectedEvent: null,
2696
- selectedEventId: null,
2697
- selectedEventIndex: null,
2698
- sessionId
2699
- };
2700
- }
2701
- const {
2702
- events
2703
- } = result;
2704
- if (events.length === 0) {
2705
- return {
2706
- ...state,
2707
- errorMessage: getSessionNotFoundMessage(sessionId),
2708
- events: [],
2709
- initial: false,
2710
- selectedEvent: null,
2711
- selectedEventId: null,
2712
- selectedEventIndex: null,
2713
- sessionId
2714
- };
2715
- }
2716
- const nextState = {
2717
- ...state,
2718
- errorMessage: '',
2719
- events,
2720
- initial: false,
2721
- sessionId
2722
- };
2723
- return restoreSelectedEvent(nextState);
2724
- };
2725
- const loadEventsFromUri = async state => {
2726
- const sessionId = getSessionIdFromUri(state);
2727
- if (!sessionId) {
2728
- return getStateWithInvalidUri(state);
2729
- }
2730
- return loadEventsForSessionId(state, sessionId);
2731
- };
2732
- const refreshEvents = async state => {
2733
- const sessionId = state.sessionId || getSessionIdFromUri(state);
2734
- if (!sessionId) {
2735
- return getStateWithInvalidUri(state);
2736
- }
2737
- return loadEventsForSessionId(state, sessionId);
2738
- };
2739
-
2740
- const loadContent = async state => {
2741
- return loadEventsFromUri(state);
2742
- };
2743
-
2744
- const refresh = async state => {
2745
- return refreshEvents(state);
2746
- };
2747
-
2748
- const Button = 1;
2749
- const Div = 4;
2750
- const Input = 6;
2751
- const Span = 8;
2752
- const Table = 9;
2753
- const TBody = 10;
2754
- const Td = 11;
2755
- const Text = 12;
2756
- const Th = 13;
2757
- const THead = 14;
2758
- const Tr = 15;
2759
- const Search = 42;
2760
- const Label = 66;
2761
- const Reference = 100;
2762
-
2763
- const ClientX = 'event.clientX';
2764
- const ClientY = 'event.clientY';
2765
- const TargetName = 'event.target.name';
2766
- const TargetValue = 'event.target.value';
2767
-
2768
- const SetCss = 'Viewlet.setCss';
2769
- const SetDom2 = 'Viewlet.setDom2';
2770
- const SetPatches = 'Viewlet.setPatches';
2771
-
2772
- const getCss = state => {
2773
- const tableWidth = clampTableWidth(state.width, state.tableWidth);
2774
- const detailsWidth = getDetailsWidth(state.width, state.tableWidth);
2775
- return `
2776
- .ChatDebugView {
2777
- --ChatDebugViewDetailsWidth: ${detailsWidth}px;
2778
- --ChatDebugViewSashWidth: ${sashWidth}px;
2779
- --ChatDebugViewTableWidth: ${tableWidth}px;
2780
- padding: ${viewPadding}px;
2781
- display: flex;
2782
- flex-direction: column;
2783
- height: 100%;
2784
- box-sizing: border-box;
2785
- gap: 8px;
2786
- contain: strict;
2787
- }
2788
-
2789
- .ChatDebugView--devtools {
2790
- gap: 4px;
2791
- }
2792
-
2793
- .ChatDebugViewTop {
2794
- display: flex;
2795
- align-items: center;
2796
- gap: 12px;
2797
- flex-wrap: wrap;
2798
- contain: content;
2799
- }
2800
-
2801
- .ChatDebugViewTop--devtools {
2802
- align-items: stretch;
2803
- }
2804
-
2805
- .ChatDebugViewFilterInput {
2806
- flex: 1;
2807
- min-width: 0;
2808
- max-width: 500px;
2809
- contain: content;
2810
- }
2811
-
2812
- .ChatDebugViewFilterInput--devtools {
2813
- flex: 0 1 80px;
2814
- width: 100%;
2815
- max-width: 80px;
2816
- }
2817
-
2818
- .ChatDebugViewQuickFilterPill {
2819
- display: flex;
2820
- align-items: center;
2821
- justify-content: center;
2822
- min-height: 22px;
2823
- padding: 0 10px;
2824
- border: 1px solid var(--vscode-editorWidget-border, #454545);
2825
- border-radius: 999px;
2826
- cursor: pointer;
2827
- white-space: nowrap;
2828
- transition:
2829
- background 120ms ease-out,
2830
- border-color 120ms ease-out,
2831
- color 120ms ease-out,
2832
- transform 120ms ease-out;
2833
- contain: content;
2834
- }
2835
-
2836
- .ChatDebugViewQuickFilterPill:not(.ChatDebugViewQuickFilterPillSelected):hover {
2837
- border-color: var(--vscode-focusBorder, #007fd4);
2838
- background: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 82%, transparent 18%);
2839
- color: var(--vscode-list-hoverForeground, inherit);
2840
- transform: translateY(-1px);
2841
- }
2842
-
2843
-
2844
- .ChatDebugViewQuickFilters {
2845
- display: flex;
2846
- align-items: center;
2847
- gap: 8px;
2848
- justify-content: center;
2849
- min-height: 28px;
2850
- font-size: 12px;
2851
- line-height: 1;
2852
- contain: content;
2853
- }
2854
-
2855
- .ChatDebugViewQuickFilterPillSelected {
2856
- border-color: var(--vscode-focusBorder, #007fd4);
2857
- background: var(--vscode-list-activeSelectionBackground, rgba(14, 99, 156, 0.35));
2858
- color: var(--vscode-list-activeSelectionForeground, inherit);
2859
- }
2860
-
2861
- .ChatDebugViewQuickFilterInput {
2862
- position: absolute;
2863
- opacity: 0;
2864
- pointer-events: none;
2865
- contain: content;
2866
- }
2867
-
2868
- .ChatDebugViewEvents {
2869
- display: flex;
2870
- flex-direction: column;
2871
- overflow: auto;
2872
- min-width: 0;
2873
- min-height: 0;
2874
- scrollbar-width: thin;
2875
- scrollbar-color: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4)) transparent;
2876
- contain: strict;
2877
- }
2878
-
2879
- .ChatDebugView--devtools .ChatDebugViewEvents {
2880
- border-radius: 6px;
2881
- margin-bottom: 0;
2882
- overflow: hidden;
2883
- }
2884
-
2885
- .ChatDebugViewEventsFullWidth {
2886
- flex: 1 1 100%;
2887
- }
2888
-
2889
- .ChatDebugViewDevtoolsMain {
2890
- display: flex;
2891
- flex-direction: column;
2892
- flex: 1;
2893
- align-items: stretch;
2894
- gap: 0;
2895
- min-width: 0;
2896
- min-height: 0;
2897
- contain: strict;
2898
- }
2899
-
2900
- .ChatDebugViewDevtoolsMain > .ChatDebugViewTimeline {
2901
- flex: 0 0 auto;
2902
- }
2903
-
2904
- .ChatDebugViewDevtoolsSplit {
2905
- display: flex;
2906
- flex: 1;
2907
- align-items: stretch;
2908
- gap: 0;
2909
- min-width: 0;
2910
- min-height: 0;
2911
- overflow: hidden;
2912
- contain: strict;
2913
- }
2914
-
2915
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents {
2916
- flex: 0 1 var(--ChatDebugViewTableWidth);
2917
- min-width: 0;
2918
- }
2919
-
2920
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents.ChatDebugViewEventsFullWidth {
2921
- flex: 1 1 100%;
2922
- }
2923
-
2924
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewDetails {
2925
- border-left: 0;
2926
- border-top-left-radius: 0;
2927
- border-bottom-left-radius: 0;
2928
- flex: 1;
2929
- }
2930
-
2931
- .ChatDebugViewSash {
2932
- flex: 0 0 var(--ChatDebugViewSashWidth);
2933
- position: relative;
2934
- cursor: col-resize;
2935
- display: flex;
2936
- justify-content: center;
2937
- min-height: 0;
2938
- contain: strict;
2939
- }
2940
-
2941
- .ChatDebugViewSashLine {
2942
- width: 1px;
2943
- height: 100%;
2944
- background: var(--vscode-editorWidget-border, #454545);
2945
- pointer-events: none;
2946
- contain: strict;
2947
- }
2948
-
2949
- .ChatDebugViewSash:hover .ChatDebugViewSashLine {
2950
- background: var(--vscode-focusBorder, #007fd4);
2951
- }
2952
-
2953
- .ChatDebugViewTable {
2954
- display: flex;
2955
- flex-direction: column;
2956
- min-height: 0;
2957
- flex: 1 1 auto;
2958
- contain: strict;
2959
- }
2960
-
2961
- .ChatDebugViewTimeline {
2962
- display: flex;
2963
- flex-direction: column;
2964
- gap: 6px;
2965
- padding: 6px ${timelineHorizontalPadding}px 8px;
2966
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
2967
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 82%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.12)) 18%);
2968
- contain: content;
2969
- }
2970
-
2971
- .ChatDebugViewTimelineTop {
2972
- display: flex;
2973
- align-items: center;
2974
- contain: content;
2975
- }
2976
-
2977
- .ChatDebugViewTimelineSummary {
2978
- display: flex;
2979
- align-items: center;
2980
- font-size: 12px;
2981
- line-height: 16px;
2982
- opacity: 0.8;
2983
- contain: content;
2984
- }
2985
-
2986
- .ChatDebugViewTimelineControls {
2987
- display: flex;
2988
- align-items: center;
2989
- gap: 8px;
2990
- flex-wrap: wrap;
2991
- contain: content;
2992
- }
2993
-
2994
- .ChatDebugViewTimelineBuckets {
2995
- display: flex;
2996
- align-items: end;
2997
- gap: 3px;
2998
- flex: 1 1 auto;
2999
- min-height: 52px;
3000
- pointer-events: none;
3001
- contain: strict;
3002
- }
3003
-
3004
- .ChatDebugViewTimelineInteractive {
3005
- display: flex;
3006
- position: relative;
3007
- min-height: 52px;
3008
- cursor: crosshair;
3009
- user-select: none;
3010
- contain: strict;
3011
- }
3012
-
3013
- .ChatDebugViewTimelineSelectionOverlay {
3014
- position: absolute;
3015
- inset: 0;
3016
- pointer-events: none;
3017
- contain: strict;
3018
- }
3019
-
3020
- .ChatDebugViewTimelineSelectionRange {
3021
- position: absolute;
3022
- top: 0;
3023
- bottom: 0;
3024
- background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 20%, transparent 80%);
3025
- border-left: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
3026
- border-right: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
3027
- contain: strict;
3028
- }
3029
-
3030
- .ChatDebugViewTimelineSelectionMarker {
3031
- position: absolute;
3032
- top: 0;
3033
- bottom: 0;
3034
- width: 1px;
3035
- margin-left: -0.5px;
3036
- background: var(--vscode-focusBorder, #007fd4);
3037
- box-shadow: 0 0 0 1px color-mix(in srgb, var(--vscode-focusBorder, #007fd4) 24%, transparent 76%);
3038
- contain: strict;
3039
- }
3040
-
3041
- .ChatDebugViewTimelineBucket {
3042
- --ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 74%, transparent 26%);
3043
- --ChatDebugViewTimelineBucketBarBorderColor: transparent;
3044
- display: flex;
3045
- align-items: stretch;
3046
- flex: 1 1 10px;
3047
- min-width: 10px;
3048
- min-height: 52px;
3049
- contain: strict;
3050
- }
3051
-
3052
- .ChatDebugViewTimelineBucketSelected {
3053
- --ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
3054
- --ChatDebugViewTimelineBucketBarBorderColor: var(--vscode-focusBorder, #007fd4);
3055
- }
3056
-
3057
- .ChatDebugViewTimelinePresetInput {
3058
- position: absolute;
3059
- opacity: 0;
3060
- pointer-events: none;
3061
- contain: content;
3062
- }
3063
-
3064
- .ChatDebugViewTimelineBucketBar {
3065
- display: flex;
3066
- flex-direction: column;
3067
- justify-content: flex-end;
3068
- gap: 2px;
3069
- padding: 6px 1px 2px;
3070
- border: 1px solid transparent;
3071
- border-radius: 2px;
3072
- width: 100%;
3073
- background: var(--ChatDebugViewTimelineBucketBarBackground);
3074
- border-color: var(--ChatDebugViewTimelineBucketBarBorderColor);
3075
- contain: strict;
3076
- }
3077
-
3078
- .ChatDebugViewTimelineBucketBarSelected {
3079
- background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
3080
- border-color: var(--vscode-focusBorder, #007fd4);
3081
- }
3082
-
3083
- .ChatDebugViewTimelineBucketUnit {
3084
- width: 100%;
3085
- height: 4px;
3086
- border-radius: 999px;
3087
- background: var(--vscode-charts-blue, #75beff);
3088
- contain: strict;
3089
- }
3090
-
3091
- .ChatDebugViewTimelineBucketUnitEmpty {
3092
- opacity: 0.35;
3093
- background: var(--vscode-editorWidget-border, #454545);
3094
- }
3095
-
3096
- .ChatDebugViewTableHeaderRow,
3097
- .ChatDebugViewEventRow {
3098
- display: flex;
3099
- align-items: center;
3100
- gap: 8px;
3101
- contain: content;
3102
- }
3103
-
3104
- .ChatDebugViewTableHeader {
3105
- padding: 3px 8px;
3106
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
3107
- background: var(--vscode-editorWidget-background, transparent);
3108
- position: sticky;
3109
- top: 0;
3110
- z-index: 1;
3111
- contain: content;
3112
- }
3113
-
3114
- .ChatDebugViewHeaderCell {
3115
- display: flex;
3116
- align-items: center;
3117
- overflow: hidden;
3118
- text-overflow: ellipsis;
3119
- white-space: nowrap;
3120
- min-width: 0;
3121
- font-size: 11px;
3122
- letter-spacing: 0.04em;
3123
- opacity: 0.8;
3124
- contain: content;
3125
- }
3126
-
3127
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(1) {
3128
- flex: 1 1 140px;
3129
- min-width: 0;
3130
- }
3131
-
3132
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(2) {
3133
- flex: 0 0 90px;
3134
- justify-content: flex-end;
3135
- }
3136
-
3137
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(3) {
3138
- flex: 0 0 96px;
3139
- justify-content: flex-end;
3140
- }
3141
-
3142
- .ChatDebugViewTableBody {
3143
- display: flex;
3144
- flex-direction: column;
3145
- overflow: auto;
3146
- min-height: 0;
3147
- flex: 1 1 auto;
3148
- contain: strict;
3149
- }
3150
-
3151
- .ChatDebugViewEventRowLabel {
3152
- display: block;
3153
- contain: content;
3154
- }
3155
-
3156
- .ChatDebugViewEventRowLabelSelected .ChatDebugViewEventRow,
3157
- .ChatDebugViewEventRowSelected {
3158
- background: var(--vscode-list-activeSelectionBackground, rgba(14, 99, 156, 0.35));
3159
- color: var(--vscode-list-activeSelectionForeground, inherit);
3160
- }
3161
-
3162
- .ChatDebugViewEventRowInput {
3163
- position: absolute;
3164
- opacity: 0;
3165
- pointer-events: none;
3166
- contain: content;
3167
- }
3168
-
3169
- .ChatDebugViewEventRow {
3170
- padding: 2px 8px;
3171
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 92%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 8%);
3172
- cursor: default;
3173
- }
3174
-
3175
- .ChatDebugViewTableBody > .ChatDebugViewEventRow:nth-child(even) {
3176
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 84%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 16%);
3177
- }
3178
-
3179
- .ChatDebugViewEventRow:hover {
3180
- background: var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31));
3181
- color: var(--vscode-list-hoverForeground, inherit);
3182
- }
3183
-
3184
- .ChatDebugViewCell {
3185
- display: flex;
3186
- align-items: center;
3187
- overflow: hidden;
3188
- text-overflow: ellipsis;
3189
- white-space: nowrap;
3190
- min-width: 0;
3191
- pointer-events: none;
3192
- contain: content;
3193
- }
3194
-
3195
- .ChatDebugViewCellType {
3196
- flex: 1 1 140px;
3197
- min-width: 0;
3198
- }
3199
-
3200
- .ChatDebugViewCellTime {
3201
- flex: 1 1 180px;
3202
- min-width: 0;
3203
- }
3204
-
3205
- .ChatDebugViewCellDuration {
3206
- flex: 0 0 90px;
3207
- justify-content: flex-end;
3208
- text-align: right;
3209
- }
3210
-
3211
- .ChatDebugViewCellStatus {
3212
- flex: 0 0 64px;
3213
- justify-content: flex-end;
3214
- text-align: right;
3215
- }
3216
-
3217
- .ChatDebugViewCellStatusError {
3218
- color: var(--vscode-errorForeground, #f14c4c);
3219
- }
3220
-
3221
- .ChatDebugViewDetails {
3222
- border: 1px solid var(--vscode-editorWidget-border, #454545);
3223
- border-radius: 6px;
3224
- overflow: hidden;
3225
- min-width: 0;
3226
- min-height: 0;
3227
- display: flex;
3228
- flex-direction: column;
3229
- contain: strict;
3230
- }
3231
-
3232
- .ChatDebugViewDetailsTop {
3233
- display: flex;
3234
- align-items: stretch;
3235
- justify-content: flex-start;
3236
- gap: 8px;
3237
- padding: 0 8px;
3238
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
3239
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 72%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.18)) 28%);
3240
- contain: content;
3241
- }
3242
-
3243
- .ChatDebugViewDetailsClose {
3244
- width: 18px;
3245
- height: 18px;
3246
- appearance: none;
3247
- border: none;
3248
- border-radius: 4px;
3249
- cursor: pointer;
3250
- position: relative;
3251
- color: var(--vscode-foreground, #cccccc);
3252
- background: transparent;
3253
- align-self: center;
3254
- flex: 0 0 auto;
3255
- contain: strict;
3256
- }
3257
-
3258
- .ChatDebugViewDetailsClose:hover {
3259
- background: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31));
3260
- }
3261
-
3262
- .ChatDebugViewDetailsClose::before,
3263
- .ChatDebugViewDetailsClose::after {
3264
- content: '';
3265
- position: absolute;
3266
- left: 50%;
3267
- top: 50%;
3268
- width: 10px;
3269
- height: 1px;
3270
- background: currentColor;
3271
- }
3272
-
3273
- .ChatDebugViewDetailsClose::before {
3274
- transform: translate(-50%, -50%) rotate(45deg);
3275
- }
3276
-
3277
- .ChatDebugViewDetailsClose::after {
3278
- transform: translate(-50%, -50%) rotate(-45deg);
3279
- }
3280
-
3281
- .ChatDebugViewDetailsBody {
3282
- display: flex;
3283
- flex-direction: column;
3284
- overflow: hidden;
3285
- padding: 0;
3286
- flex: 1 1 auto;
3287
- min-height: 0;
3288
- align-items: stretch;
3289
- contain: strict;
3290
- }
3291
-
3292
- .ChatDebugViewDetailsTabs {
3293
- display: flex;
3294
- align-items: center;
3295
- flex: 1 1 auto;
3296
- gap: 2px;
3297
- min-width: 0;
3298
- padding: 0;
3299
- overflow-x: auto;
3300
- contain: content;
3301
- }
3302
-
3303
- .ChatDebugViewDetailsTab {
3304
- display: flex;
3305
- align-items: center;
3306
- justify-content: center;
3307
- min-height: 32px;
3308
- padding: 0 10px;
3309
- appearance: none;
3310
- background: transparent;
3311
- border: 0;
3312
- border-bottom: 2px solid transparent;
3313
- color: var(--vscode-descriptionForeground, var(--vscode-foreground, #cccccc));
3314
- cursor: pointer;
3315
- white-space: nowrap;
3316
- contain: content;
3317
- }
3318
-
3319
- .ChatDebugViewDetailsTab:hover {
3320
- color: var(--vscode-foreground, #cccccc);
3321
- }
3322
-
3323
- .ChatDebugViewDetailsTabSelected {
3324
- border-bottom-color: var(--vscode-focusBorder, #007fd4);
3325
- color: var(--vscode-focusBorder, #007fd4);
3326
- }
3327
-
3328
- .ChatDebugViewDetailsPanel {
3329
- display: flex;
3330
- flex-direction: column;
3331
- overflow: auto;
3332
- padding: 8px;
3333
- flex: 1 1 auto;
3334
- min-height: 0;
3335
- align-items: flex-start;
3336
- contain: strict;
3337
- }
3338
-
3339
- .ChatDebugViewEvents::-webkit-scrollbar {
3340
- width: 10px;
3341
- height: 10px;
3342
- }
3343
-
3344
- .ChatDebugViewEvents::-webkit-scrollbar-track {
3345
- background: transparent;
3346
- }
3347
-
3348
- .ChatDebugViewEvents::-webkit-scrollbar-thumb {
3349
- background: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4));
3350
- border-radius: 999px;
3351
- border: 2px solid transparent;
3352
- background-clip: content-box;
3353
- }
3354
-
3355
- .ChatDebugViewEvents::-webkit-scrollbar-thumb:hover {
3356
- background: var(--vscode-scrollbarSlider-hoverBackground, rgba(100, 100, 100, 0.7));
3357
- }
3358
-
3359
- .ChatDebugViewEvents::-webkit-scrollbar-thumb:active {
3360
- background: var(--vscode-scrollbarSlider-activeBackground, rgba(191, 191, 191, 0.4));
3361
- }
3362
-
3363
- .ChatDebugViewEvent {
3364
- display: flex;
3365
- flex-direction: column;
3366
- width: max-content;
3367
- min-width: 100%;
3368
- margin: 0;
3369
- padding: 8px;
3370
- border: 1px solid var(--vscode-editorWidget-border, #454545);
3371
- border-radius: 6px;
3372
- margin-bottom: 8px;
3373
- white-space: nowrap;
3374
- font-family: var(--vscode-editor-font-family, monospace);
3375
- font-size: 12px;
3376
- user-select: text;
3377
- contain: content;
3378
- }
3379
-
3380
- .row {
3381
- display: flex;
3382
- align-items: baseline;
3383
- gap: 12px;
3384
- min-width: 100%;
3385
- width: max-content;
3386
- white-space: nowrap;
3387
- contain: strict;
3388
- height: 20px;
3389
- }
3390
-
3391
- .ChatDebugViewEventLineNumber {
3392
- display: flex;
3393
- justify-content: flex-end;
3394
- flex: 0 0 3ch;
3395
- opacity: 0.6;
3396
- user-select: none;
3397
- contain: content;
3398
- }
3399
-
3400
- .ChatDebugViewEventLineContent {
3401
- display: flex;
3402
- white-space: pre;
3403
- contain: content;
3404
- }
2486
+ timelineStartSeconds: value
2487
+ };
2488
+ return withPreservedSelection$1(state, nextState);
2489
+ };
2490
+ const handleTimelineEndSeconds = (state, value) => {
2491
+ const nextState = {
2492
+ ...state,
2493
+ timelineEndSeconds: value
2494
+ };
2495
+ return withPreservedSelection$1(state, nextState);
2496
+ };
2497
+ const handleTimelineRangePreset = (state, value) => {
2498
+ const nextState = {
2499
+ ...state,
2500
+ ...parseTimelineRangePreset(value)
2501
+ };
2502
+ return withPreservedSelection$1(state, nextState);
2503
+ };
3405
2504
 
3406
- .ChatDebugViewDetailsPanel > .ChatDebugViewEvent {
3407
- border: 0;
3408
- border-radius: 0;
3409
- margin-bottom: 0;
3410
- }
2505
+ const handleTimelineDoubleClick = state => {
2506
+ const nextState = handleTimelineRangePreset(state, '');
2507
+ return clearTimelineSelectionState(nextState);
2508
+ };
3411
2509
 
3412
- .ChatDebugViewTiming {
3413
- display: flex;
3414
- flex-direction: column;
3415
- width: 100%;
3416
- contain: strict;
3417
- flex: 1;
3418
- }
2510
+ const getTimelineEvents = state => {
2511
+ const {
2512
+ eventCategoryFilter,
2513
+ events,
2514
+ filterValue,
2515
+ showEventStreamFinishedEvents,
2516
+ showInputEvents,
2517
+ showResponsePartEvents
2518
+ } = state;
2519
+ return getFilteredEvents(events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
2520
+ };
3419
2521
 
3420
- .ChatDebugViewTimingRow {
3421
- display: flex;
3422
- align-items: center;
3423
- justify-content: space-between;
3424
- gap: 12px;
3425
- padding: 8px 10px;
3426
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
3427
- contain: content;
3428
- }
2522
+ const getTimelineLeft = state => {
2523
+ return state.x + viewPadding + timelineHorizontalPadding;
2524
+ };
2525
+ const getTimelineWidth = state => {
2526
+ return Math.max(0, getMainWidth(state.width) - timelineHorizontalPadding * 2);
2527
+ };
3429
2528
 
3430
- .ChatDebugViewTimingRow:last-child {
3431
- border-bottom: 0;
3432
- }
2529
+ const trailingZeroFractionRegex = /\.0+$/;
2530
+ const trailingFractionZeroRegex = /(\.\d*?)0+$/;
2531
+ const formatTimelinePresetValue = value => {
2532
+ return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
2533
+ };
3433
2534
 
3434
- .ChatDebugViewTimingLabel {
3435
- opacity: 0.8;
3436
- contain: content;
3437
- }
2535
+ const getTimelineSecondsFromClientX = (events, eventX, timelineLeft, timelineWidth) => {
2536
+ if (timelineWidth <= 0) {
2537
+ return undefined;
2538
+ }
2539
+ const durationSeconds = getTimelineDurationSeconds(events);
2540
+ const relativeX = Math.min(Math.max(eventX - timelineLeft, 0), timelineWidth);
2541
+ const ratio = relativeX / timelineWidth;
2542
+ return formatTimelinePresetValue(durationSeconds * ratio);
2543
+ };
3438
2544
 
3439
- .ChatDebugViewTimingValue {
3440
- text-align: right;
3441
- font-family: var(--vscode-editor-font-family, monospace);
3442
- contain: content;
3443
- }
2545
+ const handleTimelinePointerDown = (state, eventX) => {
2546
+ const timelineEvents = getTimelineEvents(state);
2547
+ const timelineLeft = getTimelineLeft(state);
2548
+ const timelineWidth = getTimelineWidth(state);
2549
+ const clientX = state.x + eventX;
2550
+ const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2551
+ if (seconds === undefined) {
2552
+ return state;
2553
+ }
2554
+ return {
2555
+ ...state,
2556
+ timelineSelectionActive: true,
2557
+ timelineSelectionAnchorSeconds: seconds,
2558
+ timelineSelectionFocusSeconds: seconds
2559
+ };
2560
+ };
3444
2561
 
3445
- .ChatDebugViewEmpty {
3446
- display: flex;
3447
- align-items: center;
3448
- opacity: 0.8;
3449
- contain: content;
3450
- }
2562
+ const handleTimelinePointerMove = (state, eventX) => {
2563
+ if (!state.timelineSelectionActive) {
2564
+ return state;
2565
+ }
2566
+ const timelineEvents = getTimelineEvents(state);
2567
+ const timelineLeft = getTimelineLeft(state);
2568
+ const timelineWidth = getTimelineWidth(state);
2569
+ const clientX = state.x + eventX;
2570
+ const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2571
+ if (seconds === undefined) {
2572
+ return state;
2573
+ }
2574
+ return {
2575
+ ...state,
2576
+ timelineSelectionFocusSeconds: seconds
2577
+ };
2578
+ };
3451
2579
 
3452
- .ChatDebugViewError {
3453
- display: flex;
3454
- color: var(--vscode-errorForeground, #f14c4c);
3455
- white-space: normal;
3456
- contain: content;
3457
- }
2580
+ const handleTimelinePointerUp = (state, eventX) => {
2581
+ if (!state.timelineSelectionActive) {
2582
+ return state;
2583
+ }
2584
+ const timelineEvents = getTimelineEvents(state);
2585
+ const timelineLeft = getTimelineLeft(state);
2586
+ const timelineWidth = getTimelineWidth(state);
2587
+ const clientX = state.x + eventX;
2588
+ const focusSeconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2589
+ if (focusSeconds === undefined) {
2590
+ return clearTimelineSelectionState(state);
2591
+ }
2592
+ const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
2593
+ const focus = Number.parseFloat(focusSeconds);
2594
+ const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
2595
+ const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
2596
+ const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
2597
+ return clearTimelineSelectionState(nextState);
2598
+ };
3458
2599
 
3459
- .TokenText {
3460
- color: var(--vscode-editor-foreground, inherit);
3461
- }
2600
+ const handleUseDevtoolsLayout = (state, checked) => {
2601
+ const useDevtoolsLayout = getBoolean(checked);
2602
+ const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
2603
+ return {
2604
+ ...state,
2605
+ selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
2606
+ selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
2607
+ selectedEventIndex,
2608
+ useDevtoolsLayout
2609
+ };
2610
+ };
3462
2611
 
3463
- .TokenKey {
3464
- color: var(--vscode-symbolIcon-propertyForeground, var(--vscode-editor-foreground, inherit));
3465
- }
2612
+ const handleShowEventStreamFinishedEvents = (state, checked) => {
2613
+ const nextState = {
2614
+ ...state,
2615
+ showEventStreamFinishedEvents: getBoolean(checked)
2616
+ };
2617
+ return withPreservedSelection$1(state, nextState);
2618
+ };
2619
+ const handleShowInputEvents = (state, checked) => {
2620
+ const nextState = {
2621
+ ...state,
2622
+ showInputEvents: getBoolean(checked)
2623
+ };
2624
+ return withPreservedSelection$1(state, nextState);
2625
+ };
2626
+ const handleShowResponsePartEvents = (state, checked) => {
2627
+ const nextState = {
2628
+ ...state,
2629
+ showResponsePartEvents: getBoolean(checked)
2630
+ };
2631
+ return withPreservedSelection$1(state, nextState);
2632
+ };
3466
2633
 
3467
- .TokenString {
3468
- color: var(--vscode-debugTokenExpression-string, var(--vscode-charts-green, #89d185));
3469
- }
2634
+ const loadContent = async state => {
2635
+ return loadEventsFromUri(state);
2636
+ };
3470
2637
 
3471
- .TokenNumeric {
3472
- color: var(--vscode-debugTokenExpression-number, var(--vscode-charts-blue, #75beff));
2638
+ const getCss = state => {
2639
+ const tableWidth = clampTableWidth(state.width, state.tableWidth);
2640
+ const detailsWidth = getDetailsWidth(state.width, state.tableWidth);
2641
+ return `
2642
+ .ChatDebugView {
2643
+ --ChatDebugViewDetailsWidth: ${detailsWidth}px;
2644
+ --ChatDebugViewSashWidth: ${sashWidth}px;
2645
+ --ChatDebugViewTableWidth: ${tableWidth}px;
2646
+ padding: ${viewPadding}px;
3473
2647
  }
3474
2648
 
3475
- .TokenBoolean {
3476
- color: var(--vscode-debugTokenExpression-boolean, var(--vscode-charts-yellow, #dcdcaa));
3477
- }
3478
2649
 
3479
- .ChatOrderedList{
3480
- display:flex;
3481
- flex-direction:column;
3482
- margin:0;
3483
- padding:0;
3484
- padding-left:10px;
3485
- contain: content;
2650
+ .ChatDebugViewDetails {
2651
+ contain: strict;
3486
2652
  }
3487
2653
 
3488
- .ChatOrderedListItem{
3489
- display:flex;
3490
- margin:0;
3491
- padding:0;
3492
- contain: content;
2654
+ .ChatDebugViewDetailsTop {
2655
+ height: 33px;
2656
+ contain: strict;
3493
2657
  }
3494
2658
 
3495
- .ChatToolCalls{
3496
- display:flex;
3497
- flex-direction:column;
3498
- margin:0;
3499
- padding:0;
3500
- contain: content;
2659
+ .ChatDebugViewEvent {
2660
+ contain: content
3501
2661
  }
3502
2662
  `;
3503
2663
  };
@@ -3806,9 +2966,8 @@ const diffTree = (oldNodes, newNodes) => {
3806
2966
  const ChatDebugView = 'ChatDebugView';
3807
2967
  const ChatDebugViewDevtools = 'ChatDebugView--devtools';
3808
2968
  const ChatDebugViewDetails = 'ChatDebugViewDetails';
3809
- const ChatDebugViewDetailsBody = 'ChatDebugViewDetailsBody';
2969
+ const ChatDebugViewDetailsBottom = 'ChatDebugViewDetailsBottom';
3810
2970
  const ChatDebugViewDetailsClose = 'ChatDebugViewDetailsClose';
3811
- const ChatDebugViewDetailsPanel = 'ChatDebugViewDetailsPanel';
3812
2971
  const ChatDebugViewDetailsTab = 'ChatDebugViewDetailsTab';
3813
2972
  const ChatDebugViewDetailsTabSelected = 'ChatDebugViewDetailsTabSelected';
3814
2973
  const ChatDebugViewDetailsTabs = 'ChatDebugViewDetailsTabs';
@@ -3827,6 +2986,7 @@ const ChatDebugViewEventsFullWidth = 'ChatDebugViewEventsFullWidth';
3827
2986
  const ChatDebugViewFilterInput = 'ChatDebugViewFilterInput';
3828
2987
  const ChatDebugViewFilterInputDevtools = 'ChatDebugViewFilterInput--devtools';
3829
2988
  const ChatDebugViewHeaderCell = 'ChatDebugViewHeaderCell';
2989
+ const ChatDebugViewRefreshButton = 'ChatDebugViewRefreshButton';
3830
2990
  const ChatDebugViewQuickFilterInput = 'ChatDebugViewQuickFilterInput';
3831
2991
  const ChatDebugViewQuickFilterPill = 'ChatDebugViewQuickFilterPill';
3832
2992
  const ChatDebugViewQuickFilterPillSelected = 'ChatDebugViewQuickFilterPillSelected';
@@ -3846,7 +3006,6 @@ const ChatDebugViewTimelineBucketUnit = 'ChatDebugViewTimelineBucketUnit';
3846
3006
  const ChatDebugViewTimelineBucketUnitEmpty = 'ChatDebugViewTimelineBucketUnitEmpty';
3847
3007
  const ChatDebugViewTimelineBuckets = 'ChatDebugViewTimelineBuckets';
3848
3008
  const ChatDebugViewTimelineInteractive = 'ChatDebugViewTimelineInteractive';
3849
- const ChatDebugViewTimelinePresetInput = 'ChatDebugViewTimelinePresetInput';
3850
3009
  const ChatDebugViewTimelineSelectionMarker = 'ChatDebugViewTimelineSelectionMarker';
3851
3010
  const ChatDebugViewTimelineSelectionMarkerEnd = 'ChatDebugViewTimelineSelectionMarkerEnd';
3852
3011
  const ChatDebugViewTimelineSelectionMarkerStart = 'ChatDebugViewTimelineSelectionMarkerStart';
@@ -3867,11 +3026,11 @@ const ChatDebugViewCellStatusError = 'ChatDebugViewCellStatusError';
3867
3026
  const ChatDebugViewCellType = 'ChatDebugViewCellType';
3868
3027
  const InputBox = 'InputBox';
3869
3028
  const Row = 'row';
3870
- const TokenBoolean = 'TokenBoolean';
3871
- const TokenKey = 'TokenKey';
3872
- const TokenNumeric = 'TokenNumeric';
3873
- const TokenString = 'TokenString';
3874
- const TokenText = 'TokenText';
3029
+ const TokenBoolean = 'Token TokenBoolean';
3030
+ const TokenKey = 'Token TokenKey';
3031
+ const TokenNumeric = 'Token TokenNumeric';
3032
+ const TokenString = 'Token TokenString';
3033
+ const TokenText = 'Token TokenText';
3875
3034
  const joinClassNames = (...classNames) => {
3876
3035
  return classNames.filter(Boolean).join(' ');
3877
3036
  };
@@ -3905,11 +3064,24 @@ const HandleTimelineDoubleClick = 17;
3905
3064
  const HandleTableKeyDown = 18;
3906
3065
  const HandleTimelineRangePreset = 19;
3907
3066
  const HandleCloseDetails = 20;
3067
+ const HandleClickRefresh = 21;
3908
3068
 
3069
+ const getRefreshButtonDom = () => {
3070
+ return [{
3071
+ 'aria-label': 'Refresh events',
3072
+ childCount: 1,
3073
+ className: ChatDebugViewRefreshButton,
3074
+ name: Refresh,
3075
+ onClick: HandleClickRefresh,
3076
+ type: Button$1,
3077
+ value: Refresh
3078
+ }, text('Refresh')];
3079
+ };
3909
3080
  const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
3081
+ const refreshButtonDom = getRefreshButtonDom();
3910
3082
  if (useDevtoolsLayout) {
3911
3083
  return [{
3912
- childCount: 1 + (quickFilterNodes.length > 0 ? 1 : 0),
3084
+ childCount: 2 + (quickFilterNodes.length > 0 ? 1 : 0),
3913
3085
  className: joinClassNames(ChatDebugViewTop, ChatDebugViewTopDevtools),
3914
3086
  onContextMenu: HandleHeaderContextMenu,
3915
3087
  type: Search
@@ -3923,10 +3095,10 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
3923
3095
  placeholder: 'Filter events',
3924
3096
  type: Input,
3925
3097
  value: filterValue
3926
- }, ...quickFilterNodes];
3098
+ }, ...quickFilterNodes, ...refreshButtonDom];
3927
3099
  }
3928
3100
  return [{
3929
- childCount: 1,
3101
+ childCount: 2,
3930
3102
  className: ChatDebugViewTop,
3931
3103
  onContextMenu: HandleHeaderContextMenu,
3932
3104
  type: Search
@@ -3940,7 +3112,7 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
3940
3112
  placeholder: 'Filter events',
3941
3113
  type: Input,
3942
3114
  value: filterValue
3943
- }];
3115
+ }, ...refreshButtonDom];
3944
3116
  };
3945
3117
 
3946
3118
  const getDurationText = event => {
@@ -4036,7 +3208,7 @@ const getTabNodes = selectedDetailTab => {
4036
3208
  onClick: HandleDetailTab,
4037
3209
  role: 'tab',
4038
3210
  tabIndex: isSelected ? 0 : -1,
4039
- type: Button,
3211
+ type: Button$1,
4040
3212
  value: detailTab
4041
3213
  }, text(getDetailTabLabel(detailTab))];
4042
3214
  });
@@ -4061,7 +3233,7 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
4061
3233
  name: CloseDetails,
4062
3234
  onChange: HandleCloseDetails,
4063
3235
  onClick: HandleCloseDetails,
4064
- type: Button,
3236
+ type: Button$1,
4065
3237
  value: 'close'
4066
3238
  }, {
4067
3239
  'aria-label': 'Detail sections',
@@ -4070,14 +3242,9 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
4070
3242
  role: 'tablist',
4071
3243
  type: Div
4072
3244
  }, ...getTabNodes(selectedDetailTab), {
4073
- childCount: 1,
4074
- className: ChatDebugViewDetailsBody,
4075
- role: 'document',
4076
- type: Div
4077
- }, {
4078
3245
  'aria-labelledby': getTabId(selectedDetailTab),
4079
3246
  childCount: 1,
4080
- className: ChatDebugViewDetailsPanel,
3247
+ className: ChatDebugViewDetailsBottom,
4081
3248
  id: getPanelId(selectedDetailTab),
4082
3249
  onContextMenu: HandleDetailsContextMenu,
4083
3250
  role: 'tabpanel',
@@ -4151,6 +3318,9 @@ const hasErrorStatus = event => {
4151
3318
  if (isErrorStatusCode(result.status)) {
4152
3319
  return true;
4153
3320
  }
3321
+ if (isToolEvent(event) && 'error' in result && result.error !== undefined) {
3322
+ return true;
3323
+ }
4154
3324
  if (typeof result.error === 'string' || typeof result.errorMessage === 'string' || typeof result.exception === 'string') {
4155
3325
  return true;
4156
3326
  }
@@ -4196,28 +3366,53 @@ const getEmptyStateDom = emptyMessage => {
4196
3366
  }, text(emptyMessage)];
4197
3367
  };
4198
3368
 
4199
- const pushToken = (segments, className, value) => {
4200
- if (!value) {
4201
- return segments;
3369
+ const isDigit = character => {
3370
+ return character !== undefined && character >= '0' && character <= '9';
3371
+ };
3372
+ const isWhitespace = character => {
3373
+ return character === ' ' || character === '\n' || character === '\r' || character === '\t';
3374
+ };
3375
+ const getNumberEnd = (json, start) => {
3376
+ let i = start;
3377
+ if (json[i] === '-') {
3378
+ i++;
4202
3379
  }
4203
- const lastSegment = segments.at(-1);
4204
- if (lastSegment && lastSegment.className === className) {
4205
- const merged = {
4206
- className,
4207
- value: lastSegment.value + value
4208
- };
4209
- return [...segments.slice(0, -1), merged];
3380
+ if (json[i] === '0') {
3381
+ i++;
3382
+ } else {
3383
+ if (!isDigit(json[i])) {
3384
+ return start;
3385
+ }
3386
+ while (isDigit(json[i])) {
3387
+ i++;
3388
+ }
4210
3389
  }
4211
- return [...segments, {
4212
- className,
4213
- value
4214
- }];
3390
+ if (json[i] === '.') {
3391
+ const decimalStart = i;
3392
+ i++;
3393
+ if (!isDigit(json[i])) {
3394
+ return decimalStart;
3395
+ }
3396
+ while (isDigit(json[i])) {
3397
+ i++;
3398
+ }
3399
+ }
3400
+ if (json[i] === 'e' || json[i] === 'E') {
3401
+ const exponentStart = i;
3402
+ i++;
3403
+ if (json[i] === '+' || json[i] === '-') {
3404
+ i++;
3405
+ }
3406
+ if (!isDigit(json[i])) {
3407
+ return exponentStart;
3408
+ }
3409
+ while (isDigit(json[i])) {
3410
+ i++;
3411
+ }
3412
+ }
3413
+ return i;
4215
3414
  };
4216
-
4217
- const numberRegex = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/;
4218
- const whitespaceRegex = /\s/u;
4219
- const getTokenSegments = json => {
4220
- let segments = [];
3415
+ const forEachTokenSegment = (json, onToken) => {
4221
3416
  let i = 0;
4222
3417
  while (i < json.length) {
4223
3418
  const character = json[i];
@@ -4236,40 +3431,38 @@ const getTokenSegments = json => {
4236
3431
  }
4237
3432
  i++;
4238
3433
  }
4239
- const tokenValue = json.slice(start, i);
4240
3434
  let lookAheadIndex = i;
4241
- while (lookAheadIndex < json.length && whitespaceRegex.test(json[lookAheadIndex])) {
3435
+ while (lookAheadIndex < json.length && isWhitespace(json[lookAheadIndex])) {
4242
3436
  lookAheadIndex++;
4243
3437
  }
4244
3438
  const className = json[lookAheadIndex] === ':' ? TokenKey : TokenString;
4245
- segments = pushToken(segments, className, tokenValue);
3439
+ onToken(className, json.slice(start, i));
4246
3440
  continue;
4247
3441
  }
4248
- const numberMatch = numberRegex.exec(json.slice(i));
4249
- if (numberMatch) {
4250
- segments = pushToken(segments, TokenNumeric, numberMatch[0]);
4251
- i += numberMatch[0].length;
3442
+ const numberEnd = getNumberEnd(json, i);
3443
+ if (numberEnd > i) {
3444
+ onToken(TokenNumeric, json.slice(i, numberEnd));
3445
+ i = numberEnd;
4252
3446
  continue;
4253
3447
  }
4254
3448
  if (json.startsWith('true', i)) {
4255
- segments = pushToken(segments, TokenBoolean, 'true');
3449
+ onToken(TokenBoolean, 'true');
4256
3450
  i += 4;
4257
3451
  continue;
4258
3452
  }
4259
3453
  if (json.startsWith('false', i)) {
4260
- segments = pushToken(segments, TokenBoolean, 'false');
3454
+ onToken(TokenBoolean, 'false');
4261
3455
  i += 5;
4262
3456
  continue;
4263
3457
  }
4264
3458
  if (json.startsWith('null', i)) {
4265
- segments = pushToken(segments, TokenBoolean, 'null');
3459
+ onToken(TokenBoolean, 'null');
4266
3460
  i += 4;
4267
3461
  continue;
4268
3462
  }
4269
- segments = pushToken(segments, TokenText, character);
3463
+ onToken(TokenText, character);
4270
3464
  i++;
4271
3465
  }
4272
- return segments;
4273
3466
  };
4274
3467
 
4275
3468
  const getJsonLines = value => {
@@ -4280,25 +3473,34 @@ const getJsonLines = value => {
4280
3473
  value: String(json)
4281
3474
  }]];
4282
3475
  }
4283
- const segments = getTokenSegments(json);
4284
3476
  const lines = [];
4285
3477
  let currentLine = [];
4286
- for (const segment of segments) {
4287
- const parts = segment.value.split('\n');
4288
- for (let i = 0; i < parts.length; i++) {
4289
- const part = parts[i];
4290
- if (part) {
4291
- currentLine.push({
4292
- className: segment.className,
4293
- value: part
4294
- });
4295
- }
4296
- if (i < parts.length - 1) {
3478
+ const pushLineSegment = (className, lineValue) => {
3479
+ if (!lineValue) {
3480
+ return;
3481
+ }
3482
+ const lastSegment = currentLine.at(-1);
3483
+ if (lastSegment && lastSegment.className === className) {
3484
+ lastSegment.value += lineValue;
3485
+ return;
3486
+ }
3487
+ currentLine.push({
3488
+ className,
3489
+ value: lineValue
3490
+ });
3491
+ };
3492
+ forEachTokenSegment(json, (className, segmentValue) => {
3493
+ let start = 0;
3494
+ for (let i = 0; i < segmentValue.length; i++) {
3495
+ if (segmentValue[i] === '\n') {
3496
+ pushLineSegment(className, segmentValue.slice(start, i));
4297
3497
  lines.push(currentLine);
4298
3498
  currentLine = [];
3499
+ start = i + 1;
4299
3500
  }
4300
3501
  }
4301
- }
3502
+ pushLineSegment(className, segmentValue.slice(start));
3503
+ });
4302
3504
  lines.push(currentLine);
4303
3505
  return lines;
4304
3506
  };
@@ -4357,6 +3559,33 @@ const hasOwn = (event, key) => {
4357
3559
  const isChatMessageUpdatedEvent = event => {
4358
3560
  return event.type === 'chat-message-updated';
4359
3561
  };
3562
+ const isChatMessageAddedEvent = event => {
3563
+ return event.type === 'chat-message-added';
3564
+ };
3565
+ const getPreviewMessageText = event => {
3566
+ if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
3567
+ return event.text;
3568
+ }
3569
+ if (!isChatMessageAddedEvent(event)) {
3570
+ return undefined;
3571
+ }
3572
+ const {
3573
+ message
3574
+ } = event;
3575
+ if (!message || typeof message !== 'object') {
3576
+ return undefined;
3577
+ }
3578
+ if (!Object.hasOwn(message, 'text')) {
3579
+ return undefined;
3580
+ }
3581
+ const {
3582
+ text
3583
+ } = message;
3584
+ if (typeof text !== 'string') {
3585
+ return undefined;
3586
+ }
3587
+ return text;
3588
+ };
4360
3589
  const getPreviewName = event => {
4361
3590
  if (typeof event.name === 'string' && event.name) {
4362
3591
  return event.name;
@@ -4376,8 +3605,9 @@ const shouldIncludeArguments = (event, name) => {
4376
3605
  return true;
4377
3606
  };
4378
3607
  const getPreviewEvent = event => {
4379
- if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
4380
- return event.text;
3608
+ const previewMessageText = getPreviewMessageText(event);
3609
+ if (previewMessageText !== undefined) {
3610
+ return previewMessageText;
4381
3611
  }
4382
3612
  const name = getPreviewName(event);
4383
3613
  const previewEvent = {
@@ -4462,9 +3692,12 @@ const formatPercent = value => {
4462
3692
  return `${Number(value.toFixed(3))}%`;
4463
3693
  };
4464
3694
 
4465
- const getBucketUnitDom = unitCount => {
3695
+ const getBucketUnitDom = (unitCount, presetValue) => {
4466
3696
  if (unitCount === 0) {
4467
3697
  return [{
3698
+ ...(presetValue ? {
3699
+ 'data-value': presetValue
3700
+ } : {}),
4468
3701
  childCount: 0,
4469
3702
  className: joinClassNames(ChatDebugViewTimelineBucketUnit, ChatDebugViewTimelineBucketUnitEmpty),
4470
3703
  type: Div
@@ -4473,6 +3706,9 @@ const getBucketUnitDom = unitCount => {
4473
3706
  return Array.from({
4474
3707
  length: unitCount
4475
3708
  }).fill({
3709
+ ...(presetValue ? {
3710
+ 'data-value': presetValue
3711
+ } : {}),
4476
3712
  childCount: 0,
4477
3713
  className: ChatDebugViewTimelineBucketUnit,
4478
3714
  type: Div
@@ -4482,23 +3718,17 @@ const getBucketUnitDom = unitCount => {
4482
3718
  const getBucketDom = bucket => {
4483
3719
  const presetValue = `${formatTimelinePresetValue(bucket.startSeconds)}:${formatTimelinePresetValue(bucket.endSeconds)}`;
4484
3720
  return [{
4485
- childCount: 2,
3721
+ childCount: 1,
4486
3722
  className: joinClassNames(ChatDebugViewTimelineBucket, bucket.isSelected && ChatDebugViewTimelineBucketSelected),
4487
- type: Label
4488
- }, {
4489
- checked: false,
4490
- childCount: 0,
4491
- className: ChatDebugViewTimelinePresetInput,
4492
- inputType: 'radio',
4493
- name: TimelineRangePreset,
4494
- onChange: HandleTimelineRangePreset,
4495
- type: Input,
4496
- value: presetValue
3723
+ 'data-value': presetValue,
3724
+ onClick: HandleTimelineRangePreset,
3725
+ type: Div
4497
3726
  }, {
4498
3727
  childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
4499
3728
  className: joinClassNames(ChatDebugViewTimelineBucketBar, bucket.isSelected && ChatDebugViewTimelineBucketBarSelected),
3729
+ 'data-value': presetValue,
4500
3730
  type: Div
4501
- }, ...getBucketUnitDom(bucket.unitCount)];
3731
+ }, ...getBucketUnitDom(bucket.unitCount, presetValue)];
4502
3732
  };
4503
3733
 
4504
3734
  const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
@@ -4759,10 +3989,10 @@ const render2 = (uid, diffResult) => {
4759
3989
  const renderEventListeners = () => {
4760
3990
  return [{
4761
3991
  name: HandleEventRowClick,
4762
- params: ['handleEventRowClick', 'event.target.dataset.index', 'event.button']
3992
+ params: ['handleEventRowClick', 'event.target.dataset.index', Button]
4763
3993
  }, {
4764
3994
  name: HandleTableBodyContextMenu,
4765
- params: ['handleTableBodyContextMenu'],
3995
+ params: ['handleTableBodyContextMenu', ClientX, ClientY],
4766
3996
  preventDefault: true
4767
3997
  }, {
4768
3998
  name: HandleFilterInput,
@@ -4775,10 +4005,13 @@ const renderEventListeners = () => {
4775
4005
  params: ['handleDetailTab', TargetValue]
4776
4006
  }, {
4777
4007
  name: HandleTimelineRangePreset,
4778
- params: ['handleTimelineRangePreset', TargetValue]
4008
+ params: ['handleTimelineRangePreset', 'event.target.dataset.value']
4779
4009
  }, {
4780
4010
  name: HandleCloseDetails,
4781
4011
  params: ['handleCloseDetails']
4012
+ }, {
4013
+ name: HandleClickRefresh,
4014
+ params: ['handleClickRefresh']
4782
4015
  }, {
4783
4016
  name: HandleSashPointerDown,
4784
4017
  params: ['handleSashPointerDown', ClientX, ClientY],
@@ -4871,31 +4104,15 @@ const setEvents = (state, events) => {
4871
4104
  };
4872
4105
  };
4873
4106
 
4874
- const setIndexedDbSupportForTest = supported => {
4875
- return setIndexedDbSupportOverride(supported);
4876
- };
4877
-
4878
4107
  const setSessionIdDependencies = {
4879
4108
  listChatViewEvents: listChatViewEvents
4880
4109
  };
4881
4110
  const setSessionId = async (state, sessionId) => {
4882
- const result = await setSessionIdDependencies.listChatViewEvents(sessionId, state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionIdIndexName, state.indexedDbSupportOverride);
4883
- if (result.type === 'not-supported') {
4884
- return {
4885
- ...state,
4886
- errorMessage: getIndexedDbNotSupportedMessage(),
4887
- events: [],
4888
- initial: false,
4889
- selectedEvent: null,
4890
- selectedEventId: null,
4891
- selectedEventIndex: null,
4892
- sessionId
4893
- };
4894
- }
4111
+ const result = await setSessionIdDependencies.listChatViewEvents(sessionId, state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionIdIndexName);
4895
4112
  if (result.type === 'error') {
4896
4113
  return {
4897
4114
  ...state,
4898
- errorMessage: getFailedToLoadMessage(sessionId),
4115
+ errorMessage: getFailedToLoadMessage(sessionId, result.error),
4899
4116
  events: [],
4900
4117
  initial: false,
4901
4118
  selectedEvent: null,
@@ -4923,6 +4140,8 @@ const commandMap = {
4923
4140
  'ChatDebug.create': create,
4924
4141
  'ChatDebug.diff2': diff2,
4925
4142
  'ChatDebug.getCommandIds': getCommandIds,
4143
+ 'ChatDebug.getMenuIds': getMenuIds,
4144
+ 'ChatDebug.handleClickRefresh': wrapCommand(handleClickRefresh),
4926
4145
  'ChatDebug.handleCloseDetails': wrapCommand(handleCloseDetails),
4927
4146
  'ChatDebug.handleDetailsContextMenu': wrapCommand(handleDetailsContextMenu),
4928
4147
  'ChatDebug.handleDetailTab': wrapCommand(handleDetailTab),
@@ -4954,17 +4173,28 @@ const commandMap = {
4954
4173
  'ChatDebug.resize': wrapCommand(resize),
4955
4174
  'ChatDebug.saveState': wrapGetter(saveState),
4956
4175
  'ChatDebug.setEvents': wrapCommand(setEvents),
4957
- 'ChatDebug.setIndexedDbSupportForTest': setIndexedDbSupportForTest,
4958
4176
  'ChatDebug.setSessionId': wrapCommand(setSessionId),
4959
4177
  'ChatDebug.terminate': terminate
4960
4178
  };
4961
4179
 
4180
+ const sendMessagePortToChatStorageWorker = async port => {
4181
+ await sendMessagePortToChatStorageWorker$1(port);
4182
+ };
4183
+ const initializeChatStorageWorker = async () => {
4184
+ const rpc = await create$4({
4185
+ commandMap: {},
4186
+ send: sendMessagePortToChatStorageWorker
4187
+ });
4188
+ set$2(rpc);
4189
+ };
4190
+
4962
4191
  const listen = async () => {
4963
4192
  registerCommands(commandMap);
4964
- const rpc = await create$2({
4193
+ const r = await create$3({
4965
4194
  commandMap: commandMap
4966
4195
  });
4967
- setWorkerRpc(rpc);
4196
+ set$1(r);
4197
+ await initializeChatStorageWorker();
4968
4198
  };
4969
4199
 
4970
4200
  const main = async () => {