From 2083cb0710ea1c6617ae2473d44db09898e30f3b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 10 Apr 2026 10:47:27 +0900 Subject: [PATCH] feat(agents): add centralized GPT apply_patch permission guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/agents/gpt-apply-patch-guard.ts | 7 +++++ src/agents/hephaestus/agent.ts | 5 ++-- src/agents/hephaestus/gpt-5-3-codex.ts | 3 +- src/agents/hephaestus/gpt-5-4.ts | 3 +- src/agents/hephaestus/gpt.ts | 3 +- src/agents/sisyphus-junior/agent.ts | 9 ++++-- src/agents/sisyphus-junior/gpt-5-3-codex.ts | 3 +- src/agents/sisyphus-junior/gpt-5-4.ts | 3 +- src/agents/sisyphus-junior/gpt.ts | 3 +- src/agents/sisyphus.ts | 5 ++-- src/agents/sisyphus/gpt-5-4.ts | 3 +- .../doctor/checks/model-resolution-cache.ts | 12 ++------ src/create-managers.ts | 14 +++++----- .../checker/cached-version.ts | 18 ++++++------ src/openclaw/reply-listener-discord.ts | 5 +++- src/plugin-interface.test.ts | 1 + src/plugin/chat-message.ts | 3 +- src/plugin/command-execute-before.ts | 28 ++++++++++++++++++- 18 files changed, 87 insertions(+), 41 deletions(-) create mode 100644 src/agents/gpt-apply-patch-guard.ts diff --git a/src/agents/gpt-apply-patch-guard.ts b/src/agents/gpt-apply-patch-guard.ts new file mode 100644 index 000000000..75a784524 --- /dev/null +++ b/src/agents/gpt-apply-patch-guard.ts @@ -0,0 +1,7 @@ +import { isGptModel } from "./types" + +export const GPT_APPLY_PATCH_GUIDANCE = "Use the `edit` and `write` tools for file changes. Do not use `apply_patch` on GPT models - it is unreliable here and can hang during verification." + +export function getGptApplyPatchPermission(model: string): Record { + return isGptModel(model) ? { apply_patch: "deny" as const } : {} +} diff --git a/src/agents/hephaestus/agent.ts b/src/agents/hephaestus/agent.ts index c6ce3bc1b..e42214d8f 100644 --- a/src/agents/hephaestus/agent.ts +++ b/src/agents/hephaestus/agent.ts @@ -1,6 +1,6 @@ import type { AgentConfig } from "@opencode-ai/sdk"; import type { AgentMode, AgentPromptMetadata } from "../types"; -import { isGptModel, isGpt5_4Model, isGpt5_3CodexModel } from "../types"; +import { isGpt5_4Model, isGpt5_3CodexModel } from "../types"; import type { AvailableAgent, AvailableTool, @@ -8,6 +8,7 @@ import type { AvailableCategory, } from "../dynamic-agent-prompt-builder"; import { categorizeTools, buildAgentIdentitySection } from "../dynamic-agent-prompt-builder"; +import { getGptApplyPatchPermission } from "../gpt-apply-patch-guard"; import { buildHephaestusPrompt as buildGptPrompt } from "./gpt"; import { buildHephaestusPrompt as buildGpt53CodexPrompt } from "./gpt-5-3-codex"; @@ -125,7 +126,7 @@ export function createHephaestusAgent( permission: { question: "allow", call_omo_agent: "deny", - ...(isGptModel(model) ? { apply_patch: "deny" as const } : {}), + ...getGptApplyPatchPermission(model), } as AgentConfig["permission"], reasoningEffort: "medium", }; diff --git a/src/agents/hephaestus/gpt-5-3-codex.ts b/src/agents/hephaestus/gpt-5-3-codex.ts index 93a7ef32a..2ca2964f7 100644 --- a/src/agents/hephaestus/gpt-5-3-codex.ts +++ b/src/agents/hephaestus/gpt-5-3-codex.ts @@ -1,4 +1,5 @@ /** GPT-5.3 Codex optimized Hephaestus prompt */ +import { GPT_APPLY_PATCH_GUIDANCE } from "../gpt-apply-patch-guard"; import type { AgentConfig } from "@opencode-ai/sdk"; import type { AgentMode } from "../types"; import type { @@ -448,7 +449,7 @@ ${oracleSection} 1. SEARCH existing codebase for similar patterns/styles 2. Match naming, indentation, import styles, error handling conventions 3. Default to ASCII. Add comments only for non-obvious blocks -4. Use the \`edit\` and \`write\` tools for file changes. Do not use \`apply_patch\` on GPT models - it is unreliable here and can hang during verification. +4. ${GPT_APPLY_PATCH_GUIDANCE} ### After Implementation (MANDATORY - DO NOT SKIP) diff --git a/src/agents/hephaestus/gpt-5-4.ts b/src/agents/hephaestus/gpt-5-4.ts index 2c0f8410b..a88b6ea0f 100644 --- a/src/agents/hephaestus/gpt-5-4.ts +++ b/src/agents/hephaestus/gpt-5-4.ts @@ -21,6 +21,7 @@ * 9. - Output format, tone guidance */ +import { GPT_APPLY_PATCH_GUIDANCE } from "../gpt-apply-patch-guard"; import type { AvailableAgent, AvailableTool, @@ -252,7 +253,7 @@ ${antiPatterns} 1. **Explore**: Fire 2-5 explore/librarian agents in parallel + direct tool reads. Goal: complete understanding, not just enough context. 2. **Plan**: List files to modify, specific changes, dependencies, complexity estimate. 3. **Decide**: Trivial (<10 lines, single file) -> self. Complex (multi-file, >100 lines) -> delegate. -4. **Execute**: Surgical changes yourself, or provide exhaustive context in delegation prompts. Match existing patterns. Minimal diff. Search the codebase for similar patterns before writing code. Default to ASCII. Add comments only for non-obvious blocks. Use the \`edit\` and \`write\` tools for file changes. Do not use \`apply_patch\` on GPT models - it is unreliable here and can hang during verification. +4. **Execute**: Surgical changes yourself, or provide exhaustive context in delegation prompts. Match existing patterns. Minimal diff. Search the codebase for similar patterns before writing code. Default to ASCII. Add comments only for non-obvious blocks. ${GPT_APPLY_PATCH_GUIDANCE} 5. **Verify**: \`lsp_diagnostics\` on all modified files (zero errors) -> run related tests (\`foo.ts\` -> \`foo.test.ts\`) -> typecheck -> build if applicable (exit 0). Fix only issues your changes caused. If verification fails, return to step 1 with a materially different approach. After three attempts: stop, revert to last working state, document what you tried, consult Oracle. If Oracle cannot resolve, ask the user. diff --git a/src/agents/hephaestus/gpt.ts b/src/agents/hephaestus/gpt.ts index b305d1128..cf1a3ea91 100644 --- a/src/agents/hephaestus/gpt.ts +++ b/src/agents/hephaestus/gpt.ts @@ -1,5 +1,6 @@ /** Generic GPT Hephaestus prompt - fallback for GPT models without a model-specific variant */ +import { GPT_APPLY_PATCH_GUIDANCE } from "../gpt-apply-patch-guard" import type { AvailableAgent, AvailableTool, @@ -311,7 +312,7 @@ ${oracleSection} 1. SEARCH existing codebase for similar patterns/styles 2. Match naming, indentation, import styles, error handling conventions 3. Default to ASCII. Add comments only for non-obvious blocks -4. Use the \`edit\` and \`write\` tools for file changes. Do not use \`apply_patch\` on GPT models - it is unreliable here and can hang during verification. +4. ${GPT_APPLY_PATCH_GUIDANCE} ### After Implementation (MANDATORY - DO NOT SKIP) diff --git a/src/agents/sisyphus-junior/agent.ts b/src/agents/sisyphus-junior/agent.ts index febb2512b..b8af3406c 100644 --- a/src/agents/sisyphus-junior/agent.ts +++ b/src/agents/sisyphus-junior/agent.ts @@ -18,6 +18,7 @@ import { createAgentToolRestrictions, type PermissionValue, } from "../../shared/permission-compat" +import { getGptApplyPatchPermission } from "../gpt-apply-patch-guard" import { buildDefaultSisyphusJuniorPrompt } from "./default" import { buildGptSisyphusJuniorPrompt } from "./gpt" @@ -103,7 +104,11 @@ export function createSisyphusJuniorAgentWithOverrides( merged[tool] = "deny" } merged.call_omo_agent = "allow" - const toolsConfig = { permission: { ...merged, ...basePermission } } + const toolsConfig = { permission: { ...merged, ...basePermission } as Record } + const permission: Record = { + ...toolsConfig.permission, + ...getGptApplyPatchPermission(model), + } const base: AgentConfig = { description: override?.description ?? @@ -114,7 +119,7 @@ export function createSisyphusJuniorAgentWithOverrides( maxTokens: 64000, prompt, color: override?.color ?? "#20B2AA", - ...toolsConfig, + permission, } if (override?.top_p !== undefined) { diff --git a/src/agents/sisyphus-junior/gpt-5-3-codex.ts b/src/agents/sisyphus-junior/gpt-5-3-codex.ts index 02e8d07fa..ede0e77c8 100644 --- a/src/agents/sisyphus-junior/gpt-5-3-codex.ts +++ b/src/agents/sisyphus-junior/gpt-5-3-codex.ts @@ -8,6 +8,7 @@ import { resolvePromptAppend } from "../builtin-agents/resolve-file-uri" import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder" +import { GPT_APPLY_PATCH_GUIDANCE } from "../gpt-apply-patch-guard" export function buildGpt53CodexSisyphusJuniorPrompt( useTaskSystem: boolean, @@ -92,7 +93,7 @@ Style: 1. SEARCH existing codebase for similar patterns/styles 2. Match naming, indentation, import styles, error handling conventions 3. Default to ASCII. Add comments only for non-obvious blocks -4. Use the \`edit\` and \`write\` tools for file changes. Do not use \`apply_patch\` on GPT models - it is unreliable here and can hang during verification. +4. ${GPT_APPLY_PATCH_GUIDANCE} ### After Implementation (MANDATORY - DO NOT SKIP) diff --git a/src/agents/sisyphus-junior/gpt-5-4.ts b/src/agents/sisyphus-junior/gpt-5-4.ts index 81e706530..d1bd8c177 100644 --- a/src/agents/sisyphus-junior/gpt-5-4.ts +++ b/src/agents/sisyphus-junior/gpt-5-4.ts @@ -11,6 +11,7 @@ import { resolvePromptAppend } from "../builtin-agents/resolve-file-uri"; import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder"; +import { GPT_APPLY_PATCH_GUIDANCE } from "../gpt-apply-patch-guard"; export function buildGpt54SisyphusJuniorPrompt( useTaskSystem: boolean, @@ -96,7 +97,7 @@ Style: 1. SEARCH existing codebase for similar patterns/styles 2. Match naming, indentation, import styles, error handling conventions 3. Default to ASCII. Add comments only for non-obvious blocks -4. Use the \`edit\` and \`write\` tools for file changes. Do not use \`apply_patch\` on GPT models - it is unreliable here and can hang during verification. +4. ${GPT_APPLY_PATCH_GUIDANCE} 5. Do not chain bash commands with separators - each command should be a separate tool call ### After Implementation (MANDATORY - DO NOT SKIP) diff --git a/src/agents/sisyphus-junior/gpt.ts b/src/agents/sisyphus-junior/gpt.ts index c69ab7a2a..684e830ef 100644 --- a/src/agents/sisyphus-junior/gpt.ts +++ b/src/agents/sisyphus-junior/gpt.ts @@ -9,6 +9,7 @@ import { resolvePromptAppend } from "../builtin-agents/resolve-file-uri" import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder" +import { GPT_APPLY_PATCH_GUIDANCE } from "../gpt-apply-patch-guard" export function buildGptSisyphusJuniorPrompt( useTaskSystem: boolean, @@ -93,7 +94,7 @@ Style: 1. SEARCH existing codebase for similar patterns/styles 2. Match naming, indentation, import styles, error handling conventions 3. Default to ASCII. Add comments only for non-obvious blocks -4. Use the \`edit\` and \`write\` tools for file changes. Do not use \`apply_patch\` on GPT models - it is unreliable here and can hang during verification. +4. ${GPT_APPLY_PATCH_GUIDANCE} ### After Implementation (MANDATORY - DO NOT SKIP) diff --git a/src/agents/sisyphus.ts b/src/agents/sisyphus.ts index 52442c359..55b6c1c21 100644 --- a/src/agents/sisyphus.ts +++ b/src/agents/sisyphus.ts @@ -11,6 +11,7 @@ import { } from "./sisyphus/gemini"; import { buildGpt54SisyphusPrompt } from "./sisyphus/gpt-5-4"; import { buildTaskManagementSection } from "./sisyphus/default"; +import { getGptApplyPatchPermission } from "./gpt-apply-patch-guard"; const MODE: AgentMode = "primary"; export const SISYPHUS_PROMPT_METADATA: AgentPromptMetadata = { @@ -499,7 +500,7 @@ export function createSisyphusAgent( permission: { question: "allow", call_omo_agent: "deny", - apply_patch: "deny", + ...getGptApplyPatchPermission(model), } as AgentConfig["permission"], reasoningEffort: "medium", }; @@ -539,7 +540,7 @@ export function createSisyphusAgent( const permission = { question: "allow", call_omo_agent: "deny", - ...(isGptModel(model) ? { apply_patch: "deny" as const } : {}), + ...getGptApplyPatchPermission(model), } as AgentConfig["permission"]; const base = { description: diff --git a/src/agents/sisyphus/gpt-5-4.ts b/src/agents/sisyphus/gpt-5-4.ts index 72d641b40..9e8219015 100644 --- a/src/agents/sisyphus/gpt-5-4.ts +++ b/src/agents/sisyphus/gpt-5-4.ts @@ -21,6 +21,7 @@ * 8.