fix: avoid media completion fallback while announce pending

This commit is contained in:
Peter Steinberger
2026-05-05 09:06:45 +01:00
parent fd86ab2e50
commit b32d4c5255
2 changed files with 62 additions and 1 deletions

View File

@@ -1271,6 +1271,48 @@ describe("deliverSubagentAnnouncement completion delivery", () => {
);
});
it("does not fallback while generated media announce-agent run is still pending", async () => {
const callGateway = createGatewayMock({
runId: "video_generate:task-123:ok",
status: "accepted",
acceptedAt: Date.now(),
});
const sendMessage = createSendMessageMock();
const result = await deliverSlackChannelAnnouncement({
callGateway,
sendMessage,
sessionId: "requester-session-channel",
isActive: false,
expectsCompletionMessage: true,
directIdempotencyKey: "announce-channel-media-pending",
sourceTool: "video_generate",
internalEvents: [
{
type: "task_completion",
source: "video_generation",
childSessionKey: "video_generate:task-123",
childSessionId: "task-123",
announceType: "video generation task",
taskLabel: "lobster trailer",
status: "ok",
statusLabel: "completed successfully",
result: "Generated 1 video.\nMEDIA:/tmp/lobster-trailer.mp4",
mediaUrls: ["/tmp/lobster-trailer.mp4"],
replyInstruction: "Deliver the generated video through the message tool.",
},
],
});
expect(result).toEqual(
expect.objectContaining({
delivered: true,
path: "direct",
}),
);
expect(callGateway).toHaveBeenCalled();
expect(sendMessage).not.toHaveBeenCalled();
});
it("uses a direct channel fallback when announce-agent returns no visible output", async () => {
const callGateway = createGatewayMock({
result: {

View File

@@ -689,6 +689,14 @@ function hasGatewayAgentMessagingToolDelivery(response: unknown): boolean {
return Boolean(result && hasMessagingToolDeliveryEvidence(result));
}
function isGatewayAgentRunPending(response: unknown): boolean {
if (!response || typeof response !== "object") {
return false;
}
const status = (response as { status?: unknown }).status;
return status === "accepted" || status === "in_flight" || status === "started";
}
function inferCompletionChatType(params: {
requesterSessionKey: string;
targetRequesterSessionKey: string;
@@ -1047,7 +1055,11 @@ async function sendSubagentAnnounceDirectly(params: {
throw err;
}
if (shouldSendCompletionFallback(directAnnounceResponse, completionFallbackText)) {
const directAnnounceStillPending = isGatewayAgentRunPending(directAnnounceResponse);
if (
!directAnnounceStillPending &&
shouldSendCompletionFallback(directAnnounceResponse, completionFallbackText)
) {
const didFallback = await sendCompletionFallback({
cfg,
channel: deliveryTarget.channel,
@@ -1068,6 +1080,13 @@ async function sendSubagentAnnounceDirectly(params: {
}
}
if (directAnnounceStillPending) {
return {
delivered: true,
path: "direct",
};
}
if (
requiresMessageToolDelivery &&
!hasGatewayAgentMessagingToolDelivery(directAnnounceResponse)