@mastra/pg 1.21.1-alpha.0 → 1.21.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/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # @mastra/pg
2
2
 
3
+ ## 1.21.1-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Added HTTP endpoints for caller-driven experiments: `POST /datasets/:datasetId/experiments` now accepts `start: false` to create an experiment without spawning the runner (with an optional target and run-level `scorerIds`), and new routes `POST /datasets/:datasetId/experiments/:experimentId/items/:itemId/run`, `POST /datasets/:datasetId/experiments/:experimentId/results`, and `POST /datasets/:datasetId/experiments/:experimentId/finalize` let external orchestrators run one item server-side, submit externally computed per-item results (idempotent upsert on retries), and finalize the run with server-computed counts. ([#21888](https://github.com/mastra-ai/mastra/pull/21888))
8
+
9
+ - Added `createDatasetExperiment()`, `runExperimentItem()`, `submitExperimentResult()`, and `finalizeExperiment()` methods so a caller-owned orchestrator (for example Temporal) can drive an experiment loop while Mastra either executes each item server-side or ingests externally computed results. ([#21888](https://github.com/mastra-ai/mastra/pull/21888))
10
+
11
+ - Added `upsertExperimentResult()` to the experiments storage domain plus an `attempt` column on experiment results and a nullable target with an optional `scorerIds` column on experiments, enabling retry-safe result writes for caller-driven experiments (retried submissions with the same `(experimentId, itemId, attempt)` key converge on a single row). `saveScore()` now accepts an optional caller-supplied `id` and upserts on it, so retried experiment submissions replace their previous score rows (latest wins) instead of accumulating duplicates. ([#21888](https://github.com/mastra-ai/mastra/pull/21888))
12
+
13
+ - Added caller-driven experiments so an external orchestrator (for example Temporal workers) can own the experiment loop while Mastra stays the system of record. ([#21888](https://github.com/mastra-ai/mastra/pull/21888))
14
+
15
+ Create an experiment with `dataset.createExperiment()` (idempotent when you pass your own id). With a target, Mastra runs each item for you: call `dataset.runExperimentItem()` per item and Mastra executes the registered agent or workflow, resolves scorers (experiment `scorers`, falling back to item `scorerIds`, then dataset `scorerIds`), and upserts the result. Without a target, run everything yourself and report per-item results with `dataset.submitExperimentResult()` (upsert semantics on `(experimentId, itemId, attempt)` so retried workers converge on a single row). Either way, close the run with `dataset.finalizeExperiment()` and Mastra computes per-item succeeded/failed/skipped counts from the persisted rows. Results go into the same storage as native runs, so Studio views, comparisons, and review summaries work unchanged.
16
+
17
+ ```typescript
18
+ // Caller drives the loop, Mastra runs each item
19
+ const { experimentId } = await dataset.createExperiment({
20
+ id: workflowRunId,
21
+ targetType: 'agent',
22
+ targetId: 'support-agent',
23
+ scorers: ['accuracy'],
24
+ });
25
+
26
+ await dataset.runExperimentItem({ experimentId, itemId });
27
+
28
+ // Or: caller runs everything, Mastra ingests results
29
+ const ingest = await dataset.createExperiment({ id: workflowRunId });
30
+ await dataset.submitExperimentResult({
31
+ experimentId: ingest.experimentId,
32
+ itemId,
33
+ output,
34
+ scores: [{ scorerId: 'accuracy', score: 0.92 }],
35
+ });
36
+
37
+ const experiment = await dataset.finalizeExperiment({ experimentId });
38
+ ```
39
+
40
+ - Fixed versioned dataset item lookups to return the item visible in the requested dataset snapshot. ([#21979](https://github.com/mastra-ai/mastra/pull/21979))
41
+
42
+ - Updated dependencies [[`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`acc3471`](https://github.com/mastra-ai/mastra/commit/acc3471de5f3fde8027ee4e355af292b2bc1bc30), [`b6a771e`](https://github.com/mastra-ai/mastra/commit/b6a771ef23d203ddb348efca8065eff65def8191), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`26d4016`](https://github.com/mastra-ai/mastra/commit/26d40160ff7f7d8bf95fee2039a52cbc83863533), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`57c5103`](https://github.com/mastra-ai/mastra/commit/57c51035a2a36e3df3c4f32f46bb789a66ed5946)]:
43
+ - @mastra/core@1.61.0-alpha.3
44
+
3
45
  ## 1.21.1-alpha.0
4
46
 
5
47
  ### Patch Changes
@@ -3,7 +3,7 @@ name: mastra-pg
3
3
  description: Documentation for @mastra/pg. Use when working with @mastra/pg APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/pg"
6
- version: "1.21.1-alpha.0"
6
+ version: "1.21.1-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.21.1-alpha.0",
2
+ "version": "1.21.1-alpha.1",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -46,7 +46,7 @@ const results = await store.query({
46
46
 
47
47
  ### Custom Operators
48
48
 
49
- `$contains`Text contains substring{ description: { $contains: "sale" } }Supported by: Upstash, libSQL, PgVector, OracleDB`$regex`Regular expression match{ name: { $regex: "^test" } }Supported by: Qdrant, PgVector, Upstash, MongoDB, OracleDB`$size`Array length check{ tags: { $size: 3 } }Supported by: Astra, libSQL, PgVector, MongoDB, OracleDB`$geo`Geospatial query{ location: { $geo: { type: "radius", ... } } }Supported by: Qdrant`$datetime`Datetime range query{ created: { $datetime: { range: { gt: "2024-01-01" } } } }Supported by: Qdrant`$hasId`Vector ID existence check{ $hasId: \["id1", "id2"] }Supported by: Qdrant`$hasVector`Vector existence check{ $hasVector: true }Supported by: Qdrant
49
+ `$contains`Text contains substring{ description: { $contains: "sale" } }Supported by: Upstash, libSQL, PgVector, OracleDB`$regex`Regular expression match{ name: { $regex: "^test" } }Supported by: Qdrant, PgVector, Upstash, MongoDB, OracleDB`$size`Array length check{ tags: { $size: { $gt: 2 } } } — MongoDB requires an integer instead: { tags: { $size: 3 } }Supported by: Astra, libSQL, PgVector, MongoDB, OracleDB`$geo`Geospatial query{ location: { $geo: { type: "radius", ... } } }Supported by: Qdrant`$datetime`Datetime range query{ created: { $datetime: { range: { gt: "2024-01-01" } } } }Supported by: Qdrant`$hasId`Vector ID existence check{ $hasId: \["id1", "id2"] }Supported by: Qdrant`$hasVector`Vector existence check{ $hasVector: true }Supported by: Qdrant
50
50
 
51
51
  ## Common rules and restrictions
52
52
 
@@ -186,13 +186,21 @@ const results = await store.query({
186
186
 
187
187
  ### MongoDB
188
188
 
189
- - Full support for MongoDB/Sift query syntax for metadata filters
190
- - Supports all standard comparison, array, logical, and element operators
191
- - Supports nested fields and arrays in metadata
192
- - Filtering can be applied to both `metadata` and the original document content using the `filter` and `documentFilter` options, respectively
193
- - `filter` applies to the metadata object; `documentFilter` applies to the original document fields
194
- - No artificial limits on filter size or complexity (subject to MongoDB query limits)
195
- - Indexing metadata fields is recommended for optimal performance
189
+ - Requires MongoDB Atlas or a deployment with MongoDB Vector Search enabled. The store queries with the `$vectorSearch` aggregation stage.
190
+ - Uses MongoDB query syntax directly for metadata filters, including nested fields and arrays in metadata.
191
+ - Supports the comparison, array, logical, and element operators in the tables above, plus `$regex` and `$size`. `$size` takes an integer, as in `{ tags: { $size: 3 } }`.
192
+ - Use `filter` to match fields in the metadata object and `documentFilter` to match the original document text. You can combine them in a single query.
193
+ - Declare the metadata fields you filter on in `filterFields` when you create the index. Mastra passes filters that use only declared fields and the operators MongoDB Vector Search accepts (`$and`, `$or`, `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`) directly to `$vectorSearch`:
194
+
195
+ ```typescript
196
+ await store.createIndex({
197
+ indexName: 'my_index',
198
+ dimension: 1536,
199
+ filterFields: ['category', 'price'],
200
+ })
201
+ ```
202
+
203
+ - Filters that reference an undeclared field or use another operator take a fallback path: Mastra pre-filters the collection and passes the matching document IDs to `$vectorSearch`. This works only while the ID set fits within MongoDB's 16 MB BSON document limit. On large collections the query fails once that limit is exceeded, so declare your filter fields for selective queries over large data sets.
196
204
 
197
205
  ### Couchbase
198
206
 
@@ -77,9 +77,19 @@ For detailed information about available operators and syntax, see the [Metadata
77
77
 
78
78
  Basic filtering examples:
79
79
 
80
+ **MongoDB**:
81
+
80
82
  ```ts
83
+ import { MongoDBVector } from '@mastra/mongodb'
84
+
85
+ const mongoVector = new MongoDBVector({
86
+ id: 'mongodb-vector',
87
+ uri: process.env.MONGODB_URI,
88
+ dbName: process.env.MONGODB_DB_NAME,
89
+ })
90
+
81
91
  // Simple equality filter
82
- const results = await pgVector.query({
92
+ const equalityResults = await mongoVector.query({
83
93
  indexName: 'embeddings',
84
94
  queryVector: embedding,
85
95
  topK: 10,
@@ -89,7 +99,7 @@ const results = await pgVector.query({
89
99
  })
90
100
 
91
101
  // Numeric comparison
92
- const results = await pgVector.query({
102
+ const priceResults = await mongoVector.query({
93
103
  indexName: 'embeddings',
94
104
  queryVector: embedding,
95
105
  topK: 10,
@@ -99,7 +109,7 @@ const results = await pgVector.query({
99
109
  })
100
110
 
101
111
  // Multiple conditions
102
- const results = await pgVector.query({
112
+ const compoundResults = await mongoVector.query({
103
113
  indexName: 'embeddings',
104
114
  queryVector: embedding,
105
115
  topK: 10,
@@ -111,7 +121,7 @@ const results = await pgVector.query({
111
121
  })
112
122
 
113
123
  // Array operations
114
- const results = await pgVector.query({
124
+ const tagResults = await mongoVector.query({
115
125
  indexName: 'embeddings',
116
126
  queryVector: embedding,
117
127
  topK: 10,
@@ -121,7 +131,64 @@ const results = await pgVector.query({
121
131
  })
122
132
 
123
133
  // Logical operators
124
- const results = await pgVector.query({
134
+ const categoryResults = await mongoVector.query({
135
+ indexName: 'embeddings',
136
+ queryVector: embedding,
137
+ topK: 10,
138
+ filter: {
139
+ $or: [{ category: 'electronics' }, { category: 'accessories' }],
140
+ $and: [{ price: { $gt: 50 } }, { price: { $lt: 200 } }],
141
+ },
142
+ })
143
+ ```
144
+
145
+ **pgVector**:
146
+
147
+ ```ts
148
+ // Simple equality filter
149
+ const equalityResults = await pgVector.query({
150
+ indexName: 'embeddings',
151
+ queryVector: embedding,
152
+ topK: 10,
153
+ filter: {
154
+ source: 'article1.txt',
155
+ },
156
+ })
157
+
158
+ // Numeric comparison
159
+ const priceResults = await pgVector.query({
160
+ indexName: 'embeddings',
161
+ queryVector: embedding,
162
+ topK: 10,
163
+ filter: {
164
+ price: { $gt: 100 },
165
+ },
166
+ })
167
+
168
+ // Multiple conditions
169
+ const compoundResults = await pgVector.query({
170
+ indexName: 'embeddings',
171
+ queryVector: embedding,
172
+ topK: 10,
173
+ filter: {
174
+ category: 'electronics',
175
+ price: { $lt: 1000 },
176
+ inStock: true,
177
+ },
178
+ })
179
+
180
+ // Array operations
181
+ const tagResults = await pgVector.query({
182
+ indexName: 'embeddings',
183
+ queryVector: embedding,
184
+ topK: 10,
185
+ filter: {
186
+ tags: { $in: ['sale', 'new'] },
187
+ },
188
+ })
189
+
190
+ // Logical operators
191
+ const categoryResults = await pgVector.query({
125
192
  indexName: 'embeddings',
126
193
  queryVector: embedding,
127
194
  topK: 10,
@@ -141,6 +208,47 @@ Common use cases for metadata filtering:
141
208
  - Combine multiple conditions for precise querying
142
209
  - Filter by document attributes (e.g., language, author)
143
210
 
211
+ ### Where the filter is applied
212
+
213
+ Vector stores differ in _when_ they apply a metadata filter, which affects how filtered queries scale.
214
+
215
+ MongoDB can evaluate the filter inside the vector index itself. This keeps the query on a single round trip to `$vectorSearch`, so it avoids the pre-filter pass that collects matching document IDs and the 16 MB BSON limit that pass is subject to. Declaring the fields you filter on in `filterFields` when you create the index is what enables it:
216
+
217
+ ```ts
218
+ // Declare the metadata fields you want to filter on
219
+ await mongoVector.createIndex({
220
+ indexName: 'embeddings',
221
+ dimension: 1536,
222
+ filterFields: ['source', 'price', 'category', 'inStock', 'tags'],
223
+ })
224
+
225
+ // createIndex() returns before the index finishes building
226
+ await mongoVector.waitForIndexReady({ indexName: 'embeddings' })
227
+
228
+ // The filter is applied during the index search
229
+ const results = await mongoVector.query({
230
+ indexName: 'embeddings',
231
+ queryVector: embedding,
232
+ topK: 10,
233
+ filter: { source: 'article1.txt' },
234
+ })
235
+ ```
236
+
237
+ Mastra passes the filter to the index only when every field it references is declared in `filterFields` and every operator is one the index accepts: `$and`, `$or`, `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, and `$nin`. A filter that uses an undeclared field or any other operator takes a fallback path: Mastra matches the collection first and passes the matching document IDs into the vector search. That fallback holds only while the ID set fits within MongoDB's 16 MB BSON document limit. On large collections the query fails once that limit is exceeded, so declare your filter fields when you expect selective filters over large data sets.
238
+
239
+ pgVector applies the filter as an ordinary query condition:
240
+
241
+ ```ts
242
+ const results = await pgVector.query({
243
+ indexName: 'embeddings',
244
+ queryVector: embedding,
245
+ topK: 10,
246
+ filter: { source: 'article1.txt' },
247
+ })
248
+ ```
249
+
250
+ Postgres vector indexes (HNSW and IVFFlat) can't restrict that search to rows matching a condition. When a filter is present, pgVector instead compares the query vector against every matching row and returns the closest `topK`. Results are exact, but the work grows with the number of rows the filter matches. Indexing the metadata column speeds up row retrieval. The distance comparisons still happen per row.
251
+
144
252
  ### Vector Query Tool
145
253
 
146
254
  Sometimes you want to give your agent the ability to query a vector database directly. The Vector Query Tool allows your agent to be in charge of retrieval decisions, combining semantic search with optional filtering and reranking based on the agent's understanding of the user's needs.
package/dist/index.cjs CHANGED
@@ -6338,7 +6338,7 @@ var DatasetsPG = class DatasetsPG extends _mastra_core_storage.DatasetsStorage {
6338
6338
  schemaName: getSchemaName$5(this.#schema)
6339
6339
  });
6340
6340
  let result;
6341
- if (args.datasetVersion !== void 0) result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE "id" = $1 AND "datasetVersion" = $2 AND "isDeleted" = false`, [args.id, args.datasetVersion]);
6341
+ if (args.datasetVersion !== void 0) result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE "id" = $1 AND "datasetVersion" <= $2 AND ("validTo" IS NULL OR "validTo" > $2) AND "isDeleted" = false ORDER BY "datasetVersion" DESC LIMIT 1`, [args.id, args.datasetVersion]);
6342
6342
  else result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE "id" = $1 AND "validTo" IS NULL AND "isDeleted" = false`, [args.id]);
6343
6343
  return result ? this.transformItemRow(result) : null;
6344
6344
  } catch (error) {
@@ -6596,7 +6596,8 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6596
6596
  "experimentSetId",
6597
6597
  "comparisonId",
6598
6598
  "variantId",
6599
- "trialIndex"
6599
+ "trialIndex",
6600
+ "scorerIds"
6600
6601
  ]
6601
6602
  });
6602
6603
  await this.#db.alterTable({
@@ -6608,7 +6609,8 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6608
6609
  "comment",
6609
6610
  "toolMockReport",
6610
6611
  "organizationId",
6611
- "projectId"
6612
+ "projectId",
6613
+ "attempt"
6612
6614
  ]
6613
6615
  });
6614
6616
  await this.createDefaultIndexes();
@@ -6718,9 +6720,13 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6718
6720
  columns: ["experimentId"]
6719
6721
  },
6720
6722
  {
6721
- name: "idx_experiment_results_exp_item",
6723
+ name: "idx_experiment_results_exp_item_attempt",
6722
6724
  table: _mastra_core_storage.TABLE_EXPERIMENT_RESULTS,
6723
- columns: ["experimentId", "itemId"],
6725
+ columns: [
6726
+ "experimentId",
6727
+ "itemId",
6728
+ "attempt"
6729
+ ],
6724
6730
  unique: true
6725
6731
  },
6726
6732
  {
@@ -6737,6 +6743,11 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6737
6743
  }
6738
6744
  async createDefaultIndexes() {
6739
6745
  if (this.#skipDefaultIndexes) return;
6746
+ try {
6747
+ await this.#db.dropIndex("idx_experiment_results_exp_item");
6748
+ } catch (error) {
6749
+ this.logger?.warn?.("Failed to drop legacy index idx_experiment_results_exp_item:", error);
6750
+ }
6740
6751
  for (const indexDef of this.getDefaultIndexDefinitions()) try {
6741
6752
  await this.#db.createIndex(indexDef);
6742
6753
  } catch (error) {
@@ -6768,8 +6779,9 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6768
6779
  agentVersion: row.agentVersion ?? null,
6769
6780
  organizationId: row.organizationId ?? null,
6770
6781
  projectId: row.projectId ?? null,
6771
- targetType: row.targetType,
6772
- targetId: row.targetId,
6782
+ targetType: row.targetType ?? null,
6783
+ targetId: row.targetId ?? null,
6784
+ scorerIds: row.scorerIds ? (0, _mastra_core_storage.safelyParseJSON)(row.scorerIds) : null,
6773
6785
  status: row.status,
6774
6786
  totalItems: row.totalItems,
6775
6787
  succeededCount: row.succeededCount,
@@ -6796,6 +6808,7 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6796
6808
  startedAt: (0, _mastra_core_storage.ensureDate)(row.startedAtZ || row.startedAt),
6797
6809
  completedAt: (0, _mastra_core_storage.ensureDate)(row.completedAtZ || row.completedAt),
6798
6810
  retryCount: row.retryCount,
6811
+ attempt: row.attempt != null ? row.attempt : 0,
6799
6812
  traceId: row.traceId ?? null,
6800
6813
  status: row.status ?? null,
6801
6814
  tags: row.tags ? (0, _mastra_core_storage.safelyParseJSON)(row.tags) : null,
@@ -6827,8 +6840,9 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6827
6840
  agentVersion: input.agentVersion ?? null,
6828
6841
  organizationId: input.organizationId ?? null,
6829
6842
  projectId: input.projectId ?? null,
6830
- targetType: input.targetType,
6831
- targetId: input.targetId,
6843
+ targetType: input.targetType ?? null,
6844
+ targetId: input.targetId ?? null,
6845
+ scorerIds: input.scorerIds ?? null,
6832
6846
  status: "pending",
6833
6847
  totalItems: input.totalItems,
6834
6848
  succeededCount: 0,
@@ -6856,8 +6870,9 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
6856
6870
  agentVersion: input.agentVersion ?? null,
6857
6871
  organizationId: input.organizationId ?? null,
6858
6872
  projectId: input.projectId ?? null,
6859
- targetType: input.targetType,
6860
- targetId: input.targetId,
6873
+ targetType: input.targetType ?? null,
6874
+ targetId: input.targetId ?? null,
6875
+ scorerIds: input.scorerIds ?? null,
6861
6876
  status: "pending",
6862
6877
  totalItems: input.totalItems,
6863
6878
  succeededCount: 0,
@@ -7101,6 +7116,7 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
7101
7116
  startedAt: input.startedAt.toISOString(),
7102
7117
  completedAt: input.completedAt.toISOString(),
7103
7118
  retryCount: input.retryCount,
7119
+ attempt: input.attempt ?? 0,
7104
7120
  traceId: input.traceId ?? null,
7105
7121
  status: input.status ?? null,
7106
7122
  tags: input.tags ?? null,
@@ -7122,6 +7138,7 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
7122
7138
  startedAt: input.startedAt,
7123
7139
  completedAt: input.completedAt,
7124
7140
  retryCount: input.retryCount,
7141
+ attempt: input.attempt ?? 0,
7125
7142
  traceId: input.traceId ?? null,
7126
7143
  status: input.status ?? null,
7127
7144
  tags: input.tags ?? null,
@@ -7136,6 +7153,81 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
7136
7153
  }, error);
7137
7154
  }
7138
7155
  }
7156
+ async upsertExperimentResult(input) {
7157
+ try {
7158
+ const tableName = getTableName$5({
7159
+ indexName: _mastra_core_storage.TABLE_EXPERIMENT_RESULTS,
7160
+ schemaName: getSchemaName$5(this.#schema)
7161
+ });
7162
+ const attempt = input.attempt ?? 0;
7163
+ const row = await this.#db.client.tx(async (t) => {
7164
+ const existing = await t.oneOrNone(`SELECT "id" FROM ${tableName} WHERE "experimentId" = $1 AND "itemId" = $2 AND COALESCE("attempt", 0) = $3 FOR UPDATE`, [
7165
+ input.experimentId,
7166
+ input.itemId,
7167
+ attempt
7168
+ ]);
7169
+ if (!existing) {
7170
+ const id = crypto.randomUUID();
7171
+ return t.one(`INSERT INTO ${tableName} (
7172
+ "id", "experimentId", "itemId", "itemDatasetVersion", "organizationId", "projectId",
7173
+ "input", "output", "groundTruth", "error", "startedAt", "completedAt",
7174
+ "retryCount", "attempt", "traceId", "status", "tags", "toolMockReport", "createdAt"
7175
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)
7176
+ RETURNING *`, [
7177
+ id,
7178
+ input.experimentId,
7179
+ input.itemId,
7180
+ input.itemDatasetVersion ?? null,
7181
+ input.organizationId ?? null,
7182
+ input.projectId ?? null,
7183
+ JSON.stringify(input.input),
7184
+ input.output != null ? JSON.stringify(input.output) : null,
7185
+ input.groundTruth != null ? JSON.stringify(input.groundTruth) : null,
7186
+ input.error != null ? JSON.stringify(input.error) : null,
7187
+ input.startedAt.toISOString(),
7188
+ input.completedAt.toISOString(),
7189
+ input.retryCount,
7190
+ attempt,
7191
+ input.traceId ?? null,
7192
+ input.status ?? null,
7193
+ input.tags != null ? JSON.stringify(input.tags) : null,
7194
+ input.toolMockReport != null ? JSON.stringify(input.toolMockReport) : null,
7195
+ (/* @__PURE__ */ new Date()).toISOString()
7196
+ ]);
7197
+ }
7198
+ return t.one(`UPDATE ${tableName} SET
7199
+ "itemDatasetVersion" = $2, "organizationId" = $3, "projectId" = $4,
7200
+ "input" = $5, "output" = $6, "groundTruth" = $7, "error" = $8,
7201
+ "startedAt" = $9, "completedAt" = $10, "retryCount" = $11, "attempt" = $12,
7202
+ "traceId" = $13, "status" = $14, "tags" = $15, "toolMockReport" = $16
7203
+ WHERE "id" = $1 RETURNING *`, [
7204
+ existing.id,
7205
+ input.itemDatasetVersion ?? null,
7206
+ input.organizationId ?? null,
7207
+ input.projectId ?? null,
7208
+ JSON.stringify(input.input),
7209
+ input.output != null ? JSON.stringify(input.output) : null,
7210
+ input.groundTruth != null ? JSON.stringify(input.groundTruth) : null,
7211
+ input.error != null ? JSON.stringify(input.error) : null,
7212
+ input.startedAt.toISOString(),
7213
+ input.completedAt.toISOString(),
7214
+ input.retryCount,
7215
+ attempt,
7216
+ input.traceId ?? null,
7217
+ input.status ?? null,
7218
+ input.tags != null ? JSON.stringify(input.tags) : null,
7219
+ input.toolMockReport != null ? JSON.stringify(input.toolMockReport) : null
7220
+ ]);
7221
+ });
7222
+ return this.transformExperimentResultRow(row);
7223
+ } catch (error) {
7224
+ throw new _mastra_core_error.MastraError({
7225
+ id: (0, _mastra_core_storage.createStorageErrorId)("PG", "UPSERT_EXPERIMENT_RESULT", "FAILED"),
7226
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
7227
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY
7228
+ }, error);
7229
+ }
7230
+ }
7139
7231
  async updateExperimentResult(input) {
7140
7232
  try {
7141
7233
  const tableName = getTableName$5({
@@ -18940,9 +19032,14 @@ var ScoresPG = class ScoresPG extends _mastra_core_storage.ScoresStorage {
18940
19032
  }, error);
18941
19033
  }
18942
19034
  try {
18943
- const id = crypto.randomUUID();
19035
+ const suppliedId = parsedScore.id;
19036
+ const id = suppliedId ?? crypto.randomUUID();
18944
19037
  const now = /* @__PURE__ */ new Date();
18945
- const { scorer, preprocessStepResult, analyzeStepResult, metadata, input, output, additionalContext, requestContext, entity, ...rest } = parsedScore;
19038
+ const { id: _suppliedId, scorer, preprocessStepResult, analyzeStepResult, metadata, input, output, additionalContext, requestContext, entity, ...rest } = parsedScore;
19039
+ if (suppliedId) await this.#db.client.none(`DELETE FROM ${getTableName$1({
19040
+ indexName: _mastra_core_storage.TABLE_SCORERS,
19041
+ schemaName: getSchemaName$1(this.#schema)
19042
+ })} WHERE id = $1`, [suppliedId]);
18946
19043
  await this.#db.insert({
18947
19044
  tableName: _mastra_core_storage.TABLE_SCORERS,
18948
19045
  record: {