agentgui 1.0.241 → 1.0.242

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.241",
3
+ "version": "1.0.242",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/static/index.html CHANGED
@@ -1883,33 +1883,15 @@
1883
1883
  padding: 0.3rem 0.625rem;
1884
1884
  font-size: 0.75rem;
1885
1885
  line-height: 1.3;
1886
- cursor: pointer;
1886
+ cursor: default;
1887
1887
  user-select: none;
1888
- list-style: none;
1889
1888
  }
1890
1889
  .tool-result-status::-webkit-details-marker { display: none; }
1891
1890
  .tool-result-status::marker { display: none; content: ''; }
1892
- .tool-result-status::before {
1893
- content: '\25b6';
1894
- font-size: 0.5rem;
1895
- margin-right: 0.125rem;
1896
- display: inline-block;
1897
- transition: transform 0.15s;
1898
- color: #16a34a;
1899
- flex-shrink: 0;
1900
- }
1901
- html.dark .tool-result-status::before { color: #4ade80; }
1902
- .tool-result-inline[open] > .tool-result-status::before { transform: rotate(90deg); }
1903
- .tool-result-status:hover { background: #bbf7d0; }
1904
- html.dark .tool-result-status:hover { background: #14532d; }
1905
1891
  .tool-result-inline > .folded-tool-body { border-top: 1px solid #bbf7d0; }
1906
1892
  html.dark .tool-result-inline > .folded-tool-body { border-top-color: #166534; }
1907
1893
  .tool-result-error { background: #fef2f2; border-top-color: #fecaca; }
1908
1894
  html.dark .tool-result-error { background: #1f0a0a; border-top-color: #991b1b; }
1909
- .tool-result-error > .tool-result-status:hover { background: #fecaca; }
1910
- html.dark .tool-result-error > .tool-result-status:hover { background: #2d0f0f; }
1911
- .tool-result-error .tool-result-status::before { color: #dc2626; }
1912
- html.dark .tool-result-error .tool-result-status::before { color: #f87171; }
1913
1895
  .tool-result-error .folded-tool-icon { color: #dc2626; }
1914
1896
  html.dark .tool-result-error .folded-tool-icon { color: #f87171; }
1915
1897
  .tool-result-error .folded-tool-name { color: #991b1b; }
@@ -2390,6 +2372,174 @@
2390
2372
  animation: pulse 1s ease-in-out infinite;
2391
2373
  background-color: var(--color-warning) !important;
2392
2374
  }
2375
+
2376
+ /* ===== IN-UI DIALOGS ===== */
2377
+ .dialog-overlay {
2378
+ position: fixed;
2379
+ top: 0;
2380
+ left: 0;
2381
+ right: 0;
2382
+ bottom: 0;
2383
+ z-index: 10000;
2384
+ display: flex;
2385
+ align-items: center;
2386
+ justify-content: center;
2387
+ opacity: 0;
2388
+ transition: opacity 0.2s ease;
2389
+ }
2390
+ .dialog-overlay.visible { opacity: 1; }
2391
+ .dialog-backdrop {
2392
+ position: absolute;
2393
+ top: 0;
2394
+ left: 0;
2395
+ right: 0;
2396
+ bottom: 0;
2397
+ background: rgba(0, 0, 0, 0.5);
2398
+ backdrop-filter: blur(2px);
2399
+ }
2400
+ .dialog-container {
2401
+ position: fixed;
2402
+ top: 0;
2403
+ left: 0;
2404
+ right: 0;
2405
+ bottom: 0;
2406
+ display: flex;
2407
+ align-items: center;
2408
+ justify-content: center;
2409
+ z-index: 10001;
2410
+ opacity: 0;
2411
+ transition: opacity 0.2s ease;
2412
+ }
2413
+ .dialog-container.visible { opacity: 1; }
2414
+ .dialog-box {
2415
+ background: var(--color-bg-primary);
2416
+ border-radius: 0.75rem;
2417
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
2418
+ max-width: 90vw;
2419
+ width: 400px;
2420
+ overflow: hidden;
2421
+ transform: scale(0.95) translateY(-10px);
2422
+ transition: transform 0.2s ease;
2423
+ }
2424
+ .dialog-container.visible .dialog-box {
2425
+ transform: scale(1) translateY(0);
2426
+ }
2427
+ .dialog-box-progress { width: 450px; }
2428
+ .dialog-header {
2429
+ padding: 1rem 1.25rem;
2430
+ border-bottom: 1px solid var(--color-border);
2431
+ }
2432
+ .dialog-title {
2433
+ margin: 0;
2434
+ font-size: 1.1rem;
2435
+ font-weight: 600;
2436
+ }
2437
+ .dialog-body {
2438
+ padding: 1.25rem;
2439
+ }
2440
+ .dialog-message {
2441
+ margin: 0;
2442
+ font-size: 0.9rem;
2443
+ line-height: 1.5;
2444
+ color: var(--color-text-primary);
2445
+ }
2446
+ .dialog-label {
2447
+ display: block;
2448
+ margin-bottom: 0.5rem;
2449
+ font-size: 0.9rem;
2450
+ color: var(--color-text-primary);
2451
+ }
2452
+ .dialog-input {
2453
+ width: 100%;
2454
+ padding: 0.625rem 0.875rem;
2455
+ border: 1px solid var(--color-border);
2456
+ border-radius: 0.5rem;
2457
+ background: var(--color-bg-secondary);
2458
+ color: var(--color-text-primary);
2459
+ font-size: 0.9rem;
2460
+ outline: none;
2461
+ transition: border-color 0.15s, box-shadow 0.15s;
2462
+ }
2463
+ .dialog-input:focus {
2464
+ border-color: var(--color-primary);
2465
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
2466
+ }
2467
+ .dialog-footer {
2468
+ padding: 0.75rem 1.25rem;
2469
+ display: flex;
2470
+ justify-content: flex-end;
2471
+ gap: 0.5rem;
2472
+ border-top: 1px solid var(--color-border);
2473
+ background: var(--color-bg-secondary);
2474
+ }
2475
+ .dialog-btn {
2476
+ padding: 0.5rem 1.25rem;
2477
+ border: none;
2478
+ border-radius: 0.5rem;
2479
+ font-size: 0.875rem;
2480
+ font-weight: 500;
2481
+ cursor: pointer;
2482
+ transition: all 0.15s;
2483
+ }
2484
+ .dialog-btn-primary {
2485
+ background: var(--color-primary);
2486
+ color: white;
2487
+ }
2488
+ .dialog-btn-primary:hover { background: var(--color-primary-dark); }
2489
+ .dialog-btn-secondary {
2490
+ background: var(--color-bg-primary);
2491
+ color: var(--color-text-primary);
2492
+ border: 1px solid var(--color-border);
2493
+ }
2494
+ .dialog-btn-secondary:hover { background: var(--color-bg-secondary); }
2495
+ .dialog-btn-danger { background: var(--color-error); }
2496
+ .dialog-btn-danger:hover { background: #dc2626; }
2497
+ .dialog-progress-bar {
2498
+ height: 8px;
2499
+ background: var(--color-bg-secondary);
2500
+ border-radius: 4px;
2501
+ overflow: hidden;
2502
+ margin: 1rem 0 0.5rem;
2503
+ }
2504
+ .dialog-progress-fill {
2505
+ height: 100%;
2506
+ background: var(--color-primary);
2507
+ border-radius: 4px;
2508
+ transition: width 0.3s ease;
2509
+ }
2510
+ .dialog-progress-percent {
2511
+ margin: 0;
2512
+ text-align: center;
2513
+ font-size: 0.8rem;
2514
+ color: var(--color-text-secondary);
2515
+ }
2516
+
2517
+ /* ===== TOAST NOTIFICATIONS ===== */
2518
+ .toast-notification {
2519
+ position: fixed;
2520
+ bottom: 100px;
2521
+ left: 50%;
2522
+ transform: translateX(-50%) translateY(20px);
2523
+ padding: 0.75rem 1.5rem;
2524
+ border-radius: 0.5rem;
2525
+ font-size: 0.875rem;
2526
+ font-weight: 500;
2527
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
2528
+ z-index: 20000;
2529
+ opacity: 0;
2530
+ transition: all 0.3s ease;
2531
+ display: flex;
2532
+ align-items: center;
2533
+ gap: 0.5rem;
2534
+ }
2535
+ .toast-notification.visible {
2536
+ opacity: 1;
2537
+ transform: translateX(-50%) translateY(0);
2538
+ }
2539
+ .toast-info { background: var(--color-primary); color: white; }
2540
+ .toast-success { background: var(--color-success); color: white; }
2541
+ .toast-error { background: var(--color-error); color: white; }
2542
+ .toast-warning { background: var(--color-warning); color: white; }
2393
2543
  </style>
2394
2544
  </head>
2395
2545
  <body>
@@ -2597,6 +2747,7 @@
2597
2747
  <script defer src="/gm/js/websocket-manager.js"></script>
2598
2748
  <script defer src="/gm/js/event-filter.js"></script>
2599
2749
  <script defer src="/gm/js/syntax-highlighter.js"></script>
2750
+ <script defer src="/gm/js/dialogs.js"></script>
2600
2751
  <script defer src="/gm/js/ui-components.js"></script>
2601
2752
  <script defer src="/gm/js/conversations.js"></script>
2602
2753
  <script defer src="/gm/js/client.js"></script>
@@ -282,10 +282,12 @@ class AgentGUIClient {
282
282
 
283
283
  try {
284
284
  const position = localStorage.getItem(`scroll_${conversationId}`);
285
+ const scrollContainer = document.getElementById(this.config.scrollContainerId);
286
+ if (!scrollContainer) return;
287
+
285
288
  if (position !== null) {
286
289
  const scrollTop = parseInt(position, 10);
287
- const scrollContainer = document.getElementById(this.config.scrollContainerId);
288
- if (scrollContainer && !isNaN(scrollTop)) {
290
+ if (!isNaN(scrollTop)) {
289
291
  requestAnimationFrame(() => {
290
292
  requestAnimationFrame(() => {
291
293
  const maxScroll = scrollContainer.scrollHeight - scrollContainer.clientHeight;
@@ -293,6 +295,12 @@ class AgentGUIClient {
293
295
  });
294
296
  });
295
297
  }
298
+ } else {
299
+ requestAnimationFrame(() => {
300
+ requestAnimationFrame(() => {
301
+ scrollContainer.scrollTop = 0;
302
+ });
303
+ });
296
304
  }
297
305
  } catch (e) {
298
306
  console.warn('Failed to restore scroll position:', e);
@@ -368,7 +376,7 @@ class AgentGUIClient {
368
376
  if (this.ui.injectButton) {
369
377
  this.ui.injectButton.addEventListener('click', async () => {
370
378
  if (!this.state.currentConversation) return;
371
- const instructions = prompt('Enter instructions to inject into the running agent:');
379
+ const instructions = await window.UIDialog.prompt('Enter instructions to inject into the running agent:', '', 'Inject Instructions');
372
380
  if (!instructions) return;
373
381
  try {
374
382
  const resp = await fetch(`${window.__BASE_URL}/api/conversations/${this.state.currentConversation.id}/inject`, {
@@ -981,17 +989,17 @@ class AgentGUIClient {
981
989
  btn.addEventListener('click', async (e) => {
982
990
  const index = parseInt(e.target.dataset.index);
983
991
  const msgId = queue[index].messageId;
984
- if (confirm('Delete this queued message?')) {
992
+ if (await window.UIDialog.confirm('Delete this queued message?', 'Delete Message')) {
985
993
  await fetch(window.__BASE_URL + `/api/conversations/${conversationId}/queue/${msgId}`, { method: 'DELETE' });
986
994
  }
987
995
  });
988
996
  });
989
997
 
990
998
  queueEl.querySelectorAll('.queue-edit-btn').forEach(btn => {
991
- btn.addEventListener('click', (e) => {
999
+ btn.addEventListener('click', async (e) => {
992
1000
  const index = parseInt(e.target.dataset.index);
993
1001
  const q = queue[index];
994
- const newContent = prompt('Edit message:', q.content);
1002
+ const newContent = await window.UIDialog.prompt('Edit message:', q.content, 'Edit Queued Message');
995
1003
  if (newContent !== null && newContent !== q.content) {
996
1004
  fetch(window.__BASE_URL + `/api/conversations/${conversationId}/queue/${q.messageId}`, {
997
1005
  method: 'PATCH',
@@ -1176,7 +1184,8 @@ class AgentGUIClient {
1176
1184
  const dName = hasRenderer ? StreamingRenderer.getToolDisplayName(tn) : tn;
1177
1185
  const tTitle = hasRenderer && block.input ? StreamingRenderer.getToolTitle(tn, block.input) : '';
1178
1186
  const iconHtml = hasRenderer && this.renderer ? `<span class="folded-tool-icon">${this.renderer.getToolIcon(tn)}</span>` : '';
1179
- html += `<details class="block-tool-use folded-tool"><summary class="folded-tool-bar">${iconHtml}<span class="folded-tool-name">${this.escapeHtml(dName)}</span>${tTitle ? `<span class="folded-tool-desc">${this.escapeHtml(tTitle)}</span>` : ''}</summary>${inputHtml}`;
1187
+ const colorIdx = hasRenderer && this.renderer ? this.renderer._getBlockColorIndex('tool_use') : 1;
1188
+ html += `<details class="block-tool-use folded-tool" open style="border-left:3px solid var(--block-color-${colorIdx})"><summary class="folded-tool-bar">${iconHtml}<span class="folded-tool-name">${this.escapeHtml(dName)}</span>${tTitle ? `<span class="folded-tool-desc">${this.escapeHtml(tTitle)}</span>` : ''}</summary>${inputHtml}`;
1180
1189
  pendingToolUseClose = true;
1181
1190
  } else if (block.type === 'tool_result') {
1182
1191
  const content = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
@@ -1185,7 +1194,8 @@ class AgentGUIClient {
1185
1194
  const resultIcon = block.is_error
1186
1195
  ? '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/></svg>'
1187
1196
  : '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 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>';
1188
- const resultHtml = `<details class="tool-result-inline${block.is_error ? ' tool-result-error' : ''}"><summary class="tool-result-status"><span class="folded-tool-icon">${resultIcon}</span><span class="folded-tool-name">${block.is_error ? 'Error' : 'Success'}</span><span class="folded-tool-desc">${this.escapeHtml(resultPreview)}</span></summary><div class="folded-tool-body">${smartHtml}</div></details>`;
1197
+ const colorIdx = hasRenderer && this.renderer ? this.renderer._getBlockColorIndex('tool_result') : 2;
1198
+ const resultHtml = `<div class="tool-result-inline${block.is_error ? ' tool-result-error' : ''}" style="border-left:3px solid var(--block-color-${colorIdx})"><div class="tool-result-status"><span class="folded-tool-icon">${resultIcon}</span><span class="folded-tool-name">${block.is_error ? 'Error' : 'Success'}</span><span class="folded-tool-desc">${this.escapeHtml(resultPreview)}</span></div><div class="folded-tool-body">${smartHtml}</div></div>`;
1189
1199
  if (pendingToolUseClose) {
1190
1200
  html += resultHtml + '</details>';
1191
1201
  pendingToolUseClose = false;
@@ -1996,6 +2006,13 @@ class AgentGUIClient {
1996
2006
  this._modelDownloadInProgress = false;
1997
2007
  console.error('[Models] Download error:', progress.error);
1998
2008
  this._updateConnectionIndicator(this.wsManager?.latency?.quality || 'unknown');
2009
+ if (window._voiceProgressDialog) {
2010
+ window._voiceProgressDialog.close();
2011
+ window._voiceProgressDialog = null;
2012
+ }
2013
+ if (window.UIDialog) {
2014
+ window.UIDialog.alert('Failed to download voice models: ' + progress.error, 'Download Error');
2015
+ }
1999
2016
  return;
2000
2017
  }
2001
2018
 
@@ -2004,12 +2021,30 @@ class AgentGUIClient {
2004
2021
  console.log('[Models] Download complete');
2005
2022
  this._updateConnectionIndicator(this.wsManager?.latency?.quality || 'unknown');
2006
2023
  this._updateVoiceTabState();
2024
+ if (window._voiceProgressDialog) {
2025
+ window._voiceProgressDialog.update(100, 'Voice models ready!');
2026
+ setTimeout(function() {
2027
+ if (window._voiceProgressDialog) {
2028
+ window._voiceProgressDialog.close();
2029
+ window._voiceProgressDialog = null;
2030
+ }
2031
+ }, 500);
2032
+ }
2007
2033
  return;
2008
2034
  }
2009
2035
 
2010
2036
  if (progress.started || progress.downloading) {
2011
2037
  this._modelDownloadInProgress = true;
2012
2038
  this._updateConnectionIndicator(this.wsManager?.latency?.quality || 'unknown');
2039
+
2040
+ if (window._voiceProgressDialog && progress.totalBytes > 0) {
2041
+ var pct = Math.round((progress.totalDownloaded / progress.totalBytes) * 100);
2042
+ var mb = Math.round(progress.totalBytes / 1024 / 1024);
2043
+ var downloaded = Math.round((progress.totalDownloaded || 0) / 1024 / 1024);
2044
+ window._voiceProgressDialog.update(pct, 'Downloading ' + downloaded + 'MB / ' + mb + 'MB');
2045
+ } else if (window._voiceProgressDialog && progress.file) {
2046
+ window._voiceProgressDialog.update(0, 'Loading ' + progress.file + '...');
2047
+ }
2013
2048
  }
2014
2049
  }
2015
2050
 
@@ -2018,8 +2053,7 @@ class AgentGUIClient {
2018
2053
  if (voiceBtn) {
2019
2054
  var isReady = this._modelDownloadProgress?.done === true ||
2020
2055
  this._modelDownloadProgress?.complete === true;
2021
- voiceBtn.disabled = !isReady;
2022
- voiceBtn.title = isReady ? 'Voice' : 'Downloading voice models...';
2056
+ voiceBtn.title = isReady ? 'Voice' : 'Voice (click to download models)';
2023
2057
  }
2024
2058
  }
2025
2059
 
@@ -2438,8 +2472,9 @@ class AgentGUIClient {
2438
2472
  */
2439
2473
  showError(message) {
2440
2474
  console.error(message);
2441
- // Could display in a toast or alert
2442
- alert(message);
2475
+ if (window.UIDialog) {
2476
+ window.UIDialog.alert(message, 'Error');
2477
+ }
2443
2478
  }
2444
2479
 
2445
2480
  /**
@@ -399,23 +399,25 @@ class StreamingRenderer {
399
399
  div.className = 'block-text';
400
400
  if (isHtml) div.classList.add('html-content');
401
401
  div.innerHTML = html;
402
- const colorIndex = this._getUniqueColorIndex(text);
402
+ const colorIndex = this._getBlockColorIndex('text');
403
403
  div.style.borderLeft = `3px solid var(--block-color-${colorIndex})`;
404
404
  return div;
405
405
  }
406
406
 
407
- _getUniqueColorIndex(text) {
408
- if (!this._colorIndexMap) {
409
- this._colorIndexMap = new Map();
410
- this._colorCounter = 0;
411
- }
412
- let index = this._colorIndexMap.get(text);
413
- if (index === undefined) {
414
- index = this._colorCounter % 10;
415
- this._colorIndexMap.set(text, index);
416
- this._colorCounter++;
417
- }
418
- return index;
407
+ _getBlockColorIndex(blockType) {
408
+ const typeColors = {
409
+ 'text': 0,
410
+ 'tool_use': 1,
411
+ 'tool_result': 2,
412
+ 'code': 3,
413
+ 'thinking': 4,
414
+ 'bash': 5,
415
+ 'system': 6,
416
+ 'result': 7,
417
+ 'error': 8,
418
+ 'image': 9
419
+ };
420
+ return typeColors[blockType] !== undefined ? typeColors[blockType] : 0;
419
421
  }
420
422
 
421
423
  containsHtmlTags(text) {
@@ -733,7 +735,10 @@ class StreamingRenderer {
733
735
 
734
736
  const details = document.createElement('details');
735
737
  details.className = 'block-tool-use folded-tool';
738
+ details.setAttribute('open', '');
736
739
  if (block.id) details.dataset.toolUseId = block.id;
740
+ const colorIndex = this._getBlockColorIndex('tool_use');
741
+ details.style.borderLeft = `3px solid var(--block-color-${colorIndex})`;
737
742
  const summary = document.createElement('summary');
738
743
  summary.className = 'folded-tool-bar';
739
744
  const displayName = this.getToolUseDisplayName(toolName);
@@ -1199,33 +1204,34 @@ class StreamingRenderer {
1199
1204
  const isError = block.is_error || false;
1200
1205
  const content = block.content || '';
1201
1206
  const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
1202
- const preview = contentStr.length > 80 ? contentStr.substring(0, 77).replace(/\n/g, ' ') + '...' : contentStr.replace(/\n/g, ' ');
1203
1207
 
1204
- const details = document.createElement('details');
1205
- details.className = 'tool-result-inline' + (isError ? ' tool-result-error' : '');
1206
- details.dataset.eventType = 'tool_result';
1207
- if (block.tool_use_id) details.dataset.toolUseId = block.tool_use_id;
1208
+ const wrapper = document.createElement('div');
1209
+ wrapper.className = 'tool-result-inline' + (isError ? ' tool-result-error' : '');
1210
+ wrapper.dataset.eventType = 'tool_result';
1211
+ if (block.tool_use_id) wrapper.dataset.toolUseId = block.tool_use_id;
1212
+ const colorIndex = this._getBlockColorIndex('tool_result');
1213
+ wrapper.style.borderLeft = `3px solid var(--block-color-${colorIndex})`;
1208
1214
 
1215
+ const header = document.createElement('div');
1216
+ header.className = 'tool-result-status';
1209
1217
  const iconSvg = isError
1210
1218
  ? '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/></svg>'
1211
1219
  : '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 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>';
1212
-
1213
- const summary = document.createElement('summary');
1214
- summary.className = 'tool-result-status';
1215
- summary.innerHTML = `
1220
+ const preview = contentStr.length > 80 ? contentStr.substring(0, 77).replace(/\n/g, ' ') + '...' : contentStr.replace(/\n/g, ' ');
1221
+ header.innerHTML = `
1216
1222
  <span class="folded-tool-icon">${iconSvg}</span>
1217
1223
  <span class="folded-tool-name">${isError ? 'Error' : 'Success'}</span>
1218
1224
  <span class="folded-tool-desc">${this.escapeHtml(preview)}</span>
1219
1225
  `;
1220
- details.appendChild(summary);
1226
+ wrapper.appendChild(header);
1221
1227
 
1222
1228
  const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this));
1223
1229
  const body = document.createElement('div');
1224
1230
  body.className = 'folded-tool-body';
1225
1231
  body.innerHTML = renderedContent;
1226
- details.appendChild(body);
1232
+ wrapper.appendChild(body);
1227
1233
 
1228
- return details;
1234
+ return wrapper;
1229
1235
  }
1230
1236
 
1231
1237
  /**