fix(delegate-task): remove auto-default for run_in_background, require explicit parameter

Remove the auto-defaulting logic from PR #2420 that silently set
run_in_background=false when category/subagent_type/session_id was present.

The tool description falsely claimed 'Default: false' which misled agents
into omitting the parameter. Now the description says REQUIRED and the
validation always throws when the parameter is missing, with a clear
error message guiding the agent to retry with the correct value.

Reverts the behavioral change from #2420 while keeping the issue's
root cause (misleading description) fixed.
This commit is contained in:
YeonGyu-Kim
2026-03-17 15:44:18 +09:00
parent 1070b9170f
commit 566031f4fa
2 changed files with 208 additions and 7 deletions
+205
View File
@@ -1258,6 +1258,211 @@ describe("sisyphus-task", () => {
}, { timeout: 20000 })
})
describe("run_in_background parameter", () => {
test("#given category without run_in_background #when executing #then throws required parameter error", async () => {
// given
const { createDelegateTask } = require("./tools")
const mockManager = { launch: async () => ({}) }
const mockClient = {
app: { agents: async () => ({ data: [] }) },
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
session: {
create: async () => ({ data: { id: "test-session" } }),
prompt: async () => ({ data: {} }),
promptAsync: async () => ({ data: {} }),
messages: async () => ({ data: [] }),
},
}
const tool = createDelegateTask({ manager: mockManager, client: mockClient })
// when
// then
await expect(tool.execute(
{
description: "Category without run flag",
prompt: "Do something",
category: "quick",
load_skills: [],
},
{ sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal }
)).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED")
})
test("#given subagent_type without run_in_background #when executing #then throws required parameter error", async () => {
// given
const { createDelegateTask } = require("./tools")
const mockManager = { launch: async () => ({}) }
const mockClient = {
app: { agents: async () => ({ data: [{ name: "explore", mode: "subagent" }] }) },
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
session: {
create: async () => ({ data: { id: "test-session" } }),
prompt: async () => ({ data: {} }),
promptAsync: async () => ({ data: {} }),
messages: async () => ({ data: [] }),
},
}
const tool = createDelegateTask({ manager: mockManager, client: mockClient })
// when
// then
await expect(tool.execute(
{
description: "Subagent without run flag",
prompt: "Find patterns",
subagent_type: "explore",
load_skills: [],
},
{ sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal }
)).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED")
})
test("#given session_id without run_in_background #when executing #then throws required parameter error", async () => {
// given
const { createDelegateTask } = require("./tools")
const mockManager = { resume: async () => ({ id: "task-1", sessionID: "ses_1", status: "running" }) }
const mockClient = {
app: { agents: async () => ({ data: [] }) },
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
session: {
create: async () => ({ data: { id: "test-session" } }),
prompt: async () => ({ data: {} }),
promptAsync: async () => ({ data: {} }),
messages: async () => ({ data: [] }),
},
}
const tool = createDelegateTask({ manager: mockManager, client: mockClient })
// when
// then
await expect(tool.execute(
{
description: "Continue without run flag",
prompt: "Continue",
session_id: "ses_existing",
load_skills: [],
},
{ sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal }
)).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED")
})
test("#given no category no subagent_type no session_id and no run_in_background #when executing #then throws required parameter error", async () => {
// given
const { createDelegateTask } = require("./tools")
const mockManager = { launch: async () => ({}) }
const mockClient = {
app: { agents: async () => ({ data: [] }) },
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
session: {
create: async () => ({ data: { id: "test-session" } }),
prompt: async () => ({ data: {} }),
promptAsync: async () => ({ data: {} }),
messages: async () => ({ data: [] }),
},
}
const tool = createDelegateTask({ manager: mockManager, client: mockClient })
// when
// then
await expect(tool.execute(
{
description: "Missing required args",
prompt: "Do something",
load_skills: [],
},
{ sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal }
)).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED")
})
test("#given explicit run_in_background=false #when executing #then sync execution succeeds", async () => {
// given
const { createDelegateTask } = require("./tools")
let promptCalled = false
const mockManager = { launch: async () => ({}) }
const mockClient = {
app: { agents: async () => ({ data: [{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-6" } }] }) },
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
session: {
get: async () => ({ data: { directory: "/project" } }),
create: async () => ({ data: { id: "ses_explicit_false" } }),
prompt: async () => {
promptCalled = true
return { data: {} }
},
promptAsync: async () => {
promptCalled = true
return { data: {} }
},
messages: async () => ({ data: [{ info: { role: "assistant" }, parts: [{ type: "text", text: "Done" }] }] }),
status: async () => ({ data: { ses_explicit_false: { type: "idle" } } }),
},
}
const tool = createDelegateTask({ manager: mockManager, client: mockClient })
// when
const result = await tool.execute(
{
description: "Explicit false",
prompt: "Run sync",
subagent_type: "oracle",
run_in_background: false,
load_skills: [],
},
{ sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal }
)
// then
expect(promptCalled).toBe(true)
expect(result).toContain("Done")
}, { timeout: 10000 })
test("#given explicit run_in_background=true #when executing #then background execution succeeds", async () => {
// given
const { createDelegateTask } = require("./tools")
let launchCalled = false
const mockManager = {
launch: async () => {
launchCalled = true
return {
id: "bg_explicit_true",
sessionID: "ses_bg_explicit_true",
description: "Explicit true",
agent: "Sisyphus-Junior",
status: "running",
}
},
}
const mockClient = {
app: { agents: async () => ({ data: [] }) },
config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) },
model: { list: async () => [] },
session: {
create: async () => ({ data: { id: "ses_bg_explicit_true" } }),
prompt: async () => ({ data: {} }),
promptAsync: async () => ({ data: {} }),
messages: async () => ({ data: [] }),
},
}
const tool = createDelegateTask({ manager: mockManager, client: mockClient })
// when
const result = await tool.execute(
{
description: "Explicit true",
prompt: "Run background",
category: "quick",
run_in_background: true,
load_skills: [],
},
{ sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal }
)
// then
expect(launchCalled).toBe(true)
expect(result).toContain("Background task launched")
}, { timeout: 10000 })
})
describe("session_id with background parameter", () => {
test("session_id with background=false should wait for result and return content", async () => {
// Note: This test needs extended timeout because the implementation has MIN_STABILITY_TIME_MS = 5000
+3 -7
View File
@@ -83,7 +83,7 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini
Available categories:
${categoryList}
- subagent_type: Use specific agent directly (explore, librarian, oracle, metis, momus)
- run_in_background: true=async (returns task_id), false=sync (waits). Default: false. Use background=true ONLY for parallel exploration with 5+ independent queries.
- run_in_background: REQUIRED. true=async (returns task_id), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries.
- session_id: Existing Task session to continue (from previous task output). Continues agent with FULL CONTEXT PRESERVED - saves tokens, maintains continuity.
- command: The command that triggered this task (optional, for slash command tracking).
@@ -100,7 +100,7 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini
load_skills: tool.schema.array(tool.schema.string()).describe("Skill names to inject. REQUIRED - pass [] if no skills needed."),
description: tool.schema.string().describe("Short task description (3-5 words)"),
prompt: tool.schema.string().describe("Full detailed prompt for the agent"),
run_in_background: tool.schema.boolean().describe("true=async (returns task_id), false=sync (waits). Default: false"),
run_in_background: tool.schema.boolean().describe("REQUIRED. true=async (returns task_id), false=sync (waits). Use false for task delegation, true ONLY for parallel exploration."),
category: tool.schema.string().optional().describe(`REQUIRED if subagent_type not provided. Do NOT provide both category and subagent_type.`),
subagent_type: tool.schema.string().optional().describe("REQUIRED if category not provided. Do NOT provide both category and subagent_type."),
session_id: tool.schema.string().optional().describe("Existing Task session to continue"),
@@ -123,11 +123,7 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini
})
if (args.run_in_background === undefined) {
if (args.category || args.subagent_type || args.session_id) {
args.run_in_background = false
} else {
throw new Error(`Invalid arguments: 'run_in_background' parameter is REQUIRED. Use run_in_background=false for task delegation, run_in_background=true only for parallel exploration.`)
}
throw new Error(`Invalid arguments: 'run_in_background' parameter is REQUIRED. Specify run_in_background=false for task delegation, or run_in_background=true for parallel exploration.`)
}
if (typeof args.load_skills === "string") {
try {