# Lifecycle Events Pattern # Use before_reasoning and after_reasoning for per-turn external work # # ★ When To Use This Pattern: # - Refresh external context BEFORE the LLM starts reasoning # - Clean up or log AFTER reasoning completes # - Supply trusted action output that instructions need to reference # # ★ Key Insight: # - before_reasoning: Runs when execution reaches the pre-reasoning hook # - after_reasoning: Runs when execution reaches the post-reasoning hook # - Hook contents are deterministic, unlike LLM-chosen actions # # ★ CRITICAL SYNTAX RULES for Lifecycle Blocks: # 1. Use "transition to" NOT "@utils.transition to" for transitions # 2. The pipe (|) command is NOT supported in lifecycle blocks # 3. after_reasoning may NOT run if a transition occurs mid-subagent # 4. `run` is supported for deterministic action execution and callbacks. # # ★ Common Use Cases: # - Fetch fresh data before each response # - Log conversation analytics after each turn # - Conditional routing based on state (use "transition to") # # This is a COMPLETE template - customize actions and metadata. system: instructions: | You are a context-aware service assistant. Answer using the external context refreshed for the current turn. Do not infer external facts that are absent from the refresh result. messages: welcome: "Hello! How can I help?" error: "I couldn't refresh the information needed for that request." access: default_agent_user: "agent@company.salesforce.com" config: developer_name: "Lifecycle_Events_Agent" agent_label: "Lifecycle Events" description: "Demonstrates deterministic context refresh and analytics logging" variables: EndUserId: linked string source: @MessagingSession.MessagingEndUserId description: "Messaging end user identifier" RoutableId: linked string source: @MessagingSession.Id description: "Messaging session identifier for analytics" current_context: mutable string = "" description: "Trusted external context refreshed and consumed on each turn" language: default_locale: "en_US" start_agent conversation: label: "Conversation" description: "Main conversation handler with lifecycle tracking" actions: refresh_context: description: "Fetches latest context for user" inputs: user_id: string description: "User to get context for" outputs: context: string description: "User's current context" target: "flow://Get_User_Context" log_turn: description: "Logs conversation turn analytics" inputs: session_id: string description: "Messaging session being logged" handler_name: string description: "Request handler producing the event" outputs: logged: boolean description: "Whether log succeeded" target: "apex://AnalyticsLogTurn" # ★ before_reasoning: Runs once when this handler enters its reasoning loop before_reasoning: # ★ CORRECT: Use "transition to" (not @utils.transition to) in lifecycle blocks # Example: Route away if session expired # if @variables.session_expired == True: # transition to @subagent.session_expired # Refresh context before every turn run @actions.refresh_context with user_id=@variables.EndUserId set @variables.current_context = @outputs.context # Main reasoning block reasoning: instructions: -> | Current user context: | {!@variables.current_context} | | Respond helpfully using the refreshed context above. actions: end_conversation: @utils.transition to @subagent.farewell # ★ after_reasoning: Runs once when this handler completes its reasoning loop after_reasoning: # Log analytics for each turn run @actions.log_turn with session_id=@variables.RoutableId with handler_name="conversation" # ★ Insight: Lifecycle blocks vs Action callbacks # # - before_reasoning/after_reasoning: Run automatically when execution reaches them # - run callbacks: Run only when parent action is invoked # # Use lifecycle for: External context refresh, logging, and session management # Use callbacks for: Post-action processing, chained operations subagent farewell: label: "Farewell" description: "Ends the conversation when the user is finished" reasoning: instructions: -> | Thank the user and close the conversation politely.