Repository navigation
feat(server): Idempotency-Key on POST /chat - #667
Merged
Merged
Conversation
LinuxDevil
force-pushed
the
fix/http-idempotency-key
branch
2 times, most recently
from
October 16, 2026 21:58
eb86164 to
a663383
Compare
A resend of a turn with the same Idempotency-Key no longer appends the user message again: a finished turn's reply is replayed as run.done (Idempotent-Replayed: true), a turn a crash interrupted is resumed from its checkpoint, and a turn still running in this process is a 409 (LOUSHO_SESSION_BUSY). The key is stored on the turn's user message (metadata.idempotencyKey), so it survives restarts; session.pending() reports an interrupted turn's key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LinuxDevil
force-pushed
the
fix/http-idempotency-key
branch
from
October 16, 2026 22:32
ed28f7d to
de7fc44
Compare
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.
Problem
A client that resends
POST /chat(retry after a crash or timeout, a double submit) appended a new user turn, so tools with side effects could run twice. An emptyinputis400, so there was no HTTP way to "just resume" an interrupted turn.Fix
POST /chataccepts anIdempotency-Keyheader (1-255 visible ASCII). The key is stored on the turn's user message (metadata.idempotencyKey), so it lives in the transcript, or in the turn's checkpoint until the turn finishes, and survives restarts. On a resend with the same key in the same session:200SSE with a singlerun.donecarrying its final reply, plusIdempotent-Replayed: true. Nothing runs.409 LOUSHO_SESSION_BUSY.in-progress): resumed viasession.resume()(finished steps are not re-run) and its events streamed throughsession.on(), instead of appending the message again.409 LOUSHO_SESSION_AWAITING_APPROVAL, the same as without a key.PendingTurngainsidempotencyKey?(from the pending checkpoint), so the route can tell its own interrupted turn from someone else's. The approvals route's in-flight release now uses the samereleasing()wrapper, so it also fires when the stream is returned before it starts.Docs: deployment.md "Resending a turn", sessions.md
pending(), errors.mdLOUSHO_SESSION_BUSY, CHANGELOG.Verification
src/server/idempotency.test.tscovers replay, a new key vs. no key, 409 while running, replay after a restart over the same store, crash-resume without a duplicate message or re-run tool, and a malformed key. 5 of its 6 tests fail against main.npx vitest run src/server src/session ...(route, deploy and remote tests): 332 passed.npx tsc --noEmitandnpm run lintare clean.npm run typecheck:testsshows only errors that already exist on main (loadMcpTools.test.ts, checkpoints.test.ts).🤖 Generated with Claude Code