agentgui 1.0.930 → 1.0.932
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/AGENTS.md +35 -12
- package/database.js +31 -2
- package/lib/http-handler.js +11 -25
- package/lib/routes-registry.js +4 -48
- package/lib/server-startup.js +3 -11
- package/lib/ws-setup.js +2 -1
- package/package.json +3 -3
- package/server.js +7 -1
- package/site/app/js/app.js +64 -68
- package/site/app/js/backend.js +1 -1
- package/static/lib/xstate.umd.min.js +1 -1
- package/lib/db-queries-chunks.js +0 -195
- package/lib/db-queries-chunks2.js +0 -82
- package/lib/db-queries-cleanup.js +0 -74
- package/lib/db-queries-del.js +0 -141
- package/lib/db-queries-events.js +0 -68
- package/lib/db-queries-import.js +0 -133
- package/lib/db-queries-messages.js +0 -102
- package/lib/db-queries-sessions.js +0 -112
- package/lib/db-queries-streams.js +0 -100
- package/lib/db-queries.js +0 -89
- package/lib/jsonl-parser.js +0 -190
- package/lib/jsonl-watcher.js +0 -64
- package/lib/routes-agent-actions.js +0 -61
- package/lib/routes-auth-config.js +0 -30
- package/lib/routes-conversations.js +0 -96
- package/lib/routes-debug.js +0 -119
- package/lib/routes-messages.js +0 -139
- package/lib/routes-runs.js +0 -156
- package/lib/routes-scripts.js +0 -135
- package/lib/routes-sessions.js +0 -144
- package/lib/routes-threads.js +0 -100
- package/lib/routes-util.js +0 -110
- package/lib/ws-handlers-conv.js +0 -138
- package/lib/ws-handlers-conv2.js +0 -169
- package/lib/ws-handlers-msg.js +0 -121
- package/lib/ws-handlers-queue.js +0 -56
- package/lib/ws-handlers-run.js +0 -182
- package/lib/ws-handlers-scripts.js +0 -66
- package/lib/ws-handlers-session.js +0 -105
- package/lib/ws-handlers-session2.js +0 -85
- package/lib/ws-legacy-handlers.js +0 -51
- package/static/app.js +0 -261
- package/static/css/app-shell.css +0 -419
- package/static/css/brand-bible.css +0 -591
- package/static/css/colors_and_type.css +0 -568
- package/static/css/gmail-skin.css +0 -663
- package/static/css/main.css +0 -4015
- package/static/css/tools-popup.css +0 -472
- package/static/index.html +0 -418
- package/static/js/agent-auth.js +0 -146
- package/static/js/app-shortcuts.js +0 -30
- package/static/js/audio-recorder-processor.js +0 -18
- package/static/js/client-agents.js +0 -155
- package/static/js/client-cache.js +0 -171
- package/static/js/client-conv.js +0 -198
- package/static/js/client-events.js +0 -164
- package/static/js/client-exec.js +0 -160
- package/static/js/client-helpers.js +0 -199
- package/static/js/client-load.js +0 -175
- package/static/js/client-render.js +0 -132
- package/static/js/client-scroll.js +0 -178
- package/static/js/client-status.js +0 -167
- package/static/js/client-streaming.js +0 -117
- package/static/js/client-streaming2.js +0 -116
- package/static/js/client-streaming3.js +0 -153
- package/static/js/client-streaming4.js +0 -194
- package/static/js/client-ui-controls.js +0 -170
- package/static/js/client-ui.js +0 -128
- package/static/js/client-ui2.js +0 -160
- package/static/js/client-url.js +0 -93
- package/static/js/client-utils.js +0 -174
- package/static/js/client-ws-msg.js +0 -88
- package/static/js/client-ws.js +0 -161
- package/static/js/client.js +0 -145
- package/static/js/codec.js +0 -4
- package/static/js/conv-list-machine.js +0 -145
- package/static/js/conv-list-renderer.js +0 -198
- package/static/js/conv-machine.js +0 -110
- package/static/js/conv-sidebar-actions.js +0 -188
- package/static/js/conv-sidebar-clone.js +0 -91
- package/static/js/conversations.js +0 -116
- package/static/js/dialogs-types.js +0 -111
- package/static/js/dialogs.js +0 -53
- package/static/js/event-filter-config.js +0 -36
- package/static/js/event-processor.js +0 -181
- package/static/js/features.js +0 -187
- package/static/js/image-loader-element.js +0 -76
- package/static/js/image-loader.js +0 -146
- package/static/js/prompt-machine.js +0 -108
- package/static/js/recording-machine.js +0 -49
- package/static/js/script-runner.js +0 -192
- package/static/js/state-barrier.js +0 -105
- package/static/js/streaming-renderer-dispatch.js +0 -144
- package/static/js/streaming-renderer-events.js +0 -163
- package/static/js/streaming-renderer-events2.js +0 -125
- package/static/js/streaming-renderer-params.js +0 -38
- package/static/js/streaming-renderer-render-misc.js +0 -107
- package/static/js/streaming-renderer-render.js +0 -181
- package/static/js/streaming-renderer-render2.js +0 -149
- package/static/js/streaming-renderer-render3.js +0 -142
- package/static/js/streaming-renderer-static.js +0 -181
- package/static/js/streaming-renderer-static2.js +0 -140
- package/static/js/streaming-renderer-stream.js +0 -170
- package/static/js/streaming-renderer-text.js +0 -185
- package/static/js/streaming-renderer-tools.js +0 -189
- package/static/js/streaming-renderer-tools2.js +0 -92
- package/static/js/streaming-renderer.js +0 -200
- package/static/js/syntax-highlighter-render.js +0 -72
- package/static/js/syntax-highlighter.js +0 -131
- package/static/js/terminal-machine.js +0 -51
- package/static/js/terminal.js +0 -178
- package/static/js/ui-components-rendering.js +0 -62
- package/static/js/ui-components.js +0 -88
- package/static/js/websocket-manager.js +0 -107
- package/static/js/ws-client.js +0 -87
- package/static/js/ws-core.js +0 -162
- package/static/js/ws-latency.js +0 -88
- package/static/js/ws-machine.js +0 -68
- package/static/lib/msgpackr.min.js +0 -2
- package/static/theme.js +0 -74
- package/static/vendor/highlight-js.css +0 -10
- package/static/vendor/highlight.min.js +0 -1244
- package/static/vendor/prism-dark.css +0 -129
- package/static/vendor/rippleui.css +0 -35
- package/static/vendor/xterm-addon-fit.min.js +0 -8
- package/static/vendor/xterm.css +0 -8
- package/static/vendor/xterm.min.js +0 -8
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
syncPromptState(conversationId) {
|
|
3
|
-
const conversation = this.state.currentConversation;
|
|
4
|
-
if (!conversation || conversation.id !== conversationId) return;
|
|
5
|
-
|
|
6
|
-
if (this.ui.messageInput) {
|
|
7
|
-
this.ui.messageInput.disabled = false;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
this.updateBusyPromptArea(conversationId);
|
|
11
|
-
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
updateBusyPromptArea(conversationId) {
|
|
15
|
-
if (this.state.currentConversation?.id !== conversationId) return;
|
|
16
|
-
const isStreaming = this._convIsStreaming(conversationId);
|
|
17
|
-
const isConnected = this.wsManager?.isConnected;
|
|
18
|
-
|
|
19
|
-
const injectBtn = document.getElementById('injectBtn');
|
|
20
|
-
const queueBtn = document.getElementById('queueBtn');
|
|
21
|
-
const stopBtn = document.getElementById('stopBtn');
|
|
22
|
-
|
|
23
|
-
[injectBtn, queueBtn, stopBtn].forEach(btn => {
|
|
24
|
-
if (!btn) return;
|
|
25
|
-
btn.classList.toggle('visible', isStreaming);
|
|
26
|
-
btn.disabled = !isConnected;
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
if (this.ui.sendButton) this.ui.sendButton.style.display = isStreaming ? 'none' : '';
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
removeScrollUpDetection() {
|
|
34
|
-
const scrollContainer = document.getElementById(this.config.scrollContainerId);
|
|
35
|
-
if (scrollContainer && this._scrollUpHandler) {
|
|
36
|
-
scrollContainer.removeEventListener('scroll', this._scrollUpHandler);
|
|
37
|
-
this._scrollUpHandler = null;
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
setupScrollUpDetection(conversationId) {
|
|
43
|
-
const scrollContainer = document.getElementById(this.config.scrollContainerId);
|
|
44
|
-
if (!scrollContainer) return;
|
|
45
|
-
|
|
46
|
-
if (!this._scrollDetectionState) this._scrollDetectionState = {};
|
|
47
|
-
|
|
48
|
-
const detectionState = {
|
|
49
|
-
isLoading: false,
|
|
50
|
-
oldestTimestamp: Date.now(),
|
|
51
|
-
oldestMessageId: null,
|
|
52
|
-
conversation: conversationId
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const handleScroll = async () => {
|
|
56
|
-
const scrollTop = scrollContainer.scrollTop;
|
|
57
|
-
const scrollHeight = scrollContainer.scrollHeight;
|
|
58
|
-
const clientHeight = scrollContainer.clientHeight;
|
|
59
|
-
const THRESHOLD = 300;
|
|
60
|
-
|
|
61
|
-
if (scrollTop < THRESHOLD && !detectionState.isLoading && scrollHeight > clientHeight) {
|
|
62
|
-
detectionState.isLoading = true;
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
const messagesEl = document.querySelector('.conversation-messages');
|
|
66
|
-
if (!messagesEl) {
|
|
67
|
-
detectionState.isLoading = false;
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const firstMessageEl = messagesEl.querySelector('.message[data-msg-id]');
|
|
72
|
-
if (!firstMessageEl) {
|
|
73
|
-
const firstChunkEl = messagesEl.querySelector('[data-chunk-created]');
|
|
74
|
-
if (firstChunkEl) {
|
|
75
|
-
detectionState.oldestTimestamp = parseInt(firstChunkEl.getAttribute('data-chunk-created')) || 0;
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
detectionState.oldestMessageId = firstMessageEl.getAttribute('data-msg-id');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
let result;
|
|
82
|
-
if (detectionState.oldestMessageId) {
|
|
83
|
-
try {
|
|
84
|
-
result = await window.wsClient.rpc('msg.ls.earlier', {
|
|
85
|
-
id: conversationId,
|
|
86
|
-
before: detectionState.oldestMessageId,
|
|
87
|
-
limit: 50
|
|
88
|
-
});
|
|
89
|
-
} catch (e) {
|
|
90
|
-
const base = window.__BASE_URL || '';
|
|
91
|
-
const r = await fetch(`${base}/api/conversations/${conversationId}/messages?limit=50`);
|
|
92
|
-
const d = await r.json();
|
|
93
|
-
result = { messages: d.messages || [] };
|
|
94
|
-
}
|
|
95
|
-
} else if (detectionState.oldestTimestamp > 0) {
|
|
96
|
-
try {
|
|
97
|
-
result = await window.wsClient.rpc('conv.chunks.earlier', {
|
|
98
|
-
id: conversationId,
|
|
99
|
-
before: detectionState.oldestTimestamp,
|
|
100
|
-
limit: 500
|
|
101
|
-
});
|
|
102
|
-
} catch (e) {
|
|
103
|
-
const base = window.__BASE_URL || '';
|
|
104
|
-
const r = await fetch(`${base}/api/conversations/${conversationId}/chunks`);
|
|
105
|
-
const d = await r.json();
|
|
106
|
-
result = { chunks: d.chunks || [] };
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (result && ((result.messages && result.messages.length > 0) || (result.chunks && result.chunks.length > 0))) {
|
|
111
|
-
const scrollHeightBefore = scrollContainer.scrollHeight;
|
|
112
|
-
const scrollTopBefore = scrollContainer.scrollTop;
|
|
113
|
-
const newContent = document.createDocumentFragment();
|
|
114
|
-
|
|
115
|
-
if (result.messages && result.messages.length > 0) {
|
|
116
|
-
result.messages.forEach(msg => {
|
|
117
|
-
const div = document.createElement('div');
|
|
118
|
-
div.className = `message message-${msg.role}`;
|
|
119
|
-
div.setAttribute('data-msg-id', msg.id);
|
|
120
|
-
div.innerHTML = `<div class="message-role">${msg.role.charAt(0).toUpperCase() + msg.role.slice(1)}</div>${this.renderMessageContent(msg.content)}<div class="message-timestamp">${new Date(msg.created_at).toLocaleString()}</div>`;
|
|
121
|
-
newContent.appendChild(div);
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (result.chunks && result.chunks.length > 0) {
|
|
126
|
-
result.chunks.forEach(chunk => {
|
|
127
|
-
const blockEl = this.renderer.renderBlock(chunk.data, {}, false);
|
|
128
|
-
if (blockEl) {
|
|
129
|
-
const wrapper = document.createElement('div');
|
|
130
|
-
wrapper.setAttribute('data-chunk-created', chunk.created_at);
|
|
131
|
-
wrapper.appendChild(blockEl);
|
|
132
|
-
newContent.appendChild(wrapper);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (messagesEl.firstChild) {
|
|
138
|
-
messagesEl.insertBefore(newContent, messagesEl.firstChild);
|
|
139
|
-
} else {
|
|
140
|
-
messagesEl.appendChild(newContent);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const scrollHeightAfter = scrollContainer.scrollHeight;
|
|
144
|
-
scrollContainer.scrollTop = scrollTopBefore + (scrollHeightAfter - scrollHeightBefore);
|
|
145
|
-
}
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.error('Failed to load earlier messages:', error);
|
|
148
|
-
} finally {
|
|
149
|
-
detectionState.isLoading = false;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
scrollContainer.removeEventListener('scroll', this._scrollUpHandler);
|
|
155
|
-
this._scrollUpHandler = handleScroll;
|
|
156
|
-
scrollContainer.addEventListener('scroll', this._scrollUpHandler, { passive: true });
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
renderMessagesFragment(messages) {
|
|
161
|
-
const frag = document.createDocumentFragment();
|
|
162
|
-
if (messages.length === 0) {
|
|
163
|
-
const p = document.createElement('p');
|
|
164
|
-
p.className = 'text-secondary';
|
|
165
|
-
p.textContent = 'No messages in this conversation yet';
|
|
166
|
-
frag.appendChild(p);
|
|
167
|
-
return frag;
|
|
168
|
-
}
|
|
169
|
-
for (const msg of messages) {
|
|
170
|
-
const div = document.createElement('div');
|
|
171
|
-
div.className = `message message-${msg.role}`;
|
|
172
|
-
div.innerHTML = `<div class="message-role">${msg.role.charAt(0).toUpperCase() + msg.role.slice(1)}</div>${this.renderMessageContent(msg.content)}<div class="message-timestamp">${new Date(msg.created_at).toLocaleString()}</div>`;
|
|
173
|
-
frag.appendChild(div);
|
|
174
|
-
}
|
|
175
|
-
return frag;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
});
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
_updateConnectionIndicator(quality) {
|
|
3
|
-
if (this._indicatorDebounce && !this._modelDownloadInProgress) return;
|
|
4
|
-
this._indicatorDebounce = true;
|
|
5
|
-
setTimeout(() => { this._indicatorDebounce = false; }, 1000);
|
|
6
|
-
|
|
7
|
-
let indicator = document.getElementById('connection-indicator');
|
|
8
|
-
if (!indicator) {
|
|
9
|
-
indicator = document.createElement('div');
|
|
10
|
-
indicator.id = 'connection-indicator';
|
|
11
|
-
indicator.className = 'connection-indicator';
|
|
12
|
-
indicator.innerHTML = '<span class="connection-dot"></span><span class="connection-label"></span>';
|
|
13
|
-
indicator.addEventListener('click', () => this._toggleConnectionTooltip());
|
|
14
|
-
const header = document.querySelector('.header-right') || document.querySelector('.app-header');
|
|
15
|
-
if (header) {
|
|
16
|
-
header.style.position = 'relative';
|
|
17
|
-
header.appendChild(indicator);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const dot = indicator.querySelector('.connection-dot');
|
|
22
|
-
const label = indicator.querySelector('.connection-label');
|
|
23
|
-
if (!dot || !label) return;
|
|
24
|
-
|
|
25
|
-
if (this._modelDownloadInProgress) {
|
|
26
|
-
dot.className = 'connection-dot downloading';
|
|
27
|
-
const progress = this._modelDownloadProgress;
|
|
28
|
-
if (progress && progress.totalBytes > 0) {
|
|
29
|
-
const pct = Math.round((progress.totalDownloaded / progress.totalBytes) * 100);
|
|
30
|
-
label.textContent = `Models ${pct}%`;
|
|
31
|
-
} else if (progress && progress.downloading) {
|
|
32
|
-
label.textContent = 'Downloading...';
|
|
33
|
-
} else {
|
|
34
|
-
label.textContent = 'Loading models...';
|
|
35
|
-
}
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
dot.className = 'connection-dot';
|
|
40
|
-
if (quality === 'disconnected' || quality === 'reconnecting') {
|
|
41
|
-
dot.classList.add(quality);
|
|
42
|
-
label.textContent = quality === 'reconnecting' ? 'Reconnecting...' : 'Disconnected';
|
|
43
|
-
} else {
|
|
44
|
-
dot.classList.add(quality);
|
|
45
|
-
const latency = this.wsManager?.latency;
|
|
46
|
-
label.textContent = latency?.avg > 0 ? Math.round(latency.avg) + 'ms' : '';
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
_handleModelDownloadProgress(progress) {
|
|
52
|
-
this._modelDownloadProgress = progress;
|
|
53
|
-
if (progress.status === 'failed' || progress.error) {
|
|
54
|
-
this._modelDownloadInProgress = false;
|
|
55
|
-
console.error('[Models] Download error:', progress.error || progress.status);
|
|
56
|
-
this._updateConnectionIndicator(this.wsManager?.latency?.quality || 'unknown');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
if (progress.done || progress.status === 'completed') {
|
|
60
|
-
this._modelDownloadInProgress = false;
|
|
61
|
-
this._dbg('[Models] Download complete');
|
|
62
|
-
this._updateConnectionIndicator(this.wsManager?.latency?.quality || 'unknown');
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (progress.started || progress.downloading || progress.status === 'downloading' || progress.status === 'connecting') {
|
|
66
|
-
this._modelDownloadInProgress = true;
|
|
67
|
-
this._updateConnectionIndicator(this.wsManager?.latency?.quality || 'unknown');
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
_handleTTSSetupProgress(data) {
|
|
73
|
-
if (data.step && data.status) {
|
|
74
|
-
this._dbg('[TTS Setup]', data.step, ':', data.status, data.message || '');
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
_toggleConnectionTooltip() {
|
|
80
|
-
let tooltip = document.getElementById('connection-tooltip');
|
|
81
|
-
if (tooltip) { tooltip.remove(); return; }
|
|
82
|
-
|
|
83
|
-
const indicator = document.getElementById('connection-indicator');
|
|
84
|
-
if (!indicator) return;
|
|
85
|
-
|
|
86
|
-
tooltip = document.createElement('div');
|
|
87
|
-
tooltip.id = 'connection-tooltip';
|
|
88
|
-
tooltip.className = 'connection-tooltip';
|
|
89
|
-
|
|
90
|
-
const latency = this.wsManager?.latency || {};
|
|
91
|
-
const stats = this.wsManager?.stats || {};
|
|
92
|
-
const state = this.wsManager?.connectionState || 'unknown';
|
|
93
|
-
|
|
94
|
-
tooltip.innerHTML = [
|
|
95
|
-
`<div>State: ${state}</div>`,
|
|
96
|
-
`<div>Latency: ${Math.round(latency.avg || 0)}ms</div>`,
|
|
97
|
-
`<div>Predicted: ${Math.round(latency.predicted || 0)}ms (Kalman)</div>`,
|
|
98
|
-
`<div>Trend: ${latency.trend || 'unknown'}</div>`,
|
|
99
|
-
`<div>Jitter: ${Math.round(latency.jitter || 0)}ms</div>`,
|
|
100
|
-
`<div>Quality: ${latency.quality || 'unknown'}</div>`,
|
|
101
|
-
`<div>Reconnects: ${stats.totalReconnects || 0}</div>`,
|
|
102
|
-
`<div>Uptime: ${stats.lastConnectedTime ? Math.round((Date.now() - stats.lastConnectedTime) / 1000) + 's' : 'N/A'}</div>`
|
|
103
|
-
].join('');
|
|
104
|
-
|
|
105
|
-
indicator.appendChild(tooltip);
|
|
106
|
-
setTimeout(() => { if (tooltip.parentNode) tooltip.remove(); }, 5000);
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
updateMetrics(metrics) {
|
|
111
|
-
const metricsDisplay = document.querySelector('[data-metrics]');
|
|
112
|
-
if (metricsDisplay && metrics) {
|
|
113
|
-
metricsDisplay.textContent = `Batches: ${metrics.totalBatches} | Events: ${metrics.totalEvents} | Avg render: ${metrics.avgRenderTime.toFixed(2)}ms`;
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
disableControls() {
|
|
119
|
-
if (this.ui.sendButton) this.ui.sendButton.disabled = true;
|
|
120
|
-
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'DISABLED' });
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
enableControls() {
|
|
125
|
-
if (this.ui.sendButton) {
|
|
126
|
-
this.ui.sendButton.disabled = !this.wsManager?.isConnected;
|
|
127
|
-
}
|
|
128
|
-
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
|
|
129
|
-
this.updateBusyPromptArea(this.state.currentConversation?.id);
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
toggleTheme() {
|
|
134
|
-
const isDark = document.documentElement.classList.toggle('dark');
|
|
135
|
-
localStorage.setItem('theme', isDark ? 'dark' : 'light');
|
|
136
|
-
},
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
async createNewConversation(workingDirectory, title) {
|
|
140
|
-
try {
|
|
141
|
-
const agentId = this.getEffectiveAgentId();
|
|
142
|
-
const model = this.ui.modelSelector?.value || null;
|
|
143
|
-
const convTitle = title || 'New Conversation';
|
|
144
|
-
const body = { agentId, title: convTitle };
|
|
145
|
-
if (workingDirectory) body.workingDirectory = workingDirectory;
|
|
146
|
-
if (model) body.model = model;
|
|
147
|
-
|
|
148
|
-
const { conversation } = await window.wsClient.rpc('conv.new', body);
|
|
149
|
-
|
|
150
|
-
await this.loadConversations();
|
|
151
|
-
|
|
152
|
-
if (window.conversationManager) {
|
|
153
|
-
await window.conversationManager.loadConversations();
|
|
154
|
-
window.conversationManager.select(conversation.id);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (this.ui.messageInput) {
|
|
158
|
-
this.ui.messageInput.value = '';
|
|
159
|
-
this.ui.messageInput.focus();
|
|
160
|
-
}
|
|
161
|
-
} catch (error) {
|
|
162
|
-
console.error('Failed to create new conversation:', error);
|
|
163
|
-
this.showError(`Failed to create conversation: ${error.message}`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
});
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
async handleStreamingStart(data) {
|
|
3
|
-
this._dbg('Streaming started:', data);
|
|
4
|
-
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'STREAMING', conversationId: data.conversationId });
|
|
5
|
-
this._clearThinkingCountdown();
|
|
6
|
-
if (this._lastSendTime > 0) {
|
|
7
|
-
const actual = Date.now() - this._lastSendTime;
|
|
8
|
-
const predicted = this.wsManager?.latency?.predicted || 0;
|
|
9
|
-
const serverTime = Math.max(500, actual - predicted);
|
|
10
|
-
this._serverProcessingEstimate = 0.7 * this._serverProcessingEstimate + 0.3 * serverTime;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (this.wsManager.isConnected) {
|
|
14
|
-
this.wsManager.subscribeToSession(data.sessionId);
|
|
15
|
-
if (!data.resumed) {
|
|
16
|
-
this.wsManager.sendMessage({ type: 'subscribe', conversationId: data.conversationId });
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (this.state.currentConversation?.id !== data.conversationId) {
|
|
21
|
-
this._dbg('Streaming started for non-active conversation:', data.conversationId);
|
|
22
|
-
this._setConvStreaming(data.conversationId, true, data.sessionId, data.agentId);
|
|
23
|
-
this._dbg('[SYNC] streaming_start - non-active conv:', { convId: data.conversationId, sessionId: data.sessionId, streamingCount: this.state.streamingConversations.size });
|
|
24
|
-
this.updateBusyPromptArea(data.conversationId);
|
|
25
|
-
this.emit('streaming:start', data);
|
|
26
|
-
|
|
27
|
-
if (!this.state.currentConversation && !this._isLoadingConversation) {
|
|
28
|
-
this._isLoadingConversation = true;
|
|
29
|
-
this.loadConversationMessages(data.conversationId).finally(() => {
|
|
30
|
-
this._isLoadingConversation = false;
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
this._setConvStreaming(data.conversationId, true, data.sessionId, data.agentId);
|
|
37
|
-
this.updateBusyPromptArea(data.conversationId);
|
|
38
|
-
this.state.currentSession = {
|
|
39
|
-
id: data.sessionId,
|
|
40
|
-
conversationId: data.conversationId,
|
|
41
|
-
agentId: data.agentId,
|
|
42
|
-
startTime: Date.now()
|
|
43
|
-
};
|
|
44
|
-
this.state.sessionEvents = [];
|
|
45
|
-
|
|
46
|
-
this.updateUrlForConversation(data.conversationId, data.sessionId);
|
|
47
|
-
|
|
48
|
-
if (this.wsManager.isConnected) {
|
|
49
|
-
this.wsManager.subscribeToSession(data.sessionId);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const outputEl = document.getElementById('output');
|
|
53
|
-
if (outputEl) {
|
|
54
|
-
let messagesEl = outputEl.querySelector('.conversation-messages');
|
|
55
|
-
if (!messagesEl) {
|
|
56
|
-
const conv = this.state.currentConversation;
|
|
57
|
-
const wdInfo = conv?.workingDirectory ? `${this.escapeHtml(conv.workingDirectory)}` : '';
|
|
58
|
-
const timestamp = new Date(conv?.created_at || Date.now()).toLocaleDateString();
|
|
59
|
-
const metaParts = [timestamp];
|
|
60
|
-
if (conv?.agentType || conv?.agentId) metaParts.push(this.escapeHtml(conv.agentType || conv.agentId));
|
|
61
|
-
if (conv?.messageCount > 0) metaParts.push(`${conv.messageCount} msgs`);
|
|
62
|
-
if (wdInfo) metaParts.push(wdInfo);
|
|
63
|
-
outputEl.innerHTML = `
|
|
64
|
-
<div class="conversation-header">
|
|
65
|
-
<h2>${this.escapeHtml(conv?.title || 'Conversation')}</h2>
|
|
66
|
-
<p class="text-secondary">${metaParts.join(' - ')}</p>
|
|
67
|
-
</div>
|
|
68
|
-
<div class="conversation-messages"></div>
|
|
69
|
-
`;
|
|
70
|
-
messagesEl = outputEl.querySelector('.conversation-messages');
|
|
71
|
-
}
|
|
72
|
-
let streamingDiv = document.getElementById(`streaming-${data.sessionId}`);
|
|
73
|
-
if (!streamingDiv) {
|
|
74
|
-
streamingDiv = document.createElement('div');
|
|
75
|
-
streamingDiv.className = 'message message-assistant streaming-message';
|
|
76
|
-
streamingDiv.id = `streaming-${data.sessionId}`;
|
|
77
|
-
streamingDiv.innerHTML = `
|
|
78
|
-
<div class="message-role">Assistant</div>
|
|
79
|
-
<div class="message-blocks streaming-blocks"></div>
|
|
80
|
-
<div class="streaming-indicator" style="display:flex;align-items:center;gap:0.5rem;padding:0.5rem 0;color:var(--color-text-secondary);font-size:0.875rem;">
|
|
81
|
-
<span class="animate-spin" style="display:inline-block;width:1rem;height:1rem;border:2px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;"></span>
|
|
82
|
-
<span class="streaming-indicator-label">Thinking...</span>
|
|
83
|
-
</div>
|
|
84
|
-
`;
|
|
85
|
-
messagesEl.appendChild(streamingDiv);
|
|
86
|
-
} else {
|
|
87
|
-
streamingDiv.classList.add('streaming-message');
|
|
88
|
-
streamingDiv.querySelectorAll('.streaming-indicator').forEach(ind => ind.remove());
|
|
89
|
-
const indDiv = document.createElement('div');
|
|
90
|
-
indDiv.className = 'streaming-indicator';
|
|
91
|
-
indDiv.style = 'display:flex;align-items:center;gap:0.5rem;padding:0.5rem 0;color:var(--color-text-secondary);font-size:0.875rem;';
|
|
92
|
-
indDiv.innerHTML = `<span class="animate-spin" style="display:inline-block;width:1rem;height:1rem;border:2px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;"></span><span class="streaming-indicator-label">Thinking...</span>`;
|
|
93
|
-
streamingDiv.appendChild(indDiv);
|
|
94
|
-
}
|
|
95
|
-
this.scrollToBottom(true);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
this._streamStartedAt = Date.now();
|
|
99
|
-
this._sessionCost = 0;
|
|
100
|
-
if (this._elapsedTimer) clearInterval(this._elapsedTimer);
|
|
101
|
-
this._elapsedTimer = setInterval(() => {
|
|
102
|
-
const label = streamingDiv?.querySelector('.streaming-indicator-label');
|
|
103
|
-
if (label) {
|
|
104
|
-
const sec = ((Date.now() - this._streamStartedAt) / 1000) | 0;
|
|
105
|
-
const time = sec < 60 ? sec + 's' : Math.floor(sec / 60) + 'm ' + (sec % 60) + 's';
|
|
106
|
-
label.textContent = this._sessionCost > 0 ? time + ' · $' + this._sessionCost.toFixed(4) : time;
|
|
107
|
-
}
|
|
108
|
-
}, 1000);
|
|
109
|
-
|
|
110
|
-
this._renderedSeqs[data.sessionId] = new Set();
|
|
111
|
-
|
|
112
|
-
this.showStreamingPromptButtons();
|
|
113
|
-
|
|
114
|
-
this.emit('streaming:start', data);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
});
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
async handleStreamingResumed(data) {
|
|
3
|
-
this._dbg('Streaming resumed:', data);
|
|
4
|
-
const conv = this.state.currentConversation || { id: data.conversationId };
|
|
5
|
-
await this.handleStreamingStart({
|
|
6
|
-
type: 'streaming_start',
|
|
7
|
-
sessionId: data.sessionId,
|
|
8
|
-
conversationId: data.conversationId,
|
|
9
|
-
agentId: conv.agentType || conv.agentId || 'claude-code',
|
|
10
|
-
resumed: true,
|
|
11
|
-
timestamp: data.timestamp
|
|
12
|
-
});
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
handleStreamingProgress(data) {
|
|
17
|
-
try { return this._handleStreamingProgressInner(data); } catch (e) { console.error('[render-error] streaming progress:', e); }
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
_handleStreamingProgressInner(data) {
|
|
21
|
-
if (!data.block || !data.sessionId) return;
|
|
22
|
-
|
|
23
|
-
const seen = this._renderedSeqs[data.sessionId] || (this._renderedSeqs[data.sessionId] = new Set());
|
|
24
|
-
if (data.seq !== undefined) {
|
|
25
|
-
if (seen.has(data.seq)) return;
|
|
26
|
-
seen.add(data.seq);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const block = data.block;
|
|
30
|
-
|
|
31
|
-
const convId = data.conversationId;
|
|
32
|
-
if (convId) {
|
|
33
|
-
let entry = this._bgCache.get(convId);
|
|
34
|
-
if (!entry) {
|
|
35
|
-
if (this._bgCache.size >= this.BG_CACHE_MAX) {
|
|
36
|
-
const oldestKey = this._bgCache.keys().next().value;
|
|
37
|
-
this._bgCache.delete(oldestKey);
|
|
38
|
-
}
|
|
39
|
-
entry = { items: [], seqSet: new Set(), sessionId: data.sessionId };
|
|
40
|
-
this._bgCache.set(convId, entry);
|
|
41
|
-
}
|
|
42
|
-
if (data.seq === undefined || !entry.seqSet.has(data.seq)) {
|
|
43
|
-
if (data.seq !== undefined) entry.seqSet.add(data.seq);
|
|
44
|
-
entry.sessionId = data.sessionId;
|
|
45
|
-
try {
|
|
46
|
-
const packed = typeof msgpackr !== 'undefined' ? msgpackr.pack(block) : block;
|
|
47
|
-
entry.items.push({ seq: data.seq, packed });
|
|
48
|
-
} catch (_) { entry.items.push({ seq: data.seq, packed: block }); }
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (this.state.currentSession?.id !== data.sessionId) return;
|
|
53
|
-
|
|
54
|
-
const streamingEl = document.getElementById(`streaming-${data.sessionId}`);
|
|
55
|
-
if (!streamingEl) return;
|
|
56
|
-
const blocksEl = streamingEl.querySelector('.streaming-blocks');
|
|
57
|
-
if (!blocksEl) return;
|
|
58
|
-
|
|
59
|
-
if (block.type === 'tool_result') {
|
|
60
|
-
const tid = block.tool_use_id;
|
|
61
|
-
const toolUseEl = (tid && blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${tid}"]`))
|
|
62
|
-
|| (blocksEl.lastElementChild?.classList?.contains('block-tool-use') ? blocksEl.lastElementChild : null);
|
|
63
|
-
if (toolUseEl) {
|
|
64
|
-
this.renderer.mergeResultIntoToolUse(toolUseEl, block);
|
|
65
|
-
this.scrollToBottom();
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (block.type === 'tool_status') {
|
|
71
|
-
const tid = block.tool_use_id;
|
|
72
|
-
const toolUseEl = tid && blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${tid}"]`);
|
|
73
|
-
if (toolUseEl) {
|
|
74
|
-
const summary = toolUseEl.querySelector(':scope > summary');
|
|
75
|
-
if (summary) {
|
|
76
|
-
let badge = summary.querySelector('.folded-tool-status-live');
|
|
77
|
-
if (!badge) { badge = document.createElement('span'); badge.className = 'folded-tool-status-live'; summary.appendChild(badge); }
|
|
78
|
-
const isRunning = block.status === 'in_progress';
|
|
79
|
-
badge.style.cssText = 'margin-left:auto;font-size:0.65rem;opacity:0.7;display:inline-flex;align-items:center;gap:0.25rem';
|
|
80
|
-
badge.innerHTML = (isRunning ? '<span class="animate-spin" style="display:inline-block;width:0.6rem;height:0.6rem;border:1.5px solid var(--color-border);border-top-color:var(--color-info);border-radius:50%"></span>' : '')
|
|
81
|
-
+ '<span>' + (isRunning ? 'Running' : (block.status || '')) + '</span>';
|
|
82
|
-
}
|
|
83
|
-
this.scrollToBottom();
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (block.type === 'hook_progress') {
|
|
89
|
-
const hookEvent = (block.hookEvent || '').split(':')[0];
|
|
90
|
-
if (hookEvent === 'PreToolUse' || hookEvent === 'PostToolUse') {
|
|
91
|
-
const lastTool = blocksEl.querySelector('.block-tool-use:last-of-type') || blocksEl.lastElementChild;
|
|
92
|
-
if (lastTool?.classList?.contains('block-tool-use')) {
|
|
93
|
-
const summary = lastTool.querySelector(':scope > summary');
|
|
94
|
-
if (summary) {
|
|
95
|
-
let hookBadge = summary.querySelector('.folded-tool-hook');
|
|
96
|
-
if (!hookBadge) { hookBadge = document.createElement('span'); hookBadge.className = 'folded-tool-hook'; hookBadge.style.cssText = 'margin-left:0.375rem;font-size:0.6rem;opacity:0.4;font-weight:400'; summary.appendChild(hookBadge); }
|
|
97
|
-
hookBadge.textContent = block.hookEvent?.split(':').pop() || hookEvent;
|
|
98
|
-
}
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (block.type === 'result' && block.total_cost_usd) {
|
|
106
|
-
this._sessionCost = (this._sessionCost || 0) + block.total_cost_usd;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const el = this.renderer.renderBlock(block, data, blocksEl);
|
|
110
|
-
if (el) {
|
|
111
|
-
blocksEl.appendChild(el);
|
|
112
|
-
this.scrollToBottom();
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
});
|