investigating-agentforce-architecture

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

investigating-agentforce-architecture — declared architecture snapshot

investigating-agentforce-architecture — 已声明架构快照

Design-time metadata tree for one Agentforce agent: planner → topics → actions → flows → Apex → prompts → NGA plugins. Reads declared metadata only —
BotDefinition
,
GenAiPlanner*
,
GenAiPlugin*
,
GenAiFunction*
,
Flow
,
ApexClass
,
GenAiPromptTemplate
. Does not read runtime audit rows.
Runtime budget: 30–45s typical, ≤60s hard cap on reference fixtures. Sequential baseline would be 90–220s; parallel Tooling SOQL fan-out delivers a 3–5× speedup. Large bots with many flows scale approximately linearly — each flow metadata retrieve is one round-trip.
Runs inline — no subagent. Every phase is deterministic file processing.
单个Agentforce代理的设计时元数据树:规划器 → 主题 → 动作 → 流程 → Apex → 提示 → NGA插件。仅读取已声明的元数据——
BotDefinition
GenAiPlanner*
GenAiPlugin*
GenAiFunction*
Flow
ApexClass
GenAiPromptTemplate
读取运行时审计记录。
运行时预算: 典型场景30–45秒,参考测试用例下硬上限≤60秒。顺序执行基准耗时为90–220秒;并行Tooling SOQL分支可实现3–5倍的速度提升。包含大量流程的大型代理大致呈线性扩展——每个流程元数据的获取需一次往返。
内联运行——无子代理。每个阶段都是确定性的文件处理。

If the user hasn't given enough to proceed

若用户未提供足够信息以继续执行

When invoked with no
agent_api_name
AND no org alias, print the following block verbatim — do not paraphrase, do not pre-run any script. Trigger condition:
$ARGUMENTS
is empty OR names no agent (no
--agent
flag and no known agent API name in the prose) OR names no org (no
--org
flag and no known alias).
Which agent should I document, and in which org?
I need:
  • Agent API name — the
    DeveloperName
    of the
    BotDefinition
    (e.g.
    MyAgent
    ,
    MySalesAgent
    ). Not the label.
  • Org alias — for
    sf
    CLI auth (the alias you configured with
    sf org login
    )
Optional:
  • Version — an
    agent_version_api_name
    like
    v5
    . If omitted, I'll resolve the active
    BotVersion
    .
  • --force
    — ignore cached tree; re-fetch everything.
  • --reprobe
    — re-run the 7-day channel-probe cache (only needed after a Salesforce release).
I'll run the metadata pipeline inline. Artifacts land under
~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/
(overridable with
--data-dir
).
当调用时未指定
agent_api_name
且未指定组织别名时,逐字打印以下内容——请勿改写,请勿预运行任何脚本。触发条件:
$ARGUMENTS
为空,或未指定代理(无
--agent
标志且文本中无已知代理API名称),或未指定组织(无
--org
标志且无已知别名)。
我需要为哪个代理、在哪个组织中生成文档?
我需要:
  • 代理API名称——
    BotDefinition
    DeveloperName
    (例如
    MyAgent
    MySalesAgent
    )。不是显示标签。
  • 组织别名——用于
    sf
    CLI认证(您通过
    sf org login
    配置的别名)
可选参数:
  • 版本——类似
    v5
    agent_version_api_name
    。若省略,我将解析当前活跃的
    BotVersion
  • --force
    ——忽略缓存的树结构;重新获取所有数据。
  • --reprobe
    ——重新运行7天周期的通道探测缓存(仅在Salesforce版本更新后需要)。
我将内联运行元数据管道。生成的工件将存储在
~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/
目录下(可通过
--data-dir
参数覆盖)。

Pipeline invocation

管道调用

When the user has supplied
--org <alias>
+
--agent <api_name>
(plus any optional flags), run this block. One
python3
invocation drives the full pipeline.
main.py
writes
.emit_ctx.json
;
emit_result.py
reads it and prints the final
=== RESULT ===
block last to stdout.
bash
set -euo pipefail
当用户提供
--org <alias>
+
--agent <api_name>
(以及任何可选标志)时,运行以下代码块。一次
python3
调用即可驱动整个管道。
main.py
会写入
.emit_ctx.json
emit_result.py
读取该文件并将最终的
=== RESULT ===
块最后打印到标准输出。
bash
set -euo pipefail

