@mastra/client-js 0.0.0-ai-v5-20250729012312 → 0.0.0-ai-v5-20250729181825

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,6 +1,6 @@
1
1
  # @mastra/client-js
2
2
 
3
- ## 0.0.0-ai-v5-20250729012312
3
+ ## 0.0.0-ai-v5-20250729181825
4
4
 
5
5
  ### Minor Changes
6
6
 
@@ -12,6 +12,8 @@
12
12
  - 2ab3115: Should not send content type if body instance of FormData
13
13
  - 0f24e20: Added the ability to pass in metadata for UIMessage and MastraMessageV2 in client-js and agent.stream/generate
14
14
  - e25ab3b: fix: save score params
15
+ - 9802f42: Added types and tests to ensure client-js and hono endpoints can save memory messages where the input is either a v1 or v2 mastra message
16
+ - 1ac8f6b: deduplicate message
15
17
  - b8efbb9: feat: add flexible deleteMessages method to memory API
16
18
  - Added `memory.deleteMessages(input)` method that accepts multiple input types:
17
19
  - Single message ID as string: `deleteMessages('msg-123')`
@@ -26,16 +28,19 @@
26
28
 
27
29
  - Updated dependencies [f96993c]
28
30
  - Updated dependencies [6725b7b]
31
+ - Updated dependencies [27cc97a]
29
32
  - Updated dependencies [5fc97af]
30
33
  - Updated dependencies [39fcf57]
31
34
  - Updated dependencies [6ab4a1c]
32
35
  - Updated dependencies [41daa63]
36
+ - Updated dependencies [ad0a58b]
33
37
  - Updated dependencies [254a36b]
34
38
  - Updated dependencies [67c55d0]
35
39
  - Updated dependencies [731c220]
36
40
  - Updated dependencies [c37d890]
37
41
  - Updated dependencies [041d2de]
38
42
  - Updated dependencies [4de4737]
43
+ - Updated dependencies [4d37822]
39
44
  - Updated dependencies [679c163]
40
45
  - Updated dependencies [0f24e20]
41
46
  - Updated dependencies [4cece2f]
@@ -43,8 +48,45 @@
43
48
  - Updated dependencies [66858d4]
44
49
  - Updated dependencies [19bc92c]
45
50
  - Updated dependencies [b8efbb9]
51
+ - Updated dependencies [71466e7]
46
52
  - Updated dependencies [0c99fbe]
47
- - @mastra/core@0.0.0-ai-v5-20250729012312
53
+ - @mastra/core@0.0.0-ai-v5-20250729181825
54
+
55
+ ## 0.10.17-alpha.3
56
+
57
+ ### Patch Changes
58
+
59
+ - 9802f42: Added types and tests to ensure client-js and hono endpoints can save memory messages where the input is either a v1 or v2 mastra message
60
+ - 1ac8f6b: deduplicate message
61
+ - @mastra/core@0.12.0-alpha.3
62
+
63
+ ## 0.10.17-alpha.2
64
+
65
+ ### Patch Changes
66
+
67
+ - aa2715b: process stream response error handling
68
+ - b8efbb9: feat: add flexible deleteMessages method to memory API
69
+ - Added `memory.deleteMessages(input)` method that accepts multiple input types:
70
+ - Single message ID as string: `deleteMessages('msg-123')`
71
+ - Array of message IDs: `deleteMessages(['msg-1', 'msg-2'])`
72
+ - Message object with id property: `deleteMessages({ id: 'msg-123' })`
73
+ - Array of message objects: `deleteMessages([{ id: 'msg-1' }, { id: 'msg-2' }])`
74
+ - Implemented in all storage adapters (LibSQL, PostgreSQL, Upstash, InMemory)
75
+ - Added REST API endpoint: `POST /api/memory/messages/delete`
76
+ - Updated client SDK: `thread.deleteMessages()` accepts all input types
77
+ - Updates thread timestamps when messages are deleted
78
+ - Added comprehensive test coverage and documentation
79
+
80
+ - Updated dependencies [27cc97a]
81
+ - Updated dependencies [41daa63]
82
+ - Updated dependencies [254a36b]
83
+ - Updated dependencies [0b89602]
84
+ - Updated dependencies [4d37822]
85
+ - Updated dependencies [ff9c125]
86
+ - Updated dependencies [b8efbb9]
87
+ - Updated dependencies [71466e7]
88
+ - Updated dependencies [0c99fbe]
89
+ - @mastra/core@0.12.0-alpha.2
48
90
 
49
91
  ## 0.10.17-alpha.1
50
92
 
