agentgui 1.0.828 → 1.0.830

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.
@@ -0,0 +1,128 @@
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
+ });
@@ -0,0 +1,159 @@
1
+ Object.assign(AgentGUIClient.prototype, {
2
+ _showWelcomeScreen() {
3
+ const outputEl = document.getElementById('output');
4
+ if (!outputEl) return;
5
+ const agents = this.state.agents || [];
6
+ const agentOptions = agents.map(a =>
7
+ `<option value="${this.escapeHtml(a.id)}">${this.escapeHtml(a.name.split(/[\s\-]+/)[0])}</option>`
8
+ ).join('');
9
+ outputEl.innerHTML = `
10
+ <div style="display:flex;align-items:center;justify-content:center;height:100%;flex-direction:column;gap:2rem;padding:2rem;">
11
+ <div style="text-align:center;">
12
+ <h1 style="margin:0;font-size:2.5rem;color:var(--color-text-primary);">Welcome to AgentGUI</h1>
13
+ <p style="margin:1rem 0 0 0;font-size:1.1rem;color:var(--color-text-secondary);">Start a new conversation or select one from the sidebar</p>
14
+ </div>
15
+ ${agents.length > 0 ? `
16
+ <div style="display:flex;flex-direction:column;align-items:center;gap:0.75rem;">
17
+ <label style="font-size:0.85rem;color:var(--color-text-secondary);font-weight:500;">Select Agent</label>
18
+ <select id="welcomeAgentSelect" style="padding:0.5rem 1rem;border-radius:0.375rem;border:1px solid var(--color-border);background:var(--color-bg-secondary);color:var(--color-text-primary);font-size:1rem;cursor:pointer;">
19
+ ${agentOptions}
20
+ </select>
21
+ </div>
22
+ ` : ''}
23
+ <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:1rem;max-width:600px;">
24
+ <div style="padding:1.5rem;border-radius:0.5rem;background:var(--color-bg-secondary);border:1px solid var(--color-border);">
25
+ <h3 style="margin:0 0 0.5rem 0;color:var(--color-primary);">New Conversation</h3>
26
+ <p style="margin:0;font-size:0.9rem;color:var(--color-text-secondary);">Create a new chat with any AI agent</p>
27
+ </div>
28
+ <div style="padding:1.5rem;border-radius:0.5rem;background:var(--color-bg-secondary);border:1px solid var(--color-border);">
29
+ <h3 style="margin:0 0 0.5rem 0;color:var(--color-primary);">Available Agents</h3>
30
+ <p style="margin:0;font-size:0.9rem;color:var(--color-text-secondary);">${agents.length > 0 ? agents.map(a => a.name.split(/[\s\-]+/)[0]).join(', ') : 'Claude Code, Gemini, OpenCode, and more'}</p>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ `;
35
+ const welcomeSel = document.getElementById('welcomeAgentSelect');
36
+ if (welcomeSel) {
37
+ if (this.ui.cliSelector) welcomeSel.value = this.ui.cliSelector.value;
38
+ welcomeSel.addEventListener('change', () => {
39
+ if (this.ui.cliSelector) {
40
+ this.ui.cliSelector.value = welcomeSel.value;
41
+ this.ui.cliSelector.dispatchEvent(new Event('change'));
42
+ }
43
+ });
44
+ }
45
+ },
46
+
47
+
48
+ _showSkeletonLoading(conversationId) {
49
+ const outputEl = document.getElementById('output');
50
+ if (!outputEl) return;
51
+ const conv = this.state.conversations.find(c => c.id === conversationId);
52
+ const title = conv?.title || 'Conversation';
53
+ const wdInfo = conv?.workingDirectory ? `${this.escapeHtml(conv.workingDirectory)}` : '';
54
+ const timestamp = conv ? new Date(conv.created_at).toLocaleDateString() : '';
55
+ const metaParts = [timestamp];
56
+ if (wdInfo) metaParts.push(wdInfo);
57
+ outputEl.innerHTML = `
58
+ <div class="conversation-header">
59
+ <h2>${this.escapeHtml(title)}</h2>
60
+ <p class="text-secondary">${metaParts.join(' - ')}</p>
61
+ </div>
62
+ <div class="conversation-messages">
63
+ <div class="skeleton-loading">
64
+ <div class="skeleton-block skeleton-pulse" style="height:3rem;margin-bottom:0.75rem;border-radius:0.5rem;background:var(--color-bg-secondary);"></div>
65
+ <div class="skeleton-block skeleton-pulse" style="height:6rem;margin-bottom:0.75rem;border-radius:0.5rem;background:var(--color-bg-secondary);"></div>
66
+ <div class="skeleton-block skeleton-pulse" style="height:2rem;margin-bottom:0.75rem;border-radius:0.5rem;background:var(--color-bg-secondary);"></div>
67
+ <div class="skeleton-block skeleton-pulse" style="height:5rem;margin-bottom:0.75rem;border-radius:0.5rem;background:var(--color-bg-secondary);"></div>
68
+ </div>
69
+ </div>
70
+ `;
71
+ },
72
+
73
+
74
+ async streamToConversation(conversationId, prompt, agentId, model, subAgent) {
75
+ try {
76
+ if (this.wsManager.isConnected) {
77
+ this.wsManager.sendMessage({ type: 'subscribe', conversationId });
78
+ }
79
+
80
+ let finalPrompt = prompt;
81
+ const streamBody = { id: conversationId, content: finalPrompt, agentId };
82
+ if (model) streamBody.model = model;
83
+ if (subAgent) streamBody.subAgent = subAgent;
84
+ let result;
85
+ try {
86
+ result = await window.wsClient.rpc('msg.stream', streamBody);
87
+ } catch (e) {
88
+ if (e.code === 404) {
89
+ console.warn('Conversation not found, recreating:', conversationId);
90
+ const conv = this.state.currentConversation;
91
+ const createBody = { agentId, title: conv?.title || prompt.substring(0, 50), workingDirectory: conv?.workingDirectory || null };
92
+ if (model) createBody.model = model;
93
+ if (subAgent) createBody.subAgent = subAgent;
94
+ const { conversation: newConv } = await window.wsClient.rpc('conv.new', createBody);
95
+ window.ConversationState?.selectConversation(newConv.id, 'stream_recreate', 1);
96
+ this.state.currentConversation = newConv;
97
+ if (window.conversationManager) {
98
+ window.conversationManager.loadConversations();
99
+ window.conversationManager.select(newConv.id);
100
+ }
101
+ this.updateUrlForConversation(newConv.id);
102
+ return this.streamToConversation(newConv.id, prompt, agentId, model, subAgent);
103
+ }
104
+ throw e;
105
+ }
106
+
107
+ if (result.queued) {
108
+ this._dbg('Message queued, position:', result.queuePosition);
109
+ this.enableControls();
110
+ return;
111
+ }
112
+
113
+ if (result.session && this.wsManager.isConnected) {
114
+ this.wsManager.subscribeToSession(result.session.id);
115
+ }
116
+
117
+ this._lastSendTime = Date.now();
118
+ this.emit('execution:started', result);
119
+ } catch (error) {
120
+ console.error('Stream execution error:', error);
121
+ this.showError('Failed to stream execution: ' + error.message);
122
+ this.enableControls();
123
+ }
124
+ },
125
+
126
+
127
+ _hydrateSessionBlocks(blocksEl, list) {
128
+ const blockFrag = document.createDocumentFragment();
129
+ const deferred = [];
130
+ for (const chunk of list) {
131
+ if (!chunk.block?.type) continue;
132
+ const bt = chunk.block.type;
133
+ if (bt === 'tool_result' || bt === 'tool_status' || bt === 'hook_progress') { deferred.push(chunk); continue; }
134
+ const el = this.renderer.renderBlock(chunk.block, chunk, blockFrag);
135
+ if (!el) continue;
136
+ el.classList.add('block-loaded');
137
+ blockFrag.appendChild(el);
138
+ }
139
+ blocksEl.appendChild(blockFrag);
140
+ const toolUseIndex = new Map();
141
+ blocksEl.querySelectorAll('.block-tool-use[data-tool-use-id]').forEach(el => toolUseIndex.set(el.dataset.toolUseId, el));
142
+ for (const chunk of deferred) {
143
+ const b = chunk.block;
144
+ if (b.type === 'tool_result') {
145
+ const toolUseEl = (b.tool_use_id && toolUseIndex.get(b.tool_use_id))
146
+ || (blocksEl.lastElementChild?.classList.contains('block-tool-use') ? blocksEl.lastElementChild : null);
147
+ if (toolUseEl) this.renderer.mergeResultIntoToolUse(toolUseEl, b);
148
+ } else if (b.type === 'tool_status') {
149
+ const toolUseEl = b.tool_use_id && toolUseIndex.get(b.tool_use_id);
150
+ if (toolUseEl) {
151
+ const isError = b.status === 'failed';
152
+ const isDone = b.status === 'completed';
153
+ if (isDone || isError) toolUseEl.classList.add(isError ? 'tool-result-error' : 'tool-result-success');
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ });
@@ -0,0 +1,93 @@
1
+ Object.assign(AgentGUIClient.prototype, {
2
+ updateUrlForConversation(conversationId, sessionId) {
3
+ if (!this.isValidId(conversationId)) return;
4
+ if (!this.routerState) return;
5
+
6
+ this.routerState.currentConversationId = conversationId;
7
+ if (sessionId && this.isValidId(sessionId)) {
8
+ this.routerState.currentSessionId = sessionId;
9
+ }
10
+
11
+ const basePath = window.location.pathname.replace(/\/conversations\/[^\/]+$/, '').replace(/\/$/, '');
12
+ let url = `${basePath}/conversations/${conversationId}`;
13
+
14
+ if (sessionId && this.isValidId(sessionId)) {
15
+ url += `?session=${sessionId}`;
16
+ }
17
+
18
+ window.history.pushState({ conversationId, sessionId }, '', url);
19
+ },
20
+
21
+
22
+ saveScrollPosition(conversationId) {
23
+ if (!this.isValidId(conversationId)) return;
24
+
25
+ const scrollContainer = document.getElementById(this.config.scrollContainerId);
26
+ if (scrollContainer) {
27
+ const position = scrollContainer.scrollTop;
28
+ try {
29
+ localStorage.setItem(`scroll_${conversationId}`, position.toString());
30
+ } catch (e) {
31
+ console.warn('Failed to save scroll position:', e);
32
+ }
33
+ }
34
+ },
35
+
36
+
37
+ restoreScrollPosition(conversationId) {
38
+ if (!this.isValidId(conversationId)) return;
39
+
40
+ try {
41
+ const position = localStorage.getItem(`scroll_${conversationId}`);
42
+ const scrollContainer = document.getElementById(this.config.scrollContainerId);
43
+ if (!scrollContainer) return;
44
+
45
+ if (position !== null) {
46
+ const scrollTop = parseInt(position, 10);
47
+ if (!isNaN(scrollTop)) {
48
+ requestAnimationFrame(() => {
49
+ requestAnimationFrame(() => {
50
+ const maxScroll = scrollContainer.scrollHeight - scrollContainer.clientHeight;
51
+ scrollContainer.scrollTop = Math.min(scrollTop, maxScroll);
52
+ });
53
+ });
54
+ }
55
+ } else {
56
+ requestAnimationFrame(() => {
57
+ requestAnimationFrame(() => {
58
+ scrollContainer.scrollTop = 0;
59
+ });
60
+ });
61
+ }
62
+ } catch (e) {
63
+ console.warn('Failed to restore scroll position:', e);
64
+ }
65
+ },
66
+
67
+
68
+ setupScrollTracking() {
69
+ const scrollContainer = document.getElementById(this.config.scrollContainerId);
70
+ if (!scrollContainer) return;
71
+
72
+ this._userScrolledUp = false;
73
+ let scrollTimer = null;
74
+ let lastScrollTop = scrollContainer.scrollTop;
75
+ scrollContainer.addEventListener('scroll', () => {
76
+ const distFromBottom = scrollContainer.scrollHeight - scrollContainer.scrollTop - scrollContainer.clientHeight;
77
+ if (scrollContainer.scrollTop < lastScrollTop && distFromBottom > 200) {
78
+ this._userScrolledUp = true;
79
+ } else if (distFromBottom < 50) {
80
+ this._userScrolledUp = false;
81
+ this._removeNewContentPill();
82
+ }
83
+ lastScrollTop = scrollContainer.scrollTop;
84
+ if (scrollTimer) clearTimeout(scrollTimer);
85
+ scrollTimer = setTimeout(() => {
86
+ if (this.state.currentConversation?.id) {
87
+ this.saveScrollPosition(this.state.currentConversation.id);
88
+ }
89
+ }, 500);
90
+ });
91
+ }
92
+
93
+ });
@@ -0,0 +1,175 @@
1
+ Object.assign(AgentGUIClient.prototype, {
2
+ renderMessages(messages) {
3
+ if (messages.length === 0) {
4
+ return '<p class="text-secondary">No messages in this conversation yet</p>';
5
+ }
6
+ return messages.map(msg => `<div class="message message-${msg.role}"><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></div>`).join('');
7
+ }
8
+
9
+
10
+ escapeHtml(text) {
11
+ return window._escHtml(text);
12
+ }
13
+
14
+
15
+ showError(message) {
16
+ console.error(message);
17
+ if (window.UIDialog) {
18
+ window.UIDialog.alert(message, 'Error');
19
+ }
20
+ }
21
+
22
+
23
+ on(event, callback) {
24
+ if (!this.eventHandlers[event]) {
25
+ this.eventHandlers[event] = [];
26
+ }
27
+ this.eventHandlers[event].push(callback);
28
+ }
29
+
30
+
31
+ emit(event, data) {
32
+ if (this.eventHandlers[event]) {
33
+ this.eventHandlers[event].forEach(callback => {
34
+ try {
35
+ callback(data);
36
+ } catch (error) {
37
+ console.error(`Event handler error for ${event}:`, error);
38
+ }
39
+ });
40
+ }
41
+ }
42
+
43
+
44
+ getEffectiveAgentId() {
45
+ return this.ui.cliSelector?.value || null;
46
+ }
47
+
48
+
49
+ getEffectiveSubAgent() {
50
+ if (this.ui.agentSelector?.value && this.ui.agentSelector.style.display !== 'none') {
51
+ return this.ui.agentSelector.value;
52
+ }
53
+ return null;
54
+ }
55
+
56
+
57
+ getCurrentAgent() {
58
+ return this.getEffectiveAgentId();
59
+ }
60
+
61
+
62
+ saveAgentAndModelToConversation() {
63
+ const convId = this.state.currentConversation?.id;
64
+ if (!convId || this._agentLocked) return;
65
+ const agentId = this.getEffectiveAgentId();
66
+ const subAgent = this.getEffectiveSubAgent();
67
+ const model = this.getCurrentModel();
68
+ window.wsClient.rpc('conv.upd', { id: convId, agentType: agentId, subAgent: subAgent || undefined, model: model || undefined }).catch(() => {});
69
+ }
70
+
71
+
72
+ getCurrentModel() {
73
+ return this.ui.modelSelector?.value || null;
74
+ }
75
+
76
+
77
+ getMetrics() {
78
+ return {
79
+ renderer: this.renderer.getMetrics(),
80
+ websocket: this.wsManager.getStatus(),
81
+ eventProcessor: this.eventProcessor.getStats(),
82
+ state: this.state
83
+ };
84
+ }
85
+
86
+
87
+ saveDraftPrompt() {
88
+ const convId = this.state.currentConversation?.id;
89
+ if (convId && this.ui.messageInput) {
90
+ const draft = this.ui.messageInput.value;
91
+ this.draftPrompts.set(convId, draft);
92
+ if (draft) {
93
+ localStorage.setItem(`draft-${convId}`, draft);
94
+ }
95
+ }
96
+ }
97
+
98
+
99
+ restoreDraftPrompt(conversationId) {
100
+ if (!this.ui.messageInput) return;
101
+
102
+ let draft = this.draftPrompts.get(conversationId) || '';
103
+ if (!draft) {
104
+ draft = localStorage.getItem(`draft-${conversationId}`) || '';
105
+ if (draft) this.draftPrompts.set(conversationId, draft);
106
+ }
107
+
108
+ this.ui.messageInput.value = draft;
109
+ }
110
+
111
+
112
+ clearDraft(conversationId) {
113
+ this.draftPrompts.delete(conversationId);
114
+ localStorage.removeItem(`draft-${conversationId}`);
115
+ }
116
+
117
+
118
+ updateSendButtonState() {
119
+ if (this.ui.sendButton) {
120
+ this.ui.sendButton.disabled = !this.wsManager.isConnected;
121
+ }
122
+ if (this.ui.injectButton && this.ui.injectButton.classList.contains('visible')) {
123
+ this.ui.injectButton.disabled = !this.wsManager.isConnected;
124
+ }
125
+ if (this.ui.queueButton && this.ui.queueButton.classList.contains('visible')) {
126
+ this.ui.queueButton.disabled = !this.wsManager.isConnected;
127
+ }
128
+ }
129
+
130
+
131
+ disablePromptArea() {
132
+ }
133
+
134
+
135
+ enablePromptArea() {
136
+ if (this.ui.messageInput) {
137
+ this.ui.messageInput.disabled = false;
138
+ }
139
+ const injectBtn = document.getElementById('injectBtn');
140
+ if (injectBtn) injectBtn.disabled = false;
141
+ }
142
+
143
+
144
+ showStreamingPromptButtons() {
145
+ if (this.ui.injectButton) {
146
+ this.ui.injectButton.classList.add('visible');
147
+ this.ui.injectButton.disabled = !this.wsManager.isConnected;
148
+ }
149
+ if (this.ui.queueButton) {
150
+ this.ui.queueButton.classList.add('visible');
151
+ this.ui.queueButton.disabled = !this.wsManager.isConnected;
152
+ }
153
+ }
154
+
155
+
156
+ ensurePromptAreaAlwaysEnabled() {
157
+ if (this.ui.messageInput) {
158
+ this.ui.messageInput.disabled = false;
159
+ }
160
+ }
161
+
162
+
163
+ destroy() {
164
+
165
+ this.renderer.destroy();
166
+ this.wsManager.destroy();
167
+ this.eventHandlers = {};
168
+ }
169
+ }
170
+
171
+ window.__convPerfMetrics = () => {
172
+ const entries = performance.getEntriesByType('measure').filter(e => e.name.startsWith('conv-'));
173
+ return entries.map(e => ({ name: e.name, ms: Math.round(e.duration) }));
174
+ };
175
+ });
@@ -0,0 +1,88 @@
1
+ Object.assign(AgentGUIClient.prototype, {
2
+ async connectWebSocket() {
3
+ try {
4
+ await this.wsManager.connect();
5
+ this.updateConnectionStatus('connected');
6
+ } catch (error) {
7
+ console.error('WebSocket connection failed:', error);
8
+ this.updateConnectionStatus('error');
9
+ throw error;
10
+ }
11
+ },
12
+
13
+
14
+ handleWebSocketMessage(data) {
15
+ try {
16
+ window.dispatchEvent(new CustomEvent('ws-message', { detail: data }));
17
+
18
+ switch (data.type) {
19
+ case 'streaming_start':
20
+ this.handleStreamingStart(data).catch(e => console.error('handleStreamingStart error:', e));
21
+ break;
22
+ case 'streaming_resumed':
23
+ this.handleStreamingResumed(data).catch(e => console.error('handleStreamingResumed error:', e));
24
+ break;
25
+ case 'streaming_progress':
26
+ this.handleStreamingProgress(data);
27
+ break;
28
+ case 'streaming_complete':
29
+ this.handleStreamingComplete(data);
30
+ break;
31
+ case 'streaming_error':
32
+ this.handleStreamingError(data);
33
+ break;
34
+ case 'conversation_created':
35
+ this.handleConversationCreated(data);
36
+ break;
37
+ case 'all_conversations_deleted':
38
+ this.handleAllConversationsDeleted(data);
39
+ break;
40
+ case 'message_created':
41
+ this.handleMessageCreated(data);
42
+ break;
43
+ case 'conversation_updated':
44
+ this.handleConversationUpdated(data);
45
+ break;
46
+ case 'queue_status':
47
+ this.handleQueueStatus(data);
48
+ break;
49
+ case 'queue_updated':
50
+ this.handleQueueUpdated(data);
51
+ break;
52
+ case 'queue_item_dequeued':
53
+ this.handleQueueItemDequeued(data);
54
+ break;
55
+ case 'rate_limit_hit':
56
+ this.handleRateLimitHit(data);
57
+ break;
58
+ case 'rate_limit_clear':
59
+ this.handleRateLimitClear(data);
60
+ break;
61
+ case 'model_download_progress':
62
+ this._handleModelDownloadProgress(data.progress || data);
63
+ break;
64
+ case 'tts_setup_progress':
65
+ this._handleTTSSetupProgress(data);
66
+ break;
67
+ default:
68
+ break;
69
+ }
70
+ } catch (error) {
71
+ console.error('Message handling error:', error);
72
+ }
73
+ },
74
+
75
+
76
+ queueEvent(data) {
77
+ try {
78
+ const processed = this.eventProcessor.processEvent(data);
79
+ if (!processed) return;
80
+ if (data.sessionId && this.state.currentSession?.id === data.sessionId) {
81
+ this.state.sessionEvents.push(processed);
82
+ }
83
+ } catch (error) {
84
+ console.error('Event queuing error:', error);
85
+ }
86
+ }
87
+
88
+ });