agentgui 1.0.545 → 1.0.547
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/package.json +1 -1
- package/static/js/client.js +99 -6
- package/static/js/features.js +2 -0
package/package.json
CHANGED
package/static/js/client.js
CHANGED
|
@@ -35,6 +35,16 @@ class AgentGUIClient {
|
|
|
35
35
|
this.conversationCache = new Map();
|
|
36
36
|
this.MAX_CACHE_SIZE = 10;
|
|
37
37
|
|
|
38
|
+
// Conversation list cache with TTL
|
|
39
|
+
this.conversationListCache = {
|
|
40
|
+
data: [],
|
|
41
|
+
timestamp: 0,
|
|
42
|
+
ttl: 30000 // 30 seconds
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Draft prompts per conversation
|
|
46
|
+
this.draftPrompts = new Map();
|
|
47
|
+
|
|
38
48
|
// Event handlers
|
|
39
49
|
this.eventHandlers = {};
|
|
40
50
|
|
|
@@ -155,12 +165,14 @@ class AgentGUIClient {
|
|
|
155
165
|
this.updateConnectionStatus('connected');
|
|
156
166
|
this._subscribeToConversationUpdates();
|
|
157
167
|
this._recoverMissedChunks();
|
|
168
|
+
this.updateSendButtonState();
|
|
158
169
|
this.emit('ws:connected');
|
|
159
170
|
});
|
|
160
171
|
|
|
161
172
|
this.wsManager.on('disconnected', () => {
|
|
162
173
|
console.log('WebSocket disconnected');
|
|
163
174
|
this.updateConnectionStatus('disconnected');
|
|
175
|
+
this.updateSendButtonState();
|
|
164
176
|
this.emit('ws:disconnected');
|
|
165
177
|
});
|
|
166
178
|
|
|
@@ -191,6 +203,21 @@ class AgentGUIClient {
|
|
|
191
203
|
if (dot) dot.classList.remove('degrading');
|
|
192
204
|
});
|
|
193
205
|
|
|
206
|
+
// Switch to idle view when selecting non-streaming conversation
|
|
207
|
+
window.addEventListener('conversation-selected', (e) => {
|
|
208
|
+
const convId = e.detail.conversationId;
|
|
209
|
+
// Save draft from previous conversation before switching
|
|
210
|
+
this.saveDraftPrompt();
|
|
211
|
+
|
|
212
|
+
const isStreaming = convId && this.state.streamingConversations.has(convId);
|
|
213
|
+
if (!isStreaming && window.switchView) {
|
|
214
|
+
window.switchView('chat');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Restore draft for new conversation after a tick
|
|
218
|
+
setTimeout(() => this.restoreDraftPrompt(convId), 0);
|
|
219
|
+
});
|
|
220
|
+
|
|
194
221
|
// Preserve controls state across tab switches
|
|
195
222
|
window.addEventListener('view-switched', (e) => {
|
|
196
223
|
const view = e.detail.view;
|
|
@@ -383,6 +410,19 @@ class AgentGUIClient {
|
|
|
383
410
|
this.ui.agentSelector = document.querySelector('[data-agent-selector]');
|
|
384
411
|
this.ui.modelSelector = document.querySelector('[data-model-selector]');
|
|
385
412
|
|
|
413
|
+
// Auto-save drafts on input
|
|
414
|
+
if (this.ui.messageInput) {
|
|
415
|
+
this.ui.messageInput.addEventListener('input', () => {
|
|
416
|
+
this.saveDraftPrompt();
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Restore draft when conversation loads
|
|
420
|
+
const currentConvId = this.state.currentConversation?.id;
|
|
421
|
+
if (currentConvId) {
|
|
422
|
+
this.restoreDraftPrompt(currentConvId);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
386
426
|
if (this.ui.cliSelector) {
|
|
387
427
|
this.ui.cliSelector.addEventListener('change', () => {
|
|
388
428
|
if (!this._agentLocked) {
|
|
@@ -2131,10 +2171,21 @@ class AgentGUIClient {
|
|
|
2131
2171
|
* Load conversations
|
|
2132
2172
|
*/
|
|
2133
2173
|
async loadConversations() {
|
|
2174
|
+
// Return cached conversations if still fresh
|
|
2175
|
+
const now = Date.now();
|
|
2176
|
+
if (this.conversationListCache.data.length > 0 &&
|
|
2177
|
+
(now - this.conversationListCache.timestamp) < this.conversationListCache.ttl) {
|
|
2178
|
+
this.state.conversations = this.conversationListCache.data;
|
|
2179
|
+
return this.conversationListCache.data;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2134
2182
|
return this._dedupedFetch('loadConversations', async () => {
|
|
2135
2183
|
try {
|
|
2136
2184
|
const { conversations } = await window.wsClient.rpc('conv.ls');
|
|
2137
2185
|
this.state.conversations = conversations;
|
|
2186
|
+
// Update cache
|
|
2187
|
+
this.conversationListCache.data = conversations;
|
|
2188
|
+
this.conversationListCache.timestamp = Date.now();
|
|
2138
2189
|
return conversations;
|
|
2139
2190
|
} catch (error) {
|
|
2140
2191
|
console.error('Failed to load conversations:', error);
|
|
@@ -2280,9 +2331,7 @@ class AgentGUIClient {
|
|
|
2280
2331
|
if (this.ui.messageInput) {
|
|
2281
2332
|
this.ui.messageInput.disabled = true;
|
|
2282
2333
|
}
|
|
2283
|
-
|
|
2284
|
-
this.ui.sendButton.disabled = true;
|
|
2285
|
-
}
|
|
2334
|
+
// Send button state managed by WebSocket connection, not streaming state
|
|
2286
2335
|
const injectBtn = document.getElementById('injectBtn');
|
|
2287
2336
|
const stopBtn = document.getElementById('stopBtn');
|
|
2288
2337
|
if (injectBtn) injectBtn.disabled = true;
|
|
@@ -2296,9 +2345,7 @@ class AgentGUIClient {
|
|
|
2296
2345
|
if (this.ui.messageInput) {
|
|
2297
2346
|
this.ui.messageInput.disabled = false;
|
|
2298
2347
|
}
|
|
2299
|
-
|
|
2300
|
-
this.ui.sendButton.disabled = false;
|
|
2301
|
-
}
|
|
2348
|
+
// Send button state managed by WebSocket connection, not streaming state
|
|
2302
2349
|
const injectBtn = document.getElementById('injectBtn');
|
|
2303
2350
|
const stopBtn = document.getElementById('stopBtn');
|
|
2304
2351
|
if (injectBtn) injectBtn.disabled = false;
|
|
@@ -2865,6 +2912,52 @@ class AgentGUIClient {
|
|
|
2865
2912
|
};
|
|
2866
2913
|
}
|
|
2867
2914
|
|
|
2915
|
+
/**
|
|
2916
|
+
* Save draft prompt for current conversation
|
|
2917
|
+
*/
|
|
2918
|
+
saveDraftPrompt() {
|
|
2919
|
+
const convId = this.state.currentConversation?.id;
|
|
2920
|
+
if (convId && this.ui.messageInput) {
|
|
2921
|
+
const draft = this.ui.messageInput.value;
|
|
2922
|
+
this.draftPrompts.set(convId, draft);
|
|
2923
|
+
if (draft) {
|
|
2924
|
+
localStorage.setItem(`draft-${convId}`, draft);
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
/**
|
|
2930
|
+
* Restore draft prompt for conversation
|
|
2931
|
+
*/
|
|
2932
|
+
restoreDraftPrompt(conversationId) {
|
|
2933
|
+
if (!this.ui.messageInput) return;
|
|
2934
|
+
|
|
2935
|
+
let draft = this.draftPrompts.get(conversationId) || '';
|
|
2936
|
+
if (!draft) {
|
|
2937
|
+
draft = localStorage.getItem(`draft-${conversationId}`) || '';
|
|
2938
|
+
if (draft) this.draftPrompts.set(conversationId, draft);
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
this.ui.messageInput.value = draft;
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
/**
|
|
2945
|
+
* Clear draft for conversation
|
|
2946
|
+
*/
|
|
2947
|
+
clearDraft(conversationId) {
|
|
2948
|
+
this.draftPrompts.delete(conversationId);
|
|
2949
|
+
localStorage.removeItem(`draft-${conversationId}`);
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
/**
|
|
2953
|
+
* Update send button state based on WebSocket connection
|
|
2954
|
+
*/
|
|
2955
|
+
updateSendButtonState() {
|
|
2956
|
+
if (this.ui.sendButton) {
|
|
2957
|
+
this.ui.sendButton.disabled = !this.wsManager.isConnected;
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2868
2961
|
/**
|
|
2869
2962
|
* Cleanup resources
|
|
2870
2963
|
*/
|