@mastra/pg 1.25.0 → 1.25.1-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.
@@ -3,7 +3,7 @@ name: mastra-pg
3
3
  description: Documentation for @mastra/pg. Use when working with @mastra/pg APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/pg"
6
- version: "1.25.0"
6
+ version: "1.25.1-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.25.0",
2
+ "version": "1.25.1-alpha.0",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -41,6 +41,8 @@ export const agent = new Agent({
41
41
 
42
42
  **options.lastMessages** (`number | false`): Number of most recent messages to include in context. Set to false to disable the message history feature entirely (messages are not loaded into context or saved). Use Number.MAX\_SAFE\_INTEGER to retrieve all messages with no limit. To load messages without saving new ones, use the readOnly option. The window slides forward on every request, so once a thread exceeds the limit, each turn invalidates the provider prompt cache. For long-running conversations, use Observational Memory instead.
43
43
 
44
+ **options.messageHistory** (`{ maxTokens: number; atMaxRemoveTokens?: number }`): Token budget for the complete prompt, including remembered history, system instructions, context, and the current turn. When the prompt exceeds maxTokens, the oldest remembered messages are dropped until the prompt is at most maxTokens - atMaxRemoveTokens (defaults to 25% of maxTokens). Protected content is never removed. Linked tool calls and results are removed together. During agent runs, trimmed history is excluded from later turns via a persisted per-thread boundary, but the messages themselves stay in storage. When set without an explicit lastMessages, the default 10-message cap is not applied. Set maxTokens to 0 to disable message history. Prefer this over lastMessages, since message count is a poor proxy for context size.
45
+
44
46
  **options.readOnly** (`boolean`): When true, prevents memory from saving new messages and provides working memory as read-only context (without the updateWorkingMemory tool). Useful for read-only operations like previews, internal routing agents, or sub agents that should reference but not modify memory.
45
47
 
46
48
  **options.semanticRecall** (`boolean | { topK: number; messageRange: number | { before: number; after: number }; scope?: 'thread' | 'resource' }`): Enable semantic search in message history. Can be a boolean or an object with configuration options. When enabled, requires both vector store and embedder to be configured. Default topK is 4, default messageRange is {before: 1, after: 1}.
@@ -248,6 +248,34 @@ await store.upsert({
248
248
  })
249
249
  ```
250
250
 
251
+ **Weaviate**:
252
+
253
+ ```ts
254
+ import { WeaviateVector } from '@mastra/weaviate'
255
+
256
+ const store = new WeaviateVector({
257
+ id: 'weaviate-vector',
258
+ httpHost: process.env.WEAVIATE_HOST,
259
+ httpPort: 443,
260
+ httpSecure: true,
261
+ grpcHost: process.env.WEAVIATE_GRPC_HOST,
262
+ grpcPort: 443,
263
+ grpcSecure: true,
264
+ apiKey: process.env.WEAVIATE_API_KEY,
265
+ })
266
+
267
+ await store.createIndex({
268
+ indexName: 'myCollection',
269
+ dimension: 1536,
270
+ })
271
+
272
+ await store.upsert({
273
+ indexName: 'myCollection',
274
+ vectors: embeddings,
275
+ metadata: chunks.map(chunk => ({ text: chunk.text })),
276
+ })
277
+ ```
278
+
251
279
  **Cloudflare**:
252
280
 
253
281
  ```ts
@@ -534,6 +562,17 @@ Namespace names must:
534
562
 
535
563
  - Example: `_namespace` isn't valid (starts with underscore)
536
564
 
565
+ **Weaviate**:
566
+
567
+ Index names map to Weaviate collections, which:
568
+
569
+ - Are capitalized by Weaviate (the first letter is upper-cased)
570
+ - Should contain only letters, numbers, and the `_` character
571
+ - Must start with a letter, since only the first character is upper-cased (a leading digit or symbol stays invalid)
572
+ - Preserve the original Mastra index name in the collection description, so `listIndexes()` and `describeIndex()` return the name you supplied
573
+ - Example: `my_collection` is stored as `My_collection` and returned as `my_collection`
574
+ - Example: `123_collection` isn't valid (starts with a digit)
575
+
537
576
  **Cloudflare**:
538
577
 
539
578
  Index names must:
package/dist/index.cjs CHANGED
@@ -2484,6 +2484,7 @@ async function loadSchemaSnapshot(client, schemaName) {
2484
2484
  }
2485
2485
  //#endregion
2486
2486
  //#region src/storage/db/index.ts
2487
+ const POSTGRES_MAX_BIND_PARAMETERS$1 = 65535;
2487
2488
  /**
2488
2489
  * Resolves PgDomainConfig to a database client and schema.
2489
2490
  * Handles creating a new pool if config is provided.
@@ -3037,6 +3038,90 @@ var PgDB = class extends _mastra_core_base.MastraBase {
3037
3038
  ON CONFLICT ("traceId", "spanId") DO NOTHING`, values);
3038
3039
  } else await client.none(`INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})`, values);
3039
3040
  }
3041
+ getChunkRowLimit(columnCount) {
3042
+ if (columnCount === 0) return 0;
3043
+ return Math.max(1, Math.floor(POSTGRES_MAX_BIND_PARAMETERS$1 / columnCount));
3044
+ }
3045
+ getSpanConflictIdentifier(record) {
3046
+ const traceId = record.traceId;
3047
+ const spanId = record.spanId;
3048
+ if (traceId === void 0 || spanId === void 0) return;
3049
+ return `${String(traceId)}|${String(spanId)}`;
3050
+ }
3051
+ async normalizeForInsert(tableName, record) {
3052
+ this.addTimestampZColumns(record);
3053
+ const filteredRecord = await this.filterRecordToKnownColumns(tableName, record);
3054
+ return {
3055
+ columns: Object.keys(filteredRecord).map((column) => (0, _mastra_core_utils.parseSqlIdentifier)(column, "column name")),
3056
+ values: this.prepareValuesForInsert(filteredRecord, tableName),
3057
+ conflictKey: tableName === _mastra_core_storage.TABLE_SPANS ? this.getSpanConflictIdentifier(filteredRecord) : void 0
3058
+ };
3059
+ }
3060
+ buildMultiRowInsertStatement({ tableName, columns, rows }) {
3061
+ const fullTableName = getTableName$6({
3062
+ indexName: tableName,
3063
+ schemaName: getSchemaName$6(this.schemaName)
3064
+ });
3065
+ const columnList = columns.map((column) => `"${column}"`).join(", ");
3066
+ const bindParams = [];
3067
+ const values = [];
3068
+ let bindIndex = 1;
3069
+ for (const rowValues of rows) {
3070
+ const placeholders = rowValues.map(() => `$${bindIndex++}`);
3071
+ bindParams.push(`(${placeholders.join(", ")})`);
3072
+ values.push(...rowValues);
3073
+ }
3074
+ let query = `INSERT INTO ${fullTableName} (${columnList}) VALUES ${bindParams.join(", ")}`;
3075
+ if (tableName === _mastra_core_storage.TABLE_SPANS) {
3076
+ const updateColumns = columns.filter((column) => column !== "traceId" && column !== "spanId");
3077
+ if (updateColumns.length > 0) {
3078
+ const updateClause = updateColumns.map((column) => `"${column}" = EXCLUDED."${column}"`).join(", ");
3079
+ query += ` ON CONFLICT ("traceId", "spanId") DO UPDATE SET ${updateClause}`;
3080
+ } else query += ` ON CONFLICT ("traceId", "spanId") DO NOTHING`;
3081
+ }
3082
+ return {
3083
+ query,
3084
+ values
3085
+ };
3086
+ }
3087
+ async executeBatchInsert(client, { tableName, records }) {
3088
+ const preparedRecords = [];
3089
+ for (const record of records) preparedRecords.push(await this.normalizeForInsert(tableName, record));
3090
+ let pendingColumns;
3091
+ let pendingConflictKeys = /* @__PURE__ */ new Set();
3092
+ let pendingRows = [];
3093
+ let pendingLimit = 0;
3094
+ const flush = async () => {
3095
+ if (!pendingColumns || pendingRows.length === 0) return;
3096
+ const statement = this.buildMultiRowInsertStatement({
3097
+ tableName,
3098
+ columns: pendingColumns,
3099
+ rows: pendingRows
3100
+ });
3101
+ await client.none(statement.query, statement.values);
3102
+ pendingColumns = void 0;
3103
+ pendingRows = [];
3104
+ pendingConflictKeys = /* @__PURE__ */ new Set();
3105
+ pendingLimit = 0;
3106
+ };
3107
+ for (const { columns, values, conflictKey } of preparedRecords) {
3108
+ if (columns.length === 0) continue;
3109
+ const columnsSignature = columns.join("\0");
3110
+ const currentPendingColumns = pendingColumns;
3111
+ const isSpans = tableName === _mastra_core_storage.TABLE_SPANS;
3112
+ const conflictDuplicate = isSpans && conflictKey !== void 0 && pendingConflictKeys.has(conflictKey);
3113
+ const exceedsLimit = pendingRows.length >= pendingLimit;
3114
+ if (currentPendingColumns === void 0 || columnsSignature !== currentPendingColumns.join("\0") || conflictDuplicate || exceedsLimit) {
3115
+ await flush();
3116
+ pendingColumns = columns;
3117
+ pendingLimit = this.getChunkRowLimit(columns.length);
3118
+ pendingRows = [values];
3119
+ pendingConflictKeys = /* @__PURE__ */ new Set();
3120
+ } else pendingRows.push(values);
3121
+ if (isSpans && conflictKey !== void 0) pendingConflictKeys.add(conflictKey);
3122
+ }
3123
+ await flush();
3124
+ }
3040
3125
  async insert({ tableName, record }) {
3041
3126
  try {
3042
3127
  await this.executeInsert(this.client, {
@@ -3485,9 +3570,9 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
3485
3570
  async batchInsert({ tableName, records }) {
3486
3571
  try {
3487
3572
  await this.client.tx(async (tx) => {
3488
- for (const record of records) await this.executeInsert(tx, {
3573
+ await this.executeBatchInsert(tx, {
3489
3574
  tableName,
3490
- record
3575
+ records
3491
3576
  });
3492
3577
  });
3493
3578
  } catch (error) {
@@ -23430,7 +23515,12 @@ var PgFactoryStorageOps = class {
23430
23515
  const assignments = columns.map((column, i) => `"${column}" = $${i + 1}`).join(", ");
23431
23516
  const filter = this.#buildWhere(schema, where, columns.length + 1);
23432
23517
  const args = [...columns.map((column) => this.#serialize(this.#column(schema, column), set[column])), ...filter.args];
23433
- return (await queryable.query(`UPDATE "${schema.name}" SET ${assignments} WHERE ${filter.sql}`, args)).rowCount ?? 0;
23518
+ try {
23519
+ return (await queryable.query(`UPDATE "${schema.name}" SET ${assignments} WHERE ${filter.sql}`, args)).rowCount ?? 0;
23520
+ } catch (error) {
23521
+ if (isUniqueViolation(error)) throw new _mastra_core_storage.UniqueViolationError(collection, { cause: error });
23522
+ throw error;
23523
+ }
23434
23524
  }
23435
23525
  async deleteMany(collection, where) {
23436
23526
  const schema = this.#schema(collection);