# Action Callbacks Pattern # Use `run` for deterministic post-action processing. # # Use this pattern when: # - a declared action must run after another action returns normally; # - the callback needs values from the parent action's `@outputs`; and # - skipping that processing would produce an inconsistent response. # # Runtime contract: # - `run` is deterministic once its containing action path is reached. # - A returned negative result such as `found=False` is still a result. Bind # that outcome into the callback so it can produce an honest response. # - Do not claim that callbacks recover from execution failures. If the # parent action does not return normally, downstream completion is not # established by this pattern. # - Keep callbacks one level deep; do not nest `run` beneath another `run`. # # This complete, read-only example looks up a shipment and deterministically # normalizes the returned fields. It uses conversation history for ordinary # turn flow and therefore needs no mutable variables. system: instructions: | You help customers check shipment status. Never invent a tracking result. Use the normalized result returned by the actions, including an explicit not-found result, when answering. messages: welcome: "Hello! I can check a shipment for you." error: "I couldn't check that shipment right now." config: developer_name: "Action_Callbacks_Agent" agent_label: "Action Callbacks" description: "Demonstrates deterministic read-only post-action processing" access: default_agent_user: "agent@company.salesforce.com" language: default_locale: "en_US" start_agent shipment_status: label: "Shipment Status" description: "Looks up and normalizes shipment status" actions: get_shipment_status: description: "Read the current status for a tracking number" inputs: tracking_number: string description: "Tracking number supplied by the customer" outputs: found: boolean description: "Whether the shipment was found" canonical_tracking_number: string description: "Canonical tracking number, empty when not found" status: string description: "Current shipment status, empty when not found" estimated_delivery: string description: "Estimated delivery date, empty when unavailable" target: "flow://Get_Shipment_Status" normalize_shipment_result: description: "Normalize a returned shipment lookup without changing data" inputs: found: boolean description: "Whether the parent lookup found a shipment" canonical_tracking_number: string description: "Canonical tracking number returned by the lookup" status: string description: "Status returned by the lookup" estimated_delivery: string description: "Estimated delivery returned by the lookup" outputs: summary: string description: "Grounded customer-facing lookup summary" is_displayable: True filter_from_agent: False target: "flow://Normalize_Shipment_Result" reasoning: instructions: -> | Ask for a tracking number when none is present in the conversation. | Use the shipment lookup for a supplied tracking number. | Answer from the normalized result. If it says the shipment was | not found or delivery is unavailable, say that directly. actions: # The callback runs after the lookup returns normally. Every value # it consumes is bound directly from that parent result, including # `found`, so an empty lookup cannot be presented as a success. track_shipment: @actions.get_shipment_status with tracking_number=... run @actions.normalize_shipment_result with found=@outputs.found with canonical_tracking_number=@outputs.canonical_tracking_number with status=@outputs.status with estimated_delivery=@outputs.estimated_delivery # Anti-pattern: nested callbacks. # # process: @actions.first # run @actions.second # run @actions.third # # If a third deterministic step is required, redesign the backing automation # as one atomic action or use a supported lifecycle/sequence with explicit # inputs and failure semantics.