Skip to content

Employee Agent example diverges from OOTB scaffold; host-context variables silently fail at runtime #10

@mgwexler84

Description

@mgwexler84

developing-agentforce: Employee Agent host-context variables produce silent runtime failure (examples.md wrong, visibility: undocumented, current* reserved names not mentioned)

Target repo: SalesforceAIResearch/agentforce-adlc
Skill: developing-agentforce
Primary files:

  • skills/developing-agentforce/references/examples.md — "Minimal Employee Agent" section (lines 63–182)
  • skills/developing-agentforce/references/agent-script-core-language.md — Core Language reference (no coverage of visibility: or host-context vars)
  • skills/developing-agentforce/SKILL.md — Syntax Quick Reference (no coverage of either)
  • skills/developing-agentforce/references/production-gotchas.md — no entry for silent host-context failure

Summary

The skill's "Minimal Employee Agent" example and surrounding references diverge from what the Salesforce Agent Builder UI actually emits when creating a new AgentforceEmployeeAgent. The divergence isn't cosmetic — it causes a silent runtime failure that cannot be caught by any tool in the skill's workflow:

  • The agent compiles (sf agent validate authoring-bundle returns success: true)
  • The agent publishes cleanly
  • The agent previews correctly for any utterance that doesn't rely on host-surface context
  • But when embedded on a Lightning Record Page, variables that were supposed to receive the current record context are never populated by the host — because the skill doesn't mention the three things required to wire them up correctly: the reserved variable names, the visibility: attribute, and the External contract with the host surface.

Concretely, three distinct errors in the skill's current content combine to produce the failure:

  • Error C1examples.md (line 181) asserts EndUserId / RoutableId / ContactId / EndUserLanguage are "service-agent-only." This is factually incorrect; the UI emits them on employee agents too.
  • Error C2 — the current* host-context variables (currentRecordId, currentObjectApiName, currentPageType, currentAppName) are the mechanism by which an embedded employee agent receives Lightning Record Page context. They are never mentioned anywhere in the skill — not in examples.md, not in agent-script-core-language.md, not in SKILL.md, not in agent-design-and-spec-creation.md.
  • Error C3 — the visibility: attribute ("External" / "Internal" / omitted) on variable declarations is undocumented. The Core Language reference and the Syntax Quick Reference never mention it. But visibility: "External" is what opts a variable in to being populated by the host surface. Without it, the host never writes — silently.

Concrete failure case: an author building an employee agent that answers "what's the billing address for this account?" will, following the skill literally, declare currentRecordId: mutable string = "" with no visibility: attribute. It compiles, validates, previews, publishes. Embedded on an Account record page, @variables.currentRecordId is always empty. The instruction if @variables.currentRecordId is not empty becomes dead code. The agent asks "which account?" even though the user is clearly on one. No validator warning fires.

I hit this while building a single-topic employee agent for Account billing address lookups on 2026-04-25. All three errors below are documented against the current state of the skill files on main, and all three show up in .agent output emitted by the Salesforce UI that contradicts the skill.


Evidence

Evidence — UI-generated variable blocks (copied directly from Agent Builder output)

Service Agent (UI default, no manual edits):

