← Tidelines/Best practices

Why your agent asks for the order number it already has

The customer clicked Chat about this order on the order page. The widget passed the order number in. The agent’s first message asked for it. Nobody wrote a bug; two people wrote two correct lines a year apart, and the older one is an instruction.

by TypeGlish team7 min read#best-practices
It is right there on the page.

TL;DR An agent re-asks for a fact the host already passed in when an unconditional ask rule sits beside that fact, so make “does the host know it” a typed input and let the build keep only the rule that applies.

Re-asking is the small failure customers notice most, because it tells them the system is not listening. In a chat that opened from an order page, it is also the first thing the agent says. It is rarely the model being forgetful. The prompt contains the answer and an order to ask for it, and the order wins.

§1A rule from before the widget knew who you were

Linden & Vale sells homeware online. When its chat assistant launched, chat lived on the help page and every conversation started anonymous, so the first rule anyone wrote was the sensible one: get the order number before anything else. A year later the platform team added a Chat about this order button to the order page and a line to the prompt that the host fills in. Nobody touched the rules.

before.tg - the launch rules, plus the line the widget fills✓ B (86/100)
# Role
You are the chat assistant for Linden & Vale, an online homeware store.
The customer's order number is {{order_number}}.

# Rules
- ALWAYS ask the customer for their order number first.
- WHEN the customer asks about an order THEN MUST call @[lookup_order].
- MUST answer in at most 3 sentences.

$TOOL lookup_order
  - description:: Find an order and its delivery status.
  - input::
    - order_number:: the order to look up.
Line 3 is the platform’s. Line 6 is the launch team’s. Each is right for the chat it was written for.
tg check, score and build - before.tg✓ clean, and both lines ship
$ typeglish check before.tg
✓ 1 file — 0 error, 0 warning, 0 info

$ typeglish score before.tg
before.tg — B (86/100)  proven errors: none  tiers: base+z3
  planes  runtime 99 (what the model reads) · hygiene 50 (source only)
  facets  enforceability 100 x.21 · hardness 100 x.12 · directness 88 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) · style 100 x.08 · security 100 x.08
  lever   annotation 0/100 (up to +12 overall) — 5 statements without a @@ note (L2 L3 L6 L7 L8) — put a "@@ why" line directly above each
  rules   3 of 3 rule-shaped lines read

$ typeglish build before.tg && cat .typeglish/dist/before.txt
✓ built .typeglish/dist/before.txt ← before.tg (8587a24030b4, full)
# Role
You are the chat assistant for Linden & Vale, an online homeware store. The customer's order number is {{order_number}}.

# Rules
- ALWAYS ask the customer for their order number first.
- WHEN the customer asks about an order THEN MUST call lookup_order.
- MUST answer in at most 3 sentences.
Every rule read, runtime 99, nothing flagged. The {{order_number}} slot is not TypeGlish syntax, so it passes through as text for the host to fill. The checker has no way to know that the slot and line 6 are about the same number.

Run it forward with the slot filled. The customer opened chat from order LV-48213, so the model reads The customer’s order number is LV-48213, and then, two lines later, an instruction to ask for it:

an illustrative exchange - the reply traces to line 6
Customer: Hi, where is this? It said Thursday.
Agent:    Happy to help! Could you share your order number so I can
          look into it?
Customer: I clicked chat ON the order. It is right there.
Short, polite, inside three sentences, and obedient to the only line that uses the word always.

§2A rule beats a fact

The two lines are different kinds of thing. Line 3 is a declaration: it states what is true. Line 6 is a directive: it says what to do, with ALWAYS in front. Nothing in the prompt connects them. No line says if you already have the order number, do not ask for it, because when line 6 was written the agent never had it.

So the model has to infer that the fact settles the rule, and against an explicit always that inference loses often enough to show up in your transcripts. When it guesses the other way and skips the ask, it is breaking a rule you wrote. An agent that sometimes asks and sometimes does not is the worst of the three outcomes, and it is what this prompt is built to produce.

There is a second path to the same failure. When chat still opens from the help page, the host has no order to fill in. Depending on the platform, the model reads The customer’s order number is . or the raw {{order_number}}. One line is serving two entry points, and in one of them it is a sentence with a hole in it.

A fact never cancels a rule. Only a condition does.

§3The ban that fires, and the one that does not

The usual fix arrives after the first complaint: a ban, appended at the bottom.

ban.tg - the ban, appended after the complaints✗ clean, and still both
# Role
You are the chat assistant for Linden & Vale, an online homeware store.
The customer's order number is {{order_number}}.

