Slot Best Practices
Six slot anti-patterns that break in production and how to fix them.
Six slot anti-patterns that break in production and how to fix them.
Slots look simple in the UI. Pick a name, write a description, choose a type. But the wrong choices here cascade through every action and conversation that touches the slot. These six patterns are the ones that break in production, not in testing.
Slot descriptions tell the reasoning engine what a slot represents. They’re semantic labels, not rule engines. When you stuff validation logic, formatting rules, or behavioral instructions into a description, none of it gets enforced.
The reasoning engine reads slot descriptions to understand what a slot represents, not how to handle it. When you pack rules into descriptions:
User submits “yesterday” as due date. The engine sees the rule in the description but has no enforcement mechanism. Bad data hits your API, which returns a cryptic error like "Invalid date range". User sees a generic failure message. Support ticket filed.
Description says what the slot is and what format to expect. Validation policy enforces the rules. The engine shows the error_message to the user and re-collects the slot automatically.
Formatting hints like “Expected format: YYYY-MM-DD” are fine in descriptions — they help the engine collect the right shape of data. What doesn’t belong is behavioral logic: “if the user says X, do Y” or “reject and ask again.”
Rule of thumb: Descriptions should say what, not how. Format hints are fine. Behavioral rules are not. If your description has instructions for the engine rather than context about the data, move those rules to validation policies, decision policies, or resolver strategies. Know the trade-off between deterministic enforcement (policies, DSL) and non-deterministic prompting (descriptions) — use the platform’s built-in tools wherever the behavior should be consistent and reliable.
Using string to collect people is the single most common slot mistake. It forces the reasoning engine to parse structured data from free text, which is unreliable and skips the platform’s built-in identity resolution.
You’re asking the engine to parse a comma-separated string into individual identities. This requires:
User says “invite John and the marketing team”. Your string slot captures "John and the marketing team". The engine tries to parse this as emails. Fails. User tries "john@company.com, marketing-team@company.com". Engine parses it. But marketing-team is a distribution list, not a user. API call fails with "Invalid attendee".
The platform’s User resolver:
Rule of thumb: If you’re collecting people, use User or list[User]. Always.
Free text slots without validation accept whatever the user provides. “Priority 99” passes through. “Start date: last Tuesday” passes through. Your API receives garbage, returns errors, and the user sees a generic failure.
Without a validation policy, the engine accepts whatever the user provides. The “1-5” constraint lives in the description only — which means it’s a suggestion, not a rule.
HR system only accepts priority 1-5. User says “make it priority 10 — super urgent!” Engine passes priority: 10. API returns 400 Bad Request: priority must be between 1 and 5. User sees “Something went wrong. Please try again.”
When validation fails, the engine shows the error_message and re-collects the slot. The user gets a clear, specific prompt instead of a cryptic API error.
Validation policies use the same DSL functions available in output mappers. $PARSE_TIME, $TIME, $LENGTH, and comparison operators all work inside rule expressions.
There’s no native datetime slot type in Agent Studio. The correct pattern is string + clear description + $PARSE_TIME validation, then convert to your API’s expected format in the input mapper.
The platform’s NLU handles the natural-language side for you. A user saying “tomorrow at 2pm” or “next Friday” fills the string slot with a value that $PARSE_TIME can parse into Unix time — you don’t need to regex anything yourself.
Most APIs want an ISO-8601 timestamp, sometimes in a specific timezone. Convert inside the input mapper with $FORMAT_TIME:
$PARSE_TIME turns the slot value into Unix time, then $FORMAT_TIME renders it in the exact shape the downstream API expects. Use a fixed timezone when the API needs one; otherwise use the user’s timezone from the data bank.
Rule of thumb: Description tells the NLU what shape of data to collect. Validation policy enforces temporal rules (future-only, within a range). Input mapper shapes the value for the API. Don’t try to do any of this in the description.
Users say “PST” or “Pacific Time”. APIs need “America/Los_Angeles”. Without a resolver mapping display values to IANA identifiers, the raw user input flows straight to your API and breaks.
Users say “PST” or “Pacific Time”. Calendar APIs (MS Graph, Google Calendar) need IANA format: America/Los_Angeles. Without a resolver:
timezone: "PST"Meeting scheduled for “9 AM PST”. MS Graph Calendar API receives timeZone: "PST". Graph doesn’t recognize “PST” — it needs IANA format. Meeting created with wrong timezone. Attendees in different timezones see the wrong time. Everyone shows up at different times.
User sees “Pacific Time (PT)” in the selection. Slot stores "America/Los_Angeles". API gets the right format. Meetings are correct. Note the description also specifies the expected format (IANA) — this helps the engine understand what shape the resolved value takes, even though the resolver handles the actual mapping.
Yes, static resolvers add an LLM call. For timezone mapping, it’s worth it — the alternative is broken meetings.
Static resolvers add an LLM call to resolve the user’s input to a value. For binary yes/no choices, this adds latency and cost with zero benefit over a native boolean slot.
Static resolvers add an LLM call to resolve the user’s input to a matched value. For two options that map to yes/no, this is overhead:
booleanEvery meeting request takes 500ms longer than necessary. Multiply by thousands of requests. Your plugin is “slow” compared to others. Users notice.
Every resolver adds an LLM call. A boolean slot is resolved without one. If you’re building a two-option choice (approve/reject, yes/no, enable/disable), always use boolean over a static resolver. See Decision Frameworks — Slot Type Selection for the full decision tree.
You can’t conditionally collect one slot based on another slot’s value through slot configuration alone. Comments like “required if meeting_type is in-person” in a description are ignored — the engine either always collects the slot or never does.
There is one exception: context passing in resolver strategies. If a slot’s resolver needs another slot’s value to fetch its options (like fetching time-off types for a specific user, or subcategories based on a selected category), you can pass collected slot values into the resolver via strategy mapping. But context passing is for resolver inputs, not for controlling whether a slot gets collected at all.
You can’t conditionally skip slot collection based on another slot’s value. Putting “required if” logic in a description doesn’t make the engine obey it. The reasoning engine will either:
User schedules a virtual meeting. Engine asks “What conference room?” User confused — “It’s virtual, I don’t need a room.” User types “none” or “N/A”. Your API receives room: "none". Room booking system tries to book a room named “none”. Fails or books the wrong room.
Use a decision policy in your conversation process to control flow based on collected slot values:
The conversation process collects is_virtual first (as a boolean slot — no resolver needed). Then the decision policy routes to the right activity based on the value. Users scheduling virtual meetings never see a room prompt.
Context passing vs decision policies: If your second slot’s resolver options depend on the first slot’s value (e.g. fetching subcategories based on a selected category), use context passing in your resolver strategy. If you need to skip collecting a slot entirely based on a condition, use a decision policy in the conversation process. They solve different problems.
Rule of thumb: If you see “required if” or “only when” in a slot description, you need a decision policy in your conversation process. If one slot’s resolver options depend on another slot’s value, use context passing.
Six decision trees including slot type selection and resolver vs boolean.
Never chain action activities without a slot barrier. Slots are the breakpoints.
How the platform converts natural language into business objects.
Static and dynamic resolver configuration with output cardinality.