Spaces:
Configuration error
Configuration error
| import { afterEach, expect, test } from "vitest"; | |
| import { createExecTool } from "./bash-tools.exec"; | |
| import { | |
| getFinishedSession, | |
| getSession, | |
| resetProcessRegistryForTests, | |
| } from "./bash-process-registry"; | |
| import { killProcessTree } from "./shell-utils"; | |
| const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); | |
| afterEach(() => { | |
| resetProcessRegistryForTests(); | |
| }); | |
| test("background exec is not killed when tool signal aborts", async () => { | |
| const tool = createExecTool({ allowBackground: true, backgroundMs: 0 }); | |
| const abortController = new AbortController(); | |
| const result = await tool.execute( | |
| "toolcall", | |
| { command: 'node -e "setTimeout(() => {}, 5000)"', background: true }, | |
| abortController.signal, | |
| ); | |
| expect(result.details.status).toBe("running"); | |
| const sessionId = (result.details as { sessionId: string }).sessionId; | |
| abortController.abort(); | |
| await sleep(150); | |
| const running = getSession(sessionId); | |
| const finished = getFinishedSession(sessionId); | |
| try { | |
| expect(finished).toBeUndefined(); | |
| expect(running?.exited).toBe(false); | |
| } finally { | |
| const pid = running?.pid; | |
| if (pid) killProcessTree(pid); | |
| } | |
| }); | |
| test("background exec still times out after tool signal abort", async () => { | |
| const tool = createExecTool({ allowBackground: true, backgroundMs: 0 }); | |
| const abortController = new AbortController(); | |
| const result = await tool.execute( | |
| "toolcall", | |
| { | |
| command: 'node -e "setTimeout(() => {}, 5000)"', | |
| background: true, | |
| timeout: 0.2, | |
| }, | |
| abortController.signal, | |
| ); | |
| expect(result.details.status).toBe("running"); | |
| const sessionId = (result.details as { sessionId: string }).sessionId; | |
| abortController.abort(); | |
| let finished = getFinishedSession(sessionId); | |
| const deadline = Date.now() + (process.platform === "win32" ? 10_000 : 2_000); | |
| while (!finished && Date.now() < deadline) { | |
| await sleep(20); | |
| finished = getFinishedSession(sessionId); | |
| } | |
| const running = getSession(sessionId); | |
| try { | |
| expect(finished).toBeTruthy(); | |
| expect(finished?.status).toBe("failed"); | |
| } finally { | |
| const pid = running?.pid; | |
| if (pid) killProcessTree(pid); | |
| } | |
| }); | |
| test("yielded background exec is not killed when tool signal aborts", async () => { | |
| const tool = createExecTool({ allowBackground: true, backgroundMs: 10 }); | |
| const abortController = new AbortController(); | |
| const result = await tool.execute( | |
| "toolcall", | |
| { command: 'node -e "setTimeout(() => {}, 5000)"', yieldMs: 5 }, | |
| abortController.signal, | |
| ); | |
| expect(result.details.status).toBe("running"); | |
| const sessionId = (result.details as { sessionId: string }).sessionId; | |
| abortController.abort(); | |
| await sleep(150); | |
| const running = getSession(sessionId); | |
| const finished = getFinishedSession(sessionId); | |
| try { | |
| expect(finished).toBeUndefined(); | |
| expect(running?.exited).toBe(false); | |
| } finally { | |
| const pid = running?.pid; | |
| if (pid) killProcessTree(pid); | |
| } | |
| }); | |
| test("yielded background exec still times out", async () => { | |
| const tool = createExecTool({ allowBackground: true, backgroundMs: 10 }); | |
| const result = await tool.execute("toolcall", { | |
| command: 'node -e "setTimeout(() => {}, 5000)"', | |
| yieldMs: 5, | |
| timeout: 0.2, | |
| }); | |
| expect(result.details.status).toBe("running"); | |
| const sessionId = (result.details as { sessionId: string }).sessionId; | |
| let finished = getFinishedSession(sessionId); | |
| const deadline = Date.now() + (process.platform === "win32" ? 10_000 : 2_000); | |
| while (!finished && Date.now() < deadline) { | |
| await sleep(20); | |
| finished = getFinishedSession(sessionId); | |
| } | |
| const running = getSession(sessionId); | |
| try { | |
| expect(finished).toBeTruthy(); | |
| expect(finished?.status).toBe("failed"); | |
| } finally { | |
| const pid = running?.pid; | |
| if (pid) killProcessTree(pid); | |
| } | |
| }); | |