@mastra/client-js 0.10.17-alpha.1 → 0.10.17-alpha.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @mastra/client-js@0.10.17-alpha.1 build /home/runner/work/mastra/mastra/client-sdks/client-js
2
+ > @mastra/client-js@0.10.17-alpha.2 build /home/runner/work/mastra/mastra/client-sdks/client-js
3
3
  > tsup src/index.ts --format esm,cjs --dts --clean --treeshake=smallest --splitting
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -9,11 +9,11 @@
9
9
  CLI Cleaning output folder
10
10
  ESM Build start
11
11
  CJS Build start
12
- CJS dist/index.cjs 74.04 KB
13
- CJS ⚡️ Build success in 2302ms
14
- ESM dist/index.js 73.73 KB
15
- ESM ⚡️ Build success in 2304ms
12
+ ESM dist/index.js 74.97 KB
13
+ ESM ⚡️ Build success in 1712ms
14
+ CJS dist/index.cjs 75.29 KB
15
+ CJS ⚡️ Build success in 1713ms
16
16
  DTS Build start
17
- DTS ⚡️ Build success in 19056ms
18
- DTS dist/index.d.ts 46.21 KB
19
- DTS dist/index.d.cts 46.21 KB
17
+ DTS ⚡️ Build success in 16680ms
18
+ DTS dist/index.d.ts 47.13 KB
19
+ DTS dist/index.d.cts 47.13 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @mastra/client-js
2
2
 
3
+ ## 0.10.17-alpha.2
4
+
5
+ ### Patch Changes
6
+
7
+ - aa2715b: process stream response error handling
8
+ - b8efbb9: feat: add flexible deleteMessages method to memory API
9
+ - Added `memory.deleteMessages(input)` method that accepts multiple input types:
10
+ - Single message ID as string: `deleteMessages('msg-123')`
11
+ - Array of message IDs: `deleteMessages(['msg-1', 'msg-2'])`
12
+ - Message object with id property: `deleteMessages({ id: 'msg-123' })`
13
+ - Array of message objects: `deleteMessages([{ id: 'msg-1' }, { id: 'msg-2' }])`
14
+ - Implemented in all storage adapters (LibSQL, PostgreSQL, Upstash, InMemory)
15
+ - Added REST API endpoint: `POST /api/memory/messages/delete`
16
+ - Updated client SDK: `thread.deleteMessages()` accepts all input types
17
+ - Updates thread timestamps when messages are deleted
18
+ - Added comprehensive test coverage and documentation
19
+
20
+ - Updated dependencies [27cc97a]
21
+ - Updated dependencies [41daa63]
22
+ - Updated dependencies [254a36b]
23
+ - Updated dependencies [0b89602]
24
+ - Updated dependencies [4d37822]
25
+ - Updated dependencies [ff9c125]
26
+ - Updated dependencies [b8efbb9]
27
+ - Updated dependencies [71466e7]
28
+ - Updated dependencies [0c99fbe]
29
+ - @mastra/core@0.12.0-alpha.2
30
+
3
31
  ## 0.10.17-alpha.1
4
32
 
5
33
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -804,7 +804,9 @@ var Agent = class extends BaseResource {
804
804
  messages: [...messageArray, ...messages, lastMessage]
805
805
  },
806
806
  writable
807
- );
807
+ ).catch((error) => {
808
+ console.error("Error processing stream response:", error);
809
+ });
808
810
  }
809
811
  }
810
812
  } else {
@@ -814,6 +816,8 @@ var Agent = class extends BaseResource {
814
816
  }
815
817
  },
816
818
  lastMessage: void 0
819
+ }).catch((error) => {
820
+ console.error("Error processing stream response:", error);
817
821
  });
818
822
  } catch (error) {
819
823
  console.error("Error processing stream response:", error);
@@ -977,6 +981,21 @@ var MemoryThread = class extends BaseResource {
977
981
  });
978
982
  return this.request(`/api/memory/threads/${this.threadId}/messages/paginated?${query.toString()}`);
979
983
  }
984
+ /**
985
+ * Deletes one or more messages from the thread
986
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
987
+ * message object with id property, or array of message objects
988
+ * @returns Promise containing deletion result
989
+ */
990
+ deleteMessages(messageIds) {
991
+ const query = new URLSearchParams({
992
+ agentId: this.agentId
993
+ });
994
+ return this.request(`/api/memory/messages/delete?${query.toString()}`, {
995
+ method: "POST",
996
+ body: { messageIds }
997
+ });
998
+ }
980
999
  };
