@mastra/pg 1.24.1-alpha.0 → 1.25.0-alpha.2
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/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-memory-memory-class.md +2 -1
- package/dist/index.cjs +191 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +191 -45
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +15 -2
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/notifications/index.d.ts +6 -1
- package/dist/storage/domains/notifications/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +3 -2
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts +3 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/dist/vector/performance.helpers.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -10668,6 +10668,57 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
10668
10668
|
}, error);
|
|
10669
10669
|
}
|
|
10670
10670
|
}
|
|
10671
|
+
/**
|
|
10672
|
+
* Atomically reassign a thread and all of its messages to a different resource.
|
|
10673
|
+
*
|
|
10674
|
+
* Runs inside a single transaction and takes a `SELECT ... FOR UPDATE` row lock on the
|
|
10675
|
+
* thread, so overlapping transfers of the same thread serialize and can never interleave
|
|
10676
|
+
* the thread update with the message update. Either both the thread and every message move
|
|
10677
|
+
* to the new resource, or neither does — there is no split-ownership window. The thread's
|
|
10678
|
+
* `createdAt` is preserved. Callers are responsible for authorizing the reassignment.
|
|
10679
|
+
*/
|
|
10680
|
+
async updateThreadResourceId({ threadId, resourceId }) {
|
|
10681
|
+
const threadsTable = getTableName$3({
|
|
10682
|
+
indexName: TABLE_THREADS,
|
|
10683
|
+
schemaName: getSchemaName$3(this.#schema)
|
|
10684
|
+
});
|
|
10685
|
+
const messagesTable = getTableName$3({
|
|
10686
|
+
indexName: TABLE_MESSAGES,
|
|
10687
|
+
schemaName: getSchemaName$3(this.#schema)
|
|
10688
|
+
});
|
|
10689
|
+
try {
|
|
10690
|
+
return await this.#db.client.tx(async (t) => {
|
|
10691
|
+
const thread = await t.oneOrNone(`SELECT * FROM ${threadsTable} WHERE id = $1 FOR UPDATE`, [threadId]);
|
|
10692
|
+
if (!thread) throw new Error(`Thread "${threadId}" not found`);
|
|
10693
|
+
const normalized = {
|
|
10694
|
+
id: thread.id,
|
|
10695
|
+
resourceId: thread.resourceId,
|
|
10696
|
+
title: thread.title,
|
|
10697
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
10698
|
+
createdAt: thread.createdAtZ || thread.createdAt,
|
|
10699
|
+
updatedAt: thread.updatedAtZ || thread.updatedAt
|
|
10700
|
+
};
|
|
10701
|
+
if (thread.resourceId === resourceId) return normalized;
|
|
10702
|
+
await t.none(`UPDATE ${threadsTable} SET "resourceId" = $1, "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id = $2`, [resourceId, threadId]);
|
|
10703
|
+
await t.none(`UPDATE ${messagesTable} SET "resourceId" = $1 WHERE thread_id = $2`, [resourceId, threadId]);
|
|
10704
|
+
return {
|
|
10705
|
+
...normalized,
|
|
10706
|
+
resourceId,
|
|
10707
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
10708
|
+
};
|
|
10709
|
+
});
|
|
10710
|
+
} catch (error) {
|
|
10711
|
+
throw new MastraError({
|
|
10712
|
+
id: createStorageErrorId("PG", "UPDATE_THREAD_RESOURCE_ID", "FAILED"),
|
|
10713
|
+
domain: ErrorDomain.STORAGE,
|
|
10714
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
10715
|
+
details: {
|
|
10716
|
+
threadId,
|
|
10717
|
+
resourceId
|
|
10718
|
+
}
|
|
10719
|
+
}, error);
|
|
10720
|
+
}
|
|
10721
|
+
}
|
|
10671
10722
|
async listThreads(args) {
|
|
10672
10723
|
const { page = 0, perPage: perPageInput, orderBy, filter } = args;
|
|
10673
10724
|
try {
|
|
@@ -11672,7 +11723,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11672
11723
|
await this.#db.client.none(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = $${paramIndex}`, values);
|
|
11673
11724
|
return updatedResource;
|
|
11674
11725
|
}
|
|
11675
|
-
async
|
|
11726
|
+
async copyThread(args) {
|
|
11676
11727
|
const { sourceThreadId, newThreadId: providedThreadId, resourceId, title, metadata, options } = args;
|
|
11677
11728
|
const sourceThread = await this.#getThreadById(this.#db.client, { threadId: sourceThreadId });
|
|
11678
11729
|
if (!sourceThread) throw new MastraError({
|
|
@@ -11698,10 +11749,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11698
11749
|
indexName: TABLE_MESSAGES,
|
|
11699
11750
|
schemaName: getSchemaName$3(this.#schema)
|
|
11700
11751
|
});
|
|
11701
|
-
const hydrateMessages = options?.hydrateMessages ?? true;
|
|
11702
11752
|
try {
|
|
11703
11753
|
return await this.#db.client.tx(async (t) => {
|
|
11704
|
-
let messageQuery = `SELECT
|
|
11754
|
+
let messageQuery = `SELECT id, "createdAt"
|
|
11705
11755
|
FROM ${messageTableName} WHERE thread_id = $1`;
|
|
11706
11756
|
const messageParams = [sourceThreadId];
|
|
11707
11757
|
let paramIndex = 2;
|
|
@@ -11762,54 +11812,23 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11762
11812
|
nowStr,
|
|
11763
11813
|
nowStr
|
|
11764
11814
|
]);
|
|
11765
|
-
const clonedMessages = [];
|
|
11766
11815
|
const messageIdMap = {};
|
|
11767
11816
|
const targetResourceId = resourceId || sourceThread.resourceId;
|
|
11768
11817
|
for (const sourceMsg of sourceMessages) {
|
|
11769
11818
|
const newMessageId = crypto.randomUUID();
|
|
11770
11819
|
messageIdMap[sourceMsg.id] = newMessageId;
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
FROM ${messageTableName} WHERE id = $4`, [
|
|
11775
|
-
newMessageId,
|
|
11776
|
-
newThreadId,
|
|
11777
|
-
targetResourceId,
|
|
11778
|
-
sourceMsg.id
|
|
11779
|
-
]);
|
|
11780
|
-
if (insertResult.rowCount !== 1) throw new Error(`Failed to clone message ${sourceMsg.id}: expected 1 row copied but got ${insertResult.rowCount}`);
|
|
11781
|
-
continue;
|
|
11782
|
-
}
|
|
11783
|
-
const normalizedMsg = this.normalizeMessageRow(sourceMsg);
|
|
11784
|
-
let parsedContent = normalizedMsg.content;
|
|
11785
|
-
try {
|
|
11786
|
-
parsedContent = JSON.parse(normalizedMsg.content);
|
|
11787
|
-
} catch {}
|
|
11788
|
-
const createdAt = toUtcISOString(new Date(normalizedMsg.createdAt));
|
|
11789
|
-
await t.none(`INSERT INTO ${messageTableName} (id, thread_id, content, "createdAt", "createdAtZ", role, type, "resourceId")
|
|
11790
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
|
|
11820
|
+
const insertResult = await t.query(`INSERT INTO ${messageTableName} (id, thread_id, content, "createdAt", "createdAtZ", role, type, "resourceId")
|
|
11821
|
+
SELECT $1, $2, content, "createdAt", "createdAtZ", role, type, $3
|
|
11822
|
+
FROM ${messageTableName} WHERE id = $4`, [
|
|
11791
11823
|
newMessageId,
|
|
11792
11824
|
newThreadId,
|
|
11793
|
-
|
|
11794
|
-
|
|
11795
|
-
createdAt,
|
|
11796
|
-
normalizedMsg.role,
|
|
11797
|
-
normalizedMsg.type || "v2",
|
|
11798
|
-
targetResourceId
|
|
11825
|
+
targetResourceId,
|
|
11826
|
+
sourceMsg.id
|
|
11799
11827
|
]);
|
|
11800
|
-
|
|
11801
|
-
id: newMessageId,
|
|
11802
|
-
threadId: newThreadId,
|
|
11803
|
-
content: parsedContent,
|
|
11804
|
-
role: normalizedMsg.role,
|
|
11805
|
-
type: normalizedMsg.type,
|
|
11806
|
-
createdAt: new Date(normalizedMsg.createdAt),
|
|
11807
|
-
resourceId: targetResourceId
|
|
11808
|
-
});
|
|
11828
|
+
if (insertResult.rowCount !== 1) throw new Error(`Failed to copy message ${sourceMsg.id}: expected 1 row copied but got ${insertResult.rowCount}`);
|
|
11809
11829
|
}
|
|
11810
11830
|
return {
|
|
11811
11831
|
thread: newThread,
|
|
11812
|
-
clonedMessages,
|
|
11813
11832
|
messageIdMap
|
|
11814
11833
|
};
|
|
11815
11834
|
});
|
|
@@ -13164,6 +13183,27 @@ var NotificationsPG = class NotificationsPG extends NotificationsStorage {
|
|
|
13164
13183
|
if (!updated) throw new Error(`Notification ${input.id} was not found for thread ${input.threadId}`);
|
|
13165
13184
|
return updated;
|
|
13166
13185
|
}
|
|
13186
|
+
async updateNotificationsStatus(input) {
|
|
13187
|
+
const ids = Array.from(new Set(input.ids));
|
|
13188
|
+
if (ids.length === 0) return [];
|
|
13189
|
+
const now = /* @__PURE__ */ new Date();
|
|
13190
|
+
const assignments = {
|
|
13191
|
+
status: input.status,
|
|
13192
|
+
...statusTimestamp(input.status, now),
|
|
13193
|
+
updatedAt: now
|
|
13194
|
+
};
|
|
13195
|
+
const columns = Object.keys(assignments);
|
|
13196
|
+
const setClause = columns.map((column, index) => `"${parseSqlIdentifier(column, "column name")}" = $${index + 1}`).join(", ");
|
|
13197
|
+
const tableName = getTableName$5({
|
|
13198
|
+
indexName: TABLE_NOTIFICATIONS,
|
|
13199
|
+
schemaName: getSchemaName$5(this.#schema)
|
|
13200
|
+
});
|
|
13201
|
+
return (await this.#db.client.manyOrNone(`UPDATE ${tableName} SET ${setClause} WHERE "threadId" = $${columns.length + 1} AND "id" = ANY($${columns.length + 2}::text[]) RETURNING *`, [
|
|
13202
|
+
...Object.values(assignments),
|
|
13203
|
+
input.threadId,
|
|
13204
|
+
ids
|
|
13205
|
+
])).map(rowToNotification);
|
|
13206
|
+
}
|
|
13167
13207
|
async findCoalescable(input) {
|
|
13168
13208
|
if (!input.dedupeKey && !input.coalesceKey) return void 0;
|
|
13169
13209
|
const tableName = getTableName$5({
|
|
@@ -17318,6 +17358,13 @@ function collectRelationCollections(predicate, collections = /* @__PURE__ */ new
|
|
|
17318
17358
|
else if (predicate.type === "not") collectRelationCollections(predicate.arg, collections);
|
|
17319
17359
|
return collections;
|
|
17320
17360
|
}
|
|
17361
|
+
function collectThreadRelationCollections(predicate, collections) {
|
|
17362
|
+
if (!predicate) return collections;
|
|
17363
|
+
if (predicate.type === "relation") collectRelationCollections(predicate.predicate, collections);
|
|
17364
|
+
else if (predicate.type === "boolean") for (const arg of predicate.args) collectThreadRelationCollections(arg, collections);
|
|
17365
|
+
else collectThreadRelationCollections(predicate.arg, collections);
|
|
17366
|
+
return collections;
|
|
17367
|
+
}
|
|
17321
17368
|
function compilePredicate(predicate, parameterOffset) {
|
|
17322
17369
|
if (predicate.type === "relation") {
|
|
17323
17370
|
const compiled = predicate.collection === "feedback" ? compileFeedbackScalarPredicate(predicate.predicate, parameterOffset) : compileScalarPredicate(predicate.predicate, predicate.collection === "spans" ? SPAN_FIELDS : SCORE_FIELDS, parameterOffset);
|
|
@@ -17352,12 +17399,41 @@ function compilePredicate(predicate, parameterOffset) {
|
|
|
17352
17399
|
}
|
|
17353
17400
|
return compileScalarPredicate(predicate, TRACE_FIELDS, parameterOffset, true);
|
|
17354
17401
|
}
|
|
17355
|
-
function
|
|
17402
|
+
function compileThreadPredicate(predicate, parameterOffset) {
|
|
17403
|
+
if (predicate.type === "relation") {
|
|
17404
|
+
const compiled = compilePredicate(predicate.predicate, parameterOffset);
|
|
17405
|
+
const existence = `EXISTS (
|
|
17406
|
+
SELECT 1 FROM eligible_roots r
|
|
17407
|
+
WHERE r."threadId" = t."threadId"
|
|
17408
|
+
AND (${compiled.sql})
|
|
17409
|
+
)`;
|
|
17410
|
+
return {
|
|
17411
|
+
sql: predicate.quantifier === "some" ? existence : `NOT ${existence}`,
|
|
17412
|
+
values: compiled.values
|
|
17413
|
+
};
|
|
17414
|
+
}
|
|
17415
|
+
if (predicate.type === "boolean") {
|
|
17416
|
+
const values = [];
|
|
17417
|
+
return {
|
|
17418
|
+
sql: predicate.args.map((arg) => {
|
|
17419
|
+
const compiled = compileThreadPredicate(arg, parameterOffset + values.length);
|
|
17420
|
+
values.push(...compiled.values);
|
|
17421
|
+
return `(${compiled.sql})`;
|
|
17422
|
+
}).join(predicate.operator === "and" ? " AND " : " OR "),
|
|
17423
|
+
values
|
|
17424
|
+
};
|
|
17425
|
+
}
|
|
17426
|
+
const compiled = compileThreadPredicate(predicate.arg, parameterOffset);
|
|
17427
|
+
return {
|
|
17428
|
+
sql: `NOT (${compiled.sql})`,
|
|
17429
|
+
values: compiled.values
|
|
17430
|
+
};
|
|
17431
|
+
}
|
|
17432
|
+
function compilePostgresTraceScope(schema, selection, relationCollections) {
|
|
17356
17433
|
const spanTable = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
17357
17434
|
const scoreTable = qualifiedTable(schema, TABLE_SCORE_EVENTS);
|
|
17358
17435
|
const feedbackTable = qualifiedTable(schema, TABLE_FEEDBACK_EVENTS);
|
|
17359
|
-
const values = [
|
|
17360
|
-
const relationCollections = collectRelationCollections(plan.where);
|
|
17436
|
+
const values = [selection.timeRange.from, selection.timeRange.to];
|
|
17361
17437
|
const ctes = [`root_scope AS MATERIALIZED (
|
|
17362
17438
|
SELECT *
|
|
17363
17439
|
FROM ${spanTable} r
|
|
@@ -17432,6 +17508,13 @@ function compilePostgresTraceQuery(schema, plan) {
|
|
|
17432
17508
|
AND s."traceId" IN (SELECT "traceId" FROM root_scope)
|
|
17433
17509
|
AND ${latestFeedbackPredicate(feedbackTable)}
|
|
17434
17510
|
)`);
|
|
17511
|
+
return {
|
|
17512
|
+
ctes,
|
|
17513
|
+
values
|
|
17514
|
+
};
|
|
17515
|
+
}
|
|
17516
|
+
function compilePostgresTraceQuery(schema, plan) {
|
|
17517
|
+
const { ctes, values } = compilePostgresTraceScope(schema, plan, collectRelationCollections(plan.where));
|
|
17435
17518
|
let predicateSql = "TRUE";
|
|
17436
17519
|
if (plan.where) {
|
|
17437
17520
|
const predicate = compilePredicate(plan.where, values.length + 1);
|
|
@@ -17479,6 +17562,51 @@ LIMIT $${values.length}`,
|
|
|
17479
17562
|
values
|
|
17480
17563
|
};
|
|
17481
17564
|
}
|
|
17565
|
+
function compilePostgresThreadQuery(schema, plan) {
|
|
17566
|
+
const relationCollections = collectRelationCollections(plan.traces.where);
|
|
17567
|
+
collectThreadRelationCollections(plan.where, relationCollections);
|
|
17568
|
+
const { ctes, values } = compilePostgresTraceScope(schema, plan.traces, relationCollections);
|
|
17569
|
+
let eligibilitySql = "TRUE";
|
|
17570
|
+
if (plan.traces.where) {
|
|
17571
|
+
const eligibility = compilePredicate(plan.traces.where, values.length + 1);
|
|
17572
|
+
eligibilitySql = eligibility.sql;
|
|
17573
|
+
values.push(...eligibility.values);
|
|
17574
|
+
}
|
|
17575
|
+
ctes.push(`eligible_roots AS MATERIALIZED (
|
|
17576
|
+
SELECT *
|
|
17577
|
+
FROM root_scope r
|
|
17578
|
+
WHERE ${eligibilitySql}
|
|
17579
|
+
)`);
|
|
17580
|
+
ctes.push(`thread_ids AS (
|
|
17581
|
+
SELECT "threadId" COLLATE "C" AS "threadId"
|
|
17582
|
+
FROM eligible_roots
|
|
17583
|
+
WHERE "threadId" IS NOT NULL
|
|
17584
|
+
GROUP BY "threadId" COLLATE "C"
|
|
17585
|
+
)`);
|
|
17586
|
+
let threadPredicateSql = "TRUE";
|
|
17587
|
+
if (plan.where) {
|
|
17588
|
+
const predicate = compileThreadPredicate(plan.where, values.length + 1);
|
|
17589
|
+
threadPredicateSql = predicate.sql;
|
|
17590
|
+
values.push(...predicate.values);
|
|
17591
|
+
}
|
|
17592
|
+
ctes.push(`qualified_threads AS (
|
|
17593
|
+
SELECT t."threadId"
|
|
17594
|
+
FROM thread_ids t
|
|
17595
|
+
WHERE ${threadPredicateSql}
|
|
17596
|
+
)`);
|
|
17597
|
+
const pageCondition = plan.cursor ? `WHERE "threadId" > $${values.length + 1}` : "";
|
|
17598
|
+
if (plan.cursor) values.push(plan.cursor.threadId);
|
|
17599
|
+
values.push(plan.limit + 1);
|
|
17600
|
+
return {
|
|
17601
|
+
text: `WITH ${ctes.join(",\n")}
|
|
17602
|
+
SELECT "threadId"
|
|
17603
|
+
FROM qualified_threads
|
|
17604
|
+
${pageCondition}
|
|
17605
|
+
ORDER BY "threadId" ASC
|
|
17606
|
+
LIMIT $${values.length}`,
|
|
17607
|
+
values
|
|
17608
|
+
};
|
|
17609
|
+
}
|
|
17482
17610
|
function asIsoTimestamp$1(value) {
|
|
17483
17611
|
if (value === null || value === void 0) throw new Error("Trace query returned a null timestamp");
|
|
17484
17612
|
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
|
@@ -17537,6 +17665,19 @@ async function queryTraces(client, schema, plan, timeoutMs) {
|
|
|
17537
17665
|
}) : null }
|
|
17538
17666
|
});
|
|
17539
17667
|
}
|
|
17668
|
+
async function queryThreads(client, schema, plan, timeoutMs) {
|
|
17669
|
+
const query = compilePostgresThreadQuery(schema, plan);
|
|
17670
|
+
const rows = await runWithPostgresTraceQueryTimeout(client, timeoutMs, (transaction) => transaction.any(query.text, query.values));
|
|
17671
|
+
const threads = rows.slice(0, plan.limit).map((row) => ({ threadId: String(row.threadId) }));
|
|
17672
|
+
const last = threads.at(-1);
|
|
17673
|
+
return coreStorage.queryThreadsResultSchema.parse({
|
|
17674
|
+
threads,
|
|
17675
|
+
page: { next: rows.length > plan.limit && last ? coreStorage.encodeTraceQueryCursor(plan, {
|
|
17676
|
+
result: "threads",
|
|
17677
|
+
threadId: last.threadId
|
|
17678
|
+
}) : null }
|
|
17679
|
+
});
|
|
17680
|
+
}
|
|
17540
17681
|
//#endregion
|
|
17541
17682
|
//#region src/storage/domains/observability/v-next/traces.ts
|
|
17542
17683
|
/**
|
|
@@ -18432,13 +18573,15 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
18432
18573
|
if (!deltaPollingFeatureEnabled()) return [
|
|
18433
18574
|
"metrics",
|
|
18434
18575
|
"logs",
|
|
18435
|
-
"trace-query"
|
|
18576
|
+
"trace-query",
|
|
18577
|
+
"thread-query"
|
|
18436
18578
|
];
|
|
18437
18579
|
return [
|
|
18438
18580
|
"metrics",
|
|
18439
18581
|
"logs",
|
|
18440
18582
|
"delta-polling",
|
|
18441
|
-
"trace-query"
|
|
18583
|
+
"trace-query",
|
|
18584
|
+
"thread-query"
|
|
18442
18585
|
];
|
|
18443
18586
|
}
|
|
18444
18587
|
async #run(op, fn, details) {
|
|
@@ -18484,6 +18627,9 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
18484
18627
|
async queryTraces(plan) {
|
|
18485
18628
|
return this.#run("QUERY_TRACES", () => queryTraces(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
18486
18629
|
}
|
|
18630
|
+
async queryThreads(plan) {
|
|
18631
|
+
return this.#run("QUERY_THREADS", () => queryThreads(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
18632
|
+
}
|
|
18487
18633
|
async listBranches(args) {
|
|
18488
18634
|
return this.#run("LIST_BRANCHES", () => listBranches(this.#readClient, this.#schema, args));
|
|
18489
18635
|
}
|