feat: added per-invocation idempotency support via idempotency_token #1937
Open
BV-Venky wants to merge 8 commits intostrands-agents:mainfrom
Open
feat: added per-invocation idempotency support via idempotency_token #1937BV-Venky wants to merge 8 commits intostrands-agents:mainfrom
BV-Venky wants to merge 8 commits intostrands-agents:mainfrom
Conversation
added 6 commits
March 17, 2026 22:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds per-invocation idempotency support via an optional
idempotency_tokenparameter. When a duplicate request arrives with the same token while the original is still running, the duplicate waits for the original to finish and receives the same result or error instead of raisingConcurrencyException.Behavior
AgentResultor re-raises the same exception. Only the final result is delivered - intermediate streaming events are not replayed.
ConcurrencyExceptionpath.UNSAFE_REENTRANTmode: token is ignored entirely.Parameters
idempotency_token: Optional token for duplicate detection. Can be any hashable value (string, UUID, or the prompt itself).THROWmode; ignored inUNSAFE_REENTRANT.Public API Changes and Code Example
idempotency_tokenis added to__call__,invoke_async, andstream_asyncIt is a purely additive, opt-in parameter without existing behavior changes.
Design Decisions
THROWsemantics intact; idempotency is per-call, not per-agent.THROWonlyUNSAFE_REENTRANTallows concurrent invocations by design; retry deduplication only makes sense when concurrency is restricted._inflight_idempotency_token+_inflight_invocationTHROWmode at most one invocation is in flight; a single variable suffices. Upgradeable to a dict ifUNSAFE_REENTRANTsupport is added later without breaking changes.threading.Lockandthreading.Eventrun_async()creates separate threads with separate event loops;asyncioprimitives do not work across them.await asyncio.to_thread(waiting_on.done.wait)IdempotencyAbortedErrorwhen neither result nor error is setNone.IdempotencyTestAgentsubclass withduplicate_detectedeventSyncEventMockedModelfor deterministic two-thread tests withouttime.sleep.Use Cases
idempotency_token- the retry waits for the original and receives its result without replaying the prompt.agent(prompt, idempotency_token=prompt)agent(prompt, idempotency_token=request.headers["X-Request-ID"])Related Issues
Resolves #1365
Type of Change
Testing
hatch run prepareUNSAFE_REENTRANT, cleanup, prompt-as-token)Checklist
Documentation PR
TBD
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.