@salesforce/afv-skills 1.37.0 → 1.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/agentforce-generate/README.md +20 -3
- package/skills/agentforce-generate/SKILL.md +253 -440
- package/skills/agentforce-generate/assets/agent-spec-template.md +6 -2
- package/skills/agentforce-generate/assets/agents/order-service.agent +16 -12
- package/skills/agentforce-generate/assets/agents/production-faq.agent +4 -4
- package/skills/agentforce-generate/assets/agents/router-first.agent +5 -5
- package/skills/agentforce-generate/assets/agents/template-single-subagent.agent +4 -4
- package/skills/agentforce-generate/assets/agents/verification-gate.agent +8 -6
- package/skills/agentforce-generate/assets/agents/voice-knowledge-grounded.agent +9 -9
- package/skills/agentforce-generate/assets/agents/voice-service-agent.agent +7 -7
- package/skills/agentforce-generate/assets/patterns/README.md +3 -3
- package/skills/agentforce-generate/assets/patterns/action-callbacks.agent +5 -5
- package/skills/agentforce-generate/assets/patterns/advanced-input-bindings.agent +6 -8
- package/skills/agentforce-generate/assets/patterns/bidirectional-routing.agent +11 -13
- package/skills/agentforce-generate/assets/patterns/critical-input-collection.agent +11 -16
- package/skills/agentforce-generate/assets/patterns/lifecycle-events.agent +2 -3
- package/skills/agentforce-generate/assets/patterns/llm-controlled-actions.agent +6 -7
- package/skills/agentforce-generate/assets/patterns/open-gate-routing.agent +3 -3
- package/skills/agentforce-generate/assets/patterns/prompt-template-action.agent +14 -19
- package/skills/agentforce-generate/assets/patterns/system-instruction-overrides.agent +11 -20
- package/skills/agentforce-generate/references/actions-reference.md +2 -2
- package/skills/agentforce-generate/references/agent-audit-and-repair.md +135 -0
- package/skills/agentforce-generate/references/agent-audit-candidate-verification.md +160 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostic-catalog.md +156 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostics-actions-state.md +176 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostics-architecture-evaluation.md +68 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostics-instructions-routing.md +283 -0
- package/skills/agentforce-generate/references/agent-audit-evaluation-loop.md +191 -0
- package/skills/agentforce-generate/references/agent-audit-repair-report.md +143 -0
- package/skills/agentforce-generate/references/agent-audit-scope-path-review.md +180 -0
- package/skills/agentforce-generate/references/agent-design-and-spec-creation.md +105 -59
- package/skills/agentforce-generate/references/agent-script-core-language.md +144 -61
- package/skills/agentforce-generate/references/agent-subagent-map-diagrams.md +33 -23
- package/skills/agentforce-generate/references/agent-validation-and-debugging.md +37 -11
- package/skills/agentforce-generate/references/agentscript-toolchain.md +112 -0
- package/skills/agentforce-generate/references/architecture-patterns.md +81 -18
- package/skills/agentforce-generate/references/common-control-flow-pitfalls.md +255 -0
- package/skills/agentforce-generate/references/control-flow-actions-sequencing.md +198 -0
- package/skills/agentforce-generate/references/control-flow-lifecycle-side-effects.md +87 -0
- package/skills/agentforce-generate/references/examples.md +22 -22
- package/skills/agentforce-generate/references/instruction-resolution.md +123 -83
- package/skills/agentforce-generate/references/known-issues.md +1 -2
- package/skills/agentforce-generate/references/optimization-pattern-1-data-flow.md +4 -0
- package/skills/agentforce-generate/references/optimization-pattern-2-deterministic-logic.md +33 -0
- package/skills/agentforce-generate/references/optimization-pattern-3-reference-syntax.md +32 -3
- package/skills/agentforce-generate/references/optimization-pattern-4-escalation.md +2 -2
- package/skills/agentforce-generate/references/patterns-by-requirement.md +3 -1
- package/skills/agentforce-generate/references/posture-and-determinism.md +103 -22
- package/skills/agentforce-generate/references/reference-map.md +19 -3
- package/skills/agentforce-generate/references/scoring-rubric.md +1 -1
- package/skills/agentforce-generate/references/voice-latency-heuristics.md +4 -0
- package/skills/agentforce-generate/references/voice-modality-reference.md +4 -4
- package/skills/agentforce-generate/references/zen-of-agentscript.md +139 -23
- package/skills/agentforce-generate/scripts/agentscript-sdk-loader.mjs +133 -0
- package/skills/agentforce-generate/scripts/index-agent.mjs +141 -0
- package/skills/agentforce-generate/scripts/setup-agentscript-sdk.mjs +337 -0
- package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +1 -1
- package/skills/automation-sandbox-post-copy-configure/SKILL.md +433 -0
- package/skills/automation-sandbox-post-copy-configure/assets/api_request_templates.json +89 -0
- package/skills/automation-sandbox-post-copy-configure/examples/sample_config_input.json +40 -0
- package/skills/automation-sandbox-post-copy-configure/examples/sample_execution_summary.md +79 -0
- package/skills/automation-sandbox-post-copy-configure/references/api_endpoints.md +273 -0
- package/skills/automation-sandbox-post-copy-configure/references/authentication.md +94 -0
- package/skills/automation-sandbox-post-copy-configure/references/execution_phasing.md +93 -0
- package/skills/automation-sandbox-post-copy-configure/references/rules_gotchas.md +35 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/classify-patch-result.mjs +88 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/map-metadata-key.mjs +98 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/plan-phases.mjs +98 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/resolve-target-org.mjs +56 -0
- package/skills/design-systems-slds-validate/SKILL.md +14 -13
- package/skills/dx-code-analyzer-custom-rule-create/examples/xpath-examples.md +1 -1
- package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-security.md +1 -1
- package/skills/dx-org-devhub-configure/SKILL.md +268 -0
- package/skills/dx-org-devhub-configure/examples/status-output.md +39 -0
- package/skills/dx-org-devhub-configure/scripts/devhub.sh +650 -0
- package/skills/dx-org-devhub-configure/scripts/test-devhub.sh +116 -0
- package/skills/dx-org-manage/SKILL.md +135 -42
- package/skills/dx-org-manage/assets/derive-alias.sh +95 -0
- package/skills/dx-org-manage/assets/scratch-def.seed.json +6 -0
- package/skills/dx-org-manage/examples/README.md +1 -1
- package/skills/dx-org-manage/examples/scratch-orgs/delete_output.json +8 -0
- package/skills/dx-org-manage/examples/scratch-orgs/display_output.json +23 -0
- package/skills/dx-org-manage/examples/scratch-orgs/list_output.json +58 -0
- package/skills/dx-org-manage/examples/scratch-orgs/resume_output.json +38 -0
- package/skills/dx-org-manage/examples/scratch-orgs/success_definition_file.json +1 -1
- package/skills/dx-org-manage/examples/scratch-orgs/success_edition.json +1 -1
- package/skills/dx-org-manage/examples/scratch-orgs/success_shape.json +41 -0
- package/skills/dx-org-manage/examples/scratch-orgs/success_snapshot.json +1 -1
- package/skills/dx-org-manage/examples/snapshots/error_output.json +3 -3
- package/skills/dx-org-manage/references/creating-scratch-org.md +2 -2
- package/skills/dx-org-manage/references/creating-snapshot.md +1 -2
- package/skills/dx-org-manage/references/definition_file_options.md +24 -0
- package/skills/dx-org-manage/references/edition_types.md +10 -8
- package/skills/dx-org-manage/references/opening-org.md +11 -12
- package/skills/dx-org-manage/references/scratch-org-create.md +303 -0
- package/skills/dx-org-manage/references/scratch-org-operations.md +135 -0
- package/skills/experience-aura-lwc-migrate/SKILL.md +120 -0
- package/skills/experience-aura-lwc-migrate/references/aura-api-expert.md +170 -0
- package/skills/experience-aura-lwc-migrate/references/aura-data-expert.md +172 -0
- package/skills/experience-aura-lwc-migrate/references/aura-migration-guidelines.md +299 -0
- package/skills/experience-aura-lwc-migrate/references/aura-prd-framework.md +79 -0
- package/skills/experience-aura-lwc-migrate/references/aura-redundant-code-expert.md +24 -0
- package/skills/experience-aura-lwc-migrate/references/aura-reference-expert.md +140 -0
- package/skills/experience-aura-lwc-migrate/references/aura-resolver-expert.md +115 -0
- package/skills/experience-aura-lwc-migrate/references/aura-slots-expert.md +67 -0
- package/skills/experience-aura-lwc-migrate/references/aura-style-expert.md +62 -0
- package/skills/experience-aura-lwc-migrate/references/aura-to-lwc-completeness-checklist.md +188 -0
- package/skills/experience-aura-lwc-migrate/references/aura-values-expert.md +67 -0
- package/skills/experience-content-media-search/SKILL.md +17 -12
- package/skills/experience-content-media-stock-image-search/SKILL.md +192 -0
- package/skills/experience-content-media-stock-image-search/scripts/download-stock-image.py +102 -0
- package/skills/experience-lds-best-practices-apply/SKILL.md +245 -0
- package/skills/experience-lds-best-practices-apply/references/adapter-apis.md +1640 -0
- package/skills/experience-lds-best-practices-apply/references/lds-data-consistency.md +126 -0
- package/skills/experience-lds-best-practices-apply/references/lds-expert.md +429 -0
- package/skills/experience-lds-best-practices-apply/references/lds-referential-integrity.md +322 -0
- package/skills/experience-lds-best-practices-apply/references/wire-adapter-types.md +1511 -0
- package/skills/experience-lds-graphql-generate/SKILL.md +222 -0
- package/skills/experience-lds-graphql-generate/references/generation-guide.md +236 -0
- package/skills/experience-lds-graphql-generate/references/generation-mutation.md +277 -0
- package/skills/experience-lds-graphql-generate/references/generation-query.md +237 -0
- package/skills/experience-lds-graphql-generate/scripts/fetch-lds-graphql-schema.sh +230 -0
- package/skills/experience-lds-graphql-generate/scripts/test-lds-graphql-query.sh +128 -0
- package/skills/experience-lwc-accessibility-validate/SKILL.md +112 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +88 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +52 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +106 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +78 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +26 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +66 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +70 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +115 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +47 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +39 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +50 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +54 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +49 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +77 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +45 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +55 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +51 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +84 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +50 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +64 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +105 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +99 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +97 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-1-1-non-text-content.md +83 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-1-use-of-color.md +62 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-10-resize-reflow.md +18 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-11-non-text-contrast.md +43 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-3-contrast.md +25 -0
- package/skills/experience-lwc-accessibility-validate/scripts/contrast-ratio.py +153 -0
- package/skills/experience-lwc-design-generate/SKILL.md +261 -0
- package/skills/experience-lwc-design-generate/references/figma-to-prd-blueprint.md +66 -0
- package/skills/experience-lwc-design-generate/references/prd-analysis-template.md +17 -0
- package/skills/experience-lwc-design-generate/scripts/check-component-name.sh +75 -0
- package/skills/experience-lwc-design-generate/scripts/detect-project-tools.sh +97 -0
- package/skills/experience-lwc-runtime-observe/SKILL.md +244 -0
- package/skills/experience-lwc-runtime-observe/examples/component-preview-and-dom.md +41 -0
- package/skills/experience-lwc-runtime-observe/scripts/extract-dom.sh +79 -0
- package/skills/experience-lwc-runtime-observe/scripts/open-frontdoor.sh +46 -0
- package/skills/experience-lwc-runtime-observe/scripts/verify-toolchain.sh +48 -0
- package/skills/experience-lwc-security-validate/SKILL.md +151 -0
- package/skills/experience-lwc-security-validate/examples/review-report.md +6 -0
- package/skills/experience-lwc-security-validate/examples/score-report.sarif.json +32 -0
- package/skills/experience-lwc-security-validate/references/lws-security-expert.md +986 -0
- package/skills/experience-lwc-security-validate/references/security-analysis.md +611 -0
- package/skills/experience-lwc-security-validate/scripts/check-lwc-import.sh +166 -0
- package/skills/experience-lwc-security-validate/scripts/validate-sarif.sh +131 -0
- package/skills/experience-ui-bundle-2gp-deploy/SKILL.md +454 -0
- package/skills/experience-ui-bundle-2gp-deploy/assets/CustomApplication.app-meta.xml +12 -0
- package/skills/experience-ui-bundle-2gp-deploy/assets/PermissionSet.permissionset-meta.xml +9 -0
- package/skills/experience-ui-bundle-2gp-deploy/scripts/find-bundle-package-dir.sh +53 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/SKILL.md +104 -26
- package/skills/experience-ui-bundle-agentforce-client-generate/references/constraints.md +35 -24
- package/skills/experience-ui-bundle-agentforce-client-generate/references/examples.md +92 -1
- package/skills/experience-ui-bundle-agentforce-client-generate/references/style-tokens.md +2 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/references/troubleshooting.md +14 -1
- package/skills/experience-ui-bundle-agentforce-client-generate/scripts/detect-framework.sh +67 -0
- package/skills/experience-ui-bundle-deploy/SKILL.md +83 -14
- package/skills/experience-ui-bundle-deploy/assets/Communities.settings-meta.xml +19 -0
- package/skills/experience-ui-bundle-deploy/assets/org-setup.config.template.json +5 -0
- package/skills/experience-ui-bundle-deploy/assets/social-login-auth-providers.apex +158 -0
- package/skills/experience-ui-bundle-deploy/references/config-scaffold.md +13 -1
- package/skills/experience-ui-bundle-deploy/references/social-login.md +179 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +14 -0
- package/skills/experience-ui-bundle-mfa-configure/SKILL.md +6 -5
- package/skills/experience-ui-bundle-mfa-configure/references/social-login.md +15 -7
- package/skills/experience-ui-bundle-salesforce-data-access/SKILL.md +41 -5
- package/skills/experience-ui-bundle-salesforce-data-access/references/caching.md +10 -22
- package/skills/experience-ui-bundle-salesforce-data-access/references/graphql-hand-authoring.md +4 -19
- package/skills/experience-ui-bundle-salesforce-data-access/references/migration.md +5 -0
- package/skills/experience-ui-bundle-salesforce-data-access/references/sdk-api.md +33 -150
- package/skills/mobile-platform-native-capabilities-integrate/references/nfc.md +35 -0
- package/skills/platform-apex-generate/SKILL.md +8 -7
- package/skills/platform-apex-test-generate/SKILL.md +3 -1
- package/skills/platform-apex-test-run/SKILL.md +9 -8
- package/skills/platform-lightning-type-widget-coordinate/SKILL.md +1 -1
- package/skills/platform-lightning-type-widget-coordinate/examples/existing-lightning-type-with-widget-prompt.md +1 -1
- package/skills/platform-lightning-type-widget-coordinate/examples/new-lightning-type-with-widget-prompt.md +1 -1
- package/skills/platform-lightning-type-widget-coordinate/references/validation-gates.md +3 -3
- package/skills/platform-mcp-tool-widget-coordinate/SKILL.md +43 -67
- package/skills/platform-mcp-tool-widget-coordinate/examples/action-name-source-prompt.md +1 -2
- package/skills/platform-mcp-tool-widget-coordinate/examples/apex-invocable-source-prompt.md +2 -3
- package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-list-source-prompt.md +163 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-single-source-prompt.md +198 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/pasted-tool-output-prompt.md +0 -1
- package/skills/platform-mcp-tool-widget-coordinate/references/build-plan-format.md +17 -11
- package/skills/platform-mcp-tool-widget-coordinate/references/mcp-tool-output-discovery.md +48 -15
- package/skills/platform-mcp-tool-widget-coordinate/references/two-clt-modeling.md +73 -10
- package/skills/platform-mcp-tool-widget-coordinate/references/validation-gates.md +48 -8
- package/skills/platform-policy-rule-generate/SKILL.md +22 -12
- package/skills/platform-policy-rule-generate/references/deploy-errors.md +1 -1
- package/skills/platform-policy-rule-generate/references/policy-schema-full.md +8 -29
- package/skills/platform-policy-rule-generate/references/templates-advanced.md +1 -1
- package/skills/platform-sharing-owd-configure/SKILL.md +20 -8
- package/skills/platform-sharing-owd-configure/references/access_levels.md +14 -1
- package/skills/platform-sharing-rules-generate/SKILL.md +67 -35
- package/skills/platform-sharing-rules-generate/examples/create-cases.md +16 -17
- package/skills/platform-sharing-rules-generate/examples/delete-cases.md +34 -79
- package/skills/platform-sharing-rules-generate/examples/edit-cases.md +13 -26
- package/skills/platform-sharing-rules-generate/scripts/count-remaining-rules.sh +33 -0
- package/skills/platform-widget-generate/SKILL.md +3 -5
- package/skills/platform-widget-generate/examples/conditional.json +18 -13
- package/skills/platform-widget-generate/examples/list-with-foreach.json +2 -2
- package/skills/platform-widget-generate/examples/single-object.json +2 -2
- package/skills/platform-widget-generate/references/schema-from-lightning-type.md +27 -6
- package/skills/platform-widget-generate/references/widget-bundle-layout.md +4 -3
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +287 -0
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +260 -0
- package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +252 -0
- package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/references/mcp-invocation.md +204 -0
- package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +259 -0
- package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +188 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +197 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +77 -0
- package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +316 -0
- package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/references/mcp-invocation.md +221 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +168 -0
- package/skills/service-itsm-incident-priority-configure/examples/matrix-operations.md +200 -0
- package/skills/service-itsm-incident-priority-configure/examples/render-matrix.md +54 -0
- package/skills/service-itsm-incident-priority-configure/examples/seed-full-matrix.md +52 -0
- package/skills/service-itsm-incident-priority-configure/references/sf-cli-invocation.md +264 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-source-prompt.md +0 -191
- package/skills/platform-policy-rule-generate/references/fixtures-index.md +0 -29
package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-single-source-prompt.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Example: single nested-object payload field, discovered from the IA describe
|
|
2
|
+
|
|
3
|
+
A complete walkthrough for the case where an Invocable Action output is itself **another Apex class** —
|
|
4
|
+
a **single nested object** (`maxOccurs: 1`). **The Invocable Action (IA) describe is the source of
|
|
5
|
+
truth**; the Apex class is read only to enumerate the referenced class's own leaf fields. This is the
|
|
6
|
+
second, additive payload shape alongside the flat-primitive shape in `apex-invocable-source-prompt.md` —
|
|
7
|
+
read `references/mcp-tool-output-discovery.md` ("Nested-object and list payload fields") and
|
|
8
|
+
`references/two-clt-modeling.md` ("Nested-object and list payload fields") first. The **list** shapes
|
|
9
|
+
(top-level list, list-inside-wrapper) are in the companion example `nested-object-list-source-prompt.md`.
|
|
10
|
+
|
|
11
|
+
> **The skill never modifies the Apex.** The describe's `apexClass` + `maxOccurs` tell you the shape;
|
|
12
|
+
> reading the referenced class is a read-only enumeration step, not a reshape.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Single nested object (`maxOccurs: 1`)
|
|
17
|
+
|
|
18
|
+
### The prompt
|
|
19
|
+
|
|
20
|
+
> I have an MCP server tool backed by the `GetFlightDetailsAction` Apex invocable action. Build a
|
|
21
|
+
> widget that renders its output as a flight details card.
|
|
22
|
+
|
|
23
|
+
### Phase 1 — Input selection
|
|
24
|
+
|
|
25
|
+
- Source: `action` — the prompt names an Apex Invocable, so describe it through the Actions REST API
|
|
26
|
+
(`/services/data/v<APIVER>/actions/custom/apex/GetFlightDetailsAction`). This is the source of truth
|
|
27
|
+
for the output shape; the `.cls` is read later only to enumerate the referenced class's leaves.
|
|
28
|
+
- Tool API name: `getFlightDetails` (from the class name `GetFlightDetailsAction`, stripping the
|
|
29
|
+
trailing `Action` suffix and lower-camelCasing — see the naming convention in
|
|
30
|
+
`references/two-clt-modeling.md`).
|
|
31
|
+
|
|
32
|
+
### Phase 2 — Payload discovery (from the describe)
|
|
33
|
+
|
|
34
|
+
The Actions describe returns a scalar sibling alongside the single nested-object output:
|
|
35
|
+
|
|
36
|
+
```jsonc
|
|
37
|
+
// GET /services/data/v67.0/actions/custom/apex/GetFlightDetailsAction → .outputs[]
|
|
38
|
+
[
|
|
39
|
+
{ "name": "searchStatus", "type": "STRING", "maxOccurs": 1 },
|
|
40
|
+
{ "name": "flightInfo", "type": null, "apexClass": "SearchFlightsAction$Flight", "maxOccurs": 1 }
|
|
41
|
+
]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- `searchStatus` is a **flat primitive** (`STRING`) → `lightning__textType`, bound two segments deep. Flat scalars and a single nested object coexist in one response; handle each per its own branch.
|
|
45
|
+
- `flightInfo`: `type: null` + `apexClass` set + `maxOccurs: 1` = a **single nested object** (not a describe gap, not a list).
|
|
46
|
+
- The nested output's own leaf fields are **not** in the describe. Read the named class
|
|
47
|
+
(`SearchFlightsAction.Flight`) and enumerate its **public / `@AuraEnabled`** members — an
|
|
48
|
+
inner/referenced class is not gated by `@InvocableVariable` (that gates only the top-level response
|
|
49
|
+
class). These become the widget's flat leaf properties. **Never ignore any property.**
|
|
50
|
+
|
|
51
|
+
```apex
|
|
52
|
+
public class Flight {
|
|
53
|
+
@InvocableVariable public String flightId;
|
|
54
|
+
@InvocableVariable public String origin;
|
|
55
|
+
@InvocableVariable public String destination;
|
|
56
|
+
@InvocableVariable public String departureTime;
|
|
57
|
+
@InvocableVariable public String arrivalTime;
|
|
58
|
+
@InvocableVariable public Long price;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
| Leaf field | Apex type | widget `lightning:type` |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| flightId | String | `lightning__textType` |
|
|
65
|
+
| origin | String | `lightning__textType` |
|
|
66
|
+
| destination | String | `lightning__textType` |
|
|
67
|
+
| departureTime | String | `lightning__textType` |
|
|
68
|
+
| arrivalTime | String | `lightning__textType` |
|
|
69
|
+
| price | Long | `lightning__numberType` |
|
|
70
|
+
|
|
71
|
+
`payloadFields` (from describe) = 2 fields: `searchStatus` (flat `STRING`) + `flightInfo` (Apex-class-typed → nested-object branch).
|
|
72
|
+
`payloadFields` (flattened, for the widget) = `searchStatus` + the 6 leaf rows above (7 total).
|
|
73
|
+
|
|
74
|
+
### Phase 3 — Build plan (abridged)
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
MCP Tool Widget Build Plan: getFlightDetailsWidget
|
|
78
|
+
|
|
79
|
+
PLAN: Render the GetFlightDetails MCP tool output as a flight-details card.
|
|
80
|
+
|
|
81
|
+
TOOL / SOURCE:
|
|
82
|
+
Tool API name: getFlightDetails
|
|
83
|
+
Payload source: Actions describe of Apex Invocable GetFlightDetailsAction
|
|
84
|
+
Outputs: searchStatus (STRING, maxOccurs 1 → flat scalar) + flightInfo (apexClass SearchFlightsAction$Flight, maxOccurs 1 → single nested object)
|
|
85
|
+
|
|
86
|
+
LIGHTNING TYPES:
|
|
87
|
+
Response CLT: getFlightDetailsResponse
|
|
88
|
+
Properties: searchStatus → "lightning__textType"; flightInfo → "@apexClassType/c__SearchFlightsAction$Flight" # nested-object field, NOT {"type":"object"}
|
|
89
|
+
Envelope CLT: getFlightDetails
|
|
90
|
+
Renderer (default, bundle root): .../lightningTypes/getFlightDetails/renderer.json
|
|
91
|
+
Envelope: actionName (text), isSuccess (boolean), outputValues (c__getFlightDetailsResponse)
|
|
92
|
+
|
|
93
|
+
WIDGET: getFlightDetailsWidget
|
|
94
|
+
Schema: searchStatus (flat scalar) + flightInfo's 6 leaf fields (flightId, origin, destination, departureTime, arrivalTime, price)
|
|
95
|
+
Renderer binding: searchStatus → {!$attrs.outputValues.searchStatus} (two segments); each flightInfo leaf → {!$attrs.outputValues.flightInfo.<leaf>} (three segments)
|
|
96
|
+
|
|
97
|
+
GENERATION ORDER: response CLT → widget → envelope CLT
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Proceed unless the next reply pushes back.
|
|
101
|
+
|
|
102
|
+
### Phase 4 — Generation order
|
|
103
|
+
|
|
104
|
+
1. **Response CLT** `getFlightDetailsResponse`:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"title": "Get Flight Details Response",
|
|
109
|
+
"description": "Response fields from the GetFlightDetailsAction invocable-action (FlightDetailsResponse)",
|
|
110
|
+
"type": "object",
|
|
111
|
+
"lightning:type": "lightning__objectType",
|
|
112
|
+
"lightning:tags": ["mcp"],
|
|
113
|
+
"unevaluatedProperties": false,
|
|
114
|
+
"properties": {
|
|
115
|
+
"searchStatus": {
|
|
116
|
+
"title": "Search Status",
|
|
117
|
+
"lightning:type": "lightning__textType"
|
|
118
|
+
},
|
|
119
|
+
"flightInfo": {
|
|
120
|
+
"title": "Flight Info",
|
|
121
|
+
"lightning:type": "@apexClassType/c__SearchFlightsAction$Flight"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
2. **Widget** `getFlightDetailsWidget` — flat schema over `searchStatus` + the 6 leaf fields (not the
|
|
128
|
+
single `flightInfo` field); body binds `{!$attrs.searchStatus}`, `{!$attrs.flightId}`,
|
|
129
|
+
`{!$attrs.origin}`, etc.
|
|
130
|
+
|
|
131
|
+
3. **Envelope CLT** `getFlightDetails`:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"title": "Get Flight Details",
|
|
136
|
+
"description": "Invocable-action result envelope for the GetFlightDetailsAction MCP tool",
|
|
137
|
+
"type": "object",
|
|
138
|
+
"lightning:type": "lightning__objectType",
|
|
139
|
+
"lightning:tags": ["mcp"],
|
|
140
|
+
"unevaluatedProperties": false,
|
|
141
|
+
"properties": {
|
|
142
|
+
"actionName": { "title": "Action Name", "lightning:type": "lightning__textType" },
|
|
143
|
+
"isSuccess": { "title": "Is Success", "lightning:type": "lightning__booleanType" },
|
|
144
|
+
"outputValues": { "title": "Output Values", "lightning:type": "c__getFlightDetailsResponse" }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
4. **Default renderer** at `lightningTypes/getFlightDetails/renderer.json` —
|
|
150
|
+
`definition: @widget/c/getFlightDetailsWidget`, each attribute bound three segments deep through
|
|
151
|
+
the nested object:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"renderer": {
|
|
156
|
+
"componentOverrides": {
|
|
157
|
+
"$": {
|
|
158
|
+
"definition": "@widget/c/getFlightDetailsWidget",
|
|
159
|
+
"attributes": {
|
|
160
|
+
"searchStatus": "{!$attrs.outputValues.searchStatus}",
|
|
161
|
+
"flightId": "{!$attrs.outputValues.flightInfo.flightId}",
|
|
162
|
+
"origin": "{!$attrs.outputValues.flightInfo.origin}",
|
|
163
|
+
"destination": "{!$attrs.outputValues.flightInfo.destination}",
|
|
164
|
+
"departureTime": "{!$attrs.outputValues.flightInfo.departureTime}",
|
|
165
|
+
"arrivalTime": "{!$attrs.outputValues.flightInfo.arrivalTime}",
|
|
166
|
+
"price": "{!$attrs.outputValues.flightInfo.price}"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Phase 5 — Validation
|
|
175
|
+
|
|
176
|
+
- `clt-reference-integrity`: envelope `outputValues` → `c__getFlightDetailsResponse`, response CLT
|
|
177
|
+
exists, `searchStatus` is a primitive `lightning__textType`, `flightInfo` uses
|
|
178
|
+
`@apexClassType/c__SearchFlightsAction$Flight` (not a bare `{"type":"object"}`, not an inlined
|
|
179
|
+
`lightning__objectType`), no `$schema`/`items` → **pass**. PROP_GROUNDING: both trace to describe outputs → **ok**.
|
|
180
|
+
- `renderer-wires-widget`: bundle-root renderer present, definition `@widget/c/getFlightDetailsWidget`,
|
|
181
|
+
`searchStatus` bound two segments, every `flightInfo` leaf bound three segments as
|
|
182
|
+
`{!$attrs.outputValues.flightInfo.<property>}` (not two, which would bind to an unresolvable object) → **pass**.
|
|
183
|
+
- `field-trace`: `searchStatus` (primitive) compares directly; `flightInfo` resolves to
|
|
184
|
+
`@apexClassType/...` and expands to its class's leaves before comparing. INVOCABLE_FIELDS (expanded)
|
|
185
|
+
= `searchStatus, flightId, origin, destination, departureTime, arrivalTime, price`. Widget properties
|
|
186
|
+
match exactly; INVENTED empty; OMITTED empty → **pass**.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Notes
|
|
191
|
+
|
|
192
|
+
- **Why not a single-level opaque object.** Typing an Apex-class-typed field as `{"type":"object"}`
|
|
193
|
+
produces an opaque blob with no leaf fields — not renderable. The
|
|
194
|
+
`@apexClassType/<ns>__<OuterClass>$<InnerClass>` reference is what actually deploys.
|
|
195
|
+
- **This is additive, not a replacement.** A response of all primitives still uses the flat mapping
|
|
196
|
+
tables unchanged. Check each field independently — outputs can mix primitive and Apex-class-typed fields.
|
|
197
|
+
- **List shapes are separate.** A top-level list output or a list nested inside a wrapper is covered in
|
|
198
|
+
`nested-object-list-source-prompt.md`.
|
|
@@ -20,11 +20,14 @@ LIGHTNING TYPES (two object-based CLTs of equal standing — named for what each
|
|
|
20
20
|
Name: <responseCLT> # convention: <toolApiName>Response
|
|
21
21
|
Path: <pkgDir>/lightningTypes/<responseCLT>/schema.json
|
|
22
22
|
Properties: <field: lightning:type, ...> # 1:1 with response @InvocableVariable fields
|
|
23
|
+
Nested/list fields: <objectField: @apexClassType/c__<Outer>$<Inner>, ... — or "none">
|
|
24
|
+
# A single nested object is one @apexClassType property; a List<ApexClass> rides INSIDE an
|
|
25
|
+
# @apexClassType object (the CLT carries no lightning__listType — the list surfaces in the widget schema).
|
|
23
26
|
Envelope CLT:
|
|
24
27
|
Name: <toolCLT> # convention: <toolApiName>
|
|
25
28
|
Path: <pkgDir>/lightningTypes/<toolCLT>/schema.json
|
|
26
29
|
Renderer (default, at bundle root — wires the widget): <pkgDir>/lightningTypes/<toolCLT>/renderer.json
|
|
27
|
-
Envelope properties: actionName (text), isSuccess (boolean), outputValues (c__<responseCLT>)
|
|
30
|
+
Envelope properties: actionName (text), isSuccess (boolean), outputValues (c__<responseCLT>) # exactly these three — no others
|
|
28
31
|
|
|
29
32
|
WIDGET:
|
|
30
33
|
Name: <widgetName> # convention: <toolApiName>Widget
|
|
@@ -33,12 +36,11 @@ WIDGET:
|
|
|
33
36
|
<pkgDir>/uiWidgets/<widgetName>/schema.json
|
|
34
37
|
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml
|
|
35
38
|
Schema source: derived from the response field list (name + primitive type) — a standalone contract, not tied to any Lightning Type
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
#
|
|
41
|
-
# (operational/status indicators, not display data) — each needs its own one-line rationale, not just the field name.
|
|
39
|
+
List fields: <listField: element class @apexClassType/c__<Outer>$<Inner> — or "none"> # widget schema/body authored by platform-widget-generate
|
|
40
|
+
Renderer binding: primitive → {!$attrs.outputValues.<field>}; nested-object leaf → {!$attrs.outputValues.<objectField>.<leaf>};
|
|
41
|
+
list → {!$attrs.outputValues.<listField>} (top-level) or {!$attrs.outputValues.<wrapperField>.<listField>} (list inside wrapper)
|
|
42
|
+
Layout intent: <one-line description of the widget composition, incl. how lists are rendered>
|
|
43
|
+
# actionName/isSuccess are envelope-only fields (on the envelope CLT) and never widget candidates.
|
|
42
44
|
|
|
43
45
|
SUB-SKILLS THAT WILL RUN:
|
|
44
46
|
platform-custom-lightning-type-generate (response CLT, then envelope CLT)
|
|
@@ -52,11 +54,16 @@ VALIDATIONS THAT WILL RUN AFTER GENERATION:
|
|
|
52
54
|
- every {!$attrs.X} resolves to a widget schema property
|
|
53
55
|
- <name>.uiwidget-meta.xml is well-formed, root <UiWidgetBundle>, declares <widgetType>JSON</widgetType>
|
|
54
56
|
Cross-skill checks (run by this orchestrator):
|
|
55
|
-
- clt-reference-integrity: envelope CLT outputValues → c__<responseCLT>; response CLT exists; no $schema/items
|
|
57
|
+
- clt-reference-integrity: envelope CLT outputValues → c__<responseCLT>; response CLT exists; no $schema/items;
|
|
58
|
+
non-primitive response fields typed @apexClassType (no CLT-level lightning__listType — lists ride inside the object)
|
|
56
59
|
- renderer-wires-widget: envelope CLT renderer.json (bundle root) references the widget via @widget/c/<widgetName>,
|
|
57
|
-
binding every widget property
|
|
60
|
+
binding every widget property under outputValues ({!$attrs.outputValues.<property>}, or
|
|
61
|
+
{!$attrs.outputValues.<objectField>.<leaf|listField>} for nested/list fields)
|
|
62
|
+
- nested-list-coverage: every nested-object and list field discovered in Phase 2 is rendered by the widget
|
|
63
|
+
(authored by platform-widget-generate) and bound in the renderer at the correct depth. A discovered
|
|
64
|
+
nested/list field that is absent FAILS ("out of scope" / "beta single-response" are not valid drop rationales).
|
|
58
65
|
- field-trace (advisory): print response @InvocableVariable fields and widget schema properties; print the diff.
|
|
59
|
-
Invented widget fields fail;
|
|
66
|
+
Invented widget fields fail; a response data field absent from the widget warns.
|
|
60
67
|
|
|
61
68
|
GENERATION ORDER: response CLT → widget → envelope CLT (response CLT must exist before the envelope CLT references it).
|
|
62
69
|
|
|
@@ -70,5 +77,4 @@ Proceeding unless you push back (reply "no", "stop", "change X"). The plan above
|
|
|
70
77
|
|
|
71
78
|
- If the user replies with edits or declines, revise the plan and reprint. Do not assume which sections changed.
|
|
72
79
|
- Approval applies only to the plan as printed. A later request for another tool starts a new planning cycle.
|
|
73
|
-
- "Properties omitted" makes intentional drops explicit — e.g. `status`, `message`, internal IDs that do not belong on the render surface.
|
|
74
80
|
- If the payload source is a pasted sample that nests under `outputValues.data`, record that extra level here — it changes the response CLT and every renderer binding to `{!$attrs.outputValues.data.<field>}`.
|
|
@@ -55,8 +55,8 @@ The describe response has an `outputs` array. Each entry describes one payload f
|
|
|
55
55
|
|
|
56
56
|
- **Use `outputs` only.** `inputs` is the tool input (the request wrapper) — exclude it, exactly as `apex` excludes the request class.
|
|
57
57
|
- `name` → the CLT/widget property key. `label` → the property `title`.
|
|
58
|
-
- A field with `maxOccurs > 1` is a **collection** (list)
|
|
59
|
-
- An entry with **`"type": null` and an `"apexClass"` key instead** (e.g. `{ "name": "flightInfo", "type": null, "apexClass": "SearchFlightsAction$Flight", "maxOccurs": 1 }`) is **not missing data to default to text** — it is the describe's encoding for a field typed as another Apex class. `$` separates the outer class from the inner class, matching the `@apexClassType/<ns>__<OuterClass>$<InnerClass>` convention used elsewhere in this skill. This is the same
|
|
58
|
+
- A field with `maxOccurs > 1` is a **collection** (list) — it is in scope, not out of scope. If its `apexClass` is set (a list of nested objects) or its `type` is a primitive (a list of scalars), render it as a collection per "Nested-object and list payload fields" below; never drop it silently. (The `content[]` beta single-response limit is about rendering one tool *result*, not about list *fields* inside that result.)
|
|
59
|
+
- An entry with **`"type": null` and an `"apexClass"` key instead** (e.g. `{ "name": "flightInfo", "type": null, "apexClass": "SearchFlightsAction$Flight", "maxOccurs": 1 }`) is **not missing data to default to text** — it is the describe's encoding for a field typed as another Apex class. `$` separates the outer class from the inner class, matching the `@apexClassType/<ns>__<OuterClass>$<InnerClass>` convention used elsewhere in this skill. This is the same nested-object / list-of-objects case as from the other two sources — see "Nested-object and list payload fields" below (`maxOccurs: 1` → single object; `maxOccurs > 1` → list of that object); the Actions REST API describe never exposes that class's own leaf fields, so retrieving/reading the Apex class named in `apexClass` (via `apex` §1/§3) is the correct next step, not a fallback away from `action`.
|
|
60
60
|
|
|
61
61
|
Extract the field list with `jq` (do NOT wrap in `$()`):
|
|
62
62
|
|
|
@@ -156,29 +156,62 @@ If the grep misses multi-line annotations, read the `.cls` with the Read tool an
|
|
|
156
156
|
|
|
157
157
|
---
|
|
158
158
|
|
|
159
|
-
## Nested-object payload fields (applies to every source above)
|
|
159
|
+
## Nested-object and list payload fields (applies to every source above)
|
|
160
160
|
|
|
161
|
-
The mapping tables above (Actions-API `type`, Apex type, JSON value/schema `type`) cover **primitive** fields. A field can also be typed as **another Apex class**
|
|
161
|
+
The mapping tables above (Actions-API `type`, Apex type, JSON value/schema `type`) cover **primitive** fields. A field can also be typed as **another Apex class** — as a single object or as a list of them. Both are in scope; check every payload field against both branches, regardless of which of the three sources produced the field list. Detect a nested/list field by source:
|
|
162
162
|
|
|
163
|
-
- **Actions API**: an output entry with `"type": null` and an `"apexClass": "<OuterClass>$<InnerClass>"` key, rather than a primitive `STRING`/`INTEGER`/etc. `type` (see step 3 above).
|
|
164
|
-
- **`apex`**: an `@InvocableVariable` field whose declared type is not `String`/`Id`/`Integer`/`Long`/`Decimal`/`Double`/`Boolean`/`Date`/`Datetime`
|
|
165
|
-
- **`sample`**: a property whose JSON value/schema `type` is `"object"` (
|
|
163
|
+
- **Actions API**: an output entry with `"type": null` and an `"apexClass": "<OuterClass>$<InnerClass>"` key, rather than a primitive `STRING`/`INTEGER`/etc. `type` (see step 3 above). `maxOccurs: 1` → single object; `maxOccurs > 1` → list of that object.
|
|
164
|
+
- **`apex`**: an `@InvocableVariable` field whose declared type is not `String`/`Id`/`Integer`/`Long`/`Decimal`/`Double`/`Boolean`/`Date`/`Datetime` — either another Apex class (single object) or `List<ApexClass>` (list of objects).
|
|
165
|
+
- **`sample`**: a property whose JSON value/schema `type` is `"object"` (single object) or `"array"` of objects (list).
|
|
166
166
|
|
|
167
|
-
**Never** model such a field as `{"type":"object"}` (opaque, unrenderable) or inline it as a nested `lightning__objectType` (rejected by the CLT metaschema — same rule as the envelope↔response relationship).
|
|
167
|
+
**Never** model such a field as `{"type":"object"}` (opaque, unrenderable) or inline it as a nested `lightning__objectType` (rejected by the CLT metaschema — same rule as the envelope↔response relationship).
|
|
168
|
+
|
|
169
|
+
> **Enumerating a referenced/inner Apex class — use its public/`@AuraEnabled` members, not `@InvocableVariable`** (SKILL.md Hard Rule 6: the invocable annotation gates only the top-level response class; an inner class's leaves are never in the describe, so grepping it for `@InvocableVariable` enumerates zero leaves). The grep:
|
|
170
|
+
>
|
|
171
|
+
> ```bash
|
|
172
|
+
> # Inner/referenced class leaves — public/@AuraEnabled members (NOT @InvocableVariable).
|
|
173
|
+
> echo "INNER_FIELDS:"
|
|
174
|
+
> grep -oE '(public|global)\s+[A-Za-z0-9_<>,\s]+\s+[a-zA-Z_][a-zA-Z0-9_]*\s*;' \
|
|
175
|
+
> <pkgDir>/classes/<OuterClass>.cls \
|
|
176
|
+
> | sed -E 's/.*\s([a-zA-Z_][a-zA-Z0-9_]*)\s*;/\1/' \
|
|
177
|
+
> | sort -u
|
|
178
|
+
> # Scope to the inner class block; @AuraEnabled fields have no @InvocableVariable line above them.
|
|
179
|
+
> # If the grep misses multi-line declarations, Read the .cls and list the inner class fields manually.
|
|
180
|
+
> ```
|
|
181
|
+
|
|
182
|
+
### Single nested object (`maxOccurs: 1`)
|
|
183
|
+
|
|
184
|
+
`<objectField>` throughout this section is the output entry's own `name` from the describe (e.g. `flightInfo`) — the property key that carries the object, used verbatim in the response CLT property name and the renderer binding path. It is never an invented label.
|
|
168
185
|
|
|
169
186
|
1. Type the response CLT property as `"@apexClassType/<ns>__<OuterClass>$<InnerClass>"` (e.g. `"@apexClassType/c__SearchFlightsAction$Flight"`) — the same convention `platform-custom-lightning-type-generate` documents for Apex-backed CLTs.
|
|
170
|
-
2. Enumerate the referenced Apex class's own fields
|
|
187
|
+
2. Enumerate the referenced Apex class's own fields by its **public / `@AuraEnabled`** members (see the callout above — inner classes are *not* gated by `@InvocableVariable`) — these become the widget's leaf properties. The object field itself never appears on the widget.
|
|
171
188
|
3. Bind the renderer one level deeper: `{!$attrs.outputValues.<objectField>.<leaf>}` (e.g. `{!$attrs.outputValues.flightInfo.flightId}`), not `{!$attrs.outputValues.<objectField>}`.
|
|
172
|
-
4. A field typed `List<ApexClass>` (a list of nested objects, not a single one) is out of scope for the beta single-response flow — surface it in the build plan like a `maxOccurs > 1` scalar rather than emitting a schema for it.
|
|
173
189
|
|
|
174
|
-
|
|
190
|
+
### List of nested objects (`List<ApexClass>` / `maxOccurs > 1` with an `apexClass`)
|
|
191
|
+
|
|
192
|
+
A list of nested objects is **in scope** — a real, boundary-crossing, renderable field. Do **not** declare it "out of scope" and do **not** drop it silently. In a response CLT the list is **always a plain `@apexClassType/...` reference** (the CLT metaschema forbids `lightning__listType`/`items` on a response-CLT property — `unevaluatedProperties: false`); the list-ness surfaces in the *widget* schema. **Never touch the Apex to make a list renderable** — both list positions below bind directly, no wrapper reshape.
|
|
193
|
+
|
|
194
|
+
> **The binding depth equals the list's position in the describe — read it off the describe, never apply a transform.** Two positions, both directly bindable:
|
|
195
|
+
> - **Top-level list output** — the describe surfaces the list itself as an output entry: `apexClass` set + `maxOccurs > 1` (e.g. `GetLeadsList` → `leads`, `apexClass: GetLeadsList$LeadSummary`, `maxOccurs: 2000`), often alongside scalar sibling outputs (`leadCount`, `status`). Type the response CLT property **directly** as `@apexClassType/c__<Outer>$<ElementClass>` (the element/summary class) and bind the renderer at **two segments**: `{!$attrs.outputValues.<listField>}` (e.g. `{!$attrs.outputValues.leads}`). *No Apex change, no wrapper.*
|
|
196
|
+
> - **List inside a wrapper object** — the describe returns exactly ONE `apexClass` output with `maxOccurs: 1` (e.g. `GetShipmentDetails` → `shipmentDetailsResponse`), and the list is a field *inside* that class that the describe **does not surface**. Read the inner Apex class (via the `apex` source / apex describe) and enumerate its **public / `@AuraEnabled`** members — not `@InvocableVariable` (see the referenced/inner-class callout above) — to discover the list field, type the response CLT property as the wrapper class `@apexClassType/c__<Outer>$<ResponseClass>`, and bind the renderer at **three segments**: `{!$attrs.outputValues.<wrapperField>.<listField>}` (e.g. `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}`).
|
|
197
|
+
>
|
|
198
|
+
> Whichever position, the response CLT property is a single `@apexClassType/...` reference — the extra binding depth for the wrapper case comes from the wrapper level in the describe, not from any reshape. See `references/two-clt-modeling.md` ("Top-level list vs list-inside-wrapper") for the worked JSON.
|
|
199
|
+
|
|
200
|
+
1. **Response CLT:** type the list as a plain `@apexClassType/...` reference — `c__<Outer>$<ElementClass>` for a top-level list output, or `c__<Outer>$<ResponseClass>` (the wrapper class, whose interior list field you found by reading the class) for a list-inside-wrapper. Do NOT add a `lightning__listType` property to the CLT.
|
|
201
|
+
2. **Renderer:** bind the list at the depth its describe position dictates — **two segments** `{!$attrs.outputValues.<listField>}` for a top-level list output, or **three segments** `{!$attrs.outputValues.<wrapperField>.<listField>}` for a list inside a wrapper object (never `.<leaf>`).
|
|
202
|
+
|
|
203
|
+
The **widget bundle** (schema + body) that surfaces and iterates the list is authored and validated by `platform-widget-generate` — this skill does not specify the widget's `lightning__listType`/`items` schema property or its iteration mechanism.
|
|
204
|
+
|
|
205
|
+
A `List<InnerClass>` collection is never omitted — it is domain data and is always rendered.
|
|
206
|
+
|
|
207
|
+
See `references/two-clt-modeling.md` ("Nested-object and list payload fields") for the worked JSON, and `examples/nested-object-single-source-prompt.md` (single object) / `examples/nested-object-list-source-prompt.md` (lists) for the full end-to-end walkthroughs.
|
|
175
208
|
|
|
176
209
|
## Output of Phase 2
|
|
177
210
|
|
|
178
|
-
`payloadFields` — an ordered list of `{ name, title, lightning:type }` describing the response payload (primitive fields), plus any nested-object fields resolved to `@apexClassType/...` per above. This drives:
|
|
211
|
+
`payloadFields` — an ordered list of `{ name, title, lightning:type }` describing the response payload (primitive fields), plus any nested-object or list-of-object fields resolved to `@apexClassType/...` per above. A list-of-object field rides inside an `@apexClassType` object (it is not a CLT-level `lightning__listType`); it surfaces as a `lightning__listType` with an `items` element type in the **widget** schema. This drives:
|
|
179
212
|
|
|
180
|
-
- the **response CLT** `properties` (CLT type vocabulary, `lightning__integerType` allowed, `@apexClassType/...` for nested-object fields),
|
|
181
|
-
- the **widget schema** `
|
|
182
|
-
- the **renderer** attribute bindings (`{!$attrs.outputValues.<name>}` for primitives, `{!$attrs.outputValues.<objectField>.<leaf>}` for nested-object leaves).
|
|
213
|
+
- the **response CLT** `properties` (CLT type vocabulary, `lightning__integerType` allowed, `@apexClassType/...` for single nested-object fields and for the object a list rides inside — never `lightning__listType`/`items` in the CLT),
|
|
214
|
+
- the **widget schema** (authored by `platform-widget-generate` — flat leaf properties for single nested-object fields, and a list property for list-of-object fields; this skill supplies the field list and element typing, not the widget schema/body shape),
|
|
215
|
+
- the **renderer** attribute bindings (`{!$attrs.outputValues.<name>}` for primitives, `{!$attrs.outputValues.<objectField>.<leaf>}` for single nested-object leaves, `{!$attrs.outputValues.<listField>}` / `{!$attrs.outputValues.<wrapperField>.<listField>}` for list fields at the depth the describe dictates).
|
|
183
216
|
|
|
184
217
|
Whichever source produced the fields, record it in the build plan so the reviewer knows whether the schema came from the live org (`action`), source (`apex`), or an example (`sample`).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Two-CLT Modeling for an MCP Tool Output
|
|
2
2
|
|
|
3
|
-
A custom MCP server tool backed by an Apex Invocable Action returns the platform's **invocable-action result envelope**. The real payload the tool consumer cares about lives under `outputValues`; the surrounding fields (`
|
|
3
|
+
A custom MCP server tool backed by an Apex Invocable Action returns the platform's **invocable-action result envelope**. The real payload the tool consumer cares about lives under `outputValues`; the surrounding fields (`errors`, `sortOrder`, `version`, …) are envelope metadata and are not modeled — the envelope CLT declares only `actionName`, `isSuccess`, `outputValues`.
|
|
4
4
|
|
|
5
5
|
To render this with an HXL widget we model it as **two object-based CLTs** and wire them with a renderer that bridges the nesting. Both are ordinary CLTs of equal standing — nothing in the platform or the metaschema distinguishes an "envelope type" from a "response type." The only reason two files exist is that one CLT (the envelope) must reference the other (the response) by name via `c__<name>`, and a CLT cannot reference itself — so the two need distinct deployed names, nothing more. Don't invent a role-label pair for the two CLTs themselves ("Payload CLT"/"Envelope CLT", "Outer CLT"/"Inner CLT") — name and describe each by what it actually models (see below), and in prose refer to them by that same identifier: "the `<toolApiName>` envelope" / "the `<toolApiName>Response`". ("Payload" and "response" remain fine as ordinary words for the data itself — e.g. "response fields", "the payload the tool consumer cares about" — the rule is about not naming or labeling the *CLTs* by an invented role.)
|
|
6
6
|
|
|
@@ -20,8 +20,6 @@ To render this with an HXL widget we model it as **two object-based CLTs** and w
|
|
|
20
20
|
- Both CLT names are derived from the **same single `<toolApiName>`** — there is no separate naming decision to make per artifact, and no free-standing role word (no "Result", "OutputValues", "Payload", "Envelope", and no `_CLT` suffix either — a Lightning Type is identified by living under `lightningTypes/`, not by a suffix on its name). `Response` is not a role label; it is literally what the class is (the Invocable Action's declared `List<...Response>` return-element type) — the same word the Apex source itself already uses (e.g. `GetAccountSummaryResponse`, `FlightDetailsResponse`).
|
|
21
21
|
- The envelope CLT is *structurally* generic but **cannot be a single shared CLT** — its `outputValues` must be typed to a tool-specific response CLT via `c__<responseCLT>`. One envelope CLT per tool.
|
|
22
22
|
|
|
23
|
-
> **Naming convention supersedes the earlier hand-verified prototype.** Two bundles were manually fixed and successfully deployed during development using an older `<toolApiName>Result` / `<toolApiName>OutputValues` naming pair — that proved the *structural* pattern (two object-based CLTs, `@apexClassType` for nested fields, two-level renderer bindings) deploys correctly. The naming convention above replaces those two suffixes; every other structural rule in this file (root keys, `unevaluatedProperties`, the `c__` reference, nested-object typing, renderer bindings) is unchanged and still matches what was verified.
|
|
24
|
-
|
|
25
23
|
## Response CLT
|
|
26
24
|
|
|
27
25
|
Object-based CLT whose `properties` are exactly the response `@InvocableVariable` fields (1:1). Root `lightning:type` is `lightning__objectType`. `platform-custom-lightning-type-generate` injects and enforces `"unevaluatedProperties": false` on every object-based CLT (its metaschema rejects a CLT without it) — this orchestrator does not fight that, it matches it in every example and every generated file. Give both CLTs a real, tool-specific `description` (never `""`) — it is what a consumer sees when picking a referenced CLT. Both CLTs also carry a root-level `"lightning:tags": ["mcp"]` — it marks the type as MCP-tool-generated per `platform-custom-lightning-type-generate/assets/primitive-types-and-constraints.md`.
|
|
@@ -43,14 +41,18 @@ Object-based CLT whose `properties` are exactly the response `@InvocableVariable
|
|
|
43
41
|
}
|
|
44
42
|
```
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
> **Response CLT properties are 1:1 with the describe outputs — never an invented wrapper.** The response CLT's top-level property names equal the describe's `outputs[].name` set (for `apex`/`sample`, the response class's `@InvocableVariable` field names). A describe with **N sibling outputs** → **N flat properties** (the `GetAccountSummary` example above; `GetLeadsList` → `leadCount`, `leads`, `message`, `status`); a describe with **one output** → **one property named after it** (`GetShipmentDetails` → `shipmentDetailsResponse`, `GetFlightDetails` → `flightInfo`). Do **not** collapse several sibling outputs into one lone property such as `leadsListResponse` — that key appears in no describe output and is unresolvable under `action` (the response-class name is never in `outputs[]`). A single-property response CLT is correct only when the describe itself returns a single output. This is enforced by `clt-reference-integrity` check 5 (`PROP_GROUNDING`).
|
|
45
|
+
|
|
46
|
+
### Nested-object and list payload fields (a second, additive case)
|
|
47
|
+
|
|
48
|
+
The example above covers a **flat** payload — every `@InvocableVariable` field is a primitive. Some invocable responses instead have a field whose type is **itself an Apex class** — either a single object (e.g. `GetFlightDetailsAction.FlightDetailsResponse.flightInfo`, typed `SearchFlightsAction.Flight`) or a **list** of them (e.g. the `GetShipmentDetails` wrapper's `shipmentDetailsResponse.statusUpdates`, typed `List<StatusUpdateResponse>`). All three shapes — flat, single-object, list-of-objects — are in scope; pick the branch per field. In every case:
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
- **Never** type the property as a bare `{"type":"object"}` (opaque, unrenderable, and not what deploys) and **never** inline it as a nested `lightning__objectType` (rejected by the CLT metaschema, same as the envelope↔response relationship below).
|
|
51
|
+
|
|
52
|
+
#### Single nested object
|
|
49
53
|
|
|
50
|
-
- **Never** type that property as a bare `{"type":"object"}` (opaque, unrenderable, and not what deploys) and **never** inline it as a nested `lightning__objectType` (rejected by the CLT metaschema, same as the envelope↔response relationship below).
|
|
51
54
|
- **Do** type it as `"@apexClassType/<ns>__<OuterClass>$<InnerClass>"` — e.g. `"lightning:type": "@apexClassType/c__SearchFlightsAction$Flight"` — exactly the Apex-backed-CLT convention `platform-custom-lightning-type-generate` already documents for `@apexClassType/namespace__ClassName$InnerClass`.
|
|
52
|
-
- The **widget** and **renderer** then flatten through it — see the nested-binding note at the end of the "Default renderer" section below, and the full
|
|
53
|
-
- A field typed `List<ApexClass>` (a list of nested objects) is out of scope for the beta single-response flow — surface it in the build plan rather than emitting a schema for it, the same way a `maxOccurs > 1` scalar is surfaced.
|
|
55
|
+
- The **widget** and **renderer** then flatten through it — see the nested-binding note at the end of the "Default renderer" section below, and the full walkthroughs in `examples/nested-object-single-source-prompt.md` (single object) and `examples/nested-object-list-source-prompt.md` (lists).
|
|
54
56
|
|
|
55
57
|
```json
|
|
56
58
|
{
|
|
@@ -69,6 +71,61 @@ The example above covers a **flat** payload — every `@InvocableVariable` field
|
|
|
69
71
|
}
|
|
70
72
|
```
|
|
71
73
|
|
|
74
|
+
#### List of nested objects
|
|
75
|
+
|
|
76
|
+
A `List<ApexClass>` field (an Actions-API output with `apexClass` set and `maxOccurs > 1`, or an `@InvocableVariable List<Inner>` in source) is **in scope** — a real, renderable, boundary-crossing field. It is NOT out of scope for the beta: the `content[]` single-response limit governs how many tool *results* render (one), not list *fields* inside that one result. Render it as a collection; never drop it silently.
|
|
77
|
+
|
|
78
|
+
> **A list is bindable in whichever position the describe returns it — never reshape the Apex to move it.** Two positions occur, and both bind directly: (a) a **top-level list output** — the describe returns the list as its own output entry (`apexClass` set, `maxOccurs > 1`, e.g. a flat `GetLeadsList` whose `leads` output is `maxOccurs: 2000`); the response CLT types that property **directly** as `@apexClassType/c__<Outer>$<ElementClass>` and the renderer binds it at two segments, `{!$attrs.outputValues.<listField>}`. (b) a **list inside a single wrapper object** — the describe returns ONE output (`apexClass`, `maxOccurs: 1`, e.g. `GetShipmentDetails` → `shipmentDetailsResponse`) whose class *contains* the list (`statusUpdates`); the renderer binds it at three segments, `{!$attrs.outputValues.<wrapper>.<listField>}`. See "Top-level list vs list-inside-wrapper" below. In neither case does the CLT declare a `lightning__listType`/`items` — the list-typed property is always a plain `@apexClassType/...` reference.
|
|
79
|
+
|
|
80
|
+
The rule is that **a list-typed CLT property is always a plain `@apexClassType/...` reference — the object-based response CLT never declares the list as a `lightning__listType` property itself.** The `@apexClassType` describe layer resolves the list and its element type; the list surfaces as a `lightning__listType` in the *widget* schema, not the CLT. Which class the reference names, and how deep the renderer binds, depend on the list's **position in the describe** (see "Top-level list vs list-inside-wrapper" below). Concretely:
|
|
81
|
+
|
|
82
|
+
- **Response CLT:** the list-typed property is a plain `@apexClassType` reference (never a `lightning__listType`, never `items`). For a **top-level list output** (flat `GetLeadsList` → `leads`, `maxOccurs: 2000`) the property names the **element** class directly — `leads → @apexClassType/c__GetLeadsList$LeadSummary` — and the CLT carries that property itself. For a **list inside a wrapper** (`GetShipmentDetails` → `shipmentDetailsResponse`) the CLT carries the **wrapper** property — `shipmentDetailsResponse → @apexClassType/c__GetShipmentDetails$GetShipmentDetailsResponse` — and the `List<StatusUpdateResponse>` lives inside that class (discovered by reading it, not from the describe). Either way the CLT gets **no** `lightning__listType` property.
|
|
83
|
+
- **Renderer:** bind the list at the depth its position dictates (NOT `.<leaf>` in either case): `{!$attrs.outputValues.<listField>}` (two segments) for a **top-level list output** (e.g. `{!$attrs.outputValues.leads}`), or `{!$attrs.outputValues.<objectField>.<listField>}` (three segments) for a **list inside a wrapper** (e.g. `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}`). This bridges the envelope to the widget's flat `{!$attrs.<listField>}`.
|
|
84
|
+
|
|
85
|
+
How the widget bundle surfaces the list (its `lightning__listType` + `items` schema property) and iterates the items is authored and validated by `platform-widget-generate` — not by this skill.
|
|
86
|
+
|
|
87
|
+
Deployed response CLT (the list is NOT here — it rides inside the `@apexClassType` object):
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"title": "Get Shipment Details Response",
|
|
92
|
+
"description": "Payload fields returned by the GetShipmentDetails invocable action",
|
|
93
|
+
"type": "object",
|
|
94
|
+
"lightning:type": "lightning__objectType",
|
|
95
|
+
"lightning:tags": ["mcp"],
|
|
96
|
+
"unevaluatedProperties": false,
|
|
97
|
+
"properties": {
|
|
98
|
+
"shipmentDetailsResponse": {
|
|
99
|
+
"title": "Shipment Details Response",
|
|
100
|
+
"lightning:type": "@apexClassType/c__GetShipmentDetails$GetShipmentDetailsResponse"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Deployed renderer binding (list bound one level through the object; the widget iterates the items):
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{ "statusUpdates": "{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}" }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The widget schema property for the list (`lightning__listType` + `items`) and the widget body that iterates it are authored by `platform-widget-generate`.
|
|
113
|
+
|
|
114
|
+
#### Top-level list vs list-inside-wrapper (which position the describe returns the list in)
|
|
115
|
+
|
|
116
|
+
**The describe is the source of truth, and the list is renderable in whichever position it returns — never touch the Apex to move it.** Two positions occur in practice. They differ ONLY in renderer binding depth:
|
|
117
|
+
|
|
118
|
+
| Position | Actions describe `outputs` | Response CLT list property | Renderer binding |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| **Top-level list output** (e.g. flat `GetLeadsList`) | The list is its **own** output entry — `apexClass` set, `maxOccurs > 1` (e.g. `leads` → `apexClass: GetLeadsList$LeadSummary`, `maxOccurs: 2000`), beside sibling scalars | `leads` → `@apexClassType/c__GetLeadsList$LeadSummary` (the **element** class) | **Two segments:** `{!$attrs.outputValues.leads}` |
|
|
121
|
+
| **List inside a wrapper** (e.g. `GetShipmentDetails`) | ONE output — `shipmentDetailsResponse` · `apexClass` set · `maxOccurs: 1`; the list is a field **inside** that class (`statusUpdates`), which the describe does NOT surface | `shipmentDetailsResponse` → `@apexClassType/c__GetShipmentDetails$GetShipmentDetailsResponse` (the **wrapper** class; the list is discovered by reading it) | **Three segments:** `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}` |
|
|
122
|
+
|
|
123
|
+
**A top-level `@apexClassType` list binds directly.** A response CLT that types a top-level list property directly as `@apexClassType/c__<Outer>$<ElementClass>`, with an envelope whose renderer binds `{!$attrs.outputValues.<listField>}` (two segments, no wrapper hop), is a valid, deployable shape. There is no need for — and the skill must not perform — any Apex reshaping (no wrapper class, no `List<Wrapper>` return-type change) to render a top-level list. The Apex is never modified by this skill.
|
|
124
|
+
|
|
125
|
+
**Typing facts:**
|
|
126
|
+
- A response CLT list property **must** be a plain `@apexClassType/c__<Outer>$<ElementClass>` reference. Typing it as `lightning__listType` with an `items` element type is **rejected** by the CLT metaschema (*"You can't add the items property … because the `unevaluatedProperties` keyword value is set to false"*). `items`/`lightning__listType` belong to the **widget** schema only.
|
|
127
|
+
- The binding depth is dictated purely by the list's position in the describe (two segments for a top-level output, three for a list inside a wrapper) — not by any transform you apply.
|
|
128
|
+
|
|
72
129
|
## Envelope CLT
|
|
73
130
|
|
|
74
131
|
Object-based CLT that mimics the tool-result envelope. `outputValues` is typed to the response CLT via the referenced-CLT pattern `c__<responseCLT>` — **not** inlined as a nested `lightning__objectType` (nested object typing is rejected by the CLT metaschema; see `platform-custom-lightning-type-generate`).
|
|
@@ -91,7 +148,7 @@ Object-based CLT that mimics the tool-result envelope. `outputValues` is typed t
|
|
|
91
148
|
|
|
92
149
|
- The `c__<responseCLT>` string is the referenced type's **registered identifier / FQN**, not its `title`. It must match the response CLT's deployed name.
|
|
93
150
|
- The response CLT must be deployed **before** the envelope CLT.
|
|
94
|
-
- Include only the envelope scalars the widget or the platform needs (`actionName`, `isSuccess`, and `outputValues`
|
|
151
|
+
- Include only the envelope scalars the widget or the platform needs (`actionName`, `isSuccess`, and `outputValues` only). Add `message` etc. only when rendered. `outputValues` is the load-bearing field the renderer bridges through; the widget renders the payload under it, never the envelope metadata (`actionName`/`isSuccess`).
|
|
95
152
|
|
|
96
153
|
## Default renderer (in the ENVELOPE CLT)
|
|
97
154
|
|
|
@@ -117,7 +174,13 @@ The renderer is the **default `renderer.json` at the envelope CLT bundle root**,
|
|
|
117
174
|
|
|
118
175
|
**The binding path is the crux:** each widget attribute (left, flat) maps to the response field nested under the envelope's `outputValues` node (right) via `{!$attrs.outputValues.<field>}`. Because the envelope CLT's `outputValues` is typed to the response CLT, the runtime can resolve `outputValues.<field>` against the response CLT's `properties`.
|
|
119
176
|
|
|
120
|
-
**Nested-object response fields bind one level deeper.** When a response field is itself
|
|
177
|
+
**Nested-object response fields bind one level deeper.** When a response field is itself a single Apex-class reference (the `flightInfo` case above), the widget flattens to that class's own leaf fields, and the renderer binding goes two levels deep: `{!$attrs.outputValues.flightInfo.flightId}`, `{!$attrs.outputValues.flightInfo.origin}`, etc. — `outputValues.<objectField>.<leaf>`, not `outputValues.<objectField>` alone (which would bind the widget to an unresolvable object, not a renderable leaf).
|
|
178
|
+
|
|
179
|
+
**List-of-object response fields bind the list, not the leaves — at a depth set by the list's position.** A `List<ApexClass>` returned as a **top-level output** (flat `GetLeadsList` → `leads`) binds at two segments — `{!$attrs.outputValues.leads}`. A `List<ApexClass>` that lives **inside a wrapper object** (`GetShipmentDetails` → `shipmentDetailsResponse.statusUpdates`) binds at three — `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}`. Do NOT append `.<leaf>` to the list binding in the renderer — there is no single leaf to bind at the list level; the widget (authored by `platform-widget-generate`) iterates the list and renders each item's leaves. The renderer binding depth is set by the describe position.
|
|
180
|
+
|
|
181
|
+
> **The list binding must still go through the renderer's `outputValues` path.** A common failure is a widget that iterates the list correctly but whose *renderer* binds the list flat — `"leads": "{!$attrs.leads}"` instead of `"leads": "{!$attrs.outputValues.<wrapper>.leads}"`. The flat renderer binding resolves against the envelope root, where the payload does not live, so the widget renders "No data available" even though the widget body is correct. Every list is wired through the `outputValues` bridge.
|
|
182
|
+
|
|
183
|
+
> **A renderer attribute CAN bind a top-level `@apexClassType` list directly.** The bindable right-hand paths are: a primitive (`outputValues.<field>`), a **top-level `@apexClassType` list** (`outputValues.<listField>`, e.g. `outputValues.leads` — two segments), or a leaf/list reached *through* one `@apexClassType` wrapper (`outputValues.<wrapper>.<leaf>` / `outputValues.<wrapper>.<listField>` — three segments). There is no "top-level `@apexClassType` list is unbindable" constraint, and the skill must never reshape the Apex to a wrapper to render a top-level list. Bind at the depth the describe's position dictates and leave the Apex untouched.
|
|
121
184
|
|
|
122
185
|
## Why two CLTs and not one
|
|
123
186
|
|