feat(agents): add centralized GPT apply_patch permission guard

Extract hardcoded GPT apply_patch permission logic into a reusable module
to ensure consistent behavior across all agents. This prevents GPT models
from using the unreliable apply_patch tool while allowing other models.

- Add gpt-apply-patch-guard.ts with GPT_APPLY_PATCH_GUIDANCE and getGptApplyPatchPermission
- Update Hephaestus agent to use centralized permission logic
- Update Sisyphus-Junior agent to use centralized permission logic
- Update all GPT prompt builders to reference shared guidance constant

🤖 Generated with assistance of OhMyOpenCode
This commit is contained in:
YeonGyu-Kim
2026-04-10 10:47:27 +09:00
parent 498d021dc2
commit 2083cb0710
18 changed files with 87 additions and 41 deletions
+27 -1
View File
@@ -1,4 +1,5 @@
import type { CreatedHooks } from "../create-hooks"
import { parseRalphLoopArguments } from "../hooks/ralph-loop/command-arguments"
type CommandExecuteBeforeInput = {
command: string
@@ -8,8 +9,11 @@ type CommandExecuteBeforeInput = {
type CommandExecuteBeforeOutput = {
parts: Array<{ type: string; text?: string; [key: string]: unknown }>
message?: Record<string, unknown>
}
const NATIVE_LOOP_TRIGGERED_FLAG = "__omoNativeLoopTriggered"
function hasPartsOutput(value: unknown): value is CommandExecuteBeforeOutput {
if (typeof value !== "object" || value === null) return false
const record = value as Record<string, unknown>
@@ -28,12 +32,34 @@ export function createCommandExecuteBeforeHandler(args: {
return async (input, output): Promise<void> => {
await hooks.autoSlashCommand?.["command.execute.before"]?.(input, output)
const normalizedCommand = input.command.toLowerCase()
const sessionID = input.sessionID
if (hooks.ralphLoop && sessionID) {
if (normalizedCommand === "ralph-loop" || normalizedCommand === "ulw-loop") {
const parsedArguments = parseRalphLoopArguments(input.arguments || "")
hooks.ralphLoop.startLoop(sessionID, parsedArguments.prompt, {
ultrawork: normalizedCommand === "ulw-loop",
maxIterations: parsedArguments.maxIterations,
completionPromise: parsedArguments.completionPromise,
strategy: parsedArguments.strategy,
})
output.message ??= {}
output.message[NATIVE_LOOP_TRIGGERED_FLAG] = true
} else if (normalizedCommand === "cancel-ralph") {
hooks.ralphLoop.cancelLoop(sessionID)
output.message ??= {}
output.message[NATIVE_LOOP_TRIGGERED_FLAG] = true
}
}
if (
hooks.startWork
&& input.command.toLowerCase() === "start-work"
&& normalizedCommand === "start-work"
&& hasPartsOutput(output)
) {
await hooks.startWork["command.execute.before"]?.(input, output)
}
}
}
export { NATIVE_LOOP_TRIGGERED_FLAG }