From aa3797c8d0d74b4502d24852ce6baa70286f2f06 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 22 Jun 2026 09:09:45 +0800 Subject: [PATCH] fix: complete fast mode fallback and status wiring --- src/acp/translator.ts | 1 + src/agents/agent-command.ts | 1 + src/agents/command/attempt-execution.ts | 2 ++ src/agents/embedded-agent-runner/run.ts | 4 +++- src/agents/embedded-agent-runner/run/params.ts | 2 ++ src/agents/model-fallback.ts | 6 +++++- src/status/status-message.ts | 15 +++++++++++++-- 7 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/acp/translator.ts b/src/acp/translator.ts index 13ca39717187..e70a286def3e 100644 --- a/src/acp/translator.ts +++ b/src/acp/translator.ts @@ -1498,6 +1498,7 @@ export class AcpGatewayAgent implements Agent { modelProvider: session.modelProvider, model: session.model, fastMode: session.fastMode, + effectiveFastMode: session.effectiveFastMode, verboseLevel: session.verboseLevel, traceLevel: session.traceLevel, reasoningLevel: session.reasoningLevel, diff --git a/src/agents/agent-command.ts b/src/agents/agent-command.ts index b2eaa12ac75e..434a745b0474 100644 --- a/src/agents/agent-command.ts +++ b/src/agents/agent-command.ts @@ -1926,6 +1926,7 @@ async function agentCommandInternal( fastMode === "auto" ? (opts.fastModeAutoOnSeconds ?? fastModeState.fastAutoOnSeconds) : fastModeState.fastAutoOnSeconds, + isFinalFallbackAttempt: runOptions?.isFinalFallbackAttempt, timeoutMs, runTimeoutOverrideMs, runId, diff --git a/src/agents/command/attempt-execution.ts b/src/agents/command/attempt-execution.ts index e46f4ce7cecb..b0c44861f4ac 100644 --- a/src/agents/command/attempt-execution.ts +++ b/src/agents/command/attempt-execution.ts @@ -478,6 +478,7 @@ export function runAgentAttempt(params: { fastMode?: FastMode; fastModeStartedAtMs?: number; fastModeAutoOnSeconds?: number; + isFinalFallbackAttempt?: boolean; timeoutMs: number; runTimeoutOverrideMs?: number; runId: string; @@ -791,6 +792,7 @@ export function runAgentAttempt(params: { fastMode: params.fastMode, fastModeStartedAtMs: params.fastModeStartedAtMs, fastModeAutoOnSeconds: params.fastModeAutoOnSeconds, + isFinalFallbackAttempt: params.isFinalFallbackAttempt, verboseLevel: params.resolvedVerboseLevel, bashElevated: params.opts.bashElevated, approvalReviewerDeviceId: params.opts.approvalReviewerDeviceId, diff --git a/src/agents/embedded-agent-runner/run.ts b/src/agents/embedded-agent-runner/run.ts index 1b26f8a336d5..97b73e4e5bd6 100644 --- a/src/agents/embedded-agent-runner/run.ts +++ b/src/agents/embedded-agent-runner/run.ts @@ -4124,7 +4124,9 @@ async function runEmbeddedAgentInternal( }; } } finally { - await maybeEmitFastModeAutoResetBestEffort(); + if (params.isFinalFallbackAttempt !== false) { + await maybeEmitFastModeAutoResetBestEffort(); + } forgetPromptBuildDrainCacheForRun(params.runId); stopRuntimeAuthRefreshTimer(); await runAgentCleanupStep({ diff --git a/src/agents/embedded-agent-runner/run/params.ts b/src/agents/embedded-agent-runner/run/params.ts index 1226c18c7105..36f8a37ee7b8 100644 --- a/src/agents/embedded-agent-runner/run/params.ts +++ b/src/agents/embedded-agent-runner/run/params.ts @@ -153,6 +153,8 @@ export type RunEmbeddedAgentParams = { fastModeAutoOnSeconds?: number; /** Shared notification state for nested harnesses that can observe the same tool boundary. */ fastModeAutoProgressState?: FastModeAutoProgressState; + /** True when the outer model fallback loop has reached its final candidate. */ + isFinalFallbackAttempt?: boolean; verboseLevel?: VerboseLevel; reasoningLevel?: ReasoningLevel; toolResultFormat?: ToolResultFormat; diff --git a/src/agents/model-fallback.ts b/src/agents/model-fallback.ts index 90566b4c82f5..1a96513745da 100644 --- a/src/agents/model-fallback.ts +++ b/src/agents/model-fallback.ts @@ -168,6 +168,7 @@ export function isFallbackSummaryError(err: unknown): err is FallbackSummaryErro export type ModelFallbackRunOptions = { allowTransientCooldownProbe?: boolean; + isFinalFallbackAttempt?: boolean; }; type ModelFallbackRuntimeContext = { @@ -1657,7 +1658,10 @@ async function runWithModelFallbackInternal( run: params.run, ...candidate, attempts, - options: runOptions, + options: { + ...runOptions, + isFinalFallbackAttempt: i + 1 === candidates.length, + }, // Only the outer fallback loop knows another candidate remains. Carry // that fact through this attempt so the embedded runner does not freeze // the shared lane before the next candidate can run. diff --git a/src/status/status-message.ts b/src/status/status-message.ts index b61422d0bca8..1652cb291d5a 100644 --- a/src/status/status-message.ts +++ b/src/status/status-message.ts @@ -9,6 +9,7 @@ import { import { resolveContextTokensForModel } from "../agents/context.js"; import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js"; import { resolveExtraParams } from "../agents/embedded-agent-runner/extra-params.js"; +import { resolveFastModeState } from "../agents/fast-mode.js"; import { resolveModelAuthMode } from "../agents/model-auth.js"; import { areRuntimeModelRefsEquivalent, @@ -25,7 +26,6 @@ import { formatProviderModelRef, resolveSelectedAndActiveModel, } from "../auto-reply/model-runtime.js"; -import { formatFastModeStatusValue } from "../shared/fast-mode.js"; import type { ElevatedLevel, ReasoningLevel, @@ -56,6 +56,7 @@ import { } from "../media-understanding/runner.entries.js"; import type { MediaUnderstandingDecision } from "../media-understanding/types.js"; import { resolveAgentIdFromSessionKey } from "../routing/session-key.js"; +import { formatFastModeStatusValue } from "../shared/fast-mode.js"; import { resolveStatusTtsSnapshot } from "../tts/status-config.js"; import { estimateUsageCost, @@ -882,6 +883,13 @@ export function buildStatusMessage(args: StatusArgs): string { const verboseLevel = args.resolvedVerbose ?? args.sessionEntry?.verboseLevel ?? args.agent?.verboseDefault ?? "off"; const fastMode = args.resolvedFast ?? args.sessionEntry?.fastMode ?? false; + const fastModeState = resolveFastModeState({ + cfg: args.config, + provider: activeProvider, + model: activeModel, + agentId: args.agentId, + sessionEntry: args.sessionEntry, + }); const reasoningLevel = args.resolvedReasoning ?? args.sessionEntry?.reasoningLevel ?? @@ -970,7 +978,10 @@ export function buildStatusMessage(args: StatusArgs): string { `Execution: ${execution.label}`, `Runtime: ${agentRuntimeLabel}`, `Think: ${thinkLevel}`, - `Fast: ${formatFastModeStatusValue({ mode: fastMode })}`, + `Fast: ${formatFastModeStatusValue({ + mode: fastMode, + fastAutoOnSeconds: fastModeState.fastAutoOnSeconds, + })}`, textVerbosity ? `Text: ${textVerbosity}` : null, verboseLabel, traceLabel,