scc-universal 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.cursor/agents/sf-agentforce-agent.md +88 -40
- package/.cursor/skills/sf-2gp-security-review/SKILL.md +167 -0
- package/.cursor/skills/sf-agentforce-development/SKILL.md +385 -348
- package/.cursor/skills/sf-cli-reference/SKILL.md +221 -0
- package/.cursor-plugin/plugin.json +1 -1
- package/agents/sf-agentforce-agent.md +88 -40
- package/manifests/install-modules.json +3 -1
- package/package.json +1 -1
- package/skills/_reference/AGENTFORCE_PATTERNS.md +433 -51
- package/skills/_reference/APPEXCHANGE_REVIEW.md +427 -0
- package/skills/_reference/SF_CLI_COMMANDS.md +812 -0
- package/skills/sf-2gp-security-review/SKILL.md +168 -0
- package/skills/sf-agentforce-development/SKILL.md +385 -348
- package/skills/sf-cli-reference/SKILL.md +225 -0
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-agentforce-development
|
|
3
3
|
description: >-
|
|
4
|
-
Agentforce
|
|
4
|
+
Agentforce agent development — Agent Script, topics, actions, testing, metadata. Use when building Agentforce agents. Do NOT use for non-Agentforce Apex or Flow-only automation.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Agentforce Development
|
|
8
8
|
|
|
9
|
-
Procedures for building Agentforce AI agents
|
|
9
|
+
Procedures for building Agentforce AI agents. Architecture, syntax reference, metadata types, instruction guidelines, and context engineering principles live in the reference file.
|
|
10
10
|
|
|
11
11
|
@../_reference/AGENTFORCE_PATTERNS.md
|
|
12
12
|
|
|
13
13
|
## When to Use
|
|
14
14
|
|
|
15
|
-
- Building Agentforce AI agents
|
|
15
|
+
- Building Agentforce AI agents with Agent Script (`.agent` files)
|
|
16
|
+
- Generating and publishing authoring bundles via CLI
|
|
16
17
|
- Configuring agent topics, actions, or conversation instructions
|
|
17
18
|
- Creating custom Apex actions or Flow actions for Agentforce
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- Reviewing Agentforce limits or security requirements
|
|
19
|
+
- Testing agents with YAML test specs, CLI, or Testing Center
|
|
20
|
+
- Deploying agent metadata (GenAi types) to orgs
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -31,419 +31,456 @@ Procedures for building Agentforce AI agents on the Salesforce platform. Archite
|
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Development Approaches
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
| | Agent Script (Recommended) | Classic Setup |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| **API version** | v65+ | v60+ |
|
|
39
|
+
| **Surface** | `.agent` files in VS Code + CLI | Agentforce Builder UI |
|
|
40
|
+
| **Source control** | Yes — diffable `.agent` files | No — UI-only |
|
|
41
|
+
| **CI/CD** | Full: validate → publish → test → activate | Limited: deploy GenAi metadata |
|
|
42
|
+
| **When to use** | All new agents; teams needing code review | Orgs on API < v65; admin-managed simple agents |
|
|
37
43
|
|
|
44
|
+
**Default to Agent Script** for all new development.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Agent Script Development
|
|
49
|
+
|
|
50
|
+
### File Structure
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
force-app/main/default/aiAuthoringBundles/My_Agent/
|
|
54
|
+
My_Agent.agent # Agent Script file
|
|
55
|
+
My_Agent.bundle-meta.xml # Metadata XML
|
|
38
56
|
```
|
|
39
|
-
Topic Name: Case Management
|
|
40
|
-
Description: Handles customer service case creation, updating, and
|
|
41
|
-
status inquiries. Covers support tickets and complaints.
|
|
42
57
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
### CLI Workflow
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Generate authoring bundle (from spec or --no-spec for boilerplate)
|
|
62
|
+
sf agent generate authoring-bundle --spec specs/agentSpec.yaml \
|
|
63
|
+
--name "My Agent" --api-name My_Agent
|
|
64
|
+
|
|
65
|
+
# Edit .agent file in VS Code (syntax highlighting + validation)
|
|
66
|
+
# Validate → Publish → Preview → Activate
|
|
67
|
+
sf agent validate authoring-bundle --target-org MySandbox
|
|
68
|
+
sf agent publish authoring-bundle --target-org MySandbox
|
|
69
|
+
sf agent preview --target-org MySandbox
|
|
70
|
+
sf agent activate --api-name My_Agent --target-org MySandbox
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Complete Example
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
config:
|
|
77
|
+
developer_name: "Service_Agent"
|
|
78
|
+
agent_label: "Customer Service Agent"
|
|
79
|
+
|
|
80
|
+
variables:
|
|
81
|
+
customer_email: mutable string = ""
|
|
82
|
+
is_verified: mutable boolean = False
|
|
83
|
+
session_lang: linked string
|
|
84
|
+
source: "EndUserLanguage"
|
|
85
|
+
|
|
86
|
+
system:
|
|
87
|
+
instructions: |
|
|
88
|
+
You are a customer service agent. Be friendly and concise.
|
|
89
|
+
Always verify identity before accessing account data.
|
|
90
|
+
messages:
|
|
91
|
+
welcome: "Hello! How can I help you today?"
|
|
92
|
+
error: "I apologize. Let me transfer you to a team member."
|
|
93
|
+
|
|
94
|
+
start_agent topic_selector:
|
|
95
|
+
description: "Routes messages to the appropriate topic"
|
|
96
|
+
reasoning:
|
|
97
|
+
instructions: ->
|
|
98
|
+
| Analyze the message and determine the best topic.
|
|
99
|
+
actions:
|
|
100
|
+
verify: @utils.transition to @topic.identity
|
|
101
|
+
description: "Verify customer identity"
|
|
102
|
+
orders: @utils.transition to @topic.order_management
|
|
103
|
+
description: "Help with order status or modifications"
|
|
104
|
+
|
|
105
|
+
topic identity:
|
|
106
|
+
description: "Verifies customer identity via email lookup"
|
|
107
|
+
reasoning:
|
|
108
|
+
instructions: ->
|
|
109
|
+
if @variables.is_verified == True:
|
|
110
|
+
| Customer is already verified.
|
|
111
|
+
transition to @topic.order_management
|
|
112
|
+
| Ask for their email address to verify identity.
|
|
113
|
+
actions:
|
|
114
|
+
lookup:
|
|
115
|
+
action: @actions.lookup_customer
|
|
116
|
+
description: "Look up customer by email"
|
|
117
|
+
inputs:
|
|
118
|
+
email: ...
|
|
119
|
+
set:
|
|
120
|
+
is_verified: output.found
|
|
121
|
+
|
|
122
|
+
after_reasoning: ->
|
|
123
|
+
if @variables.is_verified == True:
|
|
124
|
+
transition to @topic.order_management
|
|
125
|
+
|
|
126
|
+
topic order_management:
|
|
127
|
+
description: "Helps customers check order status"
|
|
128
|
+
reasoning:
|
|
129
|
+
instructions: ->
|
|
130
|
+
if @variables.is_verified == False:
|
|
131
|
+
transition to @topic.identity
|
|
132
|
+
| Help the customer with their order inquiry.
|
|
133
|
+
actions:
|
|
134
|
+
get_order:
|
|
135
|
+
action: @actions.get_order_details
|
|
136
|
+
description: "Retrieve order details by order number"
|
|
137
|
+
inputs:
|
|
138
|
+
order_number: ...
|
|
139
|
+
customer_email: @variables.customer_email
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Key Patterns
|
|
143
|
+
|
|
144
|
+
**Deterministic** (`->`) — guaranteed execution:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
-> if @variables.is_verified == False:
|
|
148
|
+
transition to @topic.identity
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**LLM prompts** (`|`) — accumulated and sent to model:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
| Help the customer with their order.
|
|
155
|
+
| Be concise and provide the order number.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Deterministic action** (`run`) — bypasses LLM:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
-> run @actions.get_recent_orders with
|
|
162
|
+
customer_id: @variables.customer_id
|
|
163
|
+
set
|
|
164
|
+
recent_orders: result
|
|
53
165
|
```
|
|
54
166
|
|
|
55
167
|
---
|
|
56
168
|
|
|
57
|
-
##
|
|
169
|
+
## Action Types
|
|
58
170
|
|
|
59
|
-
###
|
|
171
|
+
### Apex @InvocableMethod
|
|
172
|
+
|
|
173
|
+
Apex actions are built by `sf-apex-agent` using patterns from `sf-apex-constraints`. Key Agentforce-specific requirements for `@InvocableMethod` actions:
|
|
174
|
+
|
|
175
|
+
- **Labels/descriptions are critical** — the LLM reads these to decide routing. Keep in sync between Apex annotations and Builder action config
|
|
176
|
+
- **InvocableVariable descriptions** must specify data type and format: `"accountId — 18-digit Account record ID"`
|
|
177
|
+
- **Return result objects** (not void) — agent needs structured confirmation to continue reasoning
|
|
178
|
+
- **Use `Database` class** (partial success) not DML verbs (all-or-nothing)
|
|
179
|
+
- **Varied verb names** across actions: "Locate", "Retrieve", "Calculate" — not "Get X", "Get Y"
|
|
180
|
+
- **Decompose** complex actions to avoid CPU timeout (10s sync limit)
|
|
181
|
+
- **Long-running work**: enqueue Queueable, return requestId for status tracking
|
|
182
|
+
|
|
183
|
+
### MCP Server
|
|
60
184
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Description = req.description,
|
|
81
|
-
Priority = req.priority != null ? req.priority : 'Medium',
|
|
82
|
-
Status = 'New',
|
|
83
|
-
Origin = 'Agentforce'
|
|
84
|
-
));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
List<Database.SaveResult> saveResults =
|
|
88
|
-
Database.insert(casesToInsert, false, AccessLevel.USER_MODE);
|
|
89
|
-
|
|
90
|
-
Set<Id> successIds = new Set<Id>();
|
|
91
|
-
for (Database.SaveResult sr : saveResults) {
|
|
92
|
-
if (sr.isSuccess()) successIds.add(sr.getId());
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
Map<Id, Case> caseMap = new Map<Id, Case>(
|
|
96
|
-
[SELECT Id, CaseNumber FROM Case WHERE Id IN :successIds]
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
for (Database.SaveResult sr : saveResults) {
|
|
100
|
-
CreateCaseResult result = new CreateCaseResult();
|
|
101
|
-
if (sr.isSuccess()) {
|
|
102
|
-
result.caseId = sr.getId();
|
|
103
|
-
result.caseNumber = caseMap.get(sr.getId())?.CaseNumber;
|
|
104
|
-
result.success = true;
|
|
105
|
-
result.message = 'Case created: ' + result.caseNumber;
|
|
106
|
-
} else {
|
|
107
|
-
result.success = false;
|
|
108
|
-
result.message = 'Failed: ' + sr.getErrors()[0].getMessage();
|
|
109
|
-
}
|
|
110
|
-
results.add(result);
|
|
111
|
-
}
|
|
112
|
-
return results;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
public class CreateCaseRequest {
|
|
116
|
-
@InvocableVariable(label='Account ID'
|
|
117
|
-
description='Salesforce Account ID of the customer'
|
|
118
|
-
required=true)
|
|
119
|
-
public Id accountId;
|
|
120
|
-
|
|
121
|
-
@InvocableVariable(label='Contact ID'
|
|
122
|
-
description='Contact ID raising the case' required=false)
|
|
123
|
-
public Id contactId;
|
|
124
|
-
|
|
125
|
-
@InvocableVariable(label='Subject'
|
|
126
|
-
description='Brief issue description (max 255 chars)'
|
|
127
|
-
required=true)
|
|
128
|
-
public String subject;
|
|
129
|
-
|
|
130
|
-
@InvocableVariable(label='Description'
|
|
131
|
-
description='Detailed issue description' required=false)
|
|
132
|
-
public String description;
|
|
133
|
-
|
|
134
|
-
@InvocableVariable(label='Priority'
|
|
135
|
-
description='Low, Medium, High, Critical' required=false)
|
|
136
|
-
public String priority;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
public class CreateCaseResult {
|
|
140
|
-
@InvocableVariable(label='Case ID')
|
|
141
|
-
public Id caseId;
|
|
142
|
-
|
|
143
|
-
@InvocableVariable(label='Case Number')
|
|
144
|
-
public String caseNumber;
|
|
145
|
-
|
|
146
|
-
@InvocableVariable(label='Success')
|
|
147
|
-
public Boolean success;
|
|
148
|
-
|
|
149
|
-
@InvocableVariable(label='Message')
|
|
150
|
-
public String message;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
185
|
+
External tools exposed to Agentforce via Model Context Protocol (JSON-RPC 2.0 over HTTP/SSE).
|
|
186
|
+
|
|
187
|
+
- **Setup**: Register server in MCP Server Registry (Setup > MCP Servers). Tools appear in Agentforce Asset Library
|
|
188
|
+
- **Auth**: OAuth 2.0 with Integration User. Principle of least privilege. FLS and sharing rules enforced
|
|
189
|
+
- **Rate limit**: ~50 requests/min/server
|
|
190
|
+
- **Tool discovery**: On connection, server returns schema with tool names, descriptions, required/optional parameters, return types
|
|
191
|
+
- **Prebuilt servers**: Salesforce DX MCP Server (deploy, test, scratch orgs), Heroku Platform, MuleSoft
|
|
192
|
+
- **Hosted MCP (Pilot)**: Fully managed cloud endpoints — zero infrastructure. Pre-built for core CRM and B2C Commerce APIs
|
|
193
|
+
|
|
194
|
+
### Named Query (GA)
|
|
195
|
+
|
|
196
|
+
Parameterized SOQL exposed as REST API endpoint and agent action. No Apex or Flow required.
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
Query Name: GetRecentOrders
|
|
200
|
+
SOQL: SELECT Id, Name, Status__c, CreatedDate
|
|
201
|
+
FROM Order__c
|
|
202
|
+
WHERE AccountId = :accountId
|
|
203
|
+
ORDER BY CreatedDate DESC LIMIT 5
|
|
153
204
|
```
|
|
154
205
|
|
|
155
|
-
|
|
206
|
+
- Auto-creates REST endpoint: `/services/data/v66.0/named/query/GetRecentOrders?accountId=001xx...`
|
|
207
|
+
- Activate in API Catalog, then add as agent action
|
|
208
|
+
- **Limitation**: Input parameters only in WHERE and LIMIT clauses. Cannot edit after agent action activation without deactivation
|
|
209
|
+
|
|
210
|
+
### AuraEnabled Methods (Beta)
|
|
211
|
+
|
|
212
|
+
Reuse existing `@AuraEnabled` controller methods as agent actions:
|
|
213
|
+
|
|
214
|
+
1. Generate OpenAPI spec: VS Code → "SFDX: Create OpenAPI Document from This Class" → creates `.yaml` + `.externalServiceRegistration-meta.xml`
|
|
215
|
+
1. Optionally add `x-sfdc: publishAsAgentAction: true` for auto-creation
|
|
216
|
+
1. Deploy to API Catalog
|
|
217
|
+
1. Add as agent action (category: "AuraEnabled Method (Beta)")
|
|
218
|
+
|
|
219
|
+
### Apex Citations
|
|
220
|
+
|
|
221
|
+
Source attribution in agent responses. Two approaches:
|
|
156
222
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
223
|
+
| Class | Behavior | Use When |
|
|
224
|
+
|---|---|---|
|
|
225
|
+
| `AiCopilot.GenAiCitationInput` | Supplies sources to reasoning engine; engine auto-places inline numbered citations | Default — let the engine decide placement |
|
|
226
|
+
| `AiCopilot.GenAiCitationOutput` | Direct control over citation placement; bypasses reasoning engine | Predetermined citation logic needed |
|
|
227
|
+
|
|
228
|
+
Supported sources: knowledge articles, PDF files, external web pages. Requires agent created after May 2025. Action must return both generated response and citation metadata.
|
|
229
|
+
|
|
230
|
+
### Lightning Types
|
|
231
|
+
|
|
232
|
+
Custom LWC components for rich conversational UI in agent responses.
|
|
165
233
|
|
|
166
|
-
// Return a result object (agent needs confirmation), not void
|
|
167
|
-
// Bulkify — agent runtime may batch calls
|
|
168
234
|
```
|
|
235
|
+
lightningTypes/
|
|
236
|
+
flightResponse/
|
|
237
|
+
schema.json # JSON Schema for validation
|
|
238
|
+
lightningDesktopGenAi/ # Channel: Employee Agent
|
|
239
|
+
renderer.json # Output LWC component
|
|
240
|
+
enhancedWebChat/ # Channel: Service Agent (Enhanced Chat v2)
|
|
241
|
+
renderer.json
|
|
242
|
+
flightFilter/
|
|
243
|
+
schema.json
|
|
244
|
+
lightningDesktopGenAi/
|
|
245
|
+
editor.json # Input LWC component
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
- LWC targets: `lightning__AgentforceInput` (editor), `lightning__AgentforceOutput` (renderer)
|
|
249
|
+
- **Constraint**: Custom Lightning Types only override UI for actions using **Apex classes** as input/output
|
|
250
|
+
- Editor LWC must include `handleInputChange()` dispatching `valuechange` event
|
|
251
|
+
|
|
252
|
+
### Adaptive Response Formats
|
|
253
|
+
|
|
254
|
+
Rich responses without custom LWC development (Service Agents on messaging channels):
|
|
255
|
+
|
|
256
|
+
| Format | UI | Fields |
|
|
257
|
+
|---|---|---|
|
|
258
|
+
| **Rich Choice** | Carousel, buttons, list selector | Title, description, link, image per tile |
|
|
259
|
+
| **Rich Link** | Media card | Link title, URL, image, description |
|
|
260
|
+
|
|
261
|
+
Determined automatically by returned data structure from Apex or Flow actions.
|
|
169
262
|
|
|
170
263
|
---
|
|
171
264
|
|
|
172
|
-
## Flow Actions
|
|
265
|
+
## Flow Actions
|
|
173
266
|
|
|
174
|
-
Use
|
|
267
|
+
Use when logic involves declarative orchestration or non-developer maintenance.
|
|
175
268
|
|
|
176
269
|
```
|
|
177
|
-
Flow: Update_Account_Segment (Autolaunched
|
|
178
|
-
Variables:
|
|
179
|
-
|
|
180
|
-
- newSegment (Input, Text, Required)
|
|
181
|
-
- result (Output, Text)
|
|
182
|
-
|
|
183
|
-
Steps:
|
|
184
|
-
1. Get Records: Account WHERE Id = {accountId}
|
|
185
|
-
2. Decision: Is segment different from current?
|
|
186
|
-
3. Update Records: Account.Segment__c = {newSegment}
|
|
187
|
-
4. Assignment: result = "Segment updated to " + {newSegment}
|
|
270
|
+
Flow: Update_Account_Segment (Autolaunched)
|
|
271
|
+
Variables: accountId (Input), newSegment (Input), result (Output)
|
|
272
|
+
Steps: Get Record → Decision → Update Record → Assign result
|
|
188
273
|
```
|
|
189
274
|
|
|
190
|
-
Add
|
|
275
|
+
Add to topics in Setup or reference in Agent Script `reasoning.actions`.
|
|
191
276
|
|
|
192
277
|
---
|
|
193
278
|
|
|
194
279
|
## Prompt Templates
|
|
195
280
|
|
|
196
|
-
### Creating a Flex Prompt Template
|
|
197
|
-
|
|
198
281
|
```
|
|
199
282
|
Template Name: Case Summary for Agent
|
|
200
|
-
Template Type: Flex
|
|
283
|
+
Template Type: Flex
|
|
201
284
|
Grounding: Case record
|
|
202
285
|
|
|
203
|
-
|
|
204
|
-
You are a helpful customer service assistant.
|
|
286
|
+
Body:
|
|
205
287
|
Summarise the following case for a support representative.
|
|
206
|
-
|
|
207
|
-
Case Details:
|
|
208
288
|
- Case Number: {!$Input:Case.CaseNumber}
|
|
209
289
|
- Subject: {!$Input:Case.Subject}
|
|
210
290
|
- Status: {!$Input:Case.Status}
|
|
211
|
-
- Priority: {!$Input:Case.Priority}
|
|
212
291
|
- Customer: {!$Input:Case.Account.Name}
|
|
213
|
-
- Description: {!$Input:Case.Description}
|
|
214
292
|
|
|
215
|
-
Provide:
|
|
216
|
-
1. A 2-sentence summary of the issue
|
|
217
|
-
2. Recommended next action
|
|
218
|
-
3. Estimated complexity: Low/Medium/High
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Using Prompt Templates in Apex
|
|
222
|
-
|
|
223
|
-
> Note: The ConnectApi surface for Einstein/Agentforce changes rapidly. Verify exact class/method names against the ConnectApi Apex Reference for your target API version (v66.0 Spring '26).
|
|
224
|
-
|
|
225
|
-
```apex
|
|
226
|
-
public with sharing class PromptTemplateAction {
|
|
227
|
-
|
|
228
|
-
@InvocableMethod(
|
|
229
|
-
label='Generate Case Summary'
|
|
230
|
-
description='Generates an AI summary using Einstein Prompt Template'
|
|
231
|
-
)
|
|
232
|
-
public static List<SummaryResult> generateCaseSummary(
|
|
233
|
-
List<SummaryRequest> requests) {
|
|
234
|
-
List<SummaryResult> results = new List<SummaryResult>();
|
|
235
|
-
|
|
236
|
-
for (SummaryRequest req : requests) {
|
|
237
|
-
try {
|
|
238
|
-
ConnectApi.EinsteinPromptTemplateGenerationsRepresentation
|
|
239
|
-
response = ConnectApi.EinsteinLLM
|
|
240
|
-
.generateMessagesForPromptTemplate(
|
|
241
|
-
'Case_Summary_for_Agent',
|
|
242
|
-
new Map<String, String>{
|
|
243
|
-
'Input:Case' => req.caseId
|
|
244
|
-
},
|
|
245
|
-
new Map<String, ConnectApi
|
|
246
|
-
.EinsteinPromptTemplateGenerationsInput>()
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
SummaryResult result = new SummaryResult();
|
|
250
|
-
result.summary = response.generations[0].text;
|
|
251
|
-
result.success = true;
|
|
252
|
-
results.add(result);
|
|
253
|
-
} catch (Exception e) {
|
|
254
|
-
SummaryResult result = new SummaryResult();
|
|
255
|
-
result.success = false;
|
|
256
|
-
result.errorMessage = e.getMessage();
|
|
257
|
-
results.add(result);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return results;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
public class SummaryRequest {
|
|
264
|
-
@InvocableVariable(label='Case ID' required=true)
|
|
265
|
-
public Id caseId;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
public class SummaryResult {
|
|
269
|
-
@InvocableVariable(label='Summary')
|
|
270
|
-
public String summary;
|
|
271
|
-
@InvocableVariable(label='Success')
|
|
272
|
-
public Boolean success;
|
|
273
|
-
@InvocableVariable(label='Error Message')
|
|
274
|
-
public String errorMessage;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
293
|
+
Provide: 1) 2-sentence summary 2) Recommended next action 3) Complexity: Low/Medium/High
|
|
277
294
|
```
|
|
278
295
|
|
|
279
296
|
---
|
|
280
297
|
|
|
281
|
-
##
|
|
298
|
+
## Testing
|
|
299
|
+
|
|
300
|
+
Apex unit tests for `@InvocableMethod` actions are handled by `sf-apex-agent` using `sf-testing-constraints`. This section covers **agent-level testing** — verifying topic routing, action execution, and response quality.
|
|
301
|
+
|
|
302
|
+
### Agent Test Spec (YAML)
|
|
303
|
+
|
|
304
|
+
```yaml
|
|
305
|
+
name: Service_Agent_Tests
|
|
306
|
+
description: End-to-end tests for Customer Service Agent
|
|
307
|
+
subjectType: AGENT
|
|
308
|
+
subjectName: Service_Agent
|
|
309
|
+
subjectVersion: v1
|
|
310
|
+
testCases:
|
|
311
|
+
- utterance: "What's the status of order #12345?"
|
|
312
|
+
expectedTopic: Order_Management
|
|
313
|
+
expectedActions:
|
|
314
|
+
- get_order_details
|
|
315
|
+
expectedOutcome: "Agent provides order status details including shipping info"
|
|
316
|
+
contextVariables:
|
|
317
|
+
- name: EndUserLanguage
|
|
318
|
+
value: en
|
|
319
|
+
metrics:
|
|
320
|
+
- topic_sequence_match
|
|
321
|
+
- action_sequence_match
|
|
322
|
+
- bot_response_rating
|
|
323
|
+
- coherence
|
|
324
|
+
- completeness
|
|
325
|
+
- conciseness
|
|
326
|
+
- latency
|
|
327
|
+
|
|
328
|
+
- utterance: "I need to file a complaint about my delivery"
|
|
329
|
+
expectedTopic: Case_Management
|
|
330
|
+
expectedActions:
|
|
331
|
+
- create_support_case
|
|
332
|
+
expectedOutcome: "Agent creates a case and provides the case number"
|
|
333
|
+
metrics:
|
|
334
|
+
- topic_sequence_match
|
|
335
|
+
- action_sequence_match
|
|
336
|
+
- bot_response_rating
|
|
337
|
+
- instructionAdherence
|
|
338
|
+
|
|
339
|
+
- utterance: "Hola, necesito ayuda con mi pedido"
|
|
340
|
+
expectedTopic: Order_Management
|
|
341
|
+
contextVariables:
|
|
342
|
+
- name: EndUserLanguage
|
|
343
|
+
value: es
|
|
344
|
+
metrics:
|
|
345
|
+
- topic_sequence_match
|
|
346
|
+
- coherence
|
|
347
|
+
```
|
|
282
348
|
|
|
283
|
-
|
|
349
|
+
### Multi-Turn Conversation Testing
|
|
350
|
+
|
|
351
|
+
```yaml
|
|
352
|
+
testCases:
|
|
353
|
+
- utterance: "I want to return my order"
|
|
354
|
+
expectedTopic: Order_Management
|
|
355
|
+
conversationHistory:
|
|
356
|
+
- role: user
|
|
357
|
+
message: "Hi, I need help"
|
|
358
|
+
- role: agent
|
|
359
|
+
message: "Hello! How can I help you today?"
|
|
360
|
+
topic: topic_selector
|
|
361
|
+
- role: user
|
|
362
|
+
message: "I have a problem with order #12345"
|
|
363
|
+
- role: agent
|
|
364
|
+
message: "I found order #12345. It was delivered on March 15."
|
|
365
|
+
topic: Order_Management
|
|
366
|
+
metrics:
|
|
367
|
+
- topic_sequence_match
|
|
368
|
+
- action_sequence_match
|
|
369
|
+
```
|
|
284
370
|
|
|
285
|
-
|
|
371
|
+
### Custom Evaluations
|
|
286
372
|
|
|
373
|
+
```yaml
|
|
374
|
+
testCases:
|
|
375
|
+
- utterance: "What's the weather in SF?"
|
|
376
|
+
customEvaluations:
|
|
377
|
+
- label: Temperature Check
|
|
378
|
+
jsonPathExpression: $.actions[0].result.temperature
|
|
379
|
+
comparisonOperator: greaterThan
|
|
380
|
+
expectedValue: "0"
|
|
287
381
|
```
|
|
288
|
-
Topic: CaseTriage
|
|
289
|
-
|
|
290
|
-
Step 1 (Deterministic — Apex):
|
|
291
|
-
Call: EscalateCaseAction
|
|
292
|
-
Condition: case.Priority == 'Critical'
|
|
293
382
|
|
|
294
|
-
|
|
295
|
-
Call: GetKnowledgeArticles
|
|
296
|
-
Input: case.Subject
|
|
297
|
-
-> Grounds the LLM with relevant articles
|
|
383
|
+
### CLI Test Workflow
|
|
298
384
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
385
|
+
```bash
|
|
386
|
+
# Generate test spec from agent definition
|
|
387
|
+
sf agent generate test-spec --output-file specs/testSpec.yaml
|
|
302
388
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
-> Audit trail logged regardless of LLM output
|
|
306
|
-
```
|
|
389
|
+
# Create test in org from YAML spec
|
|
390
|
+
sf agent test create --spec specs/testSpec.yaml --target-org MySandbox
|
|
307
391
|
|
|
308
|
-
|
|
392
|
+
# Run tests synchronously with JUnit output (CI-friendly)
|
|
393
|
+
sf agent test run --api-name Service_Agent_Tests --wait 10 \
|
|
394
|
+
--result-format junit --output-dir ./test-results \
|
|
395
|
+
--target-org MySandbox
|
|
309
396
|
|
|
310
|
-
|
|
397
|
+
# View results
|
|
398
|
+
sf agent test results --test-id <id> --target-org MySandbox
|
|
311
399
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
### Unit Testing Apex Actions
|
|
315
|
-
|
|
316
|
-
```apex
|
|
317
|
-
@IsTest
|
|
318
|
-
public class CaseManagementActionTest {
|
|
319
|
-
|
|
320
|
-
@TestSetup
|
|
321
|
-
static void setup() {
|
|
322
|
-
Account acc = new Account(Name='Test Account');
|
|
323
|
-
insert acc;
|
|
324
|
-
Contact con = new Contact(LastName='Doe', AccountId=acc.Id);
|
|
325
|
-
insert con;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
@IsTest
|
|
329
|
-
static void testCreateCase_validInput_createsCase() {
|
|
330
|
-
Account acc = [SELECT Id FROM Account LIMIT 1];
|
|
331
|
-
Contact con = [SELECT Id FROM Contact LIMIT 1];
|
|
332
|
-
|
|
333
|
-
CaseManagementAction.CreateCaseRequest req =
|
|
334
|
-
new CaseManagementAction.CreateCaseRequest();
|
|
335
|
-
req.accountId = acc.Id;
|
|
336
|
-
req.contactId = con.Id;
|
|
337
|
-
req.subject = 'Cannot access portal';
|
|
338
|
-
req.priority = 'High';
|
|
339
|
-
|
|
340
|
-
Test.startTest();
|
|
341
|
-
List<CaseManagementAction.CreateCaseResult> results =
|
|
342
|
-
CaseManagementAction.createSupportCase(
|
|
343
|
-
new List<CaseManagementAction.CreateCaseRequest>{req});
|
|
344
|
-
Test.stopTest();
|
|
345
|
-
|
|
346
|
-
System.assert(results[0].success);
|
|
347
|
-
System.assertNotEquals(null, results[0].caseId);
|
|
348
|
-
|
|
349
|
-
Case created = [SELECT Status, Origin, Priority
|
|
350
|
-
FROM Case WHERE Id = :results[0].caseId];
|
|
351
|
-
System.assertEquals('Agentforce', created.Origin);
|
|
352
|
-
System.assertEquals('High', created.Priority);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
@IsTest
|
|
356
|
-
static void testCreateCase_bulk_createsMultipleCases() {
|
|
357
|
-
Account acc = [SELECT Id FROM Account LIMIT 1];
|
|
358
|
-
|
|
359
|
-
List<CaseManagementAction.CreateCaseRequest> requests =
|
|
360
|
-
new List<CaseManagementAction.CreateCaseRequest>();
|
|
361
|
-
for (Integer i = 0; i < 200; i++) {
|
|
362
|
-
CaseManagementAction.CreateCaseRequest req =
|
|
363
|
-
new CaseManagementAction.CreateCaseRequest();
|
|
364
|
-
req.accountId = acc.Id;
|
|
365
|
-
req.subject = 'Bulk test case ' + i;
|
|
366
|
-
requests.add(req);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
Test.startTest();
|
|
370
|
-
List<CaseManagementAction.CreateCaseResult> results =
|
|
371
|
-
CaseManagementAction.createSupportCase(requests);
|
|
372
|
-
Test.stopTest();
|
|
373
|
-
|
|
374
|
-
Integer successCount = 0;
|
|
375
|
-
for (CaseManagementAction.CreateCaseResult r : results) {
|
|
376
|
-
if (r.success) successCount++;
|
|
377
|
-
}
|
|
378
|
-
System.assertEquals(200, successCount);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
400
|
+
# List all agent tests
|
|
401
|
+
sf agent test list --target-org MySandbox
|
|
381
402
|
```
|
|
382
403
|
|
|
383
|
-
|
|
404
|
+
### Testing REST API (CI Integration)
|
|
384
405
|
|
|
385
|
-
|
|
406
|
+
```
|
|
407
|
+
# Start test run
|
|
408
|
+
POST /services/data/v63.0/einstein/ai-evaluations/runs
|
|
409
|
+
Body: { "aiEvaluationDefinitionName": "Service_Agent_Tests" }
|
|
410
|
+
Response: { "runId": "0Xx..." }
|
|
411
|
+
|
|
412
|
+
# Poll status
|
|
413
|
+
GET /services/data/v63.0/einstein/ai-evaluations/runs/{runId}
|
|
414
|
+
Response: { "status": "NEW | IN_PROGRESS | COMPLETED | ERROR" }
|
|
415
|
+
|
|
416
|
+
# Get results
|
|
417
|
+
GET /services/data/v63.0/einstein/ai-evaluations/runs/{runId}/results
|
|
418
|
+
Response: { "testCases": [...], "testResults": [...] }
|
|
419
|
+
```
|
|
386
420
|
|
|
387
|
-
|
|
388
|
-
# Activate an agent
|
|
389
|
-
sf agent activate --name "Sales Assistant" --target-org MySandbox
|
|
421
|
+
Auth: OAuth 2.0 via External Client App (JWT with consumer key/secret).
|
|
390
422
|
|
|
391
|
-
|
|
392
|
-
sf agent test run --target-org MySandbox --output-dir test-results/
|
|
423
|
+
### Testing Tools Summary
|
|
393
424
|
|
|
394
|
-
|
|
395
|
-
|
|
425
|
+
| Tool | Purpose |
|
|
426
|
+
|---|---|
|
|
427
|
+
| **Agent Builder Preview** | Real-time conversational testing (simulated or live mode) |
|
|
428
|
+
| **Agentforce Testing Center** | Bulk test execution; auto-generates test cases from knowledge |
|
|
429
|
+
| **CLI (`sf agent test`)** | Headless testing, JUnit output, CI pipeline integration |
|
|
430
|
+
| **VS Code Agent Panel** | View/run tests + Agent Preview pane + Apex Replay Debugger |
|
|
431
|
+
| **Testing REST API** | Programmatic test execution from external CI systems |
|
|
432
|
+
| **Agent Grid (Beta)** | Spreadsheet-like rapid testing with real CRM data |
|
|
396
433
|
|
|
397
|
-
|
|
398
|
-
sf agent test results --job-id <jobId> --result-format human
|
|
434
|
+
---
|
|
399
435
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
436
|
+
## Metadata & Deployment
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
force-app/main/default/
|
|
440
|
+
aiAuthoringBundles/My_Agent/ # .agent + .bundle-meta.xml
|
|
441
|
+
bots/My_Agent/ # .bot-meta.xml
|
|
442
|
+
botVersions/My_Agent.v1/ # .botVersion-meta.xml
|
|
443
|
+
genAiPlannerBundles/My_Agent/ # .genAiPlannerBundle-meta.xml
|
|
444
|
+
genAiPlugins/Topic_Name/ # .genAiPlugin-meta.xml
|
|
445
|
+
genAiFunctions/Action_Name/ # .genAiFunction-meta.xml + input/output schema.json
|
|
446
|
+
aiEvaluationDefinitions/ # .aiEvaluationDefinition-meta.xml
|
|
405
447
|
```
|
|
406
448
|
|
|
407
|
-
|
|
449
|
+
**Deploy order**: Bot/BotVersion → GenAiPromptTemplate → GenAiFunction → GenAiPlugin → GenAiPlannerBundle → AiAuthoringBundle → AiEvaluationDefinition → Activate
|
|
408
450
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
// Enforce sharing in Agentforce Apex actions
|
|
413
|
-
public with sharing class SecureAgentAction {
|
|
414
|
-
|
|
415
|
-
@InvocableMethod(label='Get Customer Orders')
|
|
416
|
-
public static List<OrderResult> getOrders(List<OrderRequest> requests) {
|
|
417
|
-
// Collect ALL accountIds — runtime may batch multiple requests
|
|
418
|
-
Set<Id> accountIds = new Set<Id>();
|
|
419
|
-
for (OrderRequest req : requests) {
|
|
420
|
-
accountIds.add(req.accountId);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// USER_MODE enforces CRUD/FLS and sharing rules
|
|
424
|
-
List<Order__c> orders = [
|
|
425
|
-
SELECT Id, Name, Status__c, Amount__c, AccountId
|
|
426
|
-
FROM Order__c
|
|
427
|
-
WHERE AccountId IN :accountIds
|
|
428
|
-
WITH USER_MODE
|
|
429
|
-
LIMIT 50
|
|
430
|
-
];
|
|
431
|
-
|
|
432
|
-
// Build results grouped by AccountId...
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
```
|
|
451
|
+
**Retrieve**: `sf project retrieve start --metadata "AiAuthoringBundle:My_Agent*"`
|
|
452
|
+
|
|
453
|
+
---
|
|
436
454
|
|
|
437
|
-
|
|
455
|
+
## Security
|
|
438
456
|
|
|
439
|
-
-
|
|
457
|
+
- Always use `with sharing` and `AccessLevel.USER_MODE` / `WITH USER_MODE`
|
|
440
458
|
- Ground Prompt Templates only with fields the user's profile can read
|
|
441
459
|
- Review agent conversations in Setup > Agent Conversations
|
|
442
460
|
|
|
443
461
|
---
|
|
444
462
|
|
|
463
|
+
## Classic Topics (Pre-Agent Script)
|
|
464
|
+
|
|
465
|
+
For orgs on API < v65, configure topics in Agentforce Builder UI:
|
|
466
|
+
|
|
467
|
+
```
|
|
468
|
+
Topic: Case Management
|
|
469
|
+
Description: Handles case creation, updating, and status inquiries.
|
|
470
|
+
Scope WILL: Case creation, status checks, escalation
|
|
471
|
+
Scope WILL NOT: Billing disputes, resolution timeline promises
|
|
472
|
+
Instructions:
|
|
473
|
+
1. Verify customer identity before accessing case details
|
|
474
|
+
2. Create a new case if no existing open case matches
|
|
475
|
+
3. Escalate if customer is frustrated or issue is complex
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
All instruction guidelines and context engineering principles from the reference apply identically.
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
445
482
|
## Related
|
|
446
483
|
|
|
447
|
-
- Agent: `sf-agentforce-agent`
|
|
484
|
+
- Agent: `sf-agentforce-agent` — for interactive guidance
|
|
448
485
|
- Constraints: sf-apex-constraints
|
|
449
486
|
- Reference: @../_reference/AGENTFORCE_PATTERNS.md
|