mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 06:31:24 +00:00
refactor(agent): dedupe harness and command workflows
This commit is contained in:
@@ -12,166 +12,121 @@ afterEach(() => {
|
||||
resetProcessRegistryForTests();
|
||||
});
|
||||
|
||||
test("background exec is not killed when tool signal aborts", async () => {
|
||||
const tool = createExecTool({ allowBackground: true, backgroundMs: 0 });
|
||||
const abortController = new AbortController();
|
||||
async function waitForFinishedSession(sessionId: string) {
|
||||
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);
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
const result = await tool.execute(
|
||||
function cleanupRunningSession(sessionId: string) {
|
||||
const running = getSession(sessionId);
|
||||
const pid = running?.pid;
|
||||
if (pid) {
|
||||
killProcessTree(pid);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
async function expectBackgroundSessionSurvivesAbort(params: {
|
||||
tool: ReturnType<typeof createExecTool>;
|
||||
executeParams: Record<string, unknown>;
|
||||
}) {
|
||||
const abortController = new AbortController();
|
||||
const result = await params.tool.execute(
|
||||
"toolcall",
|
||||
{ command: 'node -e "setTimeout(() => {}, 5000)"', background: true },
|
||||
params.executeParams,
|
||||
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);
|
||||
}
|
||||
cleanupRunningSession(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
async function expectBackgroundSessionTimesOut(params: {
|
||||
tool: ReturnType<typeof createExecTool>;
|
||||
executeParams: Record<string, unknown>;
|
||||
signal?: AbortSignal;
|
||||
abortAfterStart?: boolean;
|
||||
}) {
|
||||
const abortController = new AbortController();
|
||||
const signal = params.signal ?? abortController.signal;
|
||||
const result = await params.tool.execute("toolcall", params.executeParams, signal);
|
||||
expect(result.details.status).toBe("running");
|
||||
const sessionId = (result.details as { sessionId: string }).sessionId;
|
||||
|
||||
if (params.abortAfterStart) {
|
||||
abortController.abort();
|
||||
}
|
||||
|
||||
const finished = await waitForFinishedSession(sessionId);
|
||||
try {
|
||||
expect(finished).toBeTruthy();
|
||||
expect(finished?.status).toBe("failed");
|
||||
} finally {
|
||||
cleanupRunningSession(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
test("background exec is not killed when tool signal aborts", async () => {
|
||||
const tool = createExecTool({ allowBackground: true, backgroundMs: 0 });
|
||||
await expectBackgroundSessionSurvivesAbort({
|
||||
tool,
|
||||
executeParams: { command: 'node -e "setTimeout(() => {}, 5000)"', background: true },
|
||||
});
|
||||
});
|
||||
|
||||
test("pty 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, pty: 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);
|
||||
}
|
||||
}
|
||||
await expectBackgroundSessionSurvivesAbort({
|
||||
tool,
|
||||
executeParams: { command: 'node -e "setTimeout(() => {}, 5000)"', background: true, pty: true },
|
||||
});
|
||||
});
|
||||
|
||||
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",
|
||||
{
|
||||
await expectBackgroundSessionTimesOut({
|
||||
tool,
|
||||
executeParams: {
|
||||
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);
|
||||
}
|
||||
}
|
||||
abortAfterStart: true,
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
await expectBackgroundSessionSurvivesAbort({
|
||||
tool,
|
||||
executeParams: { command: 'node -e "setTimeout(() => {}, 5000)"', yieldMs: 5 },
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
await expectBackgroundSessionTimesOut({
|
||||
tool,
|
||||
executeParams: {
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user