@salesforce/afv-skills 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/package.json +4 -4
  2. package/skills/agentforce-development/SKILL.md +427 -0
  3. package/skills/agentforce-development/assets/README-legacy.md +89 -0
  4. package/skills/agentforce-development/assets/agent-spec-template.md +90 -0
  5. package/skills/agentforce-development/assets/agents/README.md +45 -0
  6. package/skills/agentforce-development/assets/agents/hello-world.agent +60 -0
  7. package/skills/agentforce-development/assets/agents/multi-topic.agent +105 -0
  8. package/skills/agentforce-development/assets/agents/production-faq.agent +101 -0
  9. package/skills/agentforce-development/assets/agents/production-faq.bundle-meta.xml +4 -0
  10. package/skills/agentforce-development/assets/agents/simple-qa.agent +72 -0
  11. package/skills/agentforce-development/assets/apex/models-api-queueable.cls +225 -0
  12. package/skills/agentforce-development/assets/bundle-meta.xml +23 -0
  13. package/skills/agentforce-development/assets/components/apex-action.agent +52 -0
  14. package/skills/agentforce-development/assets/components/error-handling.agent +58 -0
  15. package/skills/agentforce-development/assets/components/escalation-setup.agent +169 -0
  16. package/skills/agentforce-development/assets/components/flow-action.agent +66 -0
  17. package/skills/agentforce-development/assets/components/n-ary-conditions.agent +110 -0
  18. package/skills/agentforce-development/assets/components/topic-with-actions.agent +40 -0
  19. package/skills/agentforce-development/assets/deterministic-routing.agent +166 -0
  20. package/skills/agentforce-development/assets/escalation-pattern.agent +209 -0
  21. package/skills/agentforce-development/assets/flow-action-lookup.agent +115 -0
  22. package/skills/agentforce-development/assets/hub-and-spoke.agent +104 -0
  23. package/skills/agentforce-development/assets/invocable-apex-template.cls +187 -0
  24. package/skills/agentforce-development/assets/local-info-agent-annotated.agent +355 -0
  25. package/skills/agentforce-development/assets/metadata/basic-prompt-template.promptTemplate-meta.xml +109 -0
  26. package/skills/agentforce-development/assets/metadata/genai-function-apex.xml +92 -0
  27. package/skills/agentforce-development/assets/metadata/genai-function-flow.xml +57 -0
  28. package/skills/agentforce-development/assets/metadata/genai-plugin.xml +72 -0
  29. package/skills/agentforce-development/assets/metadata/http-callout-flow.flow-meta.xml +348 -0
  30. package/skills/agentforce-development/assets/metadata/record-grounded-prompt.promptTemplate-meta.xml +136 -0
  31. package/skills/agentforce-development/assets/minimal-starter.agent +42 -0
  32. package/skills/agentforce-development/assets/patterns/README.md +254 -0
  33. package/skills/agentforce-development/assets/patterns/action-callbacks.agent +178 -0
  34. package/skills/agentforce-development/assets/patterns/advanced-input-bindings.agent +141 -0
  35. package/skills/agentforce-development/assets/patterns/bidirectional-routing.agent +156 -0
  36. package/skills/agentforce-development/assets/patterns/critical-input-collection.agent +244 -0
  37. package/skills/agentforce-development/assets/patterns/delegation-routing.agent +89 -0
  38. package/skills/agentforce-development/assets/patterns/lifecycle-events.agent +127 -0
  39. package/skills/agentforce-development/assets/patterns/llm-controlled-actions.agent +184 -0
  40. package/skills/agentforce-development/assets/patterns/multi-step-workflow.agent +282 -0
  41. package/skills/agentforce-development/assets/patterns/open-gate-routing.agent +286 -0
  42. package/skills/agentforce-development/assets/patterns/procedural-instructions.agent +273 -0
  43. package/skills/agentforce-development/assets/patterns/prompt-template-action.agent +188 -0
  44. package/skills/agentforce-development/assets/patterns/system-instruction-overrides.agent +293 -0
  45. package/skills/agentforce-development/assets/prompt-rag-search.agent +131 -0
  46. package/skills/agentforce-development/assets/template-multi-topic.agent +160 -0
  47. package/skills/agentforce-development/assets/template-single-topic.agent +81 -0
  48. package/skills/agentforce-development/assets/verification-gate.agent +208 -0
  49. package/skills/agentforce-development/references/action-prompt-templates.md +164 -0
  50. package/skills/agentforce-development/references/actions-reference.md +592 -0
  51. package/skills/agentforce-development/references/agent-access-guide.md +72 -0
  52. package/skills/agentforce-development/references/agent-design-and-spec-creation.md +1010 -0
  53. package/skills/agentforce-development/references/agent-metadata-and-lifecycle.md +575 -0
  54. package/skills/agentforce-development/references/agent-script-core-language.md +1218 -0
  55. package/skills/agentforce-development/references/agent-topic-map-diagrams.md +323 -0
  56. package/skills/agentforce-development/references/agent-user-setup.md +526 -0
  57. package/skills/agentforce-development/references/agent-validation-and-debugging.md +803 -0
  58. package/skills/agentforce-development/references/known-issues.md +353 -0
  59. package/skills/agentforce-development/references/minimal-examples.md +67 -0
  60. package/skills/agentforce-development/references/production-gotchas.md +279 -0
  61. package/skills/agentforce-development/references/salesforce-cli-for-agents.md +393 -0
  62. package/skills/agentforce-development/references/version-history.md +23 -0
  63. package/skills/generate-permission-set/SKILL.md +174 -0
  64. package/skills/salesforce-custom-application/SKILL.md +1 -2
  65. package/skills/salesforce-custom-field/SKILL.md +0 -4
  66. package/skills/salesforce-custom-tab/SKILL.md +84 -8
  67. package/skills/salesforce-experience-lwr-site/SKILL.md +196 -0
  68. package/skills/salesforce-experience-lwr-site/docs/bootstrap-template-byo-lwr.md +224 -0
  69. package/skills/salesforce-experience-lwr-site/docs/configure-content-brandingSet.md +131 -0
  70. package/skills/salesforce-experience-lwr-site/docs/configure-content-route.md +232 -0
  71. package/skills/salesforce-experience-lwr-site/docs/configure-content-themeLayout.md +141 -0
  72. package/skills/salesforce-experience-lwr-site/docs/configure-content-view.md +233 -0
  73. package/skills/salesforce-experience-lwr-site/docs/configure-guest-sharing-rules.md +42 -0
  74. package/skills/salesforce-experience-lwr-site/docs/handle-component-and-region-ids.md +27 -0
  75. package/skills/salesforce-experience-lwr-site/docs/handle-ui-components.md +215 -0
  76. package/skills/salesforce-flow/SKILL.md +2 -2
  77. package/skills/salesforce-fragment/SKILL.md +85 -10
  78. package/skills/salesforce-lightning-app-build/SKILL.md +102 -10
  79. package/skills/apex-class/SKILL.md +0 -253
  80. package/skills/apex-class/examples/AccountDeduplicationBatch.cls +0 -148
  81. package/skills/apex-class/examples/AccountSelector.cls +0 -193
  82. package/skills/apex-class/examples/AccountService.cls +0 -201
  83. package/skills/apex-class/templates/abstract.cls +0 -128
  84. package/skills/apex-class/templates/batch.cls +0 -125
  85. package/skills/apex-class/templates/domain.cls +0 -102
  86. package/skills/apex-class/templates/dto.cls +0 -108
  87. package/skills/apex-class/templates/exception.cls +0 -51
  88. package/skills/apex-class/templates/interface.cls +0 -25
  89. package/skills/apex-class/templates/queueable.cls +0 -92
  90. package/skills/apex-class/templates/schedulable.cls +0 -75
  91. package/skills/apex-class/templates/selector.cls +0 -92
  92. package/skills/apex-class/templates/service.cls +0 -69
  93. package/skills/apex-class/templates/utility.cls +0 -97
  94. package/skills/apex-test-class/SKILL.md +0 -101
  95. package/skills/apex-test-class/references/assertion-patterns.md +0 -209
  96. package/skills/apex-test-class/references/async-testing.md +0 -276
  97. package/skills/apex-test-class/references/mocking-patterns.md +0 -219
  98. package/skills/apex-test-class/references/test-data-factory.md +0 -176
  99. package/skills/deployment-readiness-check/SKILL.md +0 -257
  100. package/skills/deployment-readiness-check/assets/deployment_checklist.md +0 -286
  101. package/skills/deployment-readiness-check/references/rollback_procedures.md +0 -308
  102. package/skills/deployment-readiness-check/scripts/check_metadata.sh +0 -207
  103. package/skills/salesforce-experience-site/SKILL.md +0 -178
