@lvce-editor/chat-debug-view 6.0.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
  };
@@ -1074,7 +1117,7 @@ const create$2 = rpcId => {
1074
1117
  };
1075
1118
  };
1076
1119
 
1077
- const Button = 1;
1120
+ const Button$1 = 1;
1078
1121
  const Div = 4;
1079
1122
  const Input = 6;
1080
1123
  const Span = 8;
@@ -1089,6 +1132,7 @@ const Search = 42;
1089
1132
  const Label = 66;
1090
1133
  const Reference = 100;
1091
1134
 
1135
+ const Button = 'event.button';
1092
1136
  const ClientX = 'event.clientX';
1093
1137
  const ClientY = 'event.clientY';
1094
1138
  const TargetName = 'event.target.name';
@@ -1102,14 +1146,22 @@ const SetDom2 = 'Viewlet.setDom2';
1102
1146
  const SetPatches = 'Viewlet.setPatches';
1103
1147
 
1104
1148
  const {
1105
- invoke,
1149
+ invoke: invoke$1,
1106
1150
  set: set$2
1107
1151
  } = create$2(ChatStorageWorker);
1108
1152
 
1109
1153
  const {
1154
+ invoke,
1110
1155
  invokeAndTransfer,
1111
1156
  set: set$1
1112
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
+ };
1113
1165
  const sendMessagePortToChatStorageWorker$1 = async port => {
1114
1166
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatStorageWorker', port, 'HandleMessagePort.handleMessagePort');
1115
1167
  };
@@ -1449,27 +1501,28 @@ const diff2 = uid => {
1449
1501
  return diff(oldState, newState);
1450
1502
  };
1451
1503
 
