Rename Legal Agent to Risk & Control Agent across frontend and backend

Updates all display labels (PDF report, campaign page, Knowledge Base card, analytics, status dashboard, checks overview) and aligns internal agent name in backend. Adds migration 010 to update the knowledge base display_name in production DB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-05-14 15:10:32 +01:00
parent 2ebaf6420f
commit aeab7d3b18
15 changed files with 48 additions and 19 deletions

View file

@ -117,7 +117,7 @@ def upgrade() -> None:
conn = op.get_bind()
kb_seeds = [
("legal", "Legal", "Legal compliance, advertising standards, disclaimers, and financial promotion rules."),
("legal", "Risk & Control", "Legal compliance, advertising standards, disclaimers, and financial promotion rules."),
("brand_barclays", "Brand (Barclays)", "Barclays brand guidelines: logo usage, colors, typography, and design principles."),
("brand_barclaycard", "Brand (Barclaycard)", "Barclaycard brand guidelines: logo usage, colors, typography, and design principles."),
("channel_best_practices", "Channel Best Practices", "Channel-specific best practices for social, display, email, print, and OOH."),

View file

@ -0,0 +1,29 @@
"""Rename Legal knowledge base to Risk & Control
Revision ID: 010_rename_legal_kb
Revises: 009_production_agencies
Create Date: 2026-05-14
"""
from alembic import op
revision: str = '010_rename_legal_kb'
down_revision: str = '009_production_agencies'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.execute("""
UPDATE knowledge_bases
SET display_name = 'Risk & Control'
WHERE agent_key = 'legal'
""")
def downgrade() -> None:
op.execute("""
UPDATE knowledge_bases
SET display_name = 'Legal'
WHERE agent_key = 'legal'
""")

View file

@ -95,7 +95,7 @@ In your summary:
Returns:
Tuple of (overall_status, summary, financial_promotion_reason)
"""
legal_review = reviews.get("Legal Agent")
legal_review = reviews.get("Risk & Control Agent")
# Check for financial promotion (from Legal Agent)
is_financial_promotion = (
@ -129,7 +129,7 @@ Your task is to determine the final status and write a concise, professional sum
{metadata_context}
Here is the logic you must follow:
1. The Legal Agent has determined if this is a financial promotion: {is_financial_promotion}.
1. The Risk & Control Agent has determined if this is a financial promotion: {is_financial_promotion}.
2. If it IS a financial promotion, the final verdict MUST be 'Requires Manual Legal Review'. Your summary should state this clearly, explain that a separate manual legal review is required, and then summarize any other issues found by the other agents.
3. If it is NOT a financial promotion, follow the standard logic:
a. If ANY specialist agent reports a 'ragStatus' of 'Error', the final verdict MUST be 'Analysis Error'.
@ -205,7 +205,7 @@ Now, provide your final status and summary as a JSON object.
This can be used as a fallback or for faster processing.
"""
legal_review = reviews.get("Legal Agent")
legal_review = reviews.get("Risk & Control Agent")
# Check for financial promotion
if legal_review and legal_review.isFinancialPromotion:

View file

@ -9,7 +9,7 @@ from app.services.reference_docs import ReferenceDocsService
class LegalAgent(BaseAgent):
"""Legal Agent - analyzes proofs for legal compliance using Gemini."""
name = "Legal Agent"
name = "Risk & Control Agent"
def __init__(self, gemini_service: GeminiService, reference_docs: ReferenceDocsService):
"""

View file

@ -134,7 +134,7 @@ async def info(user: dict = Depends(get_current_user)):
return {
"status": "ready",
"user": user.get("name", "Unknown"),
"agents": ["Legal Agent", "Brand Agent", "Channel Best Practices Agent", "Channel Tech Specs Agent"],
"agents": ["Risk & Control Agent", "Brand Agent", "Channel Best Practices Agent", "Channel Tech Specs Agent"],
"reference_docs": doc_summary,
}
return {"status": "initializing", "user": user.get("name", "Unknown")}

View file

@ -27,11 +27,11 @@ class AnalysisService:
"""
# Agent execution order
AGENT_ORDER = ["Legal Agent", "Brand Agent", "Channel Best Practices Agent", "Channel Tech Specs Agent"]
AGENT_ORDER = ["Risk & Control Agent", "Brand Agent", "Channel Best Practices Agent", "Channel Tech Specs Agent"]
# Mapping from agent name to the key in AgentReview/previous_analysis dict
AGENT_REVIEW_KEY_MAP = {
"Legal Agent": "legalAgentReview",
"Risk & Control Agent": "legalAgentReview",
"Brand Agent": "brandAgentReview",
"Channel Best Practices Agent": "channelBestPracticesAgentReview",
"Channel Tech Specs Agent": "channelTechSpecsAgentReview",
@ -54,7 +54,7 @@ class AnalysisService:
# Initialize agents
self.agents = {
"Legal Agent": LegalAgent(gemini_service, reference_docs),
"Risk & Control Agent": LegalAgent(gemini_service, reference_docs),
"Brand Agent": BrandAgent(gemini_service, reference_docs),
"Channel Best Practices Agent": ChannelBestPracticesAgent(gemini_service, reference_docs),
"Channel Tech Specs Agent": ChannelTechSpecsAgent(gemini_service, reference_docs),
@ -230,7 +230,7 @@ class AnalysisService:
# Build the complete AgentReview
return AgentReview(
legalAgentReview=reviews["Legal Agent"],
legalAgentReview=reviews["Risk & Control Agent"],
brandAgentReview=reviews["Brand Agent"],
channelBestPracticesAgentReview=reviews["Channel Best Practices Agent"],
channelTechSpecsAgentReview=reviews["Channel Tech Specs Agent"],

View file

@ -9,7 +9,7 @@ import apiService, { AnalyticsResponse, AgencyAnalyticsItem } from '../services/
// Agent performance is still static for now - would need separate API
const agentPerformance = [
{ name: 'Legal Agent', passRate: 85, avgIssues: 1.2, trend: 'up' },
{ name: 'Risk & Control Agent', passRate: 85, avgIssues: 1.2, trend: 'up' },
{ name: 'Brand Agent', passRate: 68, avgIssues: 2.5, trend: 'down' },
{ name: 'Channel Best Practices Agent', passRate: 92, avgIssues: 0.8, trend: 'up' },
{ name: 'Channel Tech Specs Agent', passRate: 71, avgIssues: 1.9, trend: 'stable' },

View file

@ -1056,7 +1056,7 @@ const AnalysisErrorModal: React.FC<{
if (!isOpen || !feedback) return null;
const agentEntries: { label: string; review: { ragStatus: string; feedback: string } }[] = [
{ label: 'Legal Agent', review: feedback.legalAgentReview },
{ label: 'Risk & Control Agent', review: feedback.legalAgentReview },
{ label: 'Brand Agent', review: feedback.brandAgentReview },
{ label: 'Channel Best Practices Agent', review: feedback.channelBestPracticesAgentReview },
{ label: 'Channel Tech Specs Agent', review: feedback.channelTechSpecsAgentReview },

View file

@ -14,7 +14,7 @@ interface CheckDetail {
const specialistAgents: CheckDetail[] = [
{
name: 'Legal Agent',
name: 'Risk & Control Agent',
icon: <LegalIcon />,
role: 'Standards & Disclaimers',
description: 'Ensures compliance with all regulatory requirements.'

View file

@ -871,7 +871,7 @@ export const FeedbackReport: React.FC<{
};
const agentReviews = [
{ title: 'Legal Agent', review: feedback.legalAgentReview },
{ title: 'Risk & Control Agent', review: feedback.legalAgentReview },
{ title: 'Brand Agent', review: feedback.brandAgentReview },
{ title: 'Channel Best Practices Agent', review: feedback.channelBestPracticesAgentReview },
{ title: 'Channel Tech Specs Agent', review: feedback.channelTechSpecsAgentReview },

View file

@ -165,7 +165,7 @@ export const PDFReport: React.FC<PDFReportProps> = ({ campaignName, proofs }) =>
const feedback: AgentReview = version.feedback;
const agentReviews = [
{ title: 'Legal Agent', review: feedback.legalAgentReview, icon: <LegalIcon style={{height: '24px', width: '24px'}} /> },
{ title: 'Risk & Control Agent', review: feedback.legalAgentReview, icon: <LegalIcon style={{height: '24px', width: '24px'}} /> },
{ title: 'Brand Agent', review: feedback.brandAgentReview, icon: <BrandIcon style={{height: '24px', width: '24px'}} /> },
{ title: 'Channel Best Practices Agent', review: feedback.channelBestPracticesAgentReview, icon: <ChannelIcon style={{height: '24px', width: '24px'}} /> },
{ title: 'Channel Tech Specs Agent', review: feedback.channelTechSpecsAgentReview, icon: <ChannelIcon style={{height: '24px', width: '24px'}} /> },

View file

@ -490,7 +490,7 @@ const AnalysisErrorModal: React.FC<{
if (!isOpen || !feedback) return null;
const agentEntries: { label: string; review: { ragStatus: string; feedback: string } }[] = [
{ label: 'Legal Agent', review: feedback.legalAgentReview },
{ label: 'Risk & Control Agent', review: feedback.legalAgentReview },
{ label: 'Brand Agent', review: feedback.brandAgentReview },
{ label: 'Channel Best Practices Agent', review: feedback.channelBestPracticesAgentReview },
{ label: 'Channel Tech Specs Agent', review: feedback.channelTechSpecsAgentReview },

View file

@ -19,7 +19,7 @@ interface StatusInfoProps {
// FIX: Storing components instead of instantiated elements to avoid React.cloneElement type issues.
const agentIcons: Record<AgentName, React.FC<React.SVGProps<SVGSVGElement>>> = {
'Legal Agent': LegalIcon,
'Risk & Control Agent': LegalIcon,
'Brand Agent': BrandIcon,
'Channel Best Practices Agent': ChannelIcon,
'Channel Tech Specs Agent': ChannelIcon,

View file

@ -1,4 +1,4 @@
import type { AgentName } from './types';
export const AGENT_NAMES: AgentName[] = ['Legal Agent', 'Brand Agent', 'Channel Best Practices Agent', 'Channel Tech Specs Agent'];
export const AGENT_NAMES: AgentName[] = ['Risk & Control Agent', 'Brand Agent', 'Channel Best Practices Agent', 'Channel Tech Specs Agent'];

View file

@ -1,5 +1,5 @@
// Fix: Broke a circular dependency by defining the AgentName type directly in this file instead of importing it.
export type AgentName = 'Legal Agent' | 'Brand Agent' | 'Channel Best Practices Agent' | 'Channel Tech Specs Agent';
export type AgentName = 'Risk & Control Agent' | 'Brand Agent' | 'Channel Best Practices Agent' | 'Channel Tech Specs Agent';
// RBAC types
export type UserRole = 'super_admin' | 'oversight_admin' | 'agency_admin' | 'basic_user';