Browse Source

consolidate: share wrapped phase reminder from config/constants.ts

Two hooks (phase-reminder, post-file-tool-nudge) both injected the same
workflow reminder with duplicate wrapping and constant definitions.

- Add PHASE_REMINDER wrapped constant to config/constants.ts
- phase-reminder: import PHASE_REMINDER from config, drop local def
- post-file-tool-nudge: import PHASE_REMINDER, remove POST_FILE_TOOL_NUDGE,
  simplify append to template literal

Dedup in post-file-tool-nudge now checks the tag-wrapped reminder, which is
more precise than the raw text check.
adikpb 2 months ago
parent
commit
40c877dbc6

+ 2 - 0
src/config/constants.ts

@@ -95,6 +95,8 @@ export const DEFAULT_MAX_SUBAGENT_DEPTH = 3;
 // Workflow reminders
 export const PHASE_REMINDER_TEXT = `!IMPORTANT! Scheduler workflow: plan lanes/dependencies → dispatch background specialists → track task IDs → wait for hook-driven completion → reconcile terminal results → verify. Do not poll running jobs, consume running-job output, or advance dependent work. !END!`;
 
+export const PHASE_REMINDER = `<internal_reminder>${PHASE_REMINDER_TEXT}</internal_reminder>`;
+
 export const WRITABLE_FILE_OPERATIONS_RULES = `**File Operations Rules**:
 - Prefer dedicated file tools for normal code work: glob/grep/ast_grep_search for discovery, read for file contents, and edit/write/apply_patch for targeted source changes.
 - Use bash for execution and automation: git, package managers, tests, builds, scripts, diagnostics, and shell-native filesystem operations.

+ 3 - 19
src/hooks/phase-reminder/index.ts

@@ -5,27 +5,11 @@
  * mutating the cached system prompt or prepending request-local content ahead
  * of the user's actual turn.
  */
-import { PHASE_REMINDER_TEXT } from '../../config/constants';
+import { PHASE_REMINDER } from '../../config/constants';
 import { SLIM_INTERNAL_INITIATOR_MARKER } from '../../utils';
+import type { MessageWithParts } from '../types';
 
-export const PHASE_REMINDER = `<internal_reminder>${PHASE_REMINDER_TEXT}</internal_reminder>`;
-
-interface MessageInfo {
-  role: string;
-  agent?: string;
-  sessionID?: string;
-}
-
-interface MessagePart {
-  type: string;
-  text?: string;
-  [key: string]: unknown;
-}
-
-interface MessageWithParts {
-  info: MessageInfo;
-  parts: MessagePart[];
-}
+export { PHASE_REMINDER };
 
 /**
  * Creates the experimental.chat.messages.transform hook for phase reminder injection.

+ 3 - 11
src/hooks/post-file-tool-nudge/index.ts

@@ -3,9 +3,7 @@
  * Catches the "inspect/edit files → implement myself" anti-pattern.
  */
 
-import { PHASE_REMINDER_TEXT } from '../../config/constants';
-
-const POST_FILE_TOOL_NUDGE = PHASE_REMINDER_TEXT;
+import { PHASE_REMINDER } from '../../config/constants';
 
 interface ToolExecuteAfterInput {
   tool: string;
@@ -31,17 +29,11 @@ export function createPostFileToolNudgeHook(
       return;
     }
 
-    if (output.output.includes(POST_FILE_TOOL_NUDGE)) {
+    if (output.output.includes(PHASE_REMINDER)) {
       return;
     }
 
-    output.output = [
-      output.output,
-      '',
-      '<internal_reminder>',
-      POST_FILE_TOOL_NUDGE,
-      '</internal_reminder>',
-    ].join('\n');
+    output.output = `${output.output}\n\n${PHASE_REMINDER}`;
   }
 
   return {

+ 25 - 0
src/hooks/types.ts

@@ -0,0 +1,25 @@
+/**
+ * Shared message type shapes for the OpenCode plugin API's `messages` array.
+ *
+ * These types describe the structure of chat messages passed through
+ * `experimental.chat.messages.transform` and related hooks. All fields
+ * are unioned across the files that previously defined them privately —
+ * optional extras are harmless under structural typing.
+ */
+
+export type MessageInfo = {
+  role: string;
+  agent?: string;
+  sessionID?: string;
+};
+
+export type MessagePart = {
+  type: string;
+  text?: string;
+  [key: string]: unknown;
+};
+
+export type MessageWithParts = {
+  info: MessageInfo;
+  parts: MessagePart[];
+};