fix(delegate-task): harden child-session fallback bootstrap and cleanup
Capture delegated child-session retry context before the first prompt so fallback recovery still works when session history is empty. Align background and sync launch paths around the same bootstrap contract, clear session-scoped fallback state on every terminal path, and lock the behavior with regression coverage for first-prompt retries, exhaustion, isolation, and cleanup. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -14,6 +14,11 @@ import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-
|
||||
import { resolveMetadataModel } from "./resolve-metadata-model"
|
||||
import { shouldRetryError } from "../../shared/model-error-classifier"
|
||||
import type { ModelFallbackState } from "../../hooks/model-fallback/hook"
|
||||
import { buildTaskPrompt } from "./prompt-builder"
|
||||
import {
|
||||
clearDelegatedChildSessionBootstrap,
|
||||
registerDelegatedChildSessionBootstrap,
|
||||
} from "../../shared/delegated-child-session-bootstrap"
|
||||
|
||||
export async function executeSyncTask(
|
||||
args: DelegateTaskArgs,
|
||||
@@ -36,6 +41,9 @@ export async function executeSyncTask(
|
||||
| undefined
|
||||
|
||||
try {
|
||||
const tddEnabled = executorCtx.sisyphusAgentConfig?.tdd
|
||||
const delegatedPromptText = buildTaskPrompt(args.prompt, agentToUse, tddEnabled)
|
||||
|
||||
if (typeof manager?.reserveSubagentSpawn === "function") {
|
||||
spawnReservation = await manager.reserveSubagentSpawn(parentContext.sessionID)
|
||||
}
|
||||
@@ -80,11 +88,13 @@ export async function executeSyncTask(
|
||||
subagentSessions.add(newSessionID)
|
||||
syncSubagentSessions.add(newSessionID)
|
||||
setSessionAgent(newSessionID, agentToUse)
|
||||
executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(newSessionID, fallbackChain)
|
||||
|
||||
if (args.category) {
|
||||
SessionCategoryRegistry.register(newSessionID, args.category)
|
||||
}
|
||||
registerDelegatedChildSessionBootstrap({
|
||||
sessionID: newSessionID,
|
||||
promptText: delegatedPromptText,
|
||||
fallbackChain,
|
||||
category: args.category,
|
||||
modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor,
|
||||
})
|
||||
|
||||
if (onSyncSessionCreated) {
|
||||
log("[task] Invoking onSyncSessionCreated callback", { sessionID: newSessionID, parentID: parentContext.sessionID })
|
||||
@@ -150,6 +160,7 @@ export async function executeSyncTask(
|
||||
sessionID,
|
||||
agentToUse,
|
||||
args,
|
||||
promptText: delegatedPromptText,
|
||||
systemContent,
|
||||
toastManager,
|
||||
taskId,
|
||||
@@ -171,6 +182,7 @@ export async function executeSyncTask(
|
||||
const cleanupRetrySession = (currentSessionID: string): void => {
|
||||
subagentSessions.delete(currentSessionID)
|
||||
syncSubagentSessions.delete(currentSessionID)
|
||||
clearDelegatedChildSessionBootstrap(currentSessionID)
|
||||
executorCtx.modelFallbackControllerAccessor?.clearSessionFallbackChain(currentSessionID)
|
||||
SessionCategoryRegistry.remove(currentSessionID)
|
||||
}
|
||||
@@ -308,6 +320,7 @@ ${buildTaskMetadataBlock({
|
||||
if (syncSessionID) {
|
||||
subagentSessions.delete(syncSessionID)
|
||||
syncSubagentSessions.delete(syncSessionID)
|
||||
clearDelegatedChildSessionBootstrap(syncSessionID)
|
||||
executorCtx.modelFallbackControllerAccessor?.clearSessionFallbackChain(syncSessionID)
|
||||
SessionCategoryRegistry.remove(syncSessionID)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user