feat(auto-reply): add model fallback lifecycle visibility in status, verbose logs, and WebUI (#20704)

This commit is contained in:
Josh Avant
2026-02-19 14:33:02 -08:00
committed by GitHub
parent 6cdcb5904d
commit c2876b69fb
24 changed files with 1855 additions and 55 deletions

View File

@@ -40,12 +40,23 @@ import type { FollowupRun } from "./queue.js";
import { createBlockReplyDeliveryHandler } from "./reply-delivery.js";
import type { TypingSignaler } from "./typing-mode.js";
export type RuntimeFallbackAttempt = {
provider: string;
model: string;
error: string;
reason?: string;
status?: number;
code?: string;
};
export type AgentRunLoopResult =
| {
kind: "success";
runId: string;
runResult: Awaited<ReturnType<typeof runEmbeddedPiAgent>>;
fallbackProvider?: string;
fallbackModel?: string;
fallbackAttempts: RuntimeFallbackAttempt[];
didLogHeartbeatStrip: boolean;
autoCompactionCompleted: boolean;
/** Payload keys sent directly (not via pipeline) during tool flush. */
@@ -106,6 +117,7 @@ export async function runAgentTurnWithFallback(params: {
let runResult: Awaited<ReturnType<typeof runEmbeddedPiAgent>>;
let fallbackProvider = params.followupRun.run.provider;
let fallbackModel = params.followupRun.run.model;
let fallbackAttempts: RuntimeFallbackAttempt[] = [];
let didResetAfterCompactionFailure = false;
let didRetryTransientHttpError = false;
@@ -397,6 +409,16 @@ export async function runAgentTurnWithFallback(params: {
runResult = fallbackResult.result;
fallbackProvider = fallbackResult.provider;
fallbackModel = fallbackResult.model;
fallbackAttempts = Array.isArray(fallbackResult.attempts)
? fallbackResult.attempts.map((attempt) => ({
provider: String(attempt.provider ?? ""),
model: String(attempt.model ?? ""),
error: String(attempt.error ?? ""),
reason: attempt.reason ? String(attempt.reason) : undefined,
status: typeof attempt.status === "number" ? attempt.status : undefined,
code: attempt.code ? String(attempt.code) : undefined,
}))
: [];
// Some embedded runs surface context overflow as an error payload instead of throwing.
// Treat those as a session-level failure and auto-recover by starting a fresh session.
@@ -543,9 +565,11 @@ export async function runAgentTurnWithFallback(params: {
return {
kind: "success",
runId,
runResult,
fallbackProvider,
fallbackModel,
fallbackAttempts,
didLogHeartbeatStrip,
autoCompactionCompleted,
directlySentBlockKeys: directlySentBlockKeys.size > 0 ? directlySentBlockKeys : undefined,