openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
106 lines (105 loc) • 4.81 kB
JavaScript
import { m as shortenHomePath } from "./utils-P__uGsPB.js";
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import { t as openNodeSqliteDatabase } from "./node-sqlite-BpQX3W0e.js";
import { r as migrateOpenClawAgentDatabaseForMaintenance, y as listOpenClawRegisteredAgentDatabases } from "./openclaw-agent-db-maintenance-wTIy-jt-.js";
import { _ as withAgentDatabaseMaintenanceLease, b as closeOpenClawAgentDatabaseByPath } from "./openclaw-agent-db-CWtDoRbC.js";
import { t as note } from "./note-DqHk3fA1.js";
import { i as withDoctorSqliteMaintenanceLock, t as DoctorSqliteMaintenanceLockUnavailableError } from "./doctor-sqlite-maintenance-lock-BDyGk9pJ.js";
import fs from "node:fs";
//#region src/commands/doctor-agent-memory-schema.ts
const LEGACY_MEMORY_RECALL_METADATA_COLUMNS = [
"importance",
"triggers",
"project_key"
];
const LEGACY_MEMORY_PROVENANCE_TRIGGER = "memory_index_chunk_provenance_after_insert";
const MEMORY_RECALL_METADATA_TABLE = "memory_index_chunk_recall_metadata";
function readMemoryRecallMetadataMigrationState(database) {
const rows = database.prepare("PRAGMA table_info(memory_index_chunks)").all();
if (rows.length === 0) return null;
const columns = new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
return {
columns: LEGACY_MEMORY_RECALL_METADATA_COLUMNS.filter((column) => columns.has(column)),
hasMetadataTable: Boolean(database.prepare("SELECT 1 FROM sqlite_schema WHERE type = 'table' AND name = ?").get(MEMORY_RECALL_METADATA_TABLE)),
hasProvenanceTrigger: Boolean(database.prepare("SELECT 1 FROM sqlite_schema WHERE type = 'trigger' AND name = ?").get(LEGACY_MEMORY_PROVENANCE_TRIGGER))
};
}
function inspectAgentMemoryRecallMetadataMigration(pathname) {
if (!fs.lstatSync(pathname).isFile()) throw new Error(`OpenClaw agent database is not a regular file: ${pathname}`);
const database = openNodeSqliteDatabase(pathname, { readOnly: true });
try {
return readMemoryRecallMetadataMigrationState(database);
} finally {
database.close();
}
}
/** Move the unreleased inline metadata shape into rollback-safe additive tables. */
function repairDoctorAgentMemorySchemas(options = {}) {
const env = options.env ?? process.env;
const repaired = [];
const warnings = [];
let registered;
try {
registered = listOpenClawRegisteredAgentDatabases({
env,
includeIncompatibleSchemaVersions: true
});
} catch (error) {
return {
repaired,
warnings: [`Could not inspect registered agent databases: ${formatErrorMessage(error)}`]
};
}
for (const entry of registered) try {
const before = inspectAgentMemoryRecallMetadataMigration(entry.path);
if (!before || before.columns.length === 0 && !before.hasProvenanceTrigger) continue;
closeOpenClawAgentDatabaseByPath(entry.path);
migrateOpenClawAgentDatabaseForMaintenance({
agentId: entry.agentId,
pathname: entry.path
});
const after = inspectAgentMemoryRecallMetadataMigration(entry.path);
if (after === null || after.columns.length > 0 || after.hasProvenanceTrigger || !after.hasMetadataTable) throw new Error("memory recall metadata did not converge on rollback-safe additive storage");
repaired.push({
agentId: entry.agentId,
columns: before.columns,
path: entry.path,
removedTrigger: before.hasProvenanceTrigger
});
} catch (error) {
warnings.push(`Agent ${entry.agentId} database ${shortenHomePath(entry.path)}: ${formatErrorMessage(error)}`);
}
return {
repaired,
warnings
};
}
async function noteDoctorAgentMemorySchemaHealth(params, deps = {}) {
const writeNote = deps.note ?? note;
if (!params.shouldRepair) return {
repaired: [],
warnings: []
};
let report;
try {
report = await withDoctorSqliteMaintenanceLock({
env: params.env,
operation: "agent memory schema repair",
run: () => withAgentDatabaseMaintenanceLease({ env: params.env }, async () => repairDoctorAgentMemorySchemas({ env: params.env }))
});
} catch (error) {
if (!(error instanceof DoctorSqliteMaintenanceLockUnavailableError)) throw error;
report = {
repaired: [],
warnings: [error.message]
};
}
if (report.repaired.length > 0) writeNote(report.repaired.map((repair) => {
const changes = [repair.columns.length > 0 ? `moved ${repair.columns.map((column) => `memory_index_chunks.${column}`).join(", ")} to additive storage` : null, repair.removedTrigger ? `removed ${LEGACY_MEMORY_PROVENANCE_TRIGGER}` : null].filter((change) => change !== null);
return `- Agent ${repair.agentId}: ${changes.join("; ")} (${shortenHomePath(repair.path)}).`;
}).join("\n"), "Doctor changes");
if (report.warnings.length > 0) writeNote(report.warnings.map((warning) => `- ${warning}`).join("\n"), "Doctor warnings");
return report;
}
//#endregion
export { noteDoctorAgentMemorySchemaHealth };