


































@@ -1058,6 +1058,164 @@ describe("createModelSelectionState auto-failover overrides", () => {
10581058expect(state.resetModelOverride).toBe(false);
10591059});
106010601061+it("clears stale auto-created legacy openai-codex route pins when primary is canonical openai", async () => {
1062+const sessionEntry = makeEntry({
1063+providerOverride: "openai-codex",
1064+modelOverride: "gpt-5.5",
1065+modelOverrideSource: "auto",
1066+modelProvider: "openai-codex",
1067+model: "gpt-5.5",
1068+contextTokens: 350_000,
1069+authProfileOverride: "openai-codex:default",
1070+authProfileOverrideSource: "auto",
1071+});
1072+const sessionStore = { [sessionKey]: sessionEntry };
1073+1074+const state = await createModelSelectionState({
1075+cfg: {} as OpenClawConfig,
1076+agentCfg: undefined,
1077+ sessionEntry,
1078+ sessionStore,
1079+ sessionKey,
1080+defaultProvider: "openai",
1081+defaultModel: "gpt-5.5",
1082+primaryProvider: "openai",
1083+primaryModel: "gpt-5.5",
1084+provider: "openai-codex",
1085+model: "gpt-5.5",
1086+hasModelDirective: false,
1087+});
1088+1089+expect(state.provider).toBe("openai");
1090+expect(state.model).toBe("gpt-5.5");
1091+expect(state.resetModelOverride).toBe(true);
1092+expect(state.resetModelOverrideRef).toBe("openai-codex/gpt-5.5");
1093+expect(sessionStore[sessionKey]?.providerOverride).toBeUndefined();
1094+expect(sessionStore[sessionKey]?.modelOverride).toBeUndefined();
1095+expect(sessionStore[sessionKey]?.modelOverrideSource).toBeUndefined();
1096+expect(sessionStore[sessionKey]?.modelProvider).toBeUndefined();
1097+expect(sessionStore[sessionKey]?.model).toBeUndefined();
1098+expect(sessionStore[sessionKey]?.contextTokens).toBeUndefined();
1099+expect(sessionStore[sessionKey]?.authProfileOverride).toBeUndefined();
1100+expect(sessionStore[sessionKey]?.authProfileOverrideSource).toBeUndefined();
1101+});
1102+1103+it("preserves usable Codex auth while clearing stale legacy openai-codex route pins", async () => {
1104+authProfileStoreMock.store = {
1105+version: 1,
1106+profiles: {
1107+"openai-codex:default": {
1108+type: "api_key",
1109+provider: "openai-codex",
1110+key: "test-key",
1111+},
1112+},
1113+};
1114+const sessionEntry = makeEntry({
1115+providerOverride: "openai-codex",
1116+modelOverride: "gpt-5.5",
1117+modelOverrideSource: "auto",
1118+authProfileOverride: "openai-codex:default",
1119+authProfileOverrideSource: "auto",
1120+});
1121+const sessionStore = { [sessionKey]: sessionEntry };
1122+1123+const state = await createModelSelectionState({
1124+cfg: {} as OpenClawConfig,
1125+agentCfg: undefined,
1126+ sessionEntry,
1127+ sessionStore,
1128+ sessionKey,
1129+defaultProvider: "openai",
1130+defaultModel: "gpt-5.5",
1131+primaryProvider: "openai",
1132+primaryModel: "gpt-5.5",
1133+provider: "openai-codex",
1134+model: "gpt-5.5",
1135+hasModelDirective: false,
1136+});
1137+1138+expect(state.provider).toBe("openai");
1139+expect(state.model).toBe("gpt-5.5");
1140+expect(state.resetModelOverride).toBe(true);
1141+expect(sessionStore[sessionKey]?.providerOverride).toBeUndefined();
1142+expect(sessionStore[sessionKey]?.modelOverride).toBeUndefined();
1143+expect(sessionStore[sessionKey]?.authProfileOverride).toBe("openai-codex:default");
1144+expect(sessionStore[sessionKey]?.authProfileOverrideSource).toBe("auto");
1145+});
1146+1147+it("keeps auto openai-codex pins when canonical openai uses a custom API route", async () => {
1148+const cfg = {
1149+models: {
1150+providers: {
1151+openai: {
1152+baseUrl: "https://proxy.example.test/v1",
1153+models: [],
1154+},
1155+},
1156+},
1157+} as OpenClawConfig;
1158+const sessionEntry = makeEntry({
1159+providerOverride: "openai-codex",
1160+modelOverride: "gpt-5.5",
1161+modelOverrideSource: "auto",
1162+});
1163+const sessionStore = { [sessionKey]: sessionEntry };
1164+1165+const state = await createModelSelectionState({
1166+ cfg,
1167+agentCfg: undefined,
1168+ sessionEntry,
1169+ sessionStore,
1170+ sessionKey,
1171+defaultProvider: "openai",
1172+defaultModel: "gpt-5.5",
1173+primaryProvider: "openai",
1174+primaryModel: "gpt-5.5",
1175+provider: "openai-codex",
1176+model: "gpt-5.5",
1177+hasModelDirective: false,
1178+});
1179+1180+expect(state.provider).toBe("openai-codex");
1181+expect(state.model).toBe("gpt-5.5");
1182+expect(state.resetModelOverride).toBe(false);
1183+expect(sessionStore[sessionKey]?.providerOverride).toBe("openai-codex");
1184+expect(sessionStore[sessionKey]?.modelOverride).toBe("gpt-5.5");
1185+expect(sessionStore[sessionKey]?.modelOverrideSource).toBe("auto");
1186+});
1187+1188+it("keeps explicit user openai-codex route overrides", async () => {
1189+const sessionEntry = makeEntry({
1190+providerOverride: "openai-codex",
1191+modelOverride: "gpt-5.5",
1192+modelOverrideSource: "user",
1193+});
1194+const sessionStore = { [sessionKey]: sessionEntry };
1195+1196+const state = await createModelSelectionState({
1197+cfg: {} as OpenClawConfig,
1198+agentCfg: undefined,
1199+ sessionEntry,
1200+ sessionStore,
1201+ sessionKey,
1202+defaultProvider: "openai",
1203+defaultModel: "gpt-5.5",
1204+primaryProvider: "openai",
1205+primaryModel: "gpt-5.5",
1206+provider: "openai",
1207+model: "gpt-5.5",
1208+hasModelDirective: false,
1209+});
1210+1211+expect(state.provider).toBe("openai-codex");
1212+expect(state.model).toBe("gpt-5.5");
1213+expect(state.resetModelOverride).toBe(false);
1214+expect(sessionStore[sessionKey]?.providerOverride).toBe("openai-codex");
1215+expect(sessionStore[sessionKey]?.modelOverride).toBe("gpt-5.5");
1216+expect(sessionStore[sessionKey]?.modelOverrideSource).toBe("user");
1217+});
1218+10611219it("still clears disallowed auto-failover overrides through allowlist validation", async () => {
10621220const cfg = {
10631221agents: {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。