platform-mcp-tool-widget-coordinate
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRendering a Custom MCP Tool Output With a Widget
使用Widget渲染自定义MCP工具输出
Coordinate two object-based Custom Lightning Types (CLTs) and an HXL widget to render the output of a custom MCP server tool whose implementation is an Apex . This skill never authors content directly — it loads and invokes leaf skills in dependency order, gates progress on user approval, and runs validation gates before reporting completion.
@InvocableMethod协调两个基于对象的自定义Lightning类型(CLT)和一个HXL widget,以渲染由Apex 实现的自定义MCP服务器工具的输出。本技能从不直接编写内容——它会按依赖顺序加载并调用子技能,在用户批准后推进流程,并在报告完成前运行验证检查。
@InvocableMethodScope
适用范围
Custom MCP server tools backed by an Apex Invocable Action only. The MCP tool returns the platform's invocable-action result envelope — an object with , , and an node that carries the tool's real payload. To render this envelope with a widget, model it as two object-based CLTs () of equal standing — the only reason there are two is that one must reference the other by name (a CLT cannot reference itself), so they need distinct deployed names. Name and describe each by what it actually models — never by an invented role-label pair like "Payload CLT"/"Envelope CLT" or "Inner CLT"/"Outer CLT":
actionNameisSuccessoutputValueslightning__objectType- The CLT that mimics the tool-result envelope, named . Its
<toolApiName>property is typed to the other CLT viaoutputValues.c__<responseCLT> - The CLT that is the exact shape of the Invocable Action's response (fields on the
@InvocableVariableresponse class), named@InvocableMethod— "Response" here is not an invented role word, it's the same word the Apex source already uses for that class (e.g.<toolApiName>Response).GetAccountSummaryResponse
The widget grounds on the response fields (flat), and the default in the envelope CLT bridges the envelope nesting to the flat widget via .
renderer.json{!$attrs.outputValues.<field>}Out of scope, route elsewhere:
- Customizing an Apex-backed agent action output (Apex-backed CLT , single CLT, surface-specific renderer) →
@apexClassType/....platform-lightning-type-widget-coordinate - A standalone widget with no MCP tool / Lightning Type → .
platform-widget-generate - Authoring only a CLT or only an Apex class → /
platform-custom-lightning-type-generate.platform-apex-generate
Beta cardinality: the invocable-action result is a bulk array (). For the beta release this skill models and renders a single response — the first element ofcontent[]. The CLT envelope models one result object, not thecontent[]wrapper.content[]
仅适用于由Apex Invocable Action支持的自定义MCP服务器工具。MCP工具会返回平台的invocable-action结果信封——一个包含、和承载工具实际负载的节点的对象。要使用widget渲染此信封,需将其建模为两个地位平等的基于对象的CLT()——设置两个CLT的唯一原因是其中一个必须按名称引用另一个(CLT无法引用自身),因此它们需要不同的部署名称。请根据实际建模内容为每个CLT命名和描述——切勿使用诸如“Payload CLT”/“Envelope CLT”或“Inner CLT”/“Outer CLT”这类虚构的角色标签对:
actionNameisSuccessoutputValueslightning__objectType- 模拟工具结果信封的CLT,命名为。其
<toolApiName>属性通过outputValues类型化为另一个CLT。c__<responseCLT> - 与Invocable Action响应(响应类上的
@InvocableMethod字段)完全匹配的CLT,命名为@InvocableVariable——此处的“Response”并非虚构的角色词,而是Apex源代码中该类已使用的词汇(例如<toolApiName>Response)。GetAccountSummaryResponse
Widget基于响应字段(扁平化)构建,而信封CLT中的**默认**通过将信封的嵌套结构桥接到扁平化的widget。
renderer.json{!$attrs.outputValues.<field>}超出范围,请路由至其他技能:
- 自定义基于Apex的代理动作输出(基于Apex的CLT ,单个CLT,特定界面渲染器)→
@apexClassType/...。platform-lightning-type-widget-coordinate - 不涉及MCP工具/Lightning Type的独立widget → 。
platform-widget-generate - 仅编写CLT或仅编写Apex类 → /
platform-custom-lightning-type-generate。platform-apex-generate
Beta版基数限制: invocable-action结果为批量数组()。在Beta版本中,本技能仅建模并渲染单个响应——即content[]的第一个元素。CLT信封仅建模一个结果对象,而非content[]包装器。content[]
How this differs from platform-lightning-type-widget-coordinate
platform-lightning-type-widget-coordinate与platform-lightning-type-widget-coordinate
的差异
platform-lightning-type-widget-coordinate| Dimension | agent-action flow ( | this MCP-tool flow |
|---|---|---|
| CLT kind | Apex-backed ( | Object-based ( |
| Number of CLTs | one | two (envelope + response) |
| Field source | | |
| Renderer location | | |
| Renderer binding | flat | nested |
| 维度 | 代理动作流程( | 本MCP工具流程 |
|---|---|---|
| CLT类型 | 基于Apex( | 基于对象( |
| CLT数量 | 1个 | 2个(信封 + 响应) |
| 字段来源 | | 响应类上的 |
| 渲染器位置 | | |
| 渲染器绑定 | 扁平化 | 嵌套式 |
Phase Graph
阶段流程图
| Phase | Purpose | Output |
|---|---|---|
| 1 — Input selection | Determine the payload source: an invocable action API name (preferred), an Apex Invocable class, or a pasted tool-output JSON sample. | |
| 2 — Payload discovery | Describe the invocable action via the Actions REST API and read its typed | |
| 3 — Build plan | Print the plan in full; proceed unless the next reply explicitly pushes back. | printed plan |
| 4 — Generation | Load and invoke leaf skills: response CLT → envelope CLT → widget → inline default renderer in the envelope CLT. | files written |
| 5 — Validation | Run hard gates (block) and warn gates (advisory). | gate report |
| 6 — Summary | Files, validations, deploy order, preview readiness. | summary |
Per-phase pattern: load the skill fresh → execute its workflow → verify outputs → checkpoint before the next phase. Even if you remember a leaf skill's content, skills evolve — always load fresh.
| 阶段 | 目标 | 输出 |
|---|---|---|
| 1 — 输入选择 | 确定负载来源:invocable action API名称(首选)、Apex Invocable类,或粘贴的工具输出JSON示例。 | |
| 2 — 负载发现 | 通过Actions REST API描述invocable action并读取其类型化的 | |
| 3 — 构建计划 | 完整打印计划;除非下一条回复明确反对,否则继续推进。 | 打印的计划 |
| 4 — 生成 | 加载并调用子技能:响应CLT → 信封CLT → widget → 信封CLT中的内联默认渲染器。 | 生成的文件 |
| 5 — 验证 | 运行强制检查(阻止流程)和警告检查(建议性)。 | 检查报告 |
| 6 — 总结 | 文件列表、验证结果、部署顺序、预览就绪状态。 | 总结报告 |
各阶段模式: 重新加载技能 → 执行其工作流 → 验证输出 → 进入下一阶段前检查。即使您记得子技能的内容,技能也会不断演进——始终重新加载最新版本。
Phase 1 — Input selection
阶段1 — 输入选择
Determine where the payload shape comes from. Prefer the sources top-to-bottom:
| Source | Trigger | Phase 2 action |
|---|---|---|
| Prompt gives an invocable action API name — directly, or via an Apex class name that resolves to one — AND an authenticated org is available. Preferred. | Describe the action via the Actions REST API and read its typed |
| No reachable org (or the describe 404s), but a pasted tool-output JSON sample is available. | Parse the |
| Only the Apex class is available (no action name resolvable, no reachable org, no sample) — fallback only, may be stale relative to what's deployed. | Resolve the response class and enumerate |
Capture the tool API name (used to name all artifacts — see the naming convention below).
Source priority: live/authoritative schema sources beat parsing a local class, which beats a pasted example. In order:
- if an action API name and an authenticated org are available. The Actions REST API describe is the same schema the platform itself exposes, so it needs no request/helper filtering and gives real field types.
action - if a runtime JSON sample is pasted (runtime response — explicit and current).
sample - if an Apex class exists locally AND none of the above apply (fallback only — may be stale relative to what's actually deployed behind the action).
apex
If none are available, STOP and ask the user for an action name, a class, a sample, or a schema.
确定负载结构的来源。优先选择以下从上到下的来源:
| 来源 | 触发条件 | 阶段2操作 |
|---|---|---|
| 提示提供invocable action API名称——直接提供,或通过可解析为该名称的Apex类名称提供——且存在已认证的组织。首选。 | 通过Actions REST API描述动作并读取其类型化的 |
| 无法访问组织(或描述请求返回404),但提供了粘贴的工具输出JSON示例。 | 从示例中解析 |
| 仅能获取Apex类(无法解析动作名称,无法访问组织,无示例)——仅作为备选,可能与已部署内容不一致。 | 解析响应类并枚举 |
捕获工具API名称(用于命名所有工件——请参见下文的命名约定)。
来源优先级: 实时/权威的 schema 来源优于解析本地类,解析本地类优于粘贴示例。顺序如下:
- :如果提供了动作API名称且存在已认证的组织。Actions REST API描述与平台自身暴露的schema一致,因此无需请求/辅助过滤,可提供真实的字段类型。
action - :如果提供了运行时JSON示例(运行时响应——明确且最新)。
sample - :如果本地存在Apex类且上述来源均不可用(仅作为备选——可能与动作背后实际部署的内容不一致)。
apex
如果没有可用来源,请停止并向用户请求动作名称、类、示例或schema。
Phase 2 — Payload discovery
阶段2 — 负载发现
FIRST Read (REQUIRED — do NOT run Phase 2 from this summary alone), then execute the procedure for the chosen source. Reminders:
references/mcp-tool-output-discovery.mdFor (preferred): describe the action with the Actions REST API and read its :
actionoutputs- Resolve the action API name (for Apex actions this is the class name declaring , not the method label).
@InvocableMethod - .
sf api request rest '/services/data/v<APIVER>/actions/custom/apex/<ActionApiName>' -o <org> - Use the array only (each entry
outputs). Ignore{ name, label, type, maxOccurs }— that is the tool input (request wrapper). A field withinputsis a list — surface it in the plan (beta renders a single response).maxOccurs > 1 - Map the Actions API → CLT
type(see the discovery reference's table;lightning:type/STRING/ID/… →REFERENCE,lightning__textType/INTEGER→LONG,lightning__integerType/DOUBLE/DECIMAL/CURRENCY→PERCENT,lightning__numberType→BOOLEAN,lightning__booleanType/DATE→ date types). Match case-insensitively.DATETIME - An entry with and an
"type": nullkey instead of a primitive"apexClass": "<OuterClass>$<InnerClass>"is a nested-object field, not a describe gap — see "Nested-object payload fields" below. The describe never exposes that class's own leaf fields, so retrieving/reading the named Apex class to enumerate them is the expected next step, not a fallback away fromtype.action - If the describe 404s, fall back to (a pasted tool-output JSON) if one is available, else
sample(parse the class from source, if locally available).apex
For (fallback):
apex- Locate the class (; retrieve
<pkgDir>/classes/<ClassName>.clsif absent).ApexClass:<ClassName> - Identify the response class — the element type of the return
@InvocableMethod(e.g.List<...>→List<GetAccountSummaryResponse>).GetAccountSummaryResponse - Enumerate its fields. Exclude the request class (the
@InvocableVariableparameter type) and any@InvocableMethodhelper classes — those are not part of the tool's externally visible output schema.private - Map Apex → CLT :
lightning:type/String→Id,lightning__textType→Integer,lightning__integerType/Decimal→Double,lightning__numberType→Boolean,lightning__booleanType→Date,lightning__dateType→Datetime.lightning__dateTimeType - A field whose type is itself an Apex class (e.g. ) is a second, additive case alongside the flat-primitive mapping above — see "Nested-object payload fields" below. This applies to every source (
flightInfo : SearchFlightsAction.Flight,action,apex), not justsample.apex
For (fallback): parse the object; infer each field's from its JSON value (string → , integer → , fractional number → , boolean → ).
sampleoutputValueslightning:typelightning__textTypelightning__integerTypelightning__numberTypelightning__booleanTypeNested-object payload fields (applies to every source above): when a response/output field's type is not a primitive but another Apex class (object), do NOT model it as or an inlined — both produce an opaque, unrenderable blob and neither deploys. Instead:
{"type":"object"}lightning__objectType- Type the response CLT property as (e.g.
"@apexClassType/<ns>__<OuterClass>$<InnerClass>"), matching the Apex-backed-CLT convention"@apexClassType/c__SearchFlightsAction$Flight"already documents.platform-custom-lightning-type-generate - Enumerate the referenced Apex class's own /public fields as the leaf set; the widget schema flattens to those leaves (never the object field itself).
@InvocableVariable - The renderer binds one level deeper: (e.g.
{!$attrs.outputValues.<objectField>.<leaf>}), not{!$attrs.outputValues.flightInfo.flightId}.{!$attrs.outputValues.<objectField>} - A field typed is out of scope for the beta single-response flow — surface it in the build plan like a
List<ApexClass>scalar, do not emit a schema for it.maxOccurs > 1 - See ("Nested-object payload fields") and
references/two-clt-modeling.mdfor the full walkthrough.examples/nested-object-source-prompt.md
Capture — the ordered list of that defines the response CLT and the widget schema. Record which source produced it in the build plan.
payloadFields{ name, title, lightning:type }Staleness: do NOT maintain a cross-session cache. Read the local project fresh and re-retrieve from the org per session.
首先阅读(必填——请勿仅根据本摘要运行阶段2),然后针对所选来源执行流程。注意事项:
references/mcp-tool-output-discovery.md对于(首选): 通过Actions REST API描述动作并读取其:
actionoutputs- 解析动作API名称(对于Apex动作,这是声明的类名称,而非方法标签)。
@InvocableMethod - 执行命令:。
sf api request rest '/services/data/v<APIVER>/actions/custom/apex/<ActionApiName>' -o <org> - 仅使用数组(每个条目包含
outputs)。忽略{ name, label, type, maxOccurs }——这是工具输入(请求包装器)。inputs的字段为列表——请在计划中注明(Beta版仅渲染单个响应)。maxOccurs > 1 - 将Actions API的映射到CLT的
type(请参见发现参考文档中的表格;lightning:type/STRING/ID/… →REFERENCE,lightning__textType/INTEGER→LONG,lightning__integerType/DOUBLE/DECIMAL/CURRENCY→PERCENT,lightning__numberType→BOOLEAN,lightning__booleanType/DATE→ 日期类型)。匹配时不区分大小写。DATETIME - 如果条目包含**和
"type": null键**而非原始类型,则表示该字段为嵌套对象字段,而非描述缺失——请参见下文的“嵌套对象负载字段”。描述不会暴露该类自身的叶子字段,因此预期的下一步是检索/读取指定的Apex类以枚举其字段,而非放弃"apexClass": "<OuterClass>$<InnerClass>"来源。action - 如果描述请求返回404,若有粘贴的工具输出JSON示例则回退到,否则回退到
sample(从源代码解析类,如果本地可用)。apex
对于(备选):
apex- 定位类文件(;如果不存在则检索
<pkgDir>/classes/<ClassName>.cls)。ApexClass:<ClassName> - 识别响应类——返回的
@InvocableMethod的元素类型(例如List<...>→List<GetAccountSummaryResponse>)。GetAccountSummaryResponse - 枚举其字段。排除请求类(
@InvocableVariable参数类型)和任何@InvocableMethod辅助类——这些不属于工具对外暴露的输出schema。private - 将Apex类型映射到CLT的:
lightning:type/String→Id,lightning__textType→Integer,lightning__integerType/Decimal→Double,lightning__numberType→Boolean,lightning__booleanType→Date,lightning__dateType→Datetime。lightning__dateTimeType - 类型为Apex类的字段(例如)是除扁平化原始类型映射之外的另一种情况——请参见下文的“嵌套对象负载字段”。这适用于所有来源(
flightInfo : SearchFlightsAction.Flight、action、apex),而非仅sample。apex
对于(备选): 解析对象;根据JSON值推断每个字段的(字符串 → ,整数 → ,小数 → ,布尔值 → )。
sampleoutputValueslightning:typelightning__textTypelightning__integerTypelightning__numberTypelightning__booleanType嵌套对象负载字段(适用于上述所有来源): 当响应/输出字段的类型不是原始类型而是另一个Apex类(对象)时,请勿将其建模为或内联的——这两种方式都会生成不透明、无法渲染的二进制大对象,且均无法部署。正确做法是:
{"type":"object"}lightning__objectType- 将响应CLT属性类型设置为(例如
"@apexClassType/<ns>__<OuterClass>$<InnerClass>"),与"@apexClassType/c__SearchFlightsAction$Flight"已记录的基于Apex的CLT约定一致。platform-custom-lightning-type-generate - 将引用的Apex类自身的/公共字段枚举为叶子字段集;widget schema会扁平化到这些叶子字段(而非对象字段本身)。
@InvocableVariable - 渲染器的绑定会深入一层:(例如
{!$attrs.outputValues.<objectField>.<leaf>}),而非{!$attrs.outputValues.flightInfo.flightId}。{!$attrs.outputValues.<objectField>} - 类型为的字段超出Beta版单响应流程的范围——请在构建计划中注明,类似于
List<ApexClass>的标量字段,不要为其生成schema。maxOccurs > 1 - 请参见(“嵌套对象负载字段”)和
references/two-clt-modeling.md获取完整流程说明。examples/nested-object-source-prompt.md
捕获——定义响应CLT和widget schema的有序列表。在构建计划中记录生成该列表的来源。
payloadFields{ name, title, lightning:type }时效性:请勿维护跨会话缓存。每次会话都要重新读取本地项目并从组织重新检索内容。
Phase 3 — Build plan + approval gate
阶段3 — 构建计划 + 批准检查
Print a build plan using the template in . The plan must list:
references/build-plan-format.md- A one-line developer-facing summary (the line).
PLAN: - The tool API name and the response class FQN (or "from pasted sample").
- The two CLT names (envelope + payload) and the widget name, with absolute paths.
- The envelope fields the envelope CLT will carry, and the response fields the response CLT + widget will carry.
- — any response fields intentionally dropped, with rationale.
Properties omitted:andactionNameare envelope fields and never appear here or on the widget — they belong to the envelope CLT only. Any payload-side operational/status field (isSuccess,isSuccess,errorMessage,status, and similar) that the response happens to carry is omitted from the widget by default and MUST be listed here with a one-line rationale — the widget rendersmessagedata fields only.outputValues - The validations that will run after generation.
Print the plan in full, then proceed unless the user's next reply explicitly pushes back. Explicit pushback = , , , , , or an equivalent rejection / revision request. Explicit approval is welcome but NOT required — silence, an unrelated follow-up, or the natural continuation of a single-turn eval all count as implicit approval. The invariant is the plan being visible in the transcript. If pushback arrives, revise and re-print before moving on.
nostopwaitchange Xuse Y instead使用中的模板打印构建计划。计划必须包含:
references/build-plan-format.md- 一行面向开发者的摘要(行)。
PLAN: - 工具API名称和响应类完全限定名(或“来自粘贴的示例”)。
- 两个CLT的名称(信封 + 负载)和widget名称,以及绝对路径。
- 信封CLT将包含的信封字段,以及响应CLT + widget将包含的响应字段。
- ——有意省略的任何响应字段及理由。
Properties omitted:和actionName是信封字段,绝不会出现在此处或widget中——它们仅属于信封CLT。如果响应中包含负载侧的操作/状态字段(isSuccess、isSuccess、errorMessage、status及类似字段),默认会从widget中省略,且必须在此处列出并附上一行理由——widget仅渲染message数据字段。outputValues - 生成后将运行的验证项。
完整打印计划,然后继续推进,除非用户的下一条回复明确反对。 明确反对包括、、、、或等效的拒绝/修改请求。明确批准是受欢迎的,但并非必需——沉默、无关的后续回复或单轮评估的自然延续均视为隐含批准。核心要求是计划必须在对话记录中可见。如果收到反对意见,请修改并重新打印后再继续。
nostopwaitchange Xuse Y insteadPhase 4 — Generation
阶段4 — 生成
Load and invoke leaf skills in this order. For each: load the skill, execute its workflow against the Phase 3 spec, verify the outputs, checkpoint before the next.
-
Response CLT — load. Author an object-based CLT
platform-custom-lightning-type-generate(convention:<responseCLT>) whose<toolApiName>Responseare thepropertiesfrom Phase 2 (1:1 with the responsepayloadFieldsfields). Root is@InvocableVariable, with root-levellightning__objectType."lightning:tags": ["mcp"] -
Envelope CLT — load. Author an object-based CLT
platform-custom-lightning-type-generate(convention:<toolCLT>, the envelope), also with root-level<toolApiName>, and:"lightning:tags": ["mcp"]- →
actionNamelightning__textType - →
isSuccesslightning__booleanType - →
outputValues(the referenced-CLT pattern; the response CLT must be deployed before the envelope CLT)c__<responseCLT> - Add / other envelope scalars only if the widget needs to render them.
message
-
Widget — load. Author a flat widget whose
platform-widget-generateproperties are theschema.json(name + primitive type) — a standalone widget contract, not derived from or coupled to any Lightning Type. It renders onlypayloadFieldsdata fields: neveroutputValues/actionName(envelope-only), and never a response-side operational/status field declared inisSuccess. The widget body binds each field viaProperties omitted:— the widget is envelope-agnostic and never references{!$attrs.<field>}itself.outputValues -
Default renderer (authored inline in the ENVELOPE CLT — never optional). FIRST Read(REQUIRED — do NOT author from memory or copy an existing sample, which may use a deprecated shape). Then author
platform-custom-lightning-type-generate/references/widget-rendition.md— the default renderer, at the bundle root, parallel to<pkgDir>/lightningTypes/<toolCLT>/renderer.json(NOT underschema.json). Shape:lightningDesktopGenAi/json{ "renderer": { "componentOverrides": { "$": { "definition": "@widget/c/<widgetName>", "attributes": { "<payloadField>": "{!$attrs.outputValues.<payloadField>}" } } } } }The renderer maps every widget schema property to the matching payload field nested under the envelope'snode viaoutputValues. This nested binding is the crux of this flow — it bridges the envelope CLT to the flat widget. Do NOT duplicate the widget body inside{!$attrs.outputValues.<payloadField>}.renderer.json
Existing-renderer handling: if already exists at the target path, read it first. If it references the same widget with the same bindings, leave it. If it references a different widget or a custom-LWC root override (), STOP and surface the conflict before overwriting.
renderer.jsonc/<component>按以下顺序加载并调用子技能。对于每个子技能:加载技能,针对阶段3的规范执行其工作流,验证输出,进入下一阶段前检查。
-
响应CLT——加载。编写基于对象的CLT
platform-custom-lightning-type-generate(约定:<responseCLT>),其<toolApiName>Response与阶段2的properties完全匹配(与响应的payloadFields字段一一对应)。根类型为@InvocableVariable,根级别包含lightning__objectType。"lightning:tags": ["mcp"] -
信封CLT——加载。编写基于对象的CLT
platform-custom-lightning-type-generate(约定:<toolCLT>,即信封),同样在根级别包含<toolApiName>,并包含以下字段:"lightning:tags": ["mcp"]- →
actionNamelightning__textType - →
isSuccesslightning__booleanType - →
outputValues(引用CLT模式;响应CLT必须在信封CLT之前部署)c__<responseCLT> - 仅当widget需要渲染时才添加或其他信封标量字段。
message
-
Widget——加载。编写扁平化的widget,其
platform-widget-generate属性为schema.json(名称 + 原始类型)——这是独立的widget契约,并非派生自或耦合于任何Lightning Type。它仅渲染**payloadFields数据字段**:绝不渲染outputValues/actionName(仅属于信封),也绝不渲染阶段3的isSuccess中声明的响应侧操作/状态字段。widget主体通过Properties omitted:绑定每个字段——widget与信封无关,绝不会引用{!$attrs.<field>}本身。outputValues -
默认渲染器(内联编写在信封CLT中——绝非可选)。首先阅读(必填——请勿凭记忆编写或复制现有示例,因为示例可能使用已弃用的格式)。然后编写
platform-custom-lightning-type-generate/references/widget-rendition.md——默认渲染器,位于包根目录,与<pkgDir>/lightningTypes/<toolCLT>/renderer.json同级(而非schema.json目录下)。格式如下:lightningDesktopGenAi/json{ "renderer": { "componentOverrides": { "$": { "definition": "@widget/c/<widgetName>", "attributes": { "<payloadField>": "{!$attrs.outputValues.<payloadField>}" } } } } }渲染器通过将每个widget schema属性映射到信封{!$attrs.outputValues.<payloadField>}节点下的匹配负载字段。这种嵌套绑定是本流程的核心——它将信封CLT桥接到扁平化的widget。请勿在outputValues中重复widget主体内容。renderer.json
现有渲染器处理: 如果目标路径已存在,请先读取它。如果它引用相同的widget且绑定相同,则保留它。如果它引用不同的widget或自定义LWC根覆盖(),请停止并在覆盖前告知冲突。
renderer.jsonc/<component>Phase 5 — Validation gates
阶段5 — 验证检查
Read and run every gate. Widget-bundle-internal checks (schema parse, root keys, leaf types, resolution, well-formedness) are owned by and run in its own self-validation.
references/validation-gates.md{!$attrs.X}.uiwidget-meta.xmlplatform-widget-generateHard — block on failure:
- — the envelope CLT's
clt-reference-integrityproperty hasoutputValues, the response CLT exists atlightning:type === "c__<responseCLT>", both parse as JSON, and neither carries<pkgDir>/lightningTypes/<responseCLT>/schema.jsonor (nested)$schema.items - —
renderer-wires-widgetexists (at the bundle root, not<pkgDir>/lightningTypes/<toolCLT>/renderer.json), parses, wires the widget vialightningDesktopGenAi/, and binds every widget schema property ascomponentOverrides["$"].definition === "@widget/c/<widgetName>"(nested path). Bidirectional: missing or extra bindings both fail.{!$attrs.outputValues.<property>}
Warn — advisory:
- — RUN the trace in
field-trace: grepreferences/validation-gates.mdfrom the response class,@InvocableVariablethe widget schema property keys, print both lists, classify INVENTED vs OMITTED. Invented widget fields fail; silent omissions (a response field absent from the widget AND absent from the Phase 3jqplan) warn.Properties omitted:
Report each gate result by name in Phase 6 (, , , ). Do not summarize as "all passed". This skill produces metadata only — it does not deploy; deployment is the caller's responsibility.
passfail (<reason>)warn (<reason>)not run阅读并运行所有检查项。widget包内部检查(schema解析、根键、叶子类型、解析、格式正确性)由负责,并在其自验证中运行。
references/validation-gates.md{!$attrs.X}.uiwidget-meta.xmlplatform-widget-generate强制检查——失败则阻止流程:
- ——信封CLT的
clt-reference-integrity属性的outputValues,响应CLT存在于lightning:type === "c__<responseCLT>",两者均可解析为JSON,且均不包含<pkgDir>/lightningTypes/<responseCLT>/schema.json或(嵌套的)$schema。items - ——
renderer-wires-widget存在(位于包根目录,而非<pkgDir>/lightningTypes/<toolCLT>/renderer.json),可解析,通过lightningDesktopGenAi/关联widget,并将每个widget schema属性绑定为**componentOverrides["$"].definition === "@widget/c/<widgetName>"**(嵌套路径)。双向检查:缺失或多余的绑定均视为失败。{!$attrs.outputValues.<property>}
警告检查——建议性:
- ——运行
field-trace中的跟踪:从响应类中 grepreferences/validation-gates.md,使用@InvocableVariable提取widget schema属性键,打印两个列表,分类为“虚构字段”和“省略字段”。虚构的widget字段视为失败;静默省略(响应字段未出现在widget中且未在阶段3的jq计划中声明)视为警告。Properties omitted:
在阶段6中按名称报告每个检查项的结果(、、、)。请勿总结为“全部通过”。本技能仅生成元数据——不负责部署;部署由调用方负责。
passfail (<reason>)warn (<reason>)not runPhase 6 — Summary
阶段6 — 总结
text
MCP Tool Widget Build Complete: <widgetName>
FILES GENERATED:
Response CLT:
<pkgDir>/lightningTypes/<responseCLT>/schema.json
Envelope CLT:
<pkgDir>/lightningTypes/<toolCLT>/schema.json
<pkgDir>/lightningTypes/<toolCLT>/renderer.json # default renderer — wires the widget
Widget bundle:
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.json
<pkgDir>/uiWidgets/<widgetName>/schema.json
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml
VALIDATIONS:
widget self-validation (platform-widget-generate gates): <pass | fail — see sub-skill report>
clt-reference-integrity (envelope.outputValues → c__<responseCLT>): <pass | fail (<reason>)>
renderer-wires-widget (nested {!$attrs.outputValues.X} bindings): <pass | fail (<reason>)>
field-trace (INVENTED + OMITTED lists printed): <pass | warn (<reason>) | fail (invented: <list>)>text
MCP工具Widget构建完成:<widgetName>
生成的文件:
响应CLT:
<pkgDir>/lightningTypes/<responseCLT>/schema.json
信封CLT:
<pkgDir>/lightningTypes/<toolCLT>/schema.json
<pkgDir>/lightningTypes/<toolCLT>/renderer.json # 默认渲染器——关联widget
Widget包:
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.json
<pkgDir>/uiWidgets/<widgetName>/schema.json
<pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml
验证结果:
widget自验证(platform-widget-generate检查项):<pass | fail — 请参见子技能报告>
clt-reference-integrity(envelope.outputValues → c__<responseCLT>):<pass | fail (<reason>)>
renderer-wires-widget(嵌套{!$attrs.outputValues.X}绑定):<pass | fail (<reason>)>
field-trace(打印虚构字段+省略字段列表):<pass | warn (<reason>) | fail (虚构字段:<list>)>Hard Rules (always apply)
硬性规则(始终适用)
- Plan-first, then proceed. Print the full Phase 3 build plan before writing any file. Explicit rejection or a change request → stop and revise; otherwise continue. The invariant is the plan being visible in the transcript, not an interactive human approval — this holds in manual chat, agent-to-agent flows, and single-turn evals.
- Two object-based CLTs, never one. The envelope and the payload are separate CLTs. The envelope's is typed via
outputValues, never inlined as a nestedc__<responseCLT>. Both CLTs carry root-levellightning__objectType(see"lightning:tags": ["mcp"]).platform-custom-lightning-type-generate/assets/primitive-types-and-constraints.md - Renderer lives in the ENVELOPE CLT, at the bundle root. — the default renderer, parallel to
lightningTypes/<toolCLT>/renderer.json. Neverschema.json(that is the agent-action flow's surface-specific path), never in the response CLT.lightningDesktopGenAi/renderer.json - Renderer bindings are nested. Every widget attribute maps to , not
{!$attrs.outputValues.<field>}. The widget schema stays flat; the renderer does the bridging.{!$attrs.<field>} - Widget grounds on the payload, not the envelope, and renders data fields only. The widget schema properties are the payload fields. The widget never references
outputValuesoractionName— those are envelope-only. A payload field that is itself operational/status (isSuccess,isSuccess,errorMessage,status, and similar) is omitted from the widget by default and declared inmessage.Properties omitted: - Field source is on the response class. Enumerate the response class only. Exclude the request class and private helper classes.
@InvocableVariable - No invented fields, no silent omissions. The widget schema (and the response CLT) must be a subset of the response fields. Omission requires the field to appear in the Phase 3
@InvocableVariablesection with an approved rationale.Properties omitted:prints both lists.field-trace - Single response for beta. Model one result object, not the bulk wrapper.
content[] - Always load the leaf skill before generation. Do not author from memory.
- Run gates, do not describe them. Reporting without executing a gate is a hard violation; report
passinstead.not run - No shell metacharacters that trigger the Vibes safe-shell filter. In every tool call emitted by this orchestrator and by any leaf skill it invokes, do NOT use command substitution (
Bashor backticks), process substitution ($(…),<(…)), brace expansion (>(…)or{a,b,c}), or{1..N}/eval. These force manual approval even under Bypass mode and stall the eval. Run separate commands (exec), print each intermediate value with its own command and reason about the result, and use plain shell variables (mkdir -p a && mkdir -p b) or here-strings when a value must be reused.X=literal - Resolve schema from the Actions REST API describe, never from raw HTTP to the MCP endpoint or from credential extraction. Use
actionagainst the org's Actions REST API (which uses the existingsf api request restorg auth). Never readsfor any MCP settings file, never extract an org access token, nevera4d_mcp_settings.jsonan MCP server endpoint directly — that requires credentials the session doesn't have and targets a URL the runtime doesn't actually expose that way.curl - Never invoke an MCP tool to discover its output shape. Describing the payload must never execute the underlying action. Resolve the schema via the Actions REST API describe of the backing action — never by calling the tool with sample/guessed input to observe a response. If no action name is resolvable, ask the user for a pasted instead of invoking anything.
sample - A response field typed as another Apex class is never a bare . Type it
{"type":"object"}in the response CLT, flatten to its leaf fields in the widget, and bind the renderer two levels deep (@apexClassType/<ns>__<OuterClass>$<InnerClass>). This is additive to the flat-primitive case (Hard Rule 5), not a replacement for it — see{!$attrs.outputValues.<objectField>.<leaf>}.references/two-clt-modeling.md
- 先计划,再推进。 在编写任何文件前,完整打印阶段3的构建计划。明确拒绝或修改请求→停止并修改;否则继续。核心要求是计划必须在对话记录中可见,而非需要交互式人工批准——这适用于手动聊天、代理间流程和单轮评估。
- 两个基于对象的CLT,绝不使用一个。 信封和负载是独立的CLT。信封的通过
outputValues类型化,绝不内联为嵌套的c__<responseCLT>。两个CLT均在根级别包含lightning__objectType(请参见"lightning:tags": ["mcp"])。platform-custom-lightning-type-generate/assets/primitive-types-and-constraints.md - 渲染器位于信封CLT的包根目录。 ——默认渲染器,与
lightningTypes/<toolCLT>/renderer.json同级。绝不要放在schema.json(这是代理动作流程的特定界面路径),也不要放在响应CLT中。lightningDesktopGenAi/renderer.json - 渲染器绑定为嵌套式。 每个widget属性都映射到,而非
{!$attrs.outputValues.<field>}。widget schema保持扁平化;渲染器负责桥接。{!$attrs.<field>} - Widget基于负载而非信封构建,且仅渲染数据字段。 widget schema属性为负载字段。widget绝不引用
outputValues或actionName——这些仅属于信封。负载侧的操作/状态字段(isSuccess、isSuccess、errorMessage、status及类似字段)默认从widget中省略,并在message中声明。Properties omitted: - 字段来源为响应类上的。 仅枚举响应类。排除请求类和私有辅助类。
@InvocableVariable - 无虚构字段,无静默省略。 widget schema(及响应CLT)必须是响应字段的子集。省略字段必须在阶段3的
@InvocableVariable部分列出并附上批准的理由。Properties omitted:会打印两个列表。field-trace - Beta版仅支持单个响应。 建模一个结果对象,而非批量包装器。
content[] - 生成前始终加载子技能。 请勿凭记忆编写内容。
- 运行检查项,而非描述它们。 未执行检查项就报告属于严重违规;请改为报告
pass。not run - 不使用触发Vibes安全shell过滤器的shell元字符。 在本编排器及其调用的任何子技能发出的每个Bash工具调用中,请勿使用命令替换(或反引号)、进程替换(
$(…),<(…))、大括号扩展(>(…)或{a,b,c})或{1..N}/eval。即使在绕过模式下,这些也会强制手动批准并延迟评估。请运行单独的命令(exec),使用单独的命令打印每个中间值并说明结果,使用普通shell变量(mkdir -p a && mkdir -p b)或here-string重用值。X=literal - 从Actions REST API描述解析schema,绝不从MCP端点的原始HTTP请求或凭证提取。 使用
action针对组织的Actions REST API(使用现有的sf api request rest组织认证)。绝不要读取sf或任何MCP设置文件,绝不要提取组织访问令牌,绝不要直接a4d_mcp_settings.jsonMCP服务器端点——这需要会话中没有的凭证,且目标URL并非运行时实际暴露的方式。curl - 绝不调用MCP工具来发现其输出结构。 描述负载绝不能执行底层动作。通过支持动作的Actions REST API描述解析schema——绝不要通过调用工具并提供示例/猜测的输入来观察响应。如果无法解析动作名称,请向用户请求粘贴的,而非调用任何内容。
sample - 类型为另一个Apex类的响应字段绝不能是裸。 在响应CLT中将其类型设置为
{"type":"object"},在widget中扁平化到其叶子字段,并将渲染器绑定深入两层(@apexClassType/<ns>__<OuterClass>$<InnerClass>)。这是对扁平化原始类型情况(硬性规则5)的补充,而非替代——请参见{!$attrs.outputValues.<objectField>.<leaf>}。references/two-clt-modeling.md
Reference File Index
参考文件索引
| File | When to read |
|---|---|
| Phase 2 — the three sources ( |
| Phase 4 — how the envelope + response CLTs and the nested renderer binding fit together, with the naming convention and nested-object payload handling. |
| Phase 3 — plan template the model fills before proceeding. |
| Phase 5 — full hard / warn gate table with RUN procedures. |
| Phase 3 — a complete walkthrough starting from an invocable action API name (preferred source). |
| Phase 3 — a complete walkthrough starting from an Apex Invocable class (fallback). |
| Phase 3 — a complete walkthrough starting from a pasted tool-output sample (fallback). |
| Phase 3 — a complete walkthrough where a payload field is itself an Apex-class reference, not a primitive. |
| 文件 | 阅读时机 |
|---|---|
| 阶段2——三个来源(通过Actions REST API描述 |
| 阶段4——信封+响应CLT和嵌套渲染器绑定如何配合工作,包括命名约定和嵌套对象负载处理。 |
| 阶段3——模型在推进前需填充的计划模板。 |
| 阶段5——完整的强制/警告检查项表格及执行流程。 |
| 阶段3——从invocable action API名称开始的完整流程说明(首选来源)。 |
| 阶段3——从Apex Invocable类开始的完整流程说明(备选)。 |
| 阶段3——从粘贴的工具输出示例开始的完整流程说明(备选)。 |
| 阶段3——负载字段为Apex类引用(而非原始类型)的完整流程说明。 |