@mastra/libsql 1.26.0-alpha.3 → 1.26.1-alpha.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.
- package/dist/_types/@internal_core/dist/memory/index.d.ts +102 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +679 -465
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +679 -465
- package/dist/index.js.map +1 -1
- package/dist/shared/single-connection-client.d.ts +1 -1
- package/dist/shared/single-connection-client.d.ts.map +1 -1
- package/dist/storage/db/client.d.ts +2 -0
- package/dist/storage/db/client.d.ts.map +1 -1
- package/dist/storage/db/index.d.ts +6 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +3 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -373,7 +373,7 @@ function isSingleConnectionDatabase({ url, syncUrl }) {
|
|
|
373
373
|
* transactions rather than failing with `TRANSACTION_ACTIVE`.
|
|
374
374
|
*
|
|
375
375
|
* `transaction()` takes the gate and releases it when the transaction commits,
|
|
376
|
-
* rolls back, or closes. `execute`, `batch`, `executeMultiple`, and `
|
|
376
|
+
* rolls back, or closes. `execute`, `batch`, `executeMultiple`, `migrate`, and `sync`
|
|
377
377
|
* wait for the gate to be free before running but do not hold it — the driver
|
|
378
378
|
* executes them synchronously on the connection, so they cannot interleave
|
|
379
379
|
* with each other. Every other member passes through untouched.
|
|
@@ -424,7 +424,8 @@ function gateSingleConnectionClient(client) {
|
|
|
424
424
|
case "execute":
|
|
425
425
|
case "batch":
|
|
426
426
|
case "executeMultiple":
|
|
427
|
-
case "migrate":
|
|
427
|
+
case "migrate":
|
|
428
|
+
case "sync": return (...args) => waitForGate(() => target[prop].apply(target, args));
|
|
428
429
|
default: {
|
|
429
430
|
const value = Reflect.get(target, prop);
|
|
430
431
|
return typeof value === "function" ? value.bind(target) : value;
|
|
@@ -9287,6 +9288,92 @@ var MCPServersLibSQL = class extends MCPServersStorage {
|
|
|
9287
9288
|
}
|
|
9288
9289
|
};
|
|
9289
9290
|
//#endregion
|
|
9291
|
+
//#region ../../packages/_internal-core/dist/memory/index.js
|
|
9292
|
+
/**
|
|
9293
|
+
* Shared rules for observational memory lifecycle writes. Every storage adapter applies
|
|
9294
|
+
* these inside its own atomic section (lock, transaction, or conditional update), so the
|
|
9295
|
+
* decisions are identical across adapters.
|
|
9296
|
+
*/
|
|
9297
|
+
/**
|
|
9298
|
+
* Observational memory columns that lifecycle writes depend on. Storage adapters merge these
|
|
9299
|
+
* into the table schema they get from `@mastra/core`, so the columns exist even when the
|
|
9300
|
+
* installed core predates them.
|
|
9301
|
+
*/
|
|
9302
|
+
const OBSERVATIONAL_MEMORY_LIFECYCLE_COLUMNS = { supersededBy: {
|
|
9303
|
+
type: "text",
|
|
9304
|
+
nullable: true
|
|
9305
|
+
} };
|
|
9306
|
+
/** `schema` plus {@link OBSERVATIONAL_MEMORY_LIFECYCLE_COLUMNS}; `undefined` when `schema` is. */
|
|
9307
|
+
function withObservationalMemoryLifecycleColumns(schema) {
|
|
9308
|
+
return schema ? {
|
|
9309
|
+
...schema,
|
|
9310
|
+
...OBSERVATIONAL_MEMORY_LIFECYCLE_COLUMNS
|
|
9311
|
+
} : void 0;
|
|
9312
|
+
}
|
|
9313
|
+
/**
|
|
9314
|
+
* A buffered chunk stores `lastObservedAt = max message time + 1ms`. It is wholly covered
|
|
9315
|
+
* (every message it observed is already at or before the cursor) iff
|
|
9316
|
+
* `cursor >= chunk.lastObservedAt - 1ms`.
|
|
9317
|
+
*/
|
|
9318
|
+
function isBufferedChunkCoveredByCursor(chunkLastObservedAt, cursor) {
|
|
9319
|
+
if (!cursor) return false;
|
|
9320
|
+
return new Date(cursor).getTime() >= new Date(chunkLastObservedAt).getTime() - 1;
|
|
9321
|
+
}
|
|
9322
|
+
/** The later of two cursors; `undefined` only when both are absent. */
|
|
9323
|
+
function maxObservationCursor(a, b) {
|
|
9324
|
+
if (!a) return b ? new Date(b) : void 0;
|
|
9325
|
+
if (!b) return new Date(a);
|
|
9326
|
+
return new Date(Math.max(new Date(a).getTime(), new Date(b).getTime()));
|
|
9327
|
+
}
|
|
9328
|
+
/**
|
|
9329
|
+
* Decide the new generation's text when a reflection built from `snapshot` commits against
|
|
9330
|
+
* the stored record.
|
|
9331
|
+
*
|
|
9332
|
+
* - Stored text equals the snapshot: the reflection replaces it.
|
|
9333
|
+
* - Stored text extends the snapshot (activation only appends): the appended tail is kept
|
|
9334
|
+
* after the reflection, and its tokens are added.
|
|
9335
|
+
* - Anything else (a non-append rewrite): `null` — the reflection must not be applied.
|
|
9336
|
+
*/
|
|
9337
|
+
function planReflectionGenerationText(input) {
|
|
9338
|
+
const stored = input.storedObservations ?? "";
|
|
9339
|
+
const snapshot = input.snapshotObservations ?? "";
|
|
9340
|
+
if (stored === snapshot) return {
|
|
9341
|
+
mode: "equal",
|
|
9342
|
+
observations: input.reflection,
|
|
9343
|
+
tokenCount: input.tokenCount
|
|
9344
|
+
};
|
|
9345
|
+
if (!stored.startsWith(snapshot)) return null;
|
|
9346
|
+
const tail = stored.slice(snapshot.length).trimStart();
|
|
9347
|
+
if (!tail.trim()) return {
|
|
9348
|
+
mode: "equal",
|
|
9349
|
+
observations: input.reflection,
|
|
9350
|
+
tokenCount: input.tokenCount
|
|
9351
|
+
};
|
|
9352
|
+
return {
|
|
9353
|
+
mode: "append",
|
|
9354
|
+
observations: input.reflection ? `${input.reflection}\n\n${tail}` : tail,
|
|
9355
|
+
tokenCount: input.tokenCount + Math.max(0, (input.storedObservationTokenCount ?? 0) - (input.snapshotObservationTokenCount ?? 0))
|
|
9356
|
+
};
|
|
9357
|
+
}
|
|
9358
|
+
/**
|
|
9359
|
+
* Backs `updateActiveObservations` in adapters that implement `commitActiveObservations`.
|
|
9360
|
+
* Callers of `updateActiveObservations` (which resolves `void`) can't see a commit result, so a
|
|
9361
|
+
* write that was not applied throws instead of resolving as if it had committed.
|
|
9362
|
+
*/
|
|
9363
|
+
function assertActiveObservationsApplied(result, id) {
|
|
9364
|
+
if (result.applied) return;
|
|
9365
|
+
throw new Error(result.reason === "retired" ? `Observational memory record ${id} was superseded by a newer generation; observations were not written` : `Observational memory record ${id} changed since the observations were composed; observations were not written`);
|
|
9366
|
+
}
|
|
9367
|
+
/**
|
|
9368
|
+
* Whether the stored text can still accept a reflection built from `snapshot`
|
|
9369
|
+
* (equal, or only appended to since).
|
|
9370
|
+
*/
|
|
9371
|
+
function isAppendOnlySince(storedObservations, snapshotObservations) {
|
|
9372
|
+
const stored = storedObservations ?? "";
|
|
9373
|
+
const snapshot = snapshotObservations ?? "";
|
|
9374
|
+
return stored === snapshot || stored.startsWith(snapshot);
|
|
9375
|
+
}
|
|
9376
|
+
//#endregion
|
|
9290
9377
|
//#region src/storage/domains/memory/index.ts
|
|
9291
9378
|
/**
|
|
9292
9379
|
* Local constant for the observational memory table name.
|
|
@@ -9294,6 +9381,13 @@ var MCPServersLibSQL = class extends MCPServersStorage {
|
|
|
9294
9381
|
* versions that don't export TABLE_OBSERVATIONAL_MEMORY.
|
|
9295
9382
|
*/
|
|
9296
9383
|
const OM_TABLE = "mastra_observational_memory";
|
|
9384
|
+
/** Canonical head order: newest generation, then earliest createdAt, then lowest id. */
|
|
9385
|
+
const OM_HEAD_ORDER = `"generationCount" DESC, "createdAt" ASC, id ASC`;
|
|
9386
|
+
/** Lifecycle writes aimed at a retired record follow `supersededBy` to the head at most this many times. */
|
|
9387
|
+
const OM_MAX_HEAD_HOPS = 3;
|
|
9388
|
+
/** Optimistic lifecycle writes rerun at most this many times when another process changes the row. */
|
|
9389
|
+
const OM_MAX_CAS_ATTEMPTS = 10;
|
|
9390
|
+
const OM_CAS_CONFLICT = Symbol("om-cas-conflict");
|
|
9297
9391
|
function addSqliteMetadataFilter(conditions, params, metadataFilter) {
|
|
9298
9392
|
if (!metadataFilter) return;
|
|
9299
9393
|
for (const [key, value] of Object.entries(metadataFilter)) {
|
|
@@ -9359,11 +9453,13 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
9359
9453
|
}
|
|
9360
9454
|
};
|
|
9361
9455
|
#client;
|
|
9456
|
+
#embeddedReplica;
|
|
9362
9457
|
#db;
|
|
9363
9458
|
constructor(config) {
|
|
9364
9459
|
super();
|
|
9365
9460
|
const client = resolveClient(config);
|
|
9366
9461
|
this.#client = client;
|
|
9462
|
+
this.#embeddedReplica = config.embeddedReplica === true;
|
|
9367
9463
|
this.#db = new LibSQLDB({
|
|
9368
9464
|
client,
|
|
9369
9465
|
maxRetries: config.maxRetries,
|
|
@@ -9402,7 +9498,7 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
9402
9498
|
tableName: TABLE_MEMORY_RUN_FENCES,
|
|
9403
9499
|
schema: RUN_FENCING_TABLE_SCHEMAS[TABLE_MEMORY_RUN_FENCES]
|
|
9404
9500
|
});
|
|
9405
|
-
const omSchema = OBSERVATIONAL_MEMORY_TABLE_SCHEMA?.[OM_TABLE];
|
|
9501
|
+
const omSchema = withObservationalMemoryLifecycleColumns(OBSERVATIONAL_MEMORY_TABLE_SCHEMA?.[OM_TABLE]);
|
|
9406
9502
|
if (omSchema) {
|
|
9407
9503
|
await this.#db.createTable({
|
|
9408
9504
|
tableName: OM_TABLE,
|
|
@@ -9426,7 +9522,8 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
9426
9522
|
"isBufferingReflection",
|
|
9427
9523
|
"lastBufferedAtTokens",
|
|
9428
9524
|
"lastBufferedAtTime",
|
|
9429
|
-
"metadata"
|
|
9525
|
+
"metadata",
|
|
9526
|
+
"supersededBy"
|
|
9430
9527
|
]
|
|
9431
9528
|
});
|
|
9432
9529
|
}
|
|
@@ -9442,10 +9539,13 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
9442
9539
|
sql: `CREATE INDEX IF NOT EXISTS idx_messages_thread_resource_created_at ON ${TABLE_MESSAGES} (thread_id, "resourceId", "createdAt")`,
|
|
9443
9540
|
args: []
|
|
9444
9541
|
}], "write");
|
|
9445
|
-
if (omSchema)
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9542
|
+
if (omSchema) {
|
|
9543
|
+
await this.#client.execute({
|
|
9544
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_om_lookup_key ON "${OM_TABLE}" ("lookupKey")`,
|
|
9545
|
+
args: []
|
|
9546
|
+
});
|
|
9547
|
+
await this.#backfillSupersededBy();
|
|
9548
|
+
}
|
|
9449
9549
|
}
|
|
9450
9550
|
async dangerouslyClearAll() {
|
|
9451
9551
|
await this.init();
|
|
@@ -10579,18 +10679,218 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10579
10679
|
config: row.config ? JSON.parse(row.config) : {},
|
|
10580
10680
|
metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
|
|
10581
10681
|
observedMessageIds: row.observedMessageIds ? JSON.parse(row.observedMessageIds) : void 0,
|
|
10582
|
-
observedTimezone: row.observedTimezone || void 0
|
|
10682
|
+
observedTimezone: row.observedTimezone || void 0,
|
|
10683
|
+
supersededBy: row.supersededBy ?? null
|
|
10583
10684
|
};
|
|
10584
10685
|
}
|
|
10686
|
+
/**
|
|
10687
|
+
* Runs one optimistic lifecycle write under the client write lock (in-process ordering).
|
|
10688
|
+
* `attempt` reads the rows it needs, then writes with statements guarded by those reads
|
|
10689
|
+
* (`#readOMRow`'s guard); it returns `OM_CAS_CONFLICT` when a guard matched no row because
|
|
10690
|
+
* another process changed the row in between, and the attempt reruns on fresh state.
|
|
10691
|
+
*
|
|
10692
|
+
* No interactive transaction is held across `await`s: the `libsql` driver is synchronous, so
|
|
10693
|
+
* an open write transaction makes any other connection's write in this process block the
|
|
10694
|
+
* event loop until `busy_timeout` (SQLITE_BUSY). Each statement or batch here runs in one call.
|
|
10695
|
+
*
|
|
10696
|
+
* With `fencedOperation`, a write made inside a run fence scope is fenced: each attempt first
|
|
10697
|
+
* checks the run's claim, and the attempt's reads put the claim into their guards, so a claim
|
|
10698
|
+
* taken over between the check and the write turns the write into a conflict and the next
|
|
10699
|
+
* attempt's check rejects it.
|
|
10700
|
+
*/
|
|
10701
|
+
async #withOMCas(operation, attempt, fencedOperation) {
|
|
10702
|
+
const check = fencedOperation ? this.#runFenceCheck(void 0, fencedOperation) : void 0;
|
|
10703
|
+
return this.#write(operation, async () => {
|
|
10704
|
+
for (let i = 0; i < OM_MAX_CAS_ATTEMPTS; i++) {
|
|
10705
|
+
if (check) await assertRunFence(this.#client, check);
|
|
10706
|
+
const result = await attempt(i, check);
|
|
10707
|
+
if (result !== OM_CAS_CONFLICT) return result;
|
|
10708
|
+
if (this.#embeddedReplica) await this.#client.sync?.();
|
|
10709
|
+
}
|
|
10710
|
+
throw new MastraError({
|
|
10711
|
+
id: createStorageErrorId("LIBSQL", operation, "CONFLICT"),
|
|
10712
|
+
text: `Observational memory write kept conflicting with concurrent writers (${OM_MAX_CAS_ATTEMPTS} attempts)`,
|
|
10713
|
+
domain: ErrorDomain.STORAGE,
|
|
10714
|
+
category: ErrorCategory.THIRD_PARTY
|
|
10715
|
+
});
|
|
10716
|
+
});
|
|
10717
|
+
}
|
|
10718
|
+
/**
|
|
10719
|
+
* Whether a missing row may only be missing from this embedded replica's local copy: the first
|
|
10720
|
+
* attempt reads before any sync, so it returns a conflict to sync and read again instead of
|
|
10721
|
+
* acting on the absence.
|
|
10722
|
+
*/
|
|
10723
|
+
#mayBeUnsynced(attemptIndex) {
|
|
10724
|
+
return this.#embeddedReplica && attemptIndex === 0;
|
|
10725
|
+
}
|
|
10726
|
+
/**
|
|
10727
|
+
* With `check`, the guard also requires the run's claim to still match it, so a guarded write
|
|
10728
|
+
* made after the claim was taken over matches no row.
|
|
10729
|
+
*/
|
|
10730
|
+
#toOMRow(result, check) {
|
|
10731
|
+
const row = result.rows?.[0];
|
|
10732
|
+
if (!row) return null;
|
|
10733
|
+
const columns = result.columns;
|
|
10734
|
+
const guard = {
|
|
10735
|
+
sql: columns.map((c) => `"${c}" IS ?`).join(" AND "),
|
|
10736
|
+
args: columns.map((c) => row[c])
|
|
10737
|
+
};
|
|
10738
|
+
if (check) {
|
|
10739
|
+
guard.sql += ` AND EXISTS (SELECT 1 FROM ${check.claimsTable} WHERE runId = ? AND generation = ? AND ownerId = ?)`;
|
|
10740
|
+
guard.args.push(check.fence.runId, check.fence.generation, check.fence.ownerId);
|
|
10741
|
+
}
|
|
10742
|
+
return {
|
|
10743
|
+
record: this.parseOMRow(row),
|
|
10744
|
+
guard
|
|
10745
|
+
};
|
|
10746
|
+
}
|
|
10747
|
+
async #readOMRow(id, check) {
|
|
10748
|
+
return this.#toOMRow(await this.#client.execute({
|
|
10749
|
+
sql: `SELECT * FROM "${OM_TABLE}" WHERE id = ?`,
|
|
10750
|
+
args: [id]
|
|
10751
|
+
}), check);
|
|
10752
|
+
}
|
|
10753
|
+
async #readOMHeadRow(lookupKey, check) {
|
|
10754
|
+
return this.#toOMRow(await this.#client.execute({
|
|
10755
|
+
sql: `SELECT * FROM "${OM_TABLE}" WHERE "lookupKey" = ? ORDER BY ${OM_HEAD_ORDER} LIMIT 1`,
|
|
10756
|
+
args: [lookupKey]
|
|
10757
|
+
}), check);
|
|
10758
|
+
}
|
|
10759
|
+
/** The live row a lifecycle write aimed at `row` lands on: the row itself while live, otherwise the head. */
|
|
10760
|
+
async #resolveLiveOMRow(row, check) {
|
|
10761
|
+
let current = row;
|
|
10762
|
+
for (let hop = 0; current.record.supersededBy; hop++) {
|
|
10763
|
+
const head = hop < OM_MAX_HEAD_HOPS ? await this.#readOMHeadRow(this.getOMKey(current.record.threadId, current.record.resourceId), check) : null;
|
|
10764
|
+
if (!head || head.record.id === current.record.id) throw new MastraError({
|
|
10765
|
+
id: createStorageErrorId("LIBSQL", "RESOLVE_OBSERVATIONAL_MEMORY_HEAD", "FAILED"),
|
|
10766
|
+
text: `Observational memory record ${row.record.id} is superseded but no live head was found`,
|
|
10767
|
+
domain: ErrorDomain.STORAGE,
|
|
10768
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
10769
|
+
details: { id: row.record.id }
|
|
10770
|
+
});
|
|
10771
|
+
current = head;
|
|
10772
|
+
}
|
|
10773
|
+
return current;
|
|
10774
|
+
}
|
|
10775
|
+
/**
|
|
10776
|
+
* Retire every live row of a lookup key that sorts after the canonical head, marking it
|
|
10777
|
+
* superseded by the head. Rows retired by older adapter versions (which never set
|
|
10778
|
+
* `supersededBy`) become frozen. One statement: the head it computes and the rows it retires
|
|
10779
|
+
* are read under the same SQLite write lock, so a concurrent rollover cannot leave a key
|
|
10780
|
+
* without a live row.
|
|
10781
|
+
*/
|
|
10782
|
+
async #backfillSupersededBy() {
|
|
10783
|
+
const headOf = `(SELECT h.id FROM "${OM_TABLE}" h WHERE h."lookupKey" = "${OM_TABLE}"."lookupKey" ORDER BY ${OM_HEAD_ORDER} LIMIT 1)`;
|
|
10784
|
+
const duplicated = `SELECT "lookupKey" FROM "${OM_TABLE}" WHERE "supersededBy" IS NULL GROUP BY "lookupKey" HAVING COUNT(*) > 1`;
|
|
10785
|
+
if (!(await this.#client.execute({
|
|
10786
|
+
sql: duplicated,
|
|
10787
|
+
args: []
|
|
10788
|
+
})).rows?.length) return;
|
|
10789
|
+
await this.#write("backfillSupersededBy", () => this.#client.execute({
|
|
10790
|
+
sql: `UPDATE "${OM_TABLE}" SET "supersededBy" = ${headOf}
|
|
10791
|
+
WHERE "supersededBy" IS NULL AND "lookupKey" IN (${duplicated}) AND id <> ${headOf}`,
|
|
10792
|
+
args: []
|
|
10793
|
+
}));
|
|
10794
|
+
}
|
|
10795
|
+
/**
|
|
10796
|
+
* Create the next generation from the stored (live) row and retire it in one atomic batch,
|
|
10797
|
+
* guarded by the row as read. Buffered chunks move to the new generation (in order); the
|
|
10798
|
+
* cursor, buffering markers, flags, counters, config, and metadata carry over; buffered
|
|
10799
|
+
* reflection state does not (it is cleared on the retired row). Returns `OM_CAS_CONFLICT`
|
|
10800
|
+
* when the row changed since it was read.
|
|
10801
|
+
*/
|
|
10802
|
+
async #rollOverObservationalMemory(storedRow, observations, tokenCount, newRecordId) {
|
|
10803
|
+
const stored = storedRow.record;
|
|
10804
|
+
const id = newRecordId ?? crypto.randomUUID();
|
|
10805
|
+
const now = /* @__PURE__ */ new Date();
|
|
10806
|
+
const chunks = Array.isArray(stored.bufferedObservationChunks) ? stored.bufferedObservationChunks : [];
|
|
10807
|
+
const lookupKey = this.getOMKey(stored.threadId, stored.resourceId);
|
|
10808
|
+
const record = {
|
|
10809
|
+
id,
|
|
10810
|
+
scope: stored.scope,
|
|
10811
|
+
threadId: stored.threadId,
|
|
10812
|
+
resourceId: stored.resourceId,
|
|
10813
|
+
createdAt: now,
|
|
10814
|
+
updatedAt: now,
|
|
10815
|
+
lastObservedAt: stored.lastObservedAt,
|
|
10816
|
+
originType: "reflection",
|
|
10817
|
+
generationCount: stored.generationCount + 1,
|
|
10818
|
+
activeObservations: observations,
|
|
10819
|
+
bufferedObservationChunks: chunks.length > 0 ? chunks : void 0,
|
|
10820
|
+
totalTokensObserved: stored.totalTokensObserved,
|
|
10821
|
+
observationTokenCount: tokenCount,
|
|
10822
|
+
pendingMessageTokens: stored.pendingMessageTokens,
|
|
10823
|
+
isReflecting: false,
|
|
10824
|
+
isObserving: false,
|
|
10825
|
+
isBufferingObservation: stored.isBufferingObservation,
|
|
10826
|
+
isBufferingReflection: false,
|
|
10827
|
+
lastBufferedAtTokens: stored.lastBufferedAtTokens,
|
|
10828
|
+
lastBufferedAtTime: stored.lastBufferedAtTime,
|
|
10829
|
+
config: stored.config,
|
|
10830
|
+
metadata: stored.metadata,
|
|
10831
|
+
observedTimezone: stored.observedTimezone,
|
|
10832
|
+
supersededBy: null
|
|
10833
|
+
};
|
|
10834
|
+
const [retired] = await this.#client.batch([{
|
|
10835
|
+
sql: `UPDATE "${OM_TABLE}" SET "supersededBy" = ?, "bufferedObservationChunks" = NULL,
|
|
10836
|
+
"bufferedReflection" = NULL, "bufferedReflectionTokens" = NULL,
|
|
10837
|
+
"bufferedReflectionInputTokens" = NULL, "reflectedObservationLineCount" = NULL, "updatedAt" = ?
|
|
10838
|
+
WHERE id = ? AND ${storedRow.guard.sql}`,
|
|
10839
|
+
args: [
|
|
10840
|
+
id,
|
|
10841
|
+
now.toISOString(),
|
|
10842
|
+
stored.id,
|
|
10843
|
+
...storedRow.guard.args
|
|
10844
|
+
]
|
|
10845
|
+
}, {
|
|
10846
|
+
sql: `INSERT INTO "${OM_TABLE}" (
|
|
10847
|
+
id, "lookupKey", scope, "resourceId", "threadId",
|
|
10848
|
+
"activeObservations", "activeObservationsPendingUpdate",
|
|
10849
|
+
"originType", config, "generationCount", "lastObservedAt", "lastReflectionAt",
|
|
10850
|
+
"pendingMessageTokens", "totalTokensObserved", "observationTokenCount",
|
|
10851
|
+
"bufferedObservationChunks",
|
|
10852
|
+
"isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
|
|
10853
|
+
"observedTimezone", metadata, "supersededBy", "createdAt", "updatedAt"
|
|
10854
|
+
) SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
10855
|
+
WHERE EXISTS (SELECT 1 FROM "${OM_TABLE}" WHERE id = ? AND "supersededBy" = ?)`,
|
|
10856
|
+
args: [
|
|
10857
|
+
id,
|
|
10858
|
+
lookupKey,
|
|
10859
|
+
record.scope,
|
|
10860
|
+
record.resourceId,
|
|
10861
|
+
record.threadId || null,
|
|
10862
|
+
observations,
|
|
10863
|
+
null,
|
|
10864
|
+
"reflection",
|
|
10865
|
+
JSON.stringify(record.config),
|
|
10866
|
+
record.generationCount,
|
|
10867
|
+
record.lastObservedAt ? record.lastObservedAt.toISOString() : null,
|
|
10868
|
+
now.toISOString(),
|
|
10869
|
+
record.pendingMessageTokens,
|
|
10870
|
+
record.totalTokensObserved,
|
|
10871
|
+
record.observationTokenCount,
|
|
10872
|
+
chunks.length > 0 ? JSON.stringify(chunks) : null,
|
|
10873
|
+
false,
|
|
10874
|
+
false,
|
|
10875
|
+
record.isBufferingObservation,
|
|
10876
|
+
false,
|
|
10877
|
+
record.lastBufferedAtTokens,
|
|
10878
|
+
record.lastBufferedAtTime ? new Date(record.lastBufferedAtTime).toISOString() : null,
|
|
10879
|
+
record.observedTimezone || null,
|
|
10880
|
+
record.metadata ? JSON.stringify(record.metadata) : null,
|
|
10881
|
+
null,
|
|
10882
|
+
now.toISOString(),
|
|
10883
|
+
now.toISOString(),
|
|
10884
|
+
stored.id,
|
|
10885
|
+
id
|
|
10886
|
+
]
|
|
10887
|
+
}], "write");
|
|
10888
|
+
return retired.rowsAffected === 1 ? record : OM_CAS_CONFLICT;
|
|
10889
|
+
}
|
|
10585
10890
|
async getObservationalMemory(threadId, resourceId) {
|
|
10586
10891
|
try {
|
|
10587
10892
|
const lookupKey = this.getOMKey(threadId, resourceId);
|
|
10588
|
-
|
|
10589
|
-
sql: `SELECT * FROM "${OM_TABLE}" WHERE "lookupKey" = ? ORDER BY "generationCount" DESC LIMIT 1`,
|
|
10590
|
-
args: [lookupKey]
|
|
10591
|
-
});
|
|
10592
|
-
if (!result.rows || result.rows.length === 0) return null;
|
|
10593
|
-
return this.parseOMRow(result.rows[0]);
|
|
10893
|
+
return (await this.#readOMHeadRow(lookupKey))?.record ?? null;
|
|
10594
10894
|
} catch (error) {
|
|
10595
10895
|
throw new MastraError({
|
|
10596
10896
|
id: createStorageErrorId("LIBSQL", "GET_OBSERVATIONAL_MEMORY", "FAILED"),
|
|
@@ -10664,9 +10964,9 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10664
10964
|
}
|
|
10665
10965
|
async initializeObservationalMemory(input) {
|
|
10666
10966
|
try {
|
|
10967
|
+
const lookupKey = this.getOMKey(input.threadId, input.resourceId);
|
|
10667
10968
|
const id = crypto.randomUUID();
|
|
10668
10969
|
const now = /* @__PURE__ */ new Date();
|
|
10669
|
-
const lookupKey = this.getOMKey(input.threadId, input.resourceId);
|
|
10670
10970
|
const record = {
|
|
10671
10971
|
id,
|
|
10672
10972
|
scope: input.scope,
|
|
@@ -10688,45 +10988,52 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10688
10988
|
lastBufferedAtTokens: 0,
|
|
10689
10989
|
lastBufferedAtTime: null,
|
|
10690
10990
|
config: input.config,
|
|
10691
|
-
observedTimezone: input.observedTimezone
|
|
10991
|
+
observedTimezone: input.observedTimezone,
|
|
10992
|
+
supersededBy: null
|
|
10692
10993
|
};
|
|
10693
|
-
await this.#
|
|
10694
|
-
|
|
10994
|
+
return await this.#withOMCas("INITIALIZE_OBSERVATIONAL_MEMORY", async () => {
|
|
10995
|
+
const existing = (await this.#readOMHeadRow(lookupKey))?.record ?? null;
|
|
10996
|
+
if (existing) return existing;
|
|
10997
|
+
if ((await this.#client.execute({
|
|
10998
|
+
sql: `INSERT INTO "${OM_TABLE}" (
|
|
10695
10999
|
id, "lookupKey", scope, "resourceId", "threadId",
|
|
10696
11000
|
"activeObservations", "activeObservationsPendingUpdate",
|
|
10697
11001
|
"originType", config, "generationCount", "lastObservedAt", "lastReflectionAt",
|
|
10698
11002
|
"pendingMessageTokens", "totalTokensObserved", "observationTokenCount",
|
|
10699
11003
|
"isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
|
|
10700
11004
|
"observedTimezone", "createdAt", "updatedAt"
|
|
10701
|
-
)
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
11005
|
+
) SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
11006
|
+
WHERE NOT EXISTS (SELECT 1 FROM "${OM_TABLE}" WHERE "lookupKey" = ? AND "supersededBy" IS NULL)`,
|
|
11007
|
+
args: [
|
|
11008
|
+
id,
|
|
11009
|
+
lookupKey,
|
|
11010
|
+
input.scope,
|
|
11011
|
+
input.resourceId,
|
|
11012
|
+
input.threadId || null,
|
|
11013
|
+
"",
|
|
11014
|
+
null,
|
|
11015
|
+
"initial",
|
|
11016
|
+
JSON.stringify(input.config),
|
|
11017
|
+
0,
|
|
11018
|
+
null,
|
|
11019
|
+
null,
|
|
11020
|
+
0,
|
|
11021
|
+
0,
|
|
11022
|
+
0,
|
|
11023
|
+
false,
|
|
11024
|
+
false,
|
|
11025
|
+
false,
|
|
11026
|
+
false,
|
|
11027
|
+
0,
|
|
11028
|
+
null,
|
|
11029
|
+
input.observedTimezone || null,
|
|
11030
|
+
now.toISOString(),
|
|
11031
|
+
now.toISOString(),
|
|
11032
|
+
lookupKey
|
|
11033
|
+
]
|
|
11034
|
+
})).rowsAffected === 1) return record;
|
|
11035
|
+
return (await this.#readOMHeadRow(lookupKey))?.record ?? OM_CAS_CONFLICT;
|
|
11036
|
+
});
|
|
10730
11037
|
} catch (error) {
|
|
10731
11038
|
throw new MastraError({
|
|
10732
11039
|
id: createStorageErrorId("LIBSQL", "INITIALIZE_OBSERVATIONAL_MEMORY", "FAILED"),
|
|
@@ -10753,8 +11060,8 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10753
11060
|
"reflectedObservationLineCount",
|
|
10754
11061
|
"isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection",
|
|
10755
11062
|
"lastBufferedAtTokens", "lastBufferedAtTime",
|
|
10756
|
-
"observedTimezone", metadata, "createdAt", "updatedAt"
|
|
10757
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11063
|
+
"observedTimezone", metadata, "supersededBy", "createdAt", "updatedAt"
|
|
11064
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
10758
11065
|
args: [
|
|
10759
11066
|
record.id,
|
|
10760
11067
|
lookupKey,
|
|
@@ -10785,6 +11092,7 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10785
11092
|
record.lastBufferedAtTime ? record.lastBufferedAtTime.toISOString() : null,
|
|
10786
11093
|
record.observedTimezone || null,
|
|
10787
11094
|
record.metadata ? JSON.stringify(record.metadata) : null,
|
|
11095
|
+
record.supersededBy ?? null,
|
|
10788
11096
|
record.createdAt.toISOString(),
|
|
10789
11097
|
record.updatedAt.toISOString()
|
|
10790
11098
|
]
|
|
@@ -10803,11 +11111,36 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10803
11111
|
}
|
|
10804
11112
|
}
|
|
10805
11113
|
async updateActiveObservations(input) {
|
|
11114
|
+
assertActiveObservationsApplied(await this.commitActiveObservations(input), input.id);
|
|
11115
|
+
}
|
|
11116
|
+
async commitActiveObservations(input) {
|
|
10806
11117
|
try {
|
|
10807
11118
|
const now = /* @__PURE__ */ new Date();
|
|
10808
11119
|
const observedMessageIdsJson = input.observedMessageIds ? JSON.stringify(input.observedMessageIds) : null;
|
|
10809
|
-
|
|
10810
|
-
|
|
11120
|
+
return await this.#withOMCas("UPDATE_ACTIVE_OBSERVATIONS", async (attemptIndex, check) => {
|
|
11121
|
+
const row = await this.#readOMRow(input.id, check);
|
|
11122
|
+
if (!row) {
|
|
11123
|
+
if (this.#mayBeUnsynced(attemptIndex)) return OM_CAS_CONFLICT;
|
|
11124
|
+
throw new MastraError({
|
|
11125
|
+
id: createStorageErrorId("LIBSQL", "UPDATE_ACTIVE_OBSERVATIONS", "NOT_FOUND"),
|
|
11126
|
+
text: `Observational memory record not found: ${input.id}`,
|
|
11127
|
+
domain: ErrorDomain.STORAGE,
|
|
11128
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
11129
|
+
details: { id: input.id }
|
|
11130
|
+
});
|
|
11131
|
+
}
|
|
11132
|
+
const stored = row.record;
|
|
11133
|
+
if (stored.supersededBy) return {
|
|
11134
|
+
applied: false,
|
|
11135
|
+
reason: "retired"
|
|
11136
|
+
};
|
|
11137
|
+
if (input.expectedActiveObservations !== void 0 && input.expectedActiveObservations !== stored.activeObservations) return {
|
|
11138
|
+
applied: false,
|
|
11139
|
+
reason: "conflict"
|
|
11140
|
+
};
|
|
11141
|
+
const lastObservedAt = maxObservationCursor(stored.lastObservedAt, input.lastObservedAt);
|
|
11142
|
+
return (await this.#client.execute({
|
|
11143
|
+
sql: `UPDATE "${OM_TABLE}" SET
|
|
10811
11144
|
"activeObservations" = ?,
|
|
10812
11145
|
"lastObservedAt" = ?,
|
|
10813
11146
|
"pendingMessageTokens" = 0,
|
|
@@ -10815,23 +11148,19 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10815
11148
|
"totalTokensObserved" = "totalTokensObserved" + ?,
|
|
10816
11149
|
"observedMessageIds" = ?,
|
|
10817
11150
|
"updatedAt" = ?
|
|
10818
|
-
WHERE id =
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
10828
|
-
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
domain: ErrorDomain.STORAGE,
|
|
10832
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
10833
|
-
details: { id: input.id }
|
|
10834
|
-
});
|
|
11151
|
+
WHERE id = ? AND ${row.guard.sql}`,
|
|
11152
|
+
args: [
|
|
11153
|
+
input.observations,
|
|
11154
|
+
lastObservedAt.toISOString(),
|
|
11155
|
+
input.tokenCount,
|
|
11156
|
+
input.tokenCount,
|
|
11157
|
+
observedMessageIdsJson,
|
|
11158
|
+
now.toISOString(),
|
|
11159
|
+
input.id,
|
|
11160
|
+
...row.guard.args
|
|
11161
|
+
]
|
|
11162
|
+
})).rowsAffected === 1 ? { applied: true } : OM_CAS_CONFLICT;
|
|
11163
|
+
}, "commitActiveObservations");
|
|
10835
11164
|
} catch (error) {
|
|
10836
11165
|
if (error instanceof MastraError) throw error;
|
|
10837
11166
|
throw new MastraError({
|
|
@@ -10844,19 +11173,23 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10844
11173
|
}
|
|
10845
11174
|
async createReflectionGeneration(input) {
|
|
10846
11175
|
try {
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
const
|
|
10850
|
-
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
11176
|
+
return await this.#withOMCas("CREATE_REFLECTION_GENERATION", async (attemptIndex, check) => {
|
|
11177
|
+
const { currentRecord } = input;
|
|
11178
|
+
const row = await this.#readOMRow(currentRecord.id, check);
|
|
11179
|
+
if (!row) return this.#mayBeUnsynced(attemptIndex) ? OM_CAS_CONFLICT : currentRecord;
|
|
11180
|
+
const stored = row.record;
|
|
11181
|
+
if (stored.supersededBy) return (await this.#resolveLiveOMRow(row, check)).record;
|
|
11182
|
+
const plan = planReflectionGenerationText({
|
|
11183
|
+
storedObservations: stored.activeObservations,
|
|
11184
|
+
storedObservationTokenCount: stored.observationTokenCount,
|
|
11185
|
+
snapshotObservations: currentRecord.activeObservations,
|
|
11186
|
+
snapshotObservationTokenCount: currentRecord.observationTokenCount,
|
|
11187
|
+
reflection: input.reflection,
|
|
11188
|
+
tokenCount: input.tokenCount
|
|
11189
|
+
});
|
|
11190
|
+
if (!plan) return stored;
|
|
11191
|
+
return this.#rollOverObservationalMemory(row, plan.observations, plan.tokenCount, input.newRecordId);
|
|
11192
|
+
}, "createReflectionGeneration");
|
|
10860
11193
|
} catch (error) {
|
|
10861
11194
|
if (error instanceof MastraError) throw error;
|
|
10862
11195
|
throw new MastraError({
|
|
@@ -10867,79 +11200,6 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
10867
11200
|
}, error);
|
|
10868
11201
|
}
|
|
10869
11202
|
}
|
|
10870
|
-
/**
|
|
10871
|
-
* Inserts a new reflection-generation row. Called inside a locked write
|
|
10872
|
-
* transaction — either from {@link createReflectionGeneration} (standalone)
|
|
10873
|
-
* or from {@link swapBufferedReflectionToActive} (as part of a compound
|
|
10874
|
-
* swap). Must not acquire the write lock itself; the caller owns it.
|
|
10875
|
-
*/
|
|
10876
|
-
async #insertReflectionGeneration(tx, input) {
|
|
10877
|
-
const id = crypto.randomUUID();
|
|
10878
|
-
const now = /* @__PURE__ */ new Date();
|
|
10879
|
-
const lookupKey = this.getOMKey(input.currentRecord.threadId, input.currentRecord.resourceId);
|
|
10880
|
-
const record = {
|
|
10881
|
-
id,
|
|
10882
|
-
scope: input.currentRecord.scope,
|
|
10883
|
-
threadId: input.currentRecord.threadId,
|
|
10884
|
-
resourceId: input.currentRecord.resourceId,
|
|
10885
|
-
createdAt: now,
|
|
10886
|
-
updatedAt: now,
|
|
10887
|
-
lastObservedAt: input.currentRecord.lastObservedAt,
|
|
10888
|
-
originType: "reflection",
|
|
10889
|
-
generationCount: input.currentRecord.generationCount + 1,
|
|
10890
|
-
activeObservations: input.reflection,
|
|
10891
|
-
totalTokensObserved: input.currentRecord.totalTokensObserved,
|
|
10892
|
-
observationTokenCount: input.tokenCount,
|
|
10893
|
-
pendingMessageTokens: 0,
|
|
10894
|
-
isReflecting: false,
|
|
10895
|
-
isObserving: false,
|
|
10896
|
-
isBufferingObservation: false,
|
|
10897
|
-
isBufferingReflection: false,
|
|
10898
|
-
lastBufferedAtTokens: 0,
|
|
10899
|
-
lastBufferedAtTime: null,
|
|
10900
|
-
config: input.currentRecord.config,
|
|
10901
|
-
metadata: input.currentRecord.metadata,
|
|
10902
|
-
observedTimezone: input.currentRecord.observedTimezone
|
|
10903
|
-
};
|
|
10904
|
-
await tx.execute({
|
|
10905
|
-
sql: `INSERT INTO "${OM_TABLE}" (
|
|
10906
|
-
id, "lookupKey", scope, "resourceId", "threadId",
|
|
10907
|
-
"activeObservations", "activeObservationsPendingUpdate",
|
|
10908
|
-
"originType", config, "generationCount", "lastObservedAt", "lastReflectionAt",
|
|
10909
|
-
"pendingMessageTokens", "totalTokensObserved", "observationTokenCount",
|
|
10910
|
-
"isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
|
|
10911
|
-
"observedTimezone", metadata, "createdAt", "updatedAt"
|
|
10912
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
10913
|
-
args: [
|
|
10914
|
-
id,
|
|
10915
|
-
lookupKey,
|
|
10916
|
-
record.scope,
|
|
10917
|
-
record.resourceId,
|
|
10918
|
-
record.threadId || null,
|
|
10919
|
-
input.reflection,
|
|
10920
|
-
null,
|
|
10921
|
-
"reflection",
|
|
10922
|
-
JSON.stringify(record.config),
|
|
10923
|
-
input.currentRecord.generationCount + 1,
|
|
10924
|
-
record.lastObservedAt?.toISOString() || null,
|
|
10925
|
-
now.toISOString(),
|
|
10926
|
-
record.pendingMessageTokens,
|
|
10927
|
-
record.totalTokensObserved,
|
|
10928
|
-
record.observationTokenCount,
|
|
10929
|
-
false,
|
|
10930
|
-
false,
|
|
10931
|
-
false,
|
|
10932
|
-
false,
|
|
10933
|
-
0,
|
|
10934
|
-
null,
|
|
10935
|
-
record.observedTimezone || null,
|
|
10936
|
-
record.metadata ? JSON.stringify(record.metadata) : null,
|
|
10937
|
-
now.toISOString(),
|
|
10938
|
-
now.toISOString()
|
|
10939
|
-
]
|
|
10940
|
-
});
|
|
10941
|
-
return record;
|
|
10942
|
-
}
|
|
10943
11203
|
async setReflectingFlag(id, isReflecting) {
|
|
10944
11204
|
try {
|
|
10945
11205
|
if ((await this.#write("setReflectingFlag", () => this.#client.execute({
|
|
@@ -11006,38 +11266,40 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
11006
11266
|
}
|
|
11007
11267
|
async setBufferingObservationFlag(id, isBuffering, lastBufferedAtTokens) {
|
|
11008
11268
|
try {
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
nowStr,
|
|
11025
|
-
id
|
|
11026
|
-
];
|
|
11027
|
-
}
|
|
11028
|
-
if ((await this.#write("setBufferingObservationFlag", () => this.#client.execute({
|
|
11029
|
-
sql,
|
|
11030
|
-
args
|
|
11031
|
-
}))).rowsAffected === 0) throw new MastraError({
|
|
11032
|
-
id: createStorageErrorId("LIBSQL", "SET_BUFFERING_OBSERVATION_FLAG", "NOT_FOUND"),
|
|
11033
|
-
text: `Observational memory record not found: ${id}`,
|
|
11034
|
-
domain: ErrorDomain.STORAGE,
|
|
11035
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
11036
|
-
details: {
|
|
11037
|
-
id,
|
|
11038
|
-
isBuffering,
|
|
11039
|
-
lastBufferedAtTokens: lastBufferedAtTokens ?? null
|
|
11269
|
+
await this.#withOMCas("SET_BUFFERING_OBSERVATION_FLAG", async (attemptIndex) => {
|
|
11270
|
+
const row = await this.#readOMRow(id);
|
|
11271
|
+
if (!row) {
|
|
11272
|
+
if (this.#mayBeUnsynced(attemptIndex)) return OM_CAS_CONFLICT;
|
|
11273
|
+
throw new MastraError({
|
|
11274
|
+
id: createStorageErrorId("LIBSQL", "SET_BUFFERING_OBSERVATION_FLAG", "NOT_FOUND"),
|
|
11275
|
+
text: `Observational memory record not found: ${id}`,
|
|
11276
|
+
domain: ErrorDomain.STORAGE,
|
|
11277
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
11278
|
+
details: {
|
|
11279
|
+
id,
|
|
11280
|
+
isBuffering,
|
|
11281
|
+
lastBufferedAtTokens: lastBufferedAtTokens ?? null
|
|
11282
|
+
}
|
|
11283
|
+
});
|
|
11040
11284
|
}
|
|
11285
|
+
const target = (await this.#resolveLiveOMRow(row)).record;
|
|
11286
|
+
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
11287
|
+
return (lastBufferedAtTokens !== void 0 ? await this.#client.execute({
|
|
11288
|
+
sql: `UPDATE "${OM_TABLE}" SET "isBufferingObservation" = ?, "lastBufferedAtTokens" = ?, "updatedAt" = ? WHERE id = ? AND "supersededBy" IS NULL`,
|
|
11289
|
+
args: [
|
|
11290
|
+
isBuffering,
|
|
11291
|
+
lastBufferedAtTokens,
|
|
11292
|
+
nowStr,
|
|
11293
|
+
target.id
|
|
11294
|
+
]
|
|
11295
|
+
}) : await this.#client.execute({
|
|
11296
|
+
sql: `UPDATE "${OM_TABLE}" SET "isBufferingObservation" = ?, "updatedAt" = ? WHERE id = ? AND "supersededBy" IS NULL`,
|
|
11297
|
+
args: [
|
|
11298
|
+
isBuffering,
|
|
11299
|
+
nowStr,
|
|
11300
|
+
target.id
|
|
11301
|
+
]
|
|
11302
|
+
})).rowsAffected === 1 ? void 0 : OM_CAS_CONFLICT;
|
|
11041
11303
|
});
|
|
11042
11304
|
} catch (error) {
|
|
11043
11305
|
if (error instanceof MastraError) throw error;
|
|
@@ -11106,25 +11368,30 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
11106
11368
|
}
|
|
11107
11369
|
async setPendingMessageTokens(id, tokenCount) {
|
|
11108
11370
|
try {
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
11124
|
-
details: {
|
|
11125
|
-
id,
|
|
11126
|
-
tokenCount
|
|
11371
|
+
await this.#withOMCas("SET_PENDING_MESSAGE_TOKENS", async (attemptIndex) => {
|
|
11372
|
+
const row = await this.#readOMRow(id);
|
|
11373
|
+
if (!row) {
|
|
11374
|
+
if (this.#mayBeUnsynced(attemptIndex)) return OM_CAS_CONFLICT;
|
|
11375
|
+
throw new MastraError({
|
|
11376
|
+
id: createStorageErrorId("LIBSQL", "SET_PENDING_MESSAGE_TOKENS", "NOT_FOUND"),
|
|
11377
|
+
text: `Observational memory record not found: ${id}`,
|
|
11378
|
+
domain: ErrorDomain.STORAGE,
|
|
11379
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
11380
|
+
details: {
|
|
11381
|
+
id,
|
|
11382
|
+
tokenCount
|
|
11383
|
+
}
|
|
11384
|
+
});
|
|
11127
11385
|
}
|
|
11386
|
+
const target = (await this.#resolveLiveOMRow(row)).record;
|
|
11387
|
+
return (await this.#client.execute({
|
|
11388
|
+
sql: `UPDATE "${OM_TABLE}" SET "pendingMessageTokens" = ?, "updatedAt" = ? WHERE id = ? AND "supersededBy" IS NULL`,
|
|
11389
|
+
args: [
|
|
11390
|
+
tokenCount,
|
|
11391
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
11392
|
+
target.id
|
|
11393
|
+
]
|
|
11394
|
+
})).rowsAffected === 1 ? void 0 : OM_CAS_CONFLICT;
|
|
11128
11395
|
});
|
|
11129
11396
|
} catch (error) {
|
|
11130
11397
|
if (error instanceof MastraError) throw error;
|
|
@@ -11141,36 +11408,33 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
11141
11408
|
}
|
|
11142
11409
|
async updateObservationalMemoryConfig(input) {
|
|
11143
11410
|
try {
|
|
11144
|
-
await this.#
|
|
11145
|
-
const
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
|
|
11151
|
-
|
|
11411
|
+
await this.#withOMCas("UPDATE_OM_CONFIG", async (attemptIndex) => {
|
|
11412
|
+
const selectResult = await this.#client.execute({
|
|
11413
|
+
sql: `SELECT config FROM "${OM_TABLE}" WHERE id = ?`,
|
|
11414
|
+
args: [input.id]
|
|
11415
|
+
});
|
|
11416
|
+
if (selectResult.rows.length === 0) {
|
|
11417
|
+
if (this.#mayBeUnsynced(attemptIndex)) return OM_CAS_CONFLICT;
|
|
11418
|
+
throw new MastraError({
|
|
11152
11419
|
id: createStorageErrorId("LIBSQL", "UPDATE_OM_CONFIG", "NOT_FOUND"),
|
|
11153
11420
|
text: `Observational memory record not found: ${input.id}`,
|
|
11154
11421
|
domain: ErrorDomain.STORAGE,
|
|
11155
11422
|
category: ErrorCategory.THIRD_PARTY,
|
|
11156
11423
|
details: { id: input.id }
|
|
11157
11424
|
});
|
|
11158
|
-
const row = selectResult.rows[0];
|
|
11159
|
-
const existing = row.config ? JSON.parse(row.config) : {};
|
|
11160
|
-
const merged = this.deepMergeConfig(existing, input.config);
|
|
11161
|
-
await tx.execute({
|
|
11162
|
-
sql: `UPDATE "${OM_TABLE}" SET config = ?, "updatedAt" = ? WHERE id = ?`,
|
|
11163
|
-
args: [
|
|
11164
|
-
JSON.stringify(merged),
|
|
11165
|
-
(/* @__PURE__ */ new Date()).toISOString(),
|
|
11166
|
-
input.id
|
|
11167
|
-
]
|
|
11168
|
-
});
|
|
11169
|
-
await tx.commit();
|
|
11170
|
-
} catch (error) {
|
|
11171
|
-
if (!tx.closed) await tx.rollback();
|
|
11172
|
-
throw error;
|
|
11173
11425
|
}
|
|
11426
|
+
const row = selectResult.rows[0];
|
|
11427
|
+
const existing = row.config ? JSON.parse(row.config) : {};
|
|
11428
|
+
const merged = this.deepMergeConfig(existing, input.config);
|
|
11429
|
+
return (await this.#client.execute({
|
|
11430
|
+
sql: `UPDATE "${OM_TABLE}" SET config = ?, "updatedAt" = ? WHERE id = ? AND config IS ?`,
|
|
11431
|
+
args: [
|
|
11432
|
+
JSON.stringify(merged),
|
|
11433
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
11434
|
+
input.id,
|
|
11435
|
+
row.config ?? null
|
|
11436
|
+
]
|
|
11437
|
+
})).rowsAffected === 1 ? void 0 : OM_CAS_CONFLICT;
|
|
11174
11438
|
});
|
|
11175
11439
|
} catch (error) {
|
|
11176
11440
|
if (error instanceof MastraError) throw error;
|
|
@@ -11183,78 +11447,64 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
11183
11447
|
}
|
|
11184
11448
|
}
|
|
11185
11449
|
async updateBufferedObservations(input) {
|
|
11450
|
+
await this.appendBufferedObservations(input);
|
|
11451
|
+
}
|
|
11452
|
+
async appendBufferedObservations(input) {
|
|
11186
11453
|
try {
|
|
11187
11454
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
const current = await tx.execute({
|
|
11194
|
-
sql: `SELECT "bufferedObservationChunks" FROM "${OM_TABLE}" WHERE id = ?`,
|
|
11195
|
-
args: [input.id]
|
|
11196
|
-
});
|
|
11197
|
-
if (!current.rows || current.rows.length === 0) throw new MastraError({
|
|
11198
|
-
id: createStorageErrorId("LIBSQL", "UPDATE_BUFFERED_OBSERVATIONS", "NOT_FOUND"),
|
|
11199
|
-
text: `Observational memory record not found: ${input.id}`,
|
|
11200
|
-
domain: ErrorDomain.STORAGE,
|
|
11201
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
11202
|
-
details: { id: input.id }
|
|
11203
|
-
});
|
|
11204
|
-
const row = current.rows[0];
|
|
11205
|
-
let existingChunks = [];
|
|
11206
|
-
if (row.bufferedObservationChunks) try {
|
|
11207
|
-
const parsed = typeof row.bufferedObservationChunks === "string" ? JSON.parse(row.bufferedObservationChunks) : row.bufferedObservationChunks;
|
|
11208
|
-
existingChunks = Array.isArray(parsed) ? parsed : [];
|
|
11209
|
-
} catch {
|
|
11210
|
-
existingChunks = [];
|
|
11211
|
-
}
|
|
11212
|
-
if (existingChunks.some((existing) => existing.cycleId === input.chunk.cycleId)) {
|
|
11213
|
-
await tx.commit();
|
|
11214
|
-
return;
|
|
11215
|
-
}
|
|
11216
|
-
const newChunk = {
|
|
11217
|
-
id: `ombuf-${globalThis.crypto.randomUUID()}`,
|
|
11218
|
-
cycleId: input.chunk.cycleId,
|
|
11219
|
-
observations: input.chunk.observations,
|
|
11220
|
-
tokenCount: input.chunk.tokenCount,
|
|
11221
|
-
messageIds: input.chunk.messageIds,
|
|
11222
|
-
messageTokens: input.chunk.messageTokens,
|
|
11223
|
-
lastObservedAt: input.chunk.lastObservedAt,
|
|
11224
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
11225
|
-
suggestedContinuation: input.chunk.suggestedContinuation,
|
|
11226
|
-
currentTask: input.chunk.currentTask,
|
|
11227
|
-
threadTitle: input.chunk.threadTitle,
|
|
11228
|
-
extractedValues: input.chunk.extractedValues,
|
|
11229
|
-
extractionFailures: input.chunk.extractionFailures
|
|
11230
|
-
};
|
|
11231
|
-
const newChunks = [...existingChunks, newChunk];
|
|
11232
|
-
const lastBufferedAtTime = input.lastBufferedAtTime ? input.lastBufferedAtTime.toISOString() : null;
|
|
11233
|
-
if ((await tx.execute({
|
|
11234
|
-
sql: `UPDATE "${OM_TABLE}" SET
|
|
11235
|
-
"bufferedObservationChunks" = ?,
|
|
11236
|
-
"lastBufferedAtTime" = COALESCE(?, "lastBufferedAtTime"),
|
|
11237
|
-
"updatedAt" = ?
|
|
11238
|
-
WHERE id = ?`,
|
|
11239
|
-
args: [
|
|
11240
|
-
JSON.stringify(newChunks),
|
|
11241
|
-
lastBufferedAtTime,
|
|
11242
|
-
nowStr,
|
|
11243
|
-
input.id
|
|
11244
|
-
]
|
|
11245
|
-
})).rowsAffected === 0) throw new MastraError({
|
|
11455
|
+
return await this.#withOMCas("UPDATE_BUFFERED_OBSERVATIONS", async (attemptIndex, check) => {
|
|
11456
|
+
const row = await this.#readOMRow(input.id, check);
|
|
11457
|
+
if (!row) {
|
|
11458
|
+
if (this.#mayBeUnsynced(attemptIndex)) return OM_CAS_CONFLICT;
|
|
11459
|
+
throw new MastraError({
|
|
11246
11460
|
id: createStorageErrorId("LIBSQL", "UPDATE_BUFFERED_OBSERVATIONS", "NOT_FOUND"),
|
|
11247
11461
|
text: `Observational memory record not found: ${input.id}`,
|
|
11248
11462
|
domain: ErrorDomain.STORAGE,
|
|
11249
11463
|
category: ErrorCategory.THIRD_PARTY,
|
|
11250
11464
|
details: { id: input.id }
|
|
11251
11465
|
});
|
|
11252
|
-
await tx.commit();
|
|
11253
|
-
} catch (error) {
|
|
11254
|
-
if (!tx.closed) await tx.rollback();
|
|
11255
|
-
throw error;
|
|
11256
11466
|
}
|
|
11257
|
-
|
|
11467
|
+
const targetRow = await this.#resolveLiveOMRow(row, check);
|
|
11468
|
+
const target = targetRow.record;
|
|
11469
|
+
const existingChunks = Array.isArray(target.bufferedObservationChunks) ? target.bufferedObservationChunks : [];
|
|
11470
|
+
if (existingChunks.some((existing) => existing.cycleId === input.chunk.cycleId) || isBufferedChunkCoveredByCursor(input.chunk.lastObservedAt, target.lastObservedAt)) return {
|
|
11471
|
+
persisted: false,
|
|
11472
|
+
recordId: target.id
|
|
11473
|
+
};
|
|
11474
|
+
const newChunk = {
|
|
11475
|
+
id: `ombuf-${globalThis.crypto.randomUUID()}`,
|
|
11476
|
+
cycleId: input.chunk.cycleId,
|
|
11477
|
+
observations: input.chunk.observations,
|
|
11478
|
+
tokenCount: input.chunk.tokenCount,
|
|
11479
|
+
messageIds: input.chunk.messageIds,
|
|
11480
|
+
messageTokens: input.chunk.messageTokens,
|
|
11481
|
+
lastObservedAt: input.chunk.lastObservedAt,
|
|
11482
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
11483
|
+
suggestedContinuation: input.chunk.suggestedContinuation,
|
|
11484
|
+
currentTask: input.chunk.currentTask,
|
|
11485
|
+
threadTitle: input.chunk.threadTitle,
|
|
11486
|
+
extractedValues: input.chunk.extractedValues,
|
|
11487
|
+
extractionFailures: input.chunk.extractionFailures
|
|
11488
|
+
};
|
|
11489
|
+
const lastBufferedAtTime = maxObservationCursor(target.lastBufferedAtTime, input.lastBufferedAtTime);
|
|
11490
|
+
return (await this.#client.execute({
|
|
11491
|
+
sql: `UPDATE "${OM_TABLE}" SET
|
|
11492
|
+
"bufferedObservationChunks" = ?,
|
|
11493
|
+
"lastBufferedAtTime" = ?,
|
|
11494
|
+
"updatedAt" = ?
|
|
11495
|
+
WHERE id = ? AND ${targetRow.guard.sql}`,
|
|
11496
|
+
args: [
|
|
11497
|
+
JSON.stringify([...existingChunks, newChunk]),
|
|
11498
|
+
lastBufferedAtTime ? lastBufferedAtTime.toISOString() : null,
|
|
11499
|
+
nowStr,
|
|
11500
|
+
target.id,
|
|
11501
|
+
...targetRow.guard.args
|
|
11502
|
+
]
|
|
11503
|
+
})).rowsAffected === 1 ? {
|
|
11504
|
+
persisted: true,
|
|
11505
|
+
recordId: target.id
|
|
11506
|
+
} : OM_CAS_CONFLICT;
|
|
11507
|
+
}, "appendBufferedObservations");
|
|
11258
11508
|
} catch (error) {
|
|
11259
11509
|
if (error instanceof MastraError) throw error;
|
|
11260
11510
|
throw new MastraError({
|
|
@@ -11268,144 +11518,137 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
11268
11518
|
async swapBufferedToActive(input) {
|
|
11269
11519
|
try {
|
|
11270
11520
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
});
|
|
11280
|
-
if (!current.rows || current.rows.length === 0) throw new MastraError({
|
|
11521
|
+
return await this.#withOMCas("SWAP_BUFFERED_TO_ACTIVE", async (attemptIndex, check) => {
|
|
11522
|
+
const current = await this.#client.execute({
|
|
11523
|
+
sql: `SELECT * FROM "${OM_TABLE}" WHERE id = ?`,
|
|
11524
|
+
args: [input.id]
|
|
11525
|
+
});
|
|
11526
|
+
if (!current.rows || current.rows.length === 0) {
|
|
11527
|
+
if (this.#mayBeUnsynced(attemptIndex)) return OM_CAS_CONFLICT;
|
|
11528
|
+
throw new MastraError({
|
|
11281
11529
|
id: createStorageErrorId("LIBSQL", "SWAP_BUFFERED_TO_ACTIVE", "NOT_FOUND"),
|
|
11282
11530
|
text: `Observational memory record not found: ${input.id}`,
|
|
11283
11531
|
domain: ErrorDomain.STORAGE,
|
|
11284
11532
|
category: ErrorCategory.THIRD_PARTY,
|
|
11285
11533
|
details: { id: input.id }
|
|
11286
11534
|
});
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11535
|
+
}
|
|
11536
|
+
const row = current.rows[0];
|
|
11537
|
+
const guard = this.#toOMRow(current, check).guard;
|
|
11538
|
+
const emptyResult = {
|
|
11539
|
+
chunksActivated: 0,
|
|
11540
|
+
messageTokensActivated: 0,
|
|
11541
|
+
observationTokensActivated: 0,
|
|
11542
|
+
messagesActivated: 0,
|
|
11543
|
+
activatedCycleIds: [],
|
|
11544
|
+
activatedMessageIds: []
|
|
11545
|
+
};
|
|
11546
|
+
if (row.supersededBy) return {
|
|
11547
|
+
...emptyResult,
|
|
11548
|
+
retired: true
|
|
11549
|
+
};
|
|
11550
|
+
let persistedChunks = [];
|
|
11551
|
+
if (row.bufferedObservationChunks) try {
|
|
11552
|
+
const parsed = typeof row.bufferedObservationChunks === "string" ? JSON.parse(row.bufferedObservationChunks) : row.bufferedObservationChunks;
|
|
11553
|
+
persistedChunks = Array.isArray(parsed) ? parsed : [];
|
|
11554
|
+
} catch {
|
|
11555
|
+
persistedChunks = [];
|
|
11556
|
+
}
|
|
11557
|
+
const refreshedWeights = new Map((Array.isArray(input.bufferedChunks) ? input.bufferedChunks : []).map((c) => [c.id, c.messageTokens]));
|
|
11558
|
+
const chunks = persistedChunks.map((c) => refreshedWeights.has(c.id) ? {
|
|
11559
|
+
...c,
|
|
11560
|
+
messageTokens: refreshedWeights.get(c.id)
|
|
11561
|
+
} : c);
|
|
11562
|
+
if (chunks.length === 0) return emptyResult;
|
|
11563
|
+
const retentionFloor = input.messageTokensThreshold * (1 - input.activationRatio);
|
|
11564
|
+
const targetMessageTokens = Math.max(0, input.currentPendingTokens - retentionFloor);
|
|
11565
|
+
let cumulativeMessageTokens = 0;
|
|
11566
|
+
let bestOverBoundary = 0;
|
|
11567
|
+
let bestOverTokens = 0;
|
|
11568
|
+
let bestUnderBoundary = 0;
|
|
11569
|
+
let bestUnderTokens = 0;
|
|
11570
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
11571
|
+
cumulativeMessageTokens += chunks[i].messageTokens ?? 0;
|
|
11572
|
+
const boundary = i + 1;
|
|
11573
|
+
if (cumulativeMessageTokens >= targetMessageTokens) {
|
|
11574
|
+
if (bestOverBoundary === 0 || cumulativeMessageTokens < bestOverTokens) {
|
|
11575
|
+
bestOverBoundary = boundary;
|
|
11576
|
+
bestOverTokens = cumulativeMessageTokens;
|
|
11324
11577
|
}
|
|
11578
|
+
} else if (cumulativeMessageTokens > bestUnderTokens) {
|
|
11579
|
+
bestUnderBoundary = boundary;
|
|
11580
|
+
bestUnderTokens = cumulativeMessageTokens;
|
|
11325
11581
|
}
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11356
|
-
|
|
11582
|
+
}
|
|
11583
|
+
const maxOvershoot = retentionFloor * .95;
|
|
11584
|
+
const overshoot = bestOverTokens - targetMessageTokens;
|
|
11585
|
+
const remainingAfterOver = input.currentPendingTokens - bestOverTokens;
|
|
11586
|
+
const remainingAfterUnder = input.currentPendingTokens - bestUnderTokens;
|
|
11587
|
+
const minRemaining = Math.min(1e3, retentionFloor);
|
|
11588
|
+
let chunksToActivate;
|
|
11589
|
+
if (input.forceMaxActivation && bestOverBoundary > 0 && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
11590
|
+
else if (bestOverBoundary > 0 && overshoot <= maxOvershoot && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
11591
|
+
else if (bestUnderBoundary > 0 && remainingAfterUnder >= minRemaining) chunksToActivate = bestUnderBoundary;
|
|
11592
|
+
else if (bestOverBoundary > 0) chunksToActivate = bestOverBoundary;
|
|
11593
|
+
else chunksToActivate = 1;
|
|
11594
|
+
const activatedChunks = chunks.slice(0, chunksToActivate);
|
|
11595
|
+
const remainingChunks = persistedChunks.slice(chunksToActivate);
|
|
11596
|
+
const activatedContent = activatedChunks.map((c) => c.observations).join("\n\n");
|
|
11597
|
+
const activatedTokens = activatedChunks.reduce((sum, c) => sum + c.tokenCount, 0);
|
|
11598
|
+
const activatedMessageTokens = activatedChunks.reduce((sum, c) => sum + (c.messageTokens ?? 0), 0);
|
|
11599
|
+
const activatedMessageCount = activatedChunks.reduce((sum, c) => sum + c.messageIds.length, 0);
|
|
11600
|
+
const activatedCycleIds = activatedChunks.map((c) => c.cycleId).filter((id) => !!id);
|
|
11601
|
+
const activatedMessageIds = activatedChunks.flatMap((c) => c.messageIds ?? []);
|
|
11602
|
+
const latestChunk = activatedChunks[activatedChunks.length - 1];
|
|
11603
|
+
const lastObservedAt = input.lastObservedAt ?? (latestChunk?.lastObservedAt ? new Date(latestChunk.lastObservedAt) : /* @__PURE__ */ new Date());
|
|
11604
|
+
const lastObservedAtStr = maxObservationCursor(row.lastObservedAt, lastObservedAt).toISOString();
|
|
11605
|
+
const existingActive = row.activeObservations || "";
|
|
11606
|
+
const existingTokenCount = Number(row.observationTokenCount || 0);
|
|
11607
|
+
const boundary = `\n\n--- message boundary (${lastObservedAt.toISOString()}) ---\n\n`;
|
|
11608
|
+
const newActive = existingActive ? `${existingActive}${boundary}${activatedContent}` : activatedContent;
|
|
11609
|
+
const newTokenCount = existingTokenCount + activatedTokens;
|
|
11610
|
+
const existingPending = Number(row.pendingMessageTokens || 0);
|
|
11611
|
+
const newPending = Math.max(0, existingPending - activatedMessageTokens);
|
|
11612
|
+
if ((await this.#client.execute({
|
|
11613
|
+
sql: `UPDATE "${OM_TABLE}" SET
|
|
11357
11614
|
"activeObservations" = ?,
|
|
11358
11615
|
"observationTokenCount" = ?,
|
|
11359
11616
|
"pendingMessageTokens" = ?,
|
|
11360
11617
|
"bufferedObservationChunks" = ?,
|
|
11361
11618
|
"lastObservedAt" = ?,
|
|
11362
11619
|
"updatedAt" = ?
|
|
11363
|
-
WHERE id = ?
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
11377
|
-
|
|
11378
|
-
|
|
11379
|
-
|
|
11380
|
-
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
cycleId: c.cycleId ?? "",
|
|
11396
|
-
messageTokens: c.messageTokens ?? 0,
|
|
11397
|
-
observationTokens: c.tokenCount,
|
|
11398
|
-
messageCount: c.messageIds.length,
|
|
11399
|
-
observations: c.observations
|
|
11400
|
-
})),
|
|
11401
|
-
suggestedContinuation: latestChunkHints?.suggestedContinuation ?? void 0,
|
|
11402
|
-
currentTask: latestChunkHints?.currentTask ?? void 0
|
|
11403
|
-
};
|
|
11404
|
-
} catch (error) {
|
|
11405
|
-
if (!tx.closed) await tx.rollback();
|
|
11406
|
-
throw error;
|
|
11407
|
-
}
|
|
11408
|
-
});
|
|
11620
|
+
WHERE id = ? AND ${guard.sql}`,
|
|
11621
|
+
args: [
|
|
11622
|
+
newActive,
|
|
11623
|
+
newTokenCount,
|
|
11624
|
+
newPending,
|
|
11625
|
+
remainingChunks.length > 0 ? JSON.stringify(remainingChunks) : null,
|
|
11626
|
+
lastObservedAtStr,
|
|
11627
|
+
nowStr,
|
|
11628
|
+
input.id,
|
|
11629
|
+
...guard.args
|
|
11630
|
+
]
|
|
11631
|
+
})).rowsAffected === 0) return OM_CAS_CONFLICT;
|
|
11632
|
+
const latestChunkHints = activatedChunks[activatedChunks.length - 1];
|
|
11633
|
+
return {
|
|
11634
|
+
chunksActivated: activatedChunks.length,
|
|
11635
|
+
messageTokensActivated: activatedMessageTokens,
|
|
11636
|
+
observationTokensActivated: activatedTokens,
|
|
11637
|
+
messagesActivated: activatedMessageCount,
|
|
11638
|
+
activatedCycleIds,
|
|
11639
|
+
activatedMessageIds,
|
|
11640
|
+
observations: activatedContent,
|
|
11641
|
+
perChunk: activatedChunks.map((c) => ({
|
|
11642
|
+
cycleId: c.cycleId ?? "",
|
|
11643
|
+
messageTokens: c.messageTokens ?? 0,
|
|
11644
|
+
observationTokens: c.tokenCount,
|
|
11645
|
+
messageCount: c.messageIds.length,
|
|
11646
|
+
observations: c.observations
|
|
11647
|
+
})),
|
|
11648
|
+
suggestedContinuation: latestChunkHints?.suggestedContinuation ?? void 0,
|
|
11649
|
+
currentTask: latestChunkHints?.currentTask ?? void 0
|
|
11650
|
+
};
|
|
11651
|
+
}, "swapBufferedToActive");
|
|
11409
11652
|
} catch (error) {
|
|
11410
11653
|
if (error instanceof MastraError) throw error;
|
|
11411
11654
|
throw new MastraError({
|
|
@@ -11459,57 +11702,27 @@ var MemoryLibSQL = class MemoryLibSQL extends MemoryStorage {
|
|
|
11459
11702
|
}
|
|
11460
11703
|
async swapBufferedReflectionToActive(input) {
|
|
11461
11704
|
try {
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
const
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
text: "No buffered reflection to swap",
|
|
11484
|
-
domain: ErrorDomain.STORAGE,
|
|
11485
|
-
category: ErrorCategory.USER,
|
|
11486
|
-
details: { id: input.currentRecord.id }
|
|
11487
|
-
});
|
|
11488
|
-
const unreflectedContent = (row.activeObservations || "").split("\n").slice(reflectedLineCount).join("\n").trim();
|
|
11489
|
-
const newObservations = unreflectedContent ? `${bufferedReflection}\n\n${unreflectedContent}` : bufferedReflection;
|
|
11490
|
-
const newRecord = await this.#insertReflectionGeneration(tx, {
|
|
11491
|
-
currentRecord: input.currentRecord,
|
|
11492
|
-
reflection: newObservations,
|
|
11493
|
-
tokenCount: input.tokenCount
|
|
11494
|
-
});
|
|
11495
|
-
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
11496
|
-
await tx.execute({
|
|
11497
|
-
sql: `UPDATE "${OM_TABLE}" SET
|
|
11498
|
-
"bufferedReflection" = NULL,
|
|
11499
|
-
"bufferedReflectionTokens" = NULL,
|
|
11500
|
-
"bufferedReflectionInputTokens" = NULL,
|
|
11501
|
-
"reflectedObservationLineCount" = NULL,
|
|
11502
|
-
"updatedAt" = ?
|
|
11503
|
-
WHERE id = ?`,
|
|
11504
|
-
args: [nowStr, input.currentRecord.id]
|
|
11505
|
-
});
|
|
11506
|
-
await tx.commit();
|
|
11507
|
-
return newRecord;
|
|
11508
|
-
} catch (error) {
|
|
11509
|
-
if (!tx.closed) await tx.rollback();
|
|
11510
|
-
throw error;
|
|
11511
|
-
}
|
|
11512
|
-
});
|
|
11705
|
+
return await this.#withOMCas("SWAP_BUFFERED_REFLECTION_TO_ACTIVE", async (attemptIndex, check) => {
|
|
11706
|
+
const { currentRecord } = input;
|
|
11707
|
+
const row = await this.#readOMRow(currentRecord.id, check);
|
|
11708
|
+
if (!row) return this.#mayBeUnsynced(attemptIndex) ? OM_CAS_CONFLICT : currentRecord;
|
|
11709
|
+
const stored = row.record;
|
|
11710
|
+
if (stored.supersededBy) return (await this.#resolveLiveOMRow(row, check)).record;
|
|
11711
|
+
const bufferedReflection = stored.bufferedReflection || "";
|
|
11712
|
+
if (!bufferedReflection) throw new MastraError({
|
|
11713
|
+
id: createStorageErrorId("LIBSQL", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "NO_CONTENT"),
|
|
11714
|
+
text: "No buffered reflection to swap",
|
|
11715
|
+
domain: ErrorDomain.STORAGE,
|
|
11716
|
+
category: ErrorCategory.USER,
|
|
11717
|
+
details: { id: currentRecord.id }
|
|
11718
|
+
});
|
|
11719
|
+
if (!isAppendOnlySince(stored.activeObservations, currentRecord.activeObservations)) return stored;
|
|
11720
|
+
const reflectedLineCount = stored.reflectedObservationLineCount ?? 0;
|
|
11721
|
+
const unreflectedContent = (stored.activeObservations || "").split("\n").slice(reflectedLineCount).join("\n").trim();
|
|
11722
|
+
const newObservations = unreflectedContent ? `${bufferedReflection}\n\n${unreflectedContent}` : bufferedReflection;
|
|
11723
|
+
const tokenCount = input.tokenCount + Math.max(0, (stored.observationTokenCount ?? 0) - (currentRecord.observationTokenCount ?? 0));
|
|
11724
|
+
return this.#rollOverObservationalMemory(row, newObservations, tokenCount, input.newRecordId);
|
|
11725
|
+
}, "swapBufferedReflectionToActive");
|
|
11513
11726
|
} catch (error) {
|
|
11514
11727
|
if (error instanceof MastraError) throw error;
|
|
11515
11728
|
throw new MastraError({
|
|
@@ -16428,6 +16641,7 @@ var LibSQLStore = class extends MastraCompositeStore {
|
|
|
16428
16641
|
}
|
|
16429
16642
|
const domainConfig = {
|
|
16430
16643
|
client: this.client,
|
|
16644
|
+
embeddedReplica: "url" in config && !!config.syncUrl,
|
|
16431
16645
|
maxRetries: this.maxRetries,
|
|
16432
16646
|
initialBackoffMs: this.initialBackoffMs
|
|
16433
16647
|
};
|