From 1e239e6155d070422f3537419a62dea09f85cdec Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 8 Jan 2026 23:01:23 +0900 Subject: [PATCH] feat(background-agent): add parentAgent tracking to preserve agent context in background tasks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/features/background-agent/manager.ts | 7 +++++-- src/features/background-agent/types.ts | 4 ++++ src/hooks/sisyphus-orchestrator/index.ts | 1 + src/tools/background-task/tools.ts | 1 + src/tools/sisyphus-task/tools.ts | 11 +++++++++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/features/background-agent/manager.ts b/src/features/background-agent/manager.ts index f2343d575..392d6775a 100644 --- a/src/features/background-agent/manager.ts +++ b/src/features/background-agent/manager.ts @@ -98,6 +98,7 @@ export class BackgroundManager { lastUpdate: new Date(), }, parentModel: input.parentModel, + parentAgent: input.parentAgent, model: input.model, concurrencyKey, } @@ -236,6 +237,7 @@ export class BackgroundManager { existingTask.parentSessionID = input.parentSessionID existingTask.parentMessageID = input.parentMessageID existingTask.parentModel = input.parentModel + existingTask.parentAgent = input.parentAgent existingTask.progress = { toolCalls: existingTask.progress?.toolCalls ?? 0, @@ -438,8 +440,8 @@ export class BackgroundManager { } try { - // Use only parentModel - don't fallback to prevMessage.model - // This prevents accidentally changing parent session's model + // Use only parentModel/parentAgent - don't fallback to prevMessage + // This prevents accidentally changing parent session's model/agent const modelField = task.parentModel?.providerID && task.parentModel?.modelID ? { providerID: task.parentModel.providerID, modelID: task.parentModel.modelID } : undefined @@ -447,6 +449,7 @@ export class BackgroundManager { await this.client.session.prompt({ path: { id: task.parentSessionID }, body: { + agent: task.parentAgent, model: modelField, parts: [{ type: "text", text: message }], }, diff --git a/src/features/background-agent/types.ts b/src/features/background-agent/types.ts index 415320d77..b7e68cdd7 100644 --- a/src/features/background-agent/types.ts +++ b/src/features/background-agent/types.ts @@ -30,6 +30,8 @@ export interface BackgroundTask { model?: { providerID: string; modelID: string } /** Agent name used for concurrency tracking */ concurrencyKey?: string + /** Parent session's agent name for notification */ + parentAgent?: string } export interface LaunchInput { @@ -39,6 +41,7 @@ export interface LaunchInput { parentSessionID: string parentMessageID: string parentModel?: { providerID: string; modelID: string } + parentAgent?: string model?: { providerID: string; modelID: string } skills?: string[] skillContent?: string @@ -50,4 +53,5 @@ export interface ResumeInput { parentSessionID: string parentMessageID: string parentModel?: { providerID: string; modelID: string } + parentAgent?: string } diff --git a/src/hooks/sisyphus-orchestrator/index.ts b/src/hooks/sisyphus-orchestrator/index.ts index 27acbf0cd..379cd2cc4 100644 --- a/src/hooks/sisyphus-orchestrator/index.ts +++ b/src/hooks/sisyphus-orchestrator/index.ts @@ -352,6 +352,7 @@ export function createSisyphusOrchestratorHook( await ctx.client.session.prompt({ path: { id: sessionID }, body: { + agent: "orchestrator-sisyphus", parts: [{ type: "text", text: prompt }], }, query: { directory: ctx.directory }, diff --git a/src/tools/background-task/tools.ts b/src/tools/background-task/tools.ts index b9637e23a..9dd39447b 100644 --- a/src/tools/background-task/tools.ts +++ b/src/tools/background-task/tools.ts @@ -74,6 +74,7 @@ export function createBackgroundTask(manager: BackgroundManager): ToolDefinition parentSessionID: ctx.sessionID, parentMessageID: ctx.messageID, parentModel, + parentAgent: prevMessage?.agent, }) ctx.metadata?.({ diff --git a/src/tools/sisyphus-task/tools.ts b/src/tools/sisyphus-task/tools.ts index 66d39dfb8..ebe72e4b5 100644 --- a/src/tools/sisyphus-task/tools.ts +++ b/src/tools/sisyphus-task/tools.ts @@ -9,6 +9,7 @@ import { findNearestMessageWithFields, MESSAGE_STORAGE } from "../../features/ho import { resolveMultipleSkills } from "../../features/opencode-skill-loader/skill-content" import { createBuiltinSkills } from "../../features/builtin-skills/skills" import { getTaskToastManager } from "../../features/task-toast-manager" +import { subagentSessions } from "../../features/claude-code-session-state" type OpencodeClient = PluginInput["client"] @@ -159,6 +160,7 @@ export function createSisyphusTask(options: SisyphusTaskToolOptions): ToolDefini parentSessionID: ctx.sessionID, parentMessageID: ctx.messageID, parentModel, + parentAgent: prevMessage?.agent, }) ctx.metadata?.({ @@ -325,6 +327,7 @@ ${textContent || "(No text output)"}` parentSessionID: ctx.sessionID, parentMessageID: ctx.messageID, parentModel, + parentAgent: prevMessage?.agent, model: categoryModel, skills: args.skills, skillContent: systemContent, @@ -352,6 +355,7 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id const toastManager = getTaskToastManager() let taskId: string | undefined + let syncSessionID: string | undefined try { 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 + syncSessionID = sessionID + subagentSessions.add(sessionID) taskId = `sync_${sessionID.slice(0, 8)}` const startTime = new Date() @@ -461,6 +467,8 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id toastManager.removeTask(taskId) } + subagentSessions.delete(sessionID) + return `Task completed in ${duration}. Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""} @@ -473,6 +481,9 @@ ${textContent || "(No text output)"}` if (toastManager && taskId !== undefined) { toastManager.removeTask(taskId) } + if (syncSessionID) { + subagentSessions.delete(syncSessionID) + } const message = error instanceof Error ? error.message : String(error) return `❌ Task failed: ${message}` }