@mastra/pg 1.23.0-alpha.2 → 1.23.0-alpha.4

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,3 +1,4 @@
1
+ import { createHash, randomUUID } from "crypto";
1
2
  import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
2
3
  import * as coreStorage from "@mastra/core/storage";
3
4
  import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage, KNOWLEDGE_ACTIVITY_SCHEMA, KNOWLEDGE_CURSORS_SCHEMA, KNOWLEDGE_MENTIONS_SCHEMA, KNOWLEDGE_NODES_SCHEMA, KNOWLEDGE_RECORDS_SCHEMA, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_CURSORS, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_THREAD_STATE, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertKnowledgeCeilingRaised, assertKnowledgeScopeWithinCeiling, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
@@ -10,7 +11,6 @@ import xxhash from "xxhash-wasm";
10
11
  import { parse } from "pg-connection-string";
11
12
  import { BaseFilterTranslator } from "@mastra/core/vector/filter";
12
13
  import { MastraBase } from "@mastra/core/base";
13
- import { randomUUID } from "crypto";
14
14
  import { MessageList } from "@mastra/core/agent";
15
15
  import { coreFeatures } from "@mastra/core/features";
16
16
  import { saveScorePayloadSchema } from "@mastra/core/evals";
@@ -804,6 +804,8 @@ var PgVector = class extends MastraVector {
804
804
  AND attnum > 0
805
805
  AND NOT attisdropped`, [tableName])).rowCount === 0) return;
806
806
  await client.query(`ALTER TABLE ${tableName} ADD COLUMN IF NOT EXISTS namespace VARCHAR(255) NOT NULL DEFAULT '${DEFAULT_NAMESPACE}'`);
807
+ const namespaceIndexName = this.getNamespaceIndexName(parsedIndexName);
808
+ await client.query(`CREATE UNIQUE INDEX IF NOT EXISTS "${namespaceIndexName}" ON ${tableName} (namespace, vector_id)`);
807
809
  const legacyConstraints = await client.query(`SELECT c.conname
808
810
  FROM pg_constraint c
809
811
  WHERE c.conrelid = to_regclass($1)
@@ -813,8 +815,21 @@ var PgVector = class extends MastraVector {
813
815
  const parsedConstraintName = parseSqlIdentifier(conname, "constraint name");
814
816
  await client.query(`ALTER TABLE ${tableName} DROP CONSTRAINT "${parsedConstraintName}"`);
815
817
  }
816
- const namespaceIndexName = parseSqlIdentifier(`${parsedIndexName}_namespace_vector_id_idx`, "index name");
817
- await client.query(`CREATE UNIQUE INDEX IF NOT EXISTS "${namespaceIndexName}" ON ${tableName} (namespace, vector_id)`);
818
+ }
819
+ /**
820
+ * Name of the unique (namespace, vector_id) index for a table.
821
+ *
822
+ * The full `<index>_namespace_vector_id_idx` name is kept whenever it fits so tables that
823
+ * were already migrated keep matching `IF NOT EXISTS`. Longer index names would exceed
824
+ * Postgres' 63-char identifier limit, so those fall back to a truncated prefix plus a hash
825
+ * of the index name to distinguish tables that
826
+ * share a long prefix.
827
+ */
828
+ getNamespaceIndexName(parsedIndexName) {
829
+ const fullName = `${parsedIndexName}_namespace_vector_id_idx`;
830
+ if (fullName.length <= 63) return fullName;
831
+ const suffix = `_ns_${createHash("sha256").update(parsedIndexName).digest("hex").slice(0, 32)}_idx`;
832
+ return `${parsedIndexName.slice(0, 63 - suffix.length)}${suffix}`;
818
833
  }
819
834
  transformFilter(filter) {
820
835
  return new PGFilterTranslator().translate(filter);
@@ -912,12 +927,12 @@ var PgVector = class extends MastraVector {
912
927
  client.release();
913
928
  }
914
929
  }
930
+ const indexInfo = await this.getIndexMetadata({ indexName });
915
931
  const client = await this.pool.connect();
