@memberjunction/ng-ai-test-harness 2.57.0 → 2.59.0

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.
@@ -144,14 +144,40 @@ export class AgentExecutionMonitorComponent {
144
144
  this.destroy$ = new Subject();
145
145
  }
146
146
  ngOnChanges(changes) {
147
+ console.log('🔄 Execution Monitor ngOnChanges:', {
148
+ executionDataChanged: !!changes['executionData'],
149
+ modeChanged: !!changes['mode'],
150
+ hasExecutionData: !!this.executionData,
151
+ currentTreeLength: this.executionTree.length
152
+ });
147
153
  if (changes['executionData']) {
148
- // Check if we're starting a new live execution (empty liveSteps array)
149
- if (this.mode === 'live' &&
150
- this.executionData &&
151
- this.executionData.liveSteps &&
152
- this.executionData.liveSteps.length === 0 &&
153
- this.executionTree.length > 0) {
154
- // Clear everything for new run
154
+ // Log the change details
155
+ const oldData = changes['executionData'].previousValue;
156
+ const newData = changes['executionData'].currentValue;
157
+ console.log('📊 Execution data changed:', {
158
+ oldDataExists: !!oldData,
159
+ newDataExists: !!newData,
160
+ newDataKeys: newData ? Object.keys(newData) : [],
161
+ executionTreeLength: newData?.executionTree?.length,
162
+ forceRefresh: newData?._forceRefresh
163
+ });
164
+ // Check if this is a different execution by comparing run IDs
165
+ const oldRunId = oldData?.agentRun?.ID || oldData?.promptRun?.ID;
166
+ const newRunId = newData?.agentRun?.ID || newData?.promptRun?.ID;
167
+ const isDifferentExecution = oldRunId && newRunId && oldRunId !== newRunId;
168
+ const isStartingNewLiveExecution = this.mode === 'live' &&
169
+ newData &&
170
+ newData.liveSteps &&
171
+ newData.liveSteps.length === 0 &&
172
+ this.executionTree.length > 0;
173
+ const isForceRefresh = newData && newData._forceRefresh;
174
+ // Clear if it's a genuinely different execution, starting fresh live execution, or force refresh
175
+ if (isDifferentExecution || isStartingNewLiveExecution || isForceRefresh) {
176
+ console.log('🗑️ Clearing execution tree due to:', {
177
+ isDifferentExecution,
178
+ isStartingNewLiveExecution,
179
+ isForceRefresh
180
+ });
155
181
  this.processedStepIds.clear();
156
182
  this.newlyAddedNodeIds.clear();
157
183
  this.clearNodeComponents();
@@ -159,37 +185,59 @@ export class AgentExecutionMonitorComponent {
159
185
  this.currentStep = null;
160
186
  this.calculateStats();
161
187
  }
162
- // Process data even if it's empty/null (for initial setup)
188
+ // Check for auto-expand flag
189
+ if (this.executionData && this.executionData._autoExpandAll) {
190
+ // Auto-expand all nodes after a short delay to ensure rendering is complete
191
+ setTimeout(() => {
192
+ this.expandAllNodes();
193
+ }, 50);
194
+ }
195
+ // Process data (this will preserve existing nodes if it's the same execution)
163
196
  this.processExecutionData();
164
197
  }
165
- // Handle mode changes
198
+ // Handle mode changes - be more selective about when to clear
166
199
  if (changes['mode'] && !changes['mode'].firstChange) {
167
- // Clear live nodes when switching from live to historical
168
- if (changes['mode'].previousValue === 'live' && changes['mode'].currentValue === 'historical') {
200
+ const previousMode = changes['mode'].previousValue;
201
+ const currentMode = changes['mode'].currentValue;
202
+ console.log('🔄 Mode changed:', { previousMode, currentMode });
203
+ // Only clear when switching from live to historical AND we don't have historical data
204
+ if (previousMode === 'live' && currentMode === 'historical') {
169
205
  // Stop live updates
170
206
  if (this.updateSubscription) {
171
207
  this.updateSubscription.unsubscribe();
172
208
  this.updateSubscription = undefined;
173
209
  }
174
- // Clear all tracking data from live mode
175
- this.processedStepIds.clear();
176
- this.newlyAddedNodeIds.clear();
177
- this.clearNodeComponents();
178
- this.executionTree = [];
210
+ // Only clear if we don't have valid historical data to show
211
+ if (!this.executionData || (!this.executionData.executionTree && !this.executionData.steps)) {
212
+ this.processedStepIds.clear();
213
+ this.newlyAddedNodeIds.clear();
214
+ this.clearNodeComponents();
215
+ this.executionTree = [];
216
+ }
179
217
  }
180
218
  this.processExecutionData();
181
219
  }
182
220
  }
183
221
  ngAfterViewInit() {
184
222
  this.viewInitialized = true;
223
+ console.log('🎯 View initialized, checking for pending data:', {
224
+ hasExecutionData: !!this.executionData,
225
+ treeLength: this.executionTree.length,
226
+ hasContainer: !!this.executionNodesContainer
227
+ });
185
228
  // Initial setup for scroll behavior
186
229
  if (this.mode === 'live') {
187
230
  this.checkIfUserAtBottom();
188
231
  }
189
232
  // If we have data waiting to be rendered, render it now
190
233
  if (this.executionData && this.executionTree.length === 0) {
234
+ console.log('⚡ Processing pending execution data after view init');
191
235
  this.processExecutionData();
192
236
  }
237
+ else if (this.executionTree.length > 0 && this.nodeComponentMap.size === 0) {
238
+ console.log('⚡ Re-rendering existing tree after view init');
239
+ this.renderTree();
240
+ }
193
241
  }
194
242
  ngOnDestroy() {
195
243
  this.destroy$.next();
@@ -214,15 +262,23 @@ export class AgentExecutionMonitorComponent {
214
262
  * Process execution data based on mode
215
263
  */
216
264
  processExecutionData() {
265
+ console.log('⚙️ Processing execution data:', {
266
+ mode: this.mode,
267
+ hasExecutionData: !!this.executionData,
268
+ currentTreeLength: this.executionTree.length,
269
+ viewInitialized: this.viewInitialized,
270
+ hasContainer: !!this.executionNodesContainer
271
+ });
217
272
  if (this.mode === 'historical') {
218
- // Clear processed step IDs when processing historical data
219
- this.processedStepIds.clear();
273
+ // Only clear processed step IDs if we don't have existing data or it's different data
274
+ if (this.executionTree.length === 0) {
275
+ this.processedStepIds.clear();
276
+ }
220
277
  // Process historical data
221
278
  this.buildTreeFromHistoricalData();
222
279
  }
223
280
  else {
224
- // For live mode, only clear if we don't have existing data
225
- // This prevents losing state when switching tabs
281
+ // For live mode, preserve existing data when possible
226
282
  if (this.executionTree.length === 0) {
227
283
  this.processedStepIds.clear();
228
284
  this.newlyAddedNodeIds.clear();
@@ -230,16 +286,26 @@ export class AgentExecutionMonitorComponent {
230
286
  // Set up live updates
231
287
  this.setupLiveUpdates();
232
288
  }
233
- // Only calculate stats if we have data
234
- if (this.executionTree.length > 0) {
235
- this.calculateStats();
289
+ // Always calculate stats when we have data or when processing new data
290
+ this.calculateStats();
291
+ // Force change detection after processing
292
+ if (this.viewInitialized) {
293
+ this.cdr.markForCheck();
294
+ this.cdr.detectChanges();
236
295
  }
237
296
  }
238
297
  /**
239
298
  * Build tree from historical execution data
240
299
  */
241
300
  buildTreeFromHistoricalData() {
301
+ console.log('🏗️ Building tree from historical data:', {
302
+ hasExecutionData: !!this.executionData,
303
+ executionTreeLength: this.executionData?.executionTree?.length,
304
+ stepsLength: this.executionData?.steps?.length,
305
+ currentTreeLength: this.executionTree.length
306
+ });
242
307
  if (!this.executionData) {
308
+ console.log('⚠️ No execution data available');
243
309
  this.clearNodeComponents();
244
310
  this.executionTree = [];
245
311
  return;
@@ -248,47 +314,74 @@ export class AgentExecutionMonitorComponent {
248
314
  this.clearNodeComponents();
249
315
  // Handle executionTree format - historical mode should only use saved database data
250
316
  if (this.executionData.executionTree) {
317
+ console.log('📊 Converting execution tree with', this.executionData.executionTree.length, 'nodes');
251
318
  const allNodes = this.convertExecutionTree(this.executionData.executionTree);
319
+ console.log('🔄 Converted to', allNodes.length, 'tree nodes');
252
320
  // Filter out live-only nodes in historical mode
253
321
  this.executionTree = this.filterNodesForMode(allNodes, 'historical');
322
+ console.log('✅ After filtering for historical mode:', this.executionTree.length, 'nodes');
254
323
  }
255
324
  else if (this.executionData.steps) {
325
+ console.log('📊 Converting legacy steps with', this.executionData.steps.length, 'steps');
256
326
  // Handle legacy steps format
257
327
  const allNodes = this.convertLegacySteps(this.executionData.steps);
258
328
  this.executionTree = this.filterNodesForMode(allNodes, 'historical');
329
+ console.log('✅ After converting legacy steps:', this.executionTree.length, 'nodes');
259
330
  }
260
331
  else {
332
+ console.log('⚠️ No executionTree or steps found in data');
261
333
  this.executionTree = [];
262
334
  }
263
- // Render the tree using dynamic components
335
+ // Always render the tree if we have a container
264
336
  if (this.executionNodesContainer) {
337
+ console.log('🎨 Rendering tree with', this.executionTree.length, 'nodes');
265
338
  this.renderTree();
266
339
  }
340
+ else {
341
+ console.log('⚠️ No execution nodes container available for rendering');
342
+ }
267
343
  }
268
344
  /**
269
345
  * Render the execution tree using dynamic components
270
346
  */
271
347
  renderTree() {
348
+ console.log('🎨 Rendering execution tree:', {
349
+ hasContainer: !!this.executionNodesContainer,
350
+ treeLength: this.executionTree.length,
351
+ viewInitialized: this.viewInitialized
352
+ });
272
353
  if (!this.executionNodesContainer) {
273
354
  console.warn('📊 Execution Monitor: No container available for rendering');
274
355
  return;
275
356
  }
276
357
  // Clear and recreate all components for historical view
277
358
  this.clearNodeComponents();
359
+ console.log('🔄 Creating components for', this.executionTree.length, 'nodes');
278
360
  // Create components for each root node
279
361
  for (const node of this.executionTree) {
280
- this.createNodeComponent(node, this.executionNodesContainer);
362
+ const componentRef = this.createNodeComponent(node, this.executionNodesContainer);
363
+ console.log('✅ Created component for node:', node.name, 'depth:', node.depth);
281
364
  }
365
+ // Force change detection after rendering
366
+ this.cdr.markForCheck();
367
+ this.cdr.detectChanges();
368
+ console.log('🎯 Tree rendering complete. Components created:', this.nodeComponentMap.size);
282
369
  }
283
370
  /**
284
371
  * Create a component for a node and its children
372
+ * This now ensures proper depth is passed and used for indentation
285
373
  */
286
374
  createNodeComponent(node, container) {
287
375
  const componentRef = container.createComponent(ExecutionNodeComponent);
288
376
  const instance = componentRef.instance;
377
+ // IMPORTANT: Ensure the node has the correct depth
378
+ // Create a new node object to ensure Angular detects the change
379
+ const nodeWithDepth = {
380
+ ...node,
381
+ depth: node.depth || 0 // Ensure depth is always defined
382
+ };
289
383
  // Set inputs
290
- instance.node = node;
291
- // No need to apply margin here - it's handled in the component template
384
+ instance.node = nodeWithDepth;
292
385
  // Subscribe to outputs
293
386
  instance.toggleNode.subscribe((n) => this.toggleNode(n));
294
387
  instance.userInteracted.subscribe(() => this.onUserInteraction());
@@ -301,25 +394,25 @@ export class AgentExecutionMonitorComponent {
301
394
  }
302
395
  /**
303
396
  * Convert new execution tree format to display nodes
397
+ * FIXED: Maintain proper hierarchy for sub-agents instead of flattening
304
398
  */
305
399
  convertExecutionTree(nodes, depth = 0) {
400
+ const treeNodes = [];
306
401
  // Sort nodes by StepNumber before processing
307
402
  const sortedNodes = [...nodes].sort((a, b) => {
308
403
  const aStepNum = a.step?.StepNumber || 0;
309
404
  const bStepNum = b.step?.StepNumber || 0;
310
405
  return aStepNum - bStepNum;
311
406
  });
312
- return sortedNodes.map((node, index) => {
313
- // Parse the step name for markdown content (same as live steps)
407
+ for (const node of sortedNodes) {
408
+ // Parse the step name for markdown content
314
409
  const stepName = node.step?.StepName || 'Unknown Step';
315
410
  let name = stepName;
316
411
  let detailsMarkdown;
317
- // Check if the step name contains markdown (indicated by newlines or markdown syntax)
412
+ // Check if the step name contains markdown
318
413
  if (stepName.includes('\n') || stepName.includes('**') || stepName.includes('##')) {
319
- // Split by newline and use first line as name
320
414
  const lines = stepName.split('\n');
321
415
  name = lines[0].trim();
322
- // Rest is markdown details
323
416
  if (lines.length > 1) {
324
417
  detailsMarkdown = lines.slice(1).join('\n').trim();
325
418
  }
@@ -343,7 +436,7 @@ export class AgentExecutionMonitorComponent {
343
436
  const inputPreview = this.createPreview(node.inputData);
344
437
  const outputPreview = this.createPreview(node.outputData);
345
438
  const treeNode = {
346
- id: node.step?.ID || `node-${Date.now()}-${index}`,
439
+ id: node.step?.ID || `node-${Date.now()}-${Math.random()}`,
347
440
  name: name,
348
441
  type: this.mapStepType(node.executionType || node.step?.StepType),
349
442
  status: this.mapStepStatus(node.step?.Status),
@@ -354,13 +447,13 @@ export class AgentExecutionMonitorComponent {
354
447
  inputPreview: inputPreview,
355
448
  outputPreview: outputPreview,
356
449
  error: node.step?.ErrorMessage,
357
- expanded: false,
358
- depth: node.depth !== undefined ? node.depth : depth, // Use node.depth if available, fallback to recursion depth
450
+ expanded: false, // Start collapsed for sub-agents
451
+ depth: depth, // Use actual depth for proper indentation
359
452
  tokensUsed: this.extractTokens(node.outputData),
360
453
  cost: this.extractCost(node.outputData),
361
454
  detailsMarkdown: detailsMarkdown,
362
455
  detailsExpanded: false,
363
- children: node.children ? this.convertExecutionTree(node.children, node.depth !== undefined ? node.depth + 1 : depth + 1) : undefined,
456
+ children: undefined, // Will be set below
364
457
  displayMode: displayMode
365
458
  };
366
459
  // Add agent metadata if this is a sub-agent node
@@ -376,8 +469,13 @@ export class AgentExecutionMonitorComponent {
376
469
  treeNode.actionId = this.lastParsedActionData.actionId;
377
470
  treeNode.actionIconClass = this.lastParsedActionData.actionIconClass;
378
471
  }
379
- return treeNode;
380
- });
472
+ // IMPORTANT: Process children recursively to maintain hierarchy
473
+ if (node.children && node.children.length > 0) {
474
+ treeNode.children = this.convertExecutionTree(node.children, depth + 1);
475
+ }
476
+ treeNodes.push(treeNode);
477
+ }
478
+ return treeNodes;
381
479
  }
382
480
  /**
383
481
  * Convert legacy step format to tree nodes
@@ -423,6 +521,7 @@ export class AgentExecutionMonitorComponent {
423
521
  'validation': 'validation',
424
522
  'prompt': 'prompt',
425
523
  'action': 'action',
524
+ 'action_execution': 'action',
426
525
  'subagent': 'sub-agent',
427
526
  'sub-agent': 'sub-agent',
428
527
  'decision': 'decision',
@@ -595,6 +694,7 @@ export class AgentExecutionMonitorComponent {
595
694
  }
596
695
  /**
597
696
  * Convert live steps format to execution tree format
697
+ * FIXED: Ensure depth is properly preserved
598
698
  */
599
699
  convertLiveStepsToTree(liveSteps) {
600
700
  const treeNodes = [];
@@ -628,7 +728,7 @@ export class AgentExecutionMonitorComponent {
628
728
  startTime: step.startTime ? new Date(step.startTime) : new Date(),
629
729
  agentPath: step.agentHierarchy || [],
630
730
  expanded: false,
631
- depth: step.depth || 0,
731
+ depth: step.depth !== undefined ? step.depth : 0, // Ensure depth is always defined
632
732
  detailsMarkdown: detailsMarkdown,
633
733
  detailsExpanded: false
634
734
  };
@@ -690,6 +790,7 @@ export class AgentExecutionMonitorComponent {
690
790
  // Update the component if it exists
691
791
  const componentRef = this.nodeComponentMap.get(nodeId);
692
792
  if (componentRef) {
793
+ // Create a new object to ensure change detection
693
794
  componentRef.instance.node = { ...node };
694
795
  componentRef.changeDetectorRef.detectChanges();
695
796
  }
@@ -732,31 +833,63 @@ export class AgentExecutionMonitorComponent {
732
833
  this.stats.totalTokens = this.executionData.agentRun.TotalTokensUsed || 0;
733
834
  this.stats.totalCost = this.executionData.agentRun.TotalCost || 0;
734
835
  }
735
- const processNode = (node) => {
736
- this.stats.totalSteps++;
737
- if (node.status === 'completed')
738
- this.stats.completedSteps++;
739
- if (node.status === 'failed')
740
- this.stats.failedSteps++;
741
- // Only accumulate tokens if we don't have agent run data
742
- if (!this.executionData?.agentRun) {
743
- if (node.tokensUsed)
744
- this.stats.totalTokens += node.tokensUsed;
745
- if (node.cost)
746
- this.stats.totalCost += node.cost;
747
- }
748
- if (node.duration)
749
- this.stats.totalDuration += node.duration;
750
- this.stats.stepsByType[node.type] = (this.stats.stepsByType[node.type] || 0) + 1;
751
- // Count prompts
752
- if (node.type === 'prompt' || node.promptCount) {
753
- this.stats.totalPrompts += node.promptCount || 1;
754
- }
755
- if (node.children) {
756
- node.children.forEach(child => processNode(child));
757
- }
758
- };
759
- this.executionTree.forEach(node => processNode(node));
836
+ // Calculate stats from execution tree nodes if we have them
837
+ if (this.executionTree.length > 0) {
838
+ const processNode = (node) => {
839
+ this.stats.totalSteps++;
840
+ if (node.status === 'completed')
841
+ this.stats.completedSteps++;
842
+ if (node.status === 'failed')
843
+ this.stats.failedSteps++;
844
+ // Only accumulate tokens if we don't have agent run data
845
+ if (!this.executionData?.agentRun) {
846
+ if (node.tokensUsed)
847
+ this.stats.totalTokens += node.tokensUsed;
848
+ if (node.cost)
849
+ this.stats.totalCost += node.cost;
850
+ }
851
+ if (node.duration)
852
+ this.stats.totalDuration += node.duration;
853
+ this.stats.stepsByType[node.type] = (this.stats.stepsByType[node.type] || 0) + 1;
854
+ // Count prompts
855
+ if (node.type === 'prompt' || node.promptCount) {
856
+ this.stats.totalPrompts += node.promptCount || 1;
857
+ }
858
+ if (node.children) {
859
+ node.children.forEach(child => processNode(child));
860
+ }
861
+ };
862
+ this.executionTree.forEach(node => processNode(node));
863
+ }
864
+ else if (this.executionData?.executionTree) {
865
+ // If we don't have processed tree nodes but have raw execution data, calculate from raw data
866
+ console.log('📈 Calculating stats from raw execution data since tree is empty');
867
+ const processRawNode = (node) => {
868
+ this.stats.totalSteps++;
869
+ const status = this.mapStepStatus(node.step?.Status);
870
+ if (status === 'completed')
871
+ this.stats.completedSteps++;
872
+ if (status === 'failed')
873
+ this.stats.failedSteps++;
874
+ if (node.durationMs)
875
+ this.stats.totalDuration += node.durationMs;
876
+ const nodeType = this.mapStepType(node.executionType || node.step?.StepType);
877
+ this.stats.stepsByType[nodeType] = (this.stats.stepsByType[nodeType] || 0) + 1;
878
+ if (nodeType === 'prompt') {
879
+ this.stats.totalPrompts += 1;
880
+ }
881
+ if (node.children) {
882
+ node.children.forEach((child) => processRawNode(child));
883
+ }
884
+ };
885
+ this.executionData.executionTree.forEach((node) => processRawNode(node));
886
+ }
887
+ console.log('📈 Stats calculated:', {
888
+ totalSteps: this.stats.totalSteps,
889
+ treeLength: this.executionTree.length,
890
+ executionDataExists: !!this.executionData,
891
+ hasRawExecutionTree: !!this.executionData?.executionTree
892
+ });
760
893
  }
761
894
  /**
762
895
  * Toggle node expansion
@@ -775,18 +908,6 @@ export class AgentExecutionMonitorComponent {
775
908
  this.cdr.markForCheck();
776
909
  }
777
910
  }
778
- /**
779
- * Check if node has expandable content
780
- */
781
- hasExpandableContent(node) {
782
- return !!(node.children && node.children.length > 0) ||
783
- node.type === 'sub-agent' ||
784
- node.type === 'action' ||
785
- !!node.inputPreview ||
786
- !!node.outputPreview ||
787
- !!node.error ||
788
- !!node.detailsMarkdown;
789
- }
790
911
  /**
791
912
  * Handle scroll events
792
913
  */
@@ -915,6 +1036,7 @@ export class AgentExecutionMonitorComponent {
915
1036
  }
916
1037
  /**
917
1038
  * Append new live steps without re-rendering entire tree
1039
+ * FIXED: Ensure depth is properly preserved when creating nodes
918
1040
  */
919
1041
  appendNewLiveSteps(liveSteps) {
920
1042
  if (!liveSteps || liveSteps.length === 0)
@@ -995,13 +1117,13 @@ export class AgentExecutionMonitorComponent {
995
1117
  }
996
1118
  }
997
1119
  else {
998
- // Create new node
1120
+ // Create new node with proper depth
999
1121
  const newNode = this.createNodeFromLiveStep(step);
1000
- // Debug: Log if depth is missing
1001
- if (newNode.depth === 0 && step.depth !== 0) {
1002
- console.warn('Node depth was reset to 0 for step:', step);
1122
+ // Ensure depth is set from the step data
1123
+ if (step.depth !== undefined) {
1124
+ newNode.depth = step.depth;
1003
1125
  }
1004
- if (step.depth === 0) {
1126
+ if (newNode.depth === 0) {
1005
1127
  // Add to tree and create component
1006
1128
  this.executionTree.push(newNode);
1007
1129
  this.createNodeComponent(newNode, this.executionNodesContainer);
@@ -1025,7 +1147,7 @@ export class AgentExecutionMonitorComponent {
1025
1147
  }
1026
1148
  }
1027
1149
  else {
1028
- // If no parent found, add as root
1150
+ // If no parent found, add as root but preserve depth
1029
1151
  this.executionTree.push(newNode);
1030
1152
  this.createNodeComponent(newNode, this.executionNodesContainer);
1031
1153
  }
@@ -1105,7 +1227,8 @@ export class AgentExecutionMonitorComponent {
1105
1227
  * Filter nodes based on display mode
1106
1228
  */
1107
1229
  filterNodesForMode(nodes, mode) {
1108
- return nodes.filter(node => {
1230
+ console.log('🔍 Filtering nodes for mode:', mode, 'from', nodes.length, 'nodes');
1231
+ const filteredNodes = nodes.filter(node => {
1109
1232
  // If no displayMode is set, default to showing in both modes
1110
1233
  if (!node.displayMode) {
1111
1234
  return true;
@@ -1118,8 +1241,11 @@ export class AgentExecutionMonitorComponent {
1118
1241
  }
1119
1242
  return true;
1120
1243
  }
1244
+ console.log('📄 Filtering out node in', mode, 'mode:', node.name, 'displayMode:', node.displayMode);
1121
1245
  return false;
1122
1246
  });
1247
+ console.log('✅ Filtered to', filteredNodes.length, 'nodes for mode:', mode);
1248
+ return filteredNodes;
1123
1249
  }
1124
1250
  /**
1125
1251
  * Build a map of nodes by ID for quick lookup
@@ -1134,6 +1260,7 @@ export class AgentExecutionMonitorComponent {
1134
1260
  }
1135
1261
  /**
1136
1262
  * Create a single node from a live step
1263
+ * FIXED: Ensure depth is properly set from step data
1137
1264
  */
1138
1265
  createNodeFromLiveStep(step) {
1139
1266
  const stepName = step.step?.StepName || 'Processing...';
@@ -1180,6 +1307,8 @@ export class AgentExecutionMonitorComponent {
1180
1307
  const inputPreview = this.createPreview(step.inputData);
1181
1308
  const outputPreview = this.createPreview(step.outputData);
1182
1309
  const nodeType = this.mapStepType(step.executionType || step.step?.StepType);
1310
+ // IMPORTANT: Use the depth from step data, ensure it's always defined
1311
+ const nodeDepth = step.depth !== undefined ? step.depth : 0;
1183
1312
  const node = {
1184
1313
  id: step.step?.ID || this.generateStepId(step),
1185
1314
  name: name,
@@ -1190,7 +1319,7 @@ export class AgentExecutionMonitorComponent {
1190
1319
  duration: step.durationMs,
1191
1320
  agentPath: step.agentHierarchy || [],
1192
1321
  expanded: false,
1193
- depth: step.depth || 0,
1322
+ depth: nodeDepth, // Use the extracted depth
1194
1323
  detailsMarkdown: detailsMarkdown,
1195
1324
  detailsExpanded: false,
1196
1325
  inputPreview: inputPreview,
@@ -1292,6 +1421,87 @@ export class AgentExecutionMonitorComponent {
1292
1421
  }
1293
1422
  return false;
1294
1423
  }
1424
+ /**
1425
+ * Expands nodes in the execution tree that have children
1426
+ * Called when auto-expand flag is detected or execution completes
1427
+ */
1428
+ expandAllNodes() {
1429
+ if (!this.executionTree || this.executionTree.length === 0) {
1430
+ return;
1431
+ }
1432
+ console.log('🔄 Starting auto-expansion of nodes with children', this.executionTree.length);
1433
+ // Recursively expand only nodes that have children
1434
+ const expandNodeRecursively = (nodes) => {
1435
+ for (const node of nodes) {
1436
+ // Only expand nodes that have children (sub-nodes)
1437
+ const hasChildren = node.children && node.children.length > 0;
1438
+ if (hasChildren) {
1439
+ node.expanded = true;
1440
+ console.log(`Expanding node with children: ${node.name}`, {
1441
+ childCount: node.children?.length,
1442
+ nodeType: node.type
1443
+ });
1444
+ // Update the corresponding component if it exists
1445
+ const componentRef = this.nodeComponentMap.get(node.id);
1446
+ if (componentRef) {
1447
+ // Create a new object to ensure change detection
1448
+ const updatedNode = { ...node, expanded: true };
1449
+ componentRef.instance.node = updatedNode;
1450
+ componentRef.changeDetectorRef.markForCheck();
1451
+ componentRef.changeDetectorRef.detectChanges();
1452
+ console.log(`Updated component for node: ${node.name}`);
1453
+ }
1454
+ else {
1455
+ console.log(`No component found for node: ${node.name}`);
1456
+ }
1457
+ // Expand children recursively
1458
+ expandNodeRecursively(node.children);
1459
+ }
1460
+ else {
1461
+ console.log(`Skipping node without children: ${node.name}`, {
1462
+ hasExpandableContent: this.hasExpandableContent(node),
1463
+ hasInputPreview: !!node.inputPreview,
1464
+ hasOutputPreview: !!node.outputPreview,
1465
+ hasError: !!node.error,
1466
+ hasDetailsMarkdown: !!node.detailsMarkdown
1467
+ });
1468
+ }
1469
+ }
1470
+ };
1471
+ expandNodeRecursively(this.executionTree);
1472
+ // Trigger change detection for the entire component
1473
+ this.cdr.markForCheck();
1474
+ this.cdr.detectChanges();
1475
+ console.log('✅ Completed auto-expansion of nodes with children');
1476
+ // Scroll to top after expansion to show the full tree
1477
+ setTimeout(() => {
1478
+ this.scrollToTop();
1479
+ }, 100);
1480
+ }
1481
+ /**
1482
+ * Scroll the execution tree to the top
1483
+ */
1484
+ scrollToTop() {
1485
+ if (this.executionTreeContainer) {
1486
+ const element = this.executionTreeContainer.nativeElement;
1487
+ element.scrollTo({
1488
+ top: 0,
1489
+ behavior: 'smooth'
1490
+ });
1491
+ }
1492
+ }
1493
+ /**
1494
+ * Check if node has expandable content
1495
+ */
1496
+ hasExpandableContent(node) {
1497
+ return !!(node.children && node.children.length > 0) ||
1498
+ node.type === 'sub-agent' ||
1499
+ node.type === 'action' ||
1500
+ !!node.inputPreview ||
1501
+ !!node.outputPreview ||
1502
+ !!node.error ||
1503
+ !!node.detailsMarkdown;
1504
+ }
1295
1505
  static { this.ɵfac = function AgentExecutionMonitorComponent_Factory(t) { return new (t || AgentExecutionMonitorComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); }; }
1296
1506
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AgentExecutionMonitorComponent, selectors: [["mj-agent-execution-monitor"]], viewQuery: function AgentExecutionMonitorComponent_Query(rf, ctx) { if (rf & 1) {
1297
1507
  i0.ɵɵviewQuery(_c0, 5);
@@ -1371,7 +1581,7 @@ export class AgentExecutionMonitorComponent {
1371
1581
  i0.ɵɵconditional(ctx.stats.totalDuration ? 37 : -1);
1372
1582
  i0.ɵɵadvance();
1373
1583
  i0.ɵɵconditional(ctx.getStepTypes().length > 0 ? 38 : -1);
1374
- } }, dependencies: [CommonModule], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n \n .execution-monitor[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n background: #fff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n \n\n .monitor-header[_ngcontent-%COMP%] {\n padding: 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .header-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n margin-bottom: 8px;\n }\n\n .header-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .live-indicator[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n background: #ff4444;\n color: white;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.5px;\n }\n\n .pulse[_ngcontent-%COMP%] {\n display: inline-block;\n width: 8px;\n height: 8px;\n background: white;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_pulse 2s infinite;\n }\n\n @keyframes _ngcontent-%COMP%_pulse {\n 0% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.8); }\n 100% { opacity: 1; transform: scale(1); }\n }\n\n .current-status[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #666;\n }\n\n .status-label[_ngcontent-%COMP%] {\n font-weight: 500;\n }\n\n .agent-path[_ngcontent-%COMP%] {\n color: #999;\n }\n\n .step-name[_ngcontent-%COMP%] {\n color: #1a1a1a;\n font-weight: 500;\n }\n\n \n\n .execution-tree[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: auto;\n padding: 16px;\n min-height: 0;\n }\n \n .nodes-container[_ngcontent-%COMP%] {\n \n\n }\n\n .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #999;\n text-align: center;\n }\n\n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n }\n\n \n\n .tree-node[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n }\n\n .node-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: #f8f9fa;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n user-select: none;\n }\n\n .node-header[_ngcontent-%COMP%]:hover {\n background: #e8f0fe;\n border-color: #2196f3;\n }\n\n .expand-icon[_ngcontent-%COMP%], .expand-spacer[_ngcontent-%COMP%] {\n width: 16px;\n text-align: center;\n color: #666;\n font-size: 10px;\n }\n\n .status-icon[_ngcontent-%COMP%] {\n width: 20px;\n text-align: center;\n font-size: 14px;\n }\n\n .status-pending[_ngcontent-%COMP%] { color: #999; }\n .status-running[_ngcontent-%COMP%] { color: #2196f3; }\n .status-completed[_ngcontent-%COMP%] { color: #4caf50; }\n .status-failed[_ngcontent-%COMP%] { color: #f44336; }\n\n .type-icon[_ngcontent-%COMP%] {\n width: 20px;\n text-align: center;\n font-size: 14px;\n color: #666;\n }\n\n .node-name[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 13px;\n font-weight: 500;\n color: #1a1a1a;\n }\n\n .node-duration[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #666;\n font-weight: 500;\n }\n\n .node-metrics[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n font-size: 12px;\n }\n\n .tokens[_ngcontent-%COMP%] {\n color: #666;\n }\n\n .cost[_ngcontent-%COMP%] {\n color: #2196f3;\n font-weight: 500;\n }\n\n \n\n .node-details[_ngcontent-%COMP%] {\n margin: 8px 0 8px 44px;\n padding: 12px;\n background: #f5f5f5;\n border-radius: 4px;\n font-size: 12px;\n }\n\n .detail-section[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n }\n\n .detail-section[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n }\n\n .detail-section.error[_ngcontent-%COMP%] {\n color: #d32f2f;\n }\n\n .detail-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n margin-bottom: 4px;\n color: #666;\n }\n\n .detail-section.error[_ngcontent-%COMP%] .detail-label[_ngcontent-%COMP%] {\n color: #d32f2f;\n }\n\n .detail-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .detail-content[_ngcontent-%COMP%] {\n padding-left: 18px;\n color: #333;\n line-height: 1.4;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n \n\n .monitor-footer[_ngcontent-%COMP%] {\n padding: 16px;\n background: #f8f9fa;\n border-top: 1px solid #e0e0e0;\n }\n\n .stats-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));\n gap: 16px;\n margin-bottom: 12px;\n }\n\n .stat-item[_ngcontent-%COMP%] {\n text-align: center;\n }\n\n .stat-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 11px;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 4px;\n }\n\n .stat-value[_ngcontent-%COMP%] {\n display: block;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n }\n\n .failed-count[_ngcontent-%COMP%] {\n color: #f44336;\n font-size: 12px;\n font-weight: normal;\n }\n\n .step-types[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n justify-content: center;\n }\n\n .type-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 4px 8px;\n background: #e3f2fd;\n color: #1976d2;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n }\n\n \n\n .details-toggle[_ngcontent-%COMP%] {\n margin-left: 8px;\n padding: 2px 6px;\n background: transparent;\n border: 1px solid #ddd;\n border-radius: 3px;\n cursor: pointer;\n font-size: 10px;\n color: #666;\n transition: all 0.2s ease;\n }\n \n .details-toggle[_ngcontent-%COMP%]:hover {\n background: #f0f0f0;\n border-color: #2196f3;\n color: #2196f3;\n }\n \n \n\n .markdown-details[_ngcontent-%COMP%] {\n margin: 8px 0 8px 44px;\n padding: 12px;\n background: #f9fafb;\n border-left: 3px solid #2196f3;\n border-radius: 0 4px 4px 0;\n font-size: 13px;\n line-height: 1.6;\n }\n \n .markdown-details[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n font-size: 16px;\n margin: 0 0 8px 0;\n color: #1a1a1a;\n }\n \n .markdown-details[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n margin: 8px 0 6px 0;\n color: #333;\n }\n \n .markdown-details[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n font-size: 13px;\n margin: 6px 0 4px 0;\n color: #555;\n }\n \n .markdown-details[_ngcontent-%COMP%] ul[_ngcontent-%COMP%] {\n margin: 4px 0;\n padding-left: 20px;\n }\n \n .markdown-details[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n margin: 2px 0;\n }\n \n .markdown-details[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: #e8f0fe;\n padding: 1px 4px;\n border-radius: 3px;\n font-family: 'Consolas', 'Monaco', monospace;\n font-size: 12px;\n }\n \n .markdown-details[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n background: #f5f5f5;\n padding: 8px;\n border-radius: 4px;\n overflow-x: auto;\n margin: 8px 0;\n }\n \n .markdown-details[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: none;\n padding: 0;\n }\n \n .markdown-details[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-weight: 600;\n color: #1a1a1a;\n }\n \n .markdown-details[_ngcontent-%COMP%] em[_ngcontent-%COMP%] {\n font-style: italic;\n color: #555;\n }\n\n \n\n .execution-history-toggle[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 4px 8px;\n margin-left: 4px;\n cursor: pointer;\n color: #666;\n font-size: 12px;\n border-radius: 3px;\n transition: all 0.2s ease;\n }\n \n .execution-history-toggle[_ngcontent-%COMP%]:hover {\n background: #e3f2fd;\n color: #2196f3;\n }\n \n \n\n .view-run-btn[_ngcontent-%COMP%] {\n background: #2196f3;\n color: white;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s ease;\n margin-left: auto;\n }\n \n .view-run-btn[_ngcontent-%COMP%]:hover {\n background: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0,0,0,0.2);\n }\n \n .view-run-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n \n\n @media (max-width: 768px) {\n .monitor-header[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .execution-tree[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .node-header[_ngcontent-%COMP%] {\n padding: 6px 8px;\n gap: 6px;\n }\n\n .node-metrics[_ngcontent-%COMP%] {\n display: none;\n }\n \n .markdown-details[_ngcontent-%COMP%] {\n margin-left: 20px;\n font-size: 12px;\n }\n }"], changeDetection: 0 }); }
1584
+ } }, dependencies: [CommonModule], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n \n .execution-monitor[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n background: #fff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n \n\n .monitor-header[_ngcontent-%COMP%] {\n padding: 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .header-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n margin-bottom: 8px;\n }\n\n .header-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .live-indicator[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n background: #ff4444;\n color: white;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.5px;\n }\n\n .pulse[_ngcontent-%COMP%] {\n display: inline-block;\n width: 8px;\n height: 8px;\n background: white;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_pulse 2s infinite;\n }\n\n @keyframes _ngcontent-%COMP%_pulse {\n 0% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.8); }\n 100% { opacity: 1; transform: scale(1); }\n }\n\n .current-status[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #666;\n }\n\n .status-label[_ngcontent-%COMP%] {\n font-weight: 500;\n }\n\n .agent-path[_ngcontent-%COMP%] {\n color: #999;\n }\n\n .step-name[_ngcontent-%COMP%] {\n color: #1a1a1a;\n font-weight: 500;\n }\n\n \n\n .execution-tree[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: auto;\n padding: 16px;\n min-height: 0;\n }\n \n .nodes-container[_ngcontent-%COMP%] {\n \n\n }\n\n .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #999;\n text-align: center;\n }\n\n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n }\n\n \n\n .tree-node[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n }\n\n \n\n .monitor-footer[_ngcontent-%COMP%] {\n padding: 16px;\n background: #f8f9fa;\n border-top: 1px solid #e0e0e0;\n }\n\n .stats-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));\n gap: 16px;\n margin-bottom: 12px;\n }\n\n .stat-item[_ngcontent-%COMP%] {\n text-align: center;\n }\n\n .stat-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 11px;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 4px;\n }\n\n .stat-value[_ngcontent-%COMP%] {\n display: block;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n }\n\n .failed-count[_ngcontent-%COMP%] {\n color: #f44336;\n font-size: 12px;\n font-weight: normal;\n }\n\n .step-types[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n justify-content: center;\n }\n\n .type-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 4px 8px;\n background: #e3f2fd;\n color: #1976d2;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n }\n \n \n\n .view-run-btn[_ngcontent-%COMP%] {\n background: #2196f3;\n color: white;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s ease;\n margin-left: auto;\n }\n \n .view-run-btn[_ngcontent-%COMP%]:hover {\n background: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0,0,0,0.2);\n }\n \n .view-run-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n \n\n @media (max-width: 768px) {\n .monitor-header[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .execution-tree[_ngcontent-%COMP%] {\n padding: 12px;\n }\n }"], changeDetection: 0 }); }
1375
1585
  }
1376
1586
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AgentExecutionMonitorComponent, [{
1377
1587
  type: Component,
@@ -1463,7 +1673,7 @@ export class AgentExecutionMonitorComponent {
1463
1673
  }
1464
1674
  </div>
1465
1675
  </div>
1466
- `, styles: ["\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n \n .execution-monitor {\n display: flex;\n flex-direction: column;\n flex: 1;\n background: #fff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n /* Header */\n .monitor-header {\n padding: 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .header-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n margin-bottom: 8px;\n }\n\n .header-title i {\n color: #2196f3;\n }\n\n .live-indicator {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n background: #ff4444;\n color: white;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.5px;\n }\n\n .pulse {\n display: inline-block;\n width: 8px;\n height: 8px;\n background: white;\n border-radius: 50%;\n animation: pulse 2s infinite;\n }\n\n @keyframes pulse {\n 0% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.8); }\n 100% { opacity: 1; transform: scale(1); }\n }\n\n .current-status {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #666;\n }\n\n .status-label {\n font-weight: 500;\n }\n\n .agent-path {\n color: #999;\n }\n\n .step-name {\n color: #1a1a1a;\n font-weight: 500;\n }\n\n /* Execution Tree */\n .execution-tree {\n flex: 1;\n overflow-y: auto;\n overflow-x: auto;\n padding: 16px;\n min-height: 0;\n }\n \n .nodes-container {\n /* No extra padding needed, indentation handled by node margins */\n }\n\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #999;\n text-align: center;\n }\n\n .empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n }\n\n .empty-state p {\n margin: 0;\n font-size: 14px;\n }\n\n /* Tree Nodes */\n .tree-node {\n margin-bottom: 4px;\n }\n\n .node-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: #f8f9fa;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n user-select: none;\n }\n\n .node-header:hover {\n background: #e8f0fe;\n border-color: #2196f3;\n }\n\n .expand-icon, .expand-spacer {\n width: 16px;\n text-align: center;\n color: #666;\n font-size: 10px;\n }\n\n .status-icon {\n width: 20px;\n text-align: center;\n font-size: 14px;\n }\n\n .status-pending { color: #999; }\n .status-running { color: #2196f3; }\n .status-completed { color: #4caf50; }\n .status-failed { color: #f44336; }\n\n .type-icon {\n width: 20px;\n text-align: center;\n font-size: 14px;\n color: #666;\n }\n\n .node-name {\n flex: 1;\n font-size: 13px;\n font-weight: 500;\n color: #1a1a1a;\n }\n\n .node-duration {\n font-size: 12px;\n color: #666;\n font-weight: 500;\n }\n\n .node-metrics {\n display: flex;\n gap: 12px;\n font-size: 12px;\n }\n\n .tokens {\n color: #666;\n }\n\n .cost {\n color: #2196f3;\n font-weight: 500;\n }\n\n /* Node Details */\n .node-details {\n margin: 8px 0 8px 44px;\n padding: 12px;\n background: #f5f5f5;\n border-radius: 4px;\n font-size: 12px;\n }\n\n .detail-section {\n margin-bottom: 8px;\n }\n\n .detail-section:last-child {\n margin-bottom: 0;\n }\n\n .detail-section.error {\n color: #d32f2f;\n }\n\n .detail-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n margin-bottom: 4px;\n color: #666;\n }\n\n .detail-section.error .detail-label {\n color: #d32f2f;\n }\n\n .detail-label i {\n font-size: 12px;\n }\n\n .detail-content {\n padding-left: 18px;\n color: #333;\n line-height: 1.4;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n /* Footer */\n .monitor-footer {\n padding: 16px;\n background: #f8f9fa;\n border-top: 1px solid #e0e0e0;\n }\n\n .stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));\n gap: 16px;\n margin-bottom: 12px;\n }\n\n .stat-item {\n text-align: center;\n }\n\n .stat-label {\n display: block;\n font-size: 11px;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 4px;\n }\n\n .stat-value {\n display: block;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n }\n\n .failed-count {\n color: #f44336;\n font-size: 12px;\n font-weight: normal;\n }\n\n .step-types {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n justify-content: center;\n }\n\n .type-badge {\n display: inline-block;\n padding: 4px 8px;\n background: #e3f2fd;\n color: #1976d2;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n }\n\n /* Details Toggle Button */\n .details-toggle {\n margin-left: 8px;\n padding: 2px 6px;\n background: transparent;\n border: 1px solid #ddd;\n border-radius: 3px;\n cursor: pointer;\n font-size: 10px;\n color: #666;\n transition: all 0.2s ease;\n }\n \n .details-toggle:hover {\n background: #f0f0f0;\n border-color: #2196f3;\n color: #2196f3;\n }\n \n /* Markdown Details Section */\n .markdown-details {\n margin: 8px 0 8px 44px;\n padding: 12px;\n background: #f9fafb;\n border-left: 3px solid #2196f3;\n border-radius: 0 4px 4px 0;\n font-size: 13px;\n line-height: 1.6;\n }\n \n .markdown-details h2 {\n font-size: 16px;\n margin: 0 0 8px 0;\n color: #1a1a1a;\n }\n \n .markdown-details h3 {\n font-size: 14px;\n margin: 8px 0 6px 0;\n color: #333;\n }\n \n .markdown-details h4 {\n font-size: 13px;\n margin: 6px 0 4px 0;\n color: #555;\n }\n \n .markdown-details ul {\n margin: 4px 0;\n padding-left: 20px;\n }\n \n .markdown-details li {\n margin: 2px 0;\n }\n \n .markdown-details code {\n background: #e8f0fe;\n padding: 1px 4px;\n border-radius: 3px;\n font-family: 'Consolas', 'Monaco', monospace;\n font-size: 12px;\n }\n \n .markdown-details pre {\n background: #f5f5f5;\n padding: 8px;\n border-radius: 4px;\n overflow-x: auto;\n margin: 8px 0;\n }\n \n .markdown-details pre code {\n background: none;\n padding: 0;\n }\n \n .markdown-details strong {\n font-weight: 600;\n color: #1a1a1a;\n }\n \n .markdown-details em {\n font-style: italic;\n color: #555;\n }\n\n /* Button styling for execution history toggle */\n .execution-history-toggle {\n background: transparent;\n border: none;\n padding: 4px 8px;\n margin-left: 4px;\n cursor: pointer;\n color: #666;\n font-size: 12px;\n border-radius: 3px;\n transition: all 0.2s ease;\n }\n \n .execution-history-toggle:hover {\n background: #e3f2fd;\n color: #2196f3;\n }\n \n /* View Run Button */\n .view-run-btn {\n background: #2196f3;\n color: white;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s ease;\n margin-left: auto;\n }\n \n .view-run-btn:hover {\n background: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0,0,0,0.2);\n }\n \n .view-run-btn i {\n font-size: 12px;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .monitor-header {\n padding: 12px;\n }\n\n .execution-tree {\n padding: 12px;\n }\n\n .node-header {\n padding: 6px 8px;\n gap: 6px;\n }\n\n .node-metrics {\n display: none;\n }\n \n .markdown-details {\n margin-left: 20px;\n font-size: 12px;\n }\n }\n "] }]
1676
+ `, styles: ["\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n \n .execution-monitor {\n display: flex;\n flex-direction: column;\n flex: 1;\n background: #fff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n /* Header */\n .monitor-header {\n padding: 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .header-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n margin-bottom: 8px;\n }\n\n .header-title i {\n color: #2196f3;\n }\n\n .live-indicator {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n background: #ff4444;\n color: white;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.5px;\n }\n\n .pulse {\n display: inline-block;\n width: 8px;\n height: 8px;\n background: white;\n border-radius: 50%;\n animation: pulse 2s infinite;\n }\n\n @keyframes pulse {\n 0% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.8); }\n 100% { opacity: 1; transform: scale(1); }\n }\n\n .current-status {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #666;\n }\n\n .status-label {\n font-weight: 500;\n }\n\n .agent-path {\n color: #999;\n }\n\n .step-name {\n color: #1a1a1a;\n font-weight: 500;\n }\n\n /* Execution Tree */\n .execution-tree {\n flex: 1;\n overflow-y: auto;\n overflow-x: auto;\n padding: 16px;\n min-height: 0;\n }\n \n .nodes-container {\n /* No extra padding needed, indentation handled by node margins */\n }\n\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #999;\n text-align: center;\n }\n\n .empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n }\n\n .empty-state p {\n margin: 0;\n font-size: 14px;\n }\n\n /* Tree Nodes - These styles are for reference only, actual rendering is done by ExecutionNodeComponent */\n .tree-node {\n margin-bottom: 4px;\n }\n\n /* Footer */\n .monitor-footer {\n padding: 16px;\n background: #f8f9fa;\n border-top: 1px solid #e0e0e0;\n }\n\n .stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));\n gap: 16px;\n margin-bottom: 12px;\n }\n\n .stat-item {\n text-align: center;\n }\n\n .stat-label {\n display: block;\n font-size: 11px;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 4px;\n }\n\n .stat-value {\n display: block;\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n }\n\n .failed-count {\n color: #f44336;\n font-size: 12px;\n font-weight: normal;\n }\n\n .step-types {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n justify-content: center;\n }\n\n .type-badge {\n display: inline-block;\n padding: 4px 8px;\n background: #e3f2fd;\n color: #1976d2;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n }\n \n /* View Run Button */\n .view-run-btn {\n background: #2196f3;\n color: white;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s ease;\n margin-left: auto;\n }\n \n .view-run-btn:hover {\n background: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0,0,0,0.2);\n }\n \n .view-run-btn i {\n font-size: 12px;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .monitor-header {\n padding: 12px;\n }\n\n .execution-tree {\n padding: 12px;\n }\n }\n "] }]
1467
1677
  }], () => [{ type: i0.ChangeDetectorRef }], { mode: [{
1468
1678
  type: Input
1469
1679
  }], executionData: [{
@@ -1483,5 +1693,5 @@ export class AgentExecutionMonitorComponent {
1483
1693
  type: ViewChild,
1484
1694
  args: ['executionNodesContainer', { read: ViewContainerRef }]
1485
1695
  }] }); })();
1486
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentExecutionMonitorComponent, { className: "AgentExecutionMonitorComponent", filePath: "lib/agent-execution-monitor.component.ts", lineNumber: 643 }); })();
1696
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentExecutionMonitorComponent, { className: "AgentExecutionMonitorComponent", filePath: "lib/agent-execution-monitor.component.ts", lineNumber: 406 }); })();
1487
1697
  //# sourceMappingURL=agent-execution-monitor.component.js.map