@mastra/spanner 1.2.0 → 1.2.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 +80 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +150 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +150 -11
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/datasets/index.d.ts +1 -1
- package/dist/storage/domains/datasets/index.d.ts.map +1 -1
- package/dist/storage/domains/experiments/index.d.ts.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,85 @@
|
|
|
1
1
|
# @mastra/spanner
|
|
2
2
|
|
|
3
|
+
## 1.2.1-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Added multi-tenant scoping columns (`organizationId`, `projectId`) to the experiments domain so experiment records and per-item results inherit the tenancy bucket of their parent dataset. ([#18388](https://github.com/mastra-ai/mastra/pull/18388))
|
|
8
|
+
|
|
9
|
+
`Experiment`, `ExperimentResult`, `CreateExperimentInput`, and `AddExperimentResultInput` now carry optional `organizationId` / `projectId` fields. `ListExperimentsInput` and `ListExperimentResultsInput` gain a `filters: ExperimentTenancyFilters` block (mirrors `DatasetTenancyFilters`) for scoping queries within a `(organizationId, projectId)` bucket. Tenancy is hydrated from the parent dataset on `createExperiment` and denormalized onto each `ExperimentResult` for efficient tenancy-scoped queries.
|
|
10
|
+
|
|
11
|
+
The corresponding columns are also added to the `mastra_experiments` and `mastra_experiment_results` table schemas. Existing rows backfill to `null`, matching the rest of the dataset-tenancy surface.
|
|
12
|
+
|
|
13
|
+
This release also clarifies the `targetType` contract via JSDoc:
|
|
14
|
+
- `CreateDatasetInput.targetType` remains optional. Datasets without a `TargetType` are **not experiment-eligible** — the experiment runner requires a non-null `CreateExperimentInput.targetType` to resolve an executor.
|
|
15
|
+
- `Experiment.targetType` / `CreateExperimentInput.targetType` stay required. An experiment by definition replays inputs against a specific target.
|
|
16
|
+
|
|
17
|
+
No behavior change for existing OSS-created experiments; the new fields are additive and optional.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// Create an experiment scoped to a tenancy bucket. When the parent dataset
|
|
23
|
+
// already carries `organizationId` / `projectId`, `runExperiment` hydrates
|
|
24
|
+
// these fields automatically from the dataset record.
|
|
25
|
+
const experiment = await storage.createExperiment({
|
|
26
|
+
name: 'qa-regression',
|
|
27
|
+
datasetId: 'ds_123',
|
|
28
|
+
datasetVersion: 1,
|
|
29
|
+
targetType: 'agent',
|
|
30
|
+
targetId: 'agent_qa',
|
|
31
|
+
totalItems: 10,
|
|
32
|
+
organizationId: 'org_123',
|
|
33
|
+
projectId: 'proj_123',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// List experiments within a tenancy bucket.
|
|
37
|
+
const experiments = await storage.listExperiments({
|
|
38
|
+
pagination: { page: 0, perPage: 20 },
|
|
39
|
+
filters: { organizationId: 'org_123', projectId: 'proj_123' },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// List per-item results within the same bucket.
|
|
43
|
+
const results = await storage.listExperimentResults({
|
|
44
|
+
experimentId: experiment.id,
|
|
45
|
+
pagination: { page: 0, perPage: 50 },
|
|
46
|
+
filters: { organizationId: 'org_123', projectId: 'proj_123' },
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- Persist and filter dataset tenancy + candidate identity in storage adapters. ([#18314](https://github.com/mastra-ai/mastra/pull/18314))
|
|
51
|
+
|
|
52
|
+
`createDataset` now persists `organizationId`, `projectId`, `candidateKey`, and `candidateId`. `listDatasets` and `listItems` accept matching tenancy filters. Dataset items inherit `organizationId` / `projectId` from their parent dataset on insert, update, delete, and batch insert/delete — items are never settable per call (item tenancy follows dataset tenancy).
|
|
53
|
+
|
|
54
|
+
All new columns are nullable and added retroactively via each adapter's existing column-migration path; no breaking DDL. Existing rows continue to read and write fine; new writes can choose to stamp tenancy.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
await storage.createDataset({
|
|
58
|
+
name: 'candidates/missing-tool-call/incident-123',
|
|
59
|
+
organizationId: 'org_abc',
|
|
60
|
+
projectId: 'project_xyz',
|
|
61
|
+
candidateKey: 'missing-tool-call',
|
|
62
|
+
candidateId: 'incident-123',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await storage.listDatasets({
|
|
66
|
+
pagination: { page: 0, perPage: 20 },
|
|
67
|
+
filters: { organizationId: 'org_abc', projectId: 'project_xyz' },
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- Updated dependencies [[`5c4e9a4`](https://github.com/mastra-ai/mastra/commit/5c4e9a4cfb2216bb3ea7f8988ad3727f3b92bb3a), [`25961e3`](https://github.com/mastra-ai/mastra/commit/25961e3260ff3b1464637af8fcdb36210551c39f), [`7b29f33`](https://github.com/mastra-ai/mastra/commit/7b29f332a357a83e555f29e718e5f2fab9979943), [`24912b1`](https://github.com/mastra-ai/mastra/commit/24912b1f855d29ec36af4ef4bde1f7417e20cdf5), [`7686216`](https://github.com/mastra-ai/mastra/commit/7686216f37e74568feddec17cef3c3d24e10e60a), [`975c59a`](https://github.com/mastra-ai/mastra/commit/975c59ae363ee275fc55062392e1ffd2cbccbd53), [`d95f394`](https://github.com/mastra-ai/mastra/commit/d95f394fd24c8411886930d727679c4d5252aa26), [`f3f0c9d`](https://github.com/mastra-ai/mastra/commit/f3f0c9d7c878db5a13177871ce3523a14f14b311)]:
|
|
72
|
+
- @mastra/core@1.46.0-alpha.4
|
|
73
|
+
|
|
74
|
+
## 1.2.1-alpha.0
|
|
75
|
+
|
|
76
|
+
### Patch Changes
|
|
77
|
+
|
|
78
|
+
- Added storage for item-level tool mocks. Dataset items persist their `toolMocks` and experiment results persist their `toolMockReport`, so mocks and run diagnostics survive across sessions. ([#18036](https://github.com/mastra-ai/mastra/pull/18036))
|
|
79
|
+
|
|
80
|
+
- Updated dependencies [[`65f255a`](https://github.com/mastra-ai/mastra/commit/65f255a38667beb6ceeadabfa9eb5059bfec8298), [`4a88c6e`](https://github.com/mastra-ai/mastra/commit/4a88c6e2bdce316f8d7551b4ec3449b0b06fc71c), [`87a17ef`](https://github.com/mastra-ai/mastra/commit/87a17efbd725aca6639febdc5e69e2abb3048689), [`e11ff30`](https://github.com/mastra-ai/mastra/commit/e11ff301408bf1731dca2fb7fbfcd8c819500a35), [`9d2c946`](https://github.com/mastra-ai/mastra/commit/9d2c946d0859e90ae4bcec5beeb1da7398d2ad1e), [`f1ec385`](https://github.com/mastra-ai/mastra/commit/f1ec385386f62b1a0847ec5353ae2bb169d1c3d9), [`e14986f`](https://github.com/mastra-ai/mastra/commit/e14986f6e5478d6384d04ff9a7f9a79a46a8b529), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`974f614`](https://github.com/mastra-ai/mastra/commit/974f614e083bd68278536f94453f7b320b86a3c7), [`31be1cf`](https://github.com/mastra-ai/mastra/commit/31be1cf5f2a7b5eef12f6123a40653b4d8115c16)]:
|
|
81
|
+
- @mastra/core@1.46.0-alpha.3
|
|
82
|
+
|
|
3
83
|
## 1.2.0
|
|
4
84
|
|
|
5
85
|
### Minor Changes
|
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -2969,6 +2969,10 @@ function rowToDataset(row) {
|
|
|
2969
2969
|
targetIds: t.targetIds ?? null,
|
|
2970
2970
|
scorerIds: t.scorerIds ?? null,
|
|
2971
2971
|
version: Number(t.version ?? 0),
|
|
2972
|
+
organizationId: t.organizationId ?? null,
|
|
2973
|
+
projectId: t.projectId ?? null,
|
|
2974
|
+
candidateKey: t.candidateKey ?? null,
|
|
2975
|
+
candidateId: t.candidateId ?? null,
|
|
2972
2976
|
createdAt: toDate(t.createdAt),
|
|
2973
2977
|
updatedAt: toDate(t.updatedAt)
|
|
2974
2978
|
};
|
|
@@ -2979,9 +2983,12 @@ function rowToItem(row) {
|
|
|
2979
2983
|
id: String(t.id),
|
|
2980
2984
|
datasetId: String(t.datasetId),
|
|
2981
2985
|
datasetVersion: Number(t.datasetVersion),
|
|
2986
|
+
organizationId: t.organizationId ?? null,
|
|
2987
|
+
projectId: t.projectId ?? null,
|
|
2982
2988
|
input: t.input,
|
|
2983
2989
|
groundTruth: t.groundTruth ?? void 0,
|
|
2984
2990
|
expectedTrajectory: t.expectedTrajectory ?? void 0,
|
|
2991
|
+
toolMocks: t.toolMocks ?? void 0,
|
|
2985
2992
|
requestContext: t.requestContext ?? void 0,
|
|
2986
2993
|
metadata: t.metadata ?? void 0,
|
|
2987
2994
|
source: t.source ?? void 0,
|
|
@@ -3024,6 +3031,16 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3024
3031
|
await this.db.createTable({ tableName: storage.TABLE_DATASETS, schema: storage.TABLE_SCHEMAS[storage.TABLE_DATASETS] });
|
|
3025
3032
|
await this.db.createTable({ tableName: storage.TABLE_DATASET_ITEMS, schema: storage.TABLE_SCHEMAS[storage.TABLE_DATASET_ITEMS] });
|
|
3026
3033
|
await this.db.createTable({ tableName: storage.TABLE_DATASET_VERSIONS, schema: storage.TABLE_SCHEMAS[storage.TABLE_DATASET_VERSIONS] });
|
|
3034
|
+
await this.db.alterTable({
|
|
3035
|
+
tableName: storage.TABLE_DATASETS,
|
|
3036
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_DATASETS],
|
|
3037
|
+
ifNotExists: ["organizationId", "projectId", "candidateKey", "candidateId"]
|
|
3038
|
+
});
|
|
3039
|
+
await this.db.alterTable({
|
|
3040
|
+
tableName: storage.TABLE_DATASET_ITEMS,
|
|
3041
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_DATASET_ITEMS],
|
|
3042
|
+
ifNotExists: ["organizationId", "projectId"]
|
|
3043
|
+
});
|
|
3027
3044
|
await this.createDefaultIndexes();
|
|
3028
3045
|
await this.createCustomIndexes();
|
|
3029
3046
|
}
|
|
@@ -3084,6 +3101,10 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3084
3101
|
targetIds: input.targetIds ?? null,
|
|
3085
3102
|
scorerIds: input.scorerIds ?? null,
|
|
3086
3103
|
version: 0,
|
|
3104
|
+
organizationId: input.organizationId ?? null,
|
|
3105
|
+
projectId: input.projectId ?? null,
|
|
3106
|
+
candidateKey: input.candidateKey ?? null,
|
|
3107
|
+
candidateId: input.candidateId ?? null,
|
|
3087
3108
|
createdAt: now,
|
|
3088
3109
|
updatedAt: now
|
|
3089
3110
|
};
|
|
@@ -3102,6 +3123,10 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3102
3123
|
targetIds: record.targetIds,
|
|
3103
3124
|
scorerIds: record.scorerIds,
|
|
3104
3125
|
version: 0,
|
|
3126
|
+
organizationId: record.organizationId,
|
|
3127
|
+
projectId: record.projectId,
|
|
3128
|
+
candidateKey: record.candidateKey,
|
|
3129
|
+
candidateId: record.candidateId,
|
|
3105
3130
|
createdAt: now,
|
|
3106
3131
|
updatedAt: now
|
|
3107
3132
|
}
|
|
@@ -3231,8 +3256,28 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3231
3256
|
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3232
3257
|
try {
|
|
3233
3258
|
const tableName = quoteIdent(storage.TABLE_DATASETS, "table name");
|
|
3259
|
+
const filterConditions = [];
|
|
3260
|
+
const filterParams = {};
|
|
3261
|
+
if (args.filters?.organizationId !== void 0) {
|
|
3262
|
+
filterConditions.push(`${quoteIdent("organizationId", "column name")} = @organizationId`);
|
|
3263
|
+
filterParams.organizationId = args.filters.organizationId;
|
|
3264
|
+
}
|
|
3265
|
+
if (args.filters?.projectId !== void 0) {
|
|
3266
|
+
filterConditions.push(`${quoteIdent("projectId", "column name")} = @projectId`);
|
|
3267
|
+
filterParams.projectId = args.filters.projectId;
|
|
3268
|
+
}
|
|
3269
|
+
if (args.filters?.candidateKey !== void 0) {
|
|
3270
|
+
filterConditions.push(`${quoteIdent("candidateKey", "column name")} = @candidateKey`);
|
|
3271
|
+
filterParams.candidateKey = args.filters.candidateKey;
|
|
3272
|
+
}
|
|
3273
|
+
if (args.filters?.candidateId !== void 0) {
|
|
3274
|
+
filterConditions.push(`${quoteIdent("candidateId", "column name")} = @candidateId`);
|
|
3275
|
+
filterParams.candidateId = args.filters.candidateId;
|
|
3276
|
+
}
|
|
3277
|
+
const whereClause = filterConditions.length > 0 ? `WHERE ${filterConditions.join(" AND ")}` : "";
|
|
3234
3278
|
const [countRows] = await this.database.run({
|
|
3235
|
-
sql: `SELECT COUNT(*) AS count FROM ${tableName}`,
|
|
3279
|
+
sql: `SELECT COUNT(*) AS count FROM ${tableName} ${whereClause}`,
|
|
3280
|
+
params: filterParams,
|
|
3236
3281
|
json: true
|
|
3237
3282
|
});
|
|
3238
3283
|
const total = Number(countRows[0]?.count ?? 0);
|
|
@@ -3241,10 +3286,10 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3241
3286
|
}
|
|
3242
3287
|
const limit = perPageInput === false ? total : perPage;
|
|
3243
3288
|
const [rows] = await this.database.run({
|
|
3244
|
-
sql: `SELECT * FROM ${tableName}
|
|
3289
|
+
sql: `SELECT * FROM ${tableName} ${whereClause}
|
|
3245
3290
|
ORDER BY ${quoteIdent("createdAt", "column name")} DESC, ${quoteIdent("id", "column name")} ASC
|
|
3246
3291
|
LIMIT @limit OFFSET @offset`,
|
|
3247
|
-
params: { limit, offset },
|
|
3292
|
+
params: { ...filterParams, limit, offset },
|
|
3248
3293
|
json: true
|
|
3249
3294
|
});
|
|
3250
3295
|
const datasets = rows.map(rowToDataset);
|
|
@@ -3271,10 +3316,13 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3271
3316
|
// ==========================================================================
|
|
3272
3317
|
// SCD-2 helpers
|
|
3273
3318
|
// ==========================================================================
|
|
3274
|
-
/** Reads and increments the dataset version inside `tx`; throws if missing. */
|
|
3319
|
+
/** Reads and increments the dataset version inside `tx`; throws if missing. Also returns parent tenancy. */
|
|
3275
3320
|
async bumpVersion(tx, datasetId, now) {
|
|
3276
3321
|
const [rows] = await tx.run({
|
|
3277
|
-
sql: `SELECT ${quoteIdent("version", "column name")} AS version
|
|
3322
|
+
sql: `SELECT ${quoteIdent("version", "column name")} AS version,
|
|
3323
|
+
${quoteIdent("organizationId", "column name")} AS organizationId,
|
|
3324
|
+
${quoteIdent("projectId", "column name")} AS projectId
|
|
3325
|
+
FROM ${quoteIdent(storage.TABLE_DATASETS, "table name")}
|
|
3278
3326
|
WHERE ${quoteIdent("id", "column name")} = @id LIMIT 1`,
|
|
3279
3327
|
params: { id: datasetId },
|
|
3280
3328
|
json: true
|
|
@@ -3298,7 +3346,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3298
3346
|
params: { newVersion, now: now.toISOString(), id: datasetId },
|
|
3299
3347
|
types: { now: "timestamp" }
|
|
3300
3348
|
});
|
|
3301
|
-
return newVersion;
|
|
3349
|
+
return { version: newVersion, organizationId: row.organizationId ?? null, projectId: row.projectId ?? null };
|
|
3302
3350
|
}
|
|
3303
3351
|
/** Inserts a dataset version snapshot row inside `tx`. */
|
|
3304
3352
|
async insertVersionRow(tx, datasetId, version, now) {
|
|
@@ -3343,18 +3391,21 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3343
3391
|
await this.db.runWithAbortRetry(
|
|
3344
3392
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3345
3393
|
try {
|
|
3346
|
-
const newVersion = await this.bumpVersion(tx, args.datasetId, now);
|
|
3394
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, args.datasetId, now);
|
|
3347
3395
|
await this.db.insert({
|
|
3348
3396
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
3349
3397
|
record: {
|
|
3350
3398
|
id: itemId,
|
|
3351
3399
|
datasetId: args.datasetId,
|
|
3352
3400
|
datasetVersion: newVersion,
|
|
3401
|
+
organizationId,
|
|
3402
|
+
projectId,
|
|
3353
3403
|
validTo: null,
|
|
3354
3404
|
isDeleted: false,
|
|
3355
3405
|
input: args.input,
|
|
3356
3406
|
groundTruth: args.groundTruth ?? null,
|
|
3357
3407
|
expectedTrajectory: args.expectedTrajectory ?? null,
|
|
3408
|
+
toolMocks: args.toolMocks ?? null,
|
|
3358
3409
|
requestContext: args.requestContext ?? null,
|
|
3359
3410
|
metadata: args.metadata ?? null,
|
|
3360
3411
|
source: args.source ?? null,
|
|
@@ -3369,9 +3420,12 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3369
3420
|
id: itemId,
|
|
3370
3421
|
datasetId: args.datasetId,
|
|
3371
3422
|
datasetVersion: newVersion,
|
|
3423
|
+
organizationId,
|
|
3424
|
+
projectId,
|
|
3372
3425
|
input: args.input,
|
|
3373
3426
|
groundTruth: args.groundTruth,
|
|
3374
3427
|
expectedTrajectory: args.expectedTrajectory,
|
|
3428
|
+
toolMocks: args.toolMocks,
|
|
3375
3429
|
requestContext: args.requestContext,
|
|
3376
3430
|
metadata: args.metadata,
|
|
3377
3431
|
source: args.source,
|
|
@@ -3424,6 +3478,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3424
3478
|
input: args.input !== void 0 ? args.input : existing.input,
|
|
3425
3479
|
groundTruth: args.groundTruth !== void 0 ? args.groundTruth : existing.groundTruth,
|
|
3426
3480
|
expectedTrajectory: args.expectedTrajectory !== void 0 ? args.expectedTrajectory : existing.expectedTrajectory,
|
|
3481
|
+
toolMocks: args.toolMocks !== void 0 ? args.toolMocks : existing.toolMocks,
|
|
3427
3482
|
requestContext: args.requestContext !== void 0 ? args.requestContext : existing.requestContext,
|
|
3428
3483
|
metadata: args.metadata !== void 0 ? args.metadata : existing.metadata,
|
|
3429
3484
|
source: args.source !== void 0 ? args.source : existing.source
|
|
@@ -3433,7 +3488,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3433
3488
|
await this.db.runWithAbortRetry(
|
|
3434
3489
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3435
3490
|
try {
|
|
3436
|
-
const newVersion = await this.bumpVersion(tx, args.datasetId, now);
|
|
3491
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, args.datasetId, now);
|
|
3437
3492
|
await this.closeCurrentRow(tx, args.id, newVersion);
|
|
3438
3493
|
await this.db.insert({
|
|
3439
3494
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
@@ -3441,11 +3496,14 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3441
3496
|
id: args.id,
|
|
3442
3497
|
datasetId: args.datasetId,
|
|
3443
3498
|
datasetVersion: newVersion,
|
|
3499
|
+
organizationId,
|
|
3500
|
+
projectId,
|
|
3444
3501
|
validTo: null,
|
|
3445
3502
|
isDeleted: false,
|
|
3446
3503
|
input: merged.input,
|
|
3447
3504
|
groundTruth: merged.groundTruth ?? null,
|
|
3448
3505
|
expectedTrajectory: merged.expectedTrajectory ?? null,
|
|
3506
|
+
toolMocks: merged.toolMocks ?? null,
|
|
3449
3507
|
requestContext: merged.requestContext ?? null,
|
|
3450
3508
|
metadata: merged.metadata ?? null,
|
|
3451
3509
|
source: merged.source ?? null,
|
|
@@ -3460,9 +3518,12 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3460
3518
|
id: args.id,
|
|
3461
3519
|
datasetId: args.datasetId,
|
|
3462
3520
|
datasetVersion: newVersion,
|
|
3521
|
+
organizationId,
|
|
3522
|
+
projectId,
|
|
3463
3523
|
input: merged.input,
|
|
3464
3524
|
groundTruth: merged.groundTruth,
|
|
3465
3525
|
expectedTrajectory: merged.expectedTrajectory,
|
|
3526
|
+
toolMocks: merged.toolMocks,
|
|
3466
3527
|
requestContext: merged.requestContext,
|
|
3467
3528
|
metadata: merged.metadata,
|
|
3468
3529
|
source: merged.source,
|
|
@@ -3507,7 +3568,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3507
3568
|
await this.db.runWithAbortRetry(
|
|
3508
3569
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3509
3570
|
try {
|
|
3510
|
-
const newVersion = await this.bumpVersion(tx, args.datasetId, now);
|
|
3571
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, args.datasetId, now);
|
|
3511
3572
|
await this.closeCurrentRow(tx, args.id, newVersion);
|
|
3512
3573
|
await this.db.insert({
|
|
3513
3574
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
@@ -3515,11 +3576,14 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3515
3576
|
id: args.id,
|
|
3516
3577
|
datasetId: args.datasetId,
|
|
3517
3578
|
datasetVersion: newVersion,
|
|
3579
|
+
organizationId,
|
|
3580
|
+
projectId,
|
|
3518
3581
|
validTo: null,
|
|
3519
3582
|
isDeleted: true,
|
|
3520
3583
|
input: existing.input,
|
|
3521
3584
|
groundTruth: existing.groundTruth ?? null,
|
|
3522
3585
|
expectedTrajectory: existing.expectedTrajectory ?? null,
|
|
3586
|
+
toolMocks: existing.toolMocks ?? null,
|
|
3523
3587
|
requestContext: existing.requestContext ?? null,
|
|
3524
3588
|
metadata: existing.metadata ?? null,
|
|
3525
3589
|
source: existing.source ?? null,
|
|
@@ -3557,6 +3621,14 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3557
3621
|
try {
|
|
3558
3622
|
const conditions = [`${quoteIdent("datasetId", "column name")} = @datasetId`];
|
|
3559
3623
|
const params = { datasetId: args.datasetId };
|
|
3624
|
+
if (args.filters?.organizationId !== void 0) {
|
|
3625
|
+
conditions.push(`${quoteIdent("organizationId", "column name")} = @organizationId`);
|
|
3626
|
+
params.organizationId = args.filters.organizationId;
|
|
3627
|
+
}
|
|
3628
|
+
if (args.filters?.projectId !== void 0) {
|
|
3629
|
+
conditions.push(`${quoteIdent("projectId", "column name")} = @projectId`);
|
|
3630
|
+
params.projectId = args.filters.projectId;
|
|
3631
|
+
}
|
|
3560
3632
|
if (args.version !== void 0) {
|
|
3561
3633
|
conditions.push(`${quoteIdent("datasetVersion", "column name")} <= @version`);
|
|
3562
3634
|
conditions.push(
|
|
@@ -3778,7 +3850,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3778
3850
|
await this.db.runWithAbortRetry(
|
|
3779
3851
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3780
3852
|
try {
|
|
3781
|
-
const newVersion = await this.bumpVersion(tx, input.datasetId, now);
|
|
3853
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, input.datasetId, now);
|
|
3782
3854
|
for (const { id, item } of prepared) {
|
|
3783
3855
|
await this.db.insert({
|
|
3784
3856
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
@@ -3786,11 +3858,14 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3786
3858
|
id,
|
|
3787
3859
|
datasetId: input.datasetId,
|
|
3788
3860
|
datasetVersion: newVersion,
|
|
3861
|
+
organizationId,
|
|
3862
|
+
projectId,
|
|
3789
3863
|
validTo: null,
|
|
3790
3864
|
isDeleted: false,
|
|
3791
3865
|
input: item.input,
|
|
3792
3866
|
groundTruth: item.groundTruth ?? null,
|
|
3793
3867
|
expectedTrajectory: item.expectedTrajectory ?? null,
|
|
3868
|
+
toolMocks: item.toolMocks ?? null,
|
|
3794
3869
|
requestContext: item.requestContext ?? null,
|
|
3795
3870
|
metadata: item.metadata ?? null,
|
|
3796
3871
|
source: item.source ?? null,
|
|
@@ -3806,9 +3881,12 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3806
3881
|
id,
|
|
3807
3882
|
datasetId: input.datasetId,
|
|
3808
3883
|
datasetVersion: newVersion,
|
|
3884
|
+
organizationId,
|
|
3885
|
+
projectId,
|
|
3809
3886
|
input: item.input,
|
|
3810
3887
|
groundTruth: item.groundTruth,
|
|
3811
3888
|
expectedTrajectory: item.expectedTrajectory,
|
|
3889
|
+
toolMocks: item.toolMocks,
|
|
3812
3890
|
requestContext: item.requestContext,
|
|
3813
3891
|
metadata: item.metadata,
|
|
3814
3892
|
source: item.source,
|
|
@@ -3848,7 +3926,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3848
3926
|
await this.db.runWithAbortRetry(
|
|
3849
3927
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3850
3928
|
try {
|
|
3851
|
-
const newVersion = await this.bumpVersion(tx, input.datasetId, now);
|
|
3929
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, input.datasetId, now);
|
|
3852
3930
|
for (const existing of current) {
|
|
3853
3931
|
await this.closeCurrentRow(tx, existing.id, newVersion);
|
|
3854
3932
|
await this.db.insert({
|
|
@@ -3857,11 +3935,14 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3857
3935
|
id: existing.id,
|
|
3858
3936
|
datasetId: input.datasetId,
|
|
3859
3937
|
datasetVersion: newVersion,
|
|
3938
|
+
organizationId,
|
|
3939
|
+
projectId,
|
|
3860
3940
|
validTo: null,
|
|
3861
3941
|
isDeleted: true,
|
|
3862
3942
|
input: existing.input,
|
|
3863
3943
|
groundTruth: existing.groundTruth ?? null,
|
|
3864
3944
|
expectedTrajectory: existing.expectedTrajectory ?? null,
|
|
3945
|
+
toolMocks: existing.toolMocks ?? null,
|
|
3865
3946
|
requestContext: existing.requestContext ?? null,
|
|
3866
3947
|
metadata: existing.metadata ?? null,
|
|
3867
3948
|
source: existing.source ?? null,
|
|
@@ -3906,6 +3987,8 @@ function rowToExperiment(row) {
|
|
|
3906
3987
|
metadata: t.metadata ?? void 0,
|
|
3907
3988
|
datasetId: t.datasetId ?? null,
|
|
3908
3989
|
datasetVersion: t.datasetVersion == null ? null : Number(t.datasetVersion),
|
|
3990
|
+
organizationId: t.organizationId ?? null,
|
|
3991
|
+
projectId: t.projectId ?? null,
|
|
3909
3992
|
targetType: t.targetType,
|
|
3910
3993
|
targetId: String(t.targetId),
|
|
3911
3994
|
status: t.status,
|
|
@@ -3927,6 +4010,8 @@ function rowToExperimentResult(row) {
|
|
|
3927
4010
|
experimentId: String(t.experimentId),
|
|
3928
4011
|
itemId: String(t.itemId),
|
|
3929
4012
|
itemDatasetVersion: t.itemDatasetVersion == null ? null : Number(t.itemDatasetVersion),
|
|
4013
|
+
organizationId: t.organizationId ?? null,
|
|
4014
|
+
projectId: t.projectId ?? null,
|
|
3930
4015
|
input: t.input ?? null,
|
|
3931
4016
|
output: t.output ?? null,
|
|
3932
4017
|
groundTruth: t.groundTruth ?? null,
|
|
@@ -3937,6 +4022,7 @@ function rowToExperimentResult(row) {
|
|
|
3937
4022
|
traceId: t.traceId ?? null,
|
|
3938
4023
|
status: t.status ?? null,
|
|
3939
4024
|
tags: t.tags ?? null,
|
|
4025
|
+
toolMockReport: t.toolMockReport ?? null,
|
|
3940
4026
|
createdAt: toDate2(t.createdAt)
|
|
3941
4027
|
};
|
|
3942
4028
|
}
|
|
@@ -3957,6 +4043,16 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
3957
4043
|
async init() {
|
|
3958
4044
|
await this.db.createTable({ tableName: storage.TABLE_EXPERIMENTS, schema: storage.TABLE_SCHEMAS[storage.TABLE_EXPERIMENTS] });
|
|
3959
4045
|
await this.db.createTable({ tableName: storage.TABLE_EXPERIMENT_RESULTS, schema: storage.TABLE_SCHEMAS[storage.TABLE_EXPERIMENT_RESULTS] });
|
|
4046
|
+
await this.db.alterTable({
|
|
4047
|
+
tableName: storage.TABLE_EXPERIMENTS,
|
|
4048
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_EXPERIMENTS],
|
|
4049
|
+
ifNotExists: ["organizationId", "projectId"]
|
|
4050
|
+
});
|
|
4051
|
+
await this.db.alterTable({
|
|
4052
|
+
tableName: storage.TABLE_EXPERIMENT_RESULTS,
|
|
4053
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_EXPERIMENT_RESULTS],
|
|
4054
|
+
ifNotExists: ["organizationId", "projectId"]
|
|
4055
|
+
});
|
|
3960
4056
|
await this.createDefaultIndexes();
|
|
3961
4057
|
await this.createCustomIndexes();
|
|
3962
4058
|
}
|
|
@@ -3978,6 +4074,17 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
3978
4074
|
table: storage.TABLE_EXPERIMENT_RESULTS,
|
|
3979
4075
|
columns: ["experimentId", "itemId"],
|
|
3980
4076
|
unique: true
|
|
4077
|
+
},
|
|
4078
|
+
// Tenancy: leading-tenant indexes for multi-tenant scans (parity with datasets domain).
|
|
4079
|
+
{
|
|
4080
|
+
name: "mastra_experiments_org_project_idx",
|
|
4081
|
+
table: storage.TABLE_EXPERIMENTS,
|
|
4082
|
+
columns: ["organizationId", "projectId"]
|
|
4083
|
+
},
|
|
4084
|
+
{
|
|
4085
|
+
name: "mastra_experiment_results_org_project_idx",
|
|
4086
|
+
table: storage.TABLE_EXPERIMENT_RESULTS,
|
|
4087
|
+
columns: ["organizationId", "projectId"]
|
|
3981
4088
|
}
|
|
3982
4089
|
];
|
|
3983
4090
|
}
|
|
@@ -4004,6 +4111,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4004
4111
|
metadata: input.metadata ?? void 0,
|
|
4005
4112
|
datasetId: input.datasetId ?? null,
|
|
4006
4113
|
datasetVersion: input.datasetVersion ?? null,
|
|
4114
|
+
organizationId: input.organizationId ?? null,
|
|
4115
|
+
projectId: input.projectId ?? null,
|
|
4007
4116
|
targetType: input.targetType,
|
|
4008
4117
|
targetId: input.targetId,
|
|
4009
4118
|
status: "pending",
|
|
@@ -4026,6 +4135,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4026
4135
|
metadata: experiment.metadata ?? null,
|
|
4027
4136
|
datasetId: experiment.datasetId,
|
|
4028
4137
|
datasetVersion: experiment.datasetVersion,
|
|
4138
|
+
organizationId: experiment.organizationId,
|
|
4139
|
+
projectId: experiment.projectId,
|
|
4029
4140
|
targetType: experiment.targetType,
|
|
4030
4141
|
targetId: experiment.targetId,
|
|
4031
4142
|
status: experiment.status,
|
|
@@ -4144,6 +4255,17 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4144
4255
|
conditions.push(`${quoteIdent("status", "column name")} = @status`);
|
|
4145
4256
|
params.status = args.status;
|
|
4146
4257
|
}
|
|
4258
|
+
if (args.filters) {
|
|
4259
|
+
const { organizationId, projectId } = args.filters;
|
|
4260
|
+
if (organizationId !== void 0) {
|
|
4261
|
+
conditions.push(`${quoteIdent("organizationId", "column name")} = @organizationId`);
|
|
4262
|
+
params.organizationId = organizationId;
|
|
4263
|
+
}
|
|
4264
|
+
if (projectId !== void 0) {
|
|
4265
|
+
conditions.push(`${quoteIdent("projectId", "column name")} = @projectId`);
|
|
4266
|
+
params.projectId = projectId;
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4147
4269
|
const whereSql = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
4148
4270
|
const tableName = quoteIdent(storage.TABLE_EXPERIMENTS, "table name");
|
|
4149
4271
|
const [countRows] = await this.database.run({
|
|
@@ -4228,6 +4350,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4228
4350
|
experimentId: input.experimentId,
|
|
4229
4351
|
itemId: input.itemId,
|
|
4230
4352
|
itemDatasetVersion: input.itemDatasetVersion ?? null,
|
|
4353
|
+
organizationId: input.organizationId ?? null,
|
|
4354
|
+
projectId: input.projectId ?? null,
|
|
4231
4355
|
input: input.input ?? null,
|
|
4232
4356
|
output: input.output ?? null,
|
|
4233
4357
|
groundTruth: input.groundTruth ?? null,
|
|
@@ -4238,6 +4362,7 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4238
4362
|
traceId: input.traceId ?? null,
|
|
4239
4363
|
status: input.status ?? null,
|
|
4240
4364
|
tags: input.tags ?? null,
|
|
4365
|
+
toolMockReport: input.toolMockReport ?? null,
|
|
4241
4366
|
createdAt: now
|
|
4242
4367
|
};
|
|
4243
4368
|
await this.db.insert({
|
|
@@ -4247,6 +4372,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4247
4372
|
experimentId: result.experimentId,
|
|
4248
4373
|
itemId: result.itemId,
|
|
4249
4374
|
itemDatasetVersion: result.itemDatasetVersion,
|
|
4375
|
+
organizationId: result.organizationId,
|
|
4376
|
+
projectId: result.projectId,
|
|
4250
4377
|
input: result.input,
|
|
4251
4378
|
output: result.output,
|
|
4252
4379
|
groundTruth: result.groundTruth,
|
|
@@ -4257,6 +4384,7 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4257
4384
|
traceId: result.traceId,
|
|
4258
4385
|
status: result.status,
|
|
4259
4386
|
tags: result.tags,
|
|
4387
|
+
toolMockReport: result.toolMockReport,
|
|
4260
4388
|
createdAt: now
|
|
4261
4389
|
}
|
|
4262
4390
|
});
|
|
@@ -4379,6 +4507,17 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4379
4507
|
conditions.push(`${quoteIdent("status", "column name")} = @status`);
|
|
4380
4508
|
params.status = args.status;
|
|
4381
4509
|
}
|
|
4510
|
+
if (args.filters) {
|
|
4511
|
+
const { organizationId, projectId } = args.filters;
|
|
4512
|
+
if (organizationId !== void 0) {
|
|
4513
|
+
conditions.push(`${quoteIdent("organizationId", "column name")} = @organizationId`);
|
|
4514
|
+
params.organizationId = organizationId;
|
|
4515
|
+
}
|
|
4516
|
+
if (projectId !== void 0) {
|
|
4517
|
+
conditions.push(`${quoteIdent("projectId", "column name")} = @projectId`);
|
|
4518
|
+
params.projectId = projectId;
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4382
4521
|
const whereSql = `WHERE ${conditions.join(" AND ")}`;
|
|
4383
4522
|
const tableName = quoteIdent(storage.TABLE_EXPERIMENT_RESULTS, "table name");
|
|
4384
4523
|
const [countRows] = await this.database.run({
|