@salesforce/afv-skills 1.46.0 → 1.48.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/agentforce-observe/SKILL.md +32 -4
- package/skills/agentforce-observe/references/ahm-alerts.md +719 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/SKILL.md +275 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/README.md +32 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/SetCommentValue.cls +75 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/SetCommentValue.cls-meta.xml +5 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/interview-answers.json +13 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/copy.json +10 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/create.json +20 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/update.json +16 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/references/conventions-and-payload-rules.md +273 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/references/generate-and-wire.md +236 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/references/reference-example-set-comment-value.md +132 -0
- package/skills/consumer-goods-promotion-bo-api-deploy/references/smoke-and-verify.md +211 -0
- package/skills/dx-devops-project-manage/SKILL.md +197 -0
- package/skills/dx-devops-project-manage/examples/common-workflows.md +197 -0
- package/skills/dx-devops-project-manage/references/cli-commands.md +295 -0
- package/skills/dx-devops-project-manage/scripts/create-project.sh +48 -0
- package/skills/dx-devops-project-manage/scripts/list-projects.sh +51 -0
- package/skills/dx-devops-project-manage/scripts/update-project.sh +96 -0
- package/skills/education-cloud-academic-calendar-generate/SKILL.md +225 -0
- package/skills/education-cloud-academic-calendar-generate/examples/quarter-calendar.json +47 -0
- package/skills/education-cloud-academic-calendar-generate/examples/sample-output.md +57 -0
- package/skills/education-cloud-academic-calendar-generate/examples/semester-calendar.json +54 -0
- package/skills/education-cloud-academic-calendar-generate/references/calendar-systems.md +127 -0
- package/skills/education-cloud-academic-calendar-generate/references/date-validation.md +222 -0
- package/skills/education-cloud-academic-calendar-generate/references/foundation_prerequisites.md +40 -0
- package/skills/education-cloud-academic-calendar-generate/scripts/validate_calendar_dates.py +143 -0
- package/skills/education-cloud-course-catalog-migrate/SKILL.md +321 -0
- package/skills/education-cloud-course-catalog-migrate/references/gotchas-detail.md +16 -0
- package/skills/education-cloud-course-catalog-migrate/references/gotchas.md +16 -0
- package/skills/education-cloud-course-catalog-migrate/references/large-catalog-handling.md +42 -0
- package/skills/education-cloud-course-catalog-migrate/scripts/batch_courses.py +36 -0
- package/skills/education-cloud-course-catalog-migrate/scripts/detect_linked_courses.py +51 -0
- package/skills/education-cloud-course-catalog-migrate/scripts/detect_modality_variants.py +48 -0
- package/skills/education-cloud-course-catalog-migrate/scripts/resolve_api_version.py +43 -0
- package/skills/education-cloud-course-catalog-migrate/scripts/split_course_code.py +39 -0
- package/skills/education-cloud-course-catalog-migrate/scripts/validate_completeness.py +54 -0
- package/skills/education-cloud-domain-configure/SKILL.md +234 -0
- package/skills/education-cloud-domain-configure/references/dependent-features.md +198 -0
- package/skills/education-cloud-domain-configure/references/domain-features/academic-operations.md +386 -0
- package/skills/education-cloud-domain-configure/references/domain-features/alumni-relations.md +155 -0
- package/skills/education-cloud-domain-configure/references/domain-features/cross-domain-dependencies.md +18 -0
- package/skills/education-cloud-domain-configure/references/domain-features/industriessettings-toggle-reference.md +43 -0
- package/skills/education-cloud-domain-configure/references/domain-features/mentoring.md +198 -0
- package/skills/education-cloud-domain-configure/references/domain-features/recruitment-admissions.md +315 -0
- package/skills/education-cloud-domain-configure/references/domain-features/student-management.md +155 -0
- package/skills/education-cloud-domain-configure/references/domain-features/student-success.md +249 -0
- package/skills/education-cloud-domain-configure/references/domain-features.md +27 -0
- package/skills/education-cloud-domain-configure/references/gotchas-extended.md +23 -0
- package/skills/education-cloud-domain-configure/references/toggle-write-path.md +67 -0
- package/skills/education-cloud-domain-configure/scripts/check_license_provisioned.py +62 -0
- package/skills/education-cloud-domain-configure/scripts/check_org_edition.py +44 -0
- package/skills/education-cloud-domain-configure/scripts/check_permission_assigned.py +39 -0
- package/skills/education-cloud-multi-campus-configure/SKILL.md +7 -0
- package/skills/education-cloud-multi-campus-configure/references/foundation_prerequisites.md +1 -2
- package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +177 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/agent-and-subagents.md +151 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/customer-narration.md +34 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/execution-model.md +54 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/flows.md +82 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/grounding.md +199 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/permissions.md +183 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/platform-enablement.md +82 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/prerequisites.md +158 -0
- package/skills/education-cloud-student-recruitment-agent-configure/references/routing.md +141 -0
- package/skills/experience-cms-brand-apply/SKILL.md +5 -5
- package/skills/experience-cms-brand-create/SKILL.md +2 -2
- package/skills/experience-cms-content-generate/SKILL.md +1 -0
- package/skills/experience-cms-content-render/SKILL.md +173 -0
- package/skills/experience-cms-content-render/assets/angular/DetailPage.component.ts +25 -0
- package/skills/experience-cms-content-render/assets/angular/MediaRenderer.component.ts +133 -0
- package/skills/experience-cms-content-render/assets/angular/TypeList.component.ts +38 -0
- package/skills/experience-cms-content-render/assets/angular/TypeRenderer.component.ts +90 -0
- package/skills/experience-cms-content-render/assets/angular/cms-content.component.ts +248 -0
- package/skills/experience-cms-content-render/assets/angular/cms-item.service.ts +100 -0
- package/skills/experience-cms-content-render/assets/react/DetailPage.tsx +20 -0
- package/skills/experience-cms-content-render/assets/react/MediaRenderer.tsx +129 -0
- package/skills/experience-cms-content-render/assets/react/TypeList.tsx +40 -0
- package/skills/experience-cms-content-render/assets/react/TypeRenderer.tsx +64 -0
- package/skills/experience-cms-content-render/assets/react/heuristicRenderer.tsx +310 -0
- package/skills/experience-cms-content-render/assets/react/useCmsItem.ts +129 -0
- package/skills/experience-cms-content-render/assets/shared/cmsContentType.ts +49 -0
- package/skills/experience-cms-content-render/assets/shared/cmsCore.types.ts +96 -0
- package/skills/experience-cms-content-render/assets/shared/externalRefs.ts +55 -0
- package/skills/experience-cms-content-render/references/bulk-loading.md +60 -0
- package/skills/experience-cms-content-render/references/codegen-guardrails.md +111 -0
- package/skills/experience-cms-content-render/references/detail-pages.md +87 -0
- package/skills/experience-cms-content-render/references/embed-recipes.md +127 -0
- package/skills/experience-cms-content-render/references/failure-modes.md +96 -0
- package/skills/experience-cms-content-render/references/heuristic-render-rules.md +131 -0
- package/skills/experience-cms-content-render/references/init-scaffold.md +122 -0
- package/skills/experience-cms-content-render/references/interaction-model.md +173 -0
- package/skills/experience-cms-content-render/references/package-api.md +106 -0
- package/skills/experience-cms-content-render/references/schema-sync.md +114 -0
- package/skills/experience-cms-content-render/references/styling-scopes.md +65 -0
- package/skills/experience-cms-content-render/references/verify.md +49 -0
- package/skills/experience-cms-content-type-generate/SKILL.md +2 -2
- package/skills/experience-content-media-stock-image-search/SKILL.md +5 -4
- package/skills/experience-search-coordinate/SKILL.md +198 -0
- package/skills/experience-search-coordinate/assets/search-payload-template.json +25 -0
- package/skills/experience-search-coordinate/references/content-route.md +313 -0
- package/skills/experience-search-coordinate/references/content-type-discovery.md +57 -0
- package/skills/experience-search-coordinate/references/media-route.md +172 -0
- package/skills/experience-search-coordinate/references/scope-resolution.md +14 -0
- package/skills/experience-ui-bundle-localize/SKILL.md +1 -1
- package/skills/experience-ui-bundle-localize/references/i18n-setup.md +5 -3
- package/skills/experience-ui-bundle-project-generate/SKILL.md +18 -14
- package/skills/experience-ui-bundle-project-generate/references/angular-project-generate.md +22 -0
- package/skills/experience-ui-bundle-project-generate/references/react-project-generate.md +20 -0
- package/skills/experience-ui-bundle-salesforce-data-access/SKILL.md +58 -54
- package/skills/experience-ui-bundle-salesforce-data-access/references/caching.md +6 -0
- package/skills/experience-ui-bundle-salesforce-data-access/references/graphiti-cli.md +2 -2
- package/skills/experience-ui-bundle-salesforce-data-access/references/migration.md +6 -0
- package/skills/experience-ui-bundle-salesforce-data-access/references/rest-and-integration.md +2 -1
- package/skills/experience-ui-bundle-salesforce-data-access/references/sdk-api.md +6 -0
- package/skills/experience-ui-bundle-site-generate/SKILL.md +59 -8
- package/skills/experience-ui-bundle-site-generate/references/configure-metadata-digital-experience.md +8 -3
- package/skills/experience-ui-bundle-site-generate/references/configure-metadata-language-settings.md +120 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +336 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +143 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-application-flexipage-mapping.md +127 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-deploy-commands.md +116 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-lifesci-metadata-deploy.md +111 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-overview.md +312 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-profile-layout-assignments.md +171 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-state-tracking.md +64 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-trigger-handlers.md +122 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-4-user-provisioning-overview.md +335 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-4-user-provisioning-user-provisioning-details.md +140 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-execution-state-and-recovery.md +196 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-metadata-cache-generation.md +155 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-overview.md +307 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-visit-creation-data.md +211 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/references/state-machine-and-changes.md +108 -0
- package/skills/life-sciences-kam-coordinate/SKILL.md +241 -0
- package/skills/life-sciences-kam-coordinate/references/orchestration-flow.md +152 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-application-flexipage-mapping.md +79 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-deploy-commands.md +131 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-kam-config-records.md +85 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-lifesci-metadata-deploy.md +112 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-overview.md +202 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-profile-layout-assignments.md +67 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-state-tracking.md +65 -0
- package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-trigger-handlers.md +123 -0
- package/skills/life-sciences-kam-coordinate/references/stage-4-participant-role-and-sprint.md +89 -0
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +337 -0
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-creation-data.md +248 -0
- package/skills/life-sciences-kam-coordinate/references/stage-6-ipad-validation-script.md +35 -0
- package/skills/life-sciences-kam-coordinate/references/stage-6-metadata-cache-generation.md +155 -0
- package/skills/life-sciences-kam-coordinate/references/stage-6-user-provisioning-details.md +146 -0
- package/skills/life-sciences-kam-coordinate/references/stage-6-user-provisioning-overview.md +89 -0
- package/skills/life-sciences-kam-coordinate/references/state-machine-and-changes.md +114 -0
- package/skills/life-sciences-prerequisites-validate/SKILL.md +138 -0
- package/skills/life-sciences-prerequisites-validate/references/checks-org-settings.md +190 -0
- package/skills/life-sciences-prerequisites-validate/references/checks-user-and-package.md +211 -0
- package/skills/life-sciences-territory-configure/SKILL.md +217 -0
- package/skills/life-sciences-territory-configure/references/territory-metadata.md +262 -0
- package/skills/platform-dsar-policy-manage/SKILL.md +272 -0
- package/skills/platform-dsar-policy-manage/references/configure.md +106 -0
- package/skills/platform-dsar-policy-manage/references/export-and-history.md +123 -0
- package/skills/platform-dsar-policy-manage/references/gap-analysis-guide.md +150 -0
- package/skills/platform-dsar-policy-manage/references/gap-scan.md +129 -0
- package/skills/platform-dsar-policy-manage/references/headless-sor.md +59 -0
- package/skills/platform-dsar-policy-manage/references/report-format.md +59 -0
- package/skills/platform-dsar-policy-manage/scripts/tests/__init__.py +0 -0
- package/skills/platform-dsar-policy-manage/scripts/tests/test_validate_policy_tree.py +76 -0
- package/skills/platform-dsar-policy-manage/scripts/validate-policy-tree.py +130 -0
- package/skills/platform-salesforce-connect-adapter-generate/SKILL.md +359 -0
- package/skills/platform-salesforce-connect-adapter-generate/references/official-examples.md +69 -0
- package/skills/platform-salesforce-connect-adapter-generate/references/scenarios.md +187 -0
- package/skills/service-agentforce-channel-configure/SKILL.md +33 -28
- package/skills/service-agentforce-human-escalation-configure/SKILL.md +205 -0
- package/skills/service-agentforce-human-escalation-configure/assets/escalation-thresholds.instructions.md +37 -0
- package/skills/service-agentforce-human-escalation-configure/assets/force-app/main/default/flows/Human_Escalation_Outbound_Flow.flow-meta.xml +173 -0
- package/skills/service-agentforce-human-escalation-configure/assets/package.xml +8 -0
- package/skills/service-agentforce-human-escalation-configure/assets/sfdx-project.json +5 -0
- package/skills/service-agentforce-human-escalation-configure/references/classifier-contracts.md +103 -0
- package/skills/service-agentforce-human-escalation-configure/references/escalation-mechanism.md +63 -0
- package/skills/service-agentforce-human-escalation-configure/references/failure-policy.md +44 -0
- package/skills/service-agentforce-human-escalation-configure/references/nga-escalation.md +57 -0
- package/skills/service-agentforce-human-escalation-configure/references/runtime-verification.md +72 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/classify-agent-active.mjs +49 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/classify-nga-escalation.mjs +166 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/extract-outbound-route.mjs +67 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/patch-escalation-surfaces.mjs +131 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/__init__.py +0 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/_bootstrap.py +249 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/tests/test_escalation_contracts.py +899 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/verify-and-configure.sh +705 -0
- package/skills/service-agentforce-human-escalation-configure/scripts/verify-escalation-config.mjs +89 -0
- package/skills/service-de-channel-routing-configure/SKILL.md +13 -5
- package/skills/service-de-channel-routing-configure/scripts/tests/test_skill_contract.py +25 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +23 -10
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +63 -48
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +6 -2
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +20 -27
- package/skills/service-native-voice-recording-transcription-configure/SKILL.md +47 -27
- package/skills/service-native-voice-recording-transcription-configure/references/thunderbird-voice-settings.md +13 -9
- package/skills/service-native-voice-recording-transcription-configure/scripts/enable-recording-transcription.sh +104 -45
- package/skills/service-omni-agent-users-create/SKILL.md +96 -0
- package/skills/service-omni-agent-users-create/assets/create-users.apex.template +80 -0
- package/skills/service-omni-agent-users-create/references/apex-patterns.md +135 -0
- package/skills/service-omni-agent-users-create/references/apex-template-notes.md +40 -0
- package/skills/service-omni-agent-users-create/scripts/detect-and-create.sh +206 -0
- package/skills/service-omni-agent-users-create/scripts/detect-existing.sh +122 -0
- package/skills/service-omni-agent-users-create/scripts/run-create.sh +298 -0
- package/skills/service-omni-agent-users-create/scripts/tests/test_user_create_security.py +171 -0
- package/skills/service-omni-agent-work-sharing-configure/SKILL.md +78 -0
- package/skills/service-omni-agent-work-sharing-configure/references/api-notes.md +31 -0
- package/skills/service-omni-agent-work-sharing-configure/scripts/configure-and-report.sh +186 -0
- package/skills/service-omni-agent-work-sharing-configure/scripts/tests/_bootstrap.py +120 -0
- package/skills/service-omni-agent-work-sharing-configure/scripts/tests/test_agent_work_sharing_contracts.py +93 -0
- package/skills/service-omni-base-settings-configure/SKILL.md +77 -0
- package/skills/service-omni-base-settings-configure/assets/force-app/main/default/settings/OmniChannel.settings-meta.xml +8 -0
- package/skills/service-omni-base-settings-configure/assets/package.xml +8 -0
- package/skills/service-omni-base-settings-configure/assets/sfdx-project.json +12 -0
- package/skills/service-omni-base-settings-configure/references/api-notes.md +121 -0
- package/skills/service-omni-base-settings-configure/scripts/configure-and-report.sh +164 -0
- package/skills/service-omni-base-settings-configure/scripts/detect-existing.sh +69 -0
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +168 -0
- package/skills/service-omni-channel-setup-coordinate/examples/output-templates.md +161 -0
- package/skills/service-omni-channel-setup-coordinate/references/gap-catalog.md +99 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +1542 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/__init__.py +0 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/_bootstrap.py +223 -0
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +804 -0
- package/skills/service-omni-command-center-analyze/SKILL.md +84 -0
- package/skills/service-omni-command-center-analyze/references/api-notes.md +54 -0
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +198 -0
- package/skills/service-omni-command-center-analyze/scripts/tests/_bootstrap.py +115 -0
- package/skills/service-omni-command-center-analyze/scripts/tests/test_command_center_analyze_contracts.py +165 -0
- package/skills/service-omni-permission-set-assign/SKILL.md +88 -0
- package/skills/service-omni-permission-set-assign/assets/package.xml +8 -0
- package/skills/service-omni-permission-set-assign/references/api-notes.md +143 -0
- package/skills/service-omni-permission-set-assign/scripts/verify-and-assign.sh +397 -0
- package/skills/service-omni-presence-status-deploy/SKILL.md +87 -0
- package/skills/service-omni-presence-status-deploy/assets/package.xml +12 -0
- package/skills/service-omni-presence-status-deploy/references/api-notes.md +115 -0
- package/skills/service-omni-presence-status-deploy/scripts/deploy-and-report.sh +422 -0
- package/skills/service-omni-presence-user-config-deploy/SKILL.md +80 -0
- package/skills/service-omni-presence-user-config-deploy/references/api-notes.md +60 -0
- package/skills/service-omni-presence-user-config-deploy/scripts/deploy-and-report.sh +261 -0
- package/skills/service-omni-presence-user-config-deploy/scripts/tests/_bootstrap.py +106 -0
- package/skills/service-omni-presence-user-config-deploy/scripts/tests/test_presence_user_config_contracts.py +142 -0
- package/skills/service-omni-queue-deploy/SKILL.md +91 -0
- package/skills/service-omni-queue-deploy/references/api-notes.md +140 -0
- package/skills/service-omni-queue-deploy/scripts/verify-and-align.sh +470 -0
- package/skills/service-omni-queue-members-assign/SKILL.md +93 -0
- package/skills/service-omni-queue-members-assign/references/api-notes.md +144 -0
- package/skills/service-omni-queue-members-assign/scripts/tests/_bootstrap.py +67 -0
- package/skills/service-omni-queue-members-assign/scripts/tests/test_queue_members_contracts.py +73 -0
- package/skills/service-omni-queue-members-assign/scripts/verify-and-bind.sh +362 -0
- package/skills/service-omni-queue-routing-config-deploy/SKILL.md +101 -0
- package/skills/service-omni-queue-routing-config-deploy/references/api-notes.md +127 -0
- package/skills/service-omni-queue-routing-config-deploy/scripts/tests/_bootstrap.py +90 -0
- package/skills/service-omni-queue-routing-config-deploy/scripts/tests/test_queue_routing_config_contracts.py +70 -0
- package/skills/service-omni-queue-routing-config-deploy/scripts/upsert-and-report.sh +538 -0
- package/skills/service-omni-routing-flow-deploy/SKILL.md +111 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.SkillsBased.flow-meta.xml +94 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.flow-meta.xml +88 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Cases.flow-meta.xml +144 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.SkillsBased.flow-meta.xml +94 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.flow-meta.xml +88 -0
- package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCalls.flow-meta.xml +144 -0
- package/skills/service-omni-routing-flow-deploy/assets/package.xml +11 -0
- package/skills/service-omni-routing-flow-deploy/assets/sfdx-project.json +11 -0
- package/skills/service-omni-routing-flow-deploy/references/api-notes.md +265 -0
- package/skills/service-omni-routing-flow-deploy/scripts/deploy-and-report.sh +684 -0
- package/skills/service-omni-service-channel-configure/SKILL.md +83 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Cases.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Incidents.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/MessagingSessions.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/VoiceCalls.serviceChannel-meta.xml +9 -0
- package/skills/service-omni-service-channel-configure/assets/package.xml +11 -0
- package/skills/service-omni-service-channel-configure/assets/sfdx-project.json +12 -0
- package/skills/service-omni-service-channel-configure/references/api-notes.md +84 -0
- package/skills/service-omni-service-channel-configure/scripts/deploy-and-report.sh +383 -0
- package/skills/service-omni-sidebar-configure/SKILL.md +77 -0
- package/skills/service-omni-sidebar-configure/references/api-notes.md +51 -0
- package/skills/service-omni-sidebar-configure/scripts/enable-and-report.sh +315 -0
- package/skills/service-omni-sidebar-configure/scripts/tests/_bootstrap.py +142 -0
- package/skills/service-omni-sidebar-configure/scripts/tests/test_sidebar_contracts.py +139 -0
- package/skills/service-omni-skills-based-routing-configure/SKILL.md +81 -0
- package/skills/service-omni-skills-based-routing-configure/references/api-notes.md +50 -0
- package/skills/service-omni-skills-based-routing-configure/scripts/configure-and-report.sh +270 -0
- package/skills/service-omni-skills-based-routing-configure/scripts/tests/_bootstrap.py +120 -0
- package/skills/service-omni-skills-based-routing-configure/scripts/tests/test_sbr_contracts.py +129 -0
- package/skills/service-omni-supervisor-config-deploy/SKILL.md +97 -0
- package/skills/service-omni-supervisor-config-deploy/assets/force-app/main/default/omniSupervisorConfigs/Omni_Supervisor.omniSupervisorConfig-meta.xml +9 -0
- package/skills/service-omni-supervisor-config-deploy/assets/package.xml +8 -0
- package/skills/service-omni-supervisor-config-deploy/assets/sfdx-project.json +12 -0
- package/skills/service-omni-supervisor-config-deploy/references/api-notes.md +205 -0
- package/skills/service-omni-supervisor-config-deploy/scripts/deploy-and-report.sh +586 -0
- package/skills/service-omni-supervisor-config-deploy/scripts/tests/_bootstrap.py +153 -0
- package/skills/service-omni-supervisor-config-deploy/scripts/tests/test_supervisor_config_contracts.py +116 -0
- package/skills/service-omni-supervisor-permset-assign/SKILL.md +88 -0
- package/skills/service-omni-supervisor-permset-assign/references/api-notes.md +48 -0
- package/skills/service-omni-supervisor-permset-assign/scripts/verify-and-assign.sh +316 -0
- package/skills/service-omni-supervisor-surface-deploy/SKILL.md +85 -0
- package/skills/service-omni-supervisor-surface-deploy/references/api-notes.md +47 -0
- package/skills/service-omni-supervisor-surface-deploy/scripts/deploy-and-report.sh +216 -0
- package/skills/service-omni-supervisor-surface-deploy/scripts/tests/_bootstrap.py +95 -0
- package/skills/service-omni-supervisor-surface-deploy/scripts/tests/test_supervisor_surface_contracts.py +154 -0
- package/skills/service-omni-supervisor-users-create/SKILL.md +92 -0
- package/skills/service-omni-supervisor-users-create/assets/create-supervisors.apex.template +72 -0
- package/skills/service-omni-supervisor-users-create/references/apex-patterns.md +73 -0
- package/skills/service-omni-supervisor-users-create/references/apex-template-notes.md +41 -0
- package/skills/service-omni-supervisor-users-create/scripts/detect-and-create.sh +197 -0
- package/skills/service-omni-supervisor-users-create/scripts/detect-existing.sh +112 -0
- package/skills/service-omni-supervisor-users-create/scripts/run-create.sh +296 -0
- package/skills/service-omni-work-skill-routing-configure/SKILL.md +80 -0
- package/skills/service-omni-work-skill-routing-configure/references/api-notes.md +67 -0
- package/skills/service-omni-work-skill-routing-configure/scripts/configure-and-report.sh +262 -0
- package/skills/service-omni-work-skill-routing-configure/scripts/tests/_bootstrap.py +121 -0
- package/skills/service-omni-work-skill-routing-configure/scripts/tests/test_work_skill_routing_contracts.py +161 -0
package/skills/service-agentforce-human-escalation-configure/references/classifier-contracts.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Escalation classifier contracts
|
|
2
|
+
|
|
3
|
+
Reference material for the deterministic Node classifiers under `scripts/`. Keeping the
|
|
4
|
+
pass/fail logic in these scripts (not in bash or model prose) satisfies authoring standard
|
|
5
|
+
A9 and makes each verdict unit-testable org-free.
|
|
6
|
+
|
|
7
|
+
## `classify-agent-active.mjs`
|
|
8
|
+
|
|
9
|
+
Gates the write: escalation can only be wired onto an agent that exists AND whose latest
|
|
10
|
+
`BotVersion` is `Active`.
|
|
11
|
+
|
|
12
|
+
Input is the file path to the JSON stdout of:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
sf data query -q "SELECT Id,DeveloperName,MasterLabel,
|
|
16
|
+
(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1)
|
|
17
|
+
FROM BotDefinition WHERE DeveloperName='<developerName>'" --target-org <org> --json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Emits: `{ exists, active, agentId, developerName, latestVersionId, latestVersionStatus, ready, reason }`
|
|
21
|
+
— `ready` is true only when `exists && active`. Exit 0 on a parseable body (verdict is in
|
|
22
|
+
the payload); exit 3 on an unparseable/failed query so the workflow surfaces the raw error
|
|
23
|
+
rather than assuming NOT-READY.
|
|
24
|
+
|
|
25
|
+
## `extract-outbound-route.mjs`
|
|
26
|
+
|
|
27
|
+
Couples `outboundRouteName` + `outboundRouteType` from WITHIN the same
|
|
28
|
+
`outboundRouteConfigs` block so a bundle cannot pass by carrying an unrelated name and type
|
|
29
|
+
in different blocks. The compiled `GenAiPlannerBundle` nests the route in a planner surface:
|
|
30
|
+
|
|
31
|
+
```xml
|
|
32
|
+
<plannerSurfaces>
|
|
33
|
+
<surfaceType>Messaging</surfaceType> <!-- or CustomerWebClient for MIAW -->
|
|
34
|
+
<outboundRouteConfigs>
|
|
35
|
+
<escalationMessage>…</escalationMessage>
|
|
36
|
+
<outboundRouteName>Human_Escalation_Outbound_Flow</outboundRouteName>
|
|
37
|
+
<outboundRouteType>OmniChannelFlow</outboundRouteType>
|
|
38
|
+
</outboundRouteConfigs>
|
|
39
|
+
</plannerSurfaces>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Emits `{ name, type, surface, sameBlock, messagingSurface }` for the block matched by the
|
|
43
|
+
expected flow name (or the first block if none matches). `sameBlock=true` means name+type
|
|
44
|
+
came from the same block; `messagingSurface=true` means it sits on a Messaging-class
|
|
45
|
+
surface. Exit 0 on any parseable input (missing file => empty result); exit 2 on bad usage.
|
|
46
|
+
|
|
47
|
+
## `patch-escalation-surfaces.mjs`
|
|
48
|
+
|
|
49
|
+
Schema-aware, loss-less, idempotent in-place patcher for the two doc-driven surfaces. It
|
|
50
|
+
only ever touches the two target elements, never reorders surrounding metadata, and
|
|
51
|
+
refuses (exit 4) rather than guess when no safe insertion point exists.
|
|
52
|
+
|
|
53
|
+
**XSD order (authoritative — `GenAiPlannerBundle.json` wsdl_segment):**
|
|
54
|
+
|
|
55
|
+
- `AiPlannerSurfaceDef` (`<plannerSurfaces>`): `adaptiveResponseAllowed?`,
|
|
56
|
+
`callRecordingAllowed?`, `outboundRouteConfigs*`, `surface`, `surfaceType` — a NEW
|
|
57
|
+
`<outboundRouteConfigs>` MUST be inserted BEFORE `<surface>` (never appended after it).
|
|
58
|
+
- `AiPlannerSurfOtbdRouteDef` (`<outboundRouteConfigs>`): `escalationMessage?`,
|
|
59
|
+
`outboundRouteName`, `outboundRouteType`.
|
|
60
|
+
- `GenAiPlugin` / `GenAiLocalPlugin`: `aiPluginUtterances*`, `canEscalate?`,
|
|
61
|
+
`description?`, `developerName`, … — `<canEscalate>` MUST be inserted AFTER the last
|
|
62
|
+
`<aiPluginUtterances>` and BEFORE `<description>` (or, if absent, before the first
|
|
63
|
+
following required sibling — `developerName`/`masterLabel`/…).
|
|
64
|
+
|
|
65
|
+
Modes:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
node patch-escalation-surfaces.mjs canEscalate <genAiPlugin-xml-file>
|
|
69
|
+
node patch-escalation-surfaces.mjs outboundRoute <genAiPlannerBundle-xml-file> <flowApiName> [escalationMessage]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Patched IN PLACE. Exit 0 on success (prints a short JSON summary), 2 on bad usage, 4 when
|
|
73
|
+
no safe patch point is found (nothing written).
|
|
74
|
+
|
|
75
|
+
## `verify-escalation-config.mjs`
|
|
76
|
+
|
|
77
|
+
Renders the single deterministic verdict from an evidence object assembled by
|
|
78
|
+
`verify-and-configure.sh` (retrieved XML greps + SOQL reads).
|
|
79
|
+
|
|
80
|
+
`evidence.json` shape (all keys optional; missing => treated as not-satisfied):
|
|
81
|
+
|
|
82
|
+
| key | meaning |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `canEscalate` | escalation topic flag set |
|
|
85
|
+
| `outboundRouteName` | route name on the bundle |
|
|
86
|
+
| `outboundRouteType` | must equal `OmniChannelFlow` |
|
|
87
|
+
| `outboundRouteSameBlock` | name+type from the SAME config block |
|
|
88
|
+
| `outboundRouteMessagingSurface` | block sits on a Messaging planner surface |
|
|
89
|
+
| `expectedFlowName` | expected outbound flow name |
|
|
90
|
+
| `flowActiveVersionId` | non-empty => flow active |
|
|
91
|
+
| `queueId` | non-empty => queue exists |
|
|
92
|
+
| `queueSobjectPresent` | context object bound to the queue |
|
|
93
|
+
| `queueHasActiveDirectUserMember` | ≥1 active DIRECT User member (necessary, not sufficient — Omni perm + presence access are proven only at runtime) |
|
|
94
|
+
| `queueRoutingConfigPresent` | QRC exists |
|
|
95
|
+
| `queueRoutingConfigBound` | `Group.QueueRoutingConfigId` points at the QRC |
|
|
96
|
+
| `agentActive` | latest BotVersion active |
|
|
97
|
+
| `thresholdAuthored` | directive policy authored (not a counter) |
|
|
98
|
+
| `defaultFailureThreshold` | numeric consecutive-failure threshold rendered into the directive (evidence only, never a gate) |
|
|
99
|
+
|
|
100
|
+
Emits `{ verdict, deterministicPass, directivePass, checks[], missing[] }` where `verdict`
|
|
101
|
+
is `CONFIGURED` | `INCOMPLETE`. The deterministic surfaces gate `CONFIGURED`; the threshold
|
|
102
|
+
directive is reported separately (never blocks the headless verdict — it is eval-verified,
|
|
103
|
+
not metadata-verified). Exit 0 on a parseable body; exit 3 on unparseable input.
|
package/skills/service-agentforce-human-escalation-configure/references/escalation-mechanism.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Escalation mechanism reference
|
|
2
|
+
|
|
3
|
+
Agent → human escalation in Agentforce is assembled from three declarative surfaces plus
|
|
4
|
+
one instruction surface. Only the first three are deterministically writable and verifiable
|
|
5
|
+
via the Metadata/Data API; the fourth (threshold policy) is directive text verified by
|
|
6
|
+
eval, and the actual conversational trigger is manual/runtime.
|
|
7
|
+
|
|
8
|
+
## 1. `canEscalate` on the escalation topic (`GenAiPlugin`)
|
|
9
|
+
|
|
10
|
+
The agent topic that represents "hand off to a human" must have `<canEscalate>true</canEscalate>`.
|
|
11
|
+
Retrieve the topic, set the flag, redeploy.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
sf project retrieve start --target-org "$ORG" \
|
|
15
|
+
--metadata "GenAiPlugin:${ESCALATION_TOPIC_API_NAME}" --target-metadata-dir /tmp/esc
|
|
16
|
+
# edit <canEscalate>true</canEscalate> in the retrieved -meta.xml
|
|
17
|
+
sf project deploy start --target-org "$ORG" --metadata "GenAiPlugin:${ESCALATION_TOPIC_API_NAME}"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Verify (the retrieved XML must contain `<canEscalate>true</canEscalate>`). There is no
|
|
21
|
+
SOQL object for `canEscalate`; the source of truth is the retrieved metadata.
|
|
22
|
+
|
|
23
|
+
## 2. `outboundRouteConfigs` on the agent's Messaging planner surface (`GenAiPlannerBundle`)
|
|
24
|
+
|
|
25
|
+
The `GenAiPlannerBundle` for the agent carries the Messaging surface. Its
|
|
26
|
+
`outboundRouteConfigs` block wires the escalation to an Omni-Channel outbound flow:
|
|
27
|
+
|
|
28
|
+
```xml
|
|
29
|
+
<outboundRouteConfigs>
|
|
30
|
+
<escalationMessage>Transferring you to a live support agent.</escalationMessage>
|
|
31
|
+
<outboundRouteName>Human_Escalation_Outbound_Flow</outboundRouteName>
|
|
32
|
+
<outboundRouteType>OmniChannelFlow</outboundRouteType>
|
|
33
|
+
</outboundRouteConfigs>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Retrieve the bundle, add/update the block on the Messaging surface, redeploy. `outboundRouteName`
|
|
37
|
+
must equal the active outbound `RoutingFlow` API name (see #3).
|
|
38
|
+
|
|
39
|
+
## 3. Outbound QueueBased `RoutingFlow`
|
|
40
|
+
|
|
41
|
+
The bundled asset `assets/force-app/main/default/flows/Human_Escalation_Outbound_Flow.flow-meta.xml`
|
|
42
|
+
is a QueueBased outbound flow template that routes the escalated conversation to the human
|
|
43
|
+
queue. It looks the queue up by `DeveloperName` at runtime (no hardcoded Id), so it is
|
|
44
|
+
portable across orgs. Tokens `__FLOW_DEVELOPER_NAME__`, `__FLOW_LABEL__`,
|
|
45
|
+
`__QUEUE_DEVELOPER_NAME__`, `__SERVICE_CHANNEL_DEV_NAME__`, `__SERVICE_CHANNEL_LABEL__`
|
|
46
|
+
are substituted before deploy.
|
|
47
|
+
|
|
48
|
+
After deploy, `FlowDefinitionView.ActiveVersionId` for the flow must be non-null.
|
|
49
|
+
|
|
50
|
+
## 4. Human queue
|
|
51
|
+
|
|
52
|
+
The escalation target is a queue whose `QueueSobject` includes the routed context object
|
|
53
|
+
(`MessagingSession` by default, for Enhanced Chat / MIAW), plus a `QueueRoutingConfig`. See
|
|
54
|
+
[queue-resolution.md](../../service-agentforce-channel-configure/references/queue-resolution.md)
|
|
55
|
+
for the create-or-adopt recipe. Provision any broader routing infrastructure through an
|
|
56
|
+
approved Omni setup workflow before running this skill.
|
|
57
|
+
|
|
58
|
+
## Handoff to `service-agentforce-channel-configure`
|
|
59
|
+
|
|
60
|
+
Inbound transport (`sessionHandlerAsa` on the MessagingChannel, Branch A) and the outbound
|
|
61
|
+
`connection customer_web_client:` connection block on the agent are owned by
|
|
62
|
+
`service-agentforce-channel-configure`. This skill focuses on the escalation-specific
|
|
63
|
+
surfaces (#1, #2, #3, #4) and the threshold policy, delegating transport wiring to that skill.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Failure-threshold policy (native, directive-based)
|
|
2
|
+
|
|
3
|
+
## Why this is not a metadata counter
|
|
4
|
+
|
|
5
|
+
Agentforce does not expose a metadata field or setting that counts "consecutive failed
|
|
6
|
+
turns" and escalates automatically. The "escalate after two failures" behaviour is a
|
|
7
|
+
**planner policy expressed as instruction text** in the agent's Agent Script (NGA
|
|
8
|
+
authoring model). This is the platform-native representation the user selected.
|
|
9
|
+
|
|
10
|
+
Consequences:
|
|
11
|
+
|
|
12
|
+
- The threshold is **authored, not enforced by a counter**. The bundled template
|
|
13
|
+
[`assets/escalation-thresholds.instructions.md`](../assets/escalation-thresholds.instructions.md)
|
|
14
|
+
is the source directive text.
|
|
15
|
+
- It is **verified by an ADK eval rubric** (does the agent escalate on the 2nd failure? on
|
|
16
|
+
the 1st failure for password reset?) and a **documented manual conversation test** — never
|
|
17
|
+
by a deterministic metadata round-trip.
|
|
18
|
+
- The `verify-and-configure.sh` verdict therefore reports the threshold as `directive`
|
|
19
|
+
(authored / not-authored), distinct from the `deterministic` config surfaces
|
|
20
|
+
(`canEscalate`, `outboundRouteConfigs` name+type coupling on the Messaging surface, outbound
|
|
21
|
+
flow Active, queue + QueueSobject + bound QueueRoutingConfig, ≥1 active human member, agent Active).
|
|
22
|
+
|
|
23
|
+
## Recommended thresholds
|
|
24
|
+
|
|
25
|
+
The threshold is a **caller input**, not a fixed constant. The values below are defaults;
|
|
26
|
+
a scenario that mandates a different number (e.g. a narrative requiring escalation after
|
|
27
|
+
**three** consecutive failures) supplies its own value via the skill input — no code change
|
|
28
|
+
is needed.
|
|
29
|
+
|
|
30
|
+
| Scenario | Threshold | Rationale |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| Default (any unresolved request) | 2 consecutive failures | Give the agent one retry before handing off |
|
|
33
|
+
| Password reset / credential issues | 1 failure | Time-sensitive; do not retry repeatedly |
|
|
34
|
+
| Caller-specified | any N | Whatever the scenario's authoritative requirement is (pass N as the input) |
|
|
35
|
+
|
|
36
|
+
## Authoring steps
|
|
37
|
+
|
|
38
|
+
1. Substitute tokens in the template (`__DEFAULT_FAILURES__=2`, `__RESET_TOPIC_LABEL__`,
|
|
39
|
+
`__ESCALATION_MESSAGE__`).
|
|
40
|
+
2. Add the default directive to the agent's global/system instructions.
|
|
41
|
+
3. Add the per-topic override to the password-reset topic instructions.
|
|
42
|
+
4. Republish + reactivate the agent (`sf agent validate|publish|activate ... --target-org $ORG`).
|
|
43
|
+
5. Confirm via the eval rubric and the manual test in
|
|
44
|
+
[runtime-verification.md](./runtime-verification.md).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Next-gen (NGA) escalation — detection, surface split, and verdict
|
|
2
|
+
|
|
3
|
+
The classic escalation surface (`GenAiPlannerBundle.outboundRouteConfigs` + `GenAiPlugin.canEscalate`) does not exist on next-gen authoring (NGA) orgs. NGA agents are defined by `AiAuthoringBundle` (Agent Script), and the escalation surface moves into the bundle. This skill supports both models from one code path; only the agent-side surface differs.
|
|
4
|
+
|
|
5
|
+
## Detection (Phase 1b)
|
|
6
|
+
|
|
7
|
+
`sf org list metadata-types` identifies the model surfaces available in the org. When both surfaces exist, the skill retrieves the requested agent from each surface and classifies that specific target rather than applying an org-wide default:
|
|
8
|
+
|
|
9
|
+
| Metadata types exposed | `authoring_model` | Agent surface authored/verified |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Requested agent is found only in `GenAiPlannerBundle` | `classic` | `canEscalate` + `outboundRouteConfigs` |
|
|
12
|
+
| Requested agent is found only in `AiAuthoringBundle` | `nga` | `@utils.escalate` (Service) / create-record (Employee) |
|
|
13
|
+
| Requested agent is found in both surfaces | `ambiguous` | — (skill blocks before any write) |
|
|
14
|
+
| Requested agent is found in neither surface while both models exist | `none` | — (skill blocks before any write) |
|
|
15
|
+
|
|
16
|
+
`AUTHORING_MODEL_OVERRIDE=classic|nga` explicitly pins the branch when the target is genuinely ambiguous or metadata retrieval is inconclusive. There is no classic-first default: an NGA target in a mixed-model org stays NGA.
|
|
17
|
+
|
|
18
|
+
## Why classic ≠ NGA (not a straight port)
|
|
19
|
+
|
|
20
|
+
The classic skill's value was deterministically authoring + verifying a failure-threshold outbound route on one metadata surface. NGA splits that into pieces of different natures:
|
|
21
|
+
|
|
22
|
+
| Classic single surface | NGA equivalent | Deterministic? |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `outboundRouteConfigs` → named queue | channel → queue Omni routing (the routing half this skill builds) | yes |
|
|
25
|
+
| failure-threshold trigger | Agent Script instruction / `@utils.escalate` action | no — prompt-led (a directive) |
|
|
26
|
+
| (n/a for employee agents) | Employee agent → create Incident/Case action → Omni-route that record | yes |
|
|
27
|
+
|
|
28
|
+
There is no numeric "escalate after N failures" field in Agent Script; the threshold stays a directive (the same boundary the classic path already uses).
|
|
29
|
+
|
|
30
|
+
## Service vs Employee split
|
|
31
|
+
|
|
32
|
+
- **Service agent** — declares `connection messaging:` and can call `@utils.escalate` for a live hand-off routed through the messaging connection to the queue.
|
|
33
|
+
- **Employee agent** — cannot declare `connection messaging:` or use `@utils.escalate`. Its escalation surrogate is an action that creates a routable record (Case/Incident/ticket) which then Omni-routes to the human queue.
|
|
34
|
+
|
|
35
|
+
`scripts/classify-nga-escalation.mjs` walks the retrieved `AiAuthoringBundle` (in-process, so it never invokes `find` — the sandbox blocks `find -exec`'s `ARG_MAX` probe) and returns:
|
|
36
|
+
|
|
37
|
+
To avoid a false `CONFIGURED`, it scans **only Agent Script** (`*.agent` files, or any file whose content declares `start_agent`), **strips comments** (`/* */`, whole-line `//`/`#`), and proves reachability **per agent block**: the escalation surface must live in the same `start_agent` block as its trigger, under a `reasoning: actions:` section (a line more indented than the `actions:` header). A commented-out block, prose mention, cross-block match, or unrelated file no longer satisfies the surface — when reachability cannot be proven it reports `escalationSurfacePresent:false` (→ caller stays `INCOMPLETE`). An unreadable/missing retrieve dir exits `3` (inconclusive), never an empty exit `0`.
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
{ agentType, bundleFound, connectionMessaging, escalateActionPresent, createRecordActionPresent, escalationSurfacePresent }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- `agentType`: `service` if `connection messaging:` present, else `employee` (or `unknown` when no bundle was retrieved).
|
|
44
|
+
- `escalationSurfacePresent`: `escalateActionPresent` for Service, `createRecordActionPresent` for Employee. `createRecordActionPresent` is a heuristic (action refs matching create + case/incident/ticket/record) — treat a false negative as "author via agentforce-generate", never as a hard failure of the agent.
|
|
45
|
+
|
|
46
|
+
## NGA verdict set
|
|
47
|
+
|
|
48
|
+
`verify-escalation-config.mjs` keeps the model-agnostic routing checks (`outboundFlowActive`, `humanQueue`, `queueSobject`, `queueHasActiveDirectUserMember`, `queueRoutingConfig`, `queueRoutingConfigBound`, `agentActive`) and swaps the surface checks:
|
|
49
|
+
|
|
50
|
+
- classic → `canEscalate` + `outboundRouteConfigs`
|
|
51
|
+
- nga → `ngaEscalationSurface` (from `escalationSurfacePresent`)
|
|
52
|
+
|
|
53
|
+
`thresholdDirective` remains a directive check in both. `CONFIGURED` requires all deterministic checks; the threshold is reported separately.
|
|
54
|
+
|
|
55
|
+
## Authoring delegation
|
|
56
|
+
|
|
57
|
+
This skill **verifies** the NGA surface; it does not mutate Agent Script. When `ngaEscalationSurface` is missing the verdict is `INCOMPLETE` and `next_steps` points to `agentforce-generate` to author the surface: for a Service agent add a reachable `{!@utils.escalate}` action (needs `connection messaging:`); for an Employee agent add a create-record (Case/Incident) action that Omni-routes to the queue. Re-run afterward to reach `CONFIGURED`.
|
package/skills/service-agentforce-human-escalation-configure/references/runtime-verification.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Runtime & manual verification checklist
|
|
2
|
+
|
|
3
|
+
The deterministic config surfaces are verified headlessly by `verify-and-configure.sh`
|
|
4
|
+
(see the JSON verdict). The conversational behaviour and context preservation **cannot be
|
|
5
|
+
driven headlessly** and must be confirmed with a live conversation (per the EC V2 reference).
|
|
6
|
+
|
|
7
|
+
## A. Deterministic config verdict (headless — done by the skill)
|
|
8
|
+
|
|
9
|
+
`verify-and-configure.sh` round-trips and asserts:
|
|
10
|
+
|
|
11
|
+
- `canEscalate=true` on the escalation topic (`GenAiPlugin`).
|
|
12
|
+
- `outboundRouteConfigs` on the `GenAiPlannerBundle` Messaging planner surface couples
|
|
13
|
+
`outboundRouteName` (= the outbound flow API name) to `outboundRouteType=OmniChannelFlow`
|
|
14
|
+
in the SAME block on a Messaging-class surface.
|
|
15
|
+
- Outbound `RoutingFlow` `ActiveVersionId` is non-null (`FlowDefinitionView`).
|
|
16
|
+
- The human queue exists with a `QueueSobject` for the context object (`MessagingSession`
|
|
17
|
+
by default), a `QueueRoutingConfig` bound to the queue (`Group.QueueRoutingConfigId`), and
|
|
18
|
+
**at least one active human member** (`GroupMember` resolving to an active `User`).
|
|
19
|
+
- The agent's latest `BotVersion` is `Active` after republish.
|
|
20
|
+
|
|
21
|
+
## B. Threshold policy (eval rubric — not a counter)
|
|
22
|
+
|
|
23
|
+
- ADK eval `TwoFailureThreshold`: on the 2nd consecutive failed attempt the agent escalates.
|
|
24
|
+
- ADK eval `PasswordResetOverride`: on the 1st failed password-reset attempt the agent escalates.
|
|
25
|
+
|
|
26
|
+
## C. Manual conversation test (runtime only)
|
|
27
|
+
|
|
28
|
+
1. Open the Enhanced Chat / MIAW deployment as an end user.
|
|
29
|
+
2. Ask the agent something it can resolve — confirm no premature escalation.
|
|
30
|
+
3. Trigger two consecutive failed attempts on the same request — confirm the agent emits
|
|
31
|
+
the escalation message and hands off.
|
|
32
|
+
4. Confirm an `AgentWork` record is created against the human queue:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
sf data query --target-org "$ORG" --json \
|
|
36
|
+
--query "SELECT Id, Status, ServiceChannel, WorkItemId FROM AgentWork ORDER BY CreatedDate DESC LIMIT 5"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
5. Confirm **context preservation**: the human agent receives the same `MessagingSession`
|
|
40
|
+
with the full prior transcript (same `MessagingSession.Id`, not a new session).
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
sf data query --target-org "$ORG" --json \
|
|
44
|
+
--query "SELECT Id, Status, Origin FROM MessagingSession ORDER BY LastModifiedDate DESC LIMIT 5"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Context preservation and `AgentWork` creation are runtime facts — record the result in the
|
|
48
|
+
run notes; they are not part of the headless verdict.
|
|
49
|
+
|
|
50
|
+
## D. Real-org proof record — 2026-08-17 (`sdb38` trial CDO)
|
|
51
|
+
|
|
52
|
+
Read-only §7 verification run against a non-production org (`IsSandbox=false`,
|
|
53
|
+
`TrialExpirationDate` non-null ⇒ `safe_to_write=true`). IDs abbreviated.
|
|
54
|
+
|
|
55
|
+
| Check | Result |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| Org safety | PASS — Enterprise trial CDO, non-production |
|
|
58
|
+
| Human queue + QRC bind | PASS — `General_IT_Queue`, `QueueRoutingConfigId=0K9…00BA` |
|
|
59
|
+
| `QueueSobject` context object | PASS — `MessagingSession` |
|
|
60
|
+
| Active human members | PASS — 2 active users |
|
|
61
|
+
| Outbound `RoutingFlow` active | PASS — `ActiveVersionId=301…pYBB` |
|
|
62
|
+
| Active MessagingChannels | PASS — 4 active |
|
|
63
|
+
| Queue-based routing runtime | PASS — `PendingServiceRouting` rows `IsReadyForRouting=true`, `RoutingType=QueueBased`; `AgentWork` rows `Closed`/`Declined` on `sfdc_livemessage`; `MessagingSession` rows `Ended`/`Waiting` |
|
|
64
|
+
|
|
65
|
+
**Not proven headlessly (manual step required):**
|
|
66
|
+
|
|
67
|
+
- Agent-authoring side (`canEscalate` + `outboundRouteConfigs` on a live Agentforce planner
|
|
68
|
+
bundle) — the default agent developer name was absent on this org; running the authoring
|
|
69
|
+
path requires an explicit `AGENT_DEVELOPER_NAME` (e.g. an Active `ExternalCopilot` agent).
|
|
70
|
+
- Phase 4 conversational escalation — must be driven through a live Enhanced Messaging
|
|
71
|
+
conversation (section C). Queue-based routing→agent-accept is already demonstrated above,
|
|
72
|
+
but the agent→human handoff trigger itself is a manual runtime confirmation.
|
package/skills/service-agentforce-human-escalation-configure/scripts/classify-agent-active.mjs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Precondition classifier: BotDefinition+latest BotVersion query JSON → { exists, active, ready, ... }; ready only when exists && active; exit 3 on unparseable. Query/output shape: references/classifier-contracts.md.
|
|
3
|
+
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const [queryPath, developerName] = process.argv.slice(2);
|
|
7
|
+
if (!queryPath || !developerName) {
|
|
8
|
+
process.stderr.write('usage: node classify-agent-active.mjs <bot-query.json> <developerName>\n');
|
|
9
|
+
process.exit(2);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let data;
|
|
13
|
+
try {
|
|
14
|
+
const text = readFileSync(queryPath, 'utf8').trim();
|
|
15
|
+
data = text ? JSON.parse(text) : null;
|
|
16
|
+
} catch {
|
|
17
|
+
process.stderr.write(`error: could not read/parse ${queryPath}\n`);
|
|
18
|
+
process.exit(3);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!data || (typeof data.status === 'number' && data.status !== 0) || data.result === undefined) {
|
|
22
|
+
process.stderr.write('error: query did not return a results envelope; surface the raw CLI error and stop\n');
|
|
23
|
+
process.exit(3);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const records = Array.isArray(data.result?.records) ? data.result.records : [];
|
|
27
|
+
const wantedLower = String(developerName).toLowerCase();
|
|
28
|
+
const matches = records.filter((r) => String(r?.DeveloperName ?? '').toLowerCase() === wantedLower);
|
|
29
|
+
const exists = matches.length > 0;
|
|
30
|
+
|
|
31
|
+
const latestVersion = exists ? matches[0]?.BotVersions?.records?.[0] ?? null : null;
|
|
32
|
+
const latestVersionStatus = latestVersion?.Status ?? null;
|
|
33
|
+
const active = exists && latestVersionStatus === 'Active';
|
|
34
|
+
|
|
35
|
+
let reason;
|
|
36
|
+
if (!exists) reason = 'agent-not-found';
|
|
37
|
+
else if (!active) reason = 'agent-inactive';
|
|
38
|
+
else reason = 'ready';
|
|
39
|
+
|
|
40
|
+
process.stdout.write(JSON.stringify({
|
|
41
|
+
exists,
|
|
42
|
+
active,
|
|
43
|
+
agentId: exists ? (matches[0].Id ?? null) : null,
|
|
44
|
+
developerName,
|
|
45
|
+
latestVersionId: latestVersion?.Id ?? null,
|
|
46
|
+
latestVersionStatus,
|
|
47
|
+
ready: exists && active,
|
|
48
|
+
reason,
|
|
49
|
+
}, null, 2) + '\n');
|
package/skills/service-agentforce-human-escalation-configure/scripts/classify-nga-escalation.mjs
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Classify the escalation surface of a retrieved next-gen (AiAuthoringBundle) agent -> { agentType, connectionMessaging, escalateActionPresent, createRecordActionPresent, escalationSurfacePresent, bundleFound }. Detection rules + Service-vs-Employee rationale: references/nga-escalation.md. Exit 3 on an unreadable dir.
|
|
3
|
+
//
|
|
4
|
+
// Hardening (avoids false CONFIGURED): only actual Agent Script (.agent files, or any file whose
|
|
5
|
+
// content declares `start_agent`) is scanned; comments are stripped; and the escalation surface must
|
|
6
|
+
// live in the SAME agent block as its trigger, under a `reasoning: actions:` section - a comment,
|
|
7
|
+
// example, or unrelated file can no longer satisfy the match. When reachability cannot be proven the
|
|
8
|
+
// surface is reported absent (escalationSurfacePresent:false) so the caller stays INCOMPLETE.
|
|
9
|
+
|
|
10
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
|
|
13
|
+
const [retrieveDir] = process.argv.slice(2);
|
|
14
|
+
if (!retrieveDir) {
|
|
15
|
+
process.stderr.write('usage: node classify-nga-escalation.mjs <retrieve-dir>\n');
|
|
16
|
+
process.exit(2);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// The TOP dir must be readable — an unreadable/missing retrieve dir is inconclusive, not "no surface"
|
|
20
|
+
// (file contract: exit 3). Nested unreadable files are skipped below (a single bad file is not fatal).
|
|
21
|
+
try {
|
|
22
|
+
if (!statSync(retrieveDir).isDirectory()) throw new Error('not a directory');
|
|
23
|
+
readdirSync(retrieveDir);
|
|
24
|
+
} catch {
|
|
25
|
+
process.stderr.write(`error: could not read ${retrieveDir}\n`);
|
|
26
|
+
process.exit(3);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Strip comments so a commented-out / example escalation block cannot satisfy the regex: remove
|
|
30
|
+
// /* ... */ blocks, then drop whole-line // and # comments (leaves inline // inside strings alone).
|
|
31
|
+
function stripComments(text) {
|
|
32
|
+
const noBlock = text.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
33
|
+
return noBlock
|
|
34
|
+
.split('\n')
|
|
35
|
+
.map((line) => {
|
|
36
|
+
const t = line.trimStart();
|
|
37
|
+
return t.startsWith('//') || t.startsWith('#') ? '' : line;
|
|
38
|
+
})
|
|
39
|
+
.join('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Walk the retrieve dir in-process (no `find`; the sandbox blocks find -exec's ARG_MAX probe) and
|
|
43
|
+
// collect ONLY Agent Script: files named *.agent, or any file whose content declares `start_agent`
|
|
44
|
+
// (covers a differently-named script). bundleFound also counts *.bundle-meta.xml so a bundle with no
|
|
45
|
+
// readable script still reports bundleFound:true (→ agentType resolvable, surface simply absent).
|
|
46
|
+
function collect(dir, acc) {
|
|
47
|
+
let entries;
|
|
48
|
+
try {
|
|
49
|
+
entries = readdirSync(dir);
|
|
50
|
+
} catch {
|
|
51
|
+
return acc;
|
|
52
|
+
}
|
|
53
|
+
for (const name of entries) {
|
|
54
|
+
const full = join(dir, name);
|
|
55
|
+
let st;
|
|
56
|
+
try {
|
|
57
|
+
st = statSync(full);
|
|
58
|
+
} catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (st.isDirectory()) {
|
|
62
|
+
collect(full, acc);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (!st.isFile()) continue;
|
|
66
|
+
const isAgentExt = /\.agent$/i.test(name);
|
|
67
|
+
if (isAgentExt || /\.bundle-meta\.xml$/i.test(name)) acc.bundleFound = true;
|
|
68
|
+
let raw;
|
|
69
|
+
try {
|
|
70
|
+
raw = readFileSync(full, 'utf8');
|
|
71
|
+
} catch {
|
|
72
|
+
continue; // skip unreadable/binary file
|
|
73
|
+
}
|
|
74
|
+
if (isAgentExt || /^[ \t]*start_agent\b/im.test(raw)) {
|
|
75
|
+
acc.scripts.push(stripComments(raw));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return acc;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const scanned = collect(retrieveDir, { scripts: [], bundleFound: false });
|
|
82
|
+
|
|
83
|
+
// Split concatenated Agent Script into per-agent blocks. Each `start_agent <name>:` opens a block that
|
|
84
|
+
// runs until the next start_agent (or EOF). Reachability is proven per block, not across the file.
|
|
85
|
+
function splitAgentBlocks(scriptText) {
|
|
86
|
+
const blocks = [];
|
|
87
|
+
let cur = null;
|
|
88
|
+
for (const line of scriptText.split('\n')) {
|
|
89
|
+
if (/^\s*start_agent\b/i.test(line)) {
|
|
90
|
+
if (cur) blocks.push(cur);
|
|
91
|
+
cur = [line];
|
|
92
|
+
} else if (cur) {
|
|
93
|
+
cur.push(line);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (cur) blocks.push(cur);
|
|
97
|
+
return blocks;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// True when `re` matches an action line inside a `reasoning: actions:` section of the block — i.e. the
|
|
101
|
+
// match is more indented than the `actions:` header it lives under (a real action, not prose/an example).
|
|
102
|
+
function actionMatches(blockLines, re) {
|
|
103
|
+
let actionsIndent = -1;
|
|
104
|
+
for (const line of blockLines) {
|
|
105
|
+
if (line.trim() === '') continue;
|
|
106
|
+
const indent = line.length - line.trimStart().length;
|
|
107
|
+
if (actionsIndent >= 0) {
|
|
108
|
+
if (indent > actionsIndent) {
|
|
109
|
+
if (re.test(line)) return true;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
actionsIndent = -1; // dedented out of the actions section; re-check this line as a new header
|
|
113
|
+
}
|
|
114
|
+
if (/^actions\s*:/.test(line.trim())) actionsIndent = indent;
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const CREATE_RECORD_RE =
|
|
120
|
+
/@actions\.[A-Za-z0-9_]*create[A-Za-z0-9_]*(case|incident|ticket|record)|create[_-]?(case|incident|ticket)\b/i;
|
|
121
|
+
const ESCALATE_RE = /@utils\.escalate\b/i;
|
|
122
|
+
const MESSAGING_RE = /^\s*connection\s+messaging\s*:/im;
|
|
123
|
+
|
|
124
|
+
let connectionMessaging = false;
|
|
125
|
+
let escalateActionPresent = false;
|
|
126
|
+
let createRecordActionPresent = false;
|
|
127
|
+
let serviceSurface = false; // messaging + reachable @utils.escalate in the SAME block
|
|
128
|
+
let employeeSurface = false; // no messaging + reachable create-record action in the block
|
|
129
|
+
|
|
130
|
+
for (const script of scanned.scripts) {
|
|
131
|
+
for (const block of splitAgentBlocks(script)) {
|
|
132
|
+
const text = block.join('\n');
|
|
133
|
+
const hasMessaging = MESSAGING_RE.test(text);
|
|
134
|
+
const hasEscalate = actionMatches(block, ESCALATE_RE);
|
|
135
|
+
const hasCreateRecord = actionMatches(block, CREATE_RECORD_RE);
|
|
136
|
+
connectionMessaging = connectionMessaging || hasMessaging;
|
|
137
|
+
escalateActionPresent = escalateActionPresent || hasEscalate;
|
|
138
|
+
createRecordActionPresent = createRecordActionPresent || hasCreateRecord;
|
|
139
|
+
if (hasMessaging && hasEscalate) serviceSurface = true;
|
|
140
|
+
if (!hasMessaging && hasCreateRecord) employeeSurface = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Service agents escalate via @utils.escalate; Employee agents lack messaging and must create a
|
|
145
|
+
// routable record instead. Without a retrieved bundle the type is unknown.
|
|
146
|
+
let agentType = 'unknown';
|
|
147
|
+
if (scanned.bundleFound) agentType = connectionMessaging ? 'service' : 'employee';
|
|
148
|
+
|
|
149
|
+
let escalationSurfacePresent = false;
|
|
150
|
+
if (agentType === 'service') escalationSurfacePresent = serviceSurface;
|
|
151
|
+
else if (agentType === 'employee') escalationSurfacePresent = employeeSurface;
|
|
152
|
+
|
|
153
|
+
process.stdout.write(
|
|
154
|
+
JSON.stringify(
|
|
155
|
+
{
|
|
156
|
+
agentType,
|
|
157
|
+
bundleFound: scanned.bundleFound,
|
|
158
|
+
connectionMessaging,
|
|
159
|
+
escalateActionPresent,
|
|
160
|
+
createRecordActionPresent,
|
|
161
|
+
escalationSurfacePresent,
|
|
162
|
+
},
|
|
163
|
+
null,
|
|
164
|
+
2,
|
|
165
|
+
) + '\n',
|
|
166
|
+
);
|
package/skills/service-agentforce-human-escalation-configure/scripts/extract-outbound-route.mjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Extracts outbound-route wiring from a retrieved GenAiPlannerBundle, coupling routeName+routeType within one outboundRouteConfigs block → { name, type, surface, sameBlock, messagingSurface }; exit 2 on bad usage. Details: references/classifier-contracts.md.
|
|
3
|
+
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const [xmlPath, expectedFlow = ''] = process.argv.slice(2);
|
|
7
|
+
if (!xmlPath) {
|
|
8
|
+
process.stderr.write('usage: node extract-outbound-route.mjs <bundle-xml-file> <expected-flow-name>\n');
|
|
9
|
+
process.exit(2);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const empty = { name: '', type: '', surface: '', sameBlock: false, messagingSurface: false };
|
|
13
|
+
|
|
14
|
+
let xml = '';
|
|
15
|
+
try {
|
|
16
|
+
xml = readFileSync(xmlPath, 'utf8');
|
|
17
|
+
} catch {
|
|
18
|
+
process.stdout.write(JSON.stringify(empty) + '\n');
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const MESSAGING_SURFACES = new Set(['Messaging', 'CustomerWebClient']);
|
|
23
|
+
const tag = (block, name) => {
|
|
24
|
+
const m = block.match(new RegExp(`<${name}>\\s*([^<]*?)\\s*</${name}>`, 's'));
|
|
25
|
+
return m ? m[1].trim() : '';
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Collect candidate blocks: prefer plannerSurfaces entries (so we know the surfaceType), and
|
|
29
|
+
// fall back to bare outboundRouteConfigs blocks if the bundle is flat/uncompiled.
|
|
30
|
+
const candidates = [];
|
|
31
|
+
for (const sm of xml.matchAll(/<plannerSurfaces>([\s\S]*?)<\/plannerSurfaces>/g)) {
|
|
32
|
+
const surfaceBlock = sm[1];
|
|
33
|
+
const surface = tag(surfaceBlock, 'surfaceType');
|
|
34
|
+
for (const cm of surfaceBlock.matchAll(/<outboundRouteConfigs>([\s\S]*?)<\/outboundRouteConfigs>/g)) {
|
|
35
|
+
candidates.push({ surface, block: cm[1] });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (candidates.length === 0) {
|
|
39
|
+
for (const cm of xml.matchAll(/<outboundRouteConfigs>([\s\S]*?)<\/outboundRouteConfigs>/g)) {
|
|
40
|
+
candidates.push({ surface: '', block: cm[1] });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const describe = (c) => {
|
|
45
|
+
const name = tag(c.block, 'outboundRouteName');
|
|
46
|
+
const type = tag(c.block, 'outboundRouteType');
|
|
47
|
+
return {
|
|
48
|
+
name,
|
|
49
|
+
type,
|
|
50
|
+
surface: c.surface,
|
|
51
|
+
sameBlock: name !== '' && type !== '',
|
|
52
|
+
messagingSurface: MESSAGING_SURFACES.has(c.surface),
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
let chosen = null;
|
|
57
|
+
if (expectedFlow) {
|
|
58
|
+
chosen = candidates.map(describe).find((d) => d.name === expectedFlow) || null;
|
|
59
|
+
}
|
|
60
|
+
if (!chosen) {
|
|
61
|
+
chosen = candidates.length ? describe(candidates[0]) : null;
|
|
62
|
+
}
|
|
63
|
+
if (!chosen) {
|
|
64
|
+
chosen = empty;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
process.stdout.write(JSON.stringify(chosen) + '\n');
|