# Rules
- ALWAYS ask the customer for their order number first.
- WHEN the customer asks about an order THEN MUST call @[lookup_order].
- MUST answer in at most 3 sentences.

# Added after the complaints
- NEVER ask the customer for their order number.

$TOOL lookup_order
  - description:: Find an order and its delivery status.
  - input::
    - order_number:: the order to look up.
tg check - with and without the word first✗ one word apart
$ typeglish check ban.tg
✓ 1 file — 0 error, 0 warning, 0 info

$ diff ban.tg ban2.tg
6c6
< - ALWAYS ask the customer for their order number first.
---
> - ALWAYS ask the customer for their order number.
$ typeglish check ban2.tg
ban2.tg:6:1  error  logic/contradiction  Conflicts with line 11. Logical conflict — "ask the customer for their order number" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
         ↳ line 11: - NEVER ask the customer for their order number.
ban2.tg:11:1  error  logic/contradiction  Conflicts with line 6. Logical conflict — "ask the customer for their order number" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
         ↳ line 6: - ALWAYS ask the customer for their order number.

✗ 1 file — 2 error, 0 warning, 0 info
With first on the end, the checker does not match the two lines as one action, and the file builds with both. Delete the word and it proves the conflict and refuses the build.

The clean result is the dangerous one. The model now reads always ask first and never ask in the same prompt, and settles it one chat at a time. (Teardown: the call-recording block from compliance found the same thing with again: a trailing word changes the phrase the checker compares.) The refusal is the honest outcome, and the checker’s message names the real fix: scope the two rules so they cannot both apply.

The obvious way to scope them is in prose. Guard only the ask, and the checker still refuses, because an unguarded NEVER covers the guarded case too:

tg check - scoping in prose, one side and both sides✓ clean once both are guarded
$ tail -2 missing.tg
- WHEN the order number is missing THEN MUST ask the customer for their order number.
- NEVER ask the customer for their order number.
$ typeglish check missing.tg
missing.tg:5:1  error  logic/contradiction  Conflicts with line 6. Logical conflict — "ask the customer for their order number" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
            ↳ line 6: - NEVER ask the customer for their order number.
missing.tg:6:1  error  logic/contradiction  Conflicts with line 5. Logical conflict — "ask the customer for their order number" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
            ↳ line 5: - WHEN the order number is missing THEN MUST ask the customer for their order number.

✗ 1 file — 2 error, 0 warning, 0 info

$ tail -2 known.tg
- WHEN the order number is missing THEN MUST ask the customer for their order number.
- WHEN the order number is known THEN NEVER ask the customer for their order number.
$ typeglish check known.tg
known.tg:6:1  info   prompt/agentless-passive  The doer is deleted (agentless passive) - who performs this? Name the actor or use the imperative: "Verify the order." instead of "The order is verified."

✓ 1 file — 0 error, 0 warning, 1 info
Guard both sides and it checks clean. It is a real improvement: the two rules now say when each applies.

But look at who decides missing and known. The model does, at runtime, by reading a sentence that may say LV-48213, may say nothing, or may say {{order_number}}. The host knew the answer before the conversation started. It clicked the button. Asking the model to work it out again is the same mistake one level down.

§4Let the host say what it knows, and the build pick the rule

Whether the order is known is not something to infer. It is a fact the host has, as a yes or a no, the moment the chat opens. So declare it as a typed input and branch on it with a $IF chain. A deterministic arm is resolved by the compiler: bind the variable at build time and the losing arm never reaches the model.

fixed.tg - one source, an arm per entry point, two tests✓ A (99/100)
$REQUIRE variable order_known: boolean
$REQUIRE variable order_number: string

# Role
@@ role: the desk this file speaks for
You are the chat assistant for Linden & Vale, an online homeware store.

# Rules
@@ order_source: the order page passes the order in; only the help page opens a chat without one
$IF @{order_known}:
  - NEVER ask the customer for their order number.
  - MUST call @[lookup_order] with order number @{order_number}.
$ELSE:
  - MUST ask the customer for their order number.
@@ status_needs_tool: never guess where a parcel is
- WHEN the customer asks about an order THEN MUST call @[lookup_order].
@@ brevity: a chat bubble, not an essay
- MUST answer in at most 3 sentences.

$TOOL lookup_order
  - description:: Find an order and its delivery status.
  - input::
    - order_number:: the order to look up.

$TEST where_is_it
  - input:: Where is my order? It said Thursday.
  - expect::
    - calls lookup_order
    - at most 3 sentences

$TEST no_reask
  - input:: I am on the order page, it is right there.
  - expect::
    - does not ask the customer for their order number
    - matches /^(?!.*[Oo]rder number\?)/
