tool_constraints in the
frontmatter make a tool invisible until its condition holds. The instructions
body stays untouched.
Tool gating with requires:
Add a tool_constraints entry for the tool. The framework removes it from the
LLM’s schema until the condition is true. The model can’t call what it can’t
see.
skills/card_replace/skill.md
selected_card_id is set, the LLM sees:
Explicit confirmations
For a tool with irreversible side effects, addrequires_confirmation: with
enabled: true. The runtime holds the call, asks the customer to approve it,
and runs the tool only if they say yes.
The two
utter_* names are optional. Set enabled: true on its own and the LLM
phrases both the ask and the denial:
How memory drives gating
Everyrequires: condition evaluates against current memory. Memory is where
tools write results and where the framework checks conditions.
Memory must be declared. A key a tool writes with context.memory.set()
has to exist in the skill’s memory.yml or the project one, or rasa train
fails with undeclared_memory_write:
skills/card_replace/memory.yml
memory.yml
tool_constraints are enforced regardless of who triggers the tool. Whether the
LLM calls it or an ordered-block step runs it via execute_tool:, the same
requires: and confirmation checks run, and gating fails closed, so an
unevaluatable condition keeps the tool hidden.Checking a gate
The Inspector’s tools panel shows every declared tool with its current gate result, so you can watch a condition flip as memory fills in. That is the quickest way to confirm arequires: expression behaves the way you intended.
Two things to confirm when a tool is not appearing:
- The condition uses the full namespaced form,
session.<skill_id>.<entry>orsession.project.<entry>. - The entry is one this skill can read: its own fields, another skill’s
publicfields, or project memory.
tools.py are auto-discovered. They only need a
tool_constraints entry when you are gating them.