Deterministic Conversation
Scripted Speech
Some sentences cannot be paraphrased. A recording notice, a cooling-off period, an affordability warning, a right-to-cancel statement: these are approved text, and a model rewording them slightly is a compliance failure even when the meaning survives. The pattern is to carve deterministic islands into a generative conversation, so the parts that must be exact are exact and everything around them stays fluent.
Two Kinds of Utterance
A scripted node in a workflow graph emits fixed text rather than asking the model to produce it. The difference is not stylistic. It changes who owns the sentence and what can go wrong with it.
| Property | Generated Utterance | Scripted Utterance |
|---|---|---|
| Wording | Varies per call, and varies with model version | Byte-identical every time |
| Ownership | Whoever last edited the prompt | Whoever approved the catalogue entry, usually legal or compliance |
| Review | Sampled from transcripts after the fact | Reviewed before release, as a text artefact |
| Failure mode | Drifts, omits a clause, or is argued away by a persistent caller | Fires at the wrong moment, or does not fire at all |
| Translation | Re-generated per language, with no guarantee of equivalence | Translated once and approved per locale |
| Evidence | You can show what was said, not what should have been | You can show the approved text and the version in force that day |
The Catalogue Pattern
A scripted node with its text typed into the graph solves the wording problem and creates a maintenance one, because the approved sentence now lives in a diagram rather than anywhere legal can govern it. Lifting the text into a catalogue and having a trigger select from it separates three concerns that otherwise collapse: when to speak, what to say, and who approved it.
A condition on the graph, evaluated the same way an edge is: an expression over variables, a tool result, or a semantic check. It decides only that something must be said, not what.
Gets you: The moment of delivery becomes testable independently of the wording.
The trigger names a message by identifier rather than by content. The catalogue resolves it against locale, product, jurisdiction and effective date, returning approved text and its version.
Gets you: The approved sentence lives in one governed place instead of scattered across graph nodes and prompts.
The text is spoken or rendered verbatim, bypassing generation entirely. Nothing about the model influences the output at this point.
Gets you: Prompt drift, jailbreaks and model upgrades cannot alter a regulated sentence.
The delivered text is appended to the conversation as an assistant turn, so subsequent generations treat it as something the agent said.
Gets you: Conversational coherence without the model having authored the words.
Injecting It as the Assistant's Own Turn
The delivered text is written back into the context window as an assistant message rather than as a system note. From the model's next turn onward it reads as something it said, which is the entire point: the model will not repeat it, will not contradict it, and can refer back to it naturally. The same mechanism as prefilling an assistant turn, used for compliance rather than formatting.
The model can see the disclosure in its own history, so it does not deliver it again a turn later.
It will not tell the caller something the injected text has already ruled out, because the constraint is in the history rather than in an instruction it might weigh.
It can refer back to what was said, as in "as I mentioned, this call is recorded", without any special handling.
A caller cannot talk the model out of a disclosure it never decided to make. There is no decision to attack.
This is steering at its strongest setting. Most steering asks the model to take a correction into account and hopes it wins against everything else in context. Writing into the conversation history does not ask, and the model has no representation of the difference.
Audit Metadata
If the model cannot tell that it did not compose the sentence, neither can anything reading the transcript later. That is fine for the model and unacceptable for the audit trail, so the injected turn needs metadata the model is never shown. Without it the pattern produces a record asserting a disclosure was made and no way to prove which one.
| Field | Why It Is Needed | Question It Answers Later |
|---|---|---|
| Message identifier and version | Catalogue entries change, and the text in force on the day of the call is what matters | Which exact wording did this caller hear |
| Trigger that fired | Separates a disclosure that was correctly required from one delivered by accident | Why was this said at this point |
| Delivery status | Queued, started, completed and interrupted are four different outcomes | Did the caller actually hear all of it |
| Spoken prefix on interruption | A barge-in means the audible text and the catalogue text diverge | How much of it was delivered before the caller cut in |
| Provenance flag on the turn | The injected turn is indistinguishable from a generated one without it | Which parts of this transcript did the model actually compose |
| Locale and jurisdiction resolved | The same identifier resolves differently by market | Was the right variant selected for this caller |
Failure Modes
The caller talks over the disclosure four words in. The full approved text is already in context and in the log, so the record asserts a disclosure the caller never heard. This is the pattern's sharpest edge, because the injection that makes it work is also what makes the failure invisible.
Fix: Reconcile against playback marks, inject only the spoken prefix, and mark the turn incomplete. Treat an interrupted mandatory message as undelivered and re-deliver rather than assuming.
A trigger condition never evaluates true because a variable was not set, so the disclosure simply never happens. Nothing errors, and the call completes looking normal.
Fix: Assert on the outcome rather than the trigger. Every call in a regulated flow should be checked at completion for the set of disclosures it was required to contain.
The disclosure fires, but after the action it was supposed to precede. Card details are taken and the recording notice follows a moment later, which is a breach even though both events occurred.
Fix: Gate the action on delivery completion, not on the trigger having fired. This is an authorisation condition, and it belongs at the tool boundary.
Having seen the disclosure in its own history, the model helpfully re-explains it in simpler words later in the call. The catalogue governed the first delivery and nothing governs the second.
Fix: Instruct explicitly against restating catalogue content, and check for it in evaluation. If callers genuinely need a plain-language version, approve one and give it its own identifier.
Approved text written by lawyers is dropped into a warm conversational agent, and the seam is audible. Callers notice the switch and some disengage exactly when attention matters most.
Fix: Approve the wording and the delivery together. Where the law fixes the words, tune pace and voice rather than the text.
An entry is updated and old transcripts are re-read against the new text, so a historic call appears to have used the wrong wording.
Fix: Version entries immutably and resolve by effective date. Never mutate an entry in place once it has been delivered to anyone.
Where This Sits
The prior art is the mandatory IVR prompt, which was deterministic because nothing in the system could be anything else. What is new is putting that determinism back inside a generative agent selectively, so a conversation can be fluent everywhere it is allowed to be and exact everywhere it is not.
Related: Agentic Workflows for the graph the trigger lives in, Turn-Taking and Interruption for the truncation problem that makes a barge-in over a disclosure a compliance question rather than a cosmetic one, Authorisation Policy for gating an action on a disclosure having completed, Steering for the weaker forms of the same idea, and Guardrails for checking what the model produced rather than replacing it.
