refactor: sync delegate_task schema with OpenCode Task tool (resume→session_id, add command param)
This commit is contained in:
parent
5a1da39def
commit
14f450bd25
@ -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>
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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:")
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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):
|
||||||
|
|
||||||
|
|||||||
@ -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.`
|
||||||
|
|||||||
@ -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")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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[]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user