mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-10 09:41:17 +08:00
Compare commits
5 Commits
3a8d73feb0
...
f15b7faf9e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f15b7faf9e | ||
|
|
565fa76add | ||
|
|
9b9161959b | ||
|
|
7a912bd355 | ||
|
|
9edf77bd6e |
@ -122,7 +122,11 @@ sf data query --json -q "SELECT Username FROM User WHERE Profile.UserLicense.Nam
|
||||
|
||||
**If results are returned:** Ask which username to use. Record choice in the Agent Spec Configuration section. Verify permissions per [Agent User Setup & Permissions](agent-user-setup.md).
|
||||
|
||||
**If no results are returned:** STOP. Do NOT invent a username. Ask if you should create a new user, then read [Agent User Setup & Permissions](agent-user-setup.md) for user creation instructions.
|
||||
**If no results are returned:** STOP. Do NOT invent a username. Ask if you should create a new user. If yes, use:
|
||||
```bash
|
||||
sf org create agent-user --target-org TARGET_ORG --first-name <AgentName> --last-name Agent --json
|
||||
```
|
||||
Then read the generated username from `result.username`. See [Agent User Setup & Permissions](agent-user-setup.md) for the complete provisioning workflow.
|
||||
|
||||
**WRONG:** Fabricating a username when query returns nothing
|
||||
```
|
||||
|
||||
@ -33,32 +33,23 @@ sf data query --json \
|
||||
-o TARGET_ORG
|
||||
|
||||
# Step 2: Create Einstein Agent User (2 minutes)
|
||||
# Get Profile ID (read result.records[0].Id from JSON response)
|
||||
sf data query --json \
|
||||
--query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" \
|
||||
-o TARGET_ORG
|
||||
# Use the new dedicated command — works in all org types (scratch, sandbox, production)
|
||||
# Automatically assigns Einstein Agent User profile + AgentforceServiceAgentBase,
|
||||
# AgentforceServiceAgentUser, and EinsteinGPTPromptTemplateUser permission sets
|
||||
sf org create agent-user \
|
||||
--target-org TARGET_ORG \
|
||||
--first-name <AgentName> \
|
||||
--last-name Agent
|
||||
|
||||
# For Production/Sandbox (non-scratch org):
|
||||
# Use the ProfileId from the query above
|
||||
sf data create record --json --sobject User --values \
|
||||
"Username=<agent_name>_user@<orgId>.ext \
|
||||
LastName=<AgentName> \
|
||||
Email=admin@example.com \
|
||||
Alias=<alias> \
|
||||
TimeZoneSidKey=America/Los_Angeles \
|
||||
LocaleSidKey=en_US \
|
||||
EmailEncodingKey=UTF-8 \
|
||||
ProfileId=<PROFILE_ID> \
|
||||
LanguageLocaleKey=en_US" \
|
||||
-o TARGET_ORG
|
||||
|
||||
# For Scratch Orgs (use user definition file):
|
||||
# sf org create user --definition-file config/einstein-agent-user.json -o TARGET_ORG
|
||||
# Capture the username from the command output (result.username) — it is generated
|
||||
# with a unique GUID suffix, e.g. agent_agent@00Dxx.org.salesforce.com-abc123
|
||||
|
||||
# Step 3: Assign System Permission Set (1 minute)
|
||||
# NOTE: AgentforceServiceAgentUser is already assigned by sf org create agent-user.
|
||||
# This step is only needed if you created the user manually (legacy method).
|
||||
sf org assign permset --json \
|
||||
--name AgentforceServiceAgentUser \
|
||||
--on-behalf-of <agent_name>_user@<orgId>.ext \
|
||||
--on-behalf-of <agent_name_from_output> \
|
||||
-o TARGET_ORG
|
||||
|
||||
# Step 4: Deploy Custom Permission Set (3 minutes)
|
||||
@ -102,11 +93,12 @@ sf agent activate --json \
|
||||
```
|
||||
|
||||
Critical notes:
|
||||
- For **scratch orgs**, use `sf org create user --definition-file`
|
||||
- For **production/sandbox**, use `sf data create record` as shown above
|
||||
- `sf org create user` only works in scratch orgs — it will fail in production/sandbox
|
||||
- `sf org create agent-user` works in **all org types** (scratch, sandbox, production) — use it instead of the legacy `sf org create user` or `sf data create record` approach
|
||||
- The command auto-assigns `AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, and `EinsteinGPTPromptTemplateUser` — no separate permset assignment needed
|
||||
- The command may exit non-zero with `PermissionSetAssignmentError` if a permset license is exhausted, **even when the user was created successfully**. Always inspect `result.username` and `result.permissionSetErrors[]` from the JSON output. If the only failure is `EinsteinGPTPromptTemplateUser` and your agent has no Prompt Template actions, you can proceed. Otherwise, free a license (or use `--base-username` to retry against a different license pool) before continuing.
|
||||
- Capture the generated username from the command output (`result.username`) and use it for `default_agent_user`
|
||||
- Always test with preview BEFORE publishing to avoid version management overhead
|
||||
- Assign `AgentforceServiceAgentUser` BEFORE publishing to prevent "Internal Error"
|
||||
- Assign any custom permission sets (`{AgentName}_Access`) BEFORE publishing to prevent "Internal Error"
|
||||
- Publishing does NOT activate — you must run `sf agent activate` separately
|
||||
|
||||
---
|
||||
@ -117,12 +109,6 @@ Critical notes:
|
||||
|
||||
Service agents need a dedicated service account with consistent permissions.
|
||||
|
||||
**Get Org ID first** (needed for username format):
|
||||
```bash
|
||||
sf org display --json -o TARGET_ORG
|
||||
# Read result.id from the JSON response
|
||||
```
|
||||
|
||||
**Query existing Einstein Agent Users** (skip creation if one exists):
|
||||
```bash
|
||||
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true" -o TARGET_ORG
|
||||
@ -130,58 +116,30 @@ sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Prof
|
||||
|
||||
**Create the user** (if none exists):
|
||||
|
||||
1. Get the Einstein Agent User profile ID:
|
||||
```bash
|
||||
sf data query --json --query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" -o TARGET_ORG
|
||||
```
|
||||
Use the dedicated command — works in all org types (scratch, sandbox, production):
|
||||
|
||||
2. Create a user definition file (`config/einstein-agent-user.json`):
|
||||
```json
|
||||
{
|
||||
"Username": "{agent_name}_agent@{orgId}.ext",
|
||||
"LastName": "{AgentName} Agent",
|
||||
"Email": "placeholder@example.com",
|
||||
"Alias": "agntuser",
|
||||
"ProfileId": "<profile-id-from-step-1>",
|
||||
"TimeZoneSidKey": "America/Los_Angeles",
|
||||
"LocaleSidKey": "en_US",
|
||||
"EmailEncodingKey": "UTF-8",
|
||||
"LanguageLocaleKey": "en_US",
|
||||
"UserPermissionsKnowledgeUser": true
|
||||
}
|
||||
```
|
||||
```bash
|
||||
sf org create agent-user \
|
||||
--target-org TARGET_ORG \
|
||||
--first-name <AgentName> \
|
||||
--last-name Agent
|
||||
```
|
||||
|
||||
3. Create the user:
|
||||
This command:
|
||||
- Creates a user with the "Einstein Agent User" profile
|
||||
- Automatically assigns `AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, and `EinsteinGPTPromptTemplateUser` permission sets
|
||||
- Returns a unique generated username in `result.username` — record this for `default_agent_user`
|
||||
|
||||
**Option A: Scratch Org (Definition File)**
|
||||
```bash
|
||||
sf org create user --json \
|
||||
--definition-file config/einstein-agent-user.json \
|
||||
-o TARGET_ORG
|
||||
```
|
||||
Optional flags:
|
||||
- `--base-username <email>` — sets the base portion of the username (a unique suffix is always appended)
|
||||
- `--json` — output as JSON for scripting
|
||||
|
||||
**Option B: Production/Sandbox (Direct Record Creation)**
|
||||
```bash
|
||||
# Get Profile ID first
|
||||
# Get Profile ID (read result.records[0].Id from JSON response)
|
||||
sf data query --json \
|
||||
--query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" \
|
||||
-o TARGET_ORG
|
||||
**Verify creation:**
|
||||
```bash
|
||||
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true ORDER BY CreatedDate DESC LIMIT 5" -o TARGET_ORG
|
||||
```
|
||||
|
||||
# Create user directly (use ProfileId from query above)
|
||||
sf data create record --json --sobject User --values \
|
||||
"Username='{agent_name}_agent@{orgId}.ext' LastName='{AgentName} Agent' Email='placeholder@example.com' Alias='agntuser' ProfileId='<PROFILE_ID>' TimeZoneSidKey='America/Los_Angeles' LocaleSidKey='en_US' EmailEncodingKey='UTF-8' LanguageLocaleKey='en_US'" \
|
||||
-o TARGET_ORG
|
||||
```
|
||||
|
||||
**Note**: `sf org create user` only works in scratch orgs. For production/sandbox, use `sf data create record`. Attempting `sf org create user` in a non-scratch org fails with an authorization error.
|
||||
|
||||
4. Verify creation:
|
||||
```bash
|
||||
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Username = '{agent_name}_agent@{orgId}.ext'" -o TARGET_ORG
|
||||
```
|
||||
|
||||
**Username format**: `{agent_name}_agent@{orgId}.ext` (production) or `{agent_name}.{suffix}@{orgfarm}.salesforce.com` (dev/scratch). Always query the target org to confirm the exact format.
|
||||
**Note**: The generated username has a GUID suffix for global uniqueness (e.g. `agentname_agent@orgid.salesforce.com-abc123`). Always read the username from command output rather than constructing it manually.
|
||||
|
||||
---
|
||||
|
||||
@ -189,18 +147,22 @@ sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Prof
|
||||
|
||||
Critical: Must be assigned BEFORE publishing the agent. Without it, publish fails with "Internal Error".
|
||||
|
||||
**If you used `sf org create agent-user` (recommended):** `AgentforceServiceAgentUser` is assigned automatically — skip to Step 3.
|
||||
|
||||
**If you created the user manually (legacy):**
|
||||
|
||||
Via Setup UI:
|
||||
1. Setup > Permission Sets > search "AgentforceServiceAgentUser"
|
||||
2. Manage Assignments > Add Assignments > select the Einstein Agent User > Save
|
||||
|
||||
Via CLI:
|
||||
```bash
|
||||
sf org assign permset --json --name AgentforceServiceAgentUser --on-behalf-of "{agent_name}_agent@{orgId}.ext" -o TARGET_ORG
|
||||
sf org assign permset --json --name AgentforceServiceAgentUser --on-behalf-of "{agent_name_from_output}" -o TARGET_ORG
|
||||
```
|
||||
|
||||
Verify assignment:
|
||||
```bash
|
||||
sf data query --json --query "SELECT Id, PermissionSet.Name FROM PermissionSetAssignment WHERE Assignee.Username = '{agent_name}_agent@{orgId}.ext' AND PermissionSet.Name = 'AgentforceServiceAgentUser'" -o TARGET_ORG
|
||||
sf data query --json --query "SELECT Id, PermissionSet.Name FROM PermissionSetAssignment WHERE Assignee.Username = '{agent_name_from_output}' AND PermissionSet.Name = 'AgentforceServiceAgentUser'" -o TARGET_ORG
|
||||
```
|
||||
|
||||
---
|
||||
@ -460,9 +422,9 @@ Checklist:
|
||||
- **Prevention:** Deploy → Test → Publish workflow (Step 6.1-6.3)
|
||||
- **Result:** No version management overhead during development
|
||||
|
||||
### 4. Wrong User Creation Command
|
||||
- **Cause:** Using `sf org create user` in non-scratch orgs
|
||||
- **Prevention:** Step 1 provides correct commands for each org type (Option A vs B)
|
||||
### 4. Wrong User Creation Command (Legacy)
|
||||
- **Cause:** Using `sf org create user` in non-scratch orgs, or manually constructing user records with `sf data create record`
|
||||
- **Prevention:** Use `sf org create agent-user --target-org TARGET_ORG` — works in all org types and auto-assigns required permission sets
|
||||
- **Result:** User created successfully without authorization errors
|
||||
|
||||
### 5. Auto-Generated Permission Set Gaps
|
||||
@ -486,7 +448,7 @@ Checklist:
|
||||
| "invocable action does not exist" | Apex class not in custom PS (auto-generated PS incomplete) | Create custom `{AgentName}_Access` with all `<classAccesses>` (Step 3) |
|
||||
| "Invalid default_agent_user" | Username typo or user not active | Query Einstein Agent Users, verify exact username + `IsActive = true` |
|
||||
| Agent runs but returns wrong data | Employee agent using wrong user context | Verify `agent_type` — Service agents use dedicated user, Employee agents use logged-in user |
|
||||
| `sf org create user` fails | Used in production/sandbox org | Use `sf data create record` instead (Step 1, Option B) |
|
||||
| `sf org create user` fails | Used in production/sandbox org | Use `sf org create agent-user --target-org TARGET_ORG` instead (Step 1) |
|
||||
|
||||
---
|
||||
|
||||
@ -526,4 +488,6 @@ Checklist:
|
||||
|
||||
---
|
||||
|
||||
*Validated against: ORM1, ORM2, AutomotiveSupport, SalesforceProductAssistant agents. Last validated: 2026-03-07.*
|
||||
*Validated against: ORM1, ORM2, AutomotiveSupport, SalesforceProductAssistant agents. Last validated: 2026-03-07.
|
||||
Updated to use `sf org create agent-user` (SF CLI 2.131.7+)
|
||||
2026-04-30.*
|
||||
|
||||
@ -331,53 +331,27 @@ If `TotalLicenses > UsedLicenses`, a license is available and a new Einstein Age
|
||||
|
||||
### Creating an Einstein Agent User
|
||||
|
||||
#### Step 1: Query for the Einstein Agent User profile ID
|
||||
Use the dedicated command — works in all org types (scratch, sandbox, production). It automatically assigns the Einstein Agent User profile and the required permission sets (`AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, `EinsteinGPTPromptTemplateUser`).
|
||||
|
||||
```bash
|
||||
sf data query --json -q "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'"
|
||||
sf org create agent-user \
|
||||
--target-org <TARGET_ORG> \
|
||||
--first-name <AgentName> \
|
||||
--last-name Agent \
|
||||
--json
|
||||
```
|
||||
|
||||
#### Step 2: Create a User import JSON file (e.g., `data-import/User.json`)
|
||||
Optional: `--base-username <email>` sets the base portion of the username (a unique suffix is always appended).
|
||||
|
||||
```json
|
||||
{
|
||||
"records": [
|
||||
{
|
||||
"attributes": {
|
||||
"type": "User",
|
||||
"referenceId": "AgentUserRef1"
|
||||
},
|
||||
"ProfileId": "<PROFILE_ID_FROM_STEP_1>",
|
||||
"Username": "<UNIQUE_USERNAME>",
|
||||
"Alias": "AgntUsr",
|
||||
"CommunityNickname": "Agent User<UNIQUE_STRING>",
|
||||
"Email": "noreply@example.com",
|
||||
"FirstName": "Agent",
|
||||
"LastName": "User",
|
||||
"IsActive": true,
|
||||
"ForecastEnabled": false,
|
||||
"EmailEncodingKey": "UTF-8",
|
||||
"LanguageLocaleKey": "en_US",
|
||||
"LocaleSidKey": "en_US",
|
||||
"TimeZoneSidKey": "America/Los_Angeles"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
**Capture the generated username** from `result.username` in the output — use it as `default_agent_user` in the `.agent` config.
|
||||
|
||||
#### Step 3: Import the user record
|
||||
|
||||
```bash
|
||||
sf data import tree --json --files data-import/User.json
|
||||
```
|
||||
|
||||
#### Step 4: Verify the user was created
|
||||
#### Verify the user was created
|
||||
|
||||
```bash
|
||||
sf data query --json -q "SELECT Username FROM User WHERE Profile.UserLicense.Name = 'Einstein Agent' AND IsActive = true LIMIT 5"
|
||||
```
|
||||
|
||||
After creating the user, continue with permission setup in [Agent User Setup & Permissions](agent-user-setup.md).
|
||||
After creating the user, continue with custom permission set setup in [Agent User Setup & Permissions](agent-user-setup.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -83,8 +83,8 @@ sf data-code-extension function init --package-dir <directory>
|
||||
my-transform/ # Project root
|
||||
├── payload/ # CRITICAL: This is what --package-dir must point to for deploy
|
||||
│ ├── entrypoint.py # Main transformation code
|
||||
│ ├── requirements.txt # Python dependencies
|
||||
│ └── config.json # Code extension configuration
|
||||
├── requirements.txt # Python dependencies
|
||||
└── README.md
|
||||
```
|
||||
|
||||
|
||||
@ -139,8 +139,8 @@ After `init`, you'll have:
|
||||
my-transform/
|
||||
├── payload/
|
||||
│ ├── entrypoint.py # Your transformation code
|
||||
│ ├── config.json # Permissions and configuration
|
||||
│ └── requirements.txt # Python dependencies
|
||||
│ └── config.json # Permissions and configuration
|
||||
├── requirements.txt # Python dependencies
|
||||
└── README.md
|
||||
```
|
||||
|
||||
|
||||
@ -219,8 +219,8 @@ sf data-code-extension script scan --entrypoint ./payload/entrypoint.py
|
||||
my-project/
|
||||
├── payload/
|
||||
│ ├── entrypoint.py # Main code
|
||||
│ ├── config.json # Auto-generated permissions
|
||||
│ └── requirements.txt # Auto-generated dependencies
|
||||
│ └── config.json # Auto-generated permissions
|
||||
├── requirements.txt # Auto-generated dependencies
|
||||
└── README.md
|
||||
```
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
---
|
||||
name: generating-images
|
||||
description: Generates high-fidelity visual assets, logos, and UI mockups using the media-management MCP server. Trigger this skill whenever the user asks to "generate image," "create logo," "produce a hero banner," "design a UI icon," or "build a visual asset." It is explicitly designed to handle technical specifications including file formats (PNG, JPEG, WEBP), specific dimensions (e.g., "1024x1024"), and transparency requirements. Load this skill when the user needs to integrate generated imagery into application code or web pages. It ensures consistent output quality and provides a standardized SVG fallback if the generation tool is unavailable.
|
||||
description: "Generates high-fidelity visual assets, logos, and UI mockups using the media-management MCP server. Trigger this skill whenever the user asks to generate an image, create a logo, produce a hero banner, design a UI icon, or build a visual asset. It is explicitly designed to handle technical specifications including file formats (PNG, JPEG, WEBP), specific dimensions (e.g. 1024x1024), and transparency requirements. Use this skill when the user needs to integrate generated imagery into application code or web pages. It ensures consistent output quality and provides a standardized SVG fallback if the generation tool is unavailable."
|
||||
metadata:
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# Generating Images
|
||||
|
||||
@ -67,30 +67,28 @@ sf org login web --alias <org_alias>
|
||||
|
||||
### Step 3a: Execute DLO Schema Script
|
||||
|
||||
Use the Python script to retrieve DLO information:
|
||||
The Python scripts are bundled with this skill. They live in the `scripts/` subdirectory of the same directory that contains this SKILL.md file. Use the absolute path to that directory — do NOT use `./scripts/` as that resolves relative to the current working directory, not the skill directory.
|
||||
|
||||
**To list all DLOs:**
|
||||
```bash
|
||||
python3 ./scripts/get_dlo_schema.py <org_alias>
|
||||
python3 <skill_dir>/scripts/get_dlo_schema.py <org_alias>
|
||||
```
|
||||
|
||||
**To get specific DLO schema:**
|
||||
```bash
|
||||
python3 ./scripts/get_dlo_schema.py <org_alias> <dlo_name>
|
||||
python3 <skill_dir>/scripts/get_dlo_schema.py <org_alias> <dlo_name>
|
||||
```
|
||||
|
||||
### Step 3b: Execute DMO Schema Script
|
||||
|
||||
Use the Python script to retrieve DMO information:
|
||||
|
||||
**To list all DMOs:**
|
||||
```bash
|
||||
python3 ./scripts/get_dmo_schema.py <org_alias>
|
||||
python3 <skill_dir>/scripts/get_dmo_schema.py <org_alias>
|
||||
```
|
||||
|
||||
**To get specific DMO schema:**
|
||||
```bash
|
||||
python3 ./scripts/get_dmo_schema.py <org_alias> <dmo_name>
|
||||
python3 <skill_dir>/scripts/get_dmo_schema.py <org_alias> <dmo_name>
|
||||
```
|
||||
|
||||
### Step 4: Present Results
|
||||
@ -227,7 +225,7 @@ User: "Show me all DLOs in afvibe org"
|
||||
Response:
|
||||
1. Run sf org list to discover connected org alias
|
||||
2. Authenticate to afvibe
|
||||
3. Run: python3 ./scripts/get_dlo_schema.py afvibe
|
||||
3. Run: python3 <skill_dir>/scripts/get_dlo_schema.py afvibe
|
||||
4. Display formatted list of DLOs
|
||||
```
|
||||
|
||||
@ -238,7 +236,7 @@ User: "Get the schema for Employee__dll in afvibe"
|
||||
Response:
|
||||
1. Run sf org list to discover connected org alias
|
||||
2. Authenticate to afvibe
|
||||
3. Run: python3 ./scripts/get_dlo_schema.py afvibe Employee__dll
|
||||
3. Run: python3 <skill_dir>/scripts/get_dlo_schema.py afvibe Employee__dll
|
||||
4. Display field schema with types and metadata
|
||||
```
|
||||
|
||||
@ -261,7 +259,7 @@ User: "Show me all DMOs in afvibe org"
|
||||
Response:
|
||||
1. Run sf org list to discover connected org alias
|
||||
2. Authenticate to afvibe
|
||||
3. Run: python3 ./scripts/get_dmo_schema.py afvibe
|
||||
3. Run: python3 <skill_dir>/scripts/get_dmo_schema.py afvibe
|
||||
4. Display formatted list of DMOs
|
||||
```
|
||||
|
||||
@ -272,7 +270,7 @@ User: "Get the schema for Individual__dlm in afvibe"
|
||||
Response:
|
||||
1. Run sf org list to discover connected org alias
|
||||
2. Authenticate to afvibe
|
||||
3. Run: python3 ./scripts/get_dmo_schema.py afvibe Individual__dlm
|
||||
3. Run: python3 <skill_dir>/scripts/get_dmo_schema.py afvibe Individual__dlm
|
||||
4. Display field schema with types and metadata
|
||||
```
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user