1452
- const handleCloseDetails = state => {
1453
- return {
1454
- ...state,
1455
- selectedEvent: null,
1456
- selectedEventId: null,
1457
- selectedEventIndex: null
1458
- };
1504
+ const getMenuIds = () => {
1505
+ return [555, 556, 557];
1459
1506
  };
1460
1507
 
1461
- const handleDetailsContextMenu = state => {
1462
- 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;
1463
1519
  };
1464
-
1465
- const handleDetailTab = (state, value) => {
1466
- if (!isDetailTab(value)) {
1467
- 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}`;
1468
1524
  }
1469
- return {
1470
- ...state,
1471
- selectedDetailTab: value
1472
- };
1525
+ return `Failed to load chat debug session "${sessionId}". Please try again.`;
1473
1526
  };
1474
1527
 
1475
1528
  const hasMatchingToolName = (startedEvent, finishedEvent) => {
@@ -1639,6 +1692,24 @@ const getFilteredEvents = (events, filterValue, eventCategoryFilter, showInputEv
1639
1692
  return filteredByCategory.filter(event => JSON.stringify(event).toLowerCase().includes(filterText));
1640
1693
  };
1641
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
+
1642
1713
  const toTimeNumber = value => {
1643
1714
  if (typeof value === 'number' && Number.isFinite(value)) {
1644
1715
  return value;
@@ -1790,74 +1861,25 @@ const getTimelineInfo = (events, startValue, endValue) => {
1790
1861
  };
1791
1862
  };
1792
1863
 
1793
- const getCurrentEvents$3 = state => {
1794
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1795
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1796
- };
1797
- const getEventIndexByStableId$1 = (events, event) => {
1798
- const stableEventId = getStableEventId(event);
1799
- return events.findIndex(candidate => getStableEventId(candidate) === stableEventId);
1800
- };
1801
- const getSelectedEventIndex$1 = state => {
1802
- const {
1803
- selectedEventIndex
1804
- } = state;
1805
- if (selectedEventIndex === null) {
1806
- return null;
1807
- }
1808
- const filteredEvents = getCurrentEvents$3(state);
1809
- const selectedEvent = filteredEvents[selectedEventIndex];
1810
- if (!selectedEvent) {
1811
- return null;
1812
- }
1813
- const newIndex = getEventIndexByStableId$1(filteredEvents, selectedEvent);
1814
- if (newIndex === -1) {
1815
- return null;
1816
- }
1817
- return newIndex;
1818
- };
1819
- const getPreservedSelectedEventIndex$1 = (oldState, newState) => {
1820
- const {
1821
- selectedEventIndex
1822
- } = oldState;
1823
- if (selectedEventIndex === null) {
1824
- return null;
1825
- }
1826
- const oldFilteredEvents = getCurrentEvents$3(oldState);
1827
- const selectedEvent = oldFilteredEvents[selectedEventIndex];
1828
- if (!selectedEvent) {
1829
- return null;
1830
- }
1831
- const newFilteredEvents = getCurrentEvents$3(newState);
1832
- const newIndex = getEventIndexByStableId$1(newFilteredEvents, selectedEvent);
1833
- if (newIndex === -1) {
1834
- return null;
1835
- }
1836
- return newIndex;
1837
- };
1838
- const withPreservedSelection$1 = (state, nextState) => {
1839
- const selectedEventIndex = getPreservedSelectedEventIndex$1(state, nextState);
1840
- return {
1841
- ...nextState,
1842
- selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
1843
- selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
1844
- selectedEventIndex
1845
- };
1864
+ const listChatViewEvents$1 = async sessionId => {
1865
+ return invoke$1('ChatStorage.listChatViewEvents', sessionId);
1846
1866
  };
1847
-
1848
- const handleEventCategoryFilter = (state, value) => {
1849
- const nextState = {
1850
- ...state,
1851
- eventCategoryFilter: value || All
1852
- };
1853
- return withPreservedSelection$1(state, nextState);
1867
+ const loadSelectedEvent$1 = async (sessionId, eventId, type) => {
1868
+ return invoke$1('ChatStorage.loadSelectedEvent', sessionId, eventId, type);
1854
1869
  };
1855
1870
 
1856
- const listChatViewEvents$1 = async sessionId => {
1857
- return invoke('ChatStorage.listChatViewEvents', sessionId);
1871
+ const listChatViewEventsDependencies = {
1872
+ listChatViewEventsFromWorker: listChatViewEvents$1
1858
1873
  };
1859
- const loadSelectedEvent$1 = async (sessionId, eventId, type) => {
1860
- return invoke('ChatStorage.loadSelectedEvent', sessionId, eventId, type);
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
+ };
1882
+ }
1861
1883
  };
1862
1884
 
1863
1885
  const loadSelectedEventDependencies = {
@@ -1867,66 +1889,330 @@ const loadSelectedEvent = async (_databaseName, _dataBaseVersion, _eventStoreNam
1867
1889
  return loadSelectedEventDependencies.loadSelectedEventFromWorker(sessionId, eventId, type);
1868
1890
  };
1869
1891
 
1870
- const getCurrentEvents$2 = state => {
1892
+ const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
1893
+ const invalidSessionIdPattern = /[/?#]/;
1894
+ const parseChatDebugUri = uri => {
1895
+ if (!uri) {
1896
+ return {
1897
+ code: ParseChatDebugUriErrorCode.MissingUri,
1898
+ message: 'Missing URI',
1899
+ type: 'error'
1900
+ };
1901
+ }
1902
+ const match = uri.match(chatDebugUriPattern);
1903
+ if (!match) {
1904
+ return {
1905
+ code: ParseChatDebugUriErrorCode.InvalidUriFormat,
1906
+ message: 'Invalid URI format',
1907
+ type: 'error'
1908
+ };
1909
+ }
1910
+ const encodedSessionId = match[1];
1911
+ let sessionId;
1912
+ try {
1913
+ sessionId = decodeURIComponent(encodedSessionId);
1914
+ } catch {
1915
+ return {
1916
+ code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
1917
+ message: 'Invalid URI encoding',
1918
+ type: 'error'
1919
+ };
1920
+ }
1921
+ if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
1922
+ return {
1923
+ code: ParseChatDebugUriErrorCode.InvalidSessionId,
1924
+ message: 'Invalid session id',
1925
+ type: 'error'
1926
+ };
1927
+ }
1928
+ return {
1929
+ sessionId,
1930
+ type: 'success'
1931
+ };
1932
+ };
1933
+
1934
+ const loadEventsDependencies = {
1935
+ listChatViewEvents: listChatViewEvents,
1936
+ loadSelectedEvent: loadSelectedEvent
1937
+ };
1938
+ const getCurrentEvents$3 = state => {
1871
1939
  const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1872
1940
  return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1873
1941
  };
1874
- const selectEventAtIndex = async (state, selectedEventIndex, dependencies) => {
1875
- const currentEvents = getCurrentEvents$2(state);
1876
- const selectedEvent = currentEvents[selectedEventIndex];
1877
- 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) {
1878
1953
  return {
1879
1954
  ...state,
1880
1955
  selectedEvent: null,
1881
1956
  selectedEventId: null,
1882
- selectedEventIndex
1957
+ selectedEventIndex: null
1883
1958
  };
1884
1959
  }
1885
- if (typeof selectedEvent.eventId !== 'number') {
1960
+ const selectedEvent = currentEvents[selectedEventIndex];
1961
+ if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
1886
1962
  return {
1887
1963
  ...state,
1888
- selectedEvent,
1964
+ selectedEvent: null,
1889
1965
  selectedEventId: null,
1890
- selectedEventIndex
1966
+ selectedEventIndex: null
1891
1967
  };
1892
1968
  }
1893
- 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);
1894
1970
  return {
1895
1971
  ...state,
1896
- selectedEvent: selectedEventDetails ?? selectedEvent,
1972
+ selectedEvent: selectedEventDetails,
1897
1973
  selectedEventId: selectedEvent.eventId,
1898
1974
  selectedEventIndex
1899
1975
  };
1900
1976
  };
1901
-
1902
- const handleEventRowClickDependencies = {
1903
- loadSelectedEvent: loadSelectedEvent
1904
- };
1905
- const isPrimaryButton = button => {
1906
- return button === 0;
1907
- };
1908
- const parseSelectedEventIndex$1 = value => {
1909
- const parsed = Number.parseInt(value, 10);
1910
- if (Number.isNaN(parsed) || parsed < 0) {
1911
- return null;
1912
- }
1913
- return parsed;
1914
- };
1915
- const handleEventRowClick = async (state, value, button = 0) => {
1916
- if (!isPrimaryButton(button)) {
1917
- return state;
1918
- }
1919
- const selectedEventIndex = parseSelectedEventIndex$1(value);
1920
- if (selectedEventIndex === null) {
1977
+ const getStateWithInvalidUri = state => {
1978
+ const parsed = parseChatDebugUri(state.uri);
1979
+ if (parsed.type !== 'error') {
1921
1980
  return state;
1922
1981
  }
1923
- return selectEventAtIndex(state, selectedEventIndex, handleEventRowClickDependencies);
1982
+ return {
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: ''
1991
+ };
1924
1992
  };
1925
-
1926
- const handleHeaderContextMenu = state => {
1927
- return state;
1993
+ const getSessionIdFromUri = state => {
1994
+ const parsed = parseChatDebugUri(state.uri);
1995
+ if (parsed.type === 'error') {
1996
+ return undefined;
1997
+ }
1998
+ return parsed.sessionId;
1928
1999
  };
1929
-
2000
+ const loadEventsForSessionId = async (state, sessionId) => {
2001
+ const {
2002
+ databaseName,
2003
+ dataBaseVersion,
2004
+ eventStoreName,
2005
+ sessionIdIndexName
2006
+ } = state;
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
+
1930
2216
  const getBoolean = value => {
1931
2217
  return value === true || value === 'true' || value === 'on' || value === '1';
1932
2218
  };
@@ -1943,8 +2229,9 @@ const DetailTab = 'detailTab';
1943
2229
  const TimelineStartSeconds = 'timelineStartSeconds';
1944
2230
  const TimelineEndSeconds = 'timelineEndSeconds';
1945
2231
  const TimelineRangePreset = 'timelineRangePreset';
2232
+ const Refresh = 'refresh';
1946
2233
 
1947
- const getCurrentEvents$1 = state => {
2234
+ const getCurrentEvents = state => {
1948
2235
  const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
1949
2236
  return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
1950
2237
  };
@@ -1972,7 +2259,7 @@ const getSelectedEventIndex = state => {
1972
2259
  if (selectedEventIndex === null) {
1973
2260
  return null;
1974
2261
  }
1975
- const filteredEvents = getCurrentEvents$1(state);
2262
+ const filteredEvents = getCurrentEvents(state);
1976
2263
  const selectedEvent = filteredEvents[selectedEventIndex];
1977
2264
  if (!selectedEvent) {
1978
2265
  return null;
@@ -1990,12 +2277,12 @@ const getPreservedSelectedEventIndex = (oldState, newState) => {
1990
2277
  if (selectedEventIndex === null) {
1991
2278
  return null;
1992
2279
  }
1993
- const oldFilteredEvents = getCurrentEvents$1(oldState);
2280
+ const oldFilteredEvents = getCurrentEvents(oldState);
1994
2281
  const selectedEvent = oldFilteredEvents[selectedEventIndex];
1995
2282
  if (!selectedEvent) {
1996
2283
  return null;
1997
2284
  }
1998
- const newFilteredEvents = getCurrentEvents$1(newState);
2285
+ const newFilteredEvents = getCurrentEvents(newState);
1999
2286
  const newIndex = getEventIndexByStableId(newFilteredEvents, selectedEvent);
2000
2287
  if (newIndex === -1) {
2001
2288
  return null;
@@ -2130,7 +2417,44 @@ const handleSashPointerUp = (state, eventX, eventY) => {
2130
2417
  return state;
2131
2418
  };
2132
2419
 
2133
- 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
+ });
2134
2458
  return state;
2135
2459
  };
2136
2460
 
@@ -2173,1096 +2497,167 @@ const handleTimelineEndSeconds = (state, value) => {
2173
2497
  const handleTimelineRangePreset = (state, value) => {
2174
2498
  const nextState = {
2175
2499
  ...state,
2176
- ...parseTimelineRangePreset(value)
2177
- };
2178
- return withPreservedSelection$1(state, nextState);
2179
- };
2180
-
2181
- const handleTimelineDoubleClick = state => {
2182
- const nextState = handleTimelineRangePreset(state, '');
2183
- return clearTimelineSelectionState(nextState);
2184
- };
2185
-
2186
- const getTimelineEvents = state => {
2187
- const {
2188
- eventCategoryFilter,
2189
- events,
2190
- filterValue,
2191
- showEventStreamFinishedEvents,
2192
- showInputEvents,
2193
- showResponsePartEvents
2194
- } = state;
2195
- return getFilteredEvents(events, filterValue, eventCategoryFilter, showInputEvents, showResponsePartEvents, showEventStreamFinishedEvents);
2196
- };
2197
-
2198
- const getTimelineLeft = state => {
2199
- return state.x + viewPadding + timelineHorizontalPadding;
2200
- };
2201
- const getTimelineWidth = state => {
2202
- return Math.max(0, getMainWidth(state.width) - timelineHorizontalPadding * 2);
2203
- };
2204
-
2205
- const trailingZeroFractionRegex = /\.0+$/;
2206
- const trailingFractionZeroRegex = /(\.\d*?)0+$/;
2207
- const formatTimelinePresetValue = value => {
2208
- return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
2209
- };
2210
-
2211
- const getTimelineSecondsFromClientX = (events, eventX, timelineLeft, timelineWidth) => {
2212
- if (timelineWidth <= 0) {
2213
- return undefined;
2214
- }
2215
- const durationSeconds = getTimelineDurationSeconds(events);
2216
- const relativeX = Math.min(Math.max(eventX - timelineLeft, 0), timelineWidth);
2217
- const ratio = relativeX / timelineWidth;
2218
- return formatTimelinePresetValue(durationSeconds * ratio);
2219
- };
2220
-
2221
- const handleTimelinePointerDown = (state, eventX) => {
2222
- const timelineEvents = getTimelineEvents(state);
2223
- const timelineLeft = getTimelineLeft(state);
2224
- const timelineWidth = getTimelineWidth(state);
2225
- const clientX = state.x + eventX;
2226
- const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2227
- if (seconds === undefined) {
2228
- return state;
2229
- }
2230
- return {
2231
- ...state,
2232
- timelineSelectionActive: true,
2233
- timelineSelectionAnchorSeconds: seconds,
2234
- timelineSelectionFocusSeconds: seconds
2235
- };
2236
- };
2237
-
2238
- const handleTimelinePointerMove = (state, eventX) => {
2239
- if (!state.timelineSelectionActive) {
2240
- return state;
2241
- }
2242
- const timelineEvents = getTimelineEvents(state);
2243
- const timelineLeft = getTimelineLeft(state);
2244
- const timelineWidth = getTimelineWidth(state);
2245
- const clientX = state.x + eventX;
2246
- const seconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2247
- if (seconds === undefined) {
2248
- return state;
2249
- }
2250
- return {
2251
- ...state,
2252
- timelineSelectionFocusSeconds: seconds
2253
- };
2254
- };
2255
-
2256
- const handleTimelinePointerUp = (state, eventX) => {
2257
- if (!state.timelineSelectionActive) {
2258
- return state;
2259
- }
2260
- const timelineEvents = getTimelineEvents(state);
2261
- const timelineLeft = getTimelineLeft(state);
2262
- const timelineWidth = getTimelineWidth(state);
2263
- const clientX = state.x + eventX;
2264
- const focusSeconds = getTimelineSecondsFromClientX(timelineEvents, clientX, timelineLeft, timelineWidth);
2265
- if (focusSeconds === undefined) {
2266
- return clearTimelineSelectionState(state);
2267
- }
2268
- const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
2269
- const focus = Number.parseFloat(focusSeconds);
2270
- const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
2271
- const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
2272
- const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
2273
- return clearTimelineSelectionState(nextState);
2274
- };
2275
-
2276
- const handleUseDevtoolsLayout = (state, checked) => {
2277
- const useDevtoolsLayout = getBoolean(checked);
2278
- const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
2279
- return {
2280
- ...state,
2281
- selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
2282
- selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
2283
- selectedEventIndex,
2284
- useDevtoolsLayout
2285
- };
2286
- };
2287
-
2288
- const handleShowEventStreamFinishedEvents = (state, checked) => {
2289
- const nextState = {
2290
- ...state,
2291
- showEventStreamFinishedEvents: getBoolean(checked)
2292
- };
2293
- return withPreservedSelection$1(state, nextState);
2294
- };
2295
- const handleShowInputEvents = (state, checked) => {
2296
- const nextState = {
2297
- ...state,
2298
- showInputEvents: getBoolean(checked)
2299
- };
2300
- return withPreservedSelection$1(state, nextState);
2301
- };
2302
- const handleShowResponsePartEvents = (state, checked) => {
2303
- const nextState = {
2304
- ...state,
2305
- showResponsePartEvents: getBoolean(checked)
2306
- };
2307
- return withPreservedSelection$1(state, nextState);
2308
- };
2309
-
2310
- const getErrorMessage = error => {
2311
- if (error instanceof Error) {
2312
- return error.message;
2313
- }
2314
- if (typeof error === 'string') {
2315
- return error;
2316
- }
2317
- if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {
2318
- return error.message;
2319
- }
2320
- return undefined;
2321
- };
2322
- const getFailedToLoadMessage = (sessionId, error) => {
2323
- const errorMessage = getErrorMessage(error);
2324
- if (errorMessage) {
2325
- return `Failed to load chat debug session "${sessionId}": ${errorMessage}`;
2326
- }
2327
- return `Failed to load chat debug session "${sessionId}". Please try again.`;
2328
- };
2329
-
2330
- const ParseChatDebugUriErrorCode = {
2331
- InvalidSessionId: 'invalid-session-id',
2332
- InvalidUriEncoding: 'invalid-uri-encoding',
2333
- InvalidUriFormat: 'invalid-uri-format',
2334
- MissingUri: 'missing-uri'
2335
- };
2336
-
2337
- const getInvalidUriMessage = (uri, code) => {
2338
- if (code === ParseChatDebugUriErrorCode.MissingUri) {
2339
- return 'Unable to load debug session: missing URI. Expected format: chat-debug://<sessionId>.';
2340
- }
2341
- return `Unable to load debug session: invalid URI "${uri}". Expected format: chat-debug://<sessionId>.`;
2342
- };
2343
-
2344
- const getSessionNotFoundMessage = sessionId => {
2345
- return `No chat session found for sessionId "${sessionId}".`;
2346
- };
2347
-
2348
- const listChatViewEventsDependencies = {
2349
- listChatViewEventsFromWorker: listChatViewEvents$1
2350
- };
2351
- const listChatViewEvents = async (sessionId, _databaseName, _dataBaseVersion, _eventStoreName, _sessionIdIndexName) => {
2352
- try {
2353
- return await listChatViewEventsDependencies.listChatViewEventsFromWorker(sessionId);
2354
- } catch (error) {
2355
- return {
2356
- error,
2357
- type: 'error'
2358
- };
2359
- }
2360
- };
2361
-
2362
- const chatDebugUriPattern = /^chat-debug:\/\/([^/?#]+)$/;
2363
- const invalidSessionIdPattern = /[/?#]/;
2364
- const parseChatDebugUri = uri => {
2365
- if (!uri) {
2366
- return {
2367
- code: ParseChatDebugUriErrorCode.MissingUri,
2368
- message: 'Missing URI',
2369
- type: 'error'
2370
- };
2371
- }
2372
- const match = uri.match(chatDebugUriPattern);
2373
- if (!match) {
2374
- return {
2375
- code: ParseChatDebugUriErrorCode.InvalidUriFormat,
2376
- message: 'Invalid URI format',
2377
- type: 'error'
2378
- };
2379
- }
2380
- const encodedSessionId = match[1];
2381
- let sessionId;
2382
- try {
2383
- sessionId = decodeURIComponent(encodedSessionId);
2384
- } catch {
2385
- return {
2386
- code: ParseChatDebugUriErrorCode.InvalidUriEncoding,
2387
- message: 'Invalid URI encoding',
2388
- type: 'error'
2389
- };
2390
- }
2391
- if (!sessionId || invalidSessionIdPattern.test(sessionId)) {
2392
- return {
2393
- code: ParseChatDebugUriErrorCode.InvalidSessionId,
2394
- message: 'Invalid session id',
2395
- type: 'error'
2396
- };
2397
- }
2398
- return {
2399
- sessionId,
2400
- type: 'success'
2401
- };
2402
- };
2403
-
2404
- const loadEventsDependencies = {
2405
- listChatViewEvents: listChatViewEvents,
2406
- loadSelectedEvent: loadSelectedEvent
2407
- };
2408
- const getCurrentEvents = state => {
2409
- const filteredEvents = getFilteredEvents(state.events, state.filterValue, state.eventCategoryFilter, state.showInputEvents, state.showResponsePartEvents, state.showEventStreamFinishedEvents);
2410
- return filterEventsByTimelineRange(filteredEvents, state.timelineStartSeconds, state.timelineEndSeconds);
2411
- };
2412
- const restoreSelectedEvent = async state => {
2413
- if (state.selectedEventId === null) {
2414
- return {
2415
- ...state,
2416
- selectedEvent: null,
2417
- selectedEventIndex: null
2418
- };
2419
- }
2420
- const currentEvents = getCurrentEvents(state);
2421
- const selectedEventIndex = currentEvents.findIndex(event => event.eventId === state.selectedEventId);
2422
- if (selectedEventIndex === -1) {
2423
- return {
2424
- ...state,
2425
- selectedEvent: null,
2426
- selectedEventId: null,
2427
- selectedEventIndex: null
2428
- };
2429
- }
2430
- const selectedEvent = currentEvents[selectedEventIndex];
2431
- if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
2432
- return {
2433
- ...state,
2434
- selectedEvent: null,
2435
- selectedEventId: null,
2436
- selectedEventIndex: null
2437
- };
2438
- }
2439
- const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
2440
- return {
2441
- ...state,
2442
- selectedEvent: selectedEventDetails,
2443
- selectedEventId: selectedEvent.eventId,
2444
- selectedEventIndex
2445
- };
2446
- };
2447
- const getStateWithInvalidUri = state => {
2448
- const parsed = parseChatDebugUri(state.uri);
2449
- if (parsed.type !== 'error') {
2450
- return state;
2451
- }
2452
- return {
2453
- ...state,
2454
- errorMessage: getInvalidUriMessage(state.uri, parsed.code),
2455
- events: [],
2456
- initial: false,
2457
- selectedEvent: null,
2458
- selectedEventId: null,
2459
- selectedEventIndex: null,
2460
- sessionId: ''
2461
- };
2462
- };
2463
- const getSessionIdFromUri = state => {
2464
- const parsed = parseChatDebugUri(state.uri);
2465
- if (parsed.type === 'error') {
2466
- return undefined;
2467
- }
2468
- return parsed.sessionId;
2469
- };
2470
- const loadEventsForSessionId = async (state, sessionId) => {
2471
- const {
2472
- databaseName,
2473
- dataBaseVersion,
2474
- eventStoreName,
2475
- sessionIdIndexName
2476
- } = state;
2477
- const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName);
2478
- if (result.type === 'error') {
2479
- return {
2480
- ...state,
2481
- errorMessage: getFailedToLoadMessage(sessionId, result.error),
2482
- events: [],
2483
- initial: false,
2484
- selectedEvent: null,
2485
- selectedEventId: null,
2486
- selectedEventIndex: null,
2487
- sessionId
2488
- };
2489
- }
2490
- const {
2491
- events
2492
- } = result;
2493
- if (events.length === 0) {
2494
- return {
2495
- ...state,
2496
- errorMessage: getSessionNotFoundMessage(sessionId),
2497
- events: [],
2498
- initial: false,
2499
- selectedEvent: null,
2500
- selectedEventId: null,
2501
- selectedEventIndex: null,
2502
- sessionId
2503
- };
2504
- }
2505
- const nextState = {
2506
- ...state,
2507
- errorMessage: '',
2508
- events,
2509
- initial: false,
2510
- sessionId
2511
- };
2512
- return restoreSelectedEvent(nextState);
2513
- };
2514
- const loadEventsFromUri = async state => {
2515
- const sessionId = getSessionIdFromUri(state);
2516
- if (!sessionId) {
2517
- return getStateWithInvalidUri(state);
2518
- }
2519
- return loadEventsForSessionId(state, sessionId);
2520
- };
2521
- const refreshEvents = async state => {
2522
- const sessionId = state.sessionId || getSessionIdFromUri(state);
2523
- if (!sessionId) {
2524
- return getStateWithInvalidUri(state);
2525
- }
2526
- return loadEventsForSessionId(state, sessionId);
2527
- };
2528
-
2529
- const loadContent = async state => {
2530
- return loadEventsFromUri(state);
2531
- };
2532
-
2533
- const refresh = async state => {
2534
- return refreshEvents(state);
2535
- };
2536
-
2537
- const getCss = state => {
2538
- const tableWidth = clampTableWidth(state.width, state.tableWidth);
2539
- const detailsWidth = getDetailsWidth(state.width, state.tableWidth);
2540
- return `
2541
- .ChatDebugView {
2542
- --ChatDebugViewDetailsWidth: ${detailsWidth}px;
2543
- --ChatDebugViewSashWidth: ${sashWidth}px;
2544
- --ChatDebugViewTableWidth: ${tableWidth}px;
2545
- padding: ${viewPadding}px;
2546
- display: flex;
2547
- flex-direction: column;
2548
- height: 100%;
2549
- box-sizing: border-box;
2550
- gap: 8px;
2551
- contain: strict;
2552
- }
2553
-
2554
- .ChatDebugView--devtools {
2555
- gap: 4px;
2556
- }
2557
-
2558
- .ChatDebugViewTop {
2559
- display: flex;
2560
- align-items: center;
2561
- gap: 12px;
2562
- flex-wrap: wrap;
2563
- contain: content;
2564
- }
2565
-
2566
- .ChatDebugViewTop--devtools {
2567
- align-items: stretch;
2568
- }
2569
-
2570
- .ChatDebugViewFilterInput {
2571
- flex: 1;
2572
- min-width: 0;
2573
- max-width: 500px;
2574
- contain: content;
2575
- }
2576
-
2577
- .ChatDebugViewFilterInput--devtools {
2578
- flex: 0 1 80px;
2579
- width: 100%;
2580
- max-width: 80px;
2581
- }
2582
-
2583
- .ChatDebugViewQuickFilterPill {
2584
- display: flex;
2585
- align-items: center;
2586
- justify-content: center;
2587
- min-height: 22px;
2588
- padding: 0 10px;
2589
- border: 1px solid var(--vscode-editorWidget-border, #454545);
2590
- border-radius: 999px;
2591
- cursor: pointer;
2592
- white-space: nowrap;
2593
- transition:
2594
- background 120ms ease-out,
2595
- border-color 120ms ease-out,
2596
- color 120ms ease-out,
2597
- transform 120ms ease-out;
2598
- contain: content;
2599
- }
2600
-
2601
- .ChatDebugViewQuickFilterPill:not(.ChatDebugViewQuickFilterPillSelected):hover {
2602
- border-color: var(--vscode-focusBorder, #007fd4);
2603
- background: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 82%, transparent 18%);
2604
- color: var(--vscode-list-hoverForeground, inherit);
2605
- transform: translateY(-1px);
2606
- }
2607
-
2608
-
2609
- .ChatDebugViewQuickFilters {
2610
- display: flex;
2611
- align-items: center;
2612
- gap: 8px;
2613
- justify-content: center;
2614
- min-height: 28px;
2615
- font-size: 12px;
2616
- line-height: 1;
2617
- contain: content;
2618
- }
2619
-
2620
- .ChatDebugViewQuickFilterPillSelected {
2621
- border-color: var(--vscode-focusBorder, #007fd4);
2622
- background: var(--vscode-list-activeSelectionBackground, rgba(14, 99, 156, 0.35));
2623
- color: var(--vscode-list-activeSelectionForeground, inherit);
2624
- }
2625
-
2626
- .ChatDebugViewQuickFilterInput {
2627
- position: absolute;
2628
- opacity: 0;
2629
- pointer-events: none;
2630
- contain: content;
2631
- }
2632
-
2633
- .ChatDebugViewEvents {
2634
- display: flex;
2635
- flex-direction: column;
2636
- overflow: auto;
2637
- min-width: 0;
2638
- min-height: 0;
2639
- scrollbar-width: thin;
2640
- scrollbar-color: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4)) transparent;
2641
- contain: strict;
2642
- }
2643
-
2644
- .ChatDebugView--devtools .ChatDebugViewEvents {
2645
- border-radius: 6px;
2646
- margin-bottom: 0;
2647
- overflow: hidden;
2648
- }
2649
-
2650
- .ChatDebugViewEventsFullWidth {
2651
- flex: 1 1 100%;
2652
- }
2653
-
2654
- .ChatDebugViewDevtoolsMain {
2655
- display: flex;
2656
- flex-direction: column;
2657
- flex: 1;
2658
- align-items: stretch;
2659
- gap: 0;
2660
- min-width: 0;
2661
- min-height: 0;
2662
- contain: strict;
2663
- }
2664
-
2665
- .ChatDebugViewDevtoolsMain > .ChatDebugViewTimeline {
2666
- flex: 0 0 auto;
2667
- }
2668
-
2669
- .ChatDebugViewDevtoolsSplit {
2670
- display: flex;
2671
- flex: 1;
2672
- align-items: stretch;
2673
- gap: 0;
2674
- min-width: 0;
2675
- min-height: 0;
2676
- overflow: hidden;
2677
- contain: strict;
2678
- }
2679
-
2680
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents {
2681
- flex: 0 1 var(--ChatDebugViewTableWidth);
2682
- min-width: 0;
2683
- }
2684
-
2685
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewEvents.ChatDebugViewEventsFullWidth {
2686
- flex: 1 1 100%;
2687
- }
2688
-
2689
- .ChatDebugViewDevtoolsSplit > .ChatDebugViewDetails {
2690
- border-left: 0;
2691
- border-top-left-radius: 0;
2692
- border-bottom-left-radius: 0;
2693
- flex: 1;
2694
- }
2695
-
2696
- .ChatDebugViewSash {
2697
- flex: 0 0 var(--ChatDebugViewSashWidth);
2698
- position: relative;
2699
- cursor: col-resize;
2700
- display: flex;
2701
- justify-content: center;
2702
- min-height: 0;
2703
- contain: strict;
2704
- }
2705
-
2706
- .ChatDebugViewSashLine {
2707
- width: 1px;
2708
- height: 100%;
2709
- background: var(--vscode-editorWidget-border, #454545);
2710
- pointer-events: none;
2711
- contain: strict;
2712
- }
2713
-
2714
- .ChatDebugViewSash:hover .ChatDebugViewSashLine {
2715
- background: var(--vscode-focusBorder, #007fd4);
2716
- }
2717
-
2718
- .ChatDebugViewTable {
2719
- display: flex;
2720
- flex-direction: column;
2721
- min-height: 0;
2722
- flex: 1 1 auto;
2723
- contain: strict;
2724
- }
2725
-
2726
- .ChatDebugViewTimeline {
2727
- display: flex;
2728
- flex-direction: column;
2729
- gap: 6px;
2730
- padding: 6px ${timelineHorizontalPadding}px 8px;
2731
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
2732
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 82%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.12)) 18%);
2733
- contain: content;
2734
- }
2735
-
2736
- .ChatDebugViewTimelineTop {
2737
- display: flex;
2738
- align-items: center;
2739
- contain: content;
2740
- }
2741
-
2742
- .ChatDebugViewTimelineSummary {
2743
- display: flex;
2744
- align-items: center;
2745
- font-size: 12px;
2746
- line-height: 16px;
2747
- opacity: 0.8;
2748
- contain: content;
2749
- }
2750
-
2751
- .ChatDebugViewTimelineControls {
2752
- display: flex;
2753
- align-items: center;
2754
- gap: 8px;
2755
- flex-wrap: wrap;
2756
- contain: content;
2757
- }
2758
-
2759
- .ChatDebugViewTimelineBuckets {
2760
- display: flex;
2761
- align-items: end;
2762
- gap: 3px;
2763
- flex: 1 1 auto;
2764
- min-height: 52px;
2765
- pointer-events: none;
2766
- contain: strict;
2767
- }
2768
-
2769
- .ChatDebugViewTimelineInteractive {
2770
- display: flex;
2771
- position: relative;
2772
- min-height: 52px;
2773
- cursor: crosshair;
2774
- user-select: none;
2775
- contain: strict;
2776
- }
2777
-
2778
- .ChatDebugViewTimelineSelectionOverlay {
2779
- position: absolute;
2780
- inset: 0;
2781
- pointer-events: none;
2782
- contain: strict;
2783
- }
2784
-
2785
- .ChatDebugViewTimelineSelectionRange {
2786
- position: absolute;
2787
- top: 0;
2788
- bottom: 0;
2789
- background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 20%, transparent 80%);
2790
- border-left: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
2791
- border-right: 1px solid color-mix(in srgb, var(--vscode-charts-blue, #75beff) 65%, transparent 35%);
2792
- contain: strict;
2793
- }
2794
-
2795
- .ChatDebugViewTimelineSelectionMarker {
2796
- position: absolute;
2797
- top: 0;
2798
- bottom: 0;
2799
- width: 1px;
2800
- margin-left: -0.5px;
2801
- background: var(--vscode-focusBorder, #007fd4);
2802
- box-shadow: 0 0 0 1px color-mix(in srgb, var(--vscode-focusBorder, #007fd4) 24%, transparent 76%);
2803
- contain: strict;
2804
- }
2805
-
2806
- .ChatDebugViewTimelineBucket {
2807
- --ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.16)) 74%, transparent 26%);
2808
- --ChatDebugViewTimelineBucketBarBorderColor: transparent;
2809
- display: flex;
2810
- align-items: stretch;
2811
- flex: 1 1 10px;
2812
- min-width: 10px;
2813
- min-height: 52px;
2814
- contain: strict;
2815
- }
2816
-
2817
- .ChatDebugViewTimelineBucketSelected {
2818
- --ChatDebugViewTimelineBucketBarBackground: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
2819
- --ChatDebugViewTimelineBucketBarBorderColor: var(--vscode-focusBorder, #007fd4);
2820
- }
2821
-
2822
- .ChatDebugViewTimelinePresetInput {
2823
- position: absolute;
2824
- opacity: 0;
2825
- pointer-events: none;
2826
- contain: content;
2827
- }
2828
-
2829
- .ChatDebugViewTimelineBucketBar {
2830
- display: flex;
2831
- flex-direction: column;
2832
- justify-content: flex-end;
2833
- gap: 2px;
2834
- padding: 6px 1px 2px;
2835
- border: 1px solid transparent;
2836
- border-radius: 2px;
2837
- width: 100%;
2838
- background: var(--ChatDebugViewTimelineBucketBarBackground);
2839
- border-color: var(--ChatDebugViewTimelineBucketBarBorderColor);
2840
- contain: strict;
2841
- }
2842
-
2843
- .ChatDebugViewTimelineBucketBarSelected {
2844
- background: color-mix(in srgb, var(--vscode-charts-blue, #75beff) 72%, transparent 28%);
2845
- border-color: var(--vscode-focusBorder, #007fd4);
2846
- }
2847
-
2848
- .ChatDebugViewTimelineBucketUnit {
2849
- width: 100%;
2850
- height: 4px;
2851
- border-radius: 999px;
2852
- background: var(--vscode-charts-blue, #75beff);
2853
- contain: strict;
2854
- }
2855
-
2856
- .ChatDebugViewTimelineBucketUnitEmpty {
2857
- opacity: 0.35;
2858
- background: var(--vscode-editorWidget-border, #454545);
2859
- }
2860
-
2861
- .ChatDebugViewTableHeaderRow,
2862
- .ChatDebugViewEventRow {
2863
- display: flex;
2864
- align-items: center;
2865
- gap: 8px;
2866
- contain: content;
2867
- }
2868
-
2869
- .ChatDebugViewTableHeader {
2870
- padding: 3px 8px;
2871
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
2872
- background: var(--vscode-editorWidget-background, transparent);
2873
- position: sticky;
2874
- top: 0;
2875
- z-index: 1;
2876
- contain: content;
2877
- }
2878
-
2879
- .ChatDebugViewHeaderCell {
2880
- display: flex;
2881
- align-items: center;
2882
- overflow: hidden;
2883
- text-overflow: ellipsis;
2884
- white-space: nowrap;
2885
- min-width: 0;
2886
- font-size: 11px;
2887
- letter-spacing: 0.04em;
2888
- opacity: 0.8;
2889
- contain: content;
2890
- }
2891
-
2892
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(1) {
2893
- flex: 1 1 140px;
2894
- min-width: 0;
2895
- }
2896
-
2897
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(2) {
2898
- flex: 0 0 90px;
2899
- justify-content: flex-end;
2900
- }
2901
-
2902
- .ChatDebugViewTableHeaderRow > .ChatDebugViewHeaderCell:nth-child(3) {
2903
- flex: 0 0 96px;
2904
- justify-content: flex-end;
2905
- }
2906
-
2907
- .ChatDebugViewTableBody {
2908
- display: flex;
2909
- flex-direction: column;
2910
- overflow: auto;
2911
- min-height: 0;
2912
- flex: 1 1 auto;
2913
- contain: strict;
2914
- }
2915
-
2916
- .ChatDebugViewEventRowLabel {
2917
- display: block;
2918
- contain: content;
2919
- }
2920
-
2921
- .ChatDebugViewEventRowLabelSelected .ChatDebugViewEventRow,
2922
- .ChatDebugViewEventRowSelected {
2923
- background: var(--vscode-list-activeSelectionBackground, rgba(14, 99, 156, 0.35));
2924
- color: var(--vscode-list-activeSelectionForeground, inherit);
2925
- }
2926
-
2927
- .ChatDebugViewEventRowInput {
2928
- position: absolute;
2929
- opacity: 0;
2930
- pointer-events: none;
2931
- contain: content;
2932
- }
2933
-
2934
- .ChatDebugViewEventRow {
2935
- padding: 2px 8px;
2936
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 92%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 8%);
2937
- cursor: default;
2938
- }
2939
-
2940
- .ChatDebugViewTableBody > .ChatDebugViewEventRow:nth-child(even) {
2941
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 84%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31)) 16%);
2942
- }
2943
-
2944
- .ChatDebugViewEventRow:hover {
2945
- background: var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.31));
2946
- color: var(--vscode-list-hoverForeground, inherit);
2947
- }
2948
-
2949
- .ChatDebugViewCell {
2950
- display: flex;
2951
- align-items: center;
2952
- overflow: hidden;
2953
- text-overflow: ellipsis;
2954
- white-space: nowrap;
2955
- min-width: 0;
2956
- pointer-events: none;
2957
- contain: content;
2958
- }
2959
-
2960
- .ChatDebugViewCellType {
2961
- flex: 1 1 140px;
2962
- min-width: 0;
2963
- }
2964
-
2965
- .ChatDebugViewCellTime {
2966
- flex: 1 1 180px;
2967
- min-width: 0;
2968
- }
2969
-
2970
- .ChatDebugViewCellDuration {
2971
- flex: 0 0 90px;
2972
- justify-content: flex-end;
2973
- text-align: right;
2974
- }
2975
-
2976
- .ChatDebugViewCellStatus {
2977
- flex: 0 0 64px;
2978
- justify-content: flex-end;
2979
- text-align: right;
2980
- }
2981
-
2982
- .ChatDebugViewCellStatusError {
2983
- color: var(--vscode-errorForeground, #f14c4c);
2984
- }
2985
-
2986
- .ChatDebugViewDetails {
2987
- border: 1px solid var(--vscode-editorWidget-border, #454545);
2988
- border-radius: 6px;
2989
- overflow: hidden;
2990
- min-width: 0;
2991
- min-height: 0;
2992
- display: flex;
2993
- flex-direction: column;
2994
- contain: strict;
2995
- }
2996
-
2997
- .ChatDebugViewDetailsTop {
2998
- display: flex;
2999
- align-items: stretch;
3000
- justify-content: flex-start;
3001
- gap: 8px;
3002
- padding: 0 8px;
3003
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
3004
- background: color-mix(in srgb, var(--vscode-editorWidget-background, transparent) 72%, var(--vscode-list-hoverBackground, rgba(90, 93, 94, 0.18)) 28%);
3005
- contain: content;
3006
- }
3007
-
3008
- .ChatDebugViewDetailsClose {
3009
- width: 18px;
3010
- height: 18px;
3011
- appearance: none;
3012
- border: none;
3013
- border-radius: 4px;
3014
- cursor: pointer;
3015
- position: relative;
3016
- color: var(--vscode-foreground, #cccccc);
3017
- background: transparent;
3018
- align-self: center;
3019
- flex: 0 0 auto;
3020
- contain: strict;
3021
- }
3022
-
3023
- .ChatDebugViewDetailsClose:hover {
3024
- background: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31));
3025
- }
3026
-
3027
- .ChatDebugViewDetailsClose::before,
3028
- .ChatDebugViewDetailsClose::after {
3029
- content: '';
3030
- position: absolute;
3031
- left: 50%;
3032
- top: 50%;
3033
- width: 10px;
3034
- height: 1px;
3035
- background: currentColor;
3036
- }
3037
-
3038
- .ChatDebugViewDetailsClose::before {
3039
- transform: translate(-50%, -50%) rotate(45deg);
3040
- }
2500
+ ...parseTimelineRangePreset(value)
2501
+ };
2502
+ return withPreservedSelection$1(state, nextState);
2503
+ };
3041
2504
 
3042
- .ChatDebugViewDetailsClose::after {
3043
- transform: translate(-50%, -50%) rotate(-45deg);
3044
- }
2505
+ const handleTimelineDoubleClick = state => {
2506
+ const nextState = handleTimelineRangePreset(state, '');
2507
+ return clearTimelineSelectionState(nextState);
2508
+ };
3045
2509
 
3046
- .ChatDebugViewDetailsBody {
3047
- display: flex;
3048
- flex-direction: column;
3049
- overflow: hidden;
3050
- padding: 0;
3051
- flex: 1 1 auto;
3052
- min-height: 0;
3053
- align-items: stretch;
3054
- contain: strict;
3055
- }
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
+ };
3056
2521
 
3057
- .ChatDebugViewDetailsTabs {
3058
- display: flex;
3059
- align-items: center;
3060
- flex: 1 1 auto;
3061
- gap: 2px;
3062
- min-width: 0;
3063
- padding: 0;
3064
- overflow-x: auto;
3065
- contain: content;
3066
- }
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
+ };
3067
2528
 
3068
- .ChatDebugViewDetailsTab {
3069
- display: flex;
3070
- align-items: center;
3071
- justify-content: center;
3072
- min-height: 32px;
3073
- padding: 0 10px;
3074
- appearance: none;
3075
- background: transparent;
3076
- border: 0;
3077
- border-bottom: 2px solid transparent;
3078
- color: var(--vscode-descriptionForeground, var(--vscode-foreground, #cccccc));
3079
- cursor: pointer;
3080
- white-space: nowrap;
3081
- contain: content;
3082
- }
2529
+ const trailingZeroFractionRegex = /\.0+$/;
2530
+ const trailingFractionZeroRegex = /(\.\d*?)0+$/;
2531
+ const formatTimelinePresetValue = value => {
2532
+ return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
2533
+ };
3083
2534
 
3084
- .ChatDebugViewDetailsTab:hover {
3085
- color: var(--vscode-foreground, #cccccc);
3086
- }
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
+ };
3087
2544
 
3088
- .ChatDebugViewDetailsTabSelected {
3089
- border-bottom-color: var(--vscode-focusBorder, #007fd4);
3090
- color: var(--vscode-focusBorder, #007fd4);
3091
- }
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
+ };
3092
2561
 
3093
- .ChatDebugViewDetailsPanel {
3094
- display: flex;
3095
- flex-direction: column;
3096
- overflow: auto;
3097
- padding: 8px;
3098
- flex: 1 1 auto;
3099
- min-height: 0;
3100
- align-items: flex-start;
3101
- contain: strict;
3102
- }
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
+ };
3103
2579
 
3104
- .ChatDebugViewEvents::-webkit-scrollbar {
3105
- width: 10px;
3106
- height: 10px;
3107
- }
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
+ };
3108
2599
 
3109
- .ChatDebugViewEvents::-webkit-scrollbar-track {
3110
- background: transparent;
3111
- }
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
+ };
3112
2611
 
3113
- .ChatDebugViewEvents::-webkit-scrollbar-thumb {
3114
- background: var(--vscode-scrollbarSlider-background, rgba(121, 121, 121, 0.4));
3115
- border-radius: 999px;
3116
- border: 2px solid transparent;
3117
- background-clip: content-box;
3118
- }
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
+ };
3119
2633
 
3120
- .ChatDebugViewEvents::-webkit-scrollbar-thumb:hover {
3121
- background: var(--vscode-scrollbarSlider-hoverBackground, rgba(100, 100, 100, 0.7));
3122
- }
2634
+ const loadContent = async state => {
2635
+ return loadEventsFromUri(state);
2636
+ };
3123
2637
 
3124
- .ChatDebugViewEvents::-webkit-scrollbar-thumb:active {
3125
- background: var(--vscode-scrollbarSlider-activeBackground, rgba(191, 191, 191, 0.4));
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;
3126
2647
  }
3127
2648
 
3128
- .ChatDebugViewEvent {
3129
- display: flex;
3130
- flex-direction: column;
3131
- width: max-content;
3132
- min-width: 100%;
3133
- margin: 0;
3134
- padding: 8px;
3135
- border: 1px solid var(--vscode-editorWidget-border, #454545);
3136
- border-radius: 6px;
3137
- margin-bottom: 8px;
3138
- white-space: nowrap;
3139
- font-family: var(--vscode-editor-font-family, monospace);
3140
- font-size: 12px;
3141
- user-select: text;
3142
- contain: content;
3143
- }
3144
2649
 
3145
- .row {
3146
- display: flex;
3147
- align-items: baseline;
3148
- gap: 12px;
3149
- min-width: 100%;
3150
- width: max-content;
3151
- white-space: nowrap;
2650
+ .ChatDebugViewDetails {
3152
2651
  contain: strict;
3153
- height: 20px;
3154
- }
3155
-
3156
- .ChatDebugViewEventLineNumber {
3157
- display: flex;
3158
- justify-content: flex-end;
3159
- flex: 0 0 3ch;
3160
- opacity: 0.6;
3161
- user-select: none;
3162
- contain: content;
3163
2652
  }
3164
2653
 
3165
- .ChatDebugViewEventLineContent {
3166
- display: flex;
3167
- white-space: pre;
3168
- contain: content;
3169
- }
3170
-
3171
- .ChatDebugViewDetailsPanel > .ChatDebugViewEvent {
3172
- border: 0;
3173
- border-radius: 0;
3174
- margin-bottom: 0;
3175
- }
3176
-
3177
- .ChatDebugViewTiming {
3178
- display: flex;
3179
- flex-direction: column;
3180
- width: 100%;
2654
+ .ChatDebugViewDetailsTop {
2655
+ height: 33px;
3181
2656
  contain: strict;
3182
- flex: 1;
3183
- }
3184
-
3185
- .ChatDebugViewTimingRow {
3186
- display: flex;
3187
- align-items: center;
3188
- justify-content: space-between;
3189
- gap: 12px;
3190
- padding: 8px 10px;
3191
- border-bottom: 1px solid var(--vscode-editorWidget-border, #454545);
3192
- contain: content;
3193
- }
3194
-
3195
- .ChatDebugViewTimingRow:last-child {
3196
- border-bottom: 0;
3197
- }
3198
-
3199
- .ChatDebugViewTimingLabel {
3200
- opacity: 0.8;
3201
- contain: content;
3202
- }
3203
-
3204
- .ChatDebugViewTimingValue {
3205
- text-align: right;
3206
- font-family: var(--vscode-editor-font-family, monospace);
3207
- contain: content;
3208
- }
3209
-
3210
- .ChatDebugViewEmpty {
3211
- display: flex;
3212
- align-items: center;
3213
- opacity: 0.8;
3214
- contain: content;
3215
- }
3216
-
3217
- .ChatDebugViewError {
3218
- display: flex;
3219
- color: var(--vscode-errorForeground, #f14c4c);
3220
- white-space: normal;
3221
- contain: content;
3222
- }
3223
-
3224
- .TokenText {
3225
- color: var(--vscode-editor-foreground, inherit);
3226
- }
3227
-
3228
- .TokenKey {
3229
- color: var(--vscode-symbolIcon-propertyForeground, var(--vscode-editor-foreground, inherit));
3230
- }
3231
-
3232
- .TokenString {
3233
- color: var(--vscode-debugTokenExpression-string, var(--vscode-charts-green, #89d185));
3234
- }
3235
-
3236
- .TokenNumeric {
3237
- color: var(--vscode-debugTokenExpression-number, var(--vscode-charts-blue, #75beff));
3238
- }
3239
-
3240
- .TokenBoolean {
3241
- color: var(--vscode-debugTokenExpression-boolean, var(--vscode-charts-yellow, #dcdcaa));
3242
- }
3243
-
3244
- .ChatOrderedList{
3245
- display:flex;
3246
- flex-direction:column;
3247
- margin:0;
3248
- padding:0;
3249
- padding-left:10px;
3250
- contain: content;
3251
- }
3252
-
3253
- .ChatOrderedListItem{
3254
- display:flex;
3255
- margin:0;
3256
- padding:0;
3257
- contain: content;
3258
2657
  }
3259
2658
 
3260
- .ChatToolCalls{
3261
- display:flex;
3262
- flex-direction:column;
3263
- margin:0;
3264
- padding:0;
3265
- contain: content;
2659
+ .ChatDebugViewEvent {
2660
+ contain: content
3266
2661
  }
3267
2662
  `;
3268
2663
  };
@@ -3571,9 +2966,8 @@ const diffTree = (oldNodes, newNodes) => {
3571
2966
  const ChatDebugView = 'ChatDebugView';
3572
2967
  const ChatDebugViewDevtools = 'ChatDebugView--devtools';
3573
2968
  const ChatDebugViewDetails = 'ChatDebugViewDetails';
3574
- const ChatDebugViewDetailsBody = 'ChatDebugViewDetailsBody';
2969
+ const ChatDebugViewDetailsBottom = 'ChatDebugViewDetailsBottom';
3575
2970
  const ChatDebugViewDetailsClose = 'ChatDebugViewDetailsClose';
3576
- const ChatDebugViewDetailsPanel = 'ChatDebugViewDetailsPanel';
3577
2971
  const ChatDebugViewDetailsTab = 'ChatDebugViewDetailsTab';
3578
2972
  const ChatDebugViewDetailsTabSelected = 'ChatDebugViewDetailsTabSelected';
3579
2973
  const ChatDebugViewDetailsTabs = 'ChatDebugViewDetailsTabs';
@@ -3592,6 +2986,7 @@ const ChatDebugViewEventsFullWidth = 'ChatDebugViewEventsFullWidth';
3592
2986
  const ChatDebugViewFilterInput = 'ChatDebugViewFilterInput';
3593
2987
  const ChatDebugViewFilterInputDevtools = 'ChatDebugViewFilterInput--devtools';
3594
2988
  const ChatDebugViewHeaderCell = 'ChatDebugViewHeaderCell';
2989
+ const ChatDebugViewRefreshButton = 'ChatDebugViewRefreshButton';
3595
2990
  const ChatDebugViewQuickFilterInput = 'ChatDebugViewQuickFilterInput';
3596
2991
  const ChatDebugViewQuickFilterPill = 'ChatDebugViewQuickFilterPill';
3597
2992
  const ChatDebugViewQuickFilterPillSelected = 'ChatDebugViewQuickFilterPillSelected';
@@ -3611,7 +3006,6 @@ const ChatDebugViewTimelineBucketUnit = 'ChatDebugViewTimelineBucketUnit';
3611
3006
  const ChatDebugViewTimelineBucketUnitEmpty = 'ChatDebugViewTimelineBucketUnitEmpty';
3612
3007
  const ChatDebugViewTimelineBuckets = 'ChatDebugViewTimelineBuckets';
3613
3008
  const ChatDebugViewTimelineInteractive = 'ChatDebugViewTimelineInteractive';
3614
- const ChatDebugViewTimelinePresetInput = 'ChatDebugViewTimelinePresetInput';
3615
3009
  const ChatDebugViewTimelineSelectionMarker = 'ChatDebugViewTimelineSelectionMarker';
3616
3010
  const ChatDebugViewTimelineSelectionMarkerEnd = 'ChatDebugViewTimelineSelectionMarkerEnd';
3617
3011
  const ChatDebugViewTimelineSelectionMarkerStart = 'ChatDebugViewTimelineSelectionMarkerStart';
@@ -3632,11 +3026,11 @@ const ChatDebugViewCellStatusError = 'ChatDebugViewCellStatusError';
3632
3026
  const ChatDebugViewCellType = 'ChatDebugViewCellType';
3633
3027
  const InputBox = 'InputBox';
3634
3028
  const Row = 'row';
3635
- const TokenBoolean = 'TokenBoolean';
3636
- const TokenKey = 'TokenKey';
3637
- const TokenNumeric = 'TokenNumeric';
3638
- const TokenString = 'TokenString';
3639
- 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';
3640
3034
  const joinClassNames = (...classNames) => {
3641
3035
  return classNames.filter(Boolean).join(' ');
3642
3036
  };
@@ -3670,11 +3064,24 @@ const HandleTimelineDoubleClick = 17;
3670
3064
  const HandleTableKeyDown = 18;
3671
3065
  const HandleTimelineRangePreset = 19;
3672
3066
  const HandleCloseDetails = 20;
3067
+ const HandleClickRefresh = 21;
3673
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
+ };
3674
3080
  const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) => {
3081
+ const refreshButtonDom = getRefreshButtonDom();
3675
3082
  if (useDevtoolsLayout) {
3676
3083
  return [{
3677
- childCount: 1 + (quickFilterNodes.length > 0 ? 1 : 0),
3084
+ childCount: 2 + (quickFilterNodes.length > 0 ? 1 : 0),
3678
3085
  className: joinClassNames(ChatDebugViewTop, ChatDebugViewTopDevtools),
3679
3086
  onContextMenu: HandleHeaderContextMenu,
3680
3087
  type: Search
@@ -3688,10 +3095,10 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
3688
3095
  placeholder: 'Filter events',
3689
3096
  type: Input,
3690
3097
  value: filterValue
3691
- }, ...quickFilterNodes];
3098
+ }, ...quickFilterNodes, ...refreshButtonDom];
3692
3099
  }
