fix(ulw-loop): read loop task from user_message
Preserve the actual /ulw-loop task text from the skill tool payload instead of falling back to the default prompt when command arguments are passed separately. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -11,6 +11,16 @@ import { readState, writeState } from "../hooks/ralph-loop/storage"
|
|||||||
|
|
||||||
import type { CreatedHooks } from "../create-hooks"
|
import type { CreatedHooks } from "../create-hooks"
|
||||||
|
|
||||||
|
function getLoopCommandArguments(args: Record<string, unknown>, command: "ralph-loop" | "ulw-loop"): string {
|
||||||
|
const rawUserMessage = typeof args.user_message === "string" ? args.user_message.trim() : ""
|
||||||
|
if (rawUserMessage) {
|
||||||
|
return rawUserMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawName = typeof args.name === "string" ? args.name : ""
|
||||||
|
return rawName.replace(new RegExp(`^/?(${command})\\s*`, "i"), "")
|
||||||
|
}
|
||||||
|
|
||||||
export function createToolExecuteBeforeHandler(args: {
|
export function createToolExecuteBeforeHandler(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
hooks: CreatedHooks
|
hooks: CreatedHooks
|
||||||
@@ -137,7 +147,7 @@ export function createToolExecuteBeforeHandler(args: {
|
|||||||
const sessionID = input.sessionID || getMainSessionID()
|
const sessionID = input.sessionID || getMainSessionID()
|
||||||
|
|
||||||
if (command === "ralph-loop" && sessionID) {
|
if (command === "ralph-loop" && sessionID) {
|
||||||
const rawArgs = rawName?.replace(/^\/?(ralph-loop)\s*/i, "") || ""
|
const rawArgs = getLoopCommandArguments(output.args, "ralph-loop")
|
||||||
const parsedArguments = parseRalphLoopArguments(rawArgs)
|
const parsedArguments = parseRalphLoopArguments(rawArgs)
|
||||||
|
|
||||||
hooks.ralphLoop.startLoop(sessionID, parsedArguments.prompt, {
|
hooks.ralphLoop.startLoop(sessionID, parsedArguments.prompt, {
|
||||||
@@ -148,7 +158,7 @@ export function createToolExecuteBeforeHandler(args: {
|
|||||||
} else if (command === "cancel-ralph" && sessionID) {
|
} else if (command === "cancel-ralph" && sessionID) {
|
||||||
hooks.ralphLoop.cancelLoop(sessionID)
|
hooks.ralphLoop.cancelLoop(sessionID)
|
||||||
} else if (command === "ulw-loop" && sessionID) {
|
} else if (command === "ulw-loop" && sessionID) {
|
||||||
const rawArgs = rawName?.replace(/^\/?(ulw-loop)\s*/i, "") || ""
|
const rawArgs = getLoopCommandArguments(output.args, "ulw-loop")
|
||||||
const parsedArguments = parseRalphLoopArguments(rawArgs)
|
const parsedArguments = parseRalphLoopArguments(rawArgs)
|
||||||
|
|
||||||
hooks.ralphLoop.startLoop(sessionID, parsedArguments.prompt, {
|
hooks.ralphLoop.startLoop(sessionID, parsedArguments.prompt, {
|
||||||
|
|||||||
@@ -91,6 +91,47 @@ describe("tool.execute.before ultrawork oracle verification", () => {
|
|||||||
rmSync(directory, { recursive: true, force: true })
|
rmSync(directory, { recursive: true, force: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("#given ulw-loop skill invocation carries user_message #when tool.execute.before runs #then the loop starts with that prompt", async () => {
|
||||||
|
const directory = join(tmpdir(), `tool-before-ulw-skill-${Date.now()}`)
|
||||||
|
mkdirSync(directory, { recursive: true })
|
||||||
|
const startLoopCalls: Array<{ sessionID: string; prompt: string; options: Record<string, unknown> }> = []
|
||||||
|
const handler = createToolExecuteBeforeHandler({
|
||||||
|
ctx: createCtx(directory) as unknown as Parameters<typeof createToolExecuteBeforeHandler>[0]["ctx"],
|
||||||
|
hooks: {
|
||||||
|
ralphLoop: {
|
||||||
|
startLoop: (sessionID: string, prompt: string, options?: Record<string, unknown>) => {
|
||||||
|
startLoopCalls.push({ sessionID, prompt, options: options ?? {} })
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
cancelLoop: () => true,
|
||||||
|
getState: () => null,
|
||||||
|
},
|
||||||
|
} as unknown as Parameters<typeof createToolExecuteBeforeHandler>[0]["hooks"],
|
||||||
|
})
|
||||||
|
const output = {
|
||||||
|
args: {
|
||||||
|
name: "ulw-loop",
|
||||||
|
user_message: '"Ship feature" --strategy=continue',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
await handler({ tool: "skill", sessionID: "ses-main", callID: "call-skill-ulw" }, output)
|
||||||
|
|
||||||
|
expect(startLoopCalls).toHaveLength(1)
|
||||||
|
expect(startLoopCalls[0]).toEqual({
|
||||||
|
sessionID: "ses-main",
|
||||||
|
prompt: "Ship feature",
|
||||||
|
options: {
|
||||||
|
ultrawork: true,
|
||||||
|
maxIterations: undefined,
|
||||||
|
completionPromise: undefined,
|
||||||
|
strategy: "continue",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
rmSync(directory, { recursive: true, force: true })
|
||||||
|
})
|
||||||
|
|
||||||
test("#given ulw loop is awaiting verification #when oracle sync task metadata is persisted #then oracle session id is stored", async () => {
|
test("#given ulw loop is awaiting verification #when oracle sync task metadata is persisted #then oracle session id is stored", async () => {
|
||||||
const directory = join(tmpdir(), `tool-after-ulw-${Date.now()}`)
|
const directory = join(tmpdir(), `tool-after-ulw-${Date.now()}`)
|
||||||
mkdirSync(directory, { recursive: true })
|
mkdirSync(directory, { recursive: true })
|
||||||
|
|||||||
Reference in New Issue
Block a user