Assign invite-joined agents to company CEO

This commit is contained in:
Dotta
2026-03-06 11:22:24 -06:00
parent f56901b473
commit cf1ccd1e14
2 changed files with 54 additions and 1 deletions

View File

@@ -0,0 +1,33 @@
import { describe, expect, it } from "vitest";
import { resolveJoinRequestAgentManagerId } from "../routes/access.js";
describe("resolveJoinRequestAgentManagerId", () => {
it("returns null when no CEO exists in the company agent list", () => {
const managerId = resolveJoinRequestAgentManagerId([
{ id: "a1", role: "cto", reportsTo: null },
{ id: "a2", role: "engineer", reportsTo: "a1" },
]);
expect(managerId).toBeNull();
});
it("selects the root CEO when available", () => {
const managerId = resolveJoinRequestAgentManagerId([
{ id: "ceo-child", role: "ceo", reportsTo: "manager-1" },
{ id: "manager-1", role: "cto", reportsTo: null },
{ id: "ceo-root", role: "ceo", reportsTo: null },
]);
expect(managerId).toBe("ceo-root");
});
it("falls back to the first CEO when no root CEO is present", () => {
const managerId = resolveJoinRequestAgentManagerId([
{ id: "ceo-1", role: "ceo", reportsTo: "mgr" },
{ id: "ceo-2", role: "ceo", reportsTo: "mgr" },
{ id: "mgr", role: "cto", reportsTo: null },
]);
expect(managerId).toBe("ceo-1");
});
});

View File

@@ -965,6 +965,21 @@ function grantsFromDefaults(
return result;
}
type JoinRequestManagerCandidate = {
id: string;
role: string;
reportsTo: string | null;
};
export function resolveJoinRequestAgentManagerId(
candidates: JoinRequestManagerCandidate[],
): string | null {
const ceoCandidates = candidates.filter((candidate) => candidate.role === "ceo");
if (ceoCandidates.length === 0) return null;
const rootCeo = ceoCandidates.find((candidate) => candidate.reportsTo === null);
return (rootCeo ?? ceoCandidates[0] ?? null)?.id ?? null;
}
function isInviteTokenHashCollisionError(error: unknown) {
const candidates = [
error,
@@ -1604,12 +1619,17 @@ export function accessRoutes(
req.actor.userId ?? null,
);
} else {
const managerId = resolveJoinRequestAgentManagerId(await agents.list(companyId));
if (!managerId) {
throw conflict("Join request cannot be approved because this company has no active CEO");
}
const created = await agents.create(companyId, {
name: existing.agentName ?? "New Agent",
role: "general",
title: null,
status: "idle",
reportsTo: null,
reportsTo: managerId,
capabilities: existing.capabilities ?? null,
adapterType: existing.adapterType ?? "process",
adapterConfig: