agentgui 1.0.163 → 1.0.164

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.163",
3
+ "version": "1.0.164",
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
@@ -1614,6 +1614,55 @@
1614
1614
  .folded-tool-info > .folded-tool-body { border-top-color: #c7d2fe; }
1615
1615
  html.dark .folded-tool-info > .folded-tool-body { border-top-color: #3730a3; }
1616
1616
 
1617
+ /* --- Inline Tool Result (nested inside tool_use) --- */
1618
+ .tool-result-inline {
1619
+ border-top: 1px solid #bbf7d0;
1620
+ overflow: hidden;
1621
+ }
1622
+ html.dark .tool-result-inline { border-top-color: #166534; }
1623
+ .tool-result-status {
1624
+ display: flex;
1625
+ align-items: center;
1626
+ gap: 0.375rem;
1627
+ padding: 0.3rem 0.625rem;
1628
+ font-size: 0.75rem;
1629
+ line-height: 1.3;
1630
+ cursor: pointer;
1631
+ user-select: none;
1632
+ list-style: none;
1633
+ }
1634
+ .tool-result-status::-webkit-details-marker { display: none; }
1635
+ .tool-result-status::marker { display: none; content: ''; }
1636
+ .tool-result-status::before {
1637
+ content: '\25b6';
1638
+ font-size: 0.5rem;
1639
+ margin-right: 0.125rem;
1640
+ display: inline-block;
1641
+ transition: transform 0.15s;
1642
+ color: #16a34a;
1643
+ flex-shrink: 0;
1644
+ }
1645
+ html.dark .tool-result-status::before { color: #4ade80; }
1646
+ .tool-result-inline[open] > .tool-result-status::before { transform: rotate(90deg); }
1647
+ .tool-result-status:hover { background: #bbf7d0; }
1648
+ html.dark .tool-result-status:hover { background: #14532d; }
1649
+ .tool-result-inline > .folded-tool-body { border-top: 1px solid #bbf7d0; }
1650
+ html.dark .tool-result-inline > .folded-tool-body { border-top-color: #166534; }
1651
+ .tool-result-error { background: #fef2f2; border-top-color: #fecaca; }
1652
+ html.dark .tool-result-error { background: #1f0a0a; border-top-color: #991b1b; }
1653
+ .tool-result-error > .tool-result-status:hover { background: #fecaca; }
1654
+ html.dark .tool-result-error > .tool-result-status:hover { background: #2d0f0f; }
1655
+ .tool-result-error .tool-result-status::before { color: #dc2626; }
1656
+ html.dark .tool-result-error .tool-result-status::before { color: #f87171; }
1657
+ .tool-result-error .folded-tool-icon { color: #dc2626; }
1658
+ html.dark .tool-result-error .folded-tool-icon { color: #f87171; }
1659
+ .tool-result-error .folded-tool-name { color: #991b1b; }
1660
+ html.dark .tool-result-error .folded-tool-name { color: #fca5a5; }
1661
+ .tool-result-error .folded-tool-desc { color: #b91c1c; }
1662
+ html.dark .tool-result-error .folded-tool-desc { color: #f87171; }
1663
+ .tool-result-error > .folded-tool-body { border-top-color: #fecaca; }
1664
+ html.dark .tool-result-error > .folded-tool-body { border-top-color: #991b1b; }
1665
+
1617
1666
  /* --- Collapsible Code Summary --- */
1618
1667
  .collapsible-code {
1619
1668
  margin: 0.125rem 0;
@@ -476,7 +476,16 @@ class AgentGUIClient {
476
476
  mDiv.innerHTML = '<div class="message-role">Assistant</div><div class="message-blocks streaming-blocks"></div>';
477
477
  const bEl = mDiv.querySelector('.message-blocks');
478
478
  const bFrag = document.createDocumentFragment();
479
- sList.forEach(chunk => { if (chunk.block?.type) { const el = this.renderer.renderBlock(chunk.block, chunk); if (el) bFrag.appendChild(el); } });
479
+ sList.forEach(chunk => {
480
+ if (!chunk.block?.type) return;
481
+ const el = this.renderer.renderBlock(chunk.block, chunk);
482
+ if (!el) return;
483
+ if (chunk.block.type === 'tool_result') {
484
+ const lastInFrag = bFrag.lastElementChild;
485
+ if (lastInFrag?.classList?.contains('block-tool-use')) { lastInFrag.appendChild(el); return; }
486
+ }
487
+ bFrag.appendChild(el);
488
+ });
480
489
  bEl.appendChild(bFrag);
481
490
  const ts = document.createElement('div'); ts.className = 'message-timestamp'; ts.textContent = new Date(sList[sList.length - 1].created_at).toLocaleString();
482
491
  mDiv.appendChild(ts);
@@ -833,7 +842,12 @@ class AgentGUIClient {
833
842
  } else if (content && typeof content === 'object' && content.type === 'claude_execution') {
834
843
  let html = '<div class="message-blocks">';
835
844
  if (content.blocks && Array.isArray(content.blocks)) {
845
+ let pendingToolUseClose = false;
836
846
  content.blocks.forEach(block => {
847
+ if (block.type !== 'tool_result' && pendingToolUseClose) {
848
+ html += '</details>';
849
+ pendingToolUseClose = false;
850
+ }
837
851
  if (block.type === 'text') {
838
852
  const parts = this.parseMarkdownCodeBlocks(block.text);
839
853
  parts.forEach(part => {
@@ -873,7 +887,8 @@ class AgentGUIClient {
873
887
  const dName = hasRenderer ? StreamingRenderer.getToolDisplayName(tn) : tn;
874
888
  const tTitle = hasRenderer && block.input ? StreamingRenderer.getToolTitle(tn, block.input) : '';
875
889
  const iconHtml = hasRenderer && this.renderer ? `<span class="folded-tool-icon">${this.renderer.getToolIcon(tn)}</span>` : '';
876
- html += `<details class="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}</details>`;
890
+ 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}`;
891
+ pendingToolUseClose = true;
877
892
  } else if (block.type === 'tool_result') {
878
893
  const content = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
879
894
  const smartHtml = typeof StreamingRenderer !== 'undefined' ? StreamingRenderer.renderSmartContentHTML(content, this.escapeHtml.bind(this)) : `<pre class="tool-result-pre">${this.escapeHtml(content.length > 2000 ? content.substring(0, 2000) + '\n... (truncated)' : content)}</pre>`;
@@ -881,9 +896,16 @@ class AgentGUIClient {
881
896
  const resultIcon = block.is_error
882
897
  ? '<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>'
883
898
  : '<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>';
884
- html += `<details class="folded-tool${block.is_error ? ' folded-tool-error' : ''}"><summary class="folded-tool-bar"><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>`;
899
+ 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>`;
900
+ if (pendingToolUseClose) {
901
+ html += resultHtml + '</details>';
902
+ pendingToolUseClose = false;
903
+ } else {
904
+ html += resultHtml;
905
+ }
885
906
  }
886
907
  });
908
+ if (pendingToolUseClose) html += '</details>';
887
909
  }
888
910
  html += '</div>';
889
911
  return html;
@@ -1116,10 +1138,15 @@ class AgentGUIClient {
1116
1138
  const blocksEl = streamingEl.querySelector('.streaming-blocks');
1117
1139
  if (!blocksEl) return;
1118
1140
  const element = this.renderer.renderBlock(chunk.block, chunk);
1119
- if (element) {
1120
- blocksEl.appendChild(element);
1121
- this.scrollToBottom();
1141
+ if (!element) return;
1142
+ if (chunk.block.type === 'tool_result') {
1143
+ const matchById = chunk.block.tool_use_id && blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${chunk.block.tool_use_id}"]`);
1144
+ const lastEl = blocksEl.lastElementChild;
1145
+ const toolUseEl = matchById || (lastEl?.classList?.contains('block-tool-use') ? lastEl : null);
1146
+ if (toolUseEl) { toolUseEl.appendChild(element); this.scrollToBottom(); return; }
1122
1147
  }
1148
+ blocksEl.appendChild(element);
1149
+ this.scrollToBottom();
1123
1150
  }
1124
1151
 
1125
1152
  renderChunkBatch(chunks) {
@@ -1136,13 +1163,20 @@ class AgentGUIClient {
1136
1163
  if (!streamingEl) continue;
1137
1164
  const blocksEl = streamingEl.querySelector('.streaming-blocks');
1138
1165
  if (!blocksEl) continue;
1139
- const frag = document.createDocumentFragment();
1140
1166
  for (const chunk of groups[sid]) {
1141
1167
  const el = this.renderer.renderBlock(chunk.block, chunk);
1142
- if (el) frag.appendChild(el);
1143
- }
1144
- if (frag.childNodes.length) {
1145
- blocksEl.appendChild(frag);
1168
+ if (!el) continue;
1169
+ if (chunk.block.type === 'tool_result') {
1170
+ const matchById = chunk.block.tool_use_id && blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${chunk.block.tool_use_id}"]`);
1171
+ const lastEl = blocksEl.lastElementChild;
1172
+ const toolUseEl = matchById || (lastEl?.classList?.contains('block-tool-use') ? lastEl : null);
1173
+ if (toolUseEl) {
1174
+ toolUseEl.appendChild(el);
1175
+ appended = true;
1176
+ continue;
1177
+ }
1178
+ }
1179
+ blocksEl.appendChild(el);
1146
1180
  appended = true;
1147
1181
  }
1148
1182
  }
@@ -1429,10 +1463,14 @@ class AgentGUIClient {
1429
1463
  const blocksEl = messageDiv.querySelector('.message-blocks');
1430
1464
  const blockFrag = document.createDocumentFragment();
1431
1465
  sessionChunkList.forEach(chunk => {
1432
- if (chunk.block && chunk.block.type) {
1433
- const element = this.renderer.renderBlock(chunk.block, chunk);
1434
- if (element) blockFrag.appendChild(element);
1466
+ if (!chunk.block?.type) return;
1467
+ const element = this.renderer.renderBlock(chunk.block, chunk);
1468
+ if (!element) return;
1469
+ if (chunk.block.type === 'tool_result') {
1470
+ const lastInFrag = blockFrag.lastElementChild;
1471
+ if (lastInFrag?.classList?.contains('block-tool-use')) { lastInFrag.appendChild(element); return; }
1435
1472
  }
1473
+ blockFrag.appendChild(element);
1436
1474
  });
1437
1475
  blocksEl.appendChild(blockFrag);
1438
1476
 
@@ -703,6 +703,7 @@ class StreamingRenderer {
703
703
 
704
704
  const details = document.createElement('details');
705
705
  details.className = 'block-tool-use folded-tool';
706
+ if (block.id) details.dataset.toolUseId = block.id;
706
707
  const summary = document.createElement('summary');
707
708
  summary.className = 'folded-tool-bar';
708
709
  const displayName = this.getToolUseDisplayName(toolName);
@@ -1154,7 +1155,7 @@ class StreamingRenderer {
1154
1155
  }
1155
1156
 
1156
1157
  /**
1157
- * Render tool result block with smart content display
1158
+ * Render tool result as inline content to be merged into preceding tool_use block
1158
1159
  */
1159
1160
  renderBlockToolResult(block, context) {
1160
1161
  const isError = block.is_error || false;
@@ -1163,15 +1164,16 @@ class StreamingRenderer {
1163
1164
  const preview = contentStr.length > 80 ? contentStr.substring(0, 77).replace(/\n/g, ' ') + '...' : contentStr.replace(/\n/g, ' ');
1164
1165
 
1165
1166
  const details = document.createElement('details');
1166
- details.className = isError ? 'folded-tool folded-tool-error' : 'folded-tool';
1167
+ details.className = 'tool-result-inline' + (isError ? ' tool-result-error' : '');
1167
1168
  details.dataset.eventType = 'tool_result';
1169
+ if (block.tool_use_id) details.dataset.toolUseId = block.tool_use_id;
1168
1170
 
1169
1171
  const iconSvg = isError
1170
1172
  ? '<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>'
1171
1173
  : '<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>';
1172
1174
 
1173
1175
  const summary = document.createElement('summary');
1174
- summary.className = 'folded-tool-bar';
1176
+ summary.className = 'tool-result-status';
1175
1177
  summary.innerHTML = `
1176
1178
  <span class="folded-tool-icon">${iconSvg}</span>
1177
1179
  <span class="folded-tool-name">${isError ? 'Error' : 'Success'}</span>