converse-mcp-server 2.3.1 → 2.4.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.
Files changed (42) hide show
  1. package/README.md +771 -738
  2. package/docs/API.md +10 -1
  3. package/docs/PROVIDERS.md +8 -4
  4. package/package.json +12 -12
  5. package/src/async/asyncJobStore.js +82 -52
  6. package/src/async/eventBus.js +25 -20
  7. package/src/async/fileCache.js +121 -40
  8. package/src/async/jobRunner.js +65 -39
  9. package/src/async/providerStreamNormalizer.js +203 -117
  10. package/src/config.js +374 -102
  11. package/src/continuationStore.js +32 -24
  12. package/src/index.js +45 -25
  13. package/src/prompts/helpPrompt.js +328 -305
  14. package/src/providers/anthropic.js +303 -119
  15. package/src/providers/codex.js +103 -45
  16. package/src/providers/deepseek.js +24 -8
  17. package/src/providers/google.js +337 -93
  18. package/src/providers/index.js +1 -1
  19. package/src/providers/interface.js +16 -11
  20. package/src/providers/mistral.js +179 -69
  21. package/src/providers/openai-compatible.js +231 -94
  22. package/src/providers/openai.js +1094 -914
  23. package/src/providers/openrouter-endpoints-client.js +220 -216
  24. package/src/providers/openrouter.js +426 -381
  25. package/src/providers/xai.js +153 -56
  26. package/src/resources/helpResource.js +70 -67
  27. package/src/router.js +95 -67
  28. package/src/services/summarizationService.js +51 -24
  29. package/src/systemPrompts.js +89 -89
  30. package/src/tools/cancelJob.js +31 -19
  31. package/src/tools/chat.js +997 -883
  32. package/src/tools/checkStatus.js +86 -65
  33. package/src/tools/consensus.js +400 -234
  34. package/src/tools/index.js +39 -16
  35. package/src/transport/httpTransport.js +82 -55
  36. package/src/utils/contextProcessor.js +54 -37
  37. package/src/utils/errorHandler.js +95 -45
  38. package/src/utils/fileValidator.js +107 -98
  39. package/src/utils/formatStatus.js +122 -64
  40. package/src/utils/logger.js +459 -449
  41. package/src/utils/pathUtils.js +2 -2
  42. package/src/utils/tokenLimiter.js +216 -216
package/docs/API.md CHANGED
@@ -99,6 +99,12 @@ MCP_TRANSPORT=stdio npm start
99
99
  "default": false,
100
100
  "description": "Enable web search for current information. Example: true for framework docs, false for private code analysis"
101
101
  },