3693
3100
  return [{
3694
- childCount: 1,
3101
+ childCount: 2,
3695
3102
  className: ChatDebugViewTop,
3696
3103
  onContextMenu: HandleHeaderContextMenu,
3697
3104
  type: Search
@@ -3705,7 +3112,7 @@ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, quickFilterNodes) =>
3705
3112
  placeholder: 'Filter events',
3706
3113
  type: Input,
3707
3114
  value: filterValue
3708
- }];
3115
+ }, ...refreshButtonDom];
3709
3116
  };
3710
3117
 
3711
3118
  const getDurationText = event => {
@@ -3801,7 +3208,7 @@ const getTabNodes = selectedDetailTab => {
3801
3208
  onClick: HandleDetailTab,
3802
3209
  role: 'tab',
3803
3210
  tabIndex: isSelected ? 0 : -1,
3804
- type: Button,
3211
+ type: Button$1,
3805
3212
  value: detailTab
3806
3213
  }, text(getDetailTabLabel(detailTab))];
3807
3214
  });
@@ -3826,7 +3233,7 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
3826
3233
  name: CloseDetails,
3827
3234
  onChange: HandleCloseDetails,
3828
3235
  onClick: HandleCloseDetails,
3829
- type: Button,
3236
+ type: Button$1,
3830
3237
  value: 'close'