variables:
    authenticationKey: mutable string
        description: "Stores the authentication key that's used to generate the verification code."
        visibility: "Internal"
    customerId: mutable string
        description: "Stores the Salesforce user ID or contact ID."
        visibility: "Internal"
    customerType: mutable string
        description: "Stores the customer ID type, whether it's a Salesforce user or a contact."
        visibility: "Internal"
    isVerified: mutable boolean = False
        label: "isVerified"
        description: "Stores a boolean value that indicates whether the customer code is verified."
        visibility: "Internal"
    EndUserId: linked string
        source: @MessagingSession.MessagingEndUserId
        description: "This variable may also be referred to as MessagingEndUser Id"
    RoutableId: linked string
        source: @MessagingSession.Id
        description: "This variable may also be referred to as MessagingSession Id"
    ContactId: linked string
        source: @MessagingEndUser.ContactId
        description: "This variable may also be referred to as MessagingEndUser ContactId"
    EndUserLanguage: linked string
        source: @MessagingSession.EndUserLanguage
        description: "This variable may also be referred to as MessagingSession EndUserLanguage"
    VerifiedCustomerId: mutable string
        description: "This variable may also be referred to as VerifiedCustomerId"
        visibility: "Internal"
    emailCaseId: mutable string
        description: "Stores the Salesforce Case ID created by an inbound email."
        visibility: "External"
    endUserEmail: mutable string
        description: "Stores email address of the end user who sent the inbound email."
        visibility: "External"
    endUserContactId: mutable string
        description: "Stores the Salesforce Contact ID associated with the end user who sent the inbound email."
        visibility: "External"

Employee Agent (UI default, no manual edits):

variables:
    EndUserId: linked string
        source: @MessagingSession.MessagingEndUserId
        description: "This variable may also be referred to as MessagingEndUser Id"
        visibility: "External"
    RoutableId: linked string
        source: @MessagingSession.Id
        description: "This variable may also be referred to as MessagingSession Id"
        visibility: "External"
    ContactId: linked string
        source: @MessagingEndUser.ContactId
        description: "This variable may also be referred to as MessagingEndUser ContactId"
        visibility: "External"
    EndUserLanguage: linked string
        source: @MessagingSession.EndUserLanguage
        description: "This variable may also be referred to as MessagingSession EndUserLanguage"
        visibility: "External"
    currentAppName: mutable string
        description: "Salesforce Application Name"
        visibility: "External"
    currentObjectApiName: mutable string
        description: "The API name of the current Salesforce object"
        visibility: "External"
    currentPageType: mutable string
        description: "Page type (record, list, home)"
        visibility: "External"
    currentRecordId: mutable string
        description: "The Salesforce ID of the current record"
        visibility: "External"
    VerifiedCustomerId: mutable string
        description: "This variable may also be referred to as VerifiedCustomerId"
        visibility: "Internal"

Side-by-side (what the UI makes unambiguous):

Variable Service UI default Employee UI default
authenticationKey / customerId / customerType / isVerified ✅ Internal
EndUserId / RoutableId / ContactId / EndUserLanguage (linked) ✅ (no visibility: attr) ✅ External
VerifiedCustomerId ✅ Internal ✅ Internal
emailCaseId / endUserEmail / endUserContactId ✅ External
currentAppName / currentObjectApiName / currentPageType / currentRecordId ✅ External

Four observations:

  • @MessagingSession linked variables appear on both agent types.
  • The visibility: attribute has three observable states: "External", "Internal", and omitted. The service-agent UI output emits MessagingSession linked vars with no visibility: at all; the employee-agent UI output emits the same names with visibility: "External". The semantic difference is undocumented.
  • The current* host-context variables only appear on employee agents. They are the mechanism for Lightning Record Page context.
  • Service agents have two additional variable groups the skill never mentions — a verification flow quartet (authenticationKey/customerId/customerType/isVerified) and an email-to-case trio (emailCaseId/endUserEmail/endUserContactId).

Error C1 — examples.md wrongly excludes @MessagingSession linked variables from employee agents

skills/developing-agentforce/references/examples.md, line 85 (inside config: of Minimal Employee Agent):

# NOTE: No default_agent_user — employee agents run as the logged-in user.
# No connection messaging: block — employee agents have no messaging channel.
# No MessagingSession linked variables — those are service-agent-only.

And line 181 (the "deliberately absent" list):

What's deliberately absent (vs. service agents):

  • No default_agent_user in config (agent runs as logged-in employee)
  • No connection messaging: block (no messaging channel)
  • No EndUserId/RoutableId/ContactId linked variables (no @MessagingSession)
  • No @utils.escalate action (requires connection messaging:)

