nothingworry commited on
Commit
d25df55
·
1 Parent(s): b6650bb

update the redflag resopnse

Browse files
.gitignore CHANGED
@@ -1,3 +1,4 @@
1
  venv/
2
  .env
3
  .pytest_cache
 
 
1
  venv/
2
  .env
3
  .pytest_cache
4
+ /_pycache_/
backend/api/services/agent_orchestrator.py CHANGED
@@ -89,25 +89,73 @@ class AgentOrchestrator:
89
  tool_input={"violations": [m.__dict__ for m in matches]},
90
  reason="redflag_triggered"
91
  )
92
- summary = "; ".join(
93
- f"{m.description or m.pattern} [severity: {m.severity}]"
94
- for m in matches
95
- ) or "Policy violation detected"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  total_latency_ms = int((time.time() - start_time) * 1000)
 
 
 
 
 
 
 
 
 
 
 
 
98
  self.analytics.log_agent_query(
99
  tenant_id=req.tenant_id,
100
  message_preview=req.message[:200],
101
  intent="admin",
102
- tools_used=["admin"],
103
- total_tokens=0,
104
  total_latency_ms=total_latency_ms,
105
  success=False,
106
  user_id=req.user_id
107
  )
108
 
109
  return AgentResponse(
110
- text=f"⚠️ Request blocked by Admin Plan: {summary}. Please review your governance rules or contact an administrator.",
111
  decision=decision,
112
  tool_traces=[{"redflags": [m.__dict__ for m in matches]}],
113
  reasoning_trace=reasoning_trace
 
89
  tool_input={"violations": [m.__dict__ for m in matches]},
90
  reason="redflag_triggered"
91
  )
92
+
93
+ # Build detailed prompt for LLM to generate natural red flag response
94
+ violations_details = []
95
+ for i, m in enumerate(matches, 1):
96
+ rule_name = m.description or m.pattern or "Policy violation"
97
+ detail = f"{i}. **{rule_name}** (Severity: {m.severity})"
98
+ if m.matched_text:
99
+ detail += f"\n - Detected phrase: \"{m.matched_text}\""
100
+ violations_details.append(detail)
101
+
102
+ llm_prompt = f"""A user made the following request: "{req.message}"
103
+
104
+ However, this request violates company policies. The following policy violations were detected:
105
+
106
+ {chr(10).join(violations_details)}
107
+
108
+ Your task: Write a clear, professional, and empathetic response to inform the user that:
109
+ 1. Their request cannot be processed due to policy violations
110
+ 2. Which specific policy was violated (mention it naturally)
111
+ 3. The incident has been logged for security review
112
+ 4. They should contact an administrator if they need assistance or believe this is an error
113
+
114
+ Write a natural, conversational response (2-4 sentences) that feels helpful rather than robotic. Be professional but understanding.
115
+
116
+ Response:"""
117
+
118
+ # Generate LLM response for red flag
119
+ try:
120
+ llm_response = await self.llm.simple_call(llm_prompt, temperature=min(req.temperature + 0.2, 0.7)) # Slightly higher temp for more natural response
121
+ llm_response = llm_response.strip()
122
+ # Add warning emoji if not present
123
+ if not llm_response.startswith("⚠️") and not llm_response.startswith("🚨"):
124
+ llm_response = f"⚠️ {llm_response}"
125
+ except Exception as e:
126
+ # Fallback to a simple message if LLM fails
127
+ summary = "; ".join(
128
+ f"{m.description or m.pattern}"
129
+ for m in matches
130
+ )
131
+ llm_response = f"⚠️ I'm unable to process your request because it violates our company policy: {summary}. This incident has been logged. Please contact your administrator if you need assistance."
132
 
133
  total_latency_ms = int((time.time() - start_time) * 1000)
