Skip to main content

Message and History

History is the earlier conversation you pass to a check, oldest first. Each entry is a Result from an earlier check, or a Message you build yourself.

from jes import Message
from jes.guard import History # Result | Message

Its job​

Some attacks only show across turns. A request can look harmless on its own and dangerous after the three messages before it. History gives the judgments that look at context the conversation so far.

History is context, not the text under check. It never changes the check's onward, and it doesn't make a turn's own findings go away.

Mental model​

History is what the judge reads before it reads the new turn:

Before any of it reaches the model, jes cleans it the same way it cleans the checked text. Emails and secrets in earlier turns are replaced too.

  • A Result from the same conversation (same Redactions store) is already clean, so jes reuses its sanitized text.
  • A Message, or a Result from another store, is cleaned again from its text.
  • A Message has a role: "user", "assistant", or "tool". A Result gets its role from its stage. An input result is the user, a tool result is the tool, and anything else is the assistant.

Using it​

Most apps keep the Results they already have:

history = []

incoming = guard.check_input(user_text, redactions=store, history=history)
reply = call_model(incoming.onward)
outgoing = guard.check_output(
reply, prompt=incoming, redactions=store, history=history
)

history += [incoming, outgoing]

When the earlier turns come from somewhere else, such as a database or a chat framework, build Messages:

from jes import Message

history = [
Message("user", "Which pills are in the cabinet?"),
Message("assistant", "Ibuprofen and acetaminophen."),
]
guard.check_input("How many would be too many?", history=history)

Good to know​

  • Only judgments that ask for context see it. hazards, indirect_injection, tool_safety, and a judge(..., context="optional") read the history. injection, toxicity, and topics judge the new text alone.
  • The newest turns win. When the history doesn't fit in one request, jes drops the oldest turns and adds a history_truncated flag. The check still runs. A prompt that doesn't fit is dropped with a context_dropped flag.
  • A blocked turn poisons the rest. A Result in history from the same store that was not ok blocks the check with context_not_ok. Add a turn to history only when it went through.
  • Pass sanitized, not onward, to your own model. An earlier reply's onward has placeholders restored, so it carries the real values.
  • History has a cap. One check takes up to 1,024 context entries, and their total size is bounded by Limits max_context_bytes.

Next​