Bluewoo HRMS
AI Development GuideFeature Specifications

AI Integration

AI tools and RAG integration for HRMS

AI Integration

This document defines how AI is integrated into the HRMS system, including function calling tools and RAG capabilities.

Full AI Chat Specification: For the complete AI Chat system including all tools, UI widgets, and implementation patterns, see AI Chat Specification.

Overview

The HRMS AI system consists of two main components:

  1. AI Chat/Copilot - User-facing conversational interface that can execute actions
  2. RAG Pipeline - Document search and Q&A using vector embeddings

All Available AI Tools

CategoryToolsDescription
Employeeemployee_create, employee_search, employee_transfer, employee_terminate, employee_tagEmployee lifecycle management
Time-Offtimeoff_submit, timeoff_check_balance, timeoff_approve, timeoff_team_calendar, timeoff_cancelLeave management
Workflowsworkflow_create, workflow_track, workflow_complete_task, onboarding_initiate, offboarding_initiateOnboarding/offboarding
Documentsdocument_search, document_ask, document_uploadRAG-powered document Q&A
Dashboarddashboard_metrics, dashboard_insights, dashboard_pending_approvalsAnalytics and insights
Organizationorg_explain, org_validate, org_generate_structure, get_all_reports, get_reporting_chainOrg structure management

See AI Chat Specification for full tool definitions.

AI Tools for Org Structure

These are the function definitions for AI assistants to interact with organizational data:

// packages/hrms-ai/src/tools/org-tools.ts

export const ORG_AI_TOOLS = [
  {
    type: 'function',
    function: {
      name: 'org_explain',
      description: 'Generate narrative summary of employee org structure',
      parameters: {
        type: 'object',
        properties: {
          employeeId: { type: 'string' },
        },
        required: ['employeeId'],
      },
    },
  },
  {
    type: 'function',
    function: {
      name: 'org_validate',
      description: 'Validate org 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 },
        },
      },
    },
  },
  {
    type: 'function',
    function: {
      name: 'org_generate_structure',
      description: 'Generate initial org structure from description',
      parameters: {
        type: 'object',
        properties: {
          description: { type: 'string' },
          teamSize: { type: 'number' },
          style: {
            type: 'string',
            enum: ['hierarchical', 'flat', 'matrix', 'squads'],
          },
        },
        required: ['description'],
      },
    },
  },
  {
    type: 'function',
    function: {
      name: 'get_all_reports',
      description: 'Get all reports for a manager (primary + dotted + additional)',
      parameters: {
        type: 'object',
        properties: {
          managerId: { type: 'string' },
          reportType: {
            type: 'string',
            enum: ['all', 'primary', 'dotted', 'additional'],
          },
        },
        required: ['managerId'],
      },
    },
  },
  {
    type: 'function',
    function: {
      name: 'get_reporting_chain',
      description: 'Get reporting chain to top for an employee',
      parameters: {
        type: 'object',
        properties: {
          employeeId: { type: 'string' },
          includeMatrixRelations: { type: 'boolean', default: false },
        },
        required: ['employeeId'],
      },
    },
  },
]

AI.org.explain

Generate a narrative summary of an employee's organizational position:

Input

{ employeeId: string }

Output

{
  summary: string  // "John reports to Sarah (CTO) with a dotted line to..."
  directManager: { name: string, title: string }
  dottedLineManagers: [{ name: string, title: string, context: string }]
  additionalManagers: [{ name: string, title: string, context: string }]
  teams: [{ name: string, role: string }]
  departments: [{ name: string, isPrimary: boolean }]
  roles: [{ name: string, category: string }]
  directReports: number
  crossFunctionalInvolvement: string[]
}

Example Output

{
  "summary": "John Doe is a Senior Developer who reports directly to Jane Smith (Engineering Manager). He also has a dotted line relationship with the CTO for strategic technical decisions. John is a member of both the SaaS Team and Web Development Team, and belongs to the Engineering and Product departments.",
  "directManager": {
    "name": "Jane Smith",
    "title": "Engineering Manager"
  },
  "dottedLineManagers": [
    {
      "name": "Bob Johnson",
      "title": "CTO",
      "context": "Strategic technical decisions"
    }
  ],
  "teams": [
    { "name": "SaaS Team", "role": "Tech Lead" },
    { "name": "Web Development", "role": "Member" }
  ],
  "directReports": 3
}

AI.org.validate

Validate the organizational structure for common issues:

Input

{
  tenantId: string
  checkCircular?: boolean      // Detect circular relationships
  checkOrphans?: boolean       // Detect employees without managers
  checkOverextended?: boolean  // Detect managers with too many reports
  maxReportsThreshold?: number // Default: 15
}

Output

{
  valid: boolean
  issues: [{
    type: 'ORPHAN' | 'OVEREXTENDED' | 'CIRCULAR' | 'MISSING_MANAGER'
    severity: 'ERROR' | 'WARNING' | 'INFO'
    employeeId: string
    message: string
  }]
  summary: {
    total: number
    withManager: number
    orphans: number
    overextended: number
    circular: number
  }
}

AI.org.generateStructure

Generate a suggested organizational structure from a description:

Input

{
  description: string  // "We're a 20-person startup with 3 squads..."
  teamSize?: number
  style?: 'hierarchical' | 'flat' | 'matrix' | 'squads'
}

Output

{
  departments: [{ name: string, description: string }]
  teams: [{ name: string, type: string, parentTeam: string }]
  roles: [{ name: string, category: string }]
  suggestedHierarchy: {
    topLevel: [{ role: string, responsibilities: string }]
    middleLevel: [{ role: string, reportsTo: string }]
    teamLevel: [{ role: string, team: string }]
  }
}

RAG Integration

