import asyncio from apps.web.vue3 import main as api def test_build_subfamily_evidence_plan_keeps_confirmed_stage_boundary(): intent = { "workflow_action_id": "build_subfamily_evidence", "stages": ["domain", "motif", "phylogeny", "structure", "combo"], "params": { "workflowActionId": "build_subfamily_evidence", "authorizedStages": [ "domain", "motif", "phylogeny", "structure", "combo", ], }, } stages = api._authorized_workflow_action_stages(intent) assert stages == ["phylogeny", "motif", "domain", "structure", "combo"] assert "identify" not in stages assert "reference_classification" not in stages def test_unbound_plan_does_not_invent_an_authorized_stage_boundary(): assert api._authorized_workflow_action_stages( {"stages": ["identify", "phylogeny", "reference_classification"]} ) == [] def test_agent_plan_honors_authorized_workflow_action_without_keyword_reclassification( monkeypatch, ): authorized = ["domain", "motif", "phylogeny", "structure", "combo"] intent = { "gene_family": "SPL", "target_species": ["Ft"], "reference_species": ["At"], "stages": authorized, "primary_stage": "combo", "workflow_action_id": "build_subfamily_evidence", "params": { "workflowActionId": "build_subfamily_evidence", "authorizedStages": authorized, "targetSpecies": ["Ft"], "referenceSpecies": ["At"], }, } monkeypatch.setattr( api, "_reconcile_confirmed_gene_family_species", lambda *args, **kwargs: {"applicable": False, "conflicts": []}, ) monkeypatch.setattr( api, "_resolve_authoritative_gene_family", lambda *args, **kwargs: "SPL" ) monkeypatch.setattr( api, "_resolve_subfamily_request_species_roles", lambda *args, **kwargs: { "classification_species": ["Ft"], "reference_species": ["At"], }, ) monkeypatch.setattr( api, "_latest_gene_family_scope_defaults", lambda *args, **kwargs: { "target_species": ["Ft"], "reference_species": ["At"], "comparative_species": [], }, ) monkeypatch.setattr( api, "_load_identify_species_selection", lambda *args, **kwargs: { "groups": { "target": [{"species": "Ft"}], "reference": [{"species": "At"}], "comparative": [], } }, ) monkeypatch.setattr( api, "_subfamily_state_for_targets", lambda *args, **kwargs: {"overall": "not_classified", "by_species": {}}, ) monkeypatch.setattr( api, "_identity_completed_stages_for_plan", lambda *args, **kwargs: [] ) monkeypatch.setattr( api, "_resolve_contextual_gene_family_request", lambda *args, **kwargs: { "family": "SPL", "prefix": "Ft.SPL", "stages": authorized, "targetSpecies": ["Ft"], "referenceSpecies": ["At"], "comparativeSpecies": [], "scopeMode": "target_plus_reference", "contextGate": {"valid": False, "issues": []}, "context_route": "gene_family_default_scope", "requiresConfirmedSubfamily": False, "skipSubfamilyLabels": False, "subfamilyState": { "overall": "not_classified", "by_species": {"Ft": {"status": "not_classified"}}, }, }, ) response = asyncio.run( api.agent_plan( api.AgentPlanRequest( message="执行接下来的步骤", session_id="authorized-action-test", job_id="job-test", prefix="Ft.SPL", intent=intent, ) ) ) expected = ["phylogeny", "motif", "domain", "structure", "combo"] assert response["plan"]["all_stages"] == expected assert response["plan"]["stages"] == expected assert response["intent"]["workflow_action_id"] == "build_subfamily_evidence" assert response["intent"]["params"]["authorizedStages"] == authorized assert "reference_classification" not in response["plan"]["all_stages"] assert "subfamily_confirm" not in response["plan"]["all_stages"]