@mastra/libsql 1.15.1 → 1.16.0-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.
Files changed (31) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/docs/SKILL.md +4 -2
  3. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  4. package/dist/docs/references/docs-agent-builder-overview.md +4 -3
  5. package/dist/docs/references/docs-agents-agent-approval.md +25 -2
  6. package/dist/docs/references/docs-agents-networks.md +1 -1
  7. package/dist/docs/references/docs-memory-memory-processors.md +67 -0
  8. package/dist/docs/references/docs-memory-message-history.md +56 -2
  9. package/dist/docs/references/docs-memory-overview.md +8 -6
  10. package/dist/docs/references/docs-memory-semantic-recall.md +36 -2
  11. package/dist/docs/references/docs-memory-working-memory.md +3 -3
  12. package/dist/docs/references/docs-storage-overview.md +214 -0
  13. package/dist/docs/references/docs-workflows-snapshots.md +1 -1
  14. package/dist/docs/references/reference-core-mastra-class.md +1 -1
  15. package/dist/docs/references/reference-file-based-agents-memory.md +58 -0
  16. package/dist/docs/references/reference-file-based-agents-storage.md +30 -0
  17. package/dist/docs/references/reference-memory-memory-class.md +1 -1
  18. package/dist/docs/references/reference-storage-composite.md +64 -6
  19. package/dist/docs/references/reference-storage-dynamodb.md +1 -1
  20. package/dist/docs/references/reference-storage-retention.md +74 -6
  21. package/dist/index.cjs +148 -68
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.js +149 -69
  24. package/dist/index.js.map +1 -1
  25. package/dist/storage/db/index.d.ts +5 -0
  26. package/dist/storage/db/index.d.ts.map +1 -1
  27. package/dist/storage/domains/datasets/index.d.ts.map +1 -1
  28. package/dist/vector/index.d.ts +12 -0
  29. package/dist/vector/index.d.ts.map +1 -1
  30. package/package.json +10 -10
  31. package/dist/docs/references/docs-memory-storage.md +0 -267
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createClient } from '@libsql/client';
2
2
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
- import { createVectorErrorId, AgentsStorage, AGENTS_SCHEMA, TABLE_AGENTS, AGENT_VERSIONS_SCHEMA, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS, TABLE_SCHEMAS, BlobStore, TABLE_SKILL_BLOBS, SKILL_BLOBS_SCHEMA, ChannelsStorage, TABLE_CHANNEL_INSTALLATIONS, TABLE_CHANNEL_CONFIG, DatasetsStorage, DATASETS_SCHEMA, TABLE_DATASETS, DATASET_ITEMS_SCHEMA, TABLE_DATASET_ITEMS, DATASET_VERSIONS_SCHEMA, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, ensureDate, safelyParseJSON, ExperimentsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, FavoritesStorage, FAVORITES_SCHEMA, TABLE_FAVORITES, TABLE_SKILLS, HarnessStorage, TABLE_HARNESS_SESSIONS, MCPClientsStorage, MCP_CLIENTS_SCHEMA, TABLE_MCP_CLIENTS, MCP_CLIENT_VERSIONS_SCHEMA, TABLE_MCP_CLIENT_VERSIONS, MCPServersStorage, MCP_SERVERS_SCHEMA, TABLE_MCP_SERVERS, MCP_SERVER_VERSIONS_SCHEMA, TABLE_MCP_SERVER_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_RESOURCES, TABLE_MESSAGES, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, NotificationsStorage, TABLE_NOTIFICATIONS, ObservabilityStorage, TABLE_SPANS, SPAN_SCHEMA, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, SchedulesStorage, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEDULES, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, TABLE_SCORERS, SCORERS_SCHEMA, transformScoreRow, SkillsStorage, SKILLS_SCHEMA, SKILL_VERSIONS_SCHEMA, TABLE_SKILL_VERSIONS, ThreadStateStorage, TABLE_THREAD_STATE, THREAD_STATE_SCHEMA, ToolProviderConnectionsStorage, TOOL_PROVIDER_CONNECTIONS_SCHEMA, TABLE_TOOL_PROVIDER_CONNECTIONS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, WorkspacesStorage, WORKSPACES_SCHEMA, TABLE_WORKSPACES, WORKSPACE_VERSIONS_SCHEMA, TABLE_WORKSPACE_VERSIONS, MastraCompositeStore, getSqlType, parseDuration, normalizeScheduleTarget, TraceStatus, mergeWorkflowStepResult } from '@mastra/core/storage';
3
+ import { createVectorErrorId, AgentsStorage, AGENTS_SCHEMA, TABLE_AGENTS, AGENT_VERSIONS_SCHEMA, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS, TABLE_SCHEMAS, BlobStore, TABLE_SKILL_BLOBS, SKILL_BLOBS_SCHEMA, ChannelsStorage, TABLE_CHANNEL_INSTALLATIONS, TABLE_CHANNEL_CONFIG, DatasetsStorage, DATASETS_SCHEMA, TABLE_DATASETS, DATASET_ITEMS_SCHEMA, TABLE_DATASET_ITEMS, DATASET_VERSIONS_SCHEMA, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, ensureDate, safelyParseJSON, hasErrorCode, ExperimentsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, FavoritesStorage, FAVORITES_SCHEMA, TABLE_FAVORITES, TABLE_SKILLS, HarnessStorage, TABLE_HARNESS_SESSIONS, MCPClientsStorage, MCP_CLIENTS_SCHEMA, TABLE_MCP_CLIENTS, MCP_CLIENT_VERSIONS_SCHEMA, TABLE_MCP_CLIENT_VERSIONS, MCPServersStorage, MCP_SERVERS_SCHEMA, TABLE_MCP_SERVERS, MCP_SERVER_VERSIONS_SCHEMA, TABLE_MCP_SERVER_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_RESOURCES, TABLE_MESSAGES, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, NotificationsStorage, TABLE_NOTIFICATIONS, ObservabilityStorage, TABLE_SPANS, SPAN_SCHEMA, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, SchedulesStorage, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEDULES, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, TABLE_SCORERS, SCORERS_SCHEMA, transformScoreRow, SkillsStorage, SKILLS_SCHEMA, SKILL_VERSIONS_SCHEMA, TABLE_SKILL_VERSIONS, ThreadStateStorage, TABLE_THREAD_STATE, THREAD_STATE_SCHEMA, ToolProviderConnectionsStorage, TOOL_PROVIDER_CONNECTIONS_SCHEMA, TABLE_TOOL_PROVIDER_CONNECTIONS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, WorkspacesStorage, WORKSPACES_SCHEMA, TABLE_WORKSPACES, WORKSPACE_VERSIONS_SCHEMA, TABLE_WORKSPACE_VERSIONS, MastraCompositeStore, getSqlType, parseDuration, normalizeScheduleTarget, TraceStatus, mergeWorkflowStepResult } from '@mastra/core/storage';
4
4
  import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