Document Processing Pipeline

  1. Upload: Document uploaded to Google Cloud Storage
  2. Extract: Text extracted from PDF/DOCX
  3. Chunk: Split into overlapping chunks (512 tokens, 50 token overlap)
  4. Embed: Generate embeddings using OpenAI text-embedding-3-small
  5. Store: Store in MongoDB Atlas Vector Search
// Chunking configuration
const CHUNK_CONFIG = {
  chunkSize: 512,
  chunkOverlap: 50,
  separators: ['\n\n', '\n', '. ', ' '],
}

Query relevant documents for AI context:

// MongoDB Atlas Vector Search
const searchResults = await collection.aggregate([
  {
    $vectorSearch: {
      index: 'vector_index',
      path: 'embedding',
      queryVector: queryEmbedding,
      numCandidates: 100,
      limit: 5,
      filter: { tenantId: currentTenantId },
    },
  },
  {
    $project: {
      text: 1,
      documentId: 1,
      score: { $meta: 'vectorSearchScore' },
    },
  },
])

AI Chat Integration

// Combine RAG results with conversation
const systemPrompt = `
You are an HR assistant for ${tenantName}.
Use the following documents to answer questions:

${ragResults.map(r => r.text).join('\n\n')}

If the information is not in the documents, say so.
`

const response = await openai.chat.completions.create({
  model: 'gpt-4-turbo-preview',
  messages: [
    { role: 'system', content: systemPrompt },
    ...conversationHistory,
    { role: 'user', content: userMessage },
  ],
  tools: ORG_AI_TOOLS,
})

AI Service Architecture

┌─────────────────────────────────────────────────┐
│                 HRMS Backend                     │
│                  (NestJS)                        │
└─────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────┐
│                 AI Service                       │
│                 (Express)                        │
│                                                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐      │
│  │   Chat   │  │   RAG    │  │   Tools  │      │
│  │ Handler  │  │ Pipeline │  │ Executor │      │
│  └──────────┘  └──────────┘  └──────────┘      │
└─────────────────────────────────────────────────┘
           │              │              │
           ▼              ▼              ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│   OpenAI     │  │   MongoDB    │  │    HRMS      │
│    API       │  │  (Vectors)   │  │  Database    │
└──────────────┘  └──────────────┘  └──────────────┘

Security Considerations

  1. Tenant Isolation: All AI queries include tenant context
  2. Permission Checks: AI tools respect user permissions
  3. Data Filtering: Only return data user has access to
  4. Audit Logging: Log all AI interactions
  5. Rate Limiting: Prevent abuse of AI endpoints
// Always include tenant context in AI calls
const response = await aiService.chat({
  message: userMessage,
  tenantId: currentTenant.id,
  userId: currentUser.id,
  permissions: currentUser.permissions,
})

Document Indexing Pipeline

When a document is uploaded via Phase 06 Document Management, it must be indexed for RAG:

Flow

Document Upload (Phase 06)

DocumentService.upload() saves to GCS

Create Document record (indexed=false)

Call AI Service: POST /ai/rag/index

AI Service extracts text, chunks, embeds

Store chunks in MongoDB with tenantId

Return vectorId

Update Document: indexed=true, vectorId=vectorId

Integration Point (Phase 06 → Phase 09)

// In DocumentService.upload() - add after GCS upload
if (document.category !== 'PRIVATE') {
  await this.aiService.indexDocument({
    sourceType: 'document',
    sourceId: document.id,
    title: document.title,
    content: extractedText,
    metadata: {
      category: document.category,
      visibility: document.visibility,
      uploadedBy: document.uploadedById,
    },
  });
}

AI Tool Access Control

All AI tools MUST enforce access control at the HRMS API level:

Tenant Isolation

  • Every tool handler receives context.tenantId
  • All HRMS API calls include x-tenant-id header
  • Vector searches filter by tenantId

Permission Enforcement

ToolPermission Check
employee_searchReturns all tenant employees (MVP: no department filtering)
org_explainRequires read access to employee
timeoff_balanceOnly own balance OR manager/HR viewing subordinate
document_searchFilter results by document visibility permissions

Implementation Pattern

async execute(params, context: ChatContext) {
  // 1. Validate user can perform this action
  if (params.employeeId !== context.employeeId) {
    const canView = await this.permissionService.canViewEmployee(
      context.userId,
      params.employeeId,
      context.tenantId,
    );
    if (!canView) throw new ForbiddenError('Cannot view this employee');
  }

  // 2. Make API call with tenant context
  const response = await fetch(endpoint, {
    headers: {
      'x-tenant-id': context.tenantId,
      'Authorization': `Bearer ${context.token}`,
    },
  });

  // 3. Filter results by user permissions if needed
  return this.filterByPermissions(response.data, context);
}

Technical Implementation Notes

MongoDB ID Handling

  • Use HRMS CUID strings as document IDs in vector store
  • Store documentId field matching HRMS Document.id
  • Avoid MongoDB auto-generated ObjectIDs for cross-database joins

API Path Conventions

ToolEndpointPhase
employee_searchGET /api/v1/employeesPhase 02
org_explainGET /api/v1/org/employees/:id/summaryPhase 03
timeoff_balanceGET /api/v1/timeoff/balances/:employeeIdPhase 05
document_searchPOST /ai/rag/queryPhase 09

Service-to-Service Authentication

  • AI Service uses x-service-secret header for HRMS API calls
  • HRMS validates via ServiceSecretGuard (Phase 09, Step 147)
  • Secret stored in environment variable AI_SERVICE_SECRET

Future Enhancements (Phase 10+)

  • SSE streaming for real-time chat responses
  • Redis caching for frequent tool queries
  • Extended employee_search with department/tag filtering
  • Full org_explain response with roles and cross-functional data