agentidemp 0.1.0

Idempotency keys for LLM agent retries. Deterministic content-derived keys (UUIDv5 or sha256-hex) so retries dedupe at the provider.
Documentation

agentidemp

crates.io docs.rs License: MIT

Idempotency keys for LLM agent retries. Deterministic content-derived keys (UUIDv5 or sha256-hex) so retries dedupe at the provider or your dedup layer.

[dependencies]
agentidemp = "0.1"

Why

When an agent retries — on a 429, a timeout, or a cachebench miss-aware policy — the retry needs the same idempotency key as the first attempt. Otherwise your dedup layer treats it as a new request and you double-bill or double-dispatch. agentidemp derives the key from the content, so retries get the same key automatically.

Quick start

use agentidemp::{sha256_hex, uuid_v5, random, NAMESPACE_ANTHROPIC};

let body = serde_json::json!({
    "model": "claude-sonnet-4-20250514",
    "messages": [{"role": "user", "content": "hi"}]
});
let bytes = serde_json::to_vec(&body).unwrap();

// Short hex form (35 chars total, "ik_" prefix + 32 hex):
let key1 = sha256_hex(&bytes);
// → "ik_a3f9c1d8b2e7f046189f43a2b8e7c106"

// UUID v5 form (for `Idempotency-Key: <uuid>` headers):
let key2 = uuid_v5(&NAMESPACE_ANTHROPIC, &bytes);

// Random fresh key when you don't have content to derive from:
let key3 = random();

Composing with cachebench retries

cachebench's miss-aware policy retries on a silent cache miss. Pair with agentidemp so the retry is recognized:

use cachebench::{CacheTracker, CachePolicy, Provider};
use agentidemp::sha256_hex;

let body = serde_json::to_vec(&payload).unwrap();
let key = sha256_hex(&body);
// add `Idempotency-Key: ${key}` to your request headers
// retries built by CachePolicy::miss_aware reuse the same body → same key

Scoped keys

If the same prompt body might recur across tenants and you want per-tenant dedup, prefix with a scope string:

use agentidemp::scoped_sha256_hex;

let key = scoped_sha256_hex("user-42", &body_bytes);

The scope and content are separated by a null byte so "ab" + "c" doesn't collide with "a" + "bc".

What it doesn't do

  • Doesn't make HTTP calls. Returns a string; you set the header.
  • Doesn't cache responses. That's a different layer.
  • Doesn't track which keys you've used. Stateless by design.

License

MIT