@mastra/pg 1.31.0 → 1.31.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/_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/docs/references/docs-deployment-workers.md +1 -1
- package/dist/docs/references/reference-storage-composite.md +34 -0
- package/dist/docs/references/reference-tools-vector-query-tool.md +4 -4
- package/dist/docs/references/reference-vectors-pg.md +16 -11
- package/dist/index.cjs +505 -363
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +505 -363
- package/dist/index.js.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/domains/workflows/index.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -11587,6 +11587,92 @@ var MCPServersPG = class MCPServersPG extends MCPServersStorage {
|
|
|
11587
11587
|
}
|
|
11588
11588
|
};
|
|
11589
11589
|
//#endregion
|
|
11590
|
+
//#region ../../packages/_internal-core/dist/memory/index.js
|
|
11591
|
+
/**
|
|
11592
|
+
* Shared rules for observational memory lifecycle writes. Every storage adapter applies
|
|
11593
|
+
* these inside its own atomic section (lock, transaction, or conditional update), so the
|
|
11594
|
+
* decisions are identical across adapters.
|
|
11595
|
+
*/
|
|
11596
|
+
/**
|
|
11597
|
+
* Observational memory columns that lifecycle writes depend on. Storage adapters merge these
|
|
11598
|
+
* into the table schema they get from `@mastra/core`, so the columns exist even when the
|
|
11599
|
+
* installed core predates them.
|
|
11600
|
+
*/
|
|
11601
|
+
const OBSERVATIONAL_MEMORY_LIFECYCLE_COLUMNS = { supersededBy: {
|
|
11602
|
+
type: "text",
|
|
11603
|
+
nullable: true
|
|
11604
|
+
} };
|
|
11605
|
+
/** `schema` plus {@link OBSERVATIONAL_MEMORY_LIFECYCLE_COLUMNS}; `undefined` when `schema` is. */
|
|
11606
|
+
function withObservationalMemoryLifecycleColumns(schema) {
|
|
11607
|
+
return schema ? {
|
|
11608
|
+
...schema,
|
|
11609
|
+
...OBSERVATIONAL_MEMORY_LIFECYCLE_COLUMNS
|
|
11610
|
+
} : void 0;
|
|
11611
|
+
}
|
|
11612
|
+
/**
|
|
11613
|
+
* A buffered chunk stores `lastObservedAt = max message time + 1ms`. It is wholly covered
|
|
11614
|
+
* (every message it observed is already at or before the cursor) iff
|
|
11615
|
+
* `cursor >= chunk.lastObservedAt - 1ms`.
|
|
11616
|
+
*/
|
|
11617
|
+
function isBufferedChunkCoveredByCursor(chunkLastObservedAt, cursor) {
|
|
11618
|
+
if (!cursor) return false;
|
|
11619
|
+
return new Date(cursor).getTime() >= new Date(chunkLastObservedAt).getTime() - 1;
|
|
11620
|
+
}
|
|
11621
|
+
/** The later of two cursors; `undefined` only when both are absent. */
|
|
11622
|
+
function maxObservationCursor(a, b) {
|
|
11623
|
+
if (!a) return b ? new Date(b) : void 0;
|
|
11624
|
+
if (!b) return new Date(a);
|
|
11625
|
+
return new Date(Math.max(new Date(a).getTime(), new Date(b).getTime()));
|
|
11626
|
+
}
|
|
11627
|
+
/**
|
|
11628
|
+
* Decide the new generation's text when a reflection built from `snapshot` commits against
|
|
11629
|
+
* the stored record.
|
|
11630
|
+
*
|
|
11631
|
+
* - Stored text equals the snapshot: the reflection replaces it.
|
|
11632
|
+
* - Stored text extends the snapshot (activation only appends): the appended tail is kept
|
|
11633
|
+
* after the reflection, and its tokens are added.
|
|
11634
|
+
* - Anything else (a non-append rewrite): `null` — the reflection must not be applied.
|
|
11635
|
+
*/
|
|
11636
|
+
function planReflectionGenerationText(input) {
|
|
11637
|
+
const stored = input.storedObservations ?? "";
|
|
11638
|
+
const snapshot = input.snapshotObservations ?? "";
|
|
11639
|
+
if (stored === snapshot) return {
|
|
11640
|
+
mode: "equal",
|
|
11641
|
+
observations: input.reflection,
|
|
11642
|
+
tokenCount: input.tokenCount
|
|
11643
|
+
};
|
|
11644
|
+
if (!stored.startsWith(snapshot)) return null;
|
|
11645
|
+
const tail = stored.slice(snapshot.length).trimStart();
|
|
11646
|
+
if (!tail.trim()) return {
|
|
11647
|
+
mode: "equal",
|
|
11648
|
+
observations: input.reflection,
|
|
11649
|
+
tokenCount: input.tokenCount
|
|
11650
|
+
};
|
|
11651
|
+
return {
|
|
11652
|
+
mode: "append",
|
|
11653
|
+
observations: input.reflection ? `${input.reflection}\n\n${tail}` : tail,
|
|
11654
|
+
tokenCount: input.tokenCount + Math.max(0, (input.storedObservationTokenCount ?? 0) - (input.snapshotObservationTokenCount ?? 0))
|
|
11655
|
+
};
|
|
11656
|
+
}
|
|
11657
|
+
/**
|
|
11658
|
+
* Backs `updateActiveObservations` in adapters that implement `commitActiveObservations`.
|
|
11659
|
+
* Callers of `updateActiveObservations` (which resolves `void`) can't see a commit result, so a
|
|
11660
|
+
* write that was not applied throws instead of resolving as if it had committed.
|
|
11661
|
+
*/
|
|
11662
|
+
function assertActiveObservationsApplied(result, id) {
|
|
11663
|
+
if (result.applied) return;
|
|
11664
|
+
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`);
|
|
11665
|
+
}
|
|
11666
|
+
/**
|
|
11667
|
+
* Whether the stored text can still accept a reflection built from `snapshot`
|
|
11668
|
+
* (equal, or only appended to since).
|
|
11669
|
+
*/
|
|
11670
|
+
function isAppendOnlySince(storedObservations, snapshotObservations) {
|
|
11671
|
+
const stored = storedObservations ?? "";
|
|
11672
|
+
const snapshot = snapshotObservations ?? "";
|
|
11673
|
+
return stored === snapshot || stored.startsWith(snapshot);
|
|
11674
|
+
}
|
|
11675
|
+
//#endregion
|
|
11590
11676
|
//#region src/storage/db/run-fencing.ts
|
|
11591
11677
|
/**
|
|
11592
11678
|
* Epoch milliseconds on the database clock. `clock_timestamp()` rather than
|
|
@@ -11632,6 +11718,8 @@ const OM_TABLE = "mastra_observational_memory";
|
|
|
11632
11718
|
* one wins so the active record stays stable across reads.
|
|
11633
11719
|
*/
|
|
11634
11720
|
const OM_GENERATION_ORDER = `"generationCount" DESC, "createdAt" ASC, id ASC`;
|
|
11721
|
+
/** Lifecycle writes aimed at a retired record follow it to the head at most this many times. */
|
|
11722
|
+
const OM_MAX_HEAD_HOPS = 3;
|
|
11635
11723
|
const POSTGRES_MAX_BIND_PARAMETERS = 65535;
|
|
11636
11724
|
const MESSAGE_INSERT_BIND_PARAMETERS = 8;
|
|
11637
11725
|
const MAX_MESSAGES_PER_INSERT = Math.floor(POSTGRES_MAX_BIND_PARAMETERS / MESSAGE_INSERT_BIND_PARAMETERS);
|
|
@@ -11659,7 +11747,8 @@ const OM_MIGRATION_COLUMNS = [
|
|
|
11659
11747
|
"isBufferingReflection",
|
|
11660
11748
|
"lastBufferedAtTokens",
|
|
11661
11749
|
"lastBufferedAtTime",
|
|
11662
|
-
"metadata"
|
|
11750
|
+
"metadata",
|
|
11751
|
+
"supersededBy"
|
|
11663
11752
|
];
|
|
11664
11753
|
/**
|
|
11665
11754
|
* The OM schema is imported statically above: the peer dependency range
|
|
@@ -11669,7 +11758,10 @@ const OM_MIGRATION_COLUMNS = [
|
|
|
11669
11758
|
* bundle to a shim that always throws, and the silent catch meant the
|
|
11670
11759
|
* published ESM build skipped creating the OM table entirely (#18954).
|
|
11671
11760
|
*/
|
|
11672
|
-
const _omTableSchema =
|
|
11761
|
+
const _omTableSchema = {
|
|
11762
|
+
...OBSERVATIONAL_MEMORY_TABLE_SCHEMA,
|
|
11763
|
+
[OM_TABLE]: withObservationalMemoryLifecycleColumns(OBSERVATIONAL_MEMORY_TABLE_SCHEMA?.[OM_TABLE])
|
|
11764
|
+
};
|
|
11673
11765
|
function getSchemaName$3(schema) {
|
|
11674
11766
|
return schema ? `"${schema}"` : "\"public\"";
|
|
11675
11767
|
}
|
|
@@ -11693,6 +11785,14 @@ function inPlaceholders(count, startIndex = 1) {
|
|
|
11693
11785
|
function toUtcISOString(date) {
|
|
11694
11786
|
return date.toISOString();
|
|
11695
11787
|
}
|
|
11788
|
+
/**
|
|
11789
|
+
* Read a `timestamp without time zone` column written from a UTC ISO string. Postgres drops the
|
|
11790
|
+
* zone on input, so the stored wall time is UTC; node-postgres parses it as local time.
|
|
11791
|
+
*/
|
|
11792
|
+
function utcFromTimestampWithoutTimeZone(value) {
|
|
11793
|
+
if (value instanceof Date) return new Date(Date.UTC(value.getFullYear(), value.getMonth(), value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), value.getMilliseconds()));
|
|
11794
|
+
return new Date(/[zZ]|[+-]\d{2}:?\d{2}$/.test(value) ? value : `${value.replace(" ", "T")}Z`);
|
|
11795
|
+
}
|
|
11696
11796
|
function dedupeMessagesForSave(messages) {
|
|
11697
11797
|
const deduped = /* @__PURE__ */ new Map();
|
|
11698
11798
|
for (const message of messages) {
|
|
@@ -11807,6 +11907,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11807
11907
|
schemaName: getSchemaName$3(this.#schema)
|
|
11808
11908
|
});
|
|
11809
11909
|
await this.#db.createIndexFromStatement("idx_om_lookup_key", `CREATE INDEX IF NOT EXISTS idx_om_lookup_key ON ${omTableName} ("lookupKey")`);
|
|
11910
|
+
await this.#backfillSupersededBy(omTableName);
|
|
11810
11911
|
}
|
|
11811
11912
|
await this.#db.createTable({
|
|
11812
11913
|
tableName: TABLE_MEMORY_RUN_FENCES,
|
|
@@ -13404,6 +13505,115 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13404
13505
|
async #getLatestOMRow(client, tableName, lookupKey) {
|
|
13405
13506
|
return client.oneOrNone(`SELECT * FROM ${tableName} WHERE "lookupKey" = $1 ORDER BY ${OM_GENERATION_ORDER} LIMIT 1`, [lookupKey]);
|
|
13406
13507
|
}
|
|
13508
|
+
#omTableName() {
|
|
13509
|
+
return getTableName$3({
|
|
13510
|
+
indexName: OM_TABLE,
|
|
13511
|
+
schemaName: getSchemaName$3(this.#schema)
|
|
13512
|
+
});
|
|
13513
|
+
}
|
|
13514
|
+
/** Row-locks one OM record by primary key for the rest of the transaction. */
|
|
13515
|
+
async #lockOMRow(t, tableName, id) {
|
|
13516
|
+
return t.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1 FOR UPDATE`, [id]);
|
|
13517
|
+
}
|
|
13518
|
+
/**
|
|
13519
|
+
* The live, row-locked record a lifecycle write aimed at `row` lands on: `row` itself while
|
|
13520
|
+
* live, otherwise the head of its lookup key (locked, then re-checked — a rollover may retire
|
|
13521
|
+
* it between the head read and the lock).
|
|
13522
|
+
*/
|
|
13523
|
+
async #resolveLiveOMRow(t, tableName, row) {
|
|
13524
|
+
let current = row;
|
|
13525
|
+
for (let hop = 0; current.supersededBy; hop++) {
|
|
13526
|
+
const head = hop < OM_MAX_HEAD_HOPS ? await this.#getLatestOMRow(t, tableName, current.lookupKey) : null;
|
|
13527
|
+
const locked = head && head.id !== current.id ? await this.#lockOMRow(t, tableName, head.id) : null;
|
|
13528
|
+
if (!locked) throw new MastraError({
|
|
13529
|
+
id: createStorageErrorId("PG", "RESOLVE_OBSERVATIONAL_MEMORY_HEAD", "FAILED"),
|
|
13530
|
+
text: `Observational memory record ${row.id} is superseded but no live head was found`,
|
|
13531
|
+
domain: ErrorDomain.STORAGE,
|
|
13532
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
13533
|
+
details: { id: row.id }
|
|
13534
|
+
});
|
|
13535
|
+
current = locked;
|
|
13536
|
+
}
|
|
13537
|
+
return current;
|
|
13538
|
+
}
|
|
13539
|
+
/**
|
|
13540
|
+
* Retire every live row that sorts after its key's canonical head, marking it superseded by
|
|
13541
|
+
* the head. Rows retired by older adapter versions (which never set `supersededBy`) become
|
|
13542
|
+
* frozen. One statement: the head's ordering key is part of the condition, and a row the
|
|
13543
|
+
* statement waits on (a head being retired by a concurrent rollover) is re-checked against
|
|
13544
|
+
* `"supersededBy" IS NULL` after that rollover commits.
|
|
13545
|
+
*/
|
|
13546
|
+
async #backfillSupersededBy(tableName) {
|
|
13547
|
+
await this.#db.client.none(`UPDATE ${tableName} AS r SET "supersededBy" = h.id
|
|
13548
|
+
FROM (
|
|
13549
|
+
SELECT DISTINCT ON ("lookupKey") "lookupKey", id, "generationCount", "createdAt"
|
|
13550
|
+
FROM ${tableName}
|
|
13551
|
+
WHERE "lookupKey" IN (
|
|
13552
|
+
SELECT "lookupKey" FROM ${tableName} WHERE "supersededBy" IS NULL GROUP BY "lookupKey" HAVING COUNT(*) > 1
|
|
13553
|
+
)
|
|
13554
|
+
ORDER BY "lookupKey", ${OM_GENERATION_ORDER}
|
|
13555
|
+
) AS h
|
|
13556
|
+
WHERE r."lookupKey" = h."lookupKey"
|
|
13557
|
+
AND r."supersededBy" IS NULL
|
|
13558
|
+
AND (
|
|
13559
|
+
r."generationCount" < h."generationCount"
|
|
13560
|
+
OR (r."generationCount" = h."generationCount" AND r."createdAt" > h."createdAt")
|
|
13561
|
+
OR (r."generationCount" = h."generationCount" AND r."createdAt" = h."createdAt" AND r.id > h.id)
|
|
13562
|
+
)`);
|
|
13563
|
+
}
|
|
13564
|
+
/**
|
|
13565
|
+
* Create the next generation from the stored (live, row-locked) record and retire the stored
|
|
13566
|
+
* record in the same transaction. Carried columns are copied in SQL from the stored row, so
|
|
13567
|
+
* nothing round-trips through a client-side timezone conversion. Buffered chunks move to the
|
|
13568
|
+
* new generation; the cursor, buffering markers, flags, and counters carry over; buffered
|
|
13569
|
+
* reflection state does not.
|
|
13570
|
+
*/
|
|
13571
|
+
async #rollOverOMRow(t, tableName, storedId, observations, tokenCount, newRecordId) {
|
|
13572
|
+
const id = newRecordId ?? crypto.randomUUID();
|
|
13573
|
+
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
13574
|
+
const inserted = await t.one(`INSERT INTO ${tableName} (
|
|
13575
|
+
id, "lookupKey", scope, "resourceId", "threadId",
|
|
13576
|
+
"activeObservations", "activeObservationsPendingUpdate",
|
|
13577
|
+
"originType", config, "generationCount", "lastObservedAt", "lastObservedAtZ", "lastReflectionAt", "lastReflectionAtZ",
|
|
13578
|
+
"pendingMessageTokens", "totalTokensObserved", "observationTokenCount", "bufferedObservationChunks",
|
|
13579
|
+
"isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
|
|
13580
|
+
"observedTimezone", metadata, "supersededBy", "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
|
|
13581
|
+
)
|
|
13582
|
+
SELECT
|
|
13583
|
+
$1, "lookupKey", scope, "resourceId", "threadId",
|
|
13584
|
+
$2, NULL,
|
|
13585
|
+
'reflection', config, "generationCount" + 1, "lastObservedAt", "lastObservedAtZ", $4, $5,
|
|
13586
|
+
"pendingMessageTokens", "totalTokensObserved", $3, "bufferedObservationChunks",
|
|
13587
|
+
false, false, "isBufferingObservation", false, "lastBufferedAtTokens", "lastBufferedAtTime",
|
|
13588
|
+
"observedTimezone", metadata, NULL, $6, $7, $8, $9
|
|
13589
|
+
FROM ${tableName} WHERE id = $10
|
|
13590
|
+
RETURNING *`, [
|
|
13591
|
+
id,
|
|
13592
|
+
observations,
|
|
13593
|
+
Math.round(tokenCount),
|
|
13594
|
+
nowStr,
|
|
13595
|
+
nowStr,
|
|
13596
|
+
nowStr,
|
|
13597
|
+
nowStr,
|
|
13598
|
+
nowStr,
|
|
13599
|
+
nowStr,
|
|
13600
|
+
storedId
|
|
13601
|
+
]);
|
|
13602
|
+
if ((await t.query(`UPDATE ${tableName} SET "supersededBy" = $1, "bufferedObservationChunks" = NULL, "updatedAt" = $2, "updatedAtZ" = $3
|
|
13603
|
+
WHERE id = $4 AND "supersededBy" IS NULL`, [
|
|
13604
|
+
id,
|
|
13605
|
+
nowStr,
|
|
13606
|
+
nowStr,
|
|
13607
|
+
storedId
|
|
13608
|
+
])).rowCount !== 1) throw new MastraError({
|
|
13609
|
+
id: createStorageErrorId("PG", "CREATE_REFLECTION_GENERATION", "RETIRE_FAILED"),
|
|
13610
|
+
text: `Failed to retire observational memory record ${storedId}`,
|
|
13611
|
+
domain: ErrorDomain.STORAGE,
|
|
13612
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
13613
|
+
details: { id: storedId }
|
|
13614
|
+
});
|
|
13615
|
+
return this.parseOMRow(inserted);
|
|
13616
|
+
}
|
|
13407
13617
|
parseOMRow(row) {
|
|
13408
13618
|
return {
|
|
13409
13619
|
id: row.id,
|
|
@@ -13432,11 +13642,12 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13432
13642
|
isBufferingObservation: row.isBufferingObservation === true || row.isBufferingObservation === "true",
|
|
13433
13643
|
isBufferingReflection: row.isBufferingReflection === true || row.isBufferingReflection === "true",
|
|
13434
13644
|
lastBufferedAtTokens: typeof row.lastBufferedAtTokens === "number" ? row.lastBufferedAtTokens : parseInt(String(row.lastBufferedAtTokens ?? "0"), 10) || 0,
|
|
13435
|
-
lastBufferedAtTime: row.lastBufferedAtTime ?
|
|
13645
|
+
lastBufferedAtTime: row.lastBufferedAtTime ? utcFromTimestampWithoutTimeZone(row.lastBufferedAtTime) : null,
|
|
13436
13646
|
config: row.config ? typeof row.config === "string" ? JSON.parse(row.config) : row.config : {},
|
|
13437
13647
|
metadata: row.metadata ? typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata : void 0,
|
|
13438
13648
|
observedMessageIds: row.observedMessageIds ? typeof row.observedMessageIds === "string" ? JSON.parse(row.observedMessageIds) : row.observedMessageIds : void 0,
|
|
13439
|
-
observedTimezone: row.observedTimezone || void 0
|
|
13649
|
+
observedTimezone: row.observedTimezone || void 0,
|
|
13650
|
+
supersededBy: row.supersededBy ?? null
|
|
13440
13651
|
};
|
|
13441
13652
|
}
|
|
13442
13653
|
async getObservationalMemory(threadId, resourceId) {
|
|
@@ -13446,7 +13657,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13446
13657
|
indexName: OM_TABLE,
|
|
13447
13658
|
schemaName: getSchemaName$3(this.#schema)
|
|
13448
13659
|
});
|
|
13449
|
-
const result = await this.#getLatestOMRow(this.#db.
|
|
13660
|
+
const result = await this.#getLatestOMRow(this.#db.client, tableName, lookupKey);
|
|
13450
13661
|
if (!result) return null;
|
|
13451
13662
|
return this.parseOMRow(result);
|
|
13452
13663
|
} catch (error) {
|
|
@@ -13529,9 +13740,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13529
13740
|
}
|
|
13530
13741
|
async initializeObservationalMemory(input) {
|
|
13531
13742
|
try {
|
|
13743
|
+
const lookupKey = this.getOMKey(input.threadId, input.resourceId);
|
|
13532
13744
|
const id = crypto.randomUUID();
|
|
13533
13745
|
const now = /* @__PURE__ */ new Date();
|
|
13534
|
-
const lookupKey = this.getOMKey(input.threadId, input.resourceId);
|
|
13535
13746
|
const record = {
|
|
13536
13747
|
id,
|
|
13537
13748
|
scope: input.scope,
|
|
@@ -13553,7 +13764,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13553
13764
|
lastBufferedAtTokens: 0,
|
|
13554
13765
|
lastBufferedAtTime: null,
|
|
13555
13766
|
config: input.config,
|
|
13556
|
-
observedTimezone: input.observedTimezone
|
|
13767
|
+
observedTimezone: input.observedTimezone,
|
|
13768
|
+
supersededBy: null
|
|
13557
13769
|
};
|
|
13558
13770
|
const tableName = getTableName$3({
|
|
13559
13771
|
indexName: OM_TABLE,
|
|
@@ -13633,8 +13845,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13633
13845
|
"reflectedObservationLineCount",
|
|
13634
13846
|
"isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection",
|
|
13635
13847
|
"lastBufferedAtTokens", "lastBufferedAtTime",
|
|
13636
|
-
"observedTimezone", metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
|
|
13637
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35)`, [
|
|
13848
|
+
"observedTimezone", metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ", "supersededBy"
|
|
13849
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36)`, [
|
|
13638
13850
|
record.id,
|
|
13639
13851
|
lookupKey,
|
|
13640
13852
|
record.scope,
|
|
@@ -13669,7 +13881,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13669
13881
|
record.createdAt.toISOString(),
|
|
13670
13882
|
record.createdAt.toISOString(),
|
|
13671
13883
|
record.updatedAt.toISOString(),
|
|
13672
|
-
record.updatedAt.toISOString()
|
|
13884
|
+
record.updatedAt.toISOString(),
|
|
13885
|
+
record.supersededBy ?? null
|
|
13673
13886
|
]);
|
|
13674
13887
|
} catch (error) {
|
|
13675
13888
|
throw new MastraError({
|
|
@@ -13685,41 +13898,55 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13685
13898
|
}
|
|
13686
13899
|
}
|
|
13687
13900
|
async updateActiveObservations(input) {
|
|
13901
|
+
assertActiveObservationsApplied(await this.commitActiveObservations(input), input.id);
|
|
13902
|
+
}
|
|
13903
|
+
async commitActiveObservations(input) {
|
|
13688
13904
|
try {
|
|
13689
|
-
const
|
|
13690
|
-
const
|
|
13691
|
-
indexName: OM_TABLE,
|
|
13692
|
-
schemaName: getSchemaName$3(this.#schema)
|
|
13693
|
-
});
|
|
13694
|
-
const lastObservedAtStr = input.lastObservedAt.toISOString();
|
|
13695
|
-
const nowStr = now.toISOString();
|
|
13905
|
+
const tableName = this.#omTableName();
|
|
13906
|
+
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
13696
13907
|
const observedMessageIdsJson = input.observedMessageIds ? toPgJson(input.observedMessageIds) : null;
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
input.
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13908
|
+
const fence = resolveRunFence(this, void 0);
|
|
13909
|
+
return await this.#db.client.tx(async (t) => {
|
|
13910
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "commitActiveObservations");
|
|
13911
|
+
const row = await this.#lockOMRow(t, tableName, input.id);
|
|
13912
|
+
if (!row) throw new MastraError({
|
|
13913
|
+
id: createStorageErrorId("PG", "UPDATE_ACTIVE_OBSERVATIONS", "NOT_FOUND"),
|
|
13914
|
+
text: `Observational memory record not found: ${input.id}`,
|
|
13915
|
+
domain: ErrorDomain.STORAGE,
|
|
13916
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
13917
|
+
details: { id: input.id }
|
|
13918
|
+
});
|
|
13919
|
+
if (row.supersededBy) return {
|
|
13920
|
+
applied: false,
|
|
13921
|
+
reason: "retired"
|
|
13922
|
+
};
|
|
13923
|
+
if (input.expectedActiveObservations !== void 0 && input.expectedActiveObservations !== (row.activeObservations || "")) return {
|
|
13924
|
+
applied: false,
|
|
13925
|
+
reason: "conflict"
|
|
13926
|
+
};
|
|
13927
|
+
const lastObservedAtStr = maxObservationCursor(row.lastObservedAtZ, input.lastObservedAt).toISOString();
|
|
13928
|
+
await t.none(`UPDATE ${tableName} SET
|
|
13929
|
+
"activeObservations" = $1,
|
|
13930
|
+
"lastObservedAt" = $2,
|
|
13931
|
+
"lastObservedAtZ" = $3,
|
|
13932
|
+
"pendingMessageTokens" = 0,
|
|
13933
|
+
"observationTokenCount" = $4,
|
|
13934
|
+
"totalTokensObserved" = "totalTokensObserved" + $5,
|
|
13935
|
+
"observedMessageIds" = $6,
|
|
13936
|
+
"updatedAt" = $7,
|
|
13937
|
+
"updatedAtZ" = $8
|
|
13938
|
+
WHERE id = $9`, [
|
|
13939
|
+
input.observations,
|
|
13940
|
+
lastObservedAtStr,
|
|
13941
|
+
lastObservedAtStr,
|
|
13942
|
+
Math.round(input.tokenCount),
|
|
13943
|
+
Math.round(input.tokenCount),
|
|
13944
|
+
observedMessageIdsJson,
|
|
13945
|
+
nowStr,
|
|
13946
|
+
nowStr,
|
|
13947
|
+
input.id
|
|
13948
|
+
]);
|
|
13949
|
+
return { applied: true };
|
|
13723
13950
|
});
|
|
13724
13951
|
} catch (error) {
|
|
13725
13952
|
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
@@ -13733,18 +13960,27 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13733
13960
|
}
|
|
13734
13961
|
async createReflectionGeneration(input) {
|
|
13735
13962
|
try {
|
|
13736
|
-
const
|
|
13737
|
-
const
|
|
13738
|
-
|
|
13739
|
-
schemaName: getSchemaName$3(this.#schema)
|
|
13740
|
-
});
|
|
13963
|
+
const { currentRecord } = input;
|
|
13964
|
+
const lookupKey = this.getOMKey(currentRecord.threadId, currentRecord.resourceId);
|
|
13965
|
+
const tableName = this.#omTableName();
|
|
13741
13966
|
return await this.#withOMLookupKeyLock(tableName, lookupKey, async (t) => {
|
|
13742
|
-
const
|
|
13743
|
-
if (
|
|
13744
|
-
return this.#
|
|
13967
|
+
const row = await this.#lockOMRow(t, tableName, currentRecord.id);
|
|
13968
|
+
if (!row) return currentRecord;
|
|
13969
|
+
if (row.supersededBy) return this.parseOMRow(await this.#resolveLiveOMRow(t, tableName, row));
|
|
13970
|
+
const stored = this.parseOMRow(row);
|
|
13971
|
+
const plan = planReflectionGenerationText({
|
|
13972
|
+
storedObservations: stored.activeObservations,
|
|
13973
|
+
storedObservationTokenCount: stored.observationTokenCount,
|
|
13974
|
+
snapshotObservations: currentRecord.activeObservations,
|
|
13975
|
+
snapshotObservationTokenCount: currentRecord.observationTokenCount,
|
|
13976
|
+
reflection: input.reflection,
|
|
13977
|
+
tokenCount: input.tokenCount
|
|
13978
|
+
});
|
|
13979
|
+
if (!plan) return stored;
|
|
13980
|
+
return this.#rollOverOMRow(t, tableName, stored.id, plan.observations, plan.tokenCount, input.newRecordId);
|
|
13745
13981
|
}, "createReflectionGeneration");
|
|
13746
13982
|
} catch (error) {
|
|
13747
|
-
if (
|
|
13983
|
+
if (error instanceof MastraError) throw error;
|
|
13748
13984
|
throw new MastraError({
|
|
13749
13985
|
id: createStorageErrorId("PG", "CREATE_REFLECTION_GENERATION", "FAILED"),
|
|
13750
13986
|
domain: ErrorDomain.STORAGE,
|
|
@@ -13753,84 +13989,6 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13753
13989
|
}, error);
|
|
13754
13990
|
}
|
|
13755
13991
|
}
|
|
13756
|
-
/**
|
|
13757
|
-
* Returns the active record when another writer already created a generation
|
|
13758
|
-
* after `generationCount`. Reflecting from the older generation again would
|
|
13759
|
-
* add a second record with the same generation.
|
|
13760
|
-
*/
|
|
13761
|
-
async #getNewerOMGeneration(t, tableName, lookupKey, generationCount) {
|
|
13762
|
-
const latest = await this.#getLatestOMRow(t, tableName, lookupKey);
|
|
13763
|
-
return latest && Number(latest.generationCount) > generationCount ? this.parseOMRow(latest) : null;
|
|
13764
|
-
}
|
|
13765
|
-
async #insertReflectionGeneration(t, tableName, lookupKey, input) {
|
|
13766
|
-
const id = crypto.randomUUID();
|
|
13767
|
-
const now = /* @__PURE__ */ new Date();
|
|
13768
|
-
const record = {
|
|
13769
|
-
id,
|
|
13770
|
-
scope: input.currentRecord.scope,
|
|
13771
|
-
threadId: input.currentRecord.threadId,
|
|
13772
|
-
resourceId: input.currentRecord.resourceId,
|
|
13773
|
-
createdAt: now,
|
|
13774
|
-
updatedAt: now,
|
|
13775
|
-
lastObservedAt: input.currentRecord.lastObservedAt,
|
|
13776
|
-
originType: "reflection",
|
|
13777
|
-
generationCount: input.currentRecord.generationCount + 1,
|
|
13778
|
-
activeObservations: input.reflection,
|
|
13779
|
-
totalTokensObserved: input.currentRecord.totalTokensObserved,
|
|
13780
|
-
observationTokenCount: input.tokenCount,
|
|
13781
|
-
pendingMessageTokens: 0,
|
|
13782
|
-
isReflecting: false,
|
|
13783
|
-
isObserving: false,
|
|
13784
|
-
isBufferingObservation: false,
|
|
13785
|
-
isBufferingReflection: false,
|
|
13786
|
-
lastBufferedAtTokens: 0,
|
|
13787
|
-
lastBufferedAtTime: null,
|
|
13788
|
-
config: input.currentRecord.config,
|
|
13789
|
-
metadata: input.currentRecord.metadata,
|
|
13790
|
-
observedTimezone: input.currentRecord.observedTimezone
|
|
13791
|
-
};
|
|
13792
|
-
const nowStr = now.toISOString();
|
|
13793
|
-
const lastObservedAtStr = record.lastObservedAt?.toISOString() || null;
|
|
13794
|
-
await t.none(`INSERT INTO ${tableName} (
|
|
13795
|
-
id, "lookupKey", scope, "resourceId", "threadId",
|
|
13796
|
-
"activeObservations", "activeObservationsPendingUpdate",
|
|
13797
|
-
"originType", config, "generationCount", "lastObservedAt", "lastObservedAtZ", "lastReflectionAt", "lastReflectionAtZ",
|
|
13798
|
-
"pendingMessageTokens", "totalTokensObserved", "observationTokenCount",
|
|
13799
|
-
"isObserving", "isReflecting", "isBufferingObservation", "isBufferingReflection", "lastBufferedAtTokens", "lastBufferedAtTime",
|
|
13800
|
-
"observedTimezone", metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
|
|
13801
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29)`, [
|
|
13802
|
-
id,
|
|
13803
|
-
lookupKey,
|
|
13804
|
-
record.scope,
|
|
13805
|
-
record.resourceId,
|
|
13806
|
-
record.threadId || null,
|
|
13807
|
-
input.reflection,
|
|
13808
|
-
null,
|
|
13809
|
-
"reflection",
|
|
13810
|
-
toPgJson(record.config),
|
|
13811
|
-
input.currentRecord.generationCount + 1,
|
|
13812
|
-
lastObservedAtStr,
|
|
13813
|
-
lastObservedAtStr,
|
|
13814
|
-
nowStr,
|
|
13815
|
-
nowStr,
|
|
13816
|
-
record.pendingMessageTokens,
|
|
13817
|
-
Math.round(record.totalTokensObserved),
|
|
13818
|
-
Math.round(record.observationTokenCount),
|
|
13819
|
-
false,
|
|
13820
|
-
false,
|
|
13821
|
-
false,
|
|
13822
|
-
false,
|
|
13823
|
-
0,
|
|
13824
|
-
null,
|
|
13825
|
-
record.observedTimezone || null,
|
|
13826
|
-
record.metadata ? toPgJson(record.metadata) : null,
|
|
13827
|
-
nowStr,
|
|
13828
|
-
nowStr,
|
|
13829
|
-
nowStr,
|
|
13830
|
-
nowStr
|
|
13831
|
-
]);
|
|
13832
|
-
return record;
|
|
13833
|
-
}
|
|
13834
13992
|
async setReflectingFlag(id, isReflecting) {
|
|
13835
13993
|
try {
|
|
13836
13994
|
const tableName = getTableName$3({
|
|
@@ -13903,41 +14061,35 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13903
14061
|
}
|
|
13904
14062
|
async setBufferingObservationFlag(id, isBuffering, lastBufferedAtTokens) {
|
|
13905
14063
|
try {
|
|
13906
|
-
const tableName =
|
|
13907
|
-
indexName: OM_TABLE,
|
|
13908
|
-
schemaName: getSchemaName$3(this.#schema)
|
|
13909
|
-
});
|
|
14064
|
+
const tableName = this.#omTableName();
|
|
13910
14065
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
14066
|
+
await this.#db.client.tx(async (t) => {
|
|
14067
|
+
const row = await this.#lockOMRow(t, tableName, id);
|
|
14068
|
+
if (!row) throw new MastraError({
|
|
14069
|
+
id: createStorageErrorId("PG", "SET_BUFFERING_OBSERVATION_FLAG", "NOT_FOUND"),
|
|
14070
|
+
text: `Observational memory record not found: ${id}`,
|
|
14071
|
+
domain: ErrorDomain.STORAGE,
|
|
14072
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
14073
|
+
details: {
|
|
14074
|
+
id,
|
|
14075
|
+
isBuffering,
|
|
14076
|
+
lastBufferedAtTokens: lastBufferedAtTokens ?? null
|
|
14077
|
+
}
|
|
14078
|
+
});
|
|
14079
|
+
const target = await this.#resolveLiveOMRow(t, tableName, row);
|
|
14080
|
+
if (lastBufferedAtTokens !== void 0) await t.none(`UPDATE ${tableName} SET "isBufferingObservation" = $1, "lastBufferedAtTokens" = $2, "updatedAt" = $3, "updatedAtZ" = $4 WHERE id = $5`, [
|
|
13916
14081
|
isBuffering,
|
|
13917
14082
|
Math.round(lastBufferedAtTokens),
|
|
13918
14083
|
nowStr,
|
|
13919
14084
|
nowStr,
|
|
13920
|
-
id
|
|
13921
|
-
];
|
|
13922
|
-
|
|
13923
|
-
query = `UPDATE ${tableName} SET "isBufferingObservation" = $1, "updatedAt" = $2, "updatedAtZ" = $3 WHERE id = $4`;
|
|
13924
|
-
values = [
|
|
14085
|
+
target.id
|
|
14086
|
+
]);
|
|
14087
|
+
else await t.none(`UPDATE ${tableName} SET "isBufferingObservation" = $1, "updatedAt" = $2, "updatedAtZ" = $3 WHERE id = $4`, [
|
|
13925
14088
|
isBuffering,
|
|
13926
14089
|
nowStr,
|
|
13927
14090
|
nowStr,
|
|
13928
|
-
id
|
|
13929
|
-
];
|
|
13930
|
-
}
|
|
13931
|
-
if ((await this.#db.client.query(query, values)).rowCount === 0) throw new MastraError({
|
|
13932
|
-
id: createStorageErrorId("PG", "SET_BUFFERING_OBSERVATION_FLAG", "NOT_FOUND"),
|
|
13933
|
-
text: `Observational memory record not found: ${id}`,
|
|
13934
|
-
domain: ErrorDomain.STORAGE,
|
|
13935
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
13936
|
-
details: {
|
|
13937
|
-
id,
|
|
13938
|
-
isBuffering,
|
|
13939
|
-
lastBufferedAtTokens: lastBufferedAtTokens ?? null
|
|
13940
|
-
}
|
|
14091
|
+
target.id
|
|
14092
|
+
]);
|
|
13941
14093
|
});
|
|
13942
14094
|
} catch (error) {
|
|
13943
14095
|
if (error instanceof MastraError) throw error;
|
|
@@ -14010,29 +14162,27 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14010
14162
|
}
|
|
14011
14163
|
async setPendingMessageTokens(id, tokenCount) {
|
|
14012
14164
|
try {
|
|
14013
|
-
const tableName =
|
|
14014
|
-
indexName: OM_TABLE,
|
|
14015
|
-
schemaName: getSchemaName$3(this.#schema)
|
|
14016
|
-
});
|
|
14165
|
+
const tableName = this.#omTableName();
|
|
14017
14166
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
14018
|
-
|
|
14019
|
-
|
|
14020
|
-
|
|
14021
|
-
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
14167
|
+
await this.#db.client.tx(async (t) => {
|
|
14168
|
+
const row = await this.#lockOMRow(t, tableName, id);
|
|
14169
|
+
if (!row) throw new MastraError({
|
|
14170
|
+
id: createStorageErrorId("PG", "SET_PENDING_MESSAGE_TOKENS", "NOT_FOUND"),
|
|
14171
|
+
text: `Observational memory record not found: ${id}`,
|
|
14172
|
+
domain: ErrorDomain.STORAGE,
|
|
14173
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
14174
|
+
details: {
|
|
14175
|
+
id,
|
|
14176
|
+
tokenCount
|
|
14177
|
+
}
|
|
14178
|
+
});
|
|
14179
|
+
const target = await this.#resolveLiveOMRow(t, tableName, row);
|
|
14180
|
+
await t.none(`UPDATE ${tableName} SET "pendingMessageTokens" = $1, "updatedAt" = $2, "updatedAtZ" = $3 WHERE id = $4`, [
|
|
14181
|
+
Math.round(tokenCount),
|
|
14182
|
+
nowStr,
|
|
14183
|
+
nowStr,
|
|
14184
|
+
target.id
|
|
14185
|
+
]);
|
|
14036
14186
|
});
|
|
14037
14187
|
} catch (error) {
|
|
14038
14188
|
if (error instanceof MastraError) throw error;
|
|
@@ -14082,11 +14232,11 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14082
14232
|
}
|
|
14083
14233
|
}
|
|
14084
14234
|
async updateBufferedObservations(input) {
|
|
14235
|
+
await this.appendBufferedObservations(input);
|
|
14236
|
+
}
|
|
14237
|
+
async appendBufferedObservations(input) {
|
|
14085
14238
|
try {
|
|
14086
|
-
const tableName =
|
|
14087
|
-
indexName: OM_TABLE,
|
|
14088
|
-
schemaName: getSchemaName$3(this.#schema)
|
|
14089
|
-
});
|
|
14239
|
+
const tableName = this.#omTableName();
|
|
14090
14240
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
14091
14241
|
const newChunk = {
|
|
14092
14242
|
id: `ombuf-${globalThis.crypto.randomUUID()}`,
|
|
@@ -14103,32 +14253,42 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14103
14253
|
extractedValues: input.chunk.extractedValues,
|
|
14104
14254
|
extractionFailures: input.chunk.extractionFailures
|
|
14105
14255
|
};
|
|
14106
|
-
const
|
|
14107
|
-
|
|
14108
|
-
|
|
14109
|
-
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
lastBufferedAtTime
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
|
|
14256
|
+
const fence = resolveRunFence(this, void 0);
|
|
14257
|
+
return await this.#db.client.tx(async (t) => {
|
|
14258
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "appendBufferedObservations");
|
|
14259
|
+
const row = await this.#lockOMRow(t, tableName, input.id);
|
|
14260
|
+
if (!row) throw new MastraError({
|
|
14261
|
+
id: createStorageErrorId("PG", "UPDATE_BUFFERED_OBSERVATIONS", "NOT_FOUND"),
|
|
14262
|
+
text: `Observational memory record not found: ${input.id}`,
|
|
14263
|
+
domain: ErrorDomain.STORAGE,
|
|
14264
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
14265
|
+
details: { id: input.id }
|
|
14266
|
+
});
|
|
14267
|
+
const target = this.parseOMRow(await this.#resolveLiveOMRow(t, tableName, row));
|
|
14268
|
+
if ((Array.isArray(target.bufferedObservationChunks) ? target.bufferedObservationChunks : []).some((existing) => existing.cycleId === input.chunk.cycleId) || isBufferedChunkCoveredByCursor(input.chunk.lastObservedAt, target.lastObservedAt)) return {
|
|
14269
|
+
persisted: false,
|
|
14270
|
+
recordId: target.id
|
|
14271
|
+
};
|
|
14272
|
+
const lastBufferedAtTime = input.lastBufferedAtTime ? input.lastBufferedAtTime.toISOString() : null;
|
|
14273
|
+
await t.none(`UPDATE ${tableName} SET
|
|
14274
|
+
"bufferedObservationChunks" = CASE
|
|
14275
|
+
WHEN jsonb_typeof("bufferedObservationChunks") = 'array' THEN "bufferedObservationChunks" || $1::jsonb
|
|
14276
|
+
ELSE $1::jsonb
|
|
14277
|
+
END,
|
|
14278
|
+
"lastBufferedAtTime" = GREATEST("lastBufferedAtTime", $2::timestamp),
|
|
14279
|
+
"updatedAt" = $3,
|
|
14280
|
+
"updatedAtZ" = $4
|
|
14281
|
+
WHERE id = $5`, [
|
|
14282
|
+
toPgJson([newChunk]),
|
|
14283
|
+
lastBufferedAtTime,
|
|
14284
|
+
nowStr,
|
|
14285
|
+
nowStr,
|
|
14286
|
+
target.id
|
|
14287
|
+
]);
|
|
14288
|
+
return {
|
|
14289
|
+
persisted: true,
|
|
14290
|
+
recordId: target.id
|
|
14291
|
+
};
|
|
14132
14292
|
});
|
|
14133
14293
|
} catch (error) {
|
|
14134
14294
|
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
@@ -14147,73 +14307,86 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14147
14307
|
schemaName: getSchemaName$3(this.#schema)
|
|
14148
14308
|
});
|
|
14149
14309
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
14150
|
-
const
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14185
|
-
|
|
14186
|
-
|
|
14187
|
-
|
|
14310
|
+
const fence = resolveRunFence(this, void 0);
|
|
14311
|
+
return await this.#db.client.tx(async (t) => {
|
|
14312
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "swapBufferedToActive");
|
|
14313
|
+
const record = await this.#lockOMRow(t, tableName, input.id);
|
|
14314
|
+
if (!record) throw new MastraError({
|
|
14315
|
+
id: createStorageErrorId("PG", "SWAP_BUFFERED_TO_ACTIVE", "NOT_FOUND"),
|
|
14316
|
+
text: `Observational memory record not found: ${input.id}`,
|
|
14317
|
+
domain: ErrorDomain.STORAGE,
|
|
14318
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
14319
|
+
details: { id: input.id }
|
|
14320
|
+
});
|
|
14321
|
+
const emptyResult = {
|
|
14322
|
+
chunksActivated: 0,
|
|
14323
|
+
messageTokensActivated: 0,
|
|
14324
|
+
observationTokensActivated: 0,
|
|
14325
|
+
messagesActivated: 0,
|
|
14326
|
+
activatedCycleIds: [],
|
|
14327
|
+
activatedMessageIds: []
|
|
14328
|
+
};
|
|
14329
|
+
if (record.supersededBy) return {
|
|
14330
|
+
...emptyResult,
|
|
14331
|
+
retired: true
|
|
14332
|
+
};
|
|
14333
|
+
let persistedChunks = [];
|
|
14334
|
+
if (record.bufferedObservationChunks) try {
|
|
14335
|
+
const parsed = typeof record.bufferedObservationChunks === "string" ? JSON.parse(record.bufferedObservationChunks) : record.bufferedObservationChunks;
|
|
14336
|
+
persistedChunks = Array.isArray(parsed) ? parsed : [];
|
|
14337
|
+
} catch {
|
|
14338
|
+
persistedChunks = [];
|
|
14339
|
+
}
|
|
14340
|
+
const refreshedWeights = new Map((Array.isArray(input.bufferedChunks) ? input.bufferedChunks : []).map((c) => [c.id, c.messageTokens]));
|
|
14341
|
+
const chunks = persistedChunks.map((c) => refreshedWeights.has(c.id) ? {
|
|
14342
|
+
...c,
|
|
14343
|
+
messageTokens: refreshedWeights.get(c.id)
|
|
14344
|
+
} : c);
|
|
14345
|
+
if (chunks.length === 0) return emptyResult;
|
|
14346
|
+
const retentionFloor = input.messageTokensThreshold * (1 - input.activationRatio);
|
|
14347
|
+
const targetMessageTokens = Math.max(0, input.currentPendingTokens - retentionFloor);
|
|
14348
|
+
let cumulativeMessageTokens = 0;
|
|
14349
|
+
let chunksToActivate = 0;
|
|
14350
|
+
let bestOverBoundary = 0;
|
|
14351
|
+
let bestOverTokens = 0;
|
|
14352
|
+
let bestUnderBoundary = 0;
|
|
14353
|
+
let bestUnderTokens = 0;
|
|
14354
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
14355
|
+
cumulativeMessageTokens += chunks[i].messageTokens ?? 0;
|
|
14356
|
+
const boundary = i + 1;
|
|
14357
|
+
if (cumulativeMessageTokens >= targetMessageTokens) {
|
|
14358
|
+
if (bestOverBoundary === 0 || cumulativeMessageTokens < bestOverTokens) {
|
|
14359
|
+
bestOverBoundary = boundary;
|
|
14360
|
+
bestOverTokens = cumulativeMessageTokens;
|
|
14361
|
+
}
|
|
14362
|
+
} else if (cumulativeMessageTokens > bestUnderTokens) {
|
|
14363
|
+
bestUnderBoundary = boundary;
|
|
14364
|
+
bestUnderTokens = cumulativeMessageTokens;
|
|
14188
14365
|
}
|
|
14189
|
-
} else if (cumulativeMessageTokens > bestUnderTokens) {
|
|
14190
|
-
bestUnderBoundary = boundary;
|
|
14191
|
-
bestUnderTokens = cumulativeMessageTokens;
|
|
14192
14366
|
}
|
|
14193
|
-
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
if ((await this.#fenced(void 0, "swapBufferedToActive", (q) => q.query(`UPDATE ${tableName} SET
|
|
14367
|
+
const maxOvershoot = retentionFloor * .95;
|
|
14368
|
+
const overshoot = bestOverTokens - targetMessageTokens;
|
|
14369
|
+
const remainingAfterOver = input.currentPendingTokens - bestOverTokens;
|
|
14370
|
+
const remainingAfterUnder = input.currentPendingTokens - bestUnderTokens;
|
|
14371
|
+
const minRemaining = Math.min(1e3, retentionFloor);
|
|
14372
|
+
if (input.forceMaxActivation && bestOverBoundary > 0 && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
14373
|
+
else if (bestOverBoundary > 0 && overshoot <= maxOvershoot && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
14374
|
+
else if (bestUnderBoundary > 0 && remainingAfterUnder >= minRemaining) chunksToActivate = bestUnderBoundary;
|
|
14375
|
+
else if (bestOverBoundary > 0) chunksToActivate = bestOverBoundary;
|
|
14376
|
+
else chunksToActivate = 1;
|
|
14377
|
+
const activatedChunks = chunks.slice(0, chunksToActivate);
|
|
14378
|
+
const remainingChunks = persistedChunks.slice(chunksToActivate);
|
|
14379
|
+
const activatedContent = activatedChunks.map((c) => c.observations).join("\n\n");
|
|
14380
|
+
const activatedTokens = Math.round(activatedChunks.reduce((sum, c) => sum + c.tokenCount, 0));
|
|
14381
|
+
const activatedMessageTokens = Math.round(activatedChunks.reduce((sum, c) => sum + (c.messageTokens ?? 0), 0));
|
|
14382
|
+
const activatedMessageCount = activatedChunks.reduce((sum, c) => sum + c.messageIds.length, 0);
|
|
14383
|
+
const activatedCycleIds = activatedChunks.map((c) => c.cycleId).filter((id) => !!id);
|
|
14384
|
+
const activatedMessageIds = activatedChunks.flatMap((c) => c.messageIds ?? []);
|
|
14385
|
+
const latestChunk = activatedChunks[activatedChunks.length - 1];
|
|
14386
|
+
const lastObservedAt = input.lastObservedAt ?? (latestChunk?.lastObservedAt ? new Date(latestChunk.lastObservedAt) : /* @__PURE__ */ new Date());
|
|
14387
|
+
const lastObservedAtStr = maxObservationCursor(record.lastObservedAtZ, lastObservedAt).toISOString();
|
|
14388
|
+
const boundary = `\n\n--- message boundary (${lastObservedAt.toISOString()}) ---\n\n`;
|
|
14389
|
+
if ((await t.query(`UPDATE ${tableName} SET
|
|
14217
14390
|
"activeObservations" = CASE
|
|
14218
14391
|
WHEN "activeObservations" IS NOT NULL AND "activeObservations" != ''
|
|
14219
14392
|
THEN "activeObservations" || $10 || $1
|
|
@@ -14227,45 +14400,40 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14227
14400
|
"updatedAt" = $7,
|
|
14228
14401
|
"updatedAtZ" = $8
|
|
14229
14402
|
WHERE id = $9
|
|
14403
|
+
AND "supersededBy" IS NULL
|
|
14230
14404
|
AND "bufferedObservationChunks" IS NOT NULL
|
|
14231
14405
|
AND "bufferedObservationChunks"::text != '[]'`, [
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
messageCount: c.messageIds.length,
|
|
14264
|
-
observations: c.observations
|
|
14265
|
-
})),
|
|
14266
|
-
suggestedContinuation: latestChunkHints?.suggestedContinuation ?? void 0,
|
|
14267
|
-
currentTask: latestChunkHints?.currentTask ?? void 0
|
|
14268
|
-
};
|
|
14406
|
+
activatedContent,
|
|
14407
|
+
activatedTokens,
|
|
14408
|
+
activatedMessageTokens,
|
|
14409
|
+
remainingChunks.length > 0 ? toPgJson(remainingChunks) : null,
|
|
14410
|
+
lastObservedAtStr,
|
|
14411
|
+
lastObservedAtStr,
|
|
14412
|
+
nowStr,
|
|
14413
|
+
nowStr,
|
|
14414
|
+
input.id,
|
|
14415
|
+
boundary
|
|
14416
|
+
])).rowCount === 0) return emptyResult;
|
|
14417
|
+
const latestChunkHints = activatedChunks[activatedChunks.length - 1];
|
|
14418
|
+
return {
|
|
14419
|
+
chunksActivated: activatedChunks.length,
|
|
14420
|
+
messageTokensActivated: activatedMessageTokens,
|
|
14421
|
+
observationTokensActivated: activatedTokens,
|
|
14422
|
+
messagesActivated: activatedMessageCount,
|
|
14423
|
+
activatedCycleIds,
|
|
14424
|
+
activatedMessageIds,
|
|
14425
|
+
observations: activatedContent,
|
|
14426
|
+
perChunk: activatedChunks.map((c) => ({
|
|
14427
|
+
cycleId: c.cycleId ?? "",
|
|
14428
|
+
messageTokens: c.messageTokens ?? 0,
|
|
14429
|
+
observationTokens: c.tokenCount,
|
|
14430
|
+
messageCount: c.messageIds.length,
|
|
14431
|
+
observations: c.observations
|
|
14432
|
+
})),
|
|
14433
|
+
suggestedContinuation: latestChunkHints?.suggestedContinuation ?? void 0,
|
|
14434
|
+
currentTask: latestChunkHints?.currentTask ?? void 0
|
|
14435
|
+
};
|
|
14436
|
+
});
|
|
14269
14437
|
} catch (error) {
|
|
14270
14438
|
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
14271
14439
|
throw new MastraError({
|
|
@@ -14321,50 +14489,40 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14321
14489
|
}
|
|
14322
14490
|
async swapBufferedReflectionToActive(input) {
|
|
14323
14491
|
try {
|
|
14324
|
-
const
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
});
|
|
14328
|
-
const lookupKey = this.getOMKey(input.currentRecord.threadId, input.currentRecord.resourceId);
|
|
14492
|
+
const { currentRecord } = input;
|
|
14493
|
+
const tableName = this.#omTableName();
|
|
14494
|
+
const lookupKey = this.getOMKey(currentRecord.threadId, currentRecord.resourceId);
|
|
14329
14495
|
return await this.#withOMLookupKeyLock(tableName, lookupKey, async (t) => {
|
|
14330
|
-
const
|
|
14331
|
-
if (
|
|
14332
|
-
|
|
14333
|
-
|
|
14334
|
-
|
|
14335
|
-
text: `Observational memory record not found: ${input.currentRecord.id}`,
|
|
14336
|
-
domain: ErrorDomain.STORAGE,
|
|
14337
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
14338
|
-
details: { id: input.currentRecord.id }
|
|
14339
|
-
});
|
|
14340
|
-
const bufferedReflection = record.bufferedReflection || "";
|
|
14341
|
-
const reflectedLineCount = Number(record.reflectedObservationLineCount || 0);
|
|
14496
|
+
const row = await this.#lockOMRow(t, tableName, currentRecord.id);
|
|
14497
|
+
if (!row) return currentRecord;
|
|
14498
|
+
if (row.supersededBy) return this.parseOMRow(await this.#resolveLiveOMRow(t, tableName, row));
|
|
14499
|
+
const stored = this.parseOMRow(row);
|
|
14500
|
+
const bufferedReflection = stored.bufferedReflection || "";
|
|
14342
14501
|
if (!bufferedReflection) throw new MastraError({
|
|
14343
14502
|
id: createStorageErrorId("PG", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "NO_CONTENT"),
|
|
14344
14503
|
text: "No buffered reflection to swap",
|
|
14345
14504
|
domain: ErrorDomain.STORAGE,
|
|
14346
14505
|
category: ErrorCategory.USER,
|
|
14347
|
-
details: { id:
|
|
14506
|
+
details: { id: currentRecord.id }
|
|
14348
14507
|
});
|
|
14349
|
-
|
|
14508
|
+
if (!isAppendOnlySince(stored.activeObservations, currentRecord.activeObservations)) return stored;
|
|
14509
|
+
const reflectedLineCount = stored.reflectedObservationLineCount ?? 0;
|
|
14510
|
+
const unreflectedContent = (stored.activeObservations || "").split("\n").slice(reflectedLineCount).join("\n").trim();
|
|
14350
14511
|
const newObservations = unreflectedContent ? `${bufferedReflection}\n\n${unreflectedContent}` : bufferedReflection;
|
|
14351
|
-
const
|
|
14352
|
-
|
|
14353
|
-
reflection: newObservations,
|
|
14354
|
-
tokenCount: input.tokenCount
|
|
14355
|
-
});
|
|
14512
|
+
const tokenCount = input.tokenCount + Math.max(0, (stored.observationTokenCount ?? 0) - (currentRecord.observationTokenCount ?? 0));
|
|
14513
|
+
const newRecord = await this.#rollOverOMRow(t, tableName, stored.id, newObservations, tokenCount, input.newRecordId);
|
|
14356
14514
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
14357
|
-
await t.
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
|
|
14515
|
+
await t.none(`UPDATE ${tableName} SET
|
|
14516
|
+
"bufferedReflection" = NULL,
|
|
14517
|
+
"bufferedReflectionTokens" = NULL,
|
|
14518
|
+
"bufferedReflectionInputTokens" = NULL,
|
|
14519
|
+
"reflectedObservationLineCount" = NULL,
|
|
14520
|
+
"updatedAt" = $1,
|
|
14521
|
+
"updatedAtZ" = $2
|
|
14522
|
+
WHERE id = $3`, [
|
|
14365
14523
|
nowStr,
|
|
14366
14524
|
nowStr,
|
|
14367
|
-
|
|
14525
|
+
stored.id
|
|
14368
14526
|
]);
|
|
14369
14527
|
return newRecord;
|
|
14370
14528
|
}, "swapBufferedReflectionToActive");
|
|
@@ -24969,25 +25127,9 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24969
25127
|
schemaName: getSchemaName(this.#schema)
|
|
24970
25128
|
});
|
|
24971
25129
|
const existingSnapshotResult = await t.oneOrNone(`SELECT snapshot FROM ${tableName} WHERE workflow_name = $1 AND run_id = $2 FOR UPDATE`, [workflowName, runId]);
|
|
24972
|
-
|
|
24973
|
-
|
|
24974
|
-
|
|
24975
|
-
activePaths: [],
|
|
24976
|
-
timestamp: Date.now(),
|
|
24977
|
-
suspendedPaths: {},
|
|
24978
|
-
activeStepsPath: {},
|
|
24979
|
-
resumeLabels: {},
|
|
24980
|
-
serializedStepGraph: [],
|
|
24981
|
-
status: "pending",
|
|
24982
|
-
value: {},
|
|
24983
|
-
waitingPaths: {},
|
|
24984
|
-
runId,
|
|
24985
|
-
requestContext: {}
|
|
24986
|
-
};
|
|
24987
|
-
else {
|
|
24988
|
-
const existingSnapshot = existingSnapshotResult.snapshot;
|
|
24989
|
-
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
24990
|
-
}
|
|
25130
|
+
if (!existingSnapshotResult) return {};
|
|
25131
|
+
const existingSnapshot = existingSnapshotResult.snapshot;
|
|
25132
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
24991
25133
|
mergeWorkflowStepResult({
|
|
24992
25134
|
snapshot,
|
|
24993
25135
|
stepId,
|