fix(ralph-loop): ignore synthetic idle replays

This commit is contained in:
YeonGyu-Kim
2026-05-12 15:28:46 +09:00
parent 07797e1975
commit 9ffef79dbb
6 changed files with 104 additions and 4 deletions
+57 -1
View File
@@ -288,7 +288,7 @@ describe("ralph-loop", () => {
await hook.event({
event: {
type: "session.idle",
properties: { sessionID: "session-123" },
properties: { sessionID: "session-123", synthetic: true },
},
})
@@ -304,6 +304,62 @@ describe("ralph-loop", () => {
expect(state?.iteration).toBe(2)
})
test("#given synthetic and real idle arrive back-to-back #then only one continuation is injected for the same iteration", async () => {
// given
const hook = createRalphLoopHook(createMockPluginInput(), { idleSettleMs: 0 })
hook.startLoop("session-123", "Build a feature", { maxIterations: 10 })
// when
await hook.event({
event: {
type: "session.idle",
properties: { sessionID: "session-123", synthetic: true },
},
})
await hook.event({
event: {
type: "session.idle",
properties: { sessionID: "session-123" },
},
})
// then
expect(promptCalls.length).toBe(1)
expect(promptCalls[0].sessionID).toBe("session-123")
expect(hook.getState()?.iteration).toBe(2)
})
test("#given new activity after an idle continuation #when session idles again #then next iteration can continue", async () => {
// given
const hook = createRalphLoopHook(createMockPluginInput(), { idleSettleMs: 0 })
hook.startLoop("session-123", "Build a feature", { maxIterations: 10 })
await hook.event({
event: {
type: "session.idle",
properties: { sessionID: "session-123" },
},
})
// when
await hook.event({
event: {
type: "message.part.updated",
properties: { sessionID: "session-123" },
},
})
await hook.event({
event: {
type: "session.idle",
properties: { sessionID: "session-123" },
},
})
// then
expect(promptCalls.length).toBe(2)
expect(hook.getState()?.iteration).toBe(3)
})
test("should inject continuation when idle event carries session id in info", async () => {
// given - active loop state and nested session event shape
const hook = createRalphLoopHook(createMockPluginInput())