← Tidelines/Best practices

Why your agent says let me check and then goes quiet

The customer asks where their order is. The agent says it will look into it and get back to them shortly. Then nothing happens, because nothing was ever going to. The sentence came from your prompt.

by TypeGlish team6 min read#best-practices
One moment, forever.

TL;DR An agent that says it will check and then goes quiet was usually told to announce the search or promise an update, so tie the lookup to the question with a WHEN rule, ban the follow-up outright, and keep a test case that fails if the reply says get back to you.

This is one of the most reported failures in chat agents, and it looks like a platform bug. The agent replies Let me check on that order for you, one moment! and the customer waits. A minute later they type hello? and the agent, finally getting a turn, does the lookup it described a minute ago. Some customers never type hello?. They leave, and the transcript ends on a promise.

§1The symptom: a promise with nobody behind it

A tool-calling agent works in turns. The customer sends a message, the model replies, and if the reply contains a tool call the runtime executes it and hands the result back for another pass. If the reply contains no tool call, the turn is over. The agent will not speak again until the customer does.

So let me check with no call attached is not the start of a lookup. It is the whole reply. There is no background job, no timer, no later. Whatever the agent said it would do next, it can only do on the customer's next message, if there is one.

An agent has no later. It has this reply and the next one the customer chooses to send.

The model did not invent the habit on its own. Read the prompt, and you will usually find the sentence it sent, written down as a rule.

§2The cause: the prompt scripts the wait

Marlow Cycles runs a chat assistant for its online bike shop. Its orders section was written by someone who had worked a contact-centre queue, where telling a customer you are checking is good manners, because a person really is checking.

before.tg - the orders section as it ships✗ C (73/100)
# Role
You are the chat assistant for Marlow Cycles, an online bike shop.

# Orders
- Always let the customer know you are looking into their order.
- Tell the customer you will get back to them shortly with an update.
- Check the order status if needed.
- You SHOULD keep the customer informed while you check.
tg review - before.tg✗ 1 rule invisible
$ typeglish review before.tg
before.tg — C (73/100) → A (97) projected if every fix below lands  check: 0 error, 0 warning, 3 info  tiers: base+z3

  FIXES  ranked by projected gain
  +12  put a "@@ why" note above L2 L5 L6 L7 L8 — annotation 0 → 100
  +4   commit the 1 soft statement ("if needed" on L7) to MUST / NEVER / ALWAYS / REQUIRE / ENSURE — or keep the word if it is a permission by design — up to hardness 100
  +3   make L5 provable — one verb the checker knows, one object, or a bound (the rules table names each edit)
  +3   lead with a modal (MUST / NEVER / SHOULD) on L7 — 1 rule becomes visible to the checker
  +1   fix the 1 prompt/vague finding (L7) — Vague wording the model can read many ways.
  +1   fix the 1 prompt/unintroduced-definite finding (L7) — A definite retrieves a card the document never introduces (Open the store. - which store?) - introduce the head on an…

  RULES  3 of 4 rule-shaped lines read · 1 not provable
    L5   ~ unprovable    Always let the customer know you are looking into their order.
                         "let" is not a verb the checker knows → use a verb from the catalog (redirect, escalate, ask, cite …) or add a numeric bound
    L7   ✗ invisible     Check the order status if needed.
                         no modal (MUST / NEVER / SHOULD), and the checker knows "check" but cannot prove this shape: it stops reading at "if" — the clause after it is not part of the provable action, so it reads as prose → lead with a modal (MUST …) to make it a rule, and if the clause is a condition, make it one: WHEN <clause> THEN MUST <verb> …; otherwise give it its own rule to make it provable

  FINDINGS
  before.tg:7:26  info   prompt/vague  Vague — "if needed" names a judgment call without the criterion to judge by, so nothing can check it. Replace it with a measurable form ("at most 3 sentences", "within 24 hours", "cite the source").
  before.tg:7:1  info   prompt/unparsed-rule  Reads like a rule, but the rule reader cannot parse it as one, so it earns no Enforceability credit and no measurability check: no modal (MUST / NEVER / SHOULD), and the checker knows "check" but cannot prove this shape: it stops reading at "if" — the clause after it is not part of the provable action, so it reads as prose. Fix: lead with a modal (MUST …) to make it a rule, and if the clause is a condition, make it one: WHEN <clause> THEN MUST <verb> …; otherwise give it its own rule to make it provable.
  before.tg:7:1  info   prompt/unintroduced-definite  "the order status" retrieves something this document never introduces - a model must guess which status is meant. Mention a status on an earlier line, or anchor it here ("their status", "the status you ...").

  TESTS  no $TEST cases — add one beside a rule; `test --dry` validates it offline
