diff --git a/src/agents/anti-duplication.test.ts b/src/agents/anti-duplication.test.ts new file mode 100644 index 000000000..49137329a --- /dev/null +++ b/src/agents/anti-duplication.test.ts @@ -0,0 +1,92 @@ +/// + +import { describe, it, expect } from "bun:test" +import { buildAntiDuplicationSection } from "./dynamic-agent-prompt-builder" + +describe("buildAntiDuplicationSection", () => { + it("#given no arguments #when building anti-duplication section #then returns comprehensive rule section", () => { + //#given: no special configuration needed + + //#when: building the anti-duplication section + const result = buildAntiDuplicationSection() + + //#then: should contain the anti-duplication rule with all key concepts + expect(result).toContain("Anti-Duplication Rule") + expect(result).toContain("CRITICAL") + expect(result).toContain("DO NOT perform the same search yourself") + }) + + it("#given no arguments #when building #then explicitly forbids manual re-search after delegation", () => { + //#given: no special configuration + + //#when: building the section + const result = buildAntiDuplicationSection() + + //#then: should explicitly list forbidden behaviors + expect(result).toContain("FORBIDDEN") + expect(result).toContain("manually grep/search for the same information") + expect(result).toContain("Re-doing the research") + }) + + it("#given no arguments #when building #then allows non-overlapping work", () => { + //#given: no special configuration + + //#when: building the section + const result = buildAntiDuplicationSection() + + //#then: should explicitly allow non-overlapping work + expect(result).toContain("ALLOWED") + expect(result).toContain("non-overlapping work") + expect(result).toContain("work that doesn't depend on the delegated research") + }) + + it("#given no arguments #when building #then includes wait-for-results instructions", () => { + //#given: no special configuration + + //#when: building the section + const result = buildAntiDuplicationSection() + + //#then: should include instructions for waiting properly + expect(result).toContain("Wait for Results Properly") + expect(result).toContain("End your response") + expect(result).toContain("Wait for the completion notification") + expect(result).toContain("background_output") + }) + + it("#given no arguments #when building #then explains why this matters", () => { + //#given: no special configuration + + //#when: building the section + const result = buildAntiDuplicationSection() + + //#then: should explain the purpose + expect(result).toContain("Why This Matters") + expect(result).toContain("Wasted tokens") + expect(result).toContain("Confusion") + expect(result).toContain("Efficiency") + }) + + it("#given no arguments #when building #then provides code examples", () => { + //#given: no special configuration + + //#when: building the section + const result = buildAntiDuplicationSection() + + //#then: should include examples + expect(result).toContain("Example") + expect(result).toContain("WRONG") + expect(result).toContain("CORRECT") + expect(result).toContain("task(subagent_type=") + }) + + it("#given no arguments #when building #then uses proper markdown formatting", () => { + //#given: no special configuration + + //#when: building the section + const result = buildAntiDuplicationSection() + + //#then: should be wrapped in Anti_Duplication tag + expect(result).toContain("") + expect(result).toContain("") + }) +}) diff --git a/src/agents/atlas/atlas-prompt.test.ts b/src/agents/atlas/atlas-prompt.test.ts new file mode 100644 index 000000000..759f3ac8d --- /dev/null +++ b/src/agents/atlas/atlas-prompt.test.ts @@ -0,0 +1,118 @@ +import { describe, test, expect } from "bun:test" +import { ATLAS_SYSTEM_PROMPT } from "./default" +import { ATLAS_GPT_SYSTEM_PROMPT } from "./gpt" +import { ATLAS_GEMINI_SYSTEM_PROMPT } from "./gemini" + +describe("Atlas prompts auto-continue policy", () => { + test("default variant should forbid asking user for continuation confirmation", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + + // when + const lowerPrompt = prompt.toLowerCase() + + // then + expect(lowerPrompt).toContain("auto-continue policy") + expect(lowerPrompt).toContain("never ask the user") + expect(lowerPrompt).toContain("should i continue") + expect(lowerPrompt).toContain("proceed to next task") + expect(lowerPrompt).toContain("approval-style") + expect(lowerPrompt).toContain("auto-continue immediately") + }) + + test("gpt variant should forbid asking user for continuation confirmation", () => { + // given + const prompt = ATLAS_GPT_SYSTEM_PROMPT + + // when + const lowerPrompt = prompt.toLowerCase() + + // then + expect(lowerPrompt).toContain("auto-continue policy") + expect(lowerPrompt).toContain("never ask the user") + expect(lowerPrompt).toContain("should i continue") + expect(lowerPrompt).toContain("proceed to next task") + expect(lowerPrompt).toContain("approval-style") + expect(lowerPrompt).toContain("auto-continue immediately") + }) + + test("gemini variant should forbid asking user for continuation confirmation", () => { + // given + const prompt = ATLAS_GEMINI_SYSTEM_PROMPT + + // when + const lowerPrompt = prompt.toLowerCase() + + // then + expect(lowerPrompt).toContain("auto-continue policy") + expect(lowerPrompt).toContain("never ask the user") + expect(lowerPrompt).toContain("should i continue") + expect(lowerPrompt).toContain("proceed to next task") + expect(lowerPrompt).toContain("approval-style") + expect(lowerPrompt).toContain("auto-continue immediately") + }) + + test("all variants should require immediate continuation after verification passes", () => { + // given + const prompts = [ATLAS_SYSTEM_PROMPT, ATLAS_GPT_SYSTEM_PROMPT, ATLAS_GEMINI_SYSTEM_PROMPT] + + // when / then + for (const prompt of prompts) { + const lowerPrompt = prompt.toLowerCase() + expect(lowerPrompt).toMatch(/auto-continue immediately after verification/) + expect(lowerPrompt).toMatch(/immediately delegate next task/) + } + }) + + test("all variants should define when user interaction is actually needed", () => { + // given + const prompts = [ATLAS_SYSTEM_PROMPT, ATLAS_GPT_SYSTEM_PROMPT, ATLAS_GEMINI_SYSTEM_PROMPT] + + // when / then + for (const prompt of prompts) { + const lowerPrompt = prompt.toLowerCase() + expect(lowerPrompt).toMatch(/only pause.*truly blocked/) + expect(lowerPrompt).toMatch(/plan needs clarification|blocked by external/) + } + }) +}) + +describe("Atlas prompts plan path consistency", () => { + test("default variant should use .sisyphus/plans/{plan-name}.md path", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + + // when / then + expect(prompt).toContain(".sisyphus/plans/{plan-name}.md") + expect(prompt).not.toContain(".sisyphus/tasks/{plan-name}.yaml") + expect(prompt).not.toContain(".sisyphus/tasks/") + }) + + test("gpt variant should use .sisyphus/plans/{plan-name}.md path", () => { + // given + const prompt = ATLAS_GPT_SYSTEM_PROMPT + + // when / then + expect(prompt).toContain(".sisyphus/plans/{plan-name}.md") + expect(prompt).not.toContain(".sisyphus/tasks/") + }) + + test("gemini variant should use .sisyphus/plans/{plan-name}.md path", () => { + // given + const prompt = ATLAS_GEMINI_SYSTEM_PROMPT + + // when / then + expect(prompt).toContain(".sisyphus/plans/{plan-name}.md") + expect(prompt).not.toContain(".sisyphus/tasks/") + }) + + test("all variants should read plan file after verification", () => { + // given + const prompts = [ATLAS_SYSTEM_PROMPT, ATLAS_GPT_SYSTEM_PROMPT, ATLAS_GEMINI_SYSTEM_PROMPT] + + // when / then + for (const prompt of prompts) { + expect(prompt).toMatch(/read[\s\S]*?\.sisyphus\/plans\//) + } + }) +}) diff --git a/src/agents/atlas/default.ts b/src/agents/atlas/default.ts index 8bc360795..2f4f025a1 100644 --- a/src/agents/atlas/default.ts +++ b/src/agents/atlas/default.ts @@ -100,6 +100,29 @@ Every \`task()\` prompt MUST include ALL 6 sections: **If your prompt is under 30 lines, it's TOO SHORT.** + +## AUTO-CONTINUE POLICY (STRICT) + +**CRITICAL: NEVER ask the user "should I continue", "proceed to next task", or any approval-style questions between plan steps.** + +**You MUST auto-continue immediately after verification passes:** +- After any delegation completes and passes verification → Immediately delegate next task +- Do NOT wait for user input, do NOT ask "should I continue" +- Only pause or ask if you are truly blocked by missing information, an external dependency, or a critical failure + +**The only time you ask the user:** +- Plan needs clarification or modification before execution +- Blocked by an external dependency beyond your control +- Critical failure prevents any further progress + +**Auto-continue examples:** +- Task A done → Verify → Pass → Immediately start Task B +- Task fails → Retry 3x → Still fails → Document → Move to next independent task +- NEVER: "Should I continue to the next task?" + +**This is NOT optional. This is core to your role as orchestrator.** + + ## Step 0: Register Tracking diff --git a/src/agents/atlas/gemini.ts b/src/agents/atlas/gemini.ts index 48c5b1763..a742c34d7 100644 --- a/src/agents/atlas/gemini.ts +++ b/src/agents/atlas/gemini.ts @@ -117,6 +117,29 @@ Every \`task()\` prompt MUST include ALL 6 sections: **Minimum 30 lines per delegation prompt. Under 30 lines = the subagent WILL fail.** + +## AUTO-CONTINUE POLICY (STRICT) + +**CRITICAL: NEVER ask the user "should I continue", "proceed to next task", or any approval-style questions between plan steps.** + +**You MUST auto-continue immediately after verification passes:** +- After any delegation completes and passes verification → Immediately delegate next task +- Do NOT wait for user input, do NOT ask "should I continue" +- Only pause or ask if you are truly blocked by missing information, an external dependency, or a critical failure + +**The only time you ask the user:** +- Plan needs clarification or modification before execution +- Blocked by an external dependency beyond your control +- Critical failure prevents any further progress + +**Auto-continue examples:** +- Task A done → Verify → Pass → Immediately start Task B +- Task fails → Retry 3x → Still fails → Document → Move to next independent task +- NEVER: "Should I continue to the next task?" + +**This is NOT optional. This is core to your role as orchestrator.** + + ## Step 0: Register Tracking diff --git a/src/agents/atlas/gpt.ts b/src/agents/atlas/gpt.ts index 2549075a5..dcd737068 100644 --- a/src/agents/atlas/gpt.ts +++ b/src/agents/atlas/gpt.ts @@ -40,9 +40,10 @@ Implementation tasks are the means. Final Wave approval is the goal. -- If a task is ambiguous or underspecified: +- During initial plan analysis, if a task is ambiguous or underspecified: - Ask 1-3 precise clarifying questions, OR - State your interpretation explicitly and proceed with the simplest approach. +- Once execution has started, do NOT stop to ask for continuation or approval between steps. - Never fabricate task details, file paths, or requirements. - Prefer language like "Based on the plan..." instead of absolute claims. - When unsure about parallelization, default to sequential execution. @@ -126,6 +127,29 @@ Every \`task()\` prompt MUST include ALL 6 sections: **Minimum 30 lines per delegation prompt.** + +## AUTO-CONTINUE POLICY (STRICT) + +**CRITICAL: NEVER ask the user "should I continue", "proceed to next task", or any approval-style questions between plan steps.** + +**You MUST auto-continue immediately after verification passes:** +- After any delegation completes and passes verification → Immediately delegate next task +- Do NOT wait for user input, do NOT ask "should I continue" +- Only pause or ask if you are truly blocked by missing information, an external dependency, or a critical failure + +**The only time you ask the user:** +- Plan needs clarification or modification before execution +- Blocked by an external dependency beyond your control +- Critical failure prevents any further progress + +**Auto-continue examples:** +- Task A done → Verify → Pass → Immediately start Task B +- Task fails → Retry 3x → Still fails → Document → Move to next independent task +- NEVER: "Should I continue to the next task?" + +**This is NOT optional. This is core to your role as orchestrator.** + + ## Step 0: Register Tracking diff --git a/src/agents/delegation-trust-prompt.test.ts b/src/agents/delegation-trust-prompt.test.ts new file mode 100644 index 000000000..03c4ea49a --- /dev/null +++ b/src/agents/delegation-trust-prompt.test.ts @@ -0,0 +1,145 @@ +import { describe, expect, test } from "bun:test" +import { createSisyphusAgent } from "./sisyphus" +import { createHephaestusAgent } from "./hephaestus" +import { buildSisyphusJuniorPrompt } from "./sisyphus-junior/agent" +import { + buildAntiDuplicationSection, + buildExploreSection, + type AvailableAgent, +} from "./dynamic-agent-prompt-builder" + +const exploreAgent = { + name: "explore", + description: "Contextual grep specialist", + metadata: { + category: "advisor", + cost: "FREE", + promptAlias: "Explore", + triggers: [], + useWhen: ["Multiple search angles needed"], + avoidWhen: ["Single keyword search is enough"], + }, +} satisfies AvailableAgent + +describe("delegation trust prompt rules", () => { + test("buildAntiDuplicationSection explains overlap is forbidden", () => { + // given + const section = buildAntiDuplicationSection() + + // when / then + expect(section).toContain("DO NOT perform the same search yourself") + expect(section).toContain("non-overlapping work") + expect(section).toContain("End your response") + }) + + test("buildExploreSection includes delegation trust rule", () => { + // given + const agents = [exploreAgent] + + // when + const section = buildExploreSection(agents) + + // then + expect(section).toContain("Delegation Trust Rule") + expect(section).toContain("do **not** manually perform that same search yourself") + }) + + test("Sisyphus prompt forbids duplicate delegated exploration", () => { + // given + const agent = createSisyphusAgent("anthropic/claude-sonnet-4-6", [exploreAgent]) + + // when + const prompt = agent.prompt + + // then + expect(prompt).toContain("Continue only with non-overlapping work") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Hephaestus prompt forbids duplicate delegated exploration", () => { + // given + const agent = createHephaestusAgent("openai/gpt-5.2", [exploreAgent]) + + // when + const prompt = agent.prompt + + // then + expect(prompt).toContain("Continue only with non-overlapping work after launching background agents") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Hephaestus GPT-5.4 prompt forbids duplicate delegated exploration", () => { + // given + const agent = createHephaestusAgent("openai/gpt-5.4", [exploreAgent]) + + // when + const prompt = agent.prompt + + // then + expect(prompt).toContain("continue only with non-overlapping work while they search") + expect(prompt).toContain("Continue only with non-overlapping work after launching background agents") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Hephaestus GPT-5.3 Codex prompt forbids duplicate delegated exploration", () => { + // given + const agent = createHephaestusAgent("openai/gpt-5.3-codex", [exploreAgent]) + + // when + const prompt = agent.prompt + + // then + expect(prompt).toContain("continue only with non-overlapping work while they search") + expect(prompt).toContain("Continue only with non-overlapping work after launching background agents") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Sisyphus-Junior GPT prompt forbids duplicate delegated exploration", () => { + // given + const prompt = buildSisyphusJuniorPrompt("openai/gpt-5.2", false) + + // when / then + expect(prompt).toContain("continue only with non-overlapping work while they search") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Sisyphus GPT-5.4 prompt forbids duplicate delegated exploration", () => { + // given + const agent = createSisyphusAgent("openai/gpt-5.4", [exploreAgent]) + + // when + const prompt = agent.prompt + + // then + expect(prompt).toContain("do only non-overlapping work simultaneously") + expect(prompt).toContain("Continue only with non-overlapping work") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Sisyphus-Junior GPT-5.4 prompt forbids duplicate delegated exploration", () => { + // given + const prompt = buildSisyphusJuniorPrompt("openai/gpt-5.4", false) + + // when / then + expect(prompt).toContain("continue only with non-overlapping work while they search") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Sisyphus-Junior GPT-5.3 Codex prompt forbids duplicate delegated exploration", () => { + // given + const prompt = buildSisyphusJuniorPrompt("openai/gpt-5.3-codex", false) + + // when / then + expect(prompt).toContain("continue only with non-overlapping work while they search") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) + + test("Sisyphus-Junior Gemini prompt forbids duplicate delegated exploration", () => { + // given + const prompt = buildSisyphusJuniorPrompt("google/gemini-3.1-pro", false) + + // when / then + expect(prompt).toContain("continue only with non-overlapping work while they search") + expect(prompt).toContain("DO NOT perform the same search yourself") + }) +}) diff --git a/src/agents/dynamic-agent-prompt-builder.ts b/src/agents/dynamic-agent-prompt-builder.ts index c08b3c120..fc3a9fddf 100644 --- a/src/agents/dynamic-agent-prompt-builder.ts +++ b/src/agents/dynamic-agent-prompt-builder.ts @@ -118,6 +118,8 @@ export function buildExploreSection(agents: AvailableAgent[]): string { Use it as a **peer tool**, not a fallback. Fire liberally for discovery, not for files you already know. +**Delegation Trust Rule:** Once you fire an explore agent for a search, do **not** manually perform that same search yourself. Use direct tools only for non-overlapping work or when you intentionally skipped delegation. + **Use Direct Tools when:** ${avoidWhen.map((w) => `- ${w}`).join("\n")} @@ -335,6 +337,7 @@ export function buildAntiPatternsSection(): string { "- **Search**: Firing agents for single-line typos or obvious syntax errors", "- **Debugging**: Shotgun debugging, random changes", "- **Background Tasks**: Polling `background_output` on running tasks — end response and wait for notification", + "- **Delegation Duplication**: Delegating exploration to explore/librarian and then manually doing the same search yourself", "- **Oracle**: Delivering answer without collecting Oracle results", ] @@ -470,3 +473,52 @@ export function buildUltraworkSection( return lines.join("\n") } + +// Anti-duplication section for agent prompts +export function buildAntiDuplicationSection(): string { + return ` +## Anti-Duplication Rule (CRITICAL) + +Once you delegate exploration to explore/librarian agents, **DO NOT perform the same search yourself**. + +### What this means: + +**FORBIDDEN:** +- After firing explore/librarian, manually grep/search for the same information +- Re-doing the research the agents were just tasked with +- "Just quickly checking" the same files the background agents are checking + +**ALLOWED:** +- Continue with **non-overlapping work** — work that doesn't depend on the delegated research +- Work on unrelated parts of the codebase +- Preparation work (e.g., setting up files, configs) that can proceed independently + +### Wait for Results Properly: + +When you need the delegated results but they're not ready: + +1. **End your response** — do NOT continue with work that depends on those results +2. **Wait for the completion notification** — the system will trigger your next turn +3. **Then** collect results via \`background_output(task_id="...")\` +4. **Do NOT** impatiently re-search the same topics while waiting + +### Why This Matters: + +- **Wasted tokens**: Duplicate exploration wastes your context budget +- **Confusion**: You might contradict the agent's findings +- **Efficiency**: The whole point of delegation is parallel throughput + +### Example: + +\`\`\`typescript +// WRONG: After delegating, re-doing the search +task(subagent_type="explore", run_in_background=true, ...) +// Then immediately grep for the same thing yourself — FORBIDDEN + +// CORRECT: Continue non-overlapping work +task(subagent_type="explore", run_in_background=true, ...) +// Work on a different, unrelated file while they search +// End your response and wait for the notification +\`\`\` +` +} diff --git a/src/agents/hephaestus/gpt-5-3-codex.ts b/src/agents/hephaestus/gpt-5-3-codex.ts index 7c497b901..9a5e43b18 100644 --- a/src/agents/hephaestus/gpt-5-3-codex.ts +++ b/src/agents/hephaestus/gpt-5-3-codex.ts @@ -18,6 +18,7 @@ import { buildHardBlocksSection, buildAntiPatternsSection, buildToolCallFormatSection, + buildAntiDuplicationSection, categorizeTools, } from "../dynamic-agent-prompt-builder"; const MODE: AgentMode = "all"; @@ -156,7 +157,7 @@ Asking the user is the LAST resort after exhausting creative alternatives. - Run verification (lint, tests, build) WITHOUT asking - Make decisions. Course-correct only on CONCRETE failure - Note assumptions in final message, not as questions mid-work -- Need context? Fire explore/librarian in background IMMEDIATELY — keep working while they search +- Need context? Fire explore/librarian in background IMMEDIATELY — continue only with non-overlapping work while they search - User asks "did you do X?" and you didn't → Acknowledge briefly, DO X immediately - User asks a question implying work → Answer briefly, DO the implied work in the same turn - You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines @@ -292,11 +293,13 @@ Prompt structure for each agent: - Fire 2-5 explore agents in parallel for any non-trivial codebase question - Parallelize independent file reads — don't read files one at a time - NEVER use \`run_in_background=false\` for explore/librarian -- Continue your work immediately after launching background agents +- Continue only with non-overlapping work after launching background agents - Collect results with \`background_output(task_id="...")\` when needed - BEFORE final answer, cancel DISPOSABLE tasks individually: \`background_cancel(taskId="bg_explore_xxx")\`, \`background_cancel(taskId="bg_librarian_xxx")\` - **NEVER use \`background_cancel(all=true)\`** — it kills tasks whose results you haven't collected yet +${buildAntiDuplicationSection()} + ### Search Stop Conditions STOP searching when: diff --git a/src/agents/hephaestus/gpt-5-4.ts b/src/agents/hephaestus/gpt-5-4.ts index 8a11cf8b8..43fd0b787 100644 --- a/src/agents/hephaestus/gpt-5-4.ts +++ b/src/agents/hephaestus/gpt-5-4.ts @@ -16,6 +16,7 @@ import { buildOracleSection, buildHardBlocksSection, buildAntiPatternsSection, + buildAntiDuplicationSection, } from "../dynamic-agent-prompt-builder"; function buildTodoDisciplineSection(useTaskSystem: boolean): string { @@ -115,7 +116,7 @@ When blocked: try a different approach → decompose the problem → challenge a - Run verification (lint, tests, build) WITHOUT asking - Make decisions. Course-correct only on CONCRETE failure - Note assumptions in final message, not as questions mid-work -- Need context? Fire explore/librarian in background IMMEDIATELY — keep working while they search +- Need context? Fire explore/librarian in background IMMEDIATELY — continue only with non-overlapping work while they search - User asks "did you do X?" and you didn't → Acknowledge briefly, DO X immediately - User asks a question implying work → Answer briefly, DO the implied work in the same turn - You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines @@ -241,11 +242,13 @@ Prompt structure for each agent: - Fire 2-5 explore agents in parallel for any non-trivial codebase question - Parallelize independent file reads — don't read files one at a time - NEVER use \`run_in_background=false\` for explore/librarian -- Continue your work immediately after launching background agents +- Continue only with non-overlapping work after launching background agents - Collect results with \`background_output(task_id="...")\` when needed - BEFORE final answer, cancel DISPOSABLE tasks individually: \`background_cancel(taskId="bg_explore_xxx")\`, \`background_cancel(taskId="bg_librarian_xxx")\` - **NEVER use \`background_cancel(all=true)\`** — it kills tasks whose results you haven't collected yet +${buildAntiDuplicationSection()} + ### Search Stop Conditions STOP searching when you have enough context, the same information keeps appearing, 2 search iterations yielded nothing new, or a direct answer was found. Do not over-explore. diff --git a/src/agents/hephaestus/gpt.ts b/src/agents/hephaestus/gpt.ts index c2c9a3957..c29d69609 100644 --- a/src/agents/hephaestus/gpt.ts +++ b/src/agents/hephaestus/gpt.ts @@ -16,6 +16,7 @@ import { buildOracleSection, buildHardBlocksSection, buildAntiPatternsSection, + buildAntiDuplicationSection, } from "../dynamic-agent-prompt-builder"; function buildTodoDisciplineSection(useTaskSystem: boolean): string { @@ -109,7 +110,7 @@ Asking the user is the LAST resort after exhausting creative alternatives. - Run verification (lint, tests, build) WITHOUT asking - Make decisions. Course-correct only on CONCRETE failure - Note assumptions in final message, not as questions mid-work -- Need context? Fire explore/librarian in background IMMEDIATELY — keep working while they search +- Need context? Fire explore/librarian in background IMMEDIATELY — continue only with non-overlapping work while they search ## Hard Constraints @@ -194,11 +195,13 @@ task(subagent_type="librarian", run_in_background=true, load_skills=[], descript - Fire 2-5 explore agents in parallel for any non-trivial codebase question - Parallelize independent file reads — don't read files one at a time - NEVER use \`run_in_background=false\` for explore/librarian -- Continue your work immediately after launching background agents +- Continue only with non-overlapping work after launching background agents - Collect results with \`background_output(task_id="...")\` when needed - BEFORE final answer, cancel DISPOSABLE tasks individually - **NEVER use \`background_cancel(all=true)\`** +${buildAntiDuplicationSection()} + ### Search Stop Conditions STOP searching when: diff --git a/src/agents/sisyphus-junior/gemini.ts b/src/agents/sisyphus-junior/gemini.ts index e6c727b53..b4b10980b 100644 --- a/src/agents/sisyphus-junior/gemini.ts +++ b/src/agents/sisyphus-junior/gemini.ts @@ -9,6 +9,7 @@ */ import { resolvePromptAppend } from "../builtin-agents/resolve-file-uri" +import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder" export function buildGeminiSisyphusJuniorPrompt( useTaskSystem: boolean, @@ -58,7 +59,7 @@ Before responding, ask yourself: What tools do I need to call? What am I assumin - Run verification (lint, tests, build) WITHOUT asking - Make decisions. Course-correct only on CONCRETE failure - Note assumptions in final message, not as questions mid-work -- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — keep working while they search +- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — continue only with non-overlapping work while they search ## Scope Discipline @@ -77,13 +78,15 @@ Before responding, ask yourself: What tools do I need to call? What am I assumin - Parallelize independent tool calls: multiple file reads, grep searches, agent fires — all at once -- Explore/Librarian via call_omo_agent = background research. Fire them and keep working +- Explore/Librarian via call_omo_agent = background research. Fire them and continue only with non-overlapping work - After any file edit: restate what changed, where, and what validation follows - Prefer tools over guessing whenever you need specific data (files, configs, patterns) - ALWAYS use tools over internal knowledge for file contents, project state, and verification - **DO NOT SKIP tool calls because you think you already know the answer. You DON'T.** +${buildAntiDuplicationSection()} + ${taskDiscipline} ## Progress Updates diff --git a/src/agents/sisyphus-junior/gpt-5-3-codex.ts b/src/agents/sisyphus-junior/gpt-5-3-codex.ts index 1388b8079..e1dc8fff8 100644 --- a/src/agents/sisyphus-junior/gpt-5-3-codex.ts +++ b/src/agents/sisyphus-junior/gpt-5-3-codex.ts @@ -7,6 +7,7 @@ */ import { resolvePromptAppend } from "../builtin-agents/resolve-file-uri" +import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder" export function buildGpt53CodexSisyphusJuniorPrompt( useTaskSystem: boolean, @@ -40,7 +41,7 @@ When blocked: try a different approach → decompose the problem → challenge a - Run verification (lint, tests, build) WITHOUT asking - Make decisions. Course-correct only on CONCRETE failure - Note assumptions in final message, not as questions mid-work -- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — keep working while they search +- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — continue only with non-overlapping work while they search ## Scope Discipline @@ -58,12 +59,14 @@ When blocked: try a different approach → decompose the problem → challenge a - Parallelize independent tool calls: multiple file reads, grep searches, agent fires — all at once -- Explore/Librarian via call_omo_agent = background research. Fire them and keep working +- Explore/Librarian via call_omo_agent = background research. Fire them and continue only with non-overlapping work - After any file edit: restate what changed, where, and what validation follows - Prefer tools over guessing whenever you need specific data (files, configs, patterns) - ALWAYS use tools over internal knowledge for file contents, project state, and verification +${buildAntiDuplicationSection()} + ${taskDiscipline} ## Progress Updates diff --git a/src/agents/sisyphus-junior/gpt-5-4.ts b/src/agents/sisyphus-junior/gpt-5-4.ts index 00126c051..199942c94 100644 --- a/src/agents/sisyphus-junior/gpt-5-4.ts +++ b/src/agents/sisyphus-junior/gpt-5-4.ts @@ -10,6 +10,7 @@ */ import { resolvePromptAppend } from "../builtin-agents/resolve-file-uri"; +import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder"; export function buildGpt54SisyphusJuniorPrompt( useTaskSystem: boolean, @@ -43,7 +44,7 @@ When blocked: try a different approach → decompose the problem → challenge a - Run verification (lint, tests, build) WITHOUT asking - Make decisions. Course-correct only on CONCRETE failure - Note assumptions in final message, not as questions mid-work -- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — keep working while they search +- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — continue only with non-overlapping work while they search ## Scope Discipline @@ -62,12 +63,14 @@ When blocked: try a different approach → decompose the problem → challenge a - Parallelize independent tool calls: multiple file reads, grep searches, agent fires — all at once -- Explore/Librarian via call_omo_agent = background research. Fire them and keep working +- Explore/Librarian via call_omo_agent = background research. Fire them and continue only with non-overlapping work - After any file edit: restate what changed, where, and what validation follows - Prefer tools over guessing whenever you need specific data (files, configs, patterns) - ALWAYS use tools over internal knowledge for file contents, project state, and verification +${buildAntiDuplicationSection()} + ${taskDiscipline} ## Progress Updates diff --git a/src/agents/sisyphus-junior/gpt.ts b/src/agents/sisyphus-junior/gpt.ts index e53926625..0b0ac3ea3 100644 --- a/src/agents/sisyphus-junior/gpt.ts +++ b/src/agents/sisyphus-junior/gpt.ts @@ -8,6 +8,7 @@ */ import { resolvePromptAppend } from "../builtin-agents/resolve-file-uri" +import { buildAntiDuplicationSection } from "../dynamic-agent-prompt-builder" export function buildGptSisyphusJuniorPrompt( useTaskSystem: boolean, @@ -41,7 +42,7 @@ When blocked: try a different approach → decompose the problem → challenge a - Run verification (lint, tests, build) WITHOUT asking - Make decisions. Course-correct only on CONCRETE failure - Note assumptions in final message, not as questions mid-work -- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — keep working while they search +- Need context? Fire explore/librarian via call_omo_agent IMMEDIATELY — continue only with non-overlapping work while they search ## Scope Discipline @@ -59,12 +60,14 @@ When blocked: try a different approach → decompose the problem → challenge a - Parallelize independent tool calls: multiple file reads, grep searches, agent fires — all at once -- Explore/Librarian via call_omo_agent = background research. Fire them and keep working +- Explore/Librarian via call_omo_agent = background research. Fire them and continue only with non-overlapping work - After any file edit: restate what changed, where, and what validation follows - Prefer tools over guessing whenever you need specific data (files, configs, patterns) - ALWAYS use tools over internal knowledge for file contents, project state, and verification +${buildAntiDuplicationSection()} + ${taskDiscipline} ## Progress Updates diff --git a/src/agents/sisyphus.ts b/src/agents/sisyphus.ts index 088c86b2b..dcb6bd260 100644 --- a/src/agents/sisyphus.ts +++ b/src/agents/sisyphus.ts @@ -37,6 +37,7 @@ import { buildAntiPatternsSection, buildParallelDelegationSection, buildNonClaudePlannerSection, + buildAntiDuplicationSection, categorizeTools, } from "./dynamic-agent-prompt-builder"; @@ -225,17 +226,21 @@ task(subagent_type="explore", run_in_background=true, load_skills=[], descriptio // Reference Grep (external) task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find JWT security docs", prompt="I'm implementing JWT auth and need current security best practices to choose token storage (httpOnly cookies vs localStorage) and set expiration policy. Find: OWASP auth guidelines, recommended token lifetimes, refresh token rotation strategies, common JWT vulnerabilities. Skip 'what is JWT' tutorials — production security guidance only.") task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find Express auth patterns", prompt="I'm building Express auth middleware and need production-quality patterns to structure my middleware chain. Find how established Express apps (1000+ stars) handle: middleware ordering, token refresh, role-based access control, auth error propagation. Skip basic tutorials — I need battle-tested patterns with proper error handling.") +// Continue only with non-overlapping work. If none exists, end your response and wait for completion. // WRONG: Sequential or blocking result = task(..., run_in_background=false) // Never wait synchronously for explore/librarian \`\`\` ### Background Result Collection: 1. Launch parallel agents \u2192 receive task_ids -2. If you have DIFFERENT independent work \u2192 do it now -3. Otherwise \u2192 **END YOUR RESPONSE.** -4. System sends \`\` on completion \u2192 triggers your next turn -5. Collect via \`background_output(task_id="...")\` -6. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\` +2. Continue only with non-overlapping work + - If you have DIFFERENT independent work \u2192 do it now + - Otherwise \u2192 **END YOUR RESPONSE.** +3. System sends \`\` on each task completion — then call \`background_output(task_id="...")\` +4. Need results not yet ready? **End your response.** The notification will trigger your next turn. +5. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\` + +${buildAntiDuplicationSection()} ### Search Stop Conditions diff --git a/src/agents/sisyphus/default.ts b/src/agents/sisyphus/default.ts index 043d4adf9..5293225c2 100644 --- a/src/agents/sisyphus/default.ts +++ b/src/agents/sisyphus/default.ts @@ -21,6 +21,7 @@ import { buildAntiPatternsSection, buildParallelDelegationSection, buildNonClaudePlannerSection, + buildAntiDuplicationSection, categorizeTools, } from "../dynamic-agent-prompt-builder"; @@ -319,7 +320,7 @@ task(subagent_type="explore", run_in_background=true, load_skills=[], descriptio // Reference Grep (external) task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find JWT security docs", prompt="I'm implementing JWT auth and need current security best practices to choose token storage (httpOnly cookies vs localStorage) and set expiration policy. Find: OWASP auth guidelines, recommended token lifetimes, refresh token rotation strategies, common JWT vulnerabilities. Skip 'what is JWT' tutorials — production security guidance only.") task(subagent_type="librarian", run_in_background=true, load_skills=[], description="Find Express auth patterns", prompt="I'm building Express auth middleware and need production-quality patterns to structure my middleware chain. Find how established Express apps (1000+ stars) handle: middleware ordering, token refresh, role-based access control, auth error propagation. Skip basic tutorials — I need battle-tested patterns with proper error handling.") -// Continue working immediately. System notifies on completion — collect with background_output then. +// Continue only with non-overlapping work. If none exists, end your response and wait for completion. // WRONG: Sequential or blocking result = task(..., run_in_background=false) // Never wait synchronously for explore/librarian @@ -327,11 +328,14 @@ result = task(..., run_in_background=false) // Never wait synchronously for exp ### Background Result Collection: 1. Launch parallel agents → receive task_ids -2. If you have DIFFERENT independent work → do it now -3. Otherwise → **END YOUR RESPONSE.** -4. System sends \`\` on completion → triggers your next turn -5. Collect via \`background_output(task_id="...")\` -6. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\` +2. Continue only with non-overlapping work + - If you have DIFFERENT independent work → do it now + - Otherwise → **END YOUR RESPONSE.** +3. System sends \`\` on completion → triggers your next turn +4. Collect via \`background_output(task_id="...")\` +5. Cleanup: Cancel disposable tasks individually via \`background_cancel(taskId="...")\` + +${buildAntiDuplicationSection()} ### Search Stop Conditions diff --git a/src/agents/sisyphus/gpt-5-4.ts b/src/agents/sisyphus/gpt-5-4.ts index 05e85a3ac..0a1299dbd 100644 --- a/src/agents/sisyphus/gpt-5-4.ts +++ b/src/agents/sisyphus/gpt-5-4.ts @@ -37,6 +37,7 @@ import { buildOracleSection, buildHardBlocksSection, buildAntiPatternsSection, + buildAntiDuplicationSection, buildNonClaudePlannerSection, categorizeTools, } from "../dynamic-agent-prompt-builder"; @@ -233,7 +234,7 @@ ${librarianSection} - Fire 2-5 explore/librarian agents in parallel for any non-trivial codebase question. - Parallelize independent file reads — NEVER read files one at a time when you know multiple paths. -- When delegating AND doing direct work: do both simultaneously. +- When delegating AND doing direct work: do only non-overlapping work simultaneously. Explore and Librarian agents are background grep — always \`run_in_background=true\`, always parallel. @@ -246,11 +247,14 @@ Each agent prompt should include: Background result collection: 1. Launch parallel agents → receive task_ids -2. If you have DIFFERENT independent work → do it now -3. Otherwise → **END YOUR RESPONSE.** -4. System sends \`\` on completion → triggers your next turn -5. Collect via \`background_output(task_id="...")\` -6. Cancel disposable tasks individually via \`background_cancel(taskId="...")\` +2. Continue only with non-overlapping work + - If you have DIFFERENT independent work → do it now + - Otherwise → **END YOUR RESPONSE.** +3. System sends \`\` on completion → triggers your next turn +4. Collect via \`background_output(task_id="...")\` +5. Cancel disposable tasks individually via \`background_cancel(taskId="...")\` + +${buildAntiDuplicationSection()} Stop searching when: you have enough context, same info repeating, 2 iterations with no new data, or direct answer found. `; diff --git a/src/tools/background-task/create-background-output.ts b/src/tools/background-task/create-background-output.ts index e12cfa9aa..a3e4931ed 100644 --- a/src/tools/background-task/create-background-output.ts +++ b/src/tools/background-task/create-background-output.ts @@ -87,7 +87,6 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client: const shouldBlock = args.block === true const timeoutMs = Math.min(args.timeout ?? 60000, 600000) - const fullSession = args.full_session ?? true let resolvedTask = task @@ -123,6 +122,10 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client: } const isActive = isTaskActiveStatus(resolvedTask.status) + const fullSessionProvided = args.full_session !== undefined + const fullSession = fullSessionProvided + ? (args.full_session ?? true) + : !isActive const includeThinking = isActive || (args.include_thinking ?? false) const includeToolResults = isActive || (args.include_tool_results ?? false)