Skip to content

Commit 056d840

Browse files
fix: preserve fallback provider status usage
1 parent 1eb3ffc commit 056d840

2 files changed

Lines changed: 97 additions & 0 deletions

File tree

src/auto-reply/reply/commands-status.test.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,95 @@ describe("buildStatusReply subagent summary", () => {
12491249
});
12501250
});
12511251

1252+
it("uses active fallback provider usage for legacy fallback notices", async () => {
1253+
const fallbackModel: ModelDefinitionConfig = {
1254+
id: "MiniMax-M2.7",
1255+
name: "MiniMax M2.7",
1256+
reasoning: false,
1257+
input: ["text"],
1258+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1259+
contextWindow: 200_000,
1260+
maxTokens: 32_000,
1261+
};
1262+
const selectedModel: ModelDefinitionConfig = {
1263+
id: "mimo-v2-flash",
1264+
name: "MiMo V2 Flash",
1265+
reasoning: false,
1266+
input: ["text"],
1267+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1268+
contextWindow: 1_048_576,
1269+
maxTokens: 32_000,
1270+
};
1271+
providerUsageMock.loadProviderUsageSummary.mockImplementation(async (options) => ({
1272+
updatedAt: Date.now(),
1273+
providers:
1274+
options?.providers?.includes("minimax") === true
1275+
? [
1276+
{
1277+
provider: "minimax",
1278+
displayName: "MiniMax",
1279+
windows: [{ label: "day", usedPercent: 20 }],
1280+
},
1281+
]
1282+
: [],
1283+
}));
1284+
1285+
const text = await buildStatusText({
1286+
cfg: {
1287+
...baseCfg,
1288+
models: {
1289+
providers: {
1290+
"minimax-portal": {
1291+
baseUrl: "https://api.minimax.test/v1",
1292+
models: [fallbackModel],
1293+
},
1294+
xiaomi: {
1295+
baseUrl: "https://api.xiaomi.test/v1",
1296+
models: [selectedModel],
1297+
},
1298+
},
1299+
},
1300+
},
1301+
sessionEntry: {
1302+
sessionId: "sess-status-legacy-fallback-usage",
1303+
updatedAt: 0,
1304+
providerOverride: "xiaomi",
1305+
modelOverride: "mimo-v2-flash",
1306+
modelProvider: "minimax-portal",
1307+
model: "MiniMax-M2.7",
1308+
fallbackNoticeSelectedModel: "xiaomi/mimo-v2-flash",
1309+
fallbackNoticeActiveModel: "minimax-portal/MiniMax-M2.7",
1310+
fallbackNoticeReason: "model not allowed",
1311+
totalTokens: 49_000,
1312+
totalTokensFresh: true,
1313+
contextTokens: 1_048_576,
1314+
},
1315+
sessionKey: "agent:main:main",
1316+
parentSessionKey: "agent:main:main",
1317+
sessionScope: "per-sender",
1318+
statusChannel: "mobilechat",
1319+
provider: "xiaomi",
1320+
model: "mimo-v2-flash",
1321+
contextTokens: 1_048_576,
1322+
resolvedFastMode: false,
1323+
resolvedVerboseLevel: "off",
1324+
resolvedReasoningLevel: "off",
1325+
resolveDefaultThinkingLevel: async () => undefined,
1326+
isGroup: false,
1327+
defaultGroupActivation: () => "mention",
1328+
modelAuthOverride: "api-key",
1329+
activeModelAuthOverride: "api-key",
1330+
});
1331+
1332+
const normalized = normalizeTestText(text);
1333+
expect(normalized).toContain("Fallback: minimax-portal/MiniMax-M2.7");
1334+
expect(normalized).toContain("Context: 49k/200k");
1335+
expect(normalized).toContain("Usage: day 80% left");
1336+
expect(providerUsageMock.loadProviderUsageSummary).toHaveBeenCalledWith(
1337+
expect.objectContaining({ providers: ["minimax"] }),
1338+
);
1339+
});
1340+
12521341
it("shows DeepSeek balance summaries in /status output", async () => {
12531342
providerUsageMock.loadProviderUsageSummary.mockResolvedValue({
12541343
updatedAt: Date.now(),

src/status/status-text.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import {
4949
formatTaskStatusDetail,
5050
formatTaskStatusTitle,
5151
} from "../tasks/task-status.js";
52+
import { resolveActiveFallbackState } from "./fallback-notice-state.js";
5253
import { formatCompactPluginHealthLine } from "./status-plugin-health.js";
5354
import type { BuildStatusTextParams } from "./status-text.types.js";
5455

@@ -423,6 +424,12 @@ export async function buildStatusText(params: BuildStatusTextParams): Promise<st
423424
modelRefs.active.label,
424425
{ config: cfg },
425426
);
427+
const fallbackState = resolveActiveFallbackState({
428+
selectedModelRef: modelRefs.selected.label || "unknown",
429+
activeModelRef: modelRefs.active.label || "unknown",
430+
config: cfg,
431+
state: sessionEntry,
432+
});
426433
if (
427434
shouldPreferActiveRuntimeAliasAuthLabel({
428435
runtimeAliasModelEquivalent,
@@ -436,6 +443,7 @@ export async function buildStatusText(params: BuildStatusTextParams): Promise<st
436443
}
437444
const usageShouldFollowActiveRuntime =
438445
!modelRefs.activeDiffers ||
446+
fallbackState.active ||
439447
hasSessionAutoModelFallbackProvenance(sessionEntry) ||
440448
runtimeAliasModelEquivalent;
441449
const usageAuthLabel = usageShouldFollowActiveRuntime ? activeModelAuth : selectedModelAuth;

0 commit comments

Comments
 (0)