ashishMenon05 commited on
Commit
c90dd9f
·
1 Parent(s): 0815f50

feat: add unified investigation summary combining all agent conclusions

Browse files
frontend/src/components/EpisodeEndOverlay.jsx CHANGED
@@ -9,18 +9,20 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
9
  const sc = gameState.scenario || {};
10
  const allAgents = gameState.agents || {};
11
  const allMessages = Object.values(allAgents).flatMap(a => a?.messages || []);
 
12
 
13
  let report = `=================================================================\n`;
14
- report += ` NEXUS INCIDENT INVESTIGATION REPORT \n`;
15
  report += `=================================================================\n\n`;
16
 
17
  report += `[ SCENARIO METADATA ]\n`;
18
  report += `Title: ${sc.id || 'N/A'}\n`;
19
  report += `Domain: ${sc.domain || 'N/A'}\n`;
20
  report += `Difficulty: ${sc.difficulty || 'N/A'}\n`;
21
- report += `Final Grading Score: ${Number(gameState?.cumulativeReward || metrics?.score || 0).toFixed(4)} / 1.00\n`;
22
  report += `Total Steps: ${gameState?.step || metrics?.steps || 'N/A'}\n`;
23
- report += `Active Agents: ${Object.keys(allAgents).length}\n\n`;
 
24
 
25
  report += `[ AGENTS DEPLOYED ]\n`;
26
  Object.entries(allAgents).forEach(([agentId, agentData], idx) => {
@@ -30,6 +32,22 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
30
  report += `${idx + 1}. ${agentId}: ${msgCount} messages, ${toolCount} tool calls\n`;
31
  });
32
  report += `\n`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  report += `[ STEP REWARDS ]\n`;
35
  if (gameState?.rewardHistory && gameState.rewardHistory.length > 0) {
@@ -37,7 +55,7 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
37
  report += `Step ${i + 1}: ${r.toFixed(4)}\n`;
38
  });
39
  report += `Average: ${(gameState.rewardHistory.reduce((a, b) => a + b, 0) / gameState.rewardHistory.length).toFixed(4)}\n`;
40
- report += `Final Grading Score: ${Number(gameState.cumulativeReward || 0).toFixed(4)}\n\n`;
41
  } else {
42
  report += `No step rewards recorded.\n\n`;
43
  }
@@ -55,7 +73,7 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
55
 
56
  report += `[ CONTEXT & ROOT CAUSE ]\n`;
57
  report += `${sc.context || 'No context provided.'}\n`;
58
- report += `Actual Root Cause Validation: ${metrics?.rootCause || 'N/A'}\n\n`;
59
 
60
  report += `=================================================================\n`;
61
  report += `[ INVESTIGATION LOG & DETAILED TRACE ]\n`;
@@ -84,40 +102,45 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
84
  }
85
  report += `\n`;
86
 
87
- report += `> SYSTEMS ERRORS DETECTED DURING INVESTIGATION:\n`;
88
  if (allErrors.length > 0) {
89
- // deduplicate
90
  [...new Set(allErrors)].forEach(err => report += `${err}\n`);
91
  } else {
92
- report += `No significant system errors found during tool execution.\n`;
93
  }
94
  report += `\n`;
95
 
96
  report += `=================================================================\n`;
97
- report += `[ SOLUTION IMPLEMENTED & FIX VERIFICATION ]\n`;
98
  report += `=================================================================\n\n`;
99
- report += `The Validator Agent verified the proposed fix successfully, leading to the resolution of the incident.\n`;
100
- report += `End-state: ${metrics?.rootCause === 'VERIFIED' ? 'SUCCESS' : 'UNKNOWN'}\n\n`;
 
 
 
 
 
 
 
 
101
 
102
  report += `=================================================================\n`;
103
- report += `[ TIPS FOR IMPROVEMENT & RECOMMENDATIONS ]\n`;
104
  report += `=================================================================\n\n`;
105
- report += `Based on the automated evaluation of this scenario, consider the following:\n`;
106
 
107
  if (allTools.length > 15) {
108
- report += `1. EFFICIENCY: The agents called a large number of tools (${allTools.length}). Consider refining the initial hypothesis to reduce blind querying.\n`;
109
  } else {
110
- report += `1. EFFICIENCY: Tool execution was relatively concise (${allTools.length} calls).\n`;
111
  }
112
 
113
  if (allErrors.length > 5) {
114
- report += `2. ACCURACY: Multiple tool execution errors were encountered. Ensure exact syntax and correct tool parameters are used to minimize invalid calls.\n`;
115
  }
116
 
117
- report += `3. CAUSE-ANALYSIS: Always grep application error logs before querying databases to save time tracking downstream symptoms.\n`;
118
- report += `4. REMEDIATION: Post-incident reviews should establish better automated alerting for the specific failure domain (${sc.domain || 'general'}).\n`;
119
 