zsh arrays are 1-indexed by default; bash arrays are 0-indexed.

zsh arrays are 1-indexed by default; bash arrays are 0-indexed.

This block uses 0-indexed semantics throughout (_args[$i] starting at i=0),

This block uses 0-indexed semantics throughout (_args[$i] starting at i=0),

so under zsh +
set -u
the very first read of
_args[0]
would trip

so under zsh +
set -u
the very first read of
_args[0]
would trip

parameter not set
. KSH_ARRAYS makes zsh treat arrays as 0-indexed,

parameter not set
. KSH_ARRAYS makes zsh treat arrays as 0-indexed,

matching the bash shebang's expectation. No-op under bash.

matching the bash shebang's expectation. No-op under bash.

[ -n "${ZSH_VERSION:-}" ] && setopt KSH_ARRAYS
SKILL_ROOT="${SKILL_ROOT:-${PLUGIN_ROOT:-$HOME/.vibe/skills}/investigating-agentforce-architecture}"
[ -n "${ZSH_VERSION:-}" ] && setopt KSH_ARRAYS
SKILL_ROOT="${SKILL_ROOT:-${PLUGIN_ROOT:-$HOME/.vibe/skills}/investigating-agentforce-architecture}"

Argument parser. Accepts both
--org foo
and
--org=foo
.

Argument parser. Accepts both
--org foo
and
--org=foo
.

$ARGUMENTS
is the raw user input Claude Code substitutes.

$ARGUMENTS
is the raw user input Claude Code substitutes.

ARG_ORG="" ARG_AGENT="" ARG_VERSION="" ARG_FORCE="" ARG_REPROBE="" ARG_PARALLELISM="" ARG_MAX_MERMAID=""
ARG_ORG="" ARG_AGENT="" ARG_VERSION="" ARG_FORCE="" ARG_REPROBE="" ARG_PARALLELISM="" ARG_MAX_MERMAID=""

shellcheck disable=SC2206

shellcheck disable=SC2206

