@salesforce/afv-skills 1.50.0 → 1.52.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/package.json +1 -1
- package/skills/experience-ui-bundle-deploy/SKILL.md +43 -2
- package/skills/experience-ui-bundle-deploy/references/config-scaffold.md +16 -3
- package/skills/experience-ui-bundle-deploy/references/logout-url.md +97 -0
- package/skills/experience-ui-bundle-deploy/scripts/set-logout-url.mjs +304 -0
- package/skills/experience-ui-bundle-localize/SKILL.md +107 -90
- package/skills/experience-ui-bundle-localize/references/angular/check-i18n-wired.sh +159 -0
- package/skills/experience-ui-bundle-localize/references/angular/i18n-setup.md +250 -0
- package/skills/experience-ui-bundle-localize/references/angular/interpolation.md +156 -0
- package/skills/experience-ui-bundle-localize/references/angular/localize.md +111 -0
- package/skills/experience-ui-bundle-localize/references/{gotchas.md → common/gotchas.md} +27 -43
- package/skills/experience-ui-bundle-localize/references/{label-xml.md → common/label-xml.md} +27 -17
- package/skills/experience-ui-bundle-localize/references/common/platform-sdk-i18n.md +169 -0
- package/skills/experience-ui-bundle-localize/references/{verifying.md → common/verifying.md} +26 -16
- package/skills/experience-ui-bundle-localize/{scripts → references/react}/check-i18n-wired.sh +8 -3
- package/skills/experience-ui-bundle-localize/references/{i18n-setup.md → react/i18n-setup.md} +48 -10
- package/skills/experience-ui-bundle-localize/references/{interpolation.md → react/interpolation.md} +4 -4
- package/skills/experience-ui-bundle-localize/references/react/localize.md +76 -0
- package/skills/experience-ui-bundle-localize/scripts/check-manifest-registered.sh +92 -24
- package/skills/experience-ui-bundle-localize/scripts/detect-framework.sh +73 -0
- package/skills/experience-ui-bundle-site-generate/SKILL.md +1 -1
- package/skills/field-service-data-capture-form-deployer-configure/SKILL.md +1 -1
- package/skills/field-service-data-capture-form-deployer-configure/references/flow-metadata-json.md +1 -1
- package/skills/field-service-data-capture-form-editor-configure/SKILL.md +1 -1
- package/skills/field-service-data-capture-reference-configure/SKILL.md +28 -15
- package/skills/field-service-foundation-setup-designer-get/SKILL.md +1 -1
- package/skills/field-service-mobile-branding-configure/SKILL.md +1 -1
- package/skills/field-service-objective-designer-configure/SKILL.md +381 -64
- package/skills/field-service-prework-brief-deployer-configure/SKILL.md +566 -3
- package/skills/field-service-scheduling-policy-designer-query/SKILL.md +1097 -57
- package/skills/field-service-sobject-create-configure/SKILL.md +222 -7
- package/skills/field-service-voice-to-form-configure/SKILL.md +11 -11
- package/skills/field-service-work-rule-designer-configure/SKILL.md +92 -107
- package/skills/service-digital-engagement-channel-configure/SKILL.md +20 -37
- package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +3 -2
- package/skills/service-digital-engagement-channel-configure/examples/asa_agent_channel.xml +4 -4
- package/skills/service-helpagent-coordinate/SKILL.md +37 -29
- package/skills/service-helpagent-coordinate/assets/help-agent-spec.md +33 -28
- package/skills/service-helpagent-coordinate/references/agent-script.md +4 -1
- package/skills/service-helpagent-coordinate/references/channel-voice.md +1 -1
- package/skills/service-helpagent-coordinate/references/channel-web-chat.md +10 -12
|
@@ -42,119 +42,139 @@ Each row: **name — engine (DB/Apex) — what it does.** "DB w/ ESO" means the
|
|
|
42
42
|
| **TimeSlot Designated Work** | Apex | Reserves a time slot/shift for a specific work type — only that type schedules in that window. All-or-nothing rule (no relevance groups). |
|
|
43
43
|
| **Service Crew Resources Availability** | Apex | Ensures a crew-type resource is only assigned when the crew meets the parent record's minimum crew size. |
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### Requirements mapping
|
|
46
|
+
|
|
47
|
+
Don't start from the rule list — start from **what the business needs**, then map each requirement to the rule(s) that satisfy it. Walk the user through this mapping:
|
|
48
|
+
|
|
49
|
+
| If the requirement is… | Use this work rule |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Resources need specific skills / proficiency levels | **Match Skills**; **Extended Match** |
|
|
52
|
+
| Non-skill matching factors (e.g., serviceable postal codes) | **Match Boolean**; **Match Skills**; **Extended Match** |
|
|
53
|
+
| Breaks during the day / specific or multiple breaks | **Service Resource Availability** (+ work rule entries for multiple breaks, ESO) |
|
|
54
|
+
| Can work go into overtime? Can resources travel outside working hours? | **Service Resource Availability** |
|
|
55
|
+
| Max number / duration of appointments per resource per day | **Count Rule** |
|
|
56
|
+
| A specific resource **must** be assigned | **Required Resources** |
|
|
57
|
+
| A specific resource **must not** be assigned | **Excluded Resources** |
|
|
58
|
+
| Customer has specific service-call time windows | **Service Appointment Visiting Hours** |
|
|
59
|
+
| Ensure crew-type resources get scheduled | **Service Crew Resources Availability** |
|
|
60
|
+
| Appointments have arrival windows / required arrival times | **Match Time Rule** |
|
|
61
|
+
| Cap travel distance from home / control travel cost across large territories | **Maximum Travel from Home** — ask whether the cap is by **distance** or by **travel time** (see note below) |
|
|
62
|
+
| Assign specific work types to a resource for part/all of a day | **TimeSlot Designated Work** |
|
|
63
|
+
| Restrict work to the resource's **primary and secondary** service territory memberships | **Working Territories** |
|
|
46
64
|
|
|
47
|
-
|
|
65
|
+
Always include exactly one **Service Resource Availability** rule — the only mandatory rule this skill emits. Never emit Earliest Start Permitted or Due Date — provisioned automatically.
|
|
48
66
|
|
|
49
|
-
|
|
50
|
-
2. **If it applies and it has configuration, ask that rule's config question(s) right now** — before moving on to the next rule. Never defer configuration to the end. If the rule is selection-only (no config), just confirm it and continue.
|
|
67
|
+
**Arrival Window Match Time rules (opt-in default pair).** If the user wants appointments to honor customer **arrival windows**, ask them to confirm, and if they agree, emit **two** Match Time rules with these exact default settings — do not ask the user to fill these in, they are the standard arrival-window configuration:
|
|
51
68
|
|
|
52
|
-
|
|
69
|
+
| Setting | Rule A | Rule B |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| Name | `Arrival Window Start` | `Arrival Window End` |
|
|
72
|
+
| Service Schedule Time Property | `SchedStartTime` | `SchedStartTime` |
|
|
73
|
+
| Service Time Operator | `Later than or Equal to` | `Before or Equal to` |
|
|
74
|
+
| Service Time Property | `ArrivalWindowStartTime` | `ArrivalWindowEndTime` |
|
|
75
|
+
| Pass Empty Values | `true` | `true` |
|
|
53
76
|
|
|
54
|
-
|
|
77
|
+
Emit each as a Match Time work rule whose `params` carry those four values (keys `serviceScheduleTimeProperty`, `serviceTimeOperator`, `serviceTimeProperty`, `passEmptyValues`). These are separate from the mandatory Earliest Start Permitted / Due Date rules (never emitted).
|
|
55
78
|
|
|
56
|
-
|
|
57
|
-
- **Otherwise sweep for it once, at the end.** After all 16 rules are walked, ask a single closing question: *"Are there any constraints here that should apply only to a certain part of your workforce or to certain types of work — rather than to everyone/everything? For example, different break or travel limits for part-time vs. full-time techs, or stricter handling for a specific work type or region."* Only if the user says yes do you scope the affected rules (per the *Relevance Groups* section). If no, leave every `relevanceGroup` null.
|
|
79
|
+
**Interpreting and emitting break times (clock time vs. shift-start offset):** A Service Resource Availability rule expresses breaks in one of two shapes, and **this skill decides the shape and emits the values the data-layer skill needs** — the data-layer skill never receives a clock time it has to convert. Choose the shape as follows:
|
|
58
80
|
|
|
59
|
-
|
|
81
|
+
- **One fixed daily break at an absolute clock time** (e.g. "30 minutes at 12:00 every day") → emit it as an **absolute** break: `{ "mode": "absolute", "startClock": "12:00", "durationMinutes": 30 }`. No offset math, no working-day start needed.
|
|
82
|
+
- **One or more breaks defined as an offset from the start of the working day** (e.g. "a 30-minute lunch starting 3 hours into the shift") → emit each as an **offset** break, in **minutes from the start of the working day**: `{ "mode": "offset", "earliestStartOffsetMinutes": 180, "latestEndOffsetMinutes": 240, "durationMinutes": 30 }`. All three of `earliestStartOffsetMinutes`, `latestEndOffsetMinutes`, and `durationMinutes` are **mandatory** for an offset break. **When the user states the break in offset terms already** (e.g. "3 hours after the start of day"), that offset *is* `earliestStartOffsetMinutes` (180) — **do not ask for the working-day start; you don't need it.**
|
|
83
|
+
- **Breaks given as clock times but there is more than one** (e.g. "15 minutes at 10:00 and 30 minutes at 12:00") → you must use the **offset** shape, which means **converting each clock time into an offset from the start of the working day**. You cannot do that without knowing when the day starts, so **ask the user for the shift / working-day start**, then compute `earliestStartOffsetMinutes = (break start clock − day start)` in minutes for each break. Never assume the day starts at midnight (that would turn "10:00" into a wrong 600-minute offset). *(Only ask for the day start in this clock-time case — never when the break is already expressed as an offset.)*
|
|
60
84
|
|
|
61
|
-
|
|
85
|
+
**Always emit `latestEndOffsetMinutes` for every offset break — ask for it directly, do not fabricate a window.** The earliest start comes from what the user stated (an offset, or a converted clock time) — **do not invent ± tolerance windows around it** (no "±1 hour" / "±2 hour" options). If the user only gave a break start (or a duration with no stated finish-by), **ask them plainly for the latest the break may end**, phrased in the *same terms they used*: if they gave an offset ("starts 3 hours after start of day"), ask "what is the latest it may end, as time after the start of the day?" and convert (e.g. "4 hours after start" → 240); if they gave a clock time, ask for a clock time and convert with the day start. If the user says the break is fixed/pinned with no flex, set `latestEndOffsetMinutes = earliestStartOffsetMinutes + durationMinutes`. Never emit an offset break missing any of the three fields, and never guess the latest-end. If a break requirement is too involved to convert reliably, ask clarifying questions or recommend the manual approach rather than guessing.
|
|
86
|
+
|
|
87
|
+
**Maximum Travel from Home — establish the cap type, not the unit.** When a requirement caps how far a resource may travel from home, **ask the user whether the cap is by distance or by travel time** — the two are configured differently and the data-layer skill needs to know which. Emit the value and the type in `params`: `{ "maxTravelFromHome": 50, "maxTravelFromHomeType": "Distance" | "Travel Time" }`. Interpret the user's phrasing to set the *type* — "50 miles"/"50 km" ⇒ `Distance`, "45 minutes" ⇒ `Travel Time` — but **do not ask for or emit a distance unit (miles vs km): it is not part of the work-rule config**; the unit is governed by the org's locale/distance settings elsewhere, so the rule stores only the number. For `Travel Time` the value is minutes. Never emit the cap value without its type.
|
|
62
88
|
|
|
63
|
-
###
|
|
89
|
+
### Per-rule configuration
|
|
64
90
|
|
|
65
|
-
|
|
91
|
+
Once the requirements mapping has selected which rules to build, configure the specifics for each. The **`Emit` line gives the exact `params` keys** — use these verbatim so the data-layer skill can map them. Only configure rules the user selected; skip the rest.
|
|
66
92
|
|
|
67
93
|
---
|
|
68
94
|
|
|
69
|
-
**
|
|
70
|
-
|
|
95
|
+
**Service Resource Availability** *(always present)*
|
|
96
|
+
Gate: Always included — no selection needed.
|
|
71
97
|
Ask:
|
|
72
98
|
- "Can work run into **overtime**?" (yes/no)
|
|
73
99
|
- "Can resources **travel outside working hours** to/from home?" — if yes, ask how many minutes from home (to first job) and to home (from last job); "no limit" = 120; "no" = 0 for both
|
|
74
|
-
- Breaks interview (see *Interpreting and emitting break times*
|
|
100
|
+
- Breaks interview (see *Interpreting and emitting break times*)
|
|
75
101
|
|
|
76
102
|
Emit: `{ "enableOvertime": true|false, "travelFromHomeMinutes": <number>, "travelToHomeMinutes": <number>, "breaks": [ … ] }`
|
|
77
|
-
Note: Travel values are minutes — 0 = no travel outside working hours, 120 = effectively unlimited. If
|
|
103
|
+
Note: Travel values are minutes — 0 = no travel outside working hours, 120 = effectively unlimited. If user gives no availability detail, emit baseline (`enableOvertime: false`, travel keys and breaks omitted).
|
|
78
104
|
|
|
79
105
|
---
|
|
80
106
|
|
|
81
|
-
**
|
|
82
|
-
|
|
83
|
-
|
|
107
|
+
**Match Time Rule** *(arrival windows)*
|
|
108
|
+
Gate: Only if selected in requirements mapping.
|
|
109
|
+
Ask: "Should appointments honor customer **arrival windows**?"
|
|
110
|
+
Emit: Two default rules from the Arrival Window table — no further questions.
|
|
84
111
|
|
|
85
112
|
---
|
|
86
113
|
|
|
87
|
-
**
|
|
88
|
-
|
|
114
|
+
**Match Skills**
|
|
115
|
+
Gate: Only if selected in requirements mapping.
|
|
89
116
|
Ask: "Should the resource also **meet a minimum skill level** (proficiency), or is simply *having* the skill enough?"
|
|
90
117
|
Emit: `{ "matchSkillLevel": true|false }`
|
|
91
118
|
Note: Do not ask about skill-type AND/OR logic — this skill does not configure `skillTypeLogic`.
|
|
92
119
|
|
|
93
120
|
---
|
|
94
121
|
|
|
95
|
-
**
|
|
96
|
-
|
|
122
|
+
**Match Fields**
|
|
123
|
+
Gate: Only if selected in requirements mapping.
|
|
97
124
|
Ask: "Which Service Appointment field must match which Service Resource field, and with what operator?"
|
|
98
125
|
Emit: `{ "serviceProperty": "<SA field>", "resourceProperty": "<resource field>", "booleanOperator": "=" }`
|
|
99
126
|
Note: Operator is one of `=`, `>=`, `<=`, `>`, `<` (default `=`). Field names are the customer's own — pass through as given.
|
|
100
127
|
|
|
101
128
|
---
|
|
102
129
|
|
|
103
|
-
**
|
|
104
|
-
|
|
130
|
+
**Match Boolean**
|
|
131
|
+
Gate: Only if selected in requirements mapping.
|
|
105
132
|
Ask: "Which checkbox field on the resource must be true (or false)?"
|
|
106
133
|
Emit: `{ "resourceProperty": "<resource field>", "value": true|false }`
|
|
107
134
|
Note: Max 5 Match Boolean rules per policy.
|
|
108
135
|
|
|
109
136
|
---
|
|
110
137
|
|
|
111
|
-
**
|
|
112
|
-
|
|
113
|
-
Ask:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
3. Once those exist, create and configure the rule manually in Setup (Field Service Settings → Scheduling → Work Rules)
|
|
117
|
-
|
|
118
|
-
Capture intended objects/fields in `prerequisites` as advisory text — do not emit in `workRules[]`.
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
**7. Match Territory** — *(skip entirely; not part of the interview)*
|
|
123
|
-
This interview never emits a standalone Match Territory rule. **Skip it silently** — do not ask a Match Territory question, and do not announce or narrate that you are skipping it. Move straight from rule 6 to rule 8 with no mention of Match Territory at all. (If a user explicitly asks for primary/relocation-only territory scoping, advise manual configuration then — but never raise it yourself. Also: don't cover a resource by both Match Territory and Working Territories.)
|
|
138
|
+
**Maximum Travel from Home**
|
|
139
|
+
Gate: Only if selected in requirements mapping.
|
|
140
|
+
Ask: "Is the cap by **distance** or by **travel time**?" (see cap-type note in Requirements mapping)
|
|
141
|
+
Emit: `{ "maxTravelFromHome": <number>, "maxTravelFromHomeType": "Distance"|"Travel Time" }`
|
|
142
|
+
Note: Distance unit (miles vs km) is not part of the rule — governed by org locale. For Travel Time, value is minutes.
|
|
124
143
|
|
|
125
144
|
---
|
|
126
145
|
|
|
127
|
-
**
|
|
128
|
-
|
|
146
|
+
**Working Territories**
|
|
147
|
+
Gate: Only if selected in requirements mapping.
|
|
129
148
|
Ask: None — selecting the rule is sufficient.
|
|
130
149
|
Emit: `{ "workingLocationEnablePrimary": true }`
|
|
150
|
+
Note: No separate Match Territory question — the interview does not emit a standalone Match Territory rule. If primary/relocation-only scoping is needed, advise manual configuration.
|
|
131
151
|
|
|
132
152
|
---
|
|
133
153
|
|
|
134
|
-
**
|
|
135
|
-
|
|
136
|
-
Ask:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
---
|
|
154
|
+
**Service Crew Resources Availability**
|
|
155
|
+
Gate: Only if selected in requirements mapping.
|
|
156
|
+
Ask:
|
|
157
|
+
- "Should the rule evaluate individual crew members' availability and skills, not just the crew record?" → `considerCrewMembership`
|
|
158
|
+
- "What is the maximum number of extra resources beyond the base crew that can be pulled in?" → `maxAdditionalResources` (optional)
|
|
141
159
|
|
|
142
|
-
|
|
143
|
-
Applies when: any work order ever has a resource marked **Required** that must always be assigned. Ask: "Do any work orders ever have a specific resource marked *Required* that must always be assigned to that job?"
|
|
144
|
-
Emit: `{}`
|
|
145
|
-
Prerequisite: Resource Preference records must exist on the work order / WOLI — the rule enforces them but does not create them.
|
|
160
|
+
Emit: `{ "considerCrewMembership": true|false, "maxAdditionalResources": <number> }` (omit `maxAdditionalResources` if blank)
|
|
146
161
|
|
|
147
162
|
---
|
|
148
163
|
|
|
149
|
-
**
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
164
|
+
**Extended Match** *(advisory only — data-layer skill will not build this)*
|
|
165
|
+
Gate: Only if selected in requirements mapping.
|
|
166
|
+
Ask: None — no params to collect.
|
|
167
|
+
Advise the user to set up before deploying:
|
|
168
|
+
1. A junction object with exactly **two** Master-Detail relationships (to Service Resource + matched object) — packaged trigger requires exactly two or the rule fails
|
|
169
|
+
2. A Service Appointment Lookup field driving the match; a reference field on the junction matched against it
|
|
170
|
+
3. Once those exist, create and configure the rule manually in Setup (Field Service Settings → Scheduling → Work Rules)
|
|
171
|
+
|
|
172
|
+
Capture intended objects/fields in `prerequisites` as advisory text — do not emit in `workRules[]`.
|
|
153
173
|
|
|
154
174
|
---
|
|
155
175
|
|
|
156
|
-
**
|
|
157
|
-
|
|
176
|
+
**Count Rule**
|
|
177
|
+
Gate: Only if selected in requirements mapping.
|
|
158
178
|
Ask: Have the user describe the limit in plain terms, then classify into:
|
|
159
179
|
- `countBy` — `"Appointments"` (count of jobs), `"Hours"` (duration cap), or `"Custom"` (sum of a custom SA field)
|
|
160
180
|
- `maxValue` — the numeric cap (for Hours, convert to hours)
|
|
@@ -165,67 +185,32 @@ Note: Time Resolution is always Daily; counted object is always Service Appointm
|
|
|
165
185
|
|
|
166
186
|
---
|
|
167
187
|
|
|
168
|
-
**
|
|
169
|
-
|
|
188
|
+
**Selection-only rules** *(no config fields — each rule acts as an on/off switch that tells the scheduler to enforce constraints defined elsewhere in the org; selected in requirements mapping, no further questions needed)*
|
|
189
|
+
|
|
190
|
+
**Required Resources / Excluded Resources**
|
|
191
|
+
Gate: Only if selected in requirements mapping.
|
|
170
192
|
Emit: `{}`
|
|
171
|
-
Prerequisite:
|
|
193
|
+
Prerequisite: Resource Preference records must exist on the work order / WOLI — the rule enforces them but does not create them.
|
|
172
194
|
|
|
173
|
-
|
|
195
|
+
**Work Capacity** *(ESO only)*
|
|
196
|
+
Gate: Only if selected in requirements mapping.
|
|
197
|
+
Emit: `{}`
|
|
198
|
+
Prerequisite: WorkCapacityLimit records must be configured per territory outside the policy.
|
|
174
199
|
|
|
175
|
-
**
|
|
176
|
-
|
|
200
|
+
**Service Appointment Visiting Hours**
|
|
201
|
+
Gate: Only if selected in requirements mapping.
|
|
177
202
|
Emit: `{}`
|
|
178
|
-
Note: Do not ask for the windows — they are per-account data on OperatingHours records, not a policy-wide value.
|
|
203
|
+
Note: Do not ask for the windows — they are per-account data on OperatingHours records, not a policy-wide value. (No relevance-group scoping.)
|
|
179
204
|
Prerequisite: Each account must have visiting/operating hours populated; the Work Order's Visiting Hours must resolve from the account.
|
|
180
205
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
**15. TimeSlot Designated Work** *(selection-only)*
|
|
184
|
-
Applies when: certain time slots must be reserved for specific types of work. Ask: "Do you need to reserve certain time slots for specific types of work (e.g., install work only in morning slots)?"
|
|
206
|
+
**TimeSlot Designated Work**
|
|
207
|
+
Gate: Only if selected in requirements mapping.
|
|
185
208
|
Emit: `{}`
|
|
186
|
-
Note: Do not ask for slot→work mappings — that is data setup. Phrase the selection as "types of work," not "Work Type" (the designation is broader than the Work Type object).
|
|
209
|
+
Note: Do not ask for slot→work mappings — that is data setup. Phrase the selection as "types of work," not "Work Type" (the designation is broader than the Work Type object). (No relevance-group scoping.)
|
|
187
210
|
Prerequisite: Time slots must be configured to designate the intended work.
|
|
188
211
|
|
|
189
212
|
---
|
|
190
213
|
|
|
191
|
-
**16. Service Crew Resources Availability**
|
|
192
|
-
Applies when: crew-type resources must only be assigned when the crew meets the parent record's minimum crew size.
|
|
193
|
-
Ask:
|
|
194
|
-
- "Should the rule evaluate individual crew members' availability and skills, not just the crew record?" → `considerCrewMembership`
|
|
195
|
-
- "What is the maximum number of extra resources beyond the base crew that can be pulled in?" → `maxAdditionalResources` (optional)
|
|
196
|
-
|
|
197
|
-
Emit: `{ "considerCrewMembership": true|false, "maxAdditionalResources": <number> }` (omit `maxAdditionalResources` if blank)
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
### Configuration reference notes
|
|
202
|
-
|
|
203
|
-
These deep-dives support the **Ask** lines above; consult them when configuring the rule that references them.
|
|
204
|
-
|
|
205
|
-
**Arrival Window Match Time rules (default pair — rule 2).** When the user confirms appointments should honor customer arrival windows, emit **two** Match Time rules with these exact default settings — do not ask the user to fill these in, they are the standard arrival-window configuration:
|
|
206
|
-
|
|
207
|
-
| Setting | Rule A | Rule B |
|
|
208
|
-
|---|---|---|
|
|
209
|
-
| Name | `Arrival Window Start` | `Arrival Window End` |
|
|
210
|
-
| Service Schedule Time Property | `SchedStartTime` | `SchedStartTime` |
|
|
211
|
-
| Service Time Operator | `Later than or Equal to` | `Before or Equal to` |
|
|
212
|
-
| Service Time Property | `ArrivalWindowStartTime` | `ArrivalWindowEndTime` |
|
|
213
|
-
| Pass Empty Values | `true` | `true` |
|
|
214
|
-
|
|
215
|
-
Emit each as a Match Time work rule whose `params` carry those four values (keys `serviceScheduleTimeProperty`, `serviceTimeOperator`, `serviceTimeProperty`, `passEmptyValues`). These are separate from the mandatory Earliest Start Permitted / Due Date rules (never emitted).
|
|
216
|
-
|
|
217
|
-
**Interpreting and emitting break times — clock time vs. shift-start offset (rule 1).** A Service Resource Availability rule expresses breaks in one of two shapes, and **this skill decides the shape and emits the values the data-layer skill needs** — the data-layer skill never receives a clock time it has to convert. Choose the shape as follows:
|
|
218
|
-
|
|
219
|
-
- **One fixed daily break at an absolute clock time** (e.g. "30 minutes at 12:00 every day") → emit it as an **absolute** break: `{ "mode": "absolute", "startClock": "12:00", "durationMinutes": 30 }`. No offset math, no working-day start needed.
|
|
220
|
-
- **One or more breaks defined as an offset from the start of the working day** (e.g. "a 30-minute lunch starting 3 hours into the shift") → emit each as an **offset** break, in **minutes from the start of the working day**: `{ "mode": "offset", "earliestStartOffsetMinutes": 180, "latestEndOffsetMinutes": 240, "durationMinutes": 30 }`. All three of `earliestStartOffsetMinutes`, `latestEndOffsetMinutes`, and `durationMinutes` are **mandatory** for an offset break. **When the user states the break in offset terms already** (e.g. "3 hours after the start of day"), that offset *is* `earliestStartOffsetMinutes` (180) — **do not ask for the working-day start; you don't need it.**
|
|
221
|
-
- **Breaks given as clock times but there is more than one** (e.g. "15 minutes at 10:00 and 30 minutes at 12:00") → you must use the **offset** shape, which means **converting each clock time into an offset from the start of the working day**. You cannot do that without knowing when the day starts, so **ask the user for the shift / working-day start**, then compute `earliestStartOffsetMinutes = (break start clock − day start)` in minutes for each break. Never assume the day starts at midnight (that would turn "10:00" into a wrong 600-minute offset). *(Only ask for the day start in this clock-time case — never when the break is already expressed as an offset.)*
|
|
222
|
-
|
|
223
|
-
**Always emit `latestEndOffsetMinutes` for every offset break — ask for it directly, do not fabricate a window.** The earliest start comes from what the user stated (an offset, or a converted clock time) — **do not invent ± tolerance windows around it** (no "±1 hour" / "±2 hour" options). If the user only gave a break start (or a duration with no stated finish-by), **ask them plainly for the latest the break may end**, phrased in the *same terms they used*: if they gave an offset ("starts 3 hours after start of day"), ask "what is the latest it may end, as time after the start of the day?" and convert (e.g. "4 hours after start" → 240); if they gave a clock time, ask for a clock time and convert with the day start. If the user says the break is fixed/pinned with no flex, set `latestEndOffsetMinutes = earliestStartOffsetMinutes + durationMinutes`. Never emit an offset break missing any of the three fields, and never guess the latest-end. If a break requirement is too involved to convert reliably, ask clarifying questions or recommend the manual approach rather than guessing.
|
|
224
|
-
|
|
225
|
-
**Maximum Travel from Home — establish the cap type, not the unit (rule 9).** When a requirement caps how far a resource may travel from home, **ask the user whether the cap is by distance or by travel time** — the two are configured differently and the data-layer skill needs to know which. Emit the value and the type in `params`: `{ "maxTravelFromHome": 50, "maxTravelFromHomeType": "Distance" | "Travel Time" }`. Interpret the user's phrasing to set the *type* — "50 miles"/"50 km" ⇒ `Distance`, "45 minutes" ⇒ `Travel Time` — but **do not ask for or emit a distance unit (miles vs km): it is not part of the work-rule config**; the unit is governed by the org's locale/distance settings elsewhere, so the rule stores only the number. For `Travel Time` the value is minutes. Never emit the cap value without its type.
|
|
226
|
-
|
|
227
|
-
---
|
|
228
|
-
|
|
229
214
|
## Relevance Groups
|
|
230
215
|
|
|
231
216
|
A relevance group scopes a single work rule or service objective so it applies only to certain appointments or resources, instead of the whole policy. This lets one policy hold different logic for different work or resource types — e.g., different break/travel limits for part-time vs. full-time employees, or expedited scheduling for high-value accounts.
|
|
@@ -8,6 +8,7 @@ metadata:
|
|
|
8
8
|
relatedSkills:
|
|
9
9
|
- "automation-flow-generate"
|
|
10
10
|
- "platform-permission-set-generate"
|
|
11
|
+
- "service-agentforce-channel-configure"
|
|
11
12
|
- "service-digital-engagement-deployment-configure"
|
|
12
13
|
cliTools:
|
|
13
14
|
- tool: ["sf"]
|
|
@@ -91,7 +92,7 @@ All steps are sequential. Do not skip or reorder.
|
|
|
91
92
|
- Also verify the fallback queue exists (required for Flow, User, and ASA routing)
|
|
92
93
|
|
|
93
94
|
If any target is not found, inform the user and ask whether to create it. If the user confirms:
|
|
94
|
-
- For Queue: generate a `.queue-meta.xml` with `MessagingSession` as the `queueSobject` type and deploy it before the channel
|
|
95
|
+
- For Queue: generate a `.queue-meta.xml` with `MessagingSession` as the `queueSobject` type and deploy it before the channel. **A new queue is unusable for routing without a `QueueRoutingConfig` — a channel deployed against a queue with none fails at session-start with "Agents are not available. Try again later," even though the channel itself deploys and activates cleanly.** Immediately after the queue deploys, resolve or create its routing config by following `service-agentforce-channel-configure`'s `references/queue-resolution.md` Step 4 — do not defer this to a later skill invocation, since this may be the only place a newly created queue is ever touched.
|
|
95
96
|
- For Flow/User/ASA: inform the user that the flow, user, or bot must be created separately (out of scope for this skill)
|
|
96
97
|
|
|
97
98
|
5. **Read the channel settings reference** — load `references/channel_settings.md` to understand all available configuration options and their valid values.
|
|
@@ -107,20 +108,12 @@ All steps are sequential. Do not skip or reorder.
|
|
|
107
108
|
| Omni-Channel Queue | `Queue` | `sessionHandlerQueue` |
|
|
108
109
|
| Omni-Channel Flow | `Flow` | `sessionHandlerFlow` + `sessionHandlerQueue` (fallback) |
|
|
109
110
|
| User | `User` | `sessionHandlerUser` + `sessionHandlerQueue` (fallback) |
|
|
110
|
-
| Agentforce Service Agent | `AgentforceServiceAgent` | `sessionHandlerQueue` (fallback
|
|
111
|
-
|
|
112
|
-
> **v67
|
|
113
|
-
> 1. **Verify the bot is Active before channel creation.** The
|
|
114
|
-
> 2. Deploy the XML with `<sessionHandlerType>AgentforceServiceAgent</sessionHandlerType
|
|
115
|
-
> 3.
|
|
116
|
-
> 4. Resolve the BotDefinition Id: `sf data query -o <org> -q "SELECT Id FROM BotDefinition WHERE DeveloperName='<BotDevName>'" --json`
|
|
117
|
-
> 5. PATCH both handler fields via Data API in a single call:
|
|
118
|
-
> ```bash
|
|
119
|
-
> sf api request rest -o <org> --method PATCH \
|
|
120
|
-
> "/services/data/v67.0/sobjects/MessagingChannel/<CHAN_ID>" \
|
|
121
|
-
> --body "{\"SessionHandlerId\":\"<BOT_ID>\",\"FallbackQueueId\":\"<QUEUE_ID>\"}"
|
|
122
|
-
> ```
|
|
123
|
-
> 6. Verify: `sf data query -o <org> -q "SELECT SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE Id='<CHAN_ID>'" --json` — both must be non-null.
|
|
111
|
+
| Agentforce Service Agent | `AgentforceServiceAgent` | `sessionHandlerQueue` (fallback) + `sessionHandlerAsa` (bot dev name — required, see v67 note below) |
|
|
112
|
+
|
|
113
|
+
> **v67 note — `<sessionHandlerAsa>` is required in the XML, not rejected.** Confirmed on a v67.0 org: omitting `<sessionHandlerAsa>` causes the deploy to fail with "Missing required Agentforce Service Agent." Include it and the deploy binds `SessionHandlerId` automatically — no post-deploy Data API PATCH needed.
|
|
114
|
+
> 1. **Verify the bot is Active before channel creation.** The Metadata API rejects binding with "Only active Agentforce Service Agents are supported." Run `sf agent activate -o <org> --api-name <BotDevName>` and confirm `BotVersion.Status = Active` first.
|
|
115
|
+
> 2. Deploy the XML with `<sessionHandlerType>AgentforceServiceAgent</sessionHandlerType>`, `<sessionHandlerQueue>` (fallback), and `<sessionHandlerAsa>{BotDevName}</sessionHandlerAsa>`.
|
|
116
|
+
> 3. Verify: `sf data query -o <org> -q "SELECT SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE DeveloperName='<ChannelDevName>'" --json` — both must be non-null after the deploy, with no separate PATCH step.
|
|
124
117
|
|
|
125
118
|
8. **Apply user verification** — if enabled, set `embeddedConfig.authMode` to `Auth` and include `<messagingAuthorizations>`. If not enabled, set `embeddedConfig.authMode` to `UnAuth` and omit `<messagingAuthorizations>`.
|
|
126
119
|
|
|
@@ -154,26 +147,14 @@ All steps are sequential. Do not skip or reorder.
|
|
|
154
147
|
sf project deploy start --source-dir <path-to-messagingChannels-folder> --target-org <org-alias>
|
|
155
148
|
```
|
|
156
149
|
|
|
157
|
-
15a. **ASA routing only —
|
|
150
|
+
15a. **ASA routing only — verify the bind landed.** Skip this step for Queue, Flow, and User routing types. Because `<sessionHandlerAsa>` was included in the deployed XML (step 7), the deploy itself binds `SessionHandlerId` — no separate Data API PATCH is needed.
|
|
158
151
|
|
|
159
152
|
```bash
|
|
160
|
-
|
|
161
|
-
-q "SELECT
|
|
162
|
-
| python3 -c "import sys,json; print(json.load(sys.stdin)['result']['records'][0]['Id'])")
|
|
163
|
-
BOT_ID=$(sf data query -o <org> --json \
|
|
164
|
-
-q "SELECT Id FROM BotDefinition WHERE DeveloperName='<ASA_BOT_DEV_NAME>'" \
|
|
165
|
-
| python3 -c "import sys,json; print(json.load(sys.stdin)['result']['records'][0]['Id'])")
|
|
166
|
-
QUEUE_ID=$(sf data query -o <org> --json \
|
|
167
|
-
-q "SELECT Id FROM Group WHERE Type='Queue' AND DeveloperName='<FALLBACK_QUEUE_DEV_NAME>'" \
|
|
168
|
-
| python3 -c "import sys,json; print(json.load(sys.stdin)['result']['records'][0]['Id'])")
|
|
169
|
-
|
|
170
|
-
sf api request rest -o <org> --method PATCH \
|
|
171
|
-
"/services/data/v67.0/sobjects/MessagingChannel/$CHAN_ID" \
|
|
172
|
-
--body "{\"SessionHandlerId\":\"$BOT_ID\",\"FallbackQueueId\":\"$QUEUE_ID\"}"
|
|
173
|
-
# Expected: HTTP 204
|
|
153
|
+
sf data query -o <org> --json \
|
|
154
|
+
-q "SELECT SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE DeveloperName='<CHANNEL_DEV_NAME>'"
|
|
174
155
|
```
|
|
175
156
|
|
|
176
|
-
|
|
157
|
+
Both `SessionHandlerId` and `FallbackQueueId` must be non-null. If either is null, confirm `<sessionHandlerAsa>` and `<sessionHandlerQueue>` were both present in the deployed XML and that the bot was Active before the deploy.
|
|
177
158
|
|
|
178
159
|
15. **Activate the channel** — after successful deployment, activate the messaging channel:
|
|
179
160
|
```bash
|
|
@@ -197,8 +178,8 @@ All steps are sequential. Do not skip or reorder.
|
|
|
197
178
|
| `sessionHandlerType` must match the handler fields present | Setting `Queue` but populating `sessionHandlerFlow` causes deployment error |
|
|
198
179
|
| Flow routing requires both `sessionHandlerFlow` and `sessionHandlerQueue` | Queue is the mandatory fallback for human escalation |
|
|
199
180
|
| User routing requires both `sessionHandlerUser` and `sessionHandlerQueue` | Queue is the mandatory fallback when user is unavailable |
|
|
200
|
-
| ASA routing: include `sessionHandlerQueue` in the XML
|
|
201
|
-
| Bot must be Active before the
|
|
181
|
+
| ASA routing: include both `sessionHandlerQueue` and `sessionHandlerAsa` in the XML | `sessionHandlerAsa` is required at v67 — the deploy fails with "Missing required Agentforce Service Agent" if omitted; the deploy itself binds `SessionHandlerId`, no PATCH needed |
|
|
182
|
+
| Bot must be Active before the metadata deploy that binds `SessionHandlerId` | API rejects with "Only active Agentforce Service Agents are supported" if the bot is inactive |
|
|
202
183
|
| `masterLabel` max 40 characters | Platform limit on channel labels |
|
|
203
184
|
| File name must match `^[a-zA-Z][a-zA-Z0-9_]*$` | API name format enforced by Metadata API |
|
|
204
185
|
| `allowedFileTypes` is a comma-separated string with no spaces | Not a nested list or array |
|
|
@@ -217,10 +198,12 @@ All steps are sequential. Do not skip or reorder.
|
|
|
217
198
|
|-------|------------|
|
|
218
199
|
| Channel name conflicts with existing channel | Check org for existing channels; file name must be unique |
|
|
219
200
|
| Queue not found on deploy | Ensure the referenced queue exists and has `MessagingSession` as a `queueSobject` type |
|
|
201
|
+
| Channel deploys and activates fine, but widget shows "Agents are not available. Try again later." at session start | The queue has no `QueueRoutingConfig` — this is silent at deploy time. Check `SELECT QueueRoutingConfigId FROM Group WHERE Id='<QUEUE_ID>'`; if null, resolve/create one per `queue-resolution.md` Step 4 |
|
|
220
202
|
| Omni-Channel Flow not found on deploy | Ensure the referenced flow exists and is active before deploying the channel |
|
|
221
203
|
| ASA bot reference invalid | Bot must be published and active; use exact developer name from BotDefinition metadata |
|
|
222
|
-
| ASA channel
|
|
223
|
-
|
|
|
204
|
+
| ASA channel deploy fails with "Missing required Agentforce Service Agent" | `<sessionHandlerAsa>{BotDevName}</sessionHandlerAsa>` is missing from the XML — it's required at v67, not optional |
|
|
205
|
+
| ASA channel deployed but `SessionHandlerId` is null after deploy | Bot was not Active at deploy time — run `sf agent activate`, confirm `BotVersion.Status = Active`, then redeploy |
|
|
206
|
+
| "Only active Agentforce Service Agents are supported" on deploy | Bot is inactive — run `sf agent activate` before deploying |
|
|
224
207
|
| Flow or ASA routing fails without fallback queue | `sessionHandlerQueue` is mandatory when `sessionHandlerType` is `Flow` or `AgentforceServiceAgent` |
|
|
225
208
|
| JWT verification not working | Connected app and certificate must be configured for the org |
|
|
226
209
|
| Custom parameters not collected | `name` must be unique per channel; `parameterDataType` defaults to `Text` |
|
|
@@ -242,8 +225,8 @@ All steps are sequential. Do not skip or reorder.
|
|
|
242
225
|
- [ ] For Queue routing: is `sessionHandlerQueue` in the XML?
|
|
243
226
|
- [ ] For Flow routing: is `sessionHandlerFlow` in the XML, plus `sessionHandlerQueue` as fallback?
|
|
244
227
|
- [ ] For User routing: is `sessionHandlerUser` in the XML, plus `sessionHandlerQueue` as fallback?
|
|
245
|
-
- [ ] For ASA routing:
|
|
246
|
-
- [ ] For ASA routing: was step 15a run? Are `SessionHandlerId` and `FallbackQueueId` non-null after the
|
|
228
|
+
- [ ] For ASA routing: are both `sessionHandlerQueue` and `sessionHandlerAsa` in the XML?
|
|
229
|
+
- [ ] For ASA routing: was step 15a run? Are `SessionHandlerId` and `FallbackQueueId` non-null after the deploy?
|
|
247
230
|
- [ ] Does the routing target reference an existing entity in the org?
|
|
248
231
|
|
|
249
232
|
### User Verification Checks
|
package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml
CHANGED
|
@@ -96,8 +96,9 @@
|
|
|
96
96
|
<!-- <sessionHandlerType>Flow</sessionHandlerType> -->
|
|
97
97
|
|
|
98
98
|
<!-- Routing: Agentforce Service Agent (requires a fallback queue) -->
|
|
99
|
-
<!-- NOTE: sessionHandlerAsa is
|
|
100
|
-
<!--
|
|
99
|
+
<!-- NOTE: sessionHandlerAsa is REQUIRED at v67 — deploy fails with "Missing required Agentforce Service Agent" if omitted. -->
|
|
100
|
+
<!-- The deploy binds SessionHandlerId automatically; verify it landed with a query (see SKILL.md step 15a). -->
|
|
101
|
+
<!-- <sessionHandlerAsa>{ASA_BOT_DEV_NAME}</sessionHandlerAsa> -->
|
|
101
102
|
<!-- <sessionHandlerQueue>{FALLBACK_QUEUE_NAME}</sessionHandlerQueue> -->
|
|
102
103
|
<!-- <sessionHandlerType>AgentforceServiceAgent</sessionHandlerType> -->
|
|
103
104
|
</MessagingChannel>
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
<keywordType>Help</keywordType>
|
|
48
48
|
<language>en_US</language>
|
|
49
49
|
</messagingKeywords>
|
|
50
|
-
<!-- sessionHandlerAsa is
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
<!-- sessionHandlerAsa is REQUIRED at v67 — deploy fails with "Missing required Agentforce
|
|
51
|
+
Service Agent" if omitted. The deploy binds SessionHandlerId automatically; verify with
|
|
52
|
+
step 15a in SKILL.md. -->
|
|
53
|
+
<sessionHandlerAsa>Support_Service_Agent</sessionHandlerAsa>
|
|
54
54
|
<sessionHandlerQueue>Support_Escalation_Queue</sessionHandlerQueue>
|
|
55
55
|
<sessionHandlerType>AgentforceServiceAgent</sessionHandlerType>
|
|
56
56
|
</MessagingChannel>
|