agentgui 1.0.814 → 1.0.816
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/CLAUDE.md +2 -1
- package/package.json +1 -1
- package/static/js/client.js +0 -272
- package/static/js/conv-machine.js +0 -3
- package/static/js/conversations.js +0 -5
- package/static/js/event-filter.js +0 -59
- package/static/js/image-loader.js +0 -35
- package/static/js/script-runner.js +0 -3
- package/static/js/state-barrier.js +0 -4
- package/static/js/streaming-renderer.js +0 -273
- package/static/js/syntax-highlighter.js +0 -55
- package/static/js/ui-components.js +0 -51
- package/static/js/websocket-manager.js +0 -7
- package/static/js/ws-client.js +0 -4
- package/static/js/ws-machine.js +0 -2
- package/static/theme.js +0 -8
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// Per-conversation UI state machine using XState v5
|
|
2
|
-
// Tracks IDLE -> STREAMING -> QUEUED states per conversation
|
|
3
1
|
|
|
4
2
|
const { createMachine: cmCreateMachine, createActor: cmCreateActor, assign: cmAssign } = XState;
|
|
5
3
|
|
|
@@ -91,7 +89,6 @@ function isStreaming(convId) {
|
|
|
91
89
|
return getState(convId) === 'streaming';
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
// isActive: streaming OR queued — use this to gate optimistic messages
|
|
95
92
|
function isActive(convId) {
|
|
96
93
|
const s = getState(convId);
|
|
97
94
|
return s === 'streaming' || s === 'queued';
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Event Filter & Search
|
|
3
|
-
* Provides event filtering, searching, and replay functionality
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
class EventFilter {
|
|
7
3
|
constructor(renderer) {
|
|
@@ -22,9 +18,6 @@ class EventFilter {
|
|
|
22
18
|
};
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
/**
|
|
26
|
-
* Store all events for filtering
|
|
27
|
-
*/
|
|
28
21
|
trackEvent(event) {
|
|
29
22
|
this.allEvents.push({
|
|
30
23
|
...event,
|
|
@@ -32,12 +25,10 @@ class EventFilter {
|
|
|
32
25
|
trackedAt: Date.now()
|
|
33
26
|
});
|
|
34
27
|
|
|
35
|
-
// Limit history
|
|
36
28
|
if (this.allEvents.length > 5000) {
|
|
37
29
|
this.allEvents.shift();
|
|
38
30
|
}
|
|
39
31
|
|
|
40
|
-
// Apply current filters
|
|
41
32
|
if (this.filterState.isActive) {
|
|
42
33
|
this.applyFilters();
|
|
43
34
|
}
|
|
@@ -45,17 +36,11 @@ class EventFilter {
|
|
|
45
36
|
return event;
|
|
46
37
|
}
|
|
47
38
|
|
|
48
|
-
/**
|
|
49
|
-
* Set event type filter
|
|
50
|
-
*/
|
|
51
39
|
setTypeFilter(types) {
|
|
52
40
|
this.filterState.types = new Set(types);
|
|
53
41
|
this.applyFilters();
|
|
54
42
|
}
|
|
55
43
|
|
|
56
|
-
/**
|
|
57
|
-
* Toggle event type in filter
|
|
58
|
-
*/
|
|
59
44
|
toggleType(type) {
|
|
60
45
|
if (this.filterState.types.has(type)) {
|
|
61
46
|
this.filterState.types.delete(type);
|
|
@@ -65,26 +50,17 @@ class EventFilter {
|
|
|
65
50
|
this.applyFilters();
|
|
66
51
|
}
|
|
67
52
|
|
|
68
|
-
/**
|
|
69
|
-
* Set search text
|
|
70
|
-
*/
|
|
71
53
|
setSearchText(text) {
|
|
72
54
|
this.filterState.searchText = text.toLowerCase();
|
|
73
55
|
this.applyFilters();
|
|
74
56
|
}
|
|
75
57
|
|
|
76
|
-
/**
|
|
77
|
-
* Set time range
|
|
78
|
-
*/
|
|
79
58
|
setTimeRange(startTime, endTime) {
|
|
80
59
|
this.filterState.startTime = startTime;
|
|
81
60
|
this.filterState.endTime = endTime;
|
|
82
61
|
this.applyFilters();
|
|
83
62
|
}
|
|
84
63
|
|
|
85
|
-
/**
|
|
86
|
-
* Apply all filters
|
|
87
|
-
*/
|
|
88
64
|
applyFilters() {
|
|
89
65
|
this.filterState.isActive =
|
|
90
66
|
this.filterState.types.size > 0 ||
|
|
@@ -98,12 +74,10 @@ class EventFilter {
|
|
|
98
74
|
}
|
|
99
75
|
|
|
100
76
|
this.filteredEvents = this.allEvents.filter(event => {
|
|
101
|
-
// Type filter
|
|
102
77
|
if (this.filterState.types.size > 0 && !this.filterState.types.has(event.type)) {
|
|
103
78
|
return false;
|
|
104
79
|
}
|
|
105
80
|
|
|
106
|
-
// Search filter
|
|
107
81
|
if (this.filterState.searchText.length > 0) {
|
|
108
82
|
const searchable = JSON.stringify(event).toLowerCase();
|
|
109
83
|
if (!searchable.includes(this.filterState.searchText)) {
|
|
@@ -111,7 +85,6 @@ class EventFilter {
|
|
|
111
85
|
}
|
|
112
86
|
}
|
|
113
87
|
|
|
114
|
-
// Time range filter
|
|
115
88
|
const eventTime = event.timestamp || event.trackedAt;
|
|
116
89
|
if (this.filterState.startTime && eventTime < this.filterState.startTime) {
|
|
117
90
|
return false;
|
|
@@ -126,9 +99,6 @@ class EventFilter {
|
|
|
126
99
|
return this.filteredEvents;
|
|
127
100
|
}
|
|
128
101
|
|
|
129
|
-
/**
|
|
130
|
-
* Search events by text
|
|
131
|
-
*/
|
|
132
102
|
search(query) {
|
|
133
103
|
const results = [];
|
|
134
104
|
const lowerQuery = query.toLowerCase();
|
|
@@ -149,9 +119,6 @@ class EventFilter {
|
|
|
149
119
|
return results.sort((a, b) => b.matchCount - a.matchCount);
|
|
150
120
|
}
|
|
151
121
|
|
|
152
|
-
/**
|
|
153
|
-
* Get event statistics
|
|
154
|
-
*/
|
|
155
122
|
getStats() {
|
|
156
123
|
const stats = {
|
|
157
124
|
total: this.allEvents.length,
|
|
@@ -164,10 +131,8 @@ class EventFilter {
|
|
|
164
131
|
};
|
|
165
132
|
|
|
166
133
|
for (const event of this.allEvents) {
|
|
167
|
-
// Count by type
|
|
168
134
|
stats.byType[event.type] = (stats.byType[event.type] || 0) + 1;
|
|
169
135
|
|
|
170
|
-
// Time stats
|
|
171
136
|
const time = event.timestamp || event.trackedAt;
|
|
172
137
|
if (!stats.byTime.oldest || time < stats.byTime.oldest) {
|
|
173
138
|
stats.byTime.oldest = time;
|
|
@@ -184,9 +149,6 @@ class EventFilter {
|
|
|
184
149
|
return stats;
|
|
185
150
|
}
|
|
186
151
|
|
|
187
|
-
/**
|
|
188
|
-
* Start event replay
|
|
189
|
-
*/
|
|
190
152
|
async startReplay(events = null, speed = 1) {
|
|
191
153
|
const replayEvents = events || this.filteredEvents;
|
|
192
154
|
if (replayEvents.length === 0) return;
|
|
@@ -195,13 +157,11 @@ class EventFilter {
|
|
|
195
157
|
this.replayState.currentIndex = 0;
|
|
196
158
|
this.replayState.speed = speed;
|
|
197
159
|
|
|
198
|
-
// Clear renderer
|
|
199
160
|
this.renderer.clear();
|
|
200
161
|
|
|
201
162
|
for (const event of replayEvents) {
|
|
202
163
|
if (!this.replayState.isReplaying) break;
|
|
203
164
|
|
|
204
|
-
// Estimate delay based on event timestamps
|
|
205
165
|
const delay = 100 / this.replayState.speed;
|
|
206
166
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
207
167
|
|
|
@@ -212,16 +172,10 @@ class EventFilter {
|
|
|
212
172
|
this.replayState.isReplaying = false;
|
|
213
173
|
}
|
|
214
174
|
|
|
215
|
-
/**
|
|
216
|
-
* Stop event replay
|
|
217
|
-
*/
|
|
218
175
|
stopReplay() {
|
|
219
176
|
this.replayState.isReplaying = false;
|
|
220
177
|
}
|
|
221
178
|
|
|
222
|
-
/**
|
|
223
|
-
* Get replay progress
|
|
224
|
-
*/
|
|
225
179
|
getReplayProgress() {
|
|
226
180
|
const total = this.filteredEvents.length;
|
|
227
181
|
const current = this.replayState.currentIndex;
|
|
@@ -233,9 +187,6 @@ class EventFilter {
|
|
|
233
187
|
};
|
|
234
188
|
}
|
|
235
189
|
|
|
236
|
-
/**
|
|
237
|
-
* Export filtered events
|
|
238
|
-
*/
|
|
239
190
|
export(format = 'json') {
|
|
240
191
|
const events = this.filterState.isActive ? this.filteredEvents : this.allEvents;
|
|
241
192
|
|
|
@@ -254,9 +205,6 @@ class EventFilter {
|
|
|
254
205
|
}
|
|
255
206
|
}
|
|
256
207
|
|
|
257
|
-
/**
|
|
258
|
-
* Export as CSV
|
|
259
|
-
*/
|
|
260
208
|
exportAsCSV(events) {
|
|
261
209
|
const headers = ['timestamp', 'type', 'id', 'sessionId', 'message'];
|
|
262
210
|
const rows = [headers.join(',')];
|
|
@@ -275,9 +223,6 @@ class EventFilter {
|
|
|
275
223
|
return rows.join('\n');
|
|
276
224
|
}
|
|
277
225
|
|
|
278
|
-
/**
|
|
279
|
-
* Export as Markdown
|
|
280
|
-
*/
|
|
281
226
|
exportAsMarkdown(events) {
|
|
282
227
|
const lines = ['# Event Export\n'];
|
|
283
228
|
let currentType = null;
|
|
@@ -295,9 +240,6 @@ class EventFilter {
|
|
|
295
240
|
return lines.join('\n');
|
|
296
241
|
}
|
|
297
242
|
|
|
298
|
-
/**
|
|
299
|
-
* Clear history
|
|
300
|
-
*/
|
|
301
243
|
clear() {
|
|
302
244
|
this.allEvents = [];
|
|
303
245
|
this.filteredEvents = [];
|
|
@@ -305,7 +247,6 @@ class EventFilter {
|
|
|
305
247
|
}
|
|
306
248
|
}
|
|
307
249
|
|
|
308
|
-
// Export for use in browser
|
|
309
250
|
if (typeof module !== 'undefined' && module.exports) {
|
|
310
251
|
module.exports = EventFilter;
|
|
311
252
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Image Loader Module
|
|
3
|
-
* Detects image file reads from agent events and manages lazy loading
|
|
4
|
-
* Supports PNG, JPG, JPEG, GIF, WebP, SVG formats
|
|
5
|
-
*/
|
|
6
1
|
|
|
7
2
|
class ImageLoader {
|
|
8
3
|
constructor(config = {}) {
|
|
@@ -20,26 +15,17 @@ class ImageLoader {
|
|
|
20
15
|
this.initIntersectionObserver();
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
/**
|
|
24
|
-
* Check if a path is an image file
|
|
25
|
-
*/
|
|
26
18
|
isImagePath(filePath) {
|
|
27
19
|
if (!filePath || typeof filePath !== 'string') return false;
|
|
28
20
|
const ext = this.getExtension(filePath).toLowerCase();
|
|
29
21
|
return this.config.supportedExts.includes(ext);
|
|
30
22
|
}
|
|
31
23
|
|
|
32
|
-
/**
|
|
33
|
-
* Extract file extension from path
|
|
34
|
-
*/
|
|
35
24
|
getExtension(filePath) {
|
|
36
25
|
const match = filePath.match(/\.([^.]+)$/);
|
|
37
26
|
return match ? match[1] : '';
|
|
38
27
|
}
|
|
39
28
|
|
|
40
|
-
/**
|
|
41
|
-
* Extract image paths from text content
|
|
42
|
-
*/
|
|
43
29
|
extractImagePaths(content) {
|
|
44
30
|
if (typeof content !== 'string') return [];
|
|
45
31
|
|
|
@@ -56,9 +42,6 @@ class ImageLoader {
|
|
|
56
42
|
return [...new Set(paths)];
|
|
57
43
|
}
|
|
58
44
|
|
|
59
|
-
/**
|
|
60
|
-
* Register images from event
|
|
61
|
-
*/
|
|
62
45
|
registerImagesFromEvent(event) {
|
|
63
46
|
const images = [];
|
|
64
47
|
|
|
@@ -106,9 +89,6 @@ class ImageLoader {
|
|
|
106
89
|
return images;
|
|
107
90
|
}
|
|
108
91
|
|
|
109
|
-
/**
|
|
110
|
-
* Create image element with lazy loading
|
|
111
|
-
*/
|
|
112
92
|
createImageElement(imagePath, options = {}) {
|
|
113
93
|
const container = document.createElement('div');
|
|
114
94
|
container.className = 'image-container';
|
|
@@ -183,9 +163,6 @@ class ImageLoader {
|
|
|
183
163
|
return container;
|
|
184
164
|
}
|
|
185
165
|
|
|
186
|
-
/**
|
|
187
|
-
* Initialize Intersection Observer for lazy loading
|
|
188
|
-
*/
|
|
189
166
|
initIntersectionObserver() {
|
|
190
167
|
this.intersectionObserver = new IntersectionObserver(
|
|
191
168
|
(entries) => {
|
|
@@ -203,9 +180,6 @@ class ImageLoader {
|
|
|
203
180
|
);
|
|
204
181
|
}
|
|
205
182
|
|
|
206
|
-
/**
|
|
207
|
-
* Setup drawer observer to load images when drawer opens
|
|
208
|
-
*/
|
|
209
183
|
setupDrawerObserver(drawerSelector = '.drawer-panel, [role="dialog"]') {
|
|
210
184
|
const drawers = document.querySelectorAll(drawerSelector);
|
|
211
185
|
drawers.forEach(drawer => {
|
|
@@ -219,9 +193,6 @@ class ImageLoader {
|
|
|
219
193
|
});
|
|
220
194
|
}
|
|
221
195
|
|
|
222
|
-
/**
|
|
223
|
-
* Load all visible images in a container
|
|
224
|
-
*/
|
|
225
196
|
loadVisibleImages(container = document) {
|
|
226
197
|
const images = container.querySelectorAll('img.lazy-image[data-src]');
|
|
227
198
|
images.forEach(img => {
|
|
@@ -231,9 +202,6 @@ class ImageLoader {
|
|
|
231
202
|
});
|
|
232
203
|
}
|
|
233
204
|
|
|
234
|
-
/**
|
|
235
|
-
* Get cached images for a session/conversation
|
|
236
|
-
*/
|
|
237
205
|
getImages(eventId = null) {
|
|
238
206
|
if (!eventId) {
|
|
239
207
|
return Array.from(this.imageCache.values());
|
|
@@ -241,9 +209,6 @@ class ImageLoader {
|
|
|
241
209
|
return Array.from(this.imageCache.values()).filter(img => img.eventId === eventId);
|
|
242
210
|
}
|
|
243
211
|
|
|
244
|
-
/**
|
|
245
|
-
* Clear cache
|
|
246
|
-
*/
|
|
247
212
|
clear() {
|
|
248
213
|
this.imageCache.clear();
|
|
249
214
|
this.pendingImages.clear();
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
window.addEventListener('conversation-selected', function(e) {
|
|
14
14
|
currentConversationId = e.detail.conversationId;
|
|
15
15
|
hasTerminalContent = false;
|
|
16
|
-
// Do not hide terminal tab; it should always be visible
|
|
17
16
|
fetchConversationAndCheckScripts();
|
|
18
17
|
});
|
|
19
18
|
|
|
@@ -61,12 +60,10 @@
|
|
|
61
60
|
window.wsClient.rpc('conv.get', { id: currentConversationId })
|
|
62
61
|
.then(function(data) {
|
|
63
62
|
currentWorkingDirectory = data.conversation?.workingDirectory || null;
|
|
64
|
-
// Always show the terminal tab, even without a working directory
|
|
65
63
|
showTerminalTab();
|
|
66
64
|
checkScripts();
|
|
67
65
|
})
|
|
68
66
|
.catch(function() {
|
|
69
|
-
// Still show terminal tab on error
|
|
70
67
|
showTerminalTab();
|
|
71
68
|
checkScripts();
|
|
72
69
|
});
|