@mastra/upstash 1.5.1 → 1.5.2

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-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.5.1"
6
+ version: "1.5.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.5.1",
2
+ "version": "1.5.2",
3
3
  "package": "@mastra/upstash",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -272,6 +272,22 @@ Schema-based working memory uses **merge semantics**, meaning the agent only nee
272
272
  - **Set a field to `null` to delete it:** This explicitly removes the field from memory
273
273
  - **Arrays are replaced entirely:** When an array field is provided, it replaces the existing array (arrays aren't merged element-by-element)
274
274
 
275
+ ### Concurrent updates
276
+
277
+ With `scope: 'resource'` and a storage adapter that supports atomic merges (currently `@mastra/pg`), each merge runs inside a row-locked database transaction. Concurrent updates to different fields from separate processes are all kept. Other adapters merge in the application, which only serializes writers inside a single process.
278
+
279
+ To merge a partial update from your own code, call `memory.mergeWorkingMemory()`:
280
+
281
+ ```typescript
282
+ await memory.mergeWorkingMemory({
283
+ threadId: 'thread-1',
284
+ resourceId: 'user-123',
285
+ workingMemory: { preferences: { tone: 'formal' } },
286
+ })
287
+ ```
288
+
289
+ It throws if working memory isn't schema-based and resource-scoped, or if the storage adapter doesn't support atomic merges. Check `await memory.supportsAtomicWorkingMemoryMerge()` first if you need to fall back.
290
+
275
291
  ## Choosing between template and schema
276
292
 
277
293
  - Use a **template** (Markdown) if you want the agent to maintain memory as a free-form text block, such as a user profile or scratchpad. Templates use **replace semantics**: the agent must provide the complete memory content on each update.
@@ -50,23 +50,25 @@ console.log(results)
50
50
 
51
51
  The `topK` parameter specifies the maximum number of most similar results to return from the vector search.
52
52
 
53
- Results include both the text content and a similarity score:
53
+ Each result includes an `id`, a similarity `score`, and the stored `metadata`. When you store chunk text in metadata, it's available as `metadata.text`:
54
54
 
55
55
  ```ts
56
56
  [
57
57
  {
58
- text: 'Climate change poses significant challenges...',
58
+ id: 'chunk-1',
59
59
  score: 0.89,
60
- metadata: { source: 'article1.txt' },
60
+ metadata: { text: 'Climate change poses significant challenges...', source: 'article1.txt' },
61
61
  },
62
62
  {
63
- text: 'Rising temperatures affect crop yields...',
63
+ id: 'chunk-2',
64
64
  score: 0.82,
65
- metadata: { source: 'article1.txt' },
65
+ metadata: { text: 'Rising temperatures affect crop yields...', source: 'article1.txt' },
66
66
  },
67
67
  ]
68
68
  ```
69
69
 
70
+ Results can also include `vector` when you set `includeVector: true`, and `document` when the store returns the original document (Chroma only).
71
+
70
72
  ## Advanced retrieval options
71
73
 
72
74
  ### Metadata Filtering
@@ -230,7 +230,7 @@ await store.upsert({
230
230
  **libSQL**:
231
231
 
232
232
  ```ts
233
- import { LibSQLVector } from '@mastra/core/vector/libsql'
233
+ import { LibSQLVector } from '@mastra/libsql'
234
234
 
235
235
  const store = new LibSQLVector({
236
236
  id: 'libsql-vector',
package/dist/index.cjs CHANGED
@@ -1642,7 +1642,7 @@ var WorkflowsUpstash = class extends _mastra_core_storage.WorkflowsStorage {
1642
1642
  return this.client.get(key);
1643
1643
  }))).find((w) => w?.run_id === runId && (!workflowName || w.workflow_name === workflowName) && (!resourceId || w.resourceId === resourceId)) ?? null;
1644
1644
  }
1645
- async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext }) {
1645
+ async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state }) {
1646
1646
  try {
1647
1647
  const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1648
1648
  namespace: "workflows",
@@ -1660,6 +1660,7 @@ var WorkflowsUpstash = class extends _mastra_core_storage.WorkflowsStorage {
1660
1660
  local workflowName = ARGV[6]
1661
1661
  local runId = ARGV[7]
1662
1662
  local timestamp = tonumber(ARGV[8])
1663
+ local stateJson = ARGV[9]
1663
1664
 
1664
1665
  -- Get existing data
1665
1666
  local existing = redis.call('GET', key)
@@ -1706,6 +1707,11 @@ var WorkflowsUpstash = class extends _mastra_core_storage.WorkflowsStorage {
1706
1707
  local stepResult = cjson.decode(resultJson)
1707
1708
  snapshot.context[stepId] = stepResult
1708
1709
 
1710
+ -- Record workflow state in the same write when provided
1711
+ if stateJson ~= '' then
1712
+ snapshot.context['__state'] = cjson.decode(stateJson)
1713
+ end
1714
+
1709
1715
  -- Merge request context
1710
1716
  local newRequestContext = cjson.decode(requestContextJson)
1711
1717
  if snapshot.requestContext == nil then
@@ -1732,7 +1738,8 @@ var WorkflowsUpstash = class extends _mastra_core_storage.WorkflowsStorage {
1732
1738
  "workflows",
1733
1739
  workflowName,
1734
1740
  runId,
1735
- String(Date.now())
1741
+ String(Date.now()),
1742
+ state === void 0 ? "" : JSON.stringify(state)
1736
1743
  ]);
1737
1744
  let data;
1738
1745
  if (typeof resultJson === "string") data = JSON.parse(resultJson);