123 lines
4.1 KiB
JavaScript
123 lines
4.1 KiB
JavaScript
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',
|
|
});
|
|
}
|
|
});
|
|
}
|