fix: preserve model context across background agent handoffs (#229)
Fixes #191 This commit ensures that the user's selected model is preserved when background tasks complete and notify their parent sessions. Changes: - Add parentModel field to BackgroundTask and LaunchInput interfaces - Capture model context when launching background tasks - Pass model context when notifying parent sessions after task completion Impact: - Users with OAuth providers (Google, Anthropic) will now have their model selection preserved across background task continuations - Background agents no longer revert to hardcoded defaults Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
This commit is contained in:
@@ -99,6 +99,7 @@ export class BackgroundManager {
|
|||||||
toolCalls: 0,
|
toolCalls: 0,
|
||||||
lastUpdate: new Date(),
|
lastUpdate: new Date(),
|
||||||
},
|
},
|
||||||
|
parentModel: input.parentModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tasks.set(task.id, task)
|
this.tasks.set(task.id, task)
|
||||||
@@ -322,10 +323,16 @@ export class BackgroundManager {
|
|||||||
const messageDir = getMessageDir(task.parentSessionID)
|
const messageDir = getMessageDir(task.parentSessionID)
|
||||||
const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null
|
const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null
|
||||||
|
|
||||||
|
const modelContext = task.parentModel ?? prevMessage?.model
|
||||||
|
const modelField = modelContext?.providerID && modelContext?.modelID
|
||||||
|
? { providerID: modelContext.providerID, modelID: modelContext.modelID }
|
||||||
|
: undefined
|
||||||
|
|
||||||
await this.client.session.prompt({
|
await this.client.session.prompt({
|
||||||
path: { id: task.parentSessionID },
|
path: { id: task.parentSessionID },
|
||||||
body: {
|
body: {
|
||||||
agent: prevMessage?.agent,
|
agent: prevMessage?.agent,
|
||||||
|
model: modelField,
|
||||||
parts: [{ type: "text", text: message }],
|
parts: [{ type: "text", text: message }],
|
||||||
},
|
},
|
||||||
query: { directory: this.directory },
|
query: { directory: this.directory },
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export interface BackgroundTask {
|
|||||||
result?: string
|
result?: string
|
||||||
error?: string
|
error?: string
|
||||||
progress?: TaskProgress
|
progress?: TaskProgress
|
||||||
|
parentModel?: { providerID: string; modelID: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LaunchInput {
|
export interface LaunchInput {
|
||||||
@@ -34,4 +35,5 @@ export interface LaunchInput {
|
|||||||
agent: string
|
agent: string
|
||||||
parentSessionID: string
|
parentSessionID: string
|
||||||
parentMessageID: string
|
parentMessageID: string
|
||||||
|
parentModel?: { providerID: string; modelID: string }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
import { tool, type PluginInput } from "@opencode-ai/plugin"
|
import { tool, type PluginInput } from "@opencode-ai/plugin"
|
||||||
|
import { existsSync, readdirSync } from "node:fs"
|
||||||
|
import { join } from "node:path"
|
||||||
import type { BackgroundManager, BackgroundTask } from "../../features/background-agent"
|
import type { BackgroundManager, BackgroundTask } from "../../features/background-agent"
|
||||||
import type { BackgroundTaskArgs, BackgroundOutputArgs, BackgroundCancelArgs } from "./types"
|
import type { BackgroundTaskArgs, BackgroundOutputArgs, BackgroundCancelArgs } from "./types"
|
||||||
import { BACKGROUND_TASK_DESCRIPTION, BACKGROUND_OUTPUT_DESCRIPTION, BACKGROUND_CANCEL_DESCRIPTION } from "./constants"
|
import { BACKGROUND_TASK_DESCRIPTION, BACKGROUND_OUTPUT_DESCRIPTION, BACKGROUND_CANCEL_DESCRIPTION } from "./constants"
|
||||||
|
import { findNearestMessageWithFields, MESSAGE_STORAGE } from "../../features/hook-message-injector"
|
||||||
|
|
||||||
type OpencodeClient = PluginInput["client"]
|
type OpencodeClient = PluginInput["client"]
|
||||||
|
|
||||||
|
function getMessageDir(sessionID: string): string | null {
|
||||||
|
if (!existsSync(MESSAGE_STORAGE)) return null
|
||||||
|
|
||||||
|
const directPath = join(MESSAGE_STORAGE, sessionID)
|
||||||
|
if (existsSync(directPath)) return directPath
|
||||||
|
|
||||||
|
for (const dir of readdirSync(MESSAGE_STORAGE)) {
|
||||||
|
const sessionPath = join(MESSAGE_STORAGE, dir, sessionID)
|
||||||
|
if (existsSync(sessionPath)) return sessionPath
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
function formatDuration(start: Date, end?: Date): string {
|
function formatDuration(start: Date, end?: Date): string {
|
||||||
const duration = (end ?? new Date()).getTime() - start.getTime()
|
const duration = (end ?? new Date()).getTime() - start.getTime()
|
||||||
const seconds = Math.floor(duration / 1000)
|
const seconds = Math.floor(duration / 1000)
|
||||||
@@ -34,12 +51,19 @@ export function createBackgroundTask(manager: BackgroundManager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const messageDir = getMessageDir(toolContext.sessionID)
|
||||||
|
const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null
|
||||||
|
const parentModel = prevMessage?.model?.providerID && prevMessage?.model?.modelID
|
||||||
|
? { providerID: prevMessage.model.providerID, modelID: prevMessage.model.modelID }
|
||||||
|
: undefined
|
||||||
|
|
||||||
const task = await manager.launch({
|
const task = await manager.launch({
|
||||||
description: args.description,
|
description: args.description,
|
||||||
prompt: args.prompt,
|
prompt: args.prompt,
|
||||||
agent: args.agent.trim(),
|
agent: args.agent.trim(),
|
||||||
parentSessionID: toolContext.sessionID,
|
parentSessionID: toolContext.sessionID,
|
||||||
parentMessageID: toolContext.messageID,
|
parentMessageID: toolContext.messageID,
|
||||||
|
parentModel,
|
||||||
})
|
})
|
||||||
|
|
||||||
return `Background task launched successfully.
|
return `Background task launched successfully.
|
||||||
|
|||||||
Reference in New Issue
Block a user