fix(messaging): deliver delegated tool-only replies before mirroring (#60)
deliverDelegatedReplies used allowSilence and marked teamChatMirroredAt even when no Slack/Teams message was sent, leaving tool-only delegated runs silently dropped with no retry path. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
This commit is contained in:
parent
ec597a5c68
commit
492e0f0965
@ -41,6 +41,65 @@ describe("team chat bridge", () => {
|
||||
expect(teamChatResponseText([])).toBe("Bot completed the request without a written reply.");
|
||||
});
|
||||
|
||||
it("delivers delegated tool-only replies before marking them mirrored", async () => {
|
||||
const send = vi.fn(async () => ({ handle: "reply-delegated" }));
|
||||
const runUpdateMany = vi.fn(async () => ({ count: 1 }));
|
||||
const bridge = new TeamChatBridge({
|
||||
prisma: {
|
||||
run: {
|
||||
findMany: vi.fn(async () => [
|
||||
{
|
||||
id: "run-delegated",
|
||||
status: "completed",
|
||||
sourceMessageId: "msg-source",
|
||||
},
|
||||
]),
|
||||
findUnique: vi.fn(async () => null),
|
||||
updateMany: runUpdateMany,
|
||||
},
|
||||
message: {
|
||||
findUnique: vi.fn(async () => ({ replyTo: { runId: "parent-run-1" } })),
|
||||
findFirst: vi.fn(async () => ({
|
||||
blocks: [{ kind: "progress", text: "Searching files" }],
|
||||
})),
|
||||
},
|
||||
externalMessage: {
|
||||
findUnique: vi.fn(async () => ({
|
||||
replyThreadId: "100.1",
|
||||
externalConversation: { conversationId: "C-1" },
|
||||
})),
|
||||
},
|
||||
} as unknown as PrismaClient,
|
||||
events: { sendUserMessage: vi.fn() },
|
||||
jobs: { enqueue: vi.fn() },
|
||||
send,
|
||||
providerId: "slack",
|
||||
botId: "bot-1",
|
||||
});
|
||||
(
|
||||
bridge as unknown as {
|
||||
target: { id: string; spaceId: string; userId: string; name: string };
|
||||
}
|
||||
).target = { id: "bot-1", spaceId: "space-1", userId: "owner-1", name: "Analyst" };
|
||||
|
||||
await (
|
||||
bridge as unknown as {
|
||||
deliverDelegatedReplies: (target: { id: string; name: string }) => Promise<void>;
|
||||
}
|
||||
).deliverDelegatedReplies({ id: "bot-1", name: "Analyst" });
|
||||
|
||||
expect(send).toHaveBeenCalledWith({
|
||||
conversationId: "C-1",
|
||||
replyThreadId: "100.1",
|
||||
content: "Analyst completed the request without a written reply.",
|
||||
idempotencyKey: "team-chat-run:run-delegated",
|
||||
});
|
||||
expect(runUpdateMany).toHaveBeenCalledWith({
|
||||
where: { id: "run-delegated", teamChatMirroredAt: null },
|
||||
data: { teamChatMirroredAt: expect.any(Date) },
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps deferred messages outside reconciliation until routine routing resolves them", async () => {
|
||||
const upsert = vi.fn(async ({ create }: { create: Record<string, unknown> }) => ({
|
||||
id: "external-deferred",
|
||||
|
||||
@ -710,15 +710,14 @@ export class TeamChatBridge {
|
||||
const content =
|
||||
run.status === "failed"
|
||||
? `${target.name} could not complete the delegated request. Open Rakazo for details.`
|
||||
: teamChatResponseText(blocks, target.name, true);
|
||||
if (content) {
|
||||
await this.deps.send({
|
||||
conversationId: origin.externalConversation.conversationId,
|
||||
replyThreadId: origin.replyThreadId,
|
||||
content,
|
||||
idempotencyKey: `team-chat-run:${run.id}`,
|
||||
});
|
||||
}
|
||||
: teamChatResponseText(blocks, target.name);
|
||||
if (!content) continue;
|
||||
await this.deps.send({
|
||||
conversationId: origin.externalConversation.conversationId,
|
||||
replyThreadId: origin.replyThreadId,
|
||||
content,
|
||||
idempotencyKey: `team-chat-run:${run.id}`,
|
||||
});
|
||||
await this.markTeamChatMirrored(run.id);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user