120
- // Trigger Download
121
  const blob = new Blob([report], { type: 'text/plain;charset=utf-8' });
122
  const url = URL.createObjectURL(blob);
123
  const a = document.createElement('a');
@@ -129,6 +152,59 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
129
  URL.revokeObjectURL(url);
130
  };
131
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  return (
133
  <div className="fixed inset-0 z-[100] flex items-center justify-center p-4 md:p-8 animate-in fade-in duration-500">
134
  {/* Particle/Pulse Background */}
@@ -139,7 +215,7 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
139
  </div>
140
 
141
  {/* Summary Modal */}
142
- <div className="relative w-full max-w-4xl max-h-[90vh] glass-panel rounded-xl overflow-hidden shadow-[0_0_80px_rgba(0,0,0,0.8)] border border-white/10 flex flex-col">
143
  {/* Modal Header */}
144
  <div className="flex items-center justify-between p-6 bg-surface-container-highest/20 border-b border-white/5">
145
  <div className="flex items-center gap-3">
@@ -308,11 +384,9 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
308
  }).filter(c => c.lastMsg);
309
 
310
  if (conclusions.length === 0) return null;
311
-
312
- const colors = ['primary', 'secondary', 'tertiary', 'error', 'success'];
313
 
314
  return (
315
- <div className="px-8 pb-8">
316
  <div className="p-6 bg-surface-container-low/40 border border-white/10 rounded-lg">
317
  <h3 className="font-headline font-bold text-on-surface tracking-widest uppercase mb-4 flex items-center gap-2">
318
  <span className="material-symbols-outlined">gavel</span>
@@ -336,6 +410,65 @@ const EpisodeEndOverlay = ({ isOpen, onClose, metrics, gameState }) => {
336
  </div>
337
  );
338
  })()}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  </div>
340
 
341
  {/* Modal Footer */}
 
9
  const sc = gameState.scenario || {};
10
  const allAgents = gameState.agents || {};
11
  const allMessages = Object.values(allAgents).flatMap(a => a?.messages || []);
12
+ const unifiedSummary = generateUnifiedSummary();
13
 
14
  let report = `=================================================================\n`;
15
+ report += ` NEXUS INCIDENT INVESTIGATION REPORT \n`;
16
  report += `=================================================================\n\n`;
17
 
18
  report += `[ SCENARIO METADATA ]\n`;
19
  report += `Title: ${sc.id || 'N/A'}\n`;
20
  report += `Domain: ${sc.domain || 'N/A'}\n`;
21
  report += `Difficulty: ${sc.difficulty || 'N/A'}\n`;
22
+ report += `Final Score: ${Number(gameState?.cumulativeReward || metrics?.score || 0).toFixed(4)} / 1.00\n`;
23
  report += `Total Steps: ${gameState?.step || metrics?.steps || 'N/A'}\n`;
24
+ report += `Active Agents: ${Object.keys(allAgents).length}\n`;
25
+ report += `Status: ${unifiedSummary?.isSuccess ? 'SUCCESS' : 'INCONCLUSIVE'}\n\n`;
26
 
27
  report += `[ AGENTS DEPLOYED ]\n`;
28
  Object.entries(allAgents).forEach(([agentId, agentData], idx) => {
 
32
  report += `${idx + 1}. ${agentId}: ${msgCount} messages, ${toolCount} tool calls\n`;
33
  });
34
  report += `\n`;
35
+
36
+ // UNIFIED SUMMARY SECTION
37
+ if (unifiedSummary) {
38
+ report += `=================================================================\n`;
39
+ report += `[ UNIFIED INVESTIGATION SUMMARY ]\n`;
40
+ report += `=================================================================\n\n`;
41
+
42
+ report += `## Combined Agent Conclusions\n`;
43
+ report += `${unifiedSummary.conclusionText || 'No conclusions recorded.'}\n\n`;
44
+
45
+ report += `## Key Findings & Clues\n`;
46
+ report += `${unifiedSummary.keyFindings || 'None recorded.'}\n\n`;
47
+
48
+ report += `## Key Tool Results\n`;
49
+ report += `${unifiedSummary.toolSummary}\n\n`;
50
+ }
51
 
52
  report += `[ STEP REWARDS ]\n`;
53
  if (gameState?.rewardHistory && gameState.rewardHistory.length > 0) {
 
55
  report += `Step ${i + 1}: ${r.toFixed(4)}\n`;
56
  });
57
  report += `Average: ${(gameState.rewardHistory.reduce((a, b) => a + b, 0) / gameState.rewardHistory.length).toFixed(4)}\n`;