@@ -0,0 +1,1218 @@
1
+ # Agent Script: Core Language Reference
2
+
3
+ ## Table of Contents
4
+
5
+ 1. How Agent Script Executes
6
+ 2. File Structure and Block Ordering
7
+ 3. Naming and Formatting Rules
8
+ 4. Expressions and Operators
9
+ 5. System and Config Blocks
10
+ 6. Variables
11
+ 7. Topics
12
+ 8. Reasoning Instructions
13
+ 9. Flow Control
14
+ 10. Actions
15
+ 11. Utility Functions
16
+ 12. Anti-Patterns
17
+
18
+ ---
19
+
20
+ ## 1. How Agent Script Executes
21
+
22
+ Agent Script operates in two phases: deterministic resolution, then LLM reasoning.
23
+
24
+ **Phase 1: Deterministic Resolution.** The runtime executes a topic's reasoning instructions top to bottom — evaluating `if`/`else` conditions, running actions via `run`, and setting variables via `set`. The LLM is NOT involved yet. The runtime builds a prompt string by accumulating `|` pipe text and resolving conditional logic. If a `transition` command occurs, the runtime discards the current prompt and starts fresh with the target topic.
25
+
26
+ **Phase 2: LLM Reasoning.** The runtime passes the resolved prompt to the LLM along with any reasoning actions (tools) the topic exposes. The LLM decides what to do — it can call available actions but cannot modify the prompt text. It only reasons against what Phase 1 resolved.
27
+
28
+ **Worked Example.** Consider this topic:
29
+
30
+ ```agentscript
31
+ topic check_order:
32
+ reasoning:
33
+ instructions: ->
34
+ if @variables.order_id != "":
35
+ run @actions.fetch_order
36
+ with id = @variables.order_id
37
+ set @variables.status = @outputs.status
38
+
39
+ | Your order status is {!@variables.status}.
40
+ You can modify it using the {!@actions.update_order} action.
41
+
42
+ actions:
43
+ update: @actions.update_order
44
+ with order_id = @variables.order_id
45
+ ```
46
+
47
+ If `@variables.order_id` is `"1001"` and the `fetch_order` action returns `status = "shipped"`, the runtime resolves to this prompt:
48
+
49
+ ```
50
+ Your order status is shipped.
51
+ You can modify it using the update_order action.
52
+ ```
53
+
54
+ The LLM then receives this prompt plus the `update` tool and decides whether to call it based on what the user asks.
55
+
56
+ This split is critical: **deterministic logic controls WHAT the agent knows (via resolved prompt), and the LLM controls WHETHER and HOW to act on that knowledge**.
57
+
58
+ ---
59
+
60
+ ## 2. File Structure and Block Ordering
61
+
62
+ An Agent Script file (`.agent` extension) contains eight top-level blocks in this mandatory order:
63
+
64
+ ```agentscript
65
+ system:
66
+ ...
67
+
68
+ config:
69
+ ...
70
+
71
+ variables:
72
+ ...
73
+
74
+ connection:
75
+ ...
76
+
77
+ knowledge:
78
+ ...
79
+
80
+ language:
81
+ ...
82
+
83
+ start_agent topic_selector:
84
+ ...
85
+
86
+ topic my_topic:
87
+ ...
88
+ ```
89
+
90
+ **Required blocks:** `system`, `config`, `start_agent`, and at least one `topic`.
91
+
92
+ **Optional blocks:** `variables`, `connections`, `knowledge`, `language`. Omit them if not needed.
93
+
94
+ **Within `start_agent` and `topic` blocks**, the internal ordering is:
95
+
96
+ 1. `description` (required)
97
+ 2. `system` (optional — topic-level override of global system instructions)
98
+ 3. `before_reasoning` (optional — runs before reasoning phase)
99
+ 4. `reasoning` (required)
100
+ 5. `after_reasoning` (optional — runs after reasoning phase)
101
+ 6. `actions` (optional — action definitions)
102
+
103
+ ---
104
+
105
+ ## 3. Naming and Formatting Rules
106
+
107
+ **Naming constraints for all identifiers** (developer_name, topic names, variable names, action names, connection names):
108
+
109
+ - Contain only letters, numbers, and underscores
110
+ - Begin with a letter (never underscore)
111
+ - Cannot end with an underscore
112
+ - Cannot contain two consecutive underscores (`__`)
113
+ - Maximum 80 characters
114
+ - `snake_case` is strongly recommended
115
+
116
+ Example: `check_order_status` is valid. `check_order__status` is invalid (consecutive underscores).
117
+
118
+ **Indentation:** Use 4 spaces per indent level. NEVER use tabs. Mixing spaces and tabs breaks the parser. All lines at the same nesting level must use the same indentation.
119
+
120
+ Each nesting level adds 4 spaces. The hierarchy follows the block structure — topic → reasoning → instructions → logic/prompt:
121
+
122
+ ```agentscript
123
+ topic process_order:
124
+ description: "Handle order processing"
125
+ reasoning:
126
+ instructions: ->
127
+ | Welcome
128
+ ```
129
+
130
+ **Comments:** Use `#` for single-line comments. The parser ignores everything after `#` on that line.
131
+
132
+ Comments can appear on their own line or inline after code. Both forms are valid:
133
+
134
+ ```agentscript
135
+ # This is a standalone comment
136
+ variables:
137
+ order_id: mutable string = "" # This is an inline comment
138
+ ```
139
+
140
+ ---
141
+
142
+ ## 4. Expressions and Operators
143
+
144
+ **Comparison operators**:
145
+
146
+ - `==` (equal): `@variables.status == "complete"`
147
+ - `!=` (not equal): `@variables.count != 0`
148
+ - `<` (less than): `@variables.price < 100`
149
+ - `<=` (less than or equal): `@variables.age <= 18`
150
+ - `>` (greater than): `@variables.amount > 50`
151
+ - `>=` (greater than or equal): `@variables.balance >= 0`
152
+ - `is` (identity check — use for None): `@variables.value is None`
153
+ - `is not` (negated identity check): `@variables.data is not None`
154
+
155
+ **Logical operators**:
156
+
157
+ - `and`: Both conditions must be true. `@variables.verified == True and @variables.age >= 18`
158
+ - `or`: Either condition can be true. `@variables.status == "pending" or @variables.status == "review"`
159
+ - `not`: Negates a condition. `not @variables.is_guest == True` (though `@variables.is_guest == False` is more readable)
160
+
161
+ **Arithmetic operators** (limited support):
162
+
163
+ - `+` (addition): `@variables.count + 1`
164
+ - `-` (subtraction): `@variables.total - @variables.discount`
165
+
166
+ Do NOT use `*`, `/`, `%` — they are not supported.
167
+
168
+ **Access operators**:
169
+
170
+ - `.` (property access): `@object.property`
171
+ - `[]` (index access): `@variables.items[0]`
172
+
173
+ **Conditional expressions**:
174
+
175
+ - `x if condition else y`: `"premium" if @variables.is_premium == True else "standard"`
176
+
177
+ **Template injection in strings** (within `|` multiline text):
178
+
179
+ Use `{!expression}` to inject variable values or expressions into prompt text:
180
+
181
+ ```agentscript
182
+ instructions: |
183
+ Your total is {!@variables.total}.
184
+ Your status: {!@variables.status if @variables.status else "pending"}.
185
+ ```
186
+
187
+ The expression inside `{! ... }` is evaluated by the runtime during deterministic resolution and the result replaces the entire `{! ... }` block in the prompt.
188
+
189
+ **Resource references**:
190
+
191
+ - `@actions.<name>` — reference an action defined in the topic's `actions` block
192
+ - `@topic.<name>` — reference a topic by name
193
+ - `@variables.<name>` — reference a variable (use in logic)
194
+ - `{!@variables.<name>}` — reference a variable in prompt text (template injection)
195
+ - `@outputs.<name>` — reference an action output (only in post-action context)
196
+ - `@inputs.<name>` — reference an action input (in action definition)
197
+ - `@utils.<function>` — reference a utility (escalate, transition to, setVariables)
198
+
199
+ **Do NOT use `<>` as inequality operator.** Use `!=` instead.
200
+
201
+ ```agentscript
202
+ # WRONG
203
+ if @variables.status <> "pending":
204
+
205
+ # CORRECT
206
+ if @variables.status != "pending":
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 5. System and Config Blocks
212
+
213
+ **System block** provides global instructions and messages:
214
+
215
+ ```agentscript
216
+ system:
217
+ instructions: "You are a helpful assistant. Be professional and concise."
218
+ messages:
219
+ welcome: "Hello! How can I help?"
220
+ error: "Sorry, something went wrong. Please try again."
221
+ ```
222
+
223
+ The `instructions` field is required and contains text directives sent to the LLM in every reasoning phase. Topic-level system blocks can override this.
224
+
225
+ Both `welcome` and `error` messages are required.
226
+
227
+ **Config block** contains agent metadata:
228
+
229
+ ```agentscript
230
+ config:
231
+ developer_name: "Customer_Service_Agent"
232
+ agent_label: "Customer Service"
233
+ description: "Handles customer inquiries"
234
+ agent_type: "AgentforceServiceAgent"
235
+ default_agent_user: "agent@example.com"
236
+ ```
237
+
238
+ **Required fields:**
239
+ - `developer_name` (NOT `agent_name`) — unique identifier following naming rules. Must exactly match the AiAuthoringBundle directory name (e.g., if the directory is `aiAuthoringBundles/Travel_Advisor/`, then `developer_name` must be `"Travel_Advisor"`). A mismatch causes deploy failures.
240
+ - `agent_type` — `"AgentforceServiceAgent"` or `"AgentforceEmployeeAgent"`. Determines deployment context and whether `default_agent_user` is required:
241
+ - `"AgentforceServiceAgent"` — customer-facing, deployed via messaging channels. **Requires `default_agent_user`** with Einstein Agent license.
242
+ - `"AgentforceEmployeeAgent"` — internal employee-facing. Agent Script files with this agent type MUST NOT include:
243
+ - `default_agent_user`
244
+ - MessagingSession linked variables (`EndUserId`, `RoutableId`, `ContactId`, `EndUserLanguage`)
245
+ - Escalation topic with `@utils.escalate`
246
+
247
+ **Conditionally required fields:**
248
+ - `default_agent_user` — **required for `AgentforceServiceAgent`, prohibited for `AgentforceEmployeeAgent`**. This is the Salesforce username of the Einstein Agent User that runs agent actions on behalf of the customer. The user must exist in the target org, be active, and have the Einstein Agent license assigned.
249
+
250
+ **⚠️ CRITICAL: Setting `default_agent_user` on an `AgentforceEmployeeAgent` causes publish and preview to fail with an unhelpful "unknown error" or "Internal Error, try again later" message.** The error gives no indication that `default_agent_user` is the cause. If you encounter this error on an employee agent, check whether `default_agent_user` is set and remove it.
251
+
252
+ To find a valid Einstein Agent User in the org:
253
+ ```bash
254
+ sf data query --json -q "SELECT Username FROM User WHERE Profile.UserLicense.Name = 'Einstein Agent' AND IsActive = true LIMIT 5"
255
+ ```
256
+
257
+ If no results are returned, the org does not have an Einstein Agent User configured. Read `references/salesforce-cli-for-agents.md` for steps to create one.
258
+
259
+ This field can be changed after publish, but only while no published version is activated. Deactivate the agent before changing `default_agent_user`.
260
+
261
+ **Optional fields:**
262
+ - `agent_label` — human-readable display name. Defaults to normalized `developer_name` if omitted
263
+ - `description` — what the agent does
264
+
265
+ ---
266
+
267
+ ## 6. Variables
268
+
269
+ **Two types of variables**:
270
+
271
+ **Mutable variables** — the agent can read AND write. MUST have a default value:
272
+
273
+ ```agentscript
274
+ variables:
275
+ customer_name: mutable string = ""
276
+ description: "The customer's full name"
277
+ order_count: mutable number = 0
278
+ is_premium: mutable boolean = False
279
+ preferences: mutable object = {}
280
+ items: mutable list[string] = []
281
+ ```
282
+
283
+ The `description` field is optional. Include it when the LLM needs context for slot-filling via `@utils.setVariables`.
284
+
285
+ **Linked variables** — read-only from external context. MUST have a `source`, MUST NOT have a default value:
286
+
287
+ ```agentscript
288
+ variables:
289
+ session_id: linked string
290
+ description: "The current session ID"
291
+ source: @session.sessionID
292
+ user_id: linked string
293
+ source: @MessagingSession.MessagingEndUserId
294
+ ```
295
+
296
+ The `source` field points to the external context. At runtime, the platform provides the value.
297
+
298
+ **Type constraints by context**:
299
+
300
+ - Mutable variable types: `string`, `number`, `boolean`, `object`, `date`, `id`, `list[T]`
301
+ - Linked variable types: `string`, `number`, `boolean`, `date`, `id` (no `list`)
302
+ - Action parameter types: `string`, `number`, `boolean`, `object`, `date`, `timestamp`, `currency`, `id`, `list[T]`, `datetime`, `time`, `integer`, `long`
303
+
304
+ > ⚠️ `timestamp` and `currency` compile as variable types but are absent from official GA documentation and should NOT be used. Prefer `date` for date/time variables and `number` for currency values.
305
+
306
+ **Some types are ONLY valid for action parameters**:
307
+ `integer`, `long`, `datetime`, and `time` are action-parameter-only types. They are NOT valid for mutable or linked variables:
308
+
309
+ ```agentscript
310
+ # WRONG — integer is not valid for mutable variables
311
+ low_count: mutable integer = 0
312
+
313
+ # RIGHT — use number for mutable variables
314
+ low_count: mutable number = 0
315
+ ```
316
+
317
+ **`complex_data_type_name` for action parameters**: The simple types listed above (`date`, `integer`, `datetime`, `long`) work directly for Apex-backed action parameters — no special mapping needed. The `object` + `complex_data_type_name` pattern is only required for SObject references, Apex inner classes, custom Lightning types, and typed collections. Read `references/agent-design-and-spec-creation.md` for the full Apex ↔ Agent Script type mapping table.
318
+
319
+ **Boolean capitalization**:
320
+
321
+ ALWAYS use `True` or `False` (capitalized). NEVER use `true` or `false`:
322
+
323
+ ```agentscript
324
+ # WRONG
325
+ enabled: mutable boolean = true
326
+ verified: linked boolean = false
327
+
328
+ # CORRECT
329
+ enabled: mutable boolean = True
330
+ is_verified: mutable boolean = False
331
+ ```
332
+
333
+ **Template injection for variables** in prompt text:
334
+
335
+ Use `{!@variables.X}` to interpolate a variable's value into prompt text:
336
+
337
+ ```agentscript
338
+ instructions: |
339
+ Hello, {!@variables.customer_name}!
340
+ Your balance: {!@variables.balance}
341
+ ```
342
+
343
+ In prompt text (inside `|` pipe sections), always use `{!@variables.X}` with braces — the braces trigger template evaluation. Bare `@variables.X` without braces is valid in logic contexts (e.g., `if @variables.X == True:`) but will not interpolate in prompt text.
344
+
345
+ ---
346
+
347
+ ## 7. Topics
348
+
349
+ **Topic structure** — a named scope for reasoning, actions, and flow control:
350
+
351
+ ```agentscript
352
+ topic order_lookup:
353
+ description: "Handle customer order inquiries"
354
+
355
+ reasoning:
356
+ instructions: ->
357
+ | Help the customer find their order.
358
+ actions:
359
+ search: @actions.find_order
360
+ with order_id = ...
361
+
362
+ actions:
363
+ find_order:
364
+ description: "Search for an order by ID"
365
+ target: "flow://SearchOrder"
366
+ inputs:
367
+ order_id: string
368
+ outputs:
369
+ status: string
370
+ ```
371
+
372
+ **Description is required** — the LLM uses this to understand when the topic is relevant.
373
+
374
+ **Topic-level system override** (optional) — override global system instructions for this topic only:
375
+
376
+ ```agentscript
377
+ topic product_specialist:
378
+ description: "Answer product questions"
379
+ system:
380
+ instructions: "You are a product expert. Be technical and detailed."
381
+ reasoning:
382
+ instructions: ->
383
+ | Help with product specs.
384
+ ```
385
+
386
+ **Internal block ordering within a topic**:
387
+
388
+ 1. `description`
389
+ 2. `system` (optional override)
390
+ 3. `before_reasoning` (optional)
391
+ 4. `reasoning` (required)
392
+ 5. `after_reasoning` (optional)
393
+ 6. `actions` (optional definitions)
394
+
395
+ **Before/after reasoning directive blocks**:
396
+
397
+ `before_reasoning` and `after_reasoning` contain deterministic logic that runs outside the reasoning phase:
398
+
399
+ ```agentscript
400
+ before_reasoning:
401
+ if @variables.session_expired:
402
+ transition to @topic.login
403
+
404
+ reasoning:
405
+ instructions: ->
406
+ | Main topic logic
407
+
408
+ after_reasoning:
409
+ if @variables.transaction_complete:
410
+ transition to @topic.confirmation
411
+ ```
412
+
413
+ Directive blocks use the arrow syntax (`->`) for logic but no LLM reasoning. They run deterministically.
414
+
415
+ ---
416
+
417
+ ## 8. Reasoning Instructions
418
+
419
+ Reasoning instructions combine deterministic logic and prompt text. The runtime resolves deterministic parts first, then sends the resulting prompt to the LLM for reasoning.
420
+
421
+ **Arrow syntax (`->`) for logic blocks**:
422
+
423
+ ```agentscript
424
+ reasoning:
425
+ instructions: ->
426
+ if @variables.user_verified:
427
+ run @actions.get_account
428
+ with user_id = @variables.user_id
429
+ set @variables.account_info = @outputs.account
430
+
431
+ | Now tell the user their account balance.
432
+ ```
433
+
434
+ The `->` prefix indicates "start with logic, then switch to prompt". The runtime evaluates the `if` condition and `run` command, then appends the pipe-delimited text to the prompt.
435
+
436
+ **Multiline strings with `|`** — two forms:
437
+
438
+ For static text with no logic, use `|` directly after the property:
439
+
440
+ ```agentscript
441
+ instructions: |
442
+ Welcome to our service!
443
+ Please provide details about your request.
444
+ I'll help you with whatever you need.
445
+ ```
446
+
447
+ Static `|` instructions can coexist with a sibling `actions:` block under `reasoning:`:
448
+
449
+ ```agentscript
450
+ reasoning:
451
+ instructions: |
452
+ Help the customer find a venue.
453
+ After receiving results from {!@actions.search_venues}, present them clearly.
454
+ Do NOT call the action again unless the customer asks for a new search.
455
+
456
+ actions:
457
+ find_venue: @actions.search_venues
458
+ description: "Search for available venues"
459
+ with location = ...
460
+ with date = ...
461
+ ```
462
+
463
+ For text mixed with logic, use `->` to enter a logic block, then `|` to switch to prompt text:
464
+
465
+ ```agentscript
466
+ instructions: ->
467
+ if @variables.needs_help:
468
+ | Ask the user what they need help with.
469
+ else:
470
+ | Suggest self-service options.
471
+ ```
472
+
473
+ Within `->` blocks, a line without `|` continues the previous line. A new `|` starts a new line:
474
+
475
+ ```agentscript
476
+ instructions: ->
477
+ | This is a long instruction that
478
+ continues on the next physical line.
479
+ | This starts a new logical line.
480
+ ```
481
+
482
+ **If/Else (no "else if", no nested if)**:
483
+
484
+ ```agentscript
485
+ # ✅ CORRECT — simple if/else
486
+ if @variables.status == "pending":
487
+ run @actions.notify_pending
488
+ else:
489
+ run @actions.notify_complete
490
+
491
+ # ❌ WRONG — else if not supported
492
+ if @variables.count < 5:
493
+ run @actions.small
494
+ else if @variables.count < 10:
495
+ run @actions.medium
496
+
497
+ # ❌ WRONG — nested if inside else is also invalid
498
+ if @variables.status == "pending":
499
+ run @actions.queue_pending
500
+ else:
501
+ if @variables.status == "closed":
502
+ run @actions.archive
503
+ ```
504
+
505
+ For multi-branch logic, use compound conditions (`if A and B:`) or flatten to sequential `if` statements.
506
+
507
+ **Inline action invocation (`run @actions.X`)**:
508
+
509
+ ```agentscript
510
+ run @actions.check_inventory
511
+ with product_id = @variables.selected_product
512
+ set @variables.stock_level = @outputs.available_quantity
513
+ ```
514
+
515
+ The `run` command executes the action deterministically — the runtime runs it before the LLM reasons. Use `with` to pass inputs (bound to variables or literal values). Use `set` to capture outputs into variables.
516
+
517
+ **Post-action directives** (only for `@actions`, not `@utils`):
518
+
519
+ ```agentscript
520
+ run @actions.process_order
521
+ with order_id = @variables.order_id
522
+ set @variables.result = @outputs.status
523
+ if @outputs.success == True:
524
+ transition to @topic.confirmation
525
+ else:
526
+ transition to @topic.error_handling
527
+ ```
528
+
529
+ After an action completes, you can check outputs and transition.
530
+
531
+ **How pipe sections become the LLM prompt**:
532
+
533
+ All logic is resolved first; only matching `|` pipe lines are included in the prompt:
534
+
535
+ ```agentscript
536
+ instructions: ->
537
+ | Welcome!
538
+ if @variables.is_returning:
539
+ | Nice to see you again.
540
+ else:
541
+ | Let's get started.
542
+ | How can I help?
543
+
544
+ # If is_returning == False, the prompt becomes:
545
+ # "Welcome! Let's get started. How can I help?"
546
+ ```
547
+
548
+ ---
549
+
550
+ ## 9. Flow Control
551
+
552
+ Flow control determines how execution moves between topics and responds to conditions.
553
+
554
+ **Start agent topic** — the mandatory entry point:
555
+
556
+ Every conversation begins at `start_agent`. The LLM classifies the user's intent and routes to the appropriate topic:
557
+
558
+ ```agentscript
559
+ start_agent topic_selector:
560
+ description: "Route to appropriate topic"
561
+ reasoning:
562
+ instructions: ->
563
+ | Welcome. I can help with orders, accounts, or billing.
564
+ actions:
565
+ go_orders: @utils.transition to @topic.order_info
566
+ description: "For order inquiries"
567
+ go_accounts: @utils.transition to @topic.account_help
568
+ description: "For account questions"
569
+ ```
570
+
571
+ **LLM-chosen transitions in reasoning actions**:
572
+
573
+ Expose the transition as a reasoning action when the LLM should judge the right moment:
574
+
575
+ ```agentscript
576
+ reasoning:
577
+ actions:
578
+ go_next: @utils.transition to @topic.next_topic
579
+ description: "Move to the next topic"
580
+ available when @variables.ready == True
581
+ ```
582
+
583
+ **Deterministic transitions in directive blocks**:
584
+
585
+ Use bare `transition to` in `before_reasoning` and `after_reasoning` for state-based transitions:
586
+
587
+ ```agentscript
588
+ before_reasoning:
589
+ if @variables.not_authenticated:
590
+ transition to @topic.login
591
+
592
+ after_reasoning:
593
+ if @variables.session_complete:
594
+ transition to @topic.summary
595
+ ```
596
+
597
+ The runtime evaluates the condition and transitions immediately. Do NOT use `@utils.transition to` in directive blocks — it causes compilation errors.
598
+
599
+ **Delegation with return**:
600
+
601
+ When a topic needs another topic's expertise but still has work to do afterward, use `@topic.X` to delegate. The target topic runs its reasoning, then returns control to the caller:
602
+
603
+ ```agentscript
604
+ reasoning:
605
+ actions:
606
+ ask_expert: @topic.expert_consultation
607
+ description: "Consult the expert topic"
608
+ ```
609
+
610
+ This is different from `@utils.transition to`, which is one-way — the calling topic does not resume.
611
+
612
+ **Conditional branching within topics**:
613
+
614
+ Conditions in reasoning instructions control which prompt text the LLM ultimately receives. The runtime evaluates `if`/`else` branches and includes only the matching `|` pipe sections in the resolved prompt:
615
+
616
+ ```agentscript
617
+ reasoning:
618
+ instructions: ->
619
+ if @variables.order_id != "":
620
+ | Show order details for {!@variables.order_id}.
621
+ else:
622
+ | I need an order ID to help you.
623
+ ```
624
+
625
+ ---
626
+
627
+ ## 10. Actions
628
+
629
+ Actions invoke Flows, Apex classes, Prompt Templates, or other target types. They can run deterministically (the runtime always executes them) or be exposed as tools for the LLM to choose at reasoning time.
630
+
631
+ **Action definition** — each action is defined in the topic's `actions` block with required and optional properties:
632
+
633
+ ```agentscript
634
+ actions:
635
+ get_customer:
636
+ # Required properties
637
+ target: "flow://GetCustomerInfo"
638
+ description: "Fetches customer information"
639
+ # Optional UI/UX properties
640
+ label: "Get Customer"
641
+ require_user_confirmation: False
642
+ include_in_progress_indicator: True
643
+ progress_indicator_message: "Looking up customer..."
644
+ inputs:
645
+ customer_id: string
646
+ description: "The customer's unique ID"
647
+ label: "Customer ID"
648
+ is_required: True
649
+ outputs:
650
+ name: string
651
+ description: "Customer's name"
652
+ is_displayable: True
653
+ customer_info: object
654
+ complex_data_type_name: "lightning__recordInfoType"
655
+ description: "Full customer record"
656
+ filter_from_agent: True
657
+ ```
658
+
659
+ **Action properties**:
660
+
661
+ - `target` (required) — reference to the executable, in the format `"type://DeveloperName"`
662
+ - `description` (optional) — the LLM uses this to decide when to call the action
663
+ - `label` (optional) — display name shown to the customer; auto-generated from action name if omitted
664
+ - `require_user_confirmation` (optional boolean) — when `True`, the customer must confirm before the action runs
665
+ - `include_in_progress_indicator` (optional boolean) — when `True`, shows a progress indicator during execution
666
+ - `progress_indicator_message` (optional string) — text shown during execution (e.g., `"Looking up customer..."`)
667
+
668
+ **Input properties**:
669
+
670
+ - `description` — metadata about the input parameter
671
+ - `label` — display name shown in UI; auto-generated from parameter name if omitted
672
+ - `is_required` (boolean) — when `True`, the input must be provided
673
+
674
+ **Output properties**:
675
+
676
+ - `description` — metadata about the output parameter
677
+ - `label` — display name shown in UI; auto-generated from parameter name if omitted
678
+ - `filter_from_agent` (boolean) — when `True`, hides the output from the LLM's context
679
+ - `is_displayable` (boolean) — controls whether output is shown to the customer
680
+ - `complex_data_type_name` — required for complex data types like SObject references (e.g., `"lightning__recordInfoType"`), Apex inner classes, and custom Lightning types. Not needed for simple types like `date`, `integer`, or `datetime` — use the simple type directly.
681
+
682
+ **Parameter names must exactly match the backing logic interface — including case.** Read the target class before writing the action definition.
683
+
684
+ Given this Apex class:
685
+
686
+ ```java
687
+ public class CheckVenueAvailability {
688
+ public class Request {
689
+ @InvocableVariable public String venueName;
690
+ @InvocableVariable public Date requestedDate;
691
+ }
692
+ }
693
+ ```
694
+
695
+ ```agentscript
696
+ # WRONG — snake_case does not match @InvocableVariable field names
697
+ inputs:
698
+ venue_name: string
699
+ requested_date: date
700
+
701
+ # RIGHT — exact match to @InvocableVariable names
702
+ inputs:
703
+ venueName: string
704
+ requestedDate: date
705
+ ```
706
+
707
+ Flow targets: match the Flow's input/output variable API names. Prompt Template targets: see "Prompt Template actions" below.
708
+
709
+ **Target types** — use the format `"type://DeveloperName"`:
710
+
711
+ Common targets:
712
+
713
+ - `flow` — Salesforce Flow (e.g., `"flow://GetCustomerInfo"`)
714
+ - `apex` — Invocable Apex class (e.g., `"apex://CheckWeather"`)
715
+ - `prompt` — Prompt Template (e.g., `"prompt://Get_Event_Info"`; long form: `generatePromptResponse`)
716
+
717
+ Additional targets:
718
+
719
+ - `standardInvocableAction` — built-in Salesforce actions
720
+ - `externalService` — external APIs registered via External Services
721
+ - `quickAction` — Salesforce Quick Actions
722
+ - `api` — REST API endpoints
723
+ - `apexRest` — Apex REST services
724
+ - `serviceCatalog` — Service Catalog items
725
+ - `integrationProcedureAction` — OmniStudio Integration Procedures
726
+ - `expressionSet` — Business Rules Engine expression sets
727
+ - `cdpMlPrediction` — Data Cloud ML predictions
728
+ - `externalConnector` — external system connectors
729
+ - `slack` — Slack integrations
730
+ - `namedQuery` — named SOQL queries
731
+ - `auraEnabled` — Aura-enabled Apex methods
732
+ - `mcpTool` — Model Context Protocol tools
733
+ - `retriever` — knowledge retrieval sources
734
+
735
+ **Prompt Template actions** differ from Apex and Flow actions:
736
+
737
+ 1. Input names use a quoted `"Input:"` prefix: `"Input:fieldApiName"`.
738
+ 2. Output is always `promptResponse: string`.
739
+ 3. Target protocol is `generatePromptResponse://` (long form) or `prompt://` (short form).
740
+
741
+ ```agentscript
742
+ # WRONG — bare input names and custom output (Apex/Flow pattern)
743
+ actions:
744
+ Generate_Schedule:
745
+ inputs:
746
+ email: string
747
+ outputs:
748
+ schedule_text: string
749
+ target: "prompt://Generate_Personalized_Schedule"
750
+
751
+ # RIGHT — quoted "Input:" prefix, promptResponse output
752
+ actions:
753
+ Generate_Schedule:
754
+ inputs:
755
+ "Input:email": string
756
+ description: "User's email address"
757
+ is_required: True
758
+ outputs:
759
+ promptResponse: string
760
+ description: "Generated schedule"
761
+ is_displayable: True
762
+ target: "generatePromptResponse://Generate_Personalized_Schedule"
763
+ ```
764
+
765
+ Invocation — quote the input name:
766
+
767
+ ```agentscript
768
+ reasoning:
769
+ actions:
770
+ generate: @actions.Generate_Schedule
771
+ with "Input:email" = @variables.user_email
772
+ set @variables.schedule = @outputs.promptResponse
773
+ ```
774
+
775
+ **Deterministic invocation** — when the action must always run, use `run` in the reasoning instructions. The runtime executes it before the LLM reasons:
776
+
777
+ ```agentscript
778
+ reasoning:
779
+ instructions: ->
780
+ run @actions.get_customer
781
+ with customer_id = @variables.customer_id
782
+ set @variables.customer_name = @outputs.name
783
+ set @variables.customer_email = @outputs.email
784
+ ```
785
+
786
+ **LLM exposure** — when the LLM should decide whether and when to call the action, list it in `reasoning.actions`. The LLM sees the description and chooses based on conversation context:
787
+
788
+ ```agentscript
789
+ reasoning:
790
+ actions:
791
+ lookup: @actions.get_customer
792
+ description: "Look up customer information"
793
+ with customer_id = @variables.selected_customer
794
+ set @variables.customer_name = @outputs.name
795
+ ```
796
+
797
+ **Input binding** — three patterns for providing values to action inputs:
798
+
799
+ ```agentscript
800
+ reasoning:
801
+ actions:
802
+ search: @actions.search_products
803
+ # LLM slot-fills: extracts value from conversation
804
+ with query = ...
805
+ with category = ...
806
+
807
+ lookup: @actions.get_customer
808
+ # Variable binding: prefilled from state
809
+ with customer_id = @variables.selected_customer
810
+ # Literal value: fixed at definition time
811
+ with include_archive = False
812
+ ```
813
+
814
+ **Gating** — `available when` controls which actions the LLM can see based on current state:
815
+
816
+ ```agentscript
817
+ reasoning:
818
+ actions:
819
+ check_status: @actions.order_status
820
+ description: "Check your order status"
821
+ available when @variables.order_id != ""
822
+
823
+ place_order: @actions.create_order
824
+ description: "Place a new order"
825
+ available when @variables.cart_total > 0
826
+ ```
827
+
828
+ **Output capture** — use `set` to store action outputs in variables:
829
+
830
+ ```agentscript
831
+ run @actions.fetch_order
832
+ with id = @variables.order_id
833
+ set @variables.status = @outputs.status
834
+ set @variables.total = @outputs.total
835
+ ```
836
+
837
+ ---
838
+
839
+ ## 11. Utility Functions
840
+
841
+ Utility functions control flow and state. They do not call external systems.
842
+
843
+ **`@utils.transition to`** — permanent one-way handoff to another topic:
844
+
845
+ ```agentscript
846
+ reasoning:
847
+ actions:
848
+ go_checkout: @utils.transition to @topic.checkout
849
+ description: "Proceed to checkout"
850
+ available when @variables.cart_has_items == True
851
+ ```
852
+
853
+ Transition discards the current topic's prompt and starts fresh with the target topic.
854
+
855
+ **`@utils.escalate`** — route to a human agent:
856
+
857
+ ```agentscript
858
+ reasoning:
859
+ actions:
860
+ get_help: @utils.escalate
861
+ description: "Connect with a live agent"
862
+ available when @variables.needs_human == True
863
+ ```
864
+
865
+ Escalation ends the current conversation and routes to the escalation system defined in the connection block.
866
+
867
+ **`@utils.setVariables`** — LLM-driven variable capture (slot-filling):
868
+
869
+ ```agentscript
870
+ reasoning:
871
+ actions:
872
+ collect_info: @utils.setVariables
873
+ description: "Collect customer preferences"
874
+ with preferred_color = ...
875
+ with budget = ...
876
+ ```
877
+
878
+ The LLM extracts values from the conversation and populates the specified variables.
879
+
880
+ **`@topic.X`** — delegation to another topic with return:
881
+
882
+ ```agentscript
883
+ reasoning:
884
+ actions:
885
+ consult_expert: @topic.expert_topic
886
+ description: "Get expert guidance"
887
+ available when @variables.needs_expert_help == True
888
+ ```
889
+
890
+ Calling a topic as a tool runs that topic's reasoning, then returns control to the calling topic.
891
+
892
+ **Post-action directives apply only to `@actions`, not `@utils`**:
893
+
894
+ ```agentscript
895
+ # WRONG — utilities don't support set
896
+ escalate: @utils.escalate
897
+ set @variables.escalated = True
898
+
899
+ # CORRECT — only @actions support set
900
+ process: @actions.process_order
901
+ set @variables.result = @outputs.status
902
+ ```
903
+
904
+ Utilities cannot have output, so `set` is invalid.
905
+
906
+ ---
907
+
908
+ ## 12. Anti-Patterns
909
+
910
+ **WRONG: Using `transition to` in `reasoning.actions`**
911
+
912
+ ```agentscript
913
+ # WRONG — this doesn't compile
914
+ reasoning:
915
+ actions:
916
+ go_next: transition to @topic.next
917
+ description: "Go to next"
918
+ ```
919
+
920
+ **Why it fails:** `reasoning.actions` expose tools to the LLM at reasoning time. The LLM needs an action reference, not a bare command. The runtime rejects bare `transition to` syntax in this context.
921
+
922
+ **CORRECT:**
923
+
924
+ ```agentscript
925
+ reasoning:
926
+ actions:
927
+ go_next: @utils.transition to @topic.next
928
+ description: "Go to next"
929
+ ```
930
+
931
+ The `@utils.transition to` syntax creates a callable tool.
932
+
933
+ ---
934
+
935
+ **WRONG: Using `@utils.transition to` in directive blocks**
936
+
937
+ ```agentscript
938
+ # WRONG — compile error
939
+ after_reasoning:
940
+ @utils.transition to @topic.next
941
+ ```
942
+
943
+ **Why it fails:** Directive blocks (`before_reasoning`, `after_reasoning`) execute deterministically — the runtime handles them, not the LLM. They use bare `transition to` syntax.
944
+
945
+ **CORRECT:**
946
+
947
+ ```agentscript
948
+ after_reasoning:
949
+ transition to @topic.next
950
+ ```
951
+
952
+ Bare `transition to` is deterministic — the runtime executes it directly.
953
+
954
+ ---
955
+
956
+ **WRONG: Using lowercase booleans**
957
+
958
+ ```agentscript
959
+ # WRONG
960
+ enabled: mutable boolean = true
961
+ verified: mutable boolean = false
962
+ is_premium: linked boolean
963
+
964
+ if @variables.is_premium == false:
965
+ run @actions.show_basic_features
966
+ ```
967
+
968
+ **Why it fails:** Agent Script requires `True` and `False` (capitalized first letter). The parser rejects lowercase `true`/`false`.
969
+
970
+ **CORRECT:**
971
+
972
+ ```agentscript
973
+ enabled: mutable boolean = True
974
+ verified: mutable boolean = False
975
+ is_premium: linked boolean
976
+
977
+ if @variables.is_premium == False:
978
+ run @actions.show_basic_features
979
+ ```
980
+
981
+ Always use capitalized boolean values.
982
+
983
+ ---
984
+
985
+ **WRONG: Mutable variable without default**
986
+
987
+ ```agentscript
988
+ # WRONG — missing default
989
+ variables:
990
+ customer_name: mutable string
991
+ ```
992
+
993
+ **Why it fails:** During deterministic resolution, the runtime needs an initial value. Mutable variables must have defaults.
994
+
995
+ **CORRECT:**
996
+
997
+ ```agentscript
998
+ variables:
999
+ customer_name: mutable string = ""
1000
+ ```
1001
+
1002
+ Provide a default value.
1003
+
1004
+ ---
1005
+
1006
+ **WRONG: Linked variable with default**
1007
+
1008
+ ```agentscript
1009
+ # WRONG — linked variables get value from source
1010
+ variables:
1011
+ session_id: linked string = "default_session"
1012
+ source: @session.sessionID
1013
+ ```
1014
+
1015
+ **Why it fails:** Linked variables are populated by external context at runtime. Providing a default is contradictory.
1016
+
1017
+ **CORRECT:**
1018
+
1019
+ ```agentscript
1020
+ variables:
1021
+ session_id: linked string
1022
+ source: @session.sessionID
1023
+ ```
1024
+
1025
+ Omit the default.
1026
+
1027
+ ---
1028
+
1029
+ **WRONG: Linked variable without source**
1030
+
1031
+ ```agentscript
1032
+ # WRONG — missing source
1033
+ variables:
1034
+ user_role: linked string
1035
+ ```
1036
+
1037
+ **Why it fails:** The runtime cannot populate a linked variable without knowing where to get the value.
1038
+
1039
+ **CORRECT:**
1040
+
1041
+ ```agentscript
1042
+ variables:
1043
+ user_role: linked string
1044
+ source: @context.userRole
1045
+ ```
1046
+
1047
+ Specify a source.
1048
+
1049
+ ---
1050
+
1051
+ **WRONG: Vague post-action instructions that don't name output fields**
1052
+
1053
+ ```agentscript
1054
+ # WRONG — generic "present the results" lets platform tools hijack the response
1055
+ reasoning:
1056
+ instructions: ->
1057
+ | Use the {!@actions.get_station_status} action to retrieve station information.
1058
+ After receiving the results, present the station information to the user
1059
+ in a clear, organized way.
1060
+ actions:
1061
+ get_station_status: @actions.get_station_status
1062
+ with stationName = ...
1063
+ ```
1064
+
1065
+ **Why it fails:** When instructions say "present the results" without specifying *how*, the LLM often calls `show_command` instead of composing a text response — producing a generic "Here are the results:" wrapper with raw structured data. This can corrupt session state, causing subsequent turns to fail with "unexpected error."
1066
+
1067
+ **CORRECT:**
1068
+
1069
+ ```agentscript
1070
+ reasoning:
1071
+ instructions: ->
1072
+ | Use the {!@actions.get_station_status} action to retrieve station information.
1073
+ After receiving the results, write the data directly in your text response.
1074
+ For each station, include the stationName, projectStatus, crewMembers, and
1075
+ shieldStatus values from the action output. Use the exact values returned
1076
+ by the action — do NOT paraphrase or round.
1077
+ Do NOT use the show_command tool. Always compose your response as direct text.
1078
+ actions:
1079
+ get_station_status: @actions.get_station_status
1080
+ with stationName = ...
1081
+ ```
1082
+
1083
+ Three things make this work: (1) naming the specific output fields the LLM must include, (2) directing it to write a text response rather than calling a platform tool, (3) blocking `show_command` by name.
1084
+
1085
+ ---
1086
+
1087
+ **WRONG: Post-action directive on utility**
1088
+
1089
+ ```agentscript
1090
+ # WRONG — utilities have no outputs
1091
+ reasoning:
1092
+ actions:
1093
+ go_next: @utils.transition to @topic.next
1094
+ set @variables.transitioned = True
1095
+ ```
1096
+
1097
+ **Why it fails:** Utilities like `@utils.transition to` do not return outputs. The `set` directive only works with `@actions`.
1098
+
1099
+ **CORRECT:**
1100
+
1101
+ ```agentscript
1102
+ # If you need to record state, set before transitioning
1103
+ before_reasoning:
1104
+ set @variables.last_topic = "current_topic"
1105
+ transition to @topic.next
1106
+ ```
1107
+
1108
+ ---
1109
+
1110
+ **WRONG: Action loop (action remains available after execution)**
1111
+
1112
+ ```agentscript
1113
+ # WRONG — no gating, no post-action guidance, variable-bound input
1114
+ reasoning:
1115
+ instructions: ->
1116
+ | Place an order using the {!@actions.create_order} action.
1117
+ actions:
1118
+ create_order: @actions.create_order
1119
+ with items = @variables.cart_items
1120
+ ```
1121
+
1122
+ **Why it fails:** Each reasoning cycle, the LLM sees all available actions and decides which to call. This action has no `available when` gate, so it is always available. The variable-bound input (`with items = @variables.cart_items`) means the action is "ready to go" every cycle with no slot-filling decision required. The instructions don't tell the LLM what to do after the action completes, so the LLM may call it repeatedly.
1123
+
1124
+ **CORRECT:**
1125
+
1126
+ ```agentscript
1127
+ reasoning:
1128
+ instructions: ->
1129
+ | Place an order using the {!@actions.create_order} action.
1130
+ After the order is created, confirm the order number.
1131
+ Do NOT call the action again — you have the result.
1132
+ actions:
1133
+ create_order: @actions.create_order
1134
+ with items = @variables.cart_items
1135
+ available when @variables.cart_total > 0
1136
+ ```
1137
+
1138
+ Three mitigations applied: (1) explicit post-action instructions telling the LLM to stop, (2) an `available when` gate so the action is only available when relevant, (3) clear instructions about what to do with the result.
1139
+
1140
+ ---
1141
+
1142
+ **WRONG: Expecting LLM to reason without deterministic context**
1143
+
1144
+ ```agentscript
1145
+ # WRONG — no instructions prepare the LLM
1146
+ topic check_status:
1147
+ reasoning:
1148
+ actions:
1149
+ lookup: @actions.fetch_status
1150
+ ```
1151
+
1152
+ **Why it fails:** The LLM needs instructions about when and how to use the action. Without prompt text from the reasoning instructions guiding the LLM, it may not call the action even when relevant.
1153
+
1154
+ **CORRECT:**
1155
+
1156
+ ```agentscript
1157
+ topic check_status:
1158
+ reasoning:
1159
+ instructions: ->
1160
+ | If the customer asks about their order status, use the {!@actions.fetch_status} action.
1161
+ actions:
1162
+ lookup: @actions.fetch_status
1163
+ with order_id = @variables.order_id
1164
+ ```
1165
+
1166
+ Always pair actions with guiding instructions in the reasoning block.
1167
+
1168
+ ---
1169
+
1170
+ **WRONG: Gate topic transitions to router via `after_reasoning` without defensive instructions**
1171
+
1172
+ ```agentscript
1173
+ # WRONG — the router processes the gate's triggering message in the same turn
1174
+ topic collect_username:
1175
+ reasoning:
1176
+ instructions: ->
1177
+ | Ask the customer for their username.
1178
+ after_reasoning:
1179
+ if @variables.username != "":
1180
+ transition to @topic.topic_selector
1181
+
1182
+ topic topic_selector:
1183
+ reasoning:
1184
+ instructions: ->
1185
+ | Route the customer's message:
1186
+ - Events → @topic.event_lookup
1187
+ - Venues → @topic.venue_booking
1188
+ - Weather → @topic.weather_forecast
1189
+ - Anything else → @topic.off_topic
1190
+ ```
1191
+
1192
+ **Why it fails:** When `collect_username` captures the username and `after_reasoning` transitions to `topic_selector`, both topics process in the same user turn. The router's reasoning fires against the user's original message (e.g., "My username is vivek.chawla"), not a fresh utterance. Since that message doesn't match any domain topic, the router sends it to `off_topic`.
1193
+
1194
+ **CORRECT:**
1195
+
1196
+ ```agentscript
1197
+ topic collect_username:
1198
+ reasoning:
1199
+ instructions: ->
1200
+ | Ask the customer for their username.
1201
+ after_reasoning:
1202
+ if @variables.username != "":
1203
+ transition to @topic.topic_selector
1204
+
1205
+ topic topic_selector:
1206
+ reasoning:
1207
+ instructions: ->
1208
+ | Route the customer's message to the right topic.
1209
+ If the customer just arrived from the username collection
1210
+ step, greet them and ask how you can help — do NOT route
1211
+ their previous message.
1212
+ - Events → @topic.event_lookup
1213
+ - Venues → @topic.venue_booking
1214
+ - Weather → @topic.weather_forecast
1215
+ - Anything else → @topic.off_topic
1216
+ ```
1217
+
1218
+ This pattern applies whenever a gate topic transitions into a routing topic via `after_reasoning`.