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:
YeonGyu-Kim
2026-04-18 02:35:46 +09:00
parent e2f5c0d361
commit 5e4102566c
23 changed files with 271 additions and 123 deletions
+4 -5
View File
@@ -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> {
+37 -2
View File
@@ -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,
)
},
});
}