3831
3238
  }, {
3832
3239
  'aria-label': 'Detail sections',
@@ -3835,14 +3242,9 @@ const getDetailsDom = (previewEventNodes, responseEventNodes = previewEventNodes
3835
3242
  role: 'tablist',
3836
3243
  type: Div
3837
3244
  }, ...getTabNodes(selectedDetailTab), {
3838
- childCount: 1,
3839
- className: ChatDebugViewDetailsBody,
3840
- role: 'document',
3841
- type: Div
3842
- }, {
3843
3245
  'aria-labelledby': getTabId(selectedDetailTab),
3844
3246
  childCount: 1,
3845
- className: ChatDebugViewDetailsPanel,
3247
+ className: ChatDebugViewDetailsBottom,
3846
3248
  id: getPanelId(selectedDetailTab),
3847
3249
  onContextMenu: HandleDetailsContextMenu,
3848
3250
  role: 'tabpanel',
@@ -3964,28 +3366,53 @@ const getEmptyStateDom = emptyMessage => {
3964
3366
  }, text(emptyMessage)];
3965
3367
  };
3966
3368
 
3967
- const pushToken = (segments, className, value) => {
3968
- if (!value) {
3969
- 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++;
3970
3379
  }
3971
- const lastSegment = segments.at(-1);
3972
- if (lastSegment && lastSegment.className === className) {
3973
- const merged = {
3974
- className,
3975
- value: lastSegment.value + value
3976
- };
3977
- 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
+ }
3978
3389
  }
