@mastra/pg 1.0.0-beta.6 → 1.0.0-beta.8

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
@@ -480,12 +480,14 @@ var PgVector = class extends MastraVector {
480
480
  pool;
481
481
  describeIndexCache = /* @__PURE__ */ new Map();
482
482
  createdIndexes = /* @__PURE__ */ new Map();
483
+ indexVectorTypes = /* @__PURE__ */ new Map();
483
484
  mutexesByName = /* @__PURE__ */ new Map();
484
485
  schema;
485
486
  setupSchemaPromise = null;
486
487
  installVectorExtensionPromise = null;
487
488
  vectorExtensionInstalled = void 0;
488
489
  vectorExtensionSchema = null;
490
+ vectorExtensionVersion = null;
489
491
  schemaSetupComplete = void 0;
490
492
  cacheWarmupPromise = null;
491
493
  constructor(config) {
@@ -538,9 +540,11 @@ var PgVector = class extends MastraVector {
538
540
  indexName,
539
541
  metric: info.metric,
540
542
  dimension: info.dimension,
541
- type: info.type
543
+ type: info.type,
544
+ vectorType: info.vectorType
542
545
  });
543
546
  this.createdIndexes.set(indexName, key);
547
+ this.indexVectorTypes.set(indexName, info.vectorType);
544
548
  })
545
549
  );
