from dataclasses import asdict from pam_deploy_graph.agent import PamDeployAgent from pam_deploy_graph.checkpoint_store import redact_mapping from pam_deploy_graph.llm.rule_based import RuleBasedLlmClient from pam_deploy_graph.llm.validators import validate_deploy_plan from pam_deploy_graph.models import LlmDeployPlan def test_understand_request_prefers_hybrid_for_mcp(): result = RuleBasedLlmClient().understand_request("请用 MCP 部署 HET") assert result.intent == "deploy" assert result.mode_preference == "MCP" assert result.strategy_preference == "hybrid_node_mcp" def test_extract_params_from_key_value_text(): result = RuleBasedLlmClient().extract_params( "HOME_BASE_URL=https://x CLIENT_ID=id CLIENT_SECRET=s AIRPORT_CODE=HET " "APP_NAME=PAM MODULE_NAME=Node VERSION_NUMBER=2.0.5 ZIP_FILE_PATH=C:/pkg.zip" ) assert result.extracted_params["AIRPORT_CODE"] == "HET" assert result.missing_required_params == [] assert "CLIENT_SECRET" in result.sensitive_fields_present def test_analyze_request_returns_structured_objects(): agent = PamDeployAgent() result = agent.analyze_request( "不要动环境,预演部署", { "HOME_BASE_URL": "https://x", "CLIENT_ID": "id", "CLIENT_SECRET": "s", "AIRPORT_CODE": "HET", "APP_NAME": "PAM", "MODULE_NAME": "Node", "VERSION_NUMBER": "2.0.5", "ZIP_FILE_PATH": "C:/pkg.zip", }, ) payload = {key: asdict(value) for key, value in result.items()} assert payload["intent"]["intent"] == "preview" assert payload["plan"]["execution_strategy"] == "hybrid_node_mcp" def test_analyze_payload_can_be_redacted(): agent = PamDeployAgent() result = agent.analyze_request( "帮我部署", { "HOME_BASE_URL": "https://x", "CLIENT_ID": "id", "CLIENT_SECRET": "super-secret", "AIRPORT_CODE": "HET", "APP_NAME": "PAM", "MODULE_NAME": "Node", "VERSION_NUMBER": "2.0.5", "ZIP_FILE_PATH": "C:/pkg.zip", }, ) payload = redact_mapping({key: asdict(value) for key, value in result.items()}) assert payload["params"]["extracted_params"]["CLIENT_SECRET"] == "***" def test_plan_guardrails_reject_executable_text(): plan = LlmDeployPlan(summary="run bash ./deploy.sh", planned_actions=["get-token"]) try: validate_deploy_plan(plan) except ValueError as exc: assert "forbidden" in str(exc) else: raise AssertionError("expected guardrail failure")