From b2d0f88a45ab0ce6174c23a1ad840066b284f6c2 Mon Sep 17 00:00:00 2001 From: Rui Conti Date: Fri, 28 Aug 2026 11:13:51 -0400 Subject: [PATCH] fix(eve): preserve response-authorized follow-ups Signed-off-by: Rui Conti --- .changeset/responder-approval-followups.md | 5 ++++ .../approval-delivery-coordinator.test.ts | 25 ++++++++++++++++++- .../harness/approval-delivery-coordinator.ts | 17 ------------- 3 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 .changeset/responder-approval-followups.md diff --git a/.changeset/responder-approval-followups.md b/.changeset/responder-approval-followups.md new file mode 100644 index 0000000000..924bc69da1 --- /dev/null +++ b/.changeset/responder-approval-followups.md @@ -0,0 +1,5 @@ +--- +"eve": patch +--- + +Preserve normal follow-up messages while an approval with responder authorization remains pending. diff --git a/packages/eve/src/harness/approval-delivery-coordinator.test.ts b/packages/eve/src/harness/approval-delivery-coordinator.test.ts index 9e6a1e47f2..f00b13b15d 100644 --- a/packages/eve/src/harness/approval-delivery-coordinator.test.ts +++ b/packages/eve/src/harness/approval-delivery-coordinator.test.ts @@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest"; import type { SessionAuthContext } from "#channel/types.js"; import { settleDirectApprovalResponse } from "#harness/approval-candidates.js"; import { coordinateApprovalDelivery } from "#harness/approval-delivery-coordinator.js"; -import { appendPendingInputBatch } from "#harness/pending-input-batches.js"; +import { appendPendingInputBatch, getPendingInputBatches } from "#harness/pending-input-batches.js"; import type { HarnessSession } from "#harness/types.js"; import type { InputRequest } from "#shared/input.js"; @@ -82,4 +82,27 @@ describe("coordinateApprovalDelivery", () => { { optionId: "cancel", requestId: request.requestId }, ]); }); + + it("forwards an unrelated message while a response-authorized approval remains pending", async () => { + const messageAuth: SessionAuthContext = { ...responder, principalId: "user-2" }; + const result = await coordinateApprovalDelivery({ + now: 100, + session: parkedSession(), + stepInput: { + message: "What else can you help with?", + messageAuth, + }, + tools: new Map(), + }); + + expect(result.kind).toBe("continue"); + expect(result.feedback).toEqual([]); + expect(result.stepInput?.message).toBe("What else can you help with?"); + expect(result.stepInput?.messageAuth).toEqual(messageAuth); + expect( + getPendingInputBatches(result.session.state).flatMap((batch) => + batch.requests.map((pending) => pending.requestId), + ), + ).toEqual([request.requestId]); + }); }); diff --git a/packages/eve/src/harness/approval-delivery-coordinator.ts b/packages/eve/src/harness/approval-delivery-coordinator.ts index 9c37be3ea9..63f9c2c34a 100644 --- a/packages/eve/src/harness/approval-delivery-coordinator.ts +++ b/packages/eve/src/harness/approval-delivery-coordinator.ts @@ -31,8 +31,6 @@ import type { HarnessSession, HarnessToolMap, StepInput } from "#harness/types.j import type { InputRequest } from "#shared/input.js"; const UNAUTHENTICATED_APPROVAL_FEEDBACK = "Authentication is required to respond to this approval."; -const TEXT_APPROVAL_FEEDBACK = - "Please use the Approve or Cancel buttons to respond to this approval."; const APPROVAL_AUTHORIZER_TIMEOUT_MS = 10_000; const APPROVAL_CANDIDATE_TTL_MS = 10 * 60_000; @@ -142,21 +140,6 @@ export async function coordinateApprovalDelivery(input: { ); const allRequests = batches.flatMap((batch) => batch.requests); const requests = new Map(allRequests.map((request) => [request.requestId, request])); - if ( - stepInput?.message !== undefined && - (stepInput.attributedInputResponses?.length ?? 0) === 0 && - (stepInput.inputResponses?.length ?? 0) === 0 && - audit.activeCandidates.length === 0 && - authorizationRequiredRequestIds.size > 0 - ) { - return deliveryResult( - session, - { ...stepInput, message: undefined, messageAuth: undefined }, - "park", - [], - [TEXT_APPROVAL_FEEDBACK], - ); - } const challenges: AuthorizationChallenge[] = []; const feedback: string[] = []; const consumed = new Set();