agentforce-architecture-analyze
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseagentforce-architecture-analyze — declared architecture snapshot
agentforce-architecture-analyze — 声明式架构快照
Design-time metadata tree for one Agentforce agent: planner → topics → actions → flows → Apex → prompts → NGA plugins. Reads declared metadata only — , , , , , , . Does not read runtime audit rows.
BotDefinitionGenAiPlanner*GenAiPlugin*GenAiFunction*FlowApexClassGenAiPromptTemplateRuntime 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插件。仅读取声明式元数据——、、、、、、。不读取运行时审计记录。
BotDefinitionGenAiPlanner*GenAiPlugin*GenAiFunction*FlowApexClassGenAiPromptTemplate运行时预算: 典型场景30–45秒,参考用例硬上限≤60秒。串行基线耗时为90–220秒;并行Tooling SOQL扇出可实现3–5倍的速度提升。包含大量流程的大型代理大致呈线性扩展——每个流程元数据检索对应一次往返请求。
内联运行——无需子代理。每个阶段均为确定性文件处理。
If the user hasn't given enough to proceed
若用户提供的信息不足以继续执行
When invoked with no AND no org alias, print the following block verbatim — do not paraphrase, do not pre-run any script. Trigger condition: is empty OR names no agent (no flag and no known agent API name in the prose) OR names no org (no flag and no known alias).
agent_api_name$ARGUMENTS--agent--orgWhich agent should I document, and in which org?I need:
- Agent API name — the
of theDeveloperName(e.g.BotDefinition,MyAgent). Not the label.MySalesAgent- Org alias — for
CLI auth (the alias you configured withsf)sf org loginOptional:
- Version — an
likeagent_version_api_name. If omitted, I'll resolve the activev5.BotVersion — ignore cached tree; re-fetch everything.--force — re-run the 7-day channel-probe cache (only needed after a Salesforce release).--reprobeI'll run the metadata pipeline inline. Artifacts land under(overridable with~/.vibe/data/agentforce-architecture-analyze/<org_id15>/<agent_api_name>__<agent_version>/).--data-dir
当调用时未提供且未提供组织别名时,请逐字打印以下内容——请勿意译,请勿预先运行任何脚本。触发条件:为空,或未指定代理(无标识且文本中无已知代理API名称),或未指定组织(无标识且无已知别名)。
agent_api_name$ARGUMENTS--agent--org我应该为哪个代理生成文档,以及在哪个组织中执行?我需要:
- 代理API名称 ——
的BotDefinition(例如DeveloperName、MyAgent),请勿使用标签名。MySalesAgent- 组织别名 —— 用于
CLI认证(即您通过sf配置的别名)sf org login可选参数:
- 版本 —— 类似
的v5。若省略,我将解析当前活跃的agent_version_api_name。BotVersion —— 忽略缓存树;重新获取所有数据。--force —— 重新运行7天周期的通道探测缓存(仅在Salesforce版本更新后需要)。--reprobe我将内联运行元数据管道。生成的产物将存储在目录下(可通过~/.vibe/data/agentforce-architecture-analyze/<org_id15>/<agent_api_name>__<agent_version>/参数覆盖)。--data-dir
Pipeline invocation
管道调用
When the user has supplied + (plus any optional flags), run this block. One invocation drives the full pipeline. writes ; reads it and prints the final block last to stdout.
--org <alias>--agent <api_name>python3main.py.emit_ctx.jsonemit_result.py=== RESULT ===bash
set -euo pipefail当用户提供 + (以及任意可选标识)时,执行以下代码块。一次调用即可驱动整个管道。会写入;读取该文件并在最后向标准输出打印最终的块。
--org <alias>--agent <api_name>python3main.py.emit_ctx.jsonemit_result.py=== RESULT ===bash
set -euo pipefailzsh arrays are 1-indexed by default; bash arrays are 0-indexed.
zsh数组默认是1索引;bash数组是0索引。
This block uses 0-indexed semantics throughout (_args[$i] starting at i=0),
本代码块全程使用0索引语义(_args[$i]从i=0开始),
so under zsh + set -u
the very first read of _args[0]
would trip
set -u_args[0]因此在zsh + set -u
环境下,首次读取_args[0]
会触发
set -u_args[0]parameter not set
. KSH_ARRAYS makes zsh treat arrays as 0-indexed,
parameter not setparameter not set
错误。KSH_ARRAYS可让zsh将数组视为0索引,
parameter not setmatching the bash shebang's expectation. No-op under bash.
与bash脚本的预期一致。在bash环境下无影响。
[ -n "${ZSH_VERSION:-}" ] && setopt KSH_ARRAYS
SKILL_ROOT="${SKILL_ROOT:-${PLUGIN_ROOT:-$HOME/.vibe/skills}/agentforce-architecture-analyze}"
[ -n "${ZSH_VERSION:-}" ] && setopt KSH_ARRAYS
SKILL_ROOT="${SKILL_ROOT:-${PLUGIN_ROOT:-$HOME/.vibe/skills}/agentforce-architecture-analyze}"
Argument parser. Accepts both --org foo
and --org=foo
.
--org foo--org=foo参数解析器。支持--org foo
和--org=foo
两种格式。
--org foo--org=foo$ARGUMENTS
is the raw user input Claude Code substitutes.
$ARGUMENTS$ARGUMENTS
是Claude Code替换后的原始用户输入。
$ARGUMENTSARG_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,
若缺少必填标识则显示使用说明。代理会读取标准错误输出,
prints verbatim, and stops — does NOT pre-run main.py.
逐字打印并停止——不会预先运行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
CLI auth (the alias you configured withsf)sf org loginOptional flags:
— pin a specific BotVersion (default: Active+highest)--version v5 — bypass cache--force — force channel-probe refresh--reprobe — ThreadPoolExecutor size (default 5)--parallelism N — cap Mermaid node count (default 80) USAGE exit 2 fi--max-mermaid-nodes N
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
CLI auth (the alias you configured withsf)sf org loginOptional flags:
— pin a specific BotVersion (default: Active+highest)--version v5 — bypass cache--force — force channel-probe refresh--reprobe — ThreadPoolExecutor size (default 5)--parallelism N — cap Mermaid node count (default 80) USAGE exit 2 fi--max-mermaid-nodes N
Fresh work dir per invocation. Epoch + random suffix avoids collisions
每次调用使用全新工作目录。时间戳+随机后缀可避免同一主机上并发运行时的冲突
between concurrent runs on the same host.
—
WORK_DIR="/tmp/agentforce-architecture-analyze-$(date +%s)-$RANDOM"
mkdir -p "$WORK_DIR"
WORK_DIR="/tmp/agentforce-architecture-analyze-$(date +%s)-$RANDOM"
mkdir -p "$WORK_DIR"
Input validation at the boundary, BEFORE any python3 call.
在边界处进行输入验证,在任何python3调用之前。
fs_guard exits 1 and prints an INVALID_INPUT RESULT block on failure;
fs_guard验证失败时会退出并打印INVALID_INPUT结果块;
|| exit 1
is mandatory — bare calls silently continue past failures.
|| exit 1|| exit 1
是必须的——直接调用会在失败后静默继续。
|| exit 1python3 "$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
单次python3调用驱动所有管道阶段。main.py会将
.emit_ctx.json
into $WORK_DIR — emit_result.py then renders the
.emit_ctx.json.emit_ctx.json
写入$WORK_DIR——emit_result.py随后根据该上下文渲染
.emit_ctx.jsonRESULT block from that ctx. No subprocess-per-phase.
RESULT块。无需每个阶段单独启动子进程。
_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在终端失败时返回非零值;我们不会提前终止——
emit_result still publishes the failure RESULT block. set -e
is
set -eemit_result仍会发布失败结果块。在此单次调用期间临时禁用set -e
。
set -etemporarily 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
最终RESULT块是emit_result.py的标准输出——必须是标准输出的最后内容。
stdout sees. emit_result exits 0 on render success; the bash harness
emit_result渲染成功时退出码为0;bash脚本会传播main.py的退出码作为代理的最终状态。
propagates main.py's rc for the agent's exit status.
—
WORK_DIR="$WORK_DIR" python3 "$SKILL_ROOT/tools/emit_result.py"
exit "$_rc"
undefinedWORK_DIR="$WORK_DIR" python3 "$SKILL_ROOT/tools/emit_result.py"
exit "$_rc"
undefinedInputs
输入参数
| Input | Flag | Required | Default |
|---|---|---|---|
| | yes | — |
| | yes | — |
| | no | active BotVersion |
| | no | false (honor cache) |
| | no | false (honor 7-day channel-probe cache) |
| | no | 5 |
| | no | 80 |
| | no | |
| | no | |
| 输入项 | 参数标识 | 是否必填 | 默认值 |
|---|---|---|---|
| | 是 | — |
| | 是 | — |
| | 否 | 活跃的BotVersion |
| | 否 | false(使用缓存) |
| | 否 | false(使用7天周期的通道探测缓存) |
| | 否 | 5 |
| | 否 | 80 |
| | 否 | |
| | 否 | |
Outputs
输出产物
All artifacts under (default; override with ):
~/.vibe/data/agentforce-architecture-analyze/<org_id15>/<agent_api_name>__<agent_version>/--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/agentforce-architecture-analyze/<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 seed query that resolves the planner id from the agent chain.
planner_definition_by_agent_chain - Data API SOQL for Flow (by id) and Apex (by id or name) bodies — batched.
- Metadata retrieve only for two cases: (a) (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).
GenAiPromptTemplate
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关联查询)
- functions_by_plugins (GenAiFunctionDefinition)
- planner_attrs_by_parent_ids (GenAiPlannerAttrDefinition)
- plugin_functions_by_plugin_ids (GenAiPluginFunctionDef关联查询)
- plugin_instructions_by_plugin_ids (GenAiPluginInstructionDef)
parse_bundle.py → 将检索到的XML解析为标准化节点格式
parse_wave.py → BFS扩展:在节点中发现的流程/Apex/提示引用
→ 通过SOQL批量获取Flow/Apex内容(按ID列表批量处理)
→ 仅针对GenAiPromptTemplate(以及有条件地针对NGA外部插件)执行Metadata检索
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检索:仅用于两种场景:(a) (提示内容无法通过Tooling SOQL清晰获取),以及(b) 当规划器为原生生成式代理类型时的NGA外部插件(经典ReAct类型跳过)。
GenAiPromptTemplate
这正是实现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 | | InvocationTarget style | NGA plugins? |
|---|---|---|---|
| Classic ReAct | | DeveloperName strings | no |
| NGA | | Sometimes 15/18-char Ids (ID-prefix routed) | yes (external plugins via Metadata retrieve) |
The ID-prefix router in distinguishes the two: NGA InvocationTargets that look like ids ( = ApexClass, = Flow, etc.) get resolved via id-scoped SOQL; DeveloperName targets go through name-scoped SOQL. Unknown prefixes surface as with — never silently dropped.
resolve_invocation_target.py01p…301…_unresolved[]reason="unknown-id-prefix:<prefix>"本技能将两种规划器家族标准化为单一树结构:
| 类型 | | 调用目标风格 | 是否支持NGA插件 |
|---|---|---|---|
| 经典ReAct | | DeveloperName字符串 | 否 |
| NGA | | 有时为15/18位ID(按ID前缀路由) | 是(通过Metadata检索外部插件) |
resolve_invocation_target.py01p…301…_unresolved[]reason="unknown-id-prefix:<prefix>"Caching
缓存机制
- Tree cache: is reused unless
metadata_tree.jsonis passed. Cache key includes the asset-hash of every--force/.soql/.yamltemplate bundled with the skill — bump a template, the cache busts automatically..mmd - Channel probe cache: 7-day TTL on the per-org results that validate every field name the SOQL assets reference. A Salesforce quarterly release that renames / removes a field triggers
sf sobject describe;status: PROBE_FAILEDforces a refresh.--reprobe
- 树缓存:会被重复使用,除非传入
metadata_tree.json参数。缓存键包含技能捆绑的所有--force/.soql/.yaml模板的资产哈希值——若模板更新,缓存会自动失效。.mmd - 通道探测缓存:每个组织的结果有7天的TTL,用于验证SOQL资产引用的每个字段名称。Salesforce季度版本更新若重命名/删除字段会触发
sf sobject describe;status: PROBE_FAILED参数可强制刷新缓存。--reprobe
Prerequisites
前置条件
| Tool | Required |
|---|---|
| yes — |
| Python 3.10+ | yes |
| 工具 | 是否必填 |
|---|---|
| 是 — 需执行 |
| Python 3.10+ | 是 |
Reference docs to load when needed
需要时加载的参考文档
Do NOT load eagerly. Load when the user's question requires it:
- — per-sObject field reference for the 13 sObjects this skill touches (2 Data API + 11 Tooling), with
references/soql_fields.mdvs[mandatory]tags. Load when the user asks about a specific field, or when debugging an[optional]SOQL error.INVALID_FIELD - — machine-readable schema for
references/contract.json. Load when writing downstream tooling that consumes the tree.metadata_tree.json - — section-by-section structure of the rendered
references/architecture_sections.md.<agent>_<ver>_architecture.md
请勿提前加载。仅当用户的问题需要时才加载:
- — 本技能涉及的13个sObject(2个Data API + 11个Tooling)的字段参考文档,带有
references/soql_fields.md和[mandatory]标签。当用户询问特定字段或调试[optional]SOQL错误时加载。INVALID_FIELD - —
references/contract.json的机器可读 schema。当编写消费该树结构的下游工具时加载。metadata_tree.json - — 渲染后的
references/architecture_sections.md的分节结构说明。<agent>_<ver>_architecture.md
Invariants worth knowing upfront
预先需要了解的不变规则
- Pipeline is deterministic. Same + static org metadata → byte-identical
(org, agent, version)and<agent>_<ver>_metadata_tree.json. Only manifest timestamps drift across re-runs.<agent>_<ver>_architecture.md - 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 with
_unresolved[].reason=...if any channel failed;STATUS=PARTIAL_OKonly on a clean run.STATUS=OK - Cycle detection is per-branch. Same flow visited along its own ancestor chain emits instead of recursing. A defensive
_cycle_back_to:<path>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 likeMAX_BFS_DEPTH=20tripped it on every nested tree — seehandleFlowFaultfor the rationale.)config.MAX_BFS_DEPTH - Child ordering is alphabetical by (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.
api_name
- 管道具有确定性。相同的+ 静态组织元数据 → 字节完全相同的
(组织, 代理, 版本)和<agent>_<ver>_metadata_tree.json。仅清单时间戳会在重新运行时变化。<agent>_<ver>_architecture.md - 仅向前遍历。所有发现的引用均从规划器向子节点单向传递。无反向查找。
- 显示部分结果而非静默丢弃。任何未解析的引用都会进入并附带
_unresolved[]。若任何通道失败则返回reason=...;仅当所有环节成功时才返回STATUS=PARTIAL_OK。STATUS=OK - 按分支检测循环。若沿自身祖先链访问到同一流程,会输出而非递归处理。每个分支的祖先集合背后有一个防御性的
_cycle_back_to:<path>限制;实际场景中的代理远在达到任一限制前就会终止遍历。(早期文档声称硬上限为5;这是历史限制,因共享实用流程如MAX_BFS_DEPTH=20在每个嵌套树中都会触发该限制而被废弃——详见handleFlowFault的说明。)config.MAX_BFS_DEPTH - 子节点按字母顺序排序(不区分大小写)。在根层级,主题会排在非主题规划器动作之前。Flow-actionCall的顺序不会被排序——这是流程作者定义的执行顺序。
api_name