This commit is contained in:
ZacharyZhang-NY committed 2026-03-17 12:31:06 -04:00
1 parent 54bcc77ef7
commit 7a3db27ffa
33 files changed
+5906 -3089

No files matched your search

+4 -1
View File
@@ -27,9 +27,12 @@ test("first launch onboarding creates a company and opens the desktop shell", as
try {
const page = await app.firstWindow();
await expect(page.getByText("AgentCompany Desktop")).toBeVisible();
await page.getByRole("button", { name: /Custom Setup/i }).click();
await page.getByLabel("Company name").fill("Orbit Foundry");
await page.getByLabel("Workspace folder").fill(workspaceDir);
await page.getByRole("button", { name: /Continue to dashboard/i }).click();
await page.getByRole("button", { name: /^Continue$/i }).click();
await page.getByLabel("Goal").fill("Launch the company");
await page.getByRole("button", { name: /Launch your company/i }).click();
await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible();
// Company name is rendered in a custom dropdown trigger button in the sidebar.
+104 -26
View File
@@ -293,7 +293,6 @@ describe("Step 2: CEO phased prompts", () => {
});
const prompt = buildSystemPrompt(ctx);
expect(prompt).toContain("escalate by commenting on YOUR parent task");
expect(prompt).toContain("Break down work and delegate it");
});
@@ -310,7 +309,7 @@ describe("Step 2: CEO phased prompts", () => {
const prompt = buildSystemPrompt(ctx);
expect(prompt).toContain("Your manager is auto-notified and will help");
expect(prompt).toContain("comment explaining what API key/account you need");
expect(prompt).toContain("explain what API key/account you need");
});
});
@@ -320,15 +319,15 @@ describe("Step 3: Deferred wake queue (database)", () => {
it("enqueue and consume pending wakes", () => {
const agentId = createAgent({ name: "TestAgent" });
// Enqueue two wakes
// Enqueue two wakes for the same busy agent. The queue deduplicates by agent
// so only the freshest trigger is retained.
db.enqueuePendingWake(companyId, agentId, "subtask_completed");
db.enqueuePendingWake(companyId, agentId, "comment");
// Consume returns them in order
// Consume returns the latest retained wake
const wakes = db.consumePendingWakes(agentId);
expect(wakes).toHaveLength(2);
expect(wakes[0].trigger).toBe("subtask_completed");
expect(wakes[1].trigger).toBe("comment");
expect(wakes).toHaveLength(1);
expect(wakes[0].trigger).toBe("comment");
expect(wakes[0].companyId).toBe(companyId);
// Second consume returns empty (they've been deleted)
@@ -640,10 +639,10 @@ describe("Step 8: Wake reason injection", () => {
const prompt = buildTaskPrompt(ctx);
expect(prompt).toContain("Wake Reason");
expect(prompt).toContain("subtask assigned to one of your reports has been completed");
expect(prompt).toContain("subtask you delegated has been completed");
});
it("does not include wake reason for timer triggers", () => {
it("includes wake reason for timer triggers", () => {
const agentId = createAgent({ name: "Agent" });
const ctx = buildCtx({
@@ -652,10 +651,11 @@ describe("Step 8: Wake reason injection", () => {
});
const prompt = buildTaskPrompt(ctx);
expect(prompt).not.toContain("Wake Reason");
expect(prompt).toContain("Wake Reason");
expect(prompt).toContain("Regular heartbeat check-in");
});
it("does not include wake reason for manual triggers", () => {
it("includes wake reason for manual triggers", () => {
const agentId = createAgent({ name: "Agent" });
const ctx = buildCtx({
@@ -664,17 +664,18 @@ describe("Step 8: Wake reason injection", () => {
});
const prompt = buildTaskPrompt(ctx);
expect(prompt).not.toContain("Wake Reason");
expect(prompt).toContain("Wake Reason");
expect(prompt).toContain("manually triggered by the human operator");
});
it("includes correct message for each wake reason", () => {
const agentId = createAgent({ name: "Agent" });
const reasons: Record<string, string> = {
assignment: "assigned new work",
assignment: "You have been assigned a new task",
goal_activated: "goal you own has been activated",
approval_resolved: "approval you requested has been resolved",
subtask_completed: "subtask assigned to one of your reports has been completed",
approval_resolved: "approval you requested has been decided",
subtask_completed: "subtask you delegated has been completed",
comment: "new comment has been posted",
report_blocked: "reports is blocked",
report_failed: "reports has failed",
@@ -887,7 +888,7 @@ describe("E2E: Full autonomous CEO cold start flow", () => {
});
const icPrompt = buildTaskPrompt(icPromptCtx);
expect(icPrompt).toContain("Wake Reason");
expect(icPrompt).toContain("assigned new work");
expect(icPrompt).toContain("You have been assigned a new task");
expect(icPrompt).toContain("Implement auth");
});
});
@@ -898,17 +899,16 @@ describe("E2E: Deferred wake queue with run lifecycle", () => {
it("wake enqueue + run finish + consume cycle", () => {
const agentId = createAgent({ name: "Agent" });
// Simulate: agent is running, wakes come in
// Simulate: agent is running, wakes come in. Only the freshest reason is
// retained so the agent gets one consolidated follow-up wake.
db.enqueuePendingWake(companyId, agentId, "subtask_completed");
db.enqueuePendingWake(companyId, agentId, "comment");
db.enqueuePendingWake(companyId, agentId, "report_blocked");
// Agent finishes run → consume pending wakes
const wakes = db.consumePendingWakes(agentId);
expect(wakes).toHaveLength(3);
expect(wakes[0].trigger).toBe("subtask_completed");
expect(wakes[1].trigger).toBe("comment");
expect(wakes[2].trigger).toBe("report_blocked");
expect(wakes).toHaveLength(1);
expect(wakes[0].trigger).toBe("report_blocked");
// All consumed
expect(db.consumePendingWakes(agentId)).toHaveLength(0);
@@ -1192,6 +1192,81 @@ describe("Agent Messages", () => {
expect(messages[0].readAt).toBeTruthy();
});
it("tracks read state per agent without marking the sender unread", () => {
const msgId = db.sendAgentMessage({
companyId,
fromAgentId: agentAId,
toAgentId: agentBId,
subject: "Test",
body: "Hello",
});
const senderView = db.listAgentMessages(companyId, { agentId: agentAId });
expect(senderView).toHaveLength(1);
expect(senderView[0].id).toBe(msgId);
expect(senderView[0].readAt).toBeTruthy();
const recipientViewBefore = db.listAgentMessages(companyId, { agentId: agentBId, unreadOnly: true });
expect(recipientViewBefore).toHaveLength(1);
expect(recipientViewBefore[0].id).toBe(msgId);
db.markAgentMessageRead(msgId, companyId, agentBId);
const recipientViewAfter = db.listAgentMessages(companyId, { agentId: agentBId, unreadOnly: true });
expect(recipientViewAfter).toHaveLength(0);
const thirdAgentId = createAgent({ name: "Agent C" });
const thirdView = db.listAgentMessages(companyId, { agentId: thirdAgentId });
expect(thirdView).toHaveLength(0);
});
it("limits department and project messages to relevant members", () => {
const engineeringLeadId = createAgent({ name: "Engineering Lead", role: "Lead", department: "engineering" });
const productLeadId = createAgent({ name: "Product Lead", role: "Lead", department: "product" });
const projectId = db.saveProject({
companyId,
name: "Cross-team Project",
description: "Scope",
leadAgentId: engineeringLeadId,
status: "active",
});
db.saveTask({
companyId,
title: "Project task",
description: "Do work",
assigneeAgentId: engineeringLeadId,
projectId,
status: "todo",
priority: "medium",
});
const deptMessageId = db.sendAgentMessage({
companyId,
fromAgentId: engineeringLeadId,
channel: "department",
channelTargetId: "engineering",
subject: "Engineering update",
body: "Only engineering should see this",
});
const projectMessageId = db.sendAgentMessage({
companyId,
fromAgentId: engineeringLeadId,
channel: "project",
channelTargetId: projectId,
subject: "Project update",
body: "Only project members should see this",
});
const engineeringView = db.listAgentMessages(companyId, { agentId: engineeringLeadId });
expect(engineeringView.some((message) => message.id === deptMessageId)).toBe(true);
expect(engineeringView.some((message) => message.id === projectMessageId)).toBe(true);
const productView = db.listAgentMessages(companyId, { agentId: productLeadId });
expect(productView.some((message) => message.id === deptMessageId)).toBe(false);
expect(productView.some((message) => message.id === projectMessageId)).toBe(false);
});
it("filters messages by channel", () => {
db.sendAgentMessage({ companyId, fromAgentId: agentAId, subject: "Dept update", body: "All good", channel: "department", channelTargetId: "engineering" });
db.sendAgentMessage({ companyId, fromAgentId: agentAId, toAgentId: agentBId, subject: "DM", body: "Hey", channel: "direct" });
@@ -1206,7 +1281,7 @@ describe("Agent Messages", () => {
});
it("appears in snapshot", () => {
db.sendAgentMessage({ companyId, fromAgentId: agentAId, subject: "Snapshot test", body: "Hi" });
db.sendAgentMessage({ companyId, fromAgentId: agentAId, channel: "company", subject: "Snapshot test", body: "Hi" });
const snapshot = db.listSnapshot();
expect(snapshot.agentMessages.length).toBeGreaterThanOrEqual(1);
expect(snapshot.agentMessages[0].subject).toBe("Snapshot test");
@@ -1268,10 +1343,13 @@ describe("Auto Task Assignment", () => {
expect(result).toBe(frontendId);
});
it("returns null if no agents have remaining budget", () => {
// Exhaust both agents' budgets
db.saveAgent({ id: backendId, companyId, name: "Backend Dev", role: "Backend", title: "Backend", connectorId: "codex_local", status: "active", capabilities: "backend", budgetMonthlyUsd: 0 });
db.saveAgent({ id: frontendId, companyId, name: "Frontend Dev", role: "Frontend", title: "Frontend", connectorId: "codex_local", status: "active", capabilities: "frontend", budgetMonthlyUsd: 0 });
it("returns null if all agents have exhausted their budget", () => {
// Set positive budgets that are fully spent
db.saveAgent({ id: backendId, companyId, name: "Backend Dev", role: "Backend", title: "Backend", connectorId: "codex_local", status: "active", capabilities: "backend", budgetMonthlyUsd: 100 });
db.saveAgent({ id: frontendId, companyId, name: "Frontend Dev", role: "Frontend", title: "Frontend", connectorId: "codex_local", status: "active", capabilities: "frontend", budgetMonthlyUsd: 100 });
// Exhaust budgets by recording spending via direct SQL (since finishRun would need a real run)
(db as any).db.prepare("update agents set spent_monthly_usd = 100 where id = ?").run(backendId);
(db as any).db.prepare("update agents set spent_monthly_usd = 100 where id = ?").run(frontendId);
const taskId = db.saveTask({ companyId, title: "No budget task", description: "Test", priority: "low", status: "todo" });
const result = db.autoAssignTask(taskId, companyId);
+96
View File
@@ -147,4 +147,100 @@ describe("AppDatabase", () => {
db.close();
});
it("returns a renderer snapshot scoped to the current company while preserving global selectors", async () => {
const profileDir = await createTempDir("agentcompany-renderer-snapshot-");
const db = new AppDatabase(profileDir);
db.init();
const alphaCompanyId = db.saveCompany({
name: "Alpha",
description: "Alpha company",
status: "active",
});
const betaCompanyId = db.saveCompany({
name: "Beta",
description: "Beta company",
status: "active",
});
const alphaWorkspaceId = db.saveWorkspace({
companyId: alphaCompanyId,
name: "Alpha Workspace",
localPath: profileDir,
repoUrl: "",
repoRef: "",
isPrimary: true,
});
const betaWorkspaceId = db.saveWorkspace({
companyId: betaCompanyId,
name: "Beta Workspace",
localPath: profileDir,
repoUrl: "",
repoRef: "",
isPrimary: true,
});
const alphaAgentId = db.saveAgent({
companyId: alphaCompanyId,
name: "Alpha CEO",
role: "CEO",
title: "",
status: "active",
reportsTo: null,
connectorId: "codex_local",
workspaceId: alphaWorkspaceId,
model: null,
capabilities: "Lead alpha",
budgetMonthlyUsd: 100,
});
db.saveAgent({
companyId: betaCompanyId,
name: "Beta CEO",
role: "CEO",
title: "",
status: "active",
reportsTo: null,
connectorId: "codex_local",
workspaceId: betaWorkspaceId,
model: null,
capabilities: "Lead beta",
budgetMonthlyUsd: 100,
});
db.saveTask({
companyId: alphaCompanyId,
title: "Alpha task",
description: "Alpha work",
assigneeAgentId: alphaAgentId,
workspaceId: alphaWorkspaceId,
priority: "medium",
status: "todo",
});
db.saveTask({
companyId: betaCompanyId,
title: "Beta task",
description: "Beta work",
assigneeAgentId: null,
workspaceId: betaWorkspaceId,
priority: "medium",
status: "todo",
});
db.setCurrentCompany(alphaCompanyId);
const rendererSnapshot = db.listRendererSnapshot();
expect(rendererSnapshot.currentCompanyId).toBe(alphaCompanyId);
expect(rendererSnapshot.companies).toHaveLength(2);
expect(rendererSnapshot.connectors.length).toBeGreaterThan(0);
expect(rendererSnapshot.workspaces.map((workspace) => workspace.companyId)).toEqual([alphaCompanyId]);
expect(rendererSnapshot.agents.every((agent) => agent.companyId === alphaCompanyId)).toBe(true);
expect(rendererSnapshot.tasks.every((task) => task.companyId === alphaCompanyId)).toBe(true);
db.close();
});
});
-83
View File
@@ -370,63 +370,6 @@ describe("AppDatabase", () => {
expect(db.isAgentPendingApproval(pendingAgentId)).toBe(true);
});
it("detects budget exhaustion via isAgentBudgetExhausted", () => {
const companyId = db.saveCompany({
name: "Budget Gate Co",
description: "Budget gate validation",
status: "active",
});
const workspaceId = db.saveWorkspace({
companyId,
name: "WS",
localPath: "/tmp/budget-gate",
repoUrl: "",
repoRef: "",
isPrimary: true,
});
const agentId = db.saveAgent({
companyId,
name: "Budget Agent",
role: "IC",
title: "Budget",
status: "active",
reportsTo: null,
connectorId: "codex_local",
workspaceId,
model: null,
capabilities: "Test",
budgetMonthlyUsd: 10,
});
expect(db.isAgentBudgetExhausted(agentId)).toBe(false);
// Exhaust the budget via a run
const taskId = db.saveTask({
companyId,
title: "Budget drain",
description: "Test",
assigneeAgentId: agentId,
workspaceId,
priority: "medium",
status: "todo",
});
const run = db.createRun({ companyId, taskId, agentId, workspaceId, connectorId: "codex_local" });
db.finishRun({
runId: run.id,
status: "succeeded",
summary: "Done",
errorMessage: null,
exitCode: 0,
signal: null,
model: null,
sessionDisplayId: null,
costUsd: 15,
unattributedCost: false,
});
expect(db.isAgentBudgetExhausted(agentId)).toBe(true);
});
it("runs forward-only migrations and creates schema_migrations table", () => {
// The migration system runs during init() — verify the tracking table exists
const snapshot = db.listSnapshot();
@@ -632,30 +575,4 @@ describe("AppDatabase", () => {
expect(approval2.relatedAgentId).toBe(hireId);
});
it("updates workspace state", () => {
const companyId = db.saveCompany({
name: "WS State Co",
description: "Workspace state test",
status: "active",
});
const wsId = db.saveWorkspace({
companyId,
name: "Test WS",
localPath: "/tmp/ws-state",
repoUrl: "",
repoRef: "",
isPrimary: true,
});
let ws = db.getWorkspace(wsId);
expect(ws?.state).toBe("ready");
db.setWorkspaceState(wsId, "busy");
ws = db.getWorkspace(wsId);
expect(ws?.state).toBe("busy");
db.setWorkspaceState(wsId, "error");
ws = db.getWorkspace(wsId);
expect(ws?.state).toBe("error");
});
});