关于 service-itsm-agentic-setup-agentforce-studio-configure
通过 Salesforce CLI 为 Fulfiller 或 Employee Agent 启用 Agentforce for IT Service 的前置功能。技能会检查当前状态,经明确确认后按依赖顺序启用,并验证结果。
主要功能
- 01启用 Salesforce Go 功能开关
- 02支持 Fulfiller 和 Employee 路径
- 03按依赖关系排序启用
- 04跳过已启用的开关
- 05写入前要求明确确认
- 06重新检查并报告各项结果
适用场景
- 01为创建 Fulfiller Agent 准备组织
- 02为创建 Employee Agent 准备组织
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill service-itsm-agentic-setup-agentforce-studio-configure安装后在 Claude Code 中输入/service-itsm-agentic-setup-agentforce-studio-configure确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cli-invocation.mdscripts/classify-enable-plan.mjsclassify-final-report.mjsrecord-enable-result.mjs详细介绍
启用 Agentforce for IT Service 的前提条件
完全通过 Salesforce CLI(sf) 启用 Agentforce for IT Service Salesforce Go 功能开关——Einstein Generative AI、Agentforce Studio、父级总开关以及特定路径的 Agent 模板(Fulfiller 或 Employee)。这些开关是创建 Fulfiller/Employee Agent 的前提条件;此可写入步骤通过 Setup Discovery POST /connect/setup/discovery/feature/{apiName}/enable Connect API 路由将其开启。每个开关都会以幂等方式启用(如果已为 ENABLED,则跳过),先启用依赖项,并且任何写入操作之前都需要明确确认。
| 步骤 | 技能 | 功能 |
|---|---|---|
| 1. 验证 | service-itsm-agentic-setup-agentforce-studio-validate | 读取开关 → READY / NOT-READY(不写入) |
| 2. 配置(当前技能) | service-itsm-agentic-setup-agentforce-studio-configure | 开启已禁用的开关 |
| 3. 创建 Agent | service-itsm-agentic-setup-fulfiller-agent-configure | 创建并激活 Fulfiller Agent |
通常会从验证技能的 NOT-READY 报告转到此技能,但也可以直接运行。
辅助脚本 scripts/classify-enable-plan.mjs 会读取批量 /features/status 响应,并确定性地计算按依赖顺序排列的启用计划(写入之前)和每项功能最终的判定结果(写入之后)。这与验证技能的 classify-readiness.mjs 契约(编写标准 A9)一致:判定逻辑位于脚本中,而非说明文字中。
范围
- 范围内:通过
POST .../feature/{apiName}/enable启用 Einstein Generative AI(sales-cloud-einstein-generative-ai)、Agentforce Studio(sales-cloud-agent-studio)、父级总开关(service-cloud-agentforce-for-itsm)以及特定路径的模板(Fulfiller 使用service-cloud-it-fulfiller-agent;Employee 使用service-cloud-requestor-agent+service-cloud-it-service-employee-agent);在每次写入前后读取组织实时状态/features/status;先启用依赖项;通过重新查询确认启用状态已生效;为每项功能显示 ENABLED / ALREADY-ENABLED / FAILED 判定结果。写入操作是幂等的——如果已为ENABLED,则跳过。 - 范围外:配置 Agentforce 许可证(Setup > Company Information > Permission Set Licenses);向用户分配权限集;创建、配置或激活 Agent(
service-itsm-agentic-setup-fulfiller-agent-configure);不进行写入操作的只读前提条件验证(service-itsm-agentic-setup-agentforce-studio-validate);组织范围的多 Agent 编排开关(仅 Headless360 使用的偏好设置,不是 Connect 功能)。
选择哪条路径?
确定用户要启用的是 fulfiller Agent 还是 employee Agent 的前提条件。如果不明确,请询问(AskUserQuestion)——与验证技能使用相同的路径选择方式:
- fulfiller →
sales-cloud-einstein-generative-ai→sales-cloud-agent-studio→service-cloud-agentforce-for-itsm→service-cloud-it-fulfiller-agent - employee →
sales-cloud-einstein-generative-ai→sales-cloud-agent-studio→service-cloud-agentforce-for-itsm→service-cloud-requestor-agent→service-cloud-it-service-employee-agent
Einstein Generative AI 是 Agentforce Studio 的依赖项,不是验证技能直接报告的开关之一,但如果尚未启用,则必须先启用——分类器会将其纳入两条路径的启用计划。
前提条件
与 validate 技能相同(两者使用相同的目标组织和 API 接口)。如果未满足,sf 会显示身份验证错误或 401/403/404;不要捏造状态——显示原始错误并停止。
- 已安装
sfCLI,并已通过身份验证连接到目标组织(sf org display -o <alias>显示 Connected)。所有调用都使用--target-org <alias>;绝不要手动提取或传递访问令牌。 - API v67.0+:
connect/setup/discovery功能 API 从 v67.0 起可用。版本固定在 URL 路径中;不要手动将其改为低于最低要求的版本。 - PATH 上的
node≥ 18(用于运行分类脚本)。 - 组织拥有 Agentforce 许可证(
accessCheck)——缺少许可证会显示为403,或在读取结果中显示为enableBlockedReasons。
操作一览
| 操作 | 命令 | 返回值 |
|---|---|---|
| 读取功能开关 | sf api request rest ".../connect/setup/discovery/features/status" --method POST --body '{"featureApiNames":[...]}' --target-org <alias> | {items:[{apiName,status,enableBlockedReasons[],dependencyStatuses[]}]} |
| 启用一个开关 | sf api request rest ".../connect/setup/discovery/feature/{apiName}/enable" --method POST --body '{}' --target-org <alias> | {success:boolean} — 端点不需要有实际意义的请求体,但必须显式传入 --body '{}'(参见注意事项) |
两者都是可通过 sf api request rest 访问的 Connect API 路由——无需 Headless360 分发器。完整命令格式、响应封装结构和错误分类见 references/cli-invocation.md。
绝不要提取访问令牌。 直接使用
sf api request rest——它会使用 CLI 中存储的目标组织会话。不要从sf org display中取出accessToken,再用它手动构造 HTTP 请求。
重要:不要使用 IPCManagement
updateOrgPref来切换 Agent 偏好设置。 该控制器的写入允许列表会拒绝 Agent 偏好设置的 prefNames(Invalid prefName,500)。Setup Discovery 的POST /feature/{apiName}/enable端点是这些开关唯一正确的写入途径。
架构——启用流程的工作方式
| 步骤 | 操作 | 使用的工具 |
|---|---|---|
| 选择路径 | 确定是 fulfiller 还是 employee(不明确时询问) | AskUserQuestion |
| 读取当前状态 | 为该路径的开关提交 feature-status 批量请求,并保存到文件 | Bash(sf api request rest) |
| 制定计划 | 运行 scripts/classify-enable-plan.mjs <file> <agentType> [exitStatus] → 按依赖关系排序的 pending 列表 | Bash(node) |
| 确认后写入 | 展示准确的 pending 列表,并要求明确答复“yes” | AskUserQuestion |
| 启用 | 对 order 中的每个 apiName,先重新读取并重新分类;未被阻止时提交 .../feature/{apiName}/enable 请求,并记录结果 | Bash(sf api request rest + node scripts/record-enable-result.mjs) |
| 验证 | 重新读取 /features/status,并再次运行分类器 | Bash(sf + node) |
| 报告 | 对 before/results/after 文件运行 scripts/classify-final-report.mjs → 得出最终结论 | Bash(node) |
工作流
将 <alias> 替换为目标组织别名。<agentType> 为 fulfiller 或 employee。
阶段 1——读取当前状态
-
为所选路径需要的每个开关提交 feature-status 批量请求,并将标准输出捕获到文件中。不要添加
--json。将请求正文只写入一次临时文件,并在阶段 1、4 和 5 中通过--body "$(cat ...)"原样重复使用——不要重新输入、替换为[...]之类的占位符,也不要依赖 shell 变量,因为每次 Bash 调用都可能在全新的 shell 中运行,届时普通变量将会未定义:cat > /tmp/feature-status-body.json <<'EOF' {"featureApiNames":["sales-cloud-einstein-generative-ai","sales-cloud-agent-studio","service-cloud-agentforce-for-itsm","service-cloud-it-fulfiller-agent","service-cloud-requestor-agent","service-cloud-it-service-employee-agent"]} EOF sf api request rest "/services/data/v67.0/connect/setup/discovery/features/status" \ --method POST \ --body "$(cat /tmp/feature-status-body.json)" \ --target-org <alias> > /tmp/enable-status-before.json 2>/tmp/enable-status-before.err echo $? > /tmp/enable-status-before.exit捕获退出状态——不要使用
|| true将其吞掉。
阶段 2 — 计划(辅助脚本)
-
对捕获的文件运行分类器,计算按依赖关系排序的启用计划,并保存其输出——阶段 6 使用此文件,而不是原始的
/features/status响应:node "<skill_dir>/scripts/classify-enable-plan.mjs" /tmp/enable-status-before.json <agentType> "$(cat /tmp/enable-status-before.exit)" > /tmp/enable-plan-before.json它会打印
{ agentType, readState, features, order, alreadyEnabled, pending, blocked, unconfirmed, verdict, reasons, rawError }。verdict: "ALL-ENABLED"表示无需执行任何操作——跳到阶段 6。verdict: "NEEDS-ENABLE"表示pending(位于order中)列出了需要启用的项目。blocked列出任何pending开关中enableBlockedReasons非空的项目,截至本次读取——如果某个开关仅因order中靠前的依赖项未启用而受阻,那么该依赖项启用后,这个开关就可以启用。因此,阶段 4 会在尝试每个开关前立即重新检查,而不会在整个循环中依赖这份快照。unconfirmed列出响应中缺失或状态无法被此分类器识别的必需开关——当unconfirmed非空且pending为空时,verdict: "CANNOT-CONFIRM"(而非"ALL-ENABLED")。readState: "error"⇒ 显示rawError并停止;readState: "not-wired"⇒ 报告 CANNOT-CONFIRM 并停止。
阶段 3 — 确认后再写入检查点(必需)
- 准确列出
pending列表(排除blocked中的项目),并通过AskUserQuestion要求用户明确回答“是”后再继续。启用 org 偏好设置会修改 org 状态。**只有在用户明确回答“是”后才能进入阶段 4。**如果用户回答“否”,则停止并报告当前状态,不执行任何写入。
阶段 4 — 启用(先处理依赖项,每次切换前重新检查)
-
按顺序遍历
order(Einstein GenAI → Studio → 父项 → 子模板)。尝试启用每个<apiName>前,都要重新读取并重新分类——这样,阶段 2 中曾因 Studio/父项尚未启用而blocked的子项,就能在相应依赖项启用后变为可启用,而不会因为阶段 2 的快照而被永久放弃:sf api request rest "/services/data/v67.0/connect/setup/discovery/features/status" \ --method POST \ --body "$(cat /tmp/feature-status-body.json)" \ --target-org <alias> > /tmp/enable-status-loop.json 2>/tmp/enable-status-loop.err echo $? > /tmp/enable-status-loop.exit node "<skill_dir>/scripts/classify-enable-plan.mjs" /tmp/enable-status-loop.json <agentType> "$(cat /tmp/enable-status-loop.exit)"检查该输出中
features["<apiName>"].signal的值:-
PASS→ 已经是ENABLED;无需操作,继续处理order中下一个apiName。 -
FAIL且enableBlockedReasons为空 → 现在启用:sf api request rest "/services/data/v67.0/connect/setup/discovery/feature/<apiName>/enable" \ --method POST \ --body '{}' \ --target-org <alias> > /tmp/enable-<apiName>.json 2>/tmp/enable-<apiName>.err node "<skill_dir>/scripts/record-enable-result.mjs" /tmp/enable-<apiName>.json <apiName> /tmp/enable-results.json/enable端点本身不需要有意义的请求正文,但使用sf api request rest --method POST且完全不传--body标志会失败,并报错Error (SfError): No 'mode' found in 'body' entry——务必显式传入--body '{}'。record-enable-result.mjs会读取响应,将其分类为 ENABLED/FAILED,并按apiName键将结果累积到/tmp/enable-results.json中——这是阶段 6 使用的确定性逐开关记录。 -
FAIL且enableBlockedReasons非空 → 即使经过本轮重新检查,仍然受阻(这是实际阻碍,而非仅由顺序造成的阻碍,例如未获许可)——不要发送 POST;继续处理order中下一个apiName,并让阶段 6 原样报告阻碍原因。 -
对此
apiName的读取结果为CANNOT-CONFIRM/ERROR→ 停止循环并显示读取失败;不要猜测剩余开关的状态。
某个开关启用失败,不会阻止计划中的其他项目——继续循环。
-
阶段 5 — 验证启用状态
-
重新运行阶段 1 的读取(使用相同的
/tmp/feature-status-body.json),将结果写入新文件,并对其重新运行分类器,将输出保存供阶段 6 使用:sf api request rest "/services/data/v67.0/connect/setup/discovery/features/status" \ --method POST \ --body "$(cat /tmp/feature-status-body.json)" \ --target-org <alias> > /tmp/enable-status-after.json 2>/tmp/enable-status-after.err echo $? > /tmp/enable-status-after.exit node "<skill_dir>/scripts/classify-enable-plan.mjs" /tmp/enable-status-after.json <agentType> "$(cat /tmp/enable-status-after.exit)" > /tmp/enable-plan-after.jsonverdict: "ALL-ENABLED"⇒order中的每个开关都已确认是ENABLED——成功。仍在pending/blocked/unconfirmed中的项目,需要阶段 6 准确分类(FAILED 与 CANNOT-CONFIRM)。
阶段 6 — 汇总判定(辅助脚本)
-
对阶段 2 分类器的输出(
/tmp/enable-plan-before.json,而非原始的/features/status响应)、阶段 4 的累计结果(如果阶段 2 已为ALL-ENABLED/CANNOT-CONFIRM/ERROR,且阶段 4 从未运行,则使用-),以及阶段 5 分类器的输出(/tmp/enable-plan-after.json)运行最终汇总器:node "<skill_dir>/scripts/classify-final-report.mjs" /tmp/enable-plan-before.json /tmp/enable-results.json /tmp/enable-plan-after.json它会输出
{ features: { <apiName>: { finalStatus, reason } }, order, overall, reasons },其中finalStatus为ALREADY-ENABLED | ENABLED | FAILED | CANNOT-CONFIRM | ERROR,overall为SUCCESS | PARTIAL | FAILED | CANNOT-CONFIRM | ERROR。将其直接填入输出格式 — 不要在说明文字中重新推导各功能的判定结果或整体摘要(编写标准 A9)。当overall: "SUCCESS"时,引导用户前往service-itsm-agentic-setup-fulfiller-agent-configure(fulfiller)或service-itsm-agentic-setup-employee-agent-configure(employee)继续操作。
规则 / 约束
| 约束 | 原因 |
|---|---|
仅通过 POST /connect/setup/discovery/feature/{apiName}/enable 启用 | IPCManagement 的 updateOrgPref 写入允许列表会拒绝 Agent prefNames(Invalid prefName)——这是唯一正确的写入路径 |
通过 POST /features/status 读取每项功能的实时状态,绝不使用扁平目录列表 | 只有 /status 包含每个组织的 ENABLED/NOT_ENABLED、enableBlockedReasons[] 和 dependencyStatuses[] |
按分类器的 order 先启用依赖项,再启用子项 | 在 Einstein GenAI / Studio 之前启用子项会触发未满足的依赖项阻止原因 |
| 在阶段 4 循环中,每次切换前都要立即重新读取并分类,而不是在循环开始时只读取一次 | 如果某个子项仅因先前某个依赖项尚未启用而处于 blocked 状态,那么该依赖项自己的 /enable 请求一旦生效,子项便可立即启用 — 如果只使用阶段 2 的单次快照,就会将其报告为 FAILED,尽管它实际上从未真正被阻止 |
幂等:跳过任何已处于 ENABLED 状态的项目的 /enable 请求 | 分类器的 alreadyEnabled 列表具有权威性;启用已启用的功能虽会返回 {success:true},但属于多余操作 |
执行任何 /enable POST 之前,必须经过必需的写入确认检查点 | 启用组织偏好设置会修改组织状态;用户必须明确批准准确的 pending 列表 |
绝不要尝试启用当前 enableBlockedReasons(重新检查后)非空的切换项 | 非空的 enableBlockedReasons 表示写入会失败——应报告阻止原因,而不是发送注定失败的 POST |
如果 unconfirmed 非空,即使 pending 为空,也使用 verdict: "CANNOT-CONFIRM" | 缺少必需切换项的响应,或状态无法识别时,不得仅因 pending 中没有剩余项目就报告为 ALL-ENABLED |
分类和各切换项结果的记录由 scripts/classify-enable-plan.mjs、scripts/record-enable-result.mjs 和 scripts/classify-final-report.mjs 负责,并通过 Bash 调用 — 不得在说明文字中完成 | 对固定功能状态使用确定性的决策表和汇总(编写标准 A9) |
读写通过 sf api request rest 进行;绝不提取访问令牌 | sf api request rest 使用 CLI 中存储的 --target-org 会话 |
不要向 sf api request rest 传递 --json | 某些 Connect 端点不支持此参数;原始标准输出内容本身已是 JSON |
| 这些是 Connect API 功能 — 使用 SF CLI,而非 Headless360 | 存在对应的 Connect/Tooling 接口,因此优先使用 SF CLI(可避开 Headless360HostedMcpServer 的组织权限门控) |
常见问题
| 问题 | 解决方法 |
|---|---|
使用 sf api request rest --method POST,但不带 --body 标志时,会报错 No 'mode' found in 'body' entry | /enable 端点本身不需要有意义的请求体,但 CLI 仍然要求提供该标志——请始终显式传入 --body '{}'(已在 CLI 2.140.6 和 2.145.6 上验证) |
| 组织中无法使用某个功能 API 名称,或未获得该功能的许可 | 没有可枚举有效名称的目录端点——Phase-1 的 /features/status 读取会通过 enableBlockedReasons[] 显示无法使用或未获许可的功能,无需尝试启用 |
/features/status 显示 NOT_ENABLED,且 dependencyStatuses[] 中有未满足的依赖项 | 先启用列出的依赖项(先启用 Einstein GenAI,再启用 Studio;先启用 Studio,再启用父级/子级开关) |
updateOrgPref → 500 Invalid prefName,针对的是 Agent 偏好设置 | 写入路径错误——请改用 Setup Discovery 的 feature/{apiName}/enable 端点 |
sf api request rest 出现身份验证错误 | 目标组织的会话需要重新进行身份验证(sf org login web) |
| 将身份验证/权限/空请求体导致的读取失败视为“未接入” | 将捕获的 $? 作为分类器的第 3 个参数传入——只有确认的 404 才是 CANNOT-CONFIRM;其他情况都是 ERROR(显示 rawError 并停止) |
因为 pending 为空而报告 ALL-ENABLED | 还要检查 unconfirmed——响应中缺少必需的开关,或其状态无法识别,都不代表已确认 ENABLED 或 NOT_ENABLED |
| 根据前后 JSON 用文字重新推导每项功能/整体结论 | 运行 scripts/classify-final-report.mjs——汇总逻辑是固定的比较逻辑(编写标准 A9),不是主观判断 |
| 在 Phase 1 中将功能状态请求体设为 shell 变量,并期望它在 Phase 4/5 中仍然存在 | 每次 Bash 调用都可能在全新的 shell 中运行,变量会被取消设置,导致静默发送空请求体——请将其保存到 /tmp/feature-status-body.json 一次,并在每个阶段通过 --body "$(cat /tmp/feature-status-body.json)" 读取 |
验证清单
- 已确定 Agent 路径(服务提供者/员工);如不明确,已询问用户。
- Phase 1 已通过
sf api request rest读取/features/status,保存到文件,并捕获其退出状态。 - 在进行任何写入之前,
scripts/classify-enable-plan.mjs已计算出pending(按依赖项排序)、blocked和unconfirmed列表。 - 在 Phase-3 检查点,用户已明确确认准确的
pending列表,然后才发送任何/enablePOST 请求。 - Phase 4 在每个开关之前重新读取并重新分类,而不是对整个循环只执行一次——因此,较早启用依赖项后解除阻止的子项仍会尝试启用。
- 每个已尝试的
/enablePOST 请求的响应均通过scripts/record-enable-result.mjs记录,并在整个循环中累积。 - 启用后已重新读取
/features/status,并重新运行分类器,以确认每项功能的最终结论。 -
scripts/classify-final-report.mjs(而非文字说明)已根据启用前/结果/启用后的文件计算每项功能的状态和整体摘要;从未提取访问令牌。
输出格式
以实时 Markdown 的形式输出报告——绝不可放在代码围栏内(围栏表格会显示原始
| 竖线,而不是表格)。这是阶段 1(基础),阶段 2(安装并激活
Agent)将在此基础上进行;每项状态只能是 ENABLED / ALREADY-ENABLED / FAILED / CANNOT-CONFIRM。请严格按以下格式排版:
Agentforce for IT Service — 阶段 1:启用平台功能(通过 service-itsm-agentic-setup-agentforce-studio-configure)
- 组织:
<org-alias>(API v67.0) - Agent 路径: fulfiller | employee
| # | 平台功能 | 状态 |
|---|---|---|
| 1 | Einstein Generative AI | <status> |
| 2 | Agentforce Studio | <status> |
| 3 | Agentforce for IT Service | <status> |
| 4 | <path-specific toggle(s)> | <status> |
结论: SUCCESS | PARTIAL | FAILED | CANNOT-CONFIRM | ERROR
后续步骤:
- 如果为 SUCCESS:"阶段 1(基础)已完成——继续阶段 2:通过
service-itsm-agentic-setup-fulfiller-agent-configure(fulfiller)/员工 Agent 技能安装并激活<path>Agent。" - 如果为 PARTIAL/FAILED/CANNOT-CONFIRM/ERROR:列出受影响的开关及原因(
enableBlockedReasons、状态未确认或读取错误),并给出修复步骤
将 scripts/classify-final-report.mjs 中的 overall 和每项功能的 finalStatus 原样填入 <status> 单元格——不要重新计算。除分类器的临时响应捕获文件外,不会生成其他文件。
行标签必须与分类器输出完全一致——绝不可添加 Requestor、Specialized 或 parent。
参考文件索引
| 文件 | 何时读取 |
|---|---|
references/cli-invocation.md | 每个阶段——sf api request rest 读写调用的确切格式、响应封装、功能 API 名称、分类器约定及错误分类 |