feat(08-02): add ensureGeneralistAgents startup migration for existing workspaces
- Import agentService and agents table into server/src/index.ts - ensureGeneralistAgents() queries all companies, skips any that already have a general-role agent (idempotent), creates Generalist via agentService.create() - metadata includes pendingSkillGroups: [Creative] and backfilled: true flag - Called with fire-and-forget void pattern after ensureLocalTrustedBoardPrincipal - Existing workspaces get Generalist on next server upgrade without user action
This commit is contained in:
parent
1ac1e082f9
commit
3e88a0fb9a
1 changed files with 40 additions and 1 deletions
|
|
@ -19,6 +19,7 @@ import {
|
|||
formatDatabaseBackupResult,
|
||||
runDatabaseBackup,
|
||||
authUsers,
|
||||
agents,
|
||||
companies,
|
||||
companyMemberships,
|
||||
instanceUserRoles,
|
||||
|
|
@ -28,7 +29,7 @@ import { createApp } from "./app.js";
|
|||
import { loadConfig } from "./config.js";
|
||||
import { logger } from "./middleware/logger.js";
|
||||
import { setupLiveEventsWebSocketServer } from "./realtime/live-events-ws.js";
|
||||
import { heartbeatService, reconcilePersistedRuntimeServicesOnStartup, routineService } from "./services/index.js";
|
||||
import { agentService, heartbeatService, reconcilePersistedRuntimeServicesOnStartup, routineService } from "./services/index.js";
|
||||
import { createStorageServiceFromConfig } from "./storage/index.js";
|
||||
import { printStartupBanner } from "./startup-banner.js";
|
||||
import { getBoardClaimWarningUrl, initializeBoardClaimChallenge } from "./board-claim.js";
|
||||
|
|
@ -243,6 +244,32 @@ export async function startServer(): Promise<StartedServer> {
|
|||
}
|
||||
}
|
||||
|
||||
// [nexus] Backfill Generalist agent for existing workspaces that pre-date Phase 8
|
||||
async function ensureGeneralistAgents(db: any): Promise<{ backfilled: number }> {
|
||||
const companyRows = await db.select({ id: companies.id }).from(companies);
|
||||
let backfilled = 0;
|
||||
for (const company of companyRows) {
|
||||
const existing = await db
|
||||
.select({ id: agents.id })
|
||||
.from(agents)
|
||||
.where(and(eq(agents.companyId, company.id), eq(agents.role, "general")))
|
||||
.then((rows: Array<{ id: string }>) => rows[0] ?? null);
|
||||
if (existing) continue;
|
||||
const agentSvc = agentService(db);
|
||||
await agentSvc.create(company.id, {
|
||||
name: "Generalist",
|
||||
role: "general",
|
||||
adapterType: "claude_local",
|
||||
adapterConfig: {},
|
||||
runtimeConfig: {},
|
||||
metadata: { pendingSkillGroups: ["Creative"], backfilled: true },
|
||||
});
|
||||
logger.info({ companyId: company.id }, "backfilled Generalist agent for existing workspace");
|
||||
backfilled++;
|
||||
}
|
||||
return { backfilled };
|
||||
}
|
||||
|
||||
let db;
|
||||
let embeddedPostgres: EmbeddedPostgresInstance | null = null;
|
||||
let embeddedPostgresStartedByThisProcess = false;
|
||||
|
|
@ -459,6 +486,18 @@ export async function startServer(): Promise<StartedServer> {
|
|||
if (config.deploymentMode === "local_trusted") {
|
||||
await ensureLocalTrustedBoardPrincipal(db as any);
|
||||
}
|
||||
|
||||
// [nexus] Backfill Generalist agents for any workspace that pre-dates Phase 8
|
||||
void ensureGeneralistAgents(db as any)
|
||||
.then((result) => {
|
||||
if (result.backfilled > 0) {
|
||||
logger.info({ backfilled: result.backfilled }, "backfilled Generalist agents for existing workspaces");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error({ err }, "failed to backfill Generalist agents");
|
||||
});
|
||||
|
||||
if (config.deploymentMode === "authenticated") {
|
||||
const {
|
||||
createBetterAuthHandler,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue