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:
@@ -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,
|
||||
},
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user