3v324v23 commited on
Commit
4ecc764
·
1 Parent(s): 6b3d19c

Add termination signal detection for insufficient analysis results

Browse files

- Detect when analysis results cannot answer group comparison queries
- Add termination_recommended and termination_reason fields to tool results
- Include detailed limitations and solution suggestions in summary
- Mark termination recommendation when all groups are 'default' (cannot perform group comparison)
- Provide clear guidance in summary for planner to identify when to terminate (not as error)

octotools/tools/cell_state_analyzer_multi/tool.py CHANGED
@@ -508,14 +508,46 @@ class Cell_State_Analyzer_Multi_Tool(BaseTool):
508
  adata.write(adata_path)
509
 
510
  # Generate summary based on analysis type
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
  if is_single_group:
512
  summary = f"Single-group analysis completed. {num_crops} cells analyzed. "
513
  summary += f"{len(history)} epochs trained" if history else "Zero-shot inference (no training)"
514
- summary += ". Group comparison not available (all cells in single group)."
 
 
 
 
 
515
  else:
516
  summary = f"Multi-group analysis completed. {num_crops} cells across {len(unique_groups)} groups. "
517
  summary += f"{len(history)} epochs trained" if history else "Zero-shot inference (no training)"
518
  summary += f". Groups: {', '.join(sorted(unique_groups))}"
 
 
519
 
520
  return {
521
  "summary": summary,
@@ -529,7 +561,11 @@ class Cell_State_Analyzer_Multi_Tool(BaseTool):
529
  "cluster_resolution": cluster_resolution,
530
  "analysis_type": "cell_state_analysis",
531
  "num_groups": len(unique_groups),
532
- "groups": sorted(unique_groups) if not is_single_group else ["default"]
 
 
 
 
533
  }
534
 
535
 
 
508
  adata.write(adata_path)
509
 
510
  # Generate summary based on analysis type
511
+ # Check if results are sufficient to answer group comparison queries
512
+ insufficient_for_comparison = False
513
+ comparison_limitations = []
514
+ termination_recommended = False
515
+ termination_reason = None
516
+
517
+ if is_single_group:
518
+ insufficient_for_comparison = True
519
+ comparison_limitations.append("All cells are labeled as 'default' - no group labels available for comparison")
520
+ # If query requires group comparison, recommend termination
521
+ termination_recommended = True
522
+ termination_reason = (
523
+ "**Cannot perform group comparison analysis:** All cells are in a single group ('default'). "
524
+ "Group comparison queries cannot be answered with the current data.\n\n"
525
+ "**Recommendation:** Terminate analysis and inform user that group labels are required for comparison queries.\n\n"
526
+ "**Solution:** Provide treatment/group labels when uploading images to enable group comparison analysis."
527
+ )
528
+
529
+ if num_crops < 10:
530
+ insufficient_for_comparison = True
531
+ comparison_limitations.append(f"Very small sample size ({num_crops} cells) - may be insufficient for robust statistical comparisons")
532
+
533
+ if use_zero_shot and not history:
534
+ comparison_limitations.append("Zero-shot inference mode (no training) - features may not be optimal for comparison")
535
+
536
  if is_single_group:
537
  summary = f"Single-group analysis completed. {num_crops} cells analyzed. "
538
  summary += f"{len(history)} epochs trained" if history else "Zero-shot inference (no training)"
539
+ summary += "\n\n⚠️ **Limitations for Group Comparison Queries:**\n"
540
+ summary += "- All cells are in a single group ('default') - group comparison analysis cannot be performed\n"
541
+ summary += "- To enable group comparison, provide treatment/group labels when uploading images\n"
542
+ summary += "- Current analysis provides single-group clustering and UMAP visualization only"
543
+ if termination_recommended:
544
+ summary += f"\n\n🛑 **Termination Recommendation:**\n{termination_reason}"
545
  else:
546
  summary = f"Multi-group analysis completed. {num_crops} cells across {len(unique_groups)} groups. "
547
  summary += f"{len(history)} epochs trained" if history else "Zero-shot inference (no training)"
548
  summary += f". Groups: {', '.join(sorted(unique_groups))}"
549
+ if comparison_limitations:
550
+ summary += "\n\n⚠️ **Note:** " + "; ".join(comparison_limitations)
551
 
552
  return {
553
  "summary": summary,
 
561
  "cluster_resolution": cluster_resolution,
562
  "analysis_type": "cell_state_analysis",
563
  "num_groups": len(unique_groups),
564
+ "groups": sorted(unique_groups) if not is_single_group else ["default"],
565
+ "insufficient_for_comparison": insufficient_for_comparison,
566
+ "comparison_limitations": comparison_limitations if comparison_limitations else None,
567
+ "termination_recommended": termination_recommended,
568
+ "termination_reason": termination_reason
569
  }
