agentgui 1.0.157 → 1.0.159

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.157",
3
+ "version": "1.0.159",
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
@@ -1586,6 +1586,34 @@
1586
1586
  .folded-tool-error > .folded-tool-body { border-top-color: #fecaca; }
1587
1587
  html.dark .folded-tool-error > .folded-tool-body { border-top-color: #7f1d1d; }
1588
1588
 
1589
+ /* --- Info variant of folded-tool (system blocks) --- */
1590
+ .folded-tool.folded-tool-info {
1591
+ background: #eef2ff;
1592
+ border-color: #c7d2fe;
1593
+ }
1594
+ html.dark .folded-tool.folded-tool-info {
1595
+ background: #15103a;
1596
+ border-color: #3730a3;
1597
+ }
1598
+ .folded-tool-info > .folded-tool-bar {
1599
+ background: #e0e7ff;
1600
+ }
1601
+ html.dark .folded-tool-info > .folded-tool-bar {
1602
+ background: #1e1b4b;
1603
+ }
1604
+ .folded-tool-info > .folded-tool-bar::before { color: #6366f1; }
1605
+ html.dark .folded-tool-info > .folded-tool-bar::before { color: #a5b4fc; }
1606
+ .folded-tool-info > .folded-tool-bar:hover { background: #c7d2fe; }
1607
+ html.dark .folded-tool-info > .folded-tool-bar:hover { background: #312e81; }
1608
+ .folded-tool-info .folded-tool-icon { color: #6366f1; }
1609
+ html.dark .folded-tool-info .folded-tool-icon { color: #a5b4fc; }
1610
+ .folded-tool-info .folded-tool-name { color: #3730a3; }
1611
+ html.dark .folded-tool-info .folded-tool-name { color: #c7d2fe; }
1612
+ .folded-tool-info .folded-tool-desc { color: #4f46e5; }
1613
+ html.dark .folded-tool-info .folded-tool-desc { color: #a5b4fc; }
1614
+ .folded-tool-info > .folded-tool-body { border-top-color: #c7d2fe; }
1615
+ html.dark .folded-tool-info > .folded-tool-body { border-top-color: #3730a3; }
1616
+
1589
1617
  /* --- Collapsible Code Summary --- */
1590
1618
  .collapsible-code {
1591
1619
  margin: 0.25rem 0;
@@ -1695,13 +1723,6 @@
1695
1723
  html.dark .block-tool-result.result-success .result-body { color: #bbf7d0; }
1696
1724
  html.dark .block-tool-result.result-error .result-body { color: #fecaca; }
1697
1725
 
1698
- .result-collapsible { margin: 0; }
1699
- .result-collapsible > summary { list-style: none; }
1700
- .result-collapsible > summary::-webkit-details-marker { display: none; }
1701
- .result-collapsible > summary::marker { display: none; content: ''; }
1702
- .result-collapsible > summary .status-label::before { content: '\25b6'; font-size: 0.6rem; margin-right: 0.375rem; display: inline-block; transition: transform 0.15s; }
1703
- .result-collapsible[open] > summary .status-label::before { transform: rotate(90deg); }
1704
-
1705
1726
  .block-tool-result .result-body.collapsed { max-height: 150px; position: relative; }
1706
1727
  .block-tool-result .result-body.collapsed::after {
1707
1728
  content: '';
@@ -2084,21 +2105,7 @@
2084
2105
  <!-- Input area: fixed at bottom -->
2085
2106
  <div class="input-section">
2086
2107
  <div class="input-wrapper">
2087
- <select class="agent-selector" data-agent-selector title="Select agent">
2088
- <option value="claude-code">Claude Code</option>
2089
- <option value="opencode">OpenCode</option>
2090
- <option value="gemini">Gemini CLI</option>
2091
- <option value="goose">Goose</option>
2092
- <option value="openhands">OpenHands</option>
2093
- <option value="augment">Augment Code</option>
2094
- <option value="cline">Cline</option>
2095
- <option value="kimi">Kimi CLI</option>
2096
- <option value="qwen">Qwen Code</option>
2097
- <option value="codex">Codex CLI</option>
2098
- <option value="mistral">Mistral Vibe</option>
2099
- <option value="kiro">Kiro CLI</option>
2100
- <option value="fast-agent">fast-agent</option>
2101
- </select>
2108
+ <select class="agent-selector" data-agent-selector title="Select agent"></select>
2102
2109
  <textarea
2103
2110
  class="message-textarea"
2104
2111
  data-message-input
@@ -877,7 +877,11 @@ class AgentGUIClient {
877
877
  } else if (block.type === 'tool_result') {
878
878
  const content = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
879
879
  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>`;
880
- html += `<div class="streaming-block-tool-result${block.is_error ? ' tool-result-error' : ''}"><div class="tool-result-header">${block.is_error ? '<span class="tool-result-error-badge">Error</span>' : '<span class="tool-result-ok-badge">Result</span>'}</div>${smartHtml}</div>`;
880
+ const resultPreview = content.length > 80 ? content.substring(0, 77).replace(/\n/g, ' ') + '...' : content.replace(/\n/g, ' ');
881
+ const resultIcon = block.is_error
882
+ ? '<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
+ : '<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>`;
881
885
  }
882
886
  });
883
887
  }
@@ -1154,13 +1158,15 @@ class AgentGUIClient {
1154
1158
  const { agents } = await response.json();
1155
1159
  this.state.agents = agents;
1156
1160
 
1157
- // Populate agent selector
1161
+ // Populate agent selector with discovered (available) agents only
1158
1162
  if (this.ui.agentSelector) {
1159
1163
  this.ui.agentSelector.innerHTML = agents
1160
1164
  .map(agent => `<option value="${agent.id}">${agent.name}</option>`)
1161
1165
  .join('');
1162
1166
  }
1163
1167
 
1168
+ window.dispatchEvent(new CustomEvent('agents-loaded', { detail: { agents } }));
1169
+
1164
1170
  return agents;
1165
1171
  } catch (error) {
1166
1172
  console.error('Failed to load agents:', error);
@@ -1157,41 +1157,35 @@ class StreamingRenderer {
1157
1157
  * Render tool result block with smart content display
1158
1158
  */
1159
1159
  renderBlockToolResult(block, context) {
1160
- const div = document.createElement('div');
1161
1160
  const isError = block.is_error || false;
1162
- div.className = `block-tool-result ${isError ? 'result-error' : 'result-success'}`;
1163
-
1164
1161
  const content = block.content || '';
1165
1162
  const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
1166
- const toolUseId = block.tool_use_id || '';
1163
+ const preview = contentStr.length > 80 ? contentStr.substring(0, 77).replace(/\n/g, ' ') + '...' : contentStr.replace(/\n/g, ' ');
1164
+
1165
+ const details = document.createElement('details');
1166
+ details.className = isError ? 'folded-tool folded-tool-error' : 'folded-tool';
1167
+ details.dataset.eventType = 'tool_result';
1167
1168
 
1168
1169
  const iconSvg = isError
1169
1170
  ? '<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>'
1170
1171
  : '<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>';
1171
1172
 
1172
- const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this));
1173
+ const summary = document.createElement('summary');
1174
+ summary.className = 'folded-tool-bar';
1175
+ summary.innerHTML = `
1176
+ <span class="folded-tool-icon">${iconSvg}</span>
1177
+ <span class="folded-tool-name">${isError ? 'Error' : 'Success'}</span>
1178
+ <span class="folded-tool-desc">${this.escapeHtml(preview)}</span>
1179
+ `;
1180
+ details.appendChild(summary);
1173
1181
 
1174
- if (isError) {
1175
- div.innerHTML = `
1176
- <div class="result-header">
1177
- <span class="status-label">${iconSvg} Error</span>
1178
- ${toolUseId ? `<span class="result-id">${this.escapeHtml(toolUseId)}</span>` : ''}
1179
- </div>
1180
- ${renderedContent}
1181
- `;
1182
- } else {
1183
- div.innerHTML = `
1184
- <details class="result-collapsible">
1185
- <summary class="result-header" style="cursor:pointer;list-style:none;user-select:none">
1186
- <span class="status-label">${iconSvg} Success</span>
1187
- ${toolUseId ? `<span class="result-id">${this.escapeHtml(toolUseId)}</span>` : ''}
1188
- </summary>
1189
- <div class="result-collapsible-body">${renderedContent}</div>
1190
- </details>
1191
- `;
1192
- }
1182
+ const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this));
1183
+ const body = document.createElement('div');
1184
+ body.className = 'folded-tool-body';
1185
+ body.innerHTML = renderedContent;
1186
+ details.appendChild(body);
1193
1187
 
1194
- return div;
1188
+ return details;
1195
1189
  }
1196
1190
 
1197
1191
  /**
@@ -1247,11 +1241,21 @@ class StreamingRenderer {
1247
1241
  * Render system event
1248
1242
  */
1249
1243
  renderBlockSystem(block, context) {
1250
- const div = document.createElement('div');
1251
- div.className = 'block-system';
1252
-
1253
- div.innerHTML = `
1254
- <div class="system-header">Session Information</div>
1244
+ const details = document.createElement('details');
1245
+ details.className = 'folded-tool folded-tool-info';
1246
+ details.dataset.eventType = 'system';
1247
+ const desc = block.model ? this.escapeHtml(block.model) : 'Session';
1248
+ const summary = document.createElement('summary');
1249
+ summary.className = 'folded-tool-bar';
1250
+ summary.innerHTML = `
1251
+ <span class="folded-tool-icon"><svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/></svg></span>
1252
+ <span class="folded-tool-name">Session</span>
1253
+ <span class="folded-tool-desc">${desc}</span>
1254
+ `;
1255
+ details.appendChild(summary);
1256
+ const body = document.createElement('div');
1257
+ body.className = 'folded-tool-body block-system';
1258
+ body.innerHTML = `
1255
1259
  <div class="system-body">
1256
1260
  ${block.model ? `<div class="sys-field"><span class="sys-label">Model</span><span class="sys-value"><code>${this.escapeHtml(block.model)}</code></span></div>` : ''}
1257
1261
  ${block.cwd ? `<div class="sys-field"><span class="sys-label">Directory</span><span class="sys-value"><code>${this.escapeHtml(block.cwd)}</code></span></div>` : ''}
@@ -1259,38 +1263,58 @@ class StreamingRenderer {
1259
1263
  ${block.tools && Array.isArray(block.tools) ? `<div class="sys-field" style="flex-direction:column;gap:0.375rem"><span class="sys-label">Tools (${block.tools.length})</span><div class="tools-list">${block.tools.map(t => `<span class="tool-badge">${this.escapeHtml(t)}</span>`).join('')}</div></div>` : ''}
1260
1264
  </div>
1261
1265
  `;
1262
-
1263
- return div;
1266
+ details.appendChild(body);
1267
+ return details;
1264
1268
  }
1265
1269
 
1266
1270
  /**
1267
1271
  * Render result block (execution summary)
1268
1272
  */
1269
1273
  renderBlockResult(block, context) {
1270
- const div = document.createElement('div');
1271
1274
  const isError = block.is_error || false;
1272
- div.className = `block-result ${isError ? 'result-err' : 'result-ok'}`;
1273
-
1274
1275
  const duration = block.duration_ms ? (block.duration_ms / 1000).toFixed(1) + 's' : '';
1275
1276
  const cost = block.total_cost_usd ? '$' + block.total_cost_usd.toFixed(4) : '';
1276
1277
  const turns = block.num_turns || '';
1278
+ const statsDesc = [duration, cost, turns ? turns + ' turns' : ''].filter(Boolean).join(' / ');
1277
1279
 
1278
- div.innerHTML = `
1279
- <div class="result-summary-header">
1280
- ${isError
1281
- ? '<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>'
1282
- : '<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>'}
1283
- <span class="result-title">${isError ? 'Execution Failed' : 'Execution Complete'}</span>
1284
- </div>
1285
- <div class="result-stats">
1286
- ${duration ? `<div class="result-stat"><span class="stat-icon">&#9202;</span><span class="stat-value">${this.escapeHtml(duration)}</span><span class="stat-label">duration</span></div>` : ''}
1287
- ${cost ? `<div class="result-stat"><span class="stat-icon">&#128176;</span><span class="stat-value">${this.escapeHtml(cost)}</span><span class="stat-label">cost</span></div>` : ''}
1288
- ${turns ? `<div class="result-stat"><span class="stat-icon">&#128260;</span><span class="stat-value">${this.escapeHtml(String(turns))}</span><span class="stat-label">turns</span></div>` : ''}
1289
- </div>
1290
- ${block.result ? `<div class="result-content">${(() => { const r = typeof block.result === 'string' ? block.result : JSON.stringify(block.result, null, 2); return this.containsHtmlTags(r) ? '<div class="html-content">' + this.sanitizeHtml(r) + '</div>' : this.escapeHtml(r); })()}</div>` : ''}
1280
+ const details = document.createElement('details');
1281
+ details.className = isError ? 'folded-tool folded-tool-error' : 'folded-tool';
1282
+ details.dataset.eventType = 'result';
1283
+
1284
+ const iconSvg = isError
1285
+ ? '<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>'
1286
+ : '<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>';
1287
+
1288
+ const summary = document.createElement('summary');
1289
+ summary.className = 'folded-tool-bar';
1290
+ summary.innerHTML = `
1291
+ <span class="folded-tool-icon">${iconSvg}</span>
1292
+ <span class="folded-tool-name">${isError ? 'Failed' : 'Complete'}</span>
1293
+ <span class="folded-tool-desc">${this.escapeHtml(statsDesc)}</span>
1291
1294
  `;
1295
+ details.appendChild(summary);
1292
1296
 
1293
- return div;
1297
+ if (block.result || duration || cost || turns) {
1298
+ const body = document.createElement('div');
1299
+ body.className = 'folded-tool-body';
1300
+ let bodyHtml = '';
1301
+ if (duration || cost || turns) {
1302
+ bodyHtml += `<div class="block-result"><div class="result-stats">
1303
+ ${duration ? `<div class="result-stat"><span class="stat-icon">&#9202;</span><span class="stat-value">${this.escapeHtml(duration)}</span><span class="stat-label">duration</span></div>` : ''}
1304
+ ${cost ? `<div class="result-stat"><span class="stat-icon">&#128176;</span><span class="stat-value">${this.escapeHtml(cost)}</span><span class="stat-label">cost</span></div>` : ''}
1305
+ ${turns ? `<div class="result-stat"><span class="stat-icon">&#128260;</span><span class="stat-value">${this.escapeHtml(String(turns))}</span><span class="stat-label">turns</span></div>` : ''}
1306
+ </div></div>`;
1307
+ }
1308
+ if (block.result) {
1309
+ const r = typeof block.result === 'string' ? block.result : JSON.stringify(block.result, null, 2);
1310
+ const rendered = this.containsHtmlTags(r) ? '<div class="html-content">' + this.sanitizeHtml(r) + '</div>' : `<div style="font-size:0.8rem;white-space:pre-wrap;word-break:break-word;line-height:1.5">${this.escapeHtml(r)}</div>`;
1311
+ bodyHtml += rendered;
1312
+ }
1313
+ body.innerHTML = bodyHtml;
1314
+ details.appendChild(body);
1315
+ }
1316
+
1317
+ return details;
1294
1318
  }
1295
1319
 
1296
1320
  /**
@@ -22,13 +22,20 @@
22
22
  setupAgentSelector();
23
23
  }
24
24
 
25
+ function syncVoiceSelector() {
26
+ var voiceSelector = document.querySelector('[data-voice-agent-selector]');
27
+ var mainSelector = document.querySelector('[data-agent-selector]');
28
+ if (!voiceSelector || !mainSelector) return;
29
+ voiceSelector.innerHTML = mainSelector.innerHTML;
30
+ if (mainSelector.value) voiceSelector.value = mainSelector.value;
31
+ }
32
+
25
33
  function setupAgentSelector() {
26
34
  var voiceSelector = document.querySelector('[data-voice-agent-selector]');
27
35
  if (!voiceSelector) return;
28
36
  var mainSelector = document.querySelector('[data-agent-selector]');
29
37
  if (mainSelector) {
30
- voiceSelector.innerHTML = mainSelector.innerHTML;
31
- voiceSelector.value = mainSelector.value;
38
+ syncVoiceSelector();
32
39
  mainSelector.addEventListener('change', function() {
33
40
  voiceSelector.value = mainSelector.value;
34
41
  });
@@ -36,6 +43,7 @@
36
43
  mainSelector.value = voiceSelector.value;
37
44
  });
38
45
  }
46
+ window.addEventListener('agents-loaded', syncVoiceSelector);
39
47
  }
40
48
 
41
49
  function setupTTSToggle() {