134
+
135
+ # Log LLM usage for red flag response
136
+ estimated_tokens = len(llm_response) // 4 + len(llm_prompt) // 4
137
+ self.analytics.log_tool_usage(
138
+ tenant_id=req.tenant_id,
139
+ tool_name="llm",
140
+ latency_ms=total_latency_ms,
141
+ tokens_used=estimated_tokens,
142
+ success=True,
143
+ user_id=req.user_id
144
+ )
145
+
146
  self.analytics.log_agent_query(
147
  tenant_id=req.tenant_id,
148
  message_preview=req.message[:200],
149
  intent="admin",
150
+ tools_used=["admin", "llm"],
151
+ total_tokens=estimated_tokens,
152
  total_latency_ms=total_latency_ms,
153
  success=False,
154
  user_id=req.user_id
155
  )
156
 
157
  return AgentResponse(
158
+ text=llm_response,
159
  decision=decision,
160
  tool_traces=[{"redflags": [m.__dict__ for m in matches]}],
161
  reasoning_trace=reasoning_trace
data/admin_rules.db CHANGED
Binary files a/data/admin_rules.db and b/data/admin_rules.db differ
 
data/analytics.db CHANGED
Binary files a/data/analytics.db and b/data/analytics.db differ
 
frontend/components/analytics-panel.tsx CHANGED
@@ -3,10 +3,18 @@
3
  import { useState } from "react";
4
  import { useTenant } from "@/contexts/TenantContext";
5
 
 
 
 
 
 
 
 
 
6
  type AnalyticsOverview = {
7
  overview: {
8
  total_queries: number;
9
- tool_usage: Record<string, number>;
10
  redflag_count: number;
11
  active_users: number;
12
  };
@@ -89,7 +97,7 @@ export function AnalyticsPanel() {
89
  <p className="mt-2 text-3xl font-semibold">
90
  {data
91
  ? Object.entries(data.tool_usage)
92
- .sort((a, b) => b[1] - a[1])[0]?.[0] ?? "—"
93
  : "—"}
94
  </p>
95
  </div>
@@ -101,7 +109,7 @@ export function AnalyticsPanel() {
101
  </p>
102
  <div className="mt-4 grid gap-3 sm:grid-cols-3">
103
  {data
104
- ? Object.entries(data.tool_usage).map(([tool, count]) => (
105
  <div
106
  key={tool}
107
  className="rounded-xl border border-white/10 bg-white/5 px-4 py-3"
@@ -109,7 +117,7 @@ export function AnalyticsPanel() {
109
  <p className="text-sm uppercase tracking-widest text-slate-400">
110
  {tool}
111
  </p>
112
- <p className="text-2xl font-semibold text-white">{count}</p>
113
  </div>
114
  ))
115
  : Array.from({ length: 3 }).map((_, idx) => (
 
3
  import { useState } from "react";
4
  import { useTenant } from "@/contexts/TenantContext";
5
 
6
+ type ToolUsageStats = {
7
+ count: number;
8
+ avg_latency_ms: number;
9
+ total_tokens: number;
10
+ success_count: number;
11
+ error_count: number;
12
+ };
13
+
14
  type AnalyticsOverview = {
15
  overview: {
16
  total_queries: number;
17
+ tool_usage: Record<string, ToolUsageStats>;
18
  redflag_count: number;
19
  active_users: number;
20
  };
 
97
  <p className="mt-2 text-3xl font-semibold">
98
  {data
99
  ? Object.entries(data.tool_usage)
100
+ .sort((a, b) => b[1].count - a[1].count)[0]?.[0] ?? "—"
101
  : "—"}
102
  </p>
103
  </div>
 
109
  </p>
110
  <div className="mt-4 grid gap-3 sm:grid-cols-3">
111
  {data
112
+ ? Object.entries(data.tool_usage).map(([tool, stats]) => (
113
  <div
114
  key={tool}
115
  className="rounded-xl border border-white/10 bg-white/5 px-4 py-3"
 
117
  <p className="text-sm uppercase tracking-widest text-slate-400">
118
  {tool}
119
  </p>
120
+ <p className="text-2xl font-semibold text-white">{stats.count}</p>
121
  </div>
122
  ))
123
  : Array.from({ length: 3 }).map((_, idx) => (