981
1000
 
982
1001
  // src/resources/vector.ts
@@ -1725,6 +1744,21 @@ var NetworkMemoryThread = class extends BaseResource {
1725
1744
  });
1726
1745
  return this.request(`/api/memory/network/threads/${this.threadId}/messages?${query.toString()}`);
1727
1746
  }
1747
+ /**
1748
+ * Deletes one or more messages from the thread
1749
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
1750
+ * message object with id property, or array of message objects
1751
+ * @returns Promise containing deletion result
1752
+ */
1753
+ deleteMessages(messageIds) {
1754
+ const query = new URLSearchParams({
1755
+ networkId: this.networkId
1756
+ });
1757
+ return this.request(`/api/memory/network/messages/delete?${query.toString()}`, {
1758
+ method: "POST",
1759
+ body: { messageIds }
1760
+ });
1761
+ }
1728
1762
  };
1729
1763
 
1730
1764
  // src/resources/vNextNetwork.ts
package/dist/index.d.cts CHANGED
@@ -601,6 +601,20 @@ declare class MemoryThread extends BaseResource {
601
601
  * @returns Promise containing paginated thread messages with pagination metadata (total, page, perPage, hasMore)
602
602
  */
603
603
  getMessagesPaginated({ selectBy, ...rest }: GetMemoryThreadMessagesPaginatedParams): Promise<GetMemoryThreadMessagesPaginatedResponse>;
604
+ /**
605
+ * Deletes one or more messages from the thread
606
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
607
+ * message object with id property, or array of message objects
608
+ * @returns Promise containing deletion result
609
+ */
610
+ deleteMessages(messageIds: string | string[] | {
611
+ id: string;
612
+ } | {
613
+ id: string;
614
+ }[]): Promise<{
615
+ success: boolean;
616
+ message: string;
617
+ }>;
604
618
  }
605
619
 
606
620
  declare class Vector extends BaseResource {
@@ -998,6 +1012,20 @@ declare class NetworkMemoryThread extends BaseResource {
998
1012
  * @returns Promise containing thread messages and UI messages
999
1013
  */
1000
1014
  getMessages(params?: GetMemoryThreadMessagesParams): Promise<GetMemoryThreadMessagesResponse>;
1015
+ /**
1016
+ * Deletes one or more messages from the thread
1017
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
1018
+ * message object with id property, or array of message objects
1019
+ * @returns Promise containing deletion result
1020
+ */
1021
+ deleteMessages(messageIds: string | string[] | {
1022
+ id: string;
1023
+ } | {
1024
+ id: string;
1025
+ }[]): Promise<{
1026
+ success: boolean;
1027
+ message: string;
1028
+ }>;
1001
1029
  }
1002
1030
 
1003
1031
  declare class VNextNetwork extends BaseResource {
package/dist/index.d.ts CHANGED
@@ -601,6 +601,20 @@ declare class MemoryThread extends BaseResource {
601
601
  * @returns Promise containing paginated thread messages with pagination metadata (total, page, perPage, hasMore)
602
602
  */
603
603
  getMessagesPaginated({ selectBy, ...rest }: GetMemoryThreadMessagesPaginatedParams): Promise<GetMemoryThreadMessagesPaginatedResponse>;
604
+ /**
605
+ * Deletes one or more messages from the thread
606
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
607
+ * message object with id property, or array of message objects
608
+ * @returns Promise containing deletion result
609
+ */
610
+ deleteMessages(messageIds: string | string[] | {
611
+ id: string;
612
+ } | {
613
+ id: string;
614
+ }[]): Promise<{
615
+ success: boolean;
616
+ message: string;
617
+ }>;
604
618
  }
605
619
 
606
620
  declare class Vector extends BaseResource {
@@ -998,6 +1012,20 @@ declare class NetworkMemoryThread extends BaseResource {
998
1012
  * @returns Promise containing thread messages and UI messages
999
1013
  */
1000
1014
  getMessages(params?: GetMemoryThreadMessagesParams): Promise<GetMemoryThreadMessagesResponse>;
1015
+ /**
1016
+ * Deletes one or more messages from the thread
1017
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
1018
+ * message object with id property, or array of message objects
1019
+ * @returns Promise containing deletion result
1020
+ */
1021
+ deleteMessages(messageIds: string | string[] | {
1022
+ id: string;
1023
+ } | {
1024
+ id: string;
1025
+ }[]): Promise<{
1026
+ success: boolean;
1027
+ message: string;
1028
+ }>;
1001
1029
  }
1002
1030
 
1003
1031
  declare class VNextNetwork extends BaseResource {
package/dist/index.js CHANGED
@@ -798,7 +798,9 @@ var Agent = class extends BaseResource {
798
798
  messages: [...messageArray, ...messages, lastMessage]
799
799
  },
800
800
  writable
801
- );
801
+ ).catch((error) => {
802
+ console.error("Error processing stream response:", error);
803
+ });
802
804
  }
803
805
  }
