import { resolvePortalRuntimeRole } from './portal-runtime-role.mjs'; function runtimeEnvFlag(value, fallback = false) { const raw = String(value ?? '').trim().toLowerCase(); if (!raw) return fallback; return ['1', 'true', 'yes', 'on'].includes(raw); } function runtimeCsvList(value) { return String(value ?? '') .split(',') .map((item) => item.trim()) .filter(Boolean); } function runtimeCodeRunPolicyStatus(env) { return { source: 'env', enabled: runtimeEnvFlag(env.MEMIND_AGENT_CODE_RUNS_ENABLED), clientEnabled: runtimeEnvFlag(env.VITE_AGENT_CODE_RUNS_ENABLED), userAllowlist: runtimeCsvList(env.MEMIND_AGENT_CODE_RUNS_USER_IDS), taskTypeAllowlist: runtimeCsvList(env.MEMIND_AGENT_CODE_RUN_TASK_TYPES), requireValidation: runtimeEnvFlag(env.MEMIND_AGENT_CODE_RUNS_REQUIRE_VALIDATION), pageDataDevAutodetect: runtimeEnvFlag(env.VITE_AGENT_PAGE_DATA_DEV_AUTODETECT), generalAutodetect: runtimeEnvFlag(env.VITE_AGENT_CODE_RUNS_AUTODETECT), envOverrideActive: String(env.MEMIND_CODE_RUN_POLICY_SOURCE ?? '').trim().toLowerCase() === 'env', updatedAt: null, updatedBy: null, }; } async function resolveRuntimeCodeRunPolicyStatus(env, getCodeRunPolicyService) { const service = typeof getCodeRunPolicyService === 'function' ? getCodeRunPolicyService() : null; if (service?.getRuntimeStatusSummary) { return service.getRuntimeStatusSummary(); } return runtimeCodeRunPolicyStatus(env); } export function attachPortalRuntimeRoutes( api, { waitForUserAuthReady = async () => {}, getUserAuth = () => null, getTkmindProxy = () => null, getEpisodicMemoryService = () => null, getAgentRunGateway = () => null, getCodeRunPolicyService = () => null, env = process.env, } = {}, ) { if (!api || typeof api.get !== 'function') { throw new Error('attachPortalRuntimeRoutes requires an Express-compatible router'); } api.get('/status', async (_req, res, next) => { res.setHeader?.('X-Memind-Runtime-Role', resolvePortalRuntimeRole(env)); await waitForUserAuthReady(); const userAuth = getUserAuth(); const tkmindProxy = getTkmindProxy(); if (userAuth && tkmindProxy) { try { const upstream = await tkmindProxy.apiFetch('/status', { method: 'GET' }); const text = await upstream.text(); return res.status(upstream.status).send(text); } catch (err) { return res.status(502).json({ message: err instanceof Error ? err.message : '代理失败' }); } } return next(); }); api.get('/runtime/status', async (_req, res) => { await waitForUserAuthReady(); const tkmindProxy = getTkmindProxy(); if (!tkmindProxy?.getRuntimeStatus) { return res.status(503).json({ ok: false, message: 'runtime router unavailable' }); } try { const status = await tkmindProxy.getRuntimeStatus(); const episodicMemoryService = getEpisodicMemoryService(); if (episodicMemoryService?.getStatus) { status.memory = { ...(status.memory ?? {}), episodic: await episodicMemoryService.getStatus().catch((err) => ({ configuredEnabled: false, mode: 'off', error: err instanceof Error ? err.message : String(err), })), }; } const agentRunGateway = getAgentRunGateway(); const toolQueue = agentRunGateway?.getQueueStatus ? await agentRunGateway.getQueueStatus().catch((err) => ({ error: err instanceof Error ? err.message : String(err), })) : null; if (toolQueue) { status.toolRuntime = { ...(status.toolRuntime ?? {}), codeRunPolicy: await resolveRuntimeCodeRunPolicyStatus( env, getCodeRunPolicyService, ), queue: toolQueue, }; } return res.json({ ok: true, timestamp: new Date().toISOString(), ...status, }); } catch (err) { return res.status(502).json({ ok: false, message: err instanceof Error ? err.message : 'runtime status failed', }); } }); }