关于 service-de-channel-routing-configure
为已创建的 Salesforce 增强型消息渠道配置并验证路由,面向管理消息渠道的操作者。支持队列、Flow、Agentforce Service Agent、Digital Worker 和用户目标,并检查目标资格及备用队列要求。
主要功能
- 01配置五类 SessionHandler 路由
- 02按需创建队列及路由配置
- 03验证现有路由目标状态
- 04按目标类型校验备用队列
- 05通过 sf CLI 查询并更新渠道
适用场景
- 01为新建的消息渠道设置路由
- 02核验已有渠道的路由目标
- 03排查缺少备用队列或无效目标
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill service-de-channel-routing-configure安装后在 Claude Code 中输入/service-de-channel-routing-configure确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/asa-routing.mdgotchas.mdqueue-creation.mdtarget-locate.mdworked-examples.mdscripts/tests/test_skill_contract.py详细介绍
配置渠道路由
此技能的作用
确保在激活 MessagingChannel 之前已配置有效路由。渠道的 SessionHandler 字段是一个多态外键(已根据 MessagingChannel.entity.xml 验证,domain="Queue, FlowDefinition, User, BotDefinition, AgenticCtxtDecorDefinition")——它指定渠道将传入会话路由给谁。某些目标还需要 FallbackQueue(一个全渠道队列,用于接收主目标无法处理的会话)。
这些技能会创建 Enhanced 渠道(PlatformType=Enhanced、SCRT2)。Enhanced 渠道的五种 SessionHandler 域均可写入。(Standard/SCRT1 渠道仅接受 Flow 作为 SessionHandler——服务器会拒绝其他域,并返回 "Only flows of type Omni-Channel are supported"。这些技能不会创建 Standard 渠道,因此不处理这种情况。)
适用流程: 渠道由 service-de-channel-create(或按类型划分的叶技能)插入;本技能设置路由;service-de-channel-settings-configure 设置许可;然后 service-de-channel-activate 将其设为启用状态——激活需要同时配置路由和许可。service-de-headless-channel-configure 编排器会按顺序运行这四个步骤。
支持的路由类型——均设置 SessionHandlerId,部分类型还会设置 FallbackQueueId:
| 类型 | SessionHandler 目标 | ID 前缀 | FallbackQueue |
|---|---|---|---|
| 全渠道队列 | Group(Type=Queue) | 00G | 必须为 null |
| Omni-Flow | FlowDefinition(ProcessType=RoutingFlow) | 300 | 必需 |
| Agentforce 服务 Agent(ASA) | BotDefinition(Type=ExternalCopilot) | 0Xx | 必需 |
| Digital Worker | AgenticCtxtDecorDefinition | 1iE | 必需 |
| 用户 | User(带有 RoutingConfiguration) | 005 | 必须为 null |
配置行为:
- 队列——选择现有的、支持
MessagingSession的队列,或通过 Metadata API 创建新队列和 QueueRoutingConfig。 - Flow / ASA / Digital Worker / 用户——查找符合条件的现有目标并对其执行 PATCH。这些技能不会创建 Flow、机器人、数字工作者或用户——如果没有符合条件的目标,技能会报告前置条件,并指引用户前往 Setup。
参考文件索引
| 参考文件 | 何时加载 |
|---|---|
references/queue-creation.md | 用户在队列路由流程中选择“创建新队列”时——完整的 Metadata API 脚手架 → 部署 → ID 查询 → 可选的成员添加。 |
references/target-locate.md | 需要按域查找并验证符合条件的目标(队列、Flow、ASA、Digital Worker、用户)的 SOQL,以及 FallbackQueue 要求矩阵时。 |
references/asa-routing.md | 用户选择 ASA(Agentforce Service Agent)路由时——前置条件检查、列出运行中的 ASA 并进行选择。 |
references/gotchas.md | 排查意外结果,或修改此技能之前——查看已知注意事项。 |
references/worked-examples.md | 需要参考复用现有队列、创建新队列、Flow 或 ASA 流程的运行示例时。 |
不要使用此技能的情况
- 渠道已经设置了
SessionHandlerId或FallbackQueueId。 本技能会先重新验证现有目标,然后才执行无操作处理。ASA 仍必须具有 BotUser 和 Active BotVersion;否则会报告asa-target-inactive,且不会声称已就绪。 - 渠道尚不存在。 请先运行插入技能;本技能要求存在真实的
MessagingChannel.Id。 - 你想替换现有路由。 更安全的做法是在 UI 中手动清除
SessionHandlerId,然后重新运行本技能。无操作检查是安全措施,不是值得自动绕过的限制。
输入(由调用方提供)
{CHANNEL_ID}— 15 或 18 个字符的MessagingChannel.Id(前缀为0Mj)。频道必须已存在。{ORG_ALIAS}— 可选;sfCLI 目标组织别名。默认值:sf config get target-org返回的值。所有 SOQL、PATCH 和 Metadata 部署都针对此组织运行。
输出(返回给调用方)
以下其中之一:
成功 — 无需更改:
{"ok": true, "noop": true, "routingType": "queue|flow|asa|digital_worker|user", "sessionHandlerId": "00G...|300...|0Xx...|1iE...|005...", "fallbackQueueId": "00G...|null", "targetName": "...", "message": "Routing already configured"}
成功 — 队列路由已配置:
{"ok": true, "routingType": "queue", "sessionHandlerId": "00G...", "fallbackQueueId": null, "queueName": "...", "queueDeveloperName": "...", "created": true|false}
成功 — Flow 路由已配置:
{"ok": true, "routingType": "flow", "sessionHandlerId": "300...", "fallbackQueueId": "00G...", "flowName": "...", "flowDeveloperName": "...", "created": false}
成功 — ASA 路由已配置:
{"ok": true, "routingType": "asa", "sessionHandlerId": "0Xx...", "fallbackQueueId": "00G...", "asaName": "...", "asaDeveloperName": "...", "botUserId": "005...", "botVersionId": "0X9...", "created": false}
成功 — Digital Worker 路由已配置:
{"ok": true, "routingType": "digital_worker", "sessionHandlerId": "1iE...", "fallbackQueueId": "00G...", "workerName": "...", "created": false}
成功 — 用户路由已配置:
{"ok": true, "routingType": "user", "sessionHandlerId": "005...", "fallbackQueueId": null, "userName": "...", "created": false}
未满足前置条件:
{"ok": false, "kind": "no-eligible-target", "routingType": "flow|asa|digital_worker|user", "hint": "no eligible <target> found on this org — <how to create one in Setup>, then re-run this skill"}
{"ok": false, "kind": "no-fallback-queue", "hint": "Flow/ASA/Digital Worker routing requires a FallbackQueue but no MessagingSession-capable queue exists — create one (Queue routing path) first"}
{"ok": false, "kind": "asa-not-supported", "hint": "this org doesn't have BotDefinition (Agentforce not licensed); use Queue routing instead"}
{"ok": false, "kind": "standard-channel", "hint": "this is a Standard (SCRT1) channel — only Flow routing is supported; these skills only create Enhanced channels, so this is unexpected"}
失败:
{"ok": false, "kind": "metadata-deploy-failed", "message": "..."}
{"ok": false, "kind": "patch-failed", "message": "..."}
{"ok": false, "kind": "verify-failed", "hint": "PATCH returned success but re-read shows SessionHandlerId still null — permission or trigger issue"}
PATCH 失败的 message 通常会原样包含服务器端验证错误(来自 MessagingChannelFunctionsHelper.validateSessionHandler)。请将其呈现给用户——它会准确指出哪条关联规则未通过。常见错误包括:MissingFallbackQueueForFlowRouting / ...ForAsaRouting / ...ForDigitalWorkerRouting(必须设置 FallbackQueue,但其值为 null)、UnsupportedFallbackQueue(在必须为 null 的 Queue/User 路径上设置了 FallbackQueue)、InvalidSessionHandlerFlowType(Flow 的 ProcessType 不是 RoutingFlow,或者频道为 Standard/SCRT1)、NoRoutingConfigDefined(User 没有 RoutingConfiguration)。
阶段 1:读取当前路由状态
查询频道。如果频道已有 SessionHandlerId 或 FallbackQueueId,则不作更改。否则,继续。
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, DeveloperName, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE Id = '{CHANNEL_ID}'" \
--json > /tmp/ccr-channel.json
使用 node -e 或 jq 解析。如果记录不存在,则停止并返回:Error: Channel {CHANNEL_ID} not found — check the id, or run the insertion skill first.
如果 SessionHandlerId 非 null,根据 Id 前缀判断现有路由目标,然后使用相应的成功响应封装并结束。前缀与 SessionHandler 域一一对应(已通过 MessagingChannel.entity.xml 验证)。现有路由不一定处于健康状态:只有目标查询恰好返回一条符合条件的记录,才能报告成功且无需更改。
| 前缀 | 域 / 目标 | 查询语句 | routingType |
|---|---|---|---|
00G | Group (Type=Queue) | SELECT Id, Name, DeveloperName FROM Group WHERE Id='<sh>' AND Type='Queue' | queue |
300 | FlowDefinition | SELECT DurableId, Label, ApiName FROM FlowDefinitionView WHERE DurableId='<sh>' | flow |
0Xx | BotDefinition (ASA) | SELECT Id, DeveloperName, MasterLabel, AgentType, BotUserId, (SELECT Id, Status FROM BotVersions WHERE Status='Active' LIMIT 1) FROM BotDefinition WHERE Id='<sh>' | asa |
1iE | AgenticCtxtDecorDefinition (Digital Worker) | SELECT Id, DeveloperName, MasterLabel FROM AgenticCtxtDecorDefinition WHERE Id='<sh>' | digital_worker |
005 | User | SELECT Id, Name FROM User WHERE Id='<sh>' | user |
SESSION_HANDLER_ID="$(node -e 'console.log(JSON.parse(require("fs").readFileSync("/tmp/ccr-channel.json","utf8")).result.records[0].SessionHandlerId)')"
PREFIX="${SESSION_HANDLER_ID:0:3}"
case "$PREFIX" in
00G) sf data query --target-org '{ORG_ALIAS}' --query "SELECT Id, Name, DeveloperName FROM Group WHERE Id = '$SESSION_HANDLER_ID' AND Type = 'Queue'" --json > /tmp/ccr-noop-target.json ;;
300) sf data query --target-org '{ORG_ALIAS}' --query "SELECT DurableId, Label, ApiName FROM FlowDefinitionView WHERE DurableId = '$SESSION_HANDLER_ID'" --json > /tmp/ccr-noop-target.json ;;
0Xx) sf data query --target-org '{ORG_ALIAS}' --query "SELECT Id, DeveloperName, MasterLabel, AgentType, BotUserId, (SELECT Id, Status FROM BotVersions WHERE Status='Active' LIMIT 1) FROM BotDefinition WHERE Id = '$SESSION_HANDLER_ID'" --json > /tmp/ccr-noop-target.json ;;
1iE) sf data query --target-org '{ORG_ALIAS}' --query "SELECT Id, DeveloperName, MasterLabel FROM AgenticCtxtDecorDefinition WHERE Id = '$SESSION_HANDLER_ID'" --json > /tmp/ccr-noop-target.json ;;
005) sf data query --target-org '{ORG_ALIAS}' --query "SELECT Id, Name FROM User WHERE Id = '$SESSION_HANDLER_ID'" --json > /tmp/ccr-noop-target.json ;;
*) echo "{\"records\":[{\"Id\":\"$SESSION_HANDLER_ID\"}]}" > /tmp/ccr-noop-target.json ;;
esac
对于现有 ASA(0Xx),必须确保 BotUserId 非 null,且返回一条 Status='Active' 的 BotVersions 记录。如果缺少其中任一项,请返回以下失败响应,而不要报告成功且无需更改。不要自动清除或替换频道路由:
{"ok":false,"kind":"asa-target-inactive","routingType":"asa","sessionHandlerId":"0Xx...","hint":"The configured Agentforce Service Agent has no BotUser or active BotVersion. Activate the agent in Setup, then re-run routing validation."}
对于其他前缀,必须确保目标查询恰好返回一条记录。仅在通过目标专属的资格检查后,才报告成功且无需更改的响应封装(包含阶段 1 读取到的现有 FallbackQueueId),然后返回。
如果 FallbackQueueId 非 null,但 SessionHandlerId 为 null,仍然不作更改。这是部分配置的 Flow/ASA 状态;不要修改,但请在响应封装的 message 中标记("FallbackQueue set but SessionHandler null — incomplete routing, review in Setup"),因为缺少 SessionHandler 时,激活仍无法通过就绪状态检查。
阶段 2:确认渠道为 Enhanced,然后选择路由类型
首先确认 PlatformType。阶段 1 的读取未包含此项,请将其加入,或重新查询:
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, PlatformType FROM MessagingChannel WHERE Id = '{CHANNEL_ID}'" --json > /tmp/ccr-platform.json
如果 PlatformType != 'Enhanced'(即 Standard/SCRT1),则只有 Flow 路由可写入。这些技能只会创建 Enhanced 渠道,因此此处出现 Standard 渠道并不符合预期——请返回 {ok:false, kind:"standard-channel", ...} 并停止,不要猜测。
然后通过提示词询问用户(切勿自动选择):
The MessagingChannel '{developerName}' ({CHANNEL_ID}) has no routing configured.
Which routing type do you want?
1) queue — Omni-Channel queue routing
2) flow — Omni-Flow (RoutingFlow) + fallback queue
3) asa — Agentforce Service Agent (requires Agentforce license) + fallback queue
4) digital_worker — Digital Worker (Agentic) + fallback queue
5) user — Direct to a specific user (requires a RoutingConfiguration on the user)
Pick [1-5]:
根据用户的选择分支处理。对于所有非队列路径,加载 references/target-locate.md——其中包含各领域的定位 SOQL、资格筛选条件、FallbackQueue 规则以及确切的 PATCH 格式:
- 1(队列)——继续执行下方的阶段 3-Queue。
- 2(flow)——定位符合条件的
FlowDefinition(ProcessType=RoutingFlow,且版本处于活动状态)和一个 FallbackQueue,然后进入阶段 5。 - 3(asa)——继续执行阶段 3-ASA;ASA 也需要 FallbackQueue。
- 4(digital_worker)——定位符合条件的
AgenticCtxtDecorDefinition和一个 FallbackQueue,然后进入阶段 5。 - 5(用户)——定位具有 RoutingConfiguration 的
User,然后进入阶段 5。
如果某个路径未找到符合条件的目标,请返回 {ok:false, kind:"no-eligible-target", routingType, hint}(各领域对应的 Setup 指引见 references/target-locate.md),然后返回——不要捏造 ID。
阶段 3-Queue:选择现有队列,或创建新队列
(此阶段仅在 Queue 路径中运行。ASA 路径:见下方阶段 3-ASA。)
列出符合条件的队列。UI 的路由下拉列表(MessagingRoutingMethodDataProviderController.getOmniQueues)会列出 QueueRoutingConfigId != null 的 Groups——也就是启用了 Omni-Channel 的队列。对于 MessagingChannel,我们还要求队列能够接收 MessagingSession。请查询二者的交集:先列出支持 MessagingSession 的队列,再筛选出具有 QueueRoutingConfig 的队列。
# MessagingSession-capable queues that are also Omni-enabled (QueueRoutingConfigId != null)
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, Name, DeveloperName FROM Group WHERE Type = 'Queue' AND QueueRoutingConfigId != null AND Id IN (SELECT QueueId FROM QueueSobject WHERE SobjectType = 'MessagingSession') ORDER BY Name" \
--json > /tmp/ccr-queues.json
每一行的 Id 都是 00G Group.Id——它将写入 SessionHandlerId。(如果某个组织上的半连接子查询报错,请改用两次查询:先列出 QueueSobject WHERE SobjectType='MessagingSession',然后筛选出 Group.QueueRoutingConfigId != null 的记录。)
向用户提供带编号的列表,并在末尾添加“创建新队列”选项:
Omni-enabled MessagingSession queues on {ORG_ALIAS}:
1) Messaging Queue (Messaging_Queue) — 00GSG0000000LSf2AM
2) MyQueue (MyQueue) — 00GSG000000144n2AA
...
N) Create a new queue
Pick [1-N]:
- 如果用户选择现有队列:将其
Id记录为{QUEUE_ID}(即Group.Id)。跳至阶段 5。 - 如果用户选择“创建新队列”:进入阶段 4。
如果列表为空,并且用户隐式选择(1)“创建新队列”,则直接跳至阶段 4。
阶段 3-Queue(续):通过 Metadata API 创建新 Queue
(Queue 路径的后续阶段。如果用户在上方选择了现有队列,请跳过。)
我们使用最小化的 scratch sfdx 项目(help-agent-accelerator 模式)部署一对 Queue + QueueRoutingConfig,然后查询新 Queue 的 Id,并可选择将当前用户添加为成员。
要通过 Metadata API 创建新 Queue(搭建 sfdx 项目 → 部署 → 查询 ID → 可选添加成员),请加载 references/queue-creation.md 并遵循其中的说明——这是此流程的完整指南。
完成此阶段后,跳转至阶段 5(PATCH)。
阶段 3-ASA:选择现有 ASA
(此阶段仅在 ASA 路径中运行。Queue 路径:跳至阶段 5。)
ASA 路由会将 SessionHandlerId 指向现有且处于运行状态的 Agentforce Service Agent(BotDefinition)。此技能不会创建新的 ASA——它会验证组织是否支持 ASA(已获得 Agentforce 许可),列出处于运行状态且可路由的 ASA,并让用户选择。
**如需检查 ASA 前置条件、列出并选择 ASA,请加载 references/asa-routing.md。**选择完成后,继续执行阶段 5(PATCH)。
第 5 阶段:PATCH MessagingChannel.SessionHandlerId(+ FallbackQueueId)
此时,我们已有 {TARGET_ID} 中的路由目标 ID,并且知道其 {ROUTING_TYPE}:
| routingType | {TARGET_ID} | FallbackQueue 写入 |
|---|---|---|
queue | 00G Group.Id | 无(必须保持为 null) |
flow | 300 FlowDefinition ID | 设置 FallbackQueueId={FALLBACK_QUEUE_ID} |
asa | 0Xx BotDefinition.Id | 设置 FallbackQueueId={FALLBACK_QUEUE_ID} |
digital_worker | 1iE AgenticCtxtDecorDefinition.Id | 设置 FallbackQueueId={FALLBACK_QUEUE_ID} |
user | 005 User.Id | 无(必须保持为 null) |
SessionHandler 是一个多态外键,涵盖 [Group, FlowDefinition, User, BotDefinition, AgenticCtxtDecorDefinition](依据 MessagingChannel.entity.xml;只有拥有 Agentforce 许可证的组织才会有 BotDefinition/AgenticCtxtDecorDefinition 目标)。标准 REST sObject PATCH 接受类型匹配的任意 ID。FallbackQueue 规则由服务端强制执行(validateSessionHandler):Flow/ASA/Digital Worker 不允许 FallbackQueue 为 null;Queue/User 不允许其非 null。
对于 FallbackQueue 路径,在一次 PATCH 中同时写入这两个字段,确保记录不会经过无效的中间状态:
# queue / user — SessionHandler only
sf data update record --target-org '{ORG_ALIAS}' --sobject MessagingChannel \
--record-id '{CHANNEL_ID}' \
--values 'SessionHandlerId={TARGET_ID}' --json > /tmp/ccr-patch.json
# flow / asa / digital_worker — SessionHandler + FallbackQueue together
sf data update record --target-org '{ORG_ALIAS}' --sobject MessagingChannel \
--record-id '{CHANNEL_ID}' \
--values 'SessionHandlerId={TARGET_ID} FallbackQueueId={FALLBACK_QUEUE_ID}' --json > /tmp/ccr-patch.json
如果 status !== 0:发出 {ok:false, kind:"patch-failed", message: ...} 并返回。原样显示服务端消息——其中会指出具体失败的关联规则(参见“输出(给调用方)”下的失败封装说明)。
第 6 阶段:验证
重新读取 channel:
sf data query --target-org '{ORG_ALIAS}' \
--query "SELECT Id, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE Id = '{CHANNEL_ID}'" \
--json
如果重新读取的 SessionHandlerId 不等于 {TARGET_ID},或(对于 flow/asa/digital_worker)FallbackQueueId 不等于 {FALLBACK_QUEUE_ID}:
{"ok": false, "kind": "verify-failed", "hint": "PATCH returned success but re-read shows SessionHandlerId/FallbackQueueId not persisted — check user permissions or field-level security on MessagingChannel"}
否则,发出与路径相符的成功封装(参见本文件顶部的“输出(给调用方)”——每种 routingType 对应一种结构,且都包含 fallbackQueueId)。
第 7 阶段:向调用方报告
报告 JSON 封装。如果此技能是叶节点(由用户直接调用),则输出:
Queue 路径:
Success — Routing configured — channel {CHANNEL_ID} now routes to Queue '{QUEUE_LABEL}' ({QUEUE_ID}).{'' if created else ' (reused existing queue)'}Info: Routing already configured — Queue '{name}' ({QUEUE_ID}). No changes.(无操作路径)
Flow 路径:
Success — Routing configured — channel {CHANNEL_ID} now routes to Omni-Flow '{FLOW_LABEL}' ({TARGET_ID}), fallback Queue {FALLBACK_QUEUE_ID}.
ASA 路径:
Success — Routing configured — channel {CHANNEL_ID} now routes to Agentforce Service Agent '{ASA_LABEL}' ({ASA_ID}), fallback Queue {FALLBACK_QUEUE_ID}. Bot user: {BOT_USER_ID}. Active version: {BOT_VERSION_ID}.Info: Routing already configured — ASA '{MasterLabel}' ({ASA_ID}). No changes.(无操作路径)
Digital Worker 路径:
Success — Routing configured — channel {CHANNEL_ID} now routes to Digital Worker '{WORKER_LABEL}' ({TARGET_ID}), fallback Queue {FALLBACK_QUEUE_ID}.
User 路径:
Success — Routing configured — channel {CHANNEL_ID} now routes directly to User '{USER_NAME}' ({TARGET_ID}).
失败 / 前置条件:
Warning: No eligible {routingType} target found. {per-domain Setup pointer from references/target-locate.md}. Then re-run this skill.(no-eligible-target)Warning: {routingType} routing needs a fallback queue but none exists. Create a MessagingSession queue first (queue path), then re-run.(no-fallback-queue)Warning: This org doesn't have Agentforce licensed (no BotDefinition entity). Use Queue routing instead.(asa-not-supported)Warning: This is a Standard (SCRT1) channel — only Flow routing is supported. These skills only create Enhanced channels, so this is unexpected; check the channel.(standard-channel)Error: {kind}: {message}(其他失败——消息会指出失败的服务端验证规则)
操作示例
如需查看复用现有队列快速路径(已在 test1 上验证)和通过 Metadata API 创建新队列路径的运行示例,请参阅 references/worked-examples.md。
注意事项
已知注意事项 — Group.Type 筛选、DeveloperName 唯一性、QueueRoutingConfig 命名、空队列注意事项、仅通过 Metadata API 创建队列、每个域的 FallbackQueue 要求矩阵、服务器端的 nullQueueId / 就绪状态强制检查点、Standard 与 Enhanced SessionHandler 写入限制,以及不同组织形态下 SessionHandler 的多态性。
遇到意外结果需要排查,或修改此技能之前,请加载 references/gotchas.md 并遵循其中的说明 — 该文件列出了所有注意事项。