43 · Reply safety¶
With replies: {rules: ...} set, every turn a person sends is screened for personal data before the router
or the model reads it, and every reply the model writes is screened again before it is shown, whether or not
an action came before it. Your rules say what each class of personal data gets, which phrases are never said,
which offers a reply may make and which sentences must go with a write. No model judges any of it: the runtime
on your machine decides each rule.
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.
Personal data¶
The classes the runtime finds, how each is found, what it gets where your rules say nothing, and how it is masked, generated from the runtime's detectors:
| Class | How it is found | Default | Masked as |
|---|---|---|---|
email |
an address of the form name@domain | allow |
j***@example.com |
iban |
an account number of the length its country gives, whose check digits hold | redact |
GB** **** 2681 |
national_id |
a US social security number, a UK national insurance number, or a Brazilian CPF whose check digits hold | redact |
***6789 |
card |
13 to 19 digits whose checksum (Luhn) holds: a number that fails it is left as it is | redact |
**** 1111 |
phone |
an international number of 8 to 15 digits, or a national one of 10 or 11 | allow |
***0123 |
A card number is found by its checksum, not by its shape: sixteen digits that fail the Luhn check are left as they are, because they are not a card number. Each class takes one of three actions:
| Action | In a turn sent to the model | In a reply the model wrote |
|---|---|---|
redact |
masked before the router and the model read the turn | masked in the sentence |
withhold |
the whole turn is held back: nothing reads it, and the person is asked to send it again without it | the sentence is removed |
allow |
left as it is | left as it is |
A value an outcome sentence may repeat. A sentence reporting a write may name a value the write was sent -- the card a refund went to -- and that value is masked in it rather than removed, whatever the class's action, unless the class is allowed.
Wording¶
never_say: phrases never said. A sentence holding one, whole words and any case, is removed.offers: the offers a reply may make. A sentence holding one of themarkers(such as discount or voucher) and none of theallowedoffers is removed.must_accompany: sentences that must go with something: a disclaimer added when a tool's call ran in this turn (when_done), or when an answer cites a passage with a tag (when_cited). It is added once, where the reply does not already say it.
The reply rules file¶
The rules are one file, YAML or JSON, named in agent.yaml as replies: {rules: reply-rules.yaml} or in Python
as Agent(..., replies={"rules": "reply-rules.yaml"}). The shop's:
# The shop's reply rules, as the console's Reply rules page saves them.
personal_data:
card: redact # the default, written out
national_id: withhold # a turn holding one reaches no model; a reply holding one loses the sentence
email: allow
never_say:
- "guaranteed refund"
must_accompany:
- when_done: refund_card
add: "Refunds reach the card in three to five working days."
Every key the runtime reads, generated from the runtime:
| Key | What it says |
|---|---|
personal_data |
for each class of personal data, redact, withhold or allow |
must_accompany |
sentences that must go with a write done or a passage cited |
must_accompany[].add |
the sentence added |
must_accompany[].when_done |
added when this tool's call ran in this turn |
must_accompany[].when_cited |
added when an answer cites a passage with this tag |
never_say |
phrases never to say: a sentence holding one is removed |
offers |
the offers a reply may make |
offers.allowed |
the offers allowed |
offers.markers |
the words that make a sentence an offer: one with a marker and no allowed offer is removed |
The same rules are kept on the console's Reply rules page, as a form over the same file, and at
/v1/reply-rules, in versions. A file the runtime cannot read -- a class it does not know, an action that is
not one of the three -- is refused with the key that is wrong.
The shop's replies, screened¶
The model below stands in for yours, and records what it was given:
SEEN = [] # what the model was given, turn by turn
# Stands in for your model: what it is asked, and the reply it writes.
SCRIPT = {
"zork": (None, ""),
"my card is **** 1111, is it on file?": (
None,
"Your card 4111 1111 1111 1111 is on file; the card 4111 1111 1111 1112 is not."),
"the parcel for 4412 vanished": (
{"name": "refund_card", "arguments": {"order_id": "4412", "amount": 12.50}},
"I've refunded 12.50 pounds for order 4412. It is a guaranteed refund."),
}
def model(conversation):
turn = [m for m in conversation if m["role"] == "user"][-1]["content"]
SEEN.append(turn)
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={"rules": "reply-rules.yaml"})
for text in ("zork",
"my card is 4111 1111 1111 1111, is it on file?",
"my social security number is 123-45-6789",
"the parcel for 4412 vanished"):
reply = desk.chat(text, user="u-17")
if reply.waiting:
reply = desk.confirm("u-17", "approve")
print(f"{text}\n -> {reply.text}")
print("The model was given:", SEEN)
zork
-> I didn't recognise anything in that. I can get order or refund card. Which do you mean?
my card is 4111 1111 1111 1111, is it on file?
-> Your card **** 1111 is on file; the card 4111 1111 1111 1112 is not.
my social security number is 123-45-6789
-> That message held details I can't take here, so I haven't read it or done anything. Please send it again without them.
the parcel for 4412 vanished
-> I've refunded 12.50 pounds for order 4412. Refunds reach the card in three to five working days.
The model was given: ['my card is **** 1111, is it on file?', 'the parcel for 4412 vanished', 'the parcel for 4412 vanished']
- The card number the person typed was masked before anything read the turn: the model was given
**** 1111. - The model's reply named the same valid card, masked, and a sixteen-digit number that fails the checksum, left as it is.
- The turn with a social security number was held back whole, under
national_id: withhold: nothing read it, and the person was asked to send it again without it. It is not in what the model was given. - After the refund ran, It is a guaranteed refund. was removed (
never_say), and the disclaimer the rules require for a refund was added.
The counts¶
Each check is counted, by the meter it is recorded under, with your licence's other meters. A count is a number: it carries no text, no value and no turn.
| Count | What it counts |
|---|---|
reply_pd_detected_<class> |
a value of that class of personal data found |
reply_pd_masked |
a value a write was sent, repeated in its own outcome sentence, masked |
reply_pd_withheld |
a turn held back, or a sentence removed, for a value the rules withhold |
reply_pd_redacted |
a value masked because the rules redact its class |
reply_assertion_refused |
a sentence saying a write was done that nothing in the session attempted, replaced |
reply_outcome_replaced |
a sentence its action's outcome does not allow, replaced by the phrasing |
reply_value_replaced |
a sentence stating a value its action was neither sent nor returned, replaced |
reply_outcome_added |
a write of this turn the reply left out, added from its phrasing |
reply_wording_removed |
a sentence holding a phrase never to say, removed |
reply_offer_removed |
a sentence making an offer outside the allowed ones, removed |
reply_wording_added |
a sentence the rules require, added |
The limits¶
- A detector finds the classes it names, and no others. A name, a postal address, a date of birth or an identifier of another country is not detected, and is left as it is.
- A detector finds a value written as the detector reads it. A card number spelt out in words, or split across two messages, is not found.
- No model judges a reply. A rule matches the words it is given: a phrase said in other words is not a
phrase
never_saylists. - The screen holds the turns the agent reads and the replies its model writes. A reply no model wrote -- a fixed question, a refusal, a phrasing -- is the product's own wording.