refactor: sync delegate_task schema with OpenCode Task tool (resume→session_id, add command param)

This commit is contained in:
justsisyphus 2026-01-25 13:28:44 +09:00
parent 5a1da39def
commit 14f450bd25
10 changed files with 108 additions and 100 deletions

View File

@ -323,7 +323,7 @@ delegate_task(
**If verification fails**: Resume the SAME session with the ACTUAL error output: **If verification fails**: Resume the SAME session with the ACTUAL error output:
\`\`\`typescript \`\`\`typescript
delegate_task( delegate_task(
resume="ses_xyz789", // ALWAYS use the session from the failed task session_id="ses_xyz789", // ALWAYS use the session from the failed task
load_skills=[...], load_skills=[...],
prompt="Verification failed: {actual error}. Fix." prompt="Verification failed: {actual error}. Fix."
) )
@ -331,24 +331,24 @@ delegate_task(
### 3.5 Handle Failures (USE RESUME) ### 3.5 Handle Failures (USE RESUME)
**CRITICAL: When re-delegating, ALWAYS use \`resume\` parameter.** **CRITICAL: When re-delegating, ALWAYS use \`session_id\` parameter.**
Every \`delegate_task()\` output includes a session_id. STORE IT. Every \`delegate_task()\` output includes a session_id. STORE IT.
If task fails: If task fails:
1. Identify what went wrong 1. Identify what went wrong
2. **Resume the SAME session** - subagent has full context already: 2. **Resume the SAME session** - subagent has full context already:
\`\`\`typescript \`\`\`typescript
delegate_task( delegate_task(
resume="ses_xyz789", // Session from failed task session_id="ses_xyz789", // Session from failed task
load_skills=[...], load_skills=[...],
prompt="FAILED: {error}. Fix by: {specific instruction}" prompt="FAILED: {error}. Fix by: {specific instruction}"
) )
\`\`\` \`\`\`
3. Maximum 3 retry attempts with the SAME session 3. Maximum 3 retry attempts with the SAME session
4. If blocked after 3 attempts: Document and continue to independent tasks 4. If blocked after 3 attempts: Document and continue to independent tasks
**Why resume is MANDATORY for failures:** **Why session_id is MANDATORY for failures:**
- Subagent already read all files, knows the context - Subagent already read all files, knows the context
- No repeated exploration = 70%+ token savings - No repeated exploration = 70%+ token savings
- Subagent knows what approaches already failed - Subagent knows what approaches already failed
@ -493,7 +493,7 @@ You are the QA gate. Subagents lie. Verify EVERYTHING.
- Parallelize independent tasks - Parallelize independent tasks
- Verify with your own tools - Verify with your own tools
- **Store session_id from every delegation output** - **Store session_id from every delegation output**
- **Use \`resume="{session_id}"\` for retries, fixes, and follow-ups** - **Use \`session_id="{session_id}"\` for retries, fixes, and follow-ups**
</critical_overrides> </critical_overrides>
` `

View File

@ -209,15 +209,15 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING:
Every \`delegate_task()\` output includes a session_id. **USE IT.** Every \`delegate_task()\` output includes a session_id. **USE IT.**
**ALWAYS resume when:** **ALWAYS continue when:**
| Scenario | Action | | Scenario | Action |
|----------|--------| |----------|--------|
| Task failed/incomplete | \`resume="{session_id}", prompt="Fix: {specific error}"\` | | Task failed/incomplete | \`session_id="{session_id}", prompt="Fix: {specific error}"\` |
| Follow-up question on result | \`resume="{session_id}", prompt="Also: {question}"\` | | Follow-up question on result | \`session_id="{session_id}", prompt="Also: {question}"\` |
| Multi-turn with same agent | \`resume="{session_id}"\` - NEVER start fresh | | Multi-turn with same agent | \`session_id="{session_id}"\` - NEVER start fresh |
| Verification failed | \`resume="{session_id}", prompt="Failed verification: {error}. Fix."\` | | Verification failed | \`session_id="{session_id}", prompt="Failed verification: {error}. Fix."\` |
**Why resume is CRITICAL:** **Why session_id is CRITICAL:**
- Subagent has FULL conversation context preserved - Subagent has FULL conversation context preserved
- No repeated file reads, exploration, or setup - No repeated file reads, exploration, or setup
- Saves 70%+ tokens on follow-ups - Saves 70%+ tokens on follow-ups
@ -228,10 +228,10 @@ Every \`delegate_task()\` output includes a session_id. **USE IT.**
delegate_task(category="quick", prompt="Fix the type error in auth.ts...") delegate_task(category="quick", prompt="Fix the type error in auth.ts...")
// CORRECT: Resume preserves everything // CORRECT: Resume preserves everything
delegate_task(resume="ses_abc123", prompt="Fix: Type error on line 42") delegate_task(session_id="ses_abc123", prompt="Fix: Type error on line 42")
\`\`\` \`\`\`
**After EVERY delegation, STORE the session_id for potential resume.** **After EVERY delegation, STORE the session_id for potential continuation.**
### Code Changes: ### Code Changes:
- Match existing patterns (if codebase is disciplined) - Match existing patterns (if codebase is disciplined)

View File

@ -141,7 +141,7 @@ describe("atlas hook", () => {
// #then - standalone verification reminder appended // #then - standalone verification reminder appended
expect(output.output).toContain("Task completed successfully") expect(output.output).toContain("Task completed successfully")
expect(output.output).toContain("MANDATORY:") expect(output.output).toContain("MANDATORY:")
expect(output.output).toContain("delegate_task(resume=") expect(output.output).toContain("delegate_task(session_id=")
cleanupMessageStorage(sessionID) cleanupMessageStorage(sessionID)
}) })
@ -180,7 +180,7 @@ describe("atlas hook", () => {
expect(output.output).toContain("SUBAGENT WORK COMPLETED") expect(output.output).toContain("SUBAGENT WORK COMPLETED")
expect(output.output).toContain("test-plan") expect(output.output).toContain("test-plan")
expect(output.output).toContain("LIE") expect(output.output).toContain("LIE")
expect(output.output).toContain("delegate_task(resume=") expect(output.output).toContain("delegate_task(session_id=")
cleanupMessageStorage(sessionID) cleanupMessageStorage(sessionID)
}) })
@ -332,7 +332,7 @@ describe("atlas hook", () => {
cleanupMessageStorage(sessionID) cleanupMessageStorage(sessionID)
}) })
test("should include resume and checkbox instructions in reminder", async () => { test("should include session_id and checkbox instructions in reminder", async () => {
// #given - boulder state, Atlas caller // #given - boulder state, Atlas caller
const sessionID = "session-resume-test" const sessionID = "session-resume-test"
setupMessageStorage(sessionID, "atlas") setupMessageStorage(sessionID, "atlas")
@ -361,8 +361,8 @@ describe("atlas hook", () => {
output output
) )
// #then - should include resume instructions and verification // #then - should include session_id instructions and verification
expect(output.output).toContain("delegate_task(resume=") expect(output.output).toContain("delegate_task(session_id=")
expect(output.output).toContain("[x]") expect(output.output).toContain("[x]")
expect(output.output).toContain("MANDATORY:") expect(output.output).toContain("MANDATORY:")

View File

@ -179,13 +179,13 @@ If you were NOT given **exactly ONE atomic task**, you MUST:
` `
function buildVerificationReminder(sessionId: string): string { function buildVerificationReminder(sessionId: string): string {
return `${VERIFICATION_REMINDER} return `${VERIFICATION_REMINDER}
--- ---
**If ANY verification fails, use this immediately:** **If ANY verification fails, use this immediately:**
\`\`\` \`\`\`
delegate_task(resume="${sessionId}", prompt="fix: [describe the specific failure]") delegate_task(session_id="${sessionId}", prompt="fix: [describe the specific failure]")
\`\`\`` \`\`\``
} }
@ -711,8 +711,8 @@ export function createAtlasHook(
return return
} }
const outputStr = output.output && typeof output.output === "string" ? output.output : "" const outputStr = output.output && typeof output.output === "string" ? output.output : ""
const isBackgroundLaunch = outputStr.includes("Background task launched") || outputStr.includes("Background task resumed") const isBackgroundLaunch = outputStr.includes("Background task launched") || outputStr.includes("Background task continued")
if (isBackgroundLaunch) { if (isBackgroundLaunch) {
return return

View File

@ -16,21 +16,21 @@ function extractSessionId(output: string): string | null {
} }
export function createTaskResumeInfoHook() { export function createTaskResumeInfoHook() {
const toolExecuteAfter = async ( const toolExecuteAfter = async (
input: { tool: string; sessionID: string; callID: string }, input: { tool: string; sessionID: string; callID: string },
output: { title: string; output: string; metadata: unknown } output: { title: string; output: string; metadata: unknown }
) => { ) => {
if (!TARGET_TOOLS.includes(input.tool)) return if (!TARGET_TOOLS.includes(input.tool)) return
if (output.output.startsWith("Error:") || output.output.startsWith("Failed")) return if (output.output.startsWith("Error:") || output.output.startsWith("Failed")) return
if (output.output.includes("\nto resume:")) return if (output.output.includes("\nto continue:")) return
const sessionId = extractSessionId(output.output) const sessionId = extractSessionId(output.output)
if (!sessionId) return if (!sessionId) return
output.output = output.output.trimEnd() + `\n\nto resume: delegate_task(resume="${sessionId}", prompt="...")` output.output = output.output.trimEnd() + `\n\nto continue: delegate_task(session_id="${sessionId}", prompt="...")`
} }
return { return {
"tool.execute.after": toolExecuteAfter, "tool.execute.after": toolExecuteAfter,
} }
} }

View File

@ -442,18 +442,18 @@ export function createBackgroundCancel(manager: BackgroundManager, client: Openc
.map(t => `| \`${t.id}\` | ${t.description} | ${t.status} | ${t.sessionID ? `\`${t.sessionID}\`` : "(not started)"} |`) .map(t => `| \`${t.id}\` | ${t.description} | ${t.status} | ${t.sessionID ? `\`${t.sessionID}\`` : "(not started)"} |`)
.join("\n") .join("\n")
const resumableTasks = cancelledInfo.filter(t => t.sessionID) const resumableTasks = cancelledInfo.filter(t => t.sessionID)
const resumeSection = resumableTasks.length > 0 const resumeSection = resumableTasks.length > 0
? `\n## Resume Instructions ? `\n## Continue Instructions
To resume a cancelled task, use: To continue a cancelled task, use:
\`\`\` \`\`\`
delegate_task(resume="<session_id>", prompt="Continue: <your follow-up>") delegate_task(session_id="<session_id>", prompt="Continue: <your follow-up>")
\`\`\` \`\`\`
Resumable sessions: Continuable sessions:
${resumableTasks.map(t => `- \`${t.sessionID}\` (${t.description})`).join("\n")}` ${resumableTasks.map(t => `- \`${t.sessionID}\` (${t.description})`).join("\n")}`
: "" : ""
return `Cancelled ${cancellableTasks.length} background task(s): return `Cancelled ${cancellableTasks.length} background task(s):

View File

@ -4,4 +4,4 @@ export const CALL_OMO_AGENT_DESCRIPTION = `Spawn explore/librarian agent. run_in
Available: {agents} Available: {agents}
Pass \`resume=session_id\` to continue previous agent with full context. Prompts MUST be in English. Use \`background_output\` for async results.` Pass \`session_id=<id>\` to continue previous agent with full context. Prompts MUST be in English. Use \`background_output\` for async results.`

