@mastra/libsql 1.3.0-alpha.1 → 1.4.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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, MemoryStorage, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ObservabilityStorage, SPAN_SCHEMA, TABLE_SPANS, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, transformScoreRow, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, MastraCompositeStore, TraceStatus, getSqlType, safelyParseJSON } from '@mastra/core/storage';
3
+ import { createVectorErrorId, AgentsStorage, AGENTS_SCHEMA, TABLE_AGENTS, AGENT_VERSIONS_SCHEMA, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, DatasetsStorage, DATASETS_SCHEMA, TABLE_DATASETS, DATASET_ITEMS_SCHEMA, TABLE_DATASET_ITEMS, DATASET_VERSIONS_SCHEMA, TABLE_DATASET_VERSIONS, ensureDate, safelyParseJSON, TABLE_EXPERIMENT_RESULTS, TABLE_EXPERIMENTS, ExperimentsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, MCPClientsStorage, MCP_CLIENTS_SCHEMA, TABLE_MCP_CLIENTS, MCP_CLIENT_VERSIONS_SCHEMA, TABLE_MCP_CLIENT_VERSIONS, MemoryStorage, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ObservabilityStorage, SPAN_SCHEMA, TABLE_SPANS, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, transformScoreRow, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, MastraCompositeStore, TraceStatus, getSqlType } 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';
@@ -1690,17 +1690,30 @@ var LibSQLDB = class extends MastraBase {
1690
1690
  */
1691
1691
  async createTable({
1692
1692
  tableName,
1693
- schema
1693
+ schema,
1694
+ compositePrimaryKey
1694
1695
  }) {
1695
1696
  try {
1696
1697
  const parsedTableName = parseSqlIdentifier(tableName, "table name");
1698
+ if (compositePrimaryKey) {
1699
+ for (const col of compositePrimaryKey) {
1700
+ if (!(col in schema)) {
1701
+ throw new Error(`compositePrimaryKey column "${col}" does not exist in schema for table "${tableName}"`);
1702
+ }
1703
+ }
1704
+ }
1705
+ const compositePKSet = compositePrimaryKey ? new Set(compositePrimaryKey) : null;
1697
1706
  const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
1698
1707
  const type = this.getSqlType(colDef.type);
1699
1708
  const nullable = colDef.nullable === false ? "NOT NULL" : "";
1700
- const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
1709
+ const primaryKey = colDef.primaryKey && !compositePKSet?.has(colName) ? "PRIMARY KEY" : "";
1701
1710
  return `"${colName}" ${type} ${nullable} ${primaryKey}`.trim();
1702
1711
  });
1703
1712
  const tableConstraints = [];
1713
+ if (compositePrimaryKey) {
1714
+ const pkCols = compositePrimaryKey.map((c) => `"${c}"`).join(", ");
1715
+ tableConstraints.push(`PRIMARY KEY (${pkCols})`);
1716
+ }
1704
1717
  if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
1705
1718
  tableConstraints.push("UNIQUE (workflow_name, run_id)");
1706
1719
  }
@@ -2053,7 +2066,9 @@ var SNAPSHOT_FIELDS = [
2053
2066
  "inputProcessors",
2054
2067
  "outputProcessors",
2055
2068
  "memory",
2056
- "scorers"
2069
+ "scorers",
2070
+ "mcpClients",
2071
+ "requestContextSchema"
2057
2072
  ];
