refactor(model-fallback): fully encapsulate session state in factory closure
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import type { CallOmoAgentArgs } from "./types"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { subagentSessions, syncSubagentSessions } from "../../features/claude-code-session-state"
|
||||
import { clearSessionFallbackChain, setSessionFallbackChain } from "../../hooks/model-fallback/hook"
|
||||
import { getAgentToolRestrictions, log } from "../../shared"
|
||||
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
|
||||
import type { DelegatedModelConfig } from "../../shared/model-resolution-types"
|
||||
@@ -19,8 +18,8 @@ type ExecuteSyncDeps = {
|
||||
createOrGetSession: typeof createOrGetSession
|
||||
waitForCompletion: typeof waitForCompletion
|
||||
processMessages: typeof processMessages
|
||||
setSessionFallbackChain: typeof setSessionFallbackChain
|
||||
clearSessionFallbackChain: typeof clearSessionFallbackChain
|
||||
setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => void
|
||||
clearSessionFallbackChain: (sessionID: string) => void
|
||||
}
|
||||
|
||||
type SpawnReservation = {
|
||||
@@ -32,8 +31,8 @@ const defaultDeps: ExecuteSyncDeps = {
|
||||
createOrGetSession,
|
||||
waitForCompletion,
|
||||
processMessages,
|
||||
setSessionFallbackChain,
|
||||
clearSessionFallbackChain,
|
||||
setSessionFallbackChain: () => {},
|
||||
clearSessionFallbackChain: () => {},
|
||||
}
|
||||
|
||||
function buildPromptGenerationParams(model: DelegatedModelConfig | undefined): Record<string, unknown> {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { tool, type PluginInput, type ToolDefinition } from "@opencode-ai/plugin
|
||||
import { ALLOWED_AGENTS, CALL_OMO_AGENT_DESCRIPTION } from "./constants"
|
||||
import type { CallOmoAgentArgs, ToolContextWithMetadata } from "./types"
|
||||
import type { BackgroundManager } from "../../features/background-agent"
|
||||
import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback"
|
||||
import type { CategoriesConfig, AgentOverrides } from "../../config/schema"
|
||||
import type { DelegatedModelConfig } from "../../shared/model-resolution-types"
|
||||
import type { FallbackEntry } from "../../shared/model-requirements"
|
||||
@@ -15,6 +16,23 @@ import { parseModelString } from "../../shared"
|
||||
import { executeBackground } from "./background-executor"
|
||||
import { executeSync } from "./sync-executor"
|
||||
import { resolveCallableAgents } from "./agent-resolver"
|
||||
import { createOrGetSession } from "./session-creator"
|
||||
import { processMessages } from "./message-processor"
|
||||
import { waitForCompletion } from "./completion-poller"
|
||||
|
||||
function createSyncExecutorDeps(modelFallbackControllerAccessor?: ModelFallbackControllerAccessor) {
|
||||
return {
|
||||
createOrGetSession,
|
||||
waitForCompletion,
|
||||
processMessages,
|
||||
setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => {
|
||||
modelFallbackControllerAccessor?.setSessionFallbackChain(sessionID, fallbackChain)
|
||||
},
|
||||
clearSessionFallbackChain: (sessionID: string) => {
|
||||
modelFallbackControllerAccessor?.clearSessionFallbackChain(sessionID)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function resolveModelAndFallbackChain(args: {
|
||||
subagentType: string
|
||||
@@ -82,6 +100,7 @@ export function createCallOmoAgent(
|
||||
disabledAgents: string[] = [],
|
||||
agentOverrides?: AgentOverrides,
|
||||
userCategories?: CategoriesConfig,
|
||||
modelFallbackControllerAccessor?: ModelFallbackControllerAccessor,
|
||||
): ToolDefinition {
|
||||
const agentDescriptions = ALLOWED_AGENTS.map(
|
||||
(name) => `- ${name}: Specialized agent for ${name} tasks`,
|
||||
@@ -158,14 +177,30 @@ export function createCallOmoAgent(
|
||||
let spawnReservation: Awaited<ReturnType<BackgroundManager["reserveSubagentSpawn"]>> | undefined
|
||||
try {
|
||||
spawnReservation = await backgroundManager.reserveSubagentSpawn(toolCtx.sessionID)
|
||||
return await executeSync(args, toolCtx, ctx, undefined, fallbackChain, spawnReservation, resolvedModel)
|
||||
return await executeSync(
|
||||
args,
|
||||
toolCtx,
|
||||
ctx,
|
||||
createSyncExecutorDeps(modelFallbackControllerAccessor),
|
||||
fallbackChain,
|
||||
spawnReservation,
|
||||
resolvedModel,
|
||||
)
|
||||
} catch (error) {
|
||||
spawnReservation?.rollback()
|
||||
return `Error: ${error instanceof Error ? error.message : String(error)}`
|
||||
}
|
||||
}
|
||||
|
||||
return await executeSync(args, toolCtx, ctx, undefined, fallbackChain, undefined, resolvedModel)
|
||||
return await executeSync(
|
||||
args,
|
||||
toolCtx,
|
||||
ctx,
|
||||
createSyncExecutorDeps(modelFallbackControllerAccessor),
|
||||
fallbackChain,
|
||||
undefined,
|
||||
resolvedModel,
|
||||
)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { formatDetailedError } from "./error-formatting"
|
||||
import { getSessionTools } from "../../shared/session-tools-store"
|
||||
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
|
||||
import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied-session-permission"
|
||||
import { setSessionFallbackChain } from "../../hooks/model-fallback/hook"
|
||||
import { stripAgentListSortPrefix } from "../../shared/agent-display-names"
|
||||
import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract"
|
||||
import { resolveMetadataModel } from "./resolve-metadata-model"
|
||||
@@ -19,6 +18,7 @@ function continueSessionSetup(args: {
|
||||
timing: ReturnType<typeof getTimingConfig>
|
||||
fallbackChain?: FallbackEntry[]
|
||||
category?: string
|
||||
modelFallbackControllerAccessor?: ExecutorContext["modelFallbackControllerAccessor"]
|
||||
}): void {
|
||||
if (!args.fallbackChain && !args.category) {
|
||||
return
|
||||
@@ -41,7 +41,7 @@ function continueSessionSetup(args: {
|
||||
continue
|
||||
}
|
||||
|
||||
setSessionFallbackChain(sessionId, args.fallbackChain)
|
||||
args.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, args.fallbackChain)
|
||||
if (args.category) {
|
||||
SessionCategoryRegistry.register(sessionId, args.category)
|
||||
}
|
||||
@@ -106,6 +106,7 @@ export async function executeBackgroundTask(
|
||||
timing,
|
||||
fallbackChain,
|
||||
category: args.category,
|
||||
modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor,
|
||||
})
|
||||
break
|
||||
}
|
||||
@@ -113,7 +114,7 @@ export async function executeBackgroundTask(
|
||||
}
|
||||
|
||||
if (sessionId) {
|
||||
setSessionFallbackChain(sessionId, fallbackChain)
|
||||
executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, fallbackChain)
|
||||
}
|
||||
if (args.category && sessionId) {
|
||||
SessionCategoryRegistry.register(sessionId, args.category)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { BackgroundManager } from "../../features/background-agent"
|
||||
import type { CategoriesConfig, GitMasterConfig, BrowserAutomationProvider, AgentOverrides, SisyphusAgentConfig } from "../../config/schema"
|
||||
import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback"
|
||||
import type { OpencodeClient } from "./types"
|
||||
|
||||
export interface ExecutorContext {
|
||||
@@ -12,6 +13,7 @@ export interface ExecutorContext {
|
||||
browserProvider?: BrowserAutomationProvider
|
||||
agentOverrides?: AgentOverrides
|
||||
sisyphusAgentConfig?: SisyphusAgentConfig
|
||||
modelFallbackControllerAccessor?: ModelFallbackControllerAccessor
|
||||
onSyncSessionCreated?: (event: { sessionID: string; parentID: string; title: string }) => Promise<void>
|
||||
syncPollTimeoutMs?: number
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import { SessionCategoryRegistry } from "../../shared/session-category-registry"
|
||||
import { formatDuration } from "./time-formatter"
|
||||
import { formatDetailedError } from "./error-formatting"
|
||||
import { syncTaskDeps, type SyncTaskDeps } from "./sync-task-deps"
|
||||
import { setSessionFallbackChain, clearSessionFallbackChain } from "../../hooks/model-fallback/hook"
|
||||
import { retrySyncPromptWithFallbacks } from "./sync-task-fallback"
|
||||
import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract"
|
||||
import { resolveMetadataModel } from "./resolve-metadata-model"
|
||||
@@ -81,7 +80,7 @@ export async function executeSyncTask(
|
||||
subagentSessions.add(sessionID)
|
||||
syncSubagentSessions.add(sessionID)
|
||||
setSessionAgent(sessionID, agentToUse)
|
||||
setSessionFallbackChain(sessionID, fallbackChain)
|
||||
executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionID, fallbackChain)
|
||||
|
||||
if (args.category) {
|
||||
SessionCategoryRegistry.register(sessionID, args.category)
|
||||
@@ -237,7 +236,7 @@ ${buildTaskMetadataBlock({
|
||||
if (syncSessionID) {
|
||||
subagentSessions.delete(syncSessionID)
|
||||
syncSubagentSessions.delete(syncSessionID)
|
||||
clearSessionFallbackChain(syncSessionID)
|
||||
executorCtx.modelFallbackControllerAccessor?.clearSessionFallbackChain(syncSessionID)
|
||||
SessionCategoryRegistry.remove(syncSessionID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import type { BackgroundManager } from "../../features/background-agent"
|
||||
import type { CategoriesConfig, GitMasterConfig, BrowserAutomationProvider, AgentOverrides, SisyphusAgentConfig } from "../../config/schema"
|
||||
import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback"
|
||||
import type {
|
||||
AvailableCategory,
|
||||
AvailableSkill,
|
||||
@@ -68,6 +69,7 @@ export interface DelegateTaskToolOptions {
|
||||
availableSkills?: AvailableSkill[]
|
||||
agentOverrides?: AgentOverrides
|
||||
sisyphusAgentConfig?: SisyphusAgentConfig
|
||||
modelFallbackControllerAccessor?: ModelFallbackControllerAccessor
|
||||
onSyncSessionCreated?: (event: SyncSessionCreatedEvent) => Promise<void>
|
||||
syncPollTimeoutMs?: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user