@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,256 @@
|
|
|
1
|
+
"""Additional ``render_dc`` tests targeting branches not covered by
|
|
2
|
+
``test_render_dc_integration.py``:
|
|
3
|
+
|
|
4
|
+
- ``main_for_session`` reads tree + manifest from disk; emits markdown
|
|
5
|
+
- ``main`` argparse → main_for_session
|
|
6
|
+
- ``_parse_finish_reason`` HTML-escaped JSON parsing
|
|
7
|
+
- ``_decoded_line`` tool-call JSON detection
|
|
8
|
+
- mermaid sequence diagram (requires ≥2 ACTION_STEPs OR an error_text)
|
|
9
|
+
- mermaid topic flowchart (requires repeating topics across turns)
|
|
10
|
+
- schema-version refusal on unsupported _schema_version
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import unittest
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from tempfile import TemporaryDirectory
|
|
18
|
+
from unittest import mock
|
|
19
|
+
|
|
20
|
+
from . import _bootstrap # noqa: F401 — sys.path setup
|
|
21
|
+
|
|
22
|
+
import assemble_dc # type: ignore
|
|
23
|
+
import render_dc # type: ignore
|
|
24
|
+
from config import paths # type: ignore
|
|
25
|
+
from .fixtures.synthetic_session import IDS, write_to_disk # type: ignore
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# -----------------------------------------------------------------------------
|
|
29
|
+
# main_for_session — disk-backed entry point
|
|
30
|
+
# -----------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class MainForSessionTests(unittest.TestCase):
|
|
34
|
+
|
|
35
|
+
def test_reads_tree_writes_summary_md(self):
|
|
36
|
+
with TemporaryDirectory() as t:
|
|
37
|
+
tmp = Path(t)
|
|
38
|
+
sdir = write_to_disk(tmp)
|
|
39
|
+
with mock.patch.object(paths, "DATA_ROOT", tmp):
|
|
40
|
+
tree, _ = assemble_dc.assemble(IDS.SID)
|
|
41
|
+
(sdir / "dc._session_tree.json").write_text(
|
|
42
|
+
json.dumps(tree, default=str)
|
|
43
|
+
)
|
|
44
|
+
rc = render_dc.main_for_session(IDS.SID)
|
|
45
|
+
self.assertEqual(rc, 0)
|
|
46
|
+
summary_path = sdir / "dc._session_summary.md"
|
|
47
|
+
self.assertTrue(summary_path.is_file())
|
|
48
|
+
self.assertGreater(len(summary_path.read_text()), 1000)
|
|
49
|
+
|
|
50
|
+
def test_raises_when_tree_missing(self):
|
|
51
|
+
with TemporaryDirectory() as t:
|
|
52
|
+
tmp = Path(t)
|
|
53
|
+
write_to_disk(tmp) # creates session dir but not tree
|
|
54
|
+
with mock.patch.object(paths, "DATA_ROOT", tmp):
|
|
55
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
56
|
+
render_dc.main_for_session(IDS.SID)
|
|
57
|
+
self.assertIn("tree not found", str(ctx.exception))
|
|
58
|
+
|
|
59
|
+
def test_tolerates_missing_manifest_with_warning(self):
|
|
60
|
+
with TemporaryDirectory() as t:
|
|
61
|
+
tmp = Path(t)
|
|
62
|
+
sdir = write_to_disk(tmp)
|
|
63
|
+
with mock.patch.object(paths, "DATA_ROOT", tmp):
|
|
64
|
+
tree, _ = assemble_dc.assemble(IDS.SID)
|
|
65
|
+
(sdir / "dc._session_tree.json").write_text(
|
|
66
|
+
json.dumps(tree, default=str)
|
|
67
|
+
)
|
|
68
|
+
# Wipe the manifest. main_for_session should still succeed
|
|
69
|
+
# (manifest is optional; missing → no manifest-driven sections).
|
|
70
|
+
(sdir / "dc._session_manifest.json").unlink()
|
|
71
|
+
rc = render_dc.main_for_session(IDS.SID)
|
|
72
|
+
self.assertEqual(rc, 0)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# -----------------------------------------------------------------------------
|
|
76
|
+
# main — argparse + resolve
|
|
77
|
+
# -----------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class MainTests(unittest.TestCase):
|
|
81
|
+
|
|
82
|
+
def test_main_invokes_main_for_session_with_resolved_sid(self):
|
|
83
|
+
with TemporaryDirectory() as t:
|
|
84
|
+
tmp = Path(t)
|
|
85
|
+
sdir = write_to_disk(tmp)
|
|
86
|
+
with mock.patch.object(paths, "DATA_ROOT", tmp):
|
|
87
|
+
tree, _ = assemble_dc.assemble(IDS.SID)
|
|
88
|
+
(sdir / "dc._session_tree.json").write_text(
|
|
89
|
+
json.dumps(tree, default=str)
|
|
90
|
+
)
|
|
91
|
+
with mock.patch.object(
|
|
92
|
+
render_dc.sys, "argv",
|
|
93
|
+
["render_dc.py", "--session", IDS.SID],
|
|
94
|
+
):
|
|
95
|
+
rc = render_dc.main()
|
|
96
|
+
self.assertEqual(rc, 0)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# -----------------------------------------------------------------------------
|
|
100
|
+
# _parse_finish_reason — HTML-escaped JSON
|
|
101
|
+
# -----------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class ParseFinishReasonTests(unittest.TestCase):
|
|
105
|
+
|
|
106
|
+
def test_extracts_stop_from_double_escaped_json(self):
|
|
107
|
+
# Real wire format: `{"finish_reason":"\"stop\""}`
|
|
108
|
+
params = '{"finish_reason":"\\"stop\\""}'
|
|
109
|
+
self.assertEqual(render_dc._parse_finish_reason(params), "stop")
|
|
110
|
+
|
|
111
|
+
def test_returns_none_for_empty(self):
|
|
112
|
+
self.assertIsNone(render_dc._parse_finish_reason(None))
|
|
113
|
+
self.assertIsNone(render_dc._parse_finish_reason(""))
|
|
114
|
+
|
|
115
|
+
def test_returns_none_for_unparseable_json(self):
|
|
116
|
+
self.assertIsNone(render_dc._parse_finish_reason("<<<not json>>>"))
|
|
117
|
+
|
|
118
|
+
def test_returns_none_when_finish_reason_not_string(self):
|
|
119
|
+
params = '{"finish_reason": 42}'
|
|
120
|
+
self.assertIsNone(render_dc._parse_finish_reason(params))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# -----------------------------------------------------------------------------
|
|
124
|
+
# _decoded_line — tool-call JSON detection
|
|
125
|
+
# -----------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class DecodedLineTests(unittest.TestCase):
|
|
129
|
+
|
|
130
|
+
def test_returns_dash_for_empty(self):
|
|
131
|
+
self.assertEqual(render_dc._decoded_line(None), "—")
|
|
132
|
+
self.assertEqual(render_dc._decoded_line(""), "—")
|
|
133
|
+
|
|
134
|
+
def test_renders_quoted_truncated_text_for_plain_string(self):
|
|
135
|
+
out = render_dc._decoded_line("Hello world")
|
|
136
|
+
self.assertEqual(out, '"Hello world"')
|
|
137
|
+
|
|
138
|
+
def test_summarizes_tool_call_json(self):
|
|
139
|
+
# Real wire shape: HTML-escaped JSON with toolInvocations array.
|
|
140
|
+
body = (
|
|
141
|
+
'{"toolInvocations":[{'
|
|
142
|
+
'"function":{"name":"search_orders",'
|
|
143
|
+
'"arguments":"{\\"query\\":\\"refund\\"}"}}],'
|
|
144
|
+
'"content":"I will search for orders."}'
|
|
145
|
+
)
|
|
146
|
+
out = render_dc._decoded_line(body)
|
|
147
|
+
self.assertIn("1 tool call", out)
|
|
148
|
+
self.assertIn("search_orders", out)
|
|
149
|
+
self.assertIn("query=", out)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# -----------------------------------------------------------------------------
|
|
153
|
+
# Multi-turn fixture for mermaid branches
|
|
154
|
+
# -----------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _add_extra_turn_to_tree(tree: dict) -> None:
|
|
158
|
+
"""Mutate the assembled tree to have a 2nd TURN with a topic that
|
|
159
|
+
repeats — triggers both the sequence diagram and the topic flowchart.
|
|
160
|
+
"""
|
|
161
|
+
# Tag the existing turn with a topic
|
|
162
|
+
sess = tree["session"]
|
|
163
|
+
for iv in sess["interactions"]:
|
|
164
|
+
if iv["type"] == "TURN":
|
|
165
|
+
iv["topic"] = "Refunds"
|
|
166
|
+
# Inject a 2nd action step so sequence diagram passes its
|
|
167
|
+
# has_error/len(actions)>=2 gate.
|
|
168
|
+
iv["steps"].append({
|
|
169
|
+
"id": "step-extra-action",
|
|
170
|
+
"type": "ACTION_STEP",
|
|
171
|
+
"name": "ExtraAction",
|
|
172
|
+
"start_ts": "2026-04-22T10:00:42.000Z",
|
|
173
|
+
"end_ts": "2026-04-22T10:00:48.000Z",
|
|
174
|
+
"error_text": None,
|
|
175
|
+
"generation": None,
|
|
176
|
+
"gateway_request": None,
|
|
177
|
+
})
|
|
178
|
+
break
|
|
179
|
+
# Append a 2nd TURN that uses the same topic — triggers flowchart edges.
|
|
180
|
+
sess["interactions"].append({
|
|
181
|
+
"id": "ixn-turn-002b",
|
|
182
|
+
"type": "TURN",
|
|
183
|
+
"topic": "Refunds",
|
|
184
|
+
"trace_id": "trace-2nd",
|
|
185
|
+
"start_ts": "2026-04-22T10:01:05.000Z",
|
|
186
|
+
"end_ts": "2026-04-22T10:01:25.000Z",
|
|
187
|
+
"steps": [
|
|
188
|
+
{"id": "step-2a", "type": "ACTION_STEP",
|
|
189
|
+
"name": "ActionA",
|
|
190
|
+
"start_ts": "2026-04-22T10:01:08.000Z",
|
|
191
|
+
"end_ts": "2026-04-22T10:01:12.000Z",
|
|
192
|
+
"error_text": None,
|
|
193
|
+
"generation": None,
|
|
194
|
+
"gateway_request": None},
|
|
195
|
+
{"id": "step-2b", "type": "ACTION_STEP",
|
|
196
|
+
"name": "ActionB",
|
|
197
|
+
"start_ts": "2026-04-22T10:01:13.000Z",
|
|
198
|
+
"end_ts": "2026-04-22T10:01:18.000Z",
|
|
199
|
+
"error_text": "Action B failed: timeout",
|
|
200
|
+
"generation": None,
|
|
201
|
+
"gateway_request": None},
|
|
202
|
+
],
|
|
203
|
+
"messages": [
|
|
204
|
+
{"role": "USER", "text": "I want to escalate.", "ts": None},
|
|
205
|
+
{"role": "AGENT", "text": "Connecting you to a human.", "ts": None},
|
|
206
|
+
],
|
|
207
|
+
"tag_associations": [], "telemetry_spans": [],
|
|
208
|
+
"timestamp_bound_gateway_calls": [],
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class MultiTurnRenderTests(unittest.TestCase):
|
|
213
|
+
|
|
214
|
+
def _assemble_and_render(self, tree_mutator):
|
|
215
|
+
with TemporaryDirectory() as t:
|
|
216
|
+
tmp = Path(t)
|
|
217
|
+
sdir = write_to_disk(tmp)
|
|
218
|
+
with mock.patch.object(paths, "DATA_ROOT", tmp):
|
|
219
|
+
tree, _ = assemble_dc.assemble(IDS.SID)
|
|
220
|
+
tree_mutator(tree)
|
|
221
|
+
manifest = json.loads(
|
|
222
|
+
(sdir / "dc._session_manifest.json").read_text()
|
|
223
|
+
)
|
|
224
|
+
return render_dc.render(tree, manifest=manifest, session_dir=sdir)
|
|
225
|
+
|
|
226
|
+
def test_sequence_diagram_emitted_when_turn_has_two_actions(self):
|
|
227
|
+
md = self._assemble_and_render(_add_extra_turn_to_tree)
|
|
228
|
+
self.assertIn("sequenceDiagram", md)
|
|
229
|
+
self.assertIn("participant U as USER", md)
|
|
230
|
+
self.assertIn("participant P as Planner", md)
|
|
231
|
+
|
|
232
|
+
def test_topic_flowchart_emitted_when_topics_repeat(self):
|
|
233
|
+
md = self._assemble_and_render(_add_extra_turn_to_tree)
|
|
234
|
+
self.assertIn("flowchart LR", md)
|
|
235
|
+
self.assertIn("Refunds", md)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# -----------------------------------------------------------------------------
|
|
239
|
+
# Schema-version guard
|
|
240
|
+
# -----------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class SchemaVersionGuardTests(unittest.TestCase):
|
|
244
|
+
|
|
245
|
+
def test_render_refuses_unsupported_schema_version(self):
|
|
246
|
+
# _assert_schema_version reads session._schema_version (per impl).
|
|
247
|
+
bad_tree = {
|
|
248
|
+
"session": {"id": IDS.SID, "interactions": [], "_schema_version": 999},
|
|
249
|
+
}
|
|
250
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
251
|
+
render_dc.render(bad_tree)
|
|
252
|
+
self.assertIn("unsupported tree _schema_version", str(ctx.exception))
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
if __name__ == "__main__":
|
|
256
|
+
unittest.main()
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Tests for ``render_dc._render_gateway_direct``.
|
|
2
|
+
|
|
3
|
+
Feeds a gateway-direct tree (built by ``_assemble_gateway_direct``)
|
|
4
|
+
through the public ``render()`` entry point and asserts on the emitted
|
|
5
|
+
markdown. The intent is to pin the section contract without coupling to
|
|
6
|
+
exact whitespace:
|
|
7
|
+
|
|
8
|
+
- lag banner appears
|
|
9
|
+
- gateway chain table has the expected header
|
|
10
|
+
- one H4 per gateway_request_id in per-call detail
|
|
11
|
+
- per-call detail includes a fenced code block for the prompt
|
|
12
|
+
- Interaction-dependent sections are ABSENT (Hierarchical trace,
|
|
13
|
+
Per-turn summary, Transcript, Session counts)
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import unittest
|
|
18
|
+
|
|
19
|
+
from . import _bootstrap # noqa: F401 — sys.path setup
|
|
20
|
+
|
|
21
|
+
from assemble_dc import _assemble_gateway_direct # type: ignore
|
|
22
|
+
from render_dc import render # type: ignore
|
|
23
|
+
|
|
24
|
+
from .test_assemble_dc_gateway_direct import (
|
|
25
|
+
_SID,
|
|
26
|
+
_make_manifest,
|
|
27
|
+
_make_rows,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class RenderGatewayDirectTests(unittest.TestCase):
|
|
32
|
+
|
|
33
|
+
def setUp(self):
|
|
34
|
+
rows = _make_rows()
|
|
35
|
+
manifest = _make_manifest()
|
|
36
|
+
self.tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
|
|
37
|
+
# Opt into prompt rendering — these tests exercise the *content* of
|
|
38
|
+
# the per-call detail block, not the default-gating contract. The
|
|
39
|
+
# default-gating tests live in test_render_dc_show_prompts_gating.py.
|
|
40
|
+
self.md = render(self.tree, manifest, show_prompts=True)
|
|
41
|
+
|
|
42
|
+
def test_starts_with_session_heading(self):
|
|
43
|
+
self.assertTrue(self.md.startswith(f"# Session {_SID}"))
|
|
44
|
+
|
|
45
|
+
def test_lag_banner_present(self):
|
|
46
|
+
self.assertIn("STDM Interaction/Step/Message DMOs have not yet "
|
|
47
|
+
"materialized", self.md)
|
|
48
|
+
self.assertIn("Re-run in 24–72h", self.md)
|
|
49
|
+
|
|
50
|
+
def test_gateway_chain_table_header(self):
|
|
51
|
+
self.assertIn("| Model | Provider", self.md)
|
|
52
|
+
self.assertIn("Prompt tok", self.md)
|
|
53
|
+
self.assertIn("Response ts", self.md)
|
|
54
|
+
|
|
55
|
+
def test_h4_per_gateway_call(self):
|
|
56
|
+
"""3 fixture gateway_requests → 3 `#### LLM call N` headings."""
|
|
57
|
+
h4_count = self.md.count("#### LLM call ")
|
|
58
|
+
self.assertGreaterEqual(h4_count, 3)
|
|
59
|
+
|
|
60
|
+
def test_prompt_fenced_code_block(self):
|
|
61
|
+
"""Per-call detail wraps the prompt in a fenced code block."""
|
|
62
|
+
self.assertIn("```", self.md)
|
|
63
|
+
self.assertIn("This is the prompt body for gw-1.", self.md)
|
|
64
|
+
|
|
65
|
+
def test_no_hierarchical_trace_section(self):
|
|
66
|
+
self.assertNotIn("Hierarchical trace", self.md)
|
|
67
|
+
self.assertNotIn("Complete hierarchical trace", self.md)
|
|
68
|
+
|
|
69
|
+
def test_no_per_turn_summary_section(self):
|
|
70
|
+
self.assertNotIn("Per-turn summary", self.md)
|
|
71
|
+
|
|
72
|
+
def test_no_transcript_section(self):
|
|
73
|
+
self.assertNotIn("## Transcript", self.md)
|
|
74
|
+
|
|
75
|
+
def test_session_identity_section_present(self):
|
|
76
|
+
self.assertIn("## Session identity", self.md)
|
|
77
|
+
|
|
78
|
+
def test_prompt_with_triple_backticks_uses_longer_fence(self):
|
|
79
|
+
"""Prompts containing ``` must get a 4+-backtick fence.
|
|
80
|
+
|
|
81
|
+
LLM prompt templates commonly embed triple-backtick tool-use
|
|
82
|
+
examples. A hardcoded ``` fence would close early and corrupt
|
|
83
|
+
every section after the first such prompt.
|
|
84
|
+
"""
|
|
85
|
+
rows = _make_rows()
|
|
86
|
+
rows["gateway_requests"][0]["prompt__c"] = (
|
|
87
|
+
"See this example:\n"
|
|
88
|
+
"```python\n"
|
|
89
|
+
"print('hi')\n"
|
|
90
|
+
"```\n"
|
|
91
|
+
"End of example."
|
|
92
|
+
)
|
|
93
|
+
manifest = _make_manifest()
|
|
94
|
+
tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
|
|
95
|
+
md = render(tree, manifest, show_prompts=True)
|
|
96
|
+
self.assertIn("````", md) # 4-backtick fence
|
|
97
|
+
self.assertIn("print('hi')", md)
|
|
98
|
+
# The inner triple-backticks survive intact.
|
|
99
|
+
self.assertIn("```python", md)
|
|
100
|
+
|
|
101
|
+
def test_prompt_with_four_backticks_uses_five_backtick_fence(self):
|
|
102
|
+
"""Fence length scales with the longest inner run of backticks."""
|
|
103
|
+
rows = _make_rows()
|
|
104
|
+
rows["gateway_requests"][0]["prompt__c"] = (
|
|
105
|
+
"Edge case:\n````\nnested\n````\nDone."
|
|
106
|
+
)
|
|
107
|
+
manifest = _make_manifest()
|
|
108
|
+
tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
|
|
109
|
+
md = render(tree, manifest, show_prompts=True)
|
|
110
|
+
self.assertIn("`````", md) # 5-backtick fence
|
|
111
|
+
|
|
112
|
+
def test_prompt_truncation_marker_for_oversized_prompt(self):
|
|
113
|
+
"""Display-only 64 KB cap: prompts over the limit carry a truncation marker.
|
|
114
|
+
|
|
115
|
+
Raw JSON on disk is untouched — the cap only applies to markdown.
|
|
116
|
+
"""
|
|
117
|
+
rows = _make_rows()
|
|
118
|
+
# Inflate the first prompt to 80 KB of ASCII.
|
|
119
|
+
rows["gateway_requests"][0]["prompt__c"] = "x" * 80_000
|
|
120
|
+
manifest = _make_manifest()
|
|
121
|
+
tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
|
|
122
|
+
md = render(tree, manifest, show_prompts=True)
|
|
123
|
+
self.assertIn("[truncated; full prompt in dc.gateway_requests.json]", md)
|
|
124
|
+
# The on-tree prompt_text is still the full 80 KB — the cap is render-only.
|
|
125
|
+
self.assertEqual(len(tree["session"]["gateway_chain"][0]["prompt_text"]),
|
|
126
|
+
80_000)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
if __name__ == "__main__":
|
|
130
|
+
unittest.main()
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""Tests for ``render_dc`` pure-function helpers.
|
|
2
|
+
|
|
3
|
+
The renderer is large (863 stmts); covering its end-to-end markdown
|
|
4
|
+
output requires a complex tree fixture. These tests target the small,
|
|
5
|
+
pure helpers — they're cheap to test and account for ~150 stmts of the
|
|
6
|
+
gap.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import unittest
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
|
|
13
|
+
from . import _bootstrap # noqa: F401 — sys.path setup
|
|
14
|
+
|
|
15
|
+
import render_dc # type: ignore
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
# _parse_iso
|
|
20
|
+
# -----------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ParseIsoTests(unittest.TestCase):
|
|
24
|
+
|
|
25
|
+
def test_returns_none_for_falsy_input(self):
|
|
26
|
+
self.assertIsNone(render_dc._parse_iso(None))
|
|
27
|
+
self.assertIsNone(render_dc._parse_iso(""))
|
|
28
|
+
|
|
29
|
+
def test_parses_z_terminated(self):
|
|
30
|
+
self.assertEqual(
|
|
31
|
+
render_dc._parse_iso("2026-04-22T10:00:00Z"),
|
|
32
|
+
datetime(2026, 4, 22, 10, 0, 0, tzinfo=timezone.utc),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def test_returns_none_for_unparseable(self):
|
|
36
|
+
self.assertIsNone(render_dc._parse_iso("not-a-timestamp"))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# -----------------------------------------------------------------------------
|
|
40
|
+
# _fmt_offset
|
|
41
|
+
# -----------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class FmtOffsetTests(unittest.TestCase):
|
|
45
|
+
|
|
46
|
+
def test_returns_dash_when_timestamp_or_start_missing(self):
|
|
47
|
+
anchor = datetime(2026, 4, 22, 10, 0, 0, tzinfo=timezone.utc)
|
|
48
|
+
self.assertEqual(render_dc._fmt_offset(None, anchor), "—")
|
|
49
|
+
self.assertEqual(render_dc._fmt_offset("2026-04-22T10:00:00Z", None), "—")
|
|
50
|
+
|
|
51
|
+
def test_formats_offset_with_3_decimals(self):
|
|
52
|
+
anchor = datetime(2026, 4, 22, 10, 0, 0, tzinfo=timezone.utc)
|
|
53
|
+
out = render_dc._fmt_offset("2026-04-22T10:00:01.234Z", anchor)
|
|
54
|
+
self.assertEqual(out, "+1.234s")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# -----------------------------------------------------------------------------
|
|
58
|
+
# _fmt_duration_ms
|
|
59
|
+
# -----------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class FmtDurationMsTests(unittest.TestCase):
|
|
63
|
+
|
|
64
|
+
def test_dash_when_either_side_missing(self):
|
|
65
|
+
self.assertEqual(render_dc._fmt_duration_ms(None, "2026-04-22T10:00:00Z"), "—")
|
|
66
|
+
self.assertEqual(render_dc._fmt_duration_ms("2026-04-22T10:00:00Z", None), "—")
|
|
67
|
+
|
|
68
|
+
def test_returns_int_ms_with_unit(self):
|
|
69
|
+
out = render_dc._fmt_duration_ms(
|
|
70
|
+
"2026-04-22T10:00:00.000Z", "2026-04-22T10:00:00.123Z",
|
|
71
|
+
)
|
|
72
|
+
self.assertEqual(out, "123ms")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# -----------------------------------------------------------------------------
|
|
76
|
+
# _decode + _truncate
|
|
77
|
+
# -----------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class DecodeTruncateTests(unittest.TestCase):
|
|
81
|
+
|
|
82
|
+
def test_decode_unescapes_html_and_collapses_newlines(self):
|
|
83
|
+
self.assertEqual(render_dc._decode(""hi"\nthere"), '"hi" there')
|
|
84
|
+
|
|
85
|
+
def test_decode_returns_empty_for_falsy(self):
|
|
86
|
+
self.assertEqual(render_dc._decode(None), "")
|
|
87
|
+
self.assertEqual(render_dc._decode(""), "")
|
|
88
|
+
|
|
89
|
+
def test_truncate_pads_with_ellipsis_when_over_n(self):
|
|
90
|
+
long = "a" * 100
|
|
91
|
+
out = render_dc._truncate(long, n=10)
|
|
92
|
+
self.assertEqual(len(out), 10)
|
|
93
|
+
self.assertTrue(out.endswith("…"))
|
|
94
|
+
|
|
95
|
+
def test_truncate_returns_input_when_under_or_equal_n(self):
|
|
96
|
+
self.assertEqual(render_dc._truncate("short", n=10), "short")
|
|
97
|
+
|
|
98
|
+
def test_truncate_returns_dash_for_falsy(self):
|
|
99
|
+
self.assertEqual(render_dc._truncate(None), "—")
|
|
100
|
+
self.assertEqual(render_dc._truncate(""), "—")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# -----------------------------------------------------------------------------
|
|
104
|
+
# _short
|
|
105
|
+
# -----------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ShortTests(unittest.TestCase):
|
|
109
|
+
|
|
110
|
+
def test_returns_dash_for_falsy(self):
|
|
111
|
+
self.assertEqual(render_dc._short(None), "—")
|
|
112
|
+
self.assertEqual(render_dc._short(""), "—")
|
|
113
|
+
|
|
114
|
+
def test_truncates_long_uuid_with_ellipsis(self):
|
|
115
|
+
out = render_dc._short("019dface-0000-7000-8000-000000000001", keep=8)
|
|
116
|
+
self.assertEqual(out, "019dface…")
|
|
117
|
+
|
|
118
|
+
def test_returns_input_when_short(self):
|
|
119
|
+
self.assertEqual(render_dc._short("abc"), "abc")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# -----------------------------------------------------------------------------
|
|
123
|
+
# _fmt_total_duration — h / m / s rollover
|
|
124
|
+
# -----------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class FmtTotalDurationTests(unittest.TestCase):
|
|
128
|
+
|
|
129
|
+
def test_returns_none_when_either_side_missing(self):
|
|
130
|
+
self.assertIsNone(render_dc._fmt_total_duration(None, "2026-04-22T10:00:00Z"))
|
|
131
|
+
|
|
132
|
+
def test_seconds_only(self):
|
|
133
|
+
self.assertEqual(
|
|
134
|
+
render_dc._fmt_total_duration(
|
|
135
|
+
"2026-04-22T10:00:00.000Z", "2026-04-22T10:00:42.500Z",
|
|
136
|
+
),
|
|
137
|
+
"42.500s",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def test_minutes_and_seconds(self):
|
|
141
|
+
self.assertEqual(
|
|
142
|
+
render_dc._fmt_total_duration(
|
|
143
|
+
"2026-04-22T10:00:00Z", "2026-04-22T10:02:30Z",
|
|
144
|
+
),
|
|
145
|
+
"2m 30.000s",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def test_hours_minutes_seconds(self):
|
|
149
|
+
out = render_dc._fmt_total_duration(
|
|
150
|
+
"2026-04-22T10:00:00Z", "2026-04-22T11:30:45Z",
|
|
151
|
+
)
|
|
152
|
+
self.assertEqual(out, "1h 30m 45.000s")
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# -----------------------------------------------------------------------------
|
|
156
|
+
# _derive_session_end
|
|
157
|
+
# -----------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class DeriveSessionEndTests(unittest.TestCase):
|
|
161
|
+
|
|
162
|
+
def test_returns_session_end_ts_verbatim_when_present(self):
|
|
163
|
+
end, source = render_dc._derive_session_end(
|
|
164
|
+
{"end_ts": "2026-04-22T11:00:00Z", "interactions": []},
|
|
165
|
+
)
|
|
166
|
+
self.assertEqual(end, "2026-04-22T11:00:00Z")
|
|
167
|
+
self.assertIsNone(source)
|
|
168
|
+
|
|
169
|
+
def test_uses_session_end_interaction_start_ts(self):
|
|
170
|
+
sess = {
|
|
171
|
+
"end_ts": None,
|
|
172
|
+
"interactions": [
|
|
173
|
+
{"type": "TURN", "start_ts": "10:00", "end_ts": "10:01"},
|
|
174
|
+
{"type": "SESSION_END", "start_ts": "11:00:00Z"},
|
|
175
|
+
],
|
|
176
|
+
}
|
|
177
|
+
end, source = render_dc._derive_session_end(sess)
|
|
178
|
+
self.assertEqual(end, "11:00:00Z")
|
|
179
|
+
self.assertEqual(source, "from SESSION_END interaction")
|
|
180
|
+
|
|
181
|
+
def test_falls_back_to_last_turn_end_ts(self):
|
|
182
|
+
sess = {
|
|
183
|
+
"end_ts": None,
|
|
184
|
+
"interactions": [
|
|
185
|
+
{"type": "TURN", "start_ts": "10:00", "end_ts": "10:01"},
|
|
186
|
+
{"type": "TURN", "start_ts": "10:02", "end_ts": "10:03"},
|
|
187
|
+
],
|
|
188
|
+
}
|
|
189
|
+
end, source = render_dc._derive_session_end(sess)
|
|
190
|
+
self.assertEqual(end, "10:03")
|
|
191
|
+
self.assertEqual(source, "session still open (last TURN)")
|
|
192
|
+
|
|
193
|
+
def test_returns_none_pair_when_no_data(self):
|
|
194
|
+
end, source = render_dc._derive_session_end({"interactions": []})
|
|
195
|
+
self.assertIsNone(end)
|
|
196
|
+
self.assertIsNone(source)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# -----------------------------------------------------------------------------
|
|
200
|
+
# _compose_agent_cell
|
|
201
|
+
# -----------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class ComposeAgentCellTests(unittest.TestCase):
|
|
205
|
+
|
|
206
|
+
def test_full_identity_concatenated(self):
|
|
207
|
+
out = render_dc._compose_agent_cell({
|
|
208
|
+
"agent_api_name": "MyAgent",
|
|
209
|
+
"agent_version": "v3",
|
|
210
|
+
"agent_label": "My Agent",
|
|
211
|
+
"agent_type": "Internal",
|
|
212
|
+
})
|
|
213
|
+
self.assertEqual(out, "MyAgent v3 — My Agent (Internal)")
|
|
214
|
+
|
|
215
|
+
def test_only_api_name(self):
|
|
216
|
+
out = render_dc._compose_agent_cell({"agent_api_name": "MyAgent"})
|
|
217
|
+
self.assertEqual(out, "MyAgent")
|
|
218
|
+
|
|
219
|
+
def test_only_label(self):
|
|
220
|
+
out = render_dc._compose_agent_cell({"agent_label": "Display Only"})
|
|
221
|
+
self.assertEqual(out, "Display Only")
|
|
222
|
+
|
|
223
|
+
def test_returns_none_for_empty_identity(self):
|
|
224
|
+
self.assertIsNone(render_dc._compose_agent_cell({}))
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# -----------------------------------------------------------------------------
|
|
228
|
+
# _section_session_bootstrap — channel-aware NOT_SET wording
|
|
229
|
+
# -----------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class SectionSessionBootstrapNotSetWordingTests(unittest.TestCase):
|
|
233
|
+
"""`VariableText__c == NOT_SET` is a "no bootstrap variables" signal,
|
|
234
|
+
not a messaging-channel signal. Several non-messaging shapes (E&O
|
|
235
|
+
headless API, Atlas planner, generic API/integration) legitimately
|
|
236
|
+
produce NOT_SET — the rendered line must not call those "production
|
|
237
|
+
messaging path".
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
def _identity_with_no_bootstrap(self) -> dict:
|
|
241
|
+
# Sentinel: bootstrap_variables key is present and explicitly None
|
|
242
|
+
# (the assembler stamps None when VariableText__c is NOT_SET).
|
|
243
|
+
return {"bootstrap_variables": None}
|
|
244
|
+
|
|
245
|
+
def test_messaging_channel_keeps_messaging_path_addendum(self):
|
|
246
|
+
out = "\n".join(render_dc._section_session_bootstrap(
|
|
247
|
+
self._identity_with_no_bootstrap(),
|
|
248
|
+
channel="SCRT2 - EmbeddedMessaging",
|
|
249
|
+
))
|
|
250
|
+
self.assertIn("no bootstrap variables", out)
|
|
251
|
+
self.assertIn("production messaging path", out)
|
|
252
|
+
# Alias.
|
|
253
|
+
out2 = "\n".join(render_dc._section_session_bootstrap(
|
|
254
|
+
self._identity_with_no_bootstrap(),
|
|
255
|
+
channel="Messaging",
|
|
256
|
+
))
|
|
257
|
+
self.assertIn("production messaging path", out2)
|
|
258
|
+
|
|
259
|
+
def test_non_messaging_channel_omits_messaging_path(self):
|
|
260
|
+
# E&O is the wheelz that surfaced this bug — Atlas-planner
|
|
261
|
+
# session on the "E & O" channel was being mislabeled
|
|
262
|
+
# "production messaging path".
|
|
263
|
+
out = "\n".join(render_dc._section_session_bootstrap(
|
|
264
|
+
self._identity_with_no_bootstrap(),
|
|
265
|
+
channel="E & O",
|
|
266
|
+
))
|
|
267
|
+
self.assertIn("no bootstrap variables", out)
|
|
268
|
+
self.assertNotIn("production messaging path", out)
|
|
269
|
+
self.assertNotIn("messaging", out.lower())
|
|
270
|
+
|
|
271
|
+
def test_null_channel_uses_neutral_wording(self):
|
|
272
|
+
# No channel info at all — must not assume messaging.
|
|
273
|
+
out = "\n".join(render_dc._section_session_bootstrap(
|
|
274
|
+
self._identity_with_no_bootstrap(),
|
|
275
|
+
channel=None,
|
|
276
|
+
))
|
|
277
|
+
self.assertIn("no bootstrap variables", out)
|
|
278
|
+
self.assertNotIn("production messaging path", out)
|
|
279
|
+
|
|
280
|
+
def test_default_channel_kwarg_is_neutral(self):
|
|
281
|
+
# Backward-compat: callers that don't pass channel get the
|
|
282
|
+
# neutral wording, never the messaging-path label.
|
|
283
|
+
out = "\n".join(render_dc._section_session_bootstrap(
|
|
284
|
+
self._identity_with_no_bootstrap(),
|
|
285
|
+
))
|
|
286
|
+
self.assertIn("no bootstrap variables", out)
|
|
287
|
+
self.assertNotIn("production messaging path", out)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
if __name__ == "__main__":
|
|
291
|
+
unittest.main()
|