3979
- return [...segments, {
3980
- className,
3981
- value
3982
- }];
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;
3983
3414
  };
3984
-
3985
- const numberRegex = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/;
3986
- const whitespaceRegex = /\s/u;
3987
- const getTokenSegments = json => {
3988
- let segments = [];
3415
+ const forEachTokenSegment = (json, onToken) => {
3989
3416
  let i = 0;
3990
3417
  while (i < json.length) {
3991
3418
  const character = json[i];
@@ -4004,40 +3431,38 @@ const getTokenSegments = json => {
4004
3431
  }
4005
3432
  i++;
4006
3433
  }
4007
- const tokenValue = json.slice(start, i);
4008
3434
  let lookAheadIndex = i;
4009
- while (lookAheadIndex < json.length && whitespaceRegex.test(json[lookAheadIndex])) {
3435
+ while (lookAheadIndex < json.length && isWhitespace(json[lookAheadIndex])) {
4010
3436
  lookAheadIndex++;
4011
3437
  }
4012
3438
  const className = json[lookAheadIndex] === ':' ? TokenKey : TokenString;
4013
- segments = pushToken(segments, className, tokenValue);
3439
+ onToken(className, json.slice(start, i));
4014
3440
  continue;
4015
3441
  }
4016
- const numberMatch = numberRegex.exec(json.slice(i));
4017
- if (numberMatch) {
4018
- segments = pushToken(segments, TokenNumeric, numberMatch[0]);
4019
- i += numberMatch[0].length;
3442
+ const numberEnd = getNumberEnd(json, i);
3443
+ if (numberEnd > i) {
3444
+ onToken(TokenNumeric, json.slice(i, numberEnd));
3445
+ i = numberEnd;
4020
3446
  continue;
4021
3447
  }
4022
3448
  if (json.startsWith('true', i)) {
4023
- segments = pushToken(segments, TokenBoolean, 'true');
3449
+ onToken(TokenBoolean, 'true');
4024
3450
  i += 4;
4025
3451
  continue;
4026
3452
  }
4027
3453
  if (json.startsWith('false', i)) {
4028
- segments = pushToken(segments, TokenBoolean, 'false');
3454
+ onToken(TokenBoolean, 'false');
4029
3455
  i += 5;
4030
3456
  continue;
4031
3457
  }
4032
3458
  if (json.startsWith('null', i)) {
4033
- segments = pushToken(segments, TokenBoolean, 'null');
3459
+ onToken(TokenBoolean, 'null');
4034
3460
  i += 4;
4035
3461
  continue;
4036
3462
  }
4037
- segments = pushToken(segments, TokenText, character);
3463
+ onToken(TokenText, character);
4038
3464
  i++;
4039
3465
  }
4040
- return segments;
4041
3466
  };
4042
3467
 
4043
3468
  const getJsonLines = value => {
@@ -4048,25 +3473,34 @@ const getJsonLines = value => {
4048
3473
  value: String(json)
4049
3474
  }]];
