Repository navigation
Conversation
Editing a queued prompt after delivery winsBefore the fix, the edit reported success and the model received a third request containing both B and B2. With the fix, editing the delivered prompt returns Watch the before/after video (MP4) Revision scope: The replay and video compare legacy Recorded checks, traces and reproduction commandThe embedded SDK probe uses a fresh SQLite database and a gated test model for each schedule. Base Base trace · Head trace · Replay scripts Extract the scripts into an empty directory. Set bash replay.sh base "$BASE_CHECKOUT" "$PWD/out-base"
bash replay.sh head "$HEAD_CHECKOUT" "$PWD/out-head"Use fresh output paths. Read |
User decisions: - Reproduce the queued edit through a normal caller on current v2 before fixing it. - Keep the fix minimal and verify a regression test fails before and passes after. - Publish the topic branch as a draft PR for review.
User decisions: - Validate the queued edit fix on v2. - Publish the fix as a draft PR.
User decisions: - Verify the queued edit regression and run the relevant suite. - Keep the change on a draft topic branch.
7c21d0a to
99272f3
Compare
1c4c16e to
9a0fd28
Compare
User decisions: - Apply the review fixes to queued prompt editing - Keep tests minimal; don't add race tests
There was a problem hiding this comment.
The single in-place edit fixes the race between admitting B2 and cancelling B. I ran opencode serve from this branch and called the new endpoint with curl. Editing a queued row kept its ID, creation time and position. Editing a row that had left the queue returned 409, and an edit to steer was delivered straight away. Core, app queue and server media tests pass, and typecheck:tsc passes in core, server, app, client and tui. I did not run the Playwright composer spec because no browsers are available here.
Public API:
- Adds
PUT /api/experimental/session/:sessionID/inbox/:inboxID(experimental.session.inbox.edit). It takes the prompt fields plusmetadataanddelivery, and returns 204, 409, 400 or 404. - Adds the durable event
session.inbox.edited{ sessionID, inboxID, payload, delivery }, which is also inevent.subscribefilters and the session log union. - Adds the client method
client.experimental.session.inbox.editand itsExperimentalSessionInboxEdit*types. - The generator also emits deprecated aliases
client.session.inbox.editandSessionInboxEdit*for a path that never existed.
All of this is additive and backwards compatible. Clients that switch exhaustively over event types will see the new type.
Concern: packages/client bun test has two new failures in test/promise.test.ts, caused by that generated alias (see the inline comment).
Related: #55179
| readonly cancel: SessionInboxCancelOperation<E> | ||
| readonly update: SessionInboxUpdateOperation<E> | ||
|
|
||
| /** @deprecated Use `client.experimental.session.inbox.edit`. Removed in the next minor. */ |
There was a problem hiding this comment.
The codegen adds a deprecated pre-namespace alias for every experimental route. For this new endpoint, that creates a client.session.inbox.edit (and SessionInboxEdit* types) that never existed and is already marked for removal. It also breaks two tests in packages/client/test/promise.test.ts: "exposes every standard HTTP API group" gets an unexpected inbox key, and the experimental-nesting test gets an unexpected deprecated alias session.inbox.edit. Either keep new experimental endpoints out of the alias generation, or at least update the test's expected lists so bun test in packages/client passes.

Issue for this PR
Closes #52275
Type of change
What does this PR do?
Previously, the composer admitted B2 and then cancelled queued prompt B. If A finished between those requests, the model could receive both B and B2.
The composer now sends one
experimental.session.inbox.editrequest (PUT /api/experimental/session/:sessionID/inbox/:inboxID). The server edits the queued row under the same lock as delivery, preserving its ID, creation time, and position. The durable event records the inbox reference, replacement payload, and delivery mode. Mini uses the updated text and attachments for Undo.If delivery wins, the server returns 409. The composer restores B2 immediately on a definitive rejection. If the response is lost, it checks the refreshed inbox and, if the row has already left, the delivered message before restoring a draft. Confirming an untouched editor preserves edits made by another client. The endpoint is experimental; the composer correction is a bug fix and has no feature flag.
How did you verify your code works?
session-queue.spec.ts, retries 0: 49 passed. The existing cases exercise a consumed row returning HTTP 409 and an applied edit whose response is lost.typecheck:tscpassed in core, server, app, client, schema, protocol, and TUI. Bothcheck:generatedscripts, Prettier, oxlint, andgit diff --checkpassed.typecheck:e2ecommand reports diagnostics outside the changed files, including composer fixtures and missing CSS/SVG declarations.Screenshots / recordings
The regression exercises the existing composer and checks its draft after a conflicting edit.
Checklist
Added by the opencode bot (AI-generated).
Related: #55179
Public API: adds experimental PUT /api/experimental/session/:sessionID/inbox/:inboxID, the session.inbox.edited event and client.experimental.session.inbox.edit (backwards compatible)