@sema-agent/core
Version:
Stateless, task-oriented AI agent core
68 lines (67 loc) • 2.48 kB
JavaScript
export function reconcileMemoryEntries(baseRevs, local, remote) {
const plan = { push: [], pull: [], deleteLocal: [], deleteRemote: [], conflicts: [], cleared: [] };
const localById = new Map(local.map((e) => [e.id, e]));
const remoteById = new Map(remote.map((e) => [e.id, e]));
const ids = new Set([...localById.keys(), ...remoteById.keys(), ...Object.keys(baseRevs)]);
for (const id of ids) {
const l = localById.get(id);
const r = remoteById.get(id);
const base = baseRevs[id];
if (l !== undefined && r !== undefined) {
if (l.rev === r.rev)
continue;
const localChanged = base === undefined || l.rev !== base;
const remoteChanged = base === undefined || r.rev !== base;
if (localChanged && remoteChanged)
plan.conflicts.push({ id, local: l, remote: r, ...(base !== undefined ? { baseRev: base } : {}) });
else if (localChanged)
plan.push.push(l);
else
plan.pull.push(r);
continue;
}
if (l !== undefined) {
if (base === undefined)
plan.push.push(l);
else if (l.rev !== base)
plan.conflicts.push({ id, local: l, baseRev: base });
else
plan.deleteLocal.push({ id, baseRev: base });
continue;
}
if (r !== undefined) {
if (base === undefined)
plan.pull.push(r);
else if (r.rev !== base)
plan.conflicts.push({ id, remote: r, baseRev: base });
else
plan.deleteRemote.push({ id, baseRev: base });
continue;
}
plan.cleared.push(id);
}
return plan;
}
export function nextSyncBaseline(local, remote) {
const remoteById = new Map(remote.map((e) => [e.id, e.rev]));
const base = {};
for (const e of local) {
if (remoteById.get(e.id) === e.rev)
base[e.id] = e.rev;
}
return base;
}
export function mergeRecallHits(hitLists, limit) {
const seen = new Set();
const merged = [];
for (const list of hitLists) {
for (const h of list) {
if (seen.has(h.id))
continue;
seen.add(h.id);
merged.push(h);
}
}
merged.sort((a, b) => a.score - b.score || a.id.localeCompare(b.id));
return merged.slice(0, Math.max(0, limit));
}