service-de-headless-channel-configure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHeadless Channel Setup (type-agnostic)
无头通道配置(与类型无关)
What this skill does
本技能的功能
Takes a channel type ( | | | | ) plus its type-specific inputs and drives it to an activated . It first gates on the Enhanced Messaging Terms and Conditions, then runs four steps:
WhatsAppLineAppleBusinessChatFacebookTextMessagingChannel- Accept Terms and Conditions — renders the Enhanced Messaging disclaimer and requires the user to certify they have authority to bind their org, mirroring the in-org "Add a Channel" wizard. Blocking — a decline ends the run before any org work. (Stage 0.5, in this skill)
- Insert the channel — invokes , which handles the per-type third-party prereq internally (e.g. WhatsApp's
service-de-channel-createruns insideservice-de-waba-integrate). (skill:service-de-channel-create)service-de-channel-create - Configure routing — sets to an Omni-Channel Queue (pick existing or create new). Message-type-agnostic. (skill:
SessionHandlerId)service-de-channel-routing-configure - Configure consent — ensures a valid + matching
ConsentTyperecord. The Connect insert auto-seeds a defaultMsgChannelLanguageKeyword+ opt-out keyword, so on a fresh channel this step is frequently a no-op — or an upgrade if the caller wants ExplicitOptIn/DoubleOptIn. Activation's readiness check requires both routing AND consent, so this runs before activation. (skill:ConsentType=ImplicitOptIn)service-de-channel-consent-configure - Activate — PATCHes to
MessagingChannelUsage.DeploymentStatusvia REST; the server-side save-hook drives the full observer chain synchronously and returns 204 once the MCU reachesProvisioningandActive. Message-type-agnostic. (skill:MessagingChannel.IsActive=true)service-de-channel-activate
Resume-by-default. Each step is idempotent — if you re-run after a failure, the orchestrator detects existing state and skips steps that already succeeded.
Prompt mid-flow. If isn't in the initial request, the orchestrator asks upfront. Routing choices (pick queue / create new) are prompted when step 2 runs, not upfront — keeps leaf skills self-contained.
{MESSAGE_TYPE}接收通道类型( | | | | )及其特定类型输入,将其配置为已激活的。首先会检查增强型消息服务的条款和条件,然后执行四个步骤:
WhatsAppLineAppleBusinessChatFacebookTextMessagingChannel- 接受条款和条件 —— 显示增强型消息服务的免责声明,要求用户确认其有权约束所在组织,与组织内的“添加通道”向导保持一致。此步骤为阻塞式操作——若用户拒绝,则在执行任何组织操作前终止运行。(属于本技能的0.5阶段)
- 插入通道 —— 调用,该技能会在内部处理各类型的第三方前置要求(例如,WhatsApp的
service-de-channel-create会在service-de-waba-integrate内部运行)。(技能:service-de-channel-create)service-de-channel-create - 配置路由 —— 将设置为Omni-Channel队列(选择现有队列或创建新队列)。此步骤与消息类型无关。(技能:
SessionHandlerId)service-de-channel-routing-configure - 配置同意设置 —— 确保存在有效的+ 匹配的
ConsentType记录。插入通道时会自动生成默认的MsgChannelLanguageKeyword+ 退订关键词,因此对于新创建的通道,此步骤通常是无操作(no-op)——或者如果调用者需要ExplicitOptIn/DoubleOptIn,则会进行升级。激活的就绪检查需要同时满足路由和同意设置,因此此步骤会在激活前执行。(技能:ConsentType=ImplicitOptIn)service-de-channel-consent-configure - 激活通道 —— 通过REST将更新为
MessagingChannelUsage.DeploymentStatus;服务器端的保存钩子会同步驱动完整的观察者链,一旦MCU达到Provisioning状态且Active,则返回204。此步骤与消息类型无关。(技能:MessagingChannel.IsActive=true)service-de-channel-activate
默认支持恢复。每个步骤都是幂等的——如果在失败后重新运行,编排器会检测现有状态并跳过已成功完成的步骤。
流程中提示。如果初始请求中未包含,编排器会先进行提示。路由选择(选择队列/创建新队列)会在步骤2执行时进行提示,而非提前提示——这样可保持子技能的独立性。
{MESSAGE_TYPE}Reference File Index
参考文件索引
| Reference file | Load when |
|---|---|
| You need the full input field list — MESSAGE_TYPE/ORG_ALIAS plus per-type fields for WhatsApp, LINE, AppleBusinessChat, Facebook, Text (SMS). |
| Rendering the Stage 0.5 disclaimer and certification prompt — verbatim text and per-type label/third-party mappings. |
| Wiring error handling or parsing the canonical success/failure/terms-declined JSON envelope shapes. |
| The orchestrator fails mid-way and you need to render the partial-success/resume report. |
| Debugging unexpected behavior — duplicate-key errors, resume/idempotency questions, preflight SOQL shape, unattended/CI usage. |
| You need a reference trace (fresh WhatsApp run, resume after failure, Apple dispatch, unsupported-type rejection) for exact envelope shapes. |
| 参考文件 | 加载时机 |
|---|---|
| 需要完整的输入字段列表时——包括MESSAGE_TYPE/ORG_ALIAS以及WhatsApp、LINE、AppleBusinessChat、Facebook、Text(SMS)的特定类型字段。 |
| 显示0.5阶段的免责声明和确认提示时——包含原文文本以及各类型的标签/第三方映射。 |
| 处理错误或解析标准的成功/失败/条款拒绝JSON信封格式时。 |
| 编排器中途失败,需要显示部分成功/恢复报告时。 |
| 调试意外行为时——包括重复键错误、恢复/幂等性问题、预检查SOQL格式、无人值守/CI使用场景。 |
| 需要参考跟踪记录时(如新WhatsApp运行、失败后恢复、Apple调度、不支持类型的拒绝),以获取准确的信封格式。 |
Critical execution rule
关键执行规则
This orchestrator MUST run all stages (0-5) in a SINGLE response without stopping between stages.
When you invoke a leaf skill (service-de-channel-create, service-de-channel-routing-configure, service-de-channel-consent-configure, service-de-channel-activate) and it returns via function_results:
- DO: Immediately parse the function_results return value and continue to the next stage
- DO: Run Stage 0.5 → Stage 1 → Stage 2 → Stage 3 → Stage 3.5 → Stage 4 → Stage 5 consecutively in ONE response
- DO NOT: Stop and report back to the user between stages
- DO NOT: Wait for user confirmation between stages
- DO NOT: Treat each stage as a separate turn in the conversation
Why this matters: The user invoked THIS orchestrator skill to get an end-to-end activated channel. They did NOT invoke the individual leaf skills. Your job is to run the entire pipeline autonomously and report the final result. Stopping mid-flow breaks the orchestrator pattern and forces the user to manually resume each stage.
Exception: Only stop mid-flow if a leaf skill returns with a terminal error (not a recoverable prompt), or if the user declines the Stage 0.5 Terms and Conditions gate (emit and halt). Then report the failure immediately with context about which stage failed and what state was reached.
ok: falseterms-not-acceptedStage 0.5 is a required blocking prompt. The Terms and Conditions gate is the one prompt that must be answered affirmatively before any org work. It is not optional and must not be auto-accepted. A /decline ends the run per the exception above; a continues to Stage 1 in the same response.
noyesLeaf skill prompts: Some leaf skills (like or ) may prompt the user for input mid-execution. That's fine — answer those prompts as they come up, but then CONTINUE to the next stage immediately after the prompt is answered. Don't stop just because a prompt was involved.
service-de-waba-integrateservice-de-channel-routing-configure此编排器必须在单个响应中运行所有阶段(0-5),阶段之间不得停止。
当调用子技能(service-de-channel-create、service-de-channel-routing-configure、service-de-channel-consent-configure、service-de-channel-activate)并通过function_results返回结果时:
- 必须: 立即解析function_results的返回值并继续执行下一阶段
- 必须: 在同一个响应中连续执行阶段0.5 → 阶段1 → 阶段2 → 阶段3 → 阶段3.5 → 阶段4 → 阶段5
- 禁止: 在阶段之间停止并向用户报告
- 禁止: 在阶段之间等待用户确认
- 禁止: 将每个阶段视为对话中的独立回合
为什么这很重要: 用户调用此编排器技能是为了获得端到端的已激活通道。他们并未调用单个子技能。你的任务是自主运行整个流程并报告最终结果。中途停止会破坏编排器模式,迫使用户手动恢复每个阶段。
例外情况: 只有当子技能返回且包含终端错误(不可恢复的提示除外),或者用户拒绝了0.5阶段的条款和条件门限(发出并停止)时,才可以中途停止。然后立即报告失败,并说明哪个阶段失败以及达到了什么状态。
ok: falseterms-not-accepted0.5阶段是必填的阻塞式提示。 条款和条件门限是必须得到用户肯定答复后才能执行任何组织操作的提示。它是必填项,不得自动接受。如果用户回答“否”/拒绝,则按照上述例外情况终止运行;如果回答“是”,则在同一响应中继续执行阶段1。
子技能提示: 某些子技能(如或)可能会在执行过程中提示用户输入。这是允许的——在回答提示后立即继续执行下一阶段。不要因为出现提示就停止运行。
service-de-waba-integrateservice-de-channel-routing-configureWhen NOT to use this skill
不适用本技能的场景
- You only want one step. Invoke the leaf skill directly (,
service-de-channel-create,service-de-channel-routing-configure). This orchestrator is for the full automated path from nothing → activated channel.service-de-channel-activate - You want to run stages independently in separate conversation turns. This orchestrator runs all stages consecutively in one response. If you need manual control between stages, invoke the leaf skills individually.
- You want a message type outside /
WhatsApp/Line/AppleBusinessChat/Facebook. The dispatcher will returnText. WeChat / MsCopilot / Alexa would need their own leaves + a dispatcher update.unsupported-type - The prereq hasn't been met (WABA not shared, LINE channel not created, Apple account not registered, SMS number not provisioned). The per-type insert skill's Stage 2-equivalent surfaces this clearly and returns; no orchestration fixes it. (For SMS/Text the number-provisioning prereq isn't checked at insert — an unprovisioned number surfaces later as an activation-time .)
provisioning-error
- 仅需要执行单个步骤。直接调用子技能(、
service-de-channel-create、service-de-channel-routing-configure)。此编排器适用于从无到有→已激活通道的完整自动化路径。service-de-channel-activate - 希望在对话的不同回合中独立运行各个阶段。此编排器会在一个响应中连续运行所有阶段。如果需要在阶段之间进行手动控制,请单独调用子技能。
- 需要支持/
WhatsApp/Line/AppleBusinessChat/Facebook之外的消息类型。调度器会返回Text。WeChat/MsCopilot/Alexa需要各自的子技能+调度器更新。unsupported-type - 未满足前置要求(WABA未共享、LINE通道未创建、Apple账户未注册、SMS号码未配置)。各类型的插入技能的等效阶段2会明确显示此问题并返回结果;编排无法解决此问题。(对于SMS/Text,插入时不会检查号码配置要求——未配置的号码会在激活阶段显示为。)
provisioning-error
Inputs (from user)
用户输入
{MESSAGE_TYPE}{ORG_ALIAS}references/inputs.md{MESSAGE_TYPE}{ORG_ALIAS}references/inputs.mdOutput (to user)
输出给用户
Three top-level outcomes: success, step-annotated failure, and terms-declined. Load and follow it for the exact JSON shapes.
references/output-envelopes.md三种顶层结果:成功、带步骤注释的失败、条款拒绝。加载并按照其中的说明操作,获取准确的JSON格式。
references/output-envelopes.mdStage 0: Resolve {MESSAGE_TYPE}
and type-specific key
{MESSAGE_TYPE}阶段0:解析{MESSAGE_TYPE}
和特定类型密钥
{MESSAGE_TYPE}If is omitted, prompt the user (see "Inputs" above). Refuse to proceed without one — there's no sensible default.
{MESSAGE_TYPE}Once known, determine the preflight key — the field we'll filter the SOQL on to detect existing state. It's always , but what that value is varies by type:
MessagingChannelMessagingPlatformKey | Preflight key value | Notes |
|---|---|---|
| | Required upfront |
| | Required upfront |
| | Required upfront |
| | Optional - OAuth → fetch pages → prompt if not provided |
| | Required upfront (the phone number / short code itself) |
Facebook is unique: If is not provided, the orchestrator cannot run its own Stage 1 preflight. Instead, skip Stage 1 and let handle the full OAuth → page selection → preflight → creation flow. The insertion skill has its own Stage 1 preflight that runs after page selection.
{PAGE_ID}service-de-channel-createFor non-Facebook types, validate that the caller provided the required type-specific inputs for (see Inputs above). If missing, prompt or halt — don't call the dispatcher, it will re-validate and return , wasting a round trip.
{MESSAGE_TYPE}missing-input如果省略,则提示用户(参见上面的“输入”部分)。拒绝在未提供该参数的情况下继续——没有合理的默认值。
{MESSAGE_TYPE}确定后,找到预检查密钥——我们将在的SOQL查询中使用此字段来检测现有状态。此字段始终是,但其值因类型而异:
MessagingChannelMessagingPlatformKey | 预检查密钥值 | 说明 |
|---|---|---|
| | 必须提前提供 |
| | 必须提前提供 |
| | 必须提前提供 |
| | 可选 - OAuth → 获取页面 → 若未提供则提示 |
| | 必须提前提供(电话号码/短码本身) |
Facebook是特殊情况: 如果未提供,编排器无法运行自己的阶段1预检查。此时跳过阶段1,让处理完整的OAuth→页面选择→预检查→创建流程。插入技能在页面选择后会运行自己的阶段1预检查。
{PAGE_ID}service-de-channel-create对于非Facebook类型,验证调用者是否提供了所需的特定类型输入(参见上面的“输入”部分)。如果缺失,则提示或终止——不要调用调度器,因为它会重新验证并返回,浪费一次往返。
{MESSAGE_TYPE}missing-inputStage 0.5: Enhanced Messaging Terms and Conditions (blocking gate)
阶段0.5:增强型消息服务条款和条件(阻塞式门限)
Run this before any org query or channel work. The in-org "Add a Channel" wizard requires the admin to accept the Enhanced Messaging Terms and Conditions before it will let them proceed to channel setup. The headless flow must enforce the same gate — do not skip it, do not accept on the user's behalf. This runs once per orchestrator invocation, after is known (the disclaimer names the channel) and before Stage 1.
{MESSAGE_TYPE}Render the disclaimer and certification prompt from (verbatim, substituting the channel label) — load it and follow it for the exact wording and per-type label/third-party mappings.
references/terms-and-conditions.mdGate behavior:
- If the user answers yes (affirmative acceptance), record and continue to Stage 1.
{TC_ACCEPTED} = true - If the user answers no, declines, or does not affirmatively accept, halt immediately — do not run Stage 1 or any subsequent stage. Emit:
json
{"ok": false, "kind": "terms-not-accepted", "hint": "user did not accept the Enhanced Messaging Terms and Conditions — channel setup cannot proceed. Re-run when ready to accept."} - Acceptance is required on every orchestrator invocation, including resume runs. It is a per-session gate, not persisted — we don't have a place to durably record it, and the cost of re-confirming is one prompt.
在执行任何组织查询或通道操作前运行此阶段。 组织内的“添加通道”向导要求管理员接受增强型消息服务的条款和条件后才能继续通道设置。无头流程必须强制执行相同的门限——不得跳过,不得代表用户接受。此阶段在每次调用编排器时运行一次,在确定之后(免责声明会提及通道),阶段1之前。
{MESSAGE_TYPE}从中加载并显示免责声明和确认提示(原文,替换通道标签)——按照其中的说明操作,获取准确的措辞以及各类型的标签/第三方映射。
references/terms-and-conditions.md门限行为:
- 如果用户回答是(肯定接受),记录并继续执行阶段1。
{TC_ACCEPTED} = true - 如果用户回答否、拒绝或未明确接受,立即终止——不要运行阶段1或任何后续阶段。发出:
json
{"ok": false, "kind": "terms-not-accepted", "hint": "user did not accept the Enhanced Messaging Terms and Conditions — channel setup cannot proceed. Re-run when ready to accept."} - 每次调用编排器(包括恢复运行)都需要接受条款。这是每个会话的门限,不会持久化——我们没有持久记录的位置,重新确认的成本只是一次提示。
Stage 1: Pre-flight state detection (resume support)
阶段1:预检查状态检测(支持恢复)
Skip this stage entirely if and was not provided. The Facebook insertion skill needs to run OAuth first before we know which PAGE_ID to check for. Let the insertion skill handle its own preflight in Stage 1 after page selection.
MESSAGE_TYPE=Facebook{PAGE_ID}For all other cases, query the org to see how far a prior run got. This enables skip-ahead on resume. Two queries, not a subquery — the subquery fails on some orgs where the child relationship is unnameable. Use FK-keyed second query instead (see gotcha #9).
(SELECT ... FROM MessagingChannelUsages)bash
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeveloperName, MessageType, IsActive, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE MessagingPlatformKey = '{PLATFORM_KEY}' AND MessageType = '{MESSAGE_TYPE}'" \
--json > /tmp/hcs-preflight.jsonIf the channel query returns a row, fire a second query to resolve its MCU:
bash
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeploymentStatus FROM MessagingChannelUsage WHERE MessagingChannelId = '{CHANNEL_ID}'" \
--json > /tmp/hcs-preflight-mcu.jsonParse the combined result to figure out :
{CURRENT_STATE}| Preflight result | | First step to run |
|---|---|---|
| No records | | Step 1 (insert) |
Record exists, | | Step 2 (configure routing) |
Record exists, | | Step 3 (configure consent), then Step 4 (activate) |
Record exists, | | Emit no-op success envelope; return. |
Record the existing and if present — downstream steps need them.
{CHANNEL_ID}{MCU_ID}Initialize , , .
{STEPS_RUN} = []{STEPS_SKIPPED} = []{T0} = Date.now()如果且未提供,则完全跳过此阶段。 Facebook插入技能需要先运行OAuth,然后才能知道要检查哪个PAGE_ID。让插入技能在页面选择后的阶段1中处理自己的预检查。
MESSAGE_TYPE=Facebook{PAGE_ID}对于其他所有情况,查询组织以查看之前的运行进展到了哪一步。这支持在恢复时跳过已完成的步骤。使用两个查询,而非子查询——子查询在某些组织中会失败,因为子关系无法命名。改用外键关联的第二个查询(参见陷阱#9)。
(SELECT ... FROM MessagingChannelUsages)bash
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeveloperName, MessageType, IsActive, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE MessagingPlatformKey = '{PLATFORM_KEY}' AND MessageType = '{MESSAGE_TYPE}'" \
--json > /tmp/hcs-preflight.json如果通道查询返回行,则执行第二个查询以解析其MCU:
bash
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeploymentStatus FROM MessagingChannelUsage WHERE MessagingChannelId = '{CHANNEL_ID}'" \
--json > /tmp/hcs-preflight-mcu.json解析组合结果以确定:
{CURRENT_STATE}| 预检查结果 | | 要运行的第一个步骤 |
|---|---|---|
| 无记录 | | 步骤1(插入) |
存在记录, | | 步骤2(配置路由) |
存在记录, | | 步骤3(配置同意设置),然后步骤4(激活) |
存在记录, | | 发出无操作成功信封;返回。 |
记录现有的和(如果存在)——后续步骤需要这些值。
{CHANNEL_ID}{MCU_ID}初始化,,。
{STEPS_RUN} = []{STEPS_SKIPPED} = []{T0} = Date.now()Stage 2: Insert the channel (step 1 of 4)
阶段2:插入通道(4个步骤中的第1步)
Skip this stage if ∈ — the channel already exists. Append to in that case.
CURRENT_STATE{inserted-no-routing, routed-not-active, already-active}"insert"STEPS_SKIPPEDOtherwise invoke with:
service-de-channel-create- = (from Stage 0)
{MESSAGE_TYPE} - All type-specific inputs (forwarded verbatim — dispatcher routes to the right leaf)
{ORG_ALIAS}
The insertion skill handles per-type prereqs internally (e.g., for WhatsApp, invokes as its Stage 2). This orchestrator doesn't need to know about WABA linking, LINE token verification, or Apple registration — owns the prereq semantics for whichever type it's running.
service-de-channel-createservice-de-waba-integrateservice-de-channel-createHandle the envelope:
| Leaf envelope | Orchestrator action |
|---|---|
| Record |
| These come from the per-type prereq stage. Pass through as |
| Should have been caught in Stage 0 — emit failure with |
| Emit failure envelope with |
At this point we have and regardless of whether step 1 ran or was skipped.
{CHANNEL_ID}{MCU_ID}→ Continue immediately to Stage 3 in this same response. DO NOT STOP.
如果 ∈ ,则跳过此阶段——通道已存在。此时将添加到中。
CURRENT_STATE{inserted-no-routing, routed-not-active, already-active}"insert"STEPS_SKIPPED否则调用,参数包括:
service-de-channel-create- = (来自阶段0)
{MESSAGE_TYPE} - 所有特定类型输入(原样转发——调度器会路由到正确的子技能)
{ORG_ALIAS}
插入技能会在内部处理各类型的前置要求(例如,对于WhatsApp,会调用作为其阶段2)。此编排器无需了解WABA链接、LINE令牌验证或Apple注册——负责处理其运行的任何类型的前置要求语义。
service-de-channel-createservice-de-waba-integrateservice-de-channel-create处理信封:
| 子技能信封 | 编排器操作 |
|---|---|
| 记录 |
| 这些来自各类型的前置要求阶段。原样传递,设置 |
| 本应在阶段0中捕获——发出失败信息,设置 |
| 发出失败信封,设置 |
此时无论步骤1是否运行或被跳过,我们都已获得和。
{CHANNEL_ID}{MCU_ID}→ 立即在同一个响应中继续执行阶段3。禁止停止。
Stage 3: Configure routing (step 2 of 4)
阶段3:配置路由(4个步骤中的第2步)
Skip this stage if — routing is already set. Append to .
CURRENT_STATE === "routed-not-active""route"STEPS_SKIPPEDOtherwise invoke :
service-de-channel-routing-configure- = recorded above
{CHANNEL_ID} {ORG_ALIAS}
This is the step that prompts the user for queue choice (pick existing / create new / escape hatch). Don't try to pre-empt the prompts — forward the user's answers as-is.
Handle the envelope:
| Leaf envelope | Orchestrator action |
|---|---|
| Record |
| User chose flow/user/asa/aea. Emit partial-success with |
| Emit failure envelope with |
→ Continue immediately to Stage 3.5 in this same response. DO NOT STOP.
如果,则跳过此阶段——路由已设置。将添加到中。
CURRENT_STATE === "routed-not-active""route"STEPS_SKIPPED否则调用:
service-de-channel-routing-configure- = 上面记录的值
{CHANNEL_ID} {ORG_ALIAS}
此步骤会提示用户选择队列(选择现有队列/创建新队列/退出)。不要提前提示——原样转发用户的回答。
处理信封:
| 子技能信封 | 编排器操作 |
|---|---|
| 记录 |
| 用户选择了flow/user/asa/aea。发出部分成功信息,设置 |
| 发出失败信封,设置 |
→ 立即在同一个响应中继续执行阶段3.5。禁止停止。
Stage 3.5: Configure consent (before activation)
阶段3.5:配置同意设置(激活前)
Activation's readiness check requires consent AND routing — a fully-routed channel still fails to activate if consent isn't configured. Invoke :
service-de-channel-consent-configure- = recorded above
{CHANNEL_ID} - ,
{CONSENT_TYPE}, and the keyword/prompt values — forward whatever the user supplied; omit what they didn't{LANGUAGE} {ORG_ALIAS}
This stage ensures consent is activation-ready — it doesn't always write. The Connect insert auto-seeds plus a default opt-out , which already satisfies the readiness check. So the leaf's Stage 1 will frequently find the channel already ready and return — the expected outcome on a fresh channel, not a bug. It performs a real write only to upgrade (ExplicitOptIn/DoubleOptIn) or override the seeded keywords/prompts. When the user pre-supplied inputs asking for an upgrade, expect a write and let the leaf prompt for missing values — don't suppress those prompts.
ConsentType=ImplicitOptInMsgChannelLanguageKeywordnoop: trueImplicitOptInHandle the envelope:
| Leaf envelope | Orchestrator action |
|---|---|
| Append |
| Shouldn't happen — these skills only create Enhanced channels. Emit failure with |
| The user didn't supply a required keyword/prompt for the chosen ConsentType. Emit failure with |
| Emit failure with |
→ Continue immediately to Stage 4 in this same response. DO NOT STOP.
激活的就绪检查需要同意设置和路由——即使通道已完全配置路由,如果未配置同意设置,激活仍会失败。调用:
service-de-channel-consent-configure- = 上面记录的值
{CHANNEL_ID} - 、
{CONSENT_TYPE}以及关键词/提示值——转发用户提供的所有值,省略未提供的值{LANGUAGE} {ORG_ALIAS}
此阶段确保同意设置满足激活要求——并非总是需要写入数据。插入通道时会自动生成 + 默认退订,这已经满足就绪检查。因此子技能的阶段1通常会发现通道已经就绪并返回——这是新创建的通道的预期结果,而非错误。只有在升级(ExplicitOptIn/DoubleOptIn)或覆盖生成的关键词/提示时,才会执行实际写入。当用户提前提供了要求升级的输入时,预期会执行写入操作,让子技能提示缺失的值——不要抑制这些提示。
ConsentType=ImplicitOptInMsgChannelLanguageKeywordnoop: trueImplicitOptIn处理信封:
| 子技能信封 | 编排器操作 |
|---|---|
| 将 |
| 不应发生——这些技能仅创建增强型通道。发出失败信息,设置 |
| 用户未提供所选ConsentType所需的关键词/提示。发出失败信息,设置 |
| 发出失败信息,设置 |
→ 立即在同一个响应中继续执行阶段4。禁止停止。
Stage 4: Activate (step 4 of 4)
阶段4:激活通道(4个步骤中的第4步)
Always run (unless , in which case Stage 1 returned early).
CURRENT_STATE === "already-active"Invoke :
service-de-channel-activate- = recorded above
{CHANNEL_ID} {ORG_ALIAS}
No timeout knobs — activation is a single synchronous PATCH. The leaf does a defensive poll if the server ever returns mid-transition, but the expected path is one round-trip.
Handle the envelope:
| Leaf envelope | Orchestrator action |
|---|---|
| Record results. Append |
| Unusual (we just set it) — probably a race or permission issue. Emit failure with a hint about the permissions check. Return. |
| Shouldn't happen after successful insert. Emit failure with the leaf's envelope. Return. |
| |
| Third-party side rejected (Meta |
| REST call failed at the HTTP layer (401 from |
始终运行此阶段(除非,此时阶段1已提前返回)。
CURRENT_STATE === "already-active"调用:
service-de-channel-activate- = 上面记录的值
{CHANNEL_ID} {ORG_ALIAS}
没有超时设置——激活是单个同步PATCH操作。如果服务器返回中间过渡状态,子技能会进行防御性轮询,但预期路径是一次往返。
处理信封:
| 子技能信封 | 编排器操作 |
|---|---|
| 记录结果。将 |
| 不常见(我们刚设置完路由)——可能是竞争条件或权限问题。发出失败信息并提示检查权限。返回。 |
| 插入成功后不应发生。发出失败信息并传递子技能的信封。返回。 |
| |
| 第三方拒绝(Meta |
| REST调用在HTTP层失败( |
Stage 5: Final report
阶段5:最终报告
Build the success envelope:
json
{
"ok": true,
"messageType": "{MESSAGE_TYPE}",
"channelId": "{CHANNEL_ID}",
"mcuId": "{MCU_ID}",
"channelName": "{CHANNEL_NAME or inferred}",
"sessionHandlerId": "{SESSION_HANDLER_ID}",
"queueName": "{QUEUE_NAME}",
"isActive": true,
"stepsRun": [...],
"stepsSkipped": [...],
"totalDurationMs": Date.now() - T0
}Render to the user as:
text
Success — {MESSAGE_TYPE} channel '{CHANNEL_NAME}' is live on {ORG_ALIAS}.
Channel ID: {CHANNEL_ID}
Routed to: {queueName} ({SESSION_HANDLER_ID})
Steps: ran {STEPS_RUN.join(", ")}{, skipped " + STEPS_SKIPPED.join(", ") if any}
Total time: {formatted from durationMs}If any step was skipped due to resume, the report should make that visible.
构建成功信封:
json
{
"ok": true,
"messageType": "{MESSAGE_TYPE}",
"channelId": "{CHANNEL_ID}",
"mcuId": "{MCU_ID}",
"channelName": "{CHANNEL_NAME or inferred}",
"sessionHandlerId": "{SESSION_HANDLER_ID}",
"queueName": "{QUEUE_NAME}",
"isActive": true,
"stepsRun": [...],
"stepsSkipped": [...],
"totalDurationMs": Date.now() - T0
}向用户显示为:
text
Success — {MESSAGE_TYPE} channel '{CHANNEL_NAME}' is live on {ORG_ALIAS}.
Channel ID: {CHANNEL_ID}
Routed to: {queueName} ({SESSION_HANDLER_ID})
Steps: ran {STEPS_RUN.join(", ")}{, skipped " + STEPS_SKIPPED.join(", ") if any}
Total time: {formatted from durationMs}如果由于恢复而跳过了任何步骤,报告中应明确显示这一点。
Partial-success and resume reporting
部分成功和恢复报告
If the orchestrator fails mid-way, the envelope always includes describing what landed. must always carry both and (each an array, empty if nothing landed/skipped yet) alongside the fields that landed — the partial-success renderer reads both. When rendering a failure, load and follow it — it has the exact template for showing which steps already landed and how to retry.
stateSoFarstateSoFarstepsRunstepsSkippedreferences/partial-success.md如果编排器中途失败,信封始终包含字段,描述已完成的操作。必须始终包含和(均为数组,如果尚未完成/跳过任何步骤则为空)以及已完成的字段——部分成功渲染器会读取这两个字段。显示失败信息时,加载并按照其中的说明操作——其中包含显示已完成步骤以及如何重试的准确模板。
stateSoFarstateSoFarstepsRunstepsSkippedreferences/partial-success.mdWorked examples
示例
For reference traces (fresh WhatsApp run, resume after routing failure, Apple dispatch, unsupported-type rejection), see .
references/worked-examples.md有关参考跟踪记录(新WhatsApp运行、路由失败后恢复、Apple调度、不支持类型的拒绝),请参见。
references/worked-examples.mdGotchas
陷阱
Nine known gotchas covering prereq ownership, uniqueness, resume semantics, CSOT-only support, error-classification boundaries, prompt placement, platform-key mapping, wall-clock duration, and the two-query preflight workaround. When debugging unexpected behavior, load and follow it.
MessagingPlatformKeyreferences/gotchas.md九个已知陷阱,涵盖前置要求归属、唯一性、恢复语义、仅CSOT支持、错误分类边界、提示位置、平台密钥映射、挂钟时长以及双查询预检查解决方法。调试意外行为时,加载并按照其中的说明操作。
MessagingPlatformKeyreferences/gotchas.md