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

@@ -7,8 +7,10 @@ import {
resolveModelRefFromString,
} from "../../agents/model-selection.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { SessionEntry } from "../../config/sessions.js";
import { buildBrowseProvidersButton } from "../../telegram/model-buttons.js";
import { shortenHomePath } from "../../utils.js";
import { resolveSelectedAndActiveModel } from "../model-runtime.js";
import type { ReplyPayload } from "../types.js";
import { resolveModelsCommandReply } from "./commands-models.js";
import {
@@ -198,6 +200,7 @@ export async function maybeHandleModelDirectiveInfo(params: {
allowedModelCatalog: Array<{ provider: string; id?: string; name?: string }>;
resetModelOverride: boolean;
surface?: string;
sessionEntry?: Pick<SessionEntry, "modelProvider" | "model">;
}): Promise<ReplyPayload | undefined> {
if (!params.directives.hasModelDirective) {
return undefined;
@@ -233,31 +236,45 @@ export async function maybeHandleModelDirectiveInfo(params: {
}
if (wantsSummary) {
const current = `${params.provider}/${params.model}`;
const modelRefs = resolveSelectedAndActiveModel({
selectedProvider: params.provider,
selectedModel: params.model,
sessionEntry: params.sessionEntry,
});
const current = modelRefs.selected.label;
const isTelegram = params.surface === "telegram";
const activeRuntimeLine = modelRefs.activeDiffers
? `Active: ${modelRefs.active.label} (runtime)`
: null;
if (isTelegram) {
const buttons = buildBrowseProvidersButton();
return {
text: [
`Current: ${current}`,
`Current: ${current}${modelRefs.activeDiffers ? " (selected)" : ""}`,
activeRuntimeLine,
"",
"Tap below to browse models, or use:",
"/model <provider/model> to switch",
"/model status for details",
].join("\n"),
]
.filter(Boolean)
.join("\n"),
channelData: { telegram: { buttons } },
};
}
return {
text: [
`Current: ${current}`,
`Current: ${current}${modelRefs.activeDiffers ? " (selected)" : ""}`,
activeRuntimeLine,
"",
"Switch: /model <provider/model>",
"Browse: /models (providers) or /models <provider> (models)",
"More: /model status",
].join("\n"),
]
.filter(Boolean)
.join("\n"),
};
}
@@ -284,14 +301,20 @@ export async function maybeHandleModelDirectiveInfo(params: {
authByProvider.set(provider, formatAuthLabel(auth));
}
const current = `${params.provider}/${params.model}`;
const modelRefs = resolveSelectedAndActiveModel({
selectedProvider: params.provider,
selectedModel: params.model,
sessionEntry: params.sessionEntry,
});
const current = modelRefs.selected.label;
const defaultLabel = `${params.defaultProvider}/${params.defaultModel}`;
const lines = [
`Current: ${current}`,
`Current: ${current}${modelRefs.activeDiffers ? " (selected)" : ""}`,
modelRefs.activeDiffers ? `Active: ${modelRefs.active.label} (runtime)` : null,
`Default: ${defaultLabel}`,
`Agent: ${params.activeAgentId}`,
`Auth file: ${formatPath(resolveAuthStorePathForDisplay(params.agentDir))}`,
];
].filter((line): line is string => Boolean(line));
if (params.resetModelOverride) {
lines.push(`(previous selection reset to default)`);
}