关于 service-itsm-agentic-setup-agent-runtime-access-assign
用于为已激活的 ITSM Agent 分配运行时权限和 Agent Access 的 Salesforce 技能。它通过 Salesforce CLI 检查状态,要求明确选择并统一确认写入,最后回读验证。
主要功能
- 01检测已配置的功能权限
- 02逐项选择功能权限级别
- 03为选定用户授予访问权
- 04创建或复用 Agent_Access
- 05写入后回读验证分配结果
适用场景
- 01让已激活的 ITSM Agent 执行其操作
- 02为指定 Salesforce 用户分配运行时权限
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill service-itsm-agentic-setup-agent-runtime-access-assign安装后在 Claude Code 中输入/service-itsm-agentic-setup-agent-runtime-access-assign确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cli-invocation.mdhelper-contracts.mdpermset-topology.mdscripts/classify-activated-agents.mjsclassify-agent-access-state.mjsclassify-assignment-state.mjsclassify-platform-permset-availability.mjsgate-unified-catalog-tiers.mjsrank-candidate-users.mjsresolve-target-user.mjs详细介绍
为已激活的 ITSM Agent 授予运行时访问权限
ITSM Agent(Fulfiller 或 Employee)可能已创建并激活,但打开后立即失败——其操作调用了用户无权执行的平台功能。此技能会在激活后,通过两个需要写入权限的步骤弥补这一缺口,并在操作前统一征求确认:
- 运行时操作执行权限。 检测已配置哪些功能权限集,让用户为每项功能选择一个层级(user/agent 或 admin)以及要授予权限的用户,然后进行分配——若受许可证限制,先分配许可证。
- 自定义“Agent Access”权限集。 创建(或复用)Agent Access,将用户选定的已激活 Agent授予该权限集(每个 Agent 对应一个
SetupEntityAccess),然后将该权限集分配给相同的用户。
经过验证的功能 → 层级 → 权限集矩阵位于 references/permset-topology.md。没有任何组织具备全部三项功能——只分配已配置的功能,并将其余功能报告为不可用,绝不能因缺少某项功能而失败。
所有读取和写入都通过 **Salesforce CLI(sf)**完成——不使用元数据 XML、不提取令牌,也不使用 MCP。
范围
- 范围内:检测已配置的平台功能权限集;按功能选择层级;询问要向哪些用户授予权限(提供运行中的用户选项,但绝不静默选择)并解析用户;以幂等方式先分配 PSL、再分配权限集(适用于许可证限制的层级);创建或复用自定义的
Agent_Access权限集;为每个选定的已激活 Agent 添加一个SetupEntityAccess授权;将Agent_Access分配给用户;通过回读验证分配结果。 - 范围外(括号中为负责的技能):Agentforce for IT Service 的 Go 开关/Studio 配置(
service-itsm-agentic-setup-agentforce-studio-configure);创建或激活 Employee(service-itsm-agentic-setup-employee-agent-configure)或 Fulfiller(service-itsm-agentic-setup-fulfiller-agent-configure)Agent;Fulfiller 激活导致的操作显示缺失问题(发生于创建/激活时,而非本技能处理的运行时问题——service-itsm-agentic-setup-itsm-agentforce-permset-assign);CMDB 访问权限(service-itsm-agentic-setup-cmdb-access-assign);通用的非 ITSM 权限集分配;编写或编辑功能权限集。
辅助脚本(均通过 Bash 调用)负责所有确定性决策(A9)
完整的 I/O 契约见 references/helper-contracts.md。
scripts/classify-platform-permset-availability.mjs— 检测已配置哪些功能、各层级的present和needsPsl状态,以及组织为各层级设置的显示标签。scripts/resolve-target-user.mjs— 从 API 根目录的identityURL 获取运行中用户的 Id(若格式异常,则安全失败)。scripts/rank-candidate-users.mjs— 提供最多五个真实的非服务用户候选项,并按适用对象排序(Fulfiller Agent 优先标准许可证用户,Employee Agent 优先 Unified Employee 用户)。scripts/gate-unified-catalog-tiers.mjs— 针对每个目标用户,确定可提供哪些 Unified Catalog 层级(Community User → Unified Employee;Admin → System Administrator);否则,对该用户不提供 UC。scripts/classify-activated-agents.mjs— 已激活 Agent 候选列表(BotDefinitionInternalCopilot至少有一个状态为Active的 BotVersion)。scripts/classify-agent-access-state.mjs— 判断是否必须创建Agent_Access,以及哪些选定的 Agent 仍需授权(幂等性)。scripts/classify-assignment-state.mjs— 按用户和权限集检查幂等状态;当所选层级的needsPsl:false时,传入哨兵值NO-PSL。
前提条件
- 已安装
sfCLI,并已通过身份验证连接到目标组织(sf org display -o <alias>显示 Connected)。所有调用都使用--target-org <alias>;绝不要手动提取或传递访问令牌。 - API v67.0+。
- PATH 中有
node≥ 18。
若不满足任何前提条件,sf 会返回身份验证错误或 401/403/404;请原样报告原始响应并停止——不得捏造状态。
澄清问题
只询问无法从对话中推断的信息:
- 目标组织 —
sf别名。若未设置,默认使用sf config get target-org。 - 目标用户 — 绝不静默采用默认值:如果未指定,必须通过
AskUserQuestion询问(见阶段 2);如果已指定,则按其指定执行。 - 每项已配置功能的层级 — 对每项已配置的功能,都要询问选择哪个层级(较轻量的 user/agent 还是完整的 admin);绝不自动选择。
- 要启用哪些 Agent — 从已启用 Agent 列表中多选;即使只有一个已启用,也要确认。
- 确认写入 — 用一条汇总确认涵盖所有写入;任何写入前,都必须通过
AskUserQuestion明确收到“yes”。
工作流
所有调用都通过 sf 执行;将 <alias> 替换为目标组织。每个脚本路径都必须使用该技能的绝对目录。精确的命令格式见:references/cli-invocation.md。
阶段 1 — 读取:已配置和已启用的内容有哪些?
-
查询六个平台功能权限集,保存到文件,并进行分类:
sf data query \ -q "SELECT Id, Name, Label, LicenseId FROM PermissionSet WHERE Name IN ('EinsteinGPTPromptTemplateUser','EinsteinGPTPromptTemplateManager','GenieUserEnhancedSecurity','GenieAdmin','UnifiedCatalogCommunityUser','UnifiedCatalogAdmin')" \ --target-org <alias> --json > /tmp/itsm-platform-permsets.json 2>/tmp/itsm-platform-permsets.err || true node "<skill_dir>/scripts/classify-platform-permset-availability.mjs" /tmp/itsm-platform-permsets.json分类器返回
{ features, provisionedFeatures, absentFeatures, verdict }。verdict:"ASSIGNABLE"⇒ 至少配置了一项功能;verdict:"NONE-PROVISIONED"⇒ 无法分配任何功能权限集(仍须继续处理 Agent Access 事宜);verdict:"CANNOT-CONFIRM"⇒ 显示原始错误并停止。 -
查询已启用的 Agent(BotDefinition + 活跃版本子查询),保存并分类:
sf data query \ -q "SELECT Id, DeveloperName, MasterLabel, (SELECT Status FROM BotVersions WHERE Status='Active') FROM BotDefinition WHERE Type='InternalCopilot'" \ --target-org <alias> --json > /tmp/itsm-agents.json 2>/tmp/itsm-agents.err || true node "<skill_dir>/scripts/classify-activated-agents.mjs" /tmp/itsm-agents.jsonverdict:"AGENTS-FOUND"⇒ 提供activatedAgents[]供多选;verdict:"NONE-ACTIVE"⇒Agent_Access没有可授予的内容(报告此情况;如果同时满足NONE-PROVISIONED,则无需执行任何操作 — 停止)。
阶段 2 — 选择目标用户(绝不静默采用默认值)
-
解析当前运行用户(作为带标签的选项),并查询组织中的活跃用户,以便辅助程序对真实的非服务账号候选用户排序并作为推荐选项提供 — 绝不使用未明示的默认值继续操作:
sf api request rest "/services/data/v67.0/" --method GET --target-org <alias> > /tmp/api-root.json 2>/tmp/api-root.err || true node "<skill_dir>/scripts/resolve-target-user.mjs" /tmp/api-root.json sf data query -q "SELECT Name, Profile.Name, Profile.UserLicense.Name FROM User WHERE Id='<userId>'" --target-org <alias> --json > /tmp/itsm-running-user.json 2>/dev/null || true sf data query -q "SELECT Id, Name, Username, Profile.Name, Profile.UserLicense.Name FROM User WHERE IsActive = true ORDER BY LastLoginDate DESC NULLS LAST LIMIT 25" --target-org <alias> --json > /tmp/itsm-candidate-users.json 2>/dev/null || true node "<skill_dir>/scripts/rank-candidate-users.mjs" /tmp/itsm-candidate-users.json <audience> <userId>对于
verdict:"RESOLVED",保留userId;从/tmp/itsm-running-user.json中读取其Name作为标签;对于CANNOT-CONFIRM,显示原因并停止。如果提示词中已指定目标用户(“授予我”/用户名),则按指定执行,无需询问。否则,根据此次授权所面向的 Agent 设置<audience>—fulfiller(优先选择 standard-license 用户)或employee(优先选择 Unified Employee 用户),否则设为any— 根据请求/交接中提到的 Agent,或阶段 1 的已启用 Agent 集合进行推断;rank-candidate-users.mjs会按该受众对最多五名真实的非服务账号候选用户排序。**通过AskUserQuestion(多选)展示这些用户,作为可直接选择的选项 — 绝不能只用普通文字询问用户名:**当前运行用户(标签为 “我 — ”,或仅为 “我”;建议提供)加上排名靠前的候选用户。选择器最多允许四个选项,因此提供 “我” + 排名最高的三名候选用户;内置的 “其他” 可用于输入任何未列出的用户名。按Username解析每位选中或输入的用户(查询格式见references/cli-invocation.md,每位用户分别保存到独立文件);跳过非活跃或未知用户并附注说明。已确认的用户 Id 将用于下面的所有分配。
阶段 3 — 选择(不写入)
- 对每个已配置的功能,通过
AskUserQuestion询问层级(用户/Agent 还是管理员),并记录所选层级的{ name, Id, LicenseId, needsPsl };将每个不存在的功能报告为“此组织未配置 — 已跳过”。Unified Catalog 按所选用户的许可证类型进行门控——针对每位用户,使用该用户自己的捕获结果运行一次scripts/gate-unified-catalog-tiers.mjs,并且只提供其offer[]中的层级:仅向 Unified Employee 用户提供 Community User,仅向 System Administrator 提供 Admin;遇到omit时,对该用户跳过 Unified Catalog,并报告为“此用户的许可证/配置文件不适用 — 已跳过”——绝不提供,也绝不视为写入失败。 - 通过
AskUserQuestion询问要将哪些已激活的 Agent 添加到Agent_Access(多选)。将其 BotDefinition Id 记录为逗号分隔列表。
阶段 4 — 幂等性读取(不写入)
-
Agent Access 状态。 查询
Agent_Access权限集,并且(仅当它存在时)查询其现有的BotDefinition授权 — 将结果捕获到/tmp/agent-access.json和/tmp/sea.json(查询格式见references/cli-invocation.md→ 阶段 4)— 然后根据选定的 Agent Id 进行分类:node "<skill_dir>/scripts/classify-agent-access-state.mjs" /tmp/agent-access.json <sea.json|NO-PERMSET> "<chosenAgentIds-csv>"如果
Agent_Access尚不存在,第二个参数传入NO-PERMSET。分类器返回{ permsetExists, permsetId, missingAgentIds, needsCreate, needsGrants, verdict }。 -
按用户和权限集分别处理。 对每个目标用户 ×(每个选定的功能层级以及
Agent_Access),读取现有分配(PermissionSetAssignment;仅当needsPsl:true时读取PermissionSetLicenseAssign;格式见references/cli-invocation.md),然后进行分类。Agent_Access是独立项(needsPsl:false→NO-PSL);功能层级使用其自身对应行中的needsPsl。如果步骤 6 标记Agent_Access不存在(needsCreate:true),则跳过其按键读取PermissionSetAssignment— 权限集尚不存在 ⇒ 判定为NEEDS-WRITE;阶段 6 会创建它,然后按名称分配。只有当步骤 6 返回现有的permsetId时,才对Agent_Access执行按键读取:node "<skill_dir>/scripts/classify-assignment-state.mjs" /tmp/psa.json </tmp/psla.json|NO-PSL>
阶段 5 — 确认后写入检查点(必需)
- 提供一份汇总摘要 — 列出每个目标用户、要分配的每个功能层级(以及每个被跳过的不存在功能)、是否会创建
Agent_Access及其将授权的 Agent,以及每项权限集分配 — 并通过AskUserQuestion要求用户明确回答“是”。如果回答“否”,则停止并报告计划状态,不进行任何写入。分配受许可证门控的层级会占用一个许可证席位,并立即对当前会话生效。
阶段 6 — 写入(仅执行阶段 4 标记为需要的操作)
-
Agent Access 权限集(仅一次):如果
needsCreate为真,则向/sobjects/PermissionSetPOST{"Name":"Agent_Access","Label":"Agent Access"},并记录新id。然后,对missingAgentIds中的每个 Id,向/sobjects/SetupEntityAccessPOST{"ParentId":"<permsetId>","SetupEntityId":"<agentId>"}—— 不要发送SetupEntityType(它不可创建;其值由0Xx键前缀派生)。授权时出现DUPLICATE_VALUE⇒ 已授权,视为成功。 -
功能层级,按用户处理,对阶段 4 判定为
NEEDS-WRITE的每个层级,按needsPsl排序:needsPsl:true—— 先将 PSL POST 到/sobjects/PermissionSetLicenseAssign(使用该层级自己的LicenseId),然后运行sf org assign permset --name <tierName>(当前运行用户:省略--on-behalf-of;指定用户:--on-behalf-of "<username>")。needsPsl:false—— 跳过 PSL POST;仅运行sf org assign permset。
-
Agent Access 分配,按用户处理:当阶段 4 判定为
NEEDS-WRITE时,运行sf org assign permset --name Agent_Access(当前运行用户:省略--on-behalf-of;指定用户:--on-behalf-of "<username>")。--on-behalf-of按Username解析,绝不可使用005Id 或$USERNAMEshell 变量(参见references/cli-invocation.md)。响应处理(适用于所有写入):成功 ⇒ 完成;
DUPLICATE_VALUE/already has⇒ 幂等成功;PSL POST 出现INSUFFICIENT_ACCESS/席位耗尽 ⇒ 停止并告知用户没有可用席位;其他任何错误 ⇒ 原样显示,并标记为 FAILED。(完整分类见references/cli-invocation.md。)
阶段 7 — 验证 + 汇总
- 重新读取已写入的分配(目标用户的
PermissionSetAssignment/PermissionSetLicenseAssign;Agent_Access的SetupEntityAccess),并确认每条预期记录都存在。然后报告一个汇总判定:- ASSIGNED — 至少执行了一次写入,且每次回读都确认成功。
- ALREADY-ASSIGNED — 无需写入;所有预期状态原本都已存在。
- PARTIAL — 部分分配成功,且至少有一项 FAILED 或回读未确认。列出具体项目。
- NONE-PROVISIONED — 未配置任何功能,且未激活任何 Agent:无需分配。指向创建/启用技能。
- FAILED — 所有尝试的写入都返回了非重复错误。报告原始错误。
规则 / 约束
| 约束 | 原因 |
|---|---|
| 分配前检测已配置的功能;将缺失的功能报告为“未配置”,绝不因此失败 | 没有任何组织拥有全部三项;缺失的权限集会报错并掩盖实际状态 |
| 对每项已配置的功能,询问使用层级(用户/Agent 还是管理员)——绝不自动选择 | 较低权限层级足以使用该功能;管理员权限过度授予 |
| 对 Fulfiller Agent 提供 标准许可证 用户,对 Employee Agent 提供 Unified Employee 用户;排序器会排除服务/机器人账户 | 错误的用户群会提供无法运行该 Agent 的用户 |
仅向有资格持有 Unified Catalog 层级的用户提供该层级(Community User → Unified Employee;Admin → System Administrator),否则对该用户省略——通过 scripts/gate-unified-catalog-tiers.mjs | UC PSL 受许可证类型限制;不符合条件的层级会在写入时直接失败,而非席位不足 |
| 所有可用性 / 幂等性 / 激活决策均由辅助脚本作出,绝不依赖文字说明 | 它们会控制写入/成功;脚本是确定性的,文字说明不是(A9) |
needsPsl 按行读取所选层级自身的 LicenseId;PSL POST 使用该 LicenseId——绝不硬编码 PSL 名称 | 不同组织具有不同的许可证类型;错误的 PermissionSetLicenseId 会 POST 错误的席位 |
当 needsPsl:true 时,先分配 PSL,再分配权限集 | 权限集受许可证支持;先占用席位 |
Agent_Access 仅授予对已激活 Agent 的访问权限,通过 SetupEntityAccess 行实现,其中 SetupEntityId 为 BotDefinition Id | 授权方式与 Apex 类访问权限相同——每个 Agent 对应一条授权行 |
POST SetupEntityAccess 时仅使用 ParentId + SetupEntityId——绝不使用 SetupEntityType | 此字段不可创建——根据 SetupEntityId 键前缀推导;发送该字段会报错 |
通过标准数据 API POST 到 /sobjects/PermissionSet 创建 Agent_Access——绝不使用 Tooling/Metadata XML | 仅凭 Name+Label 即可通过数据 API 创建;无需部署 |
| 任何写入前只进行一次汇总确认 | 必须一次性批准完整计划(消耗的席位、对实时会话的影响) |
每次写入都将 DUPLICATE_VALUE / already has 视为幂等成功 | 重新运行必须安全;重复意味着目标状态已存在 |
| 报告为 ASSIGNED 前,通过回读验证 | 仅有 POST 返回码并不能证明该行存在 |
| 绝不提取访问令牌;绝不使用 MCP dispatcher | 提取令牌会泄露持有者凭据 |
| 报告 CLI 响应中的确切错误文本 | 便于支持人员诊断故障 |
验证清单
- 已通过
scripts/classify-platform-permset-availability.mjs对已配置的功能进行分类;将缺失功能报告为“未配置”,而不是失败。 - 已为每项已配置功能选择层级(用户/Agent 还是管理员)——不自动选择;通过
scripts/gate-unified-catalog-tiers.mjs按用户对 Unified Catalog 层级进行资格筛选。 - 已通过
scripts/classify-activated-agents.mjs对已激活的 Agent 进行分类;仅提供活动版本的 Agent。 - 已确认目标用户——未指定姓名时,通过
AskUserQuestion询问(运行中的用户 + 通过scripts/rank-candidate-users.mjs按受众排序的用户 + “其他”),绝不静默处理。运行中的用户通过scripts/resolve-target-user.mjs确定;通过Username指定姓名。 - 是否创建/授予
Agent_Access由scripts/classify-agent-access-state.mjs决定;SetupEntityAccessPOST 仅发送ParentId+SetupEntityId。 - 写入前,已通过
scripts/classify-assignment-state.mjs对每个用户+权限集组合的幂等性进行分类。 - 当
needsPsl:true时,PSL POST 使用所选层级自身的LicenseId,且在权限集之前 POST。 - 每次写入前均经过一次汇总确认关卡。
- 将
DUPLICATE_VALUE/already has视为成功;其他错误原样报告。 - 已通过回读验证分配结果;报告一个汇总判定(见阶段 7)。
输出格式
ITSM Agent Runtime-Access Assignment (via service-itsm-agentic-setup-agent-runtime-access-assign)
Org: <org-alias> (API v67.0)
Target user(s): <username> (<userId>)[, ...]
Runtime action permissions:
Prompt Templates ...... <tier chosen: User | Manager | skipped | not provisioned> -> <assigned | already-had | FAILED>
Data Cloud ............ <tier chosen | skipped | not provisioned> -> <assigned | already-had | FAILED>
Unified Catalog ....... <tier chosen | skipped | not provisioned> -> <assigned | already-had | FAILED>
Agent Access permission set:
Permission set ........ <created | already existed>
Agents granted ........ <comma-separated agent names, or none>
Assigned to user(s) ... <assigned | already-had | FAILED>
Verdict: ASSIGNED | ALREADY-ASSIGNED | PARTIAL | NONE-PROVISIONED | FAILED
Reason: <plain-language explanation, or empty on success>
Next steps:
- <If ASSIGNED / ALREADY-ASSIGNED: "The user can now open and exercise the agent(s) in Agentforce Studio — action calls should no longer fail on missing permissions.">
- <If PARTIAL: list which assignments succeeded and which failed, verbatim.>
- <If NONE-PROVISIONED: nothing to assign — create/activate an agent and enable its features first.>
- <If FAILED: list the observed error(s) verbatim + remediation.>
面向用户的输出中不要包含内部术语(记录 Id、HTTP 代码、DUPLICATE_VALUE、对象/开发名称)。
参考文件索引
| 文件 | 何时阅读 |
|---|---|
references/permset-topology.md | 对功能/层级矩阵进行任何更改时——六个平台权限集、其层级、PSL,以及 Agent_Access / SetupEntityAccess Agent 访问机制 |
references/cli-invocation.md | 每个阶段——sf data query / sf api request rest POST / sf org assign permset 的准确调用形式、--json 规则、绝不提取令牌规则、响应封装格式和错误分类 |
references/helper-contracts.md | 所有七个辅助脚本的输入/输出格式,以及如何解读每种判定结果 |