Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,16 @@ describe("WorkspaceModeAISync", () => {
plan: { modelString: planModel },
});

// Start with a different model so the mount sync performs an update.
updatePersistedState(getModelKey(workspaceId), "some-legacy-model");

const { rerender } = renderSync({ workspaceId, agentId: "exec" });

// Mount sync should update the model but NOT record an explicit change entry.
await waitFor(() => {
expect(readPersistedState(getModelKey(workspaceId), "")).toBe(execModel);
});
// Mount sync is not a switch, so it records no explicit change entry.
expect(consumeWorkspaceModelChange(workspaceId, execModel)).toBeNull();

// Switching agents (within the same workspace) should be treated as explicit.
rerender(<SyncHarness workspaceId={workspaceId} agentId="plan" />);

await waitFor(() => {
expect(readPersistedState(getModelKey(workspaceId), "")).toBe(planModel);
expect(consumeWorkspaceModelChange(workspaceId, planModel)).toBe("agent");
});
expect(consumeWorkspaceModelChange(workspaceId, planModel)).toBe("agent");
});

test("an explicit agent switch that changes the thinking level leaves thinking Auto", async () => {
Expand Down
15 changes: 8 additions & 7 deletions tests/ui/agents/reawakenAiPins.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import { readPersistedState } from "@/browser/hooks/usePersistedState";
import { getModelKey, getThinkingLevelKey } from "@/common/constants/storage";
import { getWorkspaceAiSelection } from "@/browser/utils/workspaceAiSettingsSync";
import { getThinkingLevelKey } from "@/common/constants/storage";
import { KNOWN_MODELS, MODEL_ABBREVIATIONS } from "@/common/constants/knownModels";
import type { Workspace as WorkspaceConfigEntry } from "@/node/config";
import { shouldRunIntegrationTests } from "../../testUtils";
Expand Down Expand Up @@ -89,19 +90,19 @@ describeIntegration("Reawakened sub-agent pins from the renderer", () => {
workspace.aiSettingsByAgent = { exec: { model: SPAWN_MODEL, thinkingLevel: "high" } };
workspace.taskAiPins = {};
});
const modelKey = getModelKey(app.workspaceId);
const selection = () => getWorkspaceAiSelection(app.workspaceId);
const thinkingKey = getThinkingLevelKey(app.workspaceId);

// 1. A plain send records no pins.
await sendAndSettle(app, "plain follow-up");
expect(readChild(app).taskAiPins).toEqual({});

// 2. A backend bucket change reseeds the renderer (not a user pick): no pin.
expect(readPersistedState(modelKey, "")).not.toBe(BACKEND_MODEL);
expect(selection().model).not.toBe(BACKEND_MODEL);
await editChild(app, (workspace) => {
workspace.aiSettingsByAgent = { exec: { model: BACKEND_MODEL, thinkingLevel: "high" } };
});
await waitFor(() => expect(readPersistedState(modelKey, "")).toBe(BACKEND_MODEL), {
await waitFor(() => expect(selection().model).toBe(BACKEND_MODEL), {
timeout: 10_000,
});
await sendAndSettle(app, "after backend reseed");
Expand All @@ -114,7 +115,7 @@ describeIntegration("Reawakened sub-agent pins from the renderer", () => {
const picked = MODEL_ABBREVIATIONS.sonnet;
if (!picked) throw new Error("Missing sonnet abbreviation");
await app.chat.send("/model sonnet");
await waitFor(() => expect(readPersistedState(modelKey, "")).toBe(picked), {
await waitFor(() => expect(selection().model).toBe(picked), {
timeout: 10_000,
});
await editChild(app, (workspace) => {
Expand All @@ -123,7 +124,7 @@ describeIntegration("Reawakened sub-agent pins from the renderer", () => {
await waitFor(() => expect(readPersistedState(thinkingKey, "")).toBe("low"), {
timeout: 10_000,
});
expect(readPersistedState(modelKey, "")).toBe(picked);
expect(selection().model).toBe(picked);
await sendAndSettle(app, "send the pick");
expect(readChild(app).taskAiPins).toEqual({ model: picked });

Expand All @@ -132,7 +133,7 @@ describeIntegration("Reawakened sub-agent pins from the renderer", () => {
await editChild(app, (workspace) => {
workspace.aiSettingsByAgent = { exec: { model: BACKEND_MODEL, thinkingLevel: "high" } };
});
await waitFor(() => expect(readPersistedState(modelKey, "")).toBe(BACKEND_MODEL), {
await waitFor(() => expect(selection().model).toBe(BACKEND_MODEL), {
timeout: 10_000,
});
await sendAndSettle(app, "plain after the pin");
Expand Down
10 changes: 3 additions & 7 deletions tests/ui/agents/thinkingPersistence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import userEvent from "@testing-library/user-event";

import { CUSTOM_EVENTS } from "@/common/constants/events";
import { KNOWN_MODELS } from "@/common/constants/knownModels";
import { getModelKey } from "@/common/constants/storage";
import { readPersistedState } from "@/browser/hooks/usePersistedState";
import { getWorkspaceAiSelection } from "@/browser/utils/workspaceAiSettingsSync";
import { formatModelDisplayName } from "@/common/utils/ai/modelDisplay";

import { shouldRunIntegrationTests } from "../../testUtils";
Expand Down Expand Up @@ -61,16 +60,13 @@ async function selectModel(
fireEvent.click(option);

await waitFor(() => {
const persisted = readPersistedState(getModelKey(workspaceId), "");
const persisted = getWorkspaceAiSelection(workspaceId).model;
if (persisted !== model) {
throw new Error(`Expected model ${model} but got ${persisted}`);
}
});

// Wait for the UI to reflect the new model. This guards against race conditions
// where backend metadata updates can temporarily revert localStorage (and thus
// the displayed model) when switching models rapidly.
// Use the exact display name that the UI will show.
// Wait for the UI to reflect the new model, using the exact display name the UI shows.
const expectedDisplayName = modelDisplayName.toLowerCase();
await waitFor(
() => {
Expand Down
5 changes: 2 additions & 3 deletions tests/ui/agents/thinkingSelector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import userEvent from "@testing-library/user-event";

import { CUSTOM_EVENTS } from "@/common/constants/events";
import { KNOWN_MODELS } from "@/common/constants/knownModels";
import { getModelKey } from "@/common/constants/storage";
import { readPersistedState } from "@/browser/hooks/usePersistedState";
import { getWorkspaceAiSelection } from "@/browser/utils/workspaceAiSettingsSync";
import { formatModelDisplayName } from "@/common/utils/ai/modelDisplay";

import { shouldRunIntegrationTests } from "../../testUtils";
Expand Down Expand Up @@ -56,7 +55,7 @@ async function selectModel(
fireEvent.click(option);

await waitFor(() => {
const persisted = readPersistedState(getModelKey(workspaceId), "");
const persisted = getWorkspaceAiSelection(workspaceId).model;
if (persisted !== model) {
throw new Error(`Expected model ${model} but got ${persisted}`);
}
Expand Down
Loading