102
+ "media_resolution": {
103
+ "type": "string",
104
+ "enum": ["MEDIA_RESOLUTION_LOW", "MEDIA_RESOLUTION_MEDIUM", "MEDIA_RESOLUTION_HIGH", "MEDIA_RESOLUTION_UNSPECIFIED"],
105
+ "default": "MEDIA_RESOLUTION_HIGH",
106
+ "description": "Control image/PDF/video processing quality (Gemini 3.0). Defaults to 'MEDIA_RESOLUTION_HIGH' for Gemini 3.0. Examples: 'MEDIA_RESOLUTION_LOW' (faster, less detail), 'MEDIA_RESOLUTION_MEDIUM' (balanced), 'MEDIA_RESOLUTION_HIGH' (maximum detail)"
107
+ },
102
108
  "async": {
103
109
  "type": "boolean",
104
110
  "default": false,
@@ -329,10 +335,13 @@ MCP_TRANSPORT=stdio npm start
329
335
 
330
336
  | Model | Alias | Context | Tokens | Features | Use Cases |
331
337
  |-------|-------|---------|--------|----------|-----------|
338
+ | `gemini-3-pro-preview` | `pro`, `gemini` | 1M | 64K | Thinking levels, enhanced reasoning | Complex problems, deep analysis |
332
339
  | `gemini-2.5-flash` | `flash` | 1M | 65K | Ultra-fast | Quick analysis, simple queries |
333
- | `gemini-2.5-pro` | `pro` | 1M | 65K | Thinking mode | Deep reasoning, architecture |
340
+ | `gemini-2.5-pro` | `pro 2.5` | 1M | 65K | Thinking mode | Deep reasoning, architecture |
334
341
  | `gemini-2.0-flash` | `flash2` | 1M | 65K | Latest | Experimental thinking |
335
342
 
343
+ **Note:** Default aliases `gemini`, `pro`, and `gemini-pro` now point to Gemini 3.0 Pro. Use `gemini-2.5-pro` explicitly if you need the 2.5 version.
344
+
336
345
  ### X.AI/Grok Models
337
346
 
338
347
  | Model | Alias | Context | Tokens | Features | Use Cases |
package/docs/PROVIDERS.md CHANGED
@@ -20,9 +20,11 @@ This guide documents all supported AI providers in the Converse MCP Server and t
20
20
  - **Get Key**: [makersuite.google.com/app/apikey](https://makersuite.google.com/app/apikey)
21
21
  - **Environment Variable**: `GOOGLE_API_KEY`
22
22
  - **Supported Models**:
23
- - `gemini-2.5-pro` - Deep reasoning with thinking mode
24
- - `gemini-2.5-flash` - Ultra-fast model
25
- - `gemini-2.0-flash`, `gemini-2.0-flash-lite` - Latest generation
23
+ - `gemini-3-pro-preview` (aliases: `pro`, `gemini`) - Enhanced reasoning with thinking levels (1M context, 64K output)
24
+ - `gemini-2.5-pro` (alias: `pro 2.5`) - Deep reasoning with thinking budget (1M context, 65K output)
25
+ - `gemini-2.5-flash` (alias: `flash`) - Ultra-fast model with thinking budget (1M context, 65K output)
26
+ - `gemini-2.0-flash`, `gemini-2.0-flash-lite` - Latest generation (1M context, 65K output)
27
+ - **Note**: Default aliases (`gemini`, `pro`, `gemini-pro`) now point to Gemini 3.0 Pro. Use `gemini-2.5-pro` explicitly if you need version 2.5.
26
28
 
27
29
  ### X.AI (Grok)
28
30
  - **API Key Format**: `xai-...` (starts with `xai-`)
@@ -176,7 +178,9 @@ All providers support streaming responses for real-time output.
176
178
 
177
179
  ### Thinking/Reasoning Modes
178
180
  - **OpenAI**: O3 series models support `reasoning_effort` parameter
179
- - **Google**: Gemini Pro/Flash support thinking mode with configurable budget
181
+ - **Google**:
182
+ - Gemini 3.0 Pro: Thinking levels (low/high) via `reasoning_effort` - always enabled
183
+ - Gemini 2.5 Pro/Flash: Thinking budget (token-based) via `reasoning_effort`
180
184
  - **Anthropic**: Claude 4 and 3.7 models support extended thinking with `reasoning_effort`
181
185
  - **Codex**: Thread-based agentic reasoning with persistent context
182
186
  - **Others**: Standard inference only
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "converse-mcp-server",
3
- "version": "2.3.1",
3
+ "version": "2.4.1",
4
4
  "description": "Converse MCP Server - Converse with other LLMs with chat and consensus tools",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -40,26 +40,26 @@
40
40
  ".env.example"
41
41
  ],
42
42
  "dependencies": {
43
- "@anthropic-ai/sdk": "^0.65.0",
44
- "@google/genai": "^1.22.0",
43
+ "@anthropic-ai/sdk": "^0.70.0",
44
+ "@google/genai": "^1.30.0",
45
45
  "@mistralai/mistralai": "^1.10.0",
46
- "@modelcontextprotocol/sdk": "^1.19.1",
47
- "@openai/codex-sdk": "^0.45.0",
46
+ "@modelcontextprotocol/sdk": "^1.22.0",
47
+ "@openai/codex-sdk": "^0.58.0",
48
48
  "cors": "^2.8.5",
49
49
  "dotenv": "^17.2.3",
50
50
  "express": "^5.1.0",
51
51
  "lru-cache": "^11.2.2",
52
- "openai": "^6.1.0",
53
- "p-limit": "^4.0.0",
54
- "vite": "^7.1.9"
52
+ "openai": "^6.9.1",
53
+ "p-limit": "^7.2.0",
54
+ "vite": "^7.2.2"
55
55
  },
56
56
  "devDependencies": {
57
- "@vitest/coverage-v8": "^3.2.4",
57
+ "@vitest/coverage-v8": "^4.0.10",
58
58
  "cross-env": "^10.1.0",
59
- "eslint": "^9.36.0",
59
+ "eslint": "^9.39.1",
60
60
  "prettier": "^3.6.2",
61
- "rimraf": "^6.0.1",
62
- "vitest": "^3.2.4"
61
+ "rimraf": "^6.1.0",
62
+ "vitest": "^4.0.10"
63
63
  },
64
64
  "scripts": {
65
65
  "kill-server": "node scripts/kill-server.js",
@@ -92,7 +92,9 @@ export class AsyncJobStoreInterface {
92
92
  * @returns {Promise<Array>} Array of all jobs
93
93
  */
94
94
  async getAllJobs(_options = {}) {
95
- throw new Error('getAllJobs() method must be implemented by storage backend');
95
+ throw new Error(
96
+ 'getAllJobs() method must be implemented by storage backend',
97
+ );
96
98
  }
97
99
 
98
100
  /**
@@ -133,7 +135,9 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
133
135
  super();
134
136
 
135
137
  // Check environment variable for memory TTL
136
- const envMemoryTTL = process.env.ASYNC_MEMORY_TTL_MS ? parseInt(process.env.ASYNC_MEMORY_TTL_MS, 10) : null;
138
+ const envMemoryTTL = process.env.ASYNC_MEMORY_TTL_MS
139
+ ? parseInt(process.env.ASYNC_MEMORY_TTL_MS, 10)
140
+ : null;
137
141
  const ttl = envMemoryTTL || 24 * 60 * 60 * 1000; // Default 24 hours
138
142
 
139
143
  // Configure LRU cache with configurable TTL and 10k job capacity
@@ -166,7 +170,7 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
166
170
  if (!tool || !['chat', 'consensus'].includes(tool)) {
167
171
  throw new AsyncJobStoreError(
168
172
  'Invalid tool: must be "chat" or "consensus"',
169
- 'INVALID_TOOL'
173
+ 'INVALID_TOOL',
170
174
  );
171
175
  }
172
176
 
@@ -175,7 +179,7 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
175
179
  if (!jobId) {
176
180
  throw new AsyncJobStoreError(
177
181
  'jobId is required in options',
178
- 'MISSING_JOB_ID'
182
+ 'MISSING_JOB_ID',
179
183
  );
180
184
  }
181
185
  const now = Date.now();
@@ -211,19 +215,18 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
211
215
 
212
216
  // Log event
213
217
  this._addEvent(jobState, 'job_created', {
214
- tool
218
+ tool,
215
219
  });
216
220
 
217
221
  debugLog(`AsyncJobStore: Created job ${jobId} for ${tool}`);
218
222
  return jobId;
219
-
220
223
  } catch (error) {
221
224
  if (error instanceof AsyncJobStoreError) {
222
225
  throw error;
223
226
  }
224
227
  throw new AsyncJobStoreError(
225
228
  `Failed to create job: ${error.message}`,
226
- 'CREATION_ERROR'
229
+ 'CREATION_ERROR',
227
230
  );
228
231
  }
229
232
  }
@@ -240,7 +243,7 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
240
243
  if (!jobId || typeof jobId !== 'string') {
241
244
  throw new AsyncJobStoreError(
242
245
  'Invalid job ID: must be a non-empty string',
243
- 'INVALID_JOB_ID'
246
+ 'INVALID_JOB_ID',
244
247
  );
245
248
  }
246
249
 
@@ -254,14 +257,13 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
254
257
 
255
258
  // Return deep copy to prevent external mutations
256
259
  return this._deepClone(job);
257
-
258
260
  } catch (error) {
259
261
  if (error instanceof AsyncJobStoreError) {
260
262
  throw error;
261
263
  }
262
264
  throw new AsyncJobStoreError(
263
265
  `Failed to retrieve job: ${error.message}`,
264
- 'RETRIEVAL_ERROR'
266
+ 'RETRIEVAL_ERROR',
265
267
  );
266
268
  }
267
269
  }
@@ -279,14 +281,14 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
279
281
  if (!jobId || typeof jobId !== 'string') {
280
282
  throw new AsyncJobStoreError(
281
283
  'Invalid job ID: must be a non-empty string',
282
- 'INVALID_JOB_ID'
284
+ 'INVALID_JOB_ID',
283
285
  );
284
286
  }
285
287
 
286
288
  if (!updates || typeof updates !== 'object') {
287
289
  throw new AsyncJobStoreError(
288
290
  'Invalid updates: must be an object',
289
- 'INVALID_UPDATES'
291
+ 'INVALID_UPDATES',
290
292
  );
291
293
  }
292
294
 
@@ -298,7 +300,10 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
298
300
  const now = Date.now();
299
301
 
300
302
  // Apply updates
301
- if (updates.status && Object.values(JOB_STATUS).includes(updates.status)) {
303
+ if (
304
+ updates.status &&
305
+ Object.values(JOB_STATUS).includes(updates.status)
306
+ ) {
302
307
  job.status = updates.status;
303
308
 
304
309
  // Set startedAt when status changes to running
@@ -314,7 +319,10 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
314
319
  if (updates.providers) {
315
320
  // Update provider states
316
321
  Object.entries(updates.providers).forEach(([provider, state]) => {
317
- job.providers.set(provider, { ...job.providers.get(provider), ...state });
322
+ job.providers.set(provider, {
323
+ ...job.providers.get(provider),
324
+ ...state,
325
+ });
318
326
  });
319
327
  }
320
328
 
@@ -336,7 +344,22 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
336
344
  }
337
345
 
338
346
  // Apply any other updates as direct properties on the job
339
- const reservedFields = ['status', 'progress', 'providers', 'overall', 'jobId', 'sessionId', 'createdAt', 'updatedAt', 'events', 'seq', 'accumulated_content', 'title', 'final_summary', 'reasoning_summary'];
347
+ const reservedFields = [
348
+ 'status',
349
+ 'progress',
350
+ 'providers',
351
+ 'overall',
352
+ 'jobId',
353
+ 'sessionId',
354
+ 'createdAt',
355
+ 'updatedAt',
356
+ 'events',
357
+ 'seq',
358
+ 'accumulated_content',
359
+ 'title',
360
+ 'final_summary',
361
+ 'reasoning_summary',
362
+ ];
340
363
  Object.entries(updates).forEach(([key, value]) => {
341
364
  if (!reservedFields.includes(key)) {
342
365
  job[key] = value;
@@ -350,14 +373,13 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
350
373
  this._addEvent(job, 'job_updated', updates);
351
374
 
352
375
  return true;
353
-
354
376
  } catch (error) {
355
377
  if (error instanceof AsyncJobStoreError) {
356
378
  throw error;
357
379
  }
358
380
  throw new AsyncJobStoreError(
359
381
  `Failed to update job: ${error.message}`,
360
- 'UPDATE_ERROR'
382
+ 'UPDATE_ERROR',
361
383
  );
362
384
  }
363
385
  }
@@ -392,11 +414,10 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
392
414
 
393
415
  debugLog(`AsyncJobStore: Completed job ${jobId}`);
394
416
  return true;
395
-
396
417
  } catch (error) {
397
418
  throw new AsyncJobStoreError(
398
419
  `Failed to complete job: ${error.message}`,
399
- 'COMPLETION_ERROR'
420
+ 'COMPLETION_ERROR',
400
421
  );
401
422
  }
402
423
  }
@@ -418,9 +439,10 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
418
439
  const now = Date.now();
419
440
 
420
441
  // Serialize error information
421
- const errorInfo = error instanceof Error
422
- ? { message: error.message, name: error.name, stack: error.stack }
423
- : error;
442
+ const errorInfo =
443
+ error instanceof Error
444
+ ? { message: error.message, name: error.name, stack: error.stack }
445
+ : error;
424
446
 
425
447
  // Update job state
426
448
  job.status = JOB_STATUS.FAILED;
@@ -435,11 +457,10 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
435
457
 
436
458
  debugError(`AsyncJobStore: Failed job ${jobId}:`, errorInfo);
437
459
  return true;
438
-
439
460
  } catch (err) {
440
461
  throw new AsyncJobStoreError(
441
462
  `Failed to fail job: ${err.message}`,
442
- 'FAILURE_ERROR'
463
+ 'FAILURE_ERROR',
443
464
  );
444
465
  }
445
466
  }
@@ -453,7 +474,7 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
453
474
  let totalEvents = 0;
454
475
 
455
476
  // Count jobs by status
456
- Object.values(JOB_STATUS).forEach(status => {
477
+ Object.values(JOB_STATUS).forEach((status) => {
457
478
  statusCounts[status] = 0;
458
479
  });
459
480
 
@@ -512,26 +533,25 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
512
533
  */
513
534
  async getAllJobs(options = {}) {
514
535
  try {
515
-
516
536
  const {
517
537
  limit = 50,
518
538
  status,
519
539
  sortBy = 'updatedAt',
520
- sortOrder = 'desc'
540
+ sortOrder = 'desc',
521
541
  } = options;
522
542
 
523
543
  // Validate options
524
544
  if (!Number.isInteger(limit) || limit < 1 || limit > 1000) {
525
545
  throw new AsyncJobStoreError(
526
546
  'Limit must be an integer between 1 and 1000',
527
- 'INVALID_LIMIT'
547
+ 'INVALID_LIMIT',
528
548
  );
529
549
  }
530
550
 
531
551
  if (status && !Object.values(JOB_STATUS).includes(status)) {
532
552
  throw new AsyncJobStoreError(
533
553
  `Invalid status: must be one of ${Object.values(JOB_STATUS).join(', ')}`,
534
- 'INVALID_STATUS'
554
+ 'INVALID_STATUS',
535
555
  );
536
556
  }
537
557
 
@@ -557,14 +577,13 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
557
577
 
558
578
  debugLog(`AsyncJobStore: Found ${limitedJobs.length} jobs`);
559
579
  return limitedJobs;
560
-
561
580
  } catch (error) {
562
581
  if (error instanceof AsyncJobStoreError) {
563
582
  throw error;
564
583
  }
565
584
  throw new AsyncJobStoreError(
566
585
  `Failed to get all jobs: ${error.message}`,
567
- 'QUERY_ERROR'
586
+ 'QUERY_ERROR',
568
587
  );
569
588
  }
570
589
  }
@@ -584,13 +603,15 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
584
603
  EVENT_TYPES.JOB_CANCELLED,
585
604
  ];
586
605
 
587
- eventTypes.forEach(eventType => {
606
+ eventTypes.forEach((eventType) => {
588
607
  this.eventBus.on(eventType, (eventData) => {
589
608
  this._storeEventInJob(eventData);
590
609
  });
591
610
  });
592
611
 
593
- debugLog('AsyncJobStore: Set up EventBus listeners for job lifecycle events');
612
+ debugLog(
613
+ 'AsyncJobStore: Set up EventBus listeners for job lifecycle events',
614
+ );
594
615
  }
595
616
 
596
617
  /**
@@ -625,9 +646,11 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
625
646
 
626
647
  // Update job's last activity
627
648
  job.updatedAt = Date.now();
628
-
629
649
  } catch (error) {
630
- debugError('AsyncJobStore: Failed to store EventBus event in job:', error);
650
+ debugError(
651
+ 'AsyncJobStore: Failed to store EventBus event in job:',
652
+ error,
653
+ );
631
654
  }
632
655
  }
633
656
 
@@ -651,11 +674,11 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
651
674
 
652
675
  // Apply filters
653
676
  if (options.eventType) {
654
- events = events.filter(event => event.type === options.eventType);
677
+ events = events.filter((event) => event.type === options.eventType);
655
678
  }
656
679
 
657
680
  if (options.afterSeq !== undefined) {
658
- events = events.filter(event => event.seq > options.afterSeq);
681
+ events = events.filter((event) => event.seq > options.afterSeq);
659
682
  }
660
683
 
661
684
  // Apply limit
@@ -665,9 +688,11 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
665
688
 
666
689
  // Return deep copy to prevent mutations
667
690
  return this._deepClone(events);
668
-
669
691
  } catch (error) {
670
- debugError(`AsyncJobStore: Failed to get events for job ${jobId}:`, error);
692
+ debugError(
693
+ `AsyncJobStore: Failed to get events for job ${jobId}:`,
694
+ error,
695
+ );
671
696
  return [];
672
697
  }
673
698
  }
@@ -686,9 +711,11 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
686
711
 
687
712
  const latestEvent = job.events[job.events.length - 1];
688
713
  return this._deepClone(latestEvent);
689
-
690
714
  } catch (error) {
691
- debugError(`AsyncJobStore: Failed to get latest event for job ${jobId}:`, error);
715
+ debugError(
716
+ `AsyncJobStore: Failed to get latest event for job ${jobId}:`,
717
+ error,
718
+ );
692
719
  return null;
693
720
  }
694
721
  }
@@ -750,7 +777,7 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
750
777
  }
751
778
 
752
779
  if (Array.isArray(obj)) {
753
- return obj.map(item => this._deepClone(item));
780
+ return obj.map((item) => this._deepClone(item));
754
781
  }
755
782
 
756
783
  const cloned = {};
@@ -774,16 +801,19 @@ export function getAsyncJobStore() {
774
801
  asyncJobStore = new LRUAsyncJobStore();
775
802
 
776
803
  // Set up periodic cleanup (runs every 10 minutes, same as continuation store)
777
- cleanupIntervalId = setInterval(async () => {
778
- try {
779
- const cleaned = await asyncJobStore.cleanup();
780
- if (cleaned > 0) {
781
- debugLog(`AsyncJobStore: Cleaned up ${cleaned} old jobs`);
804
+ cleanupIntervalId = setInterval(
805
+ async () => {
806
+ try {
807
+ const cleaned = await asyncJobStore.cleanup();
808
+ if (cleaned > 0) {
809
+ debugLog(`AsyncJobStore: Cleaned up ${cleaned} old jobs`);
810
+ }
811
+ } catch (error) {
812
+ debugError('AsyncJobStore cleanup failed:', error);
782
813
  }
783
- } catch (error) {
784
- debugError('AsyncJobStore cleanup failed:', error);
785
- }
786
- }, 10 * 60 * 1000);
814
+ },
815
+ 10 * 60 * 1000,
816
+ );
787
817
 
788
818
  // Unref the interval so it doesn't keep the process alive
789
819
  if (cleanupIntervalId && typeof cleanupIntervalId.unref === 'function') {
@@ -801,7 +831,7 @@ export function setAsyncJobStore(store) {
801
831
  if (store !== null && !(store instanceof AsyncJobStoreInterface)) {
802
832
  throw new AsyncJobStoreError(
803
833
  'Store must extend AsyncJobStoreInterface',
804
- 'INVALID_STORE'
834
+ 'INVALID_STORE',
805
835
  );
806
836
  }
807
837
  asyncJobStore = store;
@@ -78,7 +78,7 @@ export class EventBus extends EventEmitter {
78
78
  tool: data.tool,
79
79
  options: data.options,
80
80
  timestamp: Date.now(),
81
- ...data
81
+ ...data,
82
82
  });
83
83
  }
84
84
 
@@ -94,7 +94,7 @@ export class EventBus extends EventEmitter {
94
94
  status: data.status,
95
95
  providers: data.providers,
96
96
  timestamp: Date.now(),
97
- ...data
97
+ ...data,
98
98
  });
99
99
  }
100
100
 
@@ -108,7 +108,7 @@ export class EventBus extends EventEmitter {
108
108
  return this._emitJobEvent(EVENT_TYPES.JOB_COMPLETED, jobId, {
109
109
  result,
110
110
  timestamp: Date.now(),
111
- duration: this._calculateDuration(jobId)
111
+ duration: this._calculateDuration(jobId),
112
112
  });
113
113
  }
114
114
 
@@ -119,16 +119,19 @@ export class EventBus extends EventEmitter {
119
119
  * @returns {boolean} True if event was emitted
120
120
  */
121
121
  emitJobFailed(jobId, error) {
122
- const errorData = error instanceof Error ? {
123
- message: error.message,
124
- code: error.code || 'UNKNOWN_ERROR',
125
- stack: error.stack
126
- } : { message: String(error) };
122
+ const errorData =
123
+ error instanceof Error
124
+ ? {
125
+ message: error.message,
126
+ code: error.code || 'UNKNOWN_ERROR',
127
+ stack: error.stack,
128
+ }
129
+ : { message: String(error) };
127
130
 
128
131
  return this._emitJobEvent(EVENT_TYPES.JOB_FAILED, jobId, {
129
132
  error: errorData,
130
133
  timestamp: Date.now(),
131
- duration: this._calculateDuration(jobId)
134
+ duration: this._calculateDuration(jobId),
132
135
  });
133
136
  }
134
137
 
@@ -143,7 +146,7 @@ export class EventBus extends EventEmitter {
143
146
  reason: data.reason || 'User cancelled',
144
147
  partial_result: data.partial_result,
145
148
  timestamp: Date.now(),
146
- ...data
149
+ ...data,
147
150
  });
148
151
  }
149
152
 
@@ -157,7 +160,7 @@ export class EventBus extends EventEmitter {
157
160
  return this._emitJobEvent(EVENT_TYPES.JOB_STARTED, jobId, {
158
161
  tool: data.tool,
159
162
  timestamp: Date.now(),
160
- ...data
163
+ ...data,
161
164
  });
162
165
  }
163
166
 
@@ -171,14 +174,14 @@ export class EventBus extends EventEmitter {
171
174
  if (!Object.values(EVENT_TYPES).includes(eventType)) {
172
175
  throw new EventBusError(
173
176
  `Invalid event type: ${eventType}`,
174
- 'INVALID_EVENT_TYPE'
177
+ 'INVALID_EVENT_TYPE',
175
178
  );
176
179
  }
177
180
 
178
181
  if (typeof listener !== 'function') {
179
182
  throw new EventBusError(
180
183
  'Listener must be a function',
181
- 'INVALID_LISTENER'
184
+ 'INVALID_LISTENER',
182
185
  );
183
186
  }
184
187
 
@@ -218,7 +221,7 @@ export class EventBus extends EventEmitter {
218
221
  ...this.stats,
219
222
  totalListeners: this.listenerCount(),
220
223
  eventHistorySize: this.eventHistory.size,
221
- memoryUsage: this._calculateMemoryUsage()
224
+ memoryUsage: this._calculateMemoryUsage(),
222
225
  };
223
226
  }
224
227
 
@@ -236,7 +239,7 @@ export class EventBus extends EventEmitter {
236
239
  if (!jobId || typeof jobId !== 'string') {
237
240
  throw new EventBusError(
238
241
  'Invalid job ID: must be a non-empty string',
239
- 'INVALID_JOB_ID'
242
+ 'INVALID_JOB_ID',
240
243
  );
241
244
  }
242
245
 
@@ -245,7 +248,7 @@ export class EventBus extends EventEmitter {
245
248
  type: eventType,
246
249
  jobId,
247
250
  data,
248
- timestamp: data.timestamp || Date.now()
251
+ timestamp: data.timestamp || Date.now(),
249
252
  };
250
253
 
251
254
  // Add to history
@@ -259,15 +262,17 @@ export class EventBus extends EventEmitter {
259
262
 
260
263
  debugLog(`EventBus: Emitted ${eventType} for job ${jobId}`);
261
264
  return hasListeners;
262
-
263
265
  } catch (error) {
264
- debugError(`EventBus: Failed to emit event ${eventType} for job ${jobId}:`, error);
266
+ debugError(
267
+ `EventBus: Failed to emit event ${eventType} for job ${jobId}:`,
268
+ error,
269
+ );
265
270
  if (error instanceof EventBusError) {
266
271
  throw error;
267
272
  }
268
273
  throw new EventBusError(
269
274
  `Failed to emit event: ${error.message}`,
270
- 'EMISSION_ERROR'
275
+ 'EMISSION_ERROR',
271
276
  );
272
277
  }
273
278
  }
@@ -304,7 +309,7 @@ export class EventBus extends EventEmitter {
304
309
  return null;
305
310
  }
306
311
 
307
- const createEvent = history.find(e => e.type === EVENT_TYPES.JOB_CREATED);
312
+ const createEvent = history.find((e) => e.type === EVENT_TYPES.JOB_CREATED);
308
313
  if (!createEvent) {
309
314
  return null;
310
315
  }