The avatars were initials-plus-spark for the machines and bare initials for people — thin, and it made five differently-skilled agents look like the same badge in five colours. The convention that reads instantly is icons for machines, initials for people: the contrast itself tells a human step from an autonomous one before a name is read, and the symbol says WHICH machine. Each employee now wears a glyph true to its job — a magnifier for Intake (checks the lead), a speech bubble for Engage (talks to the customer), a shield for the Advisor (recommends the cover), an ID badge for KYC (verifies identity), balance scales for the Referral (prepares a file for a human to weigh). The AI spark stays at the corner. People keep their initials, which is the right avatar for a person and now the clear signal that a person, not a machine, did the step. Verified legible at disc size (20-26px) across all five brand hues. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
109 lines
4.2 KiB
JavaScript
109 lines
4.2 KiB
JavaScript
/**
|
|
* 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()
|
|
}
|