From 674df1b1b83ff838c5b1706ae49025fa8600acde Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 14 Mar 2026 13:43:56 +0900 Subject: [PATCH] fix(hooks): remove dead delegate-task-english-directive hook --- assets/oh-my-openagent.schema.json | 5 +- assets/oh-my-opencode.schema.json | 5 +- src/config/schema.test.ts | 13 +++ src/config/schema/hooks.ts | 1 - .../delegate-task-english-directive/hook.ts | 24 ----- .../index.test.ts | 98 ------------------- .../delegate-task-english-directive/index.ts | 1 - src/hooks/index.ts | 1 - src/plugin/hooks/create-session-hooks.ts | 7 -- src/shared/migration.test.ts | 13 +++ src/shared/migration/hook-names.ts | 1 + 11 files changed, 31 insertions(+), 138 deletions(-) delete mode 100644 src/hooks/delegate-task-english-directive/hook.ts delete mode 100644 src/hooks/delegate-task-english-directive/index.test.ts delete mode 100644 src/hooks/delegate-task-english-directive/index.ts diff --git a/assets/oh-my-openagent.schema.json b/assets/oh-my-openagent.schema.json index 243b1ef0b..d034c5103 100644 --- a/assets/oh-my-openagent.schema.json +++ b/assets/oh-my-openagent.schema.json @@ -92,8 +92,7 @@ "write-existing-file-guard", "anthropic-effort", "hashline-read-enhancer", - "read-image-resizer", - "delegate-task-english-directive" + "read-image-resizer" ] } }, @@ -3928,4 +3927,4 @@ } }, "additionalProperties": false -} \ No newline at end of file +} diff --git a/assets/oh-my-opencode.schema.json b/assets/oh-my-opencode.schema.json index 3870ca8f6..bcd929aa2 100644 --- a/assets/oh-my-opencode.schema.json +++ b/assets/oh-my-opencode.schema.json @@ -92,8 +92,7 @@ "write-existing-file-guard", "anthropic-effort", "hashline-read-enhancer", - "read-image-resizer", - "delegate-task-english-directive" + "read-image-resizer" ] } }, @@ -3928,4 +3927,4 @@ } }, "additionalProperties": false -} \ No newline at end of file +} diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index b89e122bf..d357571c7 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -1,3 +1,5 @@ +/// + import { describe, expect, test } from "bun:test" import { AgentOverrideConfigSchema, @@ -405,6 +407,17 @@ describe("HookNameSchema", () => { //#then expect(result.success).toBe(false) }) + + test("rejects removed delegate-task-english-directive hook name", () => { + //#given + const input = "delegate-task-english-directive" + + //#when + const result = HookNameSchema.safeParse(input) + + //#then + expect(result.success).toBe(false) + }) }) describe("Sisyphus-Junior agent override", () => { diff --git a/src/config/schema/hooks.ts b/src/config/schema/hooks.ts index 776cf3d83..4acc37584 100644 --- a/src/config/schema/hooks.ts +++ b/src/config/schema/hooks.ts @@ -51,7 +51,6 @@ export const HookNameSchema = z.enum([ "anthropic-effort", "hashline-read-enhancer", "read-image-resizer", - "delegate-task-english-directive", ]) export type HookName = z.infer diff --git a/src/hooks/delegate-task-english-directive/hook.ts b/src/hooks/delegate-task-english-directive/hook.ts deleted file mode 100644 index 2397cd090..000000000 --- a/src/hooks/delegate-task-english-directive/hook.ts +++ /dev/null @@ -1,24 +0,0 @@ -export const TARGET_SUBAGENT_TYPES = ["explore", "librarian", "oracle", "plan"] as const - -export const ENGLISH_DIRECTIVE = - "**YOU MUST ALWAYS THINK, REASON, AND RESPOND IN ENGLISH REGARDLESS OF THE USER'S QUERY LANGUAGE.**" - -export function createDelegateTaskEnglishDirectiveHook() { - return { - "tool.execute.before": async ( - input: { tool: string; sessionID: string; callID: string; input: Record }, - _output: { title: string; output: string; metadata: unknown } - ) => { - if (input.tool.toLowerCase() !== "task") return - - const args = input.input - const subagentType = args.subagent_type - if (typeof subagentType !== "string") return - if (!TARGET_SUBAGENT_TYPES.includes(subagentType as (typeof TARGET_SUBAGENT_TYPES)[number])) return - - if (typeof args.prompt === "string") { - args.prompt = `${args.prompt}\n\n${ENGLISH_DIRECTIVE}` - } - }, - } -} diff --git a/src/hooks/delegate-task-english-directive/index.test.ts b/src/hooks/delegate-task-english-directive/index.test.ts deleted file mode 100644 index 38d6cadb8..000000000 --- a/src/hooks/delegate-task-english-directive/index.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { describe, expect, it } from "bun:test" - -import { createDelegateTaskEnglishDirectiveHook, ENGLISH_DIRECTIVE, TARGET_SUBAGENT_TYPES } from "./index" - -describe("delegate-task-english-directive", () => { - const hook = createDelegateTaskEnglishDirectiveHook() - const handler = hook["tool.execute.before"] - - describe("#given a task tool call with a targeted subagent_type", () => { - const targetTypes = ["explore", "librarian", "oracle", "plan"] - - for (const subagentType of targetTypes) { - describe(`#when subagent_type is "${subagentType}"`, () => { - it(`#then should append English directive to prompt`, async () => { - const originalPrompt = "Find auth patterns in the codebase" - const input = { tool: "Task", sessionID: "ses_123", callID: "call_1", input: { subagent_type: subagentType, prompt: originalPrompt } } - const output = { title: "", output: "", metadata: undefined } - - await handler(input, output) - - expect(input.input.prompt).toBe(`${originalPrompt}\n\n${ENGLISH_DIRECTIVE}`) - }) - }) - } - }) - - describe("#given a task tool call with a non-targeted subagent_type", () => { - describe("#when subagent_type is 'metis'", () => { - it("#then should not modify the prompt", async () => { - const originalPrompt = "Analyze this request" - const input = { tool: "Task", sessionID: "ses_123", callID: "call_1", input: { subagent_type: "metis", prompt: originalPrompt } } - const output = { title: "", output: "", metadata: undefined } - - await handler(input, output) - - expect(input.input.prompt).toBe(originalPrompt) - }) - }) - }) - - describe("#given a task tool call using category instead of subagent_type", () => { - describe("#when only category is provided", () => { - it("#then should not modify the prompt", async () => { - const originalPrompt = "Fix the button styling" - const input = { tool: "Task", sessionID: "ses_123", callID: "call_1", input: { category: "visual-engineering", prompt: originalPrompt } } - const output = { title: "", output: "", metadata: undefined } - - await handler(input, output) - - expect(input.input.prompt).toBe(originalPrompt) - }) - }) - }) - - describe("#given a non-task tool call", () => { - describe("#when tool is 'Bash'", () => { - it("#then should not modify anything", async () => { - const input = { tool: "Bash", sessionID: "ses_123", callID: "call_1", input: { command: "ls" } } - const output = { title: "", output: "", metadata: undefined } - - await handler(input, output) - - expect(input.input).toEqual({ command: "ls" }) - }) - }) - }) - - describe("#given a task tool call with empty prompt", () => { - describe("#when prompt is empty string", () => { - it("#then should still append directive", async () => { - const input = { tool: "Task", sessionID: "ses_123", callID: "call_1", input: { subagent_type: "explore", prompt: "" } } - const output = { title: "", output: "", metadata: undefined } - - await handler(input, output) - - expect(input.input.prompt).toBe(`\n\n${ENGLISH_DIRECTIVE}`) - }) - }) - }) - - describe("#given TARGET_SUBAGENT_TYPES constant", () => { - it("#then should contain exactly explore, librarian, oracle, and plan", () => { - expect(TARGET_SUBAGENT_TYPES).toEqual(["explore", "librarian", "oracle", "plan"]) - }) - }) - - describe("#given ENGLISH_DIRECTIVE constant", () => { - it("#then should be bold uppercase text", () => { - expect(ENGLISH_DIRECTIVE).toContain("**") - expect(ENGLISH_DIRECTIVE).toMatch(/[A-Z]/) - }) - - it("#then should instruct English-only thinking and responding", () => { - const lower = ENGLISH_DIRECTIVE.toLowerCase() - expect(lower).toContain("english") - }) - }) -}) diff --git a/src/hooks/delegate-task-english-directive/index.ts b/src/hooks/delegate-task-english-directive/index.ts deleted file mode 100644 index 2194a7264..000000000 --- a/src/hooks/delegate-task-english-directive/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { createDelegateTaskEnglishDirectiveHook, TARGET_SUBAGENT_TYPES, ENGLISH_DIRECTIVE } from "./hook" diff --git a/src/hooks/index.ts b/src/hooks/index.ts index e7b7d5995..77b2c3c13 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -52,4 +52,3 @@ export { createWriteExistingFileGuardHook } from "./write-existing-file-guard"; export { createHashlineReadEnhancerHook } from "./hashline-read-enhancer"; export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery"; export { createReadImageResizerHook } from "./read-image-resizer" -export { createDelegateTaskEnglishDirectiveHook } from "./delegate-task-english-directive" diff --git a/src/plugin/hooks/create-session-hooks.ts b/src/plugin/hooks/create-session-hooks.ts index 9dc763646..42f62bf9e 100644 --- a/src/plugin/hooks/create-session-hooks.ts +++ b/src/plugin/hooks/create-session-hooks.ts @@ -16,7 +16,6 @@ import { createRalphLoopHook, createEditErrorRecoveryHook, createDelegateTaskRetryHook, - createDelegateTaskEnglishDirectiveHook, createTaskResumeInfoHook, createStartWorkHook, createPrometheusMdOnlyHook, @@ -61,7 +60,6 @@ export type SessionHooks = { taskResumeInfo: ReturnType | null anthropicEffort: ReturnType | null runtimeFallback: ReturnType | null - delegateTaskEnglishDirective: ReturnType | null } export function createSessionHooks(args: { @@ -217,10 +215,6 @@ export function createSessionHooks(args: { ? safeHook("delegate-task-retry", () => createDelegateTaskRetryHook(ctx)) : null - const delegateTaskEnglishDirective = isHookEnabled("delegate-task-english-directive") - ? safeHook("delegate-task-english-directive", () => createDelegateTaskEnglishDirectiveHook()) - : null - const startWork = isHookEnabled("start-work") ? safeHook("start-work", () => createStartWorkHook(ctx)) : null @@ -282,7 +276,6 @@ export function createSessionHooks(args: { ralphLoop, editErrorRecovery, delegateTaskRetry, - delegateTaskEnglishDirective, startWork, prometheusMdOnly, sisyphusJuniorNotepad, diff --git a/src/shared/migration.test.ts b/src/shared/migration.test.ts index ee316c298..1d88861b7 100644 --- a/src/shared/migration.test.ts +++ b/src/shared/migration.test.ts @@ -1,3 +1,5 @@ +/// + import { describe, test, expect, afterEach } from "bun:test" import * as fs from "fs" import * as path from "path" @@ -400,6 +402,17 @@ describe("migrateConfigFile", () => { expect(rawConfig.disabled_hooks).not.toContain("anthropic-auto-compact") }) + test("removes deleted hook names from disabled_hooks", () => { + const rawConfig: Record = { + disabled_hooks: ["delegate-task-english-directive", "comment-checker"], + } + + const needsWrite = migrateConfigFile(testConfigPath, rawConfig) + + expect(needsWrite).toBe(true) + expect(rawConfig.disabled_hooks).toEqual(["comment-checker"]) + }) + test("does not write if no migration needed", () => { // given: Config with current names const rawConfig: Record = { diff --git a/src/shared/migration/hook-names.ts b/src/shared/migration/hook-names.ts index 3c0bba2eb..342206049 100644 --- a/src/shared/migration/hook-names.ts +++ b/src/shared/migration/hook-names.ts @@ -9,6 +9,7 @@ export const HOOK_NAME_MAP: Record = { // Removed hooks (v3.0.0) - will be filtered out and user warned "empty-message-sanitizer": null, + "delegate-task-english-directive": null, } export function migrateHookNames(