804
806
  } else {
@@ -808,6 +810,8 @@ var Agent = class extends BaseResource {
808
810
  }
809
811
  },
810
812
  lastMessage: void 0
813
+ }).catch((error) => {
814
+ console.error("Error processing stream response:", error);
811
815
  });
812
816
  } catch (error) {
813
817
  console.error("Error processing stream response:", error);
@@ -971,6 +975,21 @@ var MemoryThread = class extends BaseResource {
971
975
  });
972
976
  return this.request(`/api/memory/threads/${this.threadId}/messages/paginated?${query.toString()}`);
973
977
  }
978
+ /**
979
+ * Deletes one or more messages from the thread
980
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
981
+ * message object with id property, or array of message objects
982
+ * @returns Promise containing deletion result
983
+ */
984
+ deleteMessages(messageIds) {
985
+ const query = new URLSearchParams({
986
+ agentId: this.agentId
987
+ });
988
+ return this.request(`/api/memory/messages/delete?${query.toString()}`, {
989
+ method: "POST",
990
+ body: { messageIds }
991
+ });
992
+ }
974
993
  };
975
994
 
976
995
  // src/resources/vector.ts
@@ -1719,6 +1738,21 @@ var NetworkMemoryThread = class extends BaseResource {
1719
1738
  });
1720
1739
  return this.request(`/api/memory/network/threads/${this.threadId}/messages?${query.toString()}`);
1721
1740
  }
1741
+ /**
1742
+ * Deletes one or more messages from the thread
1743
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
1744
+ * message object with id property, or array of message objects
1745
+ * @returns Promise containing deletion result
1746
+ */
1747
+ deleteMessages(messageIds) {
1748
+ const query = new URLSearchParams({
1749
+ networkId: this.networkId
1750
+ });
1751
+ return this.request(`/api/memory/network/messages/delete?${query.toString()}`, {
1752
+ method: "POST",
1753
+ body: { messageIds }
1754
+ });
1755
+ }
1722
1756
  };
1723
1757
 
1724
1758
  // src/resources/vNextNetwork.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/client-js",
3
- "version": "0.10.17-alpha.1",
3
+ "version": "0.10.17-alpha.2",
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.12.0-alpha.1"
37
+ "@mastra/core": "0.12.0-alpha.2"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "zod": "^3.0.0"
@@ -714,7 +714,9 @@ export class Agent extends BaseResource {
714
714
  messages: [...messageArray, ...messages, lastMessage],
715
715
  },
716
716
  writable,
717
- );
717
+ ).catch(error => {
718
+ console.error('Error processing stream response:', error);
719
+ });
718
720
  }
719
721
  }
720
722
  } else {
@@ -724,6 +726,8 @@ export class Agent extends BaseResource {
724
726
  }
725
727
  },
726
728
  lastMessage: undefined,
729
+ }).catch(error => {
730
+ console.error('Error processing stream response:', error);
727
731
  });
