Agentic-Reliability-Framework-API / app /api /routes_governance.py
petter2025's picture
Add FastAPI app
2d521fd verified
from fastapi import APIRouter, Depends, HTTPException, Request, BackgroundTasks
from fastapi.encoders import jsonable_encoder
from sqlalchemy.orm import Session
from app.models.infrastructure_intents import InfrastructureIntentRequest
from app.services.intent_adapter import to_oss_intent
from app.services.risk_service import evaluate_intent, evaluate_healing_decision
from app.services.intent_store import save_evaluated_intent
from app.services.outcome_service import record_outcome
from app.api.deps import get_db
from pydantic import BaseModel
import uuid
import logging
import time
from agentic_reliability_framework.core.models.event import ReliabilityEvent
# ===== USAGE TRACKER IMPORTS =====
from app.core.usage_tracker import enforce_quota, UsageRecord, tracker
logger = logging.getLogger(__name__)
router = APIRouter()
class OutcomeRequest(BaseModel):
deterministic_id: str
success: bool
recorded_by: str
notes: str = ""
class HealingDecisionRequest(BaseModel):
event: ReliabilityEvent
@router.post("/intents/evaluate")
async def evaluate_intent_endpoint(
request: Request,
intent_req: InfrastructureIntentRequest,
background_tasks: BackgroundTasks,
db: Session = Depends(get_db),
quota: dict = Depends(enforce_quota)
):
start_time = time.time()
api_key = quota["api_key"]
tier = quota["tier"]
response_data = None
error_msg = None
try:
oss_intent = to_oss_intent(intent_req)
risk_engine = request.app.state.risk_engine
result = evaluate_intent(
engine=risk_engine,
intent=oss_intent,
cost_estimate=intent_req.estimated_cost,
policy_violations=intent_req.policy_violations
)
deterministic_id = str(uuid.uuid4())
api_payload = jsonable_encoder(intent_req.model_dump())
oss_payload = jsonable_encoder(oss_intent.model_dump())
save_evaluated_intent(
db=db,
deterministic_id=deterministic_id,
intent_type=intent_req.intent_type,
api_payload=api_payload,
oss_payload=oss_payload,
environment=str(intent_req.environment),
risk_score=result["risk_score"]
)
result["intent_id"] = deterministic_id
response_data = result
if tracker:
record = UsageRecord(
api_key=api_key,
tier=tier,
timestamp=time.time(),
endpoint="/api/v1/intents/evaluate",
request_body=intent_req.model_dump(),
response=response_data,
processing_ms=(time.time() - start_time) * 1000,
)
await tracker.increment_usage_async(record, background_tasks)
return response_data
except HTTPException:
raise
except Exception as e:
error_msg = str(e)
logger.exception("Error in evaluate_intent_endpoint")
if tracker:
record = UsageRecord(
api_key=api_key,
tier=tier,
timestamp=time.time(),
endpoint="/api/v1/intents/evaluate",
request_body=intent_req.model_dump(),
error=error_msg,
processing_ms=(time.time() - start_time) * 1000,
)
await tracker.increment_usage_async(record, background_tasks)
raise HTTPException(status_code=500, detail=error_msg)
@router.post("/intents/outcome")
async def record_outcome_endpoint(
request: Request,
outcome: OutcomeRequest,
db: Session = Depends(get_db)
):
# No usage tracking for outcomes (doesn't count against quota)
try:
risk_engine = request.app.state.risk_engine
outcome_record = record_outcome(
db=db,
deterministic_id=outcome.deterministic_id,
success=outcome.success,
recorded_by=outcome.recorded_by,
notes=outcome.notes,
risk_engine=risk_engine
)
return {"message": "Outcome recorded", "outcome_id": outcome_record.id}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/healing/evaluate")
async def evaluate_healing_decision_endpoint(
request: Request,
decision_req: HealingDecisionRequest,
background_tasks: BackgroundTasks,
quota: dict = Depends(enforce_quota)
):
start_time = time.time()
api_key = quota["api_key"]
tier = quota["tier"]
response_data = None
error_msg = None
try:
policy_engine = request.app.state.policy_engine
rag_graph = getattr(request.app.state, "rag_graph", None)
model = getattr(request.app.state, "epistemic_model", None)
tokenizer = getattr(request.app.state, "epistemic_tokenizer", None)
response_data = evaluate_healing_decision(
event=decision_req.event,
policy_engine=policy_engine,
decision_engine=None,
rag_graph=rag_graph,
model=model,
tokenizer=tokenizer,
)
if tracker:
record = UsageRecord(
api_key=api_key,
tier=tier,
timestamp=time.time(),
endpoint="/api/v1/healing/evaluate",
request_body=decision_req.model_dump(),
response=response_data,
processing_ms=(time.time() - start_time) * 1000,
)
await tracker.increment_usage_async(record, background_tasks)
return response_data
except HTTPException:
raise
except Exception as e:
error_msg = str(e)
logger.exception("Error in evaluate_healing_decision_endpoint")
if tracker:
record = UsageRecord(
api_key=api_key,
tier=tier,
timestamp=time.time(),
endpoint="/api/v1/healing/evaluate",
request_body=decision_req.model_dump(),
error=error_msg,
processing_ms=(time.time() - start_time) * 1000,
)
await tracker.increment_usage_async(record, background_tasks)
raise HTTPException(status_code=500, detail=error_msg)