diff --git a/src/hooks/ralph-loop/completion-promise-detector.test.ts b/src/hooks/ralph-loop/completion-promise-detector.test.ts index 704517732..bbb2206fb 100644 --- a/src/hooks/ralph-loop/completion-promise-detector.test.ts +++ b/src/hooks/ralph-loop/completion-promise-detector.test.ts @@ -273,6 +273,28 @@ describe("detectCompletionInSessionMessages", () => { // #then expect(detected).toBe(true) }) + + test("#when promise is VERIFIED #then semantic completion should NOT trigger", async () => { + // #given + const messages: SessionMessage[] = [ + { + info: { role: "assistant" }, + parts: [{ type: "text", text: "The task is complete. All work has been finished." }], + }, + ] + const ctx = createPluginInput(messages) + + // #when + const detected = await detectCompletionInSessionMessages(ctx, { + sessionID: "session-123", + promise: "VERIFIED", + apiTimeoutMs: 1000, + directory: "/tmp", + }) + + // #then + expect(detected).toBe(false) + }) }) }) diff --git a/src/hooks/ralph-loop/completion-promise-detector.ts b/src/hooks/ralph-loop/completion-promise-detector.ts index 39322e536..cd02ce7f7 100644 --- a/src/hooks/ralph-loop/completion-promise-detector.ts +++ b/src/hooks/ralph-loop/completion-promise-detector.ts @@ -49,8 +49,9 @@ export function detectCompletionInTranscript( if (entry.type === "user") continue if (startedAt && entry.timestamp && entry.timestamp < startedAt) continue if (pattern.test(line)) return true - // Fallback: check for semantic completion - if (detectSemanticCompletion(line)) { + // Fallback: semantic completion only for DONE promise and assistant entries + const isAssistantEntry = entry.type === "assistant" || entry.type === "text" + if (promise === "DONE" && isAssistantEntry && detectSemanticCompletion(line)) { log("[ralph-loop] WARNING: Semantic completion detected in transcript (agent used natural language instead of DONE)") return true } @@ -118,8 +119,8 @@ export async function detectCompletionInSessionMessages( return true } - // Fallback: check for semantic completion - if (detectSemanticCompletion(responseText)) { + // Fallback: semantic completion only for DONE promise + if (options.promise === "DONE" && detectSemanticCompletion(responseText)) { log("[ralph-loop] WARNING: Semantic completion detected (agent used natural language instead of DONE)", { sessionID: options.sessionID, })