When an LLM calls a tool that changes real state, there are three failure modes
that are easy to ship and hard to notice:
1. The phantom success. The tool returns {"ok": true}, but the write never
actually landed — a swallowed error, a fire-and-forget request, a cache that
answered instead of the database. The model happily tells the user it's done.
2. The double write. A network hiccup or the model re-issuing a call applies
the same write twice. Idempotency keys fix this — unless they introduce failure
mode three.
3. The leaky idempotency cache. If the cache returns a stored receipt before
checking who is asking, anyone who knows (or guesses) a key can read someone
else's result. And if the key isn't bound to the request content, a retry with
different arguments silently gets the old answer. I caught exactly this bug in an
early version of my own code during review — auth ran after the cache lookup.
agent-action-kit is a small JavaScript reference implementation of the layer I
now put between the model and anything that writes: one core file, an offline
demo, tests, no runtime dependencies.
What it does:
- Actions are declared up front, with argument validation. Authorization policies run before the idempotency lookup — including on retries.
- Idempotency keys are scoped to the authenticated caller. Reusing a key with a different action or different validated arguments is rejected as a conflict, not served as a "retry". Matching concurrent calls share one in-flight execution within a layer instance.
- An optional
snapshotcallback runs before and after the action; its field-level diff goes into the receipt, so the caller sees what the supplied snapshot observed before and after. You supply the state read — the library does not automatically verify database persistence or reject a write whose stored result differs from the requested value. - Eight tests cover validation, async authorization, replay, conflicting key reuse, and concurrent retries.
Honest boundaries: the demo uses in-memory state so it runs offline; idempotency
is process-local. Durable deduplication across workers, transactions, and
handling a write that commits before an error are still the host application's
job. This is a reference for the ordering and scoping rules, not a distributed
systems library.
Repo: https://github.com/linxi8590-jpg/agent-action-kit
If you've hit failure modes this doesn't cover, open an issue on the repo with a
reproducible case.
Disclosure: This article was drafted and reviewed with AI assistance. I verified
its technical claims against the linked source code and tests.
Top comments (0)