The ask and the ban sit in different arms of one chain, so they can never both apply, and the checker can see that. Neither arm asks the model to decide what it knows.
tg check, score, test --dry and two builds - fixed.tg✓ two artifacts, one rule each
$ typeglish check fixed.tg
✓ 1 file — 0 error, 0 warning, 0 info

$ typeglish score fixed.tg
fixed.tg — A (99/100)  proven errors: none  tiers: base+z3
  planes  runtime 99 (what the model reads) · hygiene 100 (source only)
  facets  enforceability 100 x.21 · hardness 100 x.12 · directness 88 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08
  lever   directness 88/100 (up to +1 overall) — Use the imperative or a named doer ("Verify the order.", "You must ..."), keep the active voice (not "is verified" / "a review must take place"), and make every it/this point at something the prompt introduced.
  rules   5 of 5 rule-shaped lines read · 5/5 covered by $TEST

$ typeglish test fixed.tg --dry
✓ fixed.tg  coverage: 5/5 rules exercised
  · where_is_it — "Where is my order? It said Thursday." (not run)
      ✓ at most 3 sentences
      · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY)
  · no_reask — "I am on the order page, it is right there." (not run)
      ✓ matches /^(?!.*[Oo]rder number\?)/
      · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY)
✓ 1 prompt — 0 failed

$ typeglish build fixed.tg --vars '{"order_known":true}' && cat .typeglish/dist/fixed.txt
✓ built .typeglish/dist/fixed.txt ← fixed.tg (b1a6459dfe61, full)
# Role
You are the chat assistant for Linden & Vale, an online homeware store.

# Rules
- NEVER ask the customer for their order number.
- MUST call lookup_order with order number {order_number}.
- WHEN the customer asks about an order THEN MUST call lookup_order.
- MUST answer in at most 3 sentences.

$ typeglish build fixed.tg --vars '{"order_known":false}' && cat .typeglish/dist/fixed.txt
✓ built .typeglish/dist/fixed.txt ← fixed.tg (18d51942916e, full)
# Role
You are the chat assistant for Linden & Vale, an online homeware store.

# Rules
- MUST ask the customer for their order number.
- WHEN the customer asks about an order THEN MUST call lookup_order.
- MUST answer in at most 3 sentences.
Two hashes, two prompts. The order-page prompt never mentions asking except to forbid it; the help-page prompt never mentions an order number it does not have. The string stays a {order_number} slot in the first artifact, for the host to fill per chat.

Wire it the way the host already works: the order-page button loads the first artifact and fills the slot, the help-page launcher loads the second. If you ever add a third entry point, say a link from the shipping email, it gets its own build, and you decide on purpose which rule it carries instead of discovering it from a transcript. The no_reask test is the line to keep forever: matches /^(?!.*[Oo]rder number\?)/ runs offline and fails the moment a reply asks for the number with a question mark. For the bigger version of this idea, Your system prompt has a compile time sorts every fact in a prompt by when it is known.

§5Common questions

Why does my AI support agent ask for an order number the customer already gave?
Usually because an unconditional rule like ALWAYS ask the customer for their order number was written before the chat widget passed the order in. The order number arrives as a fact, the rule arrives as an instruction, and nothing in the prompt says the fact settles the instruction, so the model obeys the rule.
How do I stop my chatbot asking for information it already has?
Make whether the host knows the fact an input, and branch on it at build time: $REQUIRE variable order_known: boolean, then $IF @{order_known} with NEVER ask in one arm and MUST ask in the other. Build once per entry point, and each artifact carries only the rule that applies.
Can I just add NEVER ask for the order number to my prompt?
Not on its own. Beside the old always-ask rule it is either a contradiction the checker refuses to build, or, if the old rule ends in a word like first, two rules the checker does not compare and the model has to referee. The ask and the ban need a condition between them.
What happens if the host leaves the order number placeholder empty?
The model reads a sentence with a hole in it, or the raw placeholder, and has to guess whether it knows the order. A boolean input the host sets on purpose, and a build per value, means an empty slot never reaches a prompt that promised not to ask.
Field note

Re-asking has more causes than the order number. Search your prompt for every ask the customer for and, for each one, list the entry points that already know the answer: a signed-in session knows the email, a logged-in app knows the account, a link from a shipping email knows the order. Each of those is a boolean the host can pass and a $IF arm the build can resolve. If the list is long, a $SWITCH ON over a typed entry_point input does the same job with one arm per launcher, and Bake-off: prose conditionals vs $SWITCH for multichannel agents shows why the compiler, not the model, should own that choice.

∿ washed up Oct 26, 2026 ∿