Skip to content

Commit 4b525c8

Browse files
committed
fix(agents): use configured primary as fallback origin to prevent indefinite session pinning
When a model fallback occurs without an existing autoFallbackPrimaryProbe (first fallback), resolveFallbackSelectionOrigin falls back to selectionRun (which is the fallback candidate) instead of the configured primary. This records the wrong origin, causing the snap-back probe guard (originProvider !== primaryProvider) to always return early — the session stays pinned to the fallback model indefinitely. Fix: pass params.followupRun.run (the configured primary) as the primary reference through applyFallbackCandidateSelectionToEntry → resolveFallbackSelectionOrigin, so the origin is always the primary model even on the first fallback. Fixes #92776
1 parent b3dc274 commit 4b525c8

1 file changed

Lines changed: 23 additions & 2 deletions

File tree

src/auto-reply/reply/agent-runner-execution.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,11 @@ function buildFallbackSelectionState(params: {
441441
};
442442
}
443443

444-
function resolveFallbackSelectionOrigin(params: { entry: SessionEntry; run: FollowupRun["run"] }): {
444+
function resolveFallbackSelectionOrigin(params: {
445+
entry: SessionEntry;
446+
run: FollowupRun["run"];
447+
primary?: { provider: string; model: string };
448+
}): {
445449
provider: string;
446450
model: string;
447451
} {
@@ -460,6 +464,13 @@ function resolveFallbackSelectionOrigin(params: { entry: SessionEntry; run: Foll
460464
return { provider: persistedOriginProvider, model: persistedOriginModel };
461465
}
462466
}
467+
// When a primary reference is available, use it as the origin instead of
468+
// params.run — params.run may already be a fallback candidate, which would
469+
// record the wrong origin and prevent the snap-back probe from ever matching
470+
// the configured primary. See #92776.
471+
if (params.primary) {
472+
return { provider: params.primary.provider, model: params.primary.model };
473+
}
463474
return { provider: params.run.provider, model: params.run.model };
464475
}
465476

@@ -470,6 +481,7 @@ export function applyFallbackCandidateSelectionToEntry(params: {
470481
provider: string;
471482
model: string;
472483
origin?: { provider: string; model: string };
484+
primary?: { provider: string; model: string };
473485
force?: boolean;
474486
now?: number;
475487
}): { updated: boolean; nextState?: FallbackSelectionState } {
@@ -482,7 +494,7 @@ export function applyFallbackCandidateSelectionToEntry(params: {
482494
}
483495
const scopedAuthProfile = resolveRunAuthProfile(params.run, params.provider);
484496
const origin =
485-
params.origin ?? resolveFallbackSelectionOrigin({ entry: params.entry, run: params.run });
497+
params.origin ?? resolveFallbackSelectionOrigin({ entry: params.entry, run: params.run, primary: params.primary });
486498
const nextState = buildFallbackSelectionState({
487499
provider: params.provider,
488500
model: params.model,
@@ -1814,6 +1826,15 @@ export async function runAgentTurnWithFallback(params: {
18141826
provider: persistedProvider,
18151827
model,
18161828
force: candidateRun !== effectiveRun && Boolean(effectiveRun.autoFallbackPrimaryProbe),
1829+
// Always pass the configured primary so the origin is recorded correctly
1830+
// even on the first fallback (before autoFallbackPrimaryProbe exists).
1831+
// Without this, resolveFallbackSelectionOrigin falls back to selectionRun
1832+
// which may already be a fallback candidate — recording the wrong origin
1833+
// and preventing the snap-back probe from ever matching. See #92776.
1834+
primary: {
1835+
provider: params.followupRun.run.provider,
1836+
model: params.followupRun.run.model,
1837+
},
18171838
...(effectiveRun.autoFallbackPrimaryProbe
18181839
? {
18191840
origin: {

0 commit comments

Comments
 (0)