@agentica/vector-selector 0.43.3 → 0.44.0-dev.20260313-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.
package/src/utils.test.ts CHANGED
@@ -1,357 +1,357 @@
1
- import type { AgenticaContext } from "@agentica/core";
2
-
3
- import { generateHashFromCtx, getRetry, groupByArray, uniqBy } from "./utils";
4
-
5
- describe("getRetry", () => {
6
- it("should throw error when count is less than 1", () => {
7
- // @ts-expect-error getRetry should throw error when count is not more than 0
8
- expect(() => getRetry(0)).toThrow("count should be greater than 0");
9
- });
10
-
11
- it("should retry the function specified number of times", async () => {
12
- const mockFn = vi.fn().mockImplementation(async () => {
13
- if (mockFn.mock.calls.length === 1) {
14
- throw new Error("Failed");
15
- }
16
- return "success";
17
- });
18
-
19
- const retryFn = getRetry(3);
20
- const result = await retryFn(mockFn);
21
-
22
- expect(result).toBe("success");
23
- expect(mockFn).toHaveBeenCalledTimes(2);
24
- });
25
-
26
- it("should throw the last error when all retries fail", async () => {
27
- const error = new Error("Failed");
28
- const mockFn = vi.fn().mockRejectedValue(error);
29
-
30
- const retryFn = getRetry(3);
31
- await expect(retryFn(mockFn)).rejects.toThrow(error);
32
- expect(mockFn).toHaveBeenCalledTimes(3);
33
- });
34
-
35
- it("should handle noop functions", async () => {
36
- const mockFn = vi.fn().mockResolvedValue(undefined);
37
- const retryFn = getRetry(3);
38
-
39
- const result = await retryFn(mockFn);
40
- expect(result).toBeUndefined();
41
- expect(mockFn).toHaveBeenCalledTimes(1);
42
- });
43
-
44
- it("should handle non-async functions", async () => {
45
- const mockFn: () => string = vi.fn()
46
- .mockImplementationOnce(() => { throw new Error("Failed"); })
47
- .mockImplementationOnce(() => "success");
48
-
49
- const retryFn = getRetry(3);
50
- const result = await retryFn(async () => mockFn());
51
-
52
- expect(result).toBe("success");
53
- expect(mockFn).toHaveBeenCalledTimes(2);
54
- });
55
-
56
- it("should stop retrying after successful attempt", async () => {
57
- const mockFn = vi.fn()
58
- .mockRejectedValueOnce(new Error("Failed"))
59
- .mockResolvedValueOnce("success");
60
-
61
- const retryFn = getRetry(5);
62
- const result = await retryFn(mockFn);
63
-
64
- expect(result).toBe("success");
65
- expect(mockFn).toHaveBeenCalledTimes(2);
66
- });
67
-
68
- it("should handle different types of errors", async () => {
69
- const retryFn = getRetry(3);
70
-
71
- await expect(retryFn(async () => {
72
- throw new TypeError("Type error");
73
- })).rejects.toThrow(TypeError);
74
-
75
- await expect(retryFn(async () => {
76
- throw new RangeError("Range error");
77
- })).rejects.toThrow(RangeError);
78
- });
79
-
80
- it("should handle null and undefined return values", async () => {
81
- const retryFn = getRetry(2);
82
-
83
- const nullFn = async () => null;
84
- const undefinedFn = async () => undefined;
85
-
86
- expect(await retryFn(nullFn)).toBeNull();
87
- expect(await retryFn(undefinedFn)).toBeUndefined();
88
- });
89
-
90
- it("should handle floating point calculations", async () => {
91
- let attempts = 0;
92
- const fn = async () => {
93
- attempts++;
94
- if (attempts < 2) {
95
- throw new Error("Failed");
96
- }
97
- return 3.14159;
98
- };
99
-
100
- const retryFn = getRetry(3);
101
- const result = await retryFn(fn);
102
- expect(result).toBeCloseTo(3.14159);
103
- expect(attempts).toBe(2);
104
- });
105
-
106
- it("should handle mathematical operations with floating points", async () => {
107
- let attempts = 0;
108
- const fn = async () => {
109
- attempts++;
110
- if (attempts < 2) {
111
- throw new Error("Failed");
112
- }
113
- return 0.1 + 0.2; // Known floating point precision issue
114
- };
115
-
116
- const retryFn = getRetry(3);
117
- const result = await retryFn(fn);
118
- expect(result).toBeCloseTo(0.3);
119
- expect(attempts).toBe(2);
120
- });
121
-
122
- it("should handle very small floating point numbers", async () => {
123
- const retryFn = getRetry(2);
124
- const fn = async () => 0.0000001;
125
-
126
- const result = await retryFn(fn);
127
- expect(result).toBeCloseTo(0.0000001);
128
- });
129
-
130
- it("should handle very large floating point numbers", async () => {
131
- const retryFn = getRetry(2);
132
- const fn = async () => 1e20;
133
-
134
- const result = await retryFn(fn);
135
- expect(result).toBe(1e20);
136
- });
137
- });
138
-
139
- describe("groupByArray", () => {
140
- it("should group array into chunks of specified size", () => {
141
- const array = [1, 2, 3, 4, 5, 6];
142
- const result = groupByArray(array, 2);
143
- expect(result).toEqual([[1, 2], [3, 4], [5, 6]]);
144
- });
145
-
146
- it("should handle array with length not divisible by count", () => {
147
- const array = [1, 2, 3, 4, 5];
148
- const result = groupByArray(array, 2);
149
- expect(result).toEqual([[1, 2], [3, 4], [5]]);
150
- });
151
-
152
- it("should return empty array when input array is empty", () => {
153
- const result = groupByArray([], 2);
154
- expect(result).toEqual([]);
155
- });
156
-
157
- it("should handle count larger than array length", () => {
158
- const array = [1];
159
- const result = groupByArray(array, 2);
160
- expect(result).toEqual([[1]]);
161
- });
162
-
163
- it("should throw error when count is less than 1", () => {
164
- const array = [1, 2, 3, 4, 5];
165
- // @ts-expect-error groupByArray should throw error when count is not more than 0
166
- expect(() => groupByArray(array, 0)).toThrow("count should be greater than 0");
167
- });
168
-
169
- it("should handle array with different data types", () => {
170
- const mixedArray = [1, "two", { three: 3 }, [4], true, null, undefined];
171
- const result = groupByArray(mixedArray, 2);
172
- expect(result).toEqual([
173
- [1, "two"],
174
- [{ three: 3 }, [4]],
175
- [true, null],
176
- [undefined],
177
- ]);
178
- });
179
-
180
- it("should handle very large arrays", () => {
181
- const largeArray = Array.from({ length: 1000 }, (_, i) => i);
182
- const result = groupByArray(largeArray, 100);
183
- expect(result.length).toBe(10);
184
- expect(result[0]?.length).toBe(100);
185
- expect(result[9]?.length).toBe(100);
186
- });
187
- });
188
-
189
- describe("uniqBy", () => {
190
- it("should remove duplicates based on selector function", () => {
191
- const users = [
192
- { id: 1, name: "John" },
193
- { id: 2, name: "Jane" },
194
- { id: 1, name: "John" },
195
- ];
196
-
197
- const uniqueUsers = uniqBy(users, user => user.id);
198
- expect(uniqueUsers).toEqual([
199
- { id: 1, name: "John" },
200
- { id: 2, name: "Jane" },
201
- ]);
202
- });
203
-
204
- it("should handle empty array", () => {
205
- const result = uniqBy([], item => item);
206
- expect(result).toEqual([]);
207
- });
208
-
209
- it("should handle array with no duplicates", () => {
210
- const numbers = [1, 2, 3, 4, 5];
211
- const result = uniqBy(numbers, num => num);
212
- expect(result).toEqual([1, 2, 3, 4, 5]);
213
- });
214
-
215
- it("should handle complex objects with custom selector", () => {
216
- const items = [
217
- { id: 1, data: { value: "a" } },
218
- { id: 2, data: { value: "b" } },
219
- { id: 1, data: { value: "c" } },
220
- ];
221
-
222
- const result = uniqBy(items, item => item.id);
223
- expect(result).toEqual([
224
- { id: 1, data: { value: "a" } },
225
- { id: 2, data: { value: "b" } },
226
- ]);
227
- });
228
- });
229
-
230
- describe("generateHashFromCtx", () => {
231
- it("should generate consistent hash for same context", () => {
232
- const ctx = {
233
- operations: {
234
- array: [
235
- { type: "operation1", data: "test1" },
236
- { type: "operation2", data: "test2" },
237
- ],
238
- },
239
- config: {},
240
- histories: [],
241
- stack: [],
242
- prompt: "",
243
- model: {},
244
- tools: [],
245
- messages: [],
246
- state: {},
247
- ready: true,
248
- dispatch: async () => {},
249
- request: async () => Promise.resolve({}),
250
- initialize: async () => Promise.resolve(),
251
- } as unknown as AgenticaContext;
252
-
253
- const hash1 = generateHashFromCtx(ctx);
254
- const hash2 = generateHashFromCtx(ctx);
255
- expect(hash1).toBe(hash2);
256
- });
257
-
258
- it("should generate different hashes for different contexts", () => {
259
- const ctx1 = {
260
- operations: {
261
- array: [{ type: "operation1", data: "test1" }],
262
- },
263
- config: {},
264
- histories: [],
265
- stack: [],
266
- prompt: "",
267
- model: {},
268
- tools: [],
269
- messages: [],
270
- state: {},
271
- ready: true,
272
- dispatch: () => {},
273
- request: async () => Promise.resolve({}),
274
- initialize: async () => Promise.resolve(),
275
- } as unknown as AgenticaContext;
276
-
277
- const ctx2 = {
278
- operations: {
279
- array: [{ type: "operation1", data: "test2" }],
280
- },
281
- config: {},
282
- histories: [],
283
- stack: [],
284
- prompt: "",
285
- model: {},
286
- tools: [],
287
- messages: [],
288
- state: {},
289
- ready: true,
290
- dispatch: () => {},
291
- request: async () => Promise.resolve({}),
292
- initialize: async () => Promise.resolve(),
293
- } as unknown as AgenticaContext;
294
-
295
- const hash1 = generateHashFromCtx(ctx1);
296
- const hash2 = generateHashFromCtx(ctx2);
297
- expect(hash1).not.toBe(hash2);
298
- });
299
-
300
- it("should handle empty operations array", () => {
301
- const ctx = {
302
- operations: {
303
- array: [],
304
- },
305
- config: {},
306
- histories: [],
307
- stack: [],
308
- prompt: "",
309
- model: {},
310
- tools: [],
311
- messages: [],
312
- state: {},
313
- ready: true,
314
- dispatch: () => {},
315
- request: async () => Promise.resolve({}),
316
- initialize: async () => Promise.resolve(),
317
- } as unknown as AgenticaContext;
318
-
319
- const hash = generateHashFromCtx(ctx);
320
- expect(typeof hash).toBe("string");
321
- expect(hash.length).toBeGreaterThan(0);
322
- });
323
-
324
- it("should handle complex operation objects", () => {
325
- const ctx = {
326
- operations: {
327
- array: [
328
- {
329
- type: "complex",
330
- data: {
331
- nested: {
332
- value: 123,
333
- array: [1, 2, 3],
334
- },
335
- },
336
- },
337
- ],
338
- },
339
- config: {},
340
- histories: [],
341
- stack: [],
342
- prompt: "",
343
- model: {},
344
- tools: [],
345
- messages: [],
346
- state: {},
347
- ready: true,
348
- dispatch: () => {},
349
- request: async () => Promise.resolve({}),
350
- initialize: async () => Promise.resolve(),
351
- } as unknown as AgenticaContext;
352
-
353
- const hash = generateHashFromCtx(ctx);
354
- expect(typeof hash).toBe("string");
355
- expect(hash.length).toBeGreaterThan(0);
356
- });
357
- });
1
+ import type { AgenticaContext } from "@agentica/core";
2
+
3
+ import { generateHashFromCtx, getRetry, groupByArray, uniqBy } from "./utils";
4
+
5
+ describe("getRetry", () => {
6
+ it("should throw error when count is less than 1", () => {
7
+ // @ts-expect-error getRetry should throw error when count is not more than 0
8
+ expect(() => getRetry(0)).toThrow("count should be greater than 0");
9
+ });
10
+
11
+ it("should retry the function specified number of times", async () => {
12
+ const mockFn = vi.fn().mockImplementation(async () => {
13
+ if (mockFn.mock.calls.length === 1) {
14
+ throw new Error("Failed");
15
+ }
16
+ return "success";
17
+ });
18
+
19
+ const retryFn = getRetry(3);
20
+ const result = await retryFn(mockFn);
21
+
22
+ expect(result).toBe("success");
23
+ expect(mockFn).toHaveBeenCalledTimes(2);
24
+ });
25
+
26
+ it("should throw the last error when all retries fail", async () => {
27
+ const error = new Error("Failed");
28
+ const mockFn = vi.fn().mockRejectedValue(error);
29
+
30
+ const retryFn = getRetry(3);
31
+ await expect(retryFn(mockFn)).rejects.toThrow(error);
32
+ expect(mockFn).toHaveBeenCalledTimes(3);
33
+ });
34
+
35
+ it("should handle noop functions", async () => {
36
+ const mockFn = vi.fn().mockResolvedValue(undefined);
37
+ const retryFn = getRetry(3);
38
+
39
+ const result = await retryFn(mockFn);
40
+ expect(result).toBeUndefined();
41
+ expect(mockFn).toHaveBeenCalledTimes(1);
42
+ });
43
+
44
+ it("should handle non-async functions", async () => {
45
+ const mockFn: () => string = vi.fn()
46
+ .mockImplementationOnce(() => { throw new Error("Failed"); })
47
+ .mockImplementationOnce(() => "success");
48
+
49
+ const retryFn = getRetry(3);
50
+ const result = await retryFn(async () => mockFn());
51
+
52
+ expect(result).toBe("success");
53
+ expect(mockFn).toHaveBeenCalledTimes(2);
54
+ });
55
+
56
+ it("should stop retrying after successful attempt", async () => {
57
+ const mockFn = vi.fn()
58
+ .mockRejectedValueOnce(new Error("Failed"))
59
+ .mockResolvedValueOnce("success");
60
+
61
+ const retryFn = getRetry(5);
62
+ const result = await retryFn(mockFn);
63
+
64
+ expect(result).toBe("success");
65
+ expect(mockFn).toHaveBeenCalledTimes(2);
66
+ });
67
+
68
+ it("should handle different types of errors", async () => {
69
+ const retryFn = getRetry(3);
70
+
71
+ await expect(retryFn(async () => {
72
+ throw new TypeError("Type error");
73
+ })).rejects.toThrow(TypeError);
74
+
75
+ await expect(retryFn(async () => {
76
+ throw new RangeError("Range error");
77
+ })).rejects.toThrow(RangeError);
78
+ });
79
+
80
+ it("should handle null and undefined return values", async () => {
81
+ const retryFn = getRetry(2);
82
+
83
+ const nullFn = async () => null;
84
+ const undefinedFn = async () => undefined;
85
+
86
+ expect(await retryFn(nullFn)).toBeNull();
87
+ expect(await retryFn(undefinedFn)).toBeUndefined();
88
+ });
89
+
90
+ it("should handle floating point calculations", async () => {
91
+ let attempts = 0;
92
+ const fn = async () => {
93
+ attempts++;
94
+ if (attempts < 2) {
95
+ throw new Error("Failed");
96
+ }
97
+ return 3.14159;
98
+ };
99
+
100
+ const retryFn = getRetry(3);
101
+ const result = await retryFn(fn);
102
+ expect(result).toBeCloseTo(3.14159);
103
+ expect(attempts).toBe(2);
104
+ });
105
+
106
+ it("should handle mathematical operations with floating points", async () => {
107
+ let attempts = 0;
108
+ const fn = async () => {
109
+ attempts++;
110
+ if (attempts < 2) {
111
+ throw new Error("Failed");
112
+ }
113
+ return 0.1 + 0.2; // Known floating point precision issue
114
+ };
115
+
116
+ const retryFn = getRetry(3);
117
+ const result = await retryFn(fn);
118
+ expect(result).toBeCloseTo(0.3);
119
+ expect(attempts).toBe(2);
120
+ });
121
+
122
+ it("should handle very small floating point numbers", async () => {
123
+ const retryFn = getRetry(2);
124
+ const fn = async () => 0.0000001;
125
+
126
+ const result = await retryFn(fn);
127
+ expect(result).toBeCloseTo(0.0000001);
128
+ });
129
+
130
+ it("should handle very large floating point numbers", async () => {
131
+ const retryFn = getRetry(2);
132
+ const fn = async () => 1e20;
133
+
134
+ const result = await retryFn(fn);
135
+ expect(result).toBe(1e20);
136
+ });
137
+ });
138
+
139
+ describe("groupByArray", () => {
140
+ it("should group array into chunks of specified size", () => {
141
+ const array = [1, 2, 3, 4, 5, 6];
142
+ const result = groupByArray(array, 2);
143
+ expect(result).toEqual([[1, 2], [3, 4], [5, 6]]);
144
+ });
145
+
146
+ it("should handle array with length not divisible by count", () => {
147
+ const array = [1, 2, 3, 4, 5];
148
+ const result = groupByArray(array, 2);
149
+ expect(result).toEqual([[1, 2], [3, 4], [5]]);
150
+ });
151
+
152
+ it("should return empty array when input array is empty", () => {
153
+ const result = groupByArray([], 2);
154
+ expect(result).toEqual([]);
155
+ });
156
+
157
+ it("should handle count larger than array length", () => {
158
+ const array = [1];
159
+ const result = groupByArray(array, 2);
160
+ expect(result).toEqual([[1]]);
161
+ });
162
+
163
+ it("should throw error when count is less than 1", () => {
164
+ const array = [1, 2, 3, 4, 5];
165
+ // @ts-expect-error groupByArray should throw error when count is not more than 0
166
+ expect(() => groupByArray(array, 0)).toThrow("count should be greater than 0");
167
+ });
168
+
169
+ it("should handle array with different data types", () => {
170
+ const mixedArray = [1, "two", { three: 3 }, [4], true, null, undefined];
171
+ const result = groupByArray(mixedArray, 2);
172
+ expect(result).toEqual([
173
+ [1, "two"],
174
+ [{ three: 3 }, [4]],
175
+ [true, null],
176
+ [undefined],
177
+ ]);
178
+ });
179
+
180
+ it("should handle very large arrays", () => {
181
+ const largeArray = Array.from({ length: 1000 }, (_, i) => i);
182
+ const result = groupByArray(largeArray, 100);
183
+ expect(result.length).toBe(10);
184
+ expect(result[0]?.length).toBe(100);
185
+ expect(result[9]?.length).toBe(100);
186
+ });
187
+ });
188
+
189
+ describe("uniqBy", () => {
190
+ it("should remove duplicates based on selector function", () => {
191
+ const users = [
192
+ { id: 1, name: "John" },
193
+ { id: 2, name: "Jane" },
194
+ { id: 1, name: "John" },
195
+ ];
196
+
197
+ const uniqueUsers = uniqBy(users, user => user.id);
198
+ expect(uniqueUsers).toEqual([
199
+ { id: 1, name: "John" },
200
+ { id: 2, name: "Jane" },
201
+ ]);
202
+ });
203
+
204
+ it("should handle empty array", () => {
205
+ const result = uniqBy([], item => item);
206
+ expect(result).toEqual([]);
207
+ });
208
+
209
+ it("should handle array with no duplicates", () => {
210
+ const numbers = [1, 2, 3, 4, 5];
211
+ const result = uniqBy(numbers, num => num);
212
+ expect(result).toEqual([1, 2, 3, 4, 5]);
213
+ });
214
+
215
+ it("should handle complex objects with custom selector", () => {
216
+ const items = [
217
+ { id: 1, data: { value: "a" } },
218
+ { id: 2, data: { value: "b" } },
219
+ { id: 1, data: { value: "c" } },
220
+ ];
221
+
222
+ const result = uniqBy(items, item => item.id);
223
+ expect(result).toEqual([
224
+ { id: 1, data: { value: "a" } },
225
+ { id: 2, data: { value: "b" } },
226
+ ]);
227
+ });
228
+ });
229
+
230
+ describe("generateHashFromCtx", () => {
231
+ it("should generate consistent hash for same context", () => {
232
+ const ctx = {
233
+ operations: {
234
+ array: [
235
+ { type: "operation1", data: "test1" },
236
+ { type: "operation2", data: "test2" },
237
+ ],
238
+ },
239
+ config: {},
240
+ histories: [],
241
+ stack: [],
242
+ prompt: "",
243
+ model: {},
244
+ tools: [],
245
+ messages: [],
246
+ state: {},
247
+ ready: true,
248
+ dispatch: async () => {},
249
+ request: async () => Promise.resolve({}),
250
+ initialize: async () => Promise.resolve(),
251
+ } as unknown as AgenticaContext;
252
+
253
+ const hash1 = generateHashFromCtx(ctx);
254
+ const hash2 = generateHashFromCtx(ctx);
255
+ expect(hash1).toBe(hash2);
256
+ });
257
+
258
+ it("should generate different hashes for different contexts", () => {
259
+ const ctx1 = {
260
+ operations: {
261
+ array: [{ type: "operation1", data: "test1" }],
262
+ },
263
+ config: {},
264
+ histories: [],
265
+ stack: [],
266
+ prompt: "",
267
+ model: {},
268
+ tools: [],
269
+ messages: [],
270
+ state: {},
271
+ ready: true,
272
+ dispatch: () => {},
273
+ request: async () => Promise.resolve({}),
274
+ initialize: async () => Promise.resolve(),
275
+ } as unknown as AgenticaContext;
276
+
277
+ const ctx2 = {
278
+ operations: {
279
+ array: [{ type: "operation1", data: "test2" }],
280
+ },
281
+ config: {},
282
+ histories: [],
283
+ stack: [],
284
+ prompt: "",
285
+ model: {},
286
+ tools: [],
287
+ messages: [],
288
+ state: {},
289
+ ready: true,
290
+ dispatch: () => {},
291
+ request: async () => Promise.resolve({}),
292
+ initialize: async () => Promise.resolve(),
293
+ } as unknown as AgenticaContext;
294
+
295
+ const hash1 = generateHashFromCtx(ctx1);
296
+ const hash2 = generateHashFromCtx(ctx2);
297
+ expect(hash1).not.toBe(hash2);
298
+ });
299
+
300
+ it("should handle empty operations array", () => {
301
+ const ctx = {
302
+ operations: {
303
+ array: [],
304
+ },
305
+ config: {},
306
+ histories: [],
307
+ stack: [],
308
+ prompt: "",
309
+ model: {},
310
+ tools: [],
311
+ messages: [],
312
+ state: {},
313
+ ready: true,
314
+ dispatch: () => {},
315
+ request: async () => Promise.resolve({}),
316
+ initialize: async () => Promise.resolve(),
317
+ } as unknown as AgenticaContext;
318
+
319
+ const hash = generateHashFromCtx(ctx);
320
+ expect(typeof hash).toBe("string");
321
+ expect(hash.length).toBeGreaterThan(0);
322
+ });
323
+
324
+ it("should handle complex operation objects", () => {
325
+ const ctx = {
326
+ operations: {
327
+ array: [
328
+ {
329
+ type: "complex",
330
+ data: {
331
+ nested: {
332
+ value: 123,
333
+ array: [1, 2, 3],
334
+ },
335
+ },
336
+ },
337
+ ],
338
+ },
339
+ config: {},
340
+ histories: [],
341
+ stack: [],
342
+ prompt: "",
343
+ model: {},
344
+ tools: [],
345
+ messages: [],
346
+ state: {},
347
+ ready: true,
348
+ dispatch: () => {},
349
+ request: async () => Promise.resolve({}),
350
+ initialize: async () => Promise.resolve(),
351
+ } as unknown as AgenticaContext;
352
+
353
+ const hash = generateHashFromCtx(ctx);
354
+ expect(typeof hash).toBe("string");
355
+ expect(hash.length).toBeGreaterThan(0);
356
+ });
357
+ });