test(ci): remove suite-order mock coupling
This commit is contained in:
@@ -17,6 +17,28 @@ function canonicalizeModelID(modelID: string): string {
|
||||
return modelID.toLowerCase().replace(/\./g, "-")
|
||||
}
|
||||
|
||||
export type FallbackRetryHandlerDeps = {
|
||||
log: typeof log
|
||||
readProviderModelsCache: typeof readProviderModelsCache
|
||||
readConnectedProvidersCache: typeof readConnectedProvidersCache
|
||||
shouldRetryError: typeof shouldRetryError
|
||||
getNextFallback: typeof getNextFallback
|
||||
hasMoreFallbacks: typeof hasMoreFallbacks
|
||||
selectFallbackProvider: typeof selectFallbackProvider
|
||||
transformModelForProvider: typeof transformModelForProvider
|
||||
}
|
||||
|
||||
const defaultFallbackRetryHandlerDeps: FallbackRetryHandlerDeps = {
|
||||
log,
|
||||
readProviderModelsCache,
|
||||
readConnectedProvidersCache,
|
||||
shouldRetryError,
|
||||
getNextFallback,
|
||||
hasMoreFallbacks,
|
||||
selectFallbackProvider,
|
||||
transformModelForProvider,
|
||||
}
|
||||
|
||||
export async function tryFallbackRetry(args: {
|
||||
task: BackgroundTask
|
||||
errorInfo: { name?: string; message?: string }
|
||||
@@ -34,20 +56,22 @@ export async function tryFallbackRetry(args: {
|
||||
failedError?: string
|
||||
nextModel: string
|
||||
}) => void
|
||||
deps?: Partial<FallbackRetryHandlerDeps>
|
||||
}): Promise<boolean> {
|
||||
const { task, errorInfo, source, concurrencyManager, client, idleDeferralTimers, queuesByKey, processKey, onRetrying } = args
|
||||
const deps = { ...defaultFallbackRetryHandlerDeps, ...args.deps }
|
||||
const fallbackChain = task.fallbackChain
|
||||
const canRetry =
|
||||
shouldRetryError(errorInfo) &&
|
||||
deps.shouldRetryError(errorInfo) &&
|
||||
fallbackChain &&
|
||||
fallbackChain.length > 0 &&
|
||||
hasMoreFallbacks(fallbackChain, task.attemptCount ?? 0)
|
||||
deps.hasMoreFallbacks(fallbackChain, task.attemptCount ?? 0)
|
||||
|
||||
if (!canRetry) return false
|
||||
|
||||
const attemptCount = task.attemptCount ?? 0
|
||||
const providerModelsCache = readProviderModelsCache()
|
||||
const connectedProviders = providerModelsCache?.connected ?? readConnectedProvidersCache()
|
||||
const providerModelsCache = deps.readProviderModelsCache()
|
||||
const connectedProviders = providerModelsCache?.connected ?? deps.readConnectedProvidersCache()
|
||||
const connectedSet = connectedProviders ? new Set(connectedProviders.map(p => p.toLowerCase())) : null
|
||||
const preferredProvider = task.model?.providerID?.toLowerCase()
|
||||
|
||||
@@ -63,11 +87,11 @@ export async function tryFallbackRetry(args: {
|
||||
let nextFallback: FallbackEntry | undefined
|
||||
let nextProviderID: string | undefined
|
||||
while (fallbackChain && selectedAttemptCount < fallbackChain.length) {
|
||||
const candidate = getNextFallback(fallbackChain, selectedAttemptCount)
|
||||
const candidate = deps.getNextFallback(fallbackChain, selectedAttemptCount)
|
||||
if (!candidate) break
|
||||
selectedAttemptCount++
|
||||
if (!isReachable(candidate)) {
|
||||
log("[background-agent] Skipping unreachable fallback:", {
|
||||
deps.log("[background-agent] Skipping unreachable fallback:", {
|
||||
taskId: task.id,
|
||||
source,
|
||||
model: candidate.model,
|
||||
@@ -75,17 +99,17 @@ export async function tryFallbackRetry(args: {
|
||||
})
|
||||
continue
|
||||
}
|
||||
const candidateProviderID = selectFallbackProvider(
|
||||
const candidateProviderID = deps.selectFallbackProvider(
|
||||
candidate.providers,
|
||||
task.model?.providerID,
|
||||
)
|
||||
const candidateModelID = transformModelForProvider(candidateProviderID, candidate.model)
|
||||
const candidateModelID = deps.transformModelForProvider(candidateProviderID, candidate.model)
|
||||
const isNoOpFallback =
|
||||
!!task.model &&
|
||||
candidateProviderID.toLowerCase() === task.model.providerID.toLowerCase() &&
|
||||
canonicalizeModelID(candidateModelID) === canonicalizeModelID(task.model.modelID)
|
||||
if (isNoOpFallback) {
|
||||
log("[background-agent] Skipping no-op fallback:", {
|
||||
deps.log("[background-agent] Skipping no-op fallback:", {
|
||||
taskId: task.id,
|
||||
source,
|
||||
model: candidate.model,
|
||||
@@ -99,12 +123,12 @@ export async function tryFallbackRetry(args: {
|
||||
}
|
||||
if (!nextFallback) return false
|
||||
|
||||
const providerID = nextProviderID ?? selectFallbackProvider(
|
||||
const providerID = nextProviderID ?? deps.selectFallbackProvider(
|
||||
nextFallback.providers,
|
||||
task.model?.providerID,
|
||||
)
|
||||
|
||||
log("[background-agent] Retryable error, attempting fallback:", {
|
||||
deps.log("[background-agent] Retryable error, attempting fallback:", {
|
||||
taskId: task.id,
|
||||
source,
|
||||
errorName: errorInfo.name,
|
||||
@@ -127,7 +151,7 @@ export async function tryFallbackRetry(args: {
|
||||
const previousSessionID = task.sessionId
|
||||
const previousModel = task.model
|
||||
|
||||
const transformedModelId = transformModelForProvider(providerID, nextFallback.model)
|
||||
const transformedModelId = deps.transformModelForProvider(providerID, nextFallback.model)
|
||||
const nextModel = {
|
||||
providerID,
|
||||
modelID: transformedModelId,
|
||||
|
||||
Reference in New Issue
Block a user