58
+ report += `Final Score: ${Number(gameState.cumulativeReward || 0).toFixed(4)}\n\n`;
59
  } else {
60
  report += `No step rewards recorded.\n\n`;
61
  }
 
73
 
74
  report += `[ CONTEXT & ROOT CAUSE ]\n`;
75
  report += `${sc.context || 'No context provided.'}\n`;
76
+ report += `Root Cause Validation: ${metrics?.rootCause || 'N/A'}\n\n`;
77
 
78
  report += `=================================================================\n`;
79
  report += `[ INVESTIGATION LOG & DETAILED TRACE ]\n`;
 
102
  }
103
  report += `\n`;
104
 
105
+ report += `> SYSTEMS ERRORS DETECTED:\n`;
106
  if (allErrors.length > 0) {
 
107
  [...new Set(allErrors)].forEach(err => report += `${err}\n`);
108
  } else {
109
+ report += `No significant system errors found.\n`;
110
  }
111
  report += `\n`;
112
 
113
  report += `=================================================================\n`;
114
+ report += `[ SOLUTION & FIX VERIFICATION ]\n`;
115
  report += `=================================================================\n\n`;
116
+
117
+ const resCall = gameState?.tool_calls_made?.find(c => c.tool_name === 'submit_resolution');
118
+ if (resCall?.params) {
119
+ report += `Root Cause Service: ${resCall.params.root_cause_service || 'UNKNOWN'}\n`;
120
+ report += `Root Cause Description: ${resCall.params.root_cause_description || 'None'}\n`;
121
+ report += `Fix Applied: ${resCall.params.fix_applied || 'None'}\n`;
122
+ } else {
123
+ report += `No resolution submitted.\n`;
124
+ }
125
+ report += `\n`;
126
 
127
  report += `=================================================================\n`;
128
+ report += `[ RECOMMENDATIONS ]\n`;
129
  report += `=================================================================\n\n`;
 
130
 
131
  if (allTools.length > 15) {
132
+ report += `1. EFFICIENCY: ${allTools.length} tool calls made. Consider refining hypotheses.\n`;
133
  } else {
134
+ report += `1. EFFICIENCY: Tool usage was concise (${allTools.length} calls).\n`;
135
  }
136
 
137
  if (allErrors.length > 5) {
138
+ report += `2. ACCURACY: Multiple errors encountered. Verify tool syntax.\n`;
139
  }
140
 
141
+ report += `3. CAUSE-ANALYSIS: Check error logs before database queries.\n`;
142
+ report += `4. REMEDIATION: Establish better alerting for ${sc.domain || 'general'} domain.\n`;
143
 
 
144
  const blob = new Blob([report], { type: 'text/plain;charset=utf-8' });
145
  const url = URL.createObjectURL(blob);
146
  const a = document.createElement('a');
 
152
  URL.revokeObjectURL(url);
153
  };
154
 
155
+ const generateUnifiedSummary = () => {
156
+ const allAgents = gameState?.agents || {};
157
+ const agentEntries = Object.entries(allAgents);
158
+
159
+ if (agentEntries.length === 0) return null;
160
+
161
+ const allConclusions = [];
162
+ const allToolResults = [];
163
+ const allClues = gameState?.clues_found || [];
164
+
165
+ agentEntries.forEach(([agentId, agentData]) => {
166
+ const msgs = agentData?.messages || [];
167
+ const textMsgs = msgs.filter(m => m.type === 'message');
168
+ const lastMsg = textMsgs[textMsgs.length - 1];
169
+ if (lastMsg) {
170
+ allConclusions.push({
171
+ agentId,
172
+ content: lastMsg.content || lastMsg.text || lastMsg.message || '',
173
+ role: agentData.role || agentId
174
+ });
175
+ }
176
+
177
+ const toolResults = msgs.filter(m => m.type === 'tool_result');
178
+ toolResults.forEach(tr => {
179
+ if (tr.result && !tr.result.toLowerCase().includes('error')) {
180
+ allToolResults.push({
181
+ agentId,
182
+ tool: tr.tool_name || tr.tool,
183
+ result: tr.result
184
+ });
185
+ }
186
+ });
187
+ });
188
+
189
+ const conclusionText = allConclusions.map(c => c.content).join('\n\n');
190
+ const keyFindings = allClues.slice(0, 5).join('\n• ');
191
+ const toolSummary = allToolResults.length > 0
192
+ ? allToolResults.slice(0, 3).map(t => `• ${t.tool}: ${t.result.substring(0, 100)}...`).join('\n')
193
+ : 'No tool results recorded.';
194
+
195
+ const isSuccess = Number(gameState?.cumulativeReward || metrics?.score || 0) >= 0.5;
196
+
197
+ return {
198
+ conclusionText,
199
+ keyFindings: keyFindings || 'No clues recorded.',
200
+ toolSummary,
201
+ agentCount: agentEntries.length,
202
+ isSuccess
203
+ };
204
+ };
205
+
206
+ const unifiedSummary = generateUnifiedSummary();
207
+
208
  return (
209
  <div className="fixed inset-0 z-[100] flex items-center justify-center p-4 md:p-8 animate-in fade-in duration-500">
210
  {/* Particle/Pulse Background */}
 
215
  </div>
216
 
217
  {/* Summary Modal */}
218
+ <div className="relative w-full max-w-5xl max-h-[90vh] glass-panel rounded-xl overflow-hidden shadow-[0_0_80px_rgba(0,0,0,0.8)] border border-white/10 flex flex-col">
219
  {/* Modal Header */}
220
  <div className="flex items-center justify-between p-6 bg-surface-container-highest/20 border-b border-white/5">
221
  <div className="flex items-center gap-3">
 
384
  }).filter(c => c.lastMsg);
