afv-library/skills/developing-agentforce/assets/patterns/critical-input-collection.agent
Willie Ruemmele 261abd679a
chore: rename topic to subagent for Agent Script v2 @W-21955450@ (#193)
* @W-21955450@ Rename topic to subagent for Agent Script v2

Aligns with Agent Script v2 naming standards where `topic` is renamed
to `subagent` across all skill documentation and templates.

Changes:
- Agent Script templates: topic keyword → subagent keyword
- References: @topic.* → @subagent.*
- Documentation: Updated all skill references and guides
- Natural language references preserved in comments/descriptions

* Rename start_agent topic_selector to agent_router

Completes the topic → subagent terminology alignment by:

1. Renaming start_agent from topic_selector to agent_router (15 agent files)
2. Updating template topic declarations: topic {{placeholder}} → subagent {{placeholder}} (5 files)
3. Updating all @subagent.topic_selector references to @subagent.agent_router (35 occurrences)
4. Updating documentation: prose, examples, and diagrams (10 markdown files)
5. Updating comments to use agent_router terminology

Files affected:
- 22 agent template files
- 10 documentation/reference markdown files
- Template component files

The agent_router name is more descriptive of its actual function
(routing to different subagents) and completes the Agent Script v2
terminology standardization.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Rename files with "topic" to use "subagent" terminology

Completes the topic → subagent terminology alignment by renaming
files and updating all references:

**Files renamed (5):**
- multi-topic.agent → multi-subagent.agent
- template-single-topic.agent → template-single-subagent.agent
- template-multi-topic.agent → template-multi-subagent.agent
- topic-with-actions.agent → subagent-with-actions.agent
- agent-topic-map-diagrams.md → agent-subagent-map-diagrams.md

**References updated (6 docs):**
- Updated all filename references to point to new filenames
- Updated "Topic Map" → "Subagent Map" throughout documentation
- Updated "multi-topic"/"single-topic" → "multi-subagent"/"single-subagent"

Files modified:
- README.md, SKILL.md, agent-spec-template.md
- assets/agents/README.md, assets/README-legacy.md
- references/agent-design-and-spec-creation.md

This ensures consistent "subagent" terminology across filenames,
file content, and all documentation references.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Complete topic-to-subagent terminology update across skills

Comprehensive update replacing "topic" with "subagent" terminology throughout
the developing-agentforce and testing-agentforce skills to align with Agent
Script's `subagent` block naming.

Key changes:
- "Topic Selector" → "Subagent Router" in all agent templates and docs
- "Topic/action" → "Subagent/action" in documentation
- "Topic map" → "Subagent map" in diagram references
- Updated all architecture documentation to use "subagent" terminology
- Updated 19 .agent template files with new labels and comments
- Updated 8 reference documentation files with consistent terminology

API contract preservation:
- Test spec YAML files preserve "topic" terminology to match Testing Center API
- Added clarifying comments explaining topic/subagent equivalence in YAML files
- Field names like `expectedTopic` unchanged (Salesforce API requirement)

Preserved terms:
- "off-topic" (standard phrase for out-of-scope)
- "expectedTopic" field (Testing Center API)
- "platform topics" (Salesforce guardrail features)

32 files changed, 379 insertions(+), 366 deletions(-)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Complete comprehensive topic-to-subagent terminology update

Thorough update replacing all remaining "topic" references with "subagent"
terminology across developing-agentforce, testing-agentforce, and
observing-agentforce skills to fully align with Agent Script's `subagent`
block naming.

Key changes:
- Agent Script syntax: @topic.<name> → @subagent.<name>
- Agent Script syntax: topic.actions → subagent.actions
- Shell script patterns: ^topic → ^subagent
- Documentation: "topic instructions" → "subagent instructions"
- observing-agentforce skill: Updated all agent architecture references
- Template files: Updated all inline comments and descriptions
- Variable names in scripts: TOPIC → SUBAGENT

Specific updates:
- 45 files changed, 294 insertions, 294 deletions
- Updated all Agent Script code examples to use @subagent syntax
- Updated observing-agentforce issue classification guide
- Updated shell script patterns in diagnostic tools
- Updated Apex comments to clarify topic field maps to subagents

Preserved (as required):
- "off-topic" and "off_topic" (standard out-of-scope phrase)
- Testing Center API fields: expectedTopic, topic: in YAML
- API response fields: .topic, generatedData.topic, topic_assertion
- STDM field names: ssot__TopicApiName__c (with clarifying docs)
- Template placeholders in test specs (API values)
- "Topic hash drift" (API field behavior)
- "Email topic/purpose" (means email subject)
- Explanatory comments about API field mapping

All Agent Script syntax and documentation now consistently uses "subagent"
while preserving backward compatibility with platform API field names.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* a few more topic -> subagent replacements

---------

Co-authored-by: Steve Hetzel <shetzel@salesforce.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-27 12:42:18 -06:00

245 lines
11 KiB
Plaintext

# Critical Input Collection Pattern
# Ensures reliable capture of critical data before proceeding with workflows
#
# ★ Problem This Solves:
# - LLM sends empty JSON to actions
# - LLM sends wrong field names (_id instead of account_id)
# - LLM extracts wrong values from conversation
# - Agent proceeds without required data, causing crashes
#
# ★ Root Cause:
# Slot filling (`with account_id=...`) relies on LLM inference, which is
# probabilistic and can fail in subtle ways. Critical inputs need
# deterministic collection with validation.
#
# ★ Key Patterns:
# 1. First-Interaction Collection - Tell LLM its PRIMARY GOAL
# 2. Variable Setter Action - Dedicated action to capture + validate + store
# 3. Single-Use Pattern - `available when @var == ""` disables after use
# 4. Null Guard Pattern - Block ALL downstream actions until input is valid
# 5. Explicit Action References - Guide LLM with `{!@actions.x}` in instructions
#
# ★ When To Use This Pattern:
# - Workflows that REQUIRE a specific ID (account, order, case, etc.)
# - When slot filling has been unreliable
# - When invalid input causes downstream failures
# - Multi-subagent agents where input must persist across transitions
#
# This is a COMPLETE template - customize for your use case
system:
instructions: "You are a research assistant. Your PRIMARY GOAL is to collect the account ID before performing any research. Never proceed without a validated account ID."
messages:
welcome: "Hello! I can help you research account information. Please provide the account ID to get started."
error: "I encountered an issue. Let me try again."
config:
agent_name: "Account_Research_Agent"
default_agent_user: "agent@company.salesforce.com"
agent_label: "Account Research Agent"
description: "Demonstrates critical input collection patterns for reliable slot filling"
variables:
# Standard linked variables (required)
EndUserId: linked string
source: @MessagingSession.MessagingEndUserId
description: "Messaging End User ID"
RoutableId: linked string
source: @MessagingSession.Id
description: "Messaging Session ID"
ContactId: linked string
source: @MessagingEndUser.ContactId
description: "Contact ID"
# ★ CRITICAL INPUT - The value that MUST be collected before proceeding
account_id: mutable string = ""
description: "The Salesforce Account ID (18-char, starts with 001) - MUST be collected and validated before any research"
# ★ VALIDATION STATE - Track whether input has been validated
account_id_validated: mutable boolean = False
description: "Whether account_id has been validated as a real Salesforce ID"
# ★ COLLECTION ATTEMPTS - Track retries to prevent infinite loops
collection_attempts: mutable number = 0
description: "Number of times we've tried to collect account_id"
# Research results
account_name: mutable string = ""
description: "Name of the account (from lookup)"
research_summary: mutable string = ""
description: "Research summary for the account"
language:
default_locale: "en_US"
additional_locales: ""
all_additional_locales: False
# ★ ENTRY POINT: Input Collection Subagent
# This subagent's ONLY job is to collect and validate the critical input
start_agent input_collector:
label: "Input Collector"
description: "Collects and validates the account ID before allowing research"
actions:
# ★ PATTERN 2: Variable Setter Action
# Dedicated action that captures, validates, and stores the input
capture_account_id:
description: "Captures and validates the Salesforce Account ID from user input"
inputs:
account_id: string
description: "The 18-character Salesforce Account ID provided by the user (format: starts with '001')"
is_required: True
outputs:
validated_account_id: string
description: "The validated account ID (empty if invalid)"
is_valid: boolean
description: "True if the account ID is valid and exists"
account_name: string
description: "Name of the account if found"
error_message: string
description: "Error message if validation failed"
target: "flow://Validate_Account_Id"
require_user_confirmation: False
include_in_progress_indicator: True
progress_indicator_message: "Validating account ID..."
reasoning:
# ★ PATTERN 1: First-Interaction Collection
# Tell the LLM its PRIMARY GOAL is to collect the input
instructions: ->
| YOUR PRIMARY GOAL: Collect the account ID from the user.
|
| CURRENT STATE:
if @variables.account_id == "":
| ⚠️ Account ID NOT YET COLLECTED
| ASK the user for their Salesforce Account ID.
| The ID should be 18 characters and start with "001".
|
| Example prompt: "Please provide the Account ID you'd like me to research."
if @variables.account_id != "" and @variables.account_id_validated == False:
| 🔄 Account ID received: {!@variables.account_id}
| Attempting validation...
|
| Use {!@actions.capture_account_id} to validate this ID.
if @variables.account_id_validated == True:
| ✅ Account ID validated: {!@variables.account_id}
| Account Name: {!@variables.account_name}
|
| Transition to research subagent to begin analysis.
if @variables.collection_attempts > 2 and @variables.account_id_validated == False:
| ❌ Multiple validation failures.
| Ask the user to verify their Account ID is correct.
| Suggest they check Salesforce for the correct ID format.
actions:
# ★ PATTERN 3: Single-Use Pattern
# Action becomes unavailable once account_id is successfully captured
validate_id: @actions.capture_account_id
with account_id=...
set @variables.account_id = @outputs.validated_account_id
set @variables.account_id_validated = @outputs.is_valid
set @variables.account_name = @outputs.account_name
set @variables.collection_attempts = @variables.collection_attempts + 1
# ★ SINGLE-USE: Unavailable once validated
available when @variables.account_id_validated == False
# ★ PATTERN 4: Null Guard Pattern
# Transition ONLY available when input is validated
go_research: @utils.transition to @subagent.research
available when @variables.account_id_validated == True
# ★ RESEARCH SUBAGENT: Only accessible after input is validated
subagent research:
label: "Account Research"
description: "Performs research on the validated account"
actions:
# Research action that USES the validated account_id
research_account:
description: "Performs detailed research on the account"
inputs:
account_id: string
description: "The validated account ID"
is_required: True
outputs:
research_summary: string
description: "Summary of research findings"
signal_summary: string
description: "Key signals detected"
target: "flow://Research_Account"
include_in_progress_indicator: True
progress_indicator_message: "Researching account..."
reasoning:
instructions: ->
| Researching account: {!@variables.account_name} ({!@variables.account_id})
|
if @variables.research_summary == "":
| Use {!@actions.research_account} to analyze this account.
if @variables.research_summary != "":
| Research complete!
| {!@variables.research_summary}
actions:
# ★ PATTERN 4: Null Guard - Uses variable binding, NOT slot filling
# This ensures the validated ID is used, not LLM re-extraction
do_research: @actions.research_account
with account_id=@variables.account_id
set @variables.research_summary = @outputs.research_summary
# ★ GUARD: Only available if we have validated ID (defensive)
available when @variables.account_id_validated == True
available when @variables.research_summary == ""
# Return to collector for new account
new_account: @utils.transition to @subagent.input_collector
available when @variables.research_summary != ""
# ═══════════════════════════════════════════════════════════════════════════
# ★ INSIGHTS: Critical Input Collection
# ═══════════════════════════════════════════════════════════════════════════
#
# WHY SLOT FILLING FAILS:
# The `...` syntax relies on LLM to extract values from conversation.
# This is probabilistic and can fail when:
# - User provides ID in unexpected format
# - Multiple IDs mentioned in conversation
# - LLM abbreviates or modifies field names
# - Context window is cluttered with other data
#
# THE SOLUTION: DETERMINISTIC COLLECTION
# Instead of `with account_id=...` on EVERY action:
# 1. Collect ONCE with a dedicated setter action
# 2. Validate BEFORE storing
# 3. Store in variable: `set @variables.account_id = @outputs.validated_id`
# 4. Use variable binding: `with account_id=@variables.account_id`
# 5. Guard all actions: `available when @variables.account_id_validated == True`
#
# PATTERN SUMMARY:
#
# ┌─────────────────────────────────────────────────────────────────┐
# │ CRITICAL INPUT COLLECTION FLOW │
# ├─────────────────────────────────────────────────────────────────┤
# │ │
# │ User provides ID ────► Setter Action (slot fills once) │
# │ │ │
# │ ▼ │
# │ Validation │
# │ │ │
# │ ┌────────┴────────┐ │
# │ ▼ ▼ │
# │ Valid Invalid │
# │ │ │ │
# │ set @variables.account_id Ask again │
# │ set @variables.validated=True (limit retries) │
# │ │ │
# │ ▼ │
# │ All downstream actions use │
# │ @variables.account_id (NOT ...) │
# │ │
# └─────────────────────────────────────────────────────────────────┘
#
# ═══════════════════════════════════════════════════════════════════════════