Browse Source

Remove task-rejection instructions from custom agent prompts

Alvin Unreal 2 weeks ago
parent
commit
d19669ded6

+ 2 - 3
src/agents/custom.test.ts

@@ -1,7 +1,6 @@
 import { describe, expect, spyOn, test } from 'bun:test';
 import { DEFAULT_MODELS, type PluginConfig } from '../config';
 import { createAgents, getAgentConfigs } from './index';
-import { TASK_REJECTION_INSTRUCTION } from './task-rejection';
 
 describe('custom-agent creation', () => {
   test('infers custom agents from unknown keys', () => {
@@ -24,7 +23,7 @@ describe('custom-agent creation', () => {
     expect(customAgent).toBeDefined();
     expect(customAgent?.config.model).toBe('openai/gpt-5.6');
     expect(customAgent?.config.prompt).toBe(
-      `You are the custom reviewer agent.\n\n${TASK_REJECTION_INSTRUCTION}`,
+      'You are the custom reviewer agent.',
     );
   });
 
@@ -45,7 +44,7 @@ describe('custom-agent creation', () => {
 
     expect(customAgent).toBeDefined();
     expect(customAgent?.config.prompt).toBe(
-      `You are a custom subagent for auditing.\n\n${TASK_REJECTION_INSTRUCTION}`,
+      'You are a custom subagent for auditing.',
     );
 
     const orchestrator = agents.find((agent) => agent.name === 'orchestrator');

+ 10 - 6
src/agents/index.test.ts

@@ -468,7 +468,7 @@ describe('agent classification', () => {
 });
 
 describe('createAgents', () => {
-  test('adds task-rejection instructions to every subagent after prompt resolution', () => {
+  test('keeps task-rejection instructions in default subagent prompts without modifying replacements', () => {
     const agents = createAgents({
       disabled_agents: [],
       council: councilConfig(),
@@ -496,9 +496,7 @@ describe('createAgents', () => {
     const orchestrator = agents.find((agent) => agent.name === 'orchestrator');
     const explorer = agents.find((agent) => agent.name === 'explorer');
 
-    expect(explorer?.config.prompt).toBe(
-      `Replacement explorer prompt.\n\n${TASK_REJECTION_INSTRUCTION}`,
-    );
+    expect(explorer?.config.prompt).toBe('Replacement explorer prompt.');
     expect(orchestrator?.config.prompt).not.toContain(
       TASK_REJECTION_INSTRUCTION,
     );
@@ -513,8 +511,14 @@ describe('createAgents', () => {
       ]),
     );
 
-    for (const agent of agents.filter(
-      (agent) => agent.name !== 'orchestrator',
+    for (const agent of agents.filter((agent) =>
+      [
+        'observer',
+        'council',
+        'councillor',
+        'councillor-alpha',
+        'bridge',
+      ].includes(agent.name),
     )) {
       expect(agent.config.prompt).toContain(TASK_REJECTION_INSTRUCTION);
     }

+ 8 - 3
src/agents/index.ts

@@ -232,7 +232,10 @@ function buildCustomAgentDefinition(
   filePrompt?: string,
   fileAppendPrompt?: string,
 ): AgentDefinition {
-  const basePrompt = override.prompt ?? `You are the ${name} specialist.`;
+  const defaultPrompt = appendTaskRejectionInstruction(
+    `You are the ${name} specialist.`,
+  );
+  const basePrompt = override.prompt ?? defaultPrompt;
   const primaryModel = getPrimaryModelFromOverride(override);
 
   return {
@@ -389,7 +392,9 @@ export function createAgents(
 
       const override = getAgentOverride(config, name);
       const inlinePrompt = override?.prompt;
-      const defaultPrompt = agent.config.prompt ?? '';
+      const defaultPrompt = appendTaskRejectionInstruction(
+        agent.config.prompt ?? '',
+      );
 
       const basePrompt =
         inlinePrompt !== undefined ? inlinePrompt : defaultPrompt;
@@ -509,7 +514,7 @@ export function createAgents(
     ...councillorAgents,
   ];
 
-  for (const agent of allSubAgents) {
+  for (const agent of [...acpSubAgents, ...councillorAgents]) {
     agent.config.prompt = appendTaskRejectionInstruction(
       agent.config.prompt ?? '',
     );

+ 1 - 1
src/hooks/__snapshots__/cache-payload.snapshot.test.ts.snap

@@ -151,7 +151,7 @@ Balance: respect dependencies, avoid parallelizing what must be sequential, and
 ### Background Task Discipline
 - Prefer \`task(..., background: true)\` for delegated work that can run independently.
 - For work already chosen for delegation, launch independent specialist lanes in the background so the orchestrator stays unblocked and can reconcile results when they return.
-- Track each task's specialist, objective, task/session ID, and file/topic ownership.
+- Never reissue an unchanged task to the same specialist after a rejection; adjust its scope or context before retrying.
 - Continue orchestration only on non-overlapping work; otherwise briefly report what was launched and stop.
 - Before local edits or another writer task, compare against running task scopes.
 - Parallel background tasks are allowed only when their write scopes do not conflict.