5
5
  import { MastraVector, validateTopK, validateUpsertInput } from '@mastra/core/vector';
6
6
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
@@ -543,6 +543,31 @@ var LibSQLVector = class extends MastraVector {
543
543
  }
544
544
  this.vectorIndexes = this.isMemoryDb ? Promise.resolve(/* @__PURE__ */ new Set()) : this.discoverVectorIndexes();
545
545
  }
546
+ /**
547
+ * Closes the underlying libsql client, releasing all OS file handles.
548
+ *
549
+ * For local file databases, first runs PRAGMA wal_checkpoint(TRUNCATE) and
550
+ * switches back to journal_mode=DELETE so the -wal and -shm sidecar files
551
+ * are released promptly (mirrors LibSQLStore.close()).
552
+ *
553
+ * Remote (Turso) databases skip the WAL pragmas and just close the client.
554
+ *
555
+ * Safe to call more than once; subsequent calls are no-ops.
556
+ */
557
+ async close() {
558
+ if (this.turso.closed) {
559
+ return;
560
+ }
561
+ if (this.turso.protocol === "file" && !this.isMemoryDb) {
562
+ try {
563
+ await this.turso.execute("PRAGMA wal_checkpoint(TRUNCATE);");
564
+ await this.turso.execute("PRAGMA journal_mode=DELETE;");
565
+ } catch (err) {
566
+ this.logger.warn("LibSQLVector: Failed to checkpoint WAL before close.", err);
567
+ }
568
+ }
569
+ this.turso.close();
570
+ }
546
571
  async discoverVectorIndexes() {
547
572
  try {
548
573
  const result = await this.turso.execute({
@@ -1570,6 +1595,19 @@ var LibSQLDB = class extends MastraBase {
1570
1595
  insert(args) {
1571
1596
  return this.executeWriteOperationWithRetry(() => this.doInsert(args), `insert into table ${args.tableName}`);
1572
1597
  }
1598
+ /** Inserts a record without replacing an existing primary key. */
1599
+ insertOnly(args) {
1600
+ return this.executeWriteOperationWithRetry(async () => {
1601
+ const filteredRecord = await this.filterRecordToKnownColumns(args.tableName, args.record);
1602
+ if (Object.keys(filteredRecord).length === 0) return;
1603
+ const statement = prepareStatement({ tableName: args.tableName, record: filteredRecord });
1604
+ if (!statement.sql.startsWith("INSERT OR REPLACE")) {
1605
+ throw new Error(`Unexpected insert statement generated for table ${args.tableName}`);
1606
+ }
1607
+ statement.sql = statement.sql.replace("INSERT OR REPLACE", "INSERT");
1608
+ await withClientWriteLock(this.client, () => this.client.execute(statement));
1609
+ }, `insert into table ${args.tableName}`);
1610
+ }
1573
1611
  /**
1574
1612
  * Internal update implementation without retry logic.
1575
1613
  */
@@ -3879,6 +3917,7 @@ var DatasetsLibSQL = class extends DatasetsStorage {
3879
3917
  await this.#addColumnIfNotExists(TABLE_DATASET_ITEMS, "organizationId", "TEXT");
3880
3918
  await this.#addColumnIfNotExists(TABLE_DATASET_ITEMS, "projectId", "TEXT");
3881
3919
  await this.#addColumnIfNotExists(TABLE_DATASET_ITEMS, "toolMocks", "TEXT");
3920
+ await this.#addColumnIfNotExists(TABLE_DATASET_ITEMS, "externalId", "TEXT");
3882
3921
  await this.#client.batch(
3883
3922
  [
3884
3923
  {
@@ -3889,6 +3928,10 @@ var DatasetsLibSQL = class extends DatasetsStorage {
3889
3928
  sql: `CREATE INDEX IF NOT EXISTS idx_dataset_items_dataset_version ON "${TABLE_DATASET_ITEMS}" ("datasetId", "datasetVersion")`,
3890
3929
  args: []
3891
3930
  },
3931
+ {
3932
+ sql: `CREATE INDEX IF NOT EXISTS idx_dataset_items_dataset_externalid_version ON "${TABLE_DATASET_ITEMS}" ("datasetId", "externalId", "datasetVersion")`,
3933
+ args: []
3934
+ },
3892
3935
  {
3893
3936
  sql: `CREATE INDEX IF NOT EXISTS idx_dataset_items_dataset_validto_deleted ON "${TABLE_DATASET_ITEMS}" ("datasetId", "validTo", "isDeleted")`,
3894
3937
  args: []
@@ -3968,6 +4011,7 @@ var DatasetsLibSQL = class extends DatasetsStorage {
3968
4011
  id: row.id,
3969
4012
  datasetId: row.datasetId,
3970
4013
  datasetVersion: row.datasetVersion,
4014
+ externalId: row.externalId ?? null,
3971
4015
  organizationId: row.organizationId ?? null,
3972
4016
  projectId: row.projectId ?? null,
3973
4017
  input: safelyParseJSON(row.input),
@@ -3986,6 +4030,7 @@ var DatasetsLibSQL = class extends DatasetsStorage {
3986
4030
  id: row.id,
3987
4031
  datasetId: row.datasetId,
3988
4032
  datasetVersion: row.datasetVersion,
4033
+ externalId: row.externalId ?? null,
3989
4034
  organizationId: row.organizationId ?? null,
3990
4035
  projectId: row.projectId ?? null,
3991
4036
  validTo: row.validTo,
@@ -4012,10 +4057,11 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4012
4057
  // --- Dataset CRUD ---
4013
4058
  async createDataset(input) {
4014
4059
  try {
4015
- const id = crypto.randomUUID();
4060
+ const id = input.id ?? crypto.randomUUID();
4061
+ if (input.id !== void 0) this.validateCallerDefinedDatasetId(input.id);
4016
4062
  const now = /* @__PURE__ */ new Date();
4017
4063
  const nowIso = now.toISOString();
4018
- await this.#db.insert({
4064
+ await this.#db.insertOnly({
4019
4065
  tableName: TABLE_DATASETS,
4020
4066
  record: {
4021
4067
  id,
@@ -4057,6 +4103,11 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4057
4103
  updatedAt: now
4058
4104
  };
4059
4105
  } catch (error) {
4106
+ if (input.id !== void 0 && hasErrorCode(error, /* @__PURE__ */ new Set(["SQLITE_CONSTRAINT", "SQLITE_CONSTRAINT_PRIMARYKEY", "SQLITE_CONSTRAINT_UNIQUE"]))) {
4107
+ const existing = await this.getDatasetById({ id: input.id });
4108
+ if (existing) return this.resolveExistingDataset(existing, { ...input, id: input.id });
4109
+ }
4110
+ if (error instanceof MastraError) throw error;
4060
4111
  throw new MastraError(
4061
4112
  {
4062
4113
  id: createStorageErrorId("LIBSQL", "CREATE_DATASET", "FAILED"),
@@ -4302,11 +4353,12 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4302
4353
  args: [args.datasetId]
4303
4354
  },
4304
4355
  {
4305
- sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT organizationId FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT projectId FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 0, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4356
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, externalId, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?, (SELECT organizationId FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT projectId FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 0, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4306
4357
  args: [
4307
4358
  id,
4308
4359
  args.datasetId,
4309
4360
  args.datasetId,
4361
+ args.externalId ?? null,
4310
4362
  args.datasetId,
4311
4363
  args.datasetId,
4312
4364
  jsonbArg(args.input),
@@ -4332,6 +4384,7 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4332
4384
  id,
4333
4385
  datasetId: args.datasetId,
4334
4386
  datasetVersion: newVersion,
4387
+ externalId: args.externalId ?? null,
4335
4388
  organizationId: dataset?.organizationId ?? null,
4336
4389
  projectId: dataset?.projectId ?? null,
4337
4390
  input: args.input,
@@ -4397,11 +4450,12 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4397
4450
  args: [args.datasetId, args.id]
4398
4451
  },
4399
4452
  {
4400
- sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT organizationId FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT projectId FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 0, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4453
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, externalId, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?, (SELECT organizationId FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT projectId FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 0, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4401
4454
  args: [
4402
4455
  args.id,
4403
4456
  args.datasetId,
4404
4457
  args.datasetId,
4458
+ existing.externalId ?? null,
4405
4459
  args.datasetId,
4406
4460
  args.datasetId,
4407
4461
  jsonbArg(mergedInput),
@@ -4474,11 +4528,12 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4474
4528
  args: [datasetId, id]
4475
4529
  },
4476
4530
  {
4477
- sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT organizationId FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT projectId FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 1, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4531
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, externalId, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?, (SELECT organizationId FROM ${TABLE_DATASETS} WHERE id = ?), (SELECT projectId FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 1, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4478
4532
  args: [
4479
4533
  id,
4480
4534
  datasetId,
4481
4535
  datasetId,
4536
+ existing.externalId ?? null,
4482
4537
  datasetId,
4483
4538
  datasetId,
4484
4539
  jsonbArg(existing.input),
@@ -4760,70 +4815,94 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4760
4815
  // --- Bulk operations (SCD-2 internally) ---
4761
4816
  async _doBatchInsertItems(input) {
4762
4817
  try {
4763
- const dataset = await this.getDatasetById({ id: input.datasetId });
4764
- if (!dataset) {
4765
- throw new MastraError({
4766
- id: createStorageErrorId("LIBSQL", "BULK_ADD_ITEMS", "DATASET_NOT_FOUND"),
4767
- domain: ErrorDomain.STORAGE,
4768
- category: ErrorCategory.USER,
4769
- details: { datasetId: input.datasetId }
4770
- });
4771
- }
4772
- const now = /* @__PURE__ */ new Date();
4773
- const nowIso = now.toISOString();
4774
- const versionId = crypto.randomUUID();
4775
- const statements = [
4776
- {
4777
- sql: `UPDATE ${TABLE_DATASETS} SET version = version + 1 WHERE id = ? RETURNING version`,
4778
- args: [input.datasetId]
4818
+ if (input.items.length === 0) return [];
4819
+ return await withClientWriteLock(this.#client, async () => {
4820
+ const tx = await this.#client.transaction("write");
4821
+ try {
4822
+ const datasetResult = await tx.execute({
4823
+ sql: `SELECT version, organizationId, projectId FROM ${TABLE_DATASETS} WHERE id = ?`,
4824
+ args: [input.datasetId]
4825
+ });
4826
+ const dataset = datasetResult.rows[0];
4827
+ if (!dataset)
4828
+ throw new MastraError({
4829
+ id: createStorageErrorId("LIBSQL", "BULK_ADD_ITEMS", "DATASET_NOT_FOUND"),
4830
+ domain: ErrorDomain.STORAGE,
4831
+ category: ErrorCategory.USER,
4832
+ details: { datasetId: input.datasetId }
4833
+ });
4834
+ const externalIds = [...new Set(input.items.flatMap((item) => item.externalId ? [item.externalId] : []))];
4835
+ const historyResult = externalIds.length ? await tx.execute({
4836
+ sql: `SELECT id, datasetId, datasetVersion, externalId, organizationId, projectId, validTo, isDeleted, json(input) AS input, json(groundTruth) AS groundTruth, json(expectedTrajectory) AS expectedTrajectory, json(toolMocks) AS toolMocks, json(requestContext) AS requestContext, json(metadata) AS metadata, json(source) AS source, createdAt, updatedAt FROM ${TABLE_DATASET_ITEMS} WHERE datasetId = ? AND externalId IN (${externalIds.map(() => "?").join(",")}) ORDER BY datasetVersion`,
4837
+ args: [input.datasetId, ...externalIds]
4838
+ }) : { rows: [] };
4839
+ const plan = this.planDatasetItemBatch(
4840
+ input.items,
4841
+ historyResult.rows.map((row) => this.transformItemRowFull(row)),
4842
+ () => crypto.randomUUID()
4843
+ );
4844
+ const resolved = new Map(
4845
+ [...plan.existingCurrentItems].map(([id, row]) => [id, this.datasetItemFromRow(row)])
4846
+ );
4847
+ if (plan.inserts.length > 0) {
4848
+ const newVersion = Number(dataset.version) + 1;
4849
+ const now = /* @__PURE__ */ new Date();
4850
+ const nowIso = now.toISOString();
4851
+ await tx.execute({
4852
+ sql: `UPDATE ${TABLE_DATASETS} SET version = ? WHERE id = ?`,
4853
+ args: [newVersion, input.datasetId]
4854
+ });
4855
+ for (const { id, item } of plan.inserts) {
4856
+ await tx.execute({
4857
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, externalId, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, NULL, 0, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4858
+ args: [
4859
+ id,
4860
+ input.datasetId,
4861
+ newVersion,
4862
+ item.externalId ?? null,
4863
+ dataset.organizationId ?? null,
4864
+ dataset.projectId ?? null,
4865
+ jsonbArg(item.input),
4866
+ jsonbArg(item.groundTruth),
4867
+ jsonbArg(item.expectedTrajectory),
4868
+ jsonbArg(item.toolMocks),
4869
+ jsonbArg(item.requestContext),
4870
+ jsonbArg(item.metadata),
4871
+ jsonbArg(item.source),
4872
+ nowIso,
4873
+ nowIso
4874
+ ]
4875
+ });
4876
+ resolved.set(id, {
4877
+ id,
4878
+ datasetId: input.datasetId,
4879
+ datasetVersion: newVersion,
4880
+ externalId: item.externalId ?? null,
4881
+ organizationId: dataset.organizationId,
4882
+ projectId: dataset.projectId,
4883
+ input: item.input,
4884
+ groundTruth: item.groundTruth,
4885
+ expectedTrajectory: item.expectedTrajectory,
4886
+ toolMocks: item.toolMocks,
4887
+ requestContext: item.requestContext,
4888
+ metadata: item.metadata,
4889
+ source: item.source,
4890
+ createdAt: now,
4891
+ updatedAt: now
4892
+ });
4893
+ }
4894
+ await tx.execute({
4895
+ sql: `INSERT INTO ${TABLE_DATASET_VERSIONS} (id, datasetId, version, createdAt) VALUES (?, ?, ?, ?)`,
4896
+ args: [crypto.randomUUID(), input.datasetId, newVersion, nowIso]
4897
+ });
4898
+ }
4899
+ await tx.commit();
4900
+ return plan.resolvedIds.map((id) => resolved.get(id));
4901
+ } catch (error) {
4902
+ if (!tx.closed) await tx.rollback();
4903
+ throw error;
4779
4904
  }
4780
- ];
4781
- const items = [];
4782
- for (const itemInput of input.items) {
4783
- const id = crypto.randomUUID();
4784
- items.push({ id, input: itemInput });
4785
- statements.push({
4786
- sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?, ?, NULL, 0, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4787
- args: [
4788
- id,
4789
- input.datasetId,
4790
- input.datasetId,
4791
- dataset.organizationId ?? null,
4792
- dataset.projectId ?? null,
4793
- jsonbArg(itemInput.input),
4794
- jsonbArg(itemInput.groundTruth),
4795
- jsonbArg(itemInput.expectedTrajectory),
4796
- jsonbArg(itemInput.toolMocks),
4797
- jsonbArg(itemInput.requestContext),
4798
- jsonbArg(itemInput.metadata),
4799
- jsonbArg(itemInput.source),
4800
- nowIso,
4801
- nowIso
4802
- ]
4803
- });
4804
- }
4805
- statements.push({
4806
- sql: `INSERT INTO ${TABLE_DATASET_VERSIONS} (id, datasetId, version, createdAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?)`,
4807
- args: [versionId, input.datasetId, input.datasetId, nowIso]
4808
4905
  });
4809
- const results = await this.#client.batch(statements, "write");
4810
- const newVersion = Number(results[0].rows[0].version);
4811
- return items.map(({ id, input: itemInput }) => ({
4812
- id,
4813
- datasetId: input.datasetId,
4814
- datasetVersion: newVersion,
4815
- organizationId: dataset.organizationId ?? null,
4816
- projectId: dataset.projectId ?? null,
4817
- input: itemInput.input,
4818
- groundTruth: itemInput.groundTruth,
4819
- expectedTrajectory: itemInput.expectedTrajectory,
4820
- toolMocks: itemInput.toolMocks,
4821
- requestContext: itemInput.requestContext,
4822
- metadata: itemInput.metadata,
4823
- source: itemInput.source,
4824
- createdAt: now,
4825
- updatedAt: now
4826
- }));
4827
4906
  } catch (error) {
4828
4907
  if (error instanceof MastraError) throw error;
4829
4908
  throw new MastraError(
@@ -4869,11 +4948,12 @@ var DatasetsLibSQL = class extends DatasetsStorage {
4869
4948
  args: [input.datasetId, item.id]
4870
4949
  });
4871
4950
  statements.push({
4872
- sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?, ?, NULL, 1, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4951
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, externalId, organizationId, projectId, validTo, isDeleted, input, groundTruth, expectedTrajectory, toolMocks, requestContext, metadata, source, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?, ?, ?, NULL, 1, jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
4873
4952
  args: [
4874
4953
  item.id,
4875
4954
  input.datasetId,
4876
4955
  input.datasetId,
4956
+ item.externalId ?? null,
4877
4957
  dataset.organizationId ?? null,
4878
4958
  dataset.projectId ?? null,
4879
4959
  jsonbArg(item.input),