Visual map — Ch.14 · AI — after core works
Now Assist / VA / Agent Studio / Control Tower
Optional layer
Development
Full visual path (all chapters): VISUAL_FROM_SCRATCH_00_16.html
Studio-only for core app: Create chapters 01 through 12 first. AI configuration uses ServiceNow platform UI (Now Assist, AI Agent Studio, Virtual Agent).
Also open: Properties + Direct Links · Schema · Studio Create All Objects · Previous: 13 Summary
Prerequisite: All tables, BR, Flow, and ACLs must exist on the instance before enabling AI features.
How AI features relate to HR Leave
Core app (ch.01–12) — tables, BR, Flow, ACLs
│
▼
Platform AI (this chapter) — Now Assist, Agents, VA, Search
│
▼
Optional: HR Leave skills/topics referencing req_v2 / bal_v2 data
AI layers sit on top of the scoped app — they do not replace Studio create steps in chapters 01–12.
Rule 0 — Before any object (Application + Update Set + Studio)
Repeat these checks before creating or editing any application file. This section is also section 00 Update Set — create the capture set first.
- Application picker — top-right globe / application menu → select HR Leave (
x_786686_hr_leave). Never leave Global selected when creating scoped artifacts. - Update Set — All → System Update Sets → Local Update Sets → New:
After submit: open the record → click Make Current. Direct list: {BASE}/sys_update_set_list.doField Value Name HR Leave – BuildApplication HR Leave State In Progress Description Captures all HR Leave lab artifacts - Open Studio — {BASE}/$studio.do → confirm header shows HR Leave.
If artifacts land in Global scope, delete them and recreate under HR Leave. ACLs and events created globally will not behave correctly for this app.
Verify Update Set: Create a test Script Include in Studio → open HR Leave – Build → Related List Customer Updates shows the new file.
Deep-dive sections below — original AI implementation guide content.
14 — AI in ServiceNow + Agents — Complete Implementation Guide
اقرأ أولاً (ملخص سريع): MASTER_ALL_IN_ONE_SUMMARY.md · HTML: html/MASTER_ALL_IN_ONE_SUMMARY.html
الدليل الشامل الواحد: MASTER_ALL_IN_ONE.md · HTML: html/MASTER_ALL_IN_ONE.html
ممارسة الشاشات (New/Open): MASTER_PRACTICE_GUIDE_ALL_TOPICS.md · html/MASTER_PRACTICE_GUIDE_ALL_TOPICS.html
Platform: ServiceNow Australia · Scopex_786686_hr_leave· sys_ide5f5bc9493a303507520703efaba104d
دليل الذكاء الاصطناعي والوكلاء — تنفيذ كامل من الصفر إلى الإنتاج
Platform: ServiceNow Australia (September 2026) · Next EA: Brazil
App: Custom · Scope:x_786686_hr_leave· sys_id:e5f5bc9493a303507520703efaba104d
Tables:x_786686_hr_leave_employee_v2,x_786686_hr_leave_req_v2,x_786686_hr_leave_bal_v2,x_786686_hr_leave_audit_v2
URL pattern:{BASE}=https://YOUR_INSTANCE.service-now.com
Table of Contents
- What You Will Build
- Direct Navigation URLs
- Part 0 — Quick Map & Prerequisites
- Part 1 — Plugin Activation & Roles
- Part 2 — Now Assist Studio (Skills)
- Part 3 — AI Agent Studio
- Part 4 — BYO LLM (Claude / GPT)
- Part 5 — AI Search + GenAI Search
- Part 6 — Predictive Intelligence
- Part 7 — Virtual Agent + NLU (Full Topics & Flows)
- Part 8 — Document Intelligence (IDP)
- Part 9 — Workflow Studio AI Actions
- Part 10 — Now Assist for Developers
- Part 11 — End-to-End HR Leave AI Example
- Part 12 — AI Governance & Safety
- Part 13 — Performance & Cost Optimization
- Part 14 — Hands-On Labs (5 Sessions)
- Part 15 — Best Practices
- Part 16 — Production Deployment Checklist
- Appendices
🎯 What You Will Build — ماذا ستبني
By the end of this guide you will have deployed a complete AI layer on the HR Leave scoped app:
- ✅ 6 Now Assist Skills (summarize, classify, suggest dates, history summary, sentiment, email draft)
- ✅ 1 AI Agent — HR Leave Assistant with 6 tools wired to
HRLXAIAgentTools - ✅ 1 AI Search profile —
hrlx_kb_profilewith GenAI answers + masked sensitive fields - ✅ 2 Predictive Intelligence solutions — approval prediction + duration regression
- ✅ 1 NLU model —
hrlx_leave_nluwith 8 intents and 200+ utterances - ✅ 8 Virtual Agent topics — balance, request, cancel, policy, status, handoff, greeting, fallback
- ✅ 1 IDP template — medical certificate extraction wired to sick-leave flow
- ✅ 3 Flow Designer AI Actions — summarize history, classify type, draft manager email
- ✅ Governance — AI policies, PII redaction, audit to
x_786686_hr_leave_audit_v2 - ✅ Monitoring dashboard — skill latency, agent containment, PI drift, search zero-results
Style in this doc: English instruction line → Arabic explanation on its own line where helpful. All code in fenced blocks.
📍 Direct Navigation URLs — روابط التنقل المباشرة
Replace {BASE} with your instance URL (e.g. https://dev12345.service-now.com).
Now Assist & AI Agents
| Tool | Navigation Path | Direct URL | Purpose |
|---|---|---|---|
| Now Assist Admin | All > Now Assist > Now Assist Admin | {BASE}/now/assist/admin | Skill setup wizard |
| Now Assist Studio | App Picker > Now Assist Studio | {BASE}/now/assist/studio | Create/edit skills |
| Now Assist Skills | Now Assist Admin > Skills | {BASE}/sys_one_extend_skill_list.do | Skill records |
| Prompt Templates | (Skill) Templates related list | {BASE}/sys_one_extend_prompt_template_list.do | Versioned prompts |
| Skill Audit Log | Now Assist Admin > Audit | {BASE}/sys_one_extend_audit_list.do | Execution telemetry |
| AI Agent Studio | All > AI Agent Studio | {BASE}/now/aia/studio | Build agents + tools |
| AI Agents | AI Agent Studio > Agents | {BASE}/sn_aia_agent_list.do | Agent definitions |
| AI Tools | AI Agent Studio > Tools | {BASE}/sn_aia_tool_list.do | Callable tools |
| Agent Executions | AI Agent Studio > Executions | {BASE}/sn_aia_execution_list.do | Run history |
| LLM Provider Config | Now Assist Admin > LLM Providers | {BASE}/sys_one_extend_provider_config_list.do | BYO LLM setup |
| AI Policy Center | All > AI Governance > AI Policy Center | {BASE}/now/ai/policy | Policies & rules |
AI Search
| Tool | Navigation Path | Direct URL | Purpose |
|---|---|---|---|
| AI Search Admin | All > AI Search > Admin | {BASE}/now/ais/admin | Search admin home |
| Search Sources | AI Search Admin > Sources | {BASE}/ais_search_source_list.do | Index sources |
| Search Profiles | AI Search Admin > Profiles | {BASE}/ais_search_profile_list.do | Profile config |
| Search Applications | AI Search Admin > Applications | {BASE}/ais_search_application_list.do | Portal/Workspace UI |
| Query Log | AI Search Admin > Analytics | {BASE}/sys_aisearch_query_log_list.do | Zero-result analysis |
| GenAI Search Log | AI Search Admin > GenAI Log | {BASE}/sys_aisearch_genai_log_list.do | RAG answers |
Predictive Intelligence
| Tool | Navigation Path | Direct URL | Purpose |
|---|---|---|---|
| Solution Definitions | All > Predictive Intelligence > Solution Definitions | {BASE}/ml_solution_definition_list.do | Define ML problem |
| Solutions | All > Predictive Intelligence > Solutions | {BASE}/ml_solution_list.do | Trained models |
| Solution Monitor | All > Predictive Intelligence > Solution Monitor | {BASE}/ml_solution_monitor_list.do | Drift & accuracy |
| Training Dataset | (Solution) Training Dataset | {BASE}/ml_capability_definition_base_list.do | Feature mapping |
Virtual Agent & NLU
| Tool | Navigation Path | Direct URL | Purpose |
|---|---|---|---|
| Virtual Agent Designer | All > Virtual Agent > Designer | {BASE}/now/virtual-agent/designer | Topic builder |
| Topics | Virtual Agent > Topics | {BASE}/sys_cs_topic_list.do | Topic records |
| Conversations | Virtual Agent > Conversations | {BASE}/sys_cs_conversation_list.do | Chat logs |
| NLU Workbench | All > NLU > Workbench | {BASE}/now/nlu/workbench | Intent/entity models |
| NLU Models | NLU > Models | {BASE}/nlu_model_list.do | Model list |
| NLU Intents | (Model) Intents | {BASE}/nlu_intent_list.do | Intent definitions |
| Employee Center | Direct | {BASE}/esc | Test VA in prod-like UI |
| Service Portal | Direct | {BASE}/sp?id=chat | Portal chat widget |
Document Intelligence
| Tool | Navigation Path | Direct URL | Purpose |
|---|---|---|---|
| IDP Admin | All > Document Intelligence | {BASE}/now/idp/admin | IDP home |
| Templates | IDP Admin > Templates | {BASE}/sn_idp_template_list.do | Document templates |
| Extraction Models | IDP Admin > Models | {BASE}/sn_idp_model_list.do | Trained extractors |
| Extraction Results | IDP Admin > Results | {BASE}/sn_idp_extraction_result_list.do | Run output |
HR Leave App Tables (Grounding & Tools)
| Table | Direct URL | Key Fields for AI |
|---|---|---|
| Leave Request | {BASE}/x_786686_hr_leave_req_v2_list.do | u_leave_type, u_state, u_reason, u_days_count |
| Employee | {BASE}/x_786686_hr_leave_employee_v2_list.do | u_employee_id, user reference |
| Balance | {BASE}/x_786686_hr_leave_bal_v2_list.do | u_leave_type, u_remaining_days |
| Audit | {BASE}/x_786686_hr_leave_audit_v2_list.do | u_action, u_payload |
| Knowledge (policy) | {BASE}/kb_knowledge_list.do?sysparm_query=topic=HR Leave | text, short_description |
Development & Deployment
| Tool | Direct URL |
|---|---|
| Studio | {BASE}/$studio.do |
| Script Includes | {BASE}/sys_script_include_list.do?sysparm_query=sys_scope.scope=x_786686_hr_leave |
| Business Rules | {BASE}/sys_script_list.do?sysparm_query=sys_scope.scope=x_786686_hr_leave |
| Flow Designer | {BASE}/now/flow-designer |
| Update Sets | {BASE}/sys_update_set_list.do |
| Background Scripts | {BASE}/sys.scripts.do |
| System Properties | {BASE}/sys_properties_list.do?sysparm_query=nameSTARTSWITHx_786686_hr_leave |
| Plugins | {BASE}/v_plugin_list.do |
Part 0 — Quick Map & Prerequisites
0.1 Decision matrix — which AI tool when?
| User need | Best tool | Why | Section |
|---|---|---|---|
| One-click summary on form | Now Assist Skill | Deterministic, cheap, fast | §2 |
| “How many days left?” in chat | Virtual Agent topic OR AI Agent tool | VA = predictable; Agent = flexible | §3, §7 |
| Open-ended policy Q&A | AI Search GenAI + Agent | RAG with citations | §3, §5 |
| Predict if manager approves in 24h | Predictive Intelligence | Classical ML on history | §6 |
| Extract fields from medical PDF | Document Intelligence | Structured extraction | §8 |
| Multi-step: check balance → request → confirm | AI Agent Studio | Plans + tools + memory | §3 |
| Classify free-text leave reason | Now Assist Skill OR PI | Skill = LLM; PI = ML on features | §2, §6 |
| Code a Business Rule faster | Now Assist for Developers | In-Studio codegen | §10 |
ابدأ بـ Skill للمهام أحادية الخطوة. انتقل إلى Agent عندما يحتاج المستخدم محادثة متعددة الخطوات مع أدوات.
0.2 Prerequisites checklist
Before starting any AI work:
[ ] HR Leave v2 tables exist and have ≥ 50 test leave requests
[ ] Roles assigned: x_786686_hr_leave.employee, .manager, .hr_admin
[ ] Update Set created: "HR Leave AI v1.0"
[ ] Application picker set to HR Leave (x_786686_hr_leave) in Studio
[ ] At least 5 KB articles tagged topic=HR Leave (for AI Search)
[ ] Integration user NOT used for AI testing — use real employee personas
[ ] Instance has outbound HTTPS to LLM APIs (if BYO) — check ACL network rules
[ ] Admin access to activate plugins (requires admin role)
0.3 Verify app scope (Background Script)
var app = new GlideRecord('sys_app');
app.addQuery('scope', 'x_786686_hr_leave');
app.query();
if (app.next()) {
gs.info('App: ' + app.name + ' | sys_id: ' + app.sys_id);
} else {
gs.error('HR Leave app not found — create via 01_DEVELOPMENT.md first');
}
var tables = ['x_786686_hr_leave_req_v2', 'x_786686_hr_leave_bal_v2',
'x_786686_hr_leave_employee_v2', 'x_786686_hr_leave_audit_v2'];
tables.forEach(function (t) {
var gr = new GlideRecord(t);
gs.info(t + ' exists: ' + gr.isValid());
});
Part 1 — Plugin Activation & Roles
Step 1.1: Activate required plugins
Navigation: All > System Definition > Plugins — Open direct
Direct URL: {BASE}/v_plugin_list.do
| # | Plugin name (search) | Plugin ID (typical) | Required for |
|---|---|---|---|
| 1 | Now Assist for HRSD | com.snc.now_assist.hrsd | HR skills pack |
| 2 | Now Assist Platform | com.snc.now_assist.platform | Core GenAI |
| 3 | AI Agents | com.snc.ai_agents | Agent Studio |
| 4 | AI Search | com.snc.ai_search | Modern search + RAG |
| 5 | Predictive Intelligence | com.glide.platform_ml | ML solutions |
| 6 | Document Intelligence | com.snc.document_intelligence | IDP |
| 7 | Virtual Agent | com.glide.cs.chatbot | Chatbot topics |
| 8 | NLU Workbench | com.snc.nlu_workbench | Intent models |
| 9 | Now Assist for Creator | com.snc.now_assist.creator | Dev codegen (optional) |
Detailed activation steps:
1. Open {BASE}/v_plugin_list.do
2. Filter: Name contains "Now Assist" OR "AI Search" OR "Virtual Agent"
3. For each plugin in the table above:
a. Click the plugin name
b. Click "Activate" (or "Install" on some instances)
c. UNCHECK "Load demo data" in production-like sub-prod
d. Wait for activation (may take 2–10 minutes)
e. Note any dependent plugins auto-activated
4. After all activations: logout and login (refresh session roles)
5. Open Now Assist Setup wizard: {BASE}/now/assist/admin
6. Accept terms → select data region → Enable HRSD skill pack
7. Verify: All > Now Assist > Now Assist Admin shows "Configured"
Step 1.2: Assign AI admin roles
Navigation: All > User Administration > Users — Open direct
Direct URL: {BASE}/sys_user_list.do
| Role | Assign to | Purpose |
|---|---|---|
sn_nowassist_admin |
AI lead developer | Skills, providers |
sn_aia.admin |
AI lead developer | Agent Studio |
ai_search_admin |
Search admin | AI Search profiles |
ml_admin |
Data/ML owner | Train PI solutions |
nlu_admin |
Chatbot owner | NLU models |
sn_idp.admin |
Doc processing owner | IDP templates |
x_786686_hr_leave.hr_admin |
HR team | Use AI on records |
x_786686_hr_leave.manager |
Managers | Summarize UI Action |
Step 1.3: Create system properties (AI config)
Navigation: All > System Properties — Open direct
Direct URL: {BASE}/sys_properties_list.do
Create these properties in scope x_786686_hr_leave:
| Name | Type | Default | Description |
|---|---|---|---|
x_786686_hr_leave.ai.enabled |
true/false | true | Master kill switch |
x_786686_hr_leave.llm.daily_budget_usd |
string | 10 | Daily spend cap |
x_786686_hr_leave.llm.timeout_ms |
string | 15000 | REST timeout |
x_786686_hr_leave.llm.anthropic.api_key |
password2 | (empty) | Claude key |
x_786686_hr_leave.llm.anthropic.model |
string | claude-sonnet-4-5 | Model id |
x_786686_hr_leave.llm.openai.api_key |
password2 | (empty) | OpenAI key |
x_786686_hr_leave.llm.openai.model |
string | gpt-4o-mini | Model id |
x_786686_hr_leave.ai_search.profile |
string | hrlx_kb_profile | Default profile |
x_786686_hr_leave.nlu.model |
string | hrlx_leave_nlu | NLU model name |
x_786686_hr_leave.idp.template |
string | hrlx_medical_cert | IDP template |
x_786686_hr_leave.va.bot_name |
string | HR Leave Bot | Display name |
Verification script:
var props = ['ai.enabled', 'llm.daily_budget_usd', 'ai_search.profile'];
props.forEach(function (p) {
var v = gs.getProperty('x_786686_hr_leave.' + p, 'NOT SET');
gs.info('x_786686_hr_leave.' + p + ' = ' + v);
});
Part 2 — Now Assist Studio (Skills)
2.1 Architecture overview
| Object | Table | Purpose |
|---|---|---|
| Skill | sys_one_extend_skill | One GenAI capability |
| Prompt template | sys_one_extend_prompt_template | Versioned prompt text |
| Activation | sys_one_extend_activation | Where skill is enabled |
| Audit | sys_one_extend_audit | Every execution logged |
Step 2.1: Open Now Assist Studio
1. App picker (top-left) → select "HR Leave" scope
2. Click "Skills" in left nav
3. Click "New" → "Create Skill"
4. Confirm Application = x_786686_hr_leave on every record
Step 2.2: Skill 1 — hrlx_summarize_reason
| Field | Value |
|---|---|
| Name | hrlx_summarize_reason |
| Label | Summarize Leave Reason |
| Type | Summarization |
| Application | HR Leave |
| LLM | Now LLM Service (change to BYO in §4) |
| Max tokens | 120 |
| Temperature | 0.2 |
| PII redaction | ON |
Prompt template (SYSTEM + USER):
SYSTEM:
You are an HR assistant for a multinational company. Summarize the employee's
leave reason in ONE sentence, maximum 25 words, neutral professional tone.
Do NOT include medical diagnoses, medication names, or sensitive health details.
If reason is empty, return exactly: "No reason provided."
Respond in the same language as the reason text (English or Arabic).
USER:
Employee: {{employee_name}}
Leave type: {{u_leave_type}}
Start: {{u_start_date}} | End: {{u_end_date}} | Days: {{u_days_count}}
Reason:
"""
{{u_reason}}
"""
Variable mapping:
| Variable | Source field on x_786686_hr_leave_req_v2 |
|---|---|
| employee_name | u_requested_for_user (display) |
| u_leave_type | u_leave_type |
| u_start_date | u_start_date |
| u_end_date | u_end_date |
| u_days_count | u_days_count |
| u_reason | u_reason |
Grounding config:
1. Skill > Grounding tab > Enable
2. Table: x_786686_hr_leave_req_v2
3. Key: sys_id
4. Map each {{variable}} to column above
5. Save
Test in Playground (5 samples):
| # | u_reason input | Expected output quality |
|---|---|---|
| 1 | “Family wedding in Dubai, need 4 days travel” | Mentions wedding/travel, no PII |
| 2 | “Flu — doctor advised rest” | Generic “medical rest”, no diagnosis |
| 3 | (empty) | “No reason provided.” |
| 4 | Arabic: “إجازة أمومة” | Arabic one-liner |
| 5 | 500-word essay | ≤ 25 words |
Playground steps:
1. Skills > hrlx_summarize_reason > Test
2. Paste sys_id of test request OR fill variables manually
3. Run → check latency (target ≤ 2s)
4. If bad output → edit prompt → Save as version 1.1
5. Repeat until 90%+ acceptable on 20 samples
6. Status → Active
Step 2.3: Skill 2 — hrlx_classify_leave_type
| Field | Value |
|---|---|
| Name | hrlx_classify_leave_type |
| Type | Classification |
| Output validation | Regex: ^(annual\|sick\|parental\|unpaid)$ |
SYSTEM:
Classify the leave request text into EXACTLY ONE label:
annual, sick, parental, unpaid
Return ONLY the label, lowercase, no punctuation or explanation.
USER:
Leave type already selected (may be wrong): {{u_leave_type}}
Employee reason: {{u_reason}}
Additional notes: {{u_notes}}
Wire to Business Rule (before insert/update when u_leave_type empty):
(function executeRule(current, previous) {
if (!gs.getProperty('x_786686_hr_leave.ai.enabled', 'true') === 'true') return;
if (current.u_leave_type) return;
if (!current.u_reason) return;
try {
var ext = new sn_one_extend.OneExtendUtil();
var res = ext.execute({
executionRequests: [{
capabilityId: 'hrlx_classify_leave_type',
payload: {
u_leave_type: String(current.u_leave_type),
u_reason: String(current.u_reason),
u_notes: String(current.u_notes || '')
}
}]
});
var label = (res.capabilities[0] || {}).response;
if (/^(annual|sick|parental|unpaid)$/.test(label))
current.u_leave_type = label;
} catch (e) {
gs.warn('hrlx_classify_leave_type failed: ' + e);
}
})(current, previous);
Step 2.4: Skill 3 — hrlx_suggest_dates
| Field | Value |
|---|---|
| Name | hrlx_suggest_dates |
| Type | Generic / Structured output |
| Output schema | JSON Schema (see §12) |
SYSTEM:
Suggest adjusted leave dates avoiding public holidays.
Return ONLY valid JSON:
{"start":"YYYY-MM-DD","end":"YYYY-MM-DD","notes":"..."}
No markdown fences.
USER:
Country: {{u_country}}
Requested start: {{u_start_date}}
Requested end: {{u_end_date}}
Leave type: {{u_leave_type}}
Public holidays next 90 days:
{{holidays_json}}
Pre-step Script Include to build holidays_json:
var HRLXHolidayUtil = Class.create();
HRLXHolidayUtil.prototype = {
initialize: function() {},
getHolidaysJson: function(country, days) {
// Replace with your holiday table or IntegrationHub spoke
var out = [];
var gr = new GlideRecord('sn_hr_core_federal_holiday'); // if HRSD installed
if (gr.isValid()) {
gr.addQuery('country', country);
gr.addQuery('date', '>=', new GlideDate());
gr.setLimit(days || 90);
gr.query();
while (gr.next()) {
out.push({ date: String(gr.date), name: String(gr.name) });
}
}
return JSON.stringify(out);
},
type: 'HRLXHolidayUtil'
};
Step 2.5: Skill 4 — hrlx_summarize_history
Summarizes last N leave requests for a manager email.
SYSTEM:
Summarize this employee's leave history for a manager briefing.
Max 150 words. Bullet format. Include totals by type. Neutral tone.
USER:
Employee: {{employee_name}}
Lookback days: {{lookback_days}}
History records:
{{history_text}}
Step 2.6: Skill 5 — hrlx_detect_sentiment
SYSTEM:
Classify employee leave reason sentiment: positive, neutral, frustrated, urgent.
Return ONLY the label.
USER:
Reason: {{u_reason}}
Use output to route frustrated → human HR in Flow Designer.
Step 2.7: Skill 6 — hrlx_draft_manager_email
SYSTEM:
Draft a short email from HR system to employee about their leave request.
Professional, empathetic. Max 120 words. Include request number and dates.
Do not invent approval status — use {{u_state}} exactly.
USER:
Employee name: {{employee_name}}
Request: {{u_number}}
Type: {{u_leave_type}}
Dates: {{u_start_date}} to {{u_end_date}}
State: {{u_state}}
Manager note: {{manager_comment}}
Step 2.8: Activate skills per channel
URL: {BASE}/sys_one_extend_activation_list.do
For each skill create activation:
| Skill | Channels enabled |
|---|---|
| hrlx_summarize_reason | Workspace, UI Action, Flow Designer |
| hrlx_classify_leave_type | Business Rule (server), Flow Designer |
| hrlx_suggest_dates | Service Portal widget |
| hrlx_summarize_history | Flow Designer |
| hrlx_detect_sentiment | Flow Designer |
| hrlx_draft_manager_email | Workspace |
Step 2.9: UI Action — Summarize on form
URL: {BASE}/sys_ui_action_list.do
| Field | Value |
|---|---|
| Name | Summarize reason (AI) |
| Table | x_786686_hr_leave_req_v2 |
| Condition | current.u_state != 'cancelled' && gs.hasRole('x_786686_hr_leave.manager') |
| Form button | true |
| Client | false (server-side) |
(function executeAction(current) {
var ext = new sn_one_extend.OneExtendUtil();
var res = ext.execute({
executionRequests: [{
capabilityId: 'hrlx_summarize_reason',
payload: { record: current.getUniqueValue() }
}]
});
var summary = (res.capabilities[0] || {}).response || 'No summary';
gs.addInfoMessage('AI Summary: ' + summary);
})(current);
Part 3 — AI Agent Studio
3.1 What AI Agent Studio provides
AI Agent Studio builds agentic assistants: an LLM that plans steps, selects tools, executes them, observes results, and responds — across multiple conversation turns.
| Table | Purpose |
|---|---|
| sn_aia_agent | Agent definition + system prompt |
| sn_aia_tool | Callable action (Script Include, Flow, AI Search) |
| sn_aia_team | Multi-agent routing |
| sn_aia_trigger | Chat, email, record, schedule triggers |
| sn_aia_execution | One run (tokens, latency, cost) |
| sn_aia_execution_step | Each tool invocation |
| sn_aia_audit | Compliance-grade immutable log |
Direct URL: {BASE}/now/aia/studio
Step 3.1: Create Script Include HRLXAIAgentTools
URL: {BASE}/sys_script_include_list.do
Application: HR Leave
| Field | Value |
|---|---|
| Name | HRLXAIAgentTools |
| Client callable | false |
| Accessible from | This application scope only |
var HRLXAIAgentTools = Class.create();
HRLXAIAgentTools.prototype = {
initialize: function() {
this.SCOPE = 'x_786686_hr_leave';
this.T_EMP = 'x_786686_hr_leave_employee_v2';
this.T_REQ = 'x_786686_hr_leave_req_v2';
this.T_BAL = 'x_786686_hr_leave_bal_v2';
this.T_AUD = 'x_786686_hr_leave_audit_v2';
},
_getEmployeeByUser: function(userId) {
var gr = new GlideRecord(this.T_EMP);
gr.addQuery('user', userId);
gr.setLimit(1);
gr.query();
return gr.next() ? gr : null;
},
getBalance: function(userId) {
var emp = this._getEmployeeByUser(userId);
if (!emp) return { error: 'employee_not_found' };
var out = { annual: 0, sick: 0, parental: 0, unpaid: 0 };
var bal = new GlideRecord(this.T_BAL);
bal.addQuery('u_employee_ref', emp.getUniqueValue());
bal.query();
while (bal.next()) {
var t = String(bal.u_leave_type);
if (out.hasOwnProperty(t)) out[t] = Number(bal.u_remaining_days) || 0;
}
return out;
},
requestLeave: function(payload) {
try {
if (gs.getProperty(this.SCOPE + '.ai.enabled', 'true') !== 'true')
return { ok: false, error: 'ai_disabled' };
var emp = this._getEmployeeByUser(payload.user_id);
if (!emp) return { ok: false, error: 'employee_not_found' };
var start = new GlideDateTime(payload.start_date);
var end = new GlideDateTime(payload.end_date);
if (start.compareTo(end) > 0)
return { ok: false, error: 'start_after_end' };
var bal = this.getBalance(payload.user_id);
var days = Math.ceil((end.getNumericValue() - start.getNumericValue()) / 86400000) + 1;
if ((bal[payload.type] || 0) < days)
return { ok: false, error: 'insufficient_balance', needed: days, available: bal[payload.type] || 0 };
var req = new GlideRecord(this.T_REQ);
req.initialize();
req.u_requested_for_user = payload.user_id;
req.u_employee_ref = emp.getUniqueValue();
req.u_leave_type = payload.type;
req.u_start_date = payload.start_date;
req.u_end_date = payload.end_date;
req.u_reason = payload.reason || '';
req.u_state = 'submitted';
req.u_source = 'ai_agent';
var sysId = req.insert();
this._audit('ai_request_leave', sysId, payload);
return { ok: true, request_id: sysId, number: req.getValue('u_number') };
} catch (e) {
gs.error('HRLXAIAgentTools.requestLeave: ' + e);
return { ok: false, error: 'exception' };
}
},
checkPolicy: function(question) {
var profile = gs.getProperty(this.SCOPE + '.ai_search.profile', 'hrlx_kb_profile');
try {
var sn = new sn_ais.AISearch();
var results = sn.search(profile, question, { limit: 5, genai: true });
return {
answer: results.genai_answer || '',
citations: results.citations || []
};
} catch (e) {
return { answer: '', citations: [], error: String(e) };
}
},
escalate: function(userId, summary) {
var emp = this._getEmployeeByUser(userId);
if (!emp) return { ok: false, error: 'employee_not_found' };
var hr = new GlideRecord('sn_hr_core_case');
if (!hr.isValid()) {
// Fallback: create audit + notify
this._audit('ai_escalate_no_hrsd', userId, { summary: summary });
return { ok: true, case_id: null, note: 'HRSD not installed — audit only' };
}
hr.initialize();
hr.opened_for = userId;
hr.short_description = 'AI escalation: ' + (summary || '').substring(0, 80);
hr.description = summary;
hr.subject_person = userId;
var sysId = hr.insert();
this._audit('ai_escalate', sysId, { summary: summary });
return { ok: true, case_id: sysId };
},
getMyRequests: function(userId, days) {
var emp = this._getEmployeeByUser(userId);
if (!emp) return [];
var since = new GlideDateTime();
since.addDaysLocalTime(-1 * (days || 90));
var gr = new GlideRecord(this.T_REQ);
gr.addQuery('u_employee_ref', emp.getUniqueValue());
gr.addQuery('sys_created_on', '>=', since);
gr.orderByDesc('sys_created_on');
gr.query();
var out = [];
while (gr.next()) {
out.push({
id: gr.getUniqueValue(),
number: String(gr.u_number),
type: String(gr.u_leave_type),
start: String(gr.u_start_date),
end: String(gr.u_end_date),
state: String(gr.u_state)
});
}
return out;
},
cancelRequest: function(userId, requestId) {
var gr = new GlideRecord(this.T_REQ);
if (!gr.get(requestId)) return { ok: false, error: 'not_found' };
if (gr.u_requested_for_user != userId) return { ok: false, error: 'not_owner' };
if (gr.u_state != 'submitted') return { ok: false, error: 'not_cancellable' };
gr.u_state = 'cancelled';
gr.update();
this._audit('ai_cancel_request', requestId, { user: userId });
return { ok: true };
},
_audit: function(action, recordId, payload) {
var a = new GlideRecord(this.T_AUD);
a.initialize();
a.u_action = action;
a.u_record = recordId;
a.u_payload = JSON.stringify(payload || {});
a.u_actor = gs.getUserID();
a.u_source = 'ai_agent';
a.insert();
},
type: 'HRLXAIAgentTools'
};
Step 3.2: Define tools in AI Agent Studio
URL: {BASE}/sn_aia_tool_list.do
Tool 1 — GetMyBalance
| Field | Value |
|---|---|
| Name | GetMyBalance |
| Description | Returns current user’s leave balance by type (annual, sick, parental, unpaid) |
| Implementation | Script Include |
| Script Include | HRLXAIAgentTools |
| Method | getBalance |
| Input | user_id (string) — auto-map from session |
| Output | JSON object with balances |
Tool 2 — RequestLeave
| Input field | Type | Required |
|---|---|---|
| user_id | string | yes |
| type | string (enum) | yes |
| start_date | date (YYYY-MM-DD) | yes |
| end_date | date (YYYY-MM-DD) | yes |
| reason | string | no |
Confirmation gate: Enable “Require user confirmation” for this tool in Agent Studio.
Tool 3 — CheckPolicy
| Field | Value |
|---|---|
| Implementation | AI Search Profile OR Script |
| Profile | hrlx_kb_profile |
| Input | question (string) |
Tool 4 — GetMyRequests
| Method | getMyRequests |
| Input | user_id, days (default 90) |
Tool 5 — CancelRequest
| Method | cancelRequest |
| Input | user_id, request_id |
Tool 6 — EscalateToHR
| Method | escalate |
| Input | user_id, summary |
Step 3.3: Create agent “HR Leave Assistant”
URL: {BASE}/sn_aia_agent_list.do
| Field | Value |
|---|---|
| Name | HR Leave Assistant |
| Application | x_786686_hr_leave |
| Model | now-llm-pro-v1 |
| LLM Provider | Now LLM Service |
| Status | Draft → Active |
System prompt:
You are "HR Leave Assistant" for employees of this company.
CAPABILITIES (use tools):
- GetMyBalance: show remaining leave days
- RequestLeave: submit a new request (ALWAYS confirm dates/type first)
- CheckPolicy: answer policy questions from official KB (cite sources)
- GetMyRequests: list recent requests
- CancelRequest: cancel a submitted request owned by the user
- EscalateToHR: create HR case when user is frustrated or issue is complex
RULES:
1. Identity comes from session — never ask for employee ID number.
2. NEVER reveal another employee's data.
3. Out of scope → "I can only help with leave. Contact HR at hr@company.com."
4. Match user language (English or Arabic).
5. Before RequestLeave: summarize dates, type, days count, ask "Shall I submit?"
6. If tool returns error insufficient_balance, explain clearly with numbers.
7. For medical/sick policy, remind user a certificate may be required.
STYLE: concise, friendly, professional. Use bullet lists for balances.
Agent JSON export reference:
{
"name": "HR Leave Assistant",
"scope": "x_786686_hr_leave",
"model": "now-llm-pro-v1",
"tools": ["GetMyBalance", "RequestLeave", "CheckPolicy", "GetMyRequests", "CancelRequest", "EscalateToHR"],
"knowledge_sources": [{ "type": "ai_search_profile", "name": "hrlx_kb_profile" }],
"triggers": [
{ "type": "chat", "channel": "employee_center" },
{ "type": "chat", "channel": "service_portal" }
],
"memory": { "session": true, "persistent": { "enabled": true, "max_turns": 8 } },
"guardrails": {
"pii_redaction": true,
"escalation_keywords": ["urgent", "complaint", "discrimination", "harassment", "lawyer"]
},
"audit": { "store_inputs": true, "store_outputs": true, "retention_days": 365 }
}
Step 3.4: Enable agent on Employee Center
1. Open {BASE}/now/assist/admin
2. Channels > Employee Center
3. Enable "AI Agents"
4. Add agent: HR Leave Assistant
5. Position: HR Leave category in chat launcher
6. Save
7. Test: {BASE}/esc → open chat → "How many annual days do I have?"
Step 3.5: Test agent (10 test utterances)
| # | User says | Expected tool | Pass criteria |
|---|---|---|---|
| 1 | “my balance” | GetMyBalance | Shows 4 types |
| 2 | “request 3 days annual next Mon-Wed” | RequestLeave (after confirm) | Creates req |
| 3 | “can I carry over leave?” | CheckPolicy | Cites KB |
| 4 | “show my last requests” | GetMyRequests | Lists records |
| 5 | “cancel HRLX0001234” | CancelRequest | State=cancelled |
| 6 | “what is parental leave?” | CheckPolicy | Policy answer |
| 7 | Arabic: “كم يوم إجازة عندي؟” | GetMyBalance | Arabic response |
| 8 | “I want 100 days annual” | RequestLeave | insufficient_balance error |
| 9 | “this is discrimination!” | EscalateToHR | Case created |
| 10 | “what’s the weather?” | none | Out of scope message |
Part 4 — BYO LLM (Claude / GPT)
Step 4.1: When to use BYO LLM
| Scenario | Recommendation |
|---|---|
| Default Now Assist skills | Now LLM Service |
| Regulated data residency | Azure OpenAI in your region |
| Existing Anthropic/OpenAI contract | BYO |
| Cost optimization at scale | gpt-4o-mini for classify, Claude for complex |
Step 4.2: Configure Anthropic provider
URL: {BASE}/sys_one_extend_provider_config_list.do
1. New > Provider type: Anthropic (or Generic REST)
2. Name: hrlx_anthropic
3. API endpoint: https://api.anthropic.com/v1/messages
4. Credential: link to Generic API Key credential (x-api-key)
5. Default model: claude-sonnet-4-5
6. Test connection
7. Per skill: LLM Provider = hrlx_anthropic
Step 4.3: REST Message — Claude_API
URL: {BASE}/sys_rest_message_list.do
| Header | Value |
|---|---|
| x-api-key | ${x_786686_hr_leave.llm.anthropic.api_key} |
| anthropic-version | 2023-06-01 |
| content-type | application/json |
Body template:
{
"model": "${model}",
"max_tokens": ${max_tokens},
"system": "${system}",
"messages": [{ "role": "user", "content": "${user_message}" }]
}
Step 4.4: Script Include — HRLXAIProvider (fallback chain)
var HRLXAIProvider = Class.create();
HRLXAIProvider.prototype = {
initialize: function() {
this.SCOPE = 'x_786686_hr_leave';
this.TIMEOUT_MS = parseInt(gs.getProperty(this.SCOPE + '.llm.timeout_ms', '15000'), 10);
},
_prop: function(name, def) { return gs.getProperty(this.SCOPE + '.' + name, def); },
_budgetCheck: function(provider) {
var budget = parseFloat(this._prop('llm.daily_budget_usd', '10'));
var key = 'llm.spent.' + provider + '.' + new GlideDateTime().getDate().getDisplayValue();
return parseFloat(gs.getProperty(this.SCOPE + '.' + key, '0')) < budget;
},
askClaude: function(prompt, model, maxTokens, system) {
if (!this._budgetCheck('anthropic')) return { error: 'budget_exceeded' };
try {
var rm = new sn_ws.RESTMessageV2('Claude_API', 'post');
rm.setHttpTimeout(this.TIMEOUT_MS);
rm.setStringParameterNoEscape('model', model || this._prop('llm.anthropic.model', 'claude-sonnet-4-5'));
rm.setStringParameterNoEscape('max_tokens', String(maxTokens || 400));
rm.setStringParameterNoEscape('system', system || 'You are a helpful HR assistant.');
rm.setStringParameterNoEscape('user_message', prompt);
var resp = rm.execute();
if (resp.getStatusCode() >= 400) return { error: 'http_' + resp.getStatusCode() };
var json = JSON.parse(resp.getBody());
var text = '';
(json.content || []).forEach(function(c) { if (c.type === 'text') text += c.text; });
return { text: text, usage: json.usage || {} };
} catch (e) { return { error: 'exception', message: String(e) }; }
},
askWithFallback: function(prompt, options) {
options = options || {};
var chain = options.chain || ['anthropic', 'openai', 'now_llm'];
for (var i = 0; i < chain.length; i++) {
var res = (chain[i] === 'anthropic') ? this.askClaude(prompt, options.model, options.max_tokens, options.system) : null;
if (res && !res.error && res.text) return res;
}
return { error: 'all_providers_failed' };
},
type: 'HRLXAIProvider'
};
Step 4.5: HRLXRagService (custom RAG)
var HRLXRagService = Class.create();
HRLXRagService.prototype = {
initialize: function() {
this.PROVIDER = new HRLXAIProvider();
this.PROFILE = gs.getProperty('x_786686_hr_leave.ai_search.profile', 'hrlx_kb_profile');
},
answer: function(question) {
var sn = new sn_ais.AISearch();
var res = sn.search(this.PROFILE, question, { limit: 5, genai: true, min_similarity: 0.65 });
if (res.genai_answer) return { text: res.genai_answer, citations: res.citations || [] };
return { text: 'I could not find an answer in HR Leave policies.', citations: [] };
},
type: 'HRLXRagService'
};
Part 5 — AI Search + GenAI Search
5.1 AI Search vs Zing
| Feature | Zing | AI Search |
|---|---|---|
| Vector search | No | Yes (RaptorDB) |
| GenAI answers | No | Yes |
| Re-ranking | Basic | ML re-ranker |
| Multi-source profiles | Limited | Native |
Step 5.1: Create search source — hrlx_kb
URL: {BASE}/ais_search_source_list.do
1. New Search Source
2. Name: hrlx_kb
3. Table: kb_knowledge
4. Condition: topic=HR Leave^workflow_state=published^active=true
5. Indexed fields:
- title (boost 2.0)
- short_description (boost 1.5)
- text (boost 1.0)
- meta (boost 0.5)
6. Index transform script (PII mask):
(function transform(record, indexed) {
indexed.title = record.short_description + '';
var body = (record.text || '') + '';
indexed.body = body.replace(/\b(SSN|PASSPORT|MRN|diagnosis)\b[: ]?\S+/gi, '[REDACTED]');
indexed.u_kb_number = record.number + '';
return indexed;
})(record, indexed);
7. Save → Full Index (wait for completion)
8. Verify: AI Search Admin > Index Status = Green
Step 5.2: Create source — hrlx_policy_attachments
| Field | Value |
|---|---|
| Name | hrlx_policy_attachments |
| Table | kb_knowledge (attachment text extraction) |
| Condition | Same as hrlx_kb |
| Enable | Attachment indexing |
Step 5.3: Create profile — hrlx_kb_profile
URL: {BASE}/ais_search_profile_list.do
| Setting | Value |
|---|---|
| Name | hrlx_kb_profile |
| Sources | hrlx_kb, hrlx_policy_attachments |
| GenAI Search | ON |
| LLM | Now LLM Service |
| Max chunks | 5 |
| Min similarity | 0.65 |
| Chunk size | 800 |
| Chunk overlap | 100 |
| Refusal message | “I cannot find the answer in HR Leave policies. Contact HR.” |
| Citation format | KB number + title |
Step 5.4: Create search application (Portal)
URL: {BASE}/ais_search_application_list.do
1. New Application: hrlx_portal_search
2. Profile: hrlx_kb_profile
3. UI: Service Portal
4. Placeholder: "Ask about leave policy, sick days, carry-over..."
5. Enable GenAI answer panel + citations
6. Link to page: {BASE}/sp?id=hrlx_policy_search
Widget HTML (Service Portal):
<div class="hrlx-aisearch">
<sp-search
profile="hrlx_kb_profile"
placeholder="Ask about leave policy"
show-genai-answer="true"
show-citations="true">
</sp-search>
</div>
Step 5.5: Boost rules & synonyms
| Type | Example |
|---|---|
| Synonym | “PTO” = “annual leave” = “vacation” |
| Synonym | “sick” = “medical” = “illness” |
| Boost | u_leave_type field match × 1.3 |
| Filter facet | country, leave_type |
URL for synonyms: {BASE}/ais_dictionary_term_list.do
Step 5.6: Search analytics dashboard
Build PA indicators from:
| Table | Metric |
|---|---|
| sys_aisearch_query_log | Queries/day, zero-result rate |
| sys_aisearch_click_log | Click-through rate |
| sys_aisearch_genai_log | GenAI answer rate, citation count |
Target: zero-result rate < 5% after 30 days.
Part 6 — Predictive Intelligence
6.1 Solution types for HR Leave
| Type | HR Leave use case | Output field |
|---|---|---|
| Classification | Approved within 24h? | u_predicted_approval_24h |
| Regression | Predict duration days | u_predicted_duration |
| Similarity | Find similar past requests | (UI Action link) |
| Anomaly | Unusual sick-leave pattern | u_anomaly_score |
Step 6.1: Add ML output fields to req_v2
URL: {BASE}/sys_dictionary_list.do?sysparm_query=name=x_786686_hr_leave_req_v2
| Column | Type | Label |
|---|---|---|
| u_predicted_approval_24h | string (40) | Predicted 24h Approval |
| u_predicted_confidence_24h | decimal | Prediction Confidence |
| u_predicted_duration | decimal | Predicted Duration |
| u_anomaly_score | decimal | Anomaly Score |
| u_approved_within_24h | string | Actual 24h Approval (training label) |
Step 6.2: Backfill training label (one-time script)
Run after you have historical approvals:
var gr = new GlideRecord('x_786686_hr_leave_req_v2');
gr.addQuery('u_state', 'IN', 'approved,rejected');
gr.query();
while (gr.next()) {
var created = new GlideDateTime(gr.sys_created_on);
var updated = new GlideDateTime(gr.sys_updated_on);
var hours = (updated.getNumericValue() - created.getNumericValue()) / 3600000;
var approved = gr.u_state == 'approved' && hours <= 24;
gr.u_approved_within_24h = approved ? 'yes' : 'no';
gr.setWorkflow(false);
gr.update();
}
gs.info('Backfill complete');
Minimum training rows: ≥ 1,000 historical requests (≥ 100 per class for classification).
Step 6.3: Create classification solution — hrlx_predict_approval_24h
URL: {BASE}/ml_solution_definition_list.do
1. New Solution Definition
2. Name: hrlx_predict_approval_24h
3. Table: x_786686_hr_leave_req_v2
4. Solution type: Classification
5. Input fields:
- u_leave_type
- u_days_count
- u_department (from employee)
- u_employee_tenure_days (calculated field or BR)
- day_of_week (derived from u_start_date)
- u_has_reason (boolean: u_reason length > 5)
6. Output field: u_approved_within_24h
7. Prediction fields: u_predicted_approval_24h, u_predicted_confidence_24h
8. Training window: last 18 months
9. Exclusion: u_state=draft
10. Click Train → wait (15–60 min)
11. Review accuracy report: target ≥ 0.80 accuracy, F1 ≥ 0.65 minority class
12. Activate solution
Step 6.4: Business Rule — predict on insert
(function executeRule(current, previous) {
if (current.u_predicted_approval_24h) return;
try {
var ml = new sn_ml.SolutionStore().get('hrlx_predict_approval_24h');
if (!ml || !ml.isActive()) return;
var startDt = new GlideDateTime(current.u_start_date);
var input = {
u_leave_type: String(current.u_leave_type),
u_days_count: parseInt(current.u_days_count || '0', 10),
u_department: String(current.u_department || ''),
u_employee_tenure_days: parseInt(current.u_employee_tenure_days || '0', 10),
day_of_week: startDt.getDayOfWeekUTC(),
u_has_reason: (current.u_reason && current.u_reason.length > 5) ? 1 : 0
};
var pred = ml.predict([input]);
if (pred && pred[0]) {
current.u_predicted_approval_24h = pred[0].predicted_value;
current.u_predicted_confidence_24h = pred[0].confidence;
}
} catch (e) {
gs.warn('PI predict failed: ' + e);
}
})(current, previous);
| BR setting | Value |
|---|---|
| When | before insert |
| Table | x_786686_hr_leave_req_v2 |
| Order | 500 |
Step 6.5: Regression solution — hrlx_predict_duration
Same wizard, type = Regression, output = u_days_count (actual), prediction = u_predicted_duration.
Step 6.6: Solution Monitor
URL: {BASE}/ml_solution_monitor_list.do
| KPI | Threshold | Action if breached |
|---|---|---|
| Accuracy | ≥ 0.80 | Re-train |
| Drift score | < 0.20 | Investigate feature changes |
| RMSE (regression) | ≤ 1.5 days | Re-train |
| Prediction volume | track | Capacity planning |
Schedule monthly re-train via Scheduled Script Execution.
Part 7 — Virtual Agent + NLU (Full Topics & Flows)
7.1 Virtual Agent vs AI Agent — coexistence
| Aspect | Virtual Agent (VA) | AI Agent (AIA) |
|---|---|---|
| Logic | Deterministic topic blocks | LLM-planned |
| Cost | Low | Per-token |
| Best for | Slot-filling, forms | Open Q&A |
| Handoff | VA → AIA via “Transfer to AI Agent” block | AIA → VA via tool |
Recommended pattern: VA handles structured flows; fallback / policy Q&A routes to AI Agent.
Step 7.1: Create NLU model — hrlx_leave_nlu
| Field | Value |
|---|---|
| Model name | hrlx_leave_nlu |
| Language | en (add ar as second model if needed) |
| Domain | HR Leave |
| Application | x_786686_hr_leave |
Step 7.2: Intents (8 total)
| Intent | Description |
|---|---|
| greeting | Hello, hi, start |
| check_balance | Remaining leave days |
| request_leave | Book time off |
| check_policy | Policy questions |
| cancel_leave | Withdraw request |
| check_status | Status of existing request |
| speak_to_human | Live agent handoff |
| fallback | Out of scope |
Step 7.3: Entities
| Entity | Type | Values / Notes |
|---|---|---|
| leave_type | List | annual, sick, parental, unpaid |
| date_range | SYS.DATE | “next Monday”, “June 5 to 10” |
| days_count | Number | “3 days”, “two weeks” |
| request_number | Regex | HRLX\d+ |
| leave_type_ar | List | سنوية, مرضية, أمومة |
Step 7.4: Utterances — check_balance (30 examples)
how many leave days do I have
what is my annual leave balance
show my remaining vacation days
how much PTO do I have left
check my sick leave balance
remaining parental leave
how many days off can I take
what's my leave balance
do I have any unpaid leave left
show balance for annual leave
how many annual days remaining
tell me my vacation balance
what leave do I have available
check my time off balance
how much annual leave is left
show me sick days remaining
balance inquiry for leave
how many days of leave remain
what is my current leave entitlement
remaining days for sick leave
how much leave have I got left
annual balance please
sick leave days left
parental leave balance check
unpaid leave remaining
how many holidays can I still take
leave days available
my remaining leave
check PTO balance
how many days can I still book off
Step 7.5: Utterances — request_leave (35 examples)
I want to take leave next Monday
request 3 days annual leave
book sick leave for tomorrow
I need time off from June 5 to June 10
apply for parental leave starting next month
request vacation days
take 2 days off next week
I want to book annual leave
schedule sick leave for Friday
need unpaid leave for 5 days
book me 3 days annual starting Monday
I would like to request leave
can I take leave next Tuesday and Wednesday
request time off for a wedding
apply for 10 days annual leave in July
I need sick leave for 2 days
book parental leave from September 1
request leave for family emergency
take annual leave Dec 20 to Dec 31
I want 1 week off
schedule 4 days sick leave
request unpaid leave next month
book leave type annual for 3 days
I need to take Friday off
request half day sick leave
apply for leave starting {date_range}
book {days_count} days of {leave_type} leave
I want {leave_type} leave from {date_range}
need {days_count} days off
request leave please
take time off
book my vacation
I want to go on leave
schedule my days off
can I have next week off
Step 7.6: Utterances — check_policy (25 examples)
what is the maternity leave policy
can I carry over unused annual leave
how many sick days am I allowed per year
what is the parental leave entitlement
do I need a medical certificate for sick leave
what is the notice period for annual leave
can managers reject my leave request
what happens to unused leave at year end
is unpaid leave available
what is the maximum consecutive leave days
how does sick leave accrue
what is the leave policy for new joiners
can I take leave during probation
what documents are required for sick leave
explain the annual leave policy
how far in advance must I request leave
what is the carry forward limit
are public holidays deducted from leave
what is bereavement leave policy
can I split parental leave
what is the leave approval process
how is leave calculated for part time staff
what is the sick leave waiting period
tell me about leave encashment
what are the rules for emergency leave
Step 7.7: Utterances — cancel_leave (20 examples)
cancel my leave request
withdraw my leave application
I want to cancel HRLX0001234
cancel my upcoming vacation
withdraw the leave I submitted
delete my leave request
cancel submitted leave
I no longer need those days off
please cancel my time off request
revoke my leave request
cancel annual leave for next week
withdraw sick leave request
cancel request number {request_number}
I want to undo my leave request
cancel my pending leave
stop my leave application
cancel the leave I booked
withdraw my days off
cancel leave starting Monday
I need to cancel my vacation request
Step 7.8: Utterances — check_status (20 examples)
what is the status of my leave request
has my leave been approved
track my leave application
where is my request HRLX0001234
is my leave approved yet
check approval status
status of my vacation request
has manager approved my leave
what happened to my leave request
show status of pending leave
is my sick leave approved
check my submitted leave
approval status please
where is my annual leave request
has HR approved my leave
track request {request_number}
what state is my leave in
is my leave still pending
did my leave get rejected
update on my leave request
Step 7.9: Train and publish NLU
1. NLU Workbench > hrlx_leave_nlu
2. Add all utterances above (minimum 15 per intent; we have 20–35)
3. Annotate entities in utterances (highlight dates, types)
4. Click Train → wait for model metrics
5. Target: Intent accuracy ≥ 0.92 on test set
6. Publish model version 1.0
7. Set property x_786686_hr_leave.nlu.model = hrlx_leave_nlu
Step 7.10: Topic catalog (8 topics)
URL: {BASE}/now/virtual-agent/designer
| Topic | Trigger | NLU intent |
|---|---|---|
| HRLX Greeting | greeting | greeting |
| HRLX Check Balance | check_balance | check_balance |
| HRLX Request Leave | request_leave | request_leave |
| HRLX Check Policy | check_policy | check_policy OR transfer to AI Agent |
| HRLX Cancel Leave | cancel_leave | cancel_leave |
| HRLX Check Status | check_status | check_status |
| HRLX Live Agent | speak_to_human | speak_to_human |
| HRLX Fallback | no match | fallback |
TOPIC FLOW 1 — HRLX Check Balance (block-by-block)
Topic: HRLX Check Balance
Channel: Employee Center, Service Portal
NLU: check_balance (confidence ≥ 0.7)
BLOCK 1 — Script Action "Fetch Balance"
Script:
(function execute() {
var userId = vaSystem.getUserId();
var tools = new x_786686_hr_leave.HRLXAIAgentTools();
var bal = tools.getBalance(userId);
if (bal.error) {
vaInputs.has_error = true;
vaInputs.error_msg = 'Employee profile not found. Contact HR.';
return;
}
vaInputs.has_error = false;
vaInputs.balance_text =
'Annual: ' + bal.annual + ' days\n' +
'Sick: ' + bal.sick + ' days\n' +
'Parental: ' + bal.parental + ' days\n' +
'Unpaid: ' + bal.unpaid + ' days';
})();
BLOCK 2 — Decision
Condition: has_error == true
True → Bot Message: "${error_msg}" → End
False → continue
BLOCK 3 — Bot Message
Text: "Here is your current leave balance:\n${balance_text}"
BLOCK 4 — Quick Reply
Question: "Would you like to request leave?"
Options: Yes | No
BLOCK 5 — Branch
Yes → Link to Topic "HRLX Request Leave"
No → Bot Message "Have a great day!" → End
TOPIC FLOW 2 — HRLX Request Leave (slot filling)
Topic: HRLX Request Leave
NLU: request_leave
BLOCK 1 — Collect leave_type (if not in NLU entities)
Prompt: "Which type of leave? (annual / sick / parental / unpaid)"
Slot: leave_type
Validation: must be in [annual, sick, parental, unpaid]
Max retries: 2 → on fail go to Fallback
BLOCK 2 — Collect start_date
Prompt: "What is the start date? (YYYY-MM-DD or 'next Monday')"
Slot: start_date
Validation: date >= today
BLOCK 3 — Collect end_date
Prompt: "What is the end date?"
Slot: end_date
Validation: end_date >= start_date
BLOCK 4 — Collect reason (optional)
Prompt: "Reason for leave? (optional — press Skip)"
Slot: reason
Required: false
BLOCK 5 — Script Action "Calculate Days Preview"
(function execute() {
var start = new GlideDateTime(vaVars.start_date);
var end = new GlideDateTime(vaVars.end_date);
var days = Math.ceil((end.getNumericValue() - start.getNumericValue()) / 86400000) + 1;
vaInputs.preview_days = days;
var tools = new x_786686_hr_leave.HRLXAIAgentTools();
var bal = tools.getBalance(vaSystem.getUserId());
vaInputs.enough = (bal[vaVars.leave_type] || 0) >= days;
vaInputs.available = bal[vaVars.leave_type] || 0;
})();
BLOCK 6 — Decision insufficient balance
Condition: enough == false
True → Message: "You need ${preview_days} days but only have ${available}. Choose shorter dates."
→ Go to BLOCK 2 (re-collect dates)
False → continue
BLOCK 7 — Confirmation
Message: "Please confirm:\nType: ${leave_type}\nFrom: ${start_date} To: ${end_date}\nDays: ${preview_days}\nReason: ${reason}"
Quick Reply: Confirm | Cancel
BLOCK 8 — Branch Cancel → End polite
BLOCK 9 — Script Action "Submit Request"
(function execute() {
var tools = new x_786686_hr_leave.HRLXAIAgentTools();
var res = tools.requestLeave({
user_id: vaSystem.getUserId(),
type: vaVars.leave_type,
start_date: vaVars.start_date,
end_date: vaVars.end_date,
reason: vaVars.reason || ''
});
vaInputs.ok = !!res.ok;
vaInputs.req_number = res.number || '';
vaInputs.err = res.error || '';
})();
BLOCK 10 — Decision ok
True → "Your leave request ${req_number} has been submitted for approval."
False → "Sorry, submission failed: ${err}. Try again or contact HR."
→ End
TOPIC FLOW 3 — HRLX Check Policy
BLOCK 1 — Decision: use AI Agent for open questions
If utterance length > 50 chars OR contains "?"
→ Transfer to AI Agent "HR Leave Assistant" with context
Else
→ Script Action CheckPolicy with vaInputs.last_utterance
BLOCK 2 — Display answer + citations
BLOCK 3 — "Was this helpful?" Yes/No → log to analytics
TOPIC FLOW 4 — HRLX Cancel Leave
BLOCK 1 — Collect request_number (or pick from list)
Script Action: getMyRequests → build choice list
BLOCK 2 — Confirm cancellation
BLOCK 3 — Script Action cancelRequest
BLOCK 4 — Success/fail message
TOPIC FLOW 5 — HRLX Live Agent Handoff
BLOCK 1 — Collect issue summary (optional)
BLOCK 2 — Live Agent Queue
Queue: HR Leave Support
Pre-chat fields: user_id, last_intent, last_5_messages
BLOCK 3 — Fallback if no agent available
Script Action escalate()
Message: "An HR partner will contact you. Case reference logged."
Step 7.11: Enable VA on channels
1. Virtual Agent > Administration > Channels
2. Employee Center: ON, Bot name from x_786686_hr_leave.va.bot_name
3. Service Portal: add Virtual Agent widget to sp_page
4. Topic recommendations: enable HR Leave topics
5. Test: {BASE}/esc
Step 7.12: VA analytics KPIs
| KPI | Target | Source |
|---|---|---|
| Containment rate | ≥ 70% | sys_cs_conversation |
| Avg turns | ≤ 6 | sys_cs_message count |
| Intent recognition | ≥ 90% | nlu_inference_result |
| Handoff rate | ≤ 15% | live agent transfers |
Part 8 — Document Intelligence (IDP)
8.1 Use case — medical certificate for sick leave
When u_leave_type = sick and u_days_count > 2, require medical certificate attachment. IDP extracts fields automatically.
| Extracted field | Maps to column |
|---|---|
| patient_name | (validate vs employee) |
| certificate_date | u_cert_date |
| days_recommended | u_cert_days |
| doctor_name | u_cert_doctor |
| clinic_name | u_cert_clinic |
| condition_summary | u_cert_summary (masked in UI) |
Step 8.1: Create IDP template — hrlx_medical_cert
URL: {BASE}/sn_idp_template_list.do
1. New Template
2. Name: hrlx_medical_cert
3. Document type: Medical Certificate
4. Upload 8–12 sample PDFs (anonymized):
- 3 hospital letterheads
- 3 clinic formats
- 2 Arabic certificates
- 2 poor-scan quality (for robustness)
5. For each sample, annotate bounding boxes:
- patient_name
- certificate_date
- doctor_name
- days_recommended
- clinic_name
- condition_summary
6. Save annotations
Step 8.2: Train extraction model
URL: {BASE}/sn_idp_model_list.do
1. New Model → Template: hrlx_medical_cert
2. Train/Test split: 80/20
3. Click Train (30–90 minutes)
4. Review per-field F1 scores (target ≥ 0.90 each)
5. If condition_summary F1 low: add more samples or mark optional
6. Activate model v1.0
7. Set property x_786686_hr_leave.idp.template = hrlx_medical_cert
Step 8.3: Flow — run IDP on attachment
Flow: HRLX IDP Medical Certificate
Trigger: Attachment added to x_786686_hr_leave_req_v2
Condition: u_leave_type=sick^u_days_count>2
Step 1 — Get attachment sys_id
Step 2 — Action: Document Intelligence Extract
Template: hrlx_medical_cert
Input: attachment_sys_id
Step 3 — Script (update request):
(function(inputs, outputs) {
var fields = inputs.extraction_result.fields || {};
var req = new GlideRecord('x_786686_hr_leave_req_v2');
if (!req.get(inputs.request_sys_id)) return;
req.u_cert_date = fields.certificate_date || '';
req.u_cert_days = fields.days_recommended || '';
req.u_cert_doctor = fields.doctor_name || '';
req.u_cert_clinic = fields.clinic_name || '';
// Mask sensitive summary for display
req.u_cert_summary = (fields.condition_summary || '').substring(0, 200);
req.update();
var aud = new GlideRecord('x_786686_hr_leave_audit_v2');
aud.initialize();
aud.u_action = 'idp_extract_cert';
aud.u_record = req.getUniqueValue();
aud.u_payload = JSON.stringify(fields);
aud.u_actor = gs.getUserID();
aud.u_source = 'idp';
aud.insert();
})(inputs, outputs);
Step 4 — Decision: days_recommended < u_days_count → notify HR for review
Step 5 — Email employee if extraction failed (manual upload retry)
Step 8.4: Standalone IDP test
1. IDP Admin > Test Extraction
2. Upload new PDF not in training set
3. Verify all fields extracted
4. Latency target: ≤ 8 seconds per document
Step 8.5: IDP metrics dashboard
| Metric | Target |
|---|---|
| Field-level F1 | ≥ 0.90 |
| Document success rate | ≥ 0.95 |
| Avg latency | ≤ 8s |
| Manual correction rate | ≤ 10% |
Part 9 — Workflow Studio AI Actions
Step 9.1: Built-in actions to reuse
| Platform action | HR Leave adaptation |
|---|---|
| Summarize Record | Summarize u_reason on approval |
| Categorize Text | Classify leave type from reason |
| Generate Email Response | Manager approval/rejection email |
| Sentiment Analysis | Route frustrated requests |
| Extract Entities | Parse dates from free-text reason |
Step 9.2: Custom action — HRLX Summarize Leave History
URL: {BASE}/now/flow-designer → Custom Actions
1. New Custom Action: HRLX Summarize Leave History
2. Application: HR Leave
3. Inputs:
- employee_ref (Reference: x_786686_hr_leave_employee_v2)
- lookback_days (Integer, default 365)
4. Outputs:
- summary_text (String)
5. Steps:
a. Look Up Records: x_786686_hr_leave_req_v2
Query: u_employee_ref = employee_ref AND sys_created_on >= lookback
b. Transform Data: build history_text lines
c. Now Assist Skill: hrlx_summarize_history
d. Return summary_text
6. Guardrails: PII redaction ON, max_tokens 250
Step 9.3: Flow — weekly manager digest
Trigger: Scheduled weekly Monday 08:00
For Each: managers with pending approvals
Action: HRLX Summarize Leave History (direct reports, 90 days)
Action: Send Email with summary + link to workspace
Step 9.4: Flow — auto-classify on submit
Trigger: Record created x_786686_hr_leave_req_v2, u_state=submitted
Action: Now Assist Skill hrlx_classify_leave_type
Decision: if output != u_leave_type → set u_ai_suggested_type + notify HR
Action: PI predict approval
Decision: if confidence < 0.6 → route to senior manager
Part 10 — Now Assist for Developers
Step 10.1: Generate Script Include from prompt
In Studio ({BASE}/$studio.do):
Prompt:
"Create Script Include HRLXLeaveValidation in scope x_786686_hr_leave.
Methods: validateDates(start, end), validateBalance(userId, type, days).
Use GlideRecord on x_786686_hr_leave_bal_v2. Return {ok, error} objects.
No client callable. Include null checks."
Review → Tab accept → add audit comment → ATF test.
Step 10.2: Inline shortcuts
| Action | Keys |
|---|---|
| Accept suggestion | Tab |
| Partial accept | Ctrl+Right |
| Multiline panel | Ctrl+Enter |
| Reject | Esc |
Step 10.3: Generate ATF from Script Include
1. Open HRLXAIAgentTools in Studio
2. Now Assist > Generate Tests
3. Select: getBalance, requestLeave, cancelRequest
4. Save tests under sys_atf_test scoped to HR Leave
5. Run Test Runner: {BASE}/sys_atf_test_runner.do
Step 10.4: Code review checklist for AI-generated code
[ ] No hard-coded sys_ids
[ ] Scoped table names only (x_786686_hr_leave_*)
[ ] ACL-safe (respects current user)
[ ] No gs.print in production code
[ ] Error handling with gs.error/gs.warn
[ ] Human reviewer name in header comment
Part 11 — End-to-End HR Leave AI Example
Scenario: Employee submits sick leave via chat with certificate
Actors: Employee (ESS), HR Leave Assistant (AIA), VA topics, IDP, PI, Flow
Step 1 — Employee opens {BASE}/esc
Step 2 — "I need sick leave Thu-Fri" → VA Topic Request Leave OR AIA
Step 3 — Slot fill: type=sick, dates confirmed
Step 4 — AIA calls RequestLeave → req HRLX001234 created
Step 5 — Employee uploads medical PDF on form
Step 6 — Flow HRLX IDP Medical Certificate runs → fields extracted
Step 7 — BR runs PI → u_predicted_approval_24h = yes (0.87)
Step 8 — Manager opens record → UI Action Summarize reason (AI)
Step 9 — Manager approves → Flow sends hrlx_draft_manager_email (optional)
Step 10 — Audit rows in x_786686_hr_leave_audit_v2 for ai_request_leave, idp_extract_cert
Verification queries
// All AI-touched requests last 7 days
var gr = new GlideRecord('x_786686_hr_leave_req_v2');
gr.addQuery('u_source', 'ai_agent');
gr.addQuery('sys_created_on', '>=', gs.daysAgoStart(7));
gr.query();
gs.info('AI agent requests: ' + gr.getRowCount());
var aud = new GlideRecord('x_786686_hr_leave_audit_v2');
aud.addQuery('u_source', 'IN', 'ai_agent,idp');
aud.addQuery('sys_created_on', '>=', gs.daysAgoStart(7));
aud.query();
gs.info('AI audit rows: ' + aud.getRowCount());
Part 12 — AI Governance & Safety
Step 12.1: Create AI policy — no_raw_medical_text
URL: {BASE}/now/ai/policy
{
"policy": "hrlx_no_raw_medical_text",
"scope": "x_786686_hr_leave",
"rules": [
{
"id": "redact_diagnosis",
"applies_to": ["input", "output"],
"regex": "(?i)(diagnosis|condition|illness|medication):\\s*[^\\n]+",
"action": "redact",
"replacement": "[REDACTED-MEDICAL]"
},
{
"id": "block_external_emails",
"applies_to": ["output"],
"regex": "\\b[A-Z0-9._%+-]+@(?!company\\.com)[A-Z0-9.-]+\\.[A-Z]{2,}\\b",
"action": "block"
}
]
}
Step 12.2: Human-in-the-loop matrix
| AI action | Human checkpoint |
|---|---|
| RequestLeave | User confirms in chat |
| Auto-approve (never) | Manager always approves |
| PI low confidence | Route to senior manager |
| IDP mismatch days | HR manual review |
| Generated email | Manager edits before send |
Step 12.3: Compliance notes
| Regulation | Requirement |
|---|---|
| GDPR | Right to erasure on sn_aia_audit / sys_one_extend_audit |
| EU AI Act | HR decisions = high-risk → transparency + human oversight |
| HIPAA | Encrypt certificate attachments, restrict ACL |
| PDPL (GCC) | Data residency → pick LLM region |
Step 12.4: Audit retention
Configure 365-day retention on sn_aia_audit and sys_one_extend_audit. Domain audit x_786686_hr_leave_audit_v2 retained per HR policy (typically 7 years).
Part 13 — Performance & Cost Optimization
Step 13.1: Response cache table
Create table x_786686_hr_leave_ai_cache (hash, skill, response, expires_at).
var HRLXAICache = Class.create();
HRLXAICache.prototype = {
initialize: function() { this.TABLE = 'x_786686_hr_leave_ai_cache'; },
_hash: function(s) { return new GlideDigest().getSHA256Base64(s); },
get: function(skill, input) {
var gr = new GlideRecord(this.TABLE);
gr.addQuery('u_hash', this._hash(skill + '|' + input));
gr.addQuery('u_expires_at', '>', new GlideDateTime());
gr.setLimit(1);
gr.query();
return gr.next() ? String(gr.u_response) : null;
},
put: function(skill, input, response, ttlMin) {
var gr = new GlideRecord(this.TABLE);
gr.initialize();
gr.u_hash = this._hash(skill + '|' + input);
gr.u_skill = skill;
gr.u_response = response;
var exp = new GlideDateTime();
exp.addSeconds(60 * (ttlMin || 60));
gr.u_expires_at = exp;
gr.insert();
},
type: 'HRLXAICache'
};
Use for hrlx_classify_leave_type (deterministic input).
Step 13.2: Model right-sizing
| Task | Model |
|---|---|
| classify, sentiment | gpt-4o-mini / Now LLM Generic |
| summarize | Now LLM Generic |
| agent multi-step | now-llm-pro-v1 / claude-sonnet-4-5 |
| code gen | Now Assist for Creator |
Step 13.3: Monitoring dashboard widgets
| Widget | Source | Alert |
|---|---|---|
| Skill calls/day | sys_one_extend_audit | > 2× baseline |
| p95 latency | sys_one_extend_audit | > 3s |
| Daily LLM spend | system properties | > budget |
| Agent containment | sn_aia_execution | < 60% |
| PI drift | ml_solution_monitor | > 0.2 |
Part 14 — Hands-On Labs (5 Sessions)
Lab 1 — Now Assist Skill (45 min)
Goal: Deploy hrlx_summarize_reason with UI Action.
| Time | Step |
|------|------|
| 0–5 | Verify prerequisites (§0.2) |
| 5–15 | Create skill in Now Assist Studio (§2.2) |
| 15–25 | Test 5 samples in Playground |
| 25–35 | Create UI Action on req_v2 form |
| 35–40 | Impersonate manager → click Summarize |
| 40–45 | Check sys_one_extend_audit for log row |
Pass: Summary appears ≤ 2s, no medical detail leaked.
URL: {BASE}/now/assist/studio
Lab 2 — AI Search + GenAI (45 min)
Goal: Ask “Can I carry over annual leave?” and get cited answer.
| Time | Step |
|------|------|
| 0–10 | Create 3 KB articles (topic=HR Leave) if missing |
| 10–25 | Create source hrlx_kb + profile hrlx_kb_profile (§5) |
| 25–35 | Full index → wait green |
| 35–40 | Test in AI Search Admin preview |
| 40–45 | Add sp-search widget to portal page |
Pass: GenAI answer cites KB number.
URL: {BASE}/now/ais/admin
Lab 3 — Virtual Agent topic (60 min)
Goal: Complete balance → request leave conversation.
| Time | Step |
|------|------|
| 0–15 | Import NLU utterances for check_balance + request_leave |
| 15–25 | Train + publish hrlx_leave_nlu |
| 25–45 | Build topics per §7 block diagrams |
| 45–55 | Enable on {BASE}/esc |
| 55–60 | Run conversation test script (10 utterances) |
Pass: Request created with u_source=virtual_agent (add field if needed).
URL: {BASE}/now/virtual-agent/designer
Lab 4 — AI Agent + tools (60 min)
Goal: HR Leave Assistant submits leave after confirmation.
| Time | Step |
|------|------|
| 0–15 | Deploy HRLXAIAgentTools Script Include |
| 15–30 | Create 6 tools in Agent Studio |
| 30–45 | Create agent + system prompt |
| 45–55 | Enable on Employee Center |
| 55–60 | Test: "book 2 days annual next week" → confirm → verify req |
Pass: Record in req_v2, audit row written.
URL: {BASE}/now/aia/studio
Lab 5 — IDP + PI (90 min)
Goal: Sick leave + certificate extraction + approval prediction.
| Time | Step |
|------|------|
| 0–20 | Upload samples + annotate hrlx_medical_cert |
| 20–50 | Train IDP model (parallel: backfill PI labels) |
| 50–65 | Create Flow for attachment trigger |
| 65–80 | Train hrlx_predict_approval_24h |
| 80–90 | Submit sick leave with PDF → verify cert fields + prediction |
Pass: u_cert_date populated, u_predicted_approval_24h set.
URL: {BASE}/now/idp/admin , {BASE}/ml_solution_definition_list.do
Part 15 — Best Practices
15.1 Design
✅ One skill = one job (summarize OR classify, not both)
✅ Ground skills to specific tables with field-level mapping
✅ VA for happy-path slots; AIA for long-tail questions
✅ Always show citations for policy answers
✅ Confirm destructive tool calls (RequestLeave, CancelRequest)
✅ Log every AI action to x_786686_hr_leave_audit_v2
❌ Do not send cross-employee data to LLM
❌ Do not auto-approve leave based on PI alone
❌ Do not index u_reason without PII masking
❌ Do not skip human review on AI-generated code
15.2 Prompt engineering
✅ Separate SYSTEM (rules) from USER (data)
✅ Specify output format explicitly (JSON, single label, max words)
✅ Include refusal behavior ("If unsure, say...")
✅ Test in Arabic and English if bilingual workforce
✅ Version prompts; never edit production without version bump
15.3 Operations
✅ Weekly: review zero-result AI Search queries → add KB
✅ Monthly: review skill latency + cost dashboards
✅ Quarterly: re-train PI + NLU with new utterances
✅ Per release: run 5 labs as regression suite
✅ Maintain eval set (50 questions + expected answers) per skill
15.4 Security
✅ Mask medical text in prompts sent to external LLMs
✅ Use instance ACLs — tools run as authenticated user
✅ Budget caps on BYO LLM properties
✅ Disable x_786686_hr_leave.ai.enabled kill switch tested quarterly
Part 16 — Production Deployment Checklist
Phase A — Pre-deployment (sub-prod complete)
[ ] All 5 labs passed on sub-prod
[ ] Update Set "HR Leave AI v1.0" complete + peer reviewed
[ ] ATF tests green for HRLXAIAgentTools
[ ] Eval set ≥ 90% pass rate per skill
[ ] NLU intent accuracy ≥ 0.92
[ ] IDP field F1 ≥ 0.90
[ ] PI accuracy ≥ 0.80
[ ] AI Search zero-result rate < 10%
[ ] Agent containment ≥ 70% in UAT
[ ] Security review: PII redaction verified
[ ] Cost model approved (projected RU/month)
[ ] Rollback plan documented (disable ai.enabled property)
Phase B — Deployment day
[ ] Clone Update Set to production via DevOps/CD pipeline
[ ] Set production LLM API keys (password2 properties)
[ ] Activate plugins (if not already) — maintenance window
[ ] Now Assist Admin → enable skills for production scope
[ ] AI Search → full re-index on production
[ ] NLU model published to production instance
[ ] IDP model activated
[ ] PI solutions activated (monitor only first 24h)
[ ] Enable VA on Employee Center (feature flag gradual)
[ ] Enable AI Agent on Employee Center (pilot group first)
[ ] Verify kill switch: x_786686_hr_leave.ai.enabled = true
[ ] Smoke test: 10 utterances from §3.5 + §7
[ ] Monitor logs 2 hours: syslog, sn_aia_execution, sys_one_extend_audit
Phase C — Post-deployment (week 1)
[ ] Day 1: review all sn_aia_audit for errors
[ ] Day 2: review AI Search zero-result queries
[ ] Day 3: review VA containment + handoff rate
[ ] Day 5: review LLM spend vs budget
[ ] Day 7: stakeholder sign-off meeting
[ ] Document known issues + FAQ for HR helpdesk
[ ] Schedule monthly PI re-train
[ ] Schedule quarterly prompt review
Rollback procedure
1. Set x_786686_hr_leave.ai.enabled = false (immediate stop)
2. Disable AI Agent channel in Now Assist Admin
3. Disable VA topics (set inactive)
4. Deactivate PI solutions (optional — predictions stop)
5. Revert Update Set if Script Include defects found
6. Communicate to HR: "AI assistant temporarily offline"
Appendices
Appendix A — Key tables reference
| Area | Tables |
|---|---|
| Skills | sys_one_extend_skill, sys_one_extend_prompt_template, sys_one_extend_audit |
| Agents | sn_aia_agent, sn_aia_tool, sn_aia_execution, sn_aia_execution_step, sn_aia_audit |
| AI Search | ais_search_source, ais_search_profile, sys_aisearch_query_log, sys_aisearch_genai_log |
| PI | ml_solution_definition, ml_solution, ml_solution_monitor |
| NLU | nlu_model, nlu_intent, nlu_entity, nlu_utterance |
| VA | sys_cs_topic, sys_cs_topic_block, sys_cs_conversation, sys_cs_message |
| IDP | sn_idp_template, sn_idp_model, sn_idp_extraction_result |
| HR Leave | x_786686_hr_leave_req_v2, _bal_v2, _employee_v2, _audit_v2 |
Appendix B — Script Includes
| Script Include | Purpose |
|---|---|
| HRLXAIAgentTools | Agent/VA tools |
| HRLXAIProvider | BYO LLM + fallback |
| HRLXRagService | RAG answers |
| HRLXAICache | Response cache |
| HRLXHolidayUtil | Holiday JSON for date skill |
Appendix C — REST Messages
| Name | Endpoint |
|---|---|
| Claude_API | https://api.anthropic.com/v1/messages |
| OpenAI_API | https://api.openai.com/v1/chat/completions |
Appendix D — Roles
| Role | Use |
|---|---|
| sn_nowassist_admin | Skills |
| sn_aia.admin | Agents |
| ml_admin | Predictive Intelligence |
| ai_search_admin | AI Search |
| nlu_admin | NLU |
| sn_idp.admin | IDP |
| x_786686_hr_leave.manager | UI Actions |
| x_786686_hr_leave.hr_admin | Full HR AI access |
Appendix E — Plugin quick search terms
Now Assist, AI Agents, AI Search, Predictive Intelligence,
Document Intelligence, Virtual Agent, NLU Workbench, Now Assist for Creator
Appendix F — Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Skill returns empty | Missing grounding sys_id | Pass record in payload |
| Agent can’t call tool | ACL on Script Include | Check scope + roles |
| AI Search no results | Index not built | Full index in admin |
| NLU always fallback | Model not published | Publish + bind to topic |
| IDP low F1 | Too few samples | Add 5+ annotated PDFs |
| PI predict null | Solution inactive | Activate + check field map |
| Budget exceeded | Daily cap hit | Raise budget or wait |
| VA handoff fails | Queue empty | Configure HR queue hours |
Appendix G — Related documentation
| Doc | Topic |
|---|---|
| 01_DEVELOPMENT.md | Tables, BRs, Script Includes |
| 03_SERVICE_CATALOG.md | Record producer + catalog VA |
| 07_REPORTS_DASHBOARDS_PA.md | AI metrics dashboards |
| 08_ATF_TESTING.md | Test HRLXAIAgentTools |
| External codegen | |
| 12_INTEGRATION_FULL_GUIDE.md | REST + Table API |
End of guide. Start at Part 0 → pick your track (Skill, Agent, VA, Search, PI, IDP) → run matching Lab → complete Deployment Checklist.
للأسئلة: ابدأ من Quick Map → نفّذ Lab المناسب → راجع Troubleshooting (Appendix F).