agentgui 1.0.555 → 1.0.556

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.555",
3
+ "version": "1.0.556",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -2637,26 +2637,34 @@ class AgentGUIClient {
2637
2637
 
2638
2638
  const blocksEl = messageDiv.querySelector('.message-blocks');
2639
2639
  const blockFrag = document.createDocumentFragment();
2640
+ const toolResultBlocks = new Map();
2641
+
2640
2642
  sessionChunkList.forEach(chunk => {
2641
2643
  if (!chunk.block?.type) return;
2642
2644
  if (chunk.block.type === 'tool_result') {
2643
- const lastInFrag = blockFrag.lastElementChild;
2644
- if (lastInFrag?.classList?.contains('block-tool-use')) {
2645
- lastInFrag.classList.remove('has-success', 'has-error');
2646
- lastInFrag.classList.add(chunk.block.is_error ? 'has-error' : 'has-success');
2647
- const parentIsOpen = lastInFrag.hasAttribute('open');
2648
- const contextWithParent = { ...chunk, parentIsOpen };
2649
- const element = this.renderer.renderBlock(chunk.block, contextWithParent, blockFrag);
2650
- if (element) { lastInFrag.appendChild(element); }
2651
- return;
2652
- }
2645
+ toolResultBlocks.set(chunk.id, chunk);
2646
+ return;
2653
2647
  }
2654
- const element = this.renderer.renderBlock(chunk.block, chunk, blockFrag);
2648
+ const element = this.renderer.renderBlockHeader(chunk.block, chunk);
2655
2649
  if (!element) return;
2656
2650
  blockFrag.appendChild(element);
2657
2651
  });
2652
+
2658
2653
  blocksEl.appendChild(blockFrag);
2659
2654
 
2655
+ toolResultBlocks.forEach((chunk, chunkId) => {
2656
+ const lastBlock = blocksEl.lastElementChild;
2657
+ if (lastBlock?.classList?.contains('block-type-tool_use')) {
2658
+ lastBlock.classList.remove('has-success', 'has-error');
2659
+ lastBlock.classList.add(chunk.block.is_error ? 'has-error' : 'has-success');
2660
+ const contextWithParent = { ...chunk, parentIsOpen: lastBlock.hasAttribute('open') };
2661
+ const element = this.renderer.renderBlock(chunk.block, contextWithParent);
2662
+ if (element && element !== blockFrag.lastElementChild) {
2663
+ lastBlock.appendChild(element);
2664
+ }
2665
+ }
2666
+ });
2667
+
2660
2668
  if (isCurrentActiveSession) {
2661
2669
  const indicatorDiv = document.createElement('div');
2662
2670
  indicatorDiv.className = 'streaming-indicator';
@@ -2154,6 +2154,59 @@ class StreamingRenderer {
2154
2154
  }
2155
2155
  }
2156
2156
 
2157
+ /**
2158
+ * Render block header with lazy-loading placeholder for body
2159
+ * Returns a <details> element with just the summary, body content deferred
2160
+ */
2161
+ renderBlockHeader(block, context = {}) {
2162
+ if (!block || !block.type) return null;
2163
+
2164
+ const typeLabel = block.type.charAt(0).toUpperCase() + block.type.slice(1).replace(/_/g, ' ');
2165
+ const summary = document.createElement('summary');
2166
+ summary.style.cursor = 'pointer';
2167
+ summary.style.userSelect = 'none';
2168
+ summary.className = 'block-header-summary';
2169
+
2170
+ let summaryText = typeLabel;
2171
+ if (block.type === 'code' && block.language) {
2172
+ summaryText += ` (${block.language})`;
2173
+ } else if (block.type === 'bash' && block.source) {
2174
+ summaryText += ` - ${block.source}`;
2175
+ } else if (block.type === 'tool_use' && block.name) {
2176
+ summaryText += ` - ${block.name}`;
2177
+ } else if (block.type === 'text' && block.text) {
2178
+ const preview = block.text.substring(0, 60).replace(/\n/g, ' ');
2179
+ summaryText = preview + (block.text.length > 60 ? '...' : '');
2180
+ }
2181
+
2182
+ summary.textContent = summaryText;
2183
+
2184
+ const details = document.createElement('details');
2185
+ details.className = `block-type-${block.type}`;
2186
+ details.setAttribute('data-block-type', block.type);
2187
+ details.setAttribute('data-lazy-load', 'pending');
2188
+ details.appendChild(summary);
2189
+
2190
+ // Attach lazy loader on first open
2191
+ details.addEventListener('toggle', async (e) => {
2192
+ if (details.open && details.getAttribute('data-lazy-load') === 'pending') {
2193
+ details.setAttribute('data-lazy-load', 'loading');
2194
+ try {
2195
+ const body = this.renderBlock(block, context);
2196
+ if (body && body !== summary) {
2197
+ details.appendChild(body);
2198
+ }
2199
+ details.setAttribute('data-lazy-load', 'loaded');
2200
+ } catch (err) {
2201
+ console.error('Failed to lazy-load block:', err);
2202
+ details.setAttribute('data-lazy-load', 'failed');
2203
+ }
2204
+ }
2205
+ }, { once: false });
2206
+
2207
+ return details;
2208
+ }
2209
+
2157
2210
  /**
2158
2211
  * Cleanup resources
2159
2212
  */