diff --git a/crud.py b/crud.py
index 04e0b2b..b196d4b 100644
--- a/crud.py
+++ b/crud.py
@@ -147,6 +147,8 @@ async def create_agent(agent_data: dict, user_id: str):
agent_doc["quality_audit_updated_at"] = None
if "quality_audit_updated_by_name" not in agent_doc:
agent_doc["quality_audit_updated_by_name"] = None
+ if "risk_factor" not in agent_doc:
+ agent_doc["risk_factor"] = None
result = await agents_collection.insert_one(agent_doc)
agent_doc["_id"] = result.inserted_id
return agent_doc
@@ -223,6 +225,10 @@ async def update_agent(agent_id: str, update_data: dict, user_id: str = None, ad
update_data["quality_audit_updated_by"] = admin_user_info.get("user_id")
update_data["quality_audit_updated_at"] = datetime.utcnow().isoformat()
update_data["quality_audit_updated_by_name"] = admin_user_info.get("user_name", admin_user_info.get("email"))
+
+ # If Quality Audit is being unchecked, clear Risk Factor
+ if update_data["quality_audit_status"] is False:
+ update_data["risk_factor"] = None
update_data["updated_at"] = datetime.utcnow()
result = await agents_collection.update_one(
diff --git a/main.py b/main.py
index 6246658..3af05b5 100644
--- a/main.py
+++ b/main.py
@@ -141,6 +141,7 @@ def create_agent_response(agent: dict) -> models.AiAgentResponse:
quality_audit_updated_by=agent.get("quality_audit_updated_by"),
quality_audit_updated_at=agent.get("quality_audit_updated_at"),
quality_audit_updated_by_name=agent.get("quality_audit_updated_by_name"),
+ risk_factor=agent.get("risk_factor"),
created_by=agent["created_by"]
)
@@ -466,7 +467,8 @@ async def agent_register_form(
agent_tags: str = Form(None),
agent_userbase: str = Form(None),
agent_capabilities: str = Form(None),
- quality_audit_status: bool = Form(False)
+ quality_audit_status: bool = Form(False),
+ risk_factor: int = Form(None)
):
try:
# Get user from cookie - require authentication
@@ -505,9 +507,18 @@ async def agent_register_form(
agent_data["quality_audit_updated_by"] = user_id
agent_data["quality_audit_updated_at"] = datetime.utcnow().isoformat()
agent_data["quality_audit_updated_by_name"] = current_user.get("full_name", current_user.get("email"))
+
+ # Validate Risk Factor when Quality Audit is checked
+ if risk_factor is None or not (1 <= risk_factor <= 5):
+ context = get_template_context(request, current_user)
+ context["error"] = "Risk Factor (1-5) is required when Quality Audit is checked."
+ return templates.TemplateResponse("agent_register.html", context)
+
+ agent_data["risk_factor"] = risk_factor
else:
# Non-admin or quality audit not checked
agent_data["quality_audit_status"] = False
+ agent_data["risk_factor"] = None
# Remove None values
agent_data = {k: v for k, v in agent_data.items() if v is not None}
@@ -749,6 +760,14 @@ async def update_agent(agent_id: str, agent: models.AiAgentCreate, current_user:
admin_user_info = None
agent_data = agent.model_dump()
+ # Validate Risk Factor when Quality Audit is checked (admin only)
+ if current_user.get("is_admin") and agent_data.get("quality_audit_status"):
+ if agent_data.get("risk_factor") is None or not (1 <= agent_data.get("risk_factor", 0) <= 5):
+ raise HTTPException(
+ status_code=422,
+ detail="Risk Factor (1-5) is required when Quality Audit is checked."
+ )
+
if current_user.get("is_admin"):
admin_user_info = {
"user_id": str(current_user["_id"]),
diff --git a/models.py b/models.py
index 2de2c90..2f7851a 100644
--- a/models.py
+++ b/models.py
@@ -23,6 +23,7 @@ class AiAgent(BaseModel):
quality_audit_updated_by: str | None = Field(default=None, title="Admin user ID who updated quality audit")
quality_audit_updated_at: str | None = Field(default=None, title="Quality audit last update timestamp")
quality_audit_updated_by_name: str | None = Field(default=None, title="Admin user name who updated quality audit")
+ risk_factor: int | None = Field(default=None, title="Risk factor rating (1-5)", ge=1, le=5)
@@ -71,6 +72,7 @@ class AiAgentCreate(BaseModel):
quality_audit_updated_by: Optional[str] = None
quality_audit_updated_at: Optional[str] = None
quality_audit_updated_by_name: Optional[str] = None
+ risk_factor: Optional[int] = Field(default=None, ge=1, le=5)
class AiAgentResponse(BaseModel):
agent_id: str
@@ -93,6 +95,7 @@ class AiAgentResponse(BaseModel):
quality_audit_updated_by: Optional[str] = None
quality_audit_updated_at: Optional[str] = None
quality_audit_updated_by_name: Optional[str] = None
+ risk_factor: Optional[int] = None
created_by: str
# Agent Collector API Models (for compatibility with agent_collector app)
diff --git a/templates/admin/dashboard.html b/templates/admin/dashboard.html
index 920a3ed..0e8cc87 100644
--- a/templates/admin/dashboard.html
+++ b/templates/admin/dashboard.html
@@ -306,7 +306,7 @@
+
+
+
+
+
+ Required when Quality Audit is checked. Select the appropriate risk level for this agent.
+
+
@@ -639,6 +664,7 @@ async function showAgentDetails(agentId) {
'Audited' :
'Not Audited'
}
+ ${agent.quality_audit_status && agent.risk_factor ? getRiskFactorBadge(agent.risk_factor) : ''}
@@ -828,6 +854,8 @@ async function showEditModal() {
// Handle Quality Audit field
const qualityAuditCheckbox = document.getElementById('editQualityAuditStatus');
const qualityAuditSection = document.getElementById('editQualityAuditSection');
+ const riskFactorSection = document.getElementById('editRiskFactorSection');
+ const riskFactor = document.getElementById('editRiskFactor');
if (currentUserIsAdmin) {
qualityAuditSection.style.display = 'block';
@@ -844,8 +872,19 @@ async function showEditModal() {
noteHtml += '
No quality audit changes recorded yet.';
}
document.getElementById('editQualityAuditNote').innerHTML = noteHtml;
+
+ // Handle Risk Factor field
+ riskFactor.value = agent.risk_factor || '';
+ if (agent.quality_audit_status) {
+ riskFactorSection.style.display = 'block';
+ riskFactor.required = true;
+ } else {
+ riskFactorSection.style.display = 'none';
+ riskFactor.required = false;
+ }
} else {
qualityAuditSection.style.display = 'none';
+ riskFactorSection.style.display = 'none';
}
// Hide details modal if it's open, then show edit modal
@@ -884,9 +923,16 @@ async function updateAgent(e) {
agent_capabilities: document.getElementById('editAgentCapabilities').value.split(',').map(s => s.trim()).filter(s => s)
};
- // Add Quality Audit status if user is admin
+ // Add Quality Audit status and Risk Factor if user is admin
if (currentUserIsAdmin) {
agentData.quality_audit_status = document.getElementById('editQualityAuditStatus').checked;
+ const riskFactorValue = document.getElementById('editRiskFactor').value;
+ agentData.risk_factor = riskFactorValue ? parseInt(riskFactorValue) : null;
+ }
+
+ // Validate the form before sending
+ if (!validateEditForm()) {
+ return;
}
console.log('Sending agent update data:', agentData);
@@ -1000,6 +1046,31 @@ function formatDate(dateString) {
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
}
+function getRiskFactorLabel(riskFactor) {
+ const labels = {
+ 1: '1 - Very Low Risk',
+ 2: '2 - Low Risk',
+ 3: '3 - Medium Risk',
+ 4: '4 - High Risk',
+ 5: '5 - Very High Risk'
+ };
+ return labels[riskFactor] || 'Not Set';
+}
+
+function getRiskFactorBadge(riskFactor) {
+ if (!riskFactor) return '';
+
+ const colors = {
+ 1: 'success', // Very Low Risk - Green
+ 2: 'info', // Low Risk - Blue
+ 3: 'warning', // Medium Risk - Yellow
+ 4: 'orange', // High Risk - Orange (we'll style this)
+ 5: 'danger' // Very High Risk - Red
+ };
+
+ return `Risk ${riskFactor}`;
+}
+
function showSuccess(message) {
// Simple alert - could be replaced with a toast notification
alert(message);
@@ -1010,6 +1081,36 @@ function showError(message) {
alert('Error: ' + message);
}
+function toggleEditRiskFactor() {
+ const qualityAuditStatus = document.getElementById('editQualityAuditStatus');
+ const riskFactorSection = document.getElementById('editRiskFactorSection');
+ const riskFactor = document.getElementById('editRiskFactor');
+
+ if (qualityAuditStatus.checked && currentUserIsAdmin) {
+ riskFactorSection.style.display = 'block';
+ riskFactor.required = true;
+ } else {
+ riskFactorSection.style.display = 'none';
+ riskFactor.required = false;
+ if (!qualityAuditStatus.checked) {
+ riskFactor.value = '';
+ }
+ }
+}
+
+function validateEditForm() {
+ const qualityAuditStatus = document.getElementById('editQualityAuditStatus');
+ const riskFactor = document.getElementById('editRiskFactor');
+
+ // Validate Risk Factor if Quality Audit is checked and user is admin
+ if (currentUserIsAdmin && qualityAuditStatus.checked && (!riskFactor.value || riskFactor.value === '')) {
+ showError('Risk Factor is required when Quality Audit is checked!');
+ return false;
+ }
+
+ return true;
+}
+
function editAgent(agentId) {
console.log('Edit button clicked for agent:', agentId);
console.log('Current agents array:', agents);
diff --git a/templates/agent_register.html b/templates/agent_register.html
index a2a07f2..ab31c08 100644
--- a/templates/agent_register.html
+++ b/templates/agent_register.html
@@ -175,7 +175,8 @@
name="quality_audit_status"
value="true"
id="qualityAuditStatus"
- {% if not current_user.is_admin %}disabled{% endif %}>
+ {% if not current_user.is_admin %}disabled{% endif %}
+ onchange="toggleRiskFactor()">