afv-library/skills/agentforce-generate/assets/patterns/action-callbacks.agent

109 lines
4.6 KiB
Plaintext

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