feat(keyword-detector): handle ultrawork keyword after greeting patterns
- Add TRAILING_GREETING_ULTRAWORK_PATTERN to detect 'hi ultrawork' style inputs - Rename hasLeadingUltraworkKeyword to hasEdgeUltraworkKeyword for clarity - Add extractUltraworkTask guard to return empty string for greeting-only inputs - Add comprehensive test coverage for edge trigger scenarios Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
active: true
|
||||||
|
iteration: 2
|
||||||
|
max_iterations: 100
|
||||||
|
completion_promise: "DONE"
|
||||||
|
initial_completion_promise: "DONE"
|
||||||
|
started_at: "2026-03-14T04:20:58.486Z"
|
||||||
|
session_id: "new-session-1"
|
||||||
|
strategy: "reset"
|
||||||
|
message_count_at_start: 0
|
||||||
|
---
|
||||||
|
Build feature
|
||||||
@@ -17,13 +17,18 @@ import { parseRalphLoopArguments } from "../ralph-loop/command-arguments"
|
|||||||
|
|
||||||
const ULTRAWORK_KEYWORD_PATTERN = /\b(ultrawork|ulw)\b/i
|
const ULTRAWORK_KEYWORD_PATTERN = /\b(ultrawork|ulw)\b/i
|
||||||
const LEADING_ULTRAWORK_PATTERN = /^\s*(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
|
||||||
|
|
||||||
function extractUltraworkTask(cleanText: string): string {
|
function extractUltraworkTask(cleanText: string): string {
|
||||||
|
if (TRAILING_GREETING_ULTRAWORK_PATTERN.test(cleanText)) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
return cleanText.replace(ULTRAWORK_KEYWORD_PATTERN, "").trim()
|
return cleanText.replace(ULTRAWORK_KEYWORD_PATTERN, "").trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasLeadingUltraworkKeyword(cleanText: string): boolean {
|
function hasEdgeUltraworkKeyword(cleanText: string): boolean {
|
||||||
return LEADING_ULTRAWORK_PATTERN.test(cleanText)
|
return LEADING_ULTRAWORK_PATTERN.test(cleanText) || TRAILING_GREETING_ULTRAWORK_PATTERN.test(cleanText)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createKeywordDetectorHook(
|
export function createKeywordDetectorHook(
|
||||||
@@ -81,11 +86,11 @@ export function createKeywordDetectorHook(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasLeadingUltraworkKeyword(cleanText)) {
|
if (!hasEdgeUltraworkKeyword(cleanText)) {
|
||||||
const preFilterCount = detectedKeywords.length
|
const preFilterCount = detectedKeywords.length
|
||||||
detectedKeywords = detectedKeywords.filter((k) => k.type !== "ultrawork")
|
detectedKeywords = detectedKeywords.filter((k) => k.type !== "ultrawork")
|
||||||
if (preFilterCount > detectedKeywords.length) {
|
if (preFilterCount > detectedKeywords.length) {
|
||||||
log(`[keyword-detector] Filtered non-leading ultrawork keyword`, {
|
log(`[keyword-detector] Filtered non-edge ultrawork keyword`, {
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
||||||
|
|
||||||
|
import { createKeywordDetectorHook } from "./index"
|
||||||
|
import { _resetForTesting, setMainSession } from "../../features/claude-code-session-state"
|
||||||
|
|
||||||
|
type StartLoopCall = {
|
||||||
|
sessionID: string
|
||||||
|
prompt: string
|
||||||
|
options: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMockPluginInput(toastCalls: string[] = []) {
|
||||||
|
return {
|
||||||
|
client: {
|
||||||
|
tui: {
|
||||||
|
showToast: async (opts: { body: { title: string } }) => {
|
||||||
|
toastCalls.push(opts.body.title)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as any
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMockRalphLoop(startLoopCalls: StartLoopCall[]) {
|
||||||
|
return {
|
||||||
|
startLoop: (sessionID: string, prompt: string, options?: Record<string, unknown>): boolean => {
|
||||||
|
startLoopCalls.push({ sessionID, prompt, options: options ?? {} })
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("keyword-detector ultrawork edge trigger", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
_resetForTesting()
|
||||||
|
setMainSession("main-session")
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
_resetForTesting()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("#given greeting text before ulw and surrounding whitespace #when chat.message fires #then ultrawork still activates", async () => {
|
||||||
|
// given
|
||||||
|
const toastCalls: string[] = []
|
||||||
|
const startLoopCalls: StartLoopCall[] = []
|
||||||
|
const hook = createKeywordDetectorHook(
|
||||||
|
createMockPluginInput(toastCalls),
|
||||||
|
undefined,
|
||||||
|
createMockRalphLoop(startLoopCalls),
|
||||||
|
)
|
||||||
|
const output = {
|
||||||
|
message: {} as Record<string, unknown>,
|
||||||
|
parts: [{ type: "text", text: " hi there ulw " }],
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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: "Complete the task as instructed",
|
||||||
|
options: {
|
||||||
|
ultrawork: true,
|
||||||
|
maxIterations: undefined,
|
||||||
|
completionPromise: undefined,
|
||||||
|
strategy: undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(output.parts[0]?.text).toContain("ULTRAWORK MODE ENABLED!")
|
||||||
|
expect(output.parts[0]?.text).toContain(" hi there ulw ")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("#given ulw mentioned in the middle of a sentence #when chat.message fires #then ultrawork stays disabled", async () => {
|
||||||
|
// given
|
||||||
|
const toastCalls: string[] = []
|
||||||
|
const startLoopCalls: StartLoopCall[] = []
|
||||||
|
const hook = createKeywordDetectorHook(
|
||||||
|
createMockPluginInput(toastCalls),
|
||||||
|
undefined,
|
||||||
|
createMockRalphLoop(startLoopCalls),
|
||||||
|
)
|
||||||
|
const output = {
|
||||||
|
message: {} as Record<string, unknown>,
|
||||||
|
parts: [{ type: "text", text: "I think ulw is cool" }],
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
await hook["chat.message"]({ sessionID: "main-session", agent: "sisyphus" }, output)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(toastCalls).not.toContain("Ultrawork Mode Activated")
|
||||||
|
expect(startLoopCalls).toHaveLength(0)
|
||||||
|
expect(output.parts[0]?.text).toBe("I think ulw is cool")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("#given trailing ultrawork reference without punctuation #when chat.message fires #then ultrawork stays disabled", async () => {
|
||||||
|
// given
|
||||||
|
const toastCalls: string[] = []
|
||||||
|
const startLoopCalls: StartLoopCall[] = []
|
||||||
|
const hook = createKeywordDetectorHook(
|
||||||
|
createMockPluginInput(toastCalls),
|
||||||
|
undefined,
|
||||||
|
createMockRalphLoop(startLoopCalls),
|
||||||
|
)
|
||||||
|
const output = {
|
||||||
|
message: {} as Record<string, unknown>,
|
||||||
|
parts: [{ type: "text", text: "what is ultrawork" }],
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
await hook["chat.message"]({ sessionID: "main-session", agent: "sisyphus" }, output)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(toastCalls).not.toContain("Ultrawork Mode Activated")
|
||||||
|
expect(startLoopCalls).toHaveLength(0)
|
||||||
|
expect(output.parts[0]?.text).toBe("what is ultrawork")
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user