fix(ui): deny open permission prompts on send (#2445)

Sending a message while a permission prompt is open now denies every
pending permission in the session subtree (optimistically, then formally
via permission.reply reject) and queues the message for next-turn
delivery, mirroring the question-dismiss path from #1740.

- Add dismissOpenPermissionsForSession plus isPermissionRequestNotFoundError
  and removePermissionRequestFromChildStores helpers to session-actions
- Extend dismissPermission with not-found cleanup, parallel to rejectQuestion
- Wire handleSubmit to deny permissions and dismiss questions together,
  queueing once if either prompt type was open
- Add unit tests mirroring the dismissOpenQuestionsForSession suite

Closes #1958
This commit is contained in:
Tom Rochette
2026-07-28 17:36:00 +03:00
committed by GitHub
parent 92abdefea8
commit d50cb5becc
3 changed files with 303 additions and 9 deletions
+14 -2
View File
@@ -978,8 +978,20 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
}
if (currentSessionId && !queuedOnly) {
const dismissedQuestions = await sessionActions.dismissOpenQuestionsForSession(currentSessionId);
if (dismissedQuestions) {
// Sending is authoritative for blocking prompts: deny pending
// permissions and dismiss open questions for the session subtree,
// then queue the message once if either was open. The deny/clear
// vanishes the card instantly (optimistic); rejecting unblocks the
// agent's tool but does NOT end its turn, so a direct send would
// race with the still-active run and be silently discarded by the
// OpenCode runner. Instead we queue; the queued-message auto-send
// hook delivers it as the next turn once the rejected turn winds
// down and the session returns to idle (parity with #1740).
const [deniedPermissions, dismissedQuestions] = await Promise.all([
sessionActions.dismissOpenPermissionsForSession(currentSessionId),
sessionActions.dismissOpenQuestionsForSession(currentSessionId),
]);
if (deniedPermissions || dismissedQuestions) {
handleQueueMessage();
return;
}