package/dist/index.cjs CHANGED
@@ -741,7 +741,12 @@ var Agent = class extends BaseResource {
741
741
  this.processChatResponse({
742
742
  stream: streamForProcessing,
743
743
  update: ({ message }) => {
744
- messages.push(message);
744
+ const existingIndex = messages.findIndex((m) => m.id === message.id);
745
+ if (existingIndex !== -1) {
746
+ messages[existingIndex] = message;
747
+ } else {
748
+ messages.push(message);
749
+ }
745
750
  },
746
751
  onFinish: async ({ finishReason, message }) => {
747
752
  if (finishReason === "tool-calls") {
@@ -801,7 +806,7 @@ var Agent = class extends BaseResource {
801
806
  this.processStreamResponse(
802
807
  {
803
808
  ...processedParams,
804
- messages: [...messageArray, ...messages, lastMessage]
809
+ messages: [...messageArray, ...messages.filter((m) => m.id !== lastMessage.id), lastMessage]
805
810
  },
806
811
  writable
807
812
  ).catch((error) => {
package/dist/index.d.cts CHANGED
@@ -163,14 +163,14 @@ interface GetVectorIndexResponse {
163
163
  count: number;
164
164
  }
165
165
  interface SaveMessageToMemoryParams {
166
- messages: MastraMessageV1[];
166
+ messages: (MastraMessageV1 | MastraMessageV2)[];
167
167
  agentId: string;
168
168
  }
169
169
  interface SaveNetworkMessageToMemoryParams {
170
- messages: MastraMessageV1[];
170
+ messages: (MastraMessageV1 | MastraMessageV2)[];
171
171
  networkId: string;
172
172
  }
173
- type SaveMessageToMemoryResponse = MastraMessageV1[];
173
+ type SaveMessageToMemoryResponse = (MastraMessageV1 | MastraMessageV2)[];
174
174
  interface CreateMemoryThreadParams {
175
175
  title?: string;
176
176
  metadata?: Record<string, any>;
package/dist/index.d.ts CHANGED
@@ -163,14 +163,14 @@ interface GetVectorIndexResponse {
163
163
  count: number;
164
164
  }
165
165
  interface SaveMessageToMemoryParams {
166
- messages: MastraMessageV1[];
166
+ messages: (MastraMessageV1 | MastraMessageV2)[];
167
167
  agentId: string;
168
168
  }
169
169
  interface SaveNetworkMessageToMemoryParams {
170
- messages: MastraMessageV1[];
170
+ messages: (MastraMessageV1 | MastraMessageV2)[];
171
171
  networkId: string;
172
172
  }
173
- type SaveMessageToMemoryResponse = MastraMessageV1[];
173
+ type SaveMessageToMemoryResponse = (MastraMessageV1 | MastraMessageV2)[];
174
174
  interface CreateMemoryThreadParams {
175
175
  title?: string;
176
176
  metadata?: Record<string, any>;
package/dist/index.js CHANGED
@@ -735,7 +735,12 @@ var Agent = class extends BaseResource {
735
735
  this.processChatResponse({
736
736
  stream: streamForProcessing,
737
737
  update: ({ message }) => {
738
- messages.push(message);
738
+ const existingIndex = messages.findIndex((m) => m.id === message.id);
739
+ if (existingIndex !== -1) {
740
+ messages[existingIndex] = message;
741
+ } else {
742
+ messages.push(message);
743
+ }
739
744
  },
740
745
  onFinish: async ({ finishReason, message }) => {
741
746
  if (finishReason === "tool-calls") {
@@ -795,7 +800,7 @@ var Agent = class extends BaseResource {
795
800
  this.processStreamResponse(
796
801
  {
797
802
  ...processedParams,
798
- messages: [...messageArray, ...messages, lastMessage]
803
+ messages: [...messageArray, ...messages.filter((m) => m.id !== lastMessage.id), lastMessage]
799
804
  },
800
805
  writable
801
806
  ).catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/client-js",
3
- "version": "0.0.0-ai-v5-20250729012312",
3
+ "version": "0.0.0-ai-v5-20250729181825",
4
4
  "description": "The official TypeScript library for the Mastra Client API",
5
5
  "author": "",
6
6
  "type": "module",
@@ -34,7 +34,7 @@
34
34
  "rxjs": "7.8.1",
35
35
  "zod": "^3.25.67",
36
36
  "zod-to-json-schema": "^3.24.5",
37
- "@mastra/core": "0.0.0-ai-v5-20250729012312"
37
+ "@mastra/core": "0.0.0-ai-v5-20250729181825"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "zod": "^3.0.0"
@@ -48,7 +48,7 @@
48
48
  "tsup": "^8.5.0",
49
49
  "typescript": "^5.8.3",
50
50
  "vitest": "^3.2.4",
51
- "@internal/lint": "0.0.0-ai-v5-20250729012312"
51
+ "@internal/lint": "0.0.0-ai-v5-20250729181825"
52
52
  },
53
53
  "scripts": {
54
54
  "build": "tsup src/index.ts --format esm,cjs --dts --clean --treeshake=smallest --splitting",
package/src/index.test.ts CHANGED
@@ -310,6 +310,114 @@ describe('MastraClient Resources', () => {
310
310
  }
311
311
  });
312
312
 
313
+ it('should stream responses with tool calls', async () => {
314
+ const firstMockChunk = `0:"test "
315
+ 0:"response"
316
+ 9:{"toolCallId":"tool1","toolName":"testTool","args":{"arg1":"value1"}}
317
+ e:{"finishReason":"tool-calls","usage":{"promptTokens":1,"completionTokens":1},"isContinued":false}
318
+ d:{"finishReason":"tool-calls","usage":{"promptTokens":2,"completionTokens":2}}
319
+ `;
320
+
321
+ const secondMockChunk = `0:"final response"
322
+ e:{"finishReason":"stop","usage":{"promptTokens":2,"completionTokens":2},"isContinued":false}
323
+ d:{"finishReason":"stop","usage":{"promptTokens":2,"completionTokens":2}}
324
+ `;
325
+
326
+ const firstResponseBody = new ReadableStream({
327
+ start(controller) {
328
+ controller.enqueue(new TextEncoder().encode(firstMockChunk));
329
+ controller.close();
330
+ },
331
+ });
332
+
333
+ const secondResponseBody = new ReadableStream({
334
+ start(controller) {
335
+ controller.enqueue(new TextEncoder().encode(secondMockChunk));
336
+ controller.close();
337
+ },
338
+ });
339
+
340
+ (global.fetch as any)
341
+ .mockResolvedValueOnce(
342
+ new Response(firstResponseBody, {
343
+ status: 200,
344
+ headers: new Headers({ 'Content-Type': 'text/event-stream' }),
345
+ }),
346
+ )
347
+ .mockResolvedValueOnce(
348
+ new Response(secondResponseBody, {
349
+ status: 200,
350
+ headers: new Headers({ 'Content-Type': 'text/event-stream' }),
351
+ }),
352
+ );
353
+
354
+ const response = await agent.stream({
355
+ messages: [
356
+ {
357
+ role: 'user',
358
+ content: 'test',
359
+ },
360
+ ],
361
+ clientTools: {
362
+ testTool: {
363
+ id: 'testTool',
364
+ description: 'Test Tool',
365
+ inputSchema: {
366
+ type: 'object',
367
+ properties: {
368
+ arg1: { type: 'string' },
369
+ },
370
+ },
371
+ execute: async () => {
372
+ return 'test result';
373
+ },
374
+ },
375
+ },
376
+ });
377
+
378
+ expect(response.body).toBeInstanceOf(ReadableStream);
379
+ const reader = response?.body?.getReader();
380
+ expect(reader).toBeDefined();
381
+
382
+ let output = '';
383
+ if (reader) {
384
+ while (true) {
385
+ const { value, done } = await reader.read();
386
+ if (done) break;
387
+ output += new TextDecoder().decode(value);
388
+ }
389
+ }
390
+
391
+ expect(global.fetch).toHaveBeenCalledTimes(2);
392
+
393
+ const [secondUrl, secondConfig] = (global.fetch as any).mock.calls[1];
394
+ expect(secondUrl).toBe(`${clientOptions.baseUrl}/api/agents/test-agent/stream`);
395
+
396
+ const secondRequestBody = JSON.parse(secondConfig.body);
397
+ expect(secondRequestBody.messages).toHaveLength(2);
398
+ expect(secondRequestBody.messages[0].content).toBe('test');
399
+ expect(secondRequestBody.messages[1].content).toBe('test response');
400
+ expect(secondRequestBody.messages[1].parts).toEqual([
401
+ {
402
+ type: 'text',
403
+ text: 'test response',
404
+ },
405
+ {
406
+ type: 'tool-invocation',
407
+ toolInvocation: {
408
+ state: 'result',
409
+ step: 0,
410
+ toolCallId: 'tool1',
411
+ toolName: 'testTool',
412
+ args: {
413
+ arg1: 'value1',
414
+ },
415
+ result: 'test result',
416
+ },
417
+ },
418
+ ]);
419
+ });
420
+
313
421
  it('should get agent tool', async () => {
314
422
  const mockResponse = {
315
423
  id: 'tool1',
@@ -632,7 +632,13 @@ export class Agent extends BaseResource {
632
632
  this.processChatResponse({
633
633
  stream: streamForProcessing,
634
634
  update: ({ message }) => {
635
- messages.push(message);
635
+ const existingIndex = messages.findIndex(m => m.id === message.id);
636
+
637
+ if (existingIndex !== -1) {
638
+ messages[existingIndex] = message;
639
+ } else {
640
+ messages.push(message);
641
+ }
636
642
  },
637
643
  onFinish: async ({ finishReason, message }) => {
638
644
  if (finishReason === 'tool-calls') {
@@ -711,7 +717,7 @@ export class Agent extends BaseResource {
711
717
  this.processStreamResponse(
712
718
  {
713
719
  ...processedParams,
714
- messages: [...messageArray, ...messages, lastMessage],
720
+ messages: [...messageArray, ...messages.filter(m => m.id !== lastMessage.id), lastMessage],
715
721
  },
716
722
  writable,
717
723
  ).catch(error => {
package/src/types.ts CHANGED
@@ -198,16 +198,16 @@ export interface GetVectorIndexResponse {
198
198
  }
199
199
 
200
200
  export interface SaveMessageToMemoryParams {
201
- messages: MastraMessageV1[];
201
+ messages: (MastraMessageV1 | MastraMessageV2)[];
202
202
  agentId: string;
203
203
  }
204
204
 
205
205
  export interface SaveNetworkMessageToMemoryParams {
206
- messages: MastraMessageV1[];
206
+ messages: (MastraMessageV1 | MastraMessageV2)[];
207
207
  networkId: string;
208
208
  }
209
209
 
210
- export type SaveMessageToMemoryResponse = MastraMessageV1[];
210
+ export type SaveMessageToMemoryResponse = (MastraMessageV1 | MastraMessageV2)[];
211
211
 
212
212
  export interface CreateMemoryThreadParams {
213
213
  title?: string;
@@ -0,0 +1,180 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import type { MastraMessageV1, MastraMessageV2 } from '@mastra/core';
3
+ import { MastraClient } from './client';
4
+
5
+ describe('V2 Message Format Support', () => {
6
+ let client: MastraClient;
7
+ const agentId = 'test-agent';
8
+
9
+ beforeEach(() => {
10
+ global.fetch = vi.fn();
11
+ client = new MastraClient({
12
+ baseUrl: 'http://localhost:3000',
13
+ });
14
+ });
15
+
16
+ it('should send v1 messages successfully', async () => {
17
+ const v1Messages: MastraMessageV1[] = [
18
+ {
19
+ id: 'msg-v1-1',
20
+ role: 'user',
21
+ content: 'Hello from v1!',
22
+ type: 'text',
23
+ createdAt: new Date(),
24
+ threadId: 'thread-123',
25
+ resourceId: 'resource-123',
26
+ },
27
+ ];
28
+
29
+ (global.fetch as any).mockResolvedValueOnce({
30
+ ok: true,
31
+ json: async () => v1Messages,
32
+ });
33
+
34
+ const result = await client.saveMessageToMemory({
35
+ agentId,
36
+ messages: v1Messages,
37
+ });
38
+
39
+ expect(result).toEqual(v1Messages);
40
+ expect(global.fetch).toHaveBeenCalledWith(
41
+ expect.stringContaining('/api/memory/save-messages'),
42
+ expect.objectContaining({
43
+ method: 'POST',
44
+ body: JSON.stringify({ agentId, messages: v1Messages }),
45
+ }),
46
+ );
47
+ });
48
+
49
+ it('should send v2 messages successfully', async () => {
50
+ const v2Messages: MastraMessageV2[] = [
51
+ {
52
+ id: 'msg-v2-1',
53
+ role: 'assistant',
54
+ createdAt: new Date(),
55
+ threadId: 'thread-123',
56
+ resourceId: 'resource-123',
57
+ content: {
58
+ format: 2,
59
+ parts: [{ type: 'text', text: 'Hello from v2!' }],
60
+ content: 'Hello from v2!',
61
+ },
62
+ },
63
+ ];
64
+
65
+ (global.fetch as any).mockResolvedValueOnce({
66
+ ok: true,
67
+ json: async () => v2Messages,
68
+ });
69
+
70
+ const result = await client.saveMessageToMemory({
71
+ agentId,
72
+ messages: v2Messages,
73
+ });
74
+
75
+ expect(result).toEqual(v2Messages);
76
+ expect(global.fetch).toHaveBeenCalledWith(
77
+ expect.stringContaining('/api/memory/save-messages'),
78
+ expect.objectContaining({
79
+ method: 'POST',
80
+ body: JSON.stringify({ agentId, messages: v2Messages }),
81
+ }),
82
+ );
83
+ });
84
+
85
+ it('should send mixed v1 and v2 messages successfully', async () => {
86
+ const mixedMessages: (MastraMessageV1 | MastraMessageV2)[] = [
87
+ {
88
+ id: 'msg-v1-1',
89
+ role: 'user',
90
+ content: 'Question in v1 format',
91
+ type: 'text',
92
+ createdAt: new Date(),
93
+ threadId: 'thread-123',
94
+ resourceId: 'resource-123',
95
+ },
96
+ {
97
+ id: 'msg-v2-1',
98
+ role: 'assistant',
99
+ createdAt: new Date(),
100
+ threadId: 'thread-123',
101
+ resourceId: 'resource-123',
102
+ content: {
103
+ format: 2,
104
+ parts: [
105
+ { type: 'text', text: 'Answer in v2 format' },
106
+ {
107
+ type: 'tool-invocation',
108
+ toolInvocation: {
109
+ state: 'result' as const,
110
+ toolCallId: 'call-123',
111
+ toolName: 'calculator',
112
+ args: { a: 1, b: 2 },
113
+ result: '3',
114
+ },
115
+ },
116
+ ],
117
+ toolInvocations: [
118
+ {
119
+ state: 'result' as const,
120
+ toolCallId: 'call-123',
121
+ toolName: 'calculator',
122
+ args: { a: 1, b: 2 },
123
+ result: '3',
124
+ },
125
+ ],
126
+ },
127
+ },
128
+ ];
129
+
130
+ (global.fetch as any).mockResolvedValueOnce({
131
+ ok: true,
132
+ json: async () => mixedMessages,
133
+ });
134
+
135
+ const result = await client.saveMessageToMemory({
136
+ agentId,
137
+ messages: mixedMessages,
138
+ });
139
+
140
+ expect(result).toEqual(mixedMessages);
141
+ expect(global.fetch).toHaveBeenCalledWith(
142
+ expect.stringContaining('/api/memory/save-messages'),
143
+ expect.objectContaining({
144
+ method: 'POST',
145
+ body: JSON.stringify({ agentId, messages: mixedMessages }),
146
+ }),
147
+ );
148
+ });
149
+
150
+ it('should handle v2 messages with attachments', async () => {
151
+ const v2MessageWithAttachments: MastraMessageV2 = {
152
+ id: 'msg-v2-att',
153
+ role: 'user',
154
+ createdAt: new Date(),
155
+ threadId: 'thread-123',
156
+ resourceId: 'resource-123',
157
+ content: {
158
+ format: 2,
159
+ parts: [
160
+ { type: 'text', text: 'Check out this image:' },
161
+ { type: 'file', data: 'data:image/png;base64,iVBORw0...', mimeType: 'image/png' },
162
+ ],
163
+ experimental_attachments: [{ url: 'data:image/png;base64,iVBORw0...', contentType: 'image/png' }],
164
+ },
165
+ };
166
+
167
+ (global.fetch as any).mockResolvedValueOnce({
168
+ ok: true,
169
+ json: async () => [v2MessageWithAttachments],
170
+ });
171
+
172
+ const result = await client.saveMessageToMemory({
173
+ agentId,
174
+ messages: [v2MessageWithAttachments],
175
+ });
176
+
177
+ expect(result).toHaveLength(1);
178
+ expect(result[0]).toEqual(v2MessageWithAttachments);
179
+ });
180
+ });
@@ -1,19 +0,0 @@
1
-
2
- > @mastra/client-js@0.10.17-alpha.1 build /home/runner/work/mastra/mastra/client-sdks/client-js
3
- > tsup src/index.ts --format esm,cjs --dts --clean --treeshake=smallest --splitting
4
-
5
- CLI Building entry: src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.0
8
- CLI Target: es2022
9
- CLI Cleaning output folder
10
- ESM Build start
11
- CJS Build start
12
- CJS dist/index.cjs 75.34 KB
13
- CJS ⚡️ Build success in 2299ms
14
- ESM dist/index.js 75.03 KB
15
- ESM ⚡️ Build success in 2304ms
16
- DTS Build start
17
- DTS ⚡️ Build success in 19159ms
18
- DTS dist/index.d.ts 47.09 KB
19
- DTS dist/index.d.cts 47.09 KB