@mastra/pg 1.36.0-alpha.2 → 1.36.0-alpha.3
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 +20 -20
- package/dist/docs/references/reference-processors-semantic-recall-processor.md +2 -0
- package/dist/index.cjs +192 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +192 -56
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +12 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/feedback.d.ts +1 -0
- package/dist/storage/domains/observability/v-next/feedback.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +2 -1
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/sql.d.ts +2 -0
- package/dist/storage/domains/observability/v-next/sql.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/docs/SKILL.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.36.0-alpha.
|
|
2
|
+
"version": "1.36.0-alpha.3",
|
|
3
3
|
"package": "@mastra/pg",
|
|
4
4
|
"exports": {
|
|
5
5
|
"AgentsPG": {
|
|
@@ -55,32 +55,32 @@
|
|
|
55
55
|
"MemoryPG": {
|
|
56
56
|
"types": "dist/storage/domains/memory/index.d.ts",
|
|
57
57
|
"implementation": "dist/index.js",
|
|
58
|
-
"line":
|
|
58
|
+
"line": 11665
|
|
59
59
|
},
|
|
60
60
|
"NotificationsPG": {
|
|
61
61
|
"types": "dist/storage/domains/notifications/index.d.ts",
|
|
62
62
|
"implementation": "dist/index.js",
|
|
63
|
-
"line":
|
|
63
|
+
"line": 14562
|
|
64
64
|
},
|
|
65
65
|
"ObservabilityPG": {
|
|
66
66
|
"types": "dist/storage/domains/observability/index.d.ts",
|
|
67
67
|
"implementation": "dist/index.js",
|
|
68
|
-
"line":
|
|
68
|
+
"line": 14984
|
|
69
69
|
},
|
|
70
70
|
"ObservabilityStoragePostgresVNext": {
|
|
71
71
|
"types": "dist/storage/domains/observability/v-next/index.d.ts",
|
|
72
72
|
"implementation": "dist/index.js",
|
|
73
|
-
"line":
|
|
73
|
+
"line": 21941
|
|
74
74
|
},
|
|
75
75
|
"PGVECTOR_PROMPT": {
|
|
76
76
|
"types": "dist/vector/prompt.d.ts",
|
|
77
77
|
"implementation": "dist/index.js",
|
|
78
|
-
"line":
|
|
78
|
+
"line": 28617
|
|
79
79
|
},
|
|
80
80
|
"PgFactoryStorage": {
|
|
81
81
|
"types": "dist/storage/factory-storage.d.ts",
|
|
82
82
|
"implementation": "dist/index.js",
|
|
83
|
-
"line":
|
|
83
|
+
"line": 28103
|
|
84
84
|
},
|
|
85
85
|
"PgVector": {
|
|
86
86
|
"types": "dist/vector/index.d.ts",
|
|
@@ -95,67 +95,67 @@
|
|
|
95
95
|
"PostgresStore": {
|
|
96
96
|
"types": "dist/storage/index.d.ts",
|
|
97
97
|
"implementation": "dist/index.js",
|
|
98
|
-
"line":
|
|
98
|
+
"line": 28318
|
|
99
99
|
},
|
|
100
100
|
"PostgresStoreVNext": {
|
|
101
101
|
"types": "dist/storage/index.d.ts",
|
|
102
102
|
"implementation": "dist/index.js",
|
|
103
|
-
"line":
|
|
103
|
+
"line": 28536
|
|
104
104
|
},
|
|
105
105
|
"PromptBlocksPG": {
|
|
106
106
|
"types": "dist/storage/domains/prompt-blocks/index.d.ts",
|
|
107
107
|
"implementation": "dist/index.js",
|
|
108
|
-
"line":
|
|
108
|
+
"line": 22391
|
|
109
109
|
},
|
|
110
110
|
"SchedulesPG": {
|
|
111
111
|
"types": "dist/storage/domains/schedules/index.d.ts",
|
|
112
112
|
"implementation": "dist/index.js",
|
|
113
|
-
"line":
|
|
113
|
+
"line": 23018
|
|
114
114
|
},
|
|
115
115
|
"ScorerDefinitionsPG": {
|
|
116
116
|
"types": "dist/storage/domains/scorer-definitions/index.d.ts",
|
|
117
117
|
"implementation": "dist/index.js",
|
|
118
|
-
"line":
|
|
118
|
+
"line": 23339
|
|
119
119
|
},
|
|
120
120
|
"ScoresPG": {
|
|
121
121
|
"types": "dist/storage/domains/scores/index.d.ts",
|
|
122
122
|
"implementation": "dist/index.js",
|
|
123
|
-
"line":
|
|
123
|
+
"line": 23962
|
|
124
124
|
},
|
|
125
125
|
"SkillsPG": {
|
|
126
126
|
"types": "dist/storage/domains/skills/index.d.ts",
|
|
127
127
|
"implementation": "dist/index.js",
|
|
128
|
-
"line":
|
|
128
|
+
"line": 24405
|
|
129
129
|
},
|
|
130
130
|
"ThreadStatePG": {
|
|
131
131
|
"types": "dist/storage/domains/thread-state/index.d.ts",
|
|
132
132
|
"implementation": "dist/index.js",
|
|
133
|
-
"line":
|
|
133
|
+
"line": 25096
|
|
134
134
|
},
|
|
135
135
|
"ToolProviderConnectionsPG": {
|
|
136
136
|
"types": "dist/storage/domains/tool-provider-connections/index.d.ts",
|
|
137
137
|
"implementation": "dist/index.js",
|
|
138
|
-
"line":
|
|
138
|
+
"line": 25270
|
|
139
139
|
},
|
|
140
140
|
"WorkflowDefinitionsPG": {
|
|
141
141
|
"types": "dist/storage/domains/workflow-definitions/index.d.ts",
|
|
142
142
|
"implementation": "dist/index.js",
|
|
143
|
-
"line":
|
|
143
|
+
"line": 25534
|
|
144
144
|
},
|
|
145
145
|
"WorkflowsPG": {
|
|
146
146
|
"types": "dist/storage/domains/workflows/index.d.ts",
|
|
147
147
|
"implementation": "dist/index.js",
|
|
148
|
-
"line":
|
|
148
|
+
"line": 25917
|
|
149
149
|
},
|
|
150
150
|
"WorkspacesPG": {
|
|
151
151
|
"types": "dist/storage/domains/workspaces/index.d.ts",
|
|
152
152
|
"implementation": "dist/index.js",
|
|
153
|
-
"line":
|
|
153
|
+
"line": 27203
|
|
154
154
|
},
|
|
155
155
|
"exportSchemas": {
|
|
156
156
|
"types": "dist/storage/index.d.ts",
|
|
157
157
|
"implementation": "dist/index.js",
|
|
158
|
-
"line":
|
|
158
|
+
"line": 28285
|
|
159
159
|
}
|
|
160
160
|
},
|
|
161
161
|
"modules": {}
|
|
@@ -40,6 +40,8 @@ const processor = new SemanticRecall({
|
|
|
40
40
|
|
|
41
41
|
**options.threshold** (`number`): Minimum similarity score threshold (0-1). Messages below this threshold are filtered out
|
|
42
42
|
|
|
43
|
+
**options.filter** (`VectorFilter`): Metadata filter for the vector query, combined with the scope filter using $and. Messages are stored with their thread's metadata, so the filter can match thread metadata. For example, { projectId: { $eq: 'project-a' } }
|
|
44
|
+
|
|
43
45
|
**options.indexName** (`string`): Index name for the vector store. If not provided, auto-generated based on embedder model
|
|
44
46
|
|
|
45
47
|
**options.logger** (`IMastraLogger`): Optional logger instance for structured logging
|
package/dist/index.cjs
CHANGED
|
@@ -11678,6 +11678,13 @@ function dedupeMessagesForSave(messages) {
|
|
|
11678
11678
|
}
|
|
11679
11679
|
return Array.from(deduped.values());
|
|
11680
11680
|
}
|
|
11681
|
+
/** Shallow merge; keys patched to `undefined` are dropped when serialized. Non-object metadata is replaced. */
|
|
11682
|
+
function mergeMetadata(existing, patch) {
|
|
11683
|
+
return {
|
|
11684
|
+
...existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {},
|
|
11685
|
+
...patch
|
|
11686
|
+
};
|
|
11687
|
+
}
|
|
11681
11688
|
var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
|
|
11682
11689
|
supportsPartialThreadUpdate = true;
|
|
11683
11690
|
supportsObservationalMemory = true;
|
|
@@ -12244,7 +12251,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
|
|
|
12244
12251
|
const createdAt = toUtcISOString(thread.createdAt);
|
|
12245
12252
|
const updatedAt = toUtcISOString(thread.updatedAt);
|
|
12246
12253
|
const metadataJson = thread.metadata ? toPgJson(thread.metadata) : null;
|
|
12247
|
-
await this.#fenced(fence, "saveThread", (q) => q.
|
|
12254
|
+
const saved = await this.#fenced(fence, "saveThread", (q) => q.oneOrNone(`INSERT INTO ${tableName} AS t (
|
|
12248
12255
|
id,
|
|
12249
12256
|
"resourceId",
|
|
12250
12257
|
title,
|
|
@@ -12255,13 +12262,12 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
|
|
|
12255
12262
|
"updatedAtZ"
|
|
12256
12263
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
12257
12264
|
ON CONFLICT (id) DO UPDATE SET
|
|
12258
|
-
"resourceId" = EXCLUDED."resourceId",
|
|
12259
12265
|
title = EXCLUDED.title,
|
|
12260
12266
|
metadata = EXCLUDED.metadata,
|
|
12261
|
-
"createdAt" = EXCLUDED."createdAt",
|
|
12262
|
-
"createdAtZ" = EXCLUDED."createdAtZ",
|
|
12263
12267
|
"updatedAt" = EXCLUDED."updatedAt",
|
|
12264
|
-
"updatedAtZ" = EXCLUDED."updatedAtZ"
|
|
12268
|
+
"updatedAtZ" = EXCLUDED."updatedAtZ"
|
|
12269
|
+
WHERE t."resourceId" = EXCLUDED."resourceId"
|
|
12270
|
+
RETURNING *`, [
|
|
12265
12271
|
thread.id,
|
|
12266
12272
|
thread.resourceId,
|
|
12267
12273
|
thread.title,
|
|
@@ -12271,12 +12277,26 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
|
|
|
12271
12277
|
updatedAt,
|
|
12272
12278
|
updatedAt
|
|
12273
12279
|
]));
|
|
12280
|
+
if (!saved) throw new _mastra_core_error.MastraError({
|
|
12281
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SAVE_THREAD", "RESOURCE_ID_MISMATCH"),
|
|
12282
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
12283
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
12284
|
+
text: `Thread ${thread.id} already exists and belongs to a different resource. Use updateThreadResourceId to move a thread and its messages to another resource.`,
|
|
12285
|
+
details: {
|
|
12286
|
+
threadId: thread.id,
|
|
12287
|
+
resourceId: thread.resourceId
|
|
12288
|
+
}
|
|
12289
|
+
});
|
|
12274
12290
|
return {
|
|
12275
|
-
|
|
12276
|
-
|
|
12291
|
+
id: saved.id,
|
|
12292
|
+
resourceId: saved.resourceId,
|
|
12293
|
+
title: saved.title,
|
|
12294
|
+
metadata: saved.metadata == null ? void 0 : typeof saved.metadata === "string" ? JSON.parse(saved.metadata) : saved.metadata,
|
|
12295
|
+
createdAt: saved.createdAtZ || saved.createdAt,
|
|
12296
|
+
updatedAt: saved.updatedAtZ || saved.updatedAt
|
|
12277
12297
|
};
|
|
12278
12298
|
} catch (error) {
|
|
12279
|
-
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
12299
|
+
if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
12280
12300
|
throw new _mastra_core_error.MastraError({
|
|
12281
12301
|
id: (0, _mastra_core_storage.createStorageErrorId)("PG", "SAVE_THREAD", "FAILED"),
|
|
12282
12302
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -12285,52 +12305,125 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
|
|
|
12285
12305
|
}, error);
|
|
12286
12306
|
}
|
|
12287
12307
|
}
|
|
12288
|
-
|
|
12308
|
+
#toThread(row) {
|
|
12309
|
+
return {
|
|
12310
|
+
id: row.id,
|
|
12311
|
+
resourceId: row.resourceId,
|
|
12312
|
+
title: row.title,
|
|
12313
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata,
|
|
12314
|
+
createdAt: row.createdAtZ || row.createdAt,
|
|
12315
|
+
updatedAt: row.updatedAtZ || row.updatedAt
|
|
12316
|
+
};
|
|
12317
|
+
}
|
|
12318
|
+
async #lockThread(t, tableName, { id, resourceId }) {
|
|
12319
|
+
const params = [id];
|
|
12320
|
+
let query = `SELECT * FROM ${tableName} WHERE id = $1`;
|
|
12321
|
+
if (resourceId !== void 0) {
|
|
12322
|
+
query += ` AND "resourceId" = $2`;
|
|
12323
|
+
params.push(resourceId);
|
|
12324
|
+
}
|
|
12325
|
+
const row = await t.oneOrNone(`${query} FOR UPDATE`, params);
|
|
12326
|
+
return row ? this.#toThread(row) : null;
|
|
12327
|
+
}
|
|
12328
|
+
/**
|
|
12329
|
+
* Writes `title` (when given) and the full `metadata` value (when given).
|
|
12330
|
+
* Callers that merge metadata must hold the row lock from `#lockThread`.
|
|
12331
|
+
*/
|
|
12332
|
+
async #writeThread(q, tableName, { id, title, metadata }) {
|
|
12333
|
+
const nowStr = toUtcISOString(/* @__PURE__ */ new Date());
|
|
12334
|
+
const params = [
|
|
12335
|
+
title ?? null,
|
|
12336
|
+
nowStr,
|
|
12337
|
+
nowStr,
|
|
12338
|
+
id
|
|
12339
|
+
];
|
|
12340
|
+
let metadataSet = "";
|
|
12341
|
+
if (metadata !== void 0) {
|
|
12342
|
+
params.push(toPgJson(metadata));
|
|
12343
|
+
metadataSet = "metadata = $5,";
|
|
12344
|
+
}
|
|
12345
|
+
const row = await q.oneOrNone(`UPDATE ${tableName}
|
|
12346
|
+
SET
|
|
12347
|
+
title = COALESCE($1, title),
|
|
12348
|
+
${metadataSet}
|
|
12349
|
+
"updatedAt" = $2,
|
|
12350
|
+
"updatedAtZ" = $3
|
|
12351
|
+
WHERE id = $4
|
|
12352
|
+
RETURNING *`, params);
|
|
12353
|
+
return row ? this.#toThread(row) : null;
|
|
12354
|
+
}
|
|
12355
|
+
/**
|
|
12356
|
+
* Cross-process atomic metadata read-modify-write: the thread row stays locked
|
|
12357
|
+
* (`SELECT ... FOR UPDATE`) from the read through the write, so concurrent
|
|
12358
|
+
* writers from any process serialize instead of overwriting each other.
|
|
12359
|
+
*/
|
|
12360
|
+
async updateThreadMetadata({ id, resourceId, update, fence: explicitFence }) {
|
|
12361
|
+
const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence);
|
|
12362
|
+
const threadsTable = getTableName$3({
|
|
12363
|
+
indexName: _mastra_core_storage.TABLE_THREADS,
|
|
12364
|
+
schemaName: getSchemaName$3(this.#schema)
|
|
12365
|
+
});
|
|
12366
|
+
try {
|
|
12367
|
+
return await this.#db.client.tx(async (t) => {
|
|
12368
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "updateThreadMetadata");
|
|
12369
|
+
const thread = await this.#lockThread(t, threadsTable, {
|
|
12370
|
+
id,
|
|
12371
|
+
resourceId
|
|
12372
|
+
});
|
|
12373
|
+
if (!thread) return null;
|
|
12374
|
+
const metadata = update(thread);
|
|
12375
|
+
if (!metadata) return thread;
|
|
12376
|
+
return this.#writeThread(t, threadsTable, {
|
|
12377
|
+
id,
|
|
12378
|
+
metadata: mergeMetadata(thread.metadata, metadata)
|
|
12379
|
+
});
|
|
12380
|
+
});
|
|
12381
|
+
} catch (error) {
|
|
12382
|
+
if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
12383
|
+
throw new _mastra_core_error.MastraError({
|
|
12384
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD_METADATA", "FAILED"),
|
|
12385
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
12386
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
12387
|
+
details: { threadId: id }
|
|
12388
|
+
}, error);
|
|
12389
|
+
}
|
|
12390
|
+
}
|
|
12391
|
+
async updateThread({ id, title, metadata, fence: explicitFence }) {
|
|
12289
12392
|
const threadTableName = getTableName$3({
|
|
12290
12393
|
indexName: _mastra_core_storage.TABLE_THREADS,
|
|
12291
12394
|
schemaName: getSchemaName$3(this.#schema)
|
|
12292
12395
|
});
|
|
12396
|
+
const notFound = () => new _mastra_core_error.MastraError({
|
|
12397
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPDATE_THREAD", "FAILED"),
|
|
12398
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
12399
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
12400
|
+
text: `Thread ${id} not found`,
|
|
12401
|
+
details: {
|
|
12402
|
+
threadId: id,
|
|
12403
|
+
title: title ?? null
|
|
12404
|
+
}
|
|
12405
|
+
});
|
|
12293
12406
|
try {
|
|
12294
|
-
return await this.#fenced(
|
|
12295
|
-
const
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
12299
|
-
category: _mastra_core_error.ErrorCategory.USER,
|
|
12300
|
-
text: `Thread ${id} not found`,
|
|
12301
|
-
details: {
|
|
12302
|
-
threadId: id,
|
|
12303
|
-
title: title ?? null
|
|
12304
|
-
}
|
|
12407
|
+
if (metadata === void 0) return await this.#fenced(explicitFence, "updateThread", async (q) => {
|
|
12408
|
+
const thread = await this.#writeThread(q, threadTableName, {
|
|
12409
|
+
id,
|
|
12410
|
+
title
|
|
12305
12411
|
});
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
mergedMetadata,
|
|
12322
|
-
nowStr,
|
|
12323
|
-
nowStr,
|
|
12324
|
-
id
|
|
12325
|
-
]);
|
|
12326
|
-
return {
|
|
12327
|
-
id: thread.id,
|
|
12328
|
-
resourceId: thread.resourceId,
|
|
12329
|
-
title: thread.title,
|
|
12330
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
12331
|
-
createdAt: thread.createdAtZ || thread.createdAt,
|
|
12332
|
-
updatedAt: thread.updatedAtZ || thread.updatedAt
|
|
12333
|
-
};
|
|
12412
|
+
if (!thread) throw notFound();
|
|
12413
|
+
return thread;
|
|
12414
|
+
});
|
|
12415
|
+
const fence = (0, _mastra_core_storage.resolveRunFence)(this, explicitFence);
|
|
12416
|
+
return await this.#db.client.tx(async (t) => {
|
|
12417
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "updateThread");
|
|
12418
|
+
const existing = await this.#lockThread(t, threadTableName, { id });
|
|
12419
|
+
if (!existing) throw notFound();
|
|
12420
|
+
const thread = await this.#writeThread(t, threadTableName, {
|
|
12421
|
+
id,
|
|
12422
|
+
title,
|
|
12423
|
+
metadata: mergeMetadata(existing.metadata, metadata)
|
|
12424
|
+
});
|
|
12425
|
+
if (!thread) throw notFound();
|
|
12426
|
+
return thread;
|
|
12334
12427
|
});
|
|
12335
12428
|
} catch (error) {
|
|
12336
12429
|
if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
@@ -17386,8 +17479,12 @@ ${onConflict}`,
|
|
|
17386
17479
|
async function insertRows(client, schema, table, records, partitioning, onConflict) {
|
|
17387
17480
|
const insert = buildInsert(schema, table, records, onConflict);
|
|
17388
17481
|
if (!insert) return;
|
|
17482
|
+
await withPartitionRetry(client, schema, table, records, partitioning, () => client.query(insert.text, insert.values));
|
|
17483
|
+
}
|
|
17484
|
+
/** Retry a complete write after creating a missing native partition, outside any failed transaction. */
|
|
17485
|
+
async function withPartitionRetry(client, schema, table, records, partitioning, write) {
|
|
17389
17486
|
try {
|
|
17390
|
-
await
|
|
17487
|
+
return await write();
|
|
17391
17488
|
} catch (error) {
|
|
17392
17489
|
if (!isMissingPartitionError(error) || await resolveMode(client, partitioning) !== "native") throw error;
|
|
17393
17490
|
const days = withinPartitionWindow(recordDays(records, SIGNAL_TIME_COLUMN[table]), partitioning);
|
|
@@ -17400,7 +17497,7 @@ async function insertRows(client, schema, table, records, partitioning, onConfli
|
|
|
17400
17497
|
cause
|
|
17401
17498
|
}), { cause });
|
|
17402
17499
|
});
|
|
17403
|
-
await
|
|
17500
|
+
return await write();
|
|
17404
17501
|
}
|
|
17405
17502
|
}
|
|
17406
17503
|
/** `42501`: the role may not create the child, or does not own the parent it must attach to. */
|
|
@@ -18334,13 +18431,47 @@ function pushFeedbackIdentity(acc, feedbackType, feedbackSource) {
|
|
|
18334
18431
|
acc.conditions.push(`"valueNumber" IS NOT NULL`);
|
|
18335
18432
|
}
|
|
18336
18433
|
async function createFeedback(client, schema, args, partitioning) {
|
|
18337
|
-
|
|
18338
|
-
|
|
18434
|
+
await writeFeedback(client, schema, [args.feedback], args.onConflict, partitioning);
|
|
18435
|
+
}
|
|
18436
|
+
async function replaceFeedback(client, schema, args, partitioning) {
|
|
18437
|
+
await writeFeedback(client, schema, [args.feedback], "replace", partitioning, true);
|
|
18339
18438
|
}
|
|
18340
18439
|
async function batchCreateFeedback(client, schema, args, partitioning) {
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18440
|
+
await writeFeedback(client, schema, args.feedbacks, args.onConflict, partitioning);
|
|
18441
|
+
}
|
|
18442
|
+
/** Serialize feedback writes by ID, including absent IDs and retries with a different timestamp. */
|
|
18443
|
+
async function writeFeedback(client, schema, feedbacks, onConflict, partitioning, preserveIdentity = false) {
|
|
18444
|
+
if (!feedbacks.length) return;
|
|
18445
|
+
const currentFeedback = new Map((onConflict === "ignore" ? [...feedbacks].reverse() : feedbacks).map((feedback) => [feedback.feedbackId, feedback]));
|
|
18446
|
+
const rows = [...currentFeedback.values()].map(feedbackRecordToRow);
|
|
18447
|
+
const ids = [...currentFeedback.keys()].sort();
|
|
18448
|
+
await withPartitionRetry(client, schema, TABLE_FEEDBACK_EVENTS, rows, partitioning, () => client.tx(async (tx) => {
|
|
18449
|
+
await tx.query(`SELECT pg_advisory_xact_lock(hashtextextended(lock_key, 0))
|
|
18450
|
+
FROM unnest($1::text[]) WITH ORDINALITY AS locks(lock_key, position)
|
|
18451
|
+
ORDER BY position`, [ids.map((id) => JSON.stringify([
|
|
18452
|
+
schema,
|
|
18453
|
+
TABLE_FEEDBACK_EVENTS,
|
|
18454
|
+
id
|
|
18455
|
+
]))]);
|
|
18456
|
+
const existing = await tx.any(`SELECT DISTINCT ON ("feedbackId") "feedbackId", "traceId", "timestamp", "organizationId", "resourceId"
|
|
18457
|
+
FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
|
|
18458
|
+
WHERE "feedbackId" = ANY($1::text[]) ORDER BY "feedbackId", "cursorId" DESC`, [ids]);
|
|
18459
|
+
const byId = new Map(existing.map((row) => [row.feedbackId, row]));
|
|
18460
|
+
const accepted = rows.filter((row) => {
|
|
18461
|
+
const previous = byId.get(row.feedbackId);
|
|
18462
|
+
if (!previous) return true;
|
|
18463
|
+
if (onConflict === "ignore") return false;
|
|
18464
|
+
if (preserveIdentity && (previous.traceId !== row.traceId || new Date(previous.timestamp).getTime() !== new Date(row.timestamp).getTime() || (previous.organizationId ?? null) !== (row.organizationId ?? null) || (previous.resourceId ?? null) !== (row.resourceId ?? null))) throw new _mastra_core_error.MastraError({
|
|
18465
|
+
id: "OBSERVABILITY_FEEDBACK_IDENTITY_CONFLICT",
|
|
18466
|
+
domain: _mastra_core_error.ErrorDomain.MASTRA_OBSERVABILITY,
|
|
18467
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
18468
|
+
text: "Feedback replacement must preserve its trace, timestamp, and tenant"
|
|
18469
|
+
});
|
|
18470
|
+
return true;
|
|
18471
|
+
});
|
|
18472
|
+
const insert = buildInsert(schema, TABLE_FEEDBACK_EVENTS, accepted, FEEDBACK_UPSERT_CLAUSE);
|
|
18473
|
+
if (insert) await tx.query(insert.text, insert.values);
|
|
18474
|
+
}));
|
|
18344
18475
|
}
|
|
18345
18476
|
async function getFeedbackById(client, schema, feedbackId) {
|
|
18346
18477
|
const row = await client.oneOrNone(`SELECT ${FEEDBACK_SELECT_COLUMNS} FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
|
|
@@ -22031,6 +22162,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
22031
22162
|
"thread-query",
|
|
22032
22163
|
"trace-query-tenant-scope",
|
|
22033
22164
|
"feedback",
|
|
22165
|
+
"feedback-replacement",
|
|
22034
22166
|
"trace-query-context-ids",
|
|
22035
22167
|
...contextFieldFeatures,
|
|
22036
22168
|
...timingFeatures,
|
|
@@ -22059,6 +22191,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
22059
22191
|
"thread-query",
|
|
22060
22192
|
"trace-query-tenant-scope",
|
|
22061
22193
|
"feedback",
|
|
22194
|
+
"feedback-replacement",
|
|
22062
22195
|
"trace-query-context-ids",
|
|
22063
22196
|
...contextFieldFeatures,
|
|
22064
22197
|
...timingFeatures,
|
|
@@ -22158,6 +22291,9 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
22158
22291
|
async batchCreateScores(args) {
|
|
22159
22292
|
await this.#run("BATCH_CREATE_SCORES", () => batchCreateScores(this.#client, this.#schema, args, this.#writePartitioning()), { count: args.scores.length });
|
|
22160
22293
|
}
|
|
22294
|
+
async writeFeedbackReplacement(args) {
|
|
22295
|
+
await this.#run("REPLACE_FEEDBACK", () => replaceFeedback(this.#client, this.#schema, args, this.#writePartitioning()));
|
|
22296
|
+
}
|
|
22161
22297
|
async createFeedback(args) {
|
|
22162
22298
|
await this.#run("CREATE_FEEDBACK", () => createFeedback(this.#client, this.#schema, args, this.#writePartitioning()));
|
|
22163
22299
|
}
|
|
@@ -22183,7 +22319,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
22183
22319
|
return this.#run("GET_SCORE_BY_ID", () => getScoreById(this.#readClient, this.#schema, scoreId), { scoreId });
|
|
22184
22320
|
}
|
|
22185
22321
|
async getFeedbackById(feedbackId) {
|
|
22186
|
-
return this.#run("GET_FEEDBACK_BY_ID", () => getFeedbackById(this.#
|
|
22322
|
+
return this.#run("GET_FEEDBACK_BY_ID", () => getFeedbackById(this.#client, this.#schema, feedbackId), { feedbackId });
|
|
22187
22323
|
}
|
|
22188
22324
|
async listFeedback(args) {
|
|
22189
22325
|
return this.#run("LIST_FEEDBACK", () => listFeedback(this.#readClient, this.#schema, args));
|