Skip to main content

llm-message-hash-py

PyPI Python License: MIT

Stable canonical sha256 hash of LLM request/message structures.

Two semantically identical Anthropic requests can produce different sha256(json.dumps(req)) results because Python dict iteration order is not part of the value, and fields like cache_control change the bytes without changing what gets sent to the model. This library walks the value tree, sorts dict keys recursively, drops a configurable set of fields, and sha256s the canonical bytes.

Useful for prompt-cache lookups, idempotency keys, and dedupe.

Sibling to the Rust crate llm-message-hash.

Install

pip install llm-message-hash-py

Use

Default (no fields dropped):

from llm_message_hash import hash_request

a = {"model": "claude", "messages": [{"role": "user", "content": "hi"}]}
b = {"messages": [{"content": "hi", "role": "user"}], "model": "claude"}

assert hash_request(a) == hash_request(b)

Per-provider preset (drops cache_control, response-only fields, etc.):

from llm_message_hash import HashOpts, hash_request

with_cc = {
    "messages": [{
        "role": "user",
        "content": [{"type": "text", "text": "hi", "cache_control": {"type": "ephemeral"}}],
    }],
}
without_cc = {
    "messages": [{
        "role": "user",
        "content": [{"type": "text", "text": "hi"}],
    }],
}

h1 = hash_request(with_cc, HashOpts.for_anthropic())
h2 = hash_request(without_cc, HashOpts.for_anthropic())
assert h1 == h2

You can also get the canonical bytes directly:

from llm_message_hash import canonical_json

s = canonical_json({"b": 1, "a": 2})
assert s == '{"a":2,"b":1}'

Presets

Each preset drops the response-side metadata that varies per call plus provider-specific request fields that do not change semantics:

Preset Drops
HashOpts.for_anthropic() cache_control, id, usage, stop_reason, stop_sequence
HashOpts.for_openai() created, id, object, system_fingerprint, usage, finish_reason
HashOpts.for_bedrock() cache_control, usage, stopReason, metrics
HashOpts.for_gemini() usageMetadata, safetyRatings, finishReason

Extend any preset:

opts = HashOpts.for_anthropic()
opts.drop_keys.add("metadata")

Or build your own:

opts = HashOpts(drop_keys={"trace_id", "request_id"})

Drop key behavior

drop_keys matches exact key names at any depth. A key named in drop_keys is removed from every dict it appears in, no matter how deeply nested. List order is preserved (a list is structurally significant). Strings are case sensitive: "hi" and "Hi" hash differently. Numbers compare by their JSON representation: 42 and 42.0 are different strings and so hash differently.

What it does NOT do

  • No tokenization. The hash is over structure, not token count.
  • No semantic equivalence beyond key-order normalization and the drop list.
  • No streaming. Pass a complete Python object.
  • No HTTP. Does not talk to any LLM provider.

License

MIT

Metadata

Release files for llm-message-hash-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-message-hash-py 0.1.0
File Size Uploaded Provenance
llm_message_hash_py-0.1.0.tar.gz 7.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for llm-message-hash-py 0.1.0
File Interpreter ABI Platform
llm_message_hash_py-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 13.2 kB

Release files / llm_message_hash_py-0.1.0.tar.gz

Download URL llm_message_hash_py-0.1.0.tar.gz
Size 7.0 kB
Tags Source
SHA-256 checksum
How to use checksums
14a585668783c8fd818e3b447ffe8a5d55c4d40ac44e6fc1037abf2eef55cfe5
BLAKE2b-256 checksum
How to use checksums
b61b6d9828f00f9ae8872f3217d11557bd87fb77b539b5096ffa6aae4cf0679a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release files / llm_message_hash_py-0.1.0-py3-none-any.whl

Download URL llm_message_hash_py-0.1.0-py3-none-any.whl
Size 6.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a07dabd2e458d467609f57ddc75a9261e595751864ea18aff7fe58c91d52a51c
BLAKE2b-256 checksum
How to use checksums
c6717acce332c81d2fcfaeede3698f03cbe84c78dad13fa2e4b6ff286494b390
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Security for llm-message-hash-py 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page