Output guards for an LLM reply that streams to a user. Prompt injection can make a model print a phishing link, a made-up price or phone number, or quote its system prompt, and by the time you check the finished reply the user has read it. These guards work on the reply as it streams: each piece is either shown now, held back until it can be judged (a half-written link, a number that may still grow), or the reply is stopped before the piece that breaks a rule reaches the screen.
Plain string logic: no model call, no ML, no dependencies.
| Install | Docs | |
|---|---|---|
| Python 3.11+ | pip install llm-stream-guards |
python/README.md |
| JavaScript / TypeScript, Node 22+ | npm install llm-stream-guards |
js/README.md |
The two packages have the same guards, the same behaviour and the same version number. Both run the cases in spec/, so a fix in one is a failing test in the other until it is made there too.
- Links: a link to a host you did not supply is removed, from its first character, while it is still being written.
- Email addresses and phone numbers that none of your sources holds.
- Prices and effort estimates that none of your sources states:
$120,40 euros,300 engineering hours,60knear a cost word. - A quoted system prompt: a reply that repeats a protected text eight words in a row.
- Code a reply was not meant to hand over: stopped at the first fence.
- Citation markers (
[1],[1, 3]) taken out of what is shown, with a list of the sources the reply cited. - Hidden blocks, such as the
<think>...</think>of a reasoning model, dropped from what is shown. - A reply cut off at the token limit: nothing half written is let out, and
tidy_cut_offends it at its last full sentence. - Your own check, run with the same windowing and holding back as the built-in ones.
guards = Chain(CodeStream(), LeakStream(leaks), AmountStream(numbers_in(*texts)), LinkStream(hosts_of(urls)))
for delta in deltas:
if shown := guards.feed(delta):
send(shown)
send(guards.finish()) # raises Blocked when the reply must be replacedconst guards = new Chain(new CodeStream(), new LeakStream(leaks), new AmountStream(numbersIn(...texts)), new LinkStream(hostsOf(urls)));
const safe = modelTextStream.pipeThrough(guardTransform(guards)); // errors with Blocked when the reply must be replacedEach package's README has the full example, the API and the limits. These checks see shapes, not meaning: they are a backstop for when the prompt, and any model-based check, did not hold.
python/ the PyPI package
js/ the npm package
spec/ test cases both packages run
See CONTRIBUTING.md and CHANGELOG.md.
MIT