@kodelyth/msteams 2026.5.39 → 2026.5.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/api.ts +3 -0
  2. package/channel-config-api.ts +1 -0
  3. package/channel-plugin-api.ts +2 -0
  4. package/config-api.ts +4 -0
  5. package/contract-api.ts +4 -0
  6. package/dist/api.js +3 -0
  7. package/dist/channel-BvTXHuGs.js +1161 -0
  8. package/dist/channel-config-api.js +2 -0
  9. package/dist/channel-plugin-api.js +2 -0
  10. package/dist/channel.runtime-NssGKZm5.js +650 -0
  11. package/dist/config-schema-Btk-XCOd.js +43 -0
  12. package/dist/contract-api.js +2 -0
  13. package/dist/graph-users-D-gKCguI.js +1411 -0
  14. package/dist/index.js +22 -0
  15. package/dist/oauth-BUxlphX3.js +114 -0
  16. package/dist/oauth.token-ebId9946.js +116 -0
  17. package/dist/probe-Cj2KsAGF.js +2190 -0
  18. package/dist/runtime-api-BL4DOWXD.js +28 -0
  19. package/dist/runtime-api.js +2 -0
  20. package/dist/secret-contract-Bo7kdUrT.js +35 -0
  21. package/dist/secret-contract-api.js +2 -0
  22. package/dist/setup-entry.js +15 -0
  23. package/dist/setup-plugin-api.js +64 -0
  24. package/dist/setup-surface-COTQDcTQ.js +531 -0
  25. package/dist/src-tvpsGYPV.js +4226 -0
  26. package/dist/test-api.js +2 -0
  27. package/index.ts +20 -0
  28. package/klaw.plugin.json +2 -726
  29. package/package.json +4 -4
  30. package/runtime-api.ts +66 -0
  31. package/secret-contract-api.ts +5 -0
  32. package/setup-entry.ts +13 -0
  33. package/setup-plugin-api.ts +3 -0
  34. package/src/ai-entity.ts +7 -0
  35. package/src/approval-auth.ts +44 -0
  36. package/src/attachments/bot-framework.test.ts +506 -0
  37. package/src/attachments/bot-framework.ts +348 -0
  38. package/src/attachments/download.ts +328 -0
  39. package/src/attachments/graph.test.ts +441 -0
  40. package/src/attachments/graph.ts +489 -0
  41. package/src/attachments/html.ts +122 -0
  42. package/src/attachments/payload.ts +14 -0
  43. package/src/attachments/remote-media.test.ts +187 -0
  44. package/src/attachments/remote-media.ts +86 -0
  45. package/src/attachments/shared.test.ts +547 -0
  46. package/src/attachments/shared.ts +655 -0
  47. package/src/attachments/types.ts +47 -0
  48. package/src/attachments.graph.test.ts +414 -0
  49. package/src/attachments.helpers.test.ts +245 -0
  50. package/src/attachments.test-helpers.ts +17 -0
  51. package/src/attachments.test.ts +754 -0
  52. package/src/attachments.ts +18 -0
  53. package/src/block-streaming-config.test.ts +61 -0
  54. package/src/channel-api.ts +1 -0
  55. package/src/channel.actions.test.ts +797 -0
  56. package/src/channel.directory.test.ts +176 -0
  57. package/src/channel.message-adapter.test.ts +227 -0
  58. package/src/channel.runtime.ts +56 -0
  59. package/src/channel.setup.ts +77 -0
  60. package/src/channel.test.ts +136 -0
  61. package/src/channel.ts +1176 -0
  62. package/src/config-schema.ts +6 -0
  63. package/src/config-ui-hints.ts +40 -0
  64. package/src/conversation-store-fs.test.ts +81 -0
  65. package/src/conversation-store-fs.ts +149 -0
  66. package/src/conversation-store-helpers.test.ts +202 -0
  67. package/src/conversation-store-helpers.ts +105 -0
  68. package/src/conversation-store-memory.ts +51 -0
  69. package/src/conversation-store.shared.test.ts +260 -0
  70. package/src/conversation-store.ts +71 -0
  71. package/src/directory-live.test.ts +156 -0
  72. package/src/directory-live.ts +111 -0
  73. package/src/doctor.ts +27 -0
  74. package/src/errors.test.ts +154 -0
  75. package/src/errors.ts +270 -0
  76. package/src/feedback-reflection-prompt.ts +117 -0
  77. package/src/feedback-reflection-store.ts +113 -0
  78. package/src/feedback-reflection.test.ts +237 -0
  79. package/src/feedback-reflection.ts +268 -0
  80. package/src/file-consent-helpers.test.ts +328 -0
  81. package/src/file-consent-helpers.ts +115 -0
  82. package/src/file-consent-invoke.ts +150 -0
  83. package/src/file-consent.test.ts +378 -0
  84. package/src/file-consent.ts +223 -0
  85. package/src/graph-chat.ts +36 -0
  86. package/src/graph-group-management.test.ts +332 -0
  87. package/src/graph-group-management.ts +168 -0
  88. package/src/graph-members.test.ts +89 -0
  89. package/src/graph-members.ts +48 -0
  90. package/src/graph-messages.actions.test.ts +253 -0
  91. package/src/graph-messages.read.test.ts +391 -0
  92. package/src/graph-messages.search.test.ts +227 -0
  93. package/src/graph-messages.test-helpers.ts +50 -0
  94. package/src/graph-messages.ts +534 -0
  95. package/src/graph-teams.test.ts +222 -0
  96. package/src/graph-teams.ts +114 -0
  97. package/src/graph-thread.test.ts +252 -0
  98. package/src/graph-thread.ts +146 -0
  99. package/src/graph-upload.test.ts +253 -0
  100. package/src/graph-upload.ts +531 -0
  101. package/src/graph-users.ts +29 -0
  102. package/src/graph.test.ts +540 -0
  103. package/src/graph.ts +308 -0
  104. package/src/inbound.test.ts +221 -0
  105. package/src/inbound.ts +148 -0
  106. package/src/index.ts +4 -0
  107. package/src/media-helpers.test.ts +220 -0
  108. package/src/media-helpers.ts +105 -0
  109. package/src/mentions.test.ts +254 -0
  110. package/src/mentions.ts +114 -0
  111. package/src/messenger.test.ts +961 -0
  112. package/src/messenger.ts +608 -0
  113. package/src/monitor-handler/access.ts +136 -0
  114. package/src/monitor-handler/inbound-media.test.ts +314 -0
  115. package/src/monitor-handler/inbound-media.ts +180 -0
  116. package/src/monitor-handler/message-handler-mock-support.test-support.ts +28 -0
  117. package/src/monitor-handler/message-handler.authz.test.ts +739 -0
  118. package/src/monitor-handler/message-handler.dm-media.test.ts +54 -0
  119. package/src/monitor-handler/message-handler.test-support.ts +99 -0
  120. package/src/monitor-handler/message-handler.thread-parent.test.ts +225 -0
  121. package/src/monitor-handler/message-handler.thread-session.test.ts +132 -0
  122. package/src/monitor-handler/message-handler.ts +1003 -0
  123. package/src/monitor-handler/reaction-handler.test.ts +325 -0
  124. package/src/monitor-handler/reaction-handler.ts +122 -0
  125. package/src/monitor-handler/thread-session.ts +30 -0
  126. package/src/monitor-handler.adaptive-card.test.ts +158 -0
  127. package/src/monitor-handler.feedback-authz.test.ts +357 -0
  128. package/src/monitor-handler.file-consent.test.ts +443 -0
  129. package/src/monitor-handler.sso.test.ts +576 -0
  130. package/src/monitor-handler.test-helpers.ts +181 -0
  131. package/src/monitor-handler.ts +538 -0
  132. package/src/monitor-handler.types.ts +27 -0
  133. package/src/monitor-types.ts +6 -0
  134. package/src/monitor.lifecycle.test.ts +457 -0
  135. package/src/monitor.test.ts +119 -0
  136. package/src/monitor.ts +476 -0
  137. package/src/oauth.flow.ts +77 -0
  138. package/src/oauth.shared.ts +37 -0
  139. package/src/oauth.test.ts +350 -0
  140. package/src/oauth.token.ts +162 -0
  141. package/src/oauth.ts +130 -0
  142. package/src/outbound.test.ts +400 -0
  143. package/src/outbound.ts +198 -0
  144. package/src/pending-uploads-fs.test.ts +261 -0
  145. package/src/pending-uploads-fs.ts +235 -0
  146. package/src/pending-uploads.test.ts +186 -0
  147. package/src/pending-uploads.ts +121 -0
  148. package/src/policy.test.ts +156 -0
  149. package/src/policy.ts +245 -0
  150. package/src/polls-store-memory.ts +32 -0
  151. package/src/polls.test.ts +169 -0
  152. package/src/polls.ts +312 -0
  153. package/src/presentation.ts +93 -0
  154. package/src/probe.test.ts +79 -0
  155. package/src/probe.ts +132 -0
  156. package/src/reply-dispatcher.test.ts +543 -0
  157. package/src/reply-dispatcher.ts +523 -0
  158. package/src/reply-stream-controller.test.ts +424 -0
  159. package/src/reply-stream-controller.ts +334 -0
  160. package/src/resolve-allowlist.test.ts +253 -0
  161. package/src/resolve-allowlist.ts +309 -0
  162. package/src/revoked-context.ts +17 -0
  163. package/src/runtime.ts +12 -0
  164. package/src/sdk-types.ts +59 -0
  165. package/src/sdk.test.ts +727 -0
  166. package/src/sdk.ts +916 -0
  167. package/src/secret-contract.ts +49 -0
  168. package/src/secret-input.ts +7 -0
  169. package/src/send-context.test.ts +93 -0
  170. package/src/send-context.ts +269 -0
  171. package/src/send.test.ts +588 -0
  172. package/src/send.ts +697 -0
  173. package/src/sent-message-cache.test.ts +106 -0
  174. package/src/sent-message-cache.ts +174 -0
  175. package/src/session-route.ts +40 -0
  176. package/src/setup-core.ts +162 -0
  177. package/src/setup-surface.test.ts +175 -0
  178. package/src/setup-surface.ts +319 -0
  179. package/src/sso-token-store.test.ts +74 -0
  180. package/src/sso-token-store.ts +166 -0
  181. package/src/sso.ts +300 -0
  182. package/src/storage.ts +25 -0
  183. package/src/store-fs.ts +42 -0
  184. package/src/streaming-message.test.ts +323 -0
  185. package/src/streaming-message.ts +327 -0
  186. package/src/test-runtime.ts +16 -0
  187. package/src/thread-parent-context.test.ts +224 -0
  188. package/src/thread-parent-context.ts +159 -0
  189. package/src/token-response.ts +11 -0
  190. package/src/token.test.ts +268 -0
  191. package/src/token.ts +194 -0
  192. package/src/user-agent.test.ts +121 -0
  193. package/src/user-agent.ts +53 -0
  194. package/src/webhook-timeouts.ts +27 -0
  195. package/src/welcome-card.test.ts +104 -0
  196. package/src/welcome-card.ts +57 -0
  197. package/test-api.ts +1 -0
  198. package/tsconfig.json +16 -0
  199. package/api.js +0 -7
  200. package/channel-config-api.js +0 -7
  201. package/channel-plugin-api.js +0 -7
  202. package/contract-api.js +0 -7
  203. package/index.js +0 -7
  204. package/runtime-api.js +0 -7
  205. package/secret-contract-api.js +0 -7
  206. package/setup-entry.js +0 -7
  207. package/setup-plugin-api.js +0 -7
  208. package/test-api.js +0 -7
