mcpField
S
service-de-channel-routing-configure

service-de-channel-routing-configure

github.com/forcedotcom其他1.1k660 次安装1 天前更新
代码仓库

关于 service-de-channel-routing-configure

为已创建的 Salesforce 增强型消息渠道配置并验证路由,面向管理消息渠道的操作者。支持队列、Flow、Agentforce Service Agent、Digital Worker 和用户目标,并检查目标资格及备用队列要求。

主要功能

  1. 01配置五类 SessionHandler 路由
  2. 02按需创建队列及路由配置
  3. 03验证现有路由目标状态
  4. 04按目标类型校验备用队列
  5. 05通过 sf CLI 查询并更新渠道

适用场景

  1. 01为新建的消息渠道设置路由
  2. 02核验已有渠道的路由目标
  3. 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.md
gotchas.md
queue-creation.md
target-locate.md
worked-examples.md
scripts/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-FlowFlowDefinition(ProcessType=RoutingFlow)300必需
Agentforce 服务 Agent(ASA)BotDefinition(Type=ExternalCopilot)0Xx必需
Digital WorkerAgenticCtxtDecorDefinition1iE必需
用户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} — 可选;sf CLI 目标组织别名。默认值: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
00GGroup (Type=Queue)SELECT Id, Name, DeveloperName FROM Group WHERE Id='<sh>' AND Type='Queue'queue
300FlowDefinitionSELECT DurableId, Label, ApiName FROM FlowDefinitionView WHERE DurableId='<sh>'flow
0XxBotDefinition (ASA)SELECT Id, DeveloperName, MasterLabel, AgentType, BotUserId, (SELECT Id, Status FROM BotVersions WHERE Status='Active' LIMIT 1) FROM BotDefinition WHERE Id='<sh>'asa
1iEAgenticCtxtDecorDefinition (Digital Worker)SELECT Id, DeveloperName, MasterLabel FROM AgenticCtxtDecorDefinition WHERE Id='<sh>'digital_worker
005UserSELECT 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 写入
queue00G Group.Id无(必须保持为 null)
flow300 FlowDefinition ID设置 FallbackQueueId={FALLBACK_QUEUE_ID}
asa0Xx BotDefinition.Id设置 FallbackQueueId={FALLBACK_QUEUE_ID}
digital_worker1iE AgenticCtxtDecorDefinition.Id设置 FallbackQueueId={FALLBACK_QUEUE_ID}
user005 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 并遵循其中的说明 — 该文件列出了所有注意事项。

评论

支持 Markdown