diff --git a/src/hooks/keyword-detector/hook.ts b/src/hooks/keyword-detector/hook.ts index 2a1462970..52a5a292b 100644 --- a/src/hooks/keyword-detector/hook.ts +++ b/src/hooks/keyword-detector/hook.ts @@ -17,18 +17,20 @@ import { parseRalphLoopArguments } from "../ralph-loop/command-arguments" const ULTRAWORK_KEYWORD_PATTERN = /\b(ultrawork|ulw)\b/i const LEADING_ULTRAWORK_PATTERN = /^\s*(ultrawork|ulw)\b/i -const TRAILING_GREETING_ULTRAWORK_PATTERN = /^\s*(?:hi|hello|hey|hiya|greetings)(?:\s+there)?\s+(ultrawork|ulw)\s*$/i +const GREETING_PREFIX_ULTRAWORK_PATTERN = /^\s*(?:hi|hello|hey|hiya|greetings)(?:\s+there)?(?:[!,.:;-]+\s*|\s+)(ultrawork|ulw)\b/i function extractUltraworkTask(cleanText: string): string { - if (TRAILING_GREETING_ULTRAWORK_PATTERN.test(cleanText)) { - return "" + const greetingPrefixedMatch = cleanText.match(GREETING_PREFIX_ULTRAWORK_PATTERN) + + if (greetingPrefixedMatch) { + return cleanText.slice(greetingPrefixedMatch[0].length).trim() } return cleanText.replace(ULTRAWORK_KEYWORD_PATTERN, "").trim() } function hasEdgeUltraworkKeyword(cleanText: string): boolean { - return LEADING_ULTRAWORK_PATTERN.test(cleanText) || TRAILING_GREETING_ULTRAWORK_PATTERN.test(cleanText) + return LEADING_ULTRAWORK_PATTERN.test(cleanText) || GREETING_PREFIX_ULTRAWORK_PATTERN.test(cleanText) } export function createKeywordDetectorHook( diff --git a/src/hooks/keyword-detector/ultrawork-edge-trigger.test.ts b/src/hooks/keyword-detector/ultrawork-edge-trigger.test.ts index 2ec21dec3..0fc7e8f30 100644 --- a/src/hooks/keyword-detector/ultrawork-edge-trigger.test.ts +++ b/src/hooks/keyword-detector/ultrawork-edge-trigger.test.ts @@ -74,6 +74,40 @@ describe("keyword-detector ultrawork edge trigger", () => { expect(output.parts[0]?.text).toContain(" hi there ulw ") }) + test("#given greeting before ulw with a trailing task #when chat.message fires #then ultrawork activates and preserves the task", async () => { + // given + const toastCalls: string[] = [] + const startLoopCalls: StartLoopCall[] = [] + const hook = createKeywordDetectorHook( + createMockPluginInput(toastCalls), + undefined, + createMockRalphLoop(startLoopCalls), + ) + const output = { + message: {} as Record, + parts: [{ type: "text", text: "hey ulw fix the flaky keyword tests" }], + } + + // when + await hook["chat.message"]({ sessionID: "main-session", agent: "sisyphus" }, output) + + // then + expect(toastCalls).toContain("Ultrawork Mode Activated") + expect(startLoopCalls).toHaveLength(1) + expect(startLoopCalls[0]).toEqual({ + sessionID: "main-session", + prompt: "fix the flaky keyword tests", + options: { + ultrawork: true, + maxIterations: undefined, + completionPromise: undefined, + strategy: undefined, + }, + }) + expect(output.parts[0]?.text).toContain("ULTRAWORK MODE ENABLED!") + expect(output.parts[0]?.text).toContain("hey ulw fix the flaky keyword tests") + }) + test("#given ulw mentioned in the middle of a sentence #when chat.message fires #then ultrawork stays disabled", async () => { // given const toastCalls: string[] = []