@@ -0,0 +1,357 @@
1
+ import { access, mkdtemp, readFile, rm } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import path from "node:path";
4
+ import { beforeEach, describe, expect, it, vi } from "vitest";
5
+ import type { KlawConfig, PluginRuntime, RuntimeEnv } from "../runtime-api.js";
6
+ import {
7
+ type MSTeamsActivityHandler,
8
+ type MSTeamsMessageHandlerDeps,
9
+ registerMSTeamsHandlers,
10
+ } from "./monitor-handler.js";
11
+ import {
12
+ createActivityHandler,
13
+ createMSTeamsMessageHandlerDeps,
14
+ } from "./monitor-handler.test-helpers.js";
15
+ import { setMSTeamsRuntime } from "./runtime.js";
16
+ import type { MSTeamsTurnContext } from "./sdk-types.js";
17
+
18
+ const feedbackReflectionMockState = vi.hoisted(() => ({
19
+ runFeedbackReflection: vi.fn(),
20
+ }));
21
+
22
+ vi.mock("./monitor-handler/message-handler.js", () => ({
23
+ createMSTeamsMessageHandler: () => async () => {},
24
+ }));
25
+
26
+ vi.mock("./monitor-handler/reaction-handler.js", () => ({
27
+ createMSTeamsReactionHandler: () => async () => {},
28
+ }));
29
+
30
+ vi.mock("./feedback-reflection.js", async () => {
31
+ const actual = await vi.importActual<typeof import("./feedback-reflection.js")>(
32
+ "./feedback-reflection.js",
33
+ );
34
+ return {
35
+ ...actual,
36
+ runFeedbackReflection: feedbackReflectionMockState.runFeedbackReflection,
37
+ };
38
+ });
39
+
40
+ function createRuntimeStub(readAllowFromStore: ReturnType<typeof vi.fn>): PluginRuntime {
41
+ return {
42
+ logging: {
43
+ shouldLogVerbose: () => false,
44
+ },
45
+ channel: {
46
+ debounce: {
47
+ resolveInboundDebounceMs: () => 0,
48
+ createInboundDebouncer: () => ({
49
+ enqueue: async () => {},
50
+ flushKey: async () => {},
51
+ cancelKey: () => false,
52
+ }),
53
+ },
54
+ pairing: {
55
+ readAllowFromStore,
56
+ upsertPairingRequest: vi.fn(async () => null),
57
+ },
58
+ routing: {
59
+ resolveAgentRoute: ({ peer }: { peer: { kind: string; id: string } }) => ({
60
+ sessionKey: `msteams:${peer.kind}:${peer.id}`,
61
+ agentId: "default",
62
+ }),
63
+ },
64
+ session: {
65
+ resolveStorePath: (storePath?: string) => storePath ?? tmpdir(),
66
+ },
67
+ },
68
+ } as unknown as PluginRuntime;
69
+ }
70
+
71
+ function createDeps(params: {
72
+ cfg: KlawConfig;
73
+ readAllowFromStore?: ReturnType<typeof vi.fn>;
74
+ }): MSTeamsMessageHandlerDeps {
75
+ const readAllowFromStore = params.readAllowFromStore ?? vi.fn(async () => []);
76
+ setMSTeamsRuntime(createRuntimeStub(readAllowFromStore));
77
+ return createMSTeamsMessageHandlerDeps({
78
+ cfg: params.cfg,
79
+ runtime: { error: vi.fn() } as unknown as RuntimeEnv,
80
+ });
81
+ }
82
+
83
+ function createFeedbackInvokeContext(params: {
84
+ reaction: "like" | "dislike";
85
+ conversationId: string;
86
+ conversationType: string;
87
+ senderId: string;
88
+ senderName?: string;
89
+ teamId?: string;
90
+ channelName?: string;
91
+ comment?: string;
92
+ }): MSTeamsTurnContext {
93
+ return {
94
+ activity: {
95
+ id: `invoke-${params.reaction}`,
96
+ type: "invoke",
97
+ name: "message/submitAction",
98
+ channelId: "msteams",
99
+ serviceUrl: "https://service.example.test",
100
+ from: {
101
+ id: `${params.senderId}-botframework`,
102
+ aadObjectId: params.senderId,
103
+ name: params.senderName ?? "Sender",
104
+ },
105
+ recipient: {
106
+ id: "bot-id",
107
+ name: "Bot",
108
+ },
109
+ conversation: {
110
+ id: params.conversationId,
111
+ conversationType: params.conversationType,
112
+ tenantId: params.teamId ? "tenant-1" : undefined,
113
+ },
114
+ channelData: params.teamId
115
+ ? {
116
+ team: { id: params.teamId, name: "Team 1" },
117
+ channel: params.channelName ? { name: params.channelName } : undefined,
118
+ }
119
+ : {},
120
+ value: {
121
+ actionName: "feedback",
122
+ actionValue: {
123
+ reaction: params.reaction,
124
+ feedback: JSON.stringify({ feedbackText: params.comment ?? "feedback text" }),
125
+ },
126
+ replyToId: "bot-msg-1",
127
+ },
128
+ },
129
+ sendActivity: vi.fn(async () => ({ id: "ignored" })),
130
+ sendActivities: async () => [],
131
+ } as unknown as MSTeamsTurnContext;
132
+ }
133
+
134
+ async function expectFileMissing(filePath: string) {
135
+ let error: unknown;
136
+ try {
137
+ await access(filePath);
138
+ } catch (caught) {
139
+ error = caught;
140
+ }
141
+ expect(error).toBeInstanceOf(Error);
142
+ expect((error as NodeJS.ErrnoException).code).toBe("ENOENT");
143
+ }
144
+
145
+ async function withFeedbackHandler(params: {
146
+ cfg: KlawConfig;
147
+ context: Parameters<typeof createFeedbackInvokeContext>[0];
148
+ assertResult: (args: { tmpDir: string; originalRun: ReturnType<typeof vi.fn> }) => Promise<void>;
149
+ }) {
150
+ const tmpDir = await mkdtemp(path.join(tmpdir(), "klaw-msteams-feedback-"));
151
+ try {
152
+ const originalRun = vi.fn(async () => undefined);
153
+ const handler = registerMSTeamsHandlers(
154
+ createActivityHandler(originalRun),
155
+ createDeps({
156
+ cfg: {
157
+ ...params.cfg,
158
+ session: { store: tmpDir },
159
+ },
160
+ }),
161
+ ) as MSTeamsActivityHandler & {
162
+ run: NonNullable<MSTeamsActivityHandler["run"]>;
163
+ };
164
+
165
+ await handler.run(createFeedbackInvokeContext(params.context));
166
+ await params.assertResult({ tmpDir, originalRun });
167
+ } finally {
168
+ await rm(tmpDir, { recursive: true, force: true });
169
+ }
170
+ }
171
+
172
+ describe("msteams feedback invoke authz", () => {
173
+ beforeEach(() => {
174
+ feedbackReflectionMockState.runFeedbackReflection.mockReset();
175
+ feedbackReflectionMockState.runFeedbackReflection.mockResolvedValue(undefined);
176
+ });
177
+
178
+ it("records feedback for an allowlisted DM sender", async () => {
179
+ await withFeedbackHandler({
180
+ cfg: {
181
+ channels: {
182
+ msteams: {
183
+ dmPolicy: "allowlist",
184
+ allowFrom: ["owner-aad"],
185
+ },
186
+ },
187
+ } as KlawConfig,
188
+ context: {
189
+ reaction: "like",
190
+ conversationId: "a:personal-chat;messageid=bot-msg-1",
191
+ conversationType: "personal",
192
+ senderId: "owner-aad",
193
+ senderName: "Owner",
194
+ comment: "allowed feedback",
195
+ },
196
+ assertResult: async ({ tmpDir, originalRun }) => {
197
+ const transcript = await readFile(
198
+ path.join(tmpDir, "msteams_direct_owner-aad.jsonl"),
199
+ "utf-8",
200
+ );
201
+ const event = JSON.parse(transcript.trim()) as Record<string, unknown>;
202
+ expect(Object.keys(event).toSorted()).toEqual([
203
+ "agentId",
204
+ "comment",
205
+ "conversationId",
206
+ "event",
207
+ "messageId",
208
+ "sessionKey",
209
+ "ts",
210
+ "type",
211
+ "value",
212
+ ]);
213
+ expect(typeof event.ts).toBe("number");
214
+ expect({ ...event, ts: 0 }).toEqual({
215
+ type: "custom",
216
+ event: "feedback",
217
+ ts: 0,
218
+ messageId: "bot-msg-1",
219
+ value: "positive",
220
+ comment: "allowed feedback",
221
+ sessionKey: "msteams:direct:owner-aad",
222
+ agentId: "default",
223
+ conversationId: "a:personal-chat",
224
+ });
225
+ expect(originalRun).not.toHaveBeenCalled();
226
+ },
227
+ });
228
+ });
229
+
230
+ it("keeps DM feedback allowed when team route allowlists exist", async () => {
231
+ await withFeedbackHandler({
232
+ cfg: {
233
+ channels: {
234
+ msteams: {
235
+ dmPolicy: "allowlist",
236
+ allowFrom: ["owner-aad"],
237
+ teams: {
238
+ team123: {
239
+ channels: {
240
+ "19:group@thread.tacv2": { requireMention: false },
241
+ },
242
+ },
243
+ },
244
+ },
245
+ },
246
+ } as KlawConfig,
247
+ context: {
248
+ reaction: "like",
249
+ conversationId: "a:personal-chat;messageid=bot-msg-1",
250
+ conversationType: "personal",
251
+ senderId: "owner-aad",
252
+ senderName: "Owner",
253
+ comment: "allowed dm feedback",
254
+ },
255
+ assertResult: async ({ tmpDir, originalRun }) => {
256
+ const transcript = await readFile(
257
+ path.join(tmpDir, "msteams_direct_owner-aad.jsonl"),
258
+ "utf-8",
259
+ );
260
+ const event = JSON.parse(transcript.trim()) as Record<string, unknown>;
261
+ expect(Object.keys(event).toSorted()).toEqual([
262
+ "agentId",
263
+ "comment",
264
+ "conversationId",
265
+ "event",
266
+ "messageId",
267
+ "sessionKey",
268
+ "ts",
269
+ "type",
270
+ "value",
271
+ ]);
272
+ expect(typeof event.ts).toBe("number");
273
+ expect({ ...event, ts: 0 }).toEqual({
274
+ type: "custom",
275
+ event: "feedback",
276
+ ts: 0,
277
+ messageId: "bot-msg-1",
278
+ value: "positive",
279
+ comment: "allowed dm feedback",
280
+ sessionKey: "msteams:direct:owner-aad",
281
+ agentId: "default",
282
+ conversationId: "a:personal-chat",
283
+ });
284
+ expect(originalRun).not.toHaveBeenCalled();
285
+ },
286
+ });
287
+ });
288
+
289
+ it("does not record feedback for a DM sender outside allowFrom", async () => {
290
+ await withFeedbackHandler({
291
+ cfg: {
292
+ channels: {
293
+ msteams: {
294
+ dmPolicy: "allowlist",
295
+ allowFrom: ["owner-aad"],
296
+ },
297
+ },
298
+ } as KlawConfig,
299
+ context: {
300
+ reaction: "like",
301
+ conversationId: "a:personal-chat;messageid=bot-msg-1",
302
+ conversationType: "personal",
303
+ senderId: "attacker-aad",
304
+ senderName: "Attacker",
305
+ comment: "blocked feedback",
306
+ },
307
+ assertResult: async ({ tmpDir, originalRun }) => {
308
+ await expectFileMissing(path.join(tmpDir, "msteams_direct_attacker-aad.jsonl"));
309
+ expect(feedbackReflectionMockState.runFeedbackReflection).not.toHaveBeenCalled();
310
+ expect(originalRun).not.toHaveBeenCalled();
311
+ },
312
+ });
313
+ });
314
+
315
+ it("does not trigger reflection for a group sender outside groupAllowFrom", async () => {
316
+ const tmpDir = await mkdtemp(path.join(tmpdir(), "klaw-msteams-feedback-"));
317
+ try {
318
+ const originalRun = vi.fn(async () => undefined);
319
+ const handler = registerMSTeamsHandlers(
320
+ createActivityHandler(originalRun),
321
+ createDeps({
322
+ cfg: {
323
+ session: { store: tmpDir },
324
+ channels: {
325
+ msteams: {
326
+ groupPolicy: "allowlist",
327
+ groupAllowFrom: ["owner-aad"],
328
+ feedbackReflection: true,
329
+ },
330
+ },
331
+ } as KlawConfig,
332
+ }),
333
+ ) as MSTeamsActivityHandler & {
334
+ run: NonNullable<MSTeamsActivityHandler["run"]>;
335
+ };
336
+
337
+ await handler.run(
338
+ createFeedbackInvokeContext({
339
+ reaction: "dislike",
340
+ conversationId: "19:group@thread.tacv2;messageid=bot-msg-1",
341
+ conversationType: "groupChat",
342
+ senderId: "attacker-aad",
343
+ senderName: "Attacker",
344
+ teamId: "team-1",
345
+ channelName: "General",
346
+ comment: "blocked reflection",
347
+ }),
348
+ );
349
+
350
+ await expectFileMissing(path.join(tmpDir, "msteams_group_19_group_thread_tacv2.jsonl"));
351
+ expect(feedbackReflectionMockState.runFeedbackReflection).not.toHaveBeenCalled();
352
+ expect(originalRun).not.toHaveBeenCalled();
353
+ } finally {
354
+ await rm(tmpDir, { recursive: true, force: true });
355
+ }
356
+ });
357
+ });