| | """Tests for run_agent parser and fallback helpers."""
|
| |
|
| | from models import ActionType, ExperimentAction
|
| | from run_agent import ensure_conclusion_claims, extract_json_object, parse_action, should_block_failed_reattempt
|
| | from server.hackathon_environment import BioExperimentEnvironment
|
| |
|
| |
|
| | def test_parse_action_accepts_reasoning_variant():
|
| | action = parse_action(
|
| | '{"action_type":"run_qc","parameters":{},"Reasoning":"check quality","confidence":0.8}'
|
| | )
|
| | assert action is not None
|
| | assert action.action_type == ActionType.RUN_QC
|
| | assert action.justification == "check quality"
|
| |
|
| |
|
| | def test_parse_action_accepts_justifyement_typo():
|
| | action = parse_action(
|
| | '{"action_type":"collect_sample","parameters":{},"justifyement":"typo key","confidence":0.7}'
|
| | )
|
| | assert action is not None
|
| | assert action.action_type == ActionType.COLLECT_SAMPLE
|
| | assert action.justification == "typo key"
|
| |
|
| |
|
| | def test_extract_json_object_unwraps_quoted_json_string():
|
| | parsed = extract_json_object(
|
| | '"{\\"action_type\\": \\"run_qc\\", \\"method\\": \\"\\", \\"parameters\\": {}, \\"Justification\\": \\"check quality\\", \\"confidence\\": 0.8}"'
|
| | )
|
| | assert parsed is not None
|
| | assert parsed["action_type"] == "run_qc"
|
| |
|
| |
|
| | def test_parse_action_falls_back_when_inner_object_lacks_action_type():
|
| | action = parse_action(
|
| | '"{\\"action_type\\": \\"design_followup_experiment\\", \\"method\\": \\"\\", \\"parameters\\": {\\"criterion_description\\": \\"\\"}, \\"Justification\\": \\"follow-up\\", \\"confidence\\": 0.6, \\"threshold_value\\": {\\"conditions\\": [], \\"gene_filter_criteria\\": \\"x\\", \\"sample_group_size\\": 3}}"'
|
| | )
|
| | assert action is not None
|
| | assert action.action_type == ActionType.DESIGN_FOLLOWUP
|
| |
|
| |
|
| | def test_should_block_failed_reattempt_until_pipeline_progress():
|
| | env = BioExperimentEnvironment(scenario_name="cardiac_disease_de", domain_randomise=False)
|
| | obs = env.reset(seed=0)
|
| | for action_type in (
|
| | ActionType.COLLECT_SAMPLE,
|
| | ActionType.PREPARE_LIBRARY,
|
| | ActionType.SEQUENCE_CELLS,
|
| | ):
|
| | obs = env.step(ExperimentAction(action_type=action_type))
|
| | assert should_block_failed_reattempt(obs.pipeline_history, ActionType.SEQUENCE_CELLS) is False
|
| | assert should_block_failed_reattempt(obs.pipeline_history, ActionType.RUN_QC) is False
|
| |
|
| |
|
| | def test_ensure_conclusion_claims_infers_from_outputs_when_discoveries_empty():
|
| | env = BioExperimentEnvironment(scenario_name="cardiac_disease_de", domain_randomise=False)
|
| | obs = env.reset(seed=0)
|
| | pipeline = [
|
| | ExperimentAction(action_type=ActionType.COLLECT_SAMPLE),
|
| | ExperimentAction(action_type=ActionType.PREPARE_LIBRARY),
|
| | ExperimentAction(action_type=ActionType.SEQUENCE_CELLS),
|
| | ExperimentAction(action_type=ActionType.RUN_QC),
|
| | ExperimentAction(action_type=ActionType.FILTER_DATA),
|
| | ExperimentAction(action_type=ActionType.NORMALIZE_DATA),
|
| | ExperimentAction(action_type=ActionType.CLUSTER_CELLS),
|
| | ExperimentAction(
|
| | action_type=ActionType.DIFFERENTIAL_EXPRESSION,
|
| | parameters={"comparison": "disease_vs_healthy"},
|
| | ),
|
| | ExperimentAction(action_type=ActionType.PATHWAY_ENRICHMENT),
|
| | ]
|
| | for action in pipeline:
|
| | obs = env.step(action)
|
| |
|
| | sparse_obs = obs.model_copy(update={
|
| | "discovered_markers": [],
|
| | "candidate_mechanisms": [],
|
| | })
|
| | action = ensure_conclusion_claims(
|
| | sparse_obs,
|
| | ExperimentAction(
|
| | action_type=ActionType.SYNTHESIZE_CONCLUSION,
|
| | confidence=0.9,
|
| | parameters={},
|
| | ),
|
| | )
|
| |
|
| | claims = action.parameters["claims"]
|
| | assert claims[0]["top_markers"]
|
| | assert claims[0]["causal_mechanisms"]
|
| | assert claims[0]["predicted_pathways"]
|
| |
|