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 += "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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":
|
| 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 |
|