728
732
  } catch (error) {
729
733
  console.error('Error processing stream response:', error);
@@ -0,0 +1,285 @@
1
+ import { describe, expect, beforeEach, it, vi } from 'vitest';
2
+ import { MemoryThread } from './memory-thread';
3
+ import type { ClientOptions } from '../types';
4
+
5
+ // Mock fetch globally
6
+ global.fetch = vi.fn();
7
+
8
+ describe('MemoryThread', () => {
9
+ let thread: MemoryThread;
10
+ const clientOptions: ClientOptions = {
11
+ baseUrl: 'http://localhost:4111',
12
+ headers: {
13
+ Authorization: 'Bearer test-key',
14
+ },
15
+ };
16
+ const threadId = 'test-thread-id';
17
+ const agentId = 'test-agent-id';
18
+
19
+ beforeEach(() => {
20
+ vi.clearAllMocks();
21
+ thread = new MemoryThread(clientOptions, threadId, agentId);
22
+ });
23
+
24
+ const mockFetchResponse = (data: any) => {
25
+ (global.fetch as any).mockResolvedValueOnce({
26
+ ok: true,
27
+ status: 200,
28
+ json: async () => data,
29
+ headers: new Headers({
30
+ 'content-type': 'application/json',
31
+ }),
32
+ });
33
+ };
34
+
35
+ describe('get', () => {
36
+ it('should retrieve thread details', async () => {
37
+ const mockThread = {
38
+ id: threadId,
39
+ title: 'Test Thread',
40
+ metadata: { test: true },
41
+ createdAt: new Date().toISOString(),
42
+ updatedAt: new Date().toISOString(),
43
+ };
44
+
45
+ mockFetchResponse(mockThread);
46
+
47
+ const result = await thread.get();
48
+
49
+ expect(global.fetch).toHaveBeenCalledWith(
50
+ `http://localhost:4111/api/memory/threads/${threadId}?agentId=${agentId}`,
51
+ expect.objectContaining({
52
+ headers: expect.objectContaining({
53
+ Authorization: 'Bearer test-key',
54
+ }),
55
+ }),
56
+ );
57
+ expect(result).toEqual(mockThread);
58
+ });
59
+ });
60
+
61
+ describe('update', () => {
62
+ it('should update thread properties', async () => {
63
+ const updateParams = {
64
+ title: 'Updated Title',
65
+ metadata: { updated: true },
66
+ resourceid: 'resource-1',
67
+ };
68
+
69
+ const mockUpdatedThread = {
70
+ id: threadId,
71
+ ...updateParams,
72
+ createdAt: new Date().toISOString(),
73
+ updatedAt: new Date().toISOString(),
74
+ };
75
+
76
+ mockFetchResponse(mockUpdatedThread);
77
+
78
+ const result = await thread.update(updateParams);
79
+
80
+ expect(global.fetch).toHaveBeenCalledWith(
81
+ `http://localhost:4111/api/memory/threads/${threadId}?agentId=${agentId}`,
82
+ expect.objectContaining({
83
+ method: 'PATCH',
84
+ headers: expect.objectContaining({
85
+ Authorization: 'Bearer test-key',
86
+ }),
87
+ body: JSON.stringify(updateParams),
88
+ }),
89
+ );
90
+ expect(result).toEqual(mockUpdatedThread);
91
+ });
92
+ });
93
+
94
+ describe('delete', () => {
95
+ it('should delete the thread', async () => {
96
+ const mockResponse = { result: 'Thread deleted' };
97
+ mockFetchResponse(mockResponse);
98
+
99
+ const result = await thread.delete();
100
+
101
+ expect(global.fetch).toHaveBeenCalledWith(
102
+ `http://localhost:4111/api/memory/threads/${threadId}?agentId=${agentId}`,
103
+ expect.objectContaining({
104
+ method: 'DELETE',
105
+ headers: expect.objectContaining({
106
+ Authorization: 'Bearer test-key',
107
+ }),
108
+ }),
109
+ );
110
+ expect(result).toEqual(mockResponse);
111
+ });
112
+ });
113
+
114
+ describe('getMessages', () => {
115
+ it('should retrieve thread messages', async () => {
116
+ const mockMessages = {
117
+ messages: [
118
+ { id: 'msg-1', content: 'Hello', role: 'user' },
119
+ { id: 'msg-2', content: 'Hi there', role: 'assistant' },
120
+ ],
121
+ uiMessages: [
122
+ { id: 'msg-1', content: 'Hello', role: 'user' },
123
+ { id: 'msg-2', content: 'Hi there', role: 'assistant' },
124
+ ],
125
+ };
126
+
127
+ mockFetchResponse(mockMessages);
128
+
129
+ const result = await thread.getMessages();
130
+
131
+ expect(global.fetch).toHaveBeenCalledWith(
132
+ `http://localhost:4111/api/memory/threads/${threadId}/messages?agentId=${agentId}`,
133
+ expect.objectContaining({
134
+ headers: expect.objectContaining({
135
+ Authorization: 'Bearer test-key',
136
+ }),
137
+ }),
138
+ );
139
+ expect(result).toEqual(mockMessages);
140
+ });
141
+
142
+ it('should retrieve thread messages with limit', async () => {
143
+ const mockMessages = {
144
+ messages: [{ id: 'msg-1', content: 'Hello', role: 'user' }],
145
+ uiMessages: [{ id: 'msg-1', content: 'Hello', role: 'user' }],
146
+ };
147
+
148
+ mockFetchResponse(mockMessages);
149
+
150
+ const result = await thread.getMessages({ limit: 5 });
151
+
152
+ expect(global.fetch).toHaveBeenCalledWith(
153
+ `http://localhost:4111/api/memory/threads/${threadId}/messages?agentId=${agentId}&limit=5`,
154
+ expect.objectContaining({
155
+ headers: expect.objectContaining({
156
+ Authorization: 'Bearer test-key',
157
+ }),
158
+ }),
159
+ );
160
+ expect(result).toEqual(mockMessages);
161
+ });
162
+ });
163
+
164
+ describe('deleteMessages', () => {
165
+ it('should delete a single message by string ID', async () => {
166
+ const messageId = 'test-message-id';
167
+ const mockResponse = { success: true, message: '1 message deleted successfully' };
168
+
169
+ mockFetchResponse(mockResponse);
170
+
171
+ const result = await thread.deleteMessages(messageId);
172
+
173
+ expect(global.fetch).toHaveBeenCalledWith(
174
+ `http://localhost:4111/api/memory/messages/delete?agentId=${agentId}`,
175
+ expect.objectContaining({
176
+ method: 'POST',
177
+ headers: expect.objectContaining({
178
+ 'content-type': 'application/json',
179
+ Authorization: 'Bearer test-key',
180
+ }),
181
+ body: JSON.stringify({ messageIds: messageId }),
182
+ }),
183
+ );
184
+ expect(result).toEqual(mockResponse);
185
+ });
186
+
187
+ it('should delete multiple messages by array of string IDs', async () => {
188
+ const messageIds = ['msg-1', 'msg-2', 'msg-3'];
189
+ const mockResponse = { success: true, message: '3 messages deleted successfully' };
190
+
191
+ mockFetchResponse(mockResponse);
192
+
193
+ const result = await thread.deleteMessages(messageIds);
194
+
195
+ expect(global.fetch).toHaveBeenCalledWith(
196
+ `http://localhost:4111/api/memory/messages/delete?agentId=${agentId}`,
197
+ expect.objectContaining({
198
+ method: 'POST',
199
+ headers: expect.objectContaining({
200
+ 'content-type': 'application/json',
201
+ Authorization: 'Bearer test-key',
202
+ }),
203
+ body: JSON.stringify({ messageIds }),
204
+ }),
205
+ );
206
+ expect(result).toEqual(mockResponse);
207
+ });
208
+
209
+ it('should delete a message by object with id property', async () => {
210
+ const messageObj = { id: 'test-message-id' };
211
+ const mockResponse = { success: true, message: '1 message deleted successfully' };
212
+
213
+ mockFetchResponse(mockResponse);
214
+
215
+ const result = await thread.deleteMessages(messageObj);
216
+
217
+ expect(global.fetch).toHaveBeenCalledWith(
218
+ `http://localhost:4111/api/memory/messages/delete?agentId=${agentId}`,
219
+ expect.objectContaining({
220
+ method: 'POST',
221
+ headers: expect.objectContaining({
222
+ 'content-type': 'application/json',
223
+ Authorization: 'Bearer test-key',
224
+ }),
225
+ body: JSON.stringify({ messageIds: messageObj }),
226
+ }),
227
+ );
228
+ expect(result).toEqual(mockResponse);
229
+ });
230
+
231
+ it('should delete messages by array of objects', async () => {
232
+ const messageObjs = [{ id: 'msg-1' }, { id: 'msg-2' }];
233
+ const mockResponse = { success: true, message: '2 messages deleted successfully' };
234
+
235
+ mockFetchResponse(mockResponse);
236
+
237
+ const result = await thread.deleteMessages(messageObjs);
238
+
239
+ expect(global.fetch).toHaveBeenCalledWith(
240
+ `http://localhost:4111/api/memory/messages/delete?agentId=${agentId}`,
241
+ expect.objectContaining({
242
+ method: 'POST',
243
+ headers: expect.objectContaining({
244
+ 'content-type': 'application/json',
245
+ Authorization: 'Bearer test-key',
246
+ }),
247
+ body: JSON.stringify({ messageIds: messageObjs }),
248
+ }),
249
+ );
250
+ expect(result).toEqual(mockResponse);
251
+ });
252
+
253
+ it('should handle empty array', async () => {
254
+ const messageIds: string[] = [];
255
+
256
+ (global.fetch as any).mockResolvedValueOnce({
257
+ ok: false,
258
+ status: 400,
259
+ statusText: 'Bad Request',
260
+ json: async () => ({ error: 'messageIds array cannot be empty' }),
261
+ headers: new Headers({
262
+ 'content-type': 'application/json',
263
+ }),
264
+ });
265
+
266
+ await expect(thread.deleteMessages(messageIds)).rejects.toThrow();
267
+ });
268
+
269
+ it('should handle bulk delete errors', async () => {
270
+ const messageIds = ['msg-1', 'msg-2'];
271
+
272
+ (global.fetch as any).mockResolvedValueOnce({
273
+ ok: false,
274
+ status: 500,
275
+ statusText: 'Internal Server Error',
276
+ json: async () => ({ error: 'Database error' }),
277
+ headers: new Headers({
278
+ 'content-type': 'application/json',
279
+ }),
280
+ });
281
+
282
+ await expect(thread.deleteMessages(messageIds)).rejects.toThrow();
283
+ });
284
+ });
285
+ });
@@ -78,4 +78,22 @@ export class MemoryThread extends BaseResource {
78
78
  });
