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,153 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
renderBlockContent(block) {
|
|
3
|
-
if (block.type === 'text' && block.text) {
|
|
4
|
-
const text = block.text;
|
|
5
|
-
if (this.isHtmlContent(text)) {
|
|
6
|
-
return `<div class="html-content">${this.sanitizeHtml(text)}</div>`;
|
|
7
|
-
}
|
|
8
|
-
const parts = this.parseMarkdownCodeBlocks(text);
|
|
9
|
-
if (parts.length === 1 && parts[0].type === 'text') {
|
|
10
|
-
return this.escapeHtml(text);
|
|
11
|
-
}
|
|
12
|
-
return parts.map(part => {
|
|
13
|
-
if (part.type === 'html') {
|
|
14
|
-
return `<div class="html-content">${this.sanitizeHtml(part.content)}</div>`;
|
|
15
|
-
} else if (part.type === 'code') {
|
|
16
|
-
return this.renderCodeBlock(part.language, part.code);
|
|
17
|
-
}
|
|
18
|
-
return this.escapeHtml(part.content);
|
|
19
|
-
}).join('');
|
|
20
|
-
}
|
|
21
|
-
const fieldsHtml = Object.entries(block)
|
|
22
|
-
.filter(([key]) => key !== 'type')
|
|
23
|
-
.map(([key, value]) => {
|
|
24
|
-
let displayValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
25
|
-
if (displayValue.length > 100) displayValue = displayValue.substring(0, 100) + '...';
|
|
26
|
-
return `<div style="font-size:0.75rem;margin-bottom:0.25rem"><span style="font-weight:600">${this.escapeHtml(key)}:</span> <code>${this.escapeHtml(displayValue)}</code></div>`;
|
|
27
|
-
}).join('');
|
|
28
|
-
return `<div style="padding:0.5rem;background:var(--color-bg-secondary);border-radius:0.375rem;border:1px solid var(--color-border)"><div style="font-size:0.7rem;font-weight:600;text-transform:uppercase;margin-bottom:0.25rem">${this.escapeHtml(block.type)}</div>${fieldsHtml}</div>`;
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
scrollToBottom(force = false) {
|
|
33
|
-
const scrollContainer = document.getElementById('output-scroll');
|
|
34
|
-
if (!scrollContainer) return;
|
|
35
|
-
const distFromBottom = scrollContainer.scrollHeight - scrollContainer.scrollTop - scrollContainer.clientHeight;
|
|
36
|
-
|
|
37
|
-
if (this._userScrolledUp && !force) {
|
|
38
|
-
this._unseenCount = (this._unseenCount || 0) + 1;
|
|
39
|
-
this._showNewContentPill();
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (!force && distFromBottom > 150) {
|
|
44
|
-
this._unseenCount = (this._unseenCount || 0) + 1;
|
|
45
|
-
this._showNewContentPill();
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
50
|
-
this._removeNewContentPill();
|
|
51
|
-
this._scrollAnimating = false;
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
_showNewContentPill() {
|
|
56
|
-
let pill = document.getElementById('new-content-pill');
|
|
57
|
-
const scrollContainer = document.getElementById('output-scroll');
|
|
58
|
-
if (!scrollContainer) return;
|
|
59
|
-
if (!pill) {
|
|
60
|
-
pill = document.createElement('button');
|
|
61
|
-
pill.id = 'new-content-pill';
|
|
62
|
-
pill.className = 'new-content-pill';
|
|
63
|
-
pill.addEventListener('click', () => {
|
|
64
|
-
scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
65
|
-
this._removeNewContentPill();
|
|
66
|
-
});
|
|
67
|
-
scrollContainer.appendChild(pill);
|
|
68
|
-
}
|
|
69
|
-
pill.textContent = (this._unseenCount || 1) + ' new';
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
_removeNewContentPill() {
|
|
74
|
-
this._unseenCount = 0;
|
|
75
|
-
const pill = document.getElementById('new-content-pill');
|
|
76
|
-
if (pill) pill.remove();
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
handleStreamingError(data) {
|
|
81
|
-
console.error('Streaming error:', data);
|
|
82
|
-
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
|
|
83
|
-
this._clearThinkingCountdown();
|
|
84
|
-
if (this._elapsedTimer) { clearInterval(this._elapsedTimer); this._elapsedTimer = null; }
|
|
85
|
-
|
|
86
|
-
if (this.ui.stopButton) this.ui.stopButton.classList.remove('visible');
|
|
87
|
-
if (this.ui.injectButton) this.ui.injectButton.classList.remove('visible');
|
|
88
|
-
if (this.ui.sendButton) this.ui.sendButton.style.display = '';
|
|
89
|
-
|
|
90
|
-
const conversationId = data.conversationId || this.state.currentSession?.conversationId;
|
|
91
|
-
|
|
92
|
-
if (conversationId && this.state.currentConversation?.id !== conversationId) {
|
|
93
|
-
this._dbg('Streaming error for non-active conversation:', conversationId);
|
|
94
|
-
this._setConvStreaming(conversationId, false);
|
|
95
|
-
this.updateBusyPromptArea(conversationId);
|
|
96
|
-
this.emit('streaming:error', data);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
this._setConvStreaming(conversationId, false);
|
|
101
|
-
this.updateBusyPromptArea(conversationId);
|
|
102
|
-
|
|
103
|
-
const queueEl = document.querySelector('.queue-indicator');
|
|
104
|
-
if (queueEl) queueEl.remove();
|
|
105
|
-
|
|
106
|
-
if (data.isPrematureEnd) {
|
|
107
|
-
this.renderer.queueEvent({
|
|
108
|
-
type: 'streaming_error',
|
|
109
|
-
isPrematureEnd: true,
|
|
110
|
-
exitCode: data.exitCode,
|
|
111
|
-
error: data.error,
|
|
112
|
-
stderrText: data.stderrText,
|
|
113
|
-
sessionId: data.sessionId,
|
|
114
|
-
conversationId: data.conversationId,
|
|
115
|
-
timestamp: data.timestamp || Date.now()
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const sessionId = data.sessionId || this.state.currentSession?.id;
|
|
120
|
-
|
|
121
|
-
const outputEl2 = document.getElementById('output');
|
|
122
|
-
if (outputEl2) {
|
|
123
|
-
outputEl2.querySelectorAll('.streaming-indicator').forEach(ind => {
|
|
124
|
-
ind.innerHTML = `<span style="color:var(--color-error);">Error: ${this.escapeHtml(data.error || 'Unknown error')}</span>`;
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const streamingEl = document.getElementById(`streaming-${sessionId}`);
|
|
129
|
-
if (streamingEl) {
|
|
130
|
-
streamingEl.classList.remove('streaming-message');
|
|
131
|
-
const indicator = streamingEl.querySelector('.streaming-indicator');
|
|
132
|
-
if (indicator) {
|
|
133
|
-
indicator.innerHTML = `<span style="color:var(--color-error);">Error: ${this.escapeHtml(data.error || 'Unknown error')}</span>`;
|
|
134
|
-
}
|
|
135
|
-
streamingEl.querySelectorAll('.block-thinking').forEach(block => block.remove());
|
|
136
|
-
} else {
|
|
137
|
-
const outputEl3 = document.getElementById('output');
|
|
138
|
-
const messagesEl3 = outputEl3 && outputEl3.querySelector('.conversation-messages');
|
|
139
|
-
if (messagesEl3 && data.error) {
|
|
140
|
-
const errDiv = document.createElement('div');
|
|
141
|
-
errDiv.className = 'message';
|
|
142
|
-
errDiv.style = 'padding:0.75rem;border:1px solid var(--color-error, #e53e3e);border-radius:4px;margin:0.5rem 0;';
|
|
143
|
-
errDiv.innerHTML = `<span style="color:var(--color-error, #e53e3e);">Error: ${this.escapeHtml(data.error)}</span>`;
|
|
144
|
-
messagesEl3.appendChild(errDiv);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
this.unlockAgentAndModel();
|
|
149
|
-
this.enableControls();
|
|
150
|
-
this.emit('streaming:error', data);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
});
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
handleStreamingComplete(data) {
|
|
3
|
-
this._dbg('Streaming completed:', data);
|
|
4
|
-
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
|
|
5
|
-
this._clearThinkingCountdown();
|
|
6
|
-
if (this._elapsedTimer) { clearInterval(this._elapsedTimer); this._elapsedTimer = null; }
|
|
7
|
-
|
|
8
|
-
const conversationId = data.conversationId || this.state.currentSession?.conversationId;
|
|
9
|
-
if (conversationId) this.invalidateCache(conversationId);
|
|
10
|
-
|
|
11
|
-
if (conversationId && this.state.currentConversation?.id !== conversationId) {
|
|
12
|
-
this._dbg('Streaming completed for non-active conversation:', conversationId);
|
|
13
|
-
this._setConvStreaming(conversationId, false);
|
|
14
|
-
this._dbg('[SYNC] streaming_complete - non-active conv:', { convId: conversationId, streamingCount: this.state.streamingConversations.size });
|
|
15
|
-
this.updateBusyPromptArea(conversationId);
|
|
16
|
-
this.emit('streaming:complete', data);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
this._setConvStreaming(conversationId, false);
|
|
21
|
-
this._dbg('[SYNC] streaming_complete - active conv:', { convId: conversationId, streamingCount: this.state.streamingConversations.size, interrupted: data.interrupted });
|
|
22
|
-
this.updateBusyPromptArea(conversationId);
|
|
23
|
-
|
|
24
|
-
const sessionId = data.sessionId || this.state.currentSession?.id;
|
|
25
|
-
|
|
26
|
-
if (sessionId && this.wsManager) {
|
|
27
|
-
try {
|
|
28
|
-
this.wsManager.unsubscribeFromSession(sessionId);
|
|
29
|
-
} catch (e) {
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const queueEl = document.querySelector('.queue-indicator');
|
|
34
|
-
if (queueEl) queueEl.remove();
|
|
35
|
-
|
|
36
|
-
const outputEl2 = document.getElementById('output');
|
|
37
|
-
if (outputEl2) {
|
|
38
|
-
outputEl2.querySelectorAll('.streaming-indicator').forEach(ind => ind.remove());
|
|
39
|
-
outputEl2.querySelectorAll('.event-streaming-start, .event-streaming-complete').forEach(block => block.remove());
|
|
40
|
-
}
|
|
41
|
-
const streamingEl = document.getElementById(`streaming-${sessionId}`);
|
|
42
|
-
if (streamingEl) {
|
|
43
|
-
streamingEl.classList.remove('streaming-message');
|
|
44
|
-
const prevTextEl = streamingEl.querySelector('.streaming-text-current');
|
|
45
|
-
if (prevTextEl) prevTextEl.classList.remove('streaming-text-current');
|
|
46
|
-
|
|
47
|
-
streamingEl.querySelectorAll('.block-thinking').forEach(block => block.remove());
|
|
48
|
-
|
|
49
|
-
const ts = document.createElement('div');
|
|
50
|
-
ts.className = 'message-timestamp';
|
|
51
|
-
ts.textContent = new Date().toLocaleString();
|
|
52
|
-
streamingEl.appendChild(ts);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (conversationId) {
|
|
56
|
-
this.saveScrollPosition(conversationId);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
this._recoverMissedChunks().catch(err => {
|
|
60
|
-
console.warn('Chunk recovery failed:', err.message);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
this.enableControls();
|
|
64
|
-
this.emit('streaming:complete', data);
|
|
65
|
-
|
|
66
|
-
this._promptPushIfWeOwnRemote();
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
async _promptPushIfWeOwnRemote() {
|
|
71
|
-
try {
|
|
72
|
-
const { ownsRemote, hasChanges, hasUnpushed, remoteUrl } = await window.wsClient.rpc('git.check');
|
|
73
|
-
if (ownsRemote && (hasChanges || hasUnpushed)) {
|
|
74
|
-
const conv = this.state.currentConversation;
|
|
75
|
-
if (conv) {
|
|
76
|
-
this.streamToConversation(conv.id, 'Push the changes to the remote repository.', conv.agentId);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
} catch (e) {
|
|
80
|
-
console.warn('Auto-push check failed:', e);
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
handleConversationCreated(data) {
|
|
86
|
-
if (data.conversation) {
|
|
87
|
-
if (this.state.conversations.some(c => c.id === data.conversation.id)) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
this.state.conversations.push(data.conversation);
|
|
91
|
-
this.emit('conversation:created', data.conversation);
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
handleMessageCreated(data) {
|
|
97
|
-
if (data.conversationId !== this.state.currentConversation?.id || !data.message) {
|
|
98
|
-
this.emit('message:created', data);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this._dbg('[SYNC] message_created:', { msgId: data.message.id, role: data.message.role, convId: data.conversationId });
|
|
103
|
-
|
|
104
|
-
if (data.message.role === 'user' && this.state.currentConversation) {
|
|
105
|
-
this.state.currentConversation.messageCount = (this.state.currentConversation.messageCount || 0) + 1;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (data.message.role === 'assistant' && this._convIsStreaming(data.conversationId)) {
|
|
109
|
-
this.emit('message:created', data);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const outputEl = document.querySelector('.conversation-messages');
|
|
114
|
-
if (!outputEl) {
|
|
115
|
-
this.emit('message:created', data);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (data.message.role === 'user') {
|
|
120
|
-
const pending = outputEl.querySelector('.message-sending');
|
|
121
|
-
if (pending) {
|
|
122
|
-
pending.id = '';
|
|
123
|
-
pending.setAttribute('data-msg-id', data.message.id);
|
|
124
|
-
pending.classList.remove('message-sending');
|
|
125
|
-
const ts = pending.querySelector('.message-timestamp');
|
|
126
|
-
if (ts) {
|
|
127
|
-
ts.style.opacity = '1';
|
|
128
|
-
ts.textContent = new Date(data.message.created_at).toLocaleString();
|
|
129
|
-
}
|
|
130
|
-
this.emit('message:created', data);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
const pendingById = outputEl.querySelector('[id^="pending-"]');
|
|
134
|
-
if (pendingById) {
|
|
135
|
-
pendingById.id = '';
|
|
136
|
-
pendingById.setAttribute('data-msg-id', data.message.id);
|
|
137
|
-
const ts = pendingById.querySelector('.message-timestamp');
|
|
138
|
-
if (ts) {
|
|
139
|
-
ts.style.opacity = '1';
|
|
140
|
-
ts.textContent = new Date(data.message.created_at).toLocaleString();
|
|
141
|
-
}
|
|
142
|
-
this.emit('message:created', data);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
const existingMsg = outputEl.querySelector(`[data-msg-id="${data.message.id}"]`);
|
|
146
|
-
if (existingMsg) {
|
|
147
|
-
this.emit('message:created', data);
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
outputEl.querySelectorAll('p.text-secondary').forEach(p => p.remove());
|
|
153
|
-
const safeRole = this.escapeHtml(data.message.role || 'user');
|
|
154
|
-
const safeId = this.escapeHtml(data.message.id || '');
|
|
155
|
-
const messageHtml = `
|
|
156
|
-
<div class="message message-${safeRole}" data-msg-id="${safeId}">
|
|
157
|
-
<div class="message-role">${safeRole.charAt(0).toUpperCase() + safeRole.slice(1)}</div>
|
|
158
|
-
${this.renderMessageContent(data.message.content)}
|
|
159
|
-
<div class="message-timestamp">${new Date(data.message.created_at).toLocaleString()}</div>
|
|
160
|
-
</div>
|
|
161
|
-
`;
|
|
162
|
-
outputEl.insertAdjacentHTML('beforeend', messageHtml);
|
|
163
|
-
this.scrollToBottom();
|
|
164
|
-
this.emit('message:created', data);
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
handleConversationUpdated(data) {
|
|
169
|
-
if (data.conversation && data.conversation.id === this.state.currentConversation?.id) {
|
|
170
|
-
this.state.currentConversation = data.conversation;
|
|
171
|
-
}
|
|
172
|
-
this.emit('conversation:updated', data);
|
|
173
|
-
},
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
handleQueueStatus(data) {
|
|
177
|
-
if (typeof convMachineAPI !== 'undefined') convMachineAPI.send(data.conversationId, { type: 'QUEUE_UPDATE', queueLength: data.queueLength || 0 });
|
|
178
|
-
if (data.conversationId !== this.state.currentConversation?.id) return;
|
|
179
|
-
this.fetchAndRenderQueue(data.conversationId);
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
handleQueueUpdated(data) {
|
|
184
|
-
if (data.conversationId !== this.state.currentConversation?.id) return;
|
|
185
|
-
this.fetchAndRenderQueue(data.conversationId);
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
handleQueueItemDequeued(data) {
|
|
190
|
-
if (data.conversationId !== this.state.currentConversation?.id) return;
|
|
191
|
-
this.fetchAndRenderQueue(data.conversationId);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
});
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
_setupUIButtonEvents() {
|
|
3
|
-
this.ui.stopButton = document.getElementById('stopBtn');
|
|
4
|
-
this.ui.injectButton = document.getElementById('injectBtn');
|
|
5
|
-
this.ui.queueButton = document.getElementById('queueBtn');
|
|
6
|
-
|
|
7
|
-
if (this.ui.stopButton) {
|
|
8
|
-
this.ui.stopButton.addEventListener('click', async () => {
|
|
9
|
-
if (!this.state.currentConversation) return;
|
|
10
|
-
try {
|
|
11
|
-
const data = await window.wsClient.rpc('conv.cancel', { id: this.state.currentConversation.id });
|
|
12
|
-
this._dbg('Stop response:', data);
|
|
13
|
-
} catch (err) {
|
|
14
|
-
console.error('Failed to stop:', err);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (this.ui.injectButton) {
|
|
20
|
-
this.ui.injectButton.addEventListener('click', async () => {
|
|
21
|
-
if (!this.state.currentConversation) return;
|
|
22
|
-
const isStreaming = this._convIsStreaming(this.state.currentConversation.id);
|
|
23
|
-
|
|
24
|
-
if (isStreaming) {
|
|
25
|
-
const message = this.ui.messageInput?.value || '';
|
|
26
|
-
if (!message.trim()) {
|
|
27
|
-
this.showError('Please enter a message to steer');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const steerMsg = message;
|
|
32
|
-
if (this.ui.messageInput) {
|
|
33
|
-
this.ui.messageInput.value = '';
|
|
34
|
-
this.ui.messageInput.style.height = 'auto';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
window.wsClient.rpc('conv.steer', { id: this.state.currentConversation.id, content: steerMsg })
|
|
38
|
-
.catch(err => {
|
|
39
|
-
console.error('Failed to steer:', err);
|
|
40
|
-
this.showError('Failed to steer: ' + err.message);
|
|
41
|
-
});
|
|
42
|
-
} else {
|
|
43
|
-
const instructions = await window.UIDialog.prompt('Enter instructions to inject into the running agent:', '', 'Inject Instructions');
|
|
44
|
-
if (!instructions) return;
|
|
45
|
-
window.wsClient.rpc('conv.inject', { id: this.state.currentConversation.id, content: instructions })
|
|
46
|
-
.catch(err => console.error('Failed to inject:', err));
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (this.ui.queueButton) {
|
|
52
|
-
this.ui.queueButton.addEventListener('click', async () => {
|
|
53
|
-
if (!this.state.currentConversation) return;
|
|
54
|
-
const message = this.ui.messageInput?.value || '';
|
|
55
|
-
if (!message.trim()) {
|
|
56
|
-
this.showError('Please enter a message to queue');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
const data = await window.wsClient.rpc('msg.send', { id: this.state.currentConversation.id, content: message });
|
|
61
|
-
this._dbg('Queue response:', data);
|
|
62
|
-
if (this.ui.messageInput) {
|
|
63
|
-
this.ui.messageInput.value = '';
|
|
64
|
-
this.ui.messageInput.style.height = 'auto';
|
|
65
|
-
}
|
|
66
|
-
} catch (err) {
|
|
67
|
-
console.error('Failed to queue:', err);
|
|
68
|
-
this.showError('Failed to queue: ' + err.message);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (this.ui.messageInput) {
|
|
74
|
-
this.ui.messageInput.addEventListener('keydown', (e) => {
|
|
75
|
-
if (e.key === 'Enter' && e.ctrlKey) {
|
|
76
|
-
this.startExecution();
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
this.ui.messageInput.addEventListener('input', () => {
|
|
81
|
-
const el = this.ui.messageInput;
|
|
82
|
-
el.style.height = 'auto';
|
|
83
|
-
el.style.height = Math.min(el.scrollHeight, 150) + 'px';
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
_setupUIWindowEvents() {
|
|
89
|
-
document.addEventListener('keydown', (e) => {
|
|
90
|
-
if (e.key === 'n' && (e.ctrlKey || e.metaKey) && !e.shiftKey) {
|
|
91
|
-
e.preventDefault();
|
|
92
|
-
const newBtn = document.querySelector('[data-new-conversation], #newConversationBtn, .new-conversation-btn');
|
|
93
|
-
if (newBtn) newBtn.click();
|
|
94
|
-
}
|
|
95
|
-
if (e.key === 'b' && (e.ctrlKey || e.metaKey) && !e.shiftKey) {
|
|
96
|
-
e.preventDefault();
|
|
97
|
-
const toggleBtn = document.querySelector('[data-sidebar-toggle]');
|
|
98
|
-
if (toggleBtn) toggleBtn.click();
|
|
99
|
-
}
|
|
100
|
-
if (e.key === 'Escape') {
|
|
101
|
-
const activeEl = document.activeElement;
|
|
102
|
-
if (activeEl && activeEl.tagName === 'TEXTAREA') { activeEl.blur(); return; }
|
|
103
|
-
if (this.state.isStreaming) {
|
|
104
|
-
const cancelBtn = document.querySelector('#cancelBtn, [data-cancel-btn]');
|
|
105
|
-
if (cancelBtn && cancelBtn.offsetParent !== null) cancelBtn.click();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const themeToggle = document.querySelector('[data-theme-toggle]');
|
|
111
|
-
if (themeToggle) {
|
|
112
|
-
themeToggle.addEventListener('click', () => this.toggleTheme());
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (this.ui.outputEl) {
|
|
116
|
-
this.ui.outputEl.addEventListener('click', async (e) => {
|
|
117
|
-
const editBtn = e.target.closest('[data-edit-msg]');
|
|
118
|
-
if (!editBtn || !this.state.currentConversation) return;
|
|
119
|
-
const msgEl = editBtn.closest('.message-user');
|
|
120
|
-
const textEl = msgEl?.querySelector('.message-text');
|
|
121
|
-
if (!textEl) return;
|
|
122
|
-
const original = textEl.textContent || '';
|
|
123
|
-
const edited = await window.UIDialog?.prompt('Edit message:', original, 'Edit & Re-run');
|
|
124
|
-
if (!edited || edited === original) return;
|
|
125
|
-
this.ui.messageInput.value = edited;
|
|
126
|
-
this.startExecution();
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
this.setupScrollTracking();
|
|
131
|
-
|
|
132
|
-
window.addEventListener('create-new-conversation', (event) => {
|
|
133
|
-
this.unlockAgentAndModel();
|
|
134
|
-
const detail = event.detail || {};
|
|
135
|
-
this.createNewConversation(detail.workingDirectory, detail.title);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
window.addEventListener('preparing-new-conversation', () => {
|
|
139
|
-
this.unlockAgentAndModel();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
window.addEventListener('conversation-selected', async (event) => {
|
|
143
|
-
const conversationId = event.detail.conversationId;
|
|
144
|
-
if (this._isLoadingConversation && this._loadingConversationId === conversationId) return;
|
|
145
|
-
this._loadingConversationId = conversationId;
|
|
146
|
-
this.updateUrlForConversation(conversationId);
|
|
147
|
-
this._isLoadingConversation = true;
|
|
148
|
-
try {
|
|
149
|
-
await this.loadConversationMessages(conversationId);
|
|
150
|
-
} finally {
|
|
151
|
-
this._isLoadingConversation = false;
|
|
152
|
-
this._loadingConversationId = null;
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
window.addEventListener('conversation-deselected', () => {
|
|
157
|
-
window.ConversationState?.clear('deselected');
|
|
158
|
-
this.state.currentConversation = null;
|
|
159
|
-
this.state.currentSession = null;
|
|
160
|
-
this.updateUrlForConversation(null);
|
|
161
|
-
this.enableControls();
|
|
162
|
-
this._showWelcomeScreen();
|
|
163
|
-
if (this.ui.messageInput) {
|
|
164
|
-
this.ui.messageInput.value = '';
|
|
165
|
-
this.ui.messageInput.style.height = 'auto';
|
|
166
|
-
}
|
|
167
|
-
this.unlockAgentAndModel();
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
});
|
package/static/js/client-ui.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
Object.assign(AgentGUIClient.prototype, {
|
|
2
|
-
setupUI() {
|
|
3
|
-
const container = document.getElementById(this.config.containerId);
|
|
4
|
-
if (!container) {
|
|
5
|
-
throw new Error(`Container not found: ${this.config.containerId}`);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
this.ui.statusIndicator = document.querySelector('[data-status-indicator]');
|
|
9
|
-
this.ui.messageInput = document.querySelector('[data-message-input]');
|
|
10
|
-
this.ui.sendButton = document.querySelector('[data-send-button]');
|
|
11
|
-
this.ui.cliSelector = document.querySelector('[data-cli-selector]');
|
|
12
|
-
this.ui.agentSelector = document.querySelector('[data-agent-selector]');
|
|
13
|
-
this.ui.modelSelector = document.querySelector('[data-model-selector]');
|
|
14
|
-
|
|
15
|
-
if (this.ui.messageInput) {
|
|
16
|
-
this.ui.messageInput.addEventListener('input', () => {
|
|
17
|
-
this.saveDraftPrompt();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const currentConvId = this.state.currentConversation?.id;
|
|
21
|
-
if (currentConvId) {
|
|
22
|
-
this.restoreDraftPrompt(currentConvId);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (this.ui.cliSelector) {
|
|
27
|
-
this.ui.cliSelector.addEventListener('change', () => {
|
|
28
|
-
if (!this._agentLocked) {
|
|
29
|
-
this.loadSubAgentsForCli(this.ui.cliSelector.value);
|
|
30
|
-
this.loadModelsForAgent(this.ui.cliSelector.value);
|
|
31
|
-
this.saveAgentAndModelToConversation();
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (this.ui.agentSelector) {
|
|
37
|
-
this.ui.agentSelector.addEventListener('change', () => {
|
|
38
|
-
const parentAgentId = this.ui.cliSelector?.value;
|
|
39
|
-
if (parentAgentId) {
|
|
40
|
-
this.loadModelsForAgent(parentAgentId);
|
|
41
|
-
}
|
|
42
|
-
if (!this._agentLocked) {
|
|
43
|
-
this.saveAgentAndModelToConversation();
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (this.ui.modelSelector) {
|
|
49
|
-
this.ui.modelSelector.addEventListener('change', () => {
|
|
50
|
-
this.saveAgentAndModelToConversation();
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (this.ui.sendButton) {
|
|
55
|
-
this.ui.sendButton.addEventListener('click', () => this.startExecution());
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
this.setupChatMicButton();
|
|
59
|
-
this._setupUIButtonEvents();
|
|
60
|
-
this._setupUIWindowEvents();
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
setupChatMicButton() {
|
|
64
|
-
const chatMicBtn = document.getElementById('chatMicBtn');
|
|
65
|
-
if (!chatMicBtn) return;
|
|
66
|
-
|
|
67
|
-
let isRecording = false;
|
|
68
|
-
|
|
69
|
-
const startRecording = async () => {
|
|
70
|
-
if (isRecording) return;
|
|
71
|
-
isRecording = true;
|
|
72
|
-
chatMicBtn.classList.add('recording');
|
|
73
|
-
const result = await window.STTHandler.startRecording();
|
|
74
|
-
if (!result.success) {
|
|
75
|
-
isRecording = false;
|
|
76
|
-
chatMicBtn.classList.remove('recording');
|
|
77
|
-
alert('Microphone access denied: ' + result.error);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const stopRecording = async () => {
|
|
82
|
-
if (!isRecording) return;
|
|
83
|
-
isRecording = false;
|
|
84
|
-
chatMicBtn.classList.remove('recording');
|
|
85
|
-
const result = await window.STTHandler.stopRecording();
|
|
86
|
-
if (result.success) {
|
|
87
|
-
if (this.ui.messageInput) {
|
|
88
|
-
this.ui.messageInput.value = result.text;
|
|
89
|
-
}
|
|
90
|
-
} else {
|
|
91
|
-
alert('Transcription failed: ' + result.error);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
chatMicBtn.addEventListener('mousedown', (e) => {
|
|
96
|
-
e.preventDefault();
|
|
97
|
-
startRecording();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
chatMicBtn.addEventListener('mouseup', (e) => {
|
|
101
|
-
e.preventDefault();
|
|
102
|
-
stopRecording();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
chatMicBtn.addEventListener('mouseleave', (e) => {
|
|
106
|
-
if (isRecording) {
|
|
107
|
-
stopRecording();
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
chatMicBtn.addEventListener('touchstart', (e) => {
|
|
112
|
-
e.preventDefault();
|
|
113
|
-
startRecording();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
chatMicBtn.addEventListener('touchend', (e) => {
|
|
117
|
-
e.preventDefault();
|
|
118
|
-
stopRecording();
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
chatMicBtn.addEventListener('touchcancel', (e) => {
|
|
122
|
-
if (isRecording) {
|
|
123
|
-
stopRecording();
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
});
|