feat(hooks): add read-only warning injection for Prometheus task delegation
When Prometheus (Planner) spawns subagents via task tools (sisyphus_task, task, call_omo_agent), a system directive is injected into the prompt to ensure subagents understand they are in a planning consultation context and must NOT modify files. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
@@ -7,3 +7,24 @@ export const ALLOWED_EXTENSIONS = [".md"]
|
||||
export const ALLOWED_PATH_PREFIX = ".sisyphus/"
|
||||
|
||||
export const BLOCKED_TOOLS = ["Write", "Edit", "write", "edit"]
|
||||
|
||||
export const PLANNING_CONSULT_WARNING = `
|
||||
|
||||
---
|
||||
|
||||
[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]
|
||||
|
||||
You are being invoked by Prometheus (Planner), a READ-ONLY planning agent.
|
||||
|
||||
**CRITICAL CONSTRAINTS:**
|
||||
- DO NOT modify any files (no Write, Edit, or any file mutations)
|
||||
- DO NOT execute commands that change system state
|
||||
- DO NOT create, delete, or rename files
|
||||
- ONLY provide analysis, recommendations, and information
|
||||
|
||||
**YOUR ROLE**: Provide consultation, research, and analysis to assist with planning.
|
||||
Return your findings and recommendations. The actual implementation will be handled separately after planning is complete.
|
||||
|
||||
---
|
||||
|
||||
`
|
||||
|
||||
@@ -159,4 +159,109 @@ describe("prometheus-md-only", () => {
|
||||
hook["tool.execute.before"](input, output)
|
||||
).resolves.toBeUndefined()
|
||||
})
|
||||
|
||||
test("should inject read-only warning when Prometheus calls sisyphus_task", async () => {
|
||||
// #given
|
||||
const hook = createPrometheusMdOnlyHook(createMockPluginInput())
|
||||
const input = {
|
||||
tool: "sisyphus_task",
|
||||
sessionID: "test-session",
|
||||
callID: "call-1",
|
||||
agent: "Prometheus (Planner)",
|
||||
}
|
||||
const output = {
|
||||
args: { prompt: "Analyze this codebase" },
|
||||
}
|
||||
|
||||
// #when
|
||||
await hook["tool.execute.before"](input, output)
|
||||
|
||||
// #then
|
||||
expect(output.args.prompt).toContain("[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]")
|
||||
expect(output.args.prompt).toContain("DO NOT modify any files")
|
||||
})
|
||||
|
||||
test("should inject read-only warning when Prometheus calls task", async () => {
|
||||
// #given
|
||||
const hook = createPrometheusMdOnlyHook(createMockPluginInput())
|
||||
const input = {
|
||||
tool: "task",
|
||||
sessionID: "test-session",
|
||||
callID: "call-1",
|
||||
agent: "Prometheus (Planner)",
|
||||
}
|
||||
const output = {
|
||||
args: { prompt: "Research this library" },
|
||||
}
|
||||
|
||||
// #when
|
||||
await hook["tool.execute.before"](input, output)
|
||||
|
||||
// #then
|
||||
expect(output.args.prompt).toContain("[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]")
|
||||
})
|
||||
|
||||
test("should inject read-only warning when Prometheus calls call_omo_agent", async () => {
|
||||
// #given
|
||||
const hook = createPrometheusMdOnlyHook(createMockPluginInput())
|
||||
const input = {
|
||||
tool: "call_omo_agent",
|
||||
sessionID: "test-session",
|
||||
callID: "call-1",
|
||||
agent: "Prometheus (Planner)",
|
||||
}
|
||||
const output = {
|
||||
args: { prompt: "Find implementation examples" },
|
||||
}
|
||||
|
||||
// #when
|
||||
await hook["tool.execute.before"](input, output)
|
||||
|
||||
// #then
|
||||
expect(output.args.prompt).toContain("[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]")
|
||||
})
|
||||
|
||||
test("should not inject warning for non-Prometheus agents calling sisyphus_task", async () => {
|
||||
// #given
|
||||
const hook = createPrometheusMdOnlyHook(createMockPluginInput())
|
||||
const input = {
|
||||
tool: "sisyphus_task",
|
||||
sessionID: "test-session",
|
||||
callID: "call-1",
|
||||
agent: "Sisyphus",
|
||||
}
|
||||
const originalPrompt = "Implement this feature"
|
||||
const output = {
|
||||
args: { prompt: originalPrompt },
|
||||
}
|
||||
|
||||
// #when
|
||||
await hook["tool.execute.before"](input, output)
|
||||
|
||||
// #then
|
||||
expect(output.args.prompt).toBe(originalPrompt)
|
||||
expect(output.args.prompt).not.toContain("[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]")
|
||||
})
|
||||
|
||||
test("should not double-inject warning if already present", async () => {
|
||||
// #given
|
||||
const hook = createPrometheusMdOnlyHook(createMockPluginInput())
|
||||
const input = {
|
||||
tool: "sisyphus_task",
|
||||
sessionID: "test-session",
|
||||
callID: "call-1",
|
||||
agent: "Prometheus (Planner)",
|
||||
}
|
||||
const promptWithWarning = "Some prompt [SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION] already here"
|
||||
const output = {
|
||||
args: { prompt: promptWithWarning },
|
||||
}
|
||||
|
||||
// #when
|
||||
await hook["tool.execute.before"](input, output)
|
||||
|
||||
// #then
|
||||
const occurrences = (output.args.prompt as string).split("[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]").length - 1
|
||||
expect(occurrences).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { HOOK_NAME, PROMETHEUS_AGENTS, ALLOWED_EXTENSIONS, ALLOWED_PATH_PREFIX, BLOCKED_TOOLS } from "./constants"
|
||||
import { HOOK_NAME, PROMETHEUS_AGENTS, ALLOWED_EXTENSIONS, ALLOWED_PATH_PREFIX, BLOCKED_TOOLS, PLANNING_CONSULT_WARNING } from "./constants"
|
||||
import { log } from "../../shared/logger"
|
||||
|
||||
export * from "./constants"
|
||||
@@ -10,6 +10,8 @@ function isAllowedFile(filePath: string): boolean {
|
||||
return hasAllowedExtension && isInAllowedPath
|
||||
}
|
||||
|
||||
const TASK_TOOLS = ["sisyphus_task", "task", "call_omo_agent"]
|
||||
|
||||
export function createPrometheusMdOnlyHook(_ctx: PluginInput) {
|
||||
return {
|
||||
"tool.execute.before": async (
|
||||
@@ -23,6 +25,21 @@ export function createPrometheusMdOnlyHook(_ctx: PluginInput) {
|
||||
}
|
||||
|
||||
const toolName = input.tool
|
||||
|
||||
// Inject read-only warning for task tools called by Prometheus
|
||||
if (TASK_TOOLS.includes(toolName)) {
|
||||
const prompt = output.args.prompt as string | undefined
|
||||
if (prompt && !prompt.includes("[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]")) {
|
||||
output.args.prompt = prompt + PLANNING_CONSULT_WARNING
|
||||
log(`[${HOOK_NAME}] Injected read-only planning warning to ${toolName}`, {
|
||||
sessionID: input.sessionID,
|
||||
tool: toolName,
|
||||
agent: agentName,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (!BLOCKED_TOOLS.includes(toolName)) {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user