@mastra/upstash 1.1.0-alpha.0 → 1.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,127 @@
1
1
  # @mastra/upstash
2
2
 
3
+ ## 1.1.1-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Track `suspendedAt` and `suspendPayload` on background tasks. SQL adapters auto-migrate the new columns via `alterTable`. ([#16260](https://github.com/mastra-ai/mastra/pull/16260))
8
+
9
+ - Updated dependencies [[`9f17410`](https://github.com/mastra-ai/mastra/commit/9f1741080def23d42ee50b39887a385ae316a3c6), [`c6eb39e`](https://github.com/mastra-ai/mastra/commit/c6eb39ea6dca381c6563cb240237fbe608e02f93), [`900d086`](https://github.com/mastra-ai/mastra/commit/900d086bb737b9cf2fcf68f11b0389b801a2738c), [`4c0e286`](https://github.com/mastra-ai/mastra/commit/4c0e28637c9cfb4f416549b55e97ebfa13319dfc), [`25184ff`](https://github.com/mastra-ai/mastra/commit/25184ffaf1293ec95119426eb1a1f8d38831b96c), [`aebde9c`](https://github.com/mastra-ai/mastra/commit/aebde9cfacf56592c6b6350cae721740fe090b8a)]:
10
+ - @mastra/core@1.33.0-alpha.4
11
+
12
+ ## 1.1.0
13
+
14
+ ### Minor Changes
15
+
16
+ - Update peer dependencies to match core package version bump (1.0.5) ([#12557](https://github.com/mastra-ai/mastra/pull/12557))
17
+
18
+ ### Patch Changes
19
+
20
+ - Add durable agents with resumable streams ([#12557](https://github.com/mastra-ai/mastra/pull/12557))
21
+
22
+ Durable agents make agent execution resilient to disconnections, crashes, and long-running operations.
23
+
24
+ ### The Problem
25
+
26
+ Standard agent streaming has two fragility points:
27
+ 1. **Connection drops** - If a client disconnects mid-stream (network blip, browser refresh, mobile app backgrounded), all subsequent events are lost. The client has no way to "catch up" on what they missed.
28
+ 2. **Long-running operations** - Agent loops with tool calls can take minutes. Holding an HTTP connection open that long is unreliable. If the server restarts or the connection times out, the work is lost.
29
+
30
+ ### The Solution
31
+
32
+ **Resumable streams** solve connection drops. Every event is cached with a sequential index. If a client disconnects at event 5, they can reconnect and request events starting from index 6. They receive cached events immediately, then continue with live events as they arrive.
33
+
34
+ **Durable execution** solves long-running operations. Instead of executing the agent loop directly in the HTTP request, execution happens in a workflow engine (built-in evented engine or Inngest). The HTTP request just subscribes to events. If the connection drops, execution continues. The client can reconnect anytime to observe progress.
35
+
36
+ ### Usage
37
+
38
+ Wrap any existing `Agent` with durability using factory functions:
39
+
40
+ ```typescript
41
+ import { Agent } from '@mastra/core/agent';
42
+ import { createDurableAgent } from '@mastra/core/agent/durable';
43
+
44
+ const agent = new Agent({
45
+ id: 'my-agent',
46
+ model: openai('gpt-4'),
47
+ instructions: 'You are helpful',
48
+ });
49
+
50
+ const durableAgent = createDurableAgent({ agent });
51
+ ```
52
+
53
+ **Factory functions for different execution strategies:**
54
+
55
+ | Factory | Execution | Use Case |
56
+ | ---------------------------------------- | ----------------------------------- | ------------------------------- |
57
+ | `createDurableAgent({ agent })` | Local, synchronous | Development, simple deployments |
58
+ | `createEventedAgent({ agent })` | Fire-and-forget via workflow engine | Long-running operations |
59
+ | `createInngestAgent({ agent, inngest })` | Inngest-powered | Production, distributed systems |
60
+
61
+ ### Resumable Streams
62
+
63
+ ```typescript
64
+ // Start streaming
65
+ const { runId, output } = await durableAgent.stream('Analyze this data...');
66
+
67
+ // Client disconnects at event 5...
68
+
69
+ // Reconnect and resume from where we left off
70
+ const { output: resumed } = await durableAgent.observe(runId, { offset: 6 });
71
+ // Receives events 6, 7, 8... from cache, then continues with live events
72
+ ```
73
+
74
+ ### PubSub and Cache
75
+
76
+ Durable agents use two infrastructure components:
77
+
78
+ | Component | Purpose | Default |
79
+ | ---------- | ----------------------------------------- | --------------------- |
80
+ | **PubSub** | Real-time event delivery during streaming | `EventEmitterPubSub` |
81
+ | **Cache** | Stores events for replay on reconnection | `InMemoryServerCache` |
82
+
83
+ When `stream()` is called, events flow through pubsub in real-time. The cache stores each event with a sequential index. When `observe()` is called, missed events replay from cache before continuing with live events.
84
+
85
+ **Configure via Mastra instance (recommended):**
86
+
87
+ ```typescript
88
+ const mastra = new Mastra({
89
+ cache: new RedisServerCache({ url: 'redis://...' }),
90
+ pubsub: new RedisPubSub({ url: 'redis://...' }),
91
+ agents: {
92
+ // Inherits cache and pubsub from Mastra
93
+ myAgent: createDurableAgent({ agent }),
94
+ },
95
+ });
96
+ ```
97
+
98
+ **Configure per-agent (overrides Mastra):**
99
+
100
+ ```typescript
101
+ const durableAgent = createDurableAgent({
102
+ agent,
103
+ cache: new RedisServerCache({ url: 'redis://...' }),
104
+ pubsub: new RedisPubSub({ url: 'redis://...' }),
105
+ });
106
+ ```
107
+
108
+ **Disable caching (streams won't be resumable):**
109
+
110
+ ```typescript
111
+ const durableAgent = createDurableAgent({ agent, cache: false });
112
+ ```
113
+
114
+ For single-instance deployments, the defaults work fine. For multi-instance deployments (load balancer, horizontal scaling), use Redis-backed implementations so any instance can serve reconnection requests.
115
+
116
+ ### Class Hierarchy
117
+ - `DurableAgent` extends `Agent` - base class with resumable streams
118
+ - `EventedAgent` extends `DurableAgent` - fire-and-forget execution
119
+ - `InngestAgent` extends `DurableAgent` - Inngest-powered execution
120
+
121
+ - Updated dependencies [[`920c757`](https://github.com/mastra-ai/mastra/commit/920c75799c6bd71787d86deaf654a35af4c839ca), [`d587199`](https://github.com/mastra-ai/mastra/commit/d5871993c0371bde2b0717d6b47194755baa1443), [`1fe2533`](https://github.com/mastra-ai/mastra/commit/1fe2533c4382ca6858aac7c4b63e888c2eac6541), [`f8694b6`](https://github.com/mastra-ai/mastra/commit/f8694b6fa0b7a5cde71d794c3bbef4957c55bcb8), [`f8694b6`](https://github.com/mastra-ai/mastra/commit/f8694b6fa0b7a5cde71d794c3bbef4957c55bcb8)]:
122
+ - @mastra/core@1.30.0
123
+ - @mastra/redis@1.1.0
124
+
3
125
  ## 1.1.0-alpha.0
4
126
 
5
127
  ### Minor Changes
@@ -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.1.0-alpha.0"
6
+ version: "1.1.1-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.0-alpha.0",
2
+ "version": "1.1.1-alpha.0",
3
3
  "package": "@mastra/upstash",
4
4
  "exports": {
5
5
  "RedisServerCache": {
package/dist/index.cjs CHANGED
@@ -171,11 +171,13 @@ function toStorageRecord(task) {
171
171
  args: task.args,
172
172
  result: task.result ?? null,
173
173
  error: task.error ?? null,
174
+ suspend_payload: task.suspendPayload ?? null,
174
175
  retry_count: task.retryCount,
175
176
  max_retries: task.maxRetries,
176
177
  timeout_ms: task.timeoutMs,
177
178
  createdAt: task.createdAt.toISOString(),
178
179
  startedAt: task.startedAt?.toISOString() ?? null,
180
+ suspendedAt: task.suspendedAt?.toISOString() ?? null,
179
181
  completedAt: task.completedAt?.toISOString() ?? null
180
182
  };
181
183
  }
@@ -192,11 +194,13 @@ function fromStorageRecord(record) {
192
194
  runId: record.run_id ?? "",
193
195
  result: record.result ?? void 0,
194
196
  error: record.error ?? void 0,
197
+ suspendPayload: record.suspend_payload ?? void 0,
195
198
  retryCount: Number(record.retry_count ?? 0),
196
199
  maxRetries: Number(record.max_retries ?? 0),
197
200
  timeoutMs: Number(record.timeout_ms ?? 3e5),
198
201
  createdAt: new Date(record.createdAt),
199
202
  startedAt: record.startedAt ? new Date(record.startedAt) : void 0,
203
+ suspendedAt: record.suspendedAt ? new Date(record.suspendedAt) : void 0,
200
204
  completedAt: record.completedAt ? new Date(record.completedAt) : void 0
201
205
  };
202
206
  }
@@ -224,8 +228,10 @@ var BackgroundTasksUpstash = class extends storage.BackgroundTasksStorage {
224
228
  if ("status" in update) merged.status = update.status;
225
229
  if ("result" in update) merged.result = update.result;
226
230
  if ("error" in update) merged.error = update.error;
231
+ if ("suspendPayload" in update) merged.suspendPayload = update.suspendPayload;
227
232
  if ("retryCount" in update) merged.retryCount = update.retryCount;
228
233
  if ("startedAt" in update) merged.startedAt = update.startedAt;
234
+ if ("suspendedAt" in update) merged.suspendedAt = update.suspendedAt;
229
235
  if ("completedAt" in update) merged.completedAt = update.completedAt;
230
236
  const record = toStorageRecord(merged);
231
237
  const { key, processedRecord } = processRecord(storage.TABLE_BACKGROUND_TASKS, record);
@@ -265,6 +271,9 @@ var BackgroundTasksUpstash = class extends storage.BackgroundTasksStorage {
265
271
  if (filter.toolName) {
266
272
  tasks = tasks.filter((t) => t.toolName === filter.toolName);
267
273
  }
274
+ if (filter.toolCallId) {
275
+ tasks = tasks.filter((t) => t.toolCallId === filter.toolCallId);
276
+ }
268
277
  const dateCol = filter.dateFilterBy ?? "createdAt";
269
278
  if (filter.fromDate) {
270
279
  tasks = tasks.filter((t) => {