agentgui 1.0.712 → 1.0.713

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.712",
3
+ "version": "1.0.713",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -910,12 +910,7 @@ class AgentGUIClient {
910
910
  if (chunk.block.type === 'tool_result') {
911
911
  const lastInFrag = bFrag.lastElementChild;
912
912
  if (lastInFrag?.classList?.contains('block-tool-use')) {
913
- lastInFrag.classList.remove('has-success', 'has-error');
914
- lastInFrag.classList.add(chunk.block.is_error ? 'has-error' : 'has-success');
915
- const parentIsOpen = lastInFrag.hasAttribute('open');
916
- const contextWithParent = { ...chunk, parentIsOpen };
917
- const el = this.renderer.renderBlock(chunk.block, contextWithParent, bFrag);
918
- if (el) { lastInFrag.appendChild(el); }
913
+ this.renderer.mergeResultIntoToolUse(lastInFrag, chunk.block);
919
914
  return;
920
915
  }
921
916
  }
@@ -1587,10 +1582,13 @@ class AgentGUIClient {
1587
1582
  let html = '<div class="message-blocks">';
1588
1583
  if (content.blocks && Array.isArray(content.blocks)) {
1589
1584
  let pendingToolUseClose = false;
1585
+ let pendingHasInput = false;
1590
1586
  content.blocks.forEach((block, blockIdx, blocks) => {
1591
1587
  if (block.type !== 'tool_result' && pendingToolUseClose) {
1588
+ if (pendingHasInput) html += '</div>';
1592
1589
  html += '</details>';
1593
1590
  pendingToolUseClose = false;
1591
+ pendingHasInput = false;
1594
1592
  }
1595
1593
  if (block.type === 'text') {
1596
1594
  const parts = this.parseMarkdownCodeBlocks(block.text);
@@ -1621,10 +1619,11 @@ class AgentGUIClient {
1621
1619
  html += `<div class="message-code"><details class="collapsible-code"><summary class="collapsible-code-summary">${this.escapeHtml(block.language || 'code')} - ${blkLineCount} line${blkLineCount !== 1 ? 's' : ''}</summary><pre style="margin:0;border-radius:0 0 0.375rem 0.375rem">${this.escapeHtml(block.code)}</pre></details></div>`;
1622
1620
  }
1623
1621
  } else if (block.type === 'tool_use') {
1624
- let inputHtml = '';
1625
- if (block.input && Object.keys(block.input).length > 0) {
1622
+ let inputContentHtml = '';
1623
+ const hasInput = block.input && Object.keys(block.input).length > 0;
1624
+ if (hasInput) {
1626
1625
  const inputStr = JSON.stringify(block.input, null, 2);
1627
- inputHtml = `<div class="folded-tool-body"><pre class="tool-input-pre">${this.escapeHtml(inputStr)}</pre></div>`;
1626
+ inputContentHtml = `<pre class="tool-input-pre">${this.escapeHtml(inputStr)}</pre>`;
1628
1627
  }
1629
1628
  const tn = block.name || 'unknown';
1630
1629
  const hasRenderer = typeof StreamingRenderer !== 'undefined';
@@ -1634,27 +1633,40 @@ class AgentGUIClient {
1634
1633
  const typeClass = hasRenderer && this.renderer ? this.renderer._getBlockTypeClass('tool_use') : 'block-type-tool_use';
1635
1634
  const toolColorClass = hasRenderer && this.renderer ? this.renderer._getToolColorClass(tn) : 'tool-color-default';
1636
1635
  const nextBlock = blocks[blockIdx + 1];
1637
- const resultClass = nextBlock?.type === 'tool_result' ? (nextBlock.is_error ? 'has-error' : 'has-success') : '';
1638
- html += `<details class="block-tool-use folded-tool ${typeClass} ${toolColorClass} ${resultClass}"><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}`;
1636
+ const resultClass = nextBlock?.type === 'tool_result' ? (nextBlock.is_error ? 'has-error tool-result-error' : 'has-success tool-result-success') : '';
1637
+ const resultStatusIcon = nextBlock?.type === 'tool_result'
1638
+ ? `<span class="folded-tool-status">${nextBlock.is_error
1639
+ ? '<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>'
1640
+ : '<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>'
1641
+ }</span>` : '';
1642
+ if (hasInput) {
1643
+ html += `<details class="block-tool-use folded-tool ${typeClass} ${toolColorClass} ${resultClass}"><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>` : ''}${resultStatusIcon}</summary><div class="folded-tool-body">${inputContentHtml}`;
1644
+ pendingHasInput = true;
1645
+ } else {
1646
+ html += `<details class="block-tool-use folded-tool ${typeClass} ${toolColorClass} ${resultClass}"><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>` : ''}${resultStatusIcon}</summary>`;
1647
+ pendingHasInput = false;
1648
+ }
1639
1649
  pendingToolUseClose = true;
1640
1650
  } else if (block.type === 'tool_result') {
1641
1651
  const content = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
1642
1652
  const smartHtml = typeof StreamingRenderer !== 'undefined' ? StreamingRenderer.renderSmartContentHTML(content, this.escapeHtml.bind(this), true) : `<pre class="tool-result-pre">${this.escapeHtml(content.length > 2000 ? content.substring(0, 2000) + '\n... (truncated)' : content)}</pre>`;
1643
- const resultPreview = content.length > 80 ? content.substring(0, 77).replace(/\n/g, ' ') + '...' : content.replace(/\n/g, ' ');
1644
- const resultIcon = block.is_error
1645
- ? '<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>'
1646
- : '<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>';
1647
- const resultTypeClass = hasRenderer && this.renderer ? this.renderer._getBlockTypeClass('tool_result') : 'block-type-tool_result';
1648
- const resultHtml = `<div class="tool-result-inline${block.is_error ? ' tool-result-error' : ' tool-result-success'} ${resultTypeClass}"><div class="tool-result-status"><span class="folded-tool-icon">${resultIcon}</span><span class="folded-tool-name">${block.is_error ? 'Error' : 'Success'}</span></div><div class="folded-tool-body">${smartHtml}</div></div>`;
1653
+ const resultContentHtml = `<div class="folded-tool-result-content">${smartHtml}</div>`;
1649
1654
  if (pendingToolUseClose) {
1650
- html += resultHtml + '</details>';
1655
+ if (pendingHasInput) {
1656
+ html += resultContentHtml + '</div></details>';
1657
+ } else {
1658
+ html += `<div class="folded-tool-body">${resultContentHtml}</div></details>`;
1659
+ }
1651
1660
  pendingToolUseClose = false;
1652
1661
  } else {
1653
- html += resultHtml;
1662
+ html += resultContentHtml;
1654
1663
  }
1655
1664
  }
1656
1665
  });
1657
- if (pendingToolUseClose) html += '</details>';
1666
+ if (pendingToolUseClose) {
1667
+ if (pendingHasInput) html += '</div>';
1668
+ html += '</details>';
1669
+ }
1658
1670
  }
1659
1671
  html += '</div>';
1660
1672
  return html;
@@ -2139,12 +2151,8 @@ class AgentGUIClient {
2139
2151
  const lastEl = blocksEl.lastElementChild;
2140
2152
  const toolUseEl = matchById || (lastEl?.classList?.contains('block-tool-use') ? lastEl : null);
2141
2153
  if (toolUseEl) {
2142
- toolUseEl.classList.remove('has-success', 'has-error');
2143
- toolUseEl.classList.add(chunk.block.is_error ? 'has-error' : 'has-success');
2144
- const parentIsOpen = toolUseEl.hasAttribute('open');
2145
- const contextWithParent = { ...chunk, parentIsOpen };
2146
- const element = this.renderer.renderBlock(chunk.block, contextWithParent, blocksEl);
2147
- if (element) { toolUseEl.appendChild(element); this.scrollToBottom(); }
2154
+ this.renderer.mergeResultIntoToolUse(toolUseEl, chunk.block);
2155
+ this.scrollToBottom();
2148
2156
  return;
2149
2157
  }
2150
2158
  }
@@ -2885,14 +2893,7 @@ class AgentGUIClient {
2885
2893
  ? blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${toolUseId}"]`)
2886
2894
  : blocksEl.lastElementChild?.classList?.contains('block-type-tool_use') ? blocksEl.lastElementChild : null;
2887
2895
  if (!toolUseEl) return;
2888
- toolUseEl.classList.remove('has-success', 'has-error');
2889
- toolUseEl.classList.add(chunk.block.is_error ? 'has-error' : 'has-success');
2890
- const contextWithParent = { ...chunk, parentIsOpen: toolUseEl.hasAttribute('open') };
2891
- const element = this.renderer.renderBlock(chunk.block, contextWithParent, toolUseEl);
2892
- if (element) {
2893
- element.classList.add('block-loaded');
2894
- toolUseEl.appendChild(element);
2895
- }
2896
+ this.renderer.mergeResultIntoToolUse(toolUseEl, chunk.block);
2896
2897
  });
2897
2898
 
2898
2899
  if (isCurrentActiveSession) {
@@ -1261,33 +1261,17 @@ class StreamingRenderer {
1261
1261
  const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
1262
1262
  const isError = (block.is_error || false) && !contentStr.trimStart().startsWith('exec ran successfully.');
1263
1263
 
1264
- const details = document.createElement('details');
1265
- details.className = 'folded-tool' + (isError ? ' folded-tool-error' : ' folded-tool-success');
1266
- details.dataset.eventType = 'tool_result';
1267
- // Only open by default if the content is an image and it's not an error
1268
- const isImageContent = contentStr.includes('data:image/') || (block.content && block.content.type === 'base64');
1269
- if (!isError && isImageContent) details.open = true;
1270
- if (block.tool_use_id) details.dataset.toolUseId = block.tool_use_id;
1271
- details.classList.add(this._getBlockTypeClass('tool_result'));
1272
-
1273
- const summary = document.createElement('summary');
1274
- summary.className = 'folded-tool-bar';
1275
- const iconSvg = isError
1276
- ? '<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>'
1277
- : '<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>';
1278
- summary.innerHTML = `
1279
- <span class="folded-tool-icon">${iconSvg}</span>
1280
- <span class="folded-tool-name">${isError ? 'Error' : 'Success'}</span>
1281
- `;
1282
- details.appendChild(summary);
1264
+ const container = document.createElement('div');
1265
+ container.className = 'tool-result-pending';
1266
+ container.dataset.eventType = 'tool_result';
1267
+ container.dataset.isError = isError ? '1' : '0';
1268
+ if (block.tool_use_id) container.dataset.toolUseId = block.tool_use_id;
1269
+ container.style.display = 'none';
1283
1270
 
1284
1271
  const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this), true);
1285
- const body = document.createElement('div');
1286
- body.className = 'folded-tool-body';
1287
- body.innerHTML = renderedContent;
1288
- details.appendChild(body);
1272
+ container.innerHTML = renderedContent;
1289
1273
 
1290
- return details;
1274
+ return container;
1291
1275
  }
1292
1276
 
1293
1277
  /**
@@ -2159,14 +2143,14 @@ class StreamingRenderer {
2159
2143
  if (!this.outputContainer) return;
2160
2144
 
2161
2145
  const toolUseBlocks = this.outputContainer.querySelectorAll('details.block-tool-use[data-tool-use-id]');
2162
- const toolResultBlocks = this.outputContainer.querySelectorAll('details[data-event-type="tool_result"][data-tool-use-id]');
2146
+ const toolResultBlocks = this.outputContainer.querySelectorAll('.tool-result-pending[data-tool-use-id]');
2163
2147
 
2164
2148
  toolResultBlocks.forEach(resultBlock => {
2165
2149
  const toolUseId = resultBlock.dataset.toolUseId;
2150
+ const isError = resultBlock.dataset.isError === '1';
2166
2151
  const toolUseBlock = Array.from(toolUseBlocks).find(b => b.dataset.toolUseId === toolUseId);
2167
2152
 
2168
- if (toolUseBlock && toolUseBlock.parentElement === resultBlock.parentElement) {
2169
- const isError = resultBlock.classList.contains('folded-tool-error');
2153
+ if (toolUseBlock) {
2170
2154
  const toolUseSummary = toolUseBlock.querySelector(':scope > summary');
2171
2155
 
2172
2156
  if (toolUseSummary && !toolUseSummary.querySelector('.folded-tool-status')) {
@@ -2180,8 +2164,7 @@ class StreamingRenderer {
2180
2164
  toolUseBlock.classList.add(isError ? 'tool-result-error' : 'tool-result-success');
2181
2165
  }
2182
2166
 
2183
- const resultBody = resultBlock.querySelector('.folded-tool-body');
2184
- if (resultBody && resultBody.innerHTML.trim()) {
2167
+ if (resultBlock.innerHTML.trim()) {
2185
2168
  let toolUseBody = toolUseBlock.querySelector(':scope > .folded-tool-body');
2186
2169
  if (!toolUseBody) {
2187
2170
  toolUseBody = document.createElement('div');
@@ -2190,10 +2173,12 @@ class StreamingRenderer {
2190
2173
  }
2191
2174
  const resultContent = document.createElement('div');
2192
2175
  resultContent.className = 'folded-tool-result-content';
2193
- resultContent.innerHTML = resultBody.innerHTML;
2176
+ resultContent.innerHTML = resultBlock.innerHTML;
2194
2177
  toolUseBody.appendChild(resultContent);
2195
2178
  }
2196
2179
 
2180
+ resultBlock.remove();
2181
+ } else {
2197
2182
  resultBlock.remove();
2198
2183
  }
2199
2184
  });
@@ -2202,6 +2187,40 @@ class StreamingRenderer {
2202
2187
  /**
2203
2188
  * Auto-scroll to bottom of container
2204
2189
  */
2190
+ mergeResultIntoToolUse(toolUseEl, block) {
2191
+ const content = block.content || '';
2192
+ const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
2193
+ const isError = (block.is_error || false) && !contentStr.trimStart().startsWith('exec ran successfully.');
2194
+
2195
+ toolUseEl.classList.remove('has-success', 'has-error');
2196
+ toolUseEl.classList.add(isError ? 'has-error tool-result-error' : 'has-success tool-result-success');
2197
+
2198
+ const summary = toolUseEl.querySelector(':scope > summary');
2199
+ if (summary && !summary.querySelector('.folded-tool-status')) {
2200
+ const statusSvg = isError
2201
+ ? '<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>'
2202
+ : '<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>';
2203
+ const statusSpan = document.createElement('span');
2204
+ statusSpan.className = 'folded-tool-status';
2205
+ statusSpan.innerHTML = statusSvg;
2206
+ summary.appendChild(statusSpan);
2207
+ }
2208
+
2209
+ const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this), true);
2210
+ if (renderedContent && renderedContent.trim()) {
2211
+ let toolUseBody = toolUseEl.querySelector(':scope > .folded-tool-body');
2212
+ if (!toolUseBody) {
2213
+ toolUseBody = document.createElement('div');
2214
+ toolUseBody.className = 'folded-tool-body';
2215
+ toolUseEl.appendChild(toolUseBody);
2216
+ }
2217
+ const resultContent = document.createElement('div');
2218
+ resultContent.className = 'folded-tool-result-content';
2219
+ resultContent.innerHTML = renderedContent;
2220
+ toolUseBody.appendChild(resultContent);
2221
+ }
2222
+ }
2223
+
2205
2224
  autoScroll() {
2206
2225
  if (this._scrollRafPending || this._userScrolledUp) return;
2207
2226
  this._scrollRafPending = true;