feat(simplex): treat an edited inbound message as a correction that supersedes the queued/in-flight original - #97317
Conversation
Overall: Thoughtful edit-supersede implementation that treats a What it does
Non-blocking notes
Non-blocking — please use your judgment. |
|
@Enough1122 Thanks for the review. One correction on the summary: the (Note: the review's line references had drifted — the On the three non-blocking notes — all as designed: the redirect/steer no-tool-cancellation tradeoff is documented in the PR body's design notes, the uncorrelated-edit drop policy is under "Open questions" in the PR body awaiting maintainer preference, and group sessions are keyed per-chat so cross-user supersede can't happen. |
|
Thanks for the correction — you're right. Re-reading at head The per-chat session keying and the documented redirect/steer and uncorrelated-drop tradeoffs are as you say — no action needed from me. |
|
@Enough1122 Appreciate the follow-up — glad the distinction is clear now. No further action needed on this thread. |
|
Ack — correction noted and accepted. Thanks for clarifying the |
Summary
Implements edited-message supersede for the SimpleX gateway adapter, closing #35535.
Today the SimpleX adapter handles only
newChatItems; achatItemUpdatedevent (the terminal-API notification emitted when a user edits a sent message) falls into the unhandled-event log, so the agent acts on the original — mistaken — text. This PR treats an inbound edit as "I meant this instead", correlated to the specific original message by platform message id:MessageEvent's text is replaced in place. FIFO order, identity, and metadata are preserved; the correction is silent (no busy-ack).TurnState.active_message_id) → the running agent is redirected with the corrected text, framed as[User edited their earlier message. Corrected message: "..."]. Falls back tosteer()when the agent doesn't support active-turn redirect, and to normal queueing when neither primitive is available. Neither primitive cancels in-flight tools — that is the best available behavior without mutating the transcript (see design notes).infolog rather than dispatched as a new message. Rationale in Open questions below.Changes
plugins/platforms/simplex/adapter.py_handle_chat_itemnow extractsmeta.itemIdand setsmessage_id=str(itemId)on every inboundMessageEvent(the prerequisite correlation key — previously never populated).chatItemUpdatedbranch routes the event'sAChatItemthrough the same parse path withis_edit=True, taggingmetadata={"is_edit": True}. The existing outgoing-direction guard means edits of the bot's own messages are ignored.gateway/session_state.pyTurnState.active_message_idrecords the message id of the event that started the turn; cleared by the existingTurnState.clear()at every turn boundary (no new lifecycle to maintain, no leak path).gateway/run.py_replace_queued_message(): first-match, in-place text replacement across both queue levels, modeled on the existing_clear_goal_pending_continuationspattern._handle_edit_supersede(): the correlation decision — queued replace → in-flight redirect/steer → drop+log. Fully synchronous (noawaitbetween the queue check, the in-flight check, and the decision), so there is no interleaving window with queue promotion. Inserted in_handle_messageafter authorization, ignored-channel, and plugin-hook guards; adapter producers other than SimpleX get the same behavior free by taggingmetadata["is_edit"]+message_id.Design notes
redirect/steer, mirroring existing mid-turn steering semantics.active_message_idstaysNone, so edits during a resumed turn fall to the uncorrelated policy rather than misfiring.Open questions
_handle_edit_supersede.Tests
tests/gateway/test_simplex_plugin.py: 7 new tests — direct/group edit correlation, outgoing-direction suppression,message_idpopulation on the normal path, image-content edits, missing-itemIdfallback.tests/gateway/test_edit_supersede.py(new): 15 tests — primary-slot replace, overflow-FIFO replace, in-flight redirect, steer fallback, sentinel-window handling, stale-correlation drop, uncorrelated drop, non-edit pass-through.tests/gateway/suite shows only pre-existing environment flakes present on cleanmain.Closes #35535