Example agent — Revenue Assistant, an Agent Script employee agent grounded on Data 360 golden records (account brief through a Data 360 flow, lookalike search through a custom-retriever Data Library, next best offer through a prompt template)
A complete Agent Script file for a seller-facing revenue agent that passes Salesforce's open-source linter and compiler. A router sends sellers to an account brief, where a flow reads the golden record's revenue rollup and a prompt template proposes a next best offer, or to account search, where AnswerQuestionsWithKnowledge queries the golden-record search index through an Agentforce Data Library. Replace the library ID and the action targets with yours.
markdownexamplev1RM00-WYPVstage: buildtrust: officialservice: agentforceinterface: agent-scriptRevenue Assistant agentgolden record agent exampleAgentforceEmployeeAgent knowledge blockAnswerQuestionsWithKnowledge custom retrieverflow://Get_Account_Revenue_Contextprompt://Next_Best_OfferInput:Account_Contextnext best offer agentaccount brief agentlookalike accounts agent
Example: Revenue Assistant
force-app/main/default/aiAuthoringBundles/Revenue_Assistant/Revenue_Assistant.agent. How to build what it calls, and how to deploy and test it: guides/data360/ground-a-revenue-agent.md.
config:
developer_name: "Revenue_Assistant"
agent_label: "Revenue Assistant"
description: "Helps sellers grow revenue from golden-record account context: briefs, lookalike accounts and next best offers"
agent_type: "AgentforceEmployeeAgent"
variables:
account_name: mutable string = ""
description: "Name of the account the seller is working on"
account_context: mutable string = ""
description: "Revenue summary returned for the current account"
system:
messages:
welcome: "Hi, I can brief you on an account, find similar accounts, and suggest a next best offer."
error: "Sorry, something went wrong. Please try again."
instructions: "You help sellers grow revenue. Use only figures returned by your actions. Never invent orders, amounts or dates."
knowledge:
rag_feature_config_id: "ARFPC_1JDXX0000000001AAA"
citations_enabled: True
citations_url: ""
start_agent agent_router:
description: "Route the seller to the right revenue task"
reasoning:
instructions: |
Pick the tool that matches the request. If no account is named for a brief or offer, ask for it.
actions:
go_brief: @utils.transition to @subagent.account_brief
description: "Brief on one named account, or suggest an offer for it"
go_find: @utils.transition to @subagent.find_accounts
description: "Find accounts that match a description, or accounts similar to one"
subagent account_brief:
description: "Summarize one account's golden-record revenue and suggest a next best offer"
actions:
get_account_context:
description: "Get the unified revenue context for an account: lifetime revenue, order count, last order, top products"
inputs:
accountName: string
description: "Account name as the seller says it"
is_required: True
outputs:
revenueSummary: string
description: "Plain-text revenue summary from Data 360"
is_displayable: True
lifetimeRevenue: number
description: "Lifetime revenue across all unified source records"
target: "flow://Get_Account_Revenue_Context"
include_in_progress_indicator: True
progress_indicator_message: "Reading the golden record..."
next_best_offer:
description: "Suggest the next best offer from the account's revenue context"
inputs:
"Input:Account_Context": string
description: "The revenue summary for the account"
is_required: True
outputs:
promptResponse: string
description: "The suggested offer with its reasoning"
is_displayable: True
target: "prompt://Next_Best_Offer"
reasoning:
instructions: ->
| Get the account's revenue context with {!@actions.get_account_context} before answering.
if @variables.account_context != "":
| Summarize it in three bullets, then offer a next best offer with {!@actions.next_best_offer}.
else:
| Ask which account the seller means.
actions:
capture_account: @utils.setVariables
description: "Record the account the seller names"
with account_name = ...
brief: @actions.get_account_context
available when @variables.account_name != ""
with accountName = @variables.account_name
set @variables.account_context = @outputs.revenueSummary
offer: @actions.next_best_offer
available when @variables.account_context != ""
with "Input:Account_Context" = @variables.account_context
subagent find_accounts:
description: "Find accounts by description or similarity using the golden-record search index"
actions:
AnswerQuestionsWithKnowledge:
description: "Searches unified account narratives (revenue, orders, products) to find matching or similar accounts"
inputs:
query: string
description: "Required. A search query created from the seller's request."
label: "Query"
is_required: True
is_user_input: True
citationsUrl: string = @knowledge.citations_url
description: "The URL to use for citations for custom Agents."
label: "Citations Url"
is_required: False
is_user_input: True
ragFeatureConfigId: string = @knowledge.rag_feature_config_id
description: "The RAG Feature ID to use for grounding this copilot action invocation."
label: "RAG Feature Configuration Id"
is_required: False
is_user_input: True
citationsEnabled: boolean = @knowledge.citations_enabled
description: "Whether or not citations are enabled."
label: "Citations Enabled"
is_required: False
is_user_input: True
outputs:
knowledgeSummary: object
description: "Rich-text summary of the matching account narratives, with citations."
label: "Knowledge Summary"
complex_data_type_name: "lightning__richTextType"
filter_from_agent: False
is_displayable: True
citationSources: object
description: "Source links for the retrieved chunks."
label: "Citation Sources"
complex_data_type_name: "@apexClassType/AiCopilot__GenAiCitationInput"
filter_from_agent: False
is_displayable: False
target: "standardInvocableAction://streamKnowledgeSearch"
label: "Answer Questions with Knowledge"
require_user_confirmation: False
include_in_progress_indicator: True
progress_indicator_message: "Searching golden records"
source: "EmployeeCopilot__AnswerQuestionsWithKnowledge"
reasoning:
instructions: ->
| For every search, call {!@actions.AnswerQuestionsWithKnowledge} before answering.
| Answer only from the returned summary and cite its sources. If it is empty, say no matching accounts were found.
actions:
search_accounts: @actions.AnswerQuestionsWithKnowledge
with query = ...
with citationsUrl = ...
with ragFeatureConfigId = ...
with citationsEnabled = ...
- Employee agent: it runs as the signed-in seller, so there is no
accessblock, and the seller needs Data 360 access. - Tool names for tests:
brief,offer,search_accounts. Agent tests expect these, not the action declaration names (reference/agentforce/agent-testing.md). - Grounding rule: "Use only figures returned by your actions" lives in
system.instructions, so every subagent inherits it.