---
cuppy_hub: salesforce
cuppy_path: examples/revenue-assistant-agent.md
cuppy_section: docs
cuppy_doc: RM00-WYPV
cuppy_doc_uuid: e081abcc-413a-438c-9d38-ef1a210ae28c
cuppy_permalink: https://cuppy.io/salesforce/d/RM00-WYPV
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/salesforce/docs/examples/revenue-assistant-agent
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 6c5cd2580ab14062a6c5a04fb52182bd44b663fbfc6722ef7ff0fee950d0d143
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# 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`.

```agentscript
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 `access` block, 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.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 376 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/salesforce/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
