Skip to main content
A first search can take Agentcard most of a minute. While it works, the shopper sees a 👀 on their own message, the way a friend reacts to a text before answering it. In a chat that shows no reactions, the shopper reads a short text instead, such as on it, looking for usb-c cables under $20.

React with a 👀

Pass onReaction to buy.turn. Show the emoji as a tapback on the shopper’s bubble.
chat.ts
A reaction is the default acknowledgement. It names nothing the shopper said, so it never reads a request back wrong, and the chat holds only real answers. Each message gets at most one 👀, and it goes out in these cases:
  • A message that starts a search gets it the moment buy.turn opens, before your model runs.
  • A call that Agentcard has not answered within 1.5 seconds puts the 👀 on a message that has none yet: a slow yes, a pick, or a confirm that is still placing the order. The tool sends no text with the 👀.
These messages get none when the turn opens, because Agentcard answers them fast: a pick of a product or a store the shopper saw, an address or other details, an answer to a question such as yes, 2, or a code, a step toward checkout such as ok lets checkout, and an acknowledgement such as its ok. When the 👀 went out, the model reads shopper_already_told_looking: true in that turn’s answers, and its description tells it not to acknowledge the request again. The reply opens with the answer or the question, not on it. The field reads false on a turn that reacted with nothing, and when onReaction threw. An onReaction that throws costs only the reaction. With onItem on the turn, the 👀 still goes to onReaction and never joins the turn’s items, because it sits on the shopper’s bubble and not in the agent’s sequence.

Send a short text instead

For SMS, or any chat that shows no reactions, pass onWorking and no onReaction, or set ack: 'text':
chat.ts
ack takes 'reaction', 'text', or 'none'. Left out, the tool reacts when the tool or the turn has an onReaction, and sends text through onWorking otherwise. With both callbacks, the shopper gets the 👀 and never the text too. 'none', or false, sends nothing. In text mode, the tool sends the reply when Agentcard has not answered a new request within 1.5 seconds, so a quick answer arrives alone. It sends one for the calls the model makes in one turn. The reply waits for onWorking, so the shopper reads it before any link and before the model answers. An onWorking that throws costs only the instant reply. The words rotate through six templates, and one tool never sends the same template twice in a row. A short paraphrase of the request goes in when the tool can read one. It stops before any link, email address, phone number, street address, or long number, and a request that starts with one gets a reply that names nothing, such as looking for that now. Pass ack: (ask) => text to write your own text from the shopper’s words, where an empty answer sends none. Pass ackDelayMs to change the 1.5 seconds for either mode.

Acknowledge before the model runs

The model takes several seconds to call the tool after the shopper’s message arrives. With buy.turn, the turn acknowledges the moment it opens, and calls instantReaction or instantAck for you. Outside a turn, call buy.instantReaction(message) the moment the message arrives, before your model runs, and put the emoji it returns on the message. In text mode, call buy.instantAck(message) and send the text it returns.
chat.ts
Both return null for a message that starts no search, such as a confirmation, a short answer, a step toward paying, a pick of something the shopper saw, a code, small talk like hi, a message that carries the shopper’s own details, or a short reply right after a question the last answer asked. A reply that opens a new request, such as find me black running shoes, or that runs past four words is still a search. When either returns an acknowledgement, the tool sends none of its own for that turn. The reply never reads the shopper’s details back, and it names the request only when it reads as a short, whole phrase. Otherwise it says on it, give me a moment or another reply that names nothing. Pass ack: 'none' to the tool when you acknowledge yourself.

Show a long wait

A turn that runs long, even past a minute, gets no text line. A search often takes 10 to 40 seconds, so a line at any wait short enough to help would land on most searches and bring back the chatter the reaction replaces. To show a long wait, pass onProgress and show its stage as a status line or a typing indicator:
chat.ts
The tool then asks Agentcard to stream each call. Pass stream: false to wait for each whole answer instead.

Check it in the sandbox

  1. Send “two packs of AA batteries from Amazon” as a test shopper. Check that the 👀 appears on your message at once, before the model answers, and that the reply opens with the answer.
  2. Send “yes” after a cart. Check that no 👀 appears at once, and that a slow answer gets one after about 1.5 seconds.
  3. Send “the first one” after a product list. Check that no reaction or text appears when the turn opens.
  4. Switch to ack: 'text'. Check that the text names your request or nothing, and that it never repeats an email address or a street address you typed.
  5. Make onReaction throw. Check that the turn still answers and the model reads shopper_already_told_looking: false.