<!-- Parent: sf-ai-agentscript/SKILL.md -->
# Prompt Template Actions

> Invoking Salesforce Prompt Templates as actions within Agent Script

**Related**: [SKILL.md — Action Target Protocols](../SKILL.md) | [action-patterns.md](action-patterns.md)

---

## Overview

Prompt Template Actions let agents invoke Salesforce Prompt Builder templates via either the `prompt://` shorthand or the equivalent `generatePromptResponse://` protocol. The agent passes structured inputs to the template and receives a generated `promptResponse` output — keeping content generation in the template while the agent manages conversation flow.

> **Terminology:** in Setup, users usually say **Prompt Template**. In source metadata, the current metadata type is **`GenAiPromptTemplate`**.

**When to use**: Personalized responses, summarization, content generation, recommendations — anything where an LLM prompt template produces better output than static Flow logic.

---

## Action Definition

Whether you author the action through Setup or directly in an `.agent` file, the key prompt-template rules are the same:

```agentscript
actions:
  Generate_Personalized_Schedule:
    description: "Generate a personalized schedule using a prompt template"
    inputs:
      "Input:email": string
        description: "User's email address"
        is_required: True
      "Input:preferences": string
        description: "User's scheduling preferences"
        is_required: False
    outputs:
      promptResponse: string
        description: "The personalized schedule generated by the template"
        is_displayable: False
        is_used_by_planner: True
    target: "prompt://Generate_Personalized_Schedule"
```

### Critical syntax rules

| Rule | Example |
|------|---------|
| Preferred target protocol | `"prompt://TemplateName"` |
| Also valid | `"generatePromptResponse://TemplateName"` |
| Input names **must be quoted** | `"Input:email"` not `Input:email` |
| Input prefix is `Input:` | Matches the template's input field API name |
| Output field is always `promptResponse` | Single string output from the template |

> Both target protocols compile to the same runtime target. Prefer `prompt://` for brevity in new authoring.

### Prompt Template Gotchas

#### 1) Quote every `Input:...` binding

Parameter names that include `:` must stay quoted in both the action definition and the invocation.

```agentscript
# ✅ Correct
inputs:
  "Input:email": string
    is_required: True

# ❌ Wrong
inputs:
  Input:email: string
```

#### 2) `...` belongs to LLM-invoked actions, not deterministic inline `run`

```agentscript
# ❌ Wrong — deterministic run cannot slot-fill
reasoning:
  instructions: ->
    run @actions.Generate_Order_Summary
      with "Input:orderId" = ...
```

```agentscript
# ✅ Correct — let the LLM invoke the action and fill the input
reasoning:
  instructions: ->
    | Ask for the order number, then call {!@actions.generate_summary}.
  actions:
    generate_summary: @actions.Generate_Order_Summary
      description: "Generate a summary for the requested order"
      with "Input:orderId" = ...
      set @variables.summary = @outputs.promptResponse
```

If you need a later deterministic `run`, capture the user input first with `@utils.setVariables` (or another LLM-invoked action), then reference the saved variable.

#### 3) Prompt outputs usually belong to the planner, not direct display

For most prompt-template actions, the safest output pattern remains:

```agentscript
outputs:
  promptResponse: string
    is_displayable: False
    is_used_by_planner: True
```

### Recommended output flags

For prompt targets, treat `promptResponse` as planner input rather than raw UI output:

```agentscript
outputs:
  promptResponse: string
    description: "Generated response text"
    is_displayable: False
    is_used_by_planner: True
```

Why:
- `is_displayable: True` on prompt outputs is a known blank-response trap
- if the output is hidden but not planner-visible, the action may run but the response can still feel "missing"
- `filter_from_agent: True` is **not** the best substitute when the planner needs the prompt output, because `filter_from_agent` and `is_used_by_planner` cannot safely share the same field in this runtime

---

## Agent Script Invocation

Reference the action definition in your `.agent` file:

```agentscript
topic schedule_generation:
  reasoning:
    actions:
      generate_schedule: @actions.Generate_Personalized_Schedule
        with "Input:email"=@variables.user_email
             "Input:preferences"=...
        set @variables.schedule = @outputs.promptResponse
```

**Input binding patterns** (same as regular actions):
- `@variables.user_email` — variable binding (data from prior turns)
- `...` — LLM slot-filling (extract from conversation)
- `"professional"` — fixed value (business rule constant)

---

## Grounded Data Integration

Templates can include **data providers** (Apex classes, Flows) that supply contextual data for personalized responses. The grounding happens inside the template — Agent Script only needs to pass the lookup key:

```agentscript
actions:
  Get_Product_Recommendations:
    description: "Generate personalized product recommendations based on purchase history"
    inputs:
      "Input:customerId": string
        description: "Customer ID for personalization"
        is_required: True
    outputs:
      promptResponse: string
        description: "Personalized recommendations grounded in customer data"
        is_displayable: False
        is_used_by_planner: True
    target: "prompt://Product_Recommender"
```

The template itself (configured in Prompt Builder) includes:
- **Data Provider**: Apex class fetching customer purchase history
- **Grounding**: Recent orders, preferences, browsing history
- **Template instructions**: How to format recommendations using the grounded data

