feat(background-agent): add parentAgent tracking to preserve agent context in background tasks
- Add parentAgent field to BackgroundTask, LaunchInput, and ResumeInput interfaces
- Pass parentAgent through background task manager to preserve agent identity
- Update sisyphus-orchestrator to set orchestrator-sisyphus agent context
- Add session tracking for background agents to prevent context loss
- Propagate agent context in background-task and sisyphus-task tools
This ensures background/subagent spawned tasks maintain proper agent context for notifications and continuity.
🤖 Generated with assistance of oh-my-opencode
This commit is contained in:
parent
9481770a39
commit
1e239e6155
@ -98,6 +98,7 @@ export class BackgroundManager {
|
|||||||
lastUpdate: new Date(),
|
lastUpdate: new Date(),
|
||||||
},
|
},
|
||||||
parentModel: input.parentModel,
|
parentModel: input.parentModel,
|
||||||
|
parentAgent: input.parentAgent,
|
||||||
model: input.model,
|
model: input.model,
|
||||||
concurrencyKey,
|
concurrencyKey,
|
||||||
}
|
}
|
||||||
@ -236,6 +237,7 @@ export class BackgroundManager {
|
|||||||
existingTask.parentSessionID = input.parentSessionID
|
existingTask.parentSessionID = input.parentSessionID
|
||||||
existingTask.parentMessageID = input.parentMessageID
|
existingTask.parentMessageID = input.parentMessageID
|
||||||
existingTask.parentModel = input.parentModel
|
existingTask.parentModel = input.parentModel
|
||||||
|
existingTask.parentAgent = input.parentAgent
|
||||||
|
|
||||||
existingTask.progress = {
|
existingTask.progress = {
|
||||||
toolCalls: existingTask.progress?.toolCalls ?? 0,
|
toolCalls: existingTask.progress?.toolCalls ?? 0,
|
||||||
@ -438,8 +440,8 @@ export class BackgroundManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use only parentModel - don't fallback to prevMessage.model
|
// Use only parentModel/parentAgent - don't fallback to prevMessage
|
||||||
// This prevents accidentally changing parent session's model
|
// This prevents accidentally changing parent session's model/agent
|
||||||
const modelField = task.parentModel?.providerID && task.parentModel?.modelID
|
const modelField = task.parentModel?.providerID && task.parentModel?.modelID
|
||||||
? { providerID: task.parentModel.providerID, modelID: task.parentModel.modelID }
|
? { providerID: task.parentModel.providerID, modelID: task.parentModel.modelID }
|
||||||
: undefined
|
: undefined
|
||||||
@ -447,6 +449,7 @@ export class BackgroundManager {
|
|||||||
await this.client.session.prompt({
|
await this.client.session.prompt({
|
||||||
path: { id: task.parentSessionID },
|
path: { id: task.parentSessionID },
|
||||||
body: {
|
body: {
|
||||||
|
agent: task.parentAgent,
|
||||||
model: modelField,
|
model: modelField,
|
||||||
parts: [{ type: "text", text: message }],
|
parts: [{ type: "text", text: message }],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -30,6 +30,8 @@ export interface BackgroundTask {
|
|||||||
model?: { providerID: string; modelID: string }
|
model?: { providerID: string; modelID: string }
|
||||||
/** Agent name used for concurrency tracking */
|
/** Agent name used for concurrency tracking */
|
||||||
concurrencyKey?: string
|
concurrencyKey?: string
|
||||||
|
/** Parent session's agent name for notification */
|
||||||
|
parentAgent?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LaunchInput {
|
export interface LaunchInput {
|
||||||
@ -39,6 +41,7 @@ export interface LaunchInput {
|
|||||||
parentSessionID: string
|
parentSessionID: string
|
||||||
parentMessageID: string
|
parentMessageID: string
|
||||||
parentModel?: { providerID: string; modelID: string }
|
parentModel?: { providerID: string; modelID: string }
|
||||||
|
parentAgent?: string
|
||||||
model?: { providerID: string; modelID: string }
|
model?: { providerID: string; modelID: string }
|
||||||
skills?: string[]
|
skills?: string[]
|
||||||
skillContent?: string
|
skillContent?: string
|
||||||
@ -50,4 +53,5 @@ export interface ResumeInput {
|
|||||||
parentSessionID: string
|
parentSessionID: string
|
||||||
parentMessageID: string
|
parentMessageID: string
|
||||||
parentModel?: { providerID: string; modelID: string }
|
parentModel?: { providerID: string; modelID: string }
|
||||||
|
parentAgent?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@ -352,6 +352,7 @@ export function createSisyphusOrchestratorHook(
|
|||||||
await ctx.client.session.prompt({
|
await ctx.client.session.prompt({
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: {
|
body: {
|
||||||
|
agent: "orchestrator-sisyphus",
|
||||||
parts: [{ type: "text", text: prompt }],
|
parts: [{ type: "text", text: prompt }],
|
||||||
},
|
},
|
||||||
query: { directory: ctx.directory },
|
query: { directory: ctx.directory },
|
||||||
|
|||||||
@ -74,6 +74,7 @@ export function createBackgroundTask(manager: BackgroundManager): ToolDefinition
|
|||||||
parentSessionID: ctx.sessionID,
|
parentSessionID: ctx.sessionID,
|
||||||
parentMessageID: ctx.messageID,
|
parentMessageID: ctx.messageID,
|
||||||
parentModel,
|
parentModel,
|
||||||
|
parentAgent: prevMessage?.agent,
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.metadata?.({
|
ctx.metadata?.({
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { findNearestMessageWithFields, MESSAGE_STORAGE } from "../../features/ho
|
|||||||
import { resolveMultipleSkills } from "../../features/opencode-skill-loader/skill-content"
|
import { resolveMultipleSkills } from "../../features/opencode-skill-loader/skill-content"
|
||||||
import { createBuiltinSkills } from "../../features/builtin-skills/skills"
|
import { createBuiltinSkills } from "../../features/builtin-skills/skills"
|
||||||
import { getTaskToastManager } from "../../features/task-toast-manager"
|
import { getTaskToastManager } from "../../features/task-toast-manager"
|
||||||
|
import { subagentSessions } from "../../features/claude-code-session-state"
|
||||||
|
|
||||||
type OpencodeClient = PluginInput["client"]
|
type OpencodeClient = PluginInput["client"]
|
||||||
|
|
||||||
@ -159,6 +160,7 @@ export function createSisyphusTask(options: SisyphusTaskToolOptions): ToolDefini
|
|||||||
parentSessionID: ctx.sessionID,
|
parentSessionID: ctx.sessionID,
|
||||||
parentMessageID: ctx.messageID,
|
parentMessageID: ctx.messageID,
|
||||||
parentModel,
|
parentModel,
|
||||||
|
parentAgent: prevMessage?.agent,
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.metadata?.({
|
ctx.metadata?.({
|
||||||
@ -325,6 +327,7 @@ ${textContent || "(No text output)"}`
|
|||||||
parentSessionID: ctx.sessionID,
|
parentSessionID: ctx.sessionID,
|
||||||
parentMessageID: ctx.messageID,
|
parentMessageID: ctx.messageID,
|
||||||
parentModel,
|
parentModel,
|
||||||
|
parentAgent: prevMessage?.agent,
|
||||||
model: categoryModel,
|
model: categoryModel,
|
||||||
skills: args.skills,
|
skills: args.skills,
|
||||||
skillContent: systemContent,
|
skillContent: systemContent,
|
||||||
@ -352,6 +355,7 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id
|
|||||||
|
|
||||||
const toastManager = getTaskToastManager()
|
const toastManager = getTaskToastManager()
|
||||||
let taskId: string | undefined
|
let taskId: string | undefined
|
||||||
|
let syncSessionID: string | undefined
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const createResult = await client.session.create({
|
const createResult = await client.session.create({
|
||||||
@ -366,6 +370,8 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sessionID = createResult.data.id
|
const sessionID = createResult.data.id
|
||||||
|
syncSessionID = sessionID
|
||||||
|
subagentSessions.add(sessionID)
|
||||||
taskId = `sync_${sessionID.slice(0, 8)}`
|
taskId = `sync_${sessionID.slice(0, 8)}`
|
||||||
const startTime = new Date()
|
const startTime = new Date()
|
||||||
|
|
||||||
@ -461,6 +467,8 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id
|
|||||||
toastManager.removeTask(taskId)
|
toastManager.removeTask(taskId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subagentSessions.delete(sessionID)
|
||||||
|
|
||||||
return `Task completed in ${duration}.
|
return `Task completed in ${duration}.
|
||||||
|
|
||||||
Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}
|
Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}
|
||||||
@ -473,6 +481,9 @@ ${textContent || "(No text output)"}`
|
|||||||
if (toastManager && taskId !== undefined) {
|
if (toastManager && taskId !== undefined) {
|
||||||
toastManager.removeTask(taskId)
|
toastManager.removeTask(taskId)
|
||||||
}
|
}
|
||||||
|
if (syncSessionID) {
|
||||||
|
subagentSessions.delete(syncSessionID)
|
||||||
|
}
|
||||||
const message = error instanceof Error ? error.message : String(error)
|
const message = error instanceof Error ? error.message : String(error)
|
||||||
return `❌ Task failed: ${message}`
|
return `❌ Task failed: ${message}`
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user