Scenario-Based Orchestration
Industry Scenario Selection Architecture¶
Overview¶
This document describes the architecture for industry-specific scenario selection with a tabbed UI that allows users to switch between different industry use cases (Banking, Insurance, Healthcare, etc.) while pointing to different orchestration configurations.
Current State¶
Frontend¶
- Component:
IndustryTag.jsx(hardcoded, branch-based) - Logic: Reads
VITE_BRANCH_NAMEto determine industry - Display: Single static badge showing "Banking Edition" or "Insurance Edition"
- Issue: No user selection, tied to Git branch
Backend¶
- Component:
scenarios/loader.py - Structure: Scenario-based configuration system
- Current:
banking/directory (empty, noscenario.yaml) - Capability: Can load multiple scenarios and apply agent overrides
Proposed Architecture¶
Design Goals¶
- User-Driven Selection: Users select industry from UI tabs (not Git branches)
- Multi-Industry Support: Banking, Insurance, Healthcare, Retail, etc.
- Scenario-Specific Agents: Each industry loads tailored agents and tools
- Dynamic Orchestration: Backend loads the right scenario configuration
- Maintainable: Add new industries without code changes
Architecture Diagram¶
Fetches scenarios from backend
Sends selection via WebSocket"] end Selector -->|"WebSocket: { scenario: 'banking' }"| Backend subgraph Backend["BACKEND (API)"] direction TB API["GET /api/v1/scenarios
Returns: ['banking', 'insurance', 'healthcare']"] WS["WebSocket Handler
Receives scenario selection
Calls load_scenario()"] Loader["scenarios/loader.py
• _discover_scenarios()
• load_scenario(name)
• get_scenario_agents()"] API --> WS --> Loader end Loader -->|"Loads scenario config"| Configs subgraph Configs["SCENARIO CONFIGURATIONS (YAML)"] direction LR B["scenarios/banking/
scenario.yaml"] I["scenarios/insurance/
scenario.yaml"] H["scenarios/healthcare/
scenario.yaml"] R["scenarios/retail/
scenario.yaml"] end style Frontend fill:#e3f2fd,stroke:#1976d2 style Backend fill:#e8f5e9,stroke:#4caf50 style Configs fill:#fff3e0,stroke:#ff9800
Implementation Plan¶
Phase 1: Backend - Scenario System¶
1.1 Create Scenario Configurations¶
File: apps/artagent/backend/agents/scenarios/banking/scenario.yaml
description: Banking and financial services scenario
# Agents to include (if empty, include all)
agents:
- ConciergeAgent
- AuthAgent
- FraudAgent
- InvestmentAdvisorAgent
- CardRecommendationAgent
- ComplianceDeskAgent
# Global template variables for all agents
template_vars:
industry: "banking"
compliance_regulations: "SEC, FINRA, AML"
# Agent-specific overrides
agent_overrides:
ConciergeAgent:
greeting: "Welcome to SecureBank's AI assistant. I can help with fraud alerts, investments, card recommendations, or compliance questions. How can I assist you today?"
template_vars:
company_name: "SecureBank"
FraudAgent:
add_tools:
- check_transaction_fraud
- freeze_card
template_vars:
fraud_threshold: 500
# Starting agent
start_agent: ConciergeAgent
File: apps/artagent/backend/agents/scenarios/insurance/scenario.yaml
description: Insurance and claims processing scenario
agents:
- ConciergeAgent
- ClaimsAgent
- PolicyAgent
- UnderwritingAgent
template_vars:
industry: "insurance"
compliance_regulations: "HIPAA, State Insurance Codes"
agent_overrides:
ConciergeAgent:
greeting: "Welcome to SafeGuard Insurance. I can help with claims, policies, or underwriting questions. What brings you here today?"
template_vars:
company_name: "SafeGuard Insurance"
ClaimsAgent:
add_tools:
- submit_claim
- check_claim_status
voice:
name: en-US-JennyNeural
start_agent: ConciergeAgent
File: apps/artagent/backend/agents/scenarios/healthcare/scenario.yaml
description: Healthcare patient support scenario
agents:
- ConciergeAgent
- AppointmentAgent
- PrescriptionAgent
- BillingAgent
template_vars:
industry: "healthcare"
compliance_regulations: "HIPAA, HITECH"
agent_overrides:
ConciergeAgent:
greeting: "Hello, this is MediCare AI assistant. I can help schedule appointments, refill prescriptions, or answer billing questions. How may I help you?"
template_vars:
company_name: "MediCare"
start_agent: ConciergeAgent
1.2 Add API Endpoint¶
File: apps/artagent/backend/api/v1/endpoints/scenarios.py (new file)
"""
Scenarios API
=============
Endpoints for listing and managing industry scenarios.
"""
from fastapi import APIRouter
from apps.artagent.backend.agents.scenarios.loader import list_scenarios, load_scenario
router = APIRouter(prefix="/scenarios", tags=["scenarios"])
@router.get("/")
async def get_scenarios():
"""
List all available scenarios.
Returns:
List of scenario names with metadata
"""
scenarios = list_scenarios()
return {
"scenarios": [
{
"name": name,
"display_name": name.replace("_", " ").title(),
"description": (load_scenario(name).description if load_scenario(name) else ""),
}
for name in scenarios
]
}
@router.get("/{scenario_name}")
async def get_scenario_details(scenario_name: str):
"""
Get details for a specific scenario.
Args:
scenario_name: Scenario identifier
Returns:
Scenario configuration details
"""
scenario = load_scenario(scenario_name)
if not scenario:
return {"error": "Scenario not found"}, 404
return {
"name": scenario.name,
"description": scenario.description,
"agents": scenario.agents,
"start_agent": scenario.start_agent,
}
Add to: apps/artagent/backend/api/v1/__init__.py
1.3 Update WebSocket Handler¶
File: apps/artagent/backend/api/v1/endpoints/realtime.py
@app.websocket("/ws/realtime")
async def realtime_endpoint(websocket: WebSocket):
await websocket.accept()
# Receive initial message with scenario selection
init_message = await websocket.receive_json()
scenario_name = init_message.get("scenario", "banking") # default to banking
# Load scenario
from apps.artagent.backend.agents.scenarios.loader import (
load_scenario,
get_scenario_agents,
get_scenario_start_agent,
)
scenario = load_scenario(scenario_name)
if not scenario:
await websocket.send_json({"error": f"Scenario '{scenario_name}' not found"})
await websocket.close()
return
# Get agents with scenario overrides
agents = get_scenario_agents(scenario_name)
start_agent = get_scenario_start_agent(scenario_name)
# Continue with orchestration setup using scenario-specific agents
# ...
Phase 2: Frontend - Tabbed Scenario Selector¶
2.1 Create IndustrySelector Component¶
File: apps/artagent/frontend/src/components/IndustrySelector.jsx (new)
import React, { useState, useEffect } from 'react';
import { styles } from '../styles/voiceAppStyles.js';
const IndustrySelector = ({ onScenarioSelect, selectedScenario }) => {
const [scenarios, setScenarios] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Fetch available scenarios from backend
fetch('/api/v1/scenarios')
.then((res) => res.json())
.then((data) => {
setScenarios(data.scenarios || []);
setLoading(false);
// Auto-select first scenario if none selected
if (!selectedScenario && data.scenarios.length > 0) {
onScenarioSelect(data.scenarios[0].name);
}
})
.catch((err) => {
console.error('Failed to load scenarios:', err);
setLoading(false);
});
}, []);
const getScenarioPalette = (scenarioName) => {
const palettes = {
banking: {
background: 'linear-gradient(135deg, #4338ca, #6366f1)',
color: '#f8fafc',
borderColor: 'rgba(99,102,241,0.45)',
shadow: '0 12px 28px rgba(99,102,241,0.25)',
},
insurance: {
background: 'linear-gradient(135deg, #0ea5e9, #10b981)',
color: '#0f172a',
borderColor: 'rgba(14,165,233,0.35)',
shadow: '0 12px 28px rgba(14,165,233,0.24)',
},
healthcare: {
background: 'linear-gradient(135deg, #ec4899, #f43f5e)',
color: '#fff',
borderColor: 'rgba(236,72,153,0.45)',
shadow: '0 12px 28px rgba(236,72,153,0.25)',
},
retail: {
background: 'linear-gradient(135deg, #f59e0b, #eab308)',
color: '#78350f',
borderColor: 'rgba(245,158,11,0.45)',
shadow: '0 12px 28px rgba(245,158,11,0.25)',
},
};
return palettes[scenarioName] || palettes.banking;
};
if (loading) {
return (
<div style={styles.topTabsContainer}>
<div style={{ padding: '10px', color: '#64748b' }}>Loading scenarios...</div>
</div>
);
}
return (
<div style={styles.topTabsContainer}>
{scenarios.map((scenario) => {
const isActive = scenario.name === selectedScenario;
const palette = getScenarioPalette(scenario.name);
return (
<div
key={scenario.name}
style={styles.topTab(isActive, palette)}
onClick={() => onScenarioSelect(scenario.name)}
>
{scenario.display_name}
</div>
);
})}
</div>
);
};
export default IndustrySelector;
2.2 Update App.jsx¶
File: apps/artagent/frontend/src/components/App.jsx
import IndustrySelector from './IndustrySelector.jsx';
function App() {
const [selectedScenario, setSelectedScenario] = useState('banking');
const [sessionStarted, setSessionStarted] = useState(false);
const handleScenarioChange = (scenarioName) => {
if (sessionStarted) {
// Show confirmation dialog
if (confirm('Changing scenario will end the current session. Continue?')) {
setSelectedScenario(scenarioName);
// Reset session
handleEndSession();
}
} else {
setSelectedScenario(scenarioName);
}
};
const handleStartSession = () => {
// Pass scenario to WebSocket
const wsPayload = {
scenario: selectedScenario,
// ... other payload
};
// Connect WebSocket with scenario info
connectWebSocket(wsPayload);
setSessionStarted(true);
};
return (
<div className="app">
{/* Replace IndustryTag with IndustrySelector */}
<IndustrySelector
onScenarioSelect={handleScenarioChange}
selectedScenario={selectedScenario}
/>
{/* Rest of the app */}
{/* ... */}
</div>
);
}
2.3 Update Styles¶
File: apps/artagent/frontend/src/styles/voiceAppStyles.js
export const styles = {
// ... existing styles
topTabsContainer: {
display: 'flex',
gap: '8px',
marginBottom: '16px',
flexWrap: 'wrap',
},
topTab: (active, palette = {}) => ({
padding: '10px 20px',
borderRadius: '8px',
background: active ? (palette.background || '#4338ca') : '#e2e8f0',
color: active ? (palette.color || '#fff') : '#475569',
border: active ? `2px solid ${palette.borderColor || '#6366f1'}` : '2px solid transparent',
boxShadow: active ? (palette.shadow || '0 4px 12px rgba(99,102,241,0.25)') : 'none',
cursor: 'pointer',
fontWeight: active ? '600' : '500',
fontSize: '14px',
transition: 'all 0.2s ease',
userSelect: 'none',
':hover': {
transform: active ? 'scale(1.02)' : 'scale(1.0)',
opacity: active ? 1 : 0.8,
},
}),
};
Usage Flow¶
User Perspective¶
- Open UI → See tabs: Banking | Insurance | Healthcare | Retail
- Click "Healthcare" tab → Tab becomes active, badge updates
- Click "Start Call" → Backend loads healthcare scenario
- Agent Greeting → "Hello, this is MediCare AI assistant..."
- Switch to "Banking" → Prompted to confirm (session restart)
- Confirm → New session with banking agents
Developer Perspective (Adding New Industry)¶
To add "Retail" scenario:
- Create directory:
scenarios/retail/ - Create config:
scenarios/retail/scenario.yaml - Define agents and overrides (see examples above)
- No code changes needed - system auto-discovers
- Restart backend → "Retail" tab appears in UI
Benefits¶
✅ User-Friendly: Click tabs to switch industries (no Git branch changes)
✅ Scalable: Add new industries without touching frontend code
✅ Maintainable: YAML-based configuration
✅ Flexible: Per-industry agent selection, tool overrides, prompts
✅ Type-Safe: Backend validates scenario configs
✅ DRY: Reuse base agents across scenarios with overrides
Migration Path¶
Step 1: Backend Setup¶
- Create
scenarios/banking/scenario.yamlwith current banking config - Add
/api/v1/scenariosendpoint - Update WebSocket handler to accept
scenarioparameter
Step 2: Frontend Refactor¶
- Create
IndustrySelector.jsxcomponent - Replace
IndustryTag.jsxinApp.jsx - Update state management to pass scenario to WebSocket
Step 3: Add More Industries¶
- Create
scenarios/insurance/scenario.yaml - Create
scenarios/healthcare/scenario.yaml - Test scenario switching
Step 4: Cleanup¶
- Remove
VITE_BRANCH_NAMElogic - Remove hardcoded "Banking Edition" references
- Update documentation
Future Enhancements¶
- Scenario Metadata: Icons, colors, descriptions from YAML
- Custom Branding: Per-scenario logos, themes
- A/B Testing: Compare scenarios for same user
- Analytics: Track which scenarios are most popular
- Scenario Marketplace: Community-contributed scenarios
File Structure¶
apps/artagent/
├── backend/
│ ├── agents/
│ │ └── scenarios/
│ │ ├── loader.py (existing - already supports this!)
│ │ ├── banking/
│ │ │ └── scenario.yaml (NEW)
│ │ ├── insurance/
│ │ │ └── scenario.yaml (NEW)
│ │ ├── healthcare/
│ │ │ └── scenario.yaml (NEW)
│ │ └── retail/
│ │ └── scenario.yaml (NEW)
│ └── api/
│ └── v1/
│ └── endpoints/
│ └── scenarios.py (NEW)
├── frontend/
│ └── src/
│ └── components/
│ ├── IndustrySelector.jsx (NEW - replaces IndustryTag.jsx)
│ └── App.jsx (UPDATED)
Conclusion¶
This architecture provides a scalable, user-friendly, and maintainable system for industry-specific voice agent scenarios. The backend scenario loader already exists and supports this design—we just need to:
- Create scenario YAML configs for each industry
- Add API endpoint to list scenarios
- Build tabbed UI to let users select scenarios
- Pass scenario name to WebSocket handler
No major refactoring needed - the foundation is already there! 🎉