From f429e539fa27ff82e0cef60f66334344e26644bd Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 27 Apr 2026 17:52:45 +0900 Subject: [PATCH] test(ralph-loop): cover background task idle guard Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/ralph-loop/index.test.ts | 51 +++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/src/hooks/ralph-loop/index.test.ts b/src/hooks/ralph-loop/index.test.ts index 9755e8e65..fa7d0032c 100644 --- a/src/hooks/ralph-loop/index.test.ts +++ b/src/hooks/ralph-loop/index.test.ts @@ -17,7 +17,7 @@ describe("ralph-loop", () => { let mockSessionMessages: Array<{ info?: { role?: string }; parts?: Array<{ type: string; text?: string }> }> let mockMessagesApiResponseShape: "data" | "array" - function createMockPluginInput() { + function createMockPluginInput(): Parameters[0] { return { client: { session: { @@ -63,7 +63,7 @@ describe("ralph-loop", () => { }, }, directory: TEST_DIR, - } as unknown as Parameters[0] + } as Parameters[0] } beforeEach(() => { @@ -304,6 +304,33 @@ describe("ralph-loop", () => { expect(state?.iteration).toBe(2) }) + test("should skip continuation when background task is running", async () => { + // given - active loop state with a running background task + const hook = createRalphLoopHook(createMockPluginInput(), { + backgroundManager: { + getTasksByParentSession: (sessionID: string) => sessionID === "session-123" + ? [{ status: "running" }] + : [], + }, + }) + hook.startLoop("session-123", "Build a feature", { maxIterations: 10 }) + + // when - session goes idle + await hook.event({ + event: { + type: "session.idle", + properties: { sessionID: "session-123" }, + }, + }) + + // then - no continuation should be injected + expect(promptCalls.length).toBe(0) + + // then - iteration should not be incremented + const state = hook.getState() + expect(state?.iteration).toBe(1) + }) + test("should stop loop when max iterations reached", async () => { // given - loop at max iteration const hook = createRalphLoopHook(createMockPluginInput()) @@ -1144,20 +1171,14 @@ Original task: Build something` test("should not hang when session.messages() throws", async () => { // given - API that throws (simulates timeout error) let apiCallCount = 0 - const errorMock = { - ...createMockPluginInput(), - client: { - ...createMockPluginInput().client, - session: { - ...createMockPluginInput().client.session, - messages: async () => { - apiCallCount++ - throw new Error("API timeout") - }, - }, + const errorMock = createMockPluginInput() + Object.defineProperty(errorMock.client.session, "messages", { + value: async () => { + apiCallCount++ + throw new Error("API timeout") }, - } - const hook = createRalphLoopHook(errorMock as any, { + }) + const hook = createRalphLoopHook(errorMock, { getTranscriptPath: () => join(TEST_DIR, "nonexistent.jsonl"), apiTimeout: 100, })