chat-ui-agent-demo / src /lib /server /api /__tests__ /agent-workspaces.spec.ts
Mike0021's picture
Deploy verified chat and coding agent UX (part 2)
fae625a verified
Raw History Blame Contribute Delete
5.86 kB
import { afterEach, beforeAll, describe, expect, it } from "vitest";
import superjson from "superjson";
import { ObjectId } from "mongodb";
import { collections, ready } from "$lib/server/database";
import { models } from "$lib/server/models";
import { cleanupTestData, createTestUser } from "./testHelpers";
import { POST as createConversation } from "../../../../routes/conversation/+server";
import type { WorkspaceView } from "$lib/types/Workspace";
function requestFor(payload: unknown): Request {
return new Request("http://localhost:5173/conversation", {
method: "POST",
headers: { "content-type": "application/json", "user-agent": "workspace-test" },
body: JSON.stringify(payload),
});
}
async function post(locals: App.Locals, payload: unknown): Promise<Response> {
return createConversation({ locals, request: requestFor(payload) } as never);
}
async function expectBadRequest(locals: App.Locals, payload: unknown) {
try {
await post(locals, payload);
expect.fail("Expected request to fail");
} catch (error) {
expect((error as { status?: number }).status).toBe(400);
}
}
beforeAll(async () => {
await ready;
}, 30_000);
describe.sequential("POST /conversation agent workspace persistence", () => {
afterEach(async () => {
await cleanupTestData();
});
it("persists legacy creates as chat mode without a workspace", async () => {
const { locals } = await createTestUser();
const res = await post(locals, { model: models[0].id });
expect(res.status).toBe(200);
const payload = (await res.json()) as {
conversationId: string;
mode: string;
workspaceId?: string;
conversation: string;
};
expect(payload.mode).toBe("chat");
expect(payload.workspaceId).toBeUndefined();
const embedded = superjson.parse<{ mode: string; workspaceId?: string }>(payload.conversation);
expect(embedded.mode).toBe("chat");
expect(embedded.workspaceId).toBeUndefined();
const conversation = await collections.conversations.findOne({
_id: new ObjectId(payload.conversationId),
});
expect(conversation?.mode).toBe("chat");
expect(conversation?.workspaceId).toBeUndefined();
expect(await collections.workspaces.countDocuments()).toBe(0);
});
it("atomically links one normalized, owner-scoped workspace for agent mode", async () => {
const { locals, user } = await createTestUser();
const res = await post(locals, {
model: models[0].id,
mode: "agent",
workspace: {
repo: { kind: "hf", ref: "test-user/test-space", repoType: "space" },
branch: "agents/first-run",
flavor: "cpu-upgrade",
model: models[1].id,
thinkingLevel: "xhigh",
policy: "ask",
},
});
const payload = (await res.json()) as {
conversationId: string;
mode: string;
workspaceId: string;
workspace: WorkspaceView;
conversation: string;
};
expect(payload.mode).toBe("agent");
expect(payload.workspace.id).toBe(payload.workspaceId);
expect(payload.workspace.repo).toEqual({
kind: "hf",
ref: "test-user/test-space",
repoType: "space",
});
expect(payload.workspace.sandbox).toMatchObject({
status: "unprovisioned",
flavor: "cpu-upgrade",
});
expect(payload.workspace.sandbox).not.toHaveProperty("nonce");
const conversation = await collections.conversations.findOne({
userId: user._id,
});
expect(conversation?.mode).toBe("agent");
expect(conversation?.workspaceId?.toString()).toBe(payload.workspaceId);
const workspaces = await collections.workspaces.find({ userId: user._id }).toArray();
expect(workspaces).toHaveLength(1);
expect(workspaces[0].conversationId.toString()).toBe(payload.conversationId);
expect(workspaces[0]).toMatchObject({
branch: "agents/first-run",
flavor: "cpu-upgrade",
model: models[1].id,
thinkingLevel: "xhigh",
policy: "ask",
spend: { accruedUsd: 0 },
});
expect(workspaces[0].llmProxy).toBeUndefined();
const embedded = superjson.parse<{
mode: string;
workspaceId: string;
workspace: WorkspaceView;
}>(payload.conversation);
expect(embedded.mode).toBe("agent");
expect(embedded.workspaceId).toBe(payload.workspaceId);
expect(embedded.workspace.thinkingLevel).toBe("xhigh");
});
it("creates a blank cpu-basic workspace when agent setup is omitted", async () => {
const { locals } = await createTestUser();
await post(locals, { model: models[0].id, mode: "agent" });
const workspace = await collections.workspaces.findOne({});
expect(workspace).toMatchObject({
repo: { kind: "blank" },
flavor: "cpu-basic",
model: models[0].id,
thinkingLevel: "medium",
policy: "auto",
sandbox: { status: "unprovisioned", flavor: "cpu-basic" },
});
});
it("rejects malformed or mode-incompatible workspace setup", async () => {
const { locals } = await createTestUser();
const model = models[0].id;
await expectBadRequest(locals, {
model,
mode: "chat",
workspace: { repo: { kind: "blank" } },
});
await expectBadRequest(locals, {
model,
mode: "agent",
workspace: { repo: { kind: "hf", ref: "owner/repo" } },
});
await expectBadRequest(locals, {
model,
mode: "agent",
workspace: { repo: { kind: "git", ref: "http://example.com/repo.git" } },
});
for (const ref of [
"https://user:secret@example.com/repo.git",
"https://example.com/repo.git?token=secret",
"https://example.com/repo.git#private",
]) {
await expectBadRequest(locals, {
model,
mode: "agent",
workspace: { repo: { kind: "git", ref } },
});
}
await expectBadRequest(locals, {
model,
mode: "agent",
workspace: { branch: "../escape" },
});
await expectBadRequest(locals, {
model,
mode: "agent",
workspace: { flavor: "not-a-flavor" },
});
expect(await collections.conversations.countDocuments()).toBe(0);
expect(await collections.workspaces.countDocuments()).toBe(0);
});
});