546
550
  } catch (error) {
@@ -566,12 +570,12 @@ var PgVector = class extends MastraVector {
566
570
  return this.mutexesByName.get(indexName);
567
571
  }
568
572
  /**
569
- * Detects which schema contains the vector extension
573
+ * Detects which schema contains the vector extension and its version
570
574
  */
571
575
  async detectVectorExtensionSchema(client) {
572
576
  try {
573
577
  const result = await client.query(`
574
- SELECT n.nspname as schema_name
578
+ SELECT n.nspname as schema_name, e.extversion as version
575
579
  FROM pg_extension e
576
580
  JOIN pg_namespace n ON e.extnamespace = n.oid
577
581
  WHERE e.extname = 'vector'
@@ -579,7 +583,11 @@ var PgVector = class extends MastraVector {
579
583
  `);
580
584
  if (result.rows.length > 0) {
581
585
  this.vectorExtensionSchema = result.rows[0].schema_name;
582
- this.logger.debug("Vector extension found in schema", { schema: this.vectorExtensionSchema });
586
+ this.vectorExtensionVersion = result.rows[0].version;
587
+ this.logger.debug("Vector extension found", {
588
+ schema: this.vectorExtensionSchema,
589
+ version: this.vectorExtensionVersion
590
+ });
583
591
  return this.vectorExtensionSchema;
584
592
  }
585
593
  return null;
@@ -588,18 +596,52 @@ var PgVector = class extends MastraVector {
588
596
  return null;
589
597
  }
590
598
  }
599
+ /**
600
+ * Checks if the installed pgvector version supports halfvec type.
601
+ * halfvec was introduced in pgvector 0.7.0.
602
+ */
603
+ supportsHalfvec() {
604
+ if (!this.vectorExtensionVersion) {
605
+ return false;
606
+ }
607
+ const parts = this.vectorExtensionVersion.split(".");
608
+ const major = parseInt(parts[0] ?? "", 10);
609
+ const minor = parseInt(parts[1] ?? "", 10);
610
+ if (isNaN(major) || isNaN(minor)) {
611
+ return false;
612
+ }
613
+ return major > 0 || major === 0 && minor >= 7;
614
+ }
591
615
  /**
592
616
  * Gets the properly qualified vector type name
617
+ * @param vectorType - The type of vector storage ('vector' or 'halfvec')
593
618
  */
594
- getVectorTypeName() {
619
+ getVectorTypeName(vectorType = "vector") {
595
620
  if (this.vectorExtensionSchema) {
596
621
  if (this.vectorExtensionSchema === "pg_catalog") {
597
- return "vector";
622
+ return vectorType;
598
623
  }
599
624
  const validatedSchema = parseSqlIdentifier(this.vectorExtensionSchema, "vector extension schema");
600
- return `${validatedSchema}.vector`;
625
+ return `${validatedSchema}.${vectorType}`;
626
+ }
627
+ return vectorType;
628
+ }
629
+ /**
630
+ * Gets the operator class for index creation based on metric and vector type.
631
+ * pgvector uses different operator classes for vector vs halfvec types.
632
+ */
633
+ getMetricOperatorClass(metric, vectorType) {
634
+ const prefix = vectorType === "halfvec" ? "halfvec" : "vector";
635
+ switch (metric) {
636
+ case "cosine":
637
+ return `${prefix}_cosine_ops`;
638
+ case "euclidean":
639
+ return `${prefix}_l2_ops`;
640
+ case "dotproduct":
641
+ return `${prefix}_ip_ops`;
642
+ default:
643
+ return `${prefix}_cosine_ops`;
601
644
  }
602
- return "vector";
603
645
  }
604
646
  getTableName(indexName) {
605
647
  const parsedIndexName = parseSqlIdentifier(indexName, "index name");
@@ -672,12 +714,12 @@ var PgVector = class extends MastraVector {
672
714
  await client.query(`SET LOCAL ivfflat.probes = ${probes}`);
673
715
  }
674
716
  const { tableName } = this.getTableName(indexName);
675
- const vectorType = this.getVectorTypeName();
717
+ const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType);
676
718
  const query = `
677
719
  WITH vector_scores AS (
678
720
  SELECT
679
721
  vector_id as id,
680
- 1 - (embedding <=> '${vectorStr}'::${vectorType}) as score,
722
+ 1 - (embedding <=> '${vectorStr}'::${qualifiedVectorType}) as score,
681
723
  metadata
682
724
  ${includeVector ? ", embedding" : ""}
683
725
  FROM ${tableName}
@@ -741,14 +783,15 @@ var PgVector = class extends MastraVector {
741
783
  }
742
784
  }
743
785
  const vectorIds = ids || vectors.map(() => crypto.randomUUID());
744
- const vectorType = this.getVectorTypeName();
786
+ const indexInfo = await this.getIndexInfo({ indexName });
787
+ const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType);
745
788
  for (let i = 0; i < vectors.length; i++) {
746
789
  const query = `
747
790
  INSERT INTO ${tableName} (vector_id, embedding, metadata)
748
- VALUES ($1, $2::${vectorType}, $3::jsonb)
791
+ VALUES ($1, $2::${qualifiedVectorType}, $3::jsonb)
749
792
  ON CONFLICT (vector_id)
750
793
  DO UPDATE SET
751
- embedding = $2::${vectorType},
794
+ embedding = $2::${qualifiedVectorType},
752
795
  metadata = $3::jsonb
753
796
  RETURNING embedding::text
754
797
  `;
@@ -807,9 +850,10 @@ var PgVector = class extends MastraVector {
807
850
  indexName,
808
851
  dimension,
809
852
  metric,
810
- type
853
+ type,
854
+ vectorType = "vector"
811
855
  }) {
812
- const input = indexName + dimension + metric + (type || "ivfflat");
856
+ const input = indexName + dimension + metric + (type || "ivfflat") + vectorType;
813
857
  return (await this.hasher).h32(input);
814
858
  }
815
859
  cachedIndexExists(indexName, newKey) {
@@ -862,7 +906,8 @@ var PgVector = class extends MastraVector {
862
906
  dimension,
863
907
  metric = "cosine",
864
908
  indexConfig = {},
865
- buildIndex = true
909
+ buildIndex = true,
910
+ vectorType = "vector"
866
911
  }) {
867
912
  const { tableName } = this.getTableName(indexName);
868
913
  try {
@@ -872,6 +917,9 @@ var PgVector = class extends MastraVector {
872
917
  if (!Number.isInteger(dimension) || dimension <= 0) {
873
918
  throw new Error("Dimension must be a positive integer");
874
919
  }
920
+ if (vectorType !== "vector" && vectorType !== "halfvec") {
921
+ throw new Error('vectorType must be "vector" or "halfvec"');
922
+ }
875
923
  } catch (error) {
876
924
  const mastraError = new MastraError(
877
925
  {
@@ -887,7 +935,13 @@ var PgVector = class extends MastraVector {
887
935
  this.logger?.trackException(mastraError);
888
936
  throw mastraError;
889
937
  }
890
- const indexCacheKey = await this.getIndexCacheKey({ indexName, dimension, type: indexConfig.type, metric });
938
+ const indexCacheKey = await this.getIndexCacheKey({
939
+ indexName,
940
+ dimension,
941
+ type: indexConfig.type,
942
+ metric,
943
+ vectorType
944
+ });
891
945
  if (this.cachedIndexExists(indexName, indexCacheKey)) {
892
946
  return;
893
947
  }
@@ -900,24 +954,40 @@ var PgVector = class extends MastraVector {
900
954
  try {
901
955
  await this.setupSchema(client);
902
956
  await this.installVectorExtension(client);
957
+ if (vectorType === "halfvec" && !this.supportsHalfvec()) {
958
+ throw new MastraError({
959
+ id: createVectorErrorId("PG", "CREATE_INDEX", "HALFVEC_NOT_SUPPORTED"),
960
+ text: `halfvec type requires pgvector >= 0.7.0, but version ${this.vectorExtensionVersion || "unknown"} is installed. Either upgrade pgvector or use vectorType: 'vector' (which supports up to 2000 dimensions for indexes).`,
961
+ domain: ErrorDomain.MASTRA_VECTOR,
962
+ category: ErrorCategory.USER,
963
+ details: {
964
+ indexName,
965
+ requestedVectorType: vectorType,
966
+ pgvectorVersion: this.vectorExtensionVersion || "unknown",
967
+ requiredVersion: "0.7.0"
968
+ }
969
+ });
970
+ }
903
971
  if (this.schema && this.vectorExtensionSchema && this.schema !== this.vectorExtensionSchema && this.vectorExtensionSchema !== "pg_catalog") {
904
972
  await client.query(`SET search_path TO ${this.getSchemaName()}, "${this.vectorExtensionSchema}"`);
905
973
  }
906
- const vectorType = this.getVectorTypeName();
974
+ const qualifiedVectorType = this.getVectorTypeName(vectorType);
907
975
  await client.query(`
908
976
  CREATE TABLE IF NOT EXISTS ${tableName} (
909
977
  id SERIAL PRIMARY KEY,
910
978
  vector_id TEXT UNIQUE NOT NULL,
911
- embedding ${vectorType}(${dimension}),
979
+ embedding ${qualifiedVectorType}(${dimension}),
912
980
  metadata JSONB DEFAULT '{}'::jsonb
913
981
  );
914
982
  `);
915
983
  this.createdIndexes.set(indexName, indexCacheKey);
984
+ this.indexVectorTypes.set(indexName, vectorType);
916
985
  if (buildIndex) {
917
- await this.setupIndex({ indexName, metric, indexConfig }, client);
986
+ await this.setupIndex({ indexName, metric, indexConfig, vectorType }, client);
918
987
  }
919
988
  } catch (error) {
920
989
  this.createdIndexes.delete(indexName);
990
+ this.indexVectorTypes.delete(indexName);
921
991
  throw error;
922
992
  } finally {
923
993
  client.release();
@@ -960,7 +1030,7 @@ var PgVector = class extends MastraVector {
960
1030
  client.release();
961
1031
  }
962
1032
  }
963
- async setupIndex({ indexName, metric, indexConfig }, client) {
1033
+ async setupIndex({ indexName, metric, indexConfig, vectorType = "vector" }, client) {
964
1034
  const mutex = this.getMutexByName(`build-${indexName}`);
965
1035
  await mutex.runExclusive(async () => {
966
1036
  const isConfigEmpty = !indexConfig || Object.keys(indexConfig).length === 0 || !indexConfig.type && !indexConfig.ivf && !indexConfig.hnsw;
@@ -982,9 +1052,11 @@ var PgVector = class extends MastraVector {
982
1052
  indexName,
983
1053
  dimension,
984
1054
  type: existingIndexInfo.type,
985
- metric: existingIndexInfo.metric
1055
+ metric: existingIndexInfo.metric,
1056
+ vectorType: existingIndexInfo.vectorType
986
1057
  });
987
1058
  this.createdIndexes.set(indexName, cacheKey);
1059
+ this.indexVectorTypes.set(indexName, existingIndexInfo.vectorType);
988
1060
  return;
989
1061
  }
990
1062
  }
@@ -1002,9 +1074,11 @@ var PgVector = class extends MastraVector {
1002
1074
  indexName,
1003
1075
  dimension,
1004
1076
  type: existingIndexInfo.type,
1005
- metric: existingIndexInfo.metric
1077
+ metric: existingIndexInfo.metric,
1078
+ vectorType: existingIndexInfo.vectorType
1006
1079
  });
1007
1080
  this.createdIndexes.set(indexName, cacheKey);
1081
+ this.indexVectorTypes.set(indexName, existingIndexInfo.vectorType);
1008
1082
  return;
1009
1083
  }
1010
1084
  this.logger?.info(`Index ${vectorIndexName} configuration changed, rebuilding index`);
@@ -1017,7 +1091,8 @@ var PgVector = class extends MastraVector {
1017
1091
  this.describeIndexCache.delete(indexName);
1018
1092
  return;
1019
1093
  }
1020
- const metricOp = metric === "cosine" ? "vector_cosine_ops" : metric === "euclidean" ? "vector_l2_ops" : "vector_ip_ops";
1094
+ const effectiveVectorType = existingIndexInfo?.vectorType ?? vectorType;
1095
+ const metricOp = this.getMetricOperatorClass(metric, effectiveVectorType);
1021
1096
  let indexSQL;
1022
1097
  if (indexType === "hnsw") {
1023
1098
  const m = indexConfig.hnsw?.m ?? 8;
@@ -1067,6 +1142,12 @@ var PgVector = class extends MastraVector {
1067
1142
  if (this.schema && this.schema !== "public") {
1068
1143
  try {
1069
1144
  await client.query(`CREATE EXTENSION IF NOT EXISTS vector SCHEMA ${this.getSchemaName()}`);
1145
+ const installedSchema2 = await this.detectVectorExtensionSchema(client);
1146
+ if (installedSchema2) {
1147
+ this.vectorExtensionInstalled = true;
1148
+ this.logger.info(`Vector extension installed in schema: ${installedSchema2}`);
1149
+ return;
1150
+ }
1070
1151
  this.vectorExtensionInstalled = true;
1071
1152
  this.vectorExtensionSchema = this.schema;
1072
1153
  this.logger.info(`Vector extension installed in schema: ${this.schema}`);
@@ -1129,7 +1210,7 @@ var PgVector = class extends MastraVector {
1129
1210
  WHERE c.table_schema = t.table_schema
1130
1211
  AND c.table_name = t.table_name
1131
1212
  AND c.column_name = 'embedding'
1132
- AND c.udt_name = 'vector'
1213
+ AND c.udt_name IN ('vector', 'halfvec')
1133
1214
  )
1134
1215
  AND EXISTS (
1135
1216
  SELECT 1
@@ -1168,17 +1249,18 @@ var PgVector = class extends MastraVector {
1168
1249
  try {
1169
1250
  const { tableName } = this.getTableName(indexName);
1170
1251
  const tableExistsQuery = `
1171
- SELECT 1
1252
+ SELECT udt_name
1172
1253
  FROM information_schema.columns
1173
1254
  WHERE table_schema = $1
1174
1255
  AND table_name = $2
1175
- AND udt_name = 'vector'
1256
+ AND udt_name IN ('vector', 'halfvec')
1176
1257
  LIMIT 1;
1177
1258
  `;
1178
1259
  const tableExists = await client.query(tableExistsQuery, [this.schema || "public", indexName]);
1179
1260
  if (tableExists.rows.length === 0) {
1180
1261
  throw new Error(`Vector table ${tableName} does not exist`);
1181
1262
  }
1263
+ const vectorType = tableExists.rows[0].udt_name === "halfvec" ? "halfvec" : "vector";
1182
1264
  const dimensionQuery = `
1183
1265
  SELECT atttypmod as dimension
1184
1266
  FROM pg_attribute
@@ -1228,6 +1310,7 @@ var PgVector = class extends MastraVector {
1228
1310
  count: parseInt(countResult.rows[0].count),
1229
1311
  metric,
1230
1312
  type: index_method,
1313
+ vectorType,
1231
1314
  config
1232
1315
  };
1233
1316
  } catch (e) {
@@ -1255,6 +1338,8 @@ var PgVector = class extends MastraVector {
1255
1338
  const { tableName } = this.getTableName(indexName);
1256
1339
  await client.query(`DROP TABLE IF EXISTS ${tableName} CASCADE`);
1257
1340
  this.createdIndexes.delete(indexName);
1341
+ this.indexVectorTypes.delete(indexName);
1342
+ this.describeIndexCache.delete(indexName);
1258
1343
  } catch (error) {
1259
1344
  await client.query("ROLLBACK");
1260
1345
  const mastraError = new MastraError(
@@ -1343,12 +1428,13 @@ var PgVector = class extends MastraVector {
1343
1428
  }
1344
1429
  client = await this.pool.connect();
1345
1430
  const { tableName } = this.getTableName(indexName);
1346
- const vectorType = this.getVectorTypeName();
1431
+ const indexInfo = await this.getIndexInfo({ indexName });
1432
+ const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType);
1347
1433
  let updateParts = [];
1348
1434
  let values = [];
1349
1435
  let valueIndex = 1;
1350
1436
  if (update.vector) {
1351
- updateParts.push(`embedding = $${valueIndex}::${vectorType}`);
1437
+ updateParts.push(`embedding = $${valueIndex}::${qualifiedVectorType}`);
1352
1438
  values.push(`[${update.vector.join(",")}]`);
1353
1439
  valueIndex++;
1354
1440
  }
@@ -3239,7 +3325,7 @@ var StoreOperationsPG = class extends StoreOperations {
3239
3325
  const constraints = [];
3240
3326
  if (def.primaryKey) constraints.push("PRIMARY KEY");
3241
3327
  if (!def.nullable) constraints.push("NOT NULL");
3242
- return `"${parsedName}" ${def.type.toUpperCase()} ${constraints.join(" ")}`;
3328
+ return `"${parsedName}" ${this.getSqlType(def.type)} ${constraints.join(" ")}`;
3243
3329
  });
3244
3330
  if (this.schemaName) {
3245
3331
  await this.setupSchema();
@@ -4348,6 +4434,27 @@ var WorkflowsPG = class extends WorkflowsStorage {
4348
4434
  );
4349
4435
  }
4350
4436
  }
4437
+ async deleteWorkflowRunById({ runId, workflowName }) {
4438
+ try {
4439
+ await this.client.none(
4440
+ `DELETE FROM ${getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: this.schema })} WHERE run_id = $1 AND workflow_name = $2`,
4441
+ [runId, workflowName]
4442
+ );
4443
+ } catch (error) {
4444
+ throw new MastraError(
4445
+ {
4446
+ id: createStorageErrorId("PG", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
4447
+ domain: ErrorDomain.STORAGE,
4448
+ category: ErrorCategory.THIRD_PARTY,
4449
+ details: {
4450
+ runId,
4451
+ workflowName
4452
+ }
4453
+ },
4454
+ error
4455
+ );
4456
+ }
4457
+ }
4351
4458
  async listWorkflowRuns({
4352
4459
  workflowName,
4353
4460
  fromDate,
@@ -4662,6 +4769,9 @@ var PostgresStore = class extends MastraStorage {
4662
4769
  }) {
4663
4770
  return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
4664
4771
  }
4772
+ async deleteWorkflowRunById({ runId, workflowName }) {
4773
+ return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
4774
+ }
4665
4775
  async close() {
4666
4776
  this.pgp.end();
4667
4777
  }