/** * The AI employees, as people the operator can recognise. * * Five agents carry this workflow and the console referred to them by their * role slug or their full title, differently in each place — "ai_engage" in one * view, "Engage" in another, "Engage AI" in a third. Someone watching a lead * move could not tell that the thing which called the customer and the thing * which wrote the quote were the same worker. * * So: one roster, one short name, one colour, one initial. Used wherever an * agent is named. `does` is written in the present tense and in the operator's * words, not the charter's — it appears on hover and in the roster strip, and * it is what makes an unfamiliar name mean something the first time. * * `tools` and `knowledge` are a MIRROR of the employee config in * aiemployee.tbl_ai_employees. The app frontend cannot read the agents schema, * so this is hand-maintained the way STAGES and ACTIONS are, and carries the * same hazard: a tool added or removed there and not here is described wrongly * in the UI, silently. * * Worth the trade, because "what can this thing actually do?" is the first * question anyone watching an agent asks — and the honest answer is short and * reassuring: four of the five hold no tools at all and work from the policy * wordings. The one tool that exists only reads a partner registry. Nothing * here can move money, and since 89 nothing here can telephone anybody. * * Keyed by the ROLE, because that is what an audit row carries. */ export const AGENTS = { ai_intake: { icon: 'inspect', short: 'Intake', full: 'Intake & Attribution', initials: 'IA', tone: 'violet', does: 'checks the lead is real, scores it, and works out whose it is', wakes: 'Once, the moment a lead is filed.', tools: [ { name: 'lookup_partner', does: 'Reads the partner registry by partner code and reports whether that POSP, broker or corporate agent is active and empanelled for this product.', }, ], knowledge: ['Products, UINs & Commission', 'SME Package (BSUS / BLUS)', 'Motor (Car Secure)'], }, ai_engage: { icon: 'chat', short: 'Engage', full: 'Engage', initials: 'EN', tone: 'blue', does: 'talks to the customer, writes up the call, and asks for what is missing', wakes: 'Most often of the five: after the call ends, after documents land, after the Advisor reports, when the premium falls due, and on every WhatsApp reply.', tools: [], knowledge: ['SME Package (BSUS / BLUS)', 'Motor (Car Secure)', 'Motor Renewal Sales Desk'], }, ai_advisor: { icon: 'shield', short: 'Advisor', full: 'Advisor', initials: 'AD', tone: 'teal', does: 'reads the captured risk and recommends the cover and add-ons', wakes: 'Once, as soon as the risk has been captured.', tools: [], knowledge: ['Products, UINs & Commission', 'SME Package (BSUS / BLUS)', 'Motor (Car Secure)', 'Motor Renewal Sales Desk'], }, ai_kyc: { icon: 'id', short: 'KYC', full: 'KYC & Evidence', initials: 'KY', tone: 'amber', does: 'verifies identity and screens the risk for underwriting', wakes: 'Twice: when the customer accepts, and again to run the underwriting screen.', tools: [], knowledge: ['Products, UINs & Commission', 'SME Package (BSUS / BLUS)', 'Motor (Car Secure)'], }, ai_uw_referral: { icon: 'scales', short: 'Referral', full: 'Underwriting Referral', initials: 'UW', tone: 'plum', does: 'prepares a referred file so a human underwriter can decide', wakes: 'Once, and only when the screen refers the risk.', tools: [], knowledge: ['Products, UINs & Commission', 'SME Package (BSUS / BLUS)', 'Motor (Car Secure)'], }, } /** The agent behind a set of roles, or null when a person did it. */ export function agentFor(roles) { if (!Array.isArray(roles)) return null const key = roles.find((r) => AGENTS[r]) return key ? { key, ...AGENTS[key] } : null } /** Initials for a person, so a human entry reads as a name too. */ export function initialsOf(name) { const parts = String(name || '').trim().split(/\s+/).filter(Boolean) if (!parts.length) return '—' return (parts[0][0] + (parts.length > 1 ? parts[parts.length - 1][0] : '')).toUpperCase() }