@salesforce/afv-skills 1.14.0 → 1.16.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/activating-datacloud/SKILL.md +0 -1
- package/skills/analyzing-omnistudio-dependencies/SKILL.md +0 -1
- package/skills/applying-slds/SKILL.md +322 -0
- package/skills/applying-slds/checklists.md +83 -0
- package/skills/applying-slds/examples.md +283 -0
- package/skills/applying-slds/guidance/README.md +83 -0
- package/skills/applying-slds/guidance/blueprints-index.md +213 -0
- package/skills/applying-slds/guidance/icons-guidance.md +186 -0
- package/skills/applying-slds/guidance/overviews/borders.md +236 -0
- package/skills/applying-slds/guidance/overviews/color.md +266 -0
- package/skills/applying-slds/guidance/overviews/display-density.md +366 -0
- package/skills/applying-slds/guidance/overviews/icons.md +240 -0
- package/skills/applying-slds/guidance/overviews/illustrations.md +235 -0
- package/skills/applying-slds/guidance/overviews/shadows.md +176 -0
- package/skills/applying-slds/guidance/overviews/spacing.md +216 -0
- package/skills/applying-slds/guidance/overviews/typography.md +323 -0
- package/skills/applying-slds/guidance/overviews/utilities.md +542 -0
- package/skills/applying-slds/guidance/slds-development-guide.md +288 -0
- package/skills/applying-slds/guidance/styling-hooks/borders.md +202 -0
- package/skills/applying-slds/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
- package/skills/applying-slds/guidance/styling-hooks/color/index.md +171 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
- package/skills/applying-slds/guidance/styling-hooks/color/system-hooks.md +132 -0
- package/skills/applying-slds/guidance/styling-hooks/index.md +327 -0
- package/skills/applying-slds/guidance/styling-hooks/shadows.md +238 -0
- package/skills/applying-slds/guidance/styling-hooks/spacing.md +254 -0
- package/skills/applying-slds/guidance/styling-hooks/typography.md +448 -0
- package/skills/applying-slds/guidance/utilities/alignment.md +119 -0
- package/skills/applying-slds/guidance/utilities/borders.md +131 -0
- package/skills/applying-slds/guidance/utilities/box.md +125 -0
- package/skills/applying-slds/guidance/utilities/color.md +165 -0
- package/skills/applying-slds/guidance/utilities/dark-mode.md +111 -0
- package/skills/applying-slds/guidance/utilities/description-list.md +168 -0
- package/skills/applying-slds/guidance/utilities/floats.md +117 -0
- package/skills/applying-slds/guidance/utilities/grid.md +264 -0
- package/skills/applying-slds/guidance/utilities/horizontal-list.md +110 -0
- package/skills/applying-slds/guidance/utilities/hyphenation.md +84 -0
- package/skills/applying-slds/guidance/utilities/index.md +205 -0
- package/skills/applying-slds/guidance/utilities/interactions.md +89 -0
- package/skills/applying-slds/guidance/utilities/layout.md +109 -0
- package/skills/applying-slds/guidance/utilities/line-clamp.md +131 -0
- package/skills/applying-slds/guidance/utilities/margin.md +155 -0
- package/skills/applying-slds/guidance/utilities/media-object.md +161 -0
- package/skills/applying-slds/guidance/utilities/name-value-list.md +152 -0
- package/skills/applying-slds/guidance/utilities/padding.md +155 -0
- package/skills/applying-slds/guidance/utilities/position.md +177 -0
- package/skills/applying-slds/guidance/utilities/print.md +114 -0
- package/skills/applying-slds/guidance/utilities/scrollable.md +126 -0
- package/skills/applying-slds/guidance/utilities/sizing.md +190 -0
- package/skills/applying-slds/guidance/utilities/themes.md +121 -0
- package/skills/applying-slds/guidance/utilities/truncate.md +127 -0
- package/skills/applying-slds/guidance/utilities/typography.md +166 -0
- package/skills/applying-slds/guidance/utilities/vertical-list.md +166 -0
- package/skills/applying-slds/guidance/utilities/visibility.md +228 -0
- package/skills/applying-slds/metadata/README.md +84 -0
- package/skills/applying-slds/metadata/blueprints/components/accordion.yaml +304 -0
- package/skills/applying-slds/metadata/blueprints/components/activity-timeline.yaml +92 -0
- package/skills/applying-slds/metadata/blueprints/components/alert.yaml +103 -0
- package/skills/applying-slds/metadata/blueprints/components/app-launcher.yaml +94 -0
- package/skills/applying-slds/metadata/blueprints/components/avatar-group.yaml +81 -0
- package/skills/applying-slds/metadata/blueprints/components/avatar.yaml +97 -0
- package/skills/applying-slds/metadata/blueprints/components/badges.yaml +102 -0
- package/skills/applying-slds/metadata/blueprints/components/brand-band.yaml +198 -0
- package/skills/applying-slds/metadata/blueprints/components/breadcrumbs.yaml +95 -0
- package/skills/applying-slds/metadata/blueprints/components/builder-header.yaml +192 -0
- package/skills/applying-slds/metadata/blueprints/components/button-groups.yaml +82 -0
- package/skills/applying-slds/metadata/blueprints/components/button-icons.yaml +295 -0
- package/skills/applying-slds/metadata/blueprints/components/buttons.yaml +230 -0
- package/skills/applying-slds/metadata/blueprints/components/cards.yaml +124 -0
- package/skills/applying-slds/metadata/blueprints/components/carousel.yaml +140 -0
- package/skills/applying-slds/metadata/blueprints/components/chat.yaml +179 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-button.yaml +204 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox.yaml +108 -0
- package/skills/applying-slds/metadata/blueprints/components/color-picker.yaml +172 -0
- package/skills/applying-slds/metadata/blueprints/components/combobox.yaml +136 -0
- package/skills/applying-slds/metadata/blueprints/components/counter.yaml +147 -0
- package/skills/applying-slds/metadata/blueprints/components/data-tables.yaml +157 -0
- package/skills/applying-slds/metadata/blueprints/components/datepickers.yaml +130 -0
- package/skills/applying-slds/metadata/blueprints/components/datetime-picker.yaml +155 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-composer.yaml +201 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-form-footer.yaml +161 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
- package/skills/applying-slds/metadata/blueprints/components/drop-zone.yaml +115 -0
- package/skills/applying-slds/metadata/blueprints/components/dueling-picklist.yaml +196 -0
- package/skills/applying-slds/metadata/blueprints/components/dynamic-icons.yaml +128 -0
- package/skills/applying-slds/metadata/blueprints/components/dynamic-menu.yaml +141 -0
- package/skills/applying-slds/metadata/blueprints/components/expandable-section.yaml +115 -0
- package/skills/applying-slds/metadata/blueprints/components/expression.yaml +143 -0
- package/skills/applying-slds/metadata/blueprints/components/feeds.yaml +125 -0
- package/skills/applying-slds/metadata/blueprints/components/file-selector.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/files.yaml +119 -0
- package/skills/applying-slds/metadata/blueprints/components/form-element.yaml +145 -0
- package/skills/applying-slds/metadata/blueprints/components/global-header.yaml +120 -0
- package/skills/applying-slds/metadata/blueprints/components/global-navigation.yaml +100 -0
- package/skills/applying-slds/metadata/blueprints/components/icons.yaml +138 -0
- package/skills/applying-slds/metadata/blueprints/components/illustration.yaml +205 -0
- package/skills/applying-slds/metadata/blueprints/components/input.yaml +151 -0
- package/skills/applying-slds/metadata/blueprints/components/list-builder.yaml +127 -0
- package/skills/applying-slds/metadata/blueprints/components/lookups.yaml +132 -0
- package/skills/applying-slds/metadata/blueprints/components/map.yaml +118 -0
- package/skills/applying-slds/metadata/blueprints/components/menus.yaml +134 -0
- package/skills/applying-slds/metadata/blueprints/components/modals.yaml +152 -0
- package/skills/applying-slds/metadata/blueprints/components/notifications.yaml +88 -0
- package/skills/applying-slds/metadata/blueprints/components/page-headers.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/panels.yaml +149 -0
- package/skills/applying-slds/metadata/blueprints/components/path.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/picklist.yaml +125 -0
- package/skills/applying-slds/metadata/blueprints/components/pills.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/popovers.yaml +120 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-bar.yaml +110 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-indicator.yaml +133 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-ring.yaml +102 -0
- package/skills/applying-slds/metadata/blueprints/components/prompt.yaml +126 -0
- package/skills/applying-slds/metadata/blueprints/components/publishers.yaml +178 -0
- package/skills/applying-slds/metadata/blueprints/components/radio-button-group.yaml +172 -0
- package/skills/applying-slds/metadata/blueprints/components/radio-group.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/rich-text-editor.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/scoped-notifications.yaml +188 -0
- package/skills/applying-slds/metadata/blueprints/components/scoped-tabs.yaml +97 -0
- package/skills/applying-slds/metadata/blueprints/components/select.yaml +127 -0
- package/skills/applying-slds/metadata/blueprints/components/setup-assistant.yaml +152 -0
- package/skills/applying-slds/metadata/blueprints/components/slider.yaml +111 -0
- package/skills/applying-slds/metadata/blueprints/components/spinners.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/split-view.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/summary-detail.yaml +103 -0
- package/skills/applying-slds/metadata/blueprints/components/tabs.yaml +138 -0
- package/skills/applying-slds/metadata/blueprints/components/textarea.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/tiles.yaml +108 -0
- package/skills/applying-slds/metadata/blueprints/components/timepicker.yaml +111 -0
- package/skills/applying-slds/metadata/blueprints/components/toast.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/tooltips.yaml +107 -0
- package/skills/applying-slds/metadata/blueprints/components/tree-grid.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/trees.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/trial-bar.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/vertical-navigation.yaml +130 -0
- package/skills/applying-slds/metadata/blueprints/components/vertical-tabs.yaml +140 -0
- package/skills/applying-slds/metadata/blueprints/components/visual-picker.yaml +150 -0
- package/skills/applying-slds/metadata/blueprints/components/welcome-mat.yaml +136 -0
- package/skills/applying-slds/metadata/hooks-index.json +6272 -0
- package/skills/applying-slds/metadata/icon-metadata.json +38466 -0
- package/skills/applying-slds/metadata/utilities-index.json +21912 -0
- package/skills/applying-slds/references/component-selection.md +112 -0
- package/skills/applying-slds/references/icons-decision-guide.md +124 -0
- package/skills/applying-slds/references/styling-decision-guide.md +228 -0
- package/skills/applying-slds/references/utilities-quick-ref.md +125 -0
- package/skills/applying-slds/scripts/search-blueprints.cjs +117 -0
- package/skills/applying-slds/scripts/search-hooks.cjs +139 -0
- package/skills/applying-slds/scripts/search-icons.cjs +174 -0
- package/skills/applying-slds/scripts/search-utilities.cjs +161 -0
- package/skills/building-mobile-apps/SKILL.md +0 -1
- package/skills/building-omnistudio-callable-apex/SKILL.md +0 -1
- package/skills/building-omnistudio-datamapper/SKILL.md +0 -1
- package/skills/building-omnistudio-flexcard/SKILL.md +0 -1
- package/skills/building-omnistudio-integration-procedure/SKILL.md +0 -1
- package/skills/building-omnistudio-omniscript/SKILL.md +0 -1
- package/skills/building-sf-integrations/SKILL.md +0 -1
- package/skills/configuring-connected-apps/SKILL.md +0 -1
- package/skills/connecting-datacloud/SKILL.md +0 -1
- package/skills/creating-b2b-commerce-store/SKILL.md +0 -1
- package/skills/debugging-apex-logs/SKILL.md +0 -1
- package/skills/deploying-metadata/SKILL.md +0 -1
- package/skills/deploying-omnistudio-datapacks/SKILL.md +0 -1
- package/skills/developing-agentforce/SKILL.md +0 -1
- package/skills/fetching-salesforce-docs/SKILL.md +0 -1
- package/skills/generating-custom-lightning-type/SKILL.md +17 -39
- package/skills/generating-custom-lightning-type/assets/primitive-types-and-constraints.md +41 -0
- package/skills/generating-custom-lightning-type/references/widget-rendition.md +124 -0
- package/skills/generating-lwc-components/SKILL.md +0 -1
- package/skills/generating-mermaid-diagrams/SKILL.md +0 -1
- package/skills/generating-visual-diagrams/SKILL.md +0 -1
- package/skills/handling-sf-data/SKILL.md +0 -1
- package/skills/harmonizing-datacloud/SKILL.md +0 -1
- package/skills/integrating-b2b-commerce-open-code-components/SKILL.md +0 -1
- package/skills/investigating-agentforce-architecture/README.md +156 -0
- package/skills/investigating-agentforce-architecture/SKILL.md +230 -0
- package/skills/investigating-agentforce-architecture/assets/cli/describe_sobject.yaml +16 -0
- package/skills/investigating-agentforce-architecture/assets/cli/describe_tooling_sobject.yaml +17 -0
- package/skills/investigating-agentforce-architecture/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
- package/skills/investigating-agentforce-architecture/assets/cli/org_display.yaml +15 -0
- package/skills/investigating-agentforce-architecture/assets/cli/retrieve_genai_plugin.yaml +18 -0
- package/skills/investigating-agentforce-architecture/assets/cli/show_access_token.yaml +27 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/action_tree.mmd +20 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/data_flow.mmd +19 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/dependency_graph.mmd +19 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/invocation_sequence.mmd +20 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/planner_state.mmd +18 -0
- package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_names.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/bot_definition_details.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/bot_version_lookup.soql +4 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_by_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_ids_by_names.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_metadata_by_id.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/functions_by_plugins.soql +5 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_bundle_functions.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_definition_by_agent_chain.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugins_by_planner.soql +4 -0
- package/skills/investigating-agentforce-architecture/references/architecture_sections.md +243 -0
- package/skills/investigating-agentforce-architecture/references/contract.json +244 -0
- package/skills/investigating-agentforce-architecture/references/soql_fields.md +512 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/__init__.py +1 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/fs_guard.py +329 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/paths.py +110 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/runtime.py +59 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/sql.py +10 -0
- package/skills/investigating-agentforce-architecture/scripts/cache_check.py +234 -0
- package/skills/investigating-agentforce-architecture/scripts/config.py +131 -0
- package/skills/investigating-agentforce-architecture/scripts/fetch_soql.py +689 -0
- package/skills/investigating-agentforce-architecture/scripts/finalize.py +295 -0
- package/skills/investigating-agentforce-architecture/scripts/main.py +2835 -0
- package/skills/investigating-agentforce-architecture/scripts/metadata_listing.py +265 -0
- package/skills/investigating-agentforce-architecture/scripts/parallel_retrieve.py +69 -0
- package/skills/investigating-agentforce-architecture/scripts/parse_bundle.py +215 -0
- package/skills/investigating-agentforce-architecture/scripts/parse_wave.py +845 -0
- package/skills/investigating-agentforce-architecture/scripts/probe_channels.py +302 -0
- package/skills/investigating-agentforce-architecture/scripts/render_architecture.py +1043 -0
- package/skills/investigating-agentforce-architecture/scripts/resolve_bot.py +255 -0
- package/skills/investigating-agentforce-architecture/scripts/resolve_invocation_target.py +130 -0
- package/skills/investigating-agentforce-architecture/scripts/rest_client.py +763 -0
- package/skills/investigating-agentforce-architecture/scripts/retrieve_planner.py +13 -0
- package/skills/investigating-agentforce-architecture/scripts/sf_cli.py +242 -0
- package/skills/investigating-agentforce-architecture/scripts/soql_loader.py +253 -0
- package/skills/investigating-agentforce-architecture/scripts/summarize_tree.py +143 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/__init__.py +0 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/_bootstrap.py +23 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/genai_payloads.py +400 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check.py +307 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check_main.py +283 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_config.py +115 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_end_to_end_fixture.py +651 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_finalize.py +278 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_flow_children_inflation.py +582 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_fs_guard.py +113 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_iterative_wave_b.py +478 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_main_pipeline.py +3359 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parallel_retrieve.py +131 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_bundle.py +400 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave.py +644 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_classifiers.py +224 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_helpers.py +380 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_main.py +397 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_per_branch_visited.py +244 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_channels.py +359 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_cli_recipes.py +185 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_render_architecture.py +810 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_bot.py +203 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_creds.py +157 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py +145 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_rest_client.py +1253 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_runtime_override.py +100 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_sf_cli.py +261 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_signature_stamping.py +466 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_soql_loader.py +501 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_summarize_tree.py +241 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_write_emit_ctx.py +480 -0
- package/skills/investigating-agentforce-architecture/tools/emit_env.py +157 -0
- package/skills/investigating-agentforce-architecture/tools/emit_result.py +262 -0
- package/skills/investigating-agentforce-architecture/tools/sanitize.py +33 -0
- package/skills/investigating-agentforce-architecture/tools/write_emit_ctx.py +332 -0
- package/skills/investigating-agentforce-d360/README.md +123 -0
- package/skills/investigating-agentforce-d360/SKILL.md +163 -0
- package/skills/investigating-agentforce-d360/assets/dc/app_generation.sql +51 -0
- package/skills/investigating-agentforce-d360/assets/dc/content_category.sql +44 -0
- package/skills/investigating-agentforce-d360/assets/dc/content_quality.sql +41 -0
- package/skills/investigating-agentforce-d360/assets/dc/discover_sessions.sql +36 -0
- package/skills/investigating-agentforce-d360/assets/dc/feedback.sql +47 -0
- package/skills/investigating-agentforce-d360/assets/dc/feedback_details.sql +38 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_records.sql +45 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_llm.sql +50 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_metadata.sql +44 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_tags.sql +42 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_requests.sql +89 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_responses.sql +43 -0
- package/skills/investigating-agentforce-d360/assets/dc/generations.sql +52 -0
- package/skills/investigating-agentforce-d360/assets/dc/interactions.sql +53 -0
- package/skills/investigating-agentforce-d360/assets/dc/messages.sql +53 -0
- package/skills/investigating-agentforce-d360/assets/dc/messaging_session.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/moment_interactions.sql +34 -0
- package/skills/investigating-agentforce-d360/assets/dc/moments.sql +39 -0
- package/skills/investigating-agentforce-d360/assets/dc/participants.sql +48 -0
- package/skills/investigating-agentforce-d360/assets/dc/sessions.sql +78 -0
- package/skills/investigating-agentforce-d360/assets/dc/steps.sql +64 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_associations.sql +46 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_definition_associations.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_definitions.sql +50 -0
- package/skills/investigating-agentforce-d360/assets/dc/tags.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/telemetry_spans.sql +55 -0
- package/skills/investigating-agentforce-d360/references/artifacts.md +50 -0
- package/skills/investigating-agentforce-d360/references/dc_dmo_fields.md +823 -0
- package/skills/investigating-agentforce-d360/references/dc_pipeline_contract.md +608 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/__init__.py +2 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/cli_override.py +98 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/fs_guard.py +334 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/paths.py +155 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/runtime.py +59 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/sql.py +14 -0
- package/skills/investigating-agentforce-d360/scripts/assemble_dc.py +1624 -0
- package/skills/investigating-agentforce-d360/scripts/config.py +45 -0
- package/skills/investigating-agentforce-d360/scripts/dc.py +188 -0
- package/skills/investigating-agentforce-d360/scripts/discover_sessions.py +556 -0
- package/skills/investigating-agentforce-d360/scripts/fetch_dc.py +1045 -0
- package/skills/investigating-agentforce-d360/scripts/render_dc.py +1750 -0
- package/skills/investigating-agentforce-d360/scripts/resolve_session.py +264 -0
- package/skills/investigating-agentforce-d360/scripts/storage.py +92 -0
- package/skills/investigating-agentforce-d360/scripts/tests/__init__.py +0 -0
- package/skills/investigating-agentforce-d360/scripts/tests/_bootstrap.py +15 -0
- package/skills/investigating-agentforce-d360/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/investigating-agentforce-d360/scripts/tests/fixtures/synthetic_session.py +424 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_helpers.py +287 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_integration.py +247 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_dc_and_resolve_session.py +433 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions.py +458 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_helpers.py +266 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_identity.py +528 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_main.py +251 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall.py +229 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_identity_coherence.py +327 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_branches.py +256 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_gateway_direct.py +130 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_helpers.py +291 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_integration.py +220 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_from_disk.py +100 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_session_main.py +149 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_runtime_override.py +104 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape.py +95 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
- package/skills/managing-managed-event-subscription/SKILL.md +152 -0
- package/skills/managing-managed-event-subscription/assets/managed-event-subscription-template.xml +20 -0
- package/skills/managing-managed-event-subscription/references/delete-guide.md +57 -0
- package/skills/managing-managed-event-subscription/references/topic-name-formats.md +26 -0
- package/skills/managing-managed-event-subscription/references/update-constraints.md +30 -0
- package/skills/modeling-omnistudio-epc-catalog/SKILL.md +0 -1
- package/skills/observing-agentforce/SKILL.md +0 -1
- package/skills/orchestrating-datacloud/SKILL.md +0 -1
- package/skills/preparing-datacloud/SKILL.md +0 -1
- package/skills/querying-soql/SKILL.md +0 -1
- package/skills/retrieving-datacloud/SKILL.md +0 -1
- package/skills/running-apex-tests/SKILL.md +0 -1
- package/skills/running-code-analyzer/SKILL.md +0 -1
- package/skills/segmenting-datacloud/SKILL.md +0 -1
- package/skills/testing-agentforce/SKILL.md +0 -1
- package/skills/uplifting-components-to-slds2/SKILL.md +3 -2
- package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +30 -9
- package/skills/uplifting-components-to-slds2/references/examples.md +24 -6
- package/skills/validating-slds/SKILL.md +262 -0
- package/skills/validating-slds/references/quality-checks.md +308 -0
- package/skills/validating-slds/references/report-format.md +302 -0
- package/skills/validating-slds/scripts/analyze-quality.cjs +521 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
"""Tests for ``fetch_dc._resolve_identity`` + ``sf org display`` fallback.
|
|
2
|
+
|
|
3
|
+
Closes a real-world failure mode: ``sessions[0].ssot__InternalOrganizationId__c``
|
|
4
|
+
is occasionally null in SSOT materialization despite every other field
|
|
5
|
+
being populated (e.g. session ``019dface-0000-7000-8000-000000000001`` in
|
|
6
|
+
``my-org-alias``). The authenticated ``sf`` alias knows the org id
|
|
7
|
+
regardless, so we fall back to ``sf org display --target-org <alias> --json``
|
|
8
|
+
and parse ``.result.id``. If that also fails, a unified diagnostic
|
|
9
|
+
surfaces both failure modes.
|
|
10
|
+
|
|
11
|
+
Every test patches ``subprocess.run`` at the ``fetch_dc`` module level so
|
|
12
|
+
no real CLI is ever invoked.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import subprocess
|
|
18
|
+
import unittest
|
|
19
|
+
from types import SimpleNamespace
|
|
20
|
+
from unittest import mock
|
|
21
|
+
|
|
22
|
+
from . import _bootstrap # noqa: F401 — sys.path setup
|
|
23
|
+
|
|
24
|
+
import fetch_dc # type: ignore
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_ORG_ALIAS = "my-org-alias"
|
|
28
|
+
_FULL_ORG_ID_18 = "00D0000000000000EA"
|
|
29
|
+
_EXPECTED_ORG_ID_15 = "00D000000000000"
|
|
30
|
+
_AGENT_API = "DemoAgent"
|
|
31
|
+
_AGENT_VER = "v5"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _agent_participant() -> dict:
|
|
35
|
+
return {
|
|
36
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
37
|
+
"ssot__AiAgentApiName__c": _AGENT_API,
|
|
38
|
+
"ssot__AiAgentVersionApiName__c": _AGENT_VER,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _sf_cli_success_stdout(org_id: str = _FULL_ORG_ID_18) -> str:
|
|
43
|
+
"""Shape mirrors the real ``sf org display --json`` payload."""
|
|
44
|
+
return json.dumps({
|
|
45
|
+
"status": 0,
|
|
46
|
+
"result": {
|
|
47
|
+
"id": org_id,
|
|
48
|
+
"instanceUrl": "https://example.my.salesforce.com",
|
|
49
|
+
"accessToken": "REDACTED",
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ResolveIdentityDmoPopulatedTests(unittest.TestCase):
|
|
55
|
+
"""Happy path — DMO field carries a valid 18-char id, no subprocess spawn."""
|
|
56
|
+
|
|
57
|
+
def test_resolve_identity_uses_dmo_when_populated(self):
|
|
58
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
59
|
+
participants = [_agent_participant()]
|
|
60
|
+
|
|
61
|
+
with mock.patch.object(fetch_dc.subprocess, "run") as m_run:
|
|
62
|
+
org_id_15, agent, ver = fetch_dc._resolve_identity(
|
|
63
|
+
sessions, participants, _ORG_ALIAS,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
|
|
67
|
+
self.assertEqual(agent, _AGENT_API)
|
|
68
|
+
self.assertEqual(ver, _AGENT_VER)
|
|
69
|
+
m_run.assert_not_called()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ResolveIdentityDmoFallbackTests(unittest.TestCase):
|
|
73
|
+
"""DMO field null/empty/short — fall back to ``sf org display``."""
|
|
74
|
+
|
|
75
|
+
def _patch_sf_cli_ok(self, org_id: str = _FULL_ORG_ID_18):
|
|
76
|
+
return mock.patch.object(
|
|
77
|
+
fetch_dc.subprocess, "run",
|
|
78
|
+
return_value=SimpleNamespace(
|
|
79
|
+
stdout=_sf_cli_success_stdout(org_id),
|
|
80
|
+
stderr="",
|
|
81
|
+
returncode=0,
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def test_resolve_identity_falls_back_to_sf_cli_when_dmo_null(self):
|
|
86
|
+
sessions = [{"ssot__InternalOrganizationId__c": None}]
|
|
87
|
+
participants = [_agent_participant()]
|
|
88
|
+
|
|
89
|
+
with self._patch_sf_cli_ok() as m_run:
|
|
90
|
+
org_id_15, agent, ver = fetch_dc._resolve_identity(
|
|
91
|
+
sessions, participants, _ORG_ALIAS,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
|
|
95
|
+
self.assertEqual(agent, _AGENT_API)
|
|
96
|
+
self.assertEqual(ver, _AGENT_VER)
|
|
97
|
+
# Exact argv shape matters — it's the public contract with the sf CLI.
|
|
98
|
+
args, kwargs = m_run.call_args
|
|
99
|
+
self.assertEqual(
|
|
100
|
+
args[0],
|
|
101
|
+
["sf", "org", "display", "--target-org", _ORG_ALIAS, "--json"],
|
|
102
|
+
)
|
|
103
|
+
self.assertTrue(kwargs.get("check"))
|
|
104
|
+
self.assertTrue(kwargs.get("capture_output"))
|
|
105
|
+
self.assertTrue(kwargs.get("text"))
|
|
106
|
+
|
|
107
|
+
def test_resolve_identity_falls_back_when_dmo_empty_string(self):
|
|
108
|
+
sessions = [{"ssot__InternalOrganizationId__c": ""}]
|
|
109
|
+
participants = [_agent_participant()]
|
|
110
|
+
|
|
111
|
+
with self._patch_sf_cli_ok():
|
|
112
|
+
org_id_15, _, _ = fetch_dc._resolve_identity(
|
|
113
|
+
sessions, participants, _ORG_ALIAS,
|
|
114
|
+
)
|
|
115
|
+
self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
|
|
116
|
+
|
|
117
|
+
def test_resolve_identity_falls_back_when_dmo_shorter_than_15(self):
|
|
118
|
+
sessions = [{"ssot__InternalOrganizationId__c": "shortid"}]
|
|
119
|
+
participants = [_agent_participant()]
|
|
120
|
+
|
|
121
|
+
with self._patch_sf_cli_ok():
|
|
122
|
+
org_id_15, _, _ = fetch_dc._resolve_identity(
|
|
123
|
+
sessions, participants, _ORG_ALIAS,
|
|
124
|
+
)
|
|
125
|
+
self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class ResolveIdentityBothSourcesFailTests(unittest.TestCase):
|
|
129
|
+
"""When both the DMO field AND the CLI fallback fail, surface both."""
|
|
130
|
+
|
|
131
|
+
def test_resolve_identity_raises_when_both_sources_fail(self):
|
|
132
|
+
sessions = [{"ssot__InternalOrganizationId__c": None}]
|
|
133
|
+
participants = [_agent_participant()]
|
|
134
|
+
|
|
135
|
+
err = subprocess.CalledProcessError(
|
|
136
|
+
returncode=1,
|
|
137
|
+
cmd=["sf", "org", "display", "--target-org", _ORG_ALIAS, "--json"],
|
|
138
|
+
stderr="No AuthInfo found for name " + _ORG_ALIAS,
|
|
139
|
+
)
|
|
140
|
+
with mock.patch.object(fetch_dc.subprocess, "run", side_effect=err):
|
|
141
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
142
|
+
fetch_dc._resolve_identity(
|
|
143
|
+
sessions, participants, _ORG_ALIAS,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
msg = str(ctx.exception)
|
|
147
|
+
# Must mention both failure modes so users know which to fix.
|
|
148
|
+
self.assertIn("both DMO field and sf org display failed", msg)
|
|
149
|
+
self.assertIn(_ORG_ALIAS, msg)
|
|
150
|
+
self.assertIn("CalledProcessError", msg)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class ResolveIdentityNoAgentParticipantsTests(unittest.TestCase):
|
|
154
|
+
"""Recently-created sessions can land here while STDM is still
|
|
155
|
+
materializing — the AGENT participant rows haven't been written yet.
|
|
156
|
+
The error must hint at retry rather than implying a malformed session.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def test_resolve_identity_raises_with_retry_hint_when_no_agent_participants(self):
|
|
160
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
161
|
+
# No AGENT-role participants; only a USER row.
|
|
162
|
+
participants = [{
|
|
163
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
164
|
+
"ssot__AiAgentApiName__c": "",
|
|
165
|
+
"ssot__AiAgentVersionApiName__c": "",
|
|
166
|
+
}]
|
|
167
|
+
|
|
168
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
169
|
+
fetch_dc._resolve_identity(sessions, participants, _ORG_ALIAS)
|
|
170
|
+
|
|
171
|
+
msg = str(ctx.exception)
|
|
172
|
+
# Identifying string for the error class.
|
|
173
|
+
self.assertIn("no AGENT participants", msg)
|
|
174
|
+
# New (Fix #6) wording — leads with retry, then falls back to malformed.
|
|
175
|
+
self.assertIn("retry in a few minutes", msg)
|
|
176
|
+
self.assertIn("STDM materialization", msg)
|
|
177
|
+
|
|
178
|
+
def test_resolve_identity_raises_when_only_empty_field_participants(self):
|
|
179
|
+
# AGENT-role row exists but agent_api_name + agent_version are blank.
|
|
180
|
+
# Same outcome — no usable identity, same retry-hint error.
|
|
181
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
182
|
+
participants = [{
|
|
183
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
184
|
+
"ssot__AiAgentApiName__c": "",
|
|
185
|
+
"ssot__AiAgentVersionApiName__c": "",
|
|
186
|
+
}]
|
|
187
|
+
|
|
188
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
189
|
+
fetch_dc._resolve_identity(sessions, participants, _ORG_ALIAS)
|
|
190
|
+
|
|
191
|
+
self.assertIn("no AGENT participants", str(ctx.exception))
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class ResolveIdentityUserRowFallbackTests(unittest.TestCase):
|
|
195
|
+
"""Some agent shapes (e.g. the OOTB ``MyAgent`` template) leave
|
|
196
|
+
AGENT-row ``ssot__AiAgentApiName__c`` / ``ssot__AiAgentVersionApiName__c``
|
|
197
|
+
as ``NOT_SET`` indefinitely, while USER-role rows correctly carry the
|
|
198
|
+
api_name. The downstream session is otherwise complete (interactions,
|
|
199
|
+
steps, generations all materialize), so refusing to run wastes signal.
|
|
200
|
+
|
|
201
|
+
The fallback promotes the api_name from any participant row, stamps
|
|
202
|
+
version=``v0`` (placeholder satisfying ``^v[0-9]+$`` per fs_guard), and
|
|
203
|
+
proceeds. Tests guard against regression — a future "tighten this back
|
|
204
|
+
up" refactor would re-break the MyAgent case silently.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def test_falls_back_to_user_row_api_name_when_agent_rows_not_set(self):
|
|
208
|
+
# Mirrors a real session shape observed in production:
|
|
209
|
+
# USER rows carry the api_name, AGENT rows are 'NOT_SET'.
|
|
210
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
211
|
+
participants = [
|
|
212
|
+
{
|
|
213
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
214
|
+
"ssot__AiAgentApiName__c": "MyAgent",
|
|
215
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
219
|
+
"ssot__AiAgentApiName__c": "NOT_SET",
|
|
220
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
221
|
+
},
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
org_id_15, agent, ver = fetch_dc._resolve_identity(
|
|
225
|
+
sessions, participants, _ORG_ALIAS,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
|
|
229
|
+
self.assertEqual(agent, "MyAgent")
|
|
230
|
+
# Placeholder must satisfy the AGENT_VERSION_RE used by paths.session_dir.
|
|
231
|
+
self.assertEqual(ver, "v0")
|
|
232
|
+
|
|
233
|
+
def test_fallback_handles_blank_api_name_on_agent_row(self):
|
|
234
|
+
# AGENT row api_name is empty string (rather than the literal
|
|
235
|
+
# 'NOT_SET'). Both shapes mean the same thing per _NOT_SET.
|
|
236
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
237
|
+
participants = [
|
|
238
|
+
{
|
|
239
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
240
|
+
"ssot__AiAgentApiName__c": "MyAgent",
|
|
241
|
+
"ssot__AiAgentVersionApiName__c": "",
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
245
|
+
"ssot__AiAgentApiName__c": "",
|
|
246
|
+
"ssot__AiAgentVersionApiName__c": "",
|
|
247
|
+
},
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
251
|
+
sessions, participants, _ORG_ALIAS,
|
|
252
|
+
)
|
|
253
|
+
self.assertEqual(agent, "MyAgent")
|
|
254
|
+
self.assertEqual(ver, "v0")
|
|
255
|
+
|
|
256
|
+
def test_fallback_picks_lexicographic_first_when_multiple_user_names(self):
|
|
257
|
+
# Multi-agent handoff session where USER rows mention both agents.
|
|
258
|
+
# The fallback uses sorted({...})[0] to match the dominant-agent
|
|
259
|
+
# policy used elsewhere in the pipeline.
|
|
260
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
261
|
+
participants = [
|
|
262
|
+
{
|
|
263
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
264
|
+
"ssot__AiAgentApiName__c": "ZAgent",
|
|
265
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
269
|
+
"ssot__AiAgentApiName__c": "AAgent",
|
|
270
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
274
|
+
"ssot__AiAgentApiName__c": "NOT_SET",
|
|
275
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
276
|
+
},
|
|
277
|
+
]
|
|
278
|
+
|
|
279
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
280
|
+
sessions, participants, _ORG_ALIAS,
|
|
281
|
+
)
|
|
282
|
+
self.assertEqual(agent, "AAgent")
|
|
283
|
+
self.assertEqual(ver, "v0")
|
|
284
|
+
|
|
285
|
+
def test_agent_row_with_only_version_not_set_still_uses_strict_path(self):
|
|
286
|
+
# Defensive: AGENT row has a real api_name but version=NOT_SET. The
|
|
287
|
+
# strict candidate filter rejects it, but the fallback should still
|
|
288
|
+
# promote the api_name (avoiding a needless raise just because version
|
|
289
|
+
# was missing on the AGENT row).
|
|
290
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
291
|
+
participants = [{
|
|
292
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
293
|
+
"ssot__AiAgentApiName__c": "RealAgent",
|
|
294
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
295
|
+
}]
|
|
296
|
+
|
|
297
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
298
|
+
sessions, participants, _ORG_ALIAS,
|
|
299
|
+
)
|
|
300
|
+
self.assertEqual(agent, "RealAgent")
|
|
301
|
+
self.assertEqual(ver, "v0")
|
|
302
|
+
|
|
303
|
+
def test_fallback_rejects_api_name_with_invalid_shape(self):
|
|
304
|
+
# Even though a non-empty api_name is present on a USER row, if it
|
|
305
|
+
# doesn't satisfy ^[A-Za-z0-9_]+$ (fs_guard.API_NAME_RE) the fallback
|
|
306
|
+
# MUST fall through to the original SystemExit. Without this guard,
|
|
307
|
+
# paths.session_dir would later reject the dir with an opaque
|
|
308
|
+
# ValidationError far from where the bad value originated.
|
|
309
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
310
|
+
for bad_name in ("Service Agent", "agent-v1", "agent.v1", "héllo"):
|
|
311
|
+
with self.subTest(bad_name=bad_name):
|
|
312
|
+
participants = [{
|
|
313
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
314
|
+
"ssot__AiAgentApiName__c": bad_name,
|
|
315
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
316
|
+
}]
|
|
317
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
318
|
+
fetch_dc._resolve_identity(
|
|
319
|
+
sessions, participants, _ORG_ALIAS,
|
|
320
|
+
)
|
|
321
|
+
# Falls through to the strict-path SystemExit, NOT a path-
|
|
322
|
+
# validation traceback from fs_guard.
|
|
323
|
+
self.assertIn("no AGENT participants", str(ctx.exception))
|
|
324
|
+
|
|
325
|
+
def test_fallback_skips_invalid_picks_valid_when_both_present(self):
|
|
326
|
+
# If multiple api_names are seen, the regex filter should drop the
|
|
327
|
+
# invalid ones and the fallback should still succeed with a valid one.
|
|
328
|
+
# Defense against a real session that mixes a malformed display-name
|
|
329
|
+
# row (e.g. legacy data) with a clean USER row.
|
|
330
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
331
|
+
participants = [
|
|
332
|
+
{
|
|
333
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
334
|
+
"ssot__AiAgentApiName__c": "Service Agent", # invalid
|
|
335
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
339
|
+
"ssot__AiAgentApiName__c": "MyAgent", # valid
|
|
340
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
341
|
+
},
|
|
342
|
+
]
|
|
343
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
344
|
+
sessions, participants, _ORG_ALIAS,
|
|
345
|
+
)
|
|
346
|
+
self.assertEqual(agent, "MyAgent")
|
|
347
|
+
self.assertEqual(ver, "v0")
|
|
348
|
+
|
|
349
|
+
def test_fallback_returned_version_matches_agent_version_regex(self):
|
|
350
|
+
# Belt-and-braces: the placeholder version we return MUST match
|
|
351
|
+
# the ^v[0-9]+$ shape enforced by paths.session_dir / fs_guard
|
|
352
|
+
# (see scripts/_shared/paths.py:_validate_agent_triple). If a
|
|
353
|
+
# future change picks a different placeholder ('NOT_SET',
|
|
354
|
+
# 'unknown', 'v0.0', etc.) directory creation downstream will
|
|
355
|
+
# blow up. Test the exact contract here without taking a
|
|
356
|
+
# cross-skill import dependency.
|
|
357
|
+
import re
|
|
358
|
+
|
|
359
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
360
|
+
participants = [{
|
|
361
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
362
|
+
"ssot__AiAgentApiName__c": "MyAgent",
|
|
363
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
364
|
+
}]
|
|
365
|
+
_, _, ver = fetch_dc._resolve_identity(
|
|
366
|
+
sessions, participants, _ORG_ALIAS,
|
|
367
|
+
)
|
|
368
|
+
self.assertRegex(ver, r"^v[0-9]+$")
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class ResolveIdentityCrossRoleVersionHarvestTests(unittest.TestCase):
|
|
372
|
+
"""Real-data shape: AGENT participant rows had api_name + version both
|
|
373
|
+
NOT_SET, but the USER rows carried the real (api_name, version) pair.
|
|
374
|
+
The prior fallback only harvested api_name from non-AGENT rows and
|
|
375
|
+
stamped version=``v0``, so the dir landed at ``<agent>__v0/`` while
|
|
376
|
+
``assemble_dc`` reconciled the real version into the tree from
|
|
377
|
+
``session.identity`` — dir + tree out of sync.
|
|
378
|
+
|
|
379
|
+
The cross-role harvest closes that gap: when the strict AGENT-only
|
|
380
|
+
candidate list is empty, scan ALL participant rows for a valid
|
|
381
|
+
(api_name, version) pair before falling back to the v0 placeholder.
|
|
382
|
+
Real version wins; placeholder is genuinely a last resort.
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
def test_user_row_carries_real_version_dir_lands_correctly(self):
|
|
386
|
+
# The exact shape found on a live session. AGENT rows: NOT_SET on
|
|
387
|
+
# both fields. USER rows: real pair.
|
|
388
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
389
|
+
participants = [
|
|
390
|
+
{
|
|
391
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
392
|
+
"ssot__AiAgentApiName__c": "MyAgent",
|
|
393
|
+
"ssot__AiAgentVersionApiName__c": "v24",
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
397
|
+
"ssot__AiAgentApiName__c": "MyAgent",
|
|
398
|
+
"ssot__AiAgentVersionApiName__c": "v24",
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
402
|
+
"ssot__AiAgentApiName__c": "NOT_SET",
|
|
403
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
404
|
+
},
|
|
405
|
+
]
|
|
406
|
+
|
|
407
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
408
|
+
sessions, participants, _ORG_ALIAS,
|
|
409
|
+
)
|
|
410
|
+
self.assertEqual(agent, "MyAgent")
|
|
411
|
+
# MUST be the real version, NOT the v0 placeholder — that's the
|
|
412
|
+
# whole point of the cross-role harvest.
|
|
413
|
+
self.assertEqual(ver, "v24")
|
|
414
|
+
|
|
415
|
+
def test_falls_through_to_v0_placeholder_when_no_role_carries_version(self):
|
|
416
|
+
# Builder Previewer shape: api_name lands on a USER row but no
|
|
417
|
+
# participant row carries a real version. Must drop through to
|
|
418
|
+
# the v0 placeholder branch (which keeps the pipeline runnable
|
|
419
|
+
# for that legitimate session shape).
|
|
420
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
421
|
+
participants = [
|
|
422
|
+
{
|
|
423
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
424
|
+
"ssot__AiAgentApiName__c": "MyAgent",
|
|
425
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
429
|
+
"ssot__AiAgentApiName__c": "NOT_SET",
|
|
430
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
431
|
+
},
|
|
432
|
+
]
|
|
433
|
+
|
|
434
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
435
|
+
sessions, participants, _ORG_ALIAS,
|
|
436
|
+
)
|
|
437
|
+
self.assertEqual(agent, "MyAgent")
|
|
438
|
+
self.assertEqual(ver, "v0")
|
|
439
|
+
|
|
440
|
+
def test_cross_role_rejects_malformed_version(self):
|
|
441
|
+
# Someone wrote a malformed version into a USER row (e.g.
|
|
442
|
+
# 'v1.0', '1', '24'). Must NOT adopt it — fs_guard will reject
|
|
443
|
+
# the dir later. Fall through to v0 placeholder so the pipeline
|
|
444
|
+
# still runs and the assemble_dc reconcile can promote later
|
|
445
|
+
# if a real version shows up elsewhere in the tree.
|
|
446
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
447
|
+
for bad_version in ("v1.0", "1", "24", "version-24", ""):
|
|
448
|
+
with self.subTest(bad_version=bad_version):
|
|
449
|
+
participants = [
|
|
450
|
+
{
|
|
451
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
452
|
+
"ssot__AiAgentApiName__c": "MyAgent",
|
|
453
|
+
"ssot__AiAgentVersionApiName__c": bad_version,
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
457
|
+
"ssot__AiAgentApiName__c": "NOT_SET",
|
|
458
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
459
|
+
},
|
|
460
|
+
]
|
|
461
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
462
|
+
sessions, participants, _ORG_ALIAS,
|
|
463
|
+
)
|
|
464
|
+
self.assertEqual(agent, "MyAgent")
|
|
465
|
+
# Bad version rejected; placeholder kicks in.
|
|
466
|
+
self.assertEqual(ver, "v0")
|
|
467
|
+
|
|
468
|
+
def test_strict_agent_row_precedence_beats_user_row(self):
|
|
469
|
+
# When BOTH AGENT and USER rows carry valid (api_name, version)
|
|
470
|
+
# pairs, the strict-AGENT path runs first and the cross-role
|
|
471
|
+
# branch is unreachable. Pin this precedence so a future
|
|
472
|
+
# refactor can't accidentally reorder the resolution. If the
|
|
473
|
+
# AGENT row's pair were ever shadowed by a USER row's pair, the
|
|
474
|
+
# dominant-agent invariant on handoff sessions breaks.
|
|
475
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
476
|
+
participants = [
|
|
477
|
+
{
|
|
478
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
479
|
+
"ssot__AiAgentApiName__c": "AAgent", # lex-first across both rows
|
|
480
|
+
"ssot__AiAgentVersionApiName__c": "v1",
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
484
|
+
"ssot__AiAgentApiName__c": "ZAgent", # lex-LAST overall
|
|
485
|
+
"ssot__AiAgentVersionApiName__c": "v9",
|
|
486
|
+
},
|
|
487
|
+
]
|
|
488
|
+
|
|
489
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
490
|
+
sessions, participants, _ORG_ALIAS,
|
|
491
|
+
)
|
|
492
|
+
# AGENT-row precedence: ZAgent/v9 wins, NOT AAgent/v1.
|
|
493
|
+
self.assertEqual(agent, "ZAgent")
|
|
494
|
+
self.assertEqual(ver, "v9")
|
|
495
|
+
|
|
496
|
+
def test_cross_role_picks_lex_first_when_multiple_valid_pairs(self):
|
|
497
|
+
# Handoff with two valid (api_name, version) pairs across USER
|
|
498
|
+
# rows. The strict-path dominant-agent rule applies: lex-first
|
|
499
|
+
# wins. This keeps the cross-role harvest aligned with the
|
|
500
|
+
# AGENT-only path's selection policy.
|
|
501
|
+
sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
|
|
502
|
+
participants = [
|
|
503
|
+
{
|
|
504
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
505
|
+
"ssot__AiAgentApiName__c": "ZAgent",
|
|
506
|
+
"ssot__AiAgentVersionApiName__c": "v9",
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"ssot__AiAgentSessionParticipantRole__c": "USER",
|
|
510
|
+
"ssot__AiAgentApiName__c": "AAgent",
|
|
511
|
+
"ssot__AiAgentVersionApiName__c": "v3",
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"ssot__AiAgentSessionParticipantRole__c": "AGENT",
|
|
515
|
+
"ssot__AiAgentApiName__c": "NOT_SET",
|
|
516
|
+
"ssot__AiAgentVersionApiName__c": "NOT_SET",
|
|
517
|
+
},
|
|
518
|
+
]
|
|
519
|
+
|
|
520
|
+
_, agent, ver = fetch_dc._resolve_identity(
|
|
521
|
+
sessions, participants, _ORG_ALIAS,
|
|
522
|
+
)
|
|
523
|
+
self.assertEqual(agent, "AAgent")
|
|
524
|
+
self.assertEqual(ver, "v3")
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
if __name__ == "__main__":
|
|
528
|
+
unittest.main()
|