afv-library/skills/agentforce-architecture-analyze/references/soql_fields.md

25 KiB

sObject field reference — architecture skill

Field reference for the 13 sObjects this skill queries across the 15 SOQL templates under assets/soql/. Two are reached via the Data API (BotDefinition, BotVersion); the remaining 11 are Tooling-only.

Source of truth: the live org (sf sobject describe --sobject <Name> [--use-tooling-api]). Schemas verified against live Salesforce API v66.0 via sf sobject describe on my-org-alias + my-org-alias-2, 2026-05-02. Official Salesforce Help pages describe logical structures that frequently diverge from the physical fields the REST / Tooling API actually expose. When a Help page disagrees with a live describe, trust the live describe — the names in this reference are what you query.

The source of truth for "mandatory" is scripts/probe_channels.py's MANDATORY_FIELDS map. A probe that sees any [mandatory] field missing flips to status: "PROBE_FAILED" — the skill aborts with a clean error rather than producing a subtly-wrong tree. [optional] fields degrade gracefully — missing ones are recorded but don't block the run.


Casing gotchas

  • Mixed case is mandatory for GenAi* sObjects. API names are GenAiPlannerDefinition, GenAiPluginDefinition, GenAiFunctionDefinition, GenAiPluginFunctionDef, GenAiPluginInstructionDef, GenAiPlannerFunctionDef, GenAiPlannerAttrDefinition. Lowercase variants (genai_planner_definition, genaiplannerdefinition) do not resolve. The SOQL parser is case-insensitive on keywords but sObject + field names must match the describe output for Tooling API calls to route correctly.
  • GenAiPluginFunctionDef vs GenAiPlannerFunctionDef are different tables. Plugin-scope join (topic → function, via PluginId) vs planner-bundle-scope join (planner → function, via PlannerId). Both are 10-field join tables with nearly identical shape; keep them straight.
  • BotVersion.DeveloperName is the version id, not the version label. DeveloperName on BotVersion is the version API name (e.g. v5), used as the second path segment under <org_id15>/<agent>__<version>/. MasterLabel is the human-readable label (e.g. "Version 5 — ported from staging"). Never mix them — the data dir layout and the SKILL.md input contract both key on DeveloperName.
  • complexvalue fields require single-row retrieval. Metadata (on Flow, FlowDefinition, GenAiPluginDefinition, GenAiFunctionDefinition), SymbolTable (on ApexClass), and AgentGraph (on GenAiPlannerDefinition, often null in practice) are complexvalue types. Salesforce enforces MALFORMED_QUERY: When retrieving results with Metadata or FullName fields, the query qualifications must specify no more than one row for retrieval. Batch IN-clause SELECTs that return ≥2 rows fail. Use a single-row equality (WHERE Id = '<id>') per fetch; parallelize across ids via concurrent.futures. ApexClass.Body + ApexClass.SymbolTable is the one notable exception: the Name IN (...) batch works even though SymbolTable is complex.

Cross-sObject join map

Every edge is strictly forward from the entry query (GenAiPlannerDefinition WHERE DeveloperName = :planner_name). No backward lookups.

BotDefinition (Data API, PK Id, matched by DeveloperName)
 └── BotVersion (Data API, FK BotDefinitionId)
 │ [resolved to planner name via Bot metadata retrieve]
 ▼
GenAiPlannerDefinition (Tooling, PK Id, matched by DeveloperName)
 │
 ├── GenAiPluginDefinition ← WHERE PlannerId = :plannerId
 │ ├── GenAiPluginInstructionDef ← WHERE GenAiPluginDefinitionId IN (:topic_ids)
 │ ├── GenAiPluginFunctionDef ← WHERE PluginId IN (:topic_ids)
 │ │ └── Function picklist → GenAiFunctionDefinition.Id
 │ └── GenAiFunctionDefinition ← WHERE PluginId IN (:topic_ids)
 │
 ├── GenAiPlannerFunctionDef ← WHERE PlannerId = :plannerId
 │ └── Plugin picklist → GenAiPluginDefinition.Id (or external via retrieve)
 │
 ├── GenAiFunctionDefinition ← WHERE PluginId IN (:topic_ids)
 │ │ (single-query — see functions_by_plugins.soql)
 │ │
 │ └── InvocationTargetType + InvocationTarget route to:
 │ ├── flow → FlowDefinition (batch IN) → Flow.Metadata (parallel single-row)
 │ ├── apex → ApexClass (batch IN, Body + SymbolTable)
 │ ├── standardInvocableAction → (no further fetch — declared only)
 │ └── generatePromptResponse → GenAiPromptTemplate (Metadata API retrieve)
 │
 └── GenAiPlannerAttrDefinition ← WHERE ParentId IN (:function_ids, :planner_id)
 (polymorphic ParentId: GenAiFunctionDefinition OR GenAiPlannerDefinition)

