fix(ralph-loop): restrict semantic completion to DONE promise and assistant entries
- Gate semantic detection on promise === 'DONE' in both transcript and session message paths to prevent false positives on VERIFIED promises - Restrict transcript semantic fallback to assistant/text entries only, skipping tool_use/tool_result to avoid matching file content - Add regression test for VERIFIED promise not triggering semantic detection
This commit is contained in:
@@ -273,6 +273,28 @@ describe("detectCompletionInSessionMessages", () => {
|
|||||||
// #then
|
// #then
|
||||||
expect(detected).toBe(true)
|
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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,9 @@ export function detectCompletionInTranscript(
|
|||||||
if (entry.type === "user") continue
|
if (entry.type === "user") continue
|
||||||
if (startedAt && entry.timestamp && entry.timestamp < startedAt) continue
|
if (startedAt && entry.timestamp && entry.timestamp < startedAt) continue
|
||||||
if (pattern.test(line)) return true
|
if (pattern.test(line)) return true
|
||||||
// Fallback: check for semantic completion
|
// Fallback: semantic completion only for DONE promise and assistant entries
|
||||||
if (detectSemanticCompletion(line)) {
|
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 <promise>DONE</promise>)")
|
log("[ralph-loop] WARNING: Semantic completion detected in transcript (agent used natural language instead of <promise>DONE</promise>)")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -118,8 +119,8 @@ export async function detectCompletionInSessionMessages(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: check for semantic completion
|
// Fallback: semantic completion only for DONE promise
|
||||||
if (detectSemanticCompletion(responseText)) {
|
if (options.promise === "DONE" && detectSemanticCompletion(responseText)) {
|
||||||
log("[ralph-loop] WARNING: Semantic completion detected (agent used natural language instead of <promise>DONE</promise>)", {
|
log("[ralph-loop] WARNING: Semantic completion detected (agent used natural language instead of <promise>DONE</promise>)", {
|
||||||
sessionID: options.sessionID,
|
sessionID: options.sessionID,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user