openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
163 lines (162 loc) • 7.13 kB
JavaScript
import { c as normalizeOptionalLowercaseString } from "./string-coerce-CIXf7egm.js";
import { w as resolveStateDir } from "./paths-D2sRr1a_.js";
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import "./error-runtime-Bz9Tw57Z.js";
import "./string-coerce-runtime-GQa0ehRA.js";
import "./state-paths-2IWTvznc.js";
import { r as MISSING_LOCAL_MEMORY_EMBEDDING_PROVIDER_MESSAGE, t as LLAMA_CPP_PROVIDER_INSTALL_COMMAND } from "./local-embedding-provider-BYt5VAF8.js";
import fs from "node:fs";
import path from "node:path";
//#region extensions/memory-core/src/doctor-vector-index-provider.ts
const MEMORY_INDEX_META_KEY = "memory_index_meta_v1";
function listConfiguredAgentIds(config) {
const ids = new Set(Object.keys(config.agents?.entries ?? {}));
for (const entry of config.agents?.list ?? []) if (entry.id.trim()) ids.add(entry.id.trim());
return ids.size > 0 ? [...ids] : ["main"];
}
async function readExistingVectorModel(databasePath) {
if (!fs.existsSync(databasePath)) return null;
const { openNodeSqliteDatabase, prepareSqliteReadOnlyLocationSync } = await import("./plugin-sdk/sqlite-runtime.js");
let prepared;
let db;
let failure;
let model = null;
try {
prepared = prepareSqliteReadOnlyLocationSync(databasePath);
db = openNodeSqliteDatabase(prepared.location, { readOnly: true });
if (db.prepare("SELECT 1 AS ok FROM sqlite_master WHERE type = 'table' AND name = 'memory_index_meta'").get()) {
const row = db.prepare("SELECT value FROM memory_index_meta WHERE key = ?").get(MEMORY_INDEX_META_KEY);
const parsed = typeof row?.value === "string" ? JSON.parse(row.value) : null;
const configuredModel = parsed && typeof parsed === "object" && typeof parsed.model === "string" ? parsed.model.trim() : "";
model = configuredModel && configuredModel !== "fts-only" ? configuredModel : null;
}
} catch (error) {
failure = error;
} finally {
try {
db?.close();
} catch (error) {
failure ??= error;
}
if (prepared && !prepared.cleanup()) failure ??= /* @__PURE__ */ new Error("Temporary SQLite inspection snapshot cleanup did not complete.");
}
if (failure) throw failure instanceof Error ? failure : new Error("Memory index inspection failed.", { cause: failure });
return model;
}
function resolveConfigPrefix(config, agentId) {
if (config.agents?.entries?.[agentId]?.memory?.search) return `agents.entries.${agentId}.memory.search`;
if (config.agents?.list?.find((entry) => entry.id === agentId)?.memory?.search) return `agents.list[].memory.search (agent id ${agentId})`;
return "memory.search";
}
async function collectVectorProviderFindings(params, inspectProvider) {
const findings = [];
for (const agentId of listConfiguredAgentIds(params.config)) {
const model = await readExistingVectorModel(path.join(params.stateDir, "agents", agentId, "agent", "openclaw-agent.sqlite"));
if (!model) continue;
const failure = await inspectProvider({
config: params.config,
agentId,
env: params.env
});
if (failure) findings.push({
...failure,
agentId,
model,
configPrefix: resolveConfigPrefix(params.config, agentId)
});
}
return findings;
}
//#endregion
//#region extensions/memory-core/src/doctor-health.ts
const MEMORY_MANAGED_LOCAL_EMBEDDING_SETUP_CHECK_ID = "memory-core/managed-local-embedding-setup";
const pluginStateIsolatedDoctorCheckIds = [MEMORY_MANAGED_LOCAL_EMBEDDING_SETUP_CHECK_ID];
const registrationsByHost = /* @__PURE__ */ new WeakMap();
function resolveSelectedMemoryProvider(config, agentId) {
const agent = config.agents?.entries?.[agentId] ?? config.agents?.list?.find((entry) => entry.id === agentId);
const defaults = config.memory?.search;
const overrides = agent?.memory?.search;
if (!(overrides?.enabled ?? defaults?.enabled ?? true)) return null;
const configured = overrides?.provider ?? defaults?.provider;
const provider = normalizeOptionalLowercaseString(configured);
return !provider || provider === "auto" ? "openai" : provider;
}
function createManagedLocalEmbeddingSetupCheck(state) {
return {
id: MEMORY_MANAGED_LOCAL_EMBEDDING_SETUP_CHECK_ID,
kind: "plugin",
source: "memory-core",
defaultEnabled: false,
description: "Checks existing semantic indexes for required managed local embedding setup.",
async detect(ctx) {
if (!state.memoryCoreActive) return [];
const env = ctx.env ?? process.env;
let findings;
try {
findings = await collectVectorProviderFindings({
config: ctx.cfg,
env,
stateDir: resolveStateDir(env)
}, async (params) => {
const provider = resolveSelectedMemoryProvider(params.config, params.agentId);
if (!provider || provider === "none") return null;
if (provider !== "local") return null;
const failure = await state.inspectEmbeddingProviderSetup({
config: params.config,
env: params.env,
agentId: params.agentId,
provider
});
if (failure === void 0) return {
provider,
reason: MISSING_LOCAL_MEMORY_EMBEDDING_PROVIDER_MESSAGE,
requirement: "memory-embedding-provider-plugin",
fixHint: `Run \`${LLAMA_CPP_PROVIDER_INSTALL_COMMAND}\`, ensure the plugin is enabled, then rerun this check.`
};
return failure;
});
} catch (error) {
return [{
checkId: MEMORY_MANAGED_LOCAL_EMBEDDING_SETUP_CHECK_ID,
severity: "error",
source: "memory-core",
target: "memory-core",
requirement: "memory-index-inspection",
message: `Memory Core semantic-index readiness could not be verified (${formatErrorMessage(error)}).`,
fixHint: "Keep the current Gateway running, resolve the database inspection error, then rerun this check."
}];
}
return findings.map((finding) => ({
checkId: MEMORY_MANAGED_LOCAL_EMBEDDING_SETUP_CHECK_ID,
severity: "error",
source: "memory-core",
path: `${finding.configPrefix}.provider`,
target: `${finding.agentId}/${finding.provider}`,
requirement: finding.requirement ?? "managed-local-embedding-setup",
message: `Memory index for agent ${finding.agentId} uses vector model ${finding.model}, but embedding provider "${finding.provider}" cannot initialize (${finding.reason}).`,
fixHint: finding.fixHint
}));
}
};
}
function registerMemoryCoreDoctorChecks(host) {
let registration = registrationsByHost.get(host.registerHealthCheck);
if (registration) {
registration.state.inspectEmbeddingProviderSetup = host.inspectEmbeddingProviderSetup;
registration.state.memoryCoreActive = host.memoryCoreActive;
} else {
const state = {
inspectEmbeddingProviderSetup: host.inspectEmbeddingProviderSetup,
memoryCoreActive: host.memoryCoreActive
};
registration = {
check: createManagedLocalEmbeddingSetupCheck(state),
state
};
registrationsByHost.set(host.registerHealthCheck, registration);
}
if (host.getHealthCheck("memory-core/managed-local-embedding-setup") === registration.check) return;
host.registerHealthCheck(registration.check);
}
//#endregion
export { pluginStateIsolatedDoctorCheckIds as n, registerMemoryCoreDoctorChecks as r, MEMORY_MANAGED_LOCAL_EMBEDDING_SETUP_CHECK_ID as t };