@mastra/upstash 1.4.2-alpha.0 → 1.4.3-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/CHANGELOG.md +23 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-rag-retrieval.md +113 -5
- package/dist/docs/references/reference-rag-vector-databases.md +4 -4
- package/dist/index.cjs +23 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +23 -14
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/background-tasks/index.d.ts +3 -1
- package/dist/storage/domains/background-tasks/index.d.ts.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @mastra/upstash
|
|
2
2
|
|
|
3
|
+
## 1.4.3-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Enforce atomic conditional background task state updates so cancellation cannot be overwritten during dispatch. Background task storage is no longer exposed by Cloudflare KV or ClickHouse, which cannot provide the required compare-and-set semantics. ([#22228](https://github.com/mastra-ai/mastra/pull/22228))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`aa3a85d`](https://github.com/mastra-ai/mastra/commit/aa3a85daf094c683bb97efdf4b6a696d2e474af5), [`d29d06f`](https://github.com/mastra-ai/mastra/commit/d29d06fe00bbd35b4571150ea04c59d2ed783c71), [`e6516df`](https://github.com/mastra-ai/mastra/commit/e6516dfcdae4f4ac0e7971d84359a81385ee602f), [`0b2a3d1`](https://github.com/mastra-ai/mastra/commit/0b2a3d1783875c5b97b7b36ab3d03d7360e0dde7), [`6bb5d71`](https://github.com/mastra-ai/mastra/commit/6bb5d7193fe9166b219f0fccae17db7a5ae86e65), [`57de7d6`](https://github.com/mastra-ai/mastra/commit/57de7d644ba7146edb4e9e6111ec4fa98c3a59e9), [`e8e299c`](https://github.com/mastra-ai/mastra/commit/e8e299cc6abdfc39947e2fec25803493015d3882), [`edfc548`](https://github.com/mastra-ai/mastra/commit/edfc548886bc7bae17b681f8b6b41a47eb32bcd2), [`a8a4871`](https://github.com/mastra-ai/mastra/commit/a8a4871215f51da95c47129602157ce5372f634a), [`5165cdc`](https://github.com/mastra-ai/mastra/commit/5165cdcdcf50e144bb8113278535196cc9b07065), [`6bb5d71`](https://github.com/mastra-ai/mastra/commit/6bb5d7193fe9166b219f0fccae17db7a5ae86e65), [`9ee8120`](https://github.com/mastra-ai/mastra/commit/9ee8120ce17f76b9f617489e05a283353742690a), [`d975e92`](https://github.com/mastra-ai/mastra/commit/d975e924d4936f46c386bd3dee39c671720289f6), [`1cfa878`](https://github.com/mastra-ai/mastra/commit/1cfa8784d8da0dfaa0317e5048bc48b6084a5ea5), [`c118318`](https://github.com/mastra-ai/mastra/commit/c1183181c9804303db4b511c2e2648f8b714712b), [`fc07c64`](https://github.com/mastra-ai/mastra/commit/fc07c6465043e08e99193a6751a01c56ffc2e7a1), [`542dee2`](https://github.com/mastra-ai/mastra/commit/542dee254167f974ff8cbbbfc0ce10f9a2616a7b), [`a58483c`](https://github.com/mastra-ai/mastra/commit/a58483cff1a9d41fce7c931843f48cb0ac450f64), [`a58483c`](https://github.com/mastra-ai/mastra/commit/a58483cff1a9d41fce7c931843f48cb0ac450f64), [`895e9df`](https://github.com/mastra-ai/mastra/commit/895e9dfc17d6f34299eca64e317ded9e5f5e5ef8)]:
|
|
10
|
+
- @mastra/core@1.62.0-alpha.8
|
|
11
|
+
|
|
12
|
+
## 1.4.2
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Fixed concurrent resume() calls on the same suspended workflow run executing downstream steps more than once. A resume now atomically claims the run before executing anything, so only one caller continues a given suspension. Losing callers throw WORKFLOW_RESUME_ALREADY_CLAIMED without running any steps. Fixes #20443 ([#21725](https://github.com/mastra-ai/mastra/pull/21725))
|
|
17
|
+
|
|
18
|
+
- Workflow state updates now support an optional expectedStatus guard, so a status change is only applied when the stored run is in an expected state. This is what makes concurrent workflow resumes safe. ([#21725](https://github.com/mastra-ai/mastra/pull/21725))
|
|
19
|
+
|
|
20
|
+
- Resume conflicts now return 409 Conflict. When a suspended workflow run has already been resumed by another caller, the resume endpoints respond with 409 instead of a generic error. ([#21725](https://github.com/mastra-ai/mastra/pull/21725))
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [[`88d14ca`](https://github.com/mastra-ai/mastra/commit/88d14cac008582a618fecc3d5c7fd3bdf4f6ddc3), [`480e491`](https://github.com/mastra-ai/mastra/commit/480e491588bd6a7a1c9ee4407590ad625dd33952), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`acc3471`](https://github.com/mastra-ai/mastra/commit/acc3471de5f3fde8027ee4e355af292b2bc1bc30), [`b6a771e`](https://github.com/mastra-ai/mastra/commit/b6a771ef23d203ddb348efca8065eff65def8191), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`3bb88dd`](https://github.com/mastra-ai/mastra/commit/3bb88ddf07fb98f3cd16d3bff94e51cd3b45d011), [`d23e75d`](https://github.com/mastra-ai/mastra/commit/d23e75d57cc7cf5b9bfdbee896bf5a6a2484fed7), [`c8faa4e`](https://github.com/mastra-ai/mastra/commit/c8faa4e1cfebaec56b65e754e90b9fe46d153359), [`d378d75`](https://github.com/mastra-ai/mastra/commit/d378d7511f71309ed61a8f6b93cd0361dc6cb70f), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`26d4016`](https://github.com/mastra-ai/mastra/commit/26d40160ff7f7d8bf95fee2039a52cbc83863533), [`7c60df5`](https://github.com/mastra-ai/mastra/commit/7c60df5c7872343fbac5c3e5b1175c8076a5abfd), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`f2031a4`](https://github.com/mastra-ai/mastra/commit/f2031a47445e8f67a89ba1309036816f97ab7a65), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`cad4208`](https://github.com/mastra-ai/mastra/commit/cad42082e6aa1776168a94914f523334be45d929), [`8e529d4`](https://github.com/mastra-ai/mastra/commit/8e529d4ac754efef04b225841349e0da9edf89a6), [`57c5103`](https://github.com/mastra-ai/mastra/commit/57c51035a2a36e3df3c4f32f46bb789a66ed5946), [`038b7b4`](https://github.com/mastra-ai/mastra/commit/038b7b405cb4ac25ab3f3031334111b1f87ac112), [`4132d61`](https://github.com/mastra-ai/mastra/commit/4132d61f8367077120ee9e6420d3224dffd93c93), [`d378d75`](https://github.com/mastra-ai/mastra/commit/d378d7511f71309ed61a8f6b93cd0361dc6cb70f)]:
|
|
23
|
+
- @mastra/core@1.61.0
|
|
24
|
+
- @mastra/redis@1.4.2
|
|
25
|
+
|
|
3
26
|
## 1.4.2-alpha.0
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: mastra-upstash
|
|
|
3
3
|
description: Documentation for @mastra/upstash. Use when working with @mastra/upstash APIs, configuration, or implementation.
|
|
4
4
|
metadata:
|
|
5
5
|
package: "@mastra/upstash"
|
|
6
|
-
version: "1.4.
|
|
6
|
+
version: "1.4.3-alpha.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## When to use
|
|
@@ -77,9 +77,19 @@ For detailed information about available operators and syntax, see the [Metadata
|
|
|
77
77
|
|
|
78
78
|
Basic filtering examples:
|
|
79
79
|
|
|
80
|
+
**MongoDB**:
|
|
81
|
+
|
|
80
82
|
```ts
|
|
83
|
+
import { MongoDBVector } from '@mastra/mongodb'
|
|
84
|
+
|
|
85
|
+
const mongoVector = new MongoDBVector({
|
|
86
|
+
id: 'mongodb-vector',
|
|
87
|
+
uri: process.env.MONGODB_URI,
|
|
88
|
+
dbName: process.env.MONGODB_DB_NAME,
|
|
89
|
+
})
|
|
90
|
+
|
|
81
91
|
// Simple equality filter
|
|
82
|
-
const
|
|
92
|
+
const equalityResults = await mongoVector.query({
|
|
83
93
|
indexName: 'embeddings',
|
|
84
94
|
queryVector: embedding,
|
|
85
95
|
topK: 10,
|
|
@@ -89,7 +99,7 @@ const results = await pgVector.query({
|
|
|
89
99
|
})
|
|
90
100
|
|
|
91
101
|
// Numeric comparison
|
|
92
|
-
const
|
|
102
|
+
const priceResults = await mongoVector.query({
|
|
93
103
|
indexName: 'embeddings',
|
|
94
104
|
queryVector: embedding,
|
|
95
105
|
topK: 10,
|
|
@@ -99,7 +109,7 @@ const results = await pgVector.query({
|
|
|
99
109
|
})
|
|
100
110
|
|
|
101
111
|
// Multiple conditions
|
|
102
|
-
const
|
|
112
|
+
const compoundResults = await mongoVector.query({
|
|
103
113
|
indexName: 'embeddings',
|
|
104
114
|
queryVector: embedding,
|
|
105
115
|
topK: 10,
|
|
@@ -111,7 +121,7 @@ const results = await pgVector.query({
|
|
|
111
121
|
})
|
|
112
122
|
|
|
113
123
|
// Array operations
|
|
114
|
-
const
|
|
124
|
+
const tagResults = await mongoVector.query({
|
|
115
125
|
indexName: 'embeddings',
|
|
116
126
|
queryVector: embedding,
|
|
117
127
|
topK: 10,
|
|
@@ -121,7 +131,64 @@ const results = await pgVector.query({
|
|
|
121
131
|
})
|
|
122
132
|
|
|
123
133
|
// Logical operators
|
|
124
|
-
const
|
|
134
|
+
const categoryResults = await mongoVector.query({
|
|
135
|
+
indexName: 'embeddings',
|
|
136
|
+
queryVector: embedding,
|
|
137
|
+
topK: 10,
|
|
138
|
+
filter: {
|
|
139
|
+
$or: [{ category: 'electronics' }, { category: 'accessories' }],
|
|
140
|
+
$and: [{ price: { $gt: 50 } }, { price: { $lt: 200 } }],
|
|
141
|
+
},
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**pgVector**:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
// Simple equality filter
|
|
149
|
+
const equalityResults = await pgVector.query({
|
|
150
|
+
indexName: 'embeddings',
|
|
151
|
+
queryVector: embedding,
|
|
152
|
+
topK: 10,
|
|
153
|
+
filter: {
|
|
154
|
+
source: 'article1.txt',
|
|
155
|
+
},
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// Numeric comparison
|
|
159
|
+
const priceResults = await pgVector.query({
|
|
160
|
+
indexName: 'embeddings',
|
|
161
|
+
queryVector: embedding,
|
|
162
|
+
topK: 10,
|
|
163
|
+
filter: {
|
|
164
|
+
price: { $gt: 100 },
|
|
165
|
+
},
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
// Multiple conditions
|
|
169
|
+
const compoundResults = await pgVector.query({
|
|
170
|
+
indexName: 'embeddings',
|
|
171
|
+
queryVector: embedding,
|
|
172
|
+
topK: 10,
|
|
173
|
+
filter: {
|
|
174
|
+
category: 'electronics',
|
|
175
|
+
price: { $lt: 1000 },
|
|
176
|
+
inStock: true,
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// Array operations
|
|
181
|
+
const tagResults = await pgVector.query({
|
|
182
|
+
indexName: 'embeddings',
|
|
183
|
+
queryVector: embedding,
|
|
184
|
+
topK: 10,
|
|
185
|
+
filter: {
|
|
186
|
+
tags: { $in: ['sale', 'new'] },
|
|
187
|
+
},
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// Logical operators
|
|
191
|
+
const categoryResults = await pgVector.query({
|
|
125
192
|
indexName: 'embeddings',
|
|
126
193
|
queryVector: embedding,
|
|
127
194
|
topK: 10,
|
|
@@ -141,6 +208,47 @@ Common use cases for metadata filtering:
|
|
|
141
208
|
- Combine multiple conditions for precise querying
|
|
142
209
|
- Filter by document attributes (e.g., language, author)
|
|
143
210
|
|
|
211
|
+
### Where the filter is applied
|
|
212
|
+
|
|
213
|
+
Vector stores differ in _when_ they apply a metadata filter, which affects how filtered queries scale.
|
|
214
|
+
|
|
215
|
+
MongoDB can evaluate the filter inside the vector index itself. This keeps the query on a single round trip to `$vectorSearch`, so it avoids the pre-filter pass that collects matching document IDs and the 16 MB BSON limit that pass is subject to. Declaring the fields you filter on in `filterFields` when you create the index is what enables it:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
// Declare the metadata fields you want to filter on
|
|
219
|
+
await mongoVector.createIndex({
|
|
220
|
+
indexName: 'embeddings',
|
|
221
|
+
dimension: 1536,
|
|
222
|
+
filterFields: ['source', 'price', 'category', 'inStock', 'tags'],
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
// createIndex() returns before the index finishes building
|
|
226
|
+
await mongoVector.waitForIndexReady({ indexName: 'embeddings' })
|
|
227
|
+
|
|
228
|
+
// The filter is applied during the index search
|
|
229
|
+
const results = await mongoVector.query({
|
|
230
|
+
indexName: 'embeddings',
|
|
231
|
+
queryVector: embedding,
|
|
232
|
+
topK: 10,
|
|
233
|
+
filter: { source: 'article1.txt' },
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Mastra passes the filter to the index only when every field it references is declared in `filterFields` and every operator is one the index accepts: `$and`, `$or`, `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, and `$nin`. A filter that uses an undeclared field or any other operator takes a fallback path: Mastra matches the collection first and passes the matching document IDs into the vector search. That fallback holds only while the ID set fits within MongoDB's 16 MB BSON document limit. On large collections the query fails once that limit is exceeded, so declare your filter fields when you expect selective filters over large data sets.
|
|
238
|
+
|
|
239
|
+
pgVector applies the filter as an ordinary query condition:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
const results = await pgVector.query({
|
|
243
|
+
indexName: 'embeddings',
|
|
244
|
+
queryVector: embedding,
|
|
245
|
+
topK: 10,
|
|
246
|
+
filter: { source: 'article1.txt' },
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Postgres vector indexes (HNSW and IVFFlat) can't restrict that search to rows matching a condition. When a filter is present, pgVector instead compares the query vector against every matching row and returns the closest `topK`. Results are exact, but the work grows with the number of rows the filter matches. Indexing the metadata column speeds up row retrieval. The distance comparisons still happen per row.
|
|
251
|
+
|
|
144
252
|
### Vector Query Tool
|
|
145
253
|
|
|
146
254
|
Sometimes you want to give your agent the ability to query a vector database directly. The Vector Query Tool allows your agent to be in charge of retrieval decisions, combining semantic search with optional filtering and reranking based on the agent's understanding of the user's needs.
|
|
@@ -27,9 +27,9 @@ await store.upsert({
|
|
|
27
27
|
})
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
### Using MongoDB
|
|
30
|
+
### Using MongoDB Vector Search
|
|
31
31
|
|
|
32
|
-
For detailed setup instructions and best practices, see the [official MongoDB
|
|
32
|
+
MongoDB Vector Search is a good solution for teams who want to consolidate vector search, full-text search, and operational data in a single database to minimize infrastructure complexity and maintain production-grade performance. For detailed setup instructions and best practices, see the [official MongoDB Vector Search documentation](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-overview/?utm_campaign=devrel\&utm_source=third-party-content\&utm_medium=cta\&utm_content=mastra-docs).
|
|
33
33
|
|
|
34
34
|
### Using VoyageAI with MongoDB
|
|
35
35
|
|
|
@@ -37,7 +37,7 @@ MongoDB works seamlessly with VoyageAI's embedding models, which are optimized f
|
|
|
37
37
|
|
|
38
38
|
### Hybrid Search (Vector + Full-Text)
|
|
39
39
|
|
|
40
|
-
MongoDB supports hybrid search that fuses vector similarity with BM25 full-text search using server-side `$rankFusion` (requires MongoDB >= 8.0; generally available from 8.1, and enabled on Atlas 8.0.x). This is useful when you want to combine semantic and keyword-based retrieval:
|
|
40
|
+
MongoDB supports hybrid search that fuses vector similarity with BM25 full-text search using server-side `$rankFusion` (requires MongoDB >= 8.0; generally available from 8.1, and enabled on MongoDB Atlas 8.0.x). This is useful when you want to combine semantic and keyword-based retrieval:
|
|
41
41
|
|
|
42
42
|
```ts
|
|
43
43
|
await store.createSearchIndex({ indexName: 'myCollection', fields: ['text'] })
|
|
@@ -420,7 +420,7 @@ Each vector database enforces specific naming conventions for indexes and collec
|
|
|
420
420
|
|
|
421
421
|
**MongoDB**:
|
|
422
422
|
|
|
423
|
-
Collection
|
|
423
|
+
Collection and index names must:
|
|
424
424
|
|
|
425
425
|
- Start with a letter or underscore
|
|
426
426
|
- Be up to 120 bytes long
|
package/dist/index.cjs
CHANGED
|
@@ -231,20 +231,29 @@ var BackgroundTasksUpstash = class extends _mastra_core_storage.BackgroundTasksS
|
|
|
231
231
|
const { key, processedRecord } = processRecord(_mastra_core_storage.TABLE_BACKGROUND_TASKS, toStorageRecord(task));
|
|
232
232
|
await this.client.set(key, processedRecord);
|
|
233
233
|
}
|
|
234
|
-
async updateTask(taskId, update) {
|
|
235
|
-
const
|
|
236
|
-
if (
|
|
237
|
-
|
|
238
|
-
if ("
|
|
239
|
-
if ("
|
|
240
|
-
if ("
|
|
241
|
-
if ("
|
|
242
|
-
if ("
|
|
243
|
-
if ("
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
|
|
234
|
+
async updateTask(taskId, update, options) {
|
|
235
|
+
const patch = {};
|
|
236
|
+
if ("status" in update) patch.status = update.status;
|
|
237
|
+
if ("result" in update) patch.result = update.result ?? null;
|
|
238
|
+
if ("error" in update) patch.error = update.error ?? null;
|
|
239
|
+
if ("suspendPayload" in update) patch.suspend_payload = update.suspendPayload ?? null;
|
|
240
|
+
if ("retryCount" in update) patch.retry_count = update.retryCount;
|
|
241
|
+
if ("startedAt" in update) patch.startedAt = update.startedAt?.toISOString() ?? null;
|
|
242
|
+
if ("suspendedAt" in update) patch.suspendedAt = update.suspendedAt?.toISOString() ?? null;
|
|
243
|
+
if ("completedAt" in update) patch.completedAt = update.completedAt?.toISOString() ?? null;
|
|
244
|
+
if (Object.keys(patch).length === 0) return false;
|
|
245
|
+
const key = getKey(_mastra_core_storage.TABLE_BACKGROUND_TASKS, { id: taskId });
|
|
246
|
+
const result = await this.client.eval(`
|
|
247
|
+
local existing = redis.call('GET', KEYS[1])
|
|
248
|
+
if not existing then return 0 end
|
|
249
|
+
local record = cjson.decode(existing)
|
|
250
|
+
if ARGV[1] ~= '' and record.status ~= ARGV[1] then return 0 end
|
|
251
|
+
local patch = cjson.decode(ARGV[2])
|
|
252
|
+
for field, value in pairs(patch) do record[field] = value end
|
|
253
|
+
redis.call('SET', KEYS[1], cjson.encode(record))
|
|
254
|
+
return 1
|
|
255
|
+
`, [key], [options?.expectedStatus ?? "", JSON.stringify(patch)]);
|
|
256
|
+
return Number(result) === 1;
|
|
248
257
|
}
|
|
249
258
|
async getTask(taskId) {
|
|
250
259
|
const key = getKey(_mastra_core_storage.TABLE_BACKGROUND_TASKS, { id: taskId });
|