Files
memind/server/portal-agent-services-bootstrap.mjs
john 286069449b
Memind CI / Test, build, and release guards (push) Failing after 2m14s
feat: add guarded portal canary release
2026-07-26 19:51:44 +08:00

239 lines
7.0 KiB
JavaScript

import { createAssetGatewayConfigService } from '../asset-gateway.mjs';
import { createExperienceService } from '../experience-service.mjs';
import { createImageMakeAdminConfigService } from '../image-make-admin-config.mjs';
import { createImageMakeClientFromEnv } from '../image-make-client.mjs';
import { createLlmProviderService, RELAY_BOOTSTRAP } from '../llm-providers.mjs';
import { createMindSpaceAgentRunner } from '../mindspace-agent-runner.mjs';
import { createMindSpaceAuditWriter } from '../mindspace-audit.mjs';
import { createMindSpaceImageGenerationService } from '../mindspace-image-generation.mjs';
import { createMindSpaceImageReviewService } from '../mindspace-image-review.mjs';
import { createWordFilterService } from '../word-filter.mjs';
import { isPassiveCanaryRuntime } from './portal-runtime-role.mjs';
async function createPgExperienceServiceFromModule(options) {
const { createPgExperienceService } = await import(
'../experience-service-pg.mjs'
);
return createPgExperienceService(options);
}
export async function bootstrapPortalAgentServices({
pool,
env = process.env,
runtime,
apiTarget,
apiTargets,
apiSecret,
userAuth,
sessionAccess,
mindSpaceRuntimeAdapter,
mindSpaceAssets,
resolveUserIdByDirKey,
workspaceMaintenanceEnabled = true,
startWorkspaceThumbnailWatcher,
startWorkspaceAssetSyncWatcher,
logger = console,
createExperienceServiceFn = createExperienceService,
createPgExperienceServiceFn =
createPgExperienceServiceFromModule,
createMindSpaceAgentRunnerFn =
createMindSpaceAgentRunner,
createMindSpaceAuditWriterFn =
createMindSpaceAuditWriter,
createLlmProviderServiceFn = createLlmProviderService,
createAssetGatewayConfigServiceFn =
createAssetGatewayConfigService,
createImageMakeAdminConfigServiceFn =
createImageMakeAdminConfigService,
createImageMakeClientFromEnvFn =
createImageMakeClientFromEnv,
createMindSpaceImageReviewServiceFn =
createMindSpaceImageReviewService,
createMindSpaceImageGenerationServiceFn =
createMindSpaceImageGenerationService,
createWordFilterServiceFn = createWordFilterService,
relayBootstrap = RELAY_BOOTSTRAP,
} = {}) {
if (
!pool ||
!runtime ||
!userAuth ||
!sessionAccess ||
!mindSpaceRuntimeAdapter?.agentJobService ||
typeof mindSpaceRuntimeAdapter.startBackgroundJobs !==
'function' ||
!mindSpaceAssets ||
typeof resolveUserIdByDirKey !== 'function' ||
typeof startWorkspaceThumbnailWatcher !== 'function' ||
typeof startWorkspaceAssetSyncWatcher !== 'function'
) {
throw new Error(
'bootstrapPortalAgentServices requires runtime service dependencies',
);
}
const mindSpaceAgentJobs =
mindSpaceRuntimeAdapter.agentJobService;
let experienceService = null;
if (runtime.experienceEnabled) {
if (env.EXPERIENCE_PG_URL) {
try {
experienceService =
await createPgExperienceServiceFn({
connectionString: env.EXPERIENCE_PG_URL,
});
logger.log(
'Experience store: PostgreSQL + pgvector',
);
} catch (error) {
logger.error(
'Experience PG init failed, falling back to MySQL store:',
error instanceof Error ? error.message : error,
);
experienceService = createExperienceServiceFn(pool);
}
} else {
experienceService = createExperienceServiceFn(pool);
}
}
const mindSpaceAgentRunner =
createMindSpaceAgentRunnerFn({
apiTarget,
apiSecret,
userAuth,
sessionAccess,
agentJobService: mindSpaceAgentJobs,
experienceService,
});
const mindSpaceAudit =
createMindSpaceAuditWriterFn(pool);
if (isPassiveCanaryRuntime(env)) {
logger.log('Passive candidate runtime: MindSpace background jobs disabled');
} else {
mindSpaceRuntimeAdapter.startBackgroundJobs({
publicationCleanupIntervalMs: 60 * 1000,
agentWorker: runtime.agentWorker,
agentRunner: mindSpaceAgentRunner,
workspaceMaintenanceEnabled,
publishRoot: runtime.publishRoot,
startWorkspaceThumbnailWatcher,
startWorkspaceAssetSyncWatcher,
syncUserWorkspaceByDirKey: async (
dirKey,
options,
) => {
const userId =
await resolveUserIdByDirKey(dirKey);
if (!userId) return;
await mindSpaceAssets.syncWorkspaceAssets(
userId,
options,
);
},
expireStaleUploadsIntervalMs: 5 * 60 * 1000,
});
}
await userAuth.ensureAdminUser();
const userDataSpaceBackfill =
await userAuth.ensureAllUserDataSpaces();
if (userDataSpaceBackfill.errors.length > 0) {
logger.warn(
`[PageData] PG space backfill incomplete: ${userDataSpaceBackfill.errors.length} user(s) failed`,
);
}
const llmProviderService =
createLlmProviderServiceFn(pool, {
apiTarget,
apiTargets,
apiSecret,
});
const assetGatewayConfigService =
createAssetGatewayConfigServiceFn(pool, {
llmProviderService,
});
const imageMakeAdminConfigService =
createImageMakeAdminConfigServiceFn(pool, {
env,
llmProviderService,
});
await imageMakeAdminConfigService.ensureSchema();
let imageMakeClient = null;
try {
imageMakeClient =
createImageMakeClientFromEnvFn(env);
} catch (error) {
logger.warn(
'[image_make] invalid local configuration; integration stays disabled:',
error?.message ?? error,
);
}
const imageReviewService =
createMindSpaceImageReviewServiceFn({
llmProviderService,
env,
logger,
});
const mindSpaceImageGeneration =
createMindSpaceImageGenerationServiceFn({
configService: assetGatewayConfigService,
assetService: mindSpaceAssets,
imageMakeClient,
imageReviewService,
env,
logger,
});
const wordFilterService =
createWordFilterServiceFn(pool);
const relayBootstrapTask = env.H5_RELAY_BOOTSTRAP_DISABLED === '1'
? Promise.resolve({ ok: true, created: false, skipped: true })
: llmProviderService
.ensureBootstrapRelay()
.then((result) => {
if (result.created) {
logger.log(
`LLM relay bootstrap created: ${relayBootstrap.name}`,
);
}
})
.catch((error) => {
logger.warn(
'LLM relay bootstrap skipped:',
error instanceof Error ? error.message : error,
);
});
void relayBootstrapTask;
const providerSyncTask = llmProviderService
.syncSelectedToGoosed()
.catch((error) => {
logger.warn(
'LLM provider boot sync skipped:',
error instanceof Error ? error.message : error,
);
});
void providerSyncTask;
return {
mindSpaceAgentJobs,
experienceService,
mindSpaceAgentRunner,
mindSpaceAudit,
userDataSpaceBackfill,
llmProviderService,
assetGatewayConfigService,
imageMakeAdminConfigService,
imageMakeClient,
imageReviewService,
mindSpaceImageGeneration,
wordFilterService,
relayBootstrapTask,
providerSyncTask,
};
}