View File

@ -594,16 +594,16 @@ describe("sisyphus-task", () => {
}, { timeout: 20000 }) }, { timeout: 20000 })
}) })
describe("resume with background parameter", () => { describe("session_id with background parameter", () => {
test("resume with background=false should wait for result and return content", async () => { 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 // Note: This test needs extended timeout because the implementation has MIN_STABILITY_TIME_MS = 5000
// #given // #given
const { createDelegateTask } = require("./tools") const { createDelegateTask } = require("./tools")
const mockTask = { const mockTask = {
id: "task-123", id: "task-123",
sessionID: "ses_resume_test", sessionID: "ses_continue_test",
description: "Resumed task", description: "Continued task",
agent: "explore", agent: "explore",
status: "running", status: "running",
} }
@ -620,7 +620,7 @@ describe("sisyphus-task", () => {
data: [ data: [
{ {
info: { role: "assistant", time: { created: Date.now() } }, info: { role: "assistant", time: { created: Date.now() } },
parts: [{ type: "text", text: "This is the resumed task result" }], parts: [{ type: "text", text: "This is the continued task result" }],
}, },
], ],
}), }),
@ -646,28 +646,28 @@ describe("sisyphus-task", () => {
// #when // #when
const result = await tool.execute( const result = await tool.execute(
{ {
description: "Resume test", description: "Continue test",
prompt: "Continue the task", prompt: "Continue the task",
resume: "ses_resume_test", session_id: "ses_continue_test",
run_in_background: false, run_in_background: false,
load_skills: ["git-master"], load_skills: ["git-master"],
}, },
toolContext toolContext
) )
// #then - should contain actual result, not just "Background task resumed" // #then - should contain actual result, not just "Background task continued"
expect(result).toContain("This is the resumed task result") expect(result).toContain("This is the continued task result")
expect(result).not.toContain("Background task resumed") expect(result).not.toContain("Background task continued")
}, { timeout: 10000 }) }, { timeout: 10000 })
test("resume with background=true should return immediately without waiting", async () => { test("session_id with background=true should return immediately without waiting", async () => {
// #given // #given
const { createDelegateTask } = require("./tools") const { createDelegateTask } = require("./tools")
const mockTask = { const mockTask = {
id: "task-456", id: "task-456",
sessionID: "ses_bg_resume", sessionID: "ses_bg_continue",
description: "Background resumed task", description: "Background continued task",
agent: "explore", agent: "explore",
status: "running", status: "running",
} }
@ -701,9 +701,9 @@ describe("sisyphus-task", () => {
// #when // #when
const result = await tool.execute( const result = await tool.execute(
{ {
description: "Resume bg test", description: "Continue bg test",
prompt: "Continue in background", prompt: "Continue in background",
resume: "ses_bg_resume", session_id: "ses_bg_continue",
run_in_background: true, run_in_background: true,
load_skills: ["git-master"], load_skills: ["git-master"],
}, },
@ -711,7 +711,7 @@ describe("sisyphus-task", () => {
) )
// #then - should return background message // #then - should return background message
expect(result).toContain("Background task resumed") expect(result).toContain("Background task continued")
expect(result).toContain("task-456") expect(result).toContain("task-456")
}) })
}) })

View File

@ -86,8 +86,8 @@ function formatDetailedError(error: unknown, ctx: ErrorContext): string {
lines.push(`- subagent_type: ${ctx.args.subagent_type ?? "(none)"}`) lines.push(`- subagent_type: ${ctx.args.subagent_type ?? "(none)"}`)
lines.push(`- run_in_background: ${ctx.args.run_in_background}`) lines.push(`- run_in_background: ${ctx.args.run_in_background}`)
lines.push(`- load_skills: [${ctx.args.load_skills?.join(", ") ?? ""}]`) lines.push(`- load_skills: [${ctx.args.load_skills?.join(", ") ?? ""}]`)
if (ctx.args.resume) { if (ctx.args.session_id) {
lines.push(`- resume: ${ctx.args.resume}`) lines.push(`- session_id: ${ctx.args.session_id}`)
} }
} }
@ -194,7 +194,7 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini
const description = `Spawn agent task with category-based or direct agent selection. const description = `Spawn agent task with category-based or direct agent selection.
MUTUALLY EXCLUSIVE: Provide EITHER category OR subagent_type, not both (unless resuming). MUTUALLY EXCLUSIVE: Provide EITHER category OR subagent_type, not both (unless continuing a session).
- load_skills: ALWAYS REQUIRED. Pass at least one skill name (e.g., ["playwright"], ["git-master", "frontend-ui-ux"]). - load_skills: ALWAYS REQUIRED. Pass at least one skill name (e.g., ["playwright"], ["git-master", "frontend-ui-ux"]).
- category: Use predefined category Spawns Sisyphus-Junior with category config - category: Use predefined category Spawns Sisyphus-Junior with category config
@ -202,12 +202,13 @@ MUTUALLY EXCLUSIVE: Provide EITHER category OR subagent_type, not both (unless r
${categoryList} ${categoryList}
- subagent_type: Use specific agent directly (e.g., "oracle", "explore") - subagent_type: Use specific agent directly (e.g., "oracle", "explore")
- run_in_background: true=async (returns task_id), false=sync (waits for result). Default: false. Use background=true ONLY for parallel exploration with 5+ independent queries. - run_in_background: true=async (returns task_id), false=sync (waits for result). Default: false. Use background=true ONLY for parallel exploration with 5+ independent queries.
- resume: Session ID to resume (from previous task output). Continues agent with FULL CONTEXT PRESERVED - saves tokens, maintains continuity. - 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).
**WHEN TO USE resume:** **WHEN TO USE session_id:**
- Task failed/incomplete resume with "fix: [specific issue]" - Task failed/incomplete session_id with "fix: [specific issue]"
- Need follow-up on previous result resume with additional question - Need follow-up on previous result session_id with additional question
- Multi-turn conversation with same agent always resume instead of new task - Multi-turn conversation with same agent always session_id instead of new task
Prompts MUST be in English.` Prompts MUST be in English.`
@ -220,7 +221,8 @@ Prompts MUST be in English.`
run_in_background: tool.schema.boolean().describe("true=async (returns task_id), false=sync (waits). Default: false"), run_in_background: tool.schema.boolean().describe("true=async (returns task_id), false=sync (waits). Default: false"),
category: tool.schema.string().optional().describe(`Category (e.g., ${categoryExamples}). Mutually exclusive with subagent_type.`), category: tool.schema.string().optional().describe(`Category (e.g., ${categoryExamples}). Mutually exclusive with subagent_type.`),
subagent_type: tool.schema.string().optional().describe("Agent name (e.g., 'oracle', 'explore'). Mutually exclusive with category."), subagent_type: tool.schema.string().optional().describe("Agent name (e.g., 'oracle', 'explore'). Mutually exclusive with category."),
resume: tool.schema.string().optional().describe("Session ID to resume"), session_id: tool.schema.string().optional().describe("Existing Task session to continue"),
command: tool.schema.string().optional().describe("The command that triggered this task"),
}, },
async execute(args: DelegateTaskArgs, toolContext) { async execute(args: DelegateTaskArgs, toolContext) {
const ctx = toolContext as ToolContextWithMetadata const ctx = toolContext as ToolContextWithMetadata
@ -265,11 +267,11 @@ Prompts MUST be in English.`
? { providerID: prevMessage.model.providerID, modelID: prevMessage.model.modelID } ? { providerID: prevMessage.model.providerID, modelID: prevMessage.model.modelID }
: undefined : undefined
if (args.resume) { if (args.session_id) {
if (runInBackground) { if (runInBackground) {
try { try {
const task = await manager.resume({ const task = await manager.resume({
sessionId: args.resume, sessionId: args.session_id,
prompt: args.prompt, prompt: args.prompt,
parentSessionID: ctx.sessionID, parentSessionID: ctx.sessionID,
parentMessageID: ctx.messageID, parentMessageID: ctx.messageID,
@ -278,7 +280,7 @@ Prompts MUST be in English.`
}) })
ctx.metadata?.({ ctx.metadata?.({
title: `Resume: ${task.description}`, title: `Continue: ${task.description}`,
metadata: { metadata: {
prompt: args.prompt, prompt: args.prompt,
agent: task.agent, agent: task.agent,
@ -286,10 +288,11 @@ Prompts MUST be in English.`
description: args.description, description: args.description,
run_in_background: args.run_in_background, run_in_background: args.run_in_background,
sessionId: task.sessionID, sessionId: task.sessionID,
command: args.command,
}, },
}) })
return `Background task resumed. return `Background task continued.
Task ID: ${task.id} Task ID: ${task.id}
Session ID: ${task.sessionID} Session ID: ${task.sessionID}
@ -301,35 +304,36 @@ Agent continues with full previous context preserved.
Use \`background_output\` with task_id="${task.id}" to check progress.` Use \`background_output\` with task_id="${task.id}" to check progress.`
} catch (error) { } catch (error) {
return formatDetailedError(error, { return formatDetailedError(error, {
operation: "Resume background task", operation: "Continue background task",
args, args,
sessionID: args.resume, sessionID: args.session_id,
}) })
} }
} }
const toastManager = getTaskToastManager() const toastManager = getTaskToastManager()
const taskId = `resume_sync_${args.resume.slice(0, 8)}` const taskId = `resume_sync_${args.session_id.slice(0, 8)}`
const startTime = new Date() const startTime = new Date()
if (toastManager) { if (toastManager) {
toastManager.addTask({ toastManager.addTask({
id: taskId, id: taskId,
description: args.description, description: args.description,
agent: "resume", agent: "continue",
isBackground: false, isBackground: false,
}) })
} }
ctx.metadata?.({ ctx.metadata?.({
title: `Resume: ${args.description}`, title: `Continue: ${args.description}`,
metadata: { metadata: {
prompt: args.prompt, prompt: args.prompt,
load_skills: args.load_skills, load_skills: args.load_skills,
description: args.description, description: args.description,
run_in_background: args.run_in_background, run_in_background: args.run_in_background,
sessionId: args.resume, sessionId: args.session_id,
sync: true, sync: true,
command: args.command,
}, },
}) })
@ -338,7 +342,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
let resumeModel: { providerID: string; modelID: string } | undefined let resumeModel: { providerID: string; modelID: string } | undefined
try { try {
const messagesResp = await client.session.messages({ path: { id: args.resume } }) const messagesResp = await client.session.messages({ path: { id: args.session_id } })
const messages = (messagesResp.data ?? []) as Array<{ const messages = (messagesResp.data ?? []) as Array<{
info?: { agent?: string; model?: { providerID: string; modelID: string }; modelID?: string; providerID?: string } info?: { agent?: string; model?: { providerID: string; modelID: string }; modelID?: string; providerID?: string }
}> }>
@ -351,7 +355,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
} }
} }
} catch { } catch {
const resumeMessageDir = getMessageDir(args.resume) const resumeMessageDir = getMessageDir(args.session_id)
const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null
resumeAgent = resumeMessage?.agent resumeAgent = resumeMessage?.agent
resumeModel = resumeMessage?.model?.providerID && resumeMessage?.model?.modelID resumeModel = resumeMessage?.model?.providerID && resumeMessage?.model?.modelID
@ -360,7 +364,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
} }
await client.session.prompt({ await client.session.prompt({
path: { id: args.resume }, path: { id: args.session_id },
body: { body: {
...(resumeAgent !== undefined ? { agent: resumeAgent } : {}), ...(resumeAgent !== undefined ? { agent: resumeAgent } : {}),
...(resumeModel !== undefined ? { model: resumeModel } : {}), ...(resumeModel !== undefined ? { model: resumeModel } : {}),
@ -378,7 +382,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
toastManager.removeTask(taskId) toastManager.removeTask(taskId)
} }
const errorMessage = promptError instanceof Error ? promptError.message : String(promptError) const errorMessage = promptError instanceof Error ? promptError.message : String(promptError)
return `Failed to send resume prompt: ${errorMessage}\n\nSession ID: ${args.resume}` return `Failed to send continuation prompt: ${errorMessage}\n\nSession ID: ${args.session_id}`
} }
// Wait for message stability after prompt completes // Wait for message stability after prompt completes
@ -395,7 +399,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
const elapsed = Date.now() - pollStart const elapsed = Date.now() - pollStart
if (elapsed < MIN_STABILITY_TIME_MS) continue if (elapsed < MIN_STABILITY_TIME_MS) continue
const messagesCheck = await client.session.messages({ path: { id: args.resume } }) const messagesCheck = await client.session.messages({ path: { id: args.session_id } })
const msgs = ((messagesCheck as { data?: unknown }).data ?? messagesCheck) as Array<unknown> const msgs = ((messagesCheck as { data?: unknown }).data ?? messagesCheck) as Array<unknown>
const currentMsgCount = msgs.length const currentMsgCount = msgs.length
@ -409,14 +413,14 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
} }
const messagesResult = await client.session.messages({ const messagesResult = await client.session.messages({
path: { id: args.resume }, path: { id: args.session_id },
}) })
if (messagesResult.error) { if (messagesResult.error) {
if (toastManager) { if (toastManager) {
toastManager.removeTask(taskId) toastManager.removeTask(taskId)
} }
return `Error fetching result: ${messagesResult.error}\n\nSession ID: ${args.resume}` return `Error fetching result: ${messagesResult.error}\n\nSession ID: ${args.session_id}`
} }
const messages = ((messagesResult as { data?: unknown }).data ?? messagesResult) as Array<{ const messages = ((messagesResult as { data?: unknown }).data ?? messagesResult) as Array<{
@ -434,7 +438,7 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
} }
if (!lastMessage) { if (!lastMessage) {
return `No assistant response found.\n\nSession ID: ${args.resume}` return `No assistant response found.\n\nSession ID: ${args.session_id}`
} }
// Extract text from both "text" and "reasoning" parts (thinking models use "reasoning") // Extract text from both "text" and "reasoning" parts (thinking models use "reasoning")
@ -443,16 +447,16 @@ Use \`background_output\` with task_id="${task.id}" to check progress.`
const duration = formatDuration(startTime) const duration = formatDuration(startTime)
return `Task resumed and completed in ${duration}. return `Task continued and completed in ${duration}.
Session ID: ${args.resume} Session ID: ${args.session_id}
--- ---
${textContent || "(No text output)"} ${textContent || "(No text output)"}
--- ---
To resume this session: resume="${args.resume}"` To continue this session: session_id="${args.session_id}"`
} }
if (args.category && args.subagent_type) { if (args.category && args.subagent_type) {
@ -618,6 +622,7 @@ To resume this session: resume="${args.resume}"`
description: args.description, description: args.description,
run_in_background: args.run_in_background, run_in_background: args.run_in_background,
sessionId: sessionID, sessionId: sessionID,
command: args.command,
}, },
}) })
@ -705,7 +710,7 @@ RESULT:
${textContent || "(No text output)"} ${textContent || "(No text output)"}
--- ---
To resume this session: resume="${sessionID}"` To continue this session: session_id="${sessionID}"`
} catch (error) { } catch (error) {
return formatDetailedError(error, { return formatDetailedError(error, {
operation: "Launch monitored background task", operation: "Launch monitored background task",
@ -788,6 +793,7 @@ Sisyphus-Junior is spawned automatically when you specify a category. Pick the a
description: args.description, description: args.description,
run_in_background: args.run_in_background, run_in_background: args.run_in_background,
sessionId: task.sessionID, sessionId: task.sessionID,
command: args.command,
}, },
}) })
@ -800,7 +806,7 @@ Agent: ${task.agent}${args.category ? ` (category: ${args.category})` : ""}
Status: ${task.status} Status: ${task.status}
System notifies on completion. Use \`background_output\` with task_id="${task.id}" to check. System notifies on completion. Use \`background_output\` with task_id="${task.id}" to check.
To resume this session: resume="${task.sessionID}"` To continue this session: session_id="${task.sessionID}"`
} catch (error) { } catch (error) {
return formatDetailedError(error, { return formatDetailedError(error, {
operation: "Launch background task", operation: "Launch background task",
@ -864,6 +870,7 @@ To resume this session: resume="${task.sessionID}"`
run_in_background: args.run_in_background, run_in_background: args.run_in_background,
sessionId: sessionID, sessionId: sessionID,
sync: true, sync: true,
command: args.command,
}, },
}) })
@ -1018,7 +1025,7 @@ Session ID: ${sessionID}
${textContent || "(No text output)"} ${textContent || "(No text output)"}
--- ---
To resume this session: resume="${sessionID}"` To continue this session: session_id="${sessionID}"`
} catch (error) { } catch (error) {
if (toastManager && taskId !== undefined) { if (toastManager && taskId !== undefined) {
toastManager.removeTask(taskId) toastManager.removeTask(taskId)

View File

@ -4,6 +4,7 @@ export interface DelegateTaskArgs {
category?: string category?: string
subagent_type?: string subagent_type?: string
run_in_background: boolean run_in_background: boolean
resume?: string session_id?: string
command?: string
load_skills: string[] load_skills: string[]
} }