916
932
  try {
917
933
  await this.ensureSearchPath(client);
918
934
  await client.query("BEGIN");
919
935
  const { sql: filterQuery, values: filterValues } = buildFilterQuery(this.transformFilter(filter), minScore, topK);
920
- const indexInfo = await this.getIndexMetadata({ indexName });
921
936
  const metric = indexInfo.metric ?? "cosine";
922
937
  const ops = this.getVectorOps(indexInfo.vectorType, metric);
923
938
  const vectorStr = ops.formatVector(queryVector, indexInfo.dimension);
@@ -992,6 +1007,7 @@ var PgVector = class extends MastraVector {
992
1007
  async upsert({ indexName, vectors, metadata, ids, deleteFilter, namespace = DEFAULT_NAMESPACE }) {
993
1008
  validateUpsertInput("PG", vectors, metadata, ids);
994
1009
  const { tableName } = this.getTableName(indexName);
1010
+ const indexInfo = await this.getIndexMetadata({ indexName });
995
1011
  const client = await this.pool.connect();
996
1012
  try {
997
1013
  await this.ensureSearchPath(client);
@@ -1013,7 +1029,6 @@ var PgVector = class extends MastraVector {
1013
1029
  }
1014
1030
  }
1015
1031
  const vectorIds = ids || vectors.map(() => crypto.randomUUID());
1016
- const indexInfo = await this.getIndexMetadata({ indexName });
1017
1032
  const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType, indexInfo.dimension);
1018
1033
  const ops = this.getVectorOps(indexInfo.vectorType, indexInfo.metric ?? "cosine");
1019
1034
  if (new Set(vectorIds).size !== vectorIds.length) for (let i = 0; i < vectors.length; i++) {
@@ -1301,7 +1316,7 @@ var PgVector = class extends MastraVector {
1301
1316
  let existingIndexInfo = null;
1302
1317
  let dimension = 0;
1303
1318
  try {
1304
- existingIndexInfo = await this.getIndexMetadata({ indexName });
1319
+ existingIndexInfo = await this.describeIndexMetadata({ indexName }, client);
1305
1320
  dimension = existingIndexInfo.dimension;
1306
1321
  if (isConfigEmpty && existingIndexInfo.metric === metric) if (existingIndexInfo.type === "flat") this.logger?.debug(`No index exists for ${vectorIndexName}, will create default ivfflat index`);
1307
1322
  else {
@@ -1505,8 +1520,8 @@ var PgVector = class extends MastraVector {
1505
1520
  * {@link describeIndex} it issues no `COUNT(*)`, so its cost does not grow with the
1506
1521
  * number of rows in the table.
1507
1522
  */
1508
- async describeIndexMetadata({ indexName }) {
1509
- const client = await this.pool.connect();
1523
+ async describeIndexMetadata({ indexName }, existingClient) {
1524
+ const client = existingClient ?? await this.pool.connect();
1510
1525
  try {
1511
1526
  const { tableName, parsedIndexName } = this.getTableName(indexName);
1512
1527
  const tableExists = await client.query(`
@@ -1566,7 +1581,6 @@ var PgVector = class extends MastraVector {
1566
1581
  config
1567
1582
  };
1568
1583
  } catch (e) {
1569
- await client.query("ROLLBACK");
1570
1584
  const mastraError = new MastraError({
1571
1585
  id: createVectorErrorId("PG", "DESCRIBE_INDEX", "FAILED"),
1572
1586
  domain: ErrorDomain.MASTRA_VECTOR,
@@ -1576,7 +1590,7 @@ var PgVector = class extends MastraVector {
1576
1590
  this.logger?.trackException(mastraError);
1577
1591
  throw mastraError;
1578
1592
  } finally {
1579
- client.release();
1593
+ if (!existingClient) client.release();
1580
1594
  }
1581
1595
  }
1582
1596
  /**
@@ -1681,10 +1695,10 @@ var PgVector = class extends MastraVector {
1681
1695
  category: ErrorCategory.USER,
1682
1696
  details: { indexName }
1683
1697
  });
1698
+ const indexInfo = await this.getIndexMetadata({ indexName });
1684
1699
  client = await this.pool.connect();
1685
1700
  await this.ensureSearchPath(client);
1686
1701
  const { tableName } = this.getTableName(indexName);
1687
- const indexInfo = await this.getIndexMetadata({ indexName });
1688
1702
  const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType, indexInfo.dimension);
1689
1703
  const ops = this.getVectorOps(indexInfo.vectorType, indexInfo.metric ?? "cosine");
1690
1704
  let updateParts = [];