570
 
571
 
octotools/tools/cell_state_analyzer_single/tool.py CHANGED
@@ -474,8 +474,52 @@ class Cell_State_Analyzer_Single_Tool(BaseTool):
474
  adata_path = os.path.join(output_dir, "cell_state_analyzed.h5ad")
475
  adata.write(adata_path)
476
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  return {
478
- "summary": f"Analysis completed. {num_crops} cells, {len(history)} epochs" if history else f"Zero-shot: {num_crops} cells",
479
  "cell_count": num_crops,
480
  "mode": "training" if not use_zero_shot else "zero-shot",
481
  "epochs_trained": len(history),
@@ -484,7 +528,13 @@ class Cell_State_Analyzer_Single_Tool(BaseTool):
484
  "deliverables": [adata_path] + ([loss_path] if history and loss_path else []),
485
  "cluster_key": cluster_key,
486
  "cluster_resolution": cluster_resolution,
487
- "analysis_type": "cell_state_analysis"
 
 
 
 
 
 
488
  }
489
 
490
 
 
474
  adata_path = os.path.join(output_dir, "cell_state_analyzed.h5ad")
475
  adata.write(adata_path)
476
 
477
+ # Check if results are sufficient for group comparison queries
478
+ unique_groups = set(groups_extracted if len(groups_extracted) == adata.n_obs else groups[:adata.n_obs])
479
+ is_single_group = len(unique_groups) == 1
480
+ insufficient_for_comparison = False
481
+ comparison_limitations = []
482
+ termination_recommended = False
483
+ termination_reason = None
484
+
485
+ if is_single_group:
486
+ insufficient_for_comparison = True
487
+ comparison_limitations.append("All cells are labeled as 'default' - no group labels available for comparison")
488
+ # If query requires group comparison, recommend termination
489
+ termination_recommended = True
490
+ termination_reason = (
491
+ "**Cannot perform group comparison analysis:** All cells are in a single group ('default'). "
492
+ "Group comparison queries cannot be answered with the current data.\n\n"
493
+ "**Recommendation:** Terminate analysis and inform user that group labels are required for comparison queries.\n\n"
494
+ "**Solution:** Provide treatment/group labels when uploading images to enable group comparison analysis."
495
+ )
496
+
497
+ if num_crops < 10:
498
+ insufficient_for_comparison = True
499
+ comparison_limitations.append(f"Very small sample size ({num_crops} cells) - may be insufficient for robust statistical comparisons")
500
+
501
+ if use_zero_shot and not history:
502
+ comparison_limitations.append("Zero-shot inference mode (no training) - features may not be optimal for comparison")
503
+
504
+ # Generate summary
505
+ if is_single_group:
506
+ summary = f"Single-group analysis completed. {num_crops} cells analyzed. "
507
+ summary += f"{len(history)} epochs trained" if history else "Zero-shot inference (no training)"
508
+ summary += "\n\n⚠️ **Limitations for Group Comparison Queries:**\n"
509
+ summary += "- All cells are in a single group ('default') - group comparison analysis cannot be performed\n"
510
+ summary += "- To enable group comparison, provide treatment/group labels when uploading images\n"
511
+ summary += "- Current analysis provides single-group clustering and UMAP visualization only"
512
+ if termination_recommended:
513
+ summary += f"\n\n🛑 **Termination Recommendation:**\n{termination_reason}"
514
+ else:
515
+ summary = f"Multi-group analysis completed. {num_crops} cells across {len(unique_groups)} groups. "
516
+ summary += f"{len(history)} epochs trained" if history else "Zero-shot inference (no training)"
517
+ summary += f". Groups: {', '.join(sorted(unique_groups))}"
518
+ if comparison_limitations:
519
+ summary += "\n\n⚠️ **Note:** " + "; ".join(comparison_limitations)
520
+
521
  return {
522
+ "summary": summary,
523
  "cell_count": num_crops,
524
  "mode": "training" if not use_zero_shot else "zero-shot",
525
  "epochs_trained": len(history),
 
528
  "deliverables": [adata_path] + ([loss_path] if history and loss_path else []),
529
  "cluster_key": cluster_key,
530
  "cluster_resolution": cluster_resolution,
531
+ "analysis_type": "cell_state_analysis",
532
+ "num_groups": len(unique_groups),
533
+ "groups": sorted(unique_groups) if not is_single_group else ["default"],
534
+ "insufficient_for_comparison": insufficient_for_comparison,
535
+ "comparison_limitations": comparison_limitations if comparison_limitations else None,
536
+ "termination_recommended": termination_recommended,
537
+ "termination_reason": termination_reason
538
  }
539
 
540