Skip to main content
Bring your team and maximize your impact at Dreamforce. Register three or more to unlock $999 passes.

Manage State Across a Multi-Turn Conversation

Learning Objectives

After completing this unit, you'll be able to:

  • Use a step variable to enforce a required sequence of subagents across many turns.
  • Explain how action chaining runs a follow-up action automatically and deterministically.
  • Describe how after reasoning blocks run deterministic logic after each LLM response.
  • Apply a subagent-level system block to override the agent's persona for one subagent.
  • Describe how model config assigns different models to different subagents.

When One Variable Isn’t Enough

So far, your variables have held single facts—a lifetime value, a yes-or-no flag. That's plenty for the loyalty logic you built. But imagine extending the CC Service Agent to book an experience. Booking is a conversation, not a lookup—you need the date, the party size, any dietary needs, and then a confirmation. Each answer might change the next question. Customers might give vague answers and need a follow-up. And they absolutely can’t skip to "confirm" before you've collected the essentials.

This is the hardest thing to get right with an LLM, because LLMs are happy to wander. One solution in Agent Script is a step variable. It’s a single variable that records where the customer is in the sequence, with the router using it to pick the right subagent every turn.

The Step Variable Pattern

The idea has two halves that work together turn after turn.

First, the router reads the step variable. Instead of letting the LLM choose freely, the router uses deterministic transitions keyed to the current step. Remember the deterministic transitions from Unit 2? Here's where they earn their keep.

variables:
    bookingStep: mutable string = "ChooseDate"
        description: "Tracks the customer's progress through booking: ChooseDate,
                      PartySize, Confirm, or Done."
start_agent agent_router:
    description: "Route to the current booking step."
    reasoning:
        instructions: ->
            if @variables.bookingStep == "ChooseDate":
                transition to @subagent.choose_date
            if @variables.bookingStep == "PartySize":
                transition to @subagent.party_size
            if @variables.bookingStep == "Confirm":
                transition to @subagent.confirm_booking

Then each subagent owns one step and advances the variable when its work is done. The subagent decides whether the customer's answer was good enough. If not, it stays put and asks again. If so, it sets bookingStep to the next step—and on the next turn, the router routes accordingly.

subagent choose_date:
    description: "Collect the date the customer wants to book."
    reasoning:
        instructions: ->
            | Ask the customer which date they'd like to book their experience.
              If the date is in the past or unclear, ask again until you have a
              valid future date.
              Once you have a valid date, call {!@actions.advanceToPartySize}.
        actions:
            advanceToPartySize: @utils.setVariables
                description: "Advance the booking to the party size step."
                with bookingStep = "PartySize"

Think through what this guarantees. The router never sends the customer to confirm_booking until some earlier subagent sets bookingStep to "Confirm"—and a subagent only does that once it's satisfied with the answer it collected. The customer can plead, change the subject, or try to skip ahead, but the sequence holds because routing is determined by a variable you control, not by LLM goodwill.

Note

Subagent Responsibility

Keep one responsibility per subagent—one question, one validation, one advance. And use readable step names (ChooseDate, PartySize) rather than numbers, so the next person to open the script can follow the flow.

This is the same instinct behind the loyalty work in the last badge. Let deterministic logic, not the LLM, enforce the rules that matter—scaled up to a whole multi-turn workflow.

Chain Actions Together

Booking often means doing two things back to back. In the last badge, you set the isCreditIssued variable as a follow-up right after IssueResortCredit ran—that was a chained action. Agent Script lets you nest a run inside a reasoning action so the follow-up fires automatically whenever the LLM calls the first one.

subagent confirm_booking:
    reasoning:
        actions:
            book_experience: @actions.book_experience
                with date=@variables.bookingDate
                set @variables.confirmation_id=@outputs.confirmation_id
                run @actions.send_confirmation_email
                    with confirmation_id=@outputs.confirmation_id

When the LLM calls book_experience, send_confirmation_email runs immediately after—deterministically, no second decision is required. Chaining keeps your prompts clean (you don't have to tell the LLM to remember step two) and your workflow reliable (step two can't be forgotten).

Run Logic After the LLM Responds

Everything so far runs before the LLM responds. But sometimes you need a deterministic check on every turn afterward. That's the after_reasoning block.

Imagine you want to transfer the conversation to a human when booking conversations drag on too long.

subagent choose_date:
    reasoning:
        instructions: ->
            | Ask the customer which date they'd like to book.
    after_reasoning: ->
        set @variables.turn_count = @variables.turn_count + 1
        if @variables.turn_count >= 5:
            transition to @subagent.human_handoff

Because after_reasoning runs after the response is sent, the customer reads the agent's current reply, and the transition to human_handoff takes effect in the next message. It's the right tool for counters, logging, and "if we're still here after N turns" escalations.

Give Subagents a Voice

The system block sets your agent's overall persona—for Coral Cloud Resorts, that’s warm and welcoming. But a single tone doesn't always fit. A billing-dispute subagent might need to be more formal and precise. You can override the persona for just that subagent by adding a system block inside it.

system:
    instructions: "You are a warm, friendly Coral Cloud Resorts assistant."
subagent billing_dispute:
    description: "Handles billing disputes and account adjustments."
    system:
        instructions: "You are a precise billing specialist. Use exact language,
                        cite policy when explaining decisions, and never speculate
                        about account status."
    reasoning:
        instructions: ->
            | Help the customer resolve their billing dispute.

When a subagent has a discrete system block, those instructions replace the global ones for that subagent only—they don't stack. The rest of the agent keeps the friendly Coral Cloud Resorts voice. This also prevents a subtle bug—if your global persona contradicts what a subagent needs to do, the agent can stall trying to reconcile them. An override resolves the conflict cleanly.

Configure Models per Subagent

By default, every subagent uses the model the agent is configured with. But a router that just classifies intent doesn't need the same horsepower as a subagent that writes detailed responses. Use model_config to assign a model at the agent or subagent level.

config:
    developer_name: "cc_service_agent"
    model_config:
        model: "sfdc_ai__DefaultGPT4Omni"
start_agent agent_router:
    description: "Classify intent and route to the right subagent."
    model_config:
        model: "EinsteinHyperClassifier"
    reasoning:
        instructions: ->
            | Determine the best subagent for the customer's request.

EinsteinHyperClassifier is a Salesforce-owned model tuned for fast intent classification—a smart default for a router, where speed matters more than prose. Sophisticated models handle the subagents that actually reason and write. A subagent-level model_config overrides the global one for that subagent only—the same override pattern you just learned about for system instructions.

You Can Read and Write Agent Script

You started this journey going through the Canvas to reward loyal Coral Cloud Resorts customers. Now you can open Script view and read exactly what that work produced—and write the parts the Canvas doesn't reach. You know the blocks, the reasoning loop, and the variables that carry state. You can route deterministically, gate tools behind conditions, and enforce a required flow.

And you can hold a multi-turn conversation on the rails with a step variable, chain actions, run after-response logic, reshape a subagent's persona, and tune its model. That's the Agent Script language—and it's the same language whether you write it, the Canvas writes it, or an AI coding tool writes it for your review.

Resources

Salesforce 도움말에서 Trailhead 피드백을 공유하세요.

Trailhead에 관한 여러분의 의견에 귀 기울이겠습니다. 이제 Salesforce 도움말 사이트에서 언제든지 새로운 피드백 양식을 작성할 수 있습니다.

자세히 알아보기 의견 공유하기