langstate
Compress long LLM conversations into visible working state — then check that the literal facts you care about survived.
langstate is a small experimental Python library for OpenAI-format message
lists. It keeps system messages and recent turns verbatim, summarizes older
history into a visible [SCAFFOLD STATE] system message, and returns the same
list-shaped interface that chat clients already accept.
Most context compression gives you a summary and asks you to trust it.
LangState makes that lossy step inspectable: the compressed state is an ordinary
message you can view, log, edit, replace, or reject. validate(...) then gives
you a deterministic receipt for the literal facts you name explicitly.
This is a functional prototype/library, not a lossless archive, a structured
state store, or production infrastructure. Summary quality depends on the
model and the input; treat validate as a narrow check, not a guarantee of
semantic fidelity.
Install
python -m pip install langstate
Python 3.10+; no runtime dependencies beyond the standard library. The default summarizer calls a local Ollama model, so prepare it once:
ollama pull qwen3:4b
Try it in two minutes
This deterministic example produces a real scaffold and receipt without a model
call. It injects a tiny summarizer so the result is reproducible; remove
summarizer=demo_summary afterward to use local Ollama instead.
from langstate import compress, validate
messages = [{"role": "system", "content": "Be concise."}]
for user, assistant in [
(
"We are launching the developer preview on May 5. Keep the rollout "
"private until the invitation list is approved, and cap the launch "
"budget at $4,000.",
"Understood. I will treat May 5, a private preview, and the $4,000 "
"cap as launch constraints.",
),
(
"Dana owns the release checklist. Morgan owns the API migration. "
"The only blocker is the billing webhook retry bug in staging.",
"I recorded Dana as release owner, Morgan as migration owner, and "
"the staging billing webhook as the blocker.",
),
(
"The first cohort is 25 developers using Python clients. We will not "
"invite JavaScript users until the second week.",
"The first cohort is 25 Python developers; JavaScript waits until week two.",
),
(
"If the blocker is still open on May 3, move the preview to May 12 "
"rather than cutting the verification pass.",
"Unresolved on May 3 means move to May 12, never skip verification.",
),
("What should the launch note emphasize?", "The private, Python-first preview."),
("Who gives final approval?", "Dana, after webhook verification passes."),
]:
messages.extend(({"role": "user", "content": user},
{"role": "assistant", "content": assistant}))
def demo_summary(_prompt):
return (
"- Preview: May 5; budget cap: $4,000.\n"
"- Dana owns release; Morgan owns API migration.\n"
"- Blocker: staging billing webhook retries.\n"
"- If still blocked May 3, move to May 12."
)
compressed = compress(messages, preserve_recent=2, summarizer=demo_summary)
receipt = validate(
messages,
compressed,
facts=["May 5", "$4,000", "Dana", "Morgan", "May 12"],
)
assert receipt.ok
print(compressed[1]["content"])
print(receipt.summary())
The result makes the compressed state visible before you send it anywhere:
[SCAFFOLD STATE — compressed from 8 earlier messages]
- Preview: May 5; budget cap: $4,000.
- Dana owns release; Morgan owns API migration.
- Blocker: staging billing webhook retries.
- If still blocked May 3, move to May 12.
5/5 facts survived (100%) · 62% smaller
Now omit summarizer=demo_summary after preparing Ollama to judge a real local
model against the facts your application actually needs.
Receipt.ok is true only when every requested string occurs in the compressed
messages after case-and-whitespace normalization. It cannot credit a paraphrase,
so it is intentionally conservative. Use explicit facts=[...] for a focused
contract; automatic fact extraction is a convenience heuristic.
How it works
For conversations of at least six user/assistant turns, compress:
- retains all
systemmessages and the requested recent suffix verbatim; - sends the older non-system messages to the selected summarizer;
- inserts that result as
[SCAFFOLD STATE — compressed from N earlier messages]; - returns the resulting OpenAI-format list.
You can use the result with an OpenAI-compatible chat client, or keep the scaffold as an auditable intermediate artifact. The library does not make a semantic preservation claim about the model-generated summary.
Choose a summarizer
| Option | Default/model | What you provide |
|---|---|---|
| Local | Ollama qwen3:4b |
Ollama at localhost:11434 |
| OpenAI | gpt-4o-mini |
OPENAI_API_KEY |
| Anthropic | claude-haiku-4-5 |
ANTHROPIC_API_KEY |
| Custom | (prompt: str) -> str |
Your callable |
from langstate import compress
from langstate.adapters import build
local = compress(messages)
openai = compress(messages, summarizer=build("openai"))
anthropic = compress(messages, summarizer=build("anthropic"))
custom = compress(messages, summarizer=my_summarizer)
Use probe(name) to see whether a configured adapter is currently usable.
Boundaries and current evidence
- The library’s deterministic tests cover message shaping, injected summarizers, adapter-unavailable errors, lexical receipts, and version consistency. They do not establish the quality of any live model.
- Repository benchmark JSON files record single, synthetic-corpus runs for the named adapter and model. They are leads for model selection, not general performance claims.
validatechecks literal text only. It neither establishes semantic equivalence nor detects an invented claim that happens to reuse a checked phrase.- Use original messages for exact replay, regulated records, tool-call semantics, or any workflow where a lossy summary is unacceptable.
API
compress(
messages,
preserve_recent=4,
min_turns_to_compress=6,
model="qwen3:4b",
summarizer=None,
)
validate(before, after, facts=None)
See Receipt.as_dict() for a JSON-friendly receipt. The package is
Apache-2.0 licensed.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langstate-0.2.1.tar.gz.
File metadata
- Download URL: langstate-0.2.1.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59467226a1d71879f04bb305b16768e65837e807ce52c17a338f47db8af7a123
|
|
| MD5 |
7610054b021e6359bab020da64fe52a7
|
|
| BLAKE2b-256 |
1188f9bbbdd9354aaa7ad8951125e108600aa3d0d90ddc7ff4e8628e092a37e7
|
Provenance
The following attestation bundles were made for langstate-0.2.1.tar.gz:
Publisher:
publish.yml on hermes-labs-ai/langstate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langstate-0.2.1.tar.gz -
Subject digest:
59467226a1d71879f04bb305b16768e65837e807ce52c17a338f47db8af7a123 - Sigstore transparency entry: 2341149489
- Sigstore integration time:
-
Permalink:
hermes-labs-ai/langstate@0bfb71124a7fb5f42972a642c057b8887615a4d3 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/hermes-labs-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0bfb71124a7fb5f42972a642c057b8887615a4d3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file langstate-0.2.1-py3-none-any.whl.
File metadata
- Download URL: langstate-0.2.1-py3-none-any.whl
- Upload date:
- Size: 16.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af1c5201e58d022d6d6189055a4047cd3e986a7a697986b348d06515e60b40fc
|
|
| MD5 |
88fd8f0afe14af11ee16737a7cc12135
|
|
| BLAKE2b-256 |
997b9029d7000a1f6a0c3dfba3a3d9c842ef9f76c1cdf45956fdbaab164a80ad
|
Provenance
The following attestation bundles were made for langstate-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on hermes-labs-ai/langstate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langstate-0.2.1-py3-none-any.whl -
Subject digest:
af1c5201e58d022d6d6189055a4047cd3e986a7a697986b348d06515e60b40fc - Sigstore transparency entry: 2341149494
- Sigstore integration time:
-
Permalink:
hermes-labs-ai/langstate@0bfb71124a7fb5f42972a642c057b8887615a4d3 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/hermes-labs-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0bfb71124a7fb5f42972a642c057b8887615a4d3 -
Trigger Event:
push
-
Statement type: