agentgui 1.0.740 → 1.0.742
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 +100 -35
- package/static/js/streaming-renderer.js +37 -13
package/package.json
CHANGED
package/static/js/client.js
CHANGED
|
@@ -90,14 +90,18 @@ class AgentGUIClient {
|
|
|
90
90
|
currentConversationId: null,
|
|
91
91
|
currentSessionId: null
|
|
92
92
|
};
|
|
93
|
+
|
|
94
|
+
this._debug = typeof localStorage !== 'undefined' && localStorage.getItem('debug') === '1';
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
_dbg(...args) { if (this._debug) this._dbg(...args); }
|
|
98
|
+
|
|
95
99
|
/**
|
|
96
100
|
* Initialize the client
|
|
97
101
|
*/
|
|
98
102
|
async init() {
|
|
99
103
|
try {
|
|
100
|
-
|
|
104
|
+
this._dbg('Initializing AgentGUI client');
|
|
101
105
|
|
|
102
106
|
// Initialize renderer
|
|
103
107
|
this.renderer.init(this.config.outputContainerId, this.config.scrollContainerId);
|
|
@@ -105,7 +109,7 @@ class AgentGUIClient {
|
|
|
105
109
|
// Initialize image loader
|
|
106
110
|
if (typeof ImageLoader !== 'undefined') {
|
|
107
111
|
window.imageLoader = new ImageLoader();
|
|
108
|
-
|
|
112
|
+
this._dbg('Image loader initialized');
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
// Setup event listeners
|
|
@@ -137,7 +141,7 @@ class AgentGUIClient {
|
|
|
137
141
|
this.emit('initialized');
|
|
138
142
|
this._setupDebugHooks();
|
|
139
143
|
|
|
140
|
-
|
|
144
|
+
this._dbg('AgentGUI client initialized');
|
|
141
145
|
return this;
|
|
142
146
|
} catch (error) {
|
|
143
147
|
console.error('Client initialization error:', error);
|
|
@@ -151,7 +155,7 @@ class AgentGUIClient {
|
|
|
151
155
|
*/
|
|
152
156
|
setupWebSocketListeners() {
|
|
153
157
|
this.wsManager.on('connected', () => {
|
|
154
|
-
|
|
158
|
+
this._dbg('WebSocket connected');
|
|
155
159
|
this.updateConnectionStatus('connected');
|
|
156
160
|
this._subscribeToConversationUpdates();
|
|
157
161
|
// On reconnect (not initial connect), invalidate current conversation's DOM
|
|
@@ -170,7 +174,7 @@ class AgentGUIClient {
|
|
|
170
174
|
if (window.__SERVER_VERSION) {
|
|
171
175
|
fetch((window.__BASE_URL || '') + '/api/version').then(r => r.json()).then(d => {
|
|
172
176
|
if (d.version && d.version !== window.__SERVER_VERSION) {
|
|
173
|
-
|
|
177
|
+
this._dbg(`Server updated ${window.__SERVER_VERSION} → ${d.version}, reloading`);
|
|
174
178
|
window.location.reload();
|
|
175
179
|
}
|
|
176
180
|
}).catch(() => {});
|
|
@@ -178,7 +182,7 @@ class AgentGUIClient {
|
|
|
178
182
|
});
|
|
179
183
|
|
|
180
184
|
this.wsManager.on('disconnected', () => {
|
|
181
|
-
|
|
185
|
+
this._dbg('WebSocket disconnected');
|
|
182
186
|
this.updateConnectionStatus('disconnected');
|
|
183
187
|
this.updateSendButtonState();
|
|
184
188
|
this.disablePromptArea();
|
|
@@ -186,7 +190,7 @@ class AgentGUIClient {
|
|
|
186
190
|
});
|
|
187
191
|
|
|
188
192
|
this.wsManager.on('reconnecting', (data) => {
|
|
189
|
-
|
|
193
|
+
this._dbg('WebSocket reconnecting:', data);
|
|
190
194
|
this.updateConnectionStatus('reconnecting');
|
|
191
195
|
});
|
|
192
196
|
|
|
@@ -266,7 +270,7 @@ class AgentGUIClient {
|
|
|
266
270
|
*/
|
|
267
271
|
setupRendererListeners() {
|
|
268
272
|
this.renderer.on('batch:complete', (data) => {
|
|
269
|
-
|
|
273
|
+
this._dbg('Batch rendered:', data);
|
|
270
274
|
this.updateMetrics(data.metrics);
|
|
271
275
|
});
|
|
272
276
|
|
|
@@ -293,7 +297,7 @@ class AgentGUIClient {
|
|
|
293
297
|
if (sessionId && this.isValidId(sessionId)) {
|
|
294
298
|
this.routerState.currentSessionId = sessionId;
|
|
295
299
|
}
|
|
296
|
-
|
|
300
|
+
this._dbg('Restoring conversation from URL:', conversationId);
|
|
297
301
|
this._isLoadingConversation = true;
|
|
298
302
|
if (window.conversationManager) {
|
|
299
303
|
window.conversationManager.select(conversationId);
|
|
@@ -303,7 +307,7 @@ class AgentGUIClient {
|
|
|
303
307
|
// If the URL conversation doesn't exist, try loading the most recent conversation
|
|
304
308
|
if (this.state.conversations && this.state.conversations.length > 0) {
|
|
305
309
|
const latestConv = this.state.conversations[0];
|
|
306
|
-
|
|
310
|
+
this._dbg('Loading latest conversation instead:', latestConv.id);
|
|
307
311
|
return this.loadConversationMessages(latestConv.id);
|
|
308
312
|
} else {
|
|
309
313
|
// No conversations available - show welcome screen
|
|
@@ -510,7 +514,7 @@ class AgentGUIClient {
|
|
|
510
514
|
if (!this.state.currentConversation) return;
|
|
511
515
|
try {
|
|
512
516
|
const data = await window.wsClient.rpc('conv.cancel', { id: this.state.currentConversation.id });
|
|
513
|
-
|
|
517
|
+
this._dbg('Stop response:', data);
|
|
514
518
|
} catch (err) {
|
|
515
519
|
console.error('Failed to stop:', err);
|
|
516
520
|
}
|
|
@@ -561,7 +565,7 @@ class AgentGUIClient {
|
|
|
561
565
|
try {
|
|
562
566
|
// Queue uses msg.send which will enqueue if streaming is active
|
|
563
567
|
const data = await window.wsClient.rpc('msg.send', { id: this.state.currentConversation.id, content: message });
|
|
564
|
-
|
|
568
|
+
this._dbg('Queue response:', data);
|
|
565
569
|
if (this.ui.messageInput) {
|
|
566
570
|
this.ui.messageInput.value = '';
|
|
567
571
|
this.ui.messageInput.style.height = 'auto';
|
|
@@ -788,7 +792,7 @@ class AgentGUIClient {
|
|
|
788
792
|
}
|
|
789
793
|
|
|
790
794
|
async handleStreamingStart(data) {
|
|
791
|
-
|
|
795
|
+
this._dbg('Streaming started:', data);
|
|
792
796
|
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'STREAMING', conversationId: data.conversationId });
|
|
793
797
|
this._clearThinkingCountdown();
|
|
794
798
|
if (this._lastSendTime > 0) {
|
|
@@ -812,9 +816,9 @@ class AgentGUIClient {
|
|
|
812
816
|
// If this streaming event is for a different conversation than what we are viewing,
|
|
813
817
|
// just track the state but do not modify the DOM or start polling
|
|
814
818
|
if (this.state.currentConversation?.id !== data.conversationId) {
|
|
815
|
-
|
|
819
|
+
this._dbg('Streaming started for non-active conversation:', data.conversationId);
|
|
816
820
|
this._setConvStreaming(data.conversationId, true, data.sessionId, data.agentId);
|
|
817
|
-
|
|
821
|
+
this._dbg('[SYNC] streaming_start - non-active conv:', { convId: data.conversationId, sessionId: data.sessionId, streamingCount: this.state.streamingConversations.size });
|
|
818
822
|
this.updateBusyPromptArea(data.conversationId);
|
|
819
823
|
this.emit('streaming:start', data);
|
|
820
824
|
|
|
@@ -900,7 +904,7 @@ class AgentGUIClient {
|
|
|
900
904
|
}
|
|
901
905
|
|
|
902
906
|
async handleStreamingResumed(data) {
|
|
903
|
-
|
|
907
|
+
this._dbg('Streaming resumed:', data);
|
|
904
908
|
const conv = this.state.currentConversation || { id: data.conversationId };
|
|
905
909
|
await this.handleStreamingStart({
|
|
906
910
|
type: 'streaming_start',
|
|
@@ -956,6 +960,52 @@ class AgentGUIClient {
|
|
|
956
960
|
const blocksEl = streamingEl.querySelector('.streaming-blocks');
|
|
957
961
|
if (!blocksEl) return;
|
|
958
962
|
|
|
963
|
+
if (block.type === 'tool_result') {
|
|
964
|
+
const tid = block.tool_use_id;
|
|
965
|
+
const toolUseEl = (tid && blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${tid}"]`))
|
|
966
|
+
|| (blocksEl.lastElementChild?.classList?.contains('block-tool-use') ? blocksEl.lastElementChild : null);
|
|
967
|
+
if (toolUseEl) {
|
|
968
|
+
this.renderer.mergeResultIntoToolUse(toolUseEl, block);
|
|
969
|
+
this.scrollToBottom();
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (block.type === 'tool_status') {
|
|
975
|
+
const tid = block.tool_use_id;
|
|
976
|
+
const toolUseEl = tid && blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${tid}"]`);
|
|
977
|
+
if (toolUseEl) {
|
|
978
|
+
const summary = toolUseEl.querySelector(':scope > summary');
|
|
979
|
+
if (summary) {
|
|
980
|
+
let badge = summary.querySelector('.folded-tool-status-live');
|
|
981
|
+
if (!badge) { badge = document.createElement('span'); badge.className = 'folded-tool-status-live'; summary.appendChild(badge); }
|
|
982
|
+
const isRunning = block.status === 'in_progress';
|
|
983
|
+
badge.style.cssText = 'margin-left:auto;font-size:0.65rem;opacity:0.7;display:inline-flex;align-items:center;gap:0.25rem';
|
|
984
|
+
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>' : '')
|
|
985
|
+
+ '<span>' + (isRunning ? 'Running' : (block.status || '')) + '</span>';
|
|
986
|
+
}
|
|
987
|
+
this.scrollToBottom();
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
if (block.type === 'hook_progress') {
|
|
993
|
+
const hookEvent = (block.hookEvent || '').split(':')[0];
|
|
994
|
+
if (hookEvent === 'PreToolUse' || hookEvent === 'PostToolUse') {
|
|
995
|
+
const lastTool = blocksEl.querySelector('.block-tool-use:last-of-type') || blocksEl.lastElementChild;
|
|
996
|
+
if (lastTool?.classList?.contains('block-tool-use')) {
|
|
997
|
+
const summary = lastTool.querySelector(':scope > summary');
|
|
998
|
+
if (summary) {
|
|
999
|
+
let hookBadge = summary.querySelector('.folded-tool-hook');
|
|
1000
|
+
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); }
|
|
1001
|
+
hookBadge.textContent = block.hookEvent?.split(':').pop() || hookEvent;
|
|
1002
|
+
}
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
959
1009
|
const el = this.renderer.renderBlock(block, data, blocksEl);
|
|
960
1010
|
if (el) {
|
|
961
1011
|
blocksEl.appendChild(el);
|
|
@@ -1052,7 +1102,7 @@ class AgentGUIClient {
|
|
|
1052
1102
|
|
|
1053
1103
|
// If this event is for a conversation we are NOT currently viewing, just track state
|
|
1054
1104
|
if (conversationId && this.state.currentConversation?.id !== conversationId) {
|
|
1055
|
-
|
|
1105
|
+
this._dbg('Streaming error for non-active conversation:', conversationId);
|
|
1056
1106
|
this._setConvStreaming(conversationId, false);
|
|
1057
1107
|
this.updateBusyPromptArea(conversationId);
|
|
1058
1108
|
this.emit('streaming:error', data);
|
|
@@ -1117,7 +1167,7 @@ class AgentGUIClient {
|
|
|
1117
1167
|
}
|
|
1118
1168
|
|
|
1119
1169
|
handleStreamingComplete(data) {
|
|
1120
|
-
|
|
1170
|
+
this._dbg('Streaming completed:', data);
|
|
1121
1171
|
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
|
|
1122
1172
|
this._clearThinkingCountdown();
|
|
1123
1173
|
|
|
@@ -1125,16 +1175,16 @@ class AgentGUIClient {
|
|
|
1125
1175
|
if (conversationId) this.invalidateCache(conversationId);
|
|
1126
1176
|
|
|
1127
1177
|
if (conversationId && this.state.currentConversation?.id !== conversationId) {
|
|
1128
|
-
|
|
1178
|
+
this._dbg('Streaming completed for non-active conversation:', conversationId);
|
|
1129
1179
|
this._setConvStreaming(conversationId, false);
|
|
1130
|
-
|
|
1180
|
+
this._dbg('[SYNC] streaming_complete - non-active conv:', { convId: conversationId, streamingCount: this.state.streamingConversations.size });
|
|
1131
1181
|
this.updateBusyPromptArea(conversationId);
|
|
1132
1182
|
this.emit('streaming:complete', data);
|
|
1133
1183
|
return;
|
|
1134
1184
|
}
|
|
1135
1185
|
|
|
1136
1186
|
this._setConvStreaming(conversationId, false);
|
|
1137
|
-
|
|
1187
|
+
this._dbg('[SYNC] streaming_complete - active conv:', { convId: conversationId, streamingCount: this.state.streamingConversations.size, interrupted: data.interrupted });
|
|
1138
1188
|
this.updateBusyPromptArea(conversationId);
|
|
1139
1189
|
|
|
1140
1190
|
const sessionId = data.sessionId || this.state.currentSession?.id;
|
|
@@ -1222,7 +1272,7 @@ class AgentGUIClient {
|
|
|
1222
1272
|
return;
|
|
1223
1273
|
}
|
|
1224
1274
|
|
|
1225
|
-
|
|
1275
|
+
this._dbg('[SYNC] message_created:', { msgId: data.message.id, role: data.message.role, convId: data.conversationId });
|
|
1226
1276
|
|
|
1227
1277
|
// Update messageCount in current conversation state for user messages
|
|
1228
1278
|
if (data.message.role === 'user' && this.state.currentConversation) {
|
|
@@ -2036,7 +2086,7 @@ class AgentGUIClient {
|
|
|
2036
2086
|
}
|
|
2037
2087
|
|
|
2038
2088
|
if (result.queued) {
|
|
2039
|
-
|
|
2089
|
+
this._dbg('Message queued, position:', result.queuePosition);
|
|
2040
2090
|
this.enableControls();
|
|
2041
2091
|
return;
|
|
2042
2092
|
}
|
|
@@ -2083,7 +2133,8 @@ class AgentGUIClient {
|
|
|
2083
2133
|
const deferred = [];
|
|
2084
2134
|
for (const chunk of list) {
|
|
2085
2135
|
if (!chunk.block?.type) continue;
|
|
2086
|
-
|
|
2136
|
+
const bt = chunk.block.type;
|
|
2137
|
+
if (bt === 'tool_result' || bt === 'tool_status' || bt === 'hook_progress') { deferred.push(chunk); continue; }
|
|
2087
2138
|
const el = this.renderer.renderBlock(chunk.block, chunk, blockFrag);
|
|
2088
2139
|
if (!el) continue;
|
|
2089
2140
|
el.classList.add('block-loaded');
|
|
@@ -2091,10 +2142,23 @@ class AgentGUIClient {
|
|
|
2091
2142
|
}
|
|
2092
2143
|
blocksEl.appendChild(blockFrag);
|
|
2093
2144
|
for (const chunk of deferred) {
|
|
2094
|
-
const
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2145
|
+
const b = chunk.block;
|
|
2146
|
+
if (b.type === 'tool_result') {
|
|
2147
|
+
const tid = b.tool_use_id;
|
|
2148
|
+
const toolUseEl = (tid ? blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${tid}"]`) : null)
|
|
2149
|
+
|| (blocksEl.lastElementChild?.classList.contains('block-tool-use') ? blocksEl.lastElementChild : null);
|
|
2150
|
+
if (toolUseEl) this.renderer.mergeResultIntoToolUse(toolUseEl, b);
|
|
2151
|
+
} else if (b.type === 'tool_status') {
|
|
2152
|
+
const tid = b.tool_use_id;
|
|
2153
|
+
const toolUseEl = tid && blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${tid}"]`);
|
|
2154
|
+
if (toolUseEl) {
|
|
2155
|
+
const isError = b.status === 'failed';
|
|
2156
|
+
const isDone = b.status === 'completed';
|
|
2157
|
+
if (isDone || isError) {
|
|
2158
|
+
toolUseEl.classList.add(isError ? 'tool-result-error' : 'tool-result-success');
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2098
2162
|
}
|
|
2099
2163
|
if (isActive) {
|
|
2100
2164
|
const ind = document.createElement('div');
|
|
@@ -2143,6 +2207,7 @@ class AgentGUIClient {
|
|
|
2143
2207
|
return;
|
|
2144
2208
|
}
|
|
2145
2209
|
}
|
|
2210
|
+
if (chunk.block.type === 'tool_status' || chunk.block.type === 'hook_progress') return;
|
|
2146
2211
|
const element = this.renderer.renderBlock(chunk.block, chunk, blocksEl);
|
|
2147
2212
|
if (!element) { this.scrollToBottom(); return; }
|
|
2148
2213
|
blocksEl.appendChild(element);
|
|
@@ -2199,13 +2264,13 @@ class AgentGUIClient {
|
|
|
2199
2264
|
.map(a => `<option value="${a.id}">${a.name.split(/[\s\-]+/)[0]}</option>`)
|
|
2200
2265
|
.join('');
|
|
2201
2266
|
this.ui.agentSelector.style.display = 'inline-block';
|
|
2202
|
-
|
|
2267
|
+
this._dbg(`[Agent Selector] Loaded ${subAgents.length} sub-agents for ${cliAgentId}`);
|
|
2203
2268
|
// Auto-select first sub-agent and load its models
|
|
2204
2269
|
const firstSubAgentId = subAgents[0].id;
|
|
2205
2270
|
this.ui.agentSelector.value = firstSubAgentId;
|
|
2206
2271
|
this.loadModelsForAgent(cliAgentId); // models keyed to parent agent
|
|
2207
2272
|
} else {
|
|
2208
|
-
|
|
2273
|
+
this._dbg(`[Agent Selector] No sub-agents found for ${cliAgentId}`);
|
|
2209
2274
|
// Load models for the CLI agent itself (fallback for agents without sub-agents)
|
|
2210
2275
|
const cliToAcpMap = {
|
|
2211
2276
|
'cli-opencode': 'opencode',
|
|
@@ -2447,7 +2512,7 @@ class AgentGUIClient {
|
|
|
2447
2512
|
}
|
|
2448
2513
|
if (progress.done || progress.status === 'completed') {
|
|
2449
2514
|
this._modelDownloadInProgress = false;
|
|
2450
|
-
|
|
2515
|
+
this._dbg('[Models] Download complete');
|
|
2451
2516
|
this._updateConnectionIndicator(this.wsManager?.latency?.quality || 'unknown');
|
|
2452
2517
|
return;
|
|
2453
2518
|
}
|
|
@@ -2459,7 +2524,7 @@ class AgentGUIClient {
|
|
|
2459
2524
|
|
|
2460
2525
|
_handleTTSSetupProgress(data) {
|
|
2461
2526
|
if (data.step && data.status) {
|
|
2462
|
-
|
|
2527
|
+
this._dbg('[TTS Setup]', data.step, ':', data.status, data.message || '');
|
|
2463
2528
|
}
|
|
2464
2529
|
}
|
|
2465
2530
|
|
|
@@ -2716,7 +2781,7 @@ class AgentGUIClient {
|
|
|
2716
2781
|
if (window.conversationManager) window.conversationManager.loadConversations();
|
|
2717
2782
|
const fallbackConv = prevConversationId ? prevConversationId : availableFallback?.id;
|
|
2718
2783
|
if (fallbackConv && fallbackConv !== conversationId) {
|
|
2719
|
-
|
|
2784
|
+
this._dbg('Resuming from fallback conversation:', fallbackConv);
|
|
2720
2785
|
this.showError('Conversation not found. Resuming previous conversation.');
|
|
2721
2786
|
await this.loadConversationMessages(fallbackConv);
|
|
2722
2787
|
} else {
|
|
@@ -2897,7 +2962,7 @@ class AgentGUIClient {
|
|
|
2897
2962
|
// Resume from last successful conversation if available, or fall back to any available conversation
|
|
2898
2963
|
const fallbackConv = prevConversationId ? prevConversationId : availableFallback?.id;
|
|
2899
2964
|
if (fallbackConv && fallbackConv !== conversationId) {
|
|
2900
|
-
|
|
2965
|
+
this._dbg('Resuming from fallback conversation due to error:', fallbackConv);
|
|
2901
2966
|
this.showError('Failed to load conversation. Resuming previous conversation.');
|
|
2902
2967
|
try {
|
|
2903
2968
|
await this.loadConversationMessages(fallbackConv);
|
|
@@ -3293,7 +3358,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
3293
3358
|
agentGUIClient = new AgentGUIClient();
|
|
3294
3359
|
window.agentGuiClient = agentGUIClient;
|
|
3295
3360
|
await agentGUIClient.init();
|
|
3296
|
-
|
|
3361
|
+
this._dbg('AgentGUI ready');
|
|
3297
3362
|
} catch (error) {
|
|
3298
3363
|
console.error('Failed to initialize AgentGUI:', error);
|
|
3299
3364
|
}
|
|
@@ -403,6 +403,8 @@ class StreamingRenderer {
|
|
|
403
403
|
return this.renderBlockPlan(block, context);
|
|
404
404
|
case 'premature':
|
|
405
405
|
return this.renderBlockPremature(block, context);
|
|
406
|
+
case 'hook_progress':
|
|
407
|
+
return this.renderBlockHookProgress(block, context);
|
|
406
408
|
default:
|
|
407
409
|
return this.renderBlockGeneric(block, context);
|
|
408
410
|
}
|
|
@@ -540,23 +542,28 @@ class StreamingRenderer {
|
|
|
540
542
|
* Render thinking block (expandable), signature-aware
|
|
541
543
|
*/
|
|
542
544
|
renderBlockThinking(block, context) {
|
|
545
|
+
const thinking = block.thinking || '';
|
|
546
|
+
const hasSignature = !!block.signature;
|
|
543
547
|
const div = document.createElement('div');
|
|
544
548
|
div.className = 'block-thinking';
|
|
545
549
|
div.classList.add(this._getBlockTypeClass('thinking'));
|
|
546
550
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
<
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
551
|
+
if (!thinking) {
|
|
552
|
+
div.style.cssText = 'display:flex;align-items:center;gap:0.375rem;padding:0.25rem 0;font-size:0.7rem;color:var(--color-text-secondary);opacity:0.6';
|
|
553
|
+
div.innerHTML = '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.875rem;height:0.875rem"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"/></svg>'
|
|
554
|
+
+ '<span>Thinking</span>'
|
|
555
|
+
+ (hasSignature ? '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem;color:#3b82f6"><path fill-rule="evenodd" d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>' : '');
|
|
556
|
+
return div;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
div.innerHTML = '<details>'
|
|
560
|
+
+ '<summary>'
|
|
561
|
+
+ '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/></svg>'
|
|
562
|
+
+ '<span>Thinking Process</span>'
|
|
563
|
+
+ (hasSignature ? '<span style="margin-left:0.5rem;font-size:0.65rem;opacity:0.5;font-weight:400">verified</span>' : '')
|
|
564
|
+
+ '</summary>'
|
|
565
|
+
+ '<div class="thinking-content">' + this.escapeHtml(thinking) + '</div>'
|
|
566
|
+
+ '</details>';
|
|
560
567
|
return div;
|
|
561
568
|
}
|
|
562
569
|
|
|
@@ -1437,6 +1444,23 @@ class StreamingRenderer {
|
|
|
1437
1444
|
return div;
|
|
1438
1445
|
}
|
|
1439
1446
|
|
|
1447
|
+
renderBlockHookProgress(block, context) {
|
|
1448
|
+
const hookEvent = block.hookEvent || block.hookName || '';
|
|
1449
|
+
const hookIcons = {
|
|
1450
|
+
PreToolUse: '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem"><path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10.666a1 1 0 11-1.64-1.118L9.687 10H5a1 1 0 01-.82-1.573l7-10.666a1 1 0 011.12-.373z" clip-rule="evenodd"/></svg>',
|
|
1451
|
+
PostToolUse: '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>',
|
|
1452
|
+
Stop: '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z" clip-rule="evenodd"/></svg>'
|
|
1453
|
+
};
|
|
1454
|
+
const icon = hookIcons[hookEvent.split(':')[0]] || hookIcons.PreToolUse;
|
|
1455
|
+
const label = hookEvent.includes(':') ? hookEvent.split(':').pop() : hookEvent;
|
|
1456
|
+
const div = document.createElement('div');
|
|
1457
|
+
div.className = 'block-hook-progress';
|
|
1458
|
+
div.dataset.hookEvent = hookEvent;
|
|
1459
|
+
div.style.cssText = 'display:none';
|
|
1460
|
+
div.innerHTML = '<span class="hook-badge" style="display:inline-flex;align-items:center;gap:0.25rem;padding:0.125rem 0.5rem;font-size:0.65rem;color:var(--color-text-secondary);opacity:0.5">' + icon + '<span>' + this.escapeHtml(label) + '</span></span>';
|
|
1461
|
+
return div;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1440
1464
|
/**
|
|
1441
1465
|
* Render usage block (ACP usage updates)
|
|
1442
1466
|
*/
|