@mastra/spanner 1.2.1-alpha.0 → 1.2.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 +144 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +137 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +137 -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 +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,149 @@
|
|
|
1
1
|
# @mastra/spanner
|
|
2
2
|
|
|
3
|
+
## 1.2.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
|
+
- 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))
|
|
72
|
+
|
|
73
|
+
- Updated dependencies [[`5bd72d2`](https://github.com/mastra-ai/mastra/commit/5bd72d255f45b5ea8ab342643bd463814a980a24), [`1cc9ee1`](https://github.com/mastra-ai/mastra/commit/1cc9ee1ba51db53020a735626d33017a60b4b5b3), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`65f255a`](https://github.com/mastra-ai/mastra/commit/65f255a38667beb6ceeadabfa9eb5059bfec8298), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`30ebaf0`](https://github.com/mastra-ai/mastra/commit/30ebaf07bed5f4d30f2f257836c15d1bf7e40aae), [`5704634`](https://github.com/mastra-ai/mastra/commit/5704634b22133167dea337a942a34f57aaa3fa14), [`5c4e9a4`](https://github.com/mastra-ai/mastra/commit/5c4e9a4cfb2216bb3ea7f8988ad3727f3b92bb3a), [`4a88c6e`](https://github.com/mastra-ai/mastra/commit/4a88c6e2bdce316f8d7551b4ec3449b0b06fc71c), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`25961e3`](https://github.com/mastra-ai/mastra/commit/25961e3260ff3b1464637af8fcdb36210551c39f), [`6a1428a`](https://github.com/mastra-ai/mastra/commit/6a1428a23133fc070fc6c1caa08d28f3ba4fe5ff), [`87a17ef`](https://github.com/mastra-ai/mastra/commit/87a17efbd725aca6639febdc5e69e2abb3048689), [`e11ff30`](https://github.com/mastra-ai/mastra/commit/e11ff301408bf1731dca2fb7fbfcd8c819500a35), [`7794d71`](https://github.com/mastra-ai/mastra/commit/7794d71872c68733a30e028dfb7b1705daf6c5d2), [`9d2c946`](https://github.com/mastra-ai/mastra/commit/9d2c946d0859e90ae4bcec5beeb1da7398d2ad1e), [`c0eda2b`](https://github.com/mastra-ai/mastra/commit/c0eda2bcd91a228427314b12c91d8b147f3a739f), [`7b29f33`](https://github.com/mastra-ai/mastra/commit/7b29f332a357a83e555f29e718e5f2fab9979943), [`c0eda2b`](https://github.com/mastra-ai/mastra/commit/c0eda2bcd91a228427314b12c91d8b147f3a739f), [`b13925b`](https://github.com/mastra-ai/mastra/commit/b13925bfa91aa8700f56fa54a9ce707ee7e4ba62), [`f1ec385`](https://github.com/mastra-ai/mastra/commit/f1ec385386f62b1a0847ec5353ae2bb169d1c3d9), [`e14986f`](https://github.com/mastra-ai/mastra/commit/e14986f6e5478d6384d04ff9a7f9a79a46a8b529), [`24912b1`](https://github.com/mastra-ai/mastra/commit/24912b1f855d29ec36af4ef4bde1f7417e20cdf5), [`bf94ec6`](https://github.com/mastra-ai/mastra/commit/bf94ec68192d9f16e46ef7e5ac36370aeeddf35d), [`a29f371`](https://github.com/mastra-ai/mastra/commit/a29f371aef629ac8562661524a497127e93b5131), [`7686216`](https://github.com/mastra-ai/mastra/commit/7686216f37e74568feddec17cef3c3d24e10e60a), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`073f910`](https://github.com/mastra-ai/mastra/commit/073f910481e7d94b95ba3830f96531774ae95d33), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`0be490f`](https://github.com/mastra-ai/mastra/commit/0be490fabb538c5a7de796ea0aff7d04a0bea1f3), [`ebbe1d3`](https://github.com/mastra-ai/mastra/commit/ebbe1d31a965a3adb0e728758f326b8122b4b55f), [`974f614`](https://github.com/mastra-ai/mastra/commit/974f614e083bd68278536f94453f7b320b86a3c7), [`3818814`](https://github.com/mastra-ai/mastra/commit/38188149ce454c4403fe9fcbdf73b735c68d36be), [`975c59a`](https://github.com/mastra-ai/mastra/commit/975c59ae363ee275fc55062392e1ffd2cbccbd53), [`1f97ce5`](https://github.com/mastra-ai/mastra/commit/1f97ce5695463bebb4eaacf501da6fb403e20885), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`7f51548`](https://github.com/mastra-ai/mastra/commit/7f515481213780be7047cef00640b9d35f3d545c), [`64f58c0`](https://github.com/mastra-ai/mastra/commit/64f58c04e78b40137497d47f781e897e416f22a5), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`ebbe1d3`](https://github.com/mastra-ai/mastra/commit/ebbe1d31a965a3adb0e728758f326b8122b4b55f), [`d95f394`](https://github.com/mastra-ai/mastra/commit/d95f394fd24c8411886930d727679c4d5252aa26), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`8e25a78`](https://github.com/mastra-ai/mastra/commit/8e25a78e0597575f0b0729bae8c5e190c84869b5), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`f3f0c9d`](https://github.com/mastra-ai/mastra/commit/f3f0c9d7c878db5a13177871ce3523a14f14b311), [`a5b22d3`](https://github.com/mastra-ai/mastra/commit/a5b22d314d62a68d801886a8d3d0eb6c089473db), [`31be1cf`](https://github.com/mastra-ai/mastra/commit/31be1cf5f2a7b5eef12f6123a40653b4d8115c16), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858)]:
|
|
74
|
+
- @mastra/core@1.46.0
|
|
75
|
+
|
|
76
|
+
## 1.2.1-alpha.1
|
|
77
|
+
|
|
78
|
+
### Patch Changes
|
|
79
|
+
|
|
80
|
+
- 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))
|
|
81
|
+
|
|
82
|
+
`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.
|
|
83
|
+
|
|
84
|
+
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.
|
|
85
|
+
|
|
86
|
+
This release also clarifies the `targetType` contract via JSDoc:
|
|
87
|
+
- `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.
|
|
88
|
+
- `Experiment.targetType` / `CreateExperimentInput.targetType` stay required. An experiment by definition replays inputs against a specific target.
|
|
89
|
+
|
|
90
|
+
No behavior change for existing OSS-created experiments; the new fields are additive and optional.
|
|
91
|
+
|
|
92
|
+
Example:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
// Create an experiment scoped to a tenancy bucket. When the parent dataset
|
|
96
|
+
// already carries `organizationId` / `projectId`, `runExperiment` hydrates
|
|
97
|
+
// these fields automatically from the dataset record.
|
|
98
|
+
const experiment = await storage.createExperiment({
|
|
99
|
+
name: 'qa-regression',
|
|
100
|
+
datasetId: 'ds_123',
|
|
101
|
+
datasetVersion: 1,
|
|
102
|
+
targetType: 'agent',
|
|
103
|
+
targetId: 'agent_qa',
|
|
104
|
+
totalItems: 10,
|
|
105
|
+
organizationId: 'org_123',
|
|
106
|
+
projectId: 'proj_123',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// List experiments within a tenancy bucket.
|
|
110
|
+
const experiments = await storage.listExperiments({
|
|
111
|
+
pagination: { page: 0, perPage: 20 },
|
|
112
|
+
filters: { organizationId: 'org_123', projectId: 'proj_123' },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// List per-item results within the same bucket.
|
|
116
|
+
const results = await storage.listExperimentResults({
|
|
117
|
+
experimentId: experiment.id,
|
|
118
|
+
pagination: { page: 0, perPage: 50 },
|
|
119
|
+
filters: { organizationId: 'org_123', projectId: 'proj_123' },
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- Persist and filter dataset tenancy + candidate identity in storage adapters. ([#18314](https://github.com/mastra-ai/mastra/pull/18314))
|
|
124
|
+
|
|
125
|
+
`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).
|
|
126
|
+
|
|
127
|
+
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.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
await storage.createDataset({
|
|
131
|
+
name: 'candidates/missing-tool-call/incident-123',
|
|
132
|
+
organizationId: 'org_abc',
|
|
133
|
+
projectId: 'project_xyz',
|
|
134
|
+
candidateKey: 'missing-tool-call',
|
|
135
|
+
candidateId: 'incident-123',
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await storage.listDatasets({
|
|
139
|
+
pagination: { page: 0, perPage: 20 },
|
|
140
|
+
filters: { organizationId: 'org_abc', projectId: 'project_xyz' },
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- 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)]:
|
|
145
|
+
- @mastra/core@1.46.0-alpha.4
|
|
146
|
+
|
|
3
147
|
## 1.2.1-alpha.0
|
|
4
148
|
|
|
5
149
|
### Patch 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,6 +2983,8 @@ 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,
|
|
@@ -3025,6 +3031,16 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3025
3031
|
await this.db.createTable({ tableName: storage.TABLE_DATASETS, schema: storage.TABLE_SCHEMAS[storage.TABLE_DATASETS] });
|
|
3026
3032
|
await this.db.createTable({ tableName: storage.TABLE_DATASET_ITEMS, schema: storage.TABLE_SCHEMAS[storage.TABLE_DATASET_ITEMS] });
|
|
3027
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
|
+
});
|
|
3028
3044
|
await this.createDefaultIndexes();
|
|
3029
3045
|
await this.createCustomIndexes();
|
|
3030
3046
|
}
|
|
@@ -3085,6 +3101,10 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3085
3101
|
targetIds: input.targetIds ?? null,
|
|
3086
3102
|
scorerIds: input.scorerIds ?? null,
|
|
3087
3103
|
version: 0,
|
|
3104
|
+
organizationId: input.organizationId ?? null,
|
|
3105
|
+
projectId: input.projectId ?? null,
|
|
3106
|
+
candidateKey: input.candidateKey ?? null,
|
|
3107
|
+
candidateId: input.candidateId ?? null,
|
|
3088
3108
|
createdAt: now,
|
|
3089
3109
|
updatedAt: now
|
|
3090
3110
|
};
|
|
@@ -3103,6 +3123,10 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3103
3123
|
targetIds: record.targetIds,
|
|
3104
3124
|
scorerIds: record.scorerIds,
|
|
3105
3125
|
version: 0,
|
|
3126
|
+
organizationId: record.organizationId,
|
|
3127
|
+
projectId: record.projectId,
|
|
3128
|
+
candidateKey: record.candidateKey,
|
|
3129
|
+
candidateId: record.candidateId,
|
|
3106
3130
|
createdAt: now,
|
|
3107
3131
|
updatedAt: now
|
|
3108
3132
|
}
|
|
@@ -3232,8 +3256,28 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3232
3256
|
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3233
3257
|
try {
|
|
3234
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 ")}` : "";
|
|
3235
3278
|
const [countRows] = await this.database.run({
|
|
3236
|
-
sql: `SELECT COUNT(*) AS count FROM ${tableName}`,
|
|
3279
|
+
sql: `SELECT COUNT(*) AS count FROM ${tableName} ${whereClause}`,
|
|
3280
|
+
params: filterParams,
|
|
3237
3281
|
json: true
|
|
3238
3282
|
});
|
|
3239
3283
|
const total = Number(countRows[0]?.count ?? 0);
|
|
@@ -3242,10 +3286,10 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3242
3286
|
}
|
|
3243
3287
|
const limit = perPageInput === false ? total : perPage;
|
|
3244
3288
|
const [rows] = await this.database.run({
|
|
3245
|
-
sql: `SELECT * FROM ${tableName}
|
|
3289
|
+
sql: `SELECT * FROM ${tableName} ${whereClause}
|
|
3246
3290
|
ORDER BY ${quoteIdent("createdAt", "column name")} DESC, ${quoteIdent("id", "column name")} ASC
|
|
3247
3291
|
LIMIT @limit OFFSET @offset`,
|
|
3248
|
-
params: { limit, offset },
|
|
3292
|
+
params: { ...filterParams, limit, offset },
|
|
3249
3293
|
json: true
|
|
3250
3294
|
});
|
|
3251
3295
|
const datasets = rows.map(rowToDataset);
|
|
@@ -3272,10 +3316,13 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3272
3316
|
// ==========================================================================
|
|
3273
3317
|
// SCD-2 helpers
|
|
3274
3318
|
// ==========================================================================
|
|
3275
|
-
/** 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. */
|
|
3276
3320
|
async bumpVersion(tx, datasetId, now) {
|
|
3277
3321
|
const [rows] = await tx.run({
|
|
3278
|
-
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")}
|
|
3279
3326
|
WHERE ${quoteIdent("id", "column name")} = @id LIMIT 1`,
|
|
3280
3327
|
params: { id: datasetId },
|
|
3281
3328
|
json: true
|
|
@@ -3299,7 +3346,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3299
3346
|
params: { newVersion, now: now.toISOString(), id: datasetId },
|
|
3300
3347
|
types: { now: "timestamp" }
|
|
3301
3348
|
});
|
|
3302
|
-
return newVersion;
|
|
3349
|
+
return { version: newVersion, organizationId: row.organizationId ?? null, projectId: row.projectId ?? null };
|
|
3303
3350
|
}
|
|
3304
3351
|
/** Inserts a dataset version snapshot row inside `tx`. */
|
|
3305
3352
|
async insertVersionRow(tx, datasetId, version, now) {
|
|
@@ -3344,13 +3391,15 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3344
3391
|
await this.db.runWithAbortRetry(
|
|
3345
3392
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3346
3393
|
try {
|
|
3347
|
-
const newVersion = await this.bumpVersion(tx, args.datasetId, now);
|
|
3394
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, args.datasetId, now);
|
|
3348
3395
|
await this.db.insert({
|
|
3349
3396
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
3350
3397
|
record: {
|
|
3351
3398
|
id: itemId,
|
|
3352
3399
|
datasetId: args.datasetId,
|
|
3353
3400
|
datasetVersion: newVersion,
|
|
3401
|
+
organizationId,
|
|
3402
|
+
projectId,
|
|
3354
3403
|
validTo: null,
|
|
3355
3404
|
isDeleted: false,
|
|
3356
3405
|
input: args.input,
|
|
@@ -3371,6 +3420,8 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3371
3420
|
id: itemId,
|
|
3372
3421
|
datasetId: args.datasetId,
|
|
3373
3422
|
datasetVersion: newVersion,
|
|
3423
|
+
organizationId,
|
|
3424
|
+
projectId,
|
|
3374
3425
|
input: args.input,
|
|
3375
3426
|
groundTruth: args.groundTruth,
|
|
3376
3427
|
expectedTrajectory: args.expectedTrajectory,
|
|
@@ -3437,7 +3488,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3437
3488
|
await this.db.runWithAbortRetry(
|
|
3438
3489
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3439
3490
|
try {
|
|
3440
|
-
const newVersion = await this.bumpVersion(tx, args.datasetId, now);
|
|
3491
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, args.datasetId, now);
|
|
3441
3492
|
await this.closeCurrentRow(tx, args.id, newVersion);
|
|
3442
3493
|
await this.db.insert({
|
|
3443
3494
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
@@ -3445,6 +3496,8 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3445
3496
|
id: args.id,
|
|
3446
3497
|
datasetId: args.datasetId,
|
|
3447
3498
|
datasetVersion: newVersion,
|
|
3499
|
+
organizationId,
|
|
3500
|
+
projectId,
|
|
3448
3501
|
validTo: null,
|
|
3449
3502
|
isDeleted: false,
|
|
3450
3503
|
input: merged.input,
|
|
@@ -3465,6 +3518,8 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3465
3518
|
id: args.id,
|
|
3466
3519
|
datasetId: args.datasetId,
|
|
3467
3520
|
datasetVersion: newVersion,
|
|
3521
|
+
organizationId,
|
|
3522
|
+
projectId,
|
|
3468
3523
|
input: merged.input,
|
|
3469
3524
|
groundTruth: merged.groundTruth,
|
|
3470
3525
|
expectedTrajectory: merged.expectedTrajectory,
|
|
@@ -3513,7 +3568,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3513
3568
|
await this.db.runWithAbortRetry(
|
|
3514
3569
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3515
3570
|
try {
|
|
3516
|
-
const newVersion = await this.bumpVersion(tx, args.datasetId, now);
|
|
3571
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, args.datasetId, now);
|
|
3517
3572
|
await this.closeCurrentRow(tx, args.id, newVersion);
|
|
3518
3573
|
await this.db.insert({
|
|
3519
3574
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
@@ -3521,6 +3576,8 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3521
3576
|
id: args.id,
|
|
3522
3577
|
datasetId: args.datasetId,
|
|
3523
3578
|
datasetVersion: newVersion,
|
|
3579
|
+
organizationId,
|
|
3580
|
+
projectId,
|
|
3524
3581
|
validTo: null,
|
|
3525
3582
|
isDeleted: true,
|
|
3526
3583
|
input: existing.input,
|
|
@@ -3564,6 +3621,14 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3564
3621
|
try {
|
|
3565
3622
|
const conditions = [`${quoteIdent("datasetId", "column name")} = @datasetId`];
|
|
3566
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
|
+
}
|
|
3567
3632
|
if (args.version !== void 0) {
|
|
3568
3633
|
conditions.push(`${quoteIdent("datasetVersion", "column name")} <= @version`);
|
|
3569
3634
|
conditions.push(
|
|
@@ -3785,7 +3850,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3785
3850
|
await this.db.runWithAbortRetry(
|
|
3786
3851
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3787
3852
|
try {
|
|
3788
|
-
const newVersion = await this.bumpVersion(tx, input.datasetId, now);
|
|
3853
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, input.datasetId, now);
|
|
3789
3854
|
for (const { id, item } of prepared) {
|
|
3790
3855
|
await this.db.insert({
|
|
3791
3856
|
tableName: storage.TABLE_DATASET_ITEMS,
|
|
@@ -3793,6 +3858,8 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3793
3858
|
id,
|
|
3794
3859
|
datasetId: input.datasetId,
|
|
3795
3860
|
datasetVersion: newVersion,
|
|
3861
|
+
organizationId,
|
|
3862
|
+
projectId,
|
|
3796
3863
|
validTo: null,
|
|
3797
3864
|
isDeleted: false,
|
|
3798
3865
|
input: item.input,
|
|
@@ -3814,6 +3881,8 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3814
3881
|
id,
|
|
3815
3882
|
datasetId: input.datasetId,
|
|
3816
3883
|
datasetVersion: newVersion,
|
|
3884
|
+
organizationId,
|
|
3885
|
+
projectId,
|
|
3817
3886
|
input: item.input,
|
|
3818
3887
|
groundTruth: item.groundTruth,
|
|
3819
3888
|
expectedTrajectory: item.expectedTrajectory,
|
|
@@ -3857,7 +3926,7 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3857
3926
|
await this.db.runWithAbortRetry(
|
|
3858
3927
|
() => this.database.runTransactionAsync(async (tx) => {
|
|
3859
3928
|
try {
|
|
3860
|
-
const newVersion = await this.bumpVersion(tx, input.datasetId, now);
|
|
3929
|
+
const { version: newVersion, organizationId, projectId } = await this.bumpVersion(tx, input.datasetId, now);
|
|
3861
3930
|
for (const existing of current) {
|
|
3862
3931
|
await this.closeCurrentRow(tx, existing.id, newVersion);
|
|
3863
3932
|
await this.db.insert({
|
|
@@ -3866,6 +3935,8 @@ var DatasetsSpanner = class _DatasetsSpanner extends storage.DatasetsStorage {
|
|
|
3866
3935
|
id: existing.id,
|
|
3867
3936
|
datasetId: input.datasetId,
|
|
3868
3937
|
datasetVersion: newVersion,
|
|
3938
|
+
organizationId,
|
|
3939
|
+
projectId,
|
|
3869
3940
|
validTo: null,
|
|
3870
3941
|
isDeleted: true,
|
|
3871
3942
|
input: existing.input,
|
|
@@ -3916,6 +3987,8 @@ function rowToExperiment(row) {
|
|
|
3916
3987
|
metadata: t.metadata ?? void 0,
|
|
3917
3988
|
datasetId: t.datasetId ?? null,
|
|
3918
3989
|
datasetVersion: t.datasetVersion == null ? null : Number(t.datasetVersion),
|
|
3990
|
+
organizationId: t.organizationId ?? null,
|
|
3991
|
+
projectId: t.projectId ?? null,
|
|
3919
3992
|
targetType: t.targetType,
|
|
3920
3993
|
targetId: String(t.targetId),
|
|
3921
3994
|
status: t.status,
|
|
@@ -3937,6 +4010,8 @@ function rowToExperimentResult(row) {
|
|
|
3937
4010
|
experimentId: String(t.experimentId),
|
|
3938
4011
|
itemId: String(t.itemId),
|
|
3939
4012
|
itemDatasetVersion: t.itemDatasetVersion == null ? null : Number(t.itemDatasetVersion),
|
|
4013
|
+
organizationId: t.organizationId ?? null,
|
|
4014
|
+
projectId: t.projectId ?? null,
|
|
3940
4015
|
input: t.input ?? null,
|
|
3941
4016
|
output: t.output ?? null,
|
|
3942
4017
|
groundTruth: t.groundTruth ?? null,
|
|
@@ -3968,6 +4043,16 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
3968
4043
|
async init() {
|
|
3969
4044
|
await this.db.createTable({ tableName: storage.TABLE_EXPERIMENTS, schema: storage.TABLE_SCHEMAS[storage.TABLE_EXPERIMENTS] });
|
|
3970
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
|
+
});
|
|
3971
4056
|
await this.createDefaultIndexes();
|
|
3972
4057
|
await this.createCustomIndexes();
|
|
3973
4058
|
}
|
|
@@ -3989,6 +4074,17 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
3989
4074
|
table: storage.TABLE_EXPERIMENT_RESULTS,
|
|
3990
4075
|
columns: ["experimentId", "itemId"],
|
|
3991
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"]
|
|
3992
4088
|
}
|
|
3993
4089
|
];
|
|
3994
4090
|
}
|
|
@@ -4015,6 +4111,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4015
4111
|
metadata: input.metadata ?? void 0,
|
|
4016
4112
|
datasetId: input.datasetId ?? null,
|
|
4017
4113
|
datasetVersion: input.datasetVersion ?? null,
|
|
4114
|
+
organizationId: input.organizationId ?? null,
|
|
4115
|
+
projectId: input.projectId ?? null,
|
|
4018
4116
|
targetType: input.targetType,
|
|
4019
4117
|
targetId: input.targetId,
|
|
4020
4118
|
status: "pending",
|
|
@@ -4037,6 +4135,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4037
4135
|
metadata: experiment.metadata ?? null,
|
|
4038
4136
|
datasetId: experiment.datasetId,
|
|
4039
4137
|
datasetVersion: experiment.datasetVersion,
|
|
4138
|
+
organizationId: experiment.organizationId,
|
|
4139
|
+
projectId: experiment.projectId,
|
|
4040
4140
|
targetType: experiment.targetType,
|
|
4041
4141
|
targetId: experiment.targetId,
|
|
4042
4142
|
status: experiment.status,
|
|
@@ -4155,6 +4255,17 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4155
4255
|
conditions.push(`${quoteIdent("status", "column name")} = @status`);
|
|
4156
4256
|
params.status = args.status;
|
|
4157
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
|
+
}
|
|
4158
4269
|
const whereSql = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
4159
4270
|
const tableName = quoteIdent(storage.TABLE_EXPERIMENTS, "table name");
|
|
4160
4271
|
const [countRows] = await this.database.run({
|
|
@@ -4239,6 +4350,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4239
4350
|
experimentId: input.experimentId,
|
|
4240
4351
|
itemId: input.itemId,
|
|
4241
4352
|
itemDatasetVersion: input.itemDatasetVersion ?? null,
|
|
4353
|
+
organizationId: input.organizationId ?? null,
|
|
4354
|
+
projectId: input.projectId ?? null,
|
|
4242
4355
|
input: input.input ?? null,
|
|
4243
4356
|
output: input.output ?? null,
|
|
4244
4357
|
groundTruth: input.groundTruth ?? null,
|
|
@@ -4259,6 +4372,8 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4259
4372
|
experimentId: result.experimentId,
|
|
4260
4373
|
itemId: result.itemId,
|
|
4261
4374
|
itemDatasetVersion: result.itemDatasetVersion,
|
|
4375
|
+
organizationId: result.organizationId,
|
|
4376
|
+
projectId: result.projectId,
|
|
4262
4377
|
input: result.input,
|
|
4263
4378
|
output: result.output,
|
|
4264
4379
|
groundTruth: result.groundTruth,
|
|
@@ -4392,6 +4507,17 @@ var ExperimentsSpanner = class _ExperimentsSpanner extends storage.ExperimentsSt
|
|
|
4392
4507
|
conditions.push(`${quoteIdent("status", "column name")} = @status`);
|
|
4393
4508
|
params.status = args.status;
|
|
4394
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
|
+
}
|
|
4395
4521
|
const whereSql = `WHERE ${conditions.join(" AND ")}`;
|
|
4396
4522
|
const tableName = quoteIdent(storage.TABLE_EXPERIMENT_RESULTS, "table name");
|
|
4397
4523
|
const [countRows] = await this.database.run({
|