test: adapt catalog-pinned tests to regenerated model catalog

- Repointed tests off removed gpt-5.2/5.3 codex variants and devin models (e06ac0b787): context-promotion and TTSR tests pin gpt-5.5 -> gpt-5.6-sol via per-test modelOverrides since no bundled codex model has a runtime-effective promotion target anymore; replay-boundary and history-payload suites use gpt-5.5; advisor quota fallback uses devin/swe-1-6-slow with suffix-less selectors per #4579 devin-agent semantics; gateway-reference pins kilo/giga-potato and now asserts the reference carries effortRouting so the cross-provider no-inherit contract stays meaningful.
- Verified cross-provider gateway references do not inherit wire routing after variant collapse (identity/reference.ts:145-154) - stale test, no product bug.
This commit is contained in:
can1357
2026-07-22 22:26:10 +02:00
parent 0002905ec5
commit e4de9509c7
6 changed files with 141 additions and 98 deletions
@@ -108,7 +108,7 @@ const assistantSnapshotContext: Context = {
const codexAssistantSnapshotContext: Context = {
messages: [
{ role: "user", content: "generic history that should be replaced", timestamp: Date.now() },
makeAssistantMessage(snapshotHistoryItems, false, "openai-codex", "gpt-5.2-codex"),
makeAssistantMessage(snapshotHistoryItems, false, "openai-codex", "gpt-5.5"),
{ role: "user", content: "follow-up user", timestamp: Date.now() },
],
};
@@ -117,7 +117,7 @@ const codexToCopilotContext: Context = {
messages: [
{ role: "user", content: "generic user before switch", timestamp: Date.now() },
{
...makeAssistantMessage([], false, "openai-codex", "gpt-5.2-codex"),
...makeAssistantMessage([], false, "openai-codex", "gpt-5.5"),
content: [{ type: "text", text: "generic assistant that should be rebuilt" }],
providerPayload: createOpenAIResponsesHistoryPayload("openai-codex", [
{ type: "reasoning", encrypted_content: "enc_123" },
@@ -267,7 +267,7 @@ function makeAssistantMessage(
items: Record<string, unknown>[],
incremental = false,
provider: "openai" | "openai-codex" | "github-copilot" = "openai",
model = provider === "openai-codex" ? "gpt-5.2-codex" : provider === "github-copilot" ? "gpt-5.4" : "gpt-5-mini",
model = provider === "openai-codex" ? "gpt-5.5" : provider === "github-copilot" ? "gpt-5.4" : "gpt-5-mini",
) {
return {
role: "assistant" as const,
@@ -428,7 +428,7 @@ describe("OpenAI responses history payload", () => {
});
assertWireOrder(openaiItems);
const codexModel = getBundledModel<"openai-codex-responses">("openai-codex", "gpt-5.2-codex");
const codexModel = getBundledModel<"openai-codex-responses">("openai-codex", "gpt-5.5");
const codexItems = convertCodexResponsesMessages(codexModel, makeContext("openai-codex"));
assertWireOrder(codexItems);
});
@@ -810,7 +810,7 @@ describe("OpenAI responses history payload", () => {
});
it("prefers assistant native history snapshots for openai-codex-responses", async () => {
const model = getBundledModel("openai-codex", "gpt-5.2-codex") as Model<"openai-codex-responses">;
const model = getBundledModel("openai-codex", "gpt-5.5") as Model<"openai-codex-responses">;
const payload = (await captureCodexPayload(model, codexAssistantSnapshotContext)) as { input?: unknown[] };
expect(payload.input).toEqual([
...snapshotHistoryItems,
@@ -1279,7 +1279,7 @@ describe("OpenAI responses history payload", () => {
content: [{ type: "toolCall", id: callId, name: "read", arguments: { path: "README.md" } }],
api: "openai-codex-responses",
provider: "openai-codex",
model: "gpt-5.2-codex",
model: "gpt-5.5",
usage: {
input: 0,
output: 0,
@@ -1303,7 +1303,7 @@ describe("OpenAI responses history payload", () => {
{ role: "user", content: "Resume", timestamp: Date.now() },
],
};
const model = getBundledModel<"openai-codex-responses">("openai-codex", "gpt-5.2-codex");
const model = getBundledModel<"openai-codex-responses">("openai-codex", "gpt-5.5");
const payload = (await captureCodexPayload(model, context)) as { input?: unknown[] };
const functionCallItem = findResponsesInputItem(payload.input, "function_call");
const functionCallOutputItem = findResponsesInputItem(payload.input, "function_call_output");
@@ -10,8 +10,9 @@ describe("Portkey gateway model references", () => {
test("cross-provider references do not inherit wire routing thinking", () => {
const index = getBundledModelReferenceIndex();
const devinGlm = resolveModelReference("glm-5-2", index);
expect(devinGlm?.provider).toBe("devin");
expect(inheritReferenceThinking(undefined, devinGlm, "gateway")).toBeUndefined();
const kiloGigaPotato = resolveModelReference("giga-potato", index);
expect(kiloGigaPotato?.provider).toBe("kilo");
expect(kiloGigaPotato?.thinking?.effortRouting).toBeDefined();
expect(inheritReferenceThinking(undefined, kiloGigaPotato, "gateway")).toBeUndefined();
});
});
@@ -2221,12 +2221,28 @@ describe("AgentSession TTSR resume gate", () => {
const authStorage = await AuthStorage.create(path.join(tempDir, "testauth-promo.db"));
authStorages.push(authStorage);
authStorage.setRuntimeApiKey("openai-codex", "test-key");
const modelRegistry = new ModelRegistry(authStorage, path.join(tempDir, "models.yml"));
// The bundled catalog has no codex model whose promotion target carries a
// strictly larger window (gpt-5.5's bundled target gpt-5.4 is same-window),
// so pin gpt-5.5 (272k) -> gpt-5.6-sol (372k) via modelOverrides.
const modelsConfigPath = path.join(tempDir, "models-promo.json");
await Bun.write(
modelsConfigPath,
JSON.stringify({
providers: {
"openai-codex": {
modelOverrides: {
"gpt-5.5": { contextPromotionTarget: "openai-codex/gpt-5.6-sol" },
},
},
},
}),
);
const modelRegistry = new ModelRegistry(authStorage, modelsConfigPath);
const sparkModel = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.5");
if (!sparkModel || !codexModel) {
throw new Error("Expected codex spark and codex models to exist");
const smallModel = modelRegistry.find("openai-codex", "gpt-5.5");
const largeModel = modelRegistry.find("openai-codex", "gpt-5.6-sol");
if (!smallModel || !largeModel) {
throw new Error("Expected small and large codex models to exist");
}
let streamCallCount = 0;
@@ -2235,9 +2251,9 @@ describe("AgentSession TTSR resume gate", () => {
const makeOverflowMessage = (): AssistantMessage => ({
role: "assistant",
content: [{ type: "text", text: "" }],
api: sparkModel.api,
provider: sparkModel.provider,
model: sparkModel.id,
api: smallModel.api,
provider: smallModel.provider,
model: smallModel.id,
usage: {
input: 0,
output: 0,
@@ -2254,9 +2270,9 @@ describe("AgentSession TTSR resume gate", () => {
const makeSuccessMessage = (): AssistantMessage => ({
role: "assistant",
content: [{ type: "text", text: "Recovered after promotion" }],
api: codexModel.api,
provider: codexModel.provider,
model: codexModel.id,
api: largeModel.api,
provider: largeModel.provider,
model: largeModel.id,
usage: {
input: 0,
output: 0,
@@ -2271,7 +2287,7 @@ describe("AgentSession TTSR resume gate", () => {
const agent = new Agent({
getApiKey: () => "test-key",
initialState: { model: sparkModel, systemPrompt: ["Test"], tools: [] },
initialState: { model: smallModel, systemPrompt: ["Test"], tools: [] },
streamFn: () => {
streamCallCount++;
const stream = new AssistantMessageEventStream();
@@ -2312,7 +2328,7 @@ describe("AgentSession TTSR resume gate", () => {
expect(continuationCompleted).toBe(true);
expect(streamCallCount).toBeGreaterThanOrEqual(2);
expect(session.model?.id).toBe(codexModel.id);
expect(session.model?.id).toBe(largeModel.id);
expect(session.isStreaming).toBe(false);
expect(extensionRunner.emitSessionStop).toHaveBeenCalledTimes(1);
});
@@ -21,10 +21,32 @@ describe("AgentSession context promotion", () => {
// constructor (~100ms). The catalog and auth fixture never change between
// tests here (tests only read models and add benign extra runtime keys),
// so build them once instead of paying ~950ms across the 9 cases.
//
// The bundled catalog no longer ships a codex model whose configured
// promotion target has a strictly larger window (gpt-5.5's bundled target
// gpt-5.4 is a same-window no-op the runtime rejects), so pin
// gpt-5.5 (272k) -> gpt-5.6-sol (372k) via modelOverrides — the same
// mechanism users configure promotion pairs with. gpt-5.4-mini is pinned
// text-only so the snapcompact-fallback case has a codex model on which
// snapcompact (vision-based) cannot run.
tempDir = TempDir.createSync("@pi-context-promotion-");
const modelsConfigPath = path.join(tempDir.path(), "models.json");
await Bun.write(
modelsConfigPath,
JSON.stringify({
providers: {
"openai-codex": {
modelOverrides: {
"gpt-5.5": { contextPromotionTarget: "openai-codex/gpt-5.6-sol" },
"gpt-5.4-mini": { input: ["text"] },
},
},
},
}),
);
authStorage = await AuthStorage.create(path.join(tempDir.path(), "testauth.db"));
authStorage.setRuntimeApiKey("openai-codex", "test-key");
modelRegistry = new ModelRegistry(authStorage);
modelRegistry = new ModelRegistry(authStorage, modelsConfigPath);
});
afterAll(() => {
@@ -134,10 +156,10 @@ describe("AgentSession context promotion", () => {
}
it("promotes to a larger-context model on overflow and clears codex websocket session state", async () => {
const sparkModel = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.5");
if (!sparkModel || !codexModel) {
throw new Error("Expected codex spark and codex models to exist");
const smallModel = modelRegistry.find("openai-codex", "gpt-5.5");
const largeModel = modelRegistry.find("openai-codex", "gpt-5.6-sol");
if (!smallModel || !largeModel) {
throw new Error("Expected small and large codex models to exist");
}
const settings = Settings.isolated({
@@ -147,7 +169,7 @@ describe("AgentSession context promotion", () => {
const agent = new Agent({
initialState: {
model: sparkModel,
model: smallModel,
systemPrompt: ["Test"],
tools: [],
messages: [],
@@ -166,23 +188,23 @@ describe("AgentSession context promotion", () => {
close: closeSpy,
} satisfies ProviderSessionState);
const overflowMessage = createOverflowMessage(sparkModel);
const overflowMessage = createOverflowMessage(smallModel);
session.agent.emitExternalEvent({ type: "message_end", message: overflowMessage });
session.agent.emitExternalEvent({ type: "agent_end", messages: [overflowMessage] });
await waitFor(() => session.model?.id === codexModel.id);
await waitFor(() => session.model?.id === largeModel.id);
expect(session.model?.provider).toBe(codexModel.provider);
expect(session.model?.id).toBe(codexModel.id);
expect(session.model?.provider).toBe(largeModel.provider);
expect(session.model?.id).toBe(largeModel.id);
expect(closeSpy).toHaveBeenCalledTimes(1);
expect(session.providerSessionState.size).toBe(0);
});
it("promotes on 413 payload-too-large overflow errors", async () => {
const sparkModel = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.5");
if (!sparkModel || !codexModel) {
throw new Error("Expected codex spark and codex models to exist");
const smallModel = modelRegistry.find("openai-codex", "gpt-5.5");
const largeModel = modelRegistry.find("openai-codex", "gpt-5.6-sol");
if (!smallModel || !largeModel) {
throw new Error("Expected small and large codex models to exist");
}
const settings = Settings.isolated({
@@ -192,7 +214,7 @@ describe("AgentSession context promotion", () => {
const agent = new Agent({
initialState: {
model: sparkModel,
model: smallModel,
systemPrompt: ["Test"],
tools: [],
messages: [],
@@ -207,19 +229,19 @@ describe("AgentSession context promotion", () => {
});
const overflowMessage = createOverflowMessage(
sparkModel,
smallModel,
"413 Request Entity Too Large: payload too large for model request body",
);
session.agent.emitExternalEvent({ type: "message_end", message: overflowMessage });
session.agent.emitExternalEvent({ type: "agent_end", messages: [overflowMessage] });
await waitFor(() => session.model?.id === codexModel.id);
await waitFor(() => session.model?.id === largeModel.id);
expect(session.model?.provider).toBe(codexModel.provider);
expect(session.model?.id).toBe(codexModel.id);
expect(session.model?.provider).toBe(largeModel.provider);
expect(session.model?.id).toBe(largeModel.id);
});
it("clears codex provider session state on manual setModel switch away from codex", async () => {
const codexModel = modelRegistry.find("openai-codex", "gpt-5.3-codex");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.4");
const nonCodexModel = modelRegistry.getAll().find(model => model.api !== "openai-codex-responses");
if (!codexModel || !nonCodexModel) {
throw new Error("Expected codex and non-codex models to exist");
@@ -256,7 +278,7 @@ describe("AgentSession context promotion", () => {
});
it("clears codex provider session state on manual temporary switch into codex", async () => {
const codexModel = modelRegistry.find("openai-codex", "gpt-5.3-codex");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.4");
const nonCodexModel = modelRegistry.getAll().find(model => model.api !== "openai-codex-responses");
if (!codexModel || !nonCodexModel) {
throw new Error("Expected codex and non-codex models to exist");
@@ -293,7 +315,7 @@ describe("AgentSession context promotion", () => {
});
it("clears codex provider session state when branching rewrites history", async () => {
const codexModel = modelRegistry.find("openai-codex", "gpt-5.3-codex");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.4");
if (!codexModel) {
throw new Error("Expected codex model to exist");
}
@@ -334,7 +356,7 @@ describe("AgentSession context promotion", () => {
});
it("clears codex provider session state when tree navigation rewrites history", async () => {
const codexModel = modelRegistry.find("openai-codex", "gpt-5.3-codex");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.4");
if (!codexModel) {
throw new Error("Expected codex model to exist");
}
@@ -375,9 +397,9 @@ describe("AgentSession context promotion", () => {
});
it("does not promote when promotion is disabled", async () => {
const sparkModel = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
if (!sparkModel) {
throw new Error("Expected codex spark model to exist");
const smallModel = modelRegistry.find("openai-codex", "gpt-5.5");
if (!smallModel) {
throw new Error("Expected small codex model to exist");
}
const settings = Settings.isolated({
@@ -387,7 +409,7 @@ describe("AgentSession context promotion", () => {
const agent = new Agent({
initialState: {
model: sparkModel,
model: smallModel,
systemPrompt: ["Test"],
tools: [],
messages: [],
@@ -406,27 +428,27 @@ describe("AgentSession context promotion", () => {
close: closeSpy,
} satisfies ProviderSessionState);
const overflowMessage = createOverflowMessage(sparkModel);
const overflowMessage = createOverflowMessage(smallModel);
session.agent.emitExternalEvent({ type: "message_end", message: overflowMessage });
session.agent.emitExternalEvent({ type: "agent_end", messages: [overflowMessage] });
await settle();
expect(session.model?.provider).toBe(sparkModel.provider);
expect(session.model?.id).toBe(sparkModel.id);
expect(session.model?.provider).toBe(smallModel.provider);
expect(session.model?.id).toBe(smallModel.id);
expect(closeSpy).not.toHaveBeenCalled();
expect(session.providerSessionState.size).toBe(1);
});
it("does not promote by default", async () => {
const sparkModel = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
if (!sparkModel) {
throw new Error("Expected codex spark model to exist");
const smallModel = modelRegistry.find("openai-codex", "gpt-5.5");
if (!smallModel) {
throw new Error("Expected small codex model to exist");
}
const agent = new Agent({
initialState: {
model: sparkModel,
model: smallModel,
systemPrompt: ["Test"],
tools: [],
messages: [],
@@ -440,20 +462,20 @@ describe("AgentSession context promotion", () => {
modelRegistry,
});
const overflowMessage = createOverflowMessage(sparkModel);
const overflowMessage = createOverflowMessage(smallModel);
session.agent.emitExternalEvent({ type: "message_end", message: overflowMessage });
session.agent.emitExternalEvent({ type: "agent_end", messages: [overflowMessage] });
await settle();
expect(session.model?.provider).toBe(sparkModel.provider);
expect(session.model?.id).toBe(sparkModel.id);
expect(session.model?.provider).toBe(smallModel.provider);
expect(session.model?.id).toBe(smallModel.id);
});
it("falls back to LLM compaction when snapcompact cannot run during overflow recovery", async () => {
const model = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
const model = modelRegistry.find("openai-codex", "gpt-5.4-mini");
if (!model) {
throw new Error("Expected codex spark model to exist");
throw new Error("Expected codex model to exist");
}
const settings = Settings.isolated({
"compaction.enabled": true,
@@ -512,10 +534,10 @@ describe("AgentSession context promotion", () => {
});
it("promotes to a larger-context model on response.incomplete (length stop)", async () => {
const sparkModel = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.5");
if (!sparkModel || !codexModel) {
throw new Error("Expected codex spark and codex models to exist");
const smallModel = modelRegistry.find("openai-codex", "gpt-5.5");
const largeModel = modelRegistry.find("openai-codex", "gpt-5.6-sol");
if (!smallModel || !largeModel) {
throw new Error("Expected small and large codex models to exist");
}
const settings = Settings.isolated({
@@ -525,7 +547,7 @@ describe("AgentSession context promotion", () => {
const agent = new Agent({
initialState: {
model: sparkModel,
model: smallModel,
systemPrompt: ["Test"],
tools: [],
messages: [],
@@ -539,24 +561,24 @@ describe("AgentSession context promotion", () => {
modelRegistry,
});
const incompleteMessage = createIncompleteMessage(sparkModel);
const incompleteMessage = createIncompleteMessage(smallModel);
session.agent.emitExternalEvent({ type: "message_end", message: incompleteMessage });
session.agent.emitExternalEvent({ type: "agent_end", messages: [incompleteMessage] });
await waitFor(() => session.model?.id === codexModel.id);
await waitFor(() => session.model?.id === largeModel.id);
expect(session.model?.provider).toBe(codexModel.provider);
expect(session.model?.id).toBe(codexModel.id);
expect(session.model?.provider).toBe(largeModel.provider);
expect(session.model?.id).toBe(largeModel.id);
});
it("does not promote on length stop when message is from a different model", async () => {
// Switching from a small-context model to a larger one and then receiving a
// stale length-stop event for the previous model must NOT trigger promotion
// or compaction on the new model — same guard as the overflow path.
const sparkModel = modelRegistry.find("openai-codex", "gpt-5.3-codex-spark");
const codexModel = modelRegistry.find("openai-codex", "gpt-5.5");
if (!sparkModel || !codexModel) {
throw new Error("Expected codex spark and codex models to exist");
const smallModel = modelRegistry.find("openai-codex", "gpt-5.5");
const largeModel = modelRegistry.find("openai-codex", "gpt-5.6-sol");
if (!smallModel || !largeModel) {
throw new Error("Expected small and large codex models to exist");
}
const settings = Settings.isolated({
@@ -566,7 +588,7 @@ describe("AgentSession context promotion", () => {
const agent = new Agent({
initialState: {
model: codexModel,
model: largeModel,
systemPrompt: ["Test"],
tools: [],
messages: [],
@@ -580,14 +602,14 @@ describe("AgentSession context promotion", () => {
modelRegistry,
});
// Stale incomplete from the smaller model — current session is already on codex.
const staleIncomplete = createIncompleteMessage(sparkModel);
// Stale incomplete from the smaller model — current session is already on the large model.
const staleIncomplete = createIncompleteMessage(smallModel);
session.agent.emitExternalEvent({ type: "message_end", message: staleIncomplete });
session.agent.emitExternalEvent({ type: "agent_end", messages: [staleIncomplete] });
await settle();
expect(session.model?.provider).toBe(codexModel.provider);
expect(session.model?.id).toBe(codexModel.id);
expect(session.model?.provider).toBe(largeModel.provider);
expect(session.model?.id).toBe(largeModel.id);
});
});
@@ -371,7 +371,7 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
appendStaleAssistantTurn(sessionManager, assistantText, {
api: "openai-codex-responses",
provider: "openai-codex",
model: "gpt-5.2-codex",
model: "gpt-5.5",
});
});
@@ -422,12 +422,12 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
const assistantText = "Reloaded assistant response";
const { sessionFile } = await createPersistedSession(tempDir, sessionManager => {
sessionManager.appendModelChange("openai-codex/gpt-5.2-codex");
sessionManager.appendModelChange("openai-codex/gpt-5.5");
sessionManager.appendMessage({ role: "user", content: "Reload summary", timestamp: Date.now() - 2 });
appendStaleAssistantTurn(sessionManager, assistantText, {
api: "openai-codex-responses",
provider: "openai-codex",
model: "gpt-5.2-codex",
model: "gpt-5.5",
});
sessionManager.appendMessage({ role: "user", content: "Reload follow-up", timestamp: Date.now() - 1 });
});
@@ -435,7 +435,7 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
const reloadedSessionManager = await SessionManager.open(sessionFile, tempDir);
const { session } = await createSessionHarness(tempDir, reloadedSessionManager, {
provider: "openai-codex",
modelId: "gpt-5.2-codex",
modelId: "gpt-5.5",
});
sessions.push(session);
@@ -461,18 +461,18 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
const assistantText = "Reloaded metadata-only response";
const { sessionFile } = await createPersistedSession(tempDir, sessionManager => {
sessionManager.appendModelChange("openai-codex/gpt-5.2-codex");
sessionManager.appendModelChange("openai-codex/gpt-5.5");
appendStaleAssistantTurn(sessionManager, assistantText, {
api: "openai-codex-responses",
provider: "openai-codex",
model: "gpt-5.2-codex",
model: "gpt-5.5",
});
});
const reloadedSessionManager = await SessionManager.open(sessionFile, tempDir);
const { session } = await createSessionHarness(tempDir, reloadedSessionManager, {
provider: "openai-codex",
modelId: "gpt-5.2-codex",
modelId: "gpt-5.5",
});
sessions.push(session);
@@ -497,7 +497,7 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
expect(closeSpy).not.toHaveBeenCalled();
expect(session.providerSessionState.size).toBe(1);
expect(session.model?.provider).toBe("openai-codex");
expect(session.model?.id).toBe("gpt-5.2-codex");
expect(session.model?.id).toBe("gpt-5.5");
expectAssistantReplayMetadataPreserved(findRuntimeAssistant(session, assistantText));
});
@@ -552,18 +552,18 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
const assistantText = "Reloaded content change response";
const { sessionFile } = await createPersistedSession(tempDir, sessionManager => {
sessionManager.appendModelChange("openai-codex/gpt-5.2-codex");
sessionManager.appendModelChange("openai-codex/gpt-5.5");
appendStaleAssistantTurn(sessionManager, assistantText, {
api: "openai-codex-responses",
provider: "openai-codex",
model: "gpt-5.2-codex",
model: "gpt-5.5",
});
});
const reloadedSessionManager = await SessionManager.open(sessionFile, tempDir);
const { session } = await createSessionHarness(tempDir, reloadedSessionManager, {
provider: "openai-codex",
modelId: "gpt-5.2-codex",
modelId: "gpt-5.5",
});
sessions.push(session);
@@ -584,7 +584,7 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
expect(closeSpy).toHaveBeenCalledTimes(1);
expect(session.providerSessionState.size).toBe(0);
expect(session.model?.provider).toBe("openai-codex");
expect(session.model?.id).toBe("gpt-5.2-codex");
expect(session.model?.id).toBe("gpt-5.5");
expect(
session.messages.some(
message => message.role === "user" && getTextContent(message) === "Externally appended follow-up",
@@ -598,18 +598,18 @@ describe("AgentSession OpenAI Responses replay boundaries", () => {
const assistantText = "Reloaded model change response";
const { sessionFile } = await createPersistedSession(tempDir, sessionManager => {
sessionManager.appendModelChange("openai-codex/gpt-5.2-codex");
sessionManager.appendModelChange("openai-codex/gpt-5.5");
appendStaleAssistantTurn(sessionManager, assistantText, {
api: "openai-codex-responses",
provider: "openai-codex",
model: "gpt-5.2-codex",
model: "gpt-5.5",
});
});
const reloadedSessionManager = await SessionManager.open(sessionFile, tempDir);
const { session } = await createSessionHarness(tempDir, reloadedSessionManager, {
provider: "openai-codex",
modelId: "gpt-5.2-codex",
modelId: "gpt-5.5",
});
sessions.push(session);
@@ -300,7 +300,7 @@ describe("AgentSession retry fallback", () => {
it("applies a model-keyed fallback chain to advisor quota failures", async () => {
const mainModel = getBundledModel("openai", "gpt-4o-mini");
const advisorPrimary = getBundledModel("devin", "gpt-5-6-sol");
const advisorPrimary = getBundledModel("devin", "swe-1-6-slow");
const advisorFallback = getBundledModel("openai-codex", "gpt-5.6-sol");
if (!mainModel || !advisorPrimary || !advisorFallback) {
throw new Error("Expected bundled advisor fallback models to exist");
@@ -390,7 +390,9 @@ describe("AgentSession retry fallback", () => {
expect(fallbackAppliedEvents).toEqual([
{
type: "retry_fallback_applied",
from: `${advisorPrimarySelector}:medium`,
// devin-agent models expose no controllable effort (#4579), so the
// advisor selector renders without a `:level` suffix.
from: advisorPrimarySelector,
to: advisorFallbackSelector,
role: advisorPrimarySelector,
},
@@ -398,7 +400,9 @@ describe("AgentSession retry fallback", () => {
expect(fallbackSucceededEvents).toEqual([
{
type: "retry_fallback_succeeded",
model: `${advisorFallbackSelector}:medium`,
// The fallback inherits the primary's (effort-less) thinking level,
// so its selector renders without a suffix too.
model: advisorFallbackSelector,
role: advisorPrimarySelector,
},
]);