Read what got flagged and what did not. The one line that does the looking up is invisible and vague. The two lines that script the wait are read cleanly, and line 6, the promise, earns no finding at all.

Now read the section the way a model does, as a description of what a good reply contains. Line 5 says every order question gets an announcement. Line 6 says the reply promises an update later. Line 8 says keep them informed while you check, which asks for words before results. And line 7, the only line that would produce a result, applies if needed, a judgment the model makes after it has already been told to talk first.

The cheapest reply that satisfies lines 5, 6 and 8 is the exact sentence the customer received: I'm looking into your order and will get back to you shortly with an update. No tool call is required to write it. Lines written for a person who keeps working after they speak describe, for a model, a reply that ends the turn.

§3The fix: the lookup is the reply

Three edits, each aimed at one line of the old section.

  • Tie the tool to the question. If needed becomes a trigger: WHEN the customer asks about an order THEN MUST call @[lookup_order]. The condition is the customer's question, not the model's sense of whether looking is worthwhile.
  • Ban the later. The agent has nothing to come back with, so it may not offer to come back. NEVER offer a follow-up. uses offer, a verb the checker reads, so a later rule that requires a follow-up will collide with it.
  • Hand the leftovers to someone who has a later. When the lookup cannot answer, the contact goes to a team that works after the chat ends. That is a tool call, so it happens in this reply too.
marlow.tg - the orders section rebuilt✓ A (99/100)
$TOOL lookup_order
  - description:: Look up the status and tracking of a Marlow Cycles order.
  - input::
    - order_number:: string
$TOOL transfer_to_orders_team
  - description:: Transfer the chat to the orders team, who answer the customer by email.

# Role
@@ role: an online bike shop's chat desk; every later "you" is the agent
You are the chat assistant for Marlow Cycles, an online bike shop.

# Orders
@@ look_now: a reply with no tool call ends the turn, so the lookup goes in the same reply as the question
- WHEN the customer asks about an order THEN MUST call @[lookup_order].
@@ no_later: the agent has no later; it speaks again only when the customer does
- NEVER offer a follow-up.
@@ answer_from_result: the reply carries what the lookup found, not a description of the search
- WHEN @[lookup_order] returns a delivery status THEN MUST state its delivery status.
@@ no_result: when the lookup cannot answer, a team that works after the chat ends takes it
- IF @[lookup_order] finds no order THEN MUST call @[transfer_to_orders_team].

$TEST where_is_it
  - input:: Hi, where is my order 48213? It was meant to arrive Tuesday.
  - expect::
    - calls lookup_order
    - states its delivery status
    - does not offer a follow-up
    - matches /^(?![\s\S]*get back to you)/i
tg review and test --dry - marlow.tg✓ 4 of 4 rules read
$ typeglish review marlow.tg
marlow.tg — A (99/100)  check: 0 error, 0 warning, 0 info  tiers: base+z3

  FIXES  none — every facet is essentially full

  RULES  4 of 4 rule-shaped lines read · 4/4 covered by $TEST

  TESTS  1 case · 4/4 rules exercised

$ typeglish test marlow.tg --dry
✓ marlow.tg  coverage: 4/4 rules exercised
  · where_is_it — "Hi, where is my order 48213? It was meant to arrive Tuesday." (not run)
      ✓ matches /^(?![\s\S]*get back to you)/i
      · rubric — 3 prose expectations, judged on a live run (needs ANTHROPIC_API_KEY)
