AI Chat Specification
Complete specification for the AI Chat/Copilot system
AI Chat Specification
The AI Chat is a conversational interface that understands and executes HRMS features. Every feature must register its AI capabilities so users can interact naturally.
Core Philosophy
The AI Chat should understand the full software. When a user says "Create an onboarding flow for Frontend Developers", the AI knows this feature exists and can execute it.
Key Principles:
- Every feature is AI-accessible from day one
- Actions require user confirmation before execution
- Results are shown with visual widgets and links
- Errors are clear and actionable
Response Model: Phase 09 uses synchronous JSON responses. The AI service waits for all tool execution to complete before responding. Streaming (SSE) is a future enhancement for Phase 10+.
AI-Native Architecture
The AI Chat is designed as a sidebar-first, AI-native interface where the AI assistant is always accessible via a floating button. The design follows enterprise SaaS patterns with a clean white content area and colored sidebar navigation.
AIProvider Context
// components/ai/AIProvider.tsx
interface AIContextType {
// Chat state
mode: 'minimized' | 'panel' | 'fullscreen';
setMode: (mode: AIContextType['mode']) => void;
messages: ChatMessage[];
isTyping: boolean;
// Actions AI can perform
navigate: (path: string, params?: Record<string, string>) => void;
openForm: (formId: string, prefillData?: Record<string, any>) => void;
showConfirmation: (message: string, onConfirm: () => void) => void;
// User actions
sendMessage: (content: string) => void;
clearChat: () => void;
}
// Usage: Wrap entire app
<AIProvider>
<App />
<AIFloatingButton /> {/* Always rendered */}
<AIChatPanel /> {/* Renders based on mode */}
</AIProvider>AI Chat Modes
The AI Chat has three distinct modes that adapt to the sidebar-based layout:
MODE: MINIMIZED (Default)
┌─────────────────────────────────────┐
│ │
│ Any Page Content │
│ │
│ ┌────┐│
│ │ ✨ ││ ← Floating AI Button
│ └────┘│
├─────────────────────────────────────┤
│ 🏠 👥 📅 📄 ••• │ ← Mobile Nav
└─────────────────────────────────────┘
MODE: PANEL (Mobile - Bottom Sheet)
┌─────────────────────────────────────┐
│ Page Content (dimmed) │
├─────────────────────────────────────┤
│ AI Assistant [⬜] [✕] │ ← Fullscreen & Close
├─────────────────────────────────────┤
│ │
│ 👤 Show my time off balance │
│ │
│ ✨ Here's your current balance: │
│ ┌─────────────────────────────────┐│
│ │ 🏖️ Vacation 12 days left ││
│ │ 🏥 Sick 8 days left ││
│ │ 👤 Personal 4 days left ││
│ │ ││
│ │ [Request Time Off →] ││
│ └─────────────────────────────────┘│
│ │
├─────────────────────────────────────┤
│ [Ask anything...] [➤] │
└─────────────────────────────────────┘
MODE: PANEL (Desktop - Side Panel)
┌─────────────────────────────┬───────────────────┐
│ │ AI Assistant [✕] │
│ ├───────────────────┤
│ Page Content │ │
│ │ Chat messages │
│ │ │
│ │ │
│ ├───────────────────┤
│ │ [Input...] [➤] │
└─────────────────────────────┴───────────────────┘
MODE: FULLSCREEN (Immersive)
┌─────────────────────────────────────────────────┐
│ ← Back AI Assistant [⬜→┐] │
├─────────────────────────────────────────────────┤
│ │
│ 👤 Add a new employee named Sarah Chen, │
│ she's an Engineering Manager │
│ │
│ ✨ I'll help you add Sarah. Here's what I've │
│ prepared: │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ 📝 NEW EMPLOYEE │ │
│ │ │ │
│ │ Name: Sarah Chen │ │
│ │ Title: Engineering Manager │ │
│ │ Department: Engineering (suggested) │ │
│ │ │ │
│ │ [Open Form with Details →] │ │
│ │ │ │
│ │ Or tell me more to add additional info │ │
│ └─────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────┤
│ [📅 Request PTO] [👤 Find Employee] [📊 Stats] │ ← Quick Actions
├─────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────┐ │
│ │ Type a message... [➤] │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘AI Action Card Types
The AI responds with interactive cards, not just text:
// Types of AI response cards
type AIActionCard =
| {
type: 'employee_card';
employee: Employee;
actions: Array<'view' | 'edit' | 'message'>;
}
| {
type: 'balance_card';
balances: TimeOffBalance[];
actions: Array<'request'>;
}
| {
type: 'navigation_card';
title: string;
description: string;
destination: string;
params?: Record<string, string>;
}
| {
type: 'form_prefill_card';
formType: 'employee' | 'timeoff' | 'document';
prefillData: Record<string, any>;
actions: Array<'open_form' | 'edit_details'>;
}
| {
type: 'confirmation_card';
title: string;
message: string;
confirmLabel: string;
cancelLabel: string;
onConfirm: () => void;
}
| {
type: 'list_card';
title: string;
items: Array<{ label: string; value: string; icon?: string }>;
};AI Floating Button
// components/ai/AIFloatingButton.tsx
const AIFloatingButton = () => {
const { mode, setMode } = useAI();
if (mode !== 'minimized') return null;
return (
<motion.button
initial={{ scale: 0 }}
animate={{ scale: 1 }}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
onClick={() => setMode('panel')}
className="
fixed z-50
/* Mobile: centered above bottom nav */
bottom-20 right-4
md:bottom-6 md:right-6
/* Size and shape */
w-14 h-14 rounded-full
/* Vibrant gradient - MUST stand out */
bg-gradient-to-br from-violet-500 via-purple-500 to-fuchsia-500
/* Glow effect */
shadow-lg shadow-violet-500/30
/* Content */
flex items-center justify-center
text-white
/* Subtle pulse animation */
animate-pulse-subtle
"
>
<Sparkles className="w-6 h-6" />
</motion.button>
);
};Typing Indicator Component
The typing indicator shows animated dots while the AI is "thinking" or generating a response.
// components/ai/TypingIndicator.tsx
import { motion } from 'framer-motion';
const TypingIndicator = () => {
return (
<div className="flex items-center gap-1 px-4 py-3">
{/* AI Avatar */}
<div className="
w-8 h-8 rounded-full
bg-gradient-to-br from-violet-500 via-purple-500 to-fuchsia-500
flex items-center justify-center
mr-2
">
<Sparkles className="w-4 h-4 text-white" />
</div>
{/* Typing dots container */}
<div className="
flex items-center gap-1
px-4 py-2
bg-gray-100 dark:bg-gray-800
rounded-2xl rounded-bl-md
">
{[0, 1, 2].map((index) => (
<motion.div
key={index}
className="w-2 h-2 rounded-full bg-gray-400 dark:bg-gray-500"
animate={{
y: [0, -4, 0],
}}
transition={{
duration: 0.6,
repeat: Infinity,
delay: index * 0.15,
ease: 'easeInOut',
}}
/>
))}
</div>
</div>
);
};
// Alternative: CSS-only typing indicator (no Framer Motion)
const TypingIndicatorCSS = () => (
<div className="flex items-center gap-1 px-4 py-3">
<div className="
w-8 h-8 rounded-full
bg-gradient-to-br from-violet-500 via-purple-500 to-fuchsia-500
flex items-center justify-center mr-2
">
<Sparkles className="w-4 h-4 text-white" />
</div>
<div className="
flex items-center gap-1 px-4 py-2
bg-gray-100 dark:bg-gray-800 rounded-2xl rounded-bl-md
">
<span className="w-2 h-2 rounded-full bg-gray-400 animate-typing-dot" style={{ animationDelay: '0ms' }} />
<span className="w-2 h-2 rounded-full bg-gray-400 animate-typing-dot" style={{ animationDelay: '150ms' }} />
<span className="w-2 h-2 rounded-full bg-gray-400 animate-typing-dot" style={{ animationDelay: '300ms' }} />
</div>
</div>
);
// Add to tailwind.config.js:
// animation: { 'typing-dot': 'typing-dot 1.4s infinite' }
// keyframes: { 'typing-dot': { '0%, 60%, 100%': { transform: 'translateY(0)' }, '30%': { transform: 'translateY(-4px)' } } }Quick Actions Component
Quick action chips shown in fullscreen chat mode for common tasks.
// components/ai/QuickActions.tsx
interface QuickAction {
icon: React.ComponentType<{ className?: string }>;
label: string;
action: string; // Message to send to AI
}
const defaultQuickActions: QuickAction[] = [
{ icon: Calendar, label: 'Request PTO', action: 'I want to request time off' },
{ icon: Users, label: 'Find Employee', action: 'Help me find an employee' },
{ icon: BarChart3, label: 'View Stats', action: 'Show me dashboard stats' },
{ icon: FileText, label: 'Find Policy', action: 'Search for a policy document' },
];
const QuickActions = ({ onSelect }: { onSelect: (action: string) => void }) => {
return (
<div className="
flex gap-2 overflow-x-auto
px-4 py-2
scrollbar-hide
">
{defaultQuickActions.map((action) => (
<button
key={action.label}
onClick={() => onSelect(action.action)}
className="
flex items-center gap-2
px-3 py-2
bg-gray-100 dark:bg-gray-800
hover:bg-gray-200 dark:hover:bg-gray-700
rounded-full
whitespace-nowrap
text-sm font-medium
text-gray-700 dark:text-gray-300
transition-colors
min-h-[36px]
"
>
<action.icon className="w-4 h-4" />
{action.label}
</button>
))}
</div>
);
};Chat Message Component
// components/ai/ChatMessage.tsx
interface ChatMessageProps {
role: 'user' | 'assistant';
content: string;
timestamp?: Date;
actionCard?: AIActionCard;
}
const ChatMessage = ({ role, content, timestamp, actionCard }: ChatMessageProps) => {
const isUser = role === 'user';
return (
<div className={cn(
"flex gap-3 px-4",
isUser ? "flex-row-reverse" : "flex-row"
)}>
{/* Avatar */}
{!isUser && (
<div className="
w-8 h-8 rounded-full flex-shrink-0
bg-gradient-to-br from-violet-500 via-purple-500 to-fuchsia-500
flex items-center justify-center
">
<Sparkles className="w-4 h-4 text-white" />
</div>
)}
{/* Message bubble */}
<div className={cn(
"max-w-[80%] space-y-2",
isUser && "items-end"
)}>
<div className={cn(
"px-4 py-2 rounded-2xl",
isUser
? "bg-violet-500 text-white rounded-br-md"
: "bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white rounded-bl-md"
)}>
<p className="text-sm whitespace-pre-wrap">{content}</p>
</div>
{/* Action Card (if present) */}
{actionCard && (
<ActionCard card={actionCard} />
)}
{/* Timestamp */}
{timestamp && (
<p className={cn(
"text-xs text-gray-400",
isUser ? "text-right" : "text-left"
)}>
{format(timestamp, 'h:mm a')}
</p>
)}
</div>
</div>
);
};Chat UI Components
Message Types
| Type | Description | When Used |
|---|---|---|
| User Message | Text input from user | User sends request |
| AI Response | Text + optional widgets | AI responds |
| Confirmation Card | Action preview with confirm/cancel | Before write operations |
| Progress Widget | Real-time progress indicator | During async operations |
| Result Card | Success/error with links | After action completes |
| Escalation Prompt | Option to contact human HR | When AI cannot help |
Widget Specifications
Action Confirmation Card
Shows before any write operation. User must confirm.
┌─────────────────────────────────────────────┐
│ Create Onboarding Workflow │
│ │
│ Title: Frontend Developer Onboarding │
│ Department: Engineering │
│ Tasks: 12 items │
│ Assigned to: John Doe │
│ │
│ [Cancel] [Confirm] │
└─────────────────────────────────────────────┘React Component Structure:
interface ConfirmationCardProps {
title: string
icon: 'create' | 'update' | 'delete' | 'transfer'
fields: Array<{ label: string; value: string }>
onConfirm: () => void
onCancel: () => void
}Progress Widget
Shows during long-running operations.
┌─────────────────────────────────────────────┐
│ Creating workflow... │
│ ████████████████░░░░░░░░░░░░░░ 60% │
│ │
│ [ok] Template loaded │
│ [ok] Tasks created (12/12) │
│ [..] Assigning to employee... │
│ [ ] Sending notification │
└─────────────────────────────────────────────┘React Component Structure:
interface ProgressWidgetProps {
title: string
progress: number // 0-100
steps: Array<{
label: string
status: 'pending' | 'in_progress' | 'completed' | 'error'
}>
}Result Card (Success)
Shows after successful action with link to resource.
┌─────────────────────────────────────────────┐
│ [ok] Workflow Created │
│ │
│ "Frontend Developer Onboarding" │
│ 12 tasks | Assigned to John Doe │
│ │
│ [View Workflow] │
└─────────────────────────────────────────────┘Result Card (Error)
Shows when action fails with recovery options.
┌─────────────────────────────────────────────┐
│ [x] Action Failed │
│ │
│ Could not create workflow: │
│ "You don't have permission to create │
│ workflows for the Engineering department" │
│ │
│ [Try Again] [Contact HR Admin] │
└─────────────────────────────────────────────┘Info Card
Shows read-only information.
┌─────────────────────────────────────────────┐
│ Leave Balance │
│ │
│ Vacation: 15 days remaining │
│ Sick Leave: 10 days remaining │
│ Personal: 3 days remaining │
│ │
│ [View Full Details] │
└─────────────────────────────────────────────┘Action Execution Flow
Read Operations (No Confirmation)
User: "How many vacation days do I have?"
│
▼
AI parses intent → timeoff_check_balance tool
│
▼
AI calls API → GET /api/v1/time-off/balance
│
▼
AI shows Info Card with balanceWrite Operations (Requires Confirmation)
User: "Submit a leave request for next Monday"
│
▼
AI parses intent → timeoff_submit tool
│
▼
AI shows Confirmation Card
│
├── User clicks [Cancel] → AI: "No problem, request cancelled."
│
└── User clicks [Confirm]
│
▼
AI calls API → POST /api/v1/time-off
│
▼
AI shows Progress Widget (if async)
│
▼
AI shows Result Card with linkError Handling Flow
API returns error
│
├── 400 Bad Request → Show error message, suggest fix
│
├── 403 Forbidden → Show permission error, suggest contact admin
│
├── 404 Not Found → Show "resource not found" message
│
├── 429 Rate Limited → Show "too many requests", suggest wait
│
└── 500 Server Error → Show generic error, offer retryAll AI Chat Tools
Employee Management Tools
employee_create
Creates a new employee profile.
{
type: 'function',
function: {
name: 'employee_create',
description: 'Create a new employee profile in the system',
parameters: {
type: 'object',
properties: {
firstName: { type: 'string', description: 'Employee first name' },
lastName: { type: 'string', description: 'Employee last name' },
email: { type: 'string', description: 'Work email address' },
jobTitle: { type: 'string', description: 'Job title' },
departmentId: { type: 'string', description: 'Department ID' },
managerId: { type: 'string', description: 'Manager employee ID' },
startDate: { type: 'string', format: 'date', description: 'Employment start date' },
},
required: ['firstName', 'lastName', 'email', 'jobTitle'],
},
},
}Example prompts:
- "Add a new employee named John Smith"
- "Create employee profile for jane@company.com"
- "Hire a new developer starting next Monday"
Confirmation card fields:
- Name, Email, Job Title, Department, Manager, Start Date
employee_search
Searches employees by various criteria.
{
type: 'function',
function: {
name: 'employee_search',
description: 'Search for employees by name, department, role, or tags',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query (name, email, etc.)' },
departmentId: { type: 'string', description: 'Filter by department' },
roleId: { type: 'string', description: 'Filter by role' },
tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' },
status: { type: 'string', enum: ['active', 'inactive', 'all'] },
},
},
},
}Example prompts:
- "Find all engineers in the product team"
- "Search for employees tagged as 'remote'"
- "Who works in the Marketing department?"
Result: List of matching employees with links
employee_transfer
Transfers an employee to a new department or manager.
{
type: 'function',
function: {
name: 'employee_transfer',
description: 'Transfer an employee to a different department or manager',
parameters: {
type: 'object',
properties: {
employeeId: { type: 'string', description: 'Employee to transfer' },
newDepartmentId: { type: 'string', description: 'New department ID' },
newManagerId: { type: 'string', description: 'New manager ID' },
effectiveDate: { type: 'string', format: 'date', description: 'Transfer effective date' },
},
required: ['employeeId'],
},
},
}Example prompts:
- "Transfer John to the Engineering department"
- "Move Sarah to report to Mike"
- "Change department for employee #123"
employee_terminate
Initiates employee termination/offboarding.
{
type: 'function',
function: {
name: 'employee_terminate',
description: 'Initiate employee termination and offboarding process',
parameters: {
type: 'object',
properties: {
employeeId: { type: 'string', description: 'Employee ID to terminate' },
lastDay: { type: 'string', format: 'date', description: 'Last working day' },
reason: { type: 'string', enum: ['resignation', 'termination', 'retirement', 'other'] },
notes: { type: 'string', description: 'Additional notes' },
},
required: ['employeeId', 'lastDay', 'reason'],
},
},
}Example prompts:
- "Start offboarding for John Smith"
- "Process resignation for employee leaving March 15"
employee_tag
Adds or removes tags from an employee.
{
type: 'function',
function: {
name: 'employee_tag',
description: 'Add or remove tags from an employee',
parameters: {
type: 'object',
properties: {
employeeId: { type: 'string', description: 'Employee ID' },
action: { type: 'string', enum: ['add', 'remove'] },
tags: { type: 'array', items: { type: 'string' }, description: 'Tags to add/remove' },
},
required: ['employeeId', 'action', 'tags'],
},
},
}Example prompts:
- "Tag John as a senior engineer"
- "Add 'remote' tag to Sarah"
- "Remove 'contractor' tag from Mike"
Time-Off Tools
timeoff_submit
Submits a new time-off request.
{
type: 'function',
function: {
name: 'timeoff_submit',
description: 'Submit a time-off/leave request',
parameters: {
type: 'object',
properties: {
type: { type: 'string', enum: ['vacation', 'sick', 'personal', 'other'] },
startDate: { type: 'string', format: 'date', description: 'Start date' },
endDate: { type: 'string', format: 'date', description: 'End date' },
reason: { type: 'string', description: 'Optional reason' },
halfDay: { type: 'boolean', description: 'Half day request' },
},
required: ['type', 'startDate', 'endDate'],
},
},
}Example prompts:
- "Submit a vacation request for next Monday"
- "Request sick leave for today"
- "Book time off from Dec 20 to Jan 2"
Confirmation card fields:
- Type, Start Date, End Date, Duration, Reason
timeoff_check_balance
Checks remaining time-off balance.
{
type: 'function',
function: {
name: 'timeoff_check_balance',
description: 'Check time-off balance for current user or team member',
parameters: {
type: 'object',
properties: {
employeeId: { type: 'string', description: 'Employee ID (optional, defaults to self)' },
type: { type: 'string', enum: ['vacation', 'sick', 'personal', 'all'] },
},
},
},
}Example prompts:
- "How many vacation days do I have left?"
- "Check my leave balance"
- "What's my sick leave balance?"
Result: Info card with balance breakdown
timeoff_approve
Approves or rejects a time-off request (manager only).
{
type: 'function',
function: {
name: 'timeoff_approve',
description: 'Approve or reject a pending time-off request',
parameters: {
type: 'object',
properties: {
requestId: { type: 'string', description: 'Time-off request ID' },
action: { type: 'string', enum: ['approve', 'reject'] },
comment: { type: 'string', description: 'Optional comment' },
},
required: ['requestId', 'action'],
},
},
}Example prompts:
- "Approve John's vacation request"
- "Reject the leave request from Sarah"
timeoff_team_calendar
Shows team availability and scheduled time-off.
{
type: 'function',
function: {
name: 'timeoff_team_calendar',
description: 'View team time-off calendar and availability',
parameters: {
type: 'object',
properties: {
startDate: { type: 'string', format: 'date' },
endDate: { type: 'string', format: 'date' },
teamId: { type: 'string', description: 'Team ID (optional)' },
departmentId: { type: 'string', description: 'Department ID (optional)' },
},
},
},
}Example prompts:
- "Who's out this week?"
- "Show team calendar for December"
- "Check availability for next Monday"
timeoff_cancel
Cancels a pending time-off request.
{
type: 'function',
function: {
name: 'timeoff_cancel',
description: 'Cancel a pending time-off request',
parameters: {
type: 'object',
properties: {
requestId: { type: 'string', description: 'Request ID to cancel' },
},
required: ['requestId'],
},
},
}Example prompts:
- "Cancel my vacation request"
- "Withdraw my leave request for next week"
Workflow Tools
workflow_create
Creates a new workflow template.
{
type: 'function',
function: {
name: 'workflow_create',
description: 'Create a new workflow template (onboarding, offboarding, etc.)',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Workflow name' },
type: { type: 'string', enum: ['onboarding', 'offboarding', 'custom'] },
departmentId: { type: 'string', description: 'Department for template' },
roleFilter: { type: 'string', description: 'Role this applies to' },
tasks: {
type: 'array',
items: {
type: 'object',
properties: {
title: { type: 'string' },
description: { type: 'string' },
assigneeType: { type: 'string', enum: ['manager', 'hr', 'it', 'employee'] },
dueOffset: { type: 'number', description: 'Days from start' },
},
},
},
},
required: ['name', 'type'],
},
},
}Example prompts:
- "Create an onboarding flow for Frontend Developers"
- "Set up onboarding checklist for new engineers"
- "Create offboarding workflow for departing employees"
Confirmation card fields:
- Name, Type, Department, Number of tasks
workflow_track
Tracks progress of an active workflow instance.
{
type: 'function',
function: {
name: 'workflow_track',
description: 'Check progress of an active workflow',
parameters: {
type: 'object',
properties: {
workflowInstanceId: { type: 'string', description: 'Workflow instance ID' },
employeeId: { type: 'string', description: 'Employee ID to check workflows for' },
},
},
},
}Example prompts:
- "How is John's onboarding going?"
- "Check onboarding progress for new hires"
- "Show workflow status for Sarah"
workflow_complete_task
Marks a workflow task as complete.
{
type: 'function',
function: {
name: 'workflow_complete_task',
description: 'Mark a workflow task as completed',
parameters: {
type: 'object',
properties: {
taskId: { type: 'string', description: 'Task ID to complete' },
notes: { type: 'string', description: 'Completion notes' },
},
required: ['taskId'],
},
},
}Example prompts:
- "Mark the laptop setup task as done"
- "Complete the IT equipment task for John"
onboarding_initiate
Starts onboarding for a new employee.
{
type: 'function',
function: {
name: 'onboarding_initiate',
description: 'Start onboarding process for a new employee',
parameters: {
type: 'object',
properties: {
employeeId: { type: 'string', description: 'New employee ID' },
templateId: { type: 'string', description: 'Workflow template to use' },
startDate: { type: 'string', format: 'date' },
},
required: ['employeeId'],
},
},
}Example prompts:
- "Start onboarding for John Smith"
- "Initialize new hire process for employee #123"
offboarding_initiate
Starts offboarding for a departing employee.
{
type: 'function',
function: {
name: 'offboarding_initiate',
description: 'Start offboarding process for a departing employee',
parameters: {
type: 'object',
properties: {
employeeId: { type: 'string', description: 'Departing employee ID' },
lastDay: { type: 'string', format: 'date' },
templateId: { type: 'string', description: 'Offboarding template to use' },
},
required: ['employeeId', 'lastDay'],
},
},
}Example prompts:
- "Start offboarding for Sarah"
- "Initiate exit process for employee leaving Friday"
Document Tools
document_search
Semantic search across documents using RAG.
{
type: 'function',
function: {
name: 'document_search',
description: 'Search documents using natural language',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Natural language search query' },
category: { type: 'string', enum: ['policy', 'handbook', 'benefits', 'all'] },
limit: { type: 'number', description: 'Max results to return' },
},
required: ['query'],
},
},
}Example prompts:
- "Find the remote work policy"
- "Search for vacation policy documents"
- "What documents mention parental leave?"
document_ask
Ask questions about document content (Q&A with RAG).
{
type: 'function',
function: {
name: 'document_ask',
description: 'Ask a question and get an answer from HR documents',
parameters: {
type: 'object',
properties: {
question: { type: 'string', description: 'Question to answer' },
},
required: ['question'],
},
},
}Example prompts:
- "What's our parental leave policy?"
- "How do I submit an expense report?"
- "What are the company holidays this year?"
document_upload
Uploads a new document.
{
type: 'function',
function: {
name: 'document_upload',
description: 'Upload a new document to the system',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Document name' },
category: { type: 'string', enum: ['policy', 'handbook', 'form', 'other'] },
visibility: { type: 'string', enum: ['private', 'team', 'company'] },
tags: { type: 'array', items: { type: 'string' } },
},
required: ['name'],
},
},
}Note: File upload requires separate file picker UI.
Dashboard Tools
dashboard_metrics
Retrieves key metrics and KPIs.
{
type: 'function',
function: {
name: 'dashboard_metrics',
description: 'Get dashboard metrics and KPIs',
parameters: {
type: 'object',
properties: {
scope: { type: 'string', enum: ['company', 'department', 'team'] },
departmentId: { type: 'string' },
metrics: {
type: 'array',
items: {
type: 'string',
enum: ['headcount', 'turnover', 'time_off', 'onboarding', 'engagement'],
},
},
},
},
},
}Example prompts:
- "What's our current headcount?"
- "Show me turnover metrics"
- "Get department breakdown"
dashboard_insights
Generates AI insights from data.
{
type: 'function',
function: {
name: 'dashboard_insights',
description: 'Generate AI-powered insights from HR data',
parameters: {
type: 'object',
properties: {
focus: {
type: 'string',
enum: ['trends', 'anomalies', 'recommendations', 'all'],
},
timeRange: { type: 'string', enum: ['week', 'month', 'quarter', 'year'] },
},
},
},
}Example prompts:
- "What are the trends in time-off usage?"
- "Any unusual patterns this month?"
- "Give me HR insights for Q4"
dashboard_pending_approvals
Lists pending items requiring action.
{
type: 'function',
function: {
name: 'dashboard_pending_approvals',
description: 'Get list of pending approvals and action items',
parameters: {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['time_off', 'documents', 'workflows', 'all'],
},
},
},
},
}Example prompts:
- "What's pending my approval?"
- "Show my action items"
- "Any leave requests to approve?"
Organization Tools
org_explain
Generates narrative summary of org structure.
{
type: 'function',
function: {
name: 'org_explain',
description: 'Generate narrative summary of employee org structure',
parameters: {
type: 'object',
properties: {
employeeId: { type: 'string', description: 'Employee ID to explain' },
},
required: ['employeeId'],
},
},
}Example prompts:
- "Explain John's reporting structure"
- "Who does Sarah report to?"
- "Show me the org structure for employee #123"
org_validate
Validates org structure for issues.
{
type: 'function',
function: {
name: 'org_validate',
description: 'Validate organizational structure for issues',
parameters: {
type: 'object',
properties: {
checkCircular: { type: 'boolean', default: true },
checkOrphans: { type: 'boolean', default: true },
checkOverextended: { type: 'boolean', default: true },
maxReportsThreshold: { type: 'number', default: 15 },
},
},
},
}Example prompts:
- "Check for org structure issues"
- "Validate the organization"
- "Are there any orphaned employees?"
org_generate_structure
Generates suggested org structure from description.
{
type: 'function',
function: {
name: 'org_generate_structure',
description: 'Generate initial org structure from description',
parameters: {
type: 'object',
properties: {
description: { type: 'string', description: 'Description of company/team' },
teamSize: { type: 'number' },
style: { type: 'string', enum: ['hierarchical', 'flat', 'matrix', 'squads'] },
},
required: ['description'],
},
},
}Example prompts:
- "Suggest an org structure for a 20-person startup"
- "Generate team structure for engineering"
System Prompt Pattern
The AI Chat uses a system prompt that includes:
const systemPrompt = `
You are an HR assistant for ${tenantName}.
## Your Capabilities
You can help users with:
- Employee management (create, search, transfer, terminate)
- Time-off requests (submit, check balance, approve, view calendar)
- Workflows (create onboarding/offboarding, track progress)
- Document search (find policies, answer questions)
- Dashboard (view metrics, insights, pending approvals)
- Organization (explain structure, validate, generate)
## Rules
1. For write operations, ALWAYS show a confirmation card first
2. Respect user permissions - only show actions they can perform
3. When searching, show relevant results with links
4. For errors, explain what went wrong and suggest solutions
5. If you can't help, offer to escalate to human HR
## Context
Current user: ${userName} (${userRole})
Tenant: ${tenantName}
Date: ${currentDate}
## Available Tools
${toolDefinitions}
`Feature Registration Checklist
When adding a new feature to HRMS, ensure AI Chat integration:
1. Define AI Tool
// In packages/hrms-ai/src/tools/{feature}-tools.ts
export const FEATURE_TOOLS = [
{
type: 'function',
function: {
name: 'feature_action',
description: 'Clear description of what this does',
parameters: {
type: 'object',
properties: { /* ... */ },
required: ['requiredField'],
},
},
},
]2. Implement Tool Handler
// In packages/hrms-ai/src/handlers/{feature}-handler.ts
export async function handleFeatureAction(
params: FeatureActionParams,
context: AIContext
): Promise<ToolResult> {
// 1. Validate permissions
if (!context.user.can('feature:action')) {
return { error: 'Permission denied', code: 'FORBIDDEN' }
}
// 2. Validate input
const validated = featureSchema.parse(params)
// 3. Execute action
const result = await featureService.performAction(validated, context.tenantId)
// 4. Return result for widget
return {
success: true,
data: result,
widget: {
type: 'result',
title: 'Action Completed',
fields: [
{ label: 'Name', value: result.name },
{ label: 'ID', value: result.id },
],
link: `/features/${result.id}`,
},
}
}3. Define Chat Widgets
// Widget templates for this feature
export const FEATURE_WIDGETS = {
confirmation: {
title: 'Create Feature',
fields: ['name', 'description', 'type'],
},
progress: {
steps: ['Validating', 'Creating', 'Notifying'],
},
result: {
title: 'Feature Created',
fields: ['name', 'id', 'createdAt'],
linkTemplate: '/features/{id}',
},
error: {
messages: {
FORBIDDEN: 'You do not have permission to perform this action',
NOT_FOUND: 'The requested resource was not found',
VALIDATION: 'Please check your input and try again',
},
},
}4. Update System Prompt
Add feature context to the system prompt:
// In packages/hrms-ai/src/prompts/system.ts
export const FEATURE_CONTEXT = `
## Feature Management
You can help users create and manage features:
- Create new features with 'feature_create'
- Search features with 'feature_search'
- Update features with 'feature_update'
- Delete features with 'feature_delete'
`5. Register in Tool Registry
// In packages/hrms-ai/src/tools/registry.ts
import { FEATURE_TOOLS, handleFeatureAction } from './feature-tools'
export const TOOL_REGISTRY = {
// ... existing tools
feature_action: handleFeatureAction,
}
export const ALL_TOOLS = [
// ... existing tools
...FEATURE_TOOLS,
]6. Add Permission Checks
// Ensure feature permissions are checked
const FEATURE_PERMISSIONS = {
feature_create: 'feature:create',
feature_update: 'feature:update',
feature_delete: 'feature:delete',
feature_search: 'feature:read',
}7. Add Audit Logging
// Log all AI-initiated actions
await auditLog.create({
action: 'feature_create',
actor: context.userId,
actorType: 'ai_chat',
resource: 'feature',
resourceId: result.id,
tenantId: context.tenantId,
metadata: { params },
})Security Considerations
Permission Enforcement
- Every tool checks user permissions before execution
- Tools only return data the user has access to
- Write operations require explicit confirmation
Tenant Isolation
- All queries include
tenantIdfrom context - AI cannot access cross-tenant data
- System prompt includes tenant context
Audit Trail
- All AI Chat actions are logged
- Logs include: user, action, params, result, timestamp
- Failed attempts are also logged
Rate Limiting
- 100 requests per 15 minutes per user
- Separate limits for read vs write operations
- Progressive backoff for repeated failures
Error Messages
| Error Code | User Message | Recovery Action |
|---|---|---|
| FORBIDDEN | "You don't have permission to {action}" | Contact admin |
| NOT_FOUND | "Couldn't find {resource}" | Check ID/name |
| VALIDATION | "Please check: {details}" | Fix input |
| RATE_LIMITED | "Too many requests. Please wait." | Wait and retry |
| SERVER_ERROR | "Something went wrong" | Try again |
| CONFLICT | "{resource} already exists" | Use different name |
Tag Tools
tag_create
Creates a new tag in a category.
{
type: 'function',
function: {
name: 'tag_create',
description: 'Create a new tag in a category',
parameters: {
type: 'object',
properties: {
categoryId: { type: 'string', description: 'Tag category ID' },
name: { type: 'string', description: 'Tag name' },
color: { type: 'string', description: 'Tag color (hex)' },
description: { type: 'string', description: 'Tag description' },
},
required: ['categoryId', 'name'],
},
},
}Example prompts:
- "Create a 'Senior' tag in the skills category"
- "Add a new tag called 'Remote Worker'"
- "Create tag for Python skills"
Confirmation card fields:
- Category, Tag Name, Color, Description
tag_category_create
Creates a new tag category.
{
type: 'function',
function: {
name: 'tag_category_create',
description: 'Create a new tag category',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Category name (e.g., skills, status, department)' },
assetTypes: {
type: 'array',
items: { type: 'string', enum: ['employee', 'document', 'goal'] },
description: 'Entity types this category applies to',
},
color: { type: 'string', description: 'Default color for tags in this category (hex)' },
},
required: ['name', 'assetTypes'],
},
},
}Example prompts:
- "Create a new tag category for programming languages"
- "Add a skills category for employee tags"
- "Set up document classification tags"
tag_assign
Assigns a tag to an employee or document.
{
type: 'function',
function: {
name: 'tag_assign',
description: 'Assign a tag to an employee, document, or goal',
parameters: {
type: 'object',
properties: {
tagId: { type: 'string', description: 'Tag ID to assign' },
entityType: { type: 'string', enum: ['employee', 'document', 'goal'] },
entityId: { type: 'string', description: 'Employee, Document, or Goal ID' },
},
required: ['tagId', 'entityType', 'entityId'],
},
},
}Example prompts:
- "Tag John as a Python expert"
- "Add the 'Confidential' tag to this document"
- "Mark Sarah with the Senior Developer skill"
Confirmation card fields:
- Tag Name, Entity Type, Entity Name
tag_remove
Removes a tag from an entity.
{
type: 'function',
function: {
name: 'tag_remove',
description: 'Remove a tag from an employee, document, or goal',
parameters: {
type: 'object',
properties: {
tagId: { type: 'string', description: 'Tag ID to remove' },
entityType: { type: 'string', enum: ['employee', 'document', 'goal'] },
entityId: { type: 'string', description: 'Employee, Document, or Goal ID' },
},
required: ['tagId', 'entityType', 'entityId'],
},
},
}Example prompts:
- "Remove the 'Remote' tag from Mike"
- "Untag this document as confidential"
- "Remove the contractor tag from Sarah"
tag_search
Searches for entities by tag.
{
type: 'function',
function: {
name: 'tag_search',
description: 'Search for employees, documents, or goals by tag',
parameters: {
type: 'object',
properties: {
tagId: { type: 'string', description: 'Tag ID to search by' },
tagName: { type: 'string', description: 'Tag name to search by (alternative to tagId)' },
entityType: { type: 'string', enum: ['employee', 'document', 'goal', 'all'] },
},
required: [],
},
},
}Example prompts:
- "Find all employees tagged as Python developers"
- "Show me documents with the Policy tag"
- "Who has the Senior Engineer skill?"
Result: List of matching entities with links
tag_list
Lists all tags in a category.
{
type: 'function',
function: {
name: 'tag_list',
description: 'List all tags in a category or all categories',
parameters: {
type: 'object',
properties: {
categoryId: { type: 'string', description: 'Optional category ID to filter' },
entityType: { type: 'string', enum: ['employee', 'document', 'goal', 'all'] },
},
},
},
}Example prompts:
- "What skill tags do we have?"
- "List all document tags"
- "Show me available employee tags"
Custom Field Tools
custom_field_get
Gets custom field values for an entity.
{
type: 'function',
function: {
name: 'custom_field_get',
description: 'Get custom field values for an employee, department, team, or goal',
parameters: {
type: 'object',
properties: {
entityType: { type: 'string', enum: ['employee', 'department', 'team', 'goal'] },
entityId: { type: 'string', description: 'Entity ID' },
fieldName: { type: 'string', description: 'Specific field name (optional, omit for all fields)' },
},
required: ['entityType', 'entityId'],
},
},
}Example prompts:
- "What custom fields does John have?"
- "Get the T-shirt size for employee Sarah"
- "Show custom data for the Engineering department"
Result: Info card with custom field values
custom_field_set
Sets a custom field value for an entity.
{
type: 'function',
function: {
name: 'custom_field_set',
description: 'Set a custom field value for an employee, department, team, or goal',
parameters: {
type: 'object',
properties: {
entityType: { type: 'string', enum: ['employee', 'department', 'team', 'goal'] },
entityId: { type: 'string', description: 'Entity ID' },
fieldName: { type: 'string', description: 'Field name' },
value: { type: 'string', description: 'Field value' },
},
required: ['entityType', 'entityId', 'fieldName', 'value'],
},
},
}Example prompts:
- "Set John's T-shirt size to Large"
- "Update the cost center for Engineering to CC-5000"
- "Set Mike's employee ID to EMP-12345"
Confirmation card fields:
- Entity Name, Field Name, Old Value (if exists), New Value
custom_field_list_definitions
Lists available custom field definitions.
{
type: 'function',
function: {
name: 'custom_field_list_definitions',
description: 'List all custom field definitions for an entity type',
parameters: {
type: 'object',
properties: {
entityType: { type: 'string', enum: ['employee', 'department', 'team', 'goal', 'all'] },
},
},
},
}Example prompts:
- "What custom fields can employees have?"
- "List all custom field definitions"
- "Show me the available custom fields for departments"
Result: List of field definitions with types and validation rules
custom_field_search
Searches entities by custom field value.
{
type: 'function',
function: {
name: 'custom_field_search',
description: 'Search for entities by custom field value',
parameters: {
type: 'object',
properties: {
entityType: { type: 'string', enum: ['employee', 'department', 'team', 'goal'] },
fieldName: { type: 'string', description: 'Field name to search' },
value: { type: 'string', description: 'Value to search for' },
matchType: { type: 'string', enum: ['exact', 'contains'], default: 'contains' },
},
required: ['entityType', 'fieldName', 'value'],
},
},
}Example prompts:
- "Find all employees with T-shirt size Large"
- "Search for departments in cost center CC-5000"
- "Who has employee ID starting with EMP-1?"
Result: List of matching entities with links
Document Access Control Tools
document_share
Shares a document with specific users, teams, or departments.
{
type: 'function',
function: {
name: 'document_share',
description: 'Share a document with specific users, teams, or departments',
parameters: {
type: 'object',
properties: {
documentId: { type: 'string', description: 'Document ID' },
accessType: { type: 'string', enum: ['user', 'team', 'department', 'role'] },
targetId: { type: 'string', description: 'User/Team/Department/Role ID' },
permission: { type: 'string', enum: ['view', 'download', 'edit'], default: 'view' },
expiresAt: { type: 'string', format: 'date-time', description: 'Optional expiration date' },
},
required: ['documentId', 'accessType', 'targetId'],
},
},
}Example prompts:
- "Share this document with John"
- "Give the Engineering team access to the handbook"
- "Share the policy document with all managers"
- "Grant edit access to this file for Sarah"
Confirmation card fields:
- Document Name, Share With (target name), Permission Level, Expiration
document_revoke_access
Revokes document access from a user, team, or department.
{
type: 'function',
function: {
name: 'document_revoke_access',
description: 'Revoke document access from a user, team, or department',
parameters: {
type: 'object',
properties: {
documentId: { type: 'string', description: 'Document ID' },
accessType: { type: 'string', enum: ['user', 'team', 'department', 'role'] },
targetId: { type: 'string', description: 'User/Team/Department/Role ID' },
},
required: ['documentId', 'accessType', 'targetId'],
},
},
}Example prompts:
- "Remove John's access to this document"
- "Revoke the Engineering team's access to the handbook"
- "Stop sharing this file with the Sales department"
Confirmation card fields:
- Document Name, Remove Access From
document_visibility_set
Sets the visibility level for a document.
{
type: 'function',
function: {
name: 'document_visibility_set',
description: 'Set the visibility level for a document',
parameters: {
type: 'object',
properties: {
documentId: { type: 'string', description: 'Document ID' },
visibility: {
type: 'string',
enum: ['private', 'team', 'department', 'managers', 'company', 'custom'],
description: 'Visibility level',
},
},
required: ['documentId', 'visibility'],
},
},
}Example prompts:
- "Make this document private"
- "Set visibility to company-wide for the employee handbook"
- "Restrict this document to my team only"
- "Make this document visible to all managers"
Confirmation card fields:
- Document Name, Current Visibility, New Visibility
document_access_list
Lists who has access to a document.
{
type: 'function',
function: {
name: 'document_access_list',
description: 'List all users, teams, and departments with access to a document',
parameters: {
type: 'object',
properties: {
documentId: { type: 'string', description: 'Document ID' },
},
required: ['documentId'],
},
},
}Example prompts:
- "Who has access to this document?"
- "Show me the sharing settings for the handbook"
- "List everyone who can view this file"
Result: Info card with visibility level and access list
Dashboard Tools
dashboard_create
Creates a new dashboard.
{
type: 'function',
function: {
name: 'dashboard_create',
description: 'Create a new personal or shared dashboard',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Dashboard name' },
description: { type: 'string', description: 'Dashboard description' },
isDefault: { type: 'boolean', description: 'Set as default dashboard', default: false },
widgets: {
type: 'array',
items: {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['employee_count', 'active_requests', 'pending_approvals', 'time_off_balance',
'headcount_trend', 'department_breakdown', 'time_off_calendar',
'upcoming_birthdays', 'new_hires', 'anniversaries', 'team_activity'],
},
title: { type: 'string' },
},
},
description: 'Initial widgets to add',
},
},
required: ['name'],
},
},
}Example prompts:
- "Create a new dashboard called 'HR Overview'"
- "Set up a team dashboard with headcount and time-off widgets"
- "Make me a dashboard to track new hires"
Confirmation card fields:
- Dashboard Name, Description, Widget Count
dashboard_add_widget
Adds a widget to a dashboard.
{
type: 'function',
function: {
name: 'dashboard_add_widget',
description: 'Add a widget to a dashboard',
parameters: {
type: 'object',
properties: {
dashboardId: { type: 'string', description: 'Dashboard ID' },
widgetType: {
type: 'string',
enum: ['employee_count', 'active_requests', 'pending_approvals', 'time_off_balance',
'headcount_trend', 'department_breakdown', 'time_off_calendar', 'attendance_chart',
'upcoming_birthdays', 'new_hires', 'anniversaries', 'recent_documents',
'team_activity', 'my_tasks', 'announcements', 'quick_actions'],
},
title: { type: 'string', description: 'Custom widget title' },
config: {
type: 'object',
description: 'Widget-specific configuration',
properties: {
departmentId: { type: 'string' },
teamId: { type: 'string' },
dateRange: { type: 'string', enum: ['week', 'month', 'quarter', 'year'] },
limit: { type: 'number' },
},
},
},
required: ['dashboardId', 'widgetType'],
},
},
}Example prompts:
- "Add a headcount widget to my dashboard"
- "Put a time-off calendar on my HR dashboard"
- "Add an employee count widget for Engineering"
Confirmation card fields:
- Dashboard Name, Widget Type, Configuration
dashboard_share
Shares a dashboard with other users or teams.
{
type: 'function',
function: {
name: 'dashboard_share',
description: 'Share a dashboard with users, teams, or the whole company',
parameters: {
type: 'object',
properties: {
dashboardId: { type: 'string', description: 'Dashboard ID' },
shareType: { type: 'string', enum: ['user', 'team', 'department', 'company'] },
targetId: { type: 'string', description: 'User/Team/Department ID (not needed for company)' },
permission: { type: 'string', enum: ['view', 'edit'], default: 'view' },
},
required: ['dashboardId', 'shareType'],
},
},
}Example prompts:
- "Share my HR dashboard with the management team"
- "Give John access to view my dashboard"
- "Make this dashboard available company-wide"
Confirmation card fields:
- Dashboard Name, Share With, Permission Level
dashboard_list
Lists available dashboards for the user.
{
type: 'function',
function: {
name: 'dashboard_list',
description: 'List all dashboards available to the user',
parameters: {
type: 'object',
properties: {
includeShared: { type: 'boolean', description: 'Include dashboards shared with me', default: true },
},
},
},
}Example prompts:
- "What dashboards do I have?"
- "Show me my dashboards"
- "List available dashboards"
Result: List of dashboards with links
Tool Endpoint Alignment (MVP)
The following documents the actual HRMS API endpoints used by AI tools in Phase 09:
employee_search
- Endpoint:
GET /api/v1/employees?search={query}&limit={limit} - MVP Limitation: Only
queryandlimitparameters supported - Future (Phase 10+):
departmentId,roleId,tagsfiltering
org_explain
- Endpoint:
GET /api/v1/org/employees/{id}/summary - MVP Response: Simplified structure without roles or crossFunctionalInvolvement
- Full spec response documented in ai-integration.mdx will be expanded in Phase 10
timeoff_balance
- Tool Name:
timeoff_balance(nottimeoff_check_balance) - Endpoint:
GET /api/v1/timeoff/balances/{employeeId} - MVP Limitation: Returns array of balances per policy type
Response Shape Transformations
AI tools transform HRMS API responses to match expected tool output:
// timeoff_balance: API → Tool response transformation
{
// API returns:
data: [{ policy: { name, code }, entitled, used, pending, adjustment, carryOver }]
// Tool transforms to:
balances: [{ policyName, policyCode, entitled, used, pending, available }]
}API Endpoints Required Before Phase 09
Verify these endpoints exist from earlier phases:
| Endpoint | Source Phase | Notes |
|---|---|---|
GET /api/v1/employees | Phase 02 | Needs search query param |
GET /api/v1/org/employees/:id/summary | Phase 03 | New endpoint for org explain |
GET /api/v1/timeoff/balances/:employeeId | Phase 05 | Balance lookup |