





















@@ -30,6 +30,7 @@ class TestSlackStreamNotDeliveredError extends Error {
3030let mockedNativeStreaming = false;
3131let mockedBlockStreamingEnabled: boolean | undefined = false;
3232let capturedReplyOptions: { disableBlockStreaming?: boolean } | undefined;
33+let mockedReplyThreadTs: string | undefined = THREAD_TS;
3334let mockedDispatchSequence: Array<{
3435kind: "tool" | "block" | "final";
3536payload: { text: string; isError?: boolean; mediaUrl?: string; mediaUrls?: string[] };
@@ -52,7 +53,15 @@ function createDraftStreamStub() {
5253};
5354}
545555-function createPreparedSlackMessage() {
56+function createPreparedSlackMessage(params?: {
57+message?: Partial<{
58+channel: string;
59+ts: string;
60+thread_ts?: string;
61+user: string;
62+}>;
63+replyToMode?: "off" | "first" | "all" | "batched";
64+}) {
5665return {
5766ctx: {
5867cfg: {},
@@ -77,6 +86,7 @@ function createPreparedSlackMessage() {
7786ts: "171234.111",
7887thread_ts: THREAD_TS,
7988user: "U123",
89+ ...params?.message,
8090},
8191route: {
8292agentId: "agent-1",
@@ -88,7 +98,7 @@ function createPreparedSlackMessage() {
8898ctxPayload: {
8999MessageThreadId: THREAD_TS,
90100},
91-replyToMode: "all",
101+replyToMode: params?.replyToMode ?? "all",
92102isDirectMessage: false,
93103isRoomish: false,
94104historyKey: "history-key",
@@ -248,13 +258,13 @@ vi.mock("../config.runtime.js", () => ({
248258249259vi.mock("../replies.js", () => ({
250260createSlackReplyDeliveryPlan: () => ({
251-peekThreadTs: () => THREAD_TS,
252-nextThreadTs: () => THREAD_TS,
261+peekThreadTs: () => mockedReplyThreadTs,
262+nextThreadTs: () => mockedReplyThreadTs,
253263markSent: () => {},
254264}),
255265deliverReplies: deliverRepliesMock,
256266readSlackReplyBlocks: () => undefined,
257-resolveSlackThreadTs: () => THREAD_TS,
267+resolveSlackThreadTs: () => mockedReplyThreadTs,
258268}));
259269260270vi.mock("../reply.runtime.js", () => ({
@@ -311,6 +321,7 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {
311321mockedNativeStreaming = false;
312322mockedBlockStreamingEnabled = false;
313323capturedReplyOptions = undefined;
324+mockedReplyThreadTs = THREAD_TS;
314325mockedDispatchSequence = [{ kind: "final", payload: { text: FINAL_REPLY_TEXT } }];
315326316327createSlackDraftStreamMock.mockReturnValue(createDraftStreamStub());
@@ -347,6 +358,28 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {
347358expect(capturedReplyOptions?.disableBlockStreaming).toBe(true);
348359});
349360361+it("starts native streams in the first-reply thread for top-level channel messages", async () => {
362+mockedNativeStreaming = true;
363+mockedReplyThreadTs = "171234.111";
364+mockedDispatchSequence = [{ kind: "final", payload: { text: FINAL_REPLY_TEXT } }];
365+366+await dispatchPreparedSlackMessage(
367+createPreparedSlackMessage({
368+message: { thread_ts: undefined },
369+replyToMode: "all",
370+}),
371+);
372+373+expect(startSlackStreamMock).toHaveBeenCalledWith(
374+expect.objectContaining({
375+channel: "C123",
376+threadTs: "171234.111",
377+text: FINAL_REPLY_TEXT,
378+}),
379+);
380+expect(deliverRepliesMock).not.toHaveBeenCalled();
381+});
382+350383it("keeps same-content tool and final payloads distinct after preview fallback", async () => {
351384mockedDispatchSequence = [
352385{ kind: "tool", payload: { text: SAME_TEXT } },
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。