Assistant Memory (Slots)
In a conversational experience, context matters just as much as the latest user message. Information derived either from the situational context, user profiles or user provided information—like a user’s age, an appointment date, or a selected product—often influences how the assistant behaves later on.
Slots provide this memory in CALM. They preserve data about the user or the external world so that your assistant can leverage it for business logic, personalization, or simply to maintain continuity. If a user provides their email address once, you don’t want them to repeat it in every subsequent interaction. Slots let you store that information and use it across the entire conversation.
Slots in CALM are key-value pairs that represent stateful information your assistant has collected or inferred. Each slot has:
- A name (e.g.,
phone_number
oruser_name
) - A type (e.g.,
text
,boolean
,categorical
, etc.) - (Optionally) a default or initial value
CALM primarily depends on an LLM-based Command Generator to decide what to do next—including issuing commands that set slot values. However, you can still configure slot mappings to rely on an NLU pipeline if you choose to combine NLU-based extraction with CALM. In that case, the NLUCommandAdapter
can issue set slot
commands based on extracted entities or intents.
When building flows, you’ll often see collect steps that explicitly request slot values from users. But at any point in the conversation, the LLM can also set or update slots—if you permit it via the slot’s configuration.
How to Write Slots
Slots are defined in your domain file under the slots:
key. Each slot entry includes at least:
- The slot name
- The slot type (e.g.,
text
,bool
,float
,categorical
,any
, etc.) - (Optionally)
mappings
that specify how the slot should be filled
Below is a minimal example of a slot definition using LLM-based filling:
slots:
user_name:
type: text
mappings:
- type: from_llm
In this example:
user_name
is atext
slot.- It will be filled by the LLM at any point in the conversation, if the LLM issues the correct
set slot
command.
You can also combine an NLU pipeline (for classic intent/entity extraction) with CALM by giving the slot an NLU-based mapping, for example:
slots:
user_name:
type: text
mappings:
- type: from_entity
entity: person
In that case, the NLUCommandAdapter
uses the recognized person
entity to set the user_name
slot. (However, keep in mind that the LLM itself cannot override NLU-defined slot mappings.)
To read more about the NLUCommandAdapter
head over to NLU Command Adapter reference.
Defining Slots in Flows
Within a flow, you often collect slot values using the collect
step:
flows:
my_flow:
description: My flow
steps:
# ...
- collect: user_name
description: "The user’s full name"
This step instructs the LLM that you want to retrieve user_name
from the user. If the user’s response is accepted, the LLM issues a set slot
command, and user_name
gets stored in the conversation state.
How Does Slot Validation Work in CALM?
Slot validation ensures that the values you store are meaningful or properly formatted for your use case. CALM offers two main paths for validating slots:
-
Lightweight validations with rejections inside the flow
In the flow’s
collect
step, you can definerejections
that check the format or basic conditions on the extracted slot value. If the condition is not met, the assistant rejects the slot value and prompts the user again.flows.ymlflows:
my_flow:
description: My flow
steps:
# ...
- collect: phone_number
description: "User's phone number in (xxx) xxx-xxxx format"
rejections:
- if: not ( slots.phone_number matches "^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$" )
utter: utter_invalid_phone_numberThis allows straightforward checks (e.g., matching a regex, ensuring a numeric range, etc.) without writing any custom code.
-
Advanced validations with custom actions
If you need to call an external API or database to decide whether a slot value is valid, you can move the validation logic to a custom action:
flows.ymlflows:
my_flow:
description: My flow
steps:
# ...
- action: action_check_phone_number_has_account
next:
- if: slots.phone_number_has_account
then:
- action: utter_inform_phone_number_has_account
- set_slots:
- phone_number: null
next: "collect_phone_number"The custom action can accept or reject the new slot value. Rejecting the value might reset the slot and re-ask for the user input, or redirect the user to a different flow.
For more detail on advanced slot mappings, slot types and slot validation, visit the page on Slots in the Reference.