| `label` | String | No | Display name in UI; auto-generated from action name if omitted |
| `inputs` | Object | No | Input parameters and requirements |
| `outputs` | Object | No | Return parameters |
| `available_when` | Expression | No | Conditional availability for the LLM |
| `require_user_confirmation` | Boolean | No | Ask user to confirm before execution; defaults to `False` |
| `include_in_progress_indicator` | Boolean | No | Show progress indicator during execution; defaults to `False` |
| `progress_indicator_message` | String | No | Custom message shown during execution (e.g., "Processing your request...") |
> **Note**: `label`, `require_user_confirmation`, `include_in_progress_indicator`, and `progress_indicator_message` are valid on action definitions with `target:` but NOT on `@utils.transition` utility actions.
### Input Properties
| Property | Type | Description |
|----------|------|-------------|
| `description` | String | Explains the input parameter to LLM; auto-generated from field name if omitted |
| `label` | String | Display name in UI; auto-generated from field name if omitted |
| `is_required` | Boolean | Marks input as mandatory for the LLM; defaults to `False` |
| `is_user_input` | Boolean | LLM extracts value from conversation context; defaults to `False` |
| `complex_data_type_name` | String | Lightning data type mapping (required for complex types) |
### Output Properties
| Property | Type | Description |
|----------|------|-------------|
| `description` | String | Explains the output parameter to LLM; auto-generated from field name if omitted |
| `label` | String | Display name in UI; auto-generated from field name if omitted |
| `filter_from_agent` | Boolean | `True` = exclude output from agent context; defaults to `False` |
| `is_used_by_planner` | Boolean | `True` = LLM can reason about this value for routing decisions; defaults to `False` |
| `complex_data_type_name` | String | Lightning data type mapping (required for complex types) |
| `is_displayable` | Boolean | `False` = hide from user display (compile-valid alias for `filter_from_agent: True`) |
> **Note**: `filter_from_agent: True` is the GA standard. `is_displayable: False` is a compile-valid alias with the same effect.
> **Safety**: For service agents (customer-facing), internal business metrics (risk scores, retention tiers, churn probability, internal classification codes) should be `filter_from_agent: True` so the LLM can use them for reasoning but they don't appear in customer-facing responses.
Use `filter_from_agent: True` + `is_used_by_planner: True` to let the LLM route based on action outputs without being able to show them to the user:
```agentscript
outputs:
intent_classification: string
filter_from_agent: True # LLM cannot show this to user
is_used_by_planner: True # LLM can use for routing decisions
```
This prevents the LLM from fabricating classification results — it must invoke the action to get the value, then can only use it for routing decisions.
- **Actions Block** (`actions:` in `reasoning:`) — LLM chooses which to execute
- **Deterministic** (`run @actions.name`) — always executes when code path is reached
### Invoking Actions with `actions` Blocks
The LLM automatically selects appropriate actions from those defined in the `reasoning.actions` block:
```agentscript
topic order_management:
description: "Handles order inquiries"
reasoning:
instructions: ->
| Help the customer with their order.
| When they ask about an order, look it up.
actions:
# LLM automatically selects this when appropriate
lookup: @actions.get_order
with order_id=...
set @variables.order_status = @outputs.status
actions:
get_order:
description: "Retrieves order information"
inputs:
order_id: string
description: "The order ID"
outputs:
status: string
description: "Order status"
target: "flow://Get_Order_Details"
```
You can also reference action definitions inside `instructions:` using `{!@actions.name}` interpolation. This gives the LLM richer context about available actions.
```agentscript
reasoning:
instructions: ->
| To look up an order, use {!@actions.get_order}.
| To check shipping status, use {!@actions.track_shipment}.
```
> See [action-patterns.md](action-patterns.md#2-instruction-action-references) for detailed usage patterns and examples.
### Invoking Actions Deterministically with `run`
The `run` keyword is only supported in `reasoning.actions:` post-action blocks and `instructions: ->` blocks.
```agentscript
# ❌ DOES NOT WORK — run in before_reasoning (no LLM context)
before_reasoning:
run @actions.log_turn # May not execute as expected
# ✅ WORKS — run in reasoning.actions post-action block
create: @actions.create_order
with customer_id = @variables.customer_id
run @actions.send_confirmation
set @variables.order_id = @outputs.id
# ✅ WORKS — run in instructions: -> block
reasoning:
instructions: ->
run @actions.load_customer
with id = @variables.customer_id
set @variables.name = @outputs.name
```
---
## Action Type 1: Flow Actions
### When to Use
- Standard Salesforce data operations (CRUD)
- Business logic that can be expressed in Flow
- Screen flows for guided user experiences
- Approval processes
### Implementation
```yaml
actions:
create_case:
description: "Creates a new support case for the customer"
#### Step 2: Reference DIRECTLY in Agent Script via `apex://`
```yaml
topic discount_calculator:
description: "Calculates discount for customer order"
# Level 1: Action DEFINITION with target
actions:
calculate_discount:
description: "Calculates discount based on order amount and customer tier"
inputs:
orderAmount: number
description: "The total order amount before discount"
customerTier: string
description: "Customer membership tier"
outputs:
discountPercentage: number
description: "Applied discount percentage"
finalAmount: number
description: "Final order amount after discount"
target: "apex://CalculateDiscountAction"
reasoning:
instructions: |
Help the customer calculate their discount.
# Level 2: Action INVOCATION referencing the Level 1 definition
actions:
calc: @actions.calculate_discount
with orderAmount=...
with customerTier=@variables.tier
set @variables.final_amount = @outputs.finalAmount
```
#### I/O Name Matching Rules
Action `inputs:` and `outputs:` names in Agent Script must **exactly match** the `@InvocableVariable` field names in the Apex class:
```agentscript
# Given this Apex field:
# @InvocableVariable
# public Decimal orderAmount;
# ❌ WRONG — snake_case doesn't match camelCase field name
inputs:
order_amount: number
# ❌ WRONG — different name entirely
inputs:
amount: number
# ✅ CORRECT — exact match to Apex field name
inputs:
orderAmount: number
```
> **Partial Output Pattern**: You can declare a **subset** of the target's outputs in your action definition — you don't need to map every output parameter. This is useful when you only need one field from a multi-output action.
#### Bare @InvocableMethod Pattern (NOT Compatible)
Apex classes using bare `List<String>` parameters without `@InvocableVariable` wrapper classes are **incompatible** with Agent Script. The framework cannot discover bindable parameter names without `@InvocableVariable` annotations.
```apex
// ❌ WRONG — bare parameters, no wrappers (Agent Script cannot bind inputs/outputs)
public class BareAction {
@InvocableMethod(label='Bare Action')
public static List<String> execute(List<String> inputs) {
return inputs;
}
}
// ✅ CORRECT — wrapper classes with @InvocableVariable
public class WrappedAction {
public class Request {
@InvocableVariable(
label='Input Text'
description='Text to process'
required=true
)
public String inputText;
}
public class Response {
@InvocableVariable(
label='Output Text'
description='Processed result'
)
public String outputText;
}
@InvocableMethod(label='Wrapped Action')
public static List<Response> execute(List<Request> requests) { ... }
}
```
> ⚠️ **Namespace Warning (Unresolved)**: In namespaced packages, `apex://ClassName` may fail at publish time with "invocable action does not exist," even when the Apex class is confirmed deployed via SOQL. It is unclear whether namespace prefix syntax is required (e.g., `apex://ns__ClassName`). If you encounter this in a namespaced org, try: (1) `apex://ns__ClassName` format, (2) wrapping the Apex in a Flow and using `flow://` instead. See [known-issues.md](known-issues.md#issue-2-sf-agent-publish-fails-with-namespace-prefix-on-apex-targets) for tracking.
---
## Action Type 3: API Actions (External System Integration)
> **Service agents only.** The `connection messaging:` block and `@utils.escalate` are only valid for `AgentforceServiceAgent`. Employee agents (`AgentforceEmployeeAgent`) MUST NOT include a `connection` block or `@utils.escalate` actions — including them causes silent failures or "unknown error" at publish time. For employee agents, use `@utils.transition` to a help topic or an action that creates a support case instead.
| `Tool target 'X' is not an action definition` | Action not defined in topic `actions:` block, or target doesn't exist in org | Define action with `target:` in topic-level `actions:` block; ensure Apex class/Flow is deployed |
| `invalid input 'X'` or `invalid output 'X'` | I/O name doesn't match `@InvocableVariable` field name in Apex | Use exact field names from the Apex wrapper class (case-sensitive) |
| `Internal Error` with inputs-only action | Action has `inputs:` but no `outputs:` block | Add `outputs:` block — the server-side compiler requires it (see known-issues.md Issue 15) |
| `Internal Error` with bare @InvocableMethod | Apex uses `List<String>` without `@InvocableVariable` wrappers | Refactor Apex to use wrapper classes with `@InvocableVariable` annotations |
| `apex://` target not found | Apex class not deployed or missing `@InvocableMethod` | Deploy class first, ensure it has `@InvocableMethod` annotation |
| Flow action fails | Flow not active or not Autolaunched | Activate the Flow; ensure it's Autolaunched (not Screen) |
| API action timeout | External system slow | Increase timeout, add retry logic |
| Permission denied | Missing Named Principal access | Grant Permission Set |