from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from sqlmodel import Session from ..db.session import get_session from ..services import ai_remediation_planner from .connector_runtime import load_connector_runtime router = APIRouter(prefix='/api/ai/remediation', dependencies=[Depends(load_connector_runtime)]) @router.get('/status') def status(session: Session = Depends(get_session)): plans = ai_remediation_planner.get_plans(session).plans return { 'enabled': True, 'mode': 'deterministic_rule_based', 'externalAiRequired': False, 'canExecuteActions': False, 'totalPlans': len(plans), 'openPlans': sum(1 for plan in plans if plan.status == 'draft'), 'reviewedPlans': sum(1 for plan in plans if plan.status == 'reviewed'), 'dismissedPlans': sum(1 for plan in plans if plan.status == 'dismissed'), } @router.get('/plans') def plans(session: Session = Depends(get_session)): return ai_remediation_planner.get_plans(session).model_dump() @router.get('/plans/{plan_id}') def plan_detail(plan_id: str, session: Session = Depends(get_session)): plan = ai_remediation_planner.get_plan(session, plan_id) if not plan: raise HTTPException(status_code=404, detail='plan_not_found') return plan.model_dump() @router.post('/plans/generate') def generate(session: Session = Depends(get_session)): return ai_remediation_planner.generate_plans(session, audit_run=True).model_dump() @router.post('/plans/from-finding/{finding_id}') def from_finding(finding_id: str, session: Session = Depends(get_session)): return ai_remediation_planner.generate_from_finding(session, finding_id).model_dump() @router.post('/plans/from-recommendation/{recommendation_id}') def from_recommendation(recommendation_id: str, session: Session = Depends(get_session)): return ai_remediation_planner.generate_from_recommendation(session, recommendation_id).model_dump() @router.post('/plans/{plan_id}/review') def review(plan_id: str, session: Session = Depends(get_session)): if not ai_remediation_planner.get_plan(session, plan_id): raise HTTPException(status_code=404, detail='plan_not_found') return ai_remediation_planner.review_plan(session, plan_id) @router.post('/plans/{plan_id}/dismiss') def dismiss(plan_id: str, session: Session = Depends(get_session)): if not ai_remediation_planner.get_plan(session, plan_id): raise HTTPException(status_code=404, detail='plan_not_found') return ai_remediation_planner.dismiss_plan(session, plan_id) @router.post('/plans/{plan_id}/create-approval-proposal') def create_approval_proposal(plan_id: str, session: Session = Depends(get_session)): proposal = ai_remediation_planner.create_approval_proposal(session, plan_id) if not proposal: raise HTTPException(status_code=404, detail='plan_not_found') return proposal.model_dump() @router.post('/plans/{plan_id}/dry-run') def dry_run(plan_id: str, session: Session = Depends(get_session)): result = ai_remediation_planner.dry_run(session, plan_id) if not result: raise HTTPException(status_code=404, detail='plan_not_found') return result.model_dump()