---

## Common Patterns

### Pattern 1: Content Generation

```agentscript
generate_email: @actions.Generate_Email_Response
  with "Input:customerMessage"=@variables.user_message
       "Input:tone"="professional"
       "Input:context"=@variables.case_context
  set @variables.email_draft = @outputs.promptResponse
```

### Pattern 2: Summarization

```agentscript
summarize: @actions.Summarize_Conversation
  with "Input:conversationHistory"=@variables.chat_history
       "Input:maxLength"="500"
  set @variables.summary = @outputs.promptResponse
```

### Pattern 3: Personalized Recommendations

```agentscript
recommend: @actions.Get_Product_Recommendations
  with "Input:customerId"=@variables.customer_id
       "Input:category"=...
  set @variables.recommendations = @outputs.promptResponse
```

---

## Known Limitation: `run` Keyword with Prompt Templates

Chained actions using `run` may not properly map `"Input:X"` parameters:

```agentscript
# ❌ MAY NOT WORK — run + prompt template input binding:
process: @actions.create_order
  with customer_id=@variables.customer_id
  run @actions.Generate_Order_Summary
    with "Input:orderId"=@variables.order_id    # Input binding may fail

# ✅ WORKAROUND — call as primary action instead:
generate_summary: @actions.Generate_Order_Summary
  with "Input:orderId"=@variables.order_id      # Works as primary action
  set @variables.summary = @outputs.promptResponse
```

> See SKILL.md "Action Chaining with `run` Keyword" for the full known bug description.

---

<a id="draft-template-publish-errors"></a>

## Draft Template Publish Errors (Critical)

> **If your `generatePromptResponse://` action fails to publish, check the template status FIRST.** A Draft template produces a cascade of misleading errors — none of which mention the template status.

When the target prompt template is in **Draft** status, `sf agent publish authoring-bundle` reports different errors depending on which I/O blocks are present. All are caused by the same root cause:

| Agent Script State | Error Message | Actually Means |
|---|---|---|
| Full I/O (`inputs:` + `outputs:`) | `invalid input parameters found: 'Input:query'` | Template can't be resolved (Draft) |
| `outputs:` only | `invalid output parameters found: 'promptResponse'` | Template can't be resolved (Draft) |
| Bare definition (no I/O) | `Metadata API request failed: Metadata retrieval failed:` | Template can't be resolved (Draft) |
| Bare definition (retry) | `Internal Error, try again later` | Template can't be resolved (Draft) |

**`sf agent validate authoring-bundle` passes regardless of template status** — it does not check whether the target template is published / active. This gives false confidence before publish.

**Fix**: Publish or activate the template in **Setup > Prompt Builder** before publishing the agent. The original Agent Script syntax (with `"Input:X"` inputs and `promptResponse` output) is correct — it will publish successfully once the template is available for runtime use.

**Pre-publish check**:
```bash
sf project retrieve start --metadata GenAiPromptTemplate:YourTemplateName -o TARGET_ORG --json
# Then inspect the retrieved XML for <status>Published</status> or <status>Active</status>
# Draft status = publish will fail with misleading errors
```

> See [known-issues.md](known-issues.md#issue-40) Issue 40 for the full bug report.

---

## Common Errors

| Error | Cause | Fix |
|-------|-------|-----|
| `SyntaxError` on input binding | Missing quotes on parameter name | Use `"Input:email"` not `Input:email` |
| Template not found | Wrong protocol or template name | Verify `prompt://ExactTemplateName` (or the equivalent `generatePromptResponse://ExactTemplateName`) |
| Empty `promptResponse` | Template not published / active, or missing required inputs | Publish the template in Setup, check all `is_required: True` inputs are bound |
| Blank agent reply even though template ran | `is_displayable: True` on `promptResponse` | Set `is_displayable: False` and let the planner synthesize the reply |
| Planner behaves like the prompt output is missing | Output is hidden but not planner-visible | Set `is_used_by_planner: True` on the output that should drive the reply or routing |
| Input not mapped | API name mismatch | Input field name after `Input:` must exactly match template's input API name |
| `invalid input/output parameters found` | Target template is in **Draft** status | Publish the template in Setup > Prompt Builder — see "Draft Template Publish Errors" above |
| `Internal Error` with bare action definition | Missing I/O blocks AND/OR Draft template | Add `inputs:`/`outputs:` blocks and ensure the template is published / active |

---

## Checklist

- [ ] Template exists in org and is **published / active** (Draft templates cause misleading publish errors)
- [ ] Input field API names match template configuration exactly
- [ ] All `is_required: True` inputs are bound (via `...`, `@variables`, or fixed)
- [ ] `promptResponse` output is captured with `set`
- [ ] `promptResponse` uses `is_displayable: False` + `is_used_by_planner: True` when the planner should synthesize the reply
- [ ] Template response quality tested with representative inputs
- [ ] If using grounded data: data provider returns expected records

---

*Consolidated from repository prompt-template integration research and validated action configuration patterns.*
