agentgui 1.0.234 → 1.0.235

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.
@@ -580,26 +580,63 @@ registry.register({
580
580
  content: [{
581
581
  type: 'tool_use',
582
582
  id: update.toolCallId,
583
- name: update.title || 'tool',
584
- input: update.input || {}
583
+ name: update.title || update.kind || 'tool',
584
+ input: update.rawInput || update.input || {}
585
585
  }]
586
586
  },
587
587
  session_id: params.sessionId
588
588
  };
589
589
  }
590
590
 
591
- // Tool call update (result)
592
- if (update.sessionUpdate === 'tool_call_update' && update.status === 'completed') {
593
- const content = update.content && update.content[0] ? update.content[0].content : null;
591
+ // Tool call update (result) - handle all statuses
592
+ if (update.sessionUpdate === 'tool_call_update') {
593
+ const status = update.status;
594
+ const isError = status === 'failed';
595
+ const isCompleted = status === 'completed';
596
+
597
+ if (!isCompleted && !isError) {
598
+ return {
599
+ type: 'tool_status',
600
+ tool_use_id: update.toolCallId,
601
+ status: status,
602
+ session_id: params.sessionId
603
+ };
604
+ }
605
+
606
+ const contentParts = [];
607
+ if (update.content && Array.isArray(update.content)) {
608
+ for (const item of update.content) {
609
+ if (item.type === 'content' && item.content) {
610
+ const innerContent = item.content;
611
+ if (innerContent.type === 'text' && innerContent.text) {
612
+ contentParts.push(innerContent.text);
613
+ } else if (innerContent.type === 'resource' && innerContent.resource) {
614
+ contentParts.push(innerContent.resource.text || JSON.stringify(innerContent.resource));
615
+ } else {
616
+ contentParts.push(JSON.stringify(innerContent));
617
+ }
618
+ } else if (item.type === 'diff') {
619
+ const diffText = item.oldText
620
+ ? `--- ${item.path}\n+++ ${item.path}\n${item.oldText}\n---\n${item.newText}`
621
+ : `+++ ${item.path}\n${item.newText}`;
622
+ contentParts.push(diffText);
623
+ } else if (item.type === 'terminal') {
624
+ contentParts.push(`[Terminal: ${item.terminalId}]`);
625
+ }
626
+ }
627
+ }
628
+
629
+ const combinedContent = contentParts.join('\n') || (update.rawOutput ? JSON.stringify(update.rawOutput) : '');
630
+
594
631
  return {
595
- type: 'assistant',
632
+ type: 'user',
596
633
  message: {
597
- role: 'assistant',
634
+ role: 'user',
598
635
  content: [{
599
636
  type: 'tool_result',
600
637
  tool_use_id: update.toolCallId,
601
- content: content ? (content.text || JSON.stringify(content)) : '',
602
- is_error: false
638
+ content: combinedContent,
639
+ is_error: isError
603
640
  }]
604
641
  },
605
642
  session_id: params.sessionId
@@ -687,26 +724,63 @@ function createACPProtocolHandler() {
687
724
  content: [{
688
725
  type: 'tool_use',
689
726
  id: update.toolCallId,
690
- name: update.title || 'tool',
691
- input: update.input || {}
727
+ name: update.title || update.kind || 'tool',
728
+ input: update.rawInput || update.input || {}
692
729
  }]
693
730
  },
694
731
  session_id: params.sessionId
695
732
  };
696
733
  }
697
734
 
698
- // Tool call update (result)
699
- if (update.sessionUpdate === 'tool_call_update' && update.status === 'completed') {
700
- const content = update.content && update.content[0] ? update.content[0].content : null;
735
+ // Tool call update (result) - handle all statuses
736
+ if (update.sessionUpdate === 'tool_call_update') {
737
+ const status = update.status;
738
+ const isError = status === 'failed';
739
+ const isCompleted = status === 'completed';
740
+
741
+ if (!isCompleted && !isError) {
742
+ return {
743
+ type: 'tool_status',
744
+ tool_use_id: update.toolCallId,
745
+ status: status,
746
+ session_id: params.sessionId
747
+ };
748
+ }
749
+
750
+ const contentParts = [];
751
+ if (update.content && Array.isArray(update.content)) {
752
+ for (const item of update.content) {
753
+ if (item.type === 'content' && item.content) {
754
+ const innerContent = item.content;
755
+ if (innerContent.type === 'text' && innerContent.text) {
756
+ contentParts.push(innerContent.text);
757
+ } else if (innerContent.type === 'resource' && innerContent.resource) {
758
+ contentParts.push(innerContent.resource.text || JSON.stringify(innerContent.resource));
759
+ } else {
760
+ contentParts.push(JSON.stringify(innerContent));
761
+ }
762
+ } else if (item.type === 'diff') {
763
+ const diffText = item.oldText
764
+ ? `--- ${item.path}\n+++ ${item.path}\n${item.oldText}\n---\n${item.newText}`
765
+ : `+++ ${item.path}\n${item.newText}`;
766
+ contentParts.push(diffText);
767
+ } else if (item.type === 'terminal') {
768
+ contentParts.push(`[Terminal: ${item.terminalId}]`);
769
+ }
770
+ }
771
+ }
772
+
773
+ const combinedContent = contentParts.join('\n') || (update.rawOutput ? JSON.stringify(update.rawOutput) : '');
774
+
701
775
  return {
702
- type: 'assistant',
776
+ type: 'user',
703
777
  message: {
704
- role: 'assistant',
778
+ role: 'user',
705
779
  content: [{
706
780
  type: 'tool_result',
707
781
  tool_use_id: update.toolCallId,
708
- content: content ? (content.text || JSON.stringify(content)) : '',
709
- is_error: false
782
+ content: combinedContent,
783
+ is_error: isError
710
784
  }]
711
785
  },
712
786
  session_id: params.sessionId
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.234",
3
+ "version": "1.0.235",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -2069,6 +2069,46 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
2069
2069
  if (parsed.result && allBlocks.length === 0) {
2070
2070
  allBlocks.push({ type: 'text', text: String(parsed.result) });
2071
2071
  }
2072
+ } else if (parsed.type === 'tool_status') {
2073
+ // Handle ACP tool status updates (in_progress, pending)
2074
+ broadcastSync({
2075
+ type: 'streaming_progress',
2076
+ sessionId,
2077
+ conversationId,
2078
+ block: {
2079
+ type: 'tool_status',
2080
+ tool_use_id: parsed.tool_use_id,
2081
+ status: parsed.status
2082
+ },
2083
+ seq: currentSequence,
2084
+ timestamp: Date.now()
2085
+ });
2086
+ } else if (parsed.type === 'usage') {
2087
+ // Handle ACP usage updates
2088
+ broadcastSync({
2089
+ type: 'streaming_progress',
2090
+ sessionId,
2091
+ conversationId,
2092
+ block: {
2093
+ type: 'usage',
2094
+ usage: parsed.usage
2095
+ },
2096
+ seq: currentSequence,
2097
+ timestamp: Date.now()
2098
+ });
2099
+ } else if (parsed.type === 'plan') {
2100
+ // Handle ACP plan updates
2101
+ broadcastSync({
2102
+ type: 'streaming_progress',
2103
+ sessionId,
2104
+ conversationId,
2105
+ block: {
2106
+ type: 'plan',
2107
+ entries: parsed.entries
2108
+ },
2109
+ seq: currentSequence,
2110
+ timestamp: Date.now()
2111
+ });
2072
2112
  }
2073
2113
  };
2074
2114
 
@@ -351,6 +351,12 @@ class StreamingRenderer {
351
351
  return this.renderBlockSystem(block, context);
352
352
  case 'result':
353
353
  return this.renderBlockResult(block, context);
354
+ case 'tool_status':
355
+ return this.renderBlockToolStatus(block, context);
356
+ case 'usage':
357
+ return this.renderBlockUsage(block, context);
358
+ case 'plan':
359
+ return this.renderBlockPlan(block, context);
354
360
  default:
355
361
  return this.renderBlockGeneric(block, context);
356
362
  }
@@ -1320,6 +1326,95 @@ class StreamingRenderer {
1320
1326
  return details;
1321
1327
  }
1322
1328
 
1329
+ /**
1330
+ * Render tool status block (ACP in_progress/pending updates)
1331
+ */
1332
+ renderBlockToolStatus(block, context) {
1333
+ const status = block.status || 'pending';
1334
+ const statusIcons = {
1335
+ pending: '<svg viewBox="0 0 20 20" fill="currentColor" style="color:var(--color-text-secondary)"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/></svg>',
1336
+ in_progress: '<svg viewBox="0 0 20 20" fill="currentColor" class="animate-spin" style="color:var(--color-info)"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/></svg>'
1337
+ };
1338
+ const statusLabels = {
1339
+ pending: 'Pending',
1340
+ in_progress: 'Running...'
1341
+ };
1342
+
1343
+ const div = document.createElement('div');
1344
+ div.className = 'block-tool-status';
1345
+ div.dataset.toolUseId = block.tool_use_id || '';
1346
+ div.innerHTML = `
1347
+ <div style="display:flex;align-items:center;gap:0.5rem;padding:0.25rem 0.5rem;font-size:0.75rem;color:var(--color-text-secondary)">
1348
+ ${statusIcons[status] || statusIcons.pending}
1349
+ <span>${statusLabels[status] || status}</span>
1350
+ </div>
1351
+ `;
1352
+ return div;
1353
+ }
1354
+
1355
+ /**
1356
+ * Render usage block (ACP usage updates)
1357
+ */
1358
+ renderBlockUsage(block, context) {
1359
+ const usage = block.usage || {};
1360
+ const used = usage.used || 0;
1361
+ const size = usage.size || 0;
1362
+ const cost = usage.cost ? '$' + usage.cost.toFixed(4) : '';
1363
+
1364
+ const div = document.createElement('div');
1365
+ div.className = 'block-usage';
1366
+ div.innerHTML = `
1367
+ <div style="display:flex;gap:1rem;padding:0.25rem 0.5rem;font-size:0.7rem;color:var(--color-text-secondary);background:var(--color-bg-secondary);border-radius:0.25rem">
1368
+ ${used ? `<span><strong>Used:</strong> ${used.toLocaleString()}</span>` : ''}
1369
+ ${size ? `<span><strong>Context:</strong> ${size.toLocaleString()}</span>` : ''}
1370
+ ${cost ? `<span><strong>Cost:</strong> ${cost}</span>` : ''}
1371
+ </div>
1372
+ `;
1373
+ return div;
1374
+ }
1375
+
1376
+ /**
1377
+ * Render plan block (ACP plan updates)
1378
+ */
1379
+ renderBlockPlan(block, context) {
1380
+ const entries = block.entries || [];
1381
+ if (entries.length === 0) return null;
1382
+
1383
+ const priorityColors = {
1384
+ high: '#ef4444',
1385
+ medium: '#f59e0b',
1386
+ low: '#6b7280'
1387
+ };
1388
+ const statusIcons = {
1389
+ pending: '○',
1390
+ in_progress: '◐',
1391
+ completed: '●'
1392
+ };
1393
+
1394
+ const div = document.createElement('div');
1395
+ div.className = 'block-plan';
1396
+ div.innerHTML = `
1397
+ <details class="folded-tool folded-tool-info">
1398
+ <summary class="folded-tool-bar">
1399
+ <span class="folded-tool-icon"><svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"/><path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg></span>
1400
+ <span class="folded-tool-name">Plan</span>
1401
+ <span class="folded-tool-desc">${entries.length} tasks</span>
1402
+ </summary>
1403
+ <div class="folded-tool-body">
1404
+ <div style="display:flex;flex-direction:column;gap:0.375rem">
1405
+ ${entries.map(e => `
1406
+ <div style="display:flex;align-items:center;gap:0.5rem;font-size:0.8rem">
1407
+ <span style="color:${priorityColors[e.priority] || priorityColors.low}">${statusIcons[e.status] || statusIcons.pending}</span>
1408
+ <span style="${e.status === 'completed' ? 'text-decoration:line-through;opacity:0.6' : ''}">${this.escapeHtml(e.content || '')}</span>
1409
+ </div>
1410
+ `).join('')}
1411
+ </div>
1412
+ </div>
1413
+ </details>
1414
+ `;
1415
+ return div;
1416
+ }
1417
+
1323
1418
  /**
1324
1419
  * Render generic block with formatted key-value pairs
1325
1420
  */