nolo-cli 0.75.0 → 0.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -172,7 +172,8 @@ import {
|
|
|
172
172
|
parsePositiveFiniteNumberOrFallback
|
|
173
173
|
} from "./chunk-Y5GCAMGP.js";
|
|
174
174
|
import {
|
|
175
|
-
createMemoryKey
|
|
175
|
+
createMemoryKey,
|
|
176
|
+
ulid
|
|
176
177
|
} from "./chunk-VMFTFOWF.js";
|
|
177
178
|
import {
|
|
178
179
|
asTrimmedLowercaseString
|
|
@@ -185,6 +186,9 @@ import {
|
|
|
185
186
|
import {
|
|
186
187
|
parsePublicAgentId
|
|
187
188
|
} from "./chunk-BJIRLHJR.js";
|
|
189
|
+
import {
|
|
190
|
+
isLevelNotFoundError
|
|
191
|
+
} from "./chunk-OW765XBU.js";
|
|
188
192
|
import {
|
|
189
193
|
asTrimmedString
|
|
190
194
|
} from "./chunk-3EUW3WEO.js";
|
|
@@ -10411,7 +10415,7 @@ function findCollapsedPasteSpanAt(buffer, pos, opts = {}) {
|
|
|
10411
10415
|
}
|
|
10412
10416
|
|
|
10413
10417
|
// packages/cli/client/agentRun.ts
|
|
10414
|
-
import { ulid } from "ulid";
|
|
10418
|
+
import { ulid as ulid2 } from "ulid";
|
|
10415
10419
|
async function loadRunLocalAgentTurn() {
|
|
10416
10420
|
const { runLocalAgentTurn } = await import("./agentRuntimeLocal-T43UNWAY.js");
|
|
10417
10421
|
return runLocalAgentTurn;
|
|
@@ -11078,8 +11082,8 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
11078
11082
|
...options.parentWakeOnTerminal ? { parentWakeOnTerminal: true } : {},
|
|
11079
11083
|
...options.parentDialogId ? { parentThreadId: options.parentDialogId } : {}
|
|
11080
11084
|
} : void 0;
|
|
11081
|
-
const currentDialogId = options.continueDialogId ??
|
|
11082
|
-
const turnId = `turn-${
|
|
11085
|
+
const currentDialogId = options.continueDialogId ?? ulid2();
|
|
11086
|
+
const turnId = `turn-${ulid2()}`;
|
|
11083
11087
|
const runtimeContextWithOwnership = {
|
|
11084
11088
|
...runtimeContext ?? {},
|
|
11085
11089
|
dialogId: currentDialogId,
|
|
@@ -12076,8 +12080,15 @@ var rankMemoryCandidates = (items, query, context) => {
|
|
|
12076
12080
|
// packages/ai/memory/vnext/store.ts
|
|
12077
12081
|
var enc = (value) => encodeURIComponent(value).replace(/-/g, "%2D");
|
|
12078
12082
|
var rangeOf = (prefix) => ({ gte: prefix, lte: `${prefix}\uFFFF` });
|
|
12083
|
+
var entityKey = (ownerId, id) => `mem2-e-${enc(ownerId)}-${enc(id)}`;
|
|
12079
12084
|
var entityOwnerPrefix = (ownerId) => `mem2-e-${enc(ownerId)}-`;
|
|
12085
|
+
var stateKey = (ownerId, id) => `mem2-s-${enc(ownerId)}-${enc(id)}`;
|
|
12086
|
+
var stateEntityIndexKey = (ownerId, entityId, stateId) => `mem2-si-${enc(ownerId)}-${enc(entityId)}-${enc(stateId)}`;
|
|
12080
12087
|
var stateEntityIndexPrefix = (ownerId, entityId) => `mem2-si-${enc(ownerId)}-${enc(entityId)}-`;
|
|
12088
|
+
var evidenceKey = (ownerId, id) => `mem2-v-${enc(ownerId)}-${enc(id)}`;
|
|
12089
|
+
var relationKey = (ownerId, id) => `mem2-r-${enc(ownerId)}-${enc(id)}`;
|
|
12090
|
+
var relationFromIndexKey = (ownerId, from, relationId) => `mem2-rf-${enc(ownerId)}-${enc(from)}-${enc(relationId)}`;
|
|
12091
|
+
var relationToIndexKey = (ownerId, to, relationId) => `mem2-rt-${enc(ownerId)}-${enc(to)}-${enc(relationId)}`;
|
|
12081
12092
|
var readIndexed = async (db, prefix) => {
|
|
12082
12093
|
const refs = [];
|
|
12083
12094
|
for await (const [, value] of db.iterator({ ...rangeOf(prefix), reverse: false })) {
|
|
@@ -12086,6 +12097,7 @@ var readIndexed = async (db, prefix) => {
|
|
|
12086
12097
|
const rows = await Promise.all(refs.map((key) => db.get(key).catch(() => null)));
|
|
12087
12098
|
return rows.filter((row) => !!row);
|
|
12088
12099
|
};
|
|
12100
|
+
var getMemoryEntityVNext = async (db, ownerId, entityId) => db.get(entityKey(ownerId, entityId)).catch(() => null);
|
|
12089
12101
|
var listMemoryEntitiesVNext = async (db, ownerId) => {
|
|
12090
12102
|
const rows = [];
|
|
12091
12103
|
for await (const [, value] of db.iterator({
|
|
@@ -12096,7 +12108,40 @@ var listMemoryEntitiesVNext = async (db, ownerId) => {
|
|
|
12096
12108
|
}
|
|
12097
12109
|
return rows;
|
|
12098
12110
|
};
|
|
12111
|
+
var getMemoryStateVNext = async (db, ownerId, stateId) => db.get(stateKey(ownerId, stateId)).catch(() => null);
|
|
12099
12112
|
var listMemoryStatesForEntityVNext = (db, ownerId, entityId) => readIndexed(db, stateEntityIndexPrefix(ownerId, entityId));
|
|
12113
|
+
var putMemoryEvidenceVNext = async (db, evidence) => {
|
|
12114
|
+
await db.put(evidenceKey(evidence.ownerId, evidence.id), evidence);
|
|
12115
|
+
};
|
|
12116
|
+
var getMemoryEvidenceVNext = async (db, ownerId, evidenceId) => db.get(evidenceKey(ownerId, evidenceId)).catch(() => null);
|
|
12117
|
+
var getMemoryEvidenceVNextStrict = async (db, ownerId, evidenceId) => {
|
|
12118
|
+
try {
|
|
12119
|
+
return await db.get(evidenceKey(ownerId, evidenceId));
|
|
12120
|
+
} catch (error) {
|
|
12121
|
+
if (isLevelNotFoundError(error)) return null;
|
|
12122
|
+
throw error;
|
|
12123
|
+
}
|
|
12124
|
+
};
|
|
12125
|
+
var _appendEntityBatch = (batch, entity) => {
|
|
12126
|
+
batch.put(entityKey(entity.ownerId, entity.id), entity);
|
|
12127
|
+
};
|
|
12128
|
+
var _appendEvidenceBatch = (batch, evidence) => {
|
|
12129
|
+
batch.put(evidenceKey(evidence.ownerId, evidence.id), evidence);
|
|
12130
|
+
};
|
|
12131
|
+
var _appendStateBatch = (batch, state2) => {
|
|
12132
|
+
const key = stateKey(state2.ownerId, state2.id);
|
|
12133
|
+
batch.put(key, state2);
|
|
12134
|
+
batch.put(stateEntityIndexKey(state2.ownerId, state2.entityId, state2.id), { key });
|
|
12135
|
+
};
|
|
12136
|
+
var _appendRetiredStateBatch = (batch, state2) => {
|
|
12137
|
+
batch.put(stateKey(state2.ownerId, state2.id), state2);
|
|
12138
|
+
};
|
|
12139
|
+
var _appendRelationBatch = (batch, relation) => {
|
|
12140
|
+
const key = relationKey(relation.ownerId, relation.id);
|
|
12141
|
+
batch.put(key, relation);
|
|
12142
|
+
batch.put(relationFromIndexKey(relation.ownerId, relation.from, relation.id), { key });
|
|
12143
|
+
batch.put(relationToIndexKey(relation.ownerId, relation.to, relation.id), { key });
|
|
12144
|
+
};
|
|
12100
12145
|
|
|
12101
12146
|
// packages/ai/memory/vnext/recall.ts
|
|
12102
12147
|
var MAX_RECALL_REFS = 6;
|
|
@@ -12227,11 +12272,41 @@ ${catalogText(entities, states)}`
|
|
|
12227
12272
|
};
|
|
12228
12273
|
|
|
12229
12274
|
// packages/ai/memory/vnext/legacyMigration.ts
|
|
12275
|
+
import { createHash } from "crypto";
|
|
12276
|
+
var LEGACY_MEMORY_SOURCE_REF_PREFIX = "legacy-memory";
|
|
12277
|
+
var LEGACY_MEMORY_EVIDENCE_ID_PREFIX = "mem-legacy-";
|
|
12230
12278
|
var resolveLegacyMemoryPrincipal = (item) => ({
|
|
12231
12279
|
ownerType: item.ownerType,
|
|
12232
12280
|
ownerId: item.ownerId,
|
|
12233
12281
|
principalId: `${item.ownerType}:${encodeURIComponent(item.ownerId)}`
|
|
12234
12282
|
});
|
|
12283
|
+
var buildLegacyMemorySourceRef = (item) => {
|
|
12284
|
+
const { principalId } = resolveLegacyMemoryPrincipal(item);
|
|
12285
|
+
return `${LEGACY_MEMORY_SOURCE_REF_PREFIX}:${principalId}:${encodeURIComponent(item.id)}`;
|
|
12286
|
+
};
|
|
12287
|
+
var legacyEvidenceSeed = (principalId, itemId) => JSON.stringify([principalId, itemId]);
|
|
12288
|
+
var buildLegacyEvidenceId = (item) => {
|
|
12289
|
+
const { principalId } = resolveLegacyMemoryPrincipal(item);
|
|
12290
|
+
const digest = createHash("sha256").update(legacyEvidenceSeed(principalId, item.id)).digest("hex");
|
|
12291
|
+
return `${LEGACY_MEMORY_EVIDENCE_ID_PREFIX}${digest.slice(0, 32)}`;
|
|
12292
|
+
};
|
|
12293
|
+
var clampLegacyConfidence = (value) => {
|
|
12294
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 0;
|
|
12295
|
+
if (value < 0) return 0;
|
|
12296
|
+
if (value > 1) return 1;
|
|
12297
|
+
return value;
|
|
12298
|
+
};
|
|
12299
|
+
var buildLegacyMemoryEvidence = (item) => {
|
|
12300
|
+
const { principalId } = resolveLegacyMemoryPrincipal(item);
|
|
12301
|
+
return {
|
|
12302
|
+
id: buildLegacyEvidenceId(item),
|
|
12303
|
+
ownerId: principalId,
|
|
12304
|
+
text: item.content,
|
|
12305
|
+
sourceRef: buildLegacyMemorySourceRef(item),
|
|
12306
|
+
confidence: clampLegacyConfidence(item.confidence),
|
|
12307
|
+
createdAt: item.createdAt
|
|
12308
|
+
};
|
|
12309
|
+
};
|
|
12235
12310
|
|
|
12236
12311
|
// packages/ai/memory/vnext/shadowRead.ts
|
|
12237
12312
|
var SHADOW_TIMEOUT_MS = 2e4;
|
|
@@ -12340,6 +12415,736 @@ var runMemoryVNextShadowRead = async (input) => {
|
|
|
12340
12415
|
};
|
|
12341
12416
|
var isMemoryVNextShadowReadEnabled = (env = typeof process !== "undefined" ? process.env : {}) => env.NOLO_MEMORY_VNEXT_SHADOW_READ === "1" || env.NOLO_MEMORY_VNEXT_SHADOW_READ === "true";
|
|
12342
12417
|
|
|
12418
|
+
// packages/ai/memory/vnext/applyMutation.ts
|
|
12419
|
+
async function validateMutation(db, ownerId, mutation) {
|
|
12420
|
+
const pending = {
|
|
12421
|
+
evidenceIds: /* @__PURE__ */ new Set(),
|
|
12422
|
+
entityIds: /* @__PURE__ */ new Set(),
|
|
12423
|
+
stateIds: /* @__PURE__ */ new Set(),
|
|
12424
|
+
relationIds: /* @__PURE__ */ new Set()
|
|
12425
|
+
};
|
|
12426
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12427
|
+
if (!ev.id || typeof ev.id !== "string") {
|
|
12428
|
+
throw new Error("evidence id must be a non-empty string");
|
|
12429
|
+
}
|
|
12430
|
+
if (pending.evidenceIds.has(ev.id)) {
|
|
12431
|
+
throw new Error(`duplicate evidence id in mutation: ${ev.id}`);
|
|
12432
|
+
}
|
|
12433
|
+
pending.evidenceIds.add(ev.id);
|
|
12434
|
+
}
|
|
12435
|
+
for (const ent of mutation.entities ?? []) {
|
|
12436
|
+
if (!ent.id || typeof ent.id !== "string") {
|
|
12437
|
+
throw new Error("entity id must be a non-empty string");
|
|
12438
|
+
}
|
|
12439
|
+
if (pending.entityIds.has(ent.id)) {
|
|
12440
|
+
throw new Error(`duplicate entity id in mutation: ${ent.id}`);
|
|
12441
|
+
}
|
|
12442
|
+
pending.entityIds.add(ent.id);
|
|
12443
|
+
}
|
|
12444
|
+
for (const st of mutation.states ?? []) {
|
|
12445
|
+
if (!st.id || typeof st.id !== "string") {
|
|
12446
|
+
throw new Error("state id must be a non-empty string");
|
|
12447
|
+
}
|
|
12448
|
+
if (pending.stateIds.has(st.id)) {
|
|
12449
|
+
throw new Error(`duplicate state id in mutation: ${st.id}`);
|
|
12450
|
+
}
|
|
12451
|
+
pending.stateIds.add(st.id);
|
|
12452
|
+
}
|
|
12453
|
+
for (const rel of mutation.relations ?? []) {
|
|
12454
|
+
if (!rel.id || typeof rel.id !== "string") {
|
|
12455
|
+
throw new Error("relation id must be a non-empty string");
|
|
12456
|
+
}
|
|
12457
|
+
if (pending.relationIds.has(rel.id)) {
|
|
12458
|
+
throw new Error(`duplicate relation id in mutation: ${rel.id}`);
|
|
12459
|
+
}
|
|
12460
|
+
pending.relationIds.add(rel.id);
|
|
12461
|
+
}
|
|
12462
|
+
const supersededIds = /* @__PURE__ */ new Set();
|
|
12463
|
+
for (const sid of mutation.supersededStateIds ?? []) {
|
|
12464
|
+
if (supersededIds.has(sid)) {
|
|
12465
|
+
throw new Error(`duplicate supersededStateId in mutation: ${sid}`);
|
|
12466
|
+
}
|
|
12467
|
+
supersededIds.add(sid);
|
|
12468
|
+
}
|
|
12469
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12470
|
+
if (ev.ownerId !== ownerId) {
|
|
12471
|
+
throw new Error(
|
|
12472
|
+
`evidence ${ev.id} has ownerId ${ev.ownerId}, expected ${ownerId}`
|
|
12473
|
+
);
|
|
12474
|
+
}
|
|
12475
|
+
}
|
|
12476
|
+
for (const ent of mutation.entities ?? []) {
|
|
12477
|
+
if (ent.ownerId !== ownerId) {
|
|
12478
|
+
throw new Error(
|
|
12479
|
+
`entity ${ent.id} has ownerId ${ent.ownerId}, expected ${ownerId}`
|
|
12480
|
+
);
|
|
12481
|
+
}
|
|
12482
|
+
}
|
|
12483
|
+
for (const st of mutation.states ?? []) {
|
|
12484
|
+
if (st.ownerId !== ownerId) {
|
|
12485
|
+
throw new Error(
|
|
12486
|
+
`state ${st.id} has ownerId ${st.ownerId}, expected ${ownerId}`
|
|
12487
|
+
);
|
|
12488
|
+
}
|
|
12489
|
+
}
|
|
12490
|
+
for (const rel of mutation.relations ?? []) {
|
|
12491
|
+
if (rel.ownerId !== ownerId) {
|
|
12492
|
+
throw new Error(
|
|
12493
|
+
`relation ${rel.id} has ownerId ${rel.ownerId}, expected ${ownerId}`
|
|
12494
|
+
);
|
|
12495
|
+
}
|
|
12496
|
+
}
|
|
12497
|
+
for (const st of mutation.states ?? []) {
|
|
12498
|
+
if (supersededIds.has(st.id)) {
|
|
12499
|
+
throw new Error(
|
|
12500
|
+
`state ${st.id} appears in both states and supersededStateIds; a record cannot be created and retired in the same mutation`
|
|
12501
|
+
);
|
|
12502
|
+
}
|
|
12503
|
+
}
|
|
12504
|
+
const facetSlots = /* @__PURE__ */ new Set();
|
|
12505
|
+
for (const st of mutation.states ?? []) {
|
|
12506
|
+
const slot = `${st.entityId} ${st.facet}`;
|
|
12507
|
+
if (facetSlots.has(slot)) {
|
|
12508
|
+
throw new Error(
|
|
12509
|
+
`mutation writes parallel current states for entity ${st.entityId} facet ${st.facet}`
|
|
12510
|
+
);
|
|
12511
|
+
}
|
|
12512
|
+
facetSlots.add(slot);
|
|
12513
|
+
}
|
|
12514
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12515
|
+
const existing = await getMemoryEvidenceVNext(db, ownerId, ev.id);
|
|
12516
|
+
if (existing) {
|
|
12517
|
+
throw new Error(
|
|
12518
|
+
`evidence ${ev.id} already exists (owner ${ownerId}); use a unique id`
|
|
12519
|
+
);
|
|
12520
|
+
}
|
|
12521
|
+
}
|
|
12522
|
+
for (const ent of mutation.entities ?? []) {
|
|
12523
|
+
const existing = await getMemoryEntityVNext(db, ownerId, ent.id);
|
|
12524
|
+
if (existing) {
|
|
12525
|
+
throw new Error(
|
|
12526
|
+
`entity ${ent.id} already exists (owner ${ownerId}); use a unique id`
|
|
12527
|
+
);
|
|
12528
|
+
}
|
|
12529
|
+
}
|
|
12530
|
+
for (const st of mutation.states ?? []) {
|
|
12531
|
+
if (!pending.entityIds.has(st.entityId)) {
|
|
12532
|
+
const entity = await getMemoryEntityVNext(db, ownerId, st.entityId);
|
|
12533
|
+
if (!entity) {
|
|
12534
|
+
throw new Error(
|
|
12535
|
+
`memory state ${st.id} references missing entity ${st.entityId} (owner ${ownerId})`
|
|
12536
|
+
);
|
|
12537
|
+
}
|
|
12538
|
+
}
|
|
12539
|
+
for (const evidenceId of st.evidenceIds) {
|
|
12540
|
+
if (!pending.evidenceIds.has(evidenceId)) {
|
|
12541
|
+
const ev = await getMemoryEvidenceVNext(db, ownerId, evidenceId);
|
|
12542
|
+
if (!ev) {
|
|
12543
|
+
throw new Error(
|
|
12544
|
+
`memory state ${st.id} references missing evidence ${evidenceId} (owner ${ownerId})`
|
|
12545
|
+
);
|
|
12546
|
+
}
|
|
12547
|
+
}
|
|
12548
|
+
}
|
|
12549
|
+
const existing = await getMemoryStateVNext(db, ownerId, st.id);
|
|
12550
|
+
if (existing) {
|
|
12551
|
+
if (existing.retiredAt) {
|
|
12552
|
+
throw new Error(
|
|
12553
|
+
`cannot update retired memory state ${st.id} (owner ${ownerId})`
|
|
12554
|
+
);
|
|
12555
|
+
}
|
|
12556
|
+
if (existing.entityId !== st.entityId || existing.facet !== st.facet) {
|
|
12557
|
+
throw new Error(
|
|
12558
|
+
`state ${st.id} already exists with different entity/facet (${existing.entityId}/${existing.facet} vs ${st.entityId}/${st.facet}); use supersede instead`
|
|
12559
|
+
);
|
|
12560
|
+
}
|
|
12561
|
+
}
|
|
12562
|
+
if (!existing) {
|
|
12563
|
+
const existingStates = await listMemoryStatesForEntityVNext(db, ownerId, st.entityId);
|
|
12564
|
+
for (const es of existingStates) {
|
|
12565
|
+
if (es.facet === st.facet && !es.retiredAt) {
|
|
12566
|
+
if (!supersededIds.has(es.id)) {
|
|
12567
|
+
throw new Error(
|
|
12568
|
+
`entity ${st.entityId} facet ${st.facet} already has current state ${es.id}; supersede it or use a different facet`
|
|
12569
|
+
);
|
|
12570
|
+
}
|
|
12571
|
+
}
|
|
12572
|
+
}
|
|
12573
|
+
}
|
|
12574
|
+
}
|
|
12575
|
+
for (const sid of mutation.supersededStateIds ?? []) {
|
|
12576
|
+
const existing = await getMemoryStateVNext(db, ownerId, sid);
|
|
12577
|
+
if (!existing) {
|
|
12578
|
+
throw new Error(
|
|
12579
|
+
`cannot supersede missing memory state: ${sid} (owner ${ownerId})`
|
|
12580
|
+
);
|
|
12581
|
+
}
|
|
12582
|
+
if (existing.retiredAt) {
|
|
12583
|
+
throw new Error(
|
|
12584
|
+
`cannot supersede already retired memory state: ${sid} (owner ${ownerId})`
|
|
12585
|
+
);
|
|
12586
|
+
}
|
|
12587
|
+
const replacement = (mutation.states ?? []).find(
|
|
12588
|
+
(st) => st.entityId === existing.entityId && st.facet === existing.facet
|
|
12589
|
+
);
|
|
12590
|
+
if (!replacement) {
|
|
12591
|
+
throw new Error(
|
|
12592
|
+
`superseded state ${sid} (entity ${existing.entityId} facet ${existing.facet}) has no replacement in this mutation`
|
|
12593
|
+
);
|
|
12594
|
+
}
|
|
12595
|
+
}
|
|
12596
|
+
for (const rel of mutation.relations ?? []) {
|
|
12597
|
+
for (const [side, ref] of [
|
|
12598
|
+
["from", rel.from],
|
|
12599
|
+
["to", rel.to]
|
|
12600
|
+
]) {
|
|
12601
|
+
if (pending.entityIds.has(ref) || pending.stateIds.has(ref) || pending.evidenceIds.has(ref)) {
|
|
12602
|
+
continue;
|
|
12603
|
+
}
|
|
12604
|
+
const resolved = await getMemoryEntityVNext(db, ownerId, ref) ?? await getMemoryStateVNext(db, ownerId, ref) ?? await getMemoryEvidenceVNext(db, ownerId, ref);
|
|
12605
|
+
if (!resolved) {
|
|
12606
|
+
throw new Error(
|
|
12607
|
+
`memory relation ${rel.id} references missing ${side} ${ref} (owner ${ownerId})`
|
|
12608
|
+
);
|
|
12609
|
+
}
|
|
12610
|
+
}
|
|
12611
|
+
}
|
|
12612
|
+
}
|
|
12613
|
+
var applyMemoryInterpreterMutation = async (db, ownerId, mutation) => {
|
|
12614
|
+
await validateMutation(db, ownerId, mutation);
|
|
12615
|
+
const batch = db.batch();
|
|
12616
|
+
for (const ev of mutation.evidence ?? []) {
|
|
12617
|
+
_appendEvidenceBatch(batch, ev);
|
|
12618
|
+
}
|
|
12619
|
+
for (const ent of mutation.entities ?? []) {
|
|
12620
|
+
_appendEntityBatch(batch, ent);
|
|
12621
|
+
}
|
|
12622
|
+
for (const st of mutation.states ?? []) {
|
|
12623
|
+
_appendStateBatch(batch, st);
|
|
12624
|
+
}
|
|
12625
|
+
for (const sid of mutation.supersededStateIds ?? []) {
|
|
12626
|
+
const existing = await getMemoryStateVNext(db, ownerId, sid);
|
|
12627
|
+
if (!existing) {
|
|
12628
|
+
throw new Error(
|
|
12629
|
+
`cannot supersede missing memory state: ${sid} (owner ${ownerId})`
|
|
12630
|
+
);
|
|
12631
|
+
}
|
|
12632
|
+
const replacement = (mutation.states ?? []).find(
|
|
12633
|
+
(st) => st.entityId === existing.entityId && st.facet === existing.facet
|
|
12634
|
+
);
|
|
12635
|
+
const retired = {
|
|
12636
|
+
...existing,
|
|
12637
|
+
retiredAt: replacement?.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
12638
|
+
};
|
|
12639
|
+
_appendRetiredStateBatch(batch, retired);
|
|
12640
|
+
}
|
|
12641
|
+
for (const rel of mutation.relations ?? []) {
|
|
12642
|
+
_appendRelationBatch(batch, rel);
|
|
12643
|
+
}
|
|
12644
|
+
await batch.write();
|
|
12645
|
+
};
|
|
12646
|
+
|
|
12647
|
+
// packages/ai/memory/vnext/legacyMigrationApply.ts
|
|
12648
|
+
var isSameLegacyMemoryEvidence = (left, right) => left.id === right.id && left.ownerId === right.ownerId && left.text === right.text && left.sourceRef === right.sourceRef && left.confidence === right.confidence && left.createdAt === right.createdAt;
|
|
12649
|
+
var applyLegacyMemoryEvidence = async (db, item) => {
|
|
12650
|
+
const incoming = buildLegacyMemoryEvidence(item);
|
|
12651
|
+
const existing = await getMemoryEvidenceVNextStrict(db, incoming.ownerId, incoming.id);
|
|
12652
|
+
if (existing) {
|
|
12653
|
+
return isSameLegacyMemoryEvidence(existing, incoming) ? { status: "already_exists", evidence: existing } : { status: "conflict", existing, incoming };
|
|
12654
|
+
}
|
|
12655
|
+
await putMemoryEvidenceVNext(db, incoming);
|
|
12656
|
+
return { status: "created", evidence: incoming };
|
|
12657
|
+
};
|
|
12658
|
+
|
|
12659
|
+
// packages/ai/memory/vnext/types.ts
|
|
12660
|
+
var MEMORY_ENTITY_TYPES = [
|
|
12661
|
+
"person",
|
|
12662
|
+
"organization",
|
|
12663
|
+
"project",
|
|
12664
|
+
"place",
|
|
12665
|
+
"object",
|
|
12666
|
+
"activity",
|
|
12667
|
+
"concept"
|
|
12668
|
+
];
|
|
12669
|
+
var MEMORY_RELATION_TYPES = [
|
|
12670
|
+
"related_to",
|
|
12671
|
+
"part_of",
|
|
12672
|
+
"uses",
|
|
12673
|
+
"involves",
|
|
12674
|
+
"supersedes"
|
|
12675
|
+
];
|
|
12676
|
+
|
|
12677
|
+
// packages/ai/memory/vnext/interpreterWireProtocol.ts
|
|
12678
|
+
var isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
12679
|
+
var isString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
12680
|
+
var isStringArray = (value) => Array.isArray(value) && value.every(isString);
|
|
12681
|
+
var optionalArray = (value, validate2) => value === void 0 || Array.isArray(value) && value.every(validate2);
|
|
12682
|
+
var ACTIONS = /* @__PURE__ */ new Set([
|
|
12683
|
+
"no_op",
|
|
12684
|
+
"create",
|
|
12685
|
+
"update",
|
|
12686
|
+
"specialize",
|
|
12687
|
+
"supersede",
|
|
12688
|
+
"ambiguous"
|
|
12689
|
+
]);
|
|
12690
|
+
var validateEvidence = (value) => {
|
|
12691
|
+
if (!isObject(value)) return false;
|
|
12692
|
+
return isString(value.key) && isString(value.text) && typeof value.confidence === "number" && Number.isFinite(value.confidence) && value.confidence >= 0 && value.confidence <= 1 && (value.sourceRef === void 0 || isString(value.sourceRef));
|
|
12693
|
+
};
|
|
12694
|
+
var validateEntity = (value) => {
|
|
12695
|
+
if (!isObject(value)) return false;
|
|
12696
|
+
return isString(value.key) && MEMORY_ENTITY_TYPES.includes(value.type) && isString(value.name) && (value.subtype === void 0 || isString(value.subtype)) && (value.aliases === void 0 || isStringArray(value.aliases));
|
|
12697
|
+
};
|
|
12698
|
+
var validateState = (value) => {
|
|
12699
|
+
if (!isObject(value)) return false;
|
|
12700
|
+
return (value.stateId === void 0 || isString(value.stateId)) && (value.supersedes === void 0 || isString(value.supersedes)) && isString(value.entityRef) && isString(value.facet) && "value" in value && isString(value.text) && isStringArray(value.evidenceRefs);
|
|
12701
|
+
};
|
|
12702
|
+
var validateRelation = (value) => {
|
|
12703
|
+
if (!isObject(value)) return false;
|
|
12704
|
+
return isString(value.fromRef) && MEMORY_RELATION_TYPES.includes(value.type) && isString(value.toRef);
|
|
12705
|
+
};
|
|
12706
|
+
var stripJsonFence = (raw) => {
|
|
12707
|
+
const trimmed = raw.trim();
|
|
12708
|
+
const match = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
12709
|
+
return match ? match[1].trim() : trimmed;
|
|
12710
|
+
};
|
|
12711
|
+
var parseMemoryInterpreterWireMutation = (raw) => {
|
|
12712
|
+
let parsed;
|
|
12713
|
+
try {
|
|
12714
|
+
parsed = JSON.parse(stripJsonFence(raw));
|
|
12715
|
+
} catch {
|
|
12716
|
+
return { ok: false, error: "interpreter output is not valid JSON" };
|
|
12717
|
+
}
|
|
12718
|
+
if (!isObject(parsed)) return { ok: false, error: "interpreter output must be an object" };
|
|
12719
|
+
if (!isString(parsed.action) || !ACTIONS.has(parsed.action)) {
|
|
12720
|
+
return { ok: false, error: "invalid reconciliation action" };
|
|
12721
|
+
}
|
|
12722
|
+
if (!isString(parsed.reason)) return { ok: false, error: "reason is required" };
|
|
12723
|
+
if (!optionalArray(parsed.evidence, validateEvidence)) return { ok: false, error: "invalid evidence array" };
|
|
12724
|
+
if (!optionalArray(parsed.entities, validateEntity)) return { ok: false, error: "invalid entities array" };
|
|
12725
|
+
if (!optionalArray(parsed.states, validateState)) return { ok: false, error: "invalid states array" };
|
|
12726
|
+
if (!optionalArray(parsed.relations, validateRelation)) return { ok: false, error: "invalid relations array" };
|
|
12727
|
+
return { ok: true, value: parsed };
|
|
12728
|
+
};
|
|
12729
|
+
var buildMemoryInterpreterWireContract = () => `
|
|
12730
|
+
Return ONLY one JSON object:
|
|
12731
|
+
{
|
|
12732
|
+
"action": "no_op|create|update|specialize|supersede|ambiguous",
|
|
12733
|
+
"reason": "short explanation",
|
|
12734
|
+
"evidence": [{ "key": "e1", "text": "...", "confidence": 0.9, "sourceRef": "optional" }],
|
|
12735
|
+
"entities": [{ "key": "n1", "type": "person|organization|project|place|object|activity|concept", "name": "...", "subtype": "optional", "aliases": [] }],
|
|
12736
|
+
"states": [{ "stateId": "optional-existing-state-id", "supersedes": "optional-existing-state-id-this-statement-replaces", "entityRef": "existing-entity-id-or-new-entity-key", "facet": "...", "value": {}, "text": "...", "evidenceRefs": ["e1"] }],
|
|
12737
|
+
"relations": [{ "fromRef": "existing-id-or-local-key", "type": "related_to|part_of|uses|involves|supersedes", "toRef": "existing-id-or-local-key" }]
|
|
12738
|
+
}
|
|
12739
|
+
|
|
12740
|
+
Do not generate persistent ids, owner ids, timestamps or storage keys. Runtime owns identity and time.
|
|
12741
|
+
Use short local keys only to connect records created in the SAME response. Every local key must be unique across evidence/entities.
|
|
12742
|
+
State evidenceRefs may reference Evidence emitted in this response. Evidence ids marked referenceable in the supplied memory context may be referenced directly. Do not reference any other prior Evidence id.
|
|
12743
|
+
When updating an existing State, reuse its exact stateId, exact entityRef and exact facet. Runtime preserves that State's original entity/facet/createdAt and appends new Evidence provenance.
|
|
12744
|
+
When creating a new State, omit stateId.
|
|
12745
|
+
For supersede: emit the replacing statement as a NEW State (omit stateId) and set supersedes to the exact id of the replaced current State. Runtime retires the replaced State \u2014 it stays recoverable as history but is no longer current, and the new State becomes the only current one for that facet. Never update or supersede an already retired State.
|
|
12746
|
+
supersedes and stateId are mutually exclusive on one State.
|
|
12747
|
+
Do not emit an existing Entity again merely to update its State; reference its exact id in entityRef.
|
|
12748
|
+
Relations may reference only known persisted Entity/State/Evidence ids or local Entity/Evidence keys emitted in the same response.
|
|
12749
|
+
Do not invent new Entity or Relation types. Keep expressive detail in subtype/facet/value/text.
|
|
12750
|
+
`.trim();
|
|
12751
|
+
var assertUniqueLocalKeys = (wire) => {
|
|
12752
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12753
|
+
for (const item of [...wire.evidence ?? [], ...wire.entities ?? []]) {
|
|
12754
|
+
if (seen.has(item.key)) throw new Error(`duplicate local key: ${item.key}`);
|
|
12755
|
+
seen.add(item.key);
|
|
12756
|
+
}
|
|
12757
|
+
};
|
|
12758
|
+
var materializeMemoryInterpreterMutation = (input) => {
|
|
12759
|
+
assertUniqueLocalKeys(input.wire);
|
|
12760
|
+
const now = input.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
12761
|
+
const nextId = input.nextId ?? ulid;
|
|
12762
|
+
const existingStates = new Map((input.existingStates ?? []).map((state2) => [state2.id, state2]));
|
|
12763
|
+
const existingStateIds = new Set(existingStates.keys());
|
|
12764
|
+
const existingEvidenceIds = new Set(
|
|
12765
|
+
[...existingStates.values()].flatMap((state2) => state2.evidenceIds)
|
|
12766
|
+
);
|
|
12767
|
+
const existingEntityIds = new Set(input.existingEntityIds ?? []);
|
|
12768
|
+
const entityRefs = /* @__PURE__ */ new Map();
|
|
12769
|
+
const evidenceRefs = /* @__PURE__ */ new Map();
|
|
12770
|
+
const evidence = (input.wire.evidence ?? []).map((item) => {
|
|
12771
|
+
const id = nextId();
|
|
12772
|
+
evidenceRefs.set(item.key, id);
|
|
12773
|
+
return {
|
|
12774
|
+
id,
|
|
12775
|
+
ownerId: input.ownerId,
|
|
12776
|
+
text: item.text,
|
|
12777
|
+
...item.sourceRef ? { sourceRef: item.sourceRef } : {},
|
|
12778
|
+
confidence: item.confidence,
|
|
12779
|
+
createdAt: now
|
|
12780
|
+
};
|
|
12781
|
+
});
|
|
12782
|
+
const entities = (input.wire.entities ?? []).map((item) => {
|
|
12783
|
+
const id = nextId();
|
|
12784
|
+
entityRefs.set(item.key, id);
|
|
12785
|
+
return {
|
|
12786
|
+
id,
|
|
12787
|
+
ownerId: input.ownerId,
|
|
12788
|
+
type: item.type,
|
|
12789
|
+
name: item.name,
|
|
12790
|
+
...item.subtype ? { subtype: item.subtype } : {},
|
|
12791
|
+
...item.aliases ? { aliases: item.aliases } : {},
|
|
12792
|
+
createdAt: now,
|
|
12793
|
+
updatedAt: now
|
|
12794
|
+
};
|
|
12795
|
+
});
|
|
12796
|
+
const resolveEntityRef = (ref) => {
|
|
12797
|
+
const created = entityRefs.get(ref);
|
|
12798
|
+
if (created) return created;
|
|
12799
|
+
if (existingEntityIds.has(ref)) return ref;
|
|
12800
|
+
throw new Error(`unknown entity ref: ${ref}`);
|
|
12801
|
+
};
|
|
12802
|
+
const supersededStateIds = [];
|
|
12803
|
+
const referenceableEvidenceIds = new Set(input.referenceableEvidenceIds ?? []);
|
|
12804
|
+
const resolveEvidenceRef = (ref) => {
|
|
12805
|
+
const created = evidenceRefs.get(ref);
|
|
12806
|
+
if (created) return created;
|
|
12807
|
+
if (referenceableEvidenceIds.has(ref)) return ref;
|
|
12808
|
+
throw new Error(`unknown evidence ref: ${ref}`);
|
|
12809
|
+
};
|
|
12810
|
+
const states = (input.wire.states ?? []).map((item) => {
|
|
12811
|
+
const prior = item.stateId ? existingStates.get(item.stateId) : void 0;
|
|
12812
|
+
if (item.stateId && !prior) {
|
|
12813
|
+
throw new Error(`unknown existing state: ${item.stateId}`);
|
|
12814
|
+
}
|
|
12815
|
+
if (prior?.retiredAt) {
|
|
12816
|
+
throw new Error(`retired state cannot be updated: ${item.stateId}`);
|
|
12817
|
+
}
|
|
12818
|
+
if (prior && item.entityRef !== prior.entityId) {
|
|
12819
|
+
throw new Error(`existing state entityRef changed: ${item.stateId}`);
|
|
12820
|
+
}
|
|
12821
|
+
if (prior && item.facet !== prior.facet) {
|
|
12822
|
+
throw new Error(`existing state facet changed: ${item.stateId}`);
|
|
12823
|
+
}
|
|
12824
|
+
let supersededStateId;
|
|
12825
|
+
if (item.supersedes !== void 0) {
|
|
12826
|
+
if (input.wire.action !== "supersede") {
|
|
12827
|
+
throw new Error(
|
|
12828
|
+
`supersedes is only valid for the supersede action, got ${input.wire.action}`
|
|
12829
|
+
);
|
|
12830
|
+
}
|
|
12831
|
+
if (item.stateId !== void 0) {
|
|
12832
|
+
throw new Error("supersedes and stateId are mutually exclusive on one state");
|
|
12833
|
+
}
|
|
12834
|
+
const superseded = existingStates.get(item.supersedes);
|
|
12835
|
+
if (!superseded) {
|
|
12836
|
+
throw new Error(`unknown superseded state id: ${item.supersedes}`);
|
|
12837
|
+
}
|
|
12838
|
+
if (superseded.retiredAt) {
|
|
12839
|
+
throw new Error(`retired state cannot be superseded: ${item.supersedes}`);
|
|
12840
|
+
}
|
|
12841
|
+
if (supersededStateIds.includes(item.supersedes)) {
|
|
12842
|
+
throw new Error(`duplicate superseded state id: ${item.supersedes}`);
|
|
12843
|
+
}
|
|
12844
|
+
supersededStateId = item.supersedes;
|
|
12845
|
+
}
|
|
12846
|
+
const newEvidenceIds = item.evidenceRefs.map(resolveEvidenceRef);
|
|
12847
|
+
const id = prior?.id ?? nextId();
|
|
12848
|
+
if (supersededStateId !== void 0) supersededStateIds.push(supersededStateId);
|
|
12849
|
+
return {
|
|
12850
|
+
id,
|
|
12851
|
+
ownerId: input.ownerId,
|
|
12852
|
+
entityId: prior?.entityId ?? resolveEntityRef(item.entityRef),
|
|
12853
|
+
facet: prior?.facet ?? item.facet,
|
|
12854
|
+
value: item.value,
|
|
12855
|
+
text: item.text,
|
|
12856
|
+
evidenceIds: [.../* @__PURE__ */ new Set([...prior?.evidenceIds ?? [], ...newEvidenceIds])],
|
|
12857
|
+
createdAt: prior?.createdAt ?? now,
|
|
12858
|
+
updatedAt: now
|
|
12859
|
+
};
|
|
12860
|
+
});
|
|
12861
|
+
const resolveRelationRef = (ref) => {
|
|
12862
|
+
const createdEntity = entityRefs.get(ref);
|
|
12863
|
+
if (createdEntity) return createdEntity;
|
|
12864
|
+
const createdEvidence = evidenceRefs.get(ref);
|
|
12865
|
+
if (createdEvidence) return createdEvidence;
|
|
12866
|
+
if (existingEntityIds.has(ref) || existingStateIds.has(ref) || existingEvidenceIds.has(ref)) {
|
|
12867
|
+
return ref;
|
|
12868
|
+
}
|
|
12869
|
+
throw new Error(`unknown relation ref: ${ref}`);
|
|
12870
|
+
};
|
|
12871
|
+
const relations = (input.wire.relations ?? []).map((item) => ({
|
|
12872
|
+
id: nextId(),
|
|
12873
|
+
ownerId: input.ownerId,
|
|
12874
|
+
from: resolveRelationRef(item.fromRef),
|
|
12875
|
+
type: item.type,
|
|
12876
|
+
to: resolveRelationRef(item.toRef),
|
|
12877
|
+
createdAt: now
|
|
12878
|
+
}));
|
|
12879
|
+
return {
|
|
12880
|
+
action: input.wire.action,
|
|
12881
|
+
reason: input.wire.reason,
|
|
12882
|
+
...evidence.length ? { evidence } : {},
|
|
12883
|
+
...entities.length ? { entities } : {},
|
|
12884
|
+
...states.length ? { states } : {},
|
|
12885
|
+
...supersededStateIds.length ? { supersededStateIds } : {},
|
|
12886
|
+
...relations.length ? { relations } : {}
|
|
12887
|
+
};
|
|
12888
|
+
};
|
|
12889
|
+
|
|
12890
|
+
// packages/ai/memory/vnext/interpreterPrompt.ts
|
|
12891
|
+
var MEMORY_VNEXT_ENTITY_CREATION_CONTRACT = `
|
|
12892
|
+
Entity creation is NOT named-entity recognition.
|
|
12893
|
+
|
|
12894
|
+
Create a new long-lived Entity only when the subject has future continuity value.
|
|
12895
|
+
A mention alone is insufficient.
|
|
12896
|
+
|
|
12897
|
+
Prefer leaving information as Evidence until at least one strong continuity signal exists:
|
|
12898
|
+
1. The subject recurs across independent dialogs, or the user explicitly describes it as enduring.
|
|
12899
|
+
2. The user connects it to their own preferences, relationships, goals, identity, worldview, ongoing work, or repeated activity.
|
|
12900
|
+
3. Future conversations are likely to refer back to it under different wording, so a stable anchor materially improves cross-dialog continuity.
|
|
12901
|
+
4. Creating the anchor is necessary to update or relate existing long-lived State.
|
|
12902
|
+
|
|
12903
|
+
Do NOT create an Entity merely because the text contains a named person, product, place, historical event, book, philosopher, food, device, or concept.
|
|
12904
|
+
When uncertain, keep Evidence and defer Entity creation.
|
|
12905
|
+
|
|
12906
|
+
Concept-specific rule:
|
|
12907
|
+
- concept is for abstract subjects that become part of the user's personal meaning world, such as freedom, absurdism, privacy, modernity, beauty, loneliness, safety, or maintainability.
|
|
12908
|
+
- Do not create a Concept Entity for every topic discussed or external fact queried.
|
|
12909
|
+
- Promote a concept only when it recurs, carries a durable user stance/interest/tension, connects multiple memories, or is likely to become a future recall/navigation anchor.
|
|
12910
|
+
- A one-off question such as "when was Kant born?" should normally create no long-lived Concept or Person Entity. Repeated discussion about Kant, freedom, and the user's own values may justify them.
|
|
12911
|
+
`.trim();
|
|
12912
|
+
var MEMORY_VNEXT_THIRD_PARTY_RELEVANCE_CONTRACT = `
|
|
12913
|
+
Third-party relevance test:
|
|
12914
|
+
- A fact about another person is durable only when it concerns the user's own world. Observation-only third-party facts \u2014 someone's appearance, news, habits, or the doings of a person the user merely encounters \u2014 stay Evidence, no matter how often they recur.
|
|
12915
|
+
- Closeness of that person, and repeated mentions across independent dialogs, do not by themselves make such an observation durable: never invent a user-world consequence to justify promotion (for example "the user keeps watching this person").
|
|
12916
|
+
- Matters that are part of the user's own shared life \u2014 household or family arrangements the user takes part in, a family member's health, or what the user relies on someone for \u2014 do belong to the user's world: state the user-world side (caregiving, changed time, changed plans, a sustained constraint) instead of a chronicle of the other person's doings.
|
|
12917
|
+
`.trim();
|
|
12918
|
+
var MEMORY_VNEXT_RECONCILIATION_CONTRACT = `
|
|
12919
|
+
When durable understanding changes, choose the smallest correct reconciliation:
|
|
12920
|
+
- no_op: no durable change.
|
|
12921
|
+
- create: genuinely new durable state/entity.
|
|
12922
|
+
- update: advance an existing state without changing its scope.
|
|
12923
|
+
- specialize: add a scoped exception/qualification; do not replace the broader state.
|
|
12924
|
+
- supersede: a newer statement explicitly replaces old current state. Emit the replacement as a NEW State and name the replaced current State in its supersedes field; runtime retires the old one (kept as recoverable history, no longer current).
|
|
12925
|
+
- ambiguous: evidence conflicts with current state, but replacement vs exception cannot be determined reliably.
|
|
12926
|
+
|
|
12927
|
+
Examples:
|
|
12928
|
+
- "\u56DE\u7B54\u7B80\u5355" then "\u5B89\u5168\u548C bug \u6392\u67E5\u8BE6\u7EC6" => specialize, not supersede.
|
|
12929
|
+
- "\u6211\u6709 Ollama Pro" then "\u6211\u5DF2\u7ECF\u4E0D\u7528 Ollama Pro \u4E86" => supersede.
|
|
12930
|
+
- Repeatedly choosing thin noodles without explicitly rejecting thick noodles => update or ambiguous, not automatic supersession.
|
|
12931
|
+
|
|
12932
|
+
Preserve ambiguity. Do not ask the user merely to clean memory. A later task may ask only if the unresolved state materially changes the answer.
|
|
12933
|
+
`.trim();
|
|
12934
|
+
var buildMemoryVNextInterpreterPrompt = () => [
|
|
12935
|
+
"You maintain long-lived adaptive relationship memory backed by evidence.",
|
|
12936
|
+
"External dialogs/files/web facts remain authoritative outside memory.",
|
|
12937
|
+
"Prefer a small stable set of Entities and updateable States over an ever-growing bag of facts.",
|
|
12938
|
+
MEMORY_VNEXT_ENTITY_CREATION_CONTRACT,
|
|
12939
|
+
MEMORY_VNEXT_THIRD_PARTY_RELEVANCE_CONTRACT,
|
|
12940
|
+
MEMORY_VNEXT_RECONCILIATION_CONTRACT,
|
|
12941
|
+
buildMemoryInterpreterWireContract()
|
|
12942
|
+
].join("\n\n");
|
|
12943
|
+
|
|
12944
|
+
// packages/ai/memory/vnext/legacyMigrationShadow.ts
|
|
12945
|
+
var LEGACY_MIGRATION_SHADOW_INSTRUCTION = `
|
|
12946
|
+
This Evidence came from a legacy memory record.
|
|
12947
|
+
Legacy kind and subject metadata are advisory hints only.
|
|
12948
|
+
Re-evaluate it under the current vNext contract.
|
|
12949
|
+
Do not mechanically map:
|
|
12950
|
+
- semantic -> State
|
|
12951
|
+
- procedural -> procedure State
|
|
12952
|
+
- subjectType=agent -> agent Entity
|
|
12953
|
+
- visibility -> scope
|
|
12954
|
+
Prefer Evidence-only when durable semantic value is unclear.
|
|
12955
|
+
`.trim();
|
|
12956
|
+
var serializeExisting = (existing) => JSON.stringify({
|
|
12957
|
+
entityIds: existing?.entityIds ?? [],
|
|
12958
|
+
states: (existing?.states ?? []).map((state2) => ({
|
|
12959
|
+
stateId: state2.id,
|
|
12960
|
+
entityId: state2.entityId,
|
|
12961
|
+
facet: state2.facet,
|
|
12962
|
+
text: state2.text
|
|
12963
|
+
}))
|
|
12964
|
+
});
|
|
12965
|
+
var buildLegacyMigrationInterpreterInput = (input) => [
|
|
12966
|
+
LEGACY_MIGRATION_SHADOW_INSTRUCTION,
|
|
12967
|
+
`The legacy record's Evidence is marked referenceable with id "${input.evidence.id}" and sourceRef "${input.evidence.sourceRef}". Evidence ids marked referenceable in the supplied memory context may be referenced directly. When a State cites it, reference that exact id in evidenceRefs. Do not emit another Evidence for this legacy record.`,
|
|
12968
|
+
`Imported Evidence (text is the authoritative legacy content, referenceable directly):
|
|
12969
|
+
${JSON.stringify(
|
|
12970
|
+
{
|
|
12971
|
+
...input.evidence,
|
|
12972
|
+
referenceable: true
|
|
12973
|
+
},
|
|
12974
|
+
null,
|
|
12975
|
+
2
|
|
12976
|
+
)}`,
|
|
12977
|
+
`Legacy metadata (advisory hints only, NOT vNext semantics):
|
|
12978
|
+
${JSON.stringify(
|
|
12979
|
+
{
|
|
12980
|
+
kind: input.item.kind,
|
|
12981
|
+
visibility: input.item.visibility,
|
|
12982
|
+
subjectType: input.item.subjectType,
|
|
12983
|
+
subjectId: input.item.subjectId,
|
|
12984
|
+
facet: input.item.facet,
|
|
12985
|
+
importance: input.item.importance,
|
|
12986
|
+
resident: input.item.resident
|
|
12987
|
+
},
|
|
12988
|
+
null,
|
|
12989
|
+
2
|
|
12990
|
+
)}`,
|
|
12991
|
+
`Existing vNext context for this principal (caller-supplied shadow snapshot):
|
|
12992
|
+
${serializeExisting(
|
|
12993
|
+
input.existing
|
|
12994
|
+
)}`
|
|
12995
|
+
].join("\n\n");
|
|
12996
|
+
var mergeImportedEvidence = (mutation, imported) => {
|
|
12997
|
+
const emitted = mutation.evidence ?? [];
|
|
12998
|
+
const duplicatedIds = new Set(
|
|
12999
|
+
emitted.filter(
|
|
13000
|
+
(item) => item.sourceRef === imported.sourceRef || // A re-emitted copy that drops sourceRef is still the same legacy record:
|
|
13001
|
+
// text equality is the only identity left on the wire to catch it.
|
|
13002
|
+
item.sourceRef === void 0 && item.text === imported.text
|
|
13003
|
+
).map((item) => item.id)
|
|
13004
|
+
);
|
|
13005
|
+
const rewrite = (id) => duplicatedIds.has(id) ? imported.id : id;
|
|
13006
|
+
return {
|
|
13007
|
+
...mutation,
|
|
13008
|
+
evidence: [imported, ...emitted.filter((item) => !duplicatedIds.has(item.id))],
|
|
13009
|
+
...mutation.states ? {
|
|
13010
|
+
states: mutation.states.map((state2) => ({
|
|
13011
|
+
...state2,
|
|
13012
|
+
evidenceIds: [...new Set(state2.evidenceIds.map(rewrite))]
|
|
13013
|
+
}))
|
|
13014
|
+
} : {},
|
|
13015
|
+
...mutation.relations ? {
|
|
13016
|
+
relations: mutation.relations.map((relation) => ({
|
|
13017
|
+
...relation,
|
|
13018
|
+
from: rewrite(relation.from),
|
|
13019
|
+
to: rewrite(relation.to)
|
|
13020
|
+
}))
|
|
13021
|
+
} : {}
|
|
13022
|
+
};
|
|
13023
|
+
};
|
|
13024
|
+
var runLegacyMemoryMigrationShadow = async (input) => {
|
|
13025
|
+
const principal = resolveLegacyMemoryPrincipal(input.item);
|
|
13026
|
+
const evidence = buildLegacyMemoryEvidence(input.item);
|
|
13027
|
+
const completion = await input.provider.complete(
|
|
13028
|
+
[
|
|
13029
|
+
{ role: "system", content: buildMemoryVNextInterpreterPrompt() },
|
|
13030
|
+
{
|
|
13031
|
+
role: "user",
|
|
13032
|
+
content: buildLegacyMigrationInterpreterInput({
|
|
13033
|
+
item: input.item,
|
|
13034
|
+
evidence,
|
|
13035
|
+
...input.existing ? { existing: input.existing } : {}
|
|
13036
|
+
})
|
|
13037
|
+
}
|
|
13038
|
+
],
|
|
13039
|
+
input.timeoutMs === void 0 ? void 0 : { timeoutMs: input.timeoutMs }
|
|
13040
|
+
);
|
|
13041
|
+
const parsed = parseMemoryInterpreterWireMutation(completion.content);
|
|
13042
|
+
if (!parsed.ok) {
|
|
13043
|
+
throw new Error(`legacy migration shadow: unparsable interpreter response (${parsed.error})`);
|
|
13044
|
+
}
|
|
13045
|
+
const candidate = materializeMemoryInterpreterMutation({
|
|
13046
|
+
// The principal identity (user:/space:/system:<id>) is the migration owner
|
|
13047
|
+
// space, so a space migration can never land in a user space.
|
|
13048
|
+
ownerId: evidence.ownerId,
|
|
13049
|
+
wire: parsed.value,
|
|
13050
|
+
...input.existing?.states ? { existingStates: [...input.existing.states] } : {},
|
|
13051
|
+
...input.existing?.entityIds ? { existingEntityIds: [...input.existing.entityIds] } : {},
|
|
13052
|
+
referenceableEvidenceIds: [evidence.id],
|
|
13053
|
+
...input.now === void 0 ? {} : { now: input.now },
|
|
13054
|
+
...input.nextId ? { nextId: input.nextId } : {}
|
|
13055
|
+
});
|
|
13056
|
+
const mutation = mergeImportedEvidence(candidate, evidence);
|
|
13057
|
+
return {
|
|
13058
|
+
principal,
|
|
13059
|
+
evidence,
|
|
13060
|
+
wire: parsed.value,
|
|
13061
|
+
mutation,
|
|
13062
|
+
action: mutation.action,
|
|
13063
|
+
reason: mutation.reason
|
|
13064
|
+
};
|
|
13065
|
+
};
|
|
13066
|
+
|
|
13067
|
+
// packages/ai/memory/vnext/lazyPromotion.ts
|
|
13068
|
+
var ERROR_MESSAGE_MAX2 = 120;
|
|
13069
|
+
var inFlight = /* @__PURE__ */ new Set();
|
|
13070
|
+
var shortError2 = (error) => {
|
|
13071
|
+
const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
13072
|
+
return message.length > ERROR_MESSAGE_MAX2 ? `${message.slice(0, ERROR_MESSAGE_MAX2)}\u2026` : message;
|
|
13073
|
+
};
|
|
13074
|
+
var loadExistingContext = async (db, ownerId) => {
|
|
13075
|
+
const entities = await listMemoryEntitiesVNext(db, ownerId);
|
|
13076
|
+
const states = (await Promise.all(
|
|
13077
|
+
entities.map((entity) => listMemoryStatesForEntityVNext(db, ownerId, entity.id))
|
|
13078
|
+
)).flat();
|
|
13079
|
+
return {
|
|
13080
|
+
entityIds: entities.map((entity) => entity.id),
|
|
13081
|
+
states
|
|
13082
|
+
};
|
|
13083
|
+
};
|
|
13084
|
+
var withoutImportedEvidence = (mutation, importedEvidenceId) => ({
|
|
13085
|
+
...mutation,
|
|
13086
|
+
evidence: (mutation.evidence ?? []).filter((evidence) => evidence.id !== importedEvidenceId)
|
|
13087
|
+
});
|
|
13088
|
+
var hasWrites = (mutation) => (mutation.evidence?.length ?? 0) > 0 || (mutation.entities?.length ?? 0) > 0 || (mutation.states?.length ?? 0) > 0 || (mutation.supersededStateIds?.length ?? 0) > 0 || (mutation.relations?.length ?? 0) > 0;
|
|
13089
|
+
var runMemoryVNextLazyPromotion = async (input) => {
|
|
13090
|
+
const clock = input.clock ?? (() => performance.now());
|
|
13091
|
+
const startedAt = clock();
|
|
13092
|
+
const emit = input.emit ?? ((observation) => console.info("[memory] vnext lazy promotion", {
|
|
13093
|
+
event: "memory_vnext_lazy_promotion",
|
|
13094
|
+
...observation
|
|
13095
|
+
}));
|
|
13096
|
+
const finish = (partial) => {
|
|
13097
|
+
const observation = {
|
|
13098
|
+
...partial,
|
|
13099
|
+
latencyMs: Math.round((clock() - startedAt) * 10) / 10
|
|
13100
|
+
};
|
|
13101
|
+
try {
|
|
13102
|
+
emit(observation);
|
|
13103
|
+
} catch {
|
|
13104
|
+
}
|
|
13105
|
+
return observation;
|
|
13106
|
+
};
|
|
13107
|
+
const deterministicEvidence = buildLegacyMemoryEvidence(input.item);
|
|
13108
|
+
const flightKey = `${deterministicEvidence.ownerId}\0${deterministicEvidence.id}`;
|
|
13109
|
+
if (inFlight.has(flightKey)) {
|
|
13110
|
+
return finish({ status: "in_flight" });
|
|
13111
|
+
}
|
|
13112
|
+
inFlight.add(flightKey);
|
|
13113
|
+
try {
|
|
13114
|
+
const evidenceResult = await applyLegacyMemoryEvidence(input.db, input.item);
|
|
13115
|
+
if (evidenceResult.status === "conflict") {
|
|
13116
|
+
return finish({ status: "conflict" });
|
|
13117
|
+
}
|
|
13118
|
+
const evidence = evidenceResult.evidence;
|
|
13119
|
+
const existing = await loadExistingContext(input.db, evidence.ownerId);
|
|
13120
|
+
const alreadyCovered = (existing.states ?? []).some(
|
|
13121
|
+
(state2) => !state2.retiredAt && state2.evidenceIds.includes(evidence.id)
|
|
13122
|
+
);
|
|
13123
|
+
if (alreadyCovered) {
|
|
13124
|
+
return finish({ status: "already_covered" });
|
|
13125
|
+
}
|
|
13126
|
+
const interpreted = await runLegacyMemoryMigrationShadow({
|
|
13127
|
+
item: input.item,
|
|
13128
|
+
provider: input.provider,
|
|
13129
|
+
existing,
|
|
13130
|
+
...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs },
|
|
13131
|
+
...input.now === void 0 ? {} : { now: input.now },
|
|
13132
|
+
...input.nextId ? { nextId: input.nextId } : {}
|
|
13133
|
+
});
|
|
13134
|
+
const semanticMutation = withoutImportedEvidence(interpreted.mutation, evidence.id);
|
|
13135
|
+
if (!hasWrites(semanticMutation)) {
|
|
13136
|
+
return finish({ status: "no_op", action: semanticMutation.action });
|
|
13137
|
+
}
|
|
13138
|
+
await applyMemoryInterpreterMutation(input.db, evidence.ownerId, semanticMutation);
|
|
13139
|
+
return finish({ status: "promoted", action: semanticMutation.action });
|
|
13140
|
+
} catch (error) {
|
|
13141
|
+
return finish({ status: "error", error: shortError2(error) });
|
|
13142
|
+
} finally {
|
|
13143
|
+
inFlight.delete(flightKey);
|
|
13144
|
+
}
|
|
13145
|
+
};
|
|
13146
|
+
var isMemoryVNextLazyPromotionEnabled = (env = typeof process !== "undefined" ? process.env : {}) => env.NOLO_MEMORY_VNEXT_LAZY_PROMOTION === "1" || env.NOLO_MEMORY_VNEXT_LAZY_PROMOTION === "true";
|
|
13147
|
+
|
|
12343
13148
|
// packages/ai/memory/runtime.ts
|
|
12344
13149
|
var COLD_STORAGE_CONFIDENCE = 0.3;
|
|
12345
13150
|
var MEMORY_OVERLAY_TOKEN_BUDGET = DEFAULT_MEMORY_OVERLAY_TOKEN_BUDGET;
|
|
@@ -12506,6 +13311,17 @@ var resolveMemoryRuntime = async (input) => {
|
|
|
12506
13311
|
legacyContextChars: promptBlock?.length ?? 0
|
|
12507
13312
|
});
|
|
12508
13313
|
}
|
|
13314
|
+
const promotionCandidate = selected[0];
|
|
13315
|
+
const lazyPromotionEnabled = input.vNextShadowProvider != null && isMemoryVNextLazyPromotionEnabled();
|
|
13316
|
+
if (lazyPromotionEnabled && promotionCandidate) {
|
|
13317
|
+
void runMemoryVNextLazyPromotion({
|
|
13318
|
+
db: input.db,
|
|
13319
|
+
item: promotionCandidate,
|
|
13320
|
+
provider: input.vNextShadowProvider,
|
|
13321
|
+
...input.lazyPromotionEmit ? { emit: input.lazyPromotionEmit } : {}
|
|
13322
|
+
}).catch(() => {
|
|
13323
|
+
});
|
|
13324
|
+
}
|
|
12509
13325
|
if (selected.length === 0) {
|
|
12510
13326
|
return { selectedItems: [], promptBlock: null };
|
|
12511
13327
|
}
|
package/index.js
CHANGED
|
@@ -127,7 +127,7 @@ function createDaemonShortcutCommand(path, description, command2) {
|
|
|
127
127
|
// packages/cli/agentInternalCommandEntries.ts
|
|
128
128
|
function getAgentInternalCommandEntries() {
|
|
129
129
|
const createAgentRunCommand = (path, description) => createContextCommand(path, description, async (args2, ctx) => {
|
|
130
|
-
const { runAgentRunCommand } = await import("./agentRunCommand-
|
|
130
|
+
const { runAgentRunCommand } = await import("./agentRunCommand-YJOW3VB3.js");
|
|
131
131
|
return runAgentRunCommand(args2, {
|
|
132
132
|
env: ctx.env,
|
|
133
133
|
scriptDir: ctx.scriptDir,
|
|
@@ -883,7 +883,7 @@ async function runScript(script, forwardedArgs, env) {
|
|
|
883
883
|
return proc.exited;
|
|
884
884
|
}
|
|
885
885
|
async function launchTuiWorkspace(args2) {
|
|
886
|
-
const { startTuiWorkspace } = await import("./readlineWorkspace-
|
|
886
|
+
const { startTuiWorkspace } = await import("./readlineWorkspace-2RP77YDN.js");
|
|
887
887
|
const { createTuiSummaryLlmCaller } = await import("./tuiSummaryLlmCaller-T2OA5ZVB.js");
|
|
888
888
|
return startTuiWorkspace({
|
|
889
889
|
...args2,
|
package/package.json
CHANGED