






















@@ -181,16 +181,26 @@ describe("before_tool_call loop detection behavior", () => {
181181expect(loopEvent?.toolName).toBe(params.toolName);
182182}
183183184+function expectToolLoopBlockedResult(result: unknown, expectedReason: string) {
185+expect(result).toMatchObject({
186+content: [{ type: "text", text: expect.stringContaining(expectedReason) }],
187+details: {
188+status: "blocked",
189+deniedReason: "tool-loop",
190+reason: expect.stringContaining(expectedReason),
191+},
192+});
193+}
194+184195it("blocks known poll loops when no progress repeats", async () => {
185196const { tool, params } = createNoProgressProcessFixture("sess-1");
186197187198for (let i = 0; i < CRITICAL_THRESHOLD; i += 1) {
188199await expect(tool.execute(`poll-${i}`, params, undefined, undefined)).resolves.toBeDefined();
189200}
190201191-await expect(
192-tool.execute(`poll-${CRITICAL_THRESHOLD}`, params, undefined, undefined),
193-).rejects.toThrow("CRITICAL");
202+const result = await tool.execute(`poll-${CRITICAL_THRESHOLD}`, params, undefined, undefined);
203+expectToolLoopBlockedResult(result, "CRITICAL");
194204});
195205196206it("does nothing when loopDetection.enabled is false", async () => {
@@ -240,9 +250,13 @@ describe("before_tool_call loop detection behavior", () => {
240250await expect(tool.execute(`read-${i}`, params, undefined, undefined)).resolves.toBeDefined();
241251}
242252243-await expect(
244-tool.execute(`read-${GLOBAL_CIRCUIT_BREAKER_THRESHOLD}`, params, undefined, undefined),
245-).rejects.toThrow("global circuit breaker");
253+const result = await tool.execute(
254+`read-${GLOBAL_CIRCUIT_BREAKER_THRESHOLD}`,
255+params,
256+undefined,
257+undefined,
258+);
259+expectToolLoopBlockedResult(result, "global circuit breaker");
246260});
247261248262it("does not carry loop history across run ids", async () => {
@@ -315,14 +329,13 @@ describe("before_tool_call loop detection behavior", () => {
315329const { readTool, listTool } = createPingPongTools();
316330await runPingPongSequence(readTool, listTool, CRITICAL_THRESHOLD - 1);
317331318-await expect(
319-listTool.execute(
320-`list-${CRITICAL_THRESHOLD - 1}`,
321-{ dir: "/workspace" },
322-undefined,
323-undefined,
324-),
325-).rejects.toThrow("CRITICAL");
332+const result = await listTool.execute(
333+`list-${CRITICAL_THRESHOLD - 1}`,
334+{ dir: "/workspace" },
335+undefined,
336+undefined,
337+);
338+expectToolLoopBlockedResult(result, "CRITICAL");
326339327340const loopEvent = emitted.at(-1);
328341expectCriticalLoopEvent(loopEvent, {
@@ -365,9 +378,8 @@ describe("before_tool_call loop detection behavior", () => {
365378await tool.execute(`poll-${i}`, params, undefined, undefined);
366379}
367380368-await expect(
369-tool.execute(`poll-${CRITICAL_THRESHOLD}`, params, undefined, undefined),
370-).rejects.toThrow("CRITICAL");
381+const result = await tool.execute(`poll-${CRITICAL_THRESHOLD}`, params, undefined, undefined);
382+expectToolLoopBlockedResult(result, "CRITICAL");
371383372384const loopEvent = emitted.at(-1);
373385expectCriticalLoopEvent(loopEvent, {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。