Files
paseo/packages/app/e2e/browser/workspace-draft-thinking-preferences.spec.ts
T
Mohamed BoudraandGitHub f2054cc701 Preserve Claude model and thinking preferences (#2912)
* fix(agents): preserve Claude thinking selections

Model switches now resolve thinking against the target model's saved preference instead of resetting to the catalog default. Claude owns its configured-model defaults and legacy Fable alias handling, while persisted permission modes remain unchanged.

* chore(claude): tag Fable compatibility shim

* fix(app): resolve persisted model aliases

* fix(models): preserve aliases for older clients

* fix(models): hide compatibility aliases from listings

* fix(settings): hide compatibility model aliases

* test(claude): cover legacy catalog entry

* test(app): expect mock thinking controls in schedules

* fix(app): preserve queued thinking preferences

* fix(app): reconcile schedule provider snapshots

* fix(app): preserve schedule model selections

* fix(claude): preserve exact configured model ids

* fix(app): preserve committed thinking preferences

* fix(app): preserve aliased schedule thinking
2026-08-06 11:33:18 +02:00

191 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test, type Page } from "../support/fixtures";
import { clickNewChat, gotoWorkspace } from "../support/helpers/launcher";
import { seedWorkspace } from "../support/helpers/seed-client";
import {
chooseCommandCenterAgentControl,
submitDraftAgent,
waitForDraftComposer,
} from "../support/helpers/command-center-agent-controls";
import { openCommandCenter } from "../support/helpers/command-center";
import { selectModel } from "../support/helpers/app";
const DISABLE_DEFAULT_SEED_ONCE_KEY = "@paseo:e2e-disable-default-seed-once";
const SEED_NONCE_KEY = "@paseo:e2e-seed-nonce";
async function openNewAgentTab(page: Page): Promise<void> {
await clickNewChat(page);
await waitForDraftComposer(page);
}
async function chooseDraftControl(page: Page, query: string, choice: string): Promise<void> {
await openCommandCenter(page);
await chooseCommandCenterAgentControl({ page, query, choice });
}
async function expectThinkingSelected(page: Page, label: string): Promise<void> {
await expect(
page
.getByRole("button", { name: `Select thinking option (${label})` })
.filter({ visible: true }),
).toBeVisible({ timeout: 30_000 });
}
async function expectModeSelected(page: Page, label: string): Promise<void> {
await expect(
page.getByRole("button", { name: `Select agent mode (${label})` }).filter({ visible: true }),
).toBeVisible({ timeout: 30_000 });
}
async function reloadWithPersistedPreferences(page: Page): Promise<void> {
await page.evaluate(
({ disableKey, nonceKey }) => {
const nonce = localStorage.getItem(nonceKey);
if (!nonce) throw new Error("Expected the Playwright seed nonce before reload");
localStorage.setItem(disableKey, nonce);
},
{ disableKey: DISABLE_DEFAULT_SEED_ONCE_KEY, nonceKey: SEED_NONCE_KEY },
);
await page.reload();
await waitForDraftComposer(page);
}
async function readRememberedThinking(page: Page, modelId: string): Promise<string | null> {
return page.evaluate((selectedModelId) => {
const raw = localStorage.getItem("@paseo:create-agent-preferences");
if (!raw) return null;
const preferences = JSON.parse(raw) as {
providerPreferences?: { mock?: { thinkingByModel?: Record<string, string> } };
};
return preferences.providerPreferences?.mock?.thinkingByModel?.[selectedModelId] ?? null;
}, modelId);
}
async function seedLegacyModelPreference(page: Page): Promise<void> {
await page.evaluate(() => {
const storageKey = "@paseo:create-agent-preferences";
const raw = localStorage.getItem(storageKey);
const preferences = raw ? (JSON.parse(raw) as Record<string, unknown>) : {};
localStorage.setItem(
storageKey,
JSON.stringify({
...preferences,
provider: "mock",
providerPreferences: {
...(preferences.providerPreferences as Record<string, unknown> | undefined),
mock: {
model: "legacy-five-minute-stream",
thinkingByModel: { "legacy-five-minute-stream": "medium" },
},
},
}),
);
});
}
test.describe("Workspace draft thinking preferences", () => {
test.describe.configure({ timeout: 180_000 });
test("restores a model's remembered thinking after another model and a reload", async ({
page,
}) => {
const workspace = await seedWorkspace({ repoPrefix: "draft-thinking-preferences-" });
try {
await gotoWorkspace(page, workspace.workspaceId);
await openNewAgentTab(page);
await chooseDraftControl(
page,
"five minute stream",
"Model › Mock Load Test › Five minute stream",
);
await chooseDraftControl(page, "medium", "Thinking › Medium");
await expectThinkingSelected(page, "Medium");
await chooseDraftControl(
page,
"ten second stream",
"Model › Mock Load Test › Ten second stream",
);
await chooseDraftControl(
page,
"five minute stream",
"Model › Mock Load Test › Five minute stream",
);
await expectThinkingSelected(page, "Medium");
await submitDraftAgent(page, "Remember medium thinking for this model");
await openNewAgentTab(page);
await expectThinkingSelected(page, "Medium");
await chooseDraftControl(
page,
"ten second stream",
"Model › Mock Load Test › Ten second stream",
);
await submitDraftAgent(page, "Hello from the other model");
await openNewAgentTab(page);
await reloadWithPersistedPreferences(page);
await expect.poll(() => readRememberedThinking(page, "five-minute-stream")).toBe("medium");
await chooseDraftControl(
page,
"five minute stream",
"Model › Mock Load Test › Five minute stream",
);
await expectThinkingSelected(page, "Medium");
} finally {
await workspace.cleanup();
}
});
test("restores a provider's permission mode after another provider and a reload", async ({
page,
}) => {
const workspace = await seedWorkspace({ repoPrefix: "draft-mode-preferences-" });
try {
await gotoWorkspace(page, workspace.workspaceId);
await openNewAgentTab(page);
await chooseDraftControl(
page,
"five minute stream",
"Model › Mock Load Test › Five minute stream",
);
await chooseDraftControl(page, "approval test", "Mode › Approval test");
await expectModeSelected(page, "Approval test");
await submitDraftAgent(page, "Remember this permission mode");
await openNewAgentTab(page);
await expectModeSelected(page, "Approval test");
await selectModel(page, "gpt-5.4-mini");
await openNewAgentTab(page);
await reloadWithPersistedPreferences(page);
await selectModel(page, "Five minute stream");
await expectModeSelected(page, "Approval test");
} finally {
await workspace.cleanup();
}
});
test("canonicalizes a retired model preference and restores its thinking option", async ({
page,
}) => {
const workspace = await seedWorkspace({ repoPrefix: "draft-model-alias-preferences-" });
try {
await gotoWorkspace(page, workspace.workspaceId);
await openNewAgentTab(page);
await seedLegacyModelPreference(page);
await reloadWithPersistedPreferences(page);
await expect(
page.getByRole("button", { name: "Select model (Five minute stream)" }),
).toBeVisible({ timeout: 30_000 });
await expectThinkingSelected(page, "Medium");
} finally {
await workspace.cleanup();
}
});
});