79
79
  return this.request(`/api/memory/threads/${this.threadId}/messages/paginated?${query.toString()}`);
80
80
  }
81
+
82
+ /**
83
+ * Deletes one or more messages from the thread
84
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
85
+ * message object with id property, or array of message objects
86
+ * @returns Promise containing deletion result
87
+ */
88
+ deleteMessages(
89
+ messageIds: string | string[] | { id: string } | { id: string }[],
90
+ ): Promise<{ success: boolean; message: string }> {
91
+ const query = new URLSearchParams({
92
+ agentId: this.agentId,
93
+ });
94
+ return this.request(`/api/memory/messages/delete?${query.toString()}`, {
95
+ method: 'POST',
96
+ body: { messageIds },
97
+ });
98
+ }
81
99
  }
@@ -0,0 +1,269 @@
1
+ import { describe, expect, beforeEach, it, vi } from 'vitest';
2
+ import { NetworkMemoryThread } from './network-memory-thread';
3
+ import type { ClientOptions } from '../types';
4
+
5
+ // Mock fetch globally
6
+ global.fetch = vi.fn();
7
+
8
+ describe('NetworkMemoryThread', () => {
9
+ let thread: NetworkMemoryThread;
10
+ const clientOptions: ClientOptions = {
11
+ baseUrl: 'http://localhost:4111',
12
+ headers: {
13
+ Authorization: 'Bearer test-key',
14
+ },
15
+ };
16
+ const threadId = 'test-thread-id';
17
+ const networkId = 'test-network-id';
18
+
19
+ beforeEach(() => {
20
+ vi.clearAllMocks();
21
+ thread = new NetworkMemoryThread(clientOptions, threadId, networkId);
22
+ });
23
+
24
+ const mockFetchResponse = (data: any) => {
25
+ (global.fetch as any).mockResolvedValueOnce({
26
+ ok: true,
27
+ status: 200,
28
+ json: async () => data,
29
+ headers: new Headers({
30
+ 'content-type': 'application/json',
31
+ }),
32
+ });
33
+ };
34
+
35
+ describe('get', () => {
36
+ it('should retrieve thread details', async () => {
37
+ const mockThread = {
38
+ id: threadId,
39
+ title: 'Test Thread',
40
+ metadata: { test: true },
41
+ createdAt: new Date().toISOString(),
42
+ updatedAt: new Date().toISOString(),
43
+ };
44
+
45
+ mockFetchResponse(mockThread);
46
+
47
+ const result = await thread.get();
48
+
49
+ expect(global.fetch).toHaveBeenCalledWith(
50
+ `http://localhost:4111/api/memory/network/threads/${threadId}?networkId=${networkId}`,
51
+ expect.objectContaining({
52
+ headers: expect.objectContaining({
53
+ Authorization: 'Bearer test-key',
54
+ }),
55
+ }),
56
+ );
57
+ expect(result).toEqual(mockThread);
58
+ });
59
+ });
60
+
61
+ describe('update', () => {
62
+ it('should update thread properties', async () => {
63
+ const updateParams = {
64
+ title: 'Updated Title',
65
+ metadata: { updated: true },
66
+ resourceid: 'resource-1',
67
+ };
68
+
69
+ const mockUpdatedThread = {
70
+ id: threadId,
71
+ ...updateParams,
72
+ createdAt: new Date().toISOString(),
73
+ updatedAt: new Date().toISOString(),
74
+ };
75
+
76
+ mockFetchResponse(mockUpdatedThread);
77
+
78
+ const result = await thread.update(updateParams);
79
+
80
+ expect(global.fetch).toHaveBeenCalledWith(
81
+ `http://localhost:4111/api/memory/network/threads/${threadId}?networkId=${networkId}`,
82
+ expect.objectContaining({
83
+ method: 'PATCH',
84
+ headers: expect.objectContaining({
85
+ Authorization: 'Bearer test-key',
86
+ }),
87
+ body: JSON.stringify(updateParams),
88
+ }),
89
+ );
90
+ expect(result).toEqual(mockUpdatedThread);
91
+ });
92
+ });
93
+
94
+ describe('delete', () => {
95
+ it('should delete the thread', async () => {
96
+ const mockResponse = { result: 'Thread deleted' };
97
+ mockFetchResponse(mockResponse);
98
+
99
+ const result = await thread.delete();
100
+
101
+ expect(global.fetch).toHaveBeenCalledWith(
102
+ `http://localhost:4111/api/memory/network/threads/${threadId}?networkId=${networkId}`,
103
+ expect.objectContaining({
104
+ method: 'DELETE',
105
+ headers: expect.objectContaining({
106
+ Authorization: 'Bearer test-key',
107
+ }),
108
+ }),
109
+ );
110
+ expect(result).toEqual(mockResponse);
111
+ });
112
+ });
113
+
114
+ describe('getMessages', () => {
115
+ it('should retrieve thread messages', async () => {
116
+ const mockMessages = {
117
+ messages: [
118
+ { id: 'msg-1', content: 'Hello', role: 'user' },
119
+ { id: 'msg-2', content: 'Hi there', role: 'assistant' },
120
+ ],
121
+ uiMessages: [
122
+ { id: 'msg-1', content: 'Hello', role: 'user' },
123
+ { id: 'msg-2', content: 'Hi there', role: 'assistant' },
124
+ ],
125
+ };
126
+
127
+ mockFetchResponse(mockMessages);
128
+
129
+ const result = await thread.getMessages();
130
+
131
+ expect(global.fetch).toHaveBeenCalledWith(
132
+ `http://localhost:4111/api/memory/network/threads/${threadId}/messages?networkId=${networkId}`,
133
+ expect.objectContaining({
134
+ headers: expect.objectContaining({
135
+ Authorization: 'Bearer test-key',
136
+ }),
137
+ }),
138
+ );
139
+ expect(result).toEqual(mockMessages);
140
+ });
141
+
142
+ it('should retrieve thread messages with limit', async () => {
143
+ const mockMessages = {
144
+ messages: [{ id: 'msg-1', content: 'Hello', role: 'user' }],
145
+ uiMessages: [{ id: 'msg-1', content: 'Hello', role: 'user' }],
146
+ };
147
+
148
+ mockFetchResponse(mockMessages);
149
+
150
+ const result = await thread.getMessages({ limit: 5 });
151
+
152
+ expect(global.fetch).toHaveBeenCalledWith(
153
+ `http://localhost:4111/api/memory/network/threads/${threadId}/messages?networkId=${networkId}&limit=5`,
154
+ expect.objectContaining({
155
+ headers: expect.objectContaining({
156
+ Authorization: 'Bearer test-key',
157
+ }),
158
+ }),
159
+ );
160
+ expect(result).toEqual(mockMessages);
161
+ });
162
+ });
163
+
164
+ describe('deleteMessages', () => {
165
+ it('should delete a single message by string ID', async () => {
166
+ const messageId = 'test-message-id';
167
+ const mockResponse = { success: true, message: '1 message deleted successfully' };
168
+
169
+ mockFetchResponse(mockResponse);
170
+
171
+ const result = await thread.deleteMessages(messageId);
172
+
173
+ expect(global.fetch).toHaveBeenCalledWith(
174
+ `http://localhost:4111/api/memory/network/messages/delete?networkId=${networkId}`,
175
+ expect.objectContaining({
176
+ method: 'POST',
177
+ headers: expect.objectContaining({
178
+ 'content-type': 'application/json',
179
+ Authorization: 'Bearer test-key',
180
+ }),
181
+ body: JSON.stringify({ messageIds: messageId }),
182
+ }),
183
+ );
184
+ expect(result).toEqual(mockResponse);
185
+ });
186
+
187
+ it('should delete multiple messages by array of string IDs', async () => {
188
+ const messageIds = ['msg-1', 'msg-2', 'msg-3'];
189
+ const mockResponse = { success: true, message: '3 messages deleted successfully' };
190
+
191
+ mockFetchResponse(mockResponse);
192
+
193
+ const result = await thread.deleteMessages(messageIds);
194
+
195
+ expect(global.fetch).toHaveBeenCalledWith(
196
+ `http://localhost:4111/api/memory/network/messages/delete?networkId=${networkId}`,
197
+ expect.objectContaining({
198
+ method: 'POST',
199
+ headers: expect.objectContaining({
200
+ 'content-type': 'application/json',
201
+ Authorization: 'Bearer test-key',
202
+ }),
203
+ body: JSON.stringify({ messageIds }),
204
+ }),
205
+ );
206
+ expect(result).toEqual(mockResponse);
207
+ });
208
+
209
+ it('should delete a message by object with id property', async () => {
210
+ const messageObj = { id: 'test-message-id' };
211
+ const mockResponse = { success: true, message: '1 message deleted successfully' };
212
+
213
+ mockFetchResponse(mockResponse);
214
+
215
+ const result = await thread.deleteMessages(messageObj);
216
+
217
+ expect(global.fetch).toHaveBeenCalledWith(
218
+ `http://localhost:4111/api/memory/network/messages/delete?networkId=${networkId}`,
219
+ expect.objectContaining({
220
+ method: 'POST',
221
+ headers: expect.objectContaining({
222
+ 'content-type': 'application/json',
223
+ Authorization: 'Bearer test-key',
224
+ }),
225
+ body: JSON.stringify({ messageIds: messageObj }),
226
+ }),
227
+ );
228
+ expect(result).toEqual(mockResponse);
229
+ });
230
+
231
+ it('should delete messages by array of objects', async () => {
232
+ const messageObjs = [{ id: 'msg-1' }, { id: 'msg-2' }];
233
+ const mockResponse = { success: true, message: '2 messages deleted successfully' };
234
+
235
+ mockFetchResponse(mockResponse);
236
+
237
+ const result = await thread.deleteMessages(messageObjs);
238
+
239
+ expect(global.fetch).toHaveBeenCalledWith(
240
+ `http://localhost:4111/api/memory/network/messages/delete?networkId=${networkId}`,
241
+ expect.objectContaining({
242
+ method: 'POST',
243
+ headers: expect.objectContaining({
244
+ 'content-type': 'application/json',
245
+ Authorization: 'Bearer test-key',
246
+ }),
247
+ body: JSON.stringify({ messageIds: messageObjs }),
248
+ }),
249
+ );
250
+ expect(result).toEqual(mockResponse);
251
+ });
252
+
253
+ it('should handle delete messages errors', async () => {
254
+ const messageId = 'non-existent-id';
255
+
256
+ (global.fetch as any).mockResolvedValueOnce({
257
+ ok: false,
258
+ status: 404,
259
+ statusText: 'Not Found',
260
+ json: async () => ({ error: 'Message not found' }),
261
+ headers: new Headers({
262
+ 'content-type': 'application/json',
263
+ }),
264
+ });
265
+
266
+ await expect(thread.deleteMessages(messageId)).rejects.toThrow();
267
+ });
268
+ });
269
+ });
@@ -60,4 +60,22 @@ export class NetworkMemoryThread extends BaseResource {
60
60
  });
61
61
  return this.request(`/api/memory/network/threads/${this.threadId}/messages?${query.toString()}`);
62
62
  }
63
+
64
+ /**
65
+ * Deletes one or more messages from the thread
66
+ * @param messageIds - Can be a single message ID (string), array of message IDs,
67
+ * message object with id property, or array of message objects
68
+ * @returns Promise containing deletion result
69
+ */
70
+ deleteMessages(
71
+ messageIds: string | string[] | { id: string } | { id: string }[],
72
+ ): Promise<{ success: boolean; message: string }> {
73
+ const query = new URLSearchParams({
74
+ networkId: this.networkId,
75
+ });
76
+ return this.request(`/api/memory/network/messages/delete?${query.toString()}`, {
77
+ method: 'POST',
78
+ body: { messageIds },
79
+ });
80
+ }
63
81
  }