4050
3475
  }
4051
- const segments = getTokenSegments(json);
4052
3476
  const lines = [];
4053
3477
  let currentLine = [];
4054
- for (const segment of segments) {
4055
- const parts = segment.value.split('\n');
4056
- for (let i = 0; i < parts.length; i++) {
4057
- const part = parts[i];
4058
- if (part) {
4059
- currentLine.push({
4060
- className: segment.className,
4061
- value: part
4062
- });
4063
- }
4064
- 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));
4065
3497
  lines.push(currentLine);
4066
3498
  currentLine = [];
3499
+ start = i + 1;
4067
3500
  }
4068
3501
  }
4069
- }
3502
+ pushLineSegment(className, segmentValue.slice(start));
3503
+ });
4070
3504
  lines.push(currentLine);
4071
3505
  return lines;
4072
3506
  };
@@ -4125,6 +3559,33 @@ const hasOwn = (event, key) => {
4125
3559
  const isChatMessageUpdatedEvent = event => {
4126
3560
  return event.type === 'chat-message-updated';
4127
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
+ };
4128
3589
  const getPreviewName = event => {
4129
3590
  if (typeof event.name === 'string' && event.name) {
4130
3591
  return event.name;
@@ -4144,8 +3605,9 @@ const shouldIncludeArguments = (event, name) => {
4144
3605
  return true;
4145
3606
  };
4146
3607
  const getPreviewEvent = event => {
4147
- if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
4148
- return event.text;
3608
+ const previewMessageText = getPreviewMessageText(event);
3609
+ if (previewMessageText !== undefined) {
3610
+ return previewMessageText;
4149
3611
  }
4150
3612
  const name = getPreviewName(event);
4151
3613
  const previewEvent = {
@@ -4230,9 +3692,12 @@ const formatPercent = value => {
4230
3692
  return `${Number(value.toFixed(3))}%`;
4231
3693
  };
4232
3694
 
4233
- const getBucketUnitDom = unitCount => {
3695
+ const getBucketUnitDom = (unitCount, presetValue) => {
4234
3696
  if (unitCount === 0) {
4235
3697
  return [{
3698
+ ...(presetValue ? {
3699
+ 'data-value': presetValue
3700
+ } : {}),
4236
3701
  childCount: 0,
4237
3702
  className: joinClassNames(ChatDebugViewTimelineBucketUnit, ChatDebugViewTimelineBucketUnitEmpty),
4238
3703
  type: Div
@@ -4241,6 +3706,9 @@ const getBucketUnitDom = unitCount => {
4241
3706
  return Array.from({
4242
3707
  length: unitCount
4243
3708
  }).fill({
3709
+ ...(presetValue ? {
3710
+ 'data-value': presetValue
3711
+ } : {}),
4244
3712
  childCount: 0,
4245
3713
  className: ChatDebugViewTimelineBucketUnit,
4246
3714
  type: Div
@@ -4250,23 +3718,17 @@ const getBucketUnitDom = unitCount => {
4250
3718
  const getBucketDom = bucket => {
4251
3719
  const presetValue = `${formatTimelinePresetValue(bucket.startSeconds)}:${formatTimelinePresetValue(bucket.endSeconds)}`;
4252
3720
  return [{
4253
- childCount: 2,
3721
+ childCount: 1,
4254
3722
  className: joinClassNames(ChatDebugViewTimelineBucket, bucket.isSelected && ChatDebugViewTimelineBucketSelected),
4255
- type: Label
4256
- }, {
4257
- checked: false,
4258
- childCount: 0,
4259
- className: ChatDebugViewTimelinePresetInput,
4260
- inputType: 'radio',
4261
- name: TimelineRangePreset,
4262
- onChange: HandleTimelineRangePreset,
4263
- type: Input,
4264
- value: presetValue
3723
+ 'data-value': presetValue,
3724
+ onClick: HandleTimelineRangePreset,
3725
+ type: Div
4265
3726
  }, {
4266
3727
  childCount: bucket.unitCount === 0 ? 1 : bucket.unitCount,
4267
3728
  className: joinClassNames(ChatDebugViewTimelineBucketBar, bucket.isSelected && ChatDebugViewTimelineBucketBarSelected),
3729
+ 'data-value': presetValue,
4268
3730
  type: Div
4269
- }, ...getBucketUnitDom(bucket.unitCount)];
3731
+ }, ...getBucketUnitDom(bucket.unitCount, presetValue)];
4270
3732
  };
4271
3733
 
4272
3734
  const getEffectiveTimelineRange = (timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds) => {
@@ -4527,10 +3989,10 @@ const render2 = (uid, diffResult) => {
4527
3989
  const renderEventListeners = () => {
4528
3990
  return [{
4529
3991
  name: HandleEventRowClick,
4530
- params: ['handleEventRowClick', 'event.target.dataset.index', 'event.button']
3992
+ params: ['handleEventRowClick', 'event.target.dataset.index', Button]
4531
3993
  }, {
4532
3994
  name: HandleTableBodyContextMenu,
4533
- params: ['handleTableBodyContextMenu'],
3995
+ params: ['handleTableBodyContextMenu', ClientX, ClientY],
4534
3996
  preventDefault: true
4535
3997
  }, {
4536
3998
  name: HandleFilterInput,
@@ -4543,10 +4005,13 @@ const renderEventListeners = () => {
4543
4005
  params: ['handleDetailTab', TargetValue]
4544
4006
  }, {
4545
4007
  name: HandleTimelineRangePreset,
4546
- params: ['handleTimelineRangePreset', TargetValue]
4008
+ params: ['handleTimelineRangePreset', 'event.target.dataset.value']
4547
4009
  }, {
4548
4010
  name: HandleCloseDetails,
4549
4011
  params: ['handleCloseDetails']
4012
+ }, {
4013
+ name: HandleClickRefresh,
4014
+ params: ['handleClickRefresh']
4550
4015
  }, {
4551
4016
  name: HandleSashPointerDown,
4552
4017
  params: ['handleSashPointerDown', ClientX, ClientY],
@@ -4675,6 +4140,8 @@ const commandMap = {
4675
4140
  'ChatDebug.create': create,
4676
4141
  'ChatDebug.diff2': diff2,
4677
4142
  'ChatDebug.getCommandIds': getCommandIds,
4143
+ 'ChatDebug.getMenuIds': getMenuIds,
4144
+ 'ChatDebug.handleClickRefresh': wrapCommand(handleClickRefresh),
4678
4145
  'ChatDebug.handleCloseDetails': wrapCommand(handleCloseDetails),
4679
4146
  'ChatDebug.handleDetailsContextMenu': wrapCommand(handleDetailsContextMenu),
4680
4147
  'ChatDebug.handleDetailTab': wrapCommand(handleDetailTab),