@framers/agentos-ext-web-search 1.1.0 → 1.1.1

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.
@@ -11,7 +11,8 @@ describe('SearchProviderService', () => {
11
11
  service = new SearchProviderService({
12
12
  serperApiKey: 'test-serper-key',
13
13
  serpApiKey: 'test-serpapi-key',
14
- braveApiKey: 'test-brave-key'
14
+ braveApiKey: 'test-brave-key',
15
+ searxngUrl: 'http://localhost:8888',
15
16
  });
16
17
  vi.clearAllMocks();
17
18
  });
@@ -53,23 +54,15 @@ describe('SearchProviderService', () => {
53
54
 
54
55
  it('should use DuckDuckGo as final fallback', async () => {
55
56
  const mockFetch = global.fetch as any;
56
-
57
- // All API providers fail
58
- mockFetch.mockRejectedValue(new Error('API error'));
59
-
60
- // Mock DuckDuckGo HTML response
61
- const duckDuckGoHtml = `
62
- <div class="result">
63
- <h2 class="result__title">
64
- <a href="https://example.com">Test Result</a>
65
- </h2>
66
- <a class="result__snippet">Test snippet from DuckDuckGo</a>
67
- </div>
68
- `;
69
-
57
+
70
58
  mockFetch.mockResolvedValueOnce({
71
59
  ok: true,
72
- text: async () => duckDuckGoHtml
60
+ json: async () => ({
61
+ Heading: 'Test Result',
62
+ AbstractText: 'Test snippet from DuckDuckGo',
63
+ AbstractURL: 'https://example.com',
64
+ RelatedTopics: [],
65
+ }),
73
66
  });
74
67
 
75
68
  const serviceNoKeys = new SearchProviderService({});
@@ -142,12 +135,264 @@ describe('SearchProviderService', () => {
142
135
  });
143
136
  });
144
137
 
138
+ describe('getAvailableProviders', () => {
139
+ it('should return providers with configured API keys', () => {
140
+ const providers = service.getAvailableProviders();
141
+ expect(providers).toEqual(['serper', 'serpapi', 'brave', 'searxng']);
142
+ });
143
+
144
+ it('should include searxng when URL is configured', () => {
145
+ const searxngService = new SearchProviderService({ searxngUrl: 'http://searxng:8080' });
146
+ expect(searxngService.getAvailableProviders()).toEqual(['searxng']);
147
+ });
148
+
149
+ it('should return empty array with no API keys', () => {
150
+ const emptyService = new SearchProviderService({});
151
+ expect(emptyService.getAvailableProviders()).toEqual([]);
152
+ });
153
+ });
154
+
155
+ describe('searchSearXNG', () => {
156
+ it('should format request with correct URL params', async () => {
157
+ const mockFetch = global.fetch as any;
158
+ mockFetch.mockResolvedValue({
159
+ ok: true,
160
+ json: async () => ({
161
+ results: [
162
+ { title: 'SearXNG Result', url: 'https://example.com/searxng', content: 'SearXNG snippet' },
163
+ ],
164
+ }),
165
+ });
166
+
167
+ const searxngService = new SearchProviderService({ searxngUrl: 'http://searxng:8080' });
168
+ const result = await searxngService.search('test query', { provider: 'searxng' });
169
+
170
+ expect(mockFetch).toHaveBeenCalledWith(
171
+ expect.stringContaining('http://searxng:8080/search?'),
172
+ );
173
+ const calledUrl = mockFetch.mock.calls[0][0] as string;
174
+ expect(calledUrl).toContain('format=json');
175
+ expect(calledUrl).toContain('categories=general');
176
+ expect(result.provider).toBe('searxng');
177
+ expect(result.results).toHaveLength(1);
178
+ });
179
+
180
+ it('should map SearXNG "content" field to "snippet"', async () => {
181
+ const mockFetch = global.fetch as any;
182
+ mockFetch.mockResolvedValue({
183
+ ok: true,
184
+ json: async () => ({
185
+ results: [
186
+ { title: 'Title', url: 'https://example.com', content: 'SearXNG content field' },
187
+ ],
188
+ }),
189
+ });
190
+
191
+ const searxngService = new SearchProviderService({ searxngUrl: 'http://searxng:8080' });
192
+ const result = await searxngService.search('test', { provider: 'searxng' });
193
+
194
+ expect(result.results[0].snippet).toBe('SearXNG content field');
195
+ });
196
+
197
+ it('should pass category parameter to SearXNG', async () => {
198
+ const mockFetch = global.fetch as any;
199
+ mockFetch.mockResolvedValue({
200
+ ok: true,
201
+ json: async () => ({ results: [] }),
202
+ });
203
+
204
+ const searxngService = new SearchProviderService({ searxngUrl: 'http://searxng:8080' });
205
+ await searxngService.search('AI news', { provider: 'searxng', category: 'news' });
206
+
207
+ const calledUrl = mockFetch.mock.calls[0][0] as string;
208
+ expect(calledUrl).toContain('categories=news');
209
+ });
210
+
211
+ it('should handle SearXNG API errors', async () => {
212
+ const mockFetch = global.fetch as any;
213
+ mockFetch.mockResolvedValueOnce({ ok: false, statusText: 'Service Unavailable' });
214
+ // DuckDuckGo fallback
215
+ mockFetch.mockResolvedValueOnce({
216
+ ok: true,
217
+ json: async () => ({ Heading: 'DDG', AbstractText: 'Fallback', AbstractURL: 'https://example.com', RelatedTopics: [] }),
218
+ });
219
+
220
+ const searxngService = new SearchProviderService({ searxngUrl: 'http://searxng:8080' });
221
+ const result = await searxngService.search('test');
222
+
223
+ // Should fall through to DuckDuckGo
224
+ expect(result.provider).toBe('duckduckgo');
225
+ });
226
+
227
+ it('should strip trailing slashes from SearXNG URL', async () => {
228
+ const mockFetch = global.fetch as any;
229
+ mockFetch.mockResolvedValue({
230
+ ok: true,
231
+ json: async () => ({ results: [] }),
232
+ });
233
+
234
+ const searxngService = new SearchProviderService({ searxngUrl: 'http://searxng:8080///' });
235
+ await searxngService.search('test', { provider: 'searxng' });
236
+
237
+ const calledUrl = mockFetch.mock.calls[0][0] as string;
238
+ expect(calledUrl).toMatch(/^http:\/\/searxng:8080\/search\?/);
239
+ });
240
+ });
241
+
242
+ describe('normalizeUrl', () => {
243
+ it('should strip www prefix', () => {
244
+ expect(SearchProviderService.normalizeUrl('https://www.example.com/page'))
245
+ .toBe('https://example.com/page');
246
+ });
247
+
248
+ it('should strip tracking params (utm_*, fbclid, gclid)', () => {
249
+ const url = 'https://example.com/page?utm_source=google&utm_medium=cpc&fbclid=abc&real=keep';
250
+ const normalized = SearchProviderService.normalizeUrl(url);
251
+ expect(normalized).toContain('real=keep');
252
+ expect(normalized).not.toContain('utm_source');
253
+ expect(normalized).not.toContain('fbclid');
254
+ });
255
+
256
+ it('should strip trailing slashes', () => {
257
+ expect(SearchProviderService.normalizeUrl('https://example.com/page/'))
258
+ .toBe('https://example.com/page');
259
+ });
260
+
261
+ it('should sort remaining query params', () => {
262
+ const url = 'https://example.com/page?z=1&a=2';
263
+ const normalized = SearchProviderService.normalizeUrl(url);
264
+ expect(normalized).toBe('https://example.com/page?a=2&z=1');
265
+ });
266
+
267
+ it('should handle invalid URLs gracefully', () => {
268
+ expect(SearchProviderService.normalizeUrl('not a url')).toBe('not a url');
269
+ });
270
+ });
271
+
272
+ describe('multiSearch', () => {
273
+ it('should fan out to all available providers + duckduckgo', async () => {
274
+ const mockFetch = global.fetch as any;
275
+ mockFetch.mockImplementation(async (url: string) => {
276
+ const urlStr = typeof url === 'string' ? url : url.toString();
277
+ if (urlStr.includes('serper.dev')) {
278
+ return { ok: true, json: async () => ({ organic: [
279
+ { title: 'Result A', link: 'https://example.com/a', snippet: 'Snippet A', position: 1 },
280
+ { title: 'Result B', link: 'https://example.com/b', snippet: 'Snippet B', position: 2 },
281
+ ] }) };
282
+ }
283
+ if (urlStr.includes('serpapi.com')) {
284
+ return { ok: true, json: async () => ({ organic_results: [
285
+ { title: 'Result A', link: 'https://example.com/a', snippet: 'Snippet A longer', position: 1 },
286
+ { title: 'Result C', link: 'https://example.com/c', snippet: 'Snippet C', position: 2 },
287
+ ] }) };
288
+ }
289
+ if (urlStr.includes('brave.com')) {
290
+ return { ok: true, json: async () => ({ web: { results: [
291
+ { title: 'Result A', url: 'https://example.com/a', description: 'Snippet A brave' },
292
+ ] } }) };
293
+ }
294
+ if (urlStr.includes('localhost:8888')) {
295
+ return { ok: true, json: async () => ({ results: [
296
+ { title: 'Result A', url: 'https://example.com/a', content: 'Snippet A searxng' },
297
+ { title: 'Result E', url: 'https://example.com/e', content: 'Snippet E' },
298
+ ] }) };
299
+ }
300
+ // duckduckgo
301
+ return { ok: true, json: async () => ({ Heading: 'Result D', AbstractText: 'DDG snippet', AbstractURL: 'https://example.com/d', RelatedTopics: [] }) };
302
+ });
303
+
304
+ const result = await service.multiSearch('test query');
305
+
306
+ expect(result.metadata.providersQueried).toContain('serper');
307
+ expect(result.metadata.providersQueried).toContain('searxng');
308
+ expect(result.metadata.providersQueried).toContain('duckduckgo');
309
+ expect(result.metadata.deduplicatedCount).toBeLessThanOrEqual(result.metadata.totalRawResults);
310
+ });
311
+
312
+ it('should deduplicate results across providers', async () => {
313
+ const mockFetch = global.fetch as any;
314
+ // Route mocks by URL since Promise.allSettled doesn't guarantee call order
315
+ mockFetch.mockImplementation(async (url: string) => {
316
+ const urlStr = typeof url === 'string' ? url : url.toString();
317
+ if (urlStr.includes('serper.dev')) {
318
+ return { ok: true, json: async () => ({ organic: [{ title: 'Same', link: 'https://example.com/same', snippet: 'Same snippet', position: 1 }] }) };
319
+ }
320
+ if (urlStr.includes('serpapi.com')) {
321
+ return { ok: true, json: async () => ({ organic_results: [{ title: 'Same', link: 'https://example.com/same', snippet: 'Same snippet', position: 1 }] }) };
322
+ }
323
+ if (urlStr.includes('brave.com')) {
324
+ return { ok: true, json: async () => ({ web: { results: [{ title: 'Same', url: 'https://example.com/same', description: 'Same snippet' }] } }) };
325
+ }
326
+ if (urlStr.includes('localhost:8888')) {
327
+ return { ok: true, json: async () => ({ results: [{ title: 'Same', url: 'https://example.com/same', content: 'Same snippet from SearXNG' }] }) };
328
+ }
329
+ // duckduckgo
330
+ return { ok: true, json: async () => ({ Heading: 'Same', AbstractText: 'Same', AbstractURL: 'https://example.com/same', RelatedTopics: [] }) };
331
+ });
332
+
333
+ const result = await service.multiSearch('test');
334
+
335
+ // Should be deduplicated to 1 result
336
+ expect(result.results).toHaveLength(1);
337
+ expect(result.results[0].agreementCount).toBeGreaterThanOrEqual(4);
338
+ });
339
+
340
+ it('should rank results with more provider agreement higher', async () => {
341
+ const mockFetch = global.fetch as any;
342
+ mockFetch.mockImplementation(async (url: string) => {
343
+ const urlStr = typeof url === 'string' ? url : url.toString();
344
+ if (urlStr.includes('serper.dev')) {
345
+ return { ok: true, json: async () => ({ organic: [
346
+ { title: 'A', link: 'https://example.com/a', snippet: 'A', position: 1 },
347
+ { title: 'B', link: 'https://example.com/b', snippet: 'B', position: 2 },
348
+ ] }) };
349
+ }
350
+ if (urlStr.includes('serpapi.com')) {
351
+ return { ok: true, json: async () => ({ organic_results: [
352
+ { title: 'A', link: 'https://example.com/a', snippet: 'A', position: 1 },
353
+ ] }) };
354
+ }
355
+ if (urlStr.includes('brave.com')) {
356
+ return { ok: true, json: async () => ({ web: { results: [
357
+ { title: 'A', url: 'https://example.com/a', description: 'A' },
358
+ ] } }) };
359
+ }
360
+ if (urlStr.includes('localhost:8888')) {
361
+ return { ok: true, json: async () => ({ results: [
362
+ { title: 'A', url: 'https://example.com/a', content: 'A' },
363
+ ] }) };
364
+ }
365
+ // duckduckgo returns B only
366
+ return { ok: true, json: async () => ({ Heading: 'B', AbstractText: 'B', AbstractURL: 'https://example.com/b', RelatedTopics: [] }) };
367
+ });
368
+
369
+ const result = await service.multiSearch('test');
370
+
371
+ // A appears in 4 providers, B in 2 — A should rank first
372
+ expect(result.results[0].url).toBe('https://example.com/a');
373
+ expect(result.results[0].confidenceScore).toBeGreaterThan(result.results[1].confidenceScore);
374
+ });
375
+
376
+ it('should handle all providers failing gracefully', async () => {
377
+ const mockFetch = global.fetch as any;
378
+ mockFetch.mockRejectedValue(new Error('Network error'));
379
+
380
+ const result = await service.multiSearch('test');
381
+
382
+ expect(result.results).toHaveLength(0);
383
+ expect(result.metadata.providersFailed.length).toBeGreaterThan(0);
384
+ });
385
+ });
386
+
145
387
  describe('getRecommendedProviders', () => {
146
- it('should return provider recommendations', () => {
388
+ it('should return provider recommendations including SearXNG', () => {
147
389
  const providers = SearchProviderService.getRecommendedProviders();
148
- expect(providers).toHaveLength(4);
390
+ expect(providers).toHaveLength(5);
149
391
  expect(providers[0].name).toBe('Serper');
150
392
  expect(providers[0].signupUrl).toContain('serper.dev');
393
+ const searxng = providers.find((p) => p.name === 'SearXNG');
394
+ expect(searxng).toBeDefined();
395
+ expect(searxng!.freeQuota).toContain('Unlimited');
151
396
  });
152
397
  });
153
398
  });
@@ -8,7 +8,13 @@ vi.mock('../src/services/searchProvider');
8
8
  describe('WebSearchTool', () => {
9
9
  let tool: WebSearchTool;
10
10
  let mockSearchService: vi.Mocked<SearchProviderService>;
11
-
11
+
12
+ const ctx: any = {
13
+ gmiId: 'test-gmi',
14
+ personaId: 'test-persona',
15
+ userContext: { userId: 'test-user' },
16
+ };
17
+
12
18
  beforeEach(() => {
13
19
  mockSearchService = new SearchProviderService({}) as any;
14
20
  tool = new WebSearchTool(mockSearchService);
@@ -17,8 +23,9 @@ describe('WebSearchTool', () => {
17
23
 
18
24
  describe('constructor', () => {
19
25
  it('should initialize with correct metadata', () => {
20
- expect(tool.id).toBe('webSearch');
21
- expect(tool.name).toBe('Web Search');
26
+ expect(tool.id).toBe('web-search-v1');
27
+ expect(tool.name).toBe('web_search');
28
+ expect(tool.displayName).toBe('Web Search');
22
29
  expect(tool.description).toContain('Search the web');
23
30
  });
24
31
  });
@@ -41,11 +48,12 @@ describe('WebSearchTool', () => {
41
48
  provider: 'serper' as const
42
49
  };
43
50
 
44
- const result = await tool.execute(input);
51
+ const result = await tool.execute(input, ctx);
45
52
 
46
53
  expect(mockSearchService.search).toHaveBeenCalledWith('test query', {
47
54
  maxResults: 5,
48
- provider: 'serper'
55
+ provider: 'serper',
56
+ category: undefined,
49
57
  });
50
58
  expect(result.success).toBe(true);
51
59
  expect(result.output).toEqual(mockResults);
@@ -56,7 +64,7 @@ describe('WebSearchTool', () => {
56
64
  mockSearchService.search = vi.fn().mockRejectedValue(error);
57
65
 
58
66
  const input = { query: 'test query' };
59
- const result = await tool.execute(input);
67
+ const result = await tool.execute(input as any, ctx);
60
68
 
61
69
  expect(result.success).toBe(false);
62
70
  expect(result.error).toBe('API error');
@@ -68,61 +76,155 @@ describe('WebSearchTool', () => {
68
76
  results: [],
69
77
  metadata: {}
70
78
  });
71
-
79
+
72
80
  const input = { query: 'test query' };
73
- await tool.execute(input);
74
-
81
+ await tool.execute(input as any, ctx);
82
+
75
83
  expect(mockSearchService.search).toHaveBeenCalledWith('test query', {
76
84
  maxResults: 10,
77
- provider: undefined
85
+ provider: undefined,
86
+ category: undefined,
87
+ });
88
+ });
89
+
90
+ it('should pass category to search service', async () => {
91
+ mockSearchService.search = vi.fn().mockResolvedValue({
92
+ provider: 'searxng',
93
+ results: [],
94
+ metadata: {}
95
+ });
96
+
97
+ await tool.execute({ query: 'AI news', provider: 'searxng', category: 'news' }, ctx);
98
+
99
+ expect(mockSearchService.search).toHaveBeenCalledWith('AI news', {
100
+ maxResults: 10,
101
+ provider: 'searxng',
102
+ category: 'news',
78
103
  });
79
104
  });
80
105
  });
81
106
 
82
- describe('validate', () => {
107
+ describe('validateArgs', () => {
83
108
  it('should validate required query parameter', () => {
84
- const result = tool.validate({});
85
- expect(result.valid).toBe(false);
109
+ const result = tool.validateArgs({});
110
+ expect(result.isValid).toBe(false);
86
111
  expect(result.errors).toContain('Query is required');
87
112
  });
88
113
 
89
114
  it('should validate query is a string', () => {
90
- const result = tool.validate({ query: 123 });
91
- expect(result.valid).toBe(false);
115
+ const result = tool.validateArgs({ query: 123 });
116
+ expect(result.isValid).toBe(false);
92
117
  expect(result.errors).toContain('Query must be a string');
93
118
  });
94
119
 
95
120
  it('should validate maxResults is a positive number', () => {
96
- const result = tool.validate({ query: 'test', maxResults: -1 });
97
- expect(result.valid).toBe(false);
121
+ const result = tool.validateArgs({ query: 'test', maxResults: -1 });
122
+ expect(result.isValid).toBe(false);
98
123
  expect(result.errors).toContain('maxResults must be a positive number');
99
124
  });
100
125
 
101
126
  it('should validate provider is from allowed list', () => {
102
- const result = tool.validate({ query: 'test', provider: 'invalid' });
103
- expect(result.valid).toBe(false);
127
+ const result = tool.validateArgs({ query: 'test', provider: 'invalid' });
128
+ expect(result.isValid).toBe(false);
104
129
  expect(result.errors).toContain('Invalid provider');
105
130
  });
106
-
131
+
107
132
  it('should pass validation with correct inputs', () => {
108
- const result = tool.validate({
133
+ const result = tool.validateArgs({
109
134
  query: 'test query',
110
135
  maxResults: 5,
111
136
  provider: 'serper'
112
137
  });
113
- expect(result.valid).toBe(true);
114
- expect(result.errors).toHaveLength(0);
138
+ expect(result.isValid).toBe(true);
139
+ });
140
+
141
+ it('should accept searxng as a valid provider', () => {
142
+ const result = tool.validateArgs({ query: 'test', provider: 'searxng' });
143
+ expect(result.isValid).toBe(true);
115
144
  });
116
145
  });
117
146
 
118
- describe('getSchema', () => {
147
+ describe('multiSearch', () => {
148
+ it('should call multiSearch when multiSearch input is true', async () => {
149
+ const mockMultiResults = {
150
+ results: [{ title: 'Multi', url: 'https://example.com', snippet: 'Multi result', providers: ['serper', 'brave'], agreementCount: 2, confidenceScore: 80, providerPositions: { serper: 1, brave: 1 } }],
151
+ metadata: { query: 'test', timestamp: new Date().toISOString(), totalResponseTime: 100, providersQueried: ['serper', 'brave'], providersSucceeded: ['serper', 'brave'], providersFailed: [], totalRawResults: 2, deduplicatedCount: 1 },
152
+ };
153
+ mockSearchService.multiSearch = vi.fn().mockResolvedValue(mockMultiResults);
154
+
155
+ const result = await tool.execute({ query: 'test', multiSearch: true }, ctx);
156
+
157
+ expect(mockSearchService.multiSearch).toHaveBeenCalledWith('test', { maxResults: 10 });
158
+ expect(result.success).toBe(true);
159
+ expect(result.output).toEqual(mockMultiResults);
160
+ });
161
+
162
+ it('should use defaultMultiSearch from constructor when input omits multiSearch', async () => {
163
+ const toolWithDefault = new WebSearchTool(mockSearchService, true);
164
+ const mockMultiResults = {
165
+ results: [],
166
+ metadata: { query: 'test', timestamp: new Date().toISOString(), totalResponseTime: 50, providersQueried: [], providersSucceeded: [], providersFailed: [], totalRawResults: 0, deduplicatedCount: 0 },
167
+ };
168
+ mockSearchService.multiSearch = vi.fn().mockResolvedValue(mockMultiResults);
169
+
170
+ await toolWithDefault.execute({ query: 'test' }, ctx);
171
+
172
+ expect(mockSearchService.multiSearch).toHaveBeenCalled();
173
+ });
174
+
175
+ it('should fall back to single search when provider is specified even with multiSearch', async () => {
176
+ mockSearchService.search = vi.fn().mockResolvedValue({ provider: 'serper', results: [], metadata: {} });
177
+
178
+ await tool.execute({ query: 'test', multiSearch: true, provider: 'serper' }, ctx);
179
+
180
+ // When provider is specified, multiSearch is ignored — single provider search is used
181
+ expect(mockSearchService.search).toHaveBeenCalled();
182
+ });
183
+ });
184
+
185
+ describe('validateArgs - multiSearch', () => {
186
+ it('should reject multiSearch + provider combination', () => {
187
+ const result = tool.validateArgs({ query: 'test', multiSearch: true, provider: 'serper' });
188
+ expect(result.isValid).toBe(false);
189
+ expect(result.errors).toContain('Cannot specify both multiSearch and a specific provider');
190
+ });
191
+
192
+ it('should reject non-boolean multiSearch', () => {
193
+ const result = tool.validateArgs({ query: 'test', multiSearch: 'yes' });
194
+ expect(result.isValid).toBe(false);
195
+ expect(result.errors).toContain('multiSearch must be a boolean');
196
+ });
197
+
198
+ it('should accept multiSearch: true without provider', () => {
199
+ const result = tool.validateArgs({ query: 'test', multiSearch: true });
200
+ expect(result.isValid).toBe(true);
201
+ });
202
+ });
203
+
204
+ describe('inputSchema', () => {
119
205
  it('should return proper JSON schema', () => {
120
- const schema = tool.getSchema();
206
+ const schema = tool.inputSchema;
121
207
  expect(schema.type).toBe('object');
122
208
  expect(schema.required).toEqual(['query']);
123
209
  expect(schema.properties.query.type).toBe('string');
124
- expect(schema.properties.maxResults.type).toBe('number');
210
+ expect(schema.properties.maxResults.type).toBe('integer');
125
211
  expect(schema.properties.provider.enum).toContain('serper');
212
+ expect(schema.properties.provider.enum).toContain('searxng');
213
+ });
214
+
215
+ it('should include multiSearch in schema', () => {
216
+ const schema = tool.inputSchema;
217
+ expect(schema.properties.multiSearch).toBeDefined();
218
+ expect(schema.properties.multiSearch.type).toBe('boolean');
219
+ expect(schema.properties.multiSearch.default).toBe(false);
220
+ });
221
+
222
+ it('should include category field for SearXNG', () => {
223
+ const schema = tool.inputSchema;
224
+ expect(schema.properties.category).toBeDefined();
225
+ expect(schema.properties.category.type).toBe('string');
226
+ expect(schema.properties.category.enum).toContain('news');
227
+ expect(schema.properties.category.enum).toContain('science');
126
228
  });
127
229
  });
128
- });
230
+ });
package/tsconfig.json CHANGED
@@ -1,8 +1,14 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2022",
4
- "module": "commonjs",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
5
6
  "lib": ["ES2022"],
7
+ "baseUrl": ".",
8
+ "paths": {
9
+ "@framers/agentos": ["../../../../../agentos/dist/index.d.ts"],
10
+ "@framers/agentos/*": ["../../../../../agentos/dist/*"]
11
+ },
6
12
  "outDir": "./dist",
7
13
  "rootDir": "./src",
8
14
  "strict": true,
@@ -13,7 +19,6 @@
13
19
  "declarationMap": true,
14
20
  "sourceMap": true,
15
21
  "resolveJsonModule": true,
16
- "moduleResolution": "node",
17
22
  "types": ["node"]
18
23
  },
19
24
  "include": ["src/**/*"],