Per-channel row counts + _unresolved[] reasons are recorded in metadata_tree.json under _channels and _unresolved keys.


Data API sObjects (2)

BotDefinition (Data API) — one row per agent

Root of the agent metadata. Matched by DeveloperName; the rest of the tree is resolved forward from the BotVersion child.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
DeveloperName string no yes [mandatory]
MasterLabel string yes yes [optional]
Description textarea yes no [optional]
AgentType picklist yes yes [optional] — discriminator for classic vs NGA in some orgs
Type picklist yes yes [optional]
AgentTemplate string yes yes [optional] — e.g. SvcCopilotTmpl__EinsteinAgentKind
BotSource picklist yes yes [optional]
AgentUser reference yes yes [optional] — FK to User
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
LastModifiedDate datetime no yes [optional]
SystemModstamp datetime no yes [optional]

BotVersion (Data API) — one row per agent version

Resolves the active version (or user-pinned version) for a given bot. Parent relationship: BotDefinition via BotDefinitionId.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
BotDefinitionId reference no yes [mandatory]
DeveloperName string no yes [optional] — version id (e.g. v5)
MasterLabel string yes yes [optional] — human label
Status picklist yes yes [optional] — Active on the current published version
VersionNumber int yes yes [optional]
Description textarea yes no [optional]
AiReplyRecordVisibility picklist yes yes [optional]
ResponseDelayMilliseconds int yes yes [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
LastModifiedDate datetime no yes [optional]

Tooling API sObjects (11)

All sObjects in this section are reachable via the Tooling API only (sf data query --use-tooling-api or sf sobject describe --use-tooling-api).

ApexClass (Tooling) — Apex source + parsed AST

Source + full method/property AST for Apex referenced by GenAiFunctionDefinition.InvocationTarget when InvocationTargetType = 'apex'. Batch-safe on Name IN (...) or Id IN (...) (despite SymbolTable being complexvalue, Salesforce permits the batch for this particular sObject — verified live).

Note: SymbolTable is not part of FIELDS(ALL) and must be named explicitly in the SELECT.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
Name string no yes [mandatory]
Body textarea yes no [optional] — full Apex source
SymbolTable complexvalue yes no [optional] — parsed AST (methods, params, annotations, line/col)
ApiVersion double no yes [optional]
IsValid boolean no yes [optional]
Status picklist no yes [optional]
LengthWithoutComments int yes yes [optional]
NamespacePrefix string yes yes [optional]
FullName string yes no [optional] — complexvalue companion
Metadata complexvalue yes no [optional]
ManageableState picklist yes yes [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
LastModifiedDate datetime no yes [optional]
SystemModstamp datetime no yes [optional]

Single-row requirement for complexvalue columns: Metadata and FullName on ApexClass follow the standard MALFORMED_QUERY rule — batch IN-clause SELECTs that return ≥2 rows fail when these two are selected. Body + SymbolTable are the exception (batch works). Comments in assets/soql/apex_class_bodies_by_ids.soql + apex_class_bodies_by_names.soql pin this.

Flow (Tooling) — Flow version body

Single-row retrieval required — Metadata and FullName are both complexvalue. Fired once per activeVersionId returned by FlowDefinition; parallelized via ThreadPoolExecutor.

Filterability quirk: FullName is selectable but not filterable (INVALID_FIELD: field 'FullName' can not be filtered in a query call). Filter by Id instead.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
DefinitionId reference no yes [mandatory]
FullName string yes no [optional] — complexvalue companion; not filterable
Metadata complexvalue yes no [optional] — full flow JSON (actionCalls, subflows, variables, decisions, formulas, assignments, apexPluginCalls)
MasterLabel string yes yes [optional]
Description textarea yes no [optional]
VersionNumber int yes yes [optional]
ProcessType picklist yes yes [optional]
Status picklist yes yes [optional]
ApiVersion double yes yes [optional]
IsActive boolean no yes [optional]
IsTemplate boolean no yes [optional]
RunInMode picklist yes yes [optional]
Environments picklist yes yes [optional]
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
OverriddenFlowId reference yes yes [optional]
SourceTemplateId reference yes yes [optional]
TriggerType picklist yes yes [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
LastModifiedDate datetime no yes [optional]
SystemModstamp datetime no yes [optional]
InstalledPackageName string yes yes [optional]

Single-row requirement: Metadata and FullName force WHERE Id = '<version_id>'. The SOQL asset flow_metadata_by_id.soql encodes this as a single Id = '...' predicate.

FlowDefinition (Tooling) — Flow versioning index

Two-hop feeder to Flow. Batch IN-clause works. Returns ActiveVersionId + LatestVersionId — the skill prefers active.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
DeveloperName string no yes [mandatory]
ActiveVersionId reference yes yes [optional] — FK to Flow.Id
LatestVersionId reference yes yes [optional] — FK to Flow.Id
MasterLabel string yes yes [optional]
Description textarea yes no [optional]
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
Metadata complexvalue yes no [optional] — definition-level metadata (may carry what the Flow hop provides on some orgs)
FullName string yes no [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
LastModifiedDate datetime no yes [optional]
SystemModstamp datetime no yes [optional]

GenAiPlannerDefinition (Tooling) — planner root

Entry query for the tree. Matched by DeveloperName (the <genAiPlannerName> extracted from the Bot metadata retrieve). The PlannerType picklist is the classifier for classic ReAct vs NGA.

Seven-value PlannerType picklist (verified consistent across my-org-alias, my-org-alias-2, my-org-alias-3): grouped by namespace — AiCopilot__* = classic ReAct family, Atlas__* = NGA family. startswith("Atlas__") is a clean classic-vs-NGA discriminator.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
DeveloperName string no yes [mandatory]
PlannerType picklist yes yes [mandatory]
MasterLabel string yes yes [optional]
Description textarea yes no [optional]
Capabilities textarea yes no [optional] — null in every row tested on both classic + NGA
AgentGraph complexvalue yes no [optional] — null in every row tested; single-row rule still applies
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
Metadata complexvalue yes no [optional]
FullName string yes no [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
LastModifiedDate datetime no yes [optional]
SystemModstamp datetime no yes [optional]

Single-row requirement for complexvalue columns: AgentGraph, Metadata, FullName — select individually; entry query pins WHERE DeveloperName = '...' LIMIT 1.

GenAiPluginDefinition (Tooling) — topics

All topics for a planner via WHERE PlannerId = :plannerId. Carries PluginType + Scope for topic classification and CanEscalate / IsLocal for behavior flags.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
DeveloperName string no yes [mandatory]
PluginType picklist yes yes [optional] — topic type classifier
Scope textarea yes no [optional] — natural-language topic scope
MasterLabel string yes yes [optional]
Description textarea yes no [optional]
CanEscalate boolean yes yes [optional]
IsLocal boolean yes yes [optional]
Source picklist yes yes [optional]
ParentId reference yes yes [optional] — planner FK (sometimes referred to as PlannerId in SOQL filter clauses)
LocalDeveloperName string yes yes [optional]
Language picklist yes yes [optional]
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
Metadata complexvalue yes no [optional]
FullName string yes no [optional]
ClassificationDescription textarea yes no [optional]
GenAiFunctionInvoker string yes yes [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]

Single-row requirement: Metadata + FullName require per-id retrieval. The production path doesn't SELECT Metadata on this sObject (see plugins_by_planner.soql) — it pulls Scope + scalar fields instead, which batch-safely over PlannerId = :id.

GenAiPluginFunctionDef (Tooling) — plugin-function join

Join table: GenAiPluginDefinitionGenAiFunctionDefinition. Batch- safe on PluginId IN (...).

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
PluginId reference no yes [mandatory]
Function picklist yes yes [optional] — references GenAiFunctionDefinition.Id
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
SystemModstamp datetime no yes [optional]

GenAiPluginInstructionDef (Tooling) — per-topic instructions

Per-topic instruction text + ordering. Batch-safe on GenAiPluginDefinitionId IN (...).

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
GenAiPluginDefinitionId reference no yes [mandatory]
DeveloperName string no yes [optional]
MasterLabel string yes yes [optional]
Description textarea yes no [optional] — the instruction text
SortOrder int yes yes [optional]
Language picklist yes yes [optional]
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
FullName string yes no [optional]
Metadata complexvalue yes no [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]

Single-row requirement: Metadata + FullName complexvalue pair; the production SOQL omits them (scalar fields batch-safely).

GenAiFunctionDefinition (Tooling) — actions

The actions. Combined single-query fetches both bundle-scope (PlannerId) and topic-scope (PluginId IN) functions. InvocationTargetType

  • InvocationTarget route to the downstream fetch (Flow, Apex, prompt, standard invocable).

InvocationTarget format varies by planner shape (the ID-prefix router lives in scripts/resolve_invocation_target.py):

  • Classic ReAct: DeveloperName string (e.g. AGNT_SetUserSelectedOption).
  • NGA: Salesforce 15/18-char Id (e.g. 01pVF... = ApexClass, 300VF... = FlowDefinition, 0hf... = GenAiPromptTemplate).
Name Type Nillable Filterable Tag
Id id no yes [mandatory]
DeveloperName string no yes [mandatory]
InvocationTarget string yes yes [mandatory]
InvocationTargetType picklist yes yes [optional] — flow / apex / standardInvocableAction / generatePromptResponse
MasterLabel string yes yes [optional]
Description textarea yes no [optional]
IsLocal boolean yes yes [optional]
IsConfirmationRequired boolean yes yes [optional]
IsIncludeInProgressIndicator boolean yes yes [optional]
ProgressIndicatorMessage string yes yes [optional]
Source picklist yes yes [optional]
PluginId reference yes yes [optional] — topic-scope FK (null for bundle-scope functions)
PlannerId reference yes yes [optional] — bundle-scope FK (null on NGA — attachment is plugin-only)
ParentId reference yes yes [optional]
LocalDeveloperName string yes yes [optional]
Language picklist yes yes [optional]
InvocationTargetApiName string yes yes [optional]
MissingValuePromptMessage string yes yes [optional]
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
Metadata complexvalue yes no [optional]
FullName string yes no [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]

Single-row requirement: Metadata + FullName complexvalue columns; production SOQL omits both to keep the PlannerId / PluginId IN batch path intact.

GenAiPlannerFunctionDef (Tooling) — planner-bundle join

Bundle-scope join: planner → function. Analogous to GenAiPluginFunctionDef but keyed on PlannerId. Batch-safe on PlannerId = :id.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
PlannerId reference no yes [mandatory]
Plugin picklist yes yes [optional] — references plugin DeveloperName / id
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]
SystemModstamp datetime no yes [optional]

GenAiPlannerAttrDefinition (Tooling) — parameter mappings

The attributeMappings — I/O parameter bindings between actions and the planner. Polymorphic ParentId: points at either a GenAiFunctionDefinition (function-scope mappings) or GenAiPlannerDefinition (bundle-scope mappings). The production SOQL passes the union of function ids + planner id via WHERE ParentId IN (:function_ids, :planner_id).

MappingType is the input / output picklist; ParameterName identifies the bound variable on the planner side.

Name Type Nillable Filterable Tag
Id id no yes [mandatory]
ParentId reference yes yes [optional] — polymorphic: GenAiFunctionDefinition | GenAiPlannerDefinition
DeveloperName string no yes [optional]
MasterLabel string yes yes [optional]
Description textarea yes no [optional]
MappingType picklist yes yes [optional] — input / output
ParameterName string yes yes [optional]
Language picklist yes yes [optional]
NamespacePrefix string yes yes [optional]
ManageableState picklist yes yes [optional]
IsDeleted boolean no yes [optional]
CreatedById reference no yes [optional]
CreatedDate datetime no yes [optional]
LastModifiedById reference no yes [optional]

Known picklist values (live-API verified, 2026-05-02)

sObject Field Values
GenAiPlannerDefinition PlannerType Seven values split by namespace. Classic family: AiCopilot__ReAct, AiCopilot__ReactAiPlannerV1, AiCopilot__SequentialPlannerIntentClassifier. NGA family: Atlas__ConcurrentMultiAgentOrchestration, Atlas__AnthropicCompatibleV1, Atlas__AtlasReactV1, Atlas__MainSubAgent (exact set may vary by release — startswith("Atlas__") is the stable classic-vs-NGA discriminator).
GenAiFunctionDefinition InvocationTargetType flow, apex, standardInvocableAction, generatePromptResponse
GenAiPlannerAttrDefinition MappingType input, output
BotVersion Status Inactive, Active (active = currently published version)

Mandatory-field enforcement

The [mandatory] tags above mirror scripts/probe_channels.py:

MANDATORY_FIELDS: Dict[str, set[str]] = {
 "BotDefinition": {"Id", "DeveloperName"},
 "BotVersion": {"Id", "BotDefinitionId"},
 "ApexClass": {"Id", "Name"},
 "Flow": {"Id", "MasterLabel", "DefinitionId"},
 "FlowDefinition": {"Id", "DeveloperName"},
 "GenAiPlannerDefinition": {"Id", "DeveloperName", "PlannerType"},
 "GenAiPluginDefinition": {"Id", "DeveloperName"},
 "GenAiFunctionDefinition": {"Id", "DeveloperName", "InvocationTarget"},
 "GenAiPlannerAttrDefinition": {"Id"},
}

GenAiPluginFunctionDef, GenAiPluginInstructionDef, and GenAiPlannerFunctionDef don't appear in MANDATORY_FIELDS — they're join tables whose Id + FK columns are present by construction on every query. The per-sObject tables above tag their FK columns as [mandatory] because the SOQL assets SELECT them; a probe that saw them missing would still flip PROBE_FAILED via the Id check, but the tag reflects "the skill's SOQL will fail if this column is gone."

When a Salesforce quarterly release renames or removes a [mandatory] field, run with --reprobe to force a fresh describe and surface the drift cleanly.