



























@@ -1135,6 +1135,126 @@ describe("dispatchReplyFromConfig", () => {
11351135expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1);
11361136});
113711371138+it("records routed Slack thread id on dispatch-owned reply operations", async () => {
1139+setNoAbort();
1140+const cfg = emptyConfig;
1141+const dispatcher = createDispatcher();
1142+const ctx = buildTestCtx({
1143+Provider: "slack",
1144+Surface: "slack",
1145+OriginatingChannel: "slack",
1146+OriginatingTo: "user:U1",
1147+ChatType: "direct",
1148+SessionKey: "agent:main:slack:direct:U1",
1149+MessageThreadId: "501.000",
1150+});
1151+const replyResolver = vi.fn(async (_ctx: MsgContext, opts?: GetReplyOptions) => {
1152+const operation = (
1153+opts as { replyOperation?: { routeThreadId?: string | number } } | undefined
1154+)?.replyOperation;
1155+expect(operation?.routeThreadId).toBe("501.000");
1156+return { text: "hi" } satisfies ReplyPayload;
1157+});
1158+1159+await dispatchReplyFromConfig({ ctx, cfg, dispatcher, replyResolver });
1160+1161+expect(replyResolver).toHaveBeenCalledTimes(1);
1162+});
1163+1164+it("lets a different Slack DM routed thread reach reply resolution while another thread is active", async () => {
1165+setNoAbort();
1166+const sessionKey = "agent:main:slack:direct:U1";
1167+const activeOperation = createReplyOperation({
1168+ sessionKey,
1169+sessionId: "active-session",
1170+resetTriggered: false,
1171+routeThreadId: "500.000",
1172+});
1173+activeOperation.setPhase("running");
1174+const dispatcher = createDispatcher();
1175+const replyResolver = vi.fn(async () => ({ text: "thread B reply" }) satisfies ReplyPayload);
1176+1177+try {
1178+const resultPromise = dispatchReplyFromConfig({
1179+ctx: buildTestCtx({
1180+Provider: "slack",
1181+Surface: "slack",
1182+OriginatingChannel: "slack",
1183+OriginatingTo: "user:U1",
1184+ChatType: "direct",
1185+SessionKey: sessionKey,
1186+MessageThreadId: "501.000",
1187+BodyForAgent: "second top-level DM",
1188+}),
1189+cfg: emptyConfig,
1190+ dispatcher,
1191+ replyResolver,
1192+});
1193+1194+const result = await Promise.race([
1195+resultPromise,
1196+new Promise<"timed-out">((resolve) => setTimeout(() => resolve("timed-out"), 1_000)),
1197+]);
1198+if (result === "timed-out") {
1199+activeOperation.complete();
1200+await resultPromise;
1201+throw new Error("Slack routed thread was blocked by the active reply operation");
1202+}
1203+1204+expect(result).toMatchObject({
1205+queuedFinal: true,
1206+counts: { tool: 0, block: 0, final: 0 },
1207+});
1208+expect(replyResolver).toHaveBeenCalledTimes(1);
1209+expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1);
1210+} finally {
1211+activeOperation.complete();
1212+}
1213+});
1214+1215+it("keeps non-Slack routed direct turns behind the active reply operation", async () => {
1216+setNoAbort();
1217+const sessionKey = "agent:main:telegram:direct:1";
1218+const activeOperation = createReplyOperation({
1219+ sessionKey,
1220+sessionId: "active-session",
1221+resetTriggered: false,
1222+routeThreadId: "500.000",
1223+});
1224+activeOperation.setPhase("running");
1225+const dispatcher = createDispatcher();
1226+const replyResolver = vi.fn(async () => ({ text: "telegram reply" }) satisfies ReplyPayload);
1227+1228+const resultPromise = dispatchReplyFromConfig({
1229+ctx: buildTestCtx({
1230+Provider: "telegram",
1231+Surface: "telegram",
1232+OriginatingChannel: "telegram",
1233+OriginatingTo: "user:1",
1234+ChatType: "direct",
1235+SessionKey: sessionKey,
1236+MessageThreadId: "501.000",
1237+BodyForAgent: "second telegram direct turn",
1238+}),
1239+cfg: emptyConfig,
1240+ dispatcher,
1241+ replyResolver,
1242+});
1243+1244+try {
1245+const result = await Promise.race([
1246+resultPromise,
1247+new Promise<"blocked">((resolve) => setTimeout(() => resolve("blocked"), 1_000)),
1248+]);
1249+1250+expect(result).toBe("blocked");
1251+expect(replyResolver).not.toHaveBeenCalled();
1252+} finally {
1253+activeOperation.complete();
1254+await resultPromise;
1255+}
1256+});
1257+11381258it("routes when OriginatingChannel differs from Provider", async () => {
11391259setNoAbort();
11401260mocks.routeReply.mockClear();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。