The bolded line is contradicted by the UI output above — EndUserId, RoutableId, ContactId, and EndUserLanguage all appear on employee agents as visibility: "External" linked variables.


Error C2 — current* host-context variables are never mentioned anywhere in the skill

Grep across the entire skill (SKILL.md, all files under references/, all files under assets/):

  • currentRecordIdnot mentioned
  • currentObjectApiNamenot mentioned
  • currentPageTypenot mentioned
  • currentAppNamenot mentioned
  • "host-context" / "host surface" — not mentioned (the two "visibility" hits in SKILL.md are coincidental)

These are the mutable string + visibility: "External" variables the Lightning Experience Agentforce panel populates at session start. Without them — or with them declared without visibility: "External" — an agent that wants to read "this account" / "the current record" context has no way to do so. It just sits there with a dead variable the host never writes.

This is the single most important piece of wiring for record-page-embedded employee agents, and the skill doesn't mention it once.


Error C3 — The visibility: attribute is undocumented

  • references/agent-script-core-language.mdno mention of visibility: as a variable declaration attribute, or External / Internal as values. (The two hits on "Internal" at lines 270 and 406 are for "Internal Error" in publish failures, and for subagent block ordering — neither describes the variable attribute.)
  • SKILL.md Syntax Quick Reference — no mention.

The attribute governs a contract with the host surface:

  • visibility: "External" — host surface populates this variable at session start
  • visibility: "Internal" — variable is hidden from the host
  • visibility: omitted — host never populates it, silently

A new author has no way to know this attribute exists from reading the skill.


Observed failure mode

An employee agent authored by following examples.md literally (e.g., declaring currentRecordId: mutable string = "" with no visibility: and no awareness of the reserved name contract):

Check Result
sf agent validate authoring-bundle success: true
sf agent preview start --use-live-actions ✅ session starts, utterances return correct results for any path that doesn't depend on host context
Utterances referencing the currently-open record when the agent is embedded on a Lightning Record Page ❌ host-context variable is empty at runtime; agent falls back to asking the user for the record's name

The author cannot distinguish a correctly-wired agent from an incorrectly-wired one using any tool in the skill's workflow. Only interactive use in production surfaces the gap. There is no validator warning.


Suggested direction (not a prescribed fix)

