






















@@ -5,27 +5,45 @@ import { registerSlackAssistantEvents } from "./assistant.js";
5566type Handler = (args: { event: Record<string, unknown>; body: unknown }) => Promise<void>;
778-function createHarness(overrides?: { shouldDrop?: boolean }) {
8+function createHarness(overrides?: {
9+shouldDrop?: boolean;
10+existingContext?: ReturnType<SlackMonitorContext["getSlackAssistantThreadContext"]>;
11+replies?: ReturnType<typeof vi.fn>;
12+update?: ReturnType<typeof vi.fn>;
13+}) {
914const handlers: Record<string, Handler> = {};
15+const getSlackAssistantThreadContext = vi.fn(() => overrides?.existingContext);
1016const saveSlackAssistantThreadContext = vi.fn();
1117const setSlackAssistantSuggestedPrompts = vi.fn(async () => true);
18+const replies = overrides?.replies ?? vi.fn(async () => ({ messages: [] }));
19+const update = overrides?.update ?? vi.fn(async () => ({}));
1220const trackEvent = vi.fn();
1321const ctx = {
1422app: {
23+client: {
24+conversations: { replies },
25+chat: { update },
26+},
1527event: (name: string, handler: Handler) => {
1628handlers[name] = handler;
1729},
1830} as unknown as App,
1931runtime: { error: vi.fn() },
32+botToken: "xoxb-test",
33+botUserId: "B1",
2034shouldDropMismatchedSlackEvent: () => overrides?.shouldDrop === true,
35+ getSlackAssistantThreadContext,
2136 saveSlackAssistantThreadContext,
2237 setSlackAssistantSuggestedPrompts,
2338} as unknown as SlackMonitorContext;
2439registerSlackAssistantEvents({ ctx, trackEvent });
2540return {
2641 handlers,
42+ getSlackAssistantThreadContext,
2743 saveSlackAssistantThreadContext,
2844 setSlackAssistantSuggestedPrompts,
45+ replies,
46+ update,
2947 trackEvent,
3048};
3149}
@@ -112,6 +130,51 @@ describe("registerSlackAssistantEvents", () => {
112130expect(harness.setSlackAssistantSuggestedPrompts).not.toHaveBeenCalled();
113131});
114132133+it("persists changed assistant thread context onto the first bot message", async () => {
134+const replies = vi.fn(async () => ({
135+messages: [
136+{ user: "U123", ts: "1729999327.200000", text: "user asks" },
137+{
138+user: "B1",
139+ts: "1729999327.300000",
140+text: "assistant reply",
141+blocks: [{ type: "section", text: { type: "mrkdwn", text: "assistant reply" } }],
142+},
143+],
144+}));
145+const update = vi.fn(async () => ({}));
146+const harness = createHarness({ replies, update });
147+148+await harness.handlers.assistant_thread_context_changed?.({
149+event: makeThreadEvent("assistant_thread_context_changed"),
150+body: {},
151+});
152+153+expect(replies).toHaveBeenCalledWith({
154+token: "xoxb-test",
155+channel: "D123",
156+ts: "1729999327.187299",
157+oldest: "1729999327.187299",
158+include_all_metadata: true,
159+limit: 4,
160+});
161+expect(update).toHaveBeenCalledWith({
162+token: "xoxb-test",
163+channel: "D123",
164+ts: "1729999327.300000",
165+text: "assistant reply",
166+blocks: [{ type: "section", text: { type: "mrkdwn", text: "assistant reply" } }],
167+metadata: {
168+event_type: "assistant_thread_context",
169+event_payload: {
170+channel_id: "C456",
171+team_id: "T789",
172+enterprise_id: "E123",
173+},
174+},
175+});
176+});
177+115178it("accepts Slack assistant context when it is sent beside the thread", async () => {
116179const harness = createHarness();
117180@@ -130,6 +193,77 @@ describe("registerSlackAssistantEvents", () => {
130193});
131194});
132195196+it("merges partial assistant thread context per field", async () => {
197+const harness = createHarness();
198+199+await harness.handlers.assistant_thread_context_changed?.({
200+event: {
201+type: "assistant_thread_context_changed",
202+assistant_thread: {
203+user_id: "U123",
204+channel_id: "D123",
205+thread_ts: "1729999327.187299",
206+context: {
207+team_id: "T_THREAD",
208+},
209+},
210+context: {
211+channel_id: "C456",
212+team_id: "T_EVENT",
213+enterprise_id: "E123",
214+},
215+},
216+body: {},
217+});
218+219+expect(harness.saveSlackAssistantThreadContext).toHaveBeenCalledWith({
220+assistantChannelId: "D123",
221+threadTs: "1729999327.187299",
222+userId: "U123",
223+channelId: "C456",
224+teamId: "T_THREAD",
225+enterpriseId: "E123",
226+});
227+});
228+229+it("preserves cached assistant thread context when updates omit optional fields", async () => {
230+const harness = createHarness({
231+existingContext: {
232+assistantChannelId: "D123",
233+threadTs: "1729999327.187299",
234+userId: "UOLD",
235+channelId: "COLD",
236+teamId: "TOLD",
237+enterpriseId: "EOLD",
238+updatedAt: 1,
239+},
240+});
241+242+await harness.handlers.assistant_thread_context_changed?.({
243+event: {
244+type: "assistant_thread_context_changed",
245+assistant_thread: {
246+channel_id: "D123",
247+thread_ts: "1729999327.187299",
248+},
249+},
250+body: {},
251+});
252+253+expect(harness.getSlackAssistantThreadContext).toHaveBeenCalledWith(
254+"D123",
255+"1729999327.187299",
256+);
257+expect(harness.saveSlackAssistantThreadContext).toHaveBeenCalledWith({
258+assistantChannelId: "D123",
259+threadTs: "1729999327.187299",
260+userId: "UOLD",
261+channelId: "COLD",
262+teamId: "TOLD",
263+enterpriseId: "EOLD",
264+});
265+});
266+133267it("drops mismatched workspace events before touching assistant state", async () => {
134268const harness = createHarness({ shouldDrop: true });
135269此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。