fix: address Cubic findings for runtime fallback child sessions

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-03-12 11:07:14 +09:00
parent ba86ef0eea
commit 3caa3fcc3d
8 changed files with 35 additions and 19 deletions

View File

@@ -30,7 +30,7 @@ declare function clearTimeout(timeout: TimerHandle): void
>>>>>>> b6f740ed (fix: enable runtime fallback for delegated child sessions (#2357))
export function createAutoRetryHelpers(deps: HookDeps) {
const { ctx, config, options, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts, pluginConfig } = deps
const { ctx, config, options, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts, pluginConfig, sessionStatusRetryKeys } = deps
const abortSessionRequest = async (sessionID: string, source: string): Promise<void> => {
try {
@@ -201,6 +201,7 @@ export function createAutoRetryHelpers(deps: HookDeps) {
sessionAwaitingFallbackResult.delete(sessionID)
clearSessionFallbackTimeout(sessionID)
SessionCategoryRegistry.remove(sessionID)
sessionStatusRetryKeys.delete(sessionID)
cleanedCount++
}
}

View File

@@ -1,5 +1,4 @@
declare const require: (name: string) => any
const { describe, expect, test } = require("bun:test")
import { describe, expect, test } from "bun:test"
import { classifyErrorType, extractAutoRetrySignal, isRetryableError } from "./error-classifier"

View File

@@ -11,8 +11,7 @@ import { dispatchFallbackRetry } from "./fallback-retry-dispatcher"
import { createSessionStatusHandler } from "./session-status-handler"
export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
const { config, pluginConfig, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts } = deps
const sessionStatusRetryKeys = new Map<string, string>()
const { config, pluginConfig, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts, sessionStatusRetryKeys } = deps
const sessionStatusHandler = createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys)
const handleSessionCreated = (props: Record<string, unknown> | undefined) => {

View File

@@ -32,6 +32,20 @@ export function resolveFallbackBootstrapModel(
return agentModel
}
const agentCategory = typeof agentConfig?.category === "string" ? agentConfig.category : undefined
if (agentCategory) {
const agentCategoryModel = options.pluginConfig?.categories?.[agentCategory]?.model
if (typeof agentCategoryModel === "string" && agentCategoryModel.length > 0) {
log(`[${HOOK_NAME}] Derived model from agent category config for ${options.source}`, {
sessionID: options.sessionID,
agent: options.resolvedAgent,
category: agentCategory,
model: agentCategoryModel,
})
return agentCategoryModel
}
}
const sessionCategory = SessionCategoryRegistry.get(options.sessionID)
const categoryModel = sessionCategory
? options.pluginConfig?.categories?.[sessionCategory]?.model

View File

@@ -43,6 +43,7 @@ export function createRuntimeFallbackHook(
sessionRetryInFlight: new Set(),
sessionAwaitingFallbackResult: new Set(),
sessionFallbackTimeouts: new Map(),
sessionStatusRetryKeys: new Map(),
}
const helpers = createAutoRetryHelpers(deps)

View File

@@ -1,5 +1,4 @@
declare const require: (name: string) => any
const { describe, expect, test, beforeEach, afterEach, spyOn } = require("bun:test")
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
import { createRuntimeFallbackHook } from "./index"
import type { RuntimeFallbackConfig, OhMyOpenCodeConfig } from "../../config"
import * as sharedModule from "../../shared"

View File

@@ -1,14 +1,22 @@
type SessionMessagesResponse = {
data?: Array<{
info?: Record<string, unknown>
parts?: Array<{ type?: string; text?: string }>
}>
type MessageItem = {
info?: Record<string, unknown>
parts?: Array<{ type?: string; text?: string }>
}
function extractMessages(messagesResponse: unknown): MessageItem[] | undefined {
if (messagesResponse == null) return undefined
if (Array.isArray(messagesResponse)) return messagesResponse as MessageItem[]
if (typeof messagesResponse === "object") {
const data = (messagesResponse as Record<string, unknown>).data
if (Array.isArray(data)) return data as MessageItem[]
}
return undefined
}
export function getLastUserRetryParts(
messagesResponse: unknown,
): Array<{ type: "text"; text: string }> {
const messages = (messagesResponse as SessionMessagesResponse).data
const messages = extractMessages(messagesResponse)
const lastUserMessage = messages?.filter((message) => message.info?.role === "user").pop()
const lastUserParts =
lastUserMessage?.parts

View File

@@ -72,11 +72,6 @@ export interface HookDeps {
sessionLastAccess: Map<string, number>
sessionRetryInFlight: Set<string>
sessionAwaitingFallbackResult: Set<string>
<<<<<<< HEAD
sessionFallbackTimeouts: Map<string, RuntimeFallbackTimeout>
||||||| parent of b6f740ed (fix: enable runtime fallback for delegated child sessions (#2357))
sessionFallbackTimeouts: Map<string, ReturnType<typeof setTimeout>>
=======
sessionFallbackTimeouts: Map<string, TimerHandle>
>>>>>>> b6f740ed (fix: enable runtime fallback for delegated child sessions (#2357))
sessionStatusRetryKeys: Map<string, string>
}