How to write escalation rules for an AI support agent
Escalation is where a support agent earns trust or loses it, and it is the part of the prompt most likely to be a vague sentence in the persona. This guide turns "escalate when needed" into rules the compiler can hold you to: a real handoff, scoped triggers that can't collide, tiered severity, and a test that fails if the handoff ever breaks.
TL;DR Write escalation as a tool call (not a line in the persona), scope every trigger with WHEN/UNLESS so two rules can't require and forbid the same handoff, tier severity with a $IF chain, and pin the handoff with a $TEST. The checker proves the collisions (logic/contradiction) and fails a defined-but-unused escalation tool, so a broken handoff can't ship quietly.
Every support agent has an escalation policy. In most prompts it is one sentence, something like "escalate to a human when appropriate," sitting in the persona paragraph and doing almost nothing. It reads fine in review and fails in production, because "when appropriate" is not a trigger, "escalate" is not an action the model can be sure it took, and nothing checks that the two ever connect. Escalation is worth more rigor than that: it is the release valve for everything your agent should not be deciding alone. Here is how to write it so the compiler is on your side.
§1Make the handoff a tool, not a sentence
The first fix is to stop treating "escalate to a human" as prose. Prose is something the model reads and paraphrases; a tool is something it calls. Declare the escalation path as a real tool and point a WHEN rule at it, so the handoff is an action with a name and a schema instead of a suggestion.
$IMPORT tool escalate_to_human # Role You are a support agent for a telecom provider. # Constraints - WHEN a customer explicitly asks for a person THEN call @[escalate_to_human].
@[escalate_to_human] pointer ties the rule to the real tool the host runtime provides. If you declare the tool but never reference it, the checker flags a dead escalation path; if you reference a tool that was never declared, that is a dangling pointer. Either way the handoff can't silently go missing. This is the same discipline as making any tool discoverable, applied to the one tool you most need the model to reach for.With that in place, "escalate when appropriate" becomes a list of concrete triggers, each its own WHEN rule pointing at the tool: an explicit request for a person, a trigger outside the agent's authority (a legal threat, a security concern, a refund over your approval limit), and the honest one every agent needs, WHEN you are unsure of a policy THEN escalate instead of guessing. Three rules, one tool, zero vibes.
§2Scope every trigger so two rules can't collide
The moment you have more than one rule about escalation, you can write two that fight. It happens the natural way: one sprint adds "always escalate billing disputes to a specialist," a later sprint decides the agent is empowered to handle small ones and adds "never escalate a billing dispute," and no one reads both lines together. In plain English these coexist quietly and the model picks a winner per conversation. In TypeGlish they are a proven contradiction.
# Constraints - MUST escalate a billing dispute to a specialist. - You are empowered to resolve billing disputes; NEVER escalate a billing dispute to a specialist.
escalation.tg:2:1 error logic/contradiction Logical conflict - "escalate a billing dispute to a specialist." is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). (conflicts with line 3) ✗ 1 file - 2 error, 0 warning, 0 info
The fix is to give each rule a scope so the two can never fire on the same input. Escalation policy is almost always about a threshold, so put the threshold in the rule.
# Constraints - WHEN a billing dispute is over 200 dollars THEN escalate it to a specialist. - WHEN a billing dispute is 200 dollars or less THEN resolve it yourself.
§3Tier severity with a $IF chain
Thresholds handle one axis. Real escalation has levels: some things wait for a supervisor, some things page the on-call lead now. When precedence matters, a stack of loose prose conditionals leaves the ordering to the model. Hand it to the compiler instead with a $IF chain, which is ordered and first-true-wins by construction.
$REQUIRE variable severity: one of low, high, critical # Escalation $IF @{severity} is equal to critical: Escalate to the on-call lead immediately. $ELSE IF @{severity} is equal to high: Escalate to a supervisor within the hour. $ELSE: Resolve the issue yourself.
$IF chain when the tiers are ordered and may lean on judgment; reach for a $SWITCH when they are members of one closed, typed set, the trade-off laid out in the prose conditionals vs $SWITCH bake-off.§4Pin the handoff with a $TEST
You now have a real tool, scoped triggers, and tiered severity. One risk remains, and it is the quiet one: a future edit trims the prompt, the escalation rule goes with it, and every check stays green because a shorter prompt is still a valid prompt. The behavior you most need is the easiest to delete by accident. Pin it with a $TEST so the handoff has something watching it.
$IMPORT tool escalate_to_human # Role You are a support agent for a telecom provider. # Constraints - WHEN a customer explicitly asks for a person THEN call @[escalate_to_human]. $TEST human_handoff - input:: Stop. I want to talk to a real person, not a bot. - expect:: - calls the escalate_to_human tool - does not keep trying to resolve the issue itself
WHEN rule and the file still compiles, but typeglish test now has a failing case pointing straight at the missing behavior. That is the difference between hoping your agent escalates and knowing it does.Put those four together and escalation stops being the soft spot in the prompt. The handoff is an action, not a phrase. The triggers are scoped, so they cannot argue. The tiers are ordered by the compiler, not the model's mood. And the whole thing is under test, so it survives the next person who edits the file. That is the entire job: take the one policy you least want the agent to improvise, and make it the most rigorously specified part of the prompt.
The @[tool] reference family, the logic/contradiction prover, the $IF chain, and $TEST suites all shipped in TypeGlish 0.1.0, and every .tg block on this page is re-checked against the real compiler by the CI guard on each build. Once your handoff is pinned, the next question is which of your other rules are actually load-bearing, which is exactly what pulling a good prompt apart, one rule at a time sets out to measure.
FAQCommon questions
- When should an AI support agent escalate to a human?
- Escalate on three triggers: an explicit request for a person, anything outside the agent's authority (legal threats, account security, high-value refunds), and low confidence, which is the "WHEN you are unsure THEN escalate" rule. Encode each one as a
WHENrule that calls a real escalation tool, not as a hope buried in the persona, so the handoff is an action the model actually takes. - How do I stop my escalation rules from contradicting each other?
- Give every escalation rule a scope. Two rules that name the same action, one requiring it and one forbidding it, are a provable contradiction: the checker flags
logic/contradictionand refuses to build. Scope them withWHENorUNLESSso they cannot both fire on the same input, for example escalate a dispute over 200 dollars and resolve one at or under 200 dollars yourself. - Should escalation be a tool or an instruction?
- A tool. "Escalate to a human" written as prose is a wish the model can paraphrase and never act on. Import or define an escalation tool and point a
WHENrule at it with an@[tool]reference, so the handoff is an action with a schema. The checker also fails a tool that is defined but never referenced, so a dead escalation path cannot ship unnoticed. - How do I test that my agent actually escalates?
- Write a
$TESTwhose input is a clear escalation trigger, like "I want to talk to a real person," and whose expectation is that the agent calls the escalation tool and stops trying to resolve the issue itself. Runtypeglish testand the case fails the moment a future edit weakens the handoff, so the behavior is pinned rather than trusted.