@servicenow/sdk
Version:
ServiceNow SDK
750 lines (589 loc) • 29.8 kB
Markdown
---
tags: [ai-agent, agentic-workflow, agent-studio, sn_aia_agent, sn_aia_usecase, ai-automation, tools, triggers, authentication]
---
# Building AI Agents Guide
Build and configure ServiceNow AI Agents and AI Agentic Workflows using the Fluent SDK. AI Agents perform tasks with tools (CRUD, script, OOB, reference-based), while AI Agentic Workflows orchestrate multiple agents as a team. This guide covers end-to-end creation: authentication, tool configuration, instructions authoring, triggers, ACL deployment, and editing existing agents. Requires SDK 4.4.0 or higher.
---
## When to Use
- Creating a new AI Agent in ServiceNow
- Creating AI Agentic Workflows that orchestrate multiple agents
- Modifying existing agents or agentic workflows (adding tools, changing auth, updating instructions)
- Configuring agent authentication and security (Dynamic User vs AI User)
- Selecting and configuring agent tools (CRUD, script, OOB tools)
- Setting up triggers for agents or agentic workflows
- Defining team members for agentic workflows
---
## Workflow vs Single Agent Decision Tree
```
User Request
|
Does it involve multiple tasks? (AND, THEN, followed by)
| NO -> USE SINGLE AI AGENT
| YES
|
Do the tasks require DIFFERENT capability types?
(e.g., search + summarize, fetch from table A + update table B)
| NO -> USE SINGLE AI AGENT (multiple tools, one agent)
| YES -> USE AI AGENTIC WORKFLOW
```
**Pattern Recognition:**
| User Says | Type | Why |
|-----------|------|-----|
| "Fetch X AND do Y" (different capabilities) | Workflow | Different capability types working together |
| "Get data THEN process it" (different agents) | Workflow | Sequential operations needing different specializations |
| "Look up and update an incident" | Single Agent | Same table, same capability type (CRUD), multiple tools |
| "Search for incidents by priority" | Single Agent | Single task |
**Key distinction:** Multiple _tools_ on the same table or same capability type = single agent with multiple tools. Multiple _capability types_ requiring different specializations = workflow with multiple agents.
---
## AI Agent vs AI Agentic Workflow
| Feature | AI Agent | AI Agentic Workflow |
|---------|----------|---------------------|
| Purpose | Single agent performing tasks | Multiple agents working as a team |
| Import | `AiAgent` from `@servicenow/sdk/core` | `AiAgenticWorkflow` from `@servicenow/sdk/core` |
| Configuration | `tools` array | `team: { $id, name, members: [...] }` |
| Version array | `versionDetails` | `versions` |
| Record identity | `$id` (explicit ID) | `$id` (explicit ID) |
| Security | `securityAcl` (mandatory, auto-generates ACL) | `securityAcl` (mandatory, auto-generates ACL) |
| Run-as user | `runAsUser` | `runAs` |
| Execution mode | `executionMode` on tools | `executionMode` at workflow level (default: `'copilot'`) |
| Trigger channel | `'nap'` / `'nap_and_va'` (agent-level `channel`) | `"Now Assist Panel"` (trigger-level, mandatory) |
| Processing messages | `processingMessage`, `postProcessingMessage` | Not available |
---
## Security ACL (`securityAcl`)
`securityAcl` is **mandatory** on both `AiAgent` and `AiAgenticWorkflow`. It controls **who can invoke** the agent/workflow and auto-generates the `sys_security_acl` and `sys_security_acl_role` records. It is a discriminated union on the `type` field — each variant also requires a `$id` to identify the generated ACL record.
### Access Types
| `type` | Who can invoke | Extra fields |
|--------|----------------|--------------|
| `'Any authenticated user'` | Any logged-in user | None |
| `'Specific role'` | Only users with listed roles | `roles: [...]` (required) |
| `'Public'` | Anyone, no auth required | None |
```typescript fluent
// Any authenticated user
securityAcl: {
$id: Now.ID['my_agent_acl'],
type: 'Any authenticated user',
}
// Specific roles only
securityAcl: {
$id: Now.ID['my_agent_acl'],
type: 'Specific role',
roles: [
'282bf1fac6112285017366cb5f867469', // itil role sys_id
'b05926fa0a0a0aa7000130023e0bde98', // user role sys_id
]
}
```
> **Important distinction:** `securityAcl` controls *who can invoke* the agent. `runAsUser` (agent) / `runAs` (workflow) and `dataAccess` are separate — they control *which user identity the agent runs under* when executing.
### Execution Identity (`runAsUser` / `dataAccess`)
Set **either** `runAsUser` (agent) or `dataAccess` — not both:
- **`runAsUser`** — agent always runs as the specified sys_user sys_id regardless of invoker
- **`dataAccess.roleMap`** (role names) or **`dataAccess.roleList`** (role sys_ids) — agent runs as the invoking user, restricted to the listed roles. **Required when `runAsUser` is not set.** For workflows, use `dataAccess` when `runAs` is not set.
### Role Discovery
1. Identify target tables from the agent's CRUD tools
2. Query `sys_security_acl_role` for each table (encodedQuery: `sys_security_acl.nameLIKE<table_name>`)
3. Add discovered role **names** to `dataAccess.roleMap`, or role **sys_ids** to `dataAccess.roleList` and `securityAcl.roles`
### Common Role sys_ids
| Role | sys_id |
|------|--------|
| admin | `2831a114c611228501d4ea6c309d626d` |
| itil | `282bf1fac6112285017366cb5f867469` |
| user | `b05926fa0a0a0aa7000130023e0bde98` |
---
## Tool Types and Selection
### Selection Priority
1. **OOB tools** when available (e.g., Web Search, RAG, Knowledge Graph)
2. **Reference-based tools** (action, subflow, capability, catalog, topic)
3. **CRUD tools** for database operations
4. **Script tools** only when no other tool type fits
Never use CRUD tools for journal fields (`work_notes`, `comments`). Always use Script tools with `GlideRecordSecure`.
### Tool Selection Guide
| Need | Tool Type | Why |
|------|-----------|-----|
| Read/search records | CRUD (`lookup`) | Direct table query |
| Create new records | CRUD (`create`) | Maps inputs to columns |
| Modify records | CRUD (`update`) | Query + field update |
| Custom logic | Script | Full JavaScript control |
| Web information | OOB (`web_automation`) | Auto-linked OOB tool |
| Semantic/keyword search | RAG (`rag`) | Structured search with ValueLabelType inputs |
| Graph-based search | OOB (`knowledge_graph`) | Knowledge Graph tool |
| File ingestion | OOB (`file_upload`) | File Uploader tool |
| In-depth research | OOB (`deep_research`) | Deep Research tool |
| Desktop tasks | OOB (`desktop_automation`) | Desktop Automation tool |
| MCP integration | OOB (`mcp`) | MCP tool |
| Flow Designer action | Action (`action`) | Triggers existing flows |
| Now Assist skill | Capability (`capability`) | Links to skills |
### `inputs` Format by Tool Type
| Tool type | `inputs` format | Has `script` field? |
|-----------|-----------------|---------------------|
| `crud` | **Object** (`ToolInputType`) with `operationName`, `table`, `inputFields`, etc. | No (auto-generated) |
| `rag` | **Object** (`RagInputType`) with `searchType`, `searchProfile`, `sources`, etc. (all using `ValueLabelType`) | No (auto-generated) |
| `script` | **Array** of `[{ name, description, mandatory, value? }]` | Yes |
| `web_automation` | Omit (plugin provides defaults) | No |
| Reference types | Omit (platform resolves at runtime) | No |
| Other OOB types | Omit (plugin provides defaults) | No |
### Required Tool Properties
Every tool **must** have `name` and `type`. `preMessage` and `postMessage` are strongly recommended. Every agent **must** have `processingMessage` and `postProcessingMessage` (not available on workflows).
---
## CRUD Tools
### Operations
| Operation | Required Fields |
|-----------|----------------|
| `create` | `table`, `inputFields` with `mappedToColumn` |
| `lookup` | `table`, `queryCondition`, `returnFields` (mandatory) |
| `update` | `table`, `queryCondition`, `inputFields` with `mappedToColumn` |
| `delete` | `table`, `queryCondition` |
### queryCondition Syntax
Format: `"column_name=={{input_field_name}}"`. Always verify column names by querying `sys_dictionary` before writing tools.
| Operator | Syntax | Example |
|----------|--------|---------|
| Equals | `field=value` | `state=1` |
| Not equals | `field!=value` | `state!=7` |
| Contains | `fieldLIKEvalue` | `short_descriptionLIKEnetwork` |
| Is empty | `fieldISEMPTY` | `assigned_toISEMPTY` |
| OR | `^OR` | `priority=1^ORpriority=2` |
### Lookup Best Practices
- Use `LIKE` operator for text-based searches
- Use multiple keyword inputs with `OR` for natural language
- Prefer `number` over `sys_id` as primary filter: `number={{id}}^ORsys_id={{id}}`
- For reference fields in `returnFields`, include `referenceConfig`: `{ table: "sys_user", field: "name" }`
---
## Script Tools
All script inputs are **strings** at runtime. Parse with `parseInt()`, `JSON.parse()`, etc. The `inputs` field for script tools is a **simple array** of input field definitions (unlike CRUD tools which use an object).
```javascript
(function(inputs) {
var impact = parseInt(inputs.impact, 10);
var urgency = parseInt(inputs.urgency, 10);
// ... logic
return { priority: result, status: 'success' };
})(inputs);
```
- Always use `GlideRecordSecure` (not `GlideRecord`)
- Do NOT add CDATA tags (plugin handles automatically)
- `inputSchema` is auto-generated from `inputs` — do not specify it manually
- Use module imports for server-side script files (or `Now.include()` for legacy scripts)
---
## Reference-Based Tools
Each requires a type-specific reference field containing the target record's sys_id. Do NOT add `inputs`.
| Tool Type | Required Field | Target Table |
|-----------|----------------|--------------|
| `action` | `flowActionId` | `sys_hub_action_type_definition` |
| `capability` | `capabilityId` | `sn_nowassist_skill_config` |
| `subflow` | `subflowId` | `sys_hub_flow` |
| `catalog` | `catalogItemId` | `sc_cat_item` |
| `topic` | `virtualAgentId` | `sys_cs_topic` |
| `topic_block` | `virtualAgentId` | `sys_cs_topic` |
---
## OOB Tools
OOB tools only require `type` and `name`. The plugin auto-links to the existing OOB tool record.
```typescript fluent
{
type: 'web_automation',
name: 'AIA Web Search',
preMessage: 'Searching the web...',
postMessage: 'Web search results retrieved.'
}
```
Other supported OOB types: `'rag'`, `'knowledge_graph'`, `'file_upload'`, `'deep_research'`, `'desktop_automation'`, `'mcp'`.
---
## RAG (Search Retrieval) Tools
RAG tools enable semantic search and document retrieval from ServiceNow tables. The `type` for RAG tools is `'search_retrieval'` and requires structured `inputs` configuration.
### Search Types
| Type | Description | Required Fields |
|------|-------------|----------------|
| `'keyword'` | Simple text matching | None |
| `'semantic'` | Semantic search using embeddings | `semanticIndexes` (array of ValueLabelType) |
| `'hybrid'` | Combines keyword and semantic | `semanticIndexes` (array of ValueLabelType) |
**Note:** The `query` description is generated using the `searchProfile.label`. `semanticIndexes` and `documentMatchThreshold` are only included in the generated schema for `semantic` and `hybrid` search types. `fields` and `searchResultsLimit` apply to all search types.
### RAG Tool Example (Semantic Search)
```typescript fluent
{
name: 'Semantic Knowledge Search',
description: 'Searches knowledge articles using semantic search',
type: 'search_retrieval',
recordType: 'custom',
executionMode: 'autopilot',
preMessage: 'Performing semantic search...',
postMessage: 'Semantic search completed.',
inputs: {
searchType: {
type: 'semantic',
semanticIndexes: [
{ value: 'kb_knowledge_text_index', label: 'Knowledge Base Text Index' }
],
documentMatchThreshold: 0
},
searchProfile: {
value: 'quick_action_kb_search_profile',
label: 'Quick Action - KB Search Profile'
},
sources: [
{ value: 'kb_knowledge', label: 'Knowledge Articles' }
],
fields: [
{ value: 'kb_knowledge.short_description', label: 'Short description [kb_knowledge]' },
{ value: 'kb_knowledge.text', label: 'Article body [kb_knowledge]' },
{ value: 'kb_knowledge.number', label: 'Number [kb_knowledge]' }
],
searchResultsLimit: 5
}
}
```
### Search Type Comparison
| Property | `keyword` | `semantic` | `hybrid` |
|----------|-----------|------------|----------|
| `searchType.type` | `'keyword'` | `'semantic'` | `'hybrid'` |
| `semanticIndexes` | Not applicable | Required | Required |
| `documentMatchThreshold` | Not applicable | Optional (default: 0) | Optional (default: 0) |
| `searchProfile` | Required | Required | Required |
| `sources` | Optional | Optional | Optional |
| `fields` | Optional | Optional | Optional |
| `searchResultsLimit` | Optional | Optional | Optional |
---
## Instructions Authoring
### Three Key Fields
| Field | Purpose | Answers |
|-------|---------|---------|
| `description` | Scope | "What problem does this agent solve?" |
| `agentRole` | Identity (agents only) | "Who am I?" |
| `instructions` | Behavior | "How should I act and use my tools?" |
### Writing Principles
- **Actionable steps**: Every step must bind to a tool action or concrete output
- **Explicit tool references**: Name tools explicitly in instructions
- **Contingencies**: Handle failures with gates: `"DO NOT PROCEED if details are missing"`
- **Trigger context**: Use "from the task" or "from the context" -- NOT "from the triggering record"
### Scaling by Complexity
| Complexity | Tools/Agents | Instructions Length |
|------------|--------------|---------------------|
| Simple | 1-2 tools | 5-10 lines |
| Moderate | 3-4 tools | 10-20 lines |
| Complex | 5+ tools | 20-30 lines |
| Workflow | 2-10 agents | 15-30 lines |
If instructions exceed ~30 lines, split into multiple agents orchestrated by a workflow.
---
## Trigger Configuration
Triggers are optional. Agents/workflows can operate without them via Now Assist Panel.
### Trigger Types
| Type | Description |
|------|-------------|
| `record_create` | On new record creation |
| `record_update` | On record update |
| `record_create_or_update` | On both |
| `email` | On email receipt |
| `scheduled` | On a repeating interval |
| `daily` / `weekly` / `monthly` | Scheduled at specific times |
| `ui_action` (workflows only) | From a UI action button |
### Key Differences: Agent vs Workflow Triggers
| Property | Agent trigger | Workflow trigger |
|----------|--------------|------------------|
| `channel` | `"nap"` or `"nap_and_va"` | `"Now Assist Panel"` (mandatory) |
| `triggerCondition` | Optional | Mandatory for record-based |
| `objectiveTemplate` | Required (defaults to `""`) | Optional |
### Scheduled Trigger Fields
The `schedule` object is used when `triggerFlowDefinitionType` is `'scheduled'`, `'daily'`, `'weekly'`, or `'monthly'`.
| Type | Required Fields (inside `schedule` object) |
|------|---------------------------------------------|
| `daily` | `schedule.time` |
| `weekly` | `schedule.runDayOfWeek` (1=Sun to 7=Sat), `schedule.time` |
| `monthly` | `schedule.runDayOfMonth` (1-31), `schedule.time` |
| `scheduled` | `schedule.repeatInterval` (e.g., `'1970-01-05 12:00:00'` = every 5 days) |
Time format: `"1970-01-01 HH:MM:SS"`.
The `schedule.triggerStrategy` field controls repeat behavior. Values differ by entity type:
| Entity | Valid `triggerStrategy` values |
|--------|-------------------------------|
| AI Agent | `'every'`, `'once'`, `'unique_changes'`, `'always'` |
| AI Agentic Workflow | `'every'`, `'immediate'`, `'manual'`, `'once'`, `'repeat_every'`, `'unique_changes'` |
### Run-As Configuration
For record-based triggers, use one of:
- `runAs: "<column_name>"` — column-based (the column on the target table that holds the user reference)
- `runAsUser: "<sys_id>"` — run as a specific user
- `runAsScript` — a script returning a user sys_id for dynamic resolution
---
## ACL Deployment
Both AI Agents and AI Agentic Workflows use `securityAcl`. The plugin **automatically generates** `sys_security_acl` and `sys_security_acl_role` records — no manual two-step deployment is needed.
The generated ACL name follows the format: `{domain}.{scope}.{name}`
```typescript fluent
// Works the same for both AiAgent and AiAgenticWorkflow
securityAcl: {
$id: Now.ID['my_agent_acl'],
type: 'Specific role',
roles: [
'282bf1fac6112285017366cb5f867469', // itil
'b05926fa0a0a0aa7000130023e0bde98' // user
]
}
```
---
## Workflow Configuration
### Team Structure
Workflows use `$id` for record identity (just like agents). The `team` object also requires its own `$id`.
```typescript fluent
team: {
$id: Now.ID["workflow_team"], // MANDATORY on team
name: "Workflow Team",
// description is auto-populated from workflow.description — do not set it
members: [
"62826bf03710200044e0bfc8bcbe5df1" // Agent sys_id from sn_aia_agent table
]
}
```
Team members can also be specified using the `Record` API (recommended for portability across instances):
```typescript fluent
import { AiAgenticWorkflow, Record } from '@servicenow/sdk/core'
const lookupAgent = Record({ table: 'sn_aia_agent', $id: Now.ID['lookup_agent'], data: { name: 'Lookup Agent' } })
const analysisAgent = Record({ table: 'sn_aia_agent', $id: Now.ID['analysis_agent'], data: { name: 'Analysis Agent' } })
AiAgenticWorkflow({
// ...
team: {
$id: Now.ID['my_team'],
name: 'My Team',
members: [lookupAgent, analysisAgent],
},
})
```
Agents **must** be deployed before creating workflows.
### Workflow-Level Fields
| Field | Type | Default | Notes |
|-------|------|---------|-------|
| `executionMode` | `'copilot' \| 'autopilot'` | `'copilot'` | Execution mode for the workflow |
| `memoryScope` | `string` | `'global'` | Memory scope for team members |
| `active` | `boolean` | `true` | Omit if active (default) |
| `sysDomain` | `string` | `'global'` | Omit if global (default) |
Only specify fields that differ from their defaults — the plugin suppresses default values in the transform output.
### Deployment Order
1. Create and deploy AI Agents (with `securityAcl`)
2. Get agent sys_ids from `sn_aia_agent`
3. Create and deploy workflow with `securityAcl` and agent sys_ids
4. Verify with `run_query` on `sn_aia_usecase`
### contextProcessingScript
Supports inline scripts or `Now.include()` for external files:
```javascript
(function(task, user_utterance, workflow_id, context) {
return {
pageContext: context?.pageContext,
triggerContext: context?.triggerContext
};
})(task, user_utterance, workflow_id, context);
```
```typescript fluent
// Preferred: external file
contextProcessingScript: Now.include('./context-processing-script.js')
```
---
## Complete AI Agent Example
```typescript fluent
import { AiAgent } from "@servicenow/sdk/core";
export const incidentHelperAgent = AiAgent({
$id: Now.ID["incident_helper_agent"],
name: "Incident Helper Agent",
description: "Retrieves incident details and searches for resolution guidance.",
agentRole: "You are an ITSM incident specialist.",
// Security — auto-generates ACL records
securityAcl: {
$id: Now.ID['incident_helper_agent_acl'],
type: 'Specific role',
roles: [
'282bf1fac6112285017366cb5f867469', // itil
'b05926fa0a0a0aa7000130023e0bde98' // user
]
},
agentDescriptor: 'created_by_build_agent',
channel: 'nap_and_va',
recordType: 'custom',
processingMessage: "Analyzing your incident request...",
postProcessingMessage: "Incident analysis complete.",
versionDetails: [{
name: "V1",
number: 1,
state: "published",
instructions: `Step 1: Extract the incident number from the user's request.
Step 2: Use the Lookup Incident tool to fetch details.
Step 3: Present details in bullet-point format.
Step 4: Use AIA Web Search for resolution guidance.
Step 5: Recommend next steps. NEVER modify without user approval.`
}],
tools: [
{
active: true,
name: "Lookup Incident",
description: "Searches for incidents by number",
executionMode: "autopilot",
type: "crud",
recordType: "custom",
preMessage: "Searching for the incident...",
postMessage: "Incident details retrieved.",
inputs: {
operationName: "lookup",
table: "incident",
inputFields: [
{ name: "incident_number", description: "Incident number", mandatory: false }
],
queryCondition: "number={{incident_number}}",
returnFields: [
{ name: "number" },
{ name: "short_description" },
{ name: "state" },
{ name: "priority" },
{ name: "assigned_to", referenceConfig: { table: "sys_user", field: "name" } }
]
}
},
{
type: "web_automation",
name: "AIA Web Search",
active: true,
preMessage: "Searching the web...",
postMessage: "Web search results retrieved."
}
],
triggerConfig: []
});
```
## Complete Workflow Example
```typescript fluent
import { AiAgenticWorkflow } from "@servicenow/sdk/core";
export const incidentAnalysisWorkflow = AiAgenticWorkflow({
$id: Now.ID["incident_analysis_workflow"],
name: "Incident Analysis Workflow",
description: "Orchestrates two agents to retrieve and analyze incidents.",
recordType: "custom",
// Security — auto-generates ACL records (mandatory)
securityAcl: {
$id: Now.ID['incident_analysis_workflow_acl'],
type: 'Specific role',
roles: [
'282bf1fac6112285017366cb5f867469', // itil
'b05926fa0a0a0aa7000130023e0bde98' // user
]
},
// dataAccess required when runAs is omitted (dynamic user identity)
// Use roleMap (role names) or roleList (role sys_ids)
dataAccess: {
roleMap: ['itil', 'user']
},
team: {
$id: Now.ID["incident_analysis_team"],
name: "Incident Analysis Team",
// description is auto-populated from workflow description
members: [
"62826bf03710200044e0bfc8bcbe5df1",
"274b465a7d5f42e581664209557b2b18"
]
},
versions: [{
name: "V1",
number: 1,
state: "published",
instructions: `Step 1: Use the Incident Lookup Agent to fetch details.
Step 2: Use the Analysis Agent to examine patterns.
Step 3: Present findings. NEVER modify without user approval.`
}],
triggerConfig: [{
name: "high_priority_incident",
channel: "Now Assist Panel",
targetTable: "incident",
triggerFlowDefinitionType: "record_create",
triggerCondition: "priority<=2",
objectiveTemplate: "Analyze high priority incident ${number}",
showNotifications: true,
runAsScript: `(function(current) {
return current.assigned_to || "6816f79cc0a8016401c5a33be04be441";
})(current);`
}]
});
```
---
## Editing Existing Agents/Workflows
### Safe Edit Workflow
1. Locate the `.now.ts` file
2. Read the entire current configuration
3. Identify scope of changes (see Change Impact Matrix)
4. Apply only the requested changes
5. Redeploy and verify with `run_query`
### Change Impact Matrix
| Change | Also Update |
|--------|-------------|
| Add CRUD tool | Verify columns, update instructions, check executionMode |
| Remove tool | Remove instruction references, check dependencies |
| Change auth mode | Update `securityAcl.type`, add/remove `roles` as needed |
| Add trigger | Add to `triggerConfig`, verify target table |
| Add team member (workflow) | Deploy agent first, get sys_id, update instructions |
| Update instructions | Ensure all referenced tool/agent names still exist |
### Rollback
Set current published version to `state: "withdrawn"`, set previous version to `state: "published"`, redeploy.
---
## Validation and Enums
### Required Fields
| Entity | Mandatory Fields |
|--------|-----------------|
| AI Agent | `$id`, `name`, `description`, `agentRole`, `securityAcl` |
| AI Agentic Workflow | `$id`, `name`, `description`, `securityAcl`, `team.$id` |
| CRUD tool | `name`, `type`, `inputs.operationName`, `inputs.table`, `inputs.inputFields` |
| Script tool | `name`, `type`, `script` |
### Valid Enums
| Property | Valid Values |
|----------|-------------|
| `recordType` (agent) | `"custom"`, `"template"`, `"aia_internal"`, `"promoted"` (default: `"template"`) |
| `recordType` (workflow) | `"custom"`, `"template"`, `"aia_internal"` (default: `"template"`) |
| `executionMode` (tool) | `"autopilot"`, `"copilot"` |
| `executionMode` (workflow) | `"autopilot"`, `"copilot"` (default: `"copilot"`) |
| `state` (version) | `"draft"`, `"committed"`, `"published"`, `"withdrawn"` (default: `"draft"`) |
| `tool.type` | `"script"`, `"crud"`, `"capability"`, `"subflow"`, `"action"`, `"catalog"`, `"topic"`, `"topic_block"`, `"web_automation"`, `"rag"`, `"knowledge_graph"`, `"file_upload"`, `"deep_research"`, `"desktop_automation"`, `"mcp"` |
| `securityAcl.type` | `'Any authenticated user'`, `'Specific role'`, `'Public'` |
| `agentDescriptor` | `"require_caller_id"`, `"created_by_ai_agent_advisor"`, `"created_by_build_agent"`, `""` (default: `""`) |
| `agentType` | `"internal"`, `"external"`, `"voice"`, `"aia_internal"` |
| `channel` (agent) | `"nap"`, `"nap_and_va"` (default: `"nap_and_va"`) |
| `schedule.triggerStrategy` (agent) | `"every"`, `"once"`, `"unique_changes"`, `"always"` |
| `schedule.triggerStrategy` (workflow) | `"every"`, `"immediate"`, `"manual"`, `"once"`, `"repeat_every"`, `"unique_changes"` |
| `outputTransformationStrategy` | `"abstract_summary"`, `"custom"`, `"none"`, `"paraphrase"`, `"summary"`, `"summary_for_search_results"` |
### Common Hallucinations to Avoid
| Wrong | Correct |
|-------|---------|
| `"standard"` | `"custom"` (recordType) |
| `"automatic"` | `"autopilot"` (executionMode) |
| `"active"` | `"published"` (state) |
| `"database"` | `"crud"` (tool.type) |
| `versions` (for agents) | `versionDetails` |
| `versionDetails` (for workflows) | `versions` |
| `runAs` (for agents) | `runAsUser` |
| `"nap"` (for workflow triggers) | `"Now Assist Panel"` |
| `acl: "..."` (for agents or workflows) | `securityAcl: { $id, type, roles? }` (mandatory for both) |
| Missing `securityAcl` on workflows | `securityAcl` is mandatory for workflows too, not just agents |
| `securityAcl: { userAccess: 'dynamic_user' }` | `securityAcl: { $id, type: 'Any authenticated user' \| 'Specific role' \| 'Public' }` |
| Missing `$id` at workflow top level | Workflows use `$id` just like agents — always include it |
| `processingMessage` on workflows | Agent-only field — not valid on `AiAgenticWorkflow` |
| `postProcessingMessage` on workflows | Agent-only field — not valid on `AiAgenticWorkflow` |
| `team.description` set manually | Auto-populated from workflow `description` — do not set |
| Manual `inputSchema` | Auto-generated from `inputs` — never set manually |
| `inputs: {...}` for script tools | `inputs: [...]` (array, not object) for script tools |
| `dataAccess` omitted when `runAs` absent (workflow) | `dataAccess` is mandatory for workflows when `runAs` is not set |
| `searchProfile: "profile_name"` (RAG) | `searchProfile: { value: "profile_name", label: "Display Name" }` (ValueLabelType required) |
| `sources: ["table1", "table2"]` (RAG) | `sources: [{ value: "table1", label: "Label1" }, ...]` (ValueLabelType array required) |
| `semanticIndexes: ["index1"]` (RAG) | `semanticIndexes: [{ value: "index1", label: "Label1" }]` (ValueLabelType array required) |
| `fields: ["field1", "field2"]` (RAG) | `fields: [{ value: "field1", label: "Label1" }, ...]` (ValueLabelType array required) |
---
## Error Recovery
| Error Pattern | Category | Resolution |
|---------------|----------|------------|
| `dataAccess must have at least one of roleList or roleMap` | Missing roles | Add `dataAccess.roleMap` (role names) or `dataAccess.roleList` (role sys_ids) — required when `runAsUser`/`runAs` is not set |
| `Table not found` | Bad table name | Query `sys_db_object` to verify |
| `Record not found` / `Invalid reference` | Bad sys_id | Query appropriate table for correct sys_id |
| `Duplicate name` | Name collision | Query both `sn_aia_agent` and `sn_aia_usecase` |
| ACL / permission error | ACL misconfiguration | Verify `securityAcl` is set correctly |
---
## Database Tables
| Table | Purpose |
|-------|---------|
| `sn_aia_agent` | AI Agent records |
| `sn_aia_agent_config` | Agent configuration and settings |
| `sn_aia_usecase` | AI Agentic Workflow records |
| `sn_aia_usecase_config_override` | Configuration overrides for workflows |
| `sn_aia_team` | Team configuration |
| `sn_aia_team_member` | Team member records |
| `sn_aia_version` | Version information |
| `sn_aia_tool` | Tool definitions |
| `sn_aia_agent_tool_m2m` | Agent-to-tool relationships |
| `sn_aia_trigger_configuration` | Trigger configuration |
| `sn_aia_trigger_agent_usecase_m2m` | Trigger-agent-usecase mappings |
| `sys_agent_access_role_configuration` | Role-based data access controls |
| `sys_security_acl` | ACL records (auto-generated by `securityAcl`) |
| `sys_user_role` | Role records |