import inspect from app.schemas.pmflow_ai_turn_runtime import PMFlowAIAnswerState, PMFlowAITurnEvidenceState, PMFlowAITurnState from app.schemas.rag import RAGAskRequest from app.services.pmflow_ai_answer_renderer_registry import PMFlowAIAnswerRendererRegistry from app.services.pmflow_ai_turn_runtime_service import PMFlowAITurnRuntimeService def _service() -> PMFlowAITurnRuntimeService: return PMFlowAITurnRuntimeService(object(), tenant_id=1) def _assistant_identity_state(): return _service().build_initial_turn_state( request=RAGAskRequest(question="说明你的能力边界"), route_plan={}, turn_hypothesis={ "normalized_goal": "assistant_identity", "desired_outcome": "说明助手身份和能力边界", "answer_shape": "general_answer", "goal_frames": [ { "frame_id": "assistant-profile", "operation_kind": "explain_assistant", "target_scope": { "scope_type": "current_space", "binding_strength": "surface", "source": "turn_goal_assessment", }, "target_object_requirement": "none", "source_policy": "none", "answer_shape": "general_answer", "confidence": 0.9, } ], "operation_gaps": [], }, ) def test_packet_ag_renderer_registry_orders_static_contract_first() -> None: state = _assistant_identity_state() keys = [candidate.renderer_key for candidate in PMFlowAIAnswerRendererRegistry().select_candidates(state)] assert keys[:2] == ["static_contract", "open_judgement"] assert keys[-2:] == ["llm_state_compose", "safe_fallback"] def test_packet_ag_renderer_registry_detects_project_packet_before_llm() -> None: state = PMFlowAITurnState( answer_state=PMFlowAIAnswerState(answer_shape="status_answer"), evidence_state=PMFlowAITurnEvidenceState( structured_evidence={"project_operating_evidence_packet": {"project_ref": "project:1"}} ), ) keys = [candidate.renderer_key for candidate in PMFlowAIAnswerRendererRegistry().select_candidates(state)] assert "project_operating_packet" in keys assert keys.index("project_operating_packet") < keys.index("llm_state_compose") def test_packet_ag_synthesis_uses_renderer_registry_not_inline_renderer_chain() -> None: synthesis_source = inspect.getsource(PMFlowAITurnRuntimeService._run_state_answer_synthesis) registry_source = inspect.getsource(PMFlowAITurnRuntimeService._render_answer_from_registry) assert "_render_answer_from_registry" in synthesis_source assert "_render_collection_answer_from_working_state" not in synthesis_source assert "_render_project_operating_answer_from_turn_state" not in synthesis_source assert "PMFlowAIAnswerRendererRegistry" in registry_source