Scope note: these suggestions don't change any existing correct content in the skill — they're additive (documenting what's missing) and corrective (fixing the one factually-incorrect exclusion list). Nothing here removes functionality or rewrites conceptual material.

A — Correct references/examples.md "Minimal Employee Agent":

  • Remove the "service-agent-only" framing of EndUserId / RoutableId / ContactId / EndUserLanguage on line 85 and in the deliberately-absent list at line 181.
  • Rewrite the example's variables: block using the UI-generated employee-agent baseline as the starting point (including current* with visibility: "External" and VerifiedCustomerId with visibility: "Internal" if it is part of the canonical baseline).
  • Keep a separate custom-variables example to show author-defined state (like search_query / article_id) alongside the platform variables, not replacing them.

B — Document visibility: in references/agent-script-core-language.md (and reference it from SKILL.md's Syntax Quick Reference):

  • Syntax position on a variable declaration
  • "External" — host surface populates this variable at session start (and which hosts do so)
  • "Internal" — hidden from host
  • Omitted — host never populates the variable (silent failure mode)
  • Which variable names are recognized by the Lightning Record Page host: currentAppName, currentObjectApiName, currentPageType, currentRecordId

C — Add a new reference file — something like references/employee-agent-host-context.md (or a section in examples.md):

  • How employee agents receive context from Lightning Record Page, App Page, Home Page, Utility Bar
  • The canonical list of reserved current* variable names and what populates each
  • The @MessagingSession / @MessagingEndUser / @context.* availability matrix across Service / Employee / host-surface combinations

D — Add a silent-failure entry to references/production-gotchas.md (or known-issues.md):

If @variables.currentRecordId is always empty when the agent is embedded on a record page: check (1) visibility: "External" is present on the declaration, (2) the variable name exactly matches the host's recognized list (currentAppName, currentObjectApiName, currentPageType, currentRecordId). Validator + preview do not catch this; only interactive use on a real Lightning page surfaces it.

E — (Optional but high-value) note the scaffolder output. sf agent generate authoring-bundle currently emits a service-shaped template regardless of agent type. The skill should note that scaffolder output needs pruning/replacement for employee agents, pointing at the canonical baseline from A.


Open questions for the product team

These are the points where the skill maintainer would benefit from authoritative answers from the Agent Script / Agentforce product team before committing to exact wording. I'm listing them here because the issue otherwise invites "well, what exactly should the doc say about visibility?" — and a maintainer without platform-internal knowledge shouldn't have to guess.

On visibility:

  1. What is the default value when visibility: is omitted on a variable? Does it differ between linked and mutable variables?
  2. Is visibility: valid on linked variables at all, or does source: @... make it irrelevant? The service-agent UI emits linked variables without visibility:; the employee-agent UI emits the same names with visibility: "External". What does that difference do at runtime?
  3. Are there values beyond External / Internal? Any ReadOnly, Hidden, channel-specific values?
  4. What does External actually mean in terms of host-surface API — two-way contract, host-read-only, host-write-only?

On host-context variables

  1. Is currentAppName / currentObjectApiName / currentPageType / currentRecordId the complete list, or are there more (e.g., currentUserId, currentLocale, currentOrgId, currentUrl)?
  2. Are the variable names themselves special (host looks for these exact strings) or is visibility: "External" the actual contract, with any External variable settable by the host?
  3. Which host surfaces populate these variables — Lightning Copilot on Record Page, Experience Cloud, Service Cloud Voice, mobile, API sessions?
  4. On a non-record host (Home Page, App Page with no record), do currentRecordId / currentObjectApiName resolve to empty string, null, or unset?
  5. Can employee agents declare additional External variables (beyond the four current*) and have the host populate them, or is the population keyed to recognized names only?

On service-only variable groups

  1. Are authenticationKey / customerId / customerType / isVerified platform-wired (the platform populates and reads them as part of a built-in verification protocol) or are they template defaults the author is expected to wire up manually?
  2. Same question for emailCaseId / endUserEmail / endUserContactId in the email-to-case flow.
  3. VerifiedCustomerId on both agent types — what populates it?

On MessagingSession variables on employee agents

  1. Why does the UI emit @MessagingSession linked variables on employee agents? The skill's claim that employee agents "have no messaging channel" implies those sources can't resolve. Are they:
    • Dead declarations that compile but never populate (UI-emission bug)?
    • Populated in some employee contexts (e.g., an employee using a messaging tool)?
    • Required metadata for some platform feature?

On documentation process

  1. Where is the official source of truth for host-context variable names and the visibility: attribute today? Developer docs? Trailhead? Internal wiki? (The answer "the UI output, empirically" is what led to this report.)
  2. Does the Agent Script team have a process for keeping community-facing skills in sync with UI-emitted defaults as the platform evolves? If not, this class of drift will recur each release.

Evidence trail

  • Skill version observed: current main of SalesforceAIResearch/agentforce-adlc as of 2026-04-30.
  • Variable blocks: copied directly from Agent Builder UI output for newly-created agents of each type (service and employee) on 2026-04-25. No manual edits.
  • Validator confirmation: sf agent validate authoring-bundle --json returned success: true on an AgentforceEmployeeAgent authored from the skill's "Minimal Employee Agent" example, despite the agent lacking the host-context wiring needed for the current* variables to be populated at runtime.
  • Reproducer available on request: single-topic AgentforceEmployeeAgent backed by invocable Apex, published and activated in target org, exhibiting the silent-failure mode described above.

Filed by Matt Wexler, Distinguished SE, Financial Services at Salesforce.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions