42 · Replies true to what was done¶
After your agent acts, its model writes the reply the person reads, and a model can say a refund went through
when it was refused, or name an amount nobody charged. With replies: set, every reply the model writes is
held to what was actually done before it is shown: each sentence about an action must agree with that action's
outcome, as the run recorded it, and a sentence that does not is replaced by a plain one that does.
Language support
The selector understands turns written in English. Portuguese is its next grammar, and has not shipped yet; until it does, a turn written in Portuguese is not read as Portuguese.
The outcomes¶
The run records an outcome for every call it attempted, from the check's answer and what became of the call, never from what the model says. Each outcome, what a sentence about it may say, and the phrasing a sentence that says more is replaced by, generated from the runtime's check:
| Outcome | Means | A sentence about it may | Default phrasing |
|---|---|---|---|
done |
the call ran | say it was done; ask about it; say it is not yet known; mention it without saying either | Done: {action}{with}. |
failed |
the call was made and failed | say it was not done; ask about it; say it is not yet known; mention it without saying either | Not done: {action}{because}. |
refused |
the tool check refused the call; nothing ran | say it was not done; ask about it; say it is not yet known; mention it without saying either | That can't be done: {action}{because}. |
pending_confirmation |
the call waits for the person's approval | say it was not done; promise it; ask about it; say it is not yet known; mention it without saying either | Once you confirm, I will {action}{with}. |
unknown |
nobody knows yet whether the call took effect | ask about it; say it is not yet known; mention it without saying either | Whether {action} went through is still being checked; I'll confirm before doing anything else. |
undone |
the call ran and a failed run undid it | say it was done; say it was not done; ask about it; say it is not yet known; mention it without saying either | Reversed: {action}{with}. |
not_attempted |
the call was never made: skipped, cancelled, or never asked for | say it was not done; ask about it; say it is not yet known; mention it without saying either | Not done: {action}. |
{action} is the tool's name in words (refund card), {with} the arguments the call was sent, and
{because} the reason, where there is one.
The check, step by step¶
- The reply is read sentence by sentence, with the same reader that reads the person's turns, so I've
sent your money back is read as speaking of
refund_card. - Each sentence is held to the outcome of the action it speaks of: this turn's latest call of that tool,
or the session's. A sentence saying a refused refund was made is replaced by the
refusedphrasing. - An action mentioned with no call behind it: a sentence saying a write was done, where nothing in the
session attempted it, is replaced by the
not_attemptedphrasing. - Every value a sentence states -- an amount with its currency, a date, an e-mail address, an identifier -- must be one the call was sent or returned. A sentence stating another is replaced by the outcome's phrasing.
- A write this turn made that the reply leaves out is added, in its outcome's phrasing.
- The reply rules apply last: personal data, phrases never to say, offers, required sentences (chapter 43).
The reply the person reads is the one the check returns. A replaced sentence is never shown, and each replacement is counted, with no text (chapter 43).
The shop's refunds¶
The shop's desk, with on_unread: model, so that a turn nothing reads goes to its model. The model here is a
plain function that stands in for yours: for each turn, the call it asks for, and the reply it then writes:
# Stands in for your model: for each turn, the call it asks for and the reply it then writes.
SCRIPT = {
"my parcel is lost": (None, ""),
"the parcel for 4412 is lost": (
{"name": "get_order", "arguments": {"order_id": "4412"}},
"Order 4412 has been refunded."),
"the parcel for 4412 never turned up": (
{"name": "refund_card", "arguments": {"order_id": "4412", "amount": "all"}},
"I've refunded order 4412."),
"the parcel for 4412 went missing": (
{"name": "refund_card", "arguments": {"order_id": "4412", "amount": 12.50}},
"I've refunded 15.00 pounds to your card for order 4412."),
"the parcel for 4412 vanished": (
{"name": "refund_card", "arguments": {"order_id": "4412", "amount": 12.50}},
"I've refunded 12.50 pounds to your card for order 4412."),
}
def model(conversation):
turn = [m for m in conversation if m["role"] == "user"][-1]["content"]
call, reply = SCRIPT[turn]
if conversation[-1]["role"] == "user" and call:
return {"content": "", "tool_calls": [call]}
return reply
desk = Agent("desk", tools=[get_order, refund_card], model=model, on_unread="model",
replies={"phrasings": "phrasings.yaml"})
def turn(text, answer="approve"):
reply = desk.chat(text, user="u-17")
if reply.waiting: # a write waits for the person
print(f"{text} -> waits: {reply.waiting[0].wording}")
reply = desk.confirm("u-17", answer)
print(f" {answer} -> {reply.text}")
else:
print(f"{text} -> {reply.text}")
turn("my parcel is lost") # nothing reads it: asked once to say it again
turn("the parcel for 4412 is lost") # the model says a refund was made; none was called
turn("the parcel for 4412 never turned up") # the refund was refused; the model says it was made
turn("the parcel for 4412 went missing") # done, but the model states another amount
turn("the parcel for 4412 vanished") # done, and the reply says what was done
turn("the parcel for 4412 went missing", answer="skip") # the person said no: not attempted
my parcel is lost -> I didn't recognise anything in that. I can get order or refund card. Which do you mean?
the parcel for 4412 is lost -> Not done: refund card.
the parcel for 4412 never turned up -> I couldn't refund order 4412: argument_schema.
the parcel for 4412 went missing -> waits: Run refund_card?
approve -> Refunded 12.5 pounds for order 4412.
the parcel for 4412 vanished -> waits: Run refund_card?
approve -> I've refunded 12.50 pounds to your card for order 4412.
the parcel for 4412 went missing -> waits: Run refund_card?
skip -> Not done: refund card.
Line by line:
- the first turn is one nothing reads, so the person is asked once to say it again; the next goes to the model;
- the model said order 4412 has been refunded after reading it, and no refund was called:
Not done: refund card.; - the refund the model asked for was refused, its amount not a number: the shop's own
refusedphrasing; - the refund ran with 12.50, and the model wrote 15.00: the sentence is replaced by the shop's
donephrasing, with the amount the call was sent; - the refund ran, and the model's sentence says what ran: it is shown as written;
- the person said no:
Not done: refund card.
Outcome phrasings¶
A phrasing is what a reply says about a write for one outcome. The shop's, for refund_card:
# How a reply tells each write's outcome, in the shop's words. An outcome not listed takes the default.
refund_card:
done: "Refunded {argument.amount} pounds for order {argument.order_id}."
refused: "I couldn't refund order {argument.order_id}{because}."
An outcome a tool has no phrasing for takes the default above, in the language replies: {language: pt}
names (en by default). A phrasing may use {action}, {Action} (capitalised), {with}, {because},
{reason}, {argument.NAME} and {result.NAME}. Your organisation's phrasings are also kept on the
console's Phrasings page and at /v1/outcome-phrasings, in versions.
The template composer¶
With replies: {composer: template}, the reply is the phrasings themselves: whatever the model writes, the
person reads the phrasing of each call this turn made, in order:
template = Agent("desk", tools=[get_order, refund_card], model=model, on_unread="model",
replies={"phrasings": "phrasings.yaml", "composer": "template"})
for text in ("my parcel is lost", "the parcel for 4412 vanished"):
reply = template.chat(text, user="u-18")
if reply.waiting:
reply = template.confirm("u-18", "approve")
print(f"{text} -> {reply.text}")
my parcel is lost -> I didn't recognise anything in that. I can get order or refund card. Which do you mean?
the parcel for 4412 vanished -> Refunded 12.5 pounds for order 4412.
With the template composer, no reply the person reads is written by a model (chapter 45).
Where it runs¶
The check runs in the runtime on your machine, on every plan, with no network. The reply, the arguments and the results stay on your machine: only the counts are reported, with your licence's other meters.
The limits¶
- The check is deterministic and bounded, and it does not prove a reply true. It removes what the run's records do not support: a sentence about an action that disagrees with its outcome, and a value the action was neither sent nor returned.
- It reads the sentences the reader can tie to a tool. A sentence it ties to no tool is held only to the reply rules (chapter 43), and a value is checked only where it has the shape of one: an amount with its currency, a date, an address, an identifier.
- The outcome is the run's record, which for a call that left your machine is what your tool returned: a tool that reports success for something that failed is reported as done.
- It holds the replies your model writes. A reply a person reads that no model wrote -- a fixed question, a refusal, a phrasing -- is the product's own wording.