✓ 1 prompt — 0 failed
From C to A, every rule read, every rule named by the one test case. The dry run proves the case is well formed; whether the agent actually calls the tool is a live run.

Notice what the new section does not contain: any instruction about what to say while checking. It does not need one. When the reply is a tool call, the customer sees the answer, not an announcement of it. If your chat widget shows a typing indicator during tool calls, that already does the job the old line 5 was trying to do, and it does it without ending the turn.

The IF @[lookup_order] finds no order rule is a deliberately small failure path. A real one names every outcome the tool can return, and How to write what your agent says when the lookup fails shows how to make the missing outcome a build error.

§4The line that comes back

A month later somebody reads a transcript where a lookup was slow and the customer sat in silence, and they patch the prompt. Here are two ways that patch gets written, each inserted below the NEVER:

tg check - two versions of the courtesy patch✗ one refused, one at an A
$ diff marlow.tg slow.tg
16a17
> - IF the customer is still waiting THEN MUST offer a follow-up.
$ typeglish check slow.tg
slow.tg:16:1  error  logic/contradiction  Conflicts with line 17. Logical conflict — "offer a follow-up" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
         ↳ line 17: - IF the customer is still waiting THEN MUST offer a follow-up.
slow.tg:17:1  error  logic/contradiction  Conflicts with line 16. Logical conflict — "offer a follow-up" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
         ↳ line 16: - NEVER offer a follow-up.

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

$ diff marlow.tg promise.tg
16a17
> - Tell the customer you will get back to them shortly with an update.
$ typeglish check promise.tg
✓ 1 file — 0 error, 0 warning, 0 info
$ typeglish score promise.tg | head -1
promise.tg — A (97/100)  proven errors: none  tiers: base+z3
The patch that says offer a follow-up is refused: same verb, same object, required and forbidden. The patch that says the old sentence again ships at an A.

Both lines mean the same thing to a customer. To the checker they are different acts: offer a follow-up is the rule's own action and object, while tell the customer you will get back to them is a speech act about the future, and the checker does not read promises for what they commit the agent to. The same gap shows up in Why your agent promises the refund instead of issuing it, where the narrated action is a refund rather than a lookup.

That is why the test case carries a regex assert. matches /^(?![\s\S]*get back to you)/i needs no judge: on a live run, any reply containing the phrase fails the case, whichever line of the prompt put it there. The checker guards the rule you wrote; the test guards the sentence you are trying to stop.

§5Common questions

Why does my AI agent say let me check and then not reply?
In a typical tool-calling loop, a reply that carries no tool call ends the agent's turn, and the agent speaks again only when the customer does. If the prompt tells it to announce that it is checking, or to promise an update, the model can send that sentence as the whole reply. Nothing is running in the background.
How do I make my agent call the tool instead of saying it will?
Tie the tool to the question with a WHEN rule, such as WHEN the customer asks about an order THEN MUST call the lookup tool, and delete the lines that script narration or promise an update later. Then keep a test case whose input is the question and whose expectations name the tool call.
Can TypeGlish detect a promise to get back to the customer?
Not by its meaning. A line telling the agent to say it will get back to the customer checks clean beside NEVER offer a follow-up, because the two use different verbs. Only a rule that requires offering a follow-up is refused as a logic/contradiction. A regex assert in a $TEST is what catches the phrase on a live run.
What should my agent say while a tool call is running?
Usually nothing separate. Put the tool call in the same reply as any short acknowledgement, and answer from the result. If the lookup cannot answer, hand the contact to a team or a tool that will still exist after the chat ends, rather than having the agent promise to come back.
Field note

Search your prompt for the words of a person who keeps working after they hang up: looking into, get back to, shortly, one moment, keep the customer informed, update them. Each one describes a reply with no result in it. Then run typeglish review and find the line that actually calls your lookup tool; if it is listed as invisible or hangs on if needed, that is the stall. If no rule mentions the tool at all, you have the cousin of this bug, covered in Why your agent won't use the tool you gave it.

∿ washed up Oct 31, 2026 ∿