385
 
386
  if (conclusions.length === 0) return null;
 
 
387
 
388
  return (
389
+ <div className="px-8 pb-4">
390
  <div className="p-6 bg-surface-container-low/40 border border-white/10 rounded-lg">
391
  <h3 className="font-headline font-bold text-on-surface tracking-widest uppercase mb-4 flex items-center gap-2">
392
  <span className="material-symbols-outlined">gavel</span>
 
410
  </div>
411
  );
412
  })()}
413
+
414
+ {/* Unified Investigation Summary */}
415
+ {unifiedSummary && (
416
+ <div className="px-8 pb-8">
417
+ <div className="p-6 bg-gradient-to-br from-primary/5 to-secondary/5 border border-primary/20 rounded-lg">
418
+ <h3 className="font-headline font-bold text-primary tracking-widest uppercase mb-4 flex items-center gap-2">
419
+ <span className="material-symbols-outlined">psychology</span>
420
+ Unified Investigation Summary
421
+ </h3>
422
+
423
+ {/* Success/Failure Badge */}
424
+ <div className="mb-4">
425
+ <span className={`inline-flex items-center gap-2 px-3 py-1 rounded-full text-xs font-mono font-bold uppercase ${
426
+ unifiedSummary.isSuccess
427
+ ? 'bg-tertiary/20 text-tertiary border border-tertiary/30'
428
+ : 'bg-error/20 text-error border border-error/30'
429
+ }`}>
430
+ <span className={`w-2 h-2 rounded-full ${unifiedSummary.isSuccess ? 'bg-tertiary' : 'bg-error'}`}></span>
431
+ {unifiedSummary.isSuccess ? 'Investigation Successful' : 'Investigation Inconclusive'}
432
+ </span>
433
+ <span className="ml-3 text-[10px] text-outline font-mono uppercase">
434
+ {unifiedSummary.agentCount} Agents Collaborated
435
+ </span>
436
+ </div>
437
+
438
+ {/* Combined Conclusions */}
439
+ <div className="mb-4">
440
+ <span className="font-mono text-[10px] text-primary/60 uppercase tracking-widest block mb-2">Combined Agent Conclusions</span>
441
+ <div className="p-4 bg-surface-container-low/50 rounded border border-white/5 max-h-48 overflow-y-auto custom-scrollbar">
442
+ <p className="text-sm text-on-surface/90 leading-relaxed whitespace-pre-wrap">
443
+ {unifiedSummary.conclusionText || 'No conclusions recorded.'}
444
+ </p>
445
+ </div>
446
+ </div>
447
+
448
+ {/* Key Findings */}
449
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
450
+ <div>
451
+ <span className="font-mono text-[10px] text-secondary/60 uppercase tracking-widest block mb-2">Key Findings & Clues</span>
452
+ <div className="p-3 bg-surface-container-low/50 rounded border border-white/5">
453
+ <ul className="text-xs text-on-surface/80 space-y-1 list-disc list-inside">
454
+ {unifiedSummary.keyFindings.split('\n• ').map((finding, i) => (
455
+ finding && <li key={i}>{finding}</li>
456
+ ))}
457
+ </ul>
458
+ </div>
459
+ </div>
460
+ <div>
461
+ <span className="font-mono text-[10px] text-tertiary/60 uppercase tracking-widest block mb-2">Key Tool Results</span>
462
+ <div className="p-3 bg-surface-container-low/50 rounded border border-white/5 max-h-32 overflow-y-auto custom-scrollbar">
463
+ <pre className="text-[10px] text-on-surface/70 whitespace-pre-wrap font-mono">
464
+ {unifiedSummary.toolSummary}
465
+ </pre>
466
+ </div>
467
+ </div>
468
+ </div>
469
+ </div>
470
+ </div>
471
+ )}
472
  </div>
473
 
474
  {/* Modal Footer */}