Fix same-directory workspace ownership

This commit is contained in:
Mohamed Boudra
2026-06-15 22:22:31 +07:00
parent a4d4d42873
commit ba9f7740a8
21 changed files with 599 additions and 139 deletions
@@ -1,16 +1,26 @@
import { test, expect } from "./fixtures";
import {
expectComposerEditable,
expectComposerVisible,
fillComposerDraft,
} from "./helpers/composer";
import { expectComposerEditable, expectComposerVisible, submitMessage } from "./helpers/composer";
import { clickNewChat, gotoWorkspace } from "./helpers/launcher";
import { connectNewWorkspaceDaemonClient } from "./helpers/new-workspace";
import { captureWsSessionFrames } from "./helpers/rename";
import { seedWorkspace, type SeededWorkspace } from "./helpers/seed-client";
import { getVisibleWorkspaceAgentTabIds } from "./helpers/workspace-tabs";
type NewWorkspaceDaemonClient = Awaited<ReturnType<typeof connectNewWorkspaceDaemonClient>>;
interface CreateAgentFrame extends Record<string, unknown> {
initialPrompt: string | null;
workspaceId: string | null;
provider: string | null;
cwd: string | null;
modeId: string | null;
model: string | null;
}
function createFrameForPrompt(frames: CreateAgentFrame[], prompt: string): CreateAgentFrame | null {
return frames.find((frame) => frame.initialPrompt === prompt) ?? null;
}
test.describe("Workspace model regressions", () => {
let client: NewWorkspaceDaemonClient;
@@ -64,6 +74,21 @@ test.describe("Workspace model regressions", () => {
const seeded: SeededWorkspace = await seedWorkspace({
repoPrefix: "workspace-new-agent-model-",
});
const createFrames = captureWsSessionFrames<CreateAgentFrame>(
page,
"create_agent_request",
(inner) => {
const config = (inner.config ?? {}) as Record<string, unknown>;
return {
initialPrompt: typeof inner.initialPrompt === "string" ? inner.initialPrompt : null,
workspaceId: typeof inner.workspaceId === "string" ? inner.workspaceId : null,
provider: typeof config.provider === "string" ? config.provider : null,
cwd: typeof config.cwd === "string" ? config.cwd : null,
modeId: typeof config.modeId === "string" ? config.modeId : null,
model: typeof config.model === "string" ? config.model : null,
};
},
);
try {
const secondWorkspace = await seeded.client.createWorkspace({
@@ -78,9 +103,9 @@ test.describe("Workspace model regressions", () => {
localStorage.setItem(
"@paseo:create-agent-preferences",
JSON.stringify({
provider: "codex",
provider: "mock",
providerPreferences: {
codex: { mode: "full-access" },
mock: { mode: "load-test" },
},
}),
);
@@ -90,10 +115,23 @@ test.describe("Workspace model regressions", () => {
await expectComposerVisible(page);
await expectComposerEditable(page);
await fillComposerDraft(page, "d");
const prompt = `Create agent default model ${Date.now()}`;
await submitMessage(page, prompt);
await expect(page.getByText("No model is available for the selected provider")).toHaveCount(
0,
);
await expect
.poll(() => createFrameForPrompt(createFrames, prompt), {
timeout: 10_000,
})
.toEqual({
initialPrompt: prompt,
workspaceId: secondWorkspace.workspace.id,
provider: "mock",
cwd: seeded.repoPath,
modeId: "load-test",
model: "five-minute-stream",
});
} finally {
await seeded.cleanup();
}
@@ -215,6 +215,8 @@ describe("useAgentInputDraft live contract", () => {
provider: "codex",
cwd: "/repo",
modeId: "auto",
model: "gpt-5.4",
thinkingOptionId: "high",
});
await act(async () => {
@@ -52,6 +52,22 @@ describe("resolveEffectiveComposerModelId", () => {
}),
).toBe("");
});
it("falls back to the provider default model when no model is selected", () => {
expect(
resolveEffectiveComposerModelId({
provider: "codex",
modelId: "",
modeId: "",
thinkingOptionId: "",
availableModels: [
{ provider: "codex", id: "gpt-5.4-mini", label: "gpt-5.4-mini" },
{ provider: "codex", id: "gpt-5.4", label: "gpt-5.4", isDefault: true },
],
modeOptions: [],
}),
).toBe("gpt-5.4");
});
});
describe("resolveEffectiveComposerThinkingOptionId", () => {
@@ -229,7 +229,15 @@ export function filterAndRankModelRows(
}
export function resolveEffectiveComposerModelId(selection: ProviderSelectionState): string {
return selection.modelId.trim();
const selectedModelId = selection.modelId.trim();
if (selectedModelId) {
return selectedModelId;
}
return (
selection.availableModels.find((model) => model.isDefault)?.id ??
selection.availableModels[0]?.id ??
""
);
}
export function resolveEffectiveComposerThinkingOptionId(