@mastra/libsql 1.26.0 → 1.26.1-alpha.1

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