2058
2073
  var AgentsLibSQL = class extends AgentsStorage {
2059
2074
  #db;
@@ -2483,33 +2498,1858 @@ var AgentsLibSQL = class extends AgentsStorage {
2483
2498
  const total = await this.#db.selectTotalCount({ tableName: TABLE_AGENTS });
2484
2499
  if (total === 0) {
2485
2500
  return {
2486
- agents: [],
2501
+ agents: [],
2502
+ total: 0,
2503
+ page,
2504
+ perPage: perPageForResponse,
2505
+ hasMore: false
2506
+ };
2507
+ }
2508
+ const limitValue = perPageInput === false ? total : perPage;
2509
+ const rows = await this.#db.selectMany({
2510
+ tableName: TABLE_AGENTS,
2511
+ orderBy: `"${field}" ${direction}`,
2512
+ limit: limitValue,
2513
+ offset
2514
+ });
2515
+ const agents = rows.map((row) => this.parseRow(row));
2516
+ return {
2517
+ agents,
2518
+ total,
2519
+ page,
2520
+ perPage: perPageForResponse,
2521
+ hasMore: perPageInput === false ? false : offset + perPage < total
2522
+ };
2523
+ } catch (error) {
2524
+ if (error instanceof MastraError) throw error;
2525
+ throw new MastraError(
2526
+ {
2527
+ id: createStorageErrorId("LIBSQL", "LIST_AGENTS", "FAILED"),
2528
+ domain: ErrorDomain.STORAGE,
2529
+ category: ErrorCategory.THIRD_PARTY
2530
+ },
2531
+ error
2532
+ );
2533
+ }
2534
+ }
2535
+ // ==========================================================================
2536
+ // Agent Version Methods
2537
+ // ==========================================================================
2538
+ async createVersion(input) {
2539
+ try {
2540
+ const now = /* @__PURE__ */ new Date();
2541
+ await this.#db.insert({
2542
+ tableName: TABLE_AGENT_VERSIONS,
2543
+ record: {
2544
+ id: input.id,
2545
+ agentId: input.agentId,
2546
+ versionNumber: input.versionNumber,
2547
+ name: input.name ?? null,
2548
+ description: input.description ?? null,
2549
+ instructions: this.serializeInstructions(input.instructions),
2550
+ model: input.model,
2551
+ tools: input.tools ?? null,
2552
+ defaultOptions: input.defaultOptions ?? null,
2553
+ workflows: input.workflows ?? null,
2554
+ agents: input.agents ?? null,
2555
+ integrationTools: input.integrationTools ?? null,
2556
+ inputProcessors: input.inputProcessors ?? null,
2557
+ outputProcessors: input.outputProcessors ?? null,
2558
+ memory: input.memory ?? null,
2559
+ scorers: input.scorers ?? null,
2560
+ mcpClients: input.mcpClients ?? null,
2561
+ requestContextSchema: input.requestContextSchema ?? null,
2562
+ changedFields: input.changedFields ?? null,
2563
+ changeMessage: input.changeMessage ?? null,
2564
+ createdAt: now
2565
+ }
2566
+ });
2567
+ return {
2568
+ ...input,
2569
+ createdAt: now
2570
+ };
2571
+ } catch (error) {
2572
+ if (error instanceof MastraError) throw error;
2573
+ throw new MastraError(
2574
+ {
2575
+ id: createStorageErrorId("LIBSQL", "CREATE_VERSION", "FAILED"),
2576
+ domain: ErrorDomain.STORAGE,
2577
+ category: ErrorCategory.THIRD_PARTY,
2578
+ details: { versionId: input.id, agentId: input.agentId }
2579
+ },
2580
+ error
2581
+ );
2582
+ }
2583
+ }
2584
+ async getVersion(id) {
2585
+ try {
2586
+ const result = await this.#db.select({
2587
+ tableName: TABLE_AGENT_VERSIONS,
2588
+ keys: { id }
2589
+ });
2590
+ if (!result) {
2591
+ return null;
2592
+ }
2593
+ return this.parseVersionRow(result);
2594
+ } catch (error) {
2595
+ if (error instanceof MastraError) throw error;
2596
+ throw new MastraError(
2597
+ {
2598
+ id: createStorageErrorId("LIBSQL", "GET_VERSION", "FAILED"),
2599
+ domain: ErrorDomain.STORAGE,
2600
+ category: ErrorCategory.THIRD_PARTY,
2601
+ details: { versionId: id }
2602
+ },
2603
+ error
2604
+ );
2605
+ }
2606
+ }
2607
+ async getVersionByNumber(agentId, versionNumber) {
2608
+ try {
2609
+ const rows = await this.#db.selectMany({
2610
+ tableName: TABLE_AGENT_VERSIONS,
2611
+ whereClause: {
2612
+ sql: "WHERE agentId = ? AND versionNumber = ?",
2613
+ args: [agentId, versionNumber]
2614
+ },
2615
+ limit: 1
2616
+ });
2617
+ if (!rows || rows.length === 0) {
2618
+ return null;
2619
+ }
2620
+ return this.parseVersionRow(rows[0]);
2621
+ } catch (error) {
2622
+ if (error instanceof MastraError) throw error;
2623
+ throw new MastraError(
2624
+ {
2625
+ id: createStorageErrorId("LIBSQL", "GET_VERSION_BY_NUMBER", "FAILED"),
2626
+ domain: ErrorDomain.STORAGE,
2627
+ category: ErrorCategory.THIRD_PARTY,
2628
+ details: { agentId, versionNumber }
2629
+ },
2630
+ error
2631
+ );
2632
+ }
2633
+ }
2634
+ async getLatestVersion(agentId) {
2635
+ try {
2636
+ const rows = await this.#db.selectMany({
2637
+ tableName: TABLE_AGENT_VERSIONS,
2638
+ whereClause: {
2639
+ sql: "WHERE agentId = ?",
2640
+ args: [agentId]
2641
+ },
2642
+ orderBy: "versionNumber DESC",
2643
+ limit: 1
2644
+ });
2645
+ if (!rows || rows.length === 0) {
2646
+ return null;
2647
+ }
2648
+ return this.parseVersionRow(rows[0]);
2649
+ } catch (error) {
2650
+ if (error instanceof MastraError) throw error;
2651
+ throw new MastraError(
2652
+ {
2653
+ id: createStorageErrorId("LIBSQL", "GET_LATEST_VERSION", "FAILED"),
2654
+ domain: ErrorDomain.STORAGE,
2655
+ category: ErrorCategory.THIRD_PARTY,
2656
+ details: { agentId }
2657
+ },
2658
+ error
2659
+ );
2660
+ }
2661
+ }
2662
+ async listVersions(input) {
2663
+ const { agentId, page = 0, perPage: perPageInput, orderBy } = input;
2664
+ if (page < 0) {
2665
+ throw new MastraError(
2666
+ {
2667
+ id: createStorageErrorId("LIBSQL", "LIST_VERSIONS", "INVALID_PAGE"),
2668
+ domain: ErrorDomain.STORAGE,
2669
+ category: ErrorCategory.USER,
2670
+ details: { page }
2671
+ },
2672
+ new Error("page must be >= 0")
2673
+ );
2674
+ }
2675
+ const perPage = normalizePerPage(perPageInput, 20);
2676
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
2677
+ try {
2678
+ const { field, direction } = this.parseVersionOrderBy(orderBy);
2679
+ const total = await this.#db.selectTotalCount({
2680
+ tableName: TABLE_AGENT_VERSIONS,
2681
+ whereClause: {
2682
+ sql: "WHERE agentId = ?",
2683
+ args: [agentId]
2684
+ }
2685
+ });
2686
+ if (total === 0) {
2687
+ return {
2688
+ versions: [],
2689
+ total: 0,
2690
+ page,
2691
+ perPage: perPageForResponse,
2692
+ hasMore: false
2693
+ };
2694
+ }
2695
+ const limitValue = perPageInput === false ? total : perPage;
2696
+ const rows = await this.#db.selectMany({
2697
+ tableName: TABLE_AGENT_VERSIONS,
2698
+ whereClause: {
2699
+ sql: "WHERE agentId = ?",
2700
+ args: [agentId]
2701
+ },
2702
+ orderBy: `"${field}" ${direction}`,
2703
+ limit: limitValue,
2704
+ offset
2705
+ });
2706
+ const versions = rows.map((row) => this.parseVersionRow(row));
2707
+ return {
2708
+ versions,
2709
+ total,
2710
+ page,
2711
+ perPage: perPageForResponse,
2712
+ hasMore: perPageInput === false ? false : offset + perPage < total
2713
+ };
2714
+ } catch (error) {
2715
+ if (error instanceof MastraError) throw error;
2716
+ throw new MastraError(
2717
+ {
2718
+ id: createStorageErrorId("LIBSQL", "LIST_VERSIONS", "FAILED"),
2719
+ domain: ErrorDomain.STORAGE,
2720
+ category: ErrorCategory.THIRD_PARTY,
2721
+ details: { agentId }
2722
+ },
2723
+ error
2724
+ );
2725
+ }
2726
+ }
2727
+ async deleteVersion(id) {
2728
+ try {
2729
+ await this.#db.delete({
2730
+ tableName: TABLE_AGENT_VERSIONS,
2731
+ keys: { id }
2732
+ });
2733
+ } catch (error) {
2734
+ if (error instanceof MastraError) throw error;
2735
+ throw new MastraError(
2736
+ {
2737
+ id: createStorageErrorId("LIBSQL", "DELETE_VERSION", "FAILED"),
2738
+ domain: ErrorDomain.STORAGE,
2739
+ category: ErrorCategory.THIRD_PARTY,
2740
+ details: { versionId: id }
2741
+ },
2742
+ error
2743
+ );
2744
+ }
2745
+ }
2746
+ async deleteVersionsByParentId(entityId) {
2747
+ try {
2748
+ const versions = await this.#db.selectMany({
2749
+ tableName: TABLE_AGENT_VERSIONS,
2750
+ whereClause: {
2751
+ sql: "WHERE agentId = ?",
2752
+ args: [entityId]
2753
+ }
2754
+ });
2755
+ for (const version of versions) {
2756
+ await this.#db.delete({
2757
+ tableName: TABLE_AGENT_VERSIONS,
2758
+ keys: { id: version.id }
2759
+ });
2760
+ }
2761
+ } catch (error) {
2762
+ if (error instanceof MastraError) throw error;
2763
+ throw new MastraError(
2764
+ {
2765
+ id: createStorageErrorId("LIBSQL", "DELETE_VERSIONS_BY_AGENT_ID", "FAILED"),
2766
+ domain: ErrorDomain.STORAGE,
2767
+ category: ErrorCategory.THIRD_PARTY,
2768
+ details: { agentId: entityId }
2769
+ },
2770
+ error
2771
+ );
2772
+ }
2773
+ }
2774
+ async countVersions(agentId) {
2775
+ try {
2776
+ const count = await this.#db.selectTotalCount({
2777
+ tableName: TABLE_AGENT_VERSIONS,
2778
+ whereClause: {
2779
+ sql: "WHERE agentId = ?",
2780
+ args: [agentId]
2781
+ }
2782
+ });
2783
+ return count;
2784
+ } catch (error) {
2785
+ if (error instanceof MastraError) throw error;
2786
+ throw new MastraError(
2787
+ {
2788
+ id: createStorageErrorId("LIBSQL", "COUNT_VERSIONS", "FAILED"),
2789
+ domain: ErrorDomain.STORAGE,
2790
+ category: ErrorCategory.THIRD_PARTY,
2791
+ details: { agentId }
2792
+ },
2793
+ error
2794
+ );
2795
+ }
2796
+ }
2797
+ // ==========================================================================
2798
+ // Private Helper Methods
2799
+ // ==========================================================================
2800
+ serializeInstructions(instructions) {
2801
+ return Array.isArray(instructions) ? JSON.stringify(instructions) : instructions;
2802
+ }
2803
+ deserializeInstructions(raw) {
2804
+ if (!raw) return raw;
2805
+ try {
2806
+ const parsed = JSON.parse(raw);
2807
+ if (Array.isArray(parsed)) return parsed;
2808
+ } catch {
2809
+ }
2810
+ return raw;
2811
+ }
2812
+ parseVersionRow(row) {
2813
+ return {
2814
+ id: row.id,
2815
+ agentId: row.agentId,
2816
+ versionNumber: row.versionNumber,
2817
+ name: row.name,
2818
+ description: row.description,
2819
+ instructions: this.deserializeInstructions(row.instructions),
2820
+ model: this.parseJson(row.model, "model"),
2821
+ tools: this.parseJson(row.tools, "tools"),
2822
+ defaultOptions: this.parseJson(row.defaultOptions, "defaultOptions"),
2823
+ workflows: this.parseJson(row.workflows, "workflows"),
2824
+ agents: this.parseJson(row.agents, "agents"),
2825
+ integrationTools: this.parseJson(row.integrationTools, "integrationTools"),
2826
+ inputProcessors: this.parseJson(row.inputProcessors, "inputProcessors"),
2827
+ outputProcessors: this.parseJson(row.outputProcessors, "outputProcessors"),
2828
+ memory: this.parseJson(row.memory, "memory"),
2829
+ scorers: this.parseJson(row.scorers, "scorers"),
2830
+ mcpClients: this.parseJson(row.mcpClients, "mcpClients"),
2831
+ requestContextSchema: this.parseJson(row.requestContextSchema, "requestContextSchema"),
2832
+ changedFields: this.parseJson(row.changedFields, "changedFields"),
2833
+ changeMessage: row.changeMessage,
2834
+ createdAt: new Date(row.createdAt)
2835
+ };
2836
+ }
2837
+ };
2838
+ function jsonbArg(value) {
2839
+ return value === void 0 || value === null ? null : JSON.stringify(value);
2840
+ }
2841
+ var DatasetsLibSQL = class extends DatasetsStorage {
2842
+ #db;
2843
+ #client;
2844
+ constructor(config) {
2845
+ super();
2846
+ const client = resolveClient(config);
2847
+ this.#client = client;
2848
+ this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
2849
+ }
2850
+ async init() {
2851
+ await this.#db.createTable({ tableName: TABLE_DATASETS, schema: DATASETS_SCHEMA });
2852
+ await this.#db.createTable({ tableName: TABLE_DATASET_ITEMS, schema: DATASET_ITEMS_SCHEMA });
2853
+ await this.#db.createTable({ tableName: TABLE_DATASET_VERSIONS, schema: DATASET_VERSIONS_SCHEMA });
2854
+ await this.#client.execute({
2855
+ sql: `CREATE INDEX IF NOT EXISTS idx_dataset_items_dataset_validto ON "${TABLE_DATASET_ITEMS}" ("datasetId", "validTo")`,
2856
+ args: []
2857
+ });
2858
+ await this.#client.execute({
2859
+ sql: `CREATE INDEX IF NOT EXISTS idx_dataset_items_dataset_version ON "${TABLE_DATASET_ITEMS}" ("datasetId", "datasetVersion")`,
2860
+ args: []
2861
+ });
2862
+ await this.#client.execute({
2863
+ sql: `CREATE INDEX IF NOT EXISTS idx_dataset_items_dataset_validto_deleted ON "${TABLE_DATASET_ITEMS}" ("datasetId", "validTo", "isDeleted")`,
2864
+ args: []
2865
+ });
2866
+ await this.#client.execute({
2867
+ sql: `CREATE INDEX IF NOT EXISTS idx_dataset_versions_dataset_version ON "${TABLE_DATASET_VERSIONS}" ("datasetId", "version")`,
2868
+ args: []
2869
+ });
2870
+ await this.#client.execute({
2871
+ sql: `CREATE UNIQUE INDEX IF NOT EXISTS idx_dataset_versions_dataset_version_unique ON "${TABLE_DATASET_VERSIONS}" ("datasetId", "version")`,
2872
+ args: []
2873
+ });
2874
+ }
2875
+ async dangerouslyClearAll() {
2876
+ await this.#db.deleteData({ tableName: TABLE_DATASET_VERSIONS });
2877
+ await this.#db.deleteData({ tableName: TABLE_DATASET_ITEMS });
2878
+ await this.#db.deleteData({ tableName: TABLE_DATASETS });
2879
+ }
2880
+ // --- Row transformers ---
2881
+ transformDatasetRow(row) {
2882
+ return {
2883
+ id: row.id,
2884
+ name: row.name,
2885
+ description: row.description,
2886
+ metadata: row.metadata ? safelyParseJSON(row.metadata) : void 0,
2887
+ inputSchema: row.inputSchema ? safelyParseJSON(row.inputSchema) : void 0,
2888
+ groundTruthSchema: row.groundTruthSchema ? safelyParseJSON(row.groundTruthSchema) : void 0,
2889
+ version: row.version,
2890
+ createdAt: ensureDate(row.createdAt),
2891
+ updatedAt: ensureDate(row.updatedAt)
2892
+ };
2893
+ }
2894
+ transformItemRow(row) {
2895
+ return {
2896
+ id: row.id,
2897
+ datasetId: row.datasetId,
2898
+ datasetVersion: row.datasetVersion,
2899
+ input: safelyParseJSON(row.input),
2900
+ groundTruth: row.groundTruth ? safelyParseJSON(row.groundTruth) : void 0,
2901
+ metadata: row.metadata ? safelyParseJSON(row.metadata) : void 0,
2902
+ createdAt: ensureDate(row.createdAt),
2903
+ updatedAt: ensureDate(row.updatedAt)
2904
+ };
2905
+ }
2906
+ transformItemRowFull(row) {
2907
+ return {
2908
+ id: row.id,
2909
+ datasetId: row.datasetId,
2910
+ datasetVersion: row.datasetVersion,
2911
+ validTo: row.validTo,
2912
+ isDeleted: Boolean(row.isDeleted),
2913
+ input: safelyParseJSON(row.input),
2914
+ groundTruth: row.groundTruth ? safelyParseJSON(row.groundTruth) : void 0,
2915
+ metadata: row.metadata ? safelyParseJSON(row.metadata) : void 0,
2916
+ createdAt: ensureDate(row.createdAt),
2917
+ updatedAt: ensureDate(row.updatedAt)
2918
+ };
2919
+ }
2920
+ transformDatasetVersionRow(row) {
2921
+ return {
2922
+ id: row.id,
2923
+ datasetId: row.datasetId,
2924
+ version: row.version,
2925
+ createdAt: ensureDate(row.createdAt)
2926
+ };
2927
+ }
2928
+ // --- Dataset CRUD ---
2929
+ async createDataset(input) {
2930
+ try {
2931
+ const id = crypto.randomUUID();
2932
+ const now = /* @__PURE__ */ new Date();
2933
+ const nowIso = now.toISOString();
2934
+ await this.#db.insert({
2935
+ tableName: TABLE_DATASETS,
2936
+ record: {
2937
+ id,
2938
+ name: input.name,
2939
+ description: input.description ?? null,
2940
+ metadata: input.metadata,
2941
+ inputSchema: input.inputSchema ?? null,
2942
+ groundTruthSchema: input.groundTruthSchema ?? null,
2943
+ version: 0,
2944
+ createdAt: nowIso,
2945
+ updatedAt: nowIso
2946
+ }
2947
+ });
2948
+ return {
2949
+ id,
2950
+ name: input.name,
2951
+ description: input.description,
2952
+ metadata: input.metadata,
2953
+ inputSchema: input.inputSchema,
2954
+ groundTruthSchema: input.groundTruthSchema,
2955
+ version: 0,
2956
+ createdAt: now,
2957
+ updatedAt: now
2958
+ };
2959
+ } catch (error) {
2960
+ throw new MastraError(
2961
+ {
2962
+ id: createStorageErrorId("LIBSQL", "CREATE_DATASET", "FAILED"),
2963
+ domain: ErrorDomain.STORAGE,
2964
+ category: ErrorCategory.THIRD_PARTY
2965
+ },
2966
+ error
2967
+ );
2968
+ }
2969
+ }
2970
+ async getDatasetById({ id }) {
2971
+ try {
2972
+ const result = await this.#client.execute({
2973
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASETS)} FROM ${TABLE_DATASETS} WHERE id = ?`,
2974
+ args: [id]
2975
+ });
2976
+ return result.rows?.[0] ? this.transformDatasetRow(result.rows[0]) : null;
2977
+ } catch (error) {
2978
+ throw new MastraError(
2979
+ {
2980
+ id: createStorageErrorId("LIBSQL", "GET_DATASET", "FAILED"),
2981
+ domain: ErrorDomain.STORAGE,
2982
+ category: ErrorCategory.THIRD_PARTY
2983
+ },
2984
+ error
2985
+ );
2986
+ }
2987
+ }
2988
+ async _doUpdateDataset(args) {
2989
+ try {
2990
+ const existing = await this.getDatasetById({ id: args.id });
2991
+ if (!existing) {
2992
+ throw new MastraError({
2993
+ id: createStorageErrorId("LIBSQL", "UPDATE_DATASET", "NOT_FOUND"),
2994
+ domain: ErrorDomain.STORAGE,
2995
+ category: ErrorCategory.USER,
2996
+ details: { datasetId: args.id }
2997
+ });
2998
+ }
2999
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3000
+ const updates = ["updatedAt = ?"];
3001
+ const values = [now];
3002
+ if (args.name !== void 0) {
3003
+ updates.push("name = ?");
3004
+ values.push(args.name);
3005
+ }
3006
+ if (args.description !== void 0) {
3007
+ updates.push("description = ?");
3008
+ values.push(args.description);
3009
+ }
3010
+ if (args.metadata !== void 0) {
3011
+ updates.push("metadata = ?");
3012
+ values.push(JSON.stringify(args.metadata));
3013
+ }
3014
+ if (args.inputSchema !== void 0) {
3015
+ updates.push("inputSchema = ?");
3016
+ values.push(args.inputSchema === null ? null : JSON.stringify(args.inputSchema));
3017
+ }
3018
+ if (args.groundTruthSchema !== void 0) {
3019
+ updates.push("groundTruthSchema = ?");
3020
+ values.push(args.groundTruthSchema === null ? null : JSON.stringify(args.groundTruthSchema));
3021
+ }
3022
+ values.push(args.id);
3023
+ await this.#client.execute({
3024
+ sql: `UPDATE ${TABLE_DATASETS} SET ${updates.join(", ")} WHERE id = ?`,
3025
+ args: values
3026
+ });
3027
+ return {
3028
+ ...existing,
3029
+ name: args.name ?? existing.name,
3030
+ description: args.description ?? existing.description,
3031
+ metadata: args.metadata ?? existing.metadata,
3032
+ inputSchema: args.inputSchema !== void 0 ? args.inputSchema : existing.inputSchema,
3033
+ groundTruthSchema: args.groundTruthSchema !== void 0 ? args.groundTruthSchema : existing.groundTruthSchema,
3034
+ updatedAt: new Date(now)
3035
+ };
3036
+ } catch (error) {
3037
+ if (error instanceof MastraError) throw error;
3038
+ throw new MastraError(
3039
+ {
3040
+ id: createStorageErrorId("LIBSQL", "UPDATE_DATASET", "FAILED"),
3041
+ domain: ErrorDomain.STORAGE,
3042
+ category: ErrorCategory.THIRD_PARTY
3043
+ },
3044
+ error
3045
+ );
3046
+ }
3047
+ }
3048
+ async deleteDataset({ id }) {
3049
+ try {
3050
+ try {
3051
+ await this.#client.execute({
3052
+ sql: `DELETE FROM ${TABLE_EXPERIMENT_RESULTS} WHERE experimentId IN (SELECT id FROM ${TABLE_EXPERIMENTS} WHERE datasetId = ?)`,
3053
+ args: [id]
3054
+ });
3055
+ } catch {
3056
+ }
3057
+ try {
3058
+ await this.#client.execute({
3059
+ sql: `UPDATE ${TABLE_EXPERIMENTS} SET datasetId = NULL, datasetVersion = NULL WHERE datasetId = ?`,
3060
+ args: [id]
3061
+ });
3062
+ } catch {
3063
+ }
3064
+ await this.#client.batch(
3065
+ [
3066
+ { sql: `DELETE FROM ${TABLE_DATASET_VERSIONS} WHERE datasetId = ?`, args: [id] },
3067
+ { sql: `DELETE FROM ${TABLE_DATASET_ITEMS} WHERE datasetId = ?`, args: [id] },
3068
+ { sql: `DELETE FROM ${TABLE_DATASETS} WHERE id = ?`, args: [id] }
3069
+ ],
3070
+ "write"
3071
+ );
3072
+ } catch (error) {
3073
+ throw new MastraError(
3074
+ {
3075
+ id: createStorageErrorId("LIBSQL", "DELETE_DATASET", "FAILED"),
3076
+ domain: ErrorDomain.STORAGE,
3077
+ category: ErrorCategory.THIRD_PARTY
3078
+ },
3079
+ error
3080
+ );
3081
+ }
3082
+ }
3083
+ async listDatasets(args) {
3084
+ try {
3085
+ const { page, perPage: perPageInput } = args.pagination;
3086
+ const countResult = await this.#client.execute({
3087
+ sql: `SELECT COUNT(*) as count FROM ${TABLE_DATASETS}`,
3088
+ args: []
3089
+ });
3090
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
3091
+ if (total === 0) {
3092
+ return {
3093
+ datasets: [],
3094
+ pagination: { total: 0, page, perPage: perPageInput, hasMore: false }
3095
+ };
3096
+ }
3097
+ const perPage = normalizePerPage(perPageInput, 100);
3098
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
3099
+ const limitValue = perPageInput === false ? total : perPage;
3100
+ const end = perPageInput === false ? total : start + perPage;
3101
+ const result = await this.#client.execute({
3102
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASETS)} FROM ${TABLE_DATASETS} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
3103
+ args: [limitValue, start]
3104
+ });
3105
+ return {
3106
+ datasets: result.rows?.map((row) => this.transformDatasetRow(row)) ?? [],
3107
+ pagination: {
3108
+ total,
3109
+ page,
3110
+ perPage: perPageForResponse,
3111
+ hasMore: end < total
3112
+ }
3113
+ };
3114
+ } catch (error) {
3115
+ throw new MastraError(
3116
+ {
3117
+ id: createStorageErrorId("LIBSQL", "LIST_DATASETS", "FAILED"),
3118
+ domain: ErrorDomain.STORAGE,
3119
+ category: ErrorCategory.THIRD_PARTY
3120
+ },
3121
+ error
3122
+ );
3123
+ }
3124
+ }
3125
+ // --- SCD-2 item mutations ---
3126
+ async _doAddItem(args) {
3127
+ try {
3128
+ const id = crypto.randomUUID();
3129
+ const versionId = crypto.randomUUID();
3130
+ const now = /* @__PURE__ */ new Date();
3131
+ const nowIso = now.toISOString();
3132
+ const results = await this.#client.batch(
3133
+ [
3134
+ {
3135
+ sql: `UPDATE ${TABLE_DATASETS} SET version = version + 1 WHERE id = ? RETURNING version`,
3136
+ args: [args.datasetId]
3137
+ },
3138
+ {
3139
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, validTo, isDeleted, input, groundTruth, metadata, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 0, jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
3140
+ args: [
3141
+ id,
3142
+ args.datasetId,
3143
+ args.datasetId,
3144
+ jsonbArg(args.input),
3145
+ jsonbArg(args.groundTruth),
3146
+ jsonbArg(args.metadata),
3147
+ nowIso,
3148
+ nowIso
3149
+ ]
3150
+ },
3151
+ {
3152
+ sql: `INSERT INTO ${TABLE_DATASET_VERSIONS} (id, datasetId, version, createdAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?)`,
3153
+ args: [versionId, args.datasetId, args.datasetId, nowIso]
3154
+ }
3155
+ ],
3156
+ "write"
3157
+ );
3158
+ const newVersion = Number(results[0].rows[0].version);
3159
+ return {
3160
+ id,
3161
+ datasetId: args.datasetId,
3162
+ datasetVersion: newVersion,
3163
+ input: args.input,
3164
+ groundTruth: args.groundTruth,
3165
+ metadata: args.metadata,
3166
+ createdAt: now,
3167
+ updatedAt: now
3168
+ };
3169
+ } catch (error) {
3170
+ if (error instanceof MastraError) throw error;
3171
+ throw new MastraError(
3172
+ {
3173
+ id: createStorageErrorId("LIBSQL", "ADD_ITEM", "FAILED"),
3174
+ domain: ErrorDomain.STORAGE,
3175
+ category: ErrorCategory.THIRD_PARTY
3176
+ },
3177
+ error
3178
+ );
3179
+ }
3180
+ }
3181
+ async _doUpdateItem(args) {
3182
+ try {
3183
+ const existing = await this.getItemById({ id: args.id });
3184
+ if (!existing) {
3185
+ throw new MastraError({
3186
+ id: createStorageErrorId("LIBSQL", "UPDATE_ITEM", "NOT_FOUND"),
3187
+ domain: ErrorDomain.STORAGE,
3188
+ category: ErrorCategory.USER,
3189
+ details: { itemId: args.id }
3190
+ });
3191
+ }
3192
+ if (existing.datasetId !== args.datasetId) {
3193
+ throw new MastraError({
3194
+ id: createStorageErrorId("LIBSQL", "UPDATE_ITEM", "DATASET_MISMATCH"),
3195
+ domain: ErrorDomain.STORAGE,
3196
+ category: ErrorCategory.USER,
3197
+ details: { itemId: args.id, expectedDatasetId: args.datasetId, actualDatasetId: existing.datasetId }
3198
+ });
3199
+ }
3200
+ const versionId = crypto.randomUUID();
3201
+ const now = /* @__PURE__ */ new Date();
3202
+ const nowIso = now.toISOString();
3203
+ const mergedInput = args.input ?? existing.input;
3204
+ const mergedGroundTruth = args.groundTruth ?? existing.groundTruth;
3205
+ const mergedMetadata = args.metadata ?? existing.metadata;
3206
+ const results = await this.#client.batch(
3207
+ [
3208
+ {
3209
+ sql: `UPDATE ${TABLE_DATASETS} SET version = version + 1 WHERE id = ? RETURNING version`,
3210
+ args: [args.datasetId]
3211
+ },
3212
+ {
3213
+ sql: `UPDATE ${TABLE_DATASET_ITEMS} SET validTo = (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?) WHERE id = ? AND validTo IS NULL AND isDeleted = 0`,
3214
+ args: [args.datasetId, args.id]
3215
+ },
3216
+ {
3217
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, validTo, isDeleted, input, groundTruth, metadata, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 0, jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
3218
+ args: [
3219
+ args.id,
3220
+ args.datasetId,
3221
+ args.datasetId,
3222
+ jsonbArg(mergedInput),
3223
+ jsonbArg(mergedGroundTruth),
3224
+ jsonbArg(mergedMetadata),
3225
+ existing.createdAt.toISOString(),
3226
+ nowIso
3227
+ ]
3228
+ },
3229
+ {
3230
+ sql: `INSERT INTO ${TABLE_DATASET_VERSIONS} (id, datasetId, version, createdAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?)`,
3231
+ args: [versionId, args.datasetId, args.datasetId, nowIso]
3232
+ }
3233
+ ],
3234
+ "write"
3235
+ );
3236
+ const newVersion = Number(results[0].rows[0].version);
3237
+ return {
3238
+ ...existing,
3239
+ datasetVersion: newVersion,
3240
+ input: mergedInput,
3241
+ groundTruth: mergedGroundTruth,
3242
+ metadata: mergedMetadata,
3243
+ updatedAt: now
3244
+ };
3245
+ } catch (error) {
3246
+ if (error instanceof MastraError) throw error;
3247
+ throw new MastraError(
3248
+ {
3249
+ id: createStorageErrorId("LIBSQL", "UPDATE_ITEM", "FAILED"),
3250
+ domain: ErrorDomain.STORAGE,
3251
+ category: ErrorCategory.THIRD_PARTY
3252
+ },
3253
+ error
3254
+ );
3255
+ }
3256
+ }
3257
+ async _doDeleteItem({ id, datasetId }) {
3258
+ try {
3259
+ const existing = await this.getItemById({ id });
3260
+ if (!existing) return;
3261
+ if (existing.datasetId !== datasetId) {
3262
+ throw new MastraError({
3263
+ id: createStorageErrorId("LIBSQL", "DELETE_ITEM", "DATASET_MISMATCH"),
3264
+ domain: ErrorDomain.STORAGE,
3265
+ category: ErrorCategory.USER,
3266
+ details: { itemId: id, expectedDatasetId: datasetId, actualDatasetId: existing.datasetId }
3267
+ });
3268
+ }
3269
+ const versionId = crypto.randomUUID();
3270
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
3271
+ await this.#client.batch(
3272
+ [
3273
+ {
3274
+ sql: `UPDATE ${TABLE_DATASETS} SET version = version + 1 WHERE id = ? RETURNING version`,
3275
+ args: [datasetId]
3276
+ },
3277
+ {
3278
+ sql: `UPDATE ${TABLE_DATASET_ITEMS} SET validTo = (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?) WHERE id = ? AND validTo IS NULL AND isDeleted = 0`,
3279
+ args: [datasetId, id]
3280
+ },
3281
+ {
3282
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, validTo, isDeleted, input, groundTruth, metadata, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 1, jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
3283
+ args: [
3284
+ id,
3285
+ datasetId,
3286
+ datasetId,
3287
+ jsonbArg(existing.input),
3288
+ jsonbArg(existing.groundTruth),
3289
+ jsonbArg(existing.metadata),
3290
+ existing.createdAt.toISOString(),
3291
+ nowIso
3292
+ ]
3293
+ },
3294
+ {
3295
+ sql: `INSERT INTO ${TABLE_DATASET_VERSIONS} (id, datasetId, version, createdAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?)`,
3296
+ args: [versionId, datasetId, datasetId, nowIso]
3297
+ }
3298
+ ],
3299
+ "write"
3300
+ );
3301
+ } catch (error) {
3302
+ if (error instanceof MastraError) throw error;
3303
+ throw new MastraError(
3304
+ {
3305
+ id: createStorageErrorId("LIBSQL", "DELETE_ITEM", "FAILED"),
3306
+ domain: ErrorDomain.STORAGE,
3307
+ category: ErrorCategory.THIRD_PARTY
3308
+ },
3309
+ error
3310
+ );
3311
+ }
3312
+ }
3313
+ // --- SCD-2 queries ---
3314
+ async getItemById(args) {
3315
+ try {
3316
+ let result;
3317
+ if (args.datasetVersion !== void 0) {
3318
+ result = await this.#client.execute({
3319
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASET_ITEMS)} FROM ${TABLE_DATASET_ITEMS} WHERE id = ? AND datasetVersion = ? AND isDeleted = 0`,
3320
+ args: [args.id, args.datasetVersion]
3321
+ });
3322
+ } else {
3323
+ result = await this.#client.execute({
3324
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASET_ITEMS)} FROM ${TABLE_DATASET_ITEMS} WHERE id = ? AND validTo IS NULL AND isDeleted = 0`,
3325
+ args: [args.id]
3326
+ });
3327
+ }
3328
+ return result.rows?.[0] ? this.transformItemRow(result.rows[0]) : null;
3329
+ } catch (error) {
3330
+ throw new MastraError(
3331
+ {
3332
+ id: createStorageErrorId("LIBSQL", "GET_ITEM", "FAILED"),
3333
+ domain: ErrorDomain.STORAGE,
3334
+ category: ErrorCategory.THIRD_PARTY
3335
+ },
3336
+ error
3337
+ );
3338
+ }
3339
+ }
3340
+ async getItemsByVersion({ datasetId, version }) {
3341
+ try {
3342
+ const result = await this.#client.execute({
3343
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASET_ITEMS)} FROM ${TABLE_DATASET_ITEMS} WHERE datasetId = ? AND datasetVersion <= ? AND (validTo IS NULL OR validTo > ?) AND isDeleted = 0 ORDER BY createdAt DESC`,
3344
+ args: [datasetId, version, version]
3345
+ });
3346
+ return result.rows?.map((row) => this.transformItemRow(row)) ?? [];
3347
+ } catch (error) {
3348
+ throw new MastraError(
3349
+ {
3350
+ id: createStorageErrorId("LIBSQL", "GET_ITEMS_BY_VERSION", "FAILED"),
3351
+ domain: ErrorDomain.STORAGE,
3352
+ category: ErrorCategory.THIRD_PARTY
3353
+ },
3354
+ error
3355
+ );
3356
+ }
3357
+ }
3358
+ async getItemHistory(itemId) {
3359
+ try {
3360
+ const result = await this.#client.execute({
3361
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASET_ITEMS)} FROM ${TABLE_DATASET_ITEMS} WHERE id = ? ORDER BY datasetVersion DESC`,
3362
+ args: [itemId]
3363
+ });
3364
+ return result.rows?.map((row) => this.transformItemRowFull(row)) ?? [];
3365
+ } catch (error) {
3366
+ throw new MastraError(
3367
+ {
3368
+ id: createStorageErrorId("LIBSQL", "GET_ITEM_HISTORY", "FAILED"),
3369
+ domain: ErrorDomain.STORAGE,
3370
+ category: ErrorCategory.THIRD_PARTY
3371
+ },
3372
+ error
3373
+ );
3374
+ }
3375
+ }
3376
+ async listItems(args) {
3377
+ try {
3378
+ const { page, perPage: perPageInput } = args.pagination;
3379
+ if (args.version !== void 0) {
3380
+ const conditions2 = [
3381
+ "datasetId = ?",
3382
+ "datasetVersion <= ?",
3383
+ "(validTo IS NULL OR validTo > ?)",
3384
+ "isDeleted = 0"
3385
+ ];
3386
+ const queryParams2 = [args.datasetId, args.version, args.version];
3387
+ if (args.search) {
3388
+ conditions2.push(`(LOWER(json(input)) LIKE ? OR LOWER(COALESCE(json(groundTruth), '')) LIKE ?)`);
3389
+ const searchPattern = `%${args.search.toLowerCase()}%`;
3390
+ queryParams2.push(searchPattern, searchPattern);
3391
+ }
3392
+ const whereClause2 = `WHERE ${conditions2.join(" AND ")}`;
3393
+ const countResult2 = await this.#client.execute({
3394
+ sql: `SELECT COUNT(*) as count FROM ${TABLE_DATASET_ITEMS} ${whereClause2}`,
3395
+ args: queryParams2
3396
+ });
3397
+ const total2 = Number(countResult2.rows?.[0]?.count ?? 0);
3398
+ if (total2 === 0) {
3399
+ return {
3400
+ items: [],
3401
+ pagination: { total: 0, page, perPage: perPageInput, hasMore: false }
3402
+ };
3403
+ }
3404
+ const perPage2 = normalizePerPage(perPageInput, 100);
3405
+ const { offset: start2, perPage: perPageForResponse2 } = calculatePagination(page, perPageInput, perPage2);
3406
+ const limitValue2 = perPageInput === false ? total2 : perPage2;
3407
+ const end2 = perPageInput === false ? total2 : start2 + perPage2;
3408
+ const result2 = await this.#client.execute({
3409
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASET_ITEMS)} FROM ${TABLE_DATASET_ITEMS} ${whereClause2} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
3410
+ args: [...queryParams2, limitValue2, start2]
3411
+ });
3412
+ return {
3413
+ items: result2.rows?.map((row) => this.transformItemRow(row)) ?? [],
3414
+ pagination: {
3415
+ total: total2,
3416
+ page,
3417
+ perPage: perPageForResponse2,
3418
+ hasMore: end2 < total2
3419
+ }
3420
+ };
3421
+ }
3422
+ const conditions = ["datasetId = ?", "validTo IS NULL", "isDeleted = 0"];
3423
+ const queryParams = [args.datasetId];
3424
+ if (args.search) {
3425
+ conditions.push(`(LOWER(json(input)) LIKE ? OR LOWER(COALESCE(json(groundTruth), '')) LIKE ?)`);
3426
+ const searchPattern = `%${args.search.toLowerCase()}%`;
3427
+ queryParams.push(searchPattern, searchPattern);
3428
+ }
3429
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
3430
+ const countResult = await this.#client.execute({
3431
+ sql: `SELECT COUNT(*) as count FROM ${TABLE_DATASET_ITEMS} ${whereClause}`,
3432
+ args: queryParams
3433
+ });
3434
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
3435
+ if (total === 0) {
3436
+ return {
3437
+ items: [],
3438
+ pagination: { total: 0, page, perPage: perPageInput, hasMore: false }
3439
+ };
3440
+ }
3441
+ const perPage = normalizePerPage(perPageInput, 100);
3442
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
3443
+ const limitValue = perPageInput === false ? total : perPage;
3444
+ const end = perPageInput === false ? total : start + perPage;
3445
+ const result = await this.#client.execute({
3446
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASET_ITEMS)} FROM ${TABLE_DATASET_ITEMS} ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
3447
+ args: [...queryParams, limitValue, start]
3448
+ });
3449
+ return {
3450
+ items: result.rows?.map((row) => this.transformItemRow(row)) ?? [],
3451
+ pagination: {
3452
+ total,
3453
+ page,
3454
+ perPage: perPageForResponse,
3455
+ hasMore: end < total
3456
+ }
3457
+ };
3458
+ } catch (error) {
3459
+ throw new MastraError(
3460
+ {
3461
+ id: createStorageErrorId("LIBSQL", "LIST_ITEMS", "FAILED"),
3462
+ domain: ErrorDomain.STORAGE,
3463
+ category: ErrorCategory.THIRD_PARTY
3464
+ },
3465
+ error
3466
+ );
3467
+ }
3468
+ }
3469
+ // --- Dataset version methods ---
3470
+ async createDatasetVersion(datasetId, version) {
3471
+ try {
3472
+ const id = crypto.randomUUID();
3473
+ const now = /* @__PURE__ */ new Date();
3474
+ const nowIso = now.toISOString();
3475
+ await this.#db.insert({
3476
+ tableName: TABLE_DATASET_VERSIONS,
3477
+ record: {
3478
+ id,
3479
+ datasetId,
3480
+ version,
3481
+ createdAt: nowIso
3482
+ }
3483
+ });
3484
+ return {
3485
+ id,
3486
+ datasetId,
3487
+ version,
3488
+ createdAt: now
3489
+ };
3490
+ } catch (error) {
3491
+ throw new MastraError(
3492
+ {
3493
+ id: createStorageErrorId("LIBSQL", "CREATE_DATASET_VERSION", "FAILED"),
3494
+ domain: ErrorDomain.STORAGE,
3495
+ category: ErrorCategory.THIRD_PARTY
3496
+ },
3497
+ error
3498
+ );
3499
+ }
3500
+ }
3501
+ async listDatasetVersions(input) {
3502
+ try {
3503
+ const { page, perPage: perPageInput } = input.pagination;
3504
+ const countResult = await this.#client.execute({
3505
+ sql: `SELECT COUNT(*) as count FROM ${TABLE_DATASET_VERSIONS} WHERE datasetId = ?`,
3506
+ args: [input.datasetId]
3507
+ });
3508
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
3509
+ if (total === 0) {
3510
+ return {
3511
+ versions: [],
3512
+ pagination: { total: 0, page, perPage: perPageInput, hasMore: false }
3513
+ };
3514
+ }
3515
+ const perPage = normalizePerPage(perPageInput, 100);
3516
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
3517
+ const limitValue = perPageInput === false ? total : perPage;
3518
+ const end = perPageInput === false ? total : start + perPage;
3519
+ const result = await this.#client.execute({
3520
+ sql: `SELECT ${buildSelectColumns(TABLE_DATASET_VERSIONS)} FROM ${TABLE_DATASET_VERSIONS} WHERE datasetId = ? ORDER BY version DESC LIMIT ? OFFSET ?`,
3521
+ args: [input.datasetId, limitValue, start]
3522
+ });
3523
+ return {
3524
+ versions: result.rows?.map((row) => this.transformDatasetVersionRow(row)) ?? [],
3525
+ pagination: {
3526
+ total,
3527
+ page,
3528
+ perPage: perPageForResponse,
3529
+ hasMore: end < total
3530
+ }
3531
+ };
3532
+ } catch (error) {
3533
+ throw new MastraError(
3534
+ {
3535
+ id: createStorageErrorId("LIBSQL", "LIST_DATASET_VERSIONS", "FAILED"),
3536
+ domain: ErrorDomain.STORAGE,
3537
+ category: ErrorCategory.THIRD_PARTY
3538
+ },
3539
+ error
3540
+ );
3541
+ }
3542
+ }
3543
+ // --- Bulk operations (SCD-2 internally) ---
3544
+ async _doBatchInsertItems(input) {
3545
+ try {
3546
+ const dataset = await this.getDatasetById({ id: input.datasetId });
3547
+ if (!dataset) {
3548
+ throw new MastraError({
3549
+ id: createStorageErrorId("LIBSQL", "BULK_ADD_ITEMS", "DATASET_NOT_FOUND"),
3550
+ domain: ErrorDomain.STORAGE,
3551
+ category: ErrorCategory.USER,
3552
+ details: { datasetId: input.datasetId }
3553
+ });
3554
+ }
3555
+ const now = /* @__PURE__ */ new Date();
3556
+ const nowIso = now.toISOString();
3557
+ const versionId = crypto.randomUUID();
3558
+ const statements = [
3559
+ {
3560
+ sql: `UPDATE ${TABLE_DATASETS} SET version = version + 1 WHERE id = ? RETURNING version`,
3561
+ args: [input.datasetId]
3562
+ }
3563
+ ];
3564
+ const items = [];
3565
+ for (const itemInput of input.items) {
3566
+ const id = crypto.randomUUID();
3567
+ items.push({ id, input: itemInput });
3568
+ statements.push({
3569
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, validTo, isDeleted, input, groundTruth, metadata, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 0, jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
3570
+ args: [
3571
+ id,
3572
+ input.datasetId,
3573
+ input.datasetId,
3574
+ jsonbArg(itemInput.input),
3575
+ jsonbArg(itemInput.groundTruth),
3576
+ jsonbArg(itemInput.metadata),
3577
+ nowIso,
3578
+ nowIso
3579
+ ]
3580
+ });
3581
+ }
3582
+ statements.push({
3583
+ sql: `INSERT INTO ${TABLE_DATASET_VERSIONS} (id, datasetId, version, createdAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?)`,
3584
+ args: [versionId, input.datasetId, input.datasetId, nowIso]
3585
+ });
3586
+ const results = await this.#client.batch(statements, "write");
3587
+ const newVersion = Number(results[0].rows[0].version);
3588
+ return items.map(({ id, input: itemInput }) => ({
3589
+ id,
3590
+ datasetId: input.datasetId,
3591
+ datasetVersion: newVersion,
3592
+ input: itemInput.input,
3593
+ groundTruth: itemInput.groundTruth,
3594
+ metadata: itemInput.metadata,
3595
+ createdAt: now,
3596
+ updatedAt: now
3597
+ }));
3598
+ } catch (error) {
3599
+ if (error instanceof MastraError) throw error;
3600
+ throw new MastraError(
3601
+ {
3602
+ id: createStorageErrorId("LIBSQL", "BULK_ADD_ITEMS", "FAILED"),
3603
+ domain: ErrorDomain.STORAGE,
3604
+ category: ErrorCategory.THIRD_PARTY
3605
+ },
3606
+ error
3607
+ );
3608
+ }
3609
+ }
3610
+ async _doBatchDeleteItems(input) {
3611
+ try {
3612
+ const dataset = await this.getDatasetById({ id: input.datasetId });
3613
+ if (!dataset) {
3614
+ throw new MastraError({
3615
+ id: createStorageErrorId("LIBSQL", "BULK_DELETE_ITEMS", "DATASET_NOT_FOUND"),
3616
+ domain: ErrorDomain.STORAGE,
3617
+ category: ErrorCategory.USER,
3618
+ details: { datasetId: input.datasetId }
3619
+ });
3620
+ }
3621
+ const currentItems = [];
3622
+ for (const itemId of input.itemIds) {
3623
+ const item = await this.getItemById({ id: itemId });
3624
+ if (item && item.datasetId === input.datasetId) {
3625
+ currentItems.push(item);
3626
+ }
3627
+ }
3628
+ if (currentItems.length === 0) return;
3629
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
3630
+ const versionId = crypto.randomUUID();
3631
+ const statements = [
3632
+ {
3633
+ sql: `UPDATE ${TABLE_DATASETS} SET version = version + 1 WHERE id = ? RETURNING version`,
3634
+ args: [input.datasetId]
3635
+ }
3636
+ ];
3637
+ for (const item of currentItems) {
3638
+ statements.push({
3639
+ sql: `UPDATE ${TABLE_DATASET_ITEMS} SET validTo = (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?) WHERE id = ? AND validTo IS NULL AND isDeleted = 0`,
3640
+ args: [input.datasetId, item.id]
3641
+ });
3642
+ statements.push({
3643
+ sql: `INSERT INTO ${TABLE_DATASET_ITEMS} (id, datasetId, datasetVersion, validTo, isDeleted, input, groundTruth, metadata, createdAt, updatedAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), NULL, 1, jsonb(?), jsonb(?), jsonb(?), ?, ?)`,
3644
+ args: [
3645
+ item.id,
3646
+ input.datasetId,
3647
+ input.datasetId,
3648
+ jsonbArg(item.input),
3649
+ jsonbArg(item.groundTruth),
3650
+ jsonbArg(item.metadata),
3651
+ item.createdAt.toISOString(),
3652
+ nowIso
3653
+ ]
3654
+ });
3655
+ }
3656
+ statements.push({
3657
+ sql: `INSERT INTO ${TABLE_DATASET_VERSIONS} (id, datasetId, version, createdAt) VALUES (?, ?, (SELECT version FROM ${TABLE_DATASETS} WHERE id = ?), ?)`,
3658
+ args: [versionId, input.datasetId, input.datasetId, nowIso]
3659
+ });
3660
+ await this.#client.batch(statements, "write");
3661
+ } catch (error) {
3662
+ if (error instanceof MastraError) throw error;
3663
+ throw new MastraError(
3664
+ {
3665
+ id: createStorageErrorId("LIBSQL", "BULK_DELETE_ITEMS", "FAILED"),
3666
+ domain: ErrorDomain.STORAGE,
3667
+ category: ErrorCategory.THIRD_PARTY
3668
+ },
3669
+ error
3670
+ );
3671
+ }
3672
+ }
3673
+ };
3674
+ var ExperimentsLibSQL = class extends ExperimentsStorage {
3675
+ #db;
3676
+ #client;
3677
+ constructor(config) {
3678
+ super();
3679
+ const client = resolveClient(config);
3680
+ this.#client = client;
3681
+ this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
3682
+ }
3683
+ async init() {
3684
+ await this.#db.createTable({ tableName: TABLE_EXPERIMENTS, schema: EXPERIMENTS_SCHEMA });
3685
+ await this.#db.createTable({
3686
+ tableName: TABLE_EXPERIMENT_RESULTS,
3687
+ schema: EXPERIMENT_RESULTS_SCHEMA
3688
+ });
3689
+ await this.#client.execute({
3690
+ sql: `CREATE INDEX IF NOT EXISTS idx_experiments_datasetid ON "${TABLE_EXPERIMENTS}" ("datasetId")`,
3691
+ args: []
3692
+ });
3693
+ await this.#client.execute({
3694
+ sql: `CREATE INDEX IF NOT EXISTS idx_experiment_results_experimentid ON "${TABLE_EXPERIMENT_RESULTS}" ("experimentId")`,
3695
+ args: []
3696
+ });
3697
+ await this.#client.execute({
3698
+ sql: `CREATE UNIQUE INDEX IF NOT EXISTS idx_experiment_results_exp_item ON "${TABLE_EXPERIMENT_RESULTS}" ("experimentId", "itemId")`,
3699
+ args: []
3700
+ });
3701
+ }
3702
+ async dangerouslyClearAll() {
3703
+ await this.#db.deleteData({ tableName: TABLE_EXPERIMENT_RESULTS });
3704
+ await this.#db.deleteData({ tableName: TABLE_EXPERIMENTS });
3705
+ }
3706
+ // Helper to transform row to Experiment
3707
+ transformExperimentRow(row) {
3708
+ return {
3709
+ id: row.id,
3710
+ datasetId: row.datasetId ?? null,
3711
+ datasetVersion: row.datasetVersion != null ? row.datasetVersion : null,
3712
+ targetType: row.targetType,
3713
+ targetId: row.targetId,
3714
+ name: row.name ?? void 0,
3715
+ description: row.description ?? void 0,
3716
+ metadata: row.metadata ? safelyParseJSON(row.metadata) : void 0,
3717
+ status: row.status,
3718
+ totalItems: row.totalItems,
3719
+ succeededCount: row.succeededCount,
3720
+ failedCount: row.failedCount,
3721
+ skippedCount: row.skippedCount ?? 0,
3722
+ startedAt: row.startedAt ? ensureDate(row.startedAt) : null,
3723
+ completedAt: row.completedAt ? ensureDate(row.completedAt) : null,
3724
+ createdAt: ensureDate(row.createdAt),
3725
+ updatedAt: ensureDate(row.updatedAt)
3726
+ };
3727
+ }
3728
+ // Helper to transform row to ExperimentResult
3729
+ transformExperimentResultRow(row) {
3730
+ return {
3731
+ id: row.id,
3732
+ experimentId: row.experimentId,
3733
+ itemId: row.itemId,
3734
+ itemDatasetVersion: row.itemDatasetVersion != null ? row.itemDatasetVersion : null,
3735
+ input: safelyParseJSON(row.input),
3736
+ output: row.output ? safelyParseJSON(row.output) : null,
3737
+ groundTruth: row.groundTruth ? safelyParseJSON(row.groundTruth) : null,
3738
+ error: row.error ? safelyParseJSON(row.error) : null,
3739
+ startedAt: ensureDate(row.startedAt),
3740
+ completedAt: ensureDate(row.completedAt),
3741
+ retryCount: row.retryCount,
3742
+ traceId: row.traceId ?? null,
3743
+ createdAt: ensureDate(row.createdAt)
3744
+ };
3745
+ }
3746
+ // Experiment lifecycle
3747
+ async createExperiment(input) {
3748
+ try {
3749
+ const id = input.id ?? crypto.randomUUID();
3750
+ const now = /* @__PURE__ */ new Date();
3751
+ const nowIso = now.toISOString();
3752
+ await this.#db.insert({
3753
+ tableName: TABLE_EXPERIMENTS,
3754
+ record: {
3755
+ id,
3756
+ datasetId: input.datasetId ?? null,
3757
+ datasetVersion: input.datasetVersion ?? null,
3758
+ targetType: input.targetType,
3759
+ targetId: input.targetId,
3760
+ name: input.name ?? null,
3761
+ description: input.description ?? null,
3762
+ metadata: input.metadata ?? null,
3763
+ status: "pending",
3764
+ totalItems: input.totalItems,
3765
+ succeededCount: 0,
3766
+ failedCount: 0,
3767
+ skippedCount: 0,
3768
+ startedAt: null,
3769
+ completedAt: null,
3770
+ createdAt: nowIso,
3771
+ updatedAt: nowIso
3772
+ }
3773
+ });
3774
+ return {
3775
+ id,
3776
+ datasetId: input.datasetId,
3777
+ datasetVersion: input.datasetVersion,
3778
+ targetType: input.targetType,
3779
+ targetId: input.targetId,
3780
+ name: input.name,
3781
+ description: input.description,
3782
+ metadata: input.metadata,
3783
+ status: "pending",
3784
+ totalItems: input.totalItems,
3785
+ succeededCount: 0,
3786
+ failedCount: 0,
3787
+ skippedCount: 0,
3788
+ startedAt: null,
3789
+ completedAt: null,
3790
+ createdAt: now,
3791
+ updatedAt: now
3792
+ };
3793
+ } catch (error) {
3794
+ throw new MastraError(
3795
+ {
3796
+ id: createStorageErrorId("LIBSQL", "CREATE_EXPERIMENT", "FAILED"),
3797
+ domain: ErrorDomain.STORAGE,
3798
+ category: ErrorCategory.THIRD_PARTY
3799
+ },
3800
+ error
3801
+ );
3802
+ }
3803
+ }
3804
+ async updateExperiment(input) {
3805
+ try {
3806
+ const existing = await this.getExperimentById({ id: input.id });
3807
+ if (!existing) {
3808
+ throw new MastraError({
3809
+ id: createStorageErrorId("LIBSQL", "UPDATE_EXPERIMENT", "NOT_FOUND"),
3810
+ domain: ErrorDomain.STORAGE,
3811
+ category: ErrorCategory.USER,
3812
+ details: { experimentId: input.id }
3813
+ });
3814
+ }
3815
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3816
+ const updates = ["updatedAt = ?"];
3817
+ const values = [now];
3818
+ if (input.status !== void 0) {
3819
+ updates.push("status = ?");
3820
+ values.push(input.status);
3821
+ }
3822
+ if (input.succeededCount !== void 0) {
3823
+ updates.push("succeededCount = ?");
3824
+ values.push(input.succeededCount);
3825
+ }
3826
+ if (input.failedCount !== void 0) {
3827
+ updates.push("failedCount = ?");
3828
+ values.push(input.failedCount);
3829
+ }
3830
+ if (input.startedAt !== void 0) {
3831
+ updates.push("startedAt = ?");
3832
+ values.push(input.startedAt?.toISOString() ?? null);
3833
+ }
3834
+ if (input.completedAt !== void 0) {
3835
+ updates.push("completedAt = ?");
3836
+ values.push(input.completedAt?.toISOString() ?? null);
3837
+ }
3838
+ if (input.skippedCount !== void 0) {
3839
+ updates.push("skippedCount = ?");
3840
+ values.push(input.skippedCount);
3841
+ }
3842
+ if (input.name !== void 0) {
3843
+ updates.push("name = ?");
3844
+ values.push(input.name);
3845
+ }
3846
+ if (input.description !== void 0) {
3847
+ updates.push("description = ?");
3848
+ values.push(input.description);
3849
+ }
3850
+ if (input.metadata !== void 0) {
3851
+ updates.push("metadata = ?");
3852
+ values.push(JSON.stringify(input.metadata));
3853
+ }
3854
+ values.push(input.id);
3855
+ await this.#client.execute({
3856
+ sql: `UPDATE ${TABLE_EXPERIMENTS} SET ${updates.join(", ")} WHERE id = ?`,
3857
+ args: values
3858
+ });
3859
+ const updated = await this.getExperimentById({ id: input.id });
3860
+ return updated;
3861
+ } catch (error) {
3862
+ if (error instanceof MastraError) throw error;
3863
+ throw new MastraError(
3864
+ {
3865
+ id: createStorageErrorId("LIBSQL", "UPDATE_EXPERIMENT", "FAILED"),
3866
+ domain: ErrorDomain.STORAGE,
3867
+ category: ErrorCategory.THIRD_PARTY
3868
+ },
3869
+ error
3870
+ );
3871
+ }
3872
+ }
3873
+ async getExperimentById(args) {
3874
+ try {
3875
+ const result = await this.#client.execute({
3876
+ sql: `SELECT ${buildSelectColumns(TABLE_EXPERIMENTS)} FROM ${TABLE_EXPERIMENTS} WHERE id = ?`,
3877
+ args: [args.id]
3878
+ });
3879
+ return result.rows?.[0] ? this.transformExperimentRow(result.rows[0]) : null;
3880
+ } catch (error) {
3881
+ throw new MastraError(
3882
+ {
3883
+ id: createStorageErrorId("LIBSQL", "GET_EXPERIMENT", "FAILED"),
3884
+ domain: ErrorDomain.STORAGE,
3885
+ category: ErrorCategory.THIRD_PARTY
3886
+ },
3887
+ error
3888
+ );
3889
+ }
3890
+ }
3891
+ async listExperiments(args) {
3892
+ try {
3893
+ const { page, perPage: perPageInput } = args.pagination;
3894
+ const conditions = [];
3895
+ const queryParams = [];
3896
+ if (args.datasetId) {
3897
+ conditions.push("datasetId = ?");
3898
+ queryParams.push(args.datasetId);
3899
+ }
3900
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
3901
+ const countResult = await this.#client.execute({
3902
+ sql: `SELECT COUNT(*) as count FROM ${TABLE_EXPERIMENTS} ${whereClause}`,
3903
+ args: queryParams
3904
+ });
3905
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
3906
+ if (total === 0) {
3907
+ return {
3908
+ experiments: [],
3909
+ pagination: { total: 0, page, perPage: perPageInput, hasMore: false }
3910
+ };
3911
+ }
3912
+ const perPage = normalizePerPage(perPageInput, 100);
3913
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
3914
+ const limitValue = perPageInput === false ? total : perPage;
3915
+ const end = perPageInput === false ? total : start + perPage;
3916
+ const result = await this.#client.execute({
3917
+ sql: `SELECT ${buildSelectColumns(TABLE_EXPERIMENTS)} FROM ${TABLE_EXPERIMENTS} ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
3918
+ args: [...queryParams, limitValue, start]
3919
+ });
3920
+ return {
3921
+ experiments: result.rows?.map((row) => this.transformExperimentRow(row)) ?? [],
3922
+ pagination: {
3923
+ total,
3924
+ page,
3925
+ perPage: perPageForResponse,
3926
+ hasMore: end < total
3927
+ }
3928
+ };
3929
+ } catch (error) {
3930
+ throw new MastraError(
3931
+ {
3932
+ id: createStorageErrorId("LIBSQL", "LIST_EXPERIMENTS", "FAILED"),
3933
+ domain: ErrorDomain.STORAGE,
3934
+ category: ErrorCategory.THIRD_PARTY
3935
+ },
3936
+ error
3937
+ );
3938
+ }
3939
+ }
3940
+ async deleteExperiment(args) {
3941
+ try {
3942
+ await this.#client.execute({
3943
+ sql: `DELETE FROM ${TABLE_EXPERIMENT_RESULTS} WHERE experimentId = ?`,
3944
+ args: [args.id]
3945
+ });
3946
+ await this.#client.execute({
3947
+ sql: `DELETE FROM ${TABLE_EXPERIMENTS} WHERE id = ?`,
3948
+ args: [args.id]
3949
+ });
3950
+ } catch (error) {
3951
+ throw new MastraError(
3952
+ {
3953
+ id: createStorageErrorId("LIBSQL", "DELETE_EXPERIMENT", "FAILED"),
3954
+ domain: ErrorDomain.STORAGE,
3955
+ category: ErrorCategory.THIRD_PARTY
3956
+ },
3957
+ error
3958
+ );
3959
+ }
3960
+ }
3961
+ // Results (per-item)
3962
+ async addExperimentResult(input) {
3963
+ try {
3964
+ const id = input.id ?? crypto.randomUUID();
3965
+ const now = /* @__PURE__ */ new Date();
3966
+ const nowIso = now.toISOString();
3967
+ await this.#db.insert({
3968
+ tableName: TABLE_EXPERIMENT_RESULTS,
3969
+ record: {
3970
+ id,
3971
+ experimentId: input.experimentId,
3972
+ itemId: input.itemId,
3973
+ itemDatasetVersion: input.itemDatasetVersion ?? null,
3974
+ input: input.input,
3975
+ output: input.output,
3976
+ groundTruth: input.groundTruth,
3977
+ error: input.error ?? null,
3978
+ startedAt: input.startedAt.toISOString(),
3979
+ completedAt: input.completedAt.toISOString(),
3980
+ retryCount: input.retryCount,
3981
+ traceId: input.traceId ?? null,
3982
+ createdAt: nowIso
3983
+ }
3984
+ });
3985
+ return {
3986
+ id,
3987
+ experimentId: input.experimentId,
3988
+ itemId: input.itemId,
3989
+ itemDatasetVersion: input.itemDatasetVersion,
3990
+ input: input.input,
3991
+ output: input.output,
3992
+ groundTruth: input.groundTruth,
3993
+ error: input.error,
3994
+ startedAt: input.startedAt,
3995
+ completedAt: input.completedAt,
3996
+ retryCount: input.retryCount,
3997
+ traceId: input.traceId ?? null,
3998
+ createdAt: now
3999
+ };
4000
+ } catch (error) {
4001
+ throw new MastraError(
4002
+ {
4003
+ id: createStorageErrorId("LIBSQL", "ADD_EXPERIMENT_RESULT", "FAILED"),
4004
+ domain: ErrorDomain.STORAGE,
4005
+ category: ErrorCategory.THIRD_PARTY
4006
+ },
4007
+ error
4008
+ );
4009
+ }
4010
+ }
4011
+ async getExperimentResultById(args) {
4012
+ try {
4013
+ const result = await this.#client.execute({
4014
+ sql: `SELECT ${buildSelectColumns(TABLE_EXPERIMENT_RESULTS)} FROM ${TABLE_EXPERIMENT_RESULTS} WHERE id = ?`,
4015
+ args: [args.id]
4016
+ });
4017
+ return result.rows?.[0] ? this.transformExperimentResultRow(result.rows[0]) : null;
4018
+ } catch (error) {
4019
+ throw new MastraError(
4020
+ {
4021
+ id: createStorageErrorId("LIBSQL", "GET_EXPERIMENT_RESULT", "FAILED"),
4022
+ domain: ErrorDomain.STORAGE,
4023
+ category: ErrorCategory.THIRD_PARTY
4024
+ },
4025
+ error
4026
+ );
4027
+ }
4028
+ }
4029
+ async listExperimentResults(args) {
4030
+ try {
4031
+ const { page, perPage: perPageInput } = args.pagination;
4032
+ const conditions = ["experimentId = ?"];
4033
+ const queryParams = [args.experimentId];
4034
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
4035
+ const countResult = await this.#client.execute({
4036
+ sql: `SELECT COUNT(*) as count FROM ${TABLE_EXPERIMENT_RESULTS} ${whereClause}`,
4037
+ args: queryParams
4038
+ });
4039
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
4040
+ if (total === 0) {
4041
+ return {
4042
+ results: [],
4043
+ pagination: { total: 0, page, perPage: perPageInput, hasMore: false }
4044
+ };
4045
+ }
4046
+ const perPage = normalizePerPage(perPageInput, 100);
4047
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
4048
+ const limitValue = perPageInput === false ? total : perPage;
4049
+ const end = perPageInput === false ? total : start + perPage;
4050
+ const result = await this.#client.execute({
4051
+ sql: `SELECT ${buildSelectColumns(TABLE_EXPERIMENT_RESULTS)} FROM ${TABLE_EXPERIMENT_RESULTS} ${whereClause} ORDER BY startedAt ASC LIMIT ? OFFSET ?`,
4052
+ args: [...queryParams, limitValue, start]
4053
+ });
4054
+ return {
4055
+ results: result.rows?.map((row) => this.transformExperimentResultRow(row)) ?? [],
4056
+ pagination: {
4057
+ total,
4058
+ page,
4059
+ perPage: perPageForResponse,
4060
+ hasMore: end < total
4061
+ }
4062
+ };
4063
+ } catch (error) {
4064
+ throw new MastraError(
4065
+ {
4066
+ id: createStorageErrorId("LIBSQL", "LIST_EXPERIMENT_RESULTS", "FAILED"),
4067
+ domain: ErrorDomain.STORAGE,
4068
+ category: ErrorCategory.THIRD_PARTY
4069
+ },
4070
+ error
4071
+ );
4072
+ }
4073
+ }
4074
+ async deleteExperimentResults(args) {
4075
+ try {
4076
+ await this.#client.execute({
4077
+ sql: `DELETE FROM ${TABLE_EXPERIMENT_RESULTS} WHERE experimentId = ?`,
4078
+ args: [args.experimentId]
4079
+ });
4080
+ } catch (error) {
4081
+ throw new MastraError(
4082
+ {
4083
+ id: createStorageErrorId("LIBSQL", "DELETE_EXPERIMENT_RESULTS", "FAILED"),
4084
+ domain: ErrorDomain.STORAGE,
4085
+ category: ErrorCategory.THIRD_PARTY
4086
+ },
4087
+ error
4088
+ );
4089
+ }
4090
+ }
4091
+ };
4092
+ var SNAPSHOT_FIELDS2 = ["name", "description", "servers"];
4093
+ var MCPClientsLibSQL = class extends MCPClientsStorage {
4094
+ #db;
4095
+ #client;
4096
+ constructor(config) {
4097
+ super();
4098
+ const client = resolveClient(config);
4099
+ this.#client = client;
4100
+ this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
4101
+ }
4102
+ async init() {
4103
+ await this.#db.createTable({ tableName: TABLE_MCP_CLIENTS, schema: MCP_CLIENTS_SCHEMA });
4104
+ await this.#db.createTable({
4105
+ tableName: TABLE_MCP_CLIENT_VERSIONS,
4106
+ schema: MCP_CLIENT_VERSIONS_SCHEMA
4107
+ });
4108
+ await this.#client.execute(
4109
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_mcp_client_versions_client_version ON "${TABLE_MCP_CLIENT_VERSIONS}" ("mcpClientId", "versionNumber")`
4110
+ );
4111
+ }
4112
+ async dangerouslyClearAll() {
4113
+ await this.#db.deleteData({ tableName: TABLE_MCP_CLIENTS });
4114
+ await this.#db.deleteData({ tableName: TABLE_MCP_CLIENT_VERSIONS });
4115
+ }
4116
+ // ==========================================================================
4117
+ // MCP Client CRUD
4118
+ // ==========================================================================
4119
+ async getById(id) {
4120
+ try {
4121
+ const result = await this.#client.execute({
4122
+ sql: `SELECT ${buildSelectColumns(TABLE_MCP_CLIENTS)} FROM "${TABLE_MCP_CLIENTS}" WHERE id = ?`,
4123
+ args: [id]
4124
+ });
4125
+ const row = result.rows?.[0];
4126
+ return row ? this.#parseMCPClientRow(row) : null;
4127
+ } catch (error) {
4128
+ if (error instanceof MastraError) throw error;
4129
+ throw new MastraError(
4130
+ {
4131
+ id: createStorageErrorId("LIBSQL", "GET_MCP_CLIENT", "FAILED"),
4132
+ domain: ErrorDomain.STORAGE,
4133
+ category: ErrorCategory.THIRD_PARTY
4134
+ },
4135
+ error
4136
+ );
4137
+ }
4138
+ }
4139
+ async create(input) {
4140
+ const { mcpClient } = input;
4141
+ try {
4142
+ const now = /* @__PURE__ */ new Date();
4143
+ await this.#db.insert({
4144
+ tableName: TABLE_MCP_CLIENTS,
4145
+ record: {
4146
+ id: mcpClient.id,
4147
+ status: "draft",
4148
+ activeVersionId: null,
4149
+ authorId: mcpClient.authorId ?? null,
4150
+ metadata: mcpClient.metadata ?? null,
4151
+ createdAt: now.toISOString(),
4152
+ updatedAt: now.toISOString()
4153
+ }
4154
+ });
4155
+ const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = mcpClient;
4156
+ const versionId = crypto.randomUUID();
4157
+ try {
4158
+ await this.createVersion({
4159
+ id: versionId,
4160
+ mcpClientId: mcpClient.id,
4161
+ versionNumber: 1,
4162
+ ...snapshotConfig,
4163
+ changedFields: Object.keys(snapshotConfig),
4164
+ changeMessage: "Initial version"
4165
+ });
4166
+ } catch (versionError) {
4167
+ await this.#db.delete({ tableName: TABLE_MCP_CLIENTS, keys: { id: mcpClient.id } });
4168
+ throw versionError;
4169
+ }
4170
+ return {
4171
+ id: mcpClient.id,
4172
+ status: "draft",
4173
+ activeVersionId: void 0,
4174
+ authorId: mcpClient.authorId,
4175
+ metadata: mcpClient.metadata,
4176
+ createdAt: now,
4177
+ updatedAt: now
4178
+ };
4179
+ } catch (error) {
4180
+ if (error instanceof MastraError) throw error;
4181
+ throw new MastraError(
4182
+ {
4183
+ id: createStorageErrorId("LIBSQL", "CREATE_MCP_CLIENT", "FAILED"),
4184
+ domain: ErrorDomain.STORAGE,
4185
+ category: ErrorCategory.THIRD_PARTY
4186
+ },
4187
+ error
4188
+ );
4189
+ }
4190
+ }
4191
+ async update(input) {
4192
+ const { id, ...updates } = input;
4193
+ try {
4194
+ const existing = await this.getById(id);
4195
+ if (!existing) {
4196
+ throw new Error(`MCP client with id ${id} not found`);
4197
+ }
4198
+ const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
4199
+ const configFieldNames = SNAPSHOT_FIELDS2;
4200
+ const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
4201
+ const updateData = {
4202
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4203
+ };
4204
+ if (authorId !== void 0) updateData.authorId = authorId;
4205
+ if (activeVersionId !== void 0) {
4206
+ updateData.activeVersionId = activeVersionId;
4207
+ if (status === void 0) {
4208
+ updateData.status = "published";
4209
+ }
4210
+ }
4211
+ if (status !== void 0) updateData.status = status;
4212
+ if (metadata !== void 0) {
4213
+ updateData.metadata = { ...existing.metadata, ...metadata };
4214
+ }
4215
+ await this.#db.update({
4216
+ tableName: TABLE_MCP_CLIENTS,
4217
+ keys: { id },
4218
+ data: updateData
4219
+ });
4220
+ if (hasConfigUpdate) {
4221
+ const latestVersion = await this.getLatestVersion(id);
4222
+ if (!latestVersion) {
4223
+ throw new Error(`No versions found for MCP client ${id}`);
4224
+ }
4225
+ const {
4226
+ id: _versionId,
4227
+ mcpClientId: _mcpClientId,
4228
+ versionNumber: _versionNumber,
4229
+ changedFields: _changedFields,
4230
+ changeMessage: _changeMessage,
4231
+ createdAt: _createdAt,
4232
+ ...latestConfig
4233
+ } = latestVersion;
4234
+ const newConfig = { ...latestConfig, ...configFields };
4235
+ const changedFields = configFieldNames.filter(
4236
+ (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
4237
+ );
4238
+ if (changedFields.length > 0) {
4239
+ const newVersionId = crypto.randomUUID();
4240
+ await this.createVersion({
4241
+ id: newVersionId,
4242
+ mcpClientId: id,
4243
+ versionNumber: latestVersion.versionNumber + 1,
4244
+ ...newConfig,
4245
+ changedFields,
4246
+ changeMessage: `Updated ${changedFields.join(", ")}`
4247
+ });
4248
+ }
4249
+ }
4250
+ const updated = await this.getById(id);
4251
+ if (!updated) {
4252
+ throw new MastraError({
4253
+ id: createStorageErrorId("LIBSQL", "UPDATE_MCP_CLIENT", "NOT_FOUND_AFTER_UPDATE"),
4254
+ domain: ErrorDomain.STORAGE,
4255
+ category: ErrorCategory.SYSTEM,
4256
+ text: `MCP client ${id} not found after update`,
4257
+ details: { id }
4258
+ });
4259
+ }
4260
+ return updated;
4261
+ } catch (error) {
4262
+ if (error instanceof MastraError) throw error;
4263
+ throw new MastraError(
4264
+ {
4265
+ id: createStorageErrorId("LIBSQL", "UPDATE_MCP_CLIENT", "FAILED"),
4266
+ domain: ErrorDomain.STORAGE,
4267
+ category: ErrorCategory.THIRD_PARTY
4268
+ },
4269
+ error
4270
+ );
4271
+ }
4272
+ }
4273
+ async delete(id) {
4274
+ try {
4275
+ await this.deleteVersionsByParentId(id);
4276
+ await this.#client.execute({
4277
+ sql: `DELETE FROM "${TABLE_MCP_CLIENTS}" WHERE "id" = ?`,
4278
+ args: [id]
4279
+ });
4280
+ } catch (error) {
4281
+ if (error instanceof MastraError) throw error;
4282
+ throw new MastraError(
4283
+ {
4284
+ id: createStorageErrorId("LIBSQL", "DELETE_MCP_CLIENT", "FAILED"),
4285
+ domain: ErrorDomain.STORAGE,
4286
+ category: ErrorCategory.THIRD_PARTY
4287
+ },
4288
+ error
4289
+ );
4290
+ }
4291
+ }
4292
+ async list(args) {
4293
+ try {
4294
+ const { page = 0, perPage: perPageInput, orderBy, authorId, metadata } = args || {};
4295
+ const { field, direction } = this.parseOrderBy(orderBy);
4296
+ const conditions = [];
4297
+ const queryParams = [];
4298
+ if (authorId !== void 0) {
4299
+ conditions.push("authorId = ?");
4300
+ queryParams.push(authorId);
4301
+ }
4302
+ if (metadata && Object.keys(metadata).length > 0) {
4303
+ for (const [key, value] of Object.entries(metadata)) {
4304
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
4305
+ throw new MastraError({
4306
+ id: createStorageErrorId("LIBSQL", "LIST_MCP_CLIENTS", "INVALID_METADATA_KEY"),
4307
+ domain: ErrorDomain.STORAGE,
4308
+ category: ErrorCategory.USER,
4309
+ text: `Invalid metadata key: ${key}. Keys must be alphanumeric with underscores.`,
4310
+ details: { key }
4311
+ });
4312
+ }
4313
+ conditions.push(`json_extract(metadata, '$.${key}') = ?`);
4314
+ queryParams.push(typeof value === "string" ? value : JSON.stringify(value));
4315
+ }
4316
+ }
4317
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4318
+ const countResult = await this.#client.execute({
4319
+ sql: `SELECT COUNT(*) as count FROM "${TABLE_MCP_CLIENTS}" ${whereClause}`,
4320
+ args: queryParams
4321
+ });
4322
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
4323
+ if (total === 0) {
4324
+ return {
4325
+ mcpClients: [],
2487
4326
  total: 0,
2488
4327
  page,
2489
- perPage: perPageForResponse,
4328
+ perPage: perPageInput ?? 100,
2490
4329
  hasMore: false
2491
4330
  };
2492
4331
  }
4332
+ const perPage = normalizePerPage(perPageInput, 100);
4333
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
2493
4334
  const limitValue = perPageInput === false ? total : perPage;
2494
- const rows = await this.#db.selectMany({
2495
- tableName: TABLE_AGENTS,
2496
- orderBy: `"${field}" ${direction}`,
2497
- limit: limitValue,
2498
- offset
4335
+ const end = perPageInput === false ? total : start + perPage;
4336
+ const result = await this.#client.execute({
4337
+ sql: `SELECT ${buildSelectColumns(TABLE_MCP_CLIENTS)} FROM "${TABLE_MCP_CLIENTS}" ${whereClause} ORDER BY ${field} ${direction} LIMIT ? OFFSET ?`,
4338
+ args: [...queryParams, limitValue, start]
2499
4339
  });
2500
- const agents = rows.map((row) => this.parseRow(row));
4340
+ const mcpClients = result.rows?.map((row) => this.#parseMCPClientRow(row)) ?? [];
2501
4341
  return {
2502
- agents,
4342
+ mcpClients,
2503
4343
  total,
2504
4344
  page,
2505
4345
  perPage: perPageForResponse,
2506
- hasMore: perPageInput === false ? false : offset + perPage < total
4346
+ hasMore: end < total
2507
4347
  };
2508
4348
  } catch (error) {
2509
4349
  if (error instanceof MastraError) throw error;
2510
4350
  throw new MastraError(
2511
4351
  {
2512
- id: createStorageErrorId("LIBSQL", "LIST_AGENTS", "FAILED"),
4352
+ id: createStorageErrorId("LIBSQL", "LIST_MCP_CLIENTS", "FAILED"),
2513
4353
  domain: ErrorDomain.STORAGE,
2514
4354
  category: ErrorCategory.THIRD_PARTY
2515
4355
  },
@@ -2518,33 +4358,23 @@ var AgentsLibSQL = class extends AgentsStorage {
2518
4358
  }
2519
4359
  }
2520
4360
  // ==========================================================================
2521
- // Agent Version Methods
4361
+ // MCP Client Version Methods
2522
4362
  // ==========================================================================
2523
4363
  async createVersion(input) {
2524
4364
  try {
2525
4365
  const now = /* @__PURE__ */ new Date();
2526
4366
  await this.#db.insert({
2527
- tableName: TABLE_AGENT_VERSIONS,
4367
+ tableName: TABLE_MCP_CLIENT_VERSIONS,
2528
4368
  record: {
2529
4369
  id: input.id,
2530
- agentId: input.agentId,
4370
+ mcpClientId: input.mcpClientId,
2531
4371
  versionNumber: input.versionNumber,
2532
- name: input.name ?? null,
4372
+ name: input.name,
2533
4373
  description: input.description ?? null,
2534
- instructions: this.serializeInstructions(input.instructions),
2535
- model: input.model,
2536
- tools: input.tools ?? null,
2537
- defaultOptions: input.defaultOptions ?? null,
2538
- workflows: input.workflows ?? null,
2539
- agents: input.agents ?? null,
2540
- integrationTools: input.integrationTools ?? null,
2541
- inputProcessors: input.inputProcessors ?? null,
2542
- outputProcessors: input.outputProcessors ?? null,
2543
- memory: input.memory ?? null,
2544
- scorers: input.scorers ?? null,
4374
+ servers: input.servers ?? null,
2545
4375
  changedFields: input.changedFields ?? null,
2546
4376
  changeMessage: input.changeMessage ?? null,
2547
- createdAt: now
4377
+ createdAt: now.toISOString()
2548
4378
  }
2549
4379
  });
2550
4380
  return {
@@ -2555,10 +4385,9 @@ var AgentsLibSQL = class extends AgentsStorage {
2555
4385
  if (error instanceof MastraError) throw error;
2556
4386
  throw new MastraError(
2557
4387
  {
2558
- id: createStorageErrorId("LIBSQL", "CREATE_VERSION", "FAILED"),
4388
+ id: createStorageErrorId("LIBSQL", "CREATE_MCP_CLIENT_VERSION", "FAILED"),
2559
4389
  domain: ErrorDomain.STORAGE,
2560
- category: ErrorCategory.THIRD_PARTY,
2561
- details: { versionId: input.id, agentId: input.agentId }
4390
+ category: ErrorCategory.THIRD_PARTY
2562
4391
  },
2563
4392
  error
2564
4393
  );
@@ -2566,142 +4395,105 @@ var AgentsLibSQL = class extends AgentsStorage {
2566
4395
  }
2567
4396
  async getVersion(id) {
2568
4397
  try {
2569
- const result = await this.#db.select({
2570
- tableName: TABLE_AGENT_VERSIONS,
2571
- keys: { id }
4398
+ const result = await this.#client.execute({
4399
+ sql: `SELECT ${buildSelectColumns(TABLE_MCP_CLIENT_VERSIONS)} FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE id = ?`,
4400
+ args: [id]
2572
4401
  });
2573
- if (!result) {
2574
- return null;
2575
- }
2576
- return this.parseVersionRow(result);
4402
+ const row = result.rows?.[0];
4403
+ return row ? this.#parseVersionRow(row) : null;
2577
4404
  } catch (error) {
2578
4405
  if (error instanceof MastraError) throw error;
2579
4406
  throw new MastraError(
2580
4407
  {
2581
- id: createStorageErrorId("LIBSQL", "GET_VERSION", "FAILED"),
4408
+ id: createStorageErrorId("LIBSQL", "GET_MCP_CLIENT_VERSION", "FAILED"),
2582
4409
  domain: ErrorDomain.STORAGE,
2583
- category: ErrorCategory.THIRD_PARTY,
2584
- details: { versionId: id }
4410
+ category: ErrorCategory.THIRD_PARTY
2585
4411
  },
2586
4412
  error
2587
4413
  );
2588
4414
  }
2589
4415
  }
2590
- async getVersionByNumber(agentId, versionNumber) {
4416
+ async getVersionByNumber(mcpClientId, versionNumber) {
2591
4417
  try {
2592
- const rows = await this.#db.selectMany({
2593
- tableName: TABLE_AGENT_VERSIONS,
2594
- whereClause: {
2595
- sql: "WHERE agentId = ? AND versionNumber = ?",
2596
- args: [agentId, versionNumber]
2597
- },
2598
- limit: 1
4418
+ const result = await this.#client.execute({
4419
+ sql: `SELECT ${buildSelectColumns(TABLE_MCP_CLIENT_VERSIONS)} FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE mcpClientId = ? AND versionNumber = ?`,
4420
+ args: [mcpClientId, versionNumber]
2599
4421
  });
2600
- if (!rows || rows.length === 0) {
2601
- return null;
2602
- }
2603
- return this.parseVersionRow(rows[0]);
4422
+ const row = result.rows?.[0];
4423
+ return row ? this.#parseVersionRow(row) : null;
2604
4424
  } catch (error) {
2605
4425
  if (error instanceof MastraError) throw error;
2606
4426
  throw new MastraError(
2607
4427
  {
2608
- id: createStorageErrorId("LIBSQL", "GET_VERSION_BY_NUMBER", "FAILED"),
4428
+ id: createStorageErrorId("LIBSQL", "GET_MCP_CLIENT_VERSION_BY_NUMBER", "FAILED"),
2609
4429
  domain: ErrorDomain.STORAGE,
2610
- category: ErrorCategory.THIRD_PARTY,
2611
- details: { agentId, versionNumber }
4430
+ category: ErrorCategory.THIRD_PARTY
2612
4431
  },
2613
4432
  error
2614
4433
  );
2615
4434
  }
2616
4435
  }
2617
- async getLatestVersion(agentId) {
4436
+ async getLatestVersion(mcpClientId) {
2618
4437
  try {
2619
- const rows = await this.#db.selectMany({
2620
- tableName: TABLE_AGENT_VERSIONS,
2621
- whereClause: {
2622
- sql: "WHERE agentId = ?",
2623
- args: [agentId]
2624
- },
2625
- orderBy: "versionNumber DESC",
2626
- limit: 1
4438
+ const result = await this.#client.execute({
4439
+ sql: `SELECT ${buildSelectColumns(TABLE_MCP_CLIENT_VERSIONS)} FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE mcpClientId = ? ORDER BY versionNumber DESC LIMIT 1`,
4440
+ args: [mcpClientId]
2627
4441
  });
2628
- if (!rows || rows.length === 0) {
2629
- return null;
2630
- }
2631
- return this.parseVersionRow(rows[0]);
4442
+ const row = result.rows?.[0];
4443
+ return row ? this.#parseVersionRow(row) : null;
2632
4444
  } catch (error) {
2633
4445
  if (error instanceof MastraError) throw error;
2634
4446
  throw new MastraError(
2635
4447
  {
2636
- id: createStorageErrorId("LIBSQL", "GET_LATEST_VERSION", "FAILED"),
4448
+ id: createStorageErrorId("LIBSQL", "GET_LATEST_MCP_CLIENT_VERSION", "FAILED"),
2637
4449
  domain: ErrorDomain.STORAGE,
2638
- category: ErrorCategory.THIRD_PARTY,
2639
- details: { agentId }
4450
+ category: ErrorCategory.THIRD_PARTY
2640
4451
  },
2641
4452
  error
2642
4453
  );
2643
4454
  }
2644
4455
  }
2645
4456
  async listVersions(input) {
2646
- const { agentId, page = 0, perPage: perPageInput, orderBy } = input;
2647
- if (page < 0) {
2648
- throw new MastraError(
2649
- {
2650
- id: createStorageErrorId("LIBSQL", "LIST_VERSIONS", "INVALID_PAGE"),
2651
- domain: ErrorDomain.STORAGE,
2652
- category: ErrorCategory.USER,
2653
- details: { page }
2654
- },
2655
- new Error("page must be >= 0")
2656
- );
2657
- }
2658
- const perPage = normalizePerPage(perPageInput, 20);
2659
- const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
2660
4457
  try {
4458
+ const { mcpClientId, page = 0, perPage: perPageInput, orderBy } = input;
2661
4459
  const { field, direction } = this.parseVersionOrderBy(orderBy);
2662
- const total = await this.#db.selectTotalCount({
2663
- tableName: TABLE_AGENT_VERSIONS,
2664
- whereClause: {
2665
- sql: "WHERE agentId = ?",
2666
- args: [agentId]
2667
- }
4460
+ const countResult = await this.#client.execute({
4461
+ sql: `SELECT COUNT(*) as count FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE mcpClientId = ?`,
4462
+ args: [mcpClientId]
2668
4463
  });
4464
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
2669
4465
  if (total === 0) {
2670
4466
  return {
2671
4467
  versions: [],
2672
4468
  total: 0,
2673
4469
  page,
2674
- perPage: perPageForResponse,
4470
+ perPage: perPageInput ?? 20,
2675
4471
  hasMore: false
2676
4472
  };
2677
4473
  }
4474
+ const perPage = normalizePerPage(perPageInput, 20);
4475
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
2678
4476
  const limitValue = perPageInput === false ? total : perPage;
2679
- const rows = await this.#db.selectMany({
2680
- tableName: TABLE_AGENT_VERSIONS,
2681
- whereClause: {
2682
- sql: "WHERE agentId = ?",
2683
- args: [agentId]
2684
- },
2685
- orderBy: `"${field}" ${direction}`,
2686
- limit: limitValue,
2687
- offset
4477
+ const end = perPageInput === false ? total : start + perPage;
4478
+ const result = await this.#client.execute({
4479
+ sql: `SELECT ${buildSelectColumns(TABLE_MCP_CLIENT_VERSIONS)} FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE mcpClientId = ? ORDER BY ${field} ${direction} LIMIT ? OFFSET ?`,
4480
+ args: [mcpClientId, limitValue, start]
2688
4481
  });
2689
- const versions = rows.map((row) => this.parseVersionRow(row));
4482
+ const versions = result.rows?.map((row) => this.#parseVersionRow(row)) ?? [];
2690
4483
  return {
2691
4484
  versions,
2692
4485
  total,
2693
4486
  page,
2694
4487
  perPage: perPageForResponse,
2695
- hasMore: perPageInput === false ? false : offset + perPage < total
4488
+ hasMore: end < total
2696
4489
  };
2697
4490
  } catch (error) {
2698
4491
  if (error instanceof MastraError) throw error;
2699
4492
  throw new MastraError(
2700
4493
  {
2701
- id: createStorageErrorId("LIBSQL", "LIST_VERSIONS", "FAILED"),
4494
+ id: createStorageErrorId("LIBSQL", "LIST_MCP_CLIENT_VERSIONS", "FAILED"),
2702
4495
  domain: ErrorDomain.STORAGE,
2703
- category: ErrorCategory.THIRD_PARTY,
2704
- details: { agentId }
4496
+ category: ErrorCategory.THIRD_PARTY
2705
4497
  },
2706
4498
  error
2707
4499
  );
@@ -2709,18 +4501,17 @@ var AgentsLibSQL = class extends AgentsStorage {
2709
4501
  }
2710
4502
  async deleteVersion(id) {
2711
4503
  try {
2712
- await this.#db.delete({
2713
- tableName: TABLE_AGENT_VERSIONS,
2714
- keys: { id }
4504
+ await this.#client.execute({
4505
+ sql: `DELETE FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE "id" = ?`,
4506
+ args: [id]
2715
4507
  });
2716
4508
  } catch (error) {
2717
4509
  if (error instanceof MastraError) throw error;
2718
4510
  throw new MastraError(
2719
4511
  {
2720
- id: createStorageErrorId("LIBSQL", "DELETE_VERSION", "FAILED"),
4512
+ id: createStorageErrorId("LIBSQL", "DELETE_MCP_CLIENT_VERSION", "FAILED"),
2721
4513
  domain: ErrorDomain.STORAGE,
2722
- category: ErrorCategory.THIRD_PARTY,
2723
- details: { versionId: id }
4514
+ category: ErrorCategory.THIRD_PARTY
2724
4515
  },
2725
4516
  error
2726
4517
  );
@@ -2728,90 +4519,87 @@ var AgentsLibSQL = class extends AgentsStorage {
2728
4519
  }
2729
4520
  async deleteVersionsByParentId(entityId) {
2730
4521
  try {
2731
- const versions = await this.#db.selectMany({
2732
- tableName: TABLE_AGENT_VERSIONS,
2733
- whereClause: {
2734
- sql: "WHERE agentId = ?",
2735
- args: [entityId]
2736
- }
4522
+ await this.#client.execute({
4523
+ sql: `DELETE FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE "mcpClientId" = ?`,
4524
+ args: [entityId]
2737
4525
  });
2738
- for (const version of versions) {
2739
- await this.#db.delete({
2740
- tableName: TABLE_AGENT_VERSIONS,
2741
- keys: { id: version.id }
2742
- });
2743
- }
2744
4526
  } catch (error) {
2745
4527
  if (error instanceof MastraError) throw error;
2746
4528
  throw new MastraError(
2747
4529
  {
2748
- id: createStorageErrorId("LIBSQL", "DELETE_VERSIONS_BY_AGENT_ID", "FAILED"),
4530
+ id: createStorageErrorId("LIBSQL", "DELETE_MCP_CLIENT_VERSIONS_BY_CLIENT", "FAILED"),
2749
4531
  domain: ErrorDomain.STORAGE,
2750
- category: ErrorCategory.THIRD_PARTY,
2751
- details: { agentId: entityId }
4532
+ category: ErrorCategory.THIRD_PARTY
2752
4533
  },
2753
4534
  error
2754
4535
  );
2755
4536
  }
2756
4537
  }
2757
- async countVersions(agentId) {
4538
+ async countVersions(mcpClientId) {
2758
4539
  try {
2759
- const count = await this.#db.selectTotalCount({
2760
- tableName: TABLE_AGENT_VERSIONS,
2761
- whereClause: {
2762
- sql: "WHERE agentId = ?",
2763
- args: [agentId]
2764
- }
4540
+ const result = await this.#client.execute({
4541
+ sql: `SELECT COUNT(*) as count FROM "${TABLE_MCP_CLIENT_VERSIONS}" WHERE mcpClientId = ?`,
4542
+ args: [mcpClientId]
2765
4543
  });
2766
- return count;
4544
+ return Number(result.rows?.[0]?.count ?? 0);
2767
4545
  } catch (error) {
2768
4546
  if (error instanceof MastraError) throw error;
2769
4547
  throw new MastraError(
2770
4548
  {
2771
- id: createStorageErrorId("LIBSQL", "COUNT_VERSIONS", "FAILED"),
4549
+ id: createStorageErrorId("LIBSQL", "COUNT_MCP_CLIENT_VERSIONS", "FAILED"),
2772
4550
  domain: ErrorDomain.STORAGE,
2773
- category: ErrorCategory.THIRD_PARTY,
2774
- details: { agentId }
4551
+ category: ErrorCategory.THIRD_PARTY
2775
4552
  },
2776
4553
  error
2777
4554
  );
2778
4555
  }
2779
4556
  }
2780
4557
  // ==========================================================================
2781
- // Private Helper Methods
4558
+ // Private Helpers
2782
4559
  // ==========================================================================
2783
- serializeInstructions(instructions) {
2784
- return Array.isArray(instructions) ? JSON.stringify(instructions) : instructions;
2785
- }
2786
- deserializeInstructions(raw) {
2787
- if (!raw) return raw;
2788
- try {
2789
- const parsed = JSON.parse(raw);
2790
- if (Array.isArray(parsed)) return parsed;
2791
- } catch {
2792
- }
2793
- return raw;
4560
+ #parseMCPClientRow(row) {
4561
+ const safeParseJSON = (val) => {
4562
+ if (val === null || val === void 0) return void 0;
4563
+ if (typeof val === "string") {
4564
+ try {
4565
+ return JSON.parse(val);
4566
+ } catch {
4567
+ return val;
4568
+ }
4569
+ }
4570
+ return val;
4571
+ };
4572
+ return {
4573
+ id: row.id,
4574
+ status: row.status ?? "draft",
4575
+ activeVersionId: row.activeVersionId ?? void 0,
4576
+ authorId: row.authorId ?? void 0,
4577
+ metadata: safeParseJSON(row.metadata),
4578
+ createdAt: new Date(row.createdAt),
4579
+ updatedAt: new Date(row.updatedAt)
4580
+ };
2794
4581
  }
2795
- parseVersionRow(row) {
4582
+ #parseVersionRow(row) {
4583
+ const safeParseJSON = (val) => {
4584
+ if (val === null || val === void 0) return void 0;
4585
+ if (typeof val === "string") {
4586
+ try {
4587
+ return JSON.parse(val);
4588
+ } catch {
4589
+ return val;
4590
+ }
4591
+ }
4592
+ return val;
4593
+ };
2796
4594
  return {
2797
4595
  id: row.id,
2798
- agentId: row.agentId,
2799
- versionNumber: row.versionNumber,
4596
+ mcpClientId: row.mcpClientId,
4597
+ versionNumber: Number(row.versionNumber),
2800
4598
  name: row.name,
2801
- description: row.description,
2802
- instructions: this.deserializeInstructions(row.instructions),
2803
- model: this.parseJson(row.model, "model"),
2804
- tools: this.parseJson(row.tools, "tools"),
2805
- defaultOptions: this.parseJson(row.defaultOptions, "defaultOptions"),
2806
- workflows: this.parseJson(row.workflows, "workflows"),
2807
- agents: this.parseJson(row.agents, "agents"),
2808
- integrationTools: this.parseJson(row.integrationTools, "integrationTools"),
2809
- inputProcessors: this.parseJson(row.inputProcessors, "inputProcessors"),
2810
- outputProcessors: this.parseJson(row.outputProcessors, "outputProcessors"),
2811
- memory: this.parseJson(row.memory, "memory"),
2812
- scorers: this.parseJson(row.scorers, "scorers"),
2813
- changedFields: this.parseJson(row.changedFields, "changedFields"),
2814
- changeMessage: row.changeMessage,
4599
+ description: row.description ?? void 0,
4600
+ servers: safeParseJSON(row.servers),
4601
+ changedFields: safeParseJSON(row.changedFields),
4602
+ changeMessage: row.changeMessage ?? void 0,
2815
4603
  createdAt: new Date(row.createdAt)
2816
4604
  };
2817
4605
  }
@@ -5142,7 +6930,7 @@ var ObservabilityLibSQL = class extends ObservabilityStorage {
5142
6930
  }
5143
6931
  }
5144
6932
  };
5145
- var SNAPSHOT_FIELDS2 = ["name", "description", "content", "rules"];
6933
+ var SNAPSHOT_FIELDS3 = ["name", "description", "content", "rules"];
5146
6934
  var PromptBlocksLibSQL = class extends PromptBlocksStorage {
5147
6935
  #db;
5148
6936
  #client;
@@ -5241,7 +7029,7 @@ var PromptBlocksLibSQL = class extends PromptBlocksStorage {
5241
7029
  throw new Error(`Prompt block with id ${id} not found`);
5242
7030
  }
5243
7031
  const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
5244
- const configFieldNames = SNAPSHOT_FIELDS2;
7032
+ const configFieldNames = SNAPSHOT_FIELDS3;
5245
7033
  const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
5246
7034
  const updateData = {
5247
7035
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -5649,7 +7437,7 @@ var PromptBlocksLibSQL = class extends PromptBlocksStorage {
5649
7437
  };
5650
7438
  }
5651
7439
  };
5652
- var SNAPSHOT_FIELDS3 = [
7440
+ var SNAPSHOT_FIELDS4 = [
5653
7441
  "name",
5654
7442
  "description",
5655
7443
  "type",
@@ -5760,7 +7548,7 @@ var ScorerDefinitionsLibSQL = class extends ScorerDefinitionsStorage {
5760
7548
  throw new Error(`Scorer definition with id ${id} not found`);
5761
7549
  }
5762
7550
  const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
5763
- const configFieldNames = SNAPSHOT_FIELDS3;
7551
+ const configFieldNames = SNAPSHOT_FIELDS4;
5764
7552
  const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
5765
7553
  const updateData = {
5766
7554
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -6828,16 +8616,22 @@ var LibSQLStore = class extends MastraCompositeStore {
6828
8616
  const memory = new MemoryLibSQL(domainConfig);
6829
8617
  const observability = new ObservabilityLibSQL(domainConfig);
6830
8618
  const agents = new AgentsLibSQL(domainConfig);
8619
+ const datasets = new DatasetsLibSQL(domainConfig);
8620
+ const experiments = new ExperimentsLibSQL(domainConfig);
6831
8621
  const promptBlocks = new PromptBlocksLibSQL(domainConfig);
6832
8622
  const scorerDefinitions = new ScorerDefinitionsLibSQL(domainConfig);
8623
+ const mcpClients = new MCPClientsLibSQL(domainConfig);
6833
8624
  this.stores = {
6834
8625
  scores,
6835
8626
  workflows,
6836
8627
  memory,
6837
8628
  observability,
6838
8629
  agents,
8630
+ datasets,
8631
+ experiments,
6839
8632
  promptBlocks,
6840
- scorerDefinitions
8633
+ scorerDefinitions,
8634
+ mcpClients
6841
8635
  };
6842
8636
  }
6843
8637
  };
@@ -6941,6 +8735,6 @@ Example Complex Query:
6941
8735
  ]
6942
8736
  }`;
6943
8737
 
6944
- export { AgentsLibSQL, LibSQLStore as DefaultStorage, LIBSQL_PROMPT, LibSQLStore, LibSQLVector, MemoryLibSQL, ObservabilityLibSQL, PromptBlocksLibSQL, ScorerDefinitionsLibSQL, ScoresLibSQL, WorkflowsLibSQL };
8738
+ export { AgentsLibSQL, DatasetsLibSQL, LibSQLStore as DefaultStorage, ExperimentsLibSQL, LIBSQL_PROMPT, LibSQLStore, LibSQLVector, MCPClientsLibSQL, MemoryLibSQL, ObservabilityLibSQL, PromptBlocksLibSQL, ScorerDefinitionsLibSQL, ScoresLibSQL, WorkflowsLibSQL };
6945
8739
  //# sourceMappingURL=index.js.map
6946
8740
  //# sourceMappingURL=index.js.map