_args=($ARGUMENTS) i=0 while [ $i -lt ${#_args[@]} ]; do tok="${_args[$i]}" case "$tok" in --org=) ARG_ORG="${tok#--org=}" ;; --org) i=$((i+1)); ARG_ORG="${_args[$i]:-}" ;; --agent=) ARG_AGENT="${tok#--agent=}" ;; --agent) i=$((i+1)); ARG_AGENT="${_args[$i]:-}" ;; --version=) ARG_VERSION="${tok#--version=}" ;; --version) i=$((i+1)); ARG_VERSION="${_args[$i]:-}" ;; --parallelism=) ARG_PARALLELISM="${tok#--parallelism=}" ;; --parallelism) i=$((i+1)); ARG_PARALLELISM="${_args[$i]:-}" ;; --max-mermaid-nodes=*) ARG_MAX_MERMAID="${tok#--max-mermaid-nodes=}" ;; --max-mermaid-nodes) i=$((i+1)); ARG_MAX_MERMAID="${_args[$i]:-}" ;; --force) ARG_FORCE="1" ;; --reprobe) ARG_REPROBE="1" ;; esac i=$((i+1)) done
_args=($ARGUMENTS) i=0 while [ $i -lt ${#_args[@]} ]; do tok="${_args[$i]}" case "$tok" in --org=) ARG_ORG="${tok#--org=}" ;; --org) i=$((i+1)); ARG_ORG="${_args[$i]:-}" ;; --agent=) ARG_AGENT="${tok#--agent=}" ;; --agent) i=$((i+1)); ARG_AGENT="${_args[$i]:-}" ;; --version=) ARG_VERSION="${tok#--version=}" ;; --version) i=$((i+1)); ARG_VERSION="${_args[$i]:-}" ;; --parallelism=) ARG_PARALLELISM="${tok#--parallelism=}" ;; --parallelism) i=$((i+1)); ARG_PARALLELISM="${_args[$i]:-}" ;; --max-mermaid-nodes=*) ARG_MAX_MERMAID="${tok#--max-mermaid-nodes=}" ;; --max-mermaid-nodes) i=$((i+1)); ARG_MAX_MERMAID="${_args[$i]:-}" ;; --force) ARG_FORCE="1" ;; --reprobe) ARG_REPROBE="1" ;; esac i=$((i+1)) done

Usage block if required flags missing. Agent reads stderr,

Usage block if required flags missing. Agent reads stderr,

prints verbatim, and stops — does NOT pre-run main.py.

prints verbatim, and stops — does NOT pre-run main.py.

if [ -z "$ARG_ORG" ] || [ -z "$ARG_AGENT" ]; then cat >&2 <<'USAGE'
Which agent should I document, and in which org?
I need:
  • Agent API name — the BotDefinition.DeveloperName (e.g.
    MyAgent
    )
  • Org alias — for
    sf
    CLI auth (the alias you configured with
    sf org login
    )
Optional flags:
  • --version v5
    — pin a specific BotVersion (default: Active+highest)
  • --force
    — bypass cache
  • --reprobe
    — force channel-probe refresh
  • --parallelism N
    — ThreadPoolExecutor size (default 5)
  • --max-mermaid-nodes N
    — cap Mermaid node count (default 80) USAGE exit 2 fi
if [ -z "$ARG_ORG" ] || [ -z "$ARG_AGENT" ]; then cat >&2 <<'USAGE'
Which agent should I document, and in which org?
I need:
  • Agent API name — the BotDefinition.DeveloperName (e.g.
    MyAgent
    )
  • Org alias — for
    sf
    CLI auth (the alias you configured with
    sf org login
    )
Optional flags:
  • --version v5
    — pin a specific BotVersion (default: Active+highest)
  • --force
    — bypass cache
  • --reprobe
    — force channel-probe refresh
  • --parallelism N
    — ThreadPoolExecutor size (default 5)
  • --max-mermaid-nodes N
    — cap Mermaid node count (default 80) USAGE exit 2 fi

Fresh work dir per invocation. Epoch + random suffix avoids collisions

Fresh work dir per invocation. Epoch + random suffix avoids collisions

between concurrent runs on the same host.

between concurrent runs on the same host.

WORK_DIR="/tmp/investigating-agentforce-architecture-$(date +%s)-$RANDOM" mkdir -p "$WORK_DIR"
WORK_DIR="/tmp/investigating-agentforce-architecture-$(date +%s)-$RANDOM" mkdir -p "$WORK_DIR"

Input validation at the boundary, BEFORE any python3 call.

Input validation at the boundary, BEFORE any python3 call.

fs_guard exits 1 and prints an INVALID_INPUT RESULT block on failure;

fs_guard exits 1 and prints an INVALID_INPUT RESULT block on failure;

|| exit 1
is mandatory — bare calls silently continue past failures.

|| exit 1
is mandatory — bare calls silently continue past failures.

python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_AGENT" agent_api_name api_name || exit 1 python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_ORG" org_alias not_empty || exit 1 python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR symlink || exit 1 python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR owned || exit 1 if [ -n "$ARG_VERSION" ]; then python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_VERSION" agent_version api_name || exit 1 fi
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_AGENT" agent_api_name api_name || exit 1 python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_ORG" org_alias not_empty || exit 1 python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR symlink || exit 1 python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR owned || exit 1 if [ -n "$ARG_VERSION" ]; then python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_VERSION" agent_version api_name || exit 1 fi

Single python3 call drives all pipeline phases. main.py writes

Single python3 call drives all pipeline phases. main.py writes

.emit_ctx.json
into $WORK_DIR — emit_result.py then renders the

.emit_ctx.json
into $WORK_DIR — emit_result.py then renders the

RESULT block from that ctx. No subprocess-per-phase.

RESULT block from that ctx. No subprocess-per-phase.

_main_args=(--org-alias "$ARG_ORG" --agent "$ARG_AGENT" --work-dir "$WORK_DIR") [ -n "$ARG_VERSION" ] && _main_args+=(--version "$ARG_VERSION") [ -n "$ARG_FORCE" ] && _main_args+=(--force) [ -n "$ARG_REPROBE" ] && _main_args+=(--reprobe) [ -n "$ARG_PARALLELISM" ] && _main_args+=(--parallelism "$ARG_PARALLELISM") [ -n "$ARG_MAX_MERMAID" ] && _main_args+=(--max-mermaid-nodes "$ARG_MAX_MERMAID")
_main_args=(--org-alias "$ARG_ORG" --agent "$ARG_AGENT" --work-dir "$WORK_DIR") [ -n "$ARG_VERSION" ] && _main_args+=(--version "$ARG_VERSION") [ -n "$ARG_FORCE" ] && _main_args+=(--force) [ -n "$ARG_REPROBE" ] && _main_args+=(--reprobe) [ -n "$ARG_PARALLELISM" ] && _main_args+=(--parallelism "$ARG_PARALLELISM") [ -n "$ARG_MAX_MERMAID" ] && _main_args+=(--max-mermaid-nodes "$ARG_MAX_MERMAID")

main.py returns nonzero on terminal failures; we DON'T short-circuit —

main.py returns nonzero on terminal failures; we DON'T short-circuit —

emit_result still publishes the failure RESULT block.
set -e
is

emit_result still publishes the failure RESULT block.
set -e
is

temporarily relaxed around this single call.

temporarily relaxed around this single call.

set +e python3 "$SKILL_ROOT/scripts/main.py" "${_main_args[@]}" _rc=$? set -e
set +e python3 "$SKILL_ROOT/scripts/main.py" "${_main_args[@]}" _rc=$? set -e

Final RESULT block is emit_result.py's stdout — MUST be the last thing

Final RESULT block is emit_result.py's stdout — MUST be the last thing

stdout sees. emit_result exits 0 on render success; the bash harness

stdout sees. emit_result exits 0 on render success; the bash harness

propagates main.py's rc for the agent's exit status.

propagates main.py's rc for the agent's exit status.

WORK_DIR="$WORK_DIR" python3 "$SKILL_ROOT/tools/emit_result.py" exit "$_rc"
undefined
WORK_DIR="$WORK_DIR" python3 "$SKILL_ROOT/tools/emit_result.py" exit "$_rc"
undefined

Inputs

输入参数

InputFlagRequiredDefault
org_alias
--org
yes
agent_api_name
--agent
yes
agent_version_api_name
--version
noactive BotVersion
force_refresh
--force
nofalse (honor cache)
reprobe
--reprobe
nofalse (honor 7-day channel-probe cache)
parallelism
--parallelism
no5
max_mermaid_nodes
--max-mermaid-nodes
no80
data_dir
--data-dir
no
~/.vibe/data/investigating-agentforce-architecture
cache_dir
--cache-dir
no
~/.vibe/cache/investigating-agentforce-architecture
输入项标志是否必填默认值
org_alias
--org
agent_api_name
--agent
agent_version_api_name
--version
活跃的BotVersion
force_refresh
--force
false(使用缓存)
reprobe
--reprobe
false(使用7天周期的通道探测缓存)
parallelism
--parallelism
5
max_mermaid_nodes
--max-mermaid-nodes
80
data_dir
--data-dir
~/.vibe/data/investigating-agentforce-architecture
cache_dir
--cache-dir
~/.vibe/cache/investigating-agentforce-architecture

Outputs

输出结果

All artifacts under
~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/
(default; override with
--data-dir <path>
):
<agent>_<ver>_metadata_tree.json   primary artifact — normalized planner/topic/action/flow/apex/prompt/plugin tree
<agent>_<ver>_architecture.md      human-readable section-by-section rendering (H1 + 7 numbered sections, plus a conditional Dependency graph appendix). Mermaid diagrams are embedded inside the relevant sections (Action tree, Data flow, and Dependency graph)
所有工件默认存储在
~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/
目录下(可通过
--data-dir <path>
参数覆盖):
<agent>_<ver>_metadata_tree.json   主工件——标准化的规划器/主题/动作/流程/Apex/提示/插件树结构
<agent>_<ver>_architecture.md      人类可读的分节渲染文档(包含H1标题+7个编号章节,以及可选的依赖关系图附录)。Mermaid图表嵌入在相关章节中(动作树、数据流和依赖关系图)

Pipeline — inline, no subagent

管道流程——内联运行,无子代理

resolve_bot.py        → BotDefinition + BotVersion + planner name lookup
retrieve_planner.py   → Metadata API zip retrieve for GenAiPlannerBundle (+ NGA plugins if present)
parallel_retrieve.py  → 6 parallel Tooling SOQL channels fan out from the planner id
                          (resolved by the `planner_definition_by_agent_chain` seed query):
                          - plugins_by_planner (GenAiPluginDefinition)
                          - planner_bundle_functions (GenAiPlannerFunctionDef join)
                          - functions_by_plugins (GenAiFunctionDefinition)
                          - planner_attrs_by_parent_ids (GenAiPlannerAttrDefinition)
                          - plugin_functions_by_plugin_ids (GenAiPluginFunctionDef join)
                          - plugin_instructions_by_plugin_ids (GenAiPluginInstructionDef)
parse_bundle.py       → parse retrieved XML into normalized node shapes
parse_wave.py         → BFS expansion: flow/apex/prompt refs discovered in nodes
                          → SOQL for Flow/Apex bodies (batched by id list)
                          → Metadata retrieve ONLY for GenAiPromptTemplate (+ NGA external plugins conditionally)
finalize.py           → merge waves into metadata_tree.json
render_architecture.py → <agent>_<ver>_architecture.md + Mermaid invocation graph (capped at --max-mermaid-nodes)
Channel strategy — SOQL-first.
  • Tooling SOQL for every normalized tree node (planner, plugins, functions, plugin-functions, plugin-instructions, planner-functions, planner-attrs) — 6 parallel channels keyed on planner id, plus the
    planner_definition_by_agent_chain
    seed query that resolves the planner id from the agent chain.
  • Data API SOQL for Flow (by id) and Apex (by id or name) bodies — batched.
  • Metadata retrieve only for two cases: (a)
    GenAiPromptTemplate
    (prompt bodies aren't cleanly exposed via Tooling SOQL), and (b) NGA external plugins when the planner is Native Generative Agent shape (skipped for classic ReAct).
This is where the 3–5× speedup comes from. A naive implementation would retrieve everything via Metadata API zips sequentially; parallel Tooling SOQL covers ~80% of the tree in a single fan-out.
resolve_bot.py        → 查找BotDefinition + BotVersion + 规划器名称
retrieve_planner.py   → 通过Metadata API zip获取GenAiPlannerBundle(若存在则同时获取NGA插件)
parallel_retrieve.py  → 从规划器ID衍生出6个并行Tooling SOQL通道
                          (由`planner_definition_by_agent_chain`种子查询解析规划器ID):
                          - plugins_by_planner (GenAiPluginDefinition)
                          - planner_bundle_functions (GenAiPlannerFunctionDef join)
                          - functions_by_plugins (GenAiFunctionDefinition)
                          - planner_attrs_by_parent_ids (GenAiPlannerAttrDefinition)
                          - plugin_functions_by_plugin_ids (GenAiPluginFunctionDef join)
                          - plugin_instructions_by_plugin_ids (GenAiPluginInstructionDef)
parse_bundle.py       → 将获取的XML解析为标准化节点格式
parse_wave.py         → 广度优先搜索扩展:在节点中发现的流程/Apex/提示引用
                          → 通过SOQL批量获取Flow/Apex内容
                          → 仅针对GenAiPromptTemplate(以及有条件地针对NGA外部插件)执行Metadata retrieve
finalize.py           → 将各阶段结果合并为metadata_tree.json
render_architecture.py → 生成<agent>_<ver>_architecture.md + Mermaid调用图(节点数量上限由--max-mermaid-nodes指定)
通道策略——优先使用SOQL。
  • Tooling SOQL用于获取所有标准化树节点(规划器、插件、函数、插件函数、插件指令、规划器函数、规划器属性)——6个并行通道以规划器ID为键,加上用于从代理链解析规划器ID的
    planner_definition_by_agent_chain
    种子查询。
  • Data API SOQL用于批量获取Flow(按ID)和Apex(按ID或名称)的内容。
  • Metadata retrieve仅用于两种情况:(a)
    GenAiPromptTemplate
    (提示内容无法通过Tooling SOQL清晰获取);(b) 当规划器为原生生成式代理(Native Generative Agent)类型时的NGA外部插件(经典ReAct类型跳过此步骤)。
这正是实现3–5倍速度提升的关键。若采用 naive 实现,会通过Metadata API zip顺序获取所有数据;而并行Tooling SOQL可在一次分支中覆盖约80%的树结构。

Planner shapes — classic ReAct vs NGA

规划器类型——经典ReAct vs NGA

The skill normalizes two planner families into a single tree shape:
Shape
GenAiPlannerDefinition.PlannerType
InvocationTarget styleNGA plugins?
Classic ReAct
ReactAiPlannerV1
/
SequentialPlannerIntentClassifier
/ etc.
DeveloperName stringsno
NGA
ConcurrentMultiAgentOrchestration
/
AnthropicCompatibleV1
/ etc.
Sometimes 15/18-char Ids (ID-prefix routed)yes (external plugins via Metadata retrieve)
The ID-prefix router in
resolve_invocation_target.py
distinguishes the two: NGA InvocationTargets that look like ids (
01p…
= ApexClass,
301…
= Flow, etc.) get resolved via id-scoped SOQL; DeveloperName targets go through name-scoped SOQL. Unknown prefixes surface as
_unresolved[]
with
reason="unknown-id-prefix:<prefix>"
— never silently dropped.
此技能将两种规划器家族标准化为单一树结构:
类型
GenAiPlannerDefinition.PlannerType
调用目标风格是否支持NGA插件?
经典ReAct
ReactAiPlannerV1
/
SequentialPlannerIntentClassifier
/ 其他
DeveloperName字符串
NGA
ConcurrentMultiAgentOrchestration
/
AnthropicCompatibleV1
/ 其他
有时为15/18位ID(按ID前缀路由)是(通过Metadata retrieve获取外部插件)
resolve_invocation_target.py
中的ID前缀路由器可区分这两种类型:类似ID格式的NGA调用目标(
01p…
= ApexClass,
301…
= Flow等)将通过ID范围的SOQL解析;DeveloperName目标则通过名称范围的SOQL解析。未知前缀将显示为
_unresolved[]
并附带
reason="unknown-id-prefix:<prefix>"
——绝不会被静默丢弃。

Caching

缓存机制

  • Tree cache:
    metadata_tree.json
    is reused unless
    --force
    is passed. Cache key includes the asset-hash of every
    .soql
    /
    .yaml
    /
    .mmd
    template bundled with the skill — bump a template, the cache busts automatically.
  • Channel probe cache: 7-day TTL on the per-org
    sf sobject describe
    results that validate every field name the SOQL assets reference. A Salesforce quarterly release that renames / removes a field triggers
    status: PROBE_FAILED
    ;
    --reprobe
    forces a refresh.
  • 树结构缓存
    metadata_tree.json
    会被重复使用,除非传入
    --force
    参数。缓存键包含技能捆绑的所有
    .soql
    /
    .yaml
    /
    .mmd
    模板的资产哈希值——若模板更新,缓存将自动失效。
  • 通道探测缓存:每个组织的
    sf sobject describe
    结果缓存有效期为7天,用于验证SOQL资产引用的每个字段名称。Salesforce季度版本更新若重命名/删除字段,将触发
    status: PROBE_FAILED
    --reprobe
    参数可强制刷新缓存。

Prerequisites

前置条件

ToolRequired
sf
CLI (authenticated against the target org)
yes —
sf org login web --alias <alias>
Python 3.10+yes
工具是否必填
sf
CLI(已针对目标组织完成认证)
是 — 需执行
sf org login web --alias <alias>
Python 3.10+

Reference docs to load when needed

必要时加载的参考文档

Do NOT load eagerly. Load when the user's question requires it:
  • references/soql_fields.md
    — per-sObject field reference for the 13 sObjects this skill touches (2 Data API + 11 Tooling), with
    [mandatory]
    vs
    [optional]
    tags. Load when the user asks about a specific field, or when debugging an
    INVALID_FIELD
    SOQL error.
  • references/contract.json
    — machine-readable schema for
    metadata_tree.json
    . Load when writing downstream tooling that consumes the tree.
  • references/architecture_sections.md
    — section-by-section structure of the rendered
    <agent>_<ver>_architecture.md
    .
请勿提前加载。仅当用户的问题需要时加载:
  • references/soql_fields.md
    — 此技能涉及的13个sObject(2个Data API + 11个Tooling)的逐对象字段参考,带有
    [mandatory]
    [optional]
    标签。当用户询问特定字段或调试
    INVALID_FIELD
    SOQL错误时加载。
  • references/contract.json
    metadata_tree.json
    的机器可读 schema。当编写消费该树结构的下游工具时加载。
  • references/architecture_sections.md
    — 渲染后的
    <agent>_<ver>_architecture.md
    的分节结构说明。

Invariants worth knowing upfront

需提前了解的不变规则

  • Pipeline is deterministic. Same
    (org, agent, version)
    + static org metadata → byte-identical
    <agent>_<ver>_metadata_tree.json
    and
    <agent>_<ver>_architecture.md
    . Only manifest timestamps drift across re-runs.
  • Forward-only traversal. Every discovered ref goes forward from planner → children. No backward lookups.
  • Partial results are surfaced, not silenced. Any unresolved reference lands in
    _unresolved[]
    with
    reason=...
    .
    STATUS=PARTIAL_OK
    if any channel failed;
    STATUS=OK
    only on a clean run.
  • Cycle detection is per-branch. Same flow visited along its own ancestor chain emits
    _cycle_back_to:<path>
    instead of recursing. A defensive
    MAX_BFS_DEPTH=20
    guard backs the per-branch ancestor set; real-world agents bottom out well before either limit fires. (Earlier docs claimed a hard cap of 5; that was the historical limit and was abandoned because shared utility flows like
    handleFlowFault
    tripped it on every nested tree — see
    config.MAX_BFS_DEPTH
    for the rationale.)
  • Child ordering is alphabetical by
    api_name
    (case-insensitive).
    Topics come before non-topic plannerActions at the root level. Flow-actionCall order is NOT sorted — that's the flow author's execution sequence.
  • 管道具有确定性。相同的
    (组织, 代理, 版本)
    + 静态组织元数据 → 字节完全相同的
    <agent>_<ver>_metadata_tree.json
    <agent>_<ver>_architecture.md
    。仅清单时间戳会在重新运行时变化。
  • 仅向前遍历。所有发现的引用均从规划器向子节点向前遍历。无反向查找。
  • 部分结果会被展示,而非静默忽略。任何未解析的引用都会被放入
    _unresolved[]
    并附带
    reason=...
    。若任何通道失败,状态为
    STATUS=PARTIAL_OK
    ;仅当所有步骤成功完成时状态为
    STATUS=OK
  • 循环检测按分支进行。若沿自身祖先链访问到相同流程,将输出
    _cycle_back_to:<path>
    而非递归。每个分支的祖先集合配有防御性的
    MAX_BFS_DEPTH=20
    限制;实际场景中的代理在达到任一限制前就会遍历完成。(早期文档声称硬上限为5;这是历史限制,因共享实用流程如
    handleFlowFault
    在每个嵌套树中都会触发该限制而被废弃——详见
    config.MAX_BFS_DEPTH
    的说明。)
  • 子节点按
    api_name
    字母顺序排序(不区分大小写)
    。在根层级,主题排在非主题规划器动作之前。流程动作调用顺序会被排序——这是流程作者设定的执行顺序。