ms365-mcp-server 1.1.15 → 1.1.17
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/dist/index.js +1123 -10
- package/dist/utils/batch-performance-monitor.js +106 -0
- package/dist/utils/batch-test-scenarios.js +277 -0
- package/dist/utils/context-aware-search.js +499 -0
- package/dist/utils/cross-reference-detector.js +352 -0
- package/dist/utils/document-workflow.js +433 -0
- package/dist/utils/enhanced-fuzzy-search.js +514 -0
- package/dist/utils/error-handler.js +337 -0
- package/dist/utils/intelligence-engine.js +71 -0
- package/dist/utils/intelligent-cache.js +379 -0
- package/dist/utils/large-mailbox-search.js +599 -0
- package/dist/utils/ms365-operations.js +799 -219
- package/dist/utils/performance-monitor.js +395 -0
- package/dist/utils/proactive-intelligence.js +390 -0
- package/dist/utils/rate-limiter.js +284 -0
- package/dist/utils/search-batch-pipeline.js +222 -0
- package/dist/utils/thread-reconstruction.js +700 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,8 +15,24 @@ import { logger } from './utils/api.js';
|
|
|
15
15
|
import { MS365Operations } from './utils/ms365-operations.js';
|
|
16
16
|
import { multiUserMS365Auth } from './utils/multi-user-auth.js';
|
|
17
17
|
import { enhancedMS365Auth } from './utils/ms365-auth-enhanced.js';
|
|
18
|
+
import { IntelligenceEngine } from './utils/intelligence-engine.js';
|
|
19
|
+
import { ProactiveIntelligence } from './utils/proactive-intelligence.js';
|
|
20
|
+
import { DocumentWorkflow } from './utils/document-workflow.js';
|
|
21
|
+
import { ContextAwareSearch } from './utils/context-aware-search.js';
|
|
22
|
+
import { LargeMailboxSearch } from './utils/large-mailbox-search.js';
|
|
23
|
+
import { BatchTestRunner } from './utils/batch-test-scenarios.js';
|
|
24
|
+
import { performanceMonitor } from './utils/batch-performance-monitor.js';
|
|
25
|
+
import { SearchBatchPipeline } from './utils/search-batch-pipeline.js';
|
|
18
26
|
// Create singleton MS365Operations instance
|
|
19
27
|
const ms365Ops = new MS365Operations();
|
|
28
|
+
// Create singleton intelligence services
|
|
29
|
+
const intelligenceEngine = new IntelligenceEngine(ms365Ops);
|
|
30
|
+
const proactiveIntelligence = new ProactiveIntelligence(ms365Ops);
|
|
31
|
+
const documentWorkflow = new DocumentWorkflow();
|
|
32
|
+
const contextAwareSearch = new ContextAwareSearch(ms365Ops);
|
|
33
|
+
const largeMailboxSearch = new LargeMailboxSearch(ms365Ops, contextAwareSearch, intelligenceEngine, proactiveIntelligence);
|
|
34
|
+
const batchTestRunner = new BatchTestRunner(ms365Ops);
|
|
35
|
+
const searchBatchPipeline = new SearchBatchPipeline(ms365Ops);
|
|
20
36
|
let ms365Config = {
|
|
21
37
|
setupAuth: false,
|
|
22
38
|
resetAuth: false,
|
|
@@ -67,7 +83,7 @@ function parseArgs() {
|
|
|
67
83
|
}
|
|
68
84
|
const server = new Server({
|
|
69
85
|
name: "ms365-mcp-server",
|
|
70
|
-
version: "1.1.
|
|
86
|
+
version: "1.1.17"
|
|
71
87
|
}, {
|
|
72
88
|
capabilities: {
|
|
73
89
|
resources: {
|
|
@@ -88,7 +104,7 @@ const server = new Server({
|
|
|
88
104
|
}
|
|
89
105
|
}
|
|
90
106
|
});
|
|
91
|
-
logger.log('Server started with version 1.1.
|
|
107
|
+
logger.log('Server started with version 1.1.16');
|
|
92
108
|
// Set up the resource listing request handler
|
|
93
109
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
94
110
|
logger.log('Received list resources request');
|
|
@@ -210,7 +226,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
210
226
|
},
|
|
211
227
|
{
|
|
212
228
|
name: "manage_email",
|
|
213
|
-
description: "
|
|
229
|
+
description: "🚀 GRAPH API COMPLIANT EMAIL MANAGEMENT: Advanced email operations with Microsoft Graph API compliance. ✅ FIXED: Separated $filter and $search operations to respect Graph API limitations. ✅ OPTIMIZED: Dynamic timeouts (30-60s), intelligent strategy selection, and proper field restrictions. 📧 Actions: search, search_to_me, list, mark, move, delete, draft operations, threading support",
|
|
214
230
|
inputSchema: {
|
|
215
231
|
type: "object",
|
|
216
232
|
properties: {
|
|
@@ -467,6 +483,351 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
467
483
|
}
|
|
468
484
|
}
|
|
469
485
|
}
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
name: "batch_operations",
|
|
489
|
+
description: "🚀 NATIVE GRAPH BATCHING: Leverage Microsoft Graph's native JSON batching API to perform up to 20 operations in a single HTTP request. Dramatically improves performance for multiple email operations. Based on official Microsoft Graph batching documentation.",
|
|
490
|
+
inputSchema: {
|
|
491
|
+
type: "object",
|
|
492
|
+
properties: {
|
|
493
|
+
userId: {
|
|
494
|
+
type: "string",
|
|
495
|
+
description: "User ID for multi-user authentication (required if using multi-user mode)"
|
|
496
|
+
},
|
|
497
|
+
action: {
|
|
498
|
+
type: "string",
|
|
499
|
+
enum: ["batch_get_emails", "batch_email_operations", "batch_folder_operations", "get_folder_with_emails"],
|
|
500
|
+
description: "Batch action: batch_get_emails (get multiple emails efficiently), batch_email_operations (mark/move/delete multiple emails), batch_folder_operations (multiple folder operations), get_folder_with_emails (get folder info and recent emails together)"
|
|
501
|
+
},
|
|
502
|
+
messageIds: {
|
|
503
|
+
type: "array",
|
|
504
|
+
items: { type: "string" },
|
|
505
|
+
description: "List of message IDs for batch_get_emails and batch_email_operations actions"
|
|
506
|
+
},
|
|
507
|
+
includeAttachments: {
|
|
508
|
+
type: "boolean",
|
|
509
|
+
description: "Include attachment info when getting emails (batch_get_emails action)",
|
|
510
|
+
default: false
|
|
511
|
+
},
|
|
512
|
+
operations: {
|
|
513
|
+
type: "array",
|
|
514
|
+
items: {
|
|
515
|
+
type: "object",
|
|
516
|
+
properties: {
|
|
517
|
+
id: {
|
|
518
|
+
type: "string",
|
|
519
|
+
description: "Unique ID for this operation (for tracking results)"
|
|
520
|
+
},
|
|
521
|
+
operation: {
|
|
522
|
+
type: "string",
|
|
523
|
+
enum: ["mark", "move", "delete"],
|
|
524
|
+
description: "Operation type: mark (read/unread), move (to folder), delete (permanently)"
|
|
525
|
+
},
|
|
526
|
+
messageId: {
|
|
527
|
+
type: "string",
|
|
528
|
+
description: "Message ID to operate on"
|
|
529
|
+
},
|
|
530
|
+
params: {
|
|
531
|
+
type: "object",
|
|
532
|
+
properties: {
|
|
533
|
+
isRead: {
|
|
534
|
+
type: "boolean",
|
|
535
|
+
description: "Mark as read (true) or unread (false) for mark operation"
|
|
536
|
+
},
|
|
537
|
+
destinationFolderId: {
|
|
538
|
+
type: "string",
|
|
539
|
+
description: "Destination folder ID for move operation"
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
description: "Parameters for the operation"
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
required: ["id", "operation", "messageId"]
|
|
546
|
+
},
|
|
547
|
+
description: "List of email operations to perform in batch (max 20 operations)"
|
|
548
|
+
},
|
|
549
|
+
folderId: {
|
|
550
|
+
type: "string",
|
|
551
|
+
description: "Folder ID for get_folder_with_emails action"
|
|
552
|
+
},
|
|
553
|
+
emailCount: {
|
|
554
|
+
type: "number",
|
|
555
|
+
description: "Number of recent emails to get with folder info (default: 10, max: 50)",
|
|
556
|
+
minimum: 1,
|
|
557
|
+
maximum: 50,
|
|
558
|
+
default: 10
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
required: ["action"]
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
name: "ai_email_assistant",
|
|
566
|
+
description: "🤖 AI EMAIL ASSISTANT: GRAPH API COMPLIANT intelligent email companion with OPTIMIZED LARGE MAILBOX SUPPORT. ✅ FIXED: Proper $filter/$search separation, field restrictions, and timeout handling. Features: Dynamic timeouts (up to 3 minutes), progressive search tiers, Graph API compliance, smart fallbacks. 🚀 BEST FOR: Large mailboxes (20k+ emails), complex searches, timeout-sensitive operations.",
|
|
567
|
+
inputSchema: {
|
|
568
|
+
type: "object",
|
|
569
|
+
properties: {
|
|
570
|
+
userId: {
|
|
571
|
+
type: "string",
|
|
572
|
+
description: "User ID for multi-user authentication (required if using multi-user mode)"
|
|
573
|
+
},
|
|
574
|
+
action: {
|
|
575
|
+
type: "string",
|
|
576
|
+
enum: ["search", "classify", "process_attachments"],
|
|
577
|
+
description: "Action: 'search' (intelligent search with AI), 'classify' (smart email classification), 'process_attachments' (intelligent attachment processing)"
|
|
578
|
+
},
|
|
579
|
+
query: {
|
|
580
|
+
type: "string",
|
|
581
|
+
description: "Natural language search query (e.g., 'tax notice from few weeks', 'government emails urgent', 'related to project alpha') - required for search action"
|
|
582
|
+
},
|
|
583
|
+
// Search options
|
|
584
|
+
enableCrossReference: {
|
|
585
|
+
type: "boolean",
|
|
586
|
+
description: "Enable cross-reference detection to find related emails (search action)",
|
|
587
|
+
default: true
|
|
588
|
+
},
|
|
589
|
+
enableFuzzySearch: {
|
|
590
|
+
type: "boolean",
|
|
591
|
+
description: "Enable fuzzy matching for better search results (search action)",
|
|
592
|
+
default: true
|
|
593
|
+
},
|
|
594
|
+
enableThreadReconstruction: {
|
|
595
|
+
type: "boolean",
|
|
596
|
+
description: "Enable thread reconstruction for forwarded email chains (search action)",
|
|
597
|
+
default: true
|
|
598
|
+
},
|
|
599
|
+
enableContextAware: {
|
|
600
|
+
type: "boolean",
|
|
601
|
+
description: "Enable context-aware search with time/sender understanding (search action)",
|
|
602
|
+
default: true
|
|
603
|
+
},
|
|
604
|
+
folder: {
|
|
605
|
+
type: "string",
|
|
606
|
+
description: "Search within specific folder (search action, default: all folders)"
|
|
607
|
+
},
|
|
608
|
+
corpusSize: {
|
|
609
|
+
type: "number",
|
|
610
|
+
description: "Number of recent emails to search through (search action, default: 200, max: 1000)",
|
|
611
|
+
minimum: 10,
|
|
612
|
+
maximum: 1000,
|
|
613
|
+
default: 200
|
|
614
|
+
},
|
|
615
|
+
useLargeMailboxStrategy: {
|
|
616
|
+
type: "boolean",
|
|
617
|
+
description: "Enable intelligent multi-tier search for large mailboxes (20k+ emails) - automatically enabled for large mailboxes",
|
|
618
|
+
default: false
|
|
619
|
+
},
|
|
620
|
+
timeWindowDays: {
|
|
621
|
+
type: "number",
|
|
622
|
+
description: "Time window in days for large mailbox search (default: 90 for optimal performance, max: 365 for comprehensive search)",
|
|
623
|
+
minimum: 30,
|
|
624
|
+
maximum: 1095,
|
|
625
|
+
default: 90
|
|
626
|
+
},
|
|
627
|
+
// Classification options
|
|
628
|
+
classifyAction: {
|
|
629
|
+
type: "string",
|
|
630
|
+
enum: ["classify_recent", "classify_folder", "classify_batch", "get_summary"],
|
|
631
|
+
description: "Classification action: classify_recent (last 50 emails), classify_folder (specific folder), classify_batch (specific emails), get_summary (classification summary)"
|
|
632
|
+
},
|
|
633
|
+
folderId: {
|
|
634
|
+
type: "string",
|
|
635
|
+
description: "Folder ID for classify_folder action (e.g., 'inbox', 'sent')"
|
|
636
|
+
},
|
|
637
|
+
messageIds: {
|
|
638
|
+
type: "array",
|
|
639
|
+
items: { type: "string" },
|
|
640
|
+
description: "List of message IDs for classify_batch action or specific email for processing"
|
|
641
|
+
},
|
|
642
|
+
category: {
|
|
643
|
+
type: "string",
|
|
644
|
+
enum: ["government", "tax", "legal", "financial", "healthcare", "insurance", "deadline", "invoice", "security"],
|
|
645
|
+
description: "Filter by specific category (classify action)"
|
|
646
|
+
},
|
|
647
|
+
priority: {
|
|
648
|
+
type: "string",
|
|
649
|
+
enum: ["critical", "high", "medium", "low"],
|
|
650
|
+
description: "Filter by priority level (classify action)"
|
|
651
|
+
},
|
|
652
|
+
// Attachment processing options
|
|
653
|
+
messageId: {
|
|
654
|
+
type: "string",
|
|
655
|
+
description: "Email message ID containing attachments (process_attachments action)"
|
|
656
|
+
},
|
|
657
|
+
attachmentIds: {
|
|
658
|
+
type: "array",
|
|
659
|
+
items: { type: "string" },
|
|
660
|
+
description: "Specific attachment IDs to process (process_attachments action, optional)"
|
|
661
|
+
},
|
|
662
|
+
autoDecrypt: {
|
|
663
|
+
type: "boolean",
|
|
664
|
+
description: "Attempt to automatically decrypt password-protected files (process_attachments action)",
|
|
665
|
+
default: true
|
|
666
|
+
},
|
|
667
|
+
extractText: {
|
|
668
|
+
type: "boolean",
|
|
669
|
+
description: "Extract text content from documents (process_attachments action)",
|
|
670
|
+
default: true
|
|
671
|
+
},
|
|
672
|
+
customPasswords: {
|
|
673
|
+
type: "array",
|
|
674
|
+
items: { type: "string" },
|
|
675
|
+
description: "Additional passwords to try for decryption (process_attachments action)"
|
|
676
|
+
},
|
|
677
|
+
// General options
|
|
678
|
+
maxResults: {
|
|
679
|
+
type: "number",
|
|
680
|
+
description: "Maximum number of results to return",
|
|
681
|
+
minimum: 1,
|
|
682
|
+
maximum: 200,
|
|
683
|
+
default: 50
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
required: ["action"]
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
name: "performance_testing",
|
|
691
|
+
description: "🔬 PERFORMANCE TESTING & BENCHMARKING: Comprehensive testing suite to benchmark traditional vs native batched operations. Compare performance, monitor improvements, and generate detailed reports showing HTTP call reduction and speed improvements.",
|
|
692
|
+
inputSchema: {
|
|
693
|
+
type: "object",
|
|
694
|
+
properties: {
|
|
695
|
+
userId: {
|
|
696
|
+
type: "string",
|
|
697
|
+
description: "User ID for multi-user authentication (required if using multi-user mode)"
|
|
698
|
+
},
|
|
699
|
+
action: {
|
|
700
|
+
type: "string",
|
|
701
|
+
enum: ["run_tests", "benchmark_bulk_retrieval", "benchmark_bulk_operations", "benchmark_folder_operations", "benchmark_mixed_operations", "generate_report", "clear_metrics"],
|
|
702
|
+
description: "Testing action: run_tests (comprehensive test suite), benchmark_* (specific performance tests), generate_report (create performance report), clear_metrics (reset all metrics)"
|
|
703
|
+
},
|
|
704
|
+
testEmailCount: {
|
|
705
|
+
type: "number",
|
|
706
|
+
description: "Number of emails to use for testing (default: 10, max: 20 for safety)",
|
|
707
|
+
minimum: 5,
|
|
708
|
+
maximum: 20,
|
|
709
|
+
default: 10
|
|
710
|
+
},
|
|
711
|
+
includeAttachments: {
|
|
712
|
+
type: "boolean",
|
|
713
|
+
description: "Include attachment operations in bulk retrieval tests",
|
|
714
|
+
default: true
|
|
715
|
+
},
|
|
716
|
+
folderId: {
|
|
717
|
+
type: "string",
|
|
718
|
+
description: "Folder ID to test (default: inbox)",
|
|
719
|
+
default: "inbox"
|
|
720
|
+
},
|
|
721
|
+
operationType: {
|
|
722
|
+
type: "string",
|
|
723
|
+
enum: ["mark", "move"],
|
|
724
|
+
description: "Type of operation for bulk operations test (default: mark)",
|
|
725
|
+
default: "mark"
|
|
726
|
+
},
|
|
727
|
+
generateDetailedLog: {
|
|
728
|
+
type: "boolean",
|
|
729
|
+
description: "Generate detailed performance logs",
|
|
730
|
+
default: true
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
required: ["action"]
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
name: "search_batch_pipeline",
|
|
738
|
+
description: "🔄 SEARCH-TO-BATCH PIPELINE: Seamlessly combine search and batch operations for maximum efficiency. Find emails with search, then efficiently process them with native batching. Perfect for bulk operations on search results.",
|
|
739
|
+
inputSchema: {
|
|
740
|
+
type: "object",
|
|
741
|
+
properties: {
|
|
742
|
+
userId: {
|
|
743
|
+
type: "string",
|
|
744
|
+
description: "User ID for multi-user authentication (required if using multi-user mode)"
|
|
745
|
+
},
|
|
746
|
+
action: {
|
|
747
|
+
type: "string",
|
|
748
|
+
enum: ["search_and_retrieve", "search_and_mark_read", "search_and_mark_unread", "search_and_move", "search_and_delete", "quick_workflows"],
|
|
749
|
+
description: "Pipeline action: search_and_retrieve (search + get full details), search_and_mark_read (search + mark as read), search_and_mark_unread (search + mark as unread), search_and_move (search + move to folder), search_and_delete (search + delete), quick_workflows (pre-built workflows)"
|
|
750
|
+
},
|
|
751
|
+
// Search criteria
|
|
752
|
+
query: {
|
|
753
|
+
type: "string",
|
|
754
|
+
description: "Search query for finding emails"
|
|
755
|
+
},
|
|
756
|
+
from: {
|
|
757
|
+
type: "string",
|
|
758
|
+
description: "Search emails from specific sender"
|
|
759
|
+
},
|
|
760
|
+
to: {
|
|
761
|
+
type: "string",
|
|
762
|
+
description: "Search emails to specific recipient"
|
|
763
|
+
},
|
|
764
|
+
subject: {
|
|
765
|
+
type: "string",
|
|
766
|
+
description: "Search emails with specific subject"
|
|
767
|
+
},
|
|
768
|
+
folder: {
|
|
769
|
+
type: "string",
|
|
770
|
+
description: "Search within specific folder"
|
|
771
|
+
},
|
|
772
|
+
after: {
|
|
773
|
+
type: "string",
|
|
774
|
+
description: "Search emails after date (YYYY-MM-DD)"
|
|
775
|
+
},
|
|
776
|
+
before: {
|
|
777
|
+
type: "string",
|
|
778
|
+
description: "Search emails before date (YYYY-MM-DD)"
|
|
779
|
+
},
|
|
780
|
+
hasAttachment: {
|
|
781
|
+
type: "boolean",
|
|
782
|
+
description: "Filter emails with attachments"
|
|
783
|
+
},
|
|
784
|
+
isUnread: {
|
|
785
|
+
type: "boolean",
|
|
786
|
+
description: "Filter for unread emails"
|
|
787
|
+
},
|
|
788
|
+
importance: {
|
|
789
|
+
type: "string",
|
|
790
|
+
enum: ["low", "normal", "high"],
|
|
791
|
+
description: "Filter by importance level"
|
|
792
|
+
},
|
|
793
|
+
maxResults: {
|
|
794
|
+
type: "number",
|
|
795
|
+
description: "Maximum results to find and process (default: 50, max: 100)",
|
|
796
|
+
minimum: 1,
|
|
797
|
+
maximum: 100,
|
|
798
|
+
default: 50
|
|
799
|
+
},
|
|
800
|
+
// Batch operation parameters
|
|
801
|
+
includeAttachments: {
|
|
802
|
+
type: "boolean",
|
|
803
|
+
description: "Include attachments in search_and_retrieve action",
|
|
804
|
+
default: false
|
|
805
|
+
},
|
|
806
|
+
destinationFolderId: {
|
|
807
|
+
type: "string",
|
|
808
|
+
description: "Destination folder ID for search_and_move action"
|
|
809
|
+
},
|
|
810
|
+
// Quick workflow parameters
|
|
811
|
+
workflowType: {
|
|
812
|
+
type: "string",
|
|
813
|
+
enum: ["mark_sender_read", "move_by_subject", "delete_old", "get_attachments"],
|
|
814
|
+
description: "Pre-built workflow type for quick_workflows action"
|
|
815
|
+
},
|
|
816
|
+
senderEmail: {
|
|
817
|
+
type: "string",
|
|
818
|
+
description: "Sender email for mark_sender_read workflow"
|
|
819
|
+
},
|
|
820
|
+
subjectText: {
|
|
821
|
+
type: "string",
|
|
822
|
+
description: "Subject text for move_by_subject workflow"
|
|
823
|
+
},
|
|
824
|
+
beforeDate: {
|
|
825
|
+
type: "string",
|
|
826
|
+
description: "Date for delete_old workflow (YYYY-MM-DD)"
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
required: ["action"]
|
|
830
|
+
}
|
|
470
831
|
}
|
|
471
832
|
];
|
|
472
833
|
// Add multi-user specific tools
|
|
@@ -538,6 +899,19 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
538
899
|
*/
|
|
539
900
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
540
901
|
const { name, arguments: args } = request.params;
|
|
902
|
+
// Helper function to validate and normalize bodyType
|
|
903
|
+
const normalizeBodyType = (bodyType) => {
|
|
904
|
+
if (!bodyType)
|
|
905
|
+
return 'text';
|
|
906
|
+
const normalized = bodyType.toString().toLowerCase().trim();
|
|
907
|
+
if (normalized === 'html')
|
|
908
|
+
return 'html';
|
|
909
|
+
if (normalized === 'text')
|
|
910
|
+
return 'text';
|
|
911
|
+
// Invalid value provided - log warning and default to text
|
|
912
|
+
logger.log(`⚠️ Invalid bodyType '${bodyType}' provided. Valid values are 'text' or 'html'. Defaulting to 'text'.`);
|
|
913
|
+
return 'text';
|
|
914
|
+
};
|
|
541
915
|
try {
|
|
542
916
|
switch (name) {
|
|
543
917
|
// ============ UNIFIED AUTHENTICATION TOOL ============
|
|
@@ -720,7 +1094,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
720
1094
|
]
|
|
721
1095
|
};
|
|
722
1096
|
case "search":
|
|
723
|
-
|
|
1097
|
+
// Enhanced basic search with dynamic timeout based on search complexity
|
|
1098
|
+
const hasComplexFilters = !!(args?.query || args?.from || args?.subject || args?.after || args?.before);
|
|
1099
|
+
const baseTimeout = hasComplexFilters ? 60000 : 45000; // 60s for complex, 45s for simple
|
|
1100
|
+
const maxResults = args?.maxResults || 50;
|
|
1101
|
+
const adjustedTimeout = maxResults > 100 ? baseTimeout * 1.5 : baseTimeout; // Increase timeout for large result sets
|
|
1102
|
+
logger.log(`🔍 Search timeout set to ${adjustedTimeout / 1000}s (complex: ${hasComplexFilters}, maxResults: ${maxResults})`);
|
|
1103
|
+
const searchPromise = ms365Ops.searchEmails(args);
|
|
1104
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1105
|
+
setTimeout(() => {
|
|
1106
|
+
reject(new Error(`Search timed out after ${adjustedTimeout / 1000} seconds. For large mailboxes or complex searches, try: (1) ai_email_assistant with useLargeMailboxStrategy: true, (2) More specific search terms, (3) Smaller maxResults (current: ${maxResults}), or (4) Narrower date ranges.`));
|
|
1107
|
+
}, adjustedTimeout);
|
|
1108
|
+
});
|
|
1109
|
+
const searchResults = await Promise.race([searchPromise, timeoutPromise]);
|
|
724
1110
|
logger.log(`DEBUG: Search results count: ${searchResults.messages.length}`);
|
|
725
1111
|
logger.log(`DEBUG: First result:`, JSON.stringify(searchResults.messages[0], null, 2));
|
|
726
1112
|
// Enhanced feedback for search results
|
|
@@ -762,7 +1148,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
762
1148
|
const batchSize = args?.batchSize || 50;
|
|
763
1149
|
const maxBatches = args?.maxBatches || 5;
|
|
764
1150
|
logger.log(`DEBUG: Starting batched search with batchSize: ${batchSize}, maxBatches: ${maxBatches}`);
|
|
765
|
-
|
|
1151
|
+
// Add timeout protection for batched searches
|
|
1152
|
+
const batchTimeout = 45000; // 45 seconds for batched searches
|
|
1153
|
+
const batchPromise = ms365Ops.searchEmailsBatched(args, batchSize, maxBatches);
|
|
1154
|
+
const batchTimeoutPromise = new Promise((_, reject) => {
|
|
1155
|
+
setTimeout(() => {
|
|
1156
|
+
reject(new Error('Batched search timed out - try using ai_email_assistant with useLargeMailboxStrategy: true for better performance with large mailboxes'));
|
|
1157
|
+
}, batchTimeout);
|
|
1158
|
+
});
|
|
1159
|
+
const batchedSearchResults = await Promise.race([batchPromise, batchTimeoutPromise]);
|
|
766
1160
|
logger.log(`DEBUG: Batched search results count: ${batchedSearchResults.messages.length} from ${batchedSearchResults.totalBatches} batches`);
|
|
767
1161
|
// Enhanced feedback for batched search results
|
|
768
1162
|
let batchedResponseText = `🔍 Batched Email Search Results (${batchedSearchResults.messages.length} found from ${batchedSearchResults.totalBatches} batches)`;
|
|
@@ -954,7 +1348,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
954
1348
|
bcc: normalizeDraftEmailArray(args.draftBcc),
|
|
955
1349
|
subject: args.draftSubject,
|
|
956
1350
|
body: args.draftBody,
|
|
957
|
-
bodyType: args.draftBodyType
|
|
1351
|
+
bodyType: normalizeBodyType(args.draftBodyType),
|
|
958
1352
|
importance: args.draftImportance || 'normal',
|
|
959
1353
|
attachments: args.draftAttachments,
|
|
960
1354
|
conversationId: args.conversationId
|
|
@@ -998,7 +1392,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
998
1392
|
if (args.draftBody)
|
|
999
1393
|
updates.body = args.draftBody;
|
|
1000
1394
|
if (args.draftBodyType)
|
|
1001
|
-
updates.bodyType = args.draftBodyType;
|
|
1395
|
+
updates.bodyType = normalizeBodyType(args.draftBodyType);
|
|
1002
1396
|
if (args.draftImportance)
|
|
1003
1397
|
updates.importance = args.draftImportance;
|
|
1004
1398
|
if (args.draftAttachments)
|
|
@@ -1039,7 +1433,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1039
1433
|
if (!args?.originalMessageId) {
|
|
1040
1434
|
throw new Error("originalMessageId is required for reply_draft action");
|
|
1041
1435
|
}
|
|
1042
|
-
const replyDraftResult = await ms365Ops.createReplyDraft(args.originalMessageId, args.draftBody, args.replyToAll || false, args.draftBodyType
|
|
1436
|
+
const replyDraftResult = await ms365Ops.createReplyDraft(args.originalMessageId, args.draftBody, args.replyToAll || false, normalizeBodyType(args.draftBodyType));
|
|
1043
1437
|
return {
|
|
1044
1438
|
content: [
|
|
1045
1439
|
{
|
|
@@ -1052,7 +1446,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1052
1446
|
if (!args?.originalMessageId) {
|
|
1053
1447
|
throw new Error("originalMessageId is required for forward_draft action");
|
|
1054
1448
|
}
|
|
1055
|
-
const forwardDraftResult = await ms365Ops.createForwardDraft(args.originalMessageId, args.draftBody, args.draftBodyType
|
|
1449
|
+
const forwardDraftResult = await ms365Ops.createForwardDraft(args.originalMessageId, args.draftBody, normalizeBodyType(args.draftBodyType));
|
|
1056
1450
|
return {
|
|
1057
1451
|
content: [
|
|
1058
1452
|
{
|
|
@@ -1107,6 +1501,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1107
1501
|
throw new Error(`Unknown contact action: ${contactAction}`);
|
|
1108
1502
|
}
|
|
1109
1503
|
// ============ REMAINING ORIGINAL TOOLS ============
|
|
1504
|
+
// ============ REMAINING ORIGINAL TOOLS ============
|
|
1110
1505
|
case "send_email":
|
|
1111
1506
|
if (ms365Config.multiUser) {
|
|
1112
1507
|
const userId = args?.userId;
|
|
@@ -1144,7 +1539,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1144
1539
|
bcc: normalizeEmailArray(args.bcc),
|
|
1145
1540
|
subject: args.subject,
|
|
1146
1541
|
body: args.body || '',
|
|
1147
|
-
bodyType: args.bodyType
|
|
1542
|
+
bodyType: normalizeBodyType(args.bodyType),
|
|
1148
1543
|
replyTo: args.replyTo,
|
|
1149
1544
|
importance: args.importance || 'normal',
|
|
1150
1545
|
attachments: args.attachments || []
|
|
@@ -1311,6 +1706,724 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1311
1706
|
}
|
|
1312
1707
|
]
|
|
1313
1708
|
};
|
|
1709
|
+
// ============ NATIVE JSON BATCHING TOOL ============
|
|
1710
|
+
case "batch_operations":
|
|
1711
|
+
if (ms365Config.multiUser) {
|
|
1712
|
+
const userId = args?.userId;
|
|
1713
|
+
if (!userId) {
|
|
1714
|
+
throw new Error("User ID is required in multi-user mode");
|
|
1715
|
+
}
|
|
1716
|
+
const graphClient = await multiUserMS365Auth.getGraphClientForUser(userId);
|
|
1717
|
+
ms365Ops.setGraphClient(graphClient);
|
|
1718
|
+
}
|
|
1719
|
+
else {
|
|
1720
|
+
const graphClient = await enhancedMS365Auth.getGraphClient();
|
|
1721
|
+
ms365Ops.setGraphClient(graphClient);
|
|
1722
|
+
}
|
|
1723
|
+
const batchAction = args?.action;
|
|
1724
|
+
if (!batchAction) {
|
|
1725
|
+
throw new Error("Action is required for batch operations");
|
|
1726
|
+
}
|
|
1727
|
+
switch (batchAction) {
|
|
1728
|
+
case 'batch_get_emails':
|
|
1729
|
+
if (!args?.messageIds || !Array.isArray(args.messageIds)) {
|
|
1730
|
+
throw new Error("messageIds array is required for batch_get_emails action");
|
|
1731
|
+
}
|
|
1732
|
+
const batchEmails = await ms365Ops.getEmailsBatch(args.messageIds, args?.includeAttachments || false);
|
|
1733
|
+
return {
|
|
1734
|
+
content: [
|
|
1735
|
+
{
|
|
1736
|
+
type: "text",
|
|
1737
|
+
text: `🚀 Native Batch Email Results (${batchEmails.length} emails retrieved)\n\n` +
|
|
1738
|
+
`📊 Performance: Single HTTP request for ${args.messageIds.length} emails\n\n` +
|
|
1739
|
+
batchEmails.map((email, index) => `${index + 1}. 📧 ${email.subject}\n` +
|
|
1740
|
+
` 👤 From: ${email.from.name} <${email.from.address}>\n` +
|
|
1741
|
+
` 📅 ${new Date(email.receivedDateTime).toLocaleString()}\n` +
|
|
1742
|
+
` ${email.isRead ? '📖 Read' : '📩 Unread'}\n` +
|
|
1743
|
+
` 🆔 ID: ${email.id}\n` +
|
|
1744
|
+
(email.attachments?.length ? ` 📎 Attachments: ${email.attachments.length}\n` : '')).join('\n') +
|
|
1745
|
+
`\n💡 Traditional approach would require ${args.messageIds.length} separate API calls!`
|
|
1746
|
+
}
|
|
1747
|
+
]
|
|
1748
|
+
};
|
|
1749
|
+
case 'batch_email_operations':
|
|
1750
|
+
if (!args?.operations || !Array.isArray(args.operations)) {
|
|
1751
|
+
throw new Error("operations array is required for batch_email_operations action");
|
|
1752
|
+
}
|
|
1753
|
+
if (args.operations.length > 20) {
|
|
1754
|
+
throw new Error("Maximum 20 operations allowed per batch (Microsoft Graph limit)");
|
|
1755
|
+
}
|
|
1756
|
+
const operationResults = await ms365Ops.batchEmailOperations(args.operations);
|
|
1757
|
+
let successCount = 0;
|
|
1758
|
+
let failureCount = 0;
|
|
1759
|
+
const resultText = Array.from(operationResults.entries()).map(([id, result]) => {
|
|
1760
|
+
if (result.success) {
|
|
1761
|
+
successCount++;
|
|
1762
|
+
return `✅ ${id}: Success`;
|
|
1763
|
+
}
|
|
1764
|
+
else {
|
|
1765
|
+
failureCount++;
|
|
1766
|
+
return `❌ ${id}: ${result.error}`;
|
|
1767
|
+
}
|
|
1768
|
+
}).join('\n');
|
|
1769
|
+
return {
|
|
1770
|
+
content: [
|
|
1771
|
+
{
|
|
1772
|
+
type: "text",
|
|
1773
|
+
text: `🚀 Native Batch Operations Results\n\n` +
|
|
1774
|
+
`📊 Performance: ${args.operations.length} operations in single HTTP request\n` +
|
|
1775
|
+
`✅ Successful: ${successCount}\n` +
|
|
1776
|
+
`❌ Failed: ${failureCount}\n\n` +
|
|
1777
|
+
`📋 Detailed Results:\n${resultText}\n\n` +
|
|
1778
|
+
`💡 Traditional approach would require ${args.operations.length} separate API calls!`
|
|
1779
|
+
}
|
|
1780
|
+
]
|
|
1781
|
+
};
|
|
1782
|
+
case 'get_folder_with_emails':
|
|
1783
|
+
if (!args?.folderId) {
|
|
1784
|
+
throw new Error("folderId is required for get_folder_with_emails action");
|
|
1785
|
+
}
|
|
1786
|
+
const emailCount = Math.min(args?.emailCount || 10, 50);
|
|
1787
|
+
const folderWithEmails = await ms365Ops.getFolderWithRecentEmails(args.folderId, emailCount);
|
|
1788
|
+
return {
|
|
1789
|
+
content: [
|
|
1790
|
+
{
|
|
1791
|
+
type: "text",
|
|
1792
|
+
text: `🚀 Native Batch Folder + Emails Results\n\n` +
|
|
1793
|
+
`📊 Performance: Folder info + ${emailCount} emails in single HTTP request\n\n` +
|
|
1794
|
+
`📁 Folder: ${folderWithEmails.folder?.displayName || 'Unknown'}\n` +
|
|
1795
|
+
` 🆔 ID: ${folderWithEmails.folder?.id}\n` +
|
|
1796
|
+
` 📧 Total Items: ${folderWithEmails.folder?.totalItemCount || 0}\n` +
|
|
1797
|
+
` 📩 Unread: ${folderWithEmails.folder?.unreadItemCount || 0}\n\n` +
|
|
1798
|
+
`📧 Recent Emails (${folderWithEmails.emails.length}):\n` +
|
|
1799
|
+
folderWithEmails.emails.map((email, index) => `${index + 1}. ${email.subject}\n` +
|
|
1800
|
+
` 👤 From: ${email.from.name}\n` +
|
|
1801
|
+
` 📅 ${new Date(email.receivedDateTime).toLocaleDateString()}\n` +
|
|
1802
|
+
` ${email.isRead ? '📖' : '📩'} ${email.isRead ? 'Read' : 'Unread'}`).join('\n') +
|
|
1803
|
+
`\n\n💡 Traditional approach would require 2 separate API calls!`
|
|
1804
|
+
}
|
|
1805
|
+
]
|
|
1806
|
+
};
|
|
1807
|
+
default:
|
|
1808
|
+
throw new Error(`Unknown batch action: ${batchAction}`);
|
|
1809
|
+
}
|
|
1810
|
+
// ============ AI EMAIL ASSISTANT (MERGED TOOL) ============
|
|
1811
|
+
case "ai_email_assistant":
|
|
1812
|
+
if (ms365Config.multiUser) {
|
|
1813
|
+
const userId = args?.userId;
|
|
1814
|
+
if (!userId) {
|
|
1815
|
+
throw new Error("User ID is required in multi-user mode");
|
|
1816
|
+
}
|
|
1817
|
+
const graphClient = await multiUserMS365Auth.getGraphClientForUser(userId);
|
|
1818
|
+
ms365Ops.setGraphClient(graphClient);
|
|
1819
|
+
}
|
|
1820
|
+
else {
|
|
1821
|
+
const graphClient = await enhancedMS365Auth.getGraphClient();
|
|
1822
|
+
ms365Ops.setGraphClient(graphClient);
|
|
1823
|
+
}
|
|
1824
|
+
const aiAction = args?.action;
|
|
1825
|
+
if (!aiAction) {
|
|
1826
|
+
throw new Error("Action is required for AI email assistant");
|
|
1827
|
+
}
|
|
1828
|
+
switch (aiAction) {
|
|
1829
|
+
case 'search':
|
|
1830
|
+
if (!args?.query) {
|
|
1831
|
+
throw new Error("Query is required for search action");
|
|
1832
|
+
}
|
|
1833
|
+
const searchOptions = {
|
|
1834
|
+
enableCrossReference: args?.enableCrossReference !== false,
|
|
1835
|
+
enableFuzzySearch: args?.enableFuzzySearch !== false,
|
|
1836
|
+
enableThreadReconstruction: args?.enableThreadReconstruction !== false,
|
|
1837
|
+
maxResults: args?.maxResults || 50
|
|
1838
|
+
};
|
|
1839
|
+
const searchFolder = args?.folder || 'inbox';
|
|
1840
|
+
const useLargeMailboxStrategy = args?.useLargeMailboxStrategy === true;
|
|
1841
|
+
const timeWindowDays = args?.timeWindowDays || 365;
|
|
1842
|
+
// Check if we should use large mailbox strategy
|
|
1843
|
+
if (useLargeMailboxStrategy) {
|
|
1844
|
+
// Use advanced multi-tier search for large mailboxes
|
|
1845
|
+
const largeMailboxResult = await largeMailboxSearch.search(args.query, {
|
|
1846
|
+
maxTotalResults: searchOptions.maxResults,
|
|
1847
|
+
timeWindowDays: timeWindowDays,
|
|
1848
|
+
batchSize: 300,
|
|
1849
|
+
prioritizeRecent: true
|
|
1850
|
+
});
|
|
1851
|
+
return {
|
|
1852
|
+
content: [
|
|
1853
|
+
{
|
|
1854
|
+
type: "text",
|
|
1855
|
+
text: `🤖 AI Email Assistant - Large Mailbox Search Results\n\n` +
|
|
1856
|
+
`🔍 Query: "${largeMailboxResult.query}"\n` +
|
|
1857
|
+
`📊 Strategy: ${largeMailboxResult.searchStrategy}\n` +
|
|
1858
|
+
`📧 Total Mailbox Size: ~${largeMailboxResult.totalEmailsInMailbox.toLocaleString()} emails\n` +
|
|
1859
|
+
`🎯 Confidence: ${largeMailboxResult.confidence.toFixed(2)}\n` +
|
|
1860
|
+
`⏱️ Search Time: ${largeMailboxResult.searchTime}ms\n\n` +
|
|
1861
|
+
`🔍 Search Tiers Executed:\n${largeMailboxResult.tierResults.map(tier => `• ${tier.tier}: ${tier.emailsSearched} searched → ${tier.resultsFound} found (${tier.processingTime}ms)`).join('\n')}\n\n` +
|
|
1862
|
+
`📧 Found ${largeMailboxResult.finalResults.length} relevant emails:\n\n` +
|
|
1863
|
+
largeMailboxResult.finalResults.map((email, index) => `${index + 1}. ${email.subject}\n` +
|
|
1864
|
+
` 📨 From: ${email.from.name} <${email.from.address}>\n` +
|
|
1865
|
+
` 📅 ${new Date(email.receivedDateTime).toLocaleString()}\n` +
|
|
1866
|
+
` 🏷️ Categories: ${email.categories?.join(', ') || 'None'}\n` +
|
|
1867
|
+
` ⚡ Priority: ${email.importance || 'normal'}\n`).join('\n') +
|
|
1868
|
+
`\n💡 Recommendations:\n${largeMailboxResult.recommendations.join('\n')}`
|
|
1869
|
+
}
|
|
1870
|
+
]
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
else {
|
|
1874
|
+
// Use standard search for smaller mailboxes
|
|
1875
|
+
const corpusSize = args?.corpusSize || 200;
|
|
1876
|
+
const emailSearchResult = await ms365Ops.searchEmails({
|
|
1877
|
+
query: '*',
|
|
1878
|
+
maxResults: Math.min(corpusSize, 1000), // Cap at 1000 for performance
|
|
1879
|
+
folder: searchFolder
|
|
1880
|
+
});
|
|
1881
|
+
if (args?.enableContextAware !== false) {
|
|
1882
|
+
// Use context-aware search
|
|
1883
|
+
const contextResults = await contextAwareSearch.search(args.query, emailSearchResult.messages);
|
|
1884
|
+
logger.log(`🔍 Searched through ${emailSearchResult.messages.length} emails from corpus of ${corpusSize}`);
|
|
1885
|
+
const limitedResults = contextResults.emails.slice(0, searchOptions.maxResults);
|
|
1886
|
+
return {
|
|
1887
|
+
content: [
|
|
1888
|
+
{
|
|
1889
|
+
type: "text",
|
|
1890
|
+
text: `🤖 AI Email Assistant - Smart Search Results\n\n` +
|
|
1891
|
+
`🔍 Query: "${contextResults.originalQuery}"\n` +
|
|
1892
|
+
`📊 Strategy: ${contextResults.searchStrategy}\n` +
|
|
1893
|
+
`📧 Searched: ${emailSearchResult.messages.length} emails\n` +
|
|
1894
|
+
`🎯 Confidence: ${contextResults.confidence.toFixed(2)}\n\n` +
|
|
1895
|
+
`📧 Found ${limitedResults.length} relevant emails:\n\n` +
|
|
1896
|
+
limitedResults.map((email, index) => `${index + 1}. ${email.subject}\n` +
|
|
1897
|
+
` 📨 From: ${email.from.name} <${email.from.address}>\n` +
|
|
1898
|
+
` 📅 ${new Date(email.receivedDateTime).toLocaleString()}\n` +
|
|
1899
|
+
` 🏷️ Categories: ${email.categories?.join(', ') || 'None'}\n` +
|
|
1900
|
+
` ⚡ Priority: ${email.importance || 'normal'}\n`).join('\n') +
|
|
1901
|
+
`\n💡 Explanation:\n${contextResults.explanation}\n\n` +
|
|
1902
|
+
`🎯 Suggestions:\n${contextResults.suggestions.join('\n')}`
|
|
1903
|
+
}
|
|
1904
|
+
]
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
else {
|
|
1908
|
+
// Use intelligent search
|
|
1909
|
+
const intelligentResults = await intelligenceEngine.intelligentSearch(args.query, emailSearchResult.messages, searchOptions);
|
|
1910
|
+
logger.log(`🧠 Analyzed ${emailSearchResult.messages.length} emails from corpus of ${corpusSize}`);
|
|
1911
|
+
return {
|
|
1912
|
+
content: [
|
|
1913
|
+
{
|
|
1914
|
+
type: "text",
|
|
1915
|
+
text: `🤖 AI Email Assistant - Intelligent Search Results\n\n` +
|
|
1916
|
+
`🔍 Query: "${args.query}"\n` +
|
|
1917
|
+
`📧 Searched: ${emailSearchResult.messages.length} emails\n` +
|
|
1918
|
+
`📊 Found ${intelligentResults.insights.totalEmails} results with ${intelligentResults.insights.averageConfidence.toFixed(2)} confidence\n` +
|
|
1919
|
+
`⏱️ Processing Time: ${intelligentResults.insights.processingTime}ms\n\n` +
|
|
1920
|
+
`📧 Results:\n${intelligentResults.results.slice(0, searchOptions.maxResults).map((email, index) => `${index + 1}. ${email.subject}\n 📨 From: ${email.from.name} <${email.from.address}>\n 📅 ${new Date(email.receivedDateTime).toLocaleString()}\n 🔗 Cross-refs: ${intelligentResults.crossReferences.get(email.id)?.length || 0}\n 📊 Threads: ${intelligentResults.threads.has(email.id) ? 'Yes' : 'No'}\n`).join('\n')}\n\n` +
|
|
1921
|
+
`💡 Insights:\n` +
|
|
1922
|
+
`• Total Emails: ${intelligentResults.insights.totalEmails}\n` +
|
|
1923
|
+
`• High Priority: ${intelligentResults.insights.highPriorityEmails}\n` +
|
|
1924
|
+
`• Thread Count: ${intelligentResults.insights.threadCount}\n` +
|
|
1925
|
+
`• Average Confidence: ${intelligentResults.insights.averageConfidence.toFixed(2)}`
|
|
1926
|
+
}
|
|
1927
|
+
]
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
case 'classify':
|
|
1932
|
+
const classifyAction = args?.classifyAction || 'classify_recent';
|
|
1933
|
+
const maxResults = args?.maxResults || 50;
|
|
1934
|
+
switch (classifyAction) {
|
|
1935
|
+
case 'classify_recent':
|
|
1936
|
+
const recentEmailsResult = await ms365Ops.searchEmails({
|
|
1937
|
+
query: '*',
|
|
1938
|
+
maxResults: maxResults,
|
|
1939
|
+
folder: 'inbox'
|
|
1940
|
+
});
|
|
1941
|
+
const recentClassifications = await proactiveIntelligence.batchClassifyEmails(recentEmailsResult.messages);
|
|
1942
|
+
const recentSummary = proactiveIntelligence.generateClassificationSummary(recentClassifications);
|
|
1943
|
+
return {
|
|
1944
|
+
content: [
|
|
1945
|
+
{
|
|
1946
|
+
type: "text",
|
|
1947
|
+
text: `🤖 AI Email Assistant - Smart Classification\n\n` +
|
|
1948
|
+
`🏷️ Recent ${maxResults} Emails Analysis:\n\n` +
|
|
1949
|
+
`📊 Summary:\n` +
|
|
1950
|
+
`• Total emails: ${recentSummary.totalEmails}\n` +
|
|
1951
|
+
`• Critical: ${recentSummary.byPriority.critical || 0}\n` +
|
|
1952
|
+
`• High: ${recentSummary.byPriority.high || 0}\n` +
|
|
1953
|
+
`• Medium: ${recentSummary.byPriority.medium || 0}\n` +
|
|
1954
|
+
`• Low: ${recentSummary.byPriority.low || 0}\n\n` +
|
|
1955
|
+
`📈 Top Categories:\n${Object.entries(recentSummary.byCategory).map(([cat, count]) => `• ${cat}: ${count}`).join('\n')}\n\n` +
|
|
1956
|
+
`🎯 AI Recommendations:\n${recentSummary.recommendedActions.join('\n')}`
|
|
1957
|
+
}
|
|
1958
|
+
]
|
|
1959
|
+
};
|
|
1960
|
+
case 'get_summary':
|
|
1961
|
+
const summaryEmailsResult = await ms365Ops.searchEmails({
|
|
1962
|
+
query: '*',
|
|
1963
|
+
maxResults: 100,
|
|
1964
|
+
folder: 'inbox'
|
|
1965
|
+
});
|
|
1966
|
+
const summaryClassifications = await proactiveIntelligence.batchClassifyEmails(summaryEmailsResult.messages);
|
|
1967
|
+
const summary = proactiveIntelligence.generateClassificationSummary(summaryClassifications);
|
|
1968
|
+
return {
|
|
1969
|
+
content: [
|
|
1970
|
+
{
|
|
1971
|
+
type: "text",
|
|
1972
|
+
text: `🤖 AI Email Assistant - Intelligence Summary\n\n` +
|
|
1973
|
+
`📊 Total Emails Analyzed: ${summary.totalEmails}\n\n` +
|
|
1974
|
+
`⚡ Priority Distribution:\n` +
|
|
1975
|
+
`• Critical: ${summary.byPriority.critical || 0}\n` +
|
|
1976
|
+
`• High: ${summary.byPriority.high || 0}\n` +
|
|
1977
|
+
`• Medium: ${summary.byPriority.medium || 0}\n` +
|
|
1978
|
+
`• Low: ${summary.byPriority.low || 0}\n\n` +
|
|
1979
|
+
`📈 Category Distribution:\n${Object.entries(summary.byCategory).map(([cat, count]) => `• ${cat}: ${count}`).join('\n')}\n\n` +
|
|
1980
|
+
`🎯 Top AI Recommendations:\n${summary.recommendedActions.slice(0, 5).join('\n')}`
|
|
1981
|
+
}
|
|
1982
|
+
]
|
|
1983
|
+
};
|
|
1984
|
+
default:
|
|
1985
|
+
throw new Error(`Unknown classification action: ${classifyAction}`);
|
|
1986
|
+
}
|
|
1987
|
+
case 'process_attachments':
|
|
1988
|
+
if (!args?.messageId) {
|
|
1989
|
+
throw new Error("Message ID is required for attachment processing");
|
|
1990
|
+
}
|
|
1991
|
+
// Get the email and its attachments
|
|
1992
|
+
const email = await ms365Ops.getEmail(args.messageId, true);
|
|
1993
|
+
if (!email.hasAttachments || !email.attachments) {
|
|
1994
|
+
throw new Error("This email has no attachments to process");
|
|
1995
|
+
}
|
|
1996
|
+
// Filter specific attachments if requested
|
|
1997
|
+
let attachmentsToProcess = email.attachments;
|
|
1998
|
+
if (args?.attachmentIds && Array.isArray(args.attachmentIds)) {
|
|
1999
|
+
attachmentsToProcess = email.attachments.filter(att => args.attachmentIds.includes(att.id));
|
|
2000
|
+
}
|
|
2001
|
+
// Download attachments and prepare for processing
|
|
2002
|
+
const attachmentData = await Promise.all(attachmentsToProcess.map(async (att) => {
|
|
2003
|
+
const attachment = await ms365Ops.getAttachment(args.messageId, att.id);
|
|
2004
|
+
return {
|
|
2005
|
+
id: att.id,
|
|
2006
|
+
name: att.name,
|
|
2007
|
+
size: att.size,
|
|
2008
|
+
contentType: att.contentType,
|
|
2009
|
+
contentBytes: attachment.contentBytes
|
|
2010
|
+
};
|
|
2011
|
+
}));
|
|
2012
|
+
// Process attachments with document workflow
|
|
2013
|
+
const processingResults = await documentWorkflow.processEmailAttachments(email, attachmentData);
|
|
2014
|
+
// Get processing statistics
|
|
2015
|
+
const stats = documentWorkflow.getProcessingStats(processingResults);
|
|
2016
|
+
return {
|
|
2017
|
+
content: [
|
|
2018
|
+
{
|
|
2019
|
+
type: "text",
|
|
2020
|
+
text: `🤖 AI Email Assistant - Smart Attachment Processing\n\n` +
|
|
2021
|
+
`📊 Statistics:\n` +
|
|
2022
|
+
`• Total: ${stats.total}\n` +
|
|
2023
|
+
`• Successful: ${stats.successful}\n` +
|
|
2024
|
+
`• Password Protected: ${stats.passwordProtected}\n` +
|
|
2025
|
+
`• Failed: ${stats.failed}\n` +
|
|
2026
|
+
`• Text Extracted: ${stats.textExtracted}\n` +
|
|
2027
|
+
`• Avg Processing Time: ${stats.averageProcessingTime.toFixed(2)}ms\n\n` +
|
|
2028
|
+
`📋 Results:\n` +
|
|
2029
|
+
processingResults.map((result, index) => `${index + 1}. ${result.attachment.name}\n` +
|
|
2030
|
+
` 📊 Status: ${result.status}\n` +
|
|
2031
|
+
` 💾 Size: ${result.metadata.size} bytes\n` +
|
|
2032
|
+
` 🔒 Password Protected: ${result.metadata.isPasswordProtected ? 'Yes' : 'No'}\n` +
|
|
2033
|
+
` 📝 Text Extracted: ${result.metadata.extractedText ? 'Yes' : 'No'}\n` +
|
|
2034
|
+
` ⏱️ Processing Time: ${result.metadata.processingTime}ms\n` +
|
|
2035
|
+
`${result.textContent ? ` 📄 Content Preview: ${result.textContent.substring(0, 200)}...\n` : ''}` +
|
|
2036
|
+
`${result.errors ? ` ❌ Errors: ${result.errors.join(', ')}\n` : ''}`).join('\n')
|
|
2037
|
+
}
|
|
2038
|
+
]
|
|
2039
|
+
};
|
|
2040
|
+
default:
|
|
2041
|
+
throw new Error(`Unknown AI assistant action: ${aiAction}`);
|
|
2042
|
+
}
|
|
2043
|
+
// ============ PERFORMANCE TESTING TOOL ============
|
|
2044
|
+
case "performance_testing":
|
|
2045
|
+
if (ms365Config.multiUser) {
|
|
2046
|
+
const userId = args?.userId;
|
|
2047
|
+
if (!userId) {
|
|
2048
|
+
throw new Error("User ID is required in multi-user mode");
|
|
2049
|
+
}
|
|
2050
|
+
const graphClient = await multiUserMS365Auth.getGraphClientForUser(userId);
|
|
2051
|
+
ms365Ops.setGraphClient(graphClient);
|
|
2052
|
+
}
|
|
2053
|
+
else {
|
|
2054
|
+
const graphClient = await enhancedMS365Auth.getGraphClient();
|
|
2055
|
+
ms365Ops.setGraphClient(graphClient);
|
|
2056
|
+
}
|
|
2057
|
+
const testAction = args?.action;
|
|
2058
|
+
if (!testAction) {
|
|
2059
|
+
throw new Error("Action is required for performance testing");
|
|
2060
|
+
}
|
|
2061
|
+
switch (testAction) {
|
|
2062
|
+
case 'run_tests':
|
|
2063
|
+
// Get recent emails for testing
|
|
2064
|
+
const testEmailCount = Math.min(args?.testEmailCount || 10, 20);
|
|
2065
|
+
const recentEmails = await ms365Ops.searchEmails({
|
|
2066
|
+
maxResults: testEmailCount,
|
|
2067
|
+
folder: 'inbox'
|
|
2068
|
+
});
|
|
2069
|
+
if (recentEmails.messages.length < 5) {
|
|
2070
|
+
return {
|
|
2071
|
+
content: [
|
|
2072
|
+
{
|
|
2073
|
+
type: "text",
|
|
2074
|
+
text: `❌ Insufficient emails for testing. Found ${recentEmails.messages.length} emails, need at least 5.\n\n💡 Try sending yourself some test emails or use a different folder.`
|
|
2075
|
+
}
|
|
2076
|
+
]
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2079
|
+
const testMessageIds = recentEmails.messages.map(email => email.id);
|
|
2080
|
+
const testReport = await batchTestRunner.runAllTests(testMessageIds);
|
|
2081
|
+
return {
|
|
2082
|
+
content: [
|
|
2083
|
+
{
|
|
2084
|
+
type: "text",
|
|
2085
|
+
text: `🔬 COMPREHENSIVE PERFORMANCE TEST RESULTS\n\n${testReport}\n\n💡 These tests demonstrate the significant performance improvements achieved with native Microsoft Graph JSON batching!`
|
|
2086
|
+
}
|
|
2087
|
+
]
|
|
2088
|
+
};
|
|
2089
|
+
case 'benchmark_bulk_retrieval':
|
|
2090
|
+
const retrievalTestCount = Math.min(args?.testEmailCount || 10, 20);
|
|
2091
|
+
const retrievalEmails = await ms365Ops.searchEmails({
|
|
2092
|
+
maxResults: retrievalTestCount,
|
|
2093
|
+
folder: args?.folderId || 'inbox'
|
|
2094
|
+
});
|
|
2095
|
+
if (retrievalEmails.messages.length < 5) {
|
|
2096
|
+
throw new Error(`Insufficient emails for testing. Found ${retrievalEmails.messages.length}, need at least 5.`);
|
|
2097
|
+
}
|
|
2098
|
+
const retrievalTestIds = retrievalEmails.messages.slice(0, Math.min(10, retrievalEmails.messages.length)).map(e => e.id);
|
|
2099
|
+
const retrievalResult = await batchTestRunner.testBulkEmailRetrieval(retrievalTestIds);
|
|
2100
|
+
return {
|
|
2101
|
+
content: [
|
|
2102
|
+
{
|
|
2103
|
+
type: "text",
|
|
2104
|
+
text: `📧 BULK EMAIL RETRIEVAL BENCHMARK\n\n` +
|
|
2105
|
+
`🔍 Tested: ${retrievalTestIds.length} emails${args?.includeAttachments ? ' with attachments' : ''}\n\n` +
|
|
2106
|
+
`📊 Results:\n` +
|
|
2107
|
+
`• Traditional: ${retrievalResult.traditional.metrics.duration}ms (${retrievalResult.traditional.metrics.httpCalls} HTTP calls)\n` +
|
|
2108
|
+
`• Batched: ${retrievalResult.batched.metrics.duration}ms (${retrievalResult.batched.metrics.httpCalls} HTTP calls)\n\n` +
|
|
2109
|
+
`🏆 Performance Improvement:\n` +
|
|
2110
|
+
`• ${retrievalResult.comparison?.improvement.durationReduction.toFixed(1)}% faster execution\n` +
|
|
2111
|
+
`• ${retrievalResult.comparison?.improvement.httpCallReduction.toFixed(1)}% fewer HTTP calls\n` +
|
|
2112
|
+
`• ${retrievalResult.comparison?.improvement.efficiencyGain.toFixed(1)}% better efficiency per request`
|
|
2113
|
+
}
|
|
2114
|
+
]
|
|
2115
|
+
};
|
|
2116
|
+
case 'benchmark_bulk_operations':
|
|
2117
|
+
const operationsTestCount = Math.min(args?.testEmailCount || 10, 20);
|
|
2118
|
+
const operationsEmails = await ms365Ops.searchEmails({
|
|
2119
|
+
maxResults: operationsTestCount,
|
|
2120
|
+
folder: args?.folderId || 'inbox'
|
|
2121
|
+
});
|
|
2122
|
+
if (operationsEmails.messages.length < 5) {
|
|
2123
|
+
throw new Error(`Insufficient emails for testing. Found ${operationsEmails.messages.length}, need at least 5.`);
|
|
2124
|
+
}
|
|
2125
|
+
const operationsTestIds = operationsEmails.messages.slice(0, Math.min(15, operationsEmails.messages.length)).map(e => e.id);
|
|
2126
|
+
const operationsResult = await batchTestRunner.testBulkEmailOperations(operationsTestIds);
|
|
2127
|
+
return {
|
|
2128
|
+
content: [
|
|
2129
|
+
{
|
|
2130
|
+
type: "text",
|
|
2131
|
+
text: `⚡ BULK EMAIL OPERATIONS BENCHMARK\n\n` +
|
|
2132
|
+
`🔍 Tested: ${operationsTestIds.length} ${args?.operationType || 'mark'} operations\n\n` +
|
|
2133
|
+
`📊 Results:\n` +
|
|
2134
|
+
`• Traditional: ${operationsResult.traditional.metrics.duration}ms (${operationsResult.traditional.metrics.httpCalls} HTTP calls)\n` +
|
|
2135
|
+
`• Batched: ${operationsResult.batched.metrics.duration}ms (${operationsResult.batched.metrics.httpCalls} HTTP calls)\n\n` +
|
|
2136
|
+
`🏆 Performance Improvement:\n` +
|
|
2137
|
+
`• ${operationsResult.comparison?.improvement.durationReduction.toFixed(1)}% faster execution\n` +
|
|
2138
|
+
`• ${operationsResult.comparison?.improvement.httpCallReduction.toFixed(1)}% fewer HTTP calls\n` +
|
|
2139
|
+
`• ${operationsResult.comparison?.improvement.efficiencyGain.toFixed(1)}% better efficiency per request`
|
|
2140
|
+
}
|
|
2141
|
+
]
|
|
2142
|
+
};
|
|
2143
|
+
case 'benchmark_folder_operations':
|
|
2144
|
+
const folderResult = await batchTestRunner.testFolderWithEmails(args?.folderId || 'inbox', Math.min(args?.testEmailCount || 10, 15));
|
|
2145
|
+
return {
|
|
2146
|
+
content: [
|
|
2147
|
+
{
|
|
2148
|
+
type: "text",
|
|
2149
|
+
text: `📁 FOLDER + EMAILS BENCHMARK\n\n` +
|
|
2150
|
+
`🔍 Tested: Folder info + ${args?.testEmailCount || 10} emails\n\n` +
|
|
2151
|
+
`📊 Results:\n` +
|
|
2152
|
+
`• Traditional: ${folderResult.traditional.metrics.duration}ms (${folderResult.traditional.metrics.httpCalls} HTTP calls)\n` +
|
|
2153
|
+
`• Batched: ${folderResult.batched.metrics.duration}ms (${folderResult.batched.metrics.httpCalls} HTTP calls)\n\n` +
|
|
2154
|
+
`🏆 Performance Improvement:\n` +
|
|
2155
|
+
`• ${folderResult.comparison?.improvement.durationReduction.toFixed(1)}% faster execution\n` +
|
|
2156
|
+
`• ${folderResult.comparison?.improvement.httpCallReduction.toFixed(1)}% fewer HTTP calls\n` +
|
|
2157
|
+
`• ${folderResult.comparison?.improvement.efficiencyGain.toFixed(1)}% better efficiency per request`
|
|
2158
|
+
}
|
|
2159
|
+
]
|
|
2160
|
+
};
|
|
2161
|
+
case 'benchmark_mixed_operations':
|
|
2162
|
+
const mixedTestCount = Math.min(args?.testEmailCount || 12, 20);
|
|
2163
|
+
const mixedEmails = await ms365Ops.searchEmails({
|
|
2164
|
+
maxResults: mixedTestCount,
|
|
2165
|
+
folder: args?.folderId || 'inbox'
|
|
2166
|
+
});
|
|
2167
|
+
if (mixedEmails.messages.length < 9) {
|
|
2168
|
+
throw new Error(`Insufficient emails for mixed operations testing. Found ${mixedEmails.messages.length}, need at least 9.`);
|
|
2169
|
+
}
|
|
2170
|
+
const mixedTestIds = mixedEmails.messages.slice(0, Math.min(12, mixedEmails.messages.length)).map(e => e.id);
|
|
2171
|
+
const mixedResult = await batchTestRunner.testMixedOperations(mixedTestIds);
|
|
2172
|
+
return {
|
|
2173
|
+
content: [
|
|
2174
|
+
{
|
|
2175
|
+
type: "text",
|
|
2176
|
+
text: `🔄 MIXED OPERATIONS WORKFLOW BENCHMARK\n\n` +
|
|
2177
|
+
`🔍 Tested: ${mixedTestIds.length} mixed operations (mark, move, delete simulation)\n\n` +
|
|
2178
|
+
`📊 Results:\n` +
|
|
2179
|
+
`• Traditional: ${mixedResult.traditional.metrics.duration}ms (${mixedResult.traditional.metrics.httpCalls} HTTP calls)\n` +
|
|
2180
|
+
`• Batched: ${mixedResult.batched.metrics.duration}ms (${mixedResult.batched.metrics.httpCalls} HTTP calls)\n\n` +
|
|
2181
|
+
`🏆 Performance Improvement:\n` +
|
|
2182
|
+
`• ${mixedResult.comparison?.improvement.durationReduction.toFixed(1)}% faster execution\n` +
|
|
2183
|
+
`• ${mixedResult.comparison?.improvement.httpCallReduction.toFixed(1)}% fewer HTTP calls\n` +
|
|
2184
|
+
`• ${mixedResult.comparison?.improvement.efficiencyGain.toFixed(1)}% better efficiency per request`
|
|
2185
|
+
}
|
|
2186
|
+
]
|
|
2187
|
+
};
|
|
2188
|
+
case 'generate_report':
|
|
2189
|
+
const performanceReport = performanceMonitor.generateReport();
|
|
2190
|
+
return {
|
|
2191
|
+
content: [
|
|
2192
|
+
{
|
|
2193
|
+
type: "text",
|
|
2194
|
+
text: `📊 COMPREHENSIVE PERFORMANCE REPORT\n\n${performanceReport}\n\n💡 This report shows cumulative performance data from all batch operations executed during this session.`
|
|
2195
|
+
}
|
|
2196
|
+
]
|
|
2197
|
+
};
|
|
2198
|
+
case 'clear_metrics':
|
|
2199
|
+
performanceMonitor.clear();
|
|
2200
|
+
return {
|
|
2201
|
+
content: [
|
|
2202
|
+
{
|
|
2203
|
+
type: "text",
|
|
2204
|
+
text: `✅ Performance metrics cleared. Ready for new testing session.`
|
|
2205
|
+
}
|
|
2206
|
+
]
|
|
2207
|
+
};
|
|
2208
|
+
default:
|
|
2209
|
+
throw new Error(`Unknown performance testing action: ${testAction}`);
|
|
2210
|
+
}
|
|
2211
|
+
// ============ SEARCH-BATCH PIPELINE TOOL ============
|
|
2212
|
+
case "search_batch_pipeline":
|
|
2213
|
+
if (ms365Config.multiUser) {
|
|
2214
|
+
const userId = args?.userId;
|
|
2215
|
+
if (!userId) {
|
|
2216
|
+
throw new Error("User ID is required in multi-user mode");
|
|
2217
|
+
}
|
|
2218
|
+
const graphClient = await multiUserMS365Auth.getGraphClientForUser(userId);
|
|
2219
|
+
ms365Ops.setGraphClient(graphClient);
|
|
2220
|
+
}
|
|
2221
|
+
else {
|
|
2222
|
+
const graphClient = await enhancedMS365Auth.getGraphClient();
|
|
2223
|
+
ms365Ops.setGraphClient(graphClient);
|
|
2224
|
+
}
|
|
2225
|
+
const pipelineAction = args?.action;
|
|
2226
|
+
if (!pipelineAction) {
|
|
2227
|
+
throw new Error("Action is required for search-batch pipeline");
|
|
2228
|
+
}
|
|
2229
|
+
switch (pipelineAction) {
|
|
2230
|
+
case 'search_and_retrieve':
|
|
2231
|
+
const searchCriteria = {
|
|
2232
|
+
query: args?.query,
|
|
2233
|
+
from: args?.from,
|
|
2234
|
+
to: args?.to,
|
|
2235
|
+
subject: args?.subject,
|
|
2236
|
+
folder: args?.folder,
|
|
2237
|
+
after: args?.after,
|
|
2238
|
+
before: args?.before,
|
|
2239
|
+
hasAttachment: args?.hasAttachment,
|
|
2240
|
+
isUnread: args?.isUnread,
|
|
2241
|
+
importance: args?.importance,
|
|
2242
|
+
maxResults: args?.maxResults || 50
|
|
2243
|
+
};
|
|
2244
|
+
const retrieveResult = await searchBatchPipeline.searchAndRetrieveFull(searchCriteria, args?.includeAttachments || false);
|
|
2245
|
+
return {
|
|
2246
|
+
content: [
|
|
2247
|
+
{
|
|
2248
|
+
type: "text",
|
|
2249
|
+
text: `🔄 SEARCH-TO-BATCH PIPELINE: Retrieve Full Details\n\n` +
|
|
2250
|
+
`📊 ${retrieveResult.searchSummary}\n\n` +
|
|
2251
|
+
`🚀 Performance Improvement:\n` +
|
|
2252
|
+
`• Traditional: ${retrieveResult.performance.traditionalCalls} HTTP calls\n` +
|
|
2253
|
+
`• Batched: ${retrieveResult.performance.batchedCalls} HTTP calls\n` +
|
|
2254
|
+
`• Reduction: ${retrieveResult.performance.callReduction.toFixed(1)}%\n` +
|
|
2255
|
+
`• Time: ${retrieveResult.performance.timeEstimate}\n\n` +
|
|
2256
|
+
`📧 Retrieved Emails:\n` +
|
|
2257
|
+
retrieveResult.emails.map((email, index) => `${index + 1}. ${email.subject}\n` +
|
|
2258
|
+
` 👤 From: ${email.from.name} <${email.from.address}>\n` +
|
|
2259
|
+
` 📅 ${new Date(email.receivedDateTime).toLocaleString()}\n` +
|
|
2260
|
+
` ${email.hasAttachments ? '📎 Has attachments' : ''}\n`).join('\n')
|
|
2261
|
+
}
|
|
2262
|
+
]
|
|
2263
|
+
};
|
|
2264
|
+
case 'search_and_mark_read':
|
|
2265
|
+
case 'search_and_mark_unread':
|
|
2266
|
+
const markCriteria = {
|
|
2267
|
+
query: args?.query,
|
|
2268
|
+
from: args?.from,
|
|
2269
|
+
to: args?.to,
|
|
2270
|
+
subject: args?.subject,
|
|
2271
|
+
folder: args?.folder,
|
|
2272
|
+
after: args?.after,
|
|
2273
|
+
before: args?.before,
|
|
2274
|
+
hasAttachment: args?.hasAttachment,
|
|
2275
|
+
isUnread: args?.isUnread,
|
|
2276
|
+
importance: args?.importance
|
|
2277
|
+
};
|
|
2278
|
+
const markAction = pipelineAction === 'search_and_mark_read' ? 'mark_read' : 'mark_unread';
|
|
2279
|
+
const markResult = await searchBatchPipeline.executeSearchBatchPipeline({
|
|
2280
|
+
searchCriteria: markCriteria,
|
|
2281
|
+
batchAction: markAction,
|
|
2282
|
+
maxResults: args?.maxResults || 50
|
|
2283
|
+
});
|
|
2284
|
+
return {
|
|
2285
|
+
content: [
|
|
2286
|
+
{
|
|
2287
|
+
type: "text",
|
|
2288
|
+
text: `🔄 SEARCH-TO-BATCH PIPELINE: Mark as ${markAction === 'mark_read' ? 'Read' : 'Unread'}\n\n` +
|
|
2289
|
+
`📊 Search Results: ${markResult.searchResults.foundEmails} emails found (${markResult.searchResults.searchTime}ms)\n` +
|
|
2290
|
+
`📧 Batch Results: ${markResult.batchResults.successCount} marked successfully, ${markResult.batchResults.errorCount} errors (${markResult.batchResults.batchTime}ms)\n\n` +
|
|
2291
|
+
`🚀 Performance Improvement:\n` +
|
|
2292
|
+
`• Traditional: ${markResult.performanceImprovement.traditionalCalls} HTTP calls\n` +
|
|
2293
|
+
`• Batched: ${markResult.performanceImprovement.batchedCalls} HTTP calls\n` +
|
|
2294
|
+
`• Reduction: ${markResult.performanceImprovement.callReduction.toFixed(1)}%\n` +
|
|
2295
|
+
`• Time: ${markResult.performanceImprovement.timeEstimate}\n\n` +
|
|
2296
|
+
`✅ Total Time: ${markResult.totalTime}ms`
|
|
2297
|
+
}
|
|
2298
|
+
]
|
|
2299
|
+
};
|
|
2300
|
+
case 'search_and_move':
|
|
2301
|
+
if (!args?.destinationFolderId) {
|
|
2302
|
+
throw new Error("destinationFolderId is required for search_and_move action");
|
|
2303
|
+
}
|
|
2304
|
+
const moveCriteria = {
|
|
2305
|
+
query: args?.query,
|
|
2306
|
+
from: args?.from,
|
|
2307
|
+
to: args?.to,
|
|
2308
|
+
subject: args?.subject,
|
|
2309
|
+
folder: args?.folder,
|
|
2310
|
+
after: args?.after,
|
|
2311
|
+
before: args?.before,
|
|
2312
|
+
hasAttachment: args?.hasAttachment,
|
|
2313
|
+
isUnread: args?.isUnread,
|
|
2314
|
+
importance: args?.importance
|
|
2315
|
+
};
|
|
2316
|
+
const moveResult = await searchBatchPipeline.executeSearchBatchPipeline({
|
|
2317
|
+
searchCriteria: moveCriteria,
|
|
2318
|
+
batchAction: 'move',
|
|
2319
|
+
batchParams: { destinationFolderId: args.destinationFolderId },
|
|
2320
|
+
maxResults: args?.maxResults || 50
|
|
2321
|
+
});
|
|
2322
|
+
return {
|
|
2323
|
+
content: [
|
|
2324
|
+
{
|
|
2325
|
+
type: "text",
|
|
2326
|
+
text: `🔄 SEARCH-TO-BATCH PIPELINE: Move to Folder\n\n` +
|
|
2327
|
+
`📊 Search Results: ${moveResult.searchResults.foundEmails} emails found (${moveResult.searchResults.searchTime}ms)\n` +
|
|
2328
|
+
`📧 Batch Results: ${moveResult.batchResults.successCount} moved successfully, ${moveResult.batchResults.errorCount} errors (${moveResult.batchResults.batchTime}ms)\n` +
|
|
2329
|
+
`📁 Destination: ${args.destinationFolderId}\n\n` +
|
|
2330
|
+
`🚀 Performance Improvement:\n` +
|
|
2331
|
+
`• Traditional: ${moveResult.performanceImprovement.traditionalCalls} HTTP calls\n` +
|
|
2332
|
+
`• Batched: ${moveResult.performanceImprovement.batchedCalls} HTTP calls\n` +
|
|
2333
|
+
`• Reduction: ${moveResult.performanceImprovement.callReduction.toFixed(1)}%\n` +
|
|
2334
|
+
`• Time: ${moveResult.performanceImprovement.timeEstimate}\n\n` +
|
|
2335
|
+
`✅ Total Time: ${moveResult.totalTime}ms`
|
|
2336
|
+
}
|
|
2337
|
+
]
|
|
2338
|
+
};
|
|
2339
|
+
case 'search_and_delete':
|
|
2340
|
+
const deleteCriteria = {
|
|
2341
|
+
query: args?.query,
|
|
2342
|
+
from: args?.from,
|
|
2343
|
+
to: args?.to,
|
|
2344
|
+
subject: args?.subject,
|
|
2345
|
+
folder: args?.folder,
|
|
2346
|
+
after: args?.after,
|
|
2347
|
+
before: args?.before,
|
|
2348
|
+
hasAttachment: args?.hasAttachment,
|
|
2349
|
+
isUnread: args?.isUnread,
|
|
2350
|
+
importance: args?.importance
|
|
2351
|
+
};
|
|
2352
|
+
const deleteResult = await searchBatchPipeline.executeSearchBatchPipeline({
|
|
2353
|
+
searchCriteria: deleteCriteria,
|
|
2354
|
+
batchAction: 'delete',
|
|
2355
|
+
maxResults: args?.maxResults || 50
|
|
2356
|
+
});
|
|
2357
|
+
return {
|
|
2358
|
+
content: [
|
|
2359
|
+
{
|
|
2360
|
+
type: "text",
|
|
2361
|
+
text: `🔄 SEARCH-TO-BATCH PIPELINE: Delete Emails\n\n` +
|
|
2362
|
+
`📊 Search Results: ${deleteResult.searchResults.foundEmails} emails found (${deleteResult.searchResults.searchTime}ms)\n` +
|
|
2363
|
+
`📧 Batch Results: ${deleteResult.batchResults.successCount} deleted successfully, ${deleteResult.batchResults.errorCount} errors (${deleteResult.batchResults.batchTime}ms)\n\n` +
|
|
2364
|
+
`🚀 Performance Improvement:\n` +
|
|
2365
|
+
`• Traditional: ${deleteResult.performanceImprovement.traditionalCalls} HTTP calls\n` +
|
|
2366
|
+
`• Batched: ${deleteResult.performanceImprovement.batchedCalls} HTTP calls\n` +
|
|
2367
|
+
`• Reduction: ${deleteResult.performanceImprovement.callReduction.toFixed(1)}%\n` +
|
|
2368
|
+
`• Time: ${deleteResult.performanceImprovement.timeEstimate}\n\n` +
|
|
2369
|
+
`✅ Total Time: ${deleteResult.totalTime}ms`
|
|
2370
|
+
}
|
|
2371
|
+
]
|
|
2372
|
+
};
|
|
2373
|
+
case 'quick_workflows':
|
|
2374
|
+
const workflowType = args?.workflowType;
|
|
2375
|
+
if (!workflowType) {
|
|
2376
|
+
throw new Error("workflowType is required for quick_workflows action");
|
|
2377
|
+
}
|
|
2378
|
+
const workflows = await searchBatchPipeline.quickWorkflows();
|
|
2379
|
+
let workflowResult;
|
|
2380
|
+
switch (workflowType) {
|
|
2381
|
+
case 'mark_sender_read':
|
|
2382
|
+
if (!args?.senderEmail) {
|
|
2383
|
+
throw new Error("senderEmail is required for mark_sender_read workflow");
|
|
2384
|
+
}
|
|
2385
|
+
workflowResult = await workflows.markSenderEmailsRead(args.senderEmail);
|
|
2386
|
+
break;
|
|
2387
|
+
case 'move_by_subject':
|
|
2388
|
+
if (!args?.subjectText || !args?.destinationFolderId) {
|
|
2389
|
+
throw new Error("subjectText and destinationFolderId are required for move_by_subject workflow");
|
|
2390
|
+
}
|
|
2391
|
+
workflowResult = await workflows.moveEmailsBySubject(args.subjectText, args.destinationFolderId);
|
|
2392
|
+
break;
|
|
2393
|
+
case 'delete_old':
|
|
2394
|
+
if (!args?.beforeDate) {
|
|
2395
|
+
throw new Error("beforeDate is required for delete_old workflow");
|
|
2396
|
+
}
|
|
2397
|
+
workflowResult = await workflows.deleteOldEmails(args.beforeDate);
|
|
2398
|
+
break;
|
|
2399
|
+
case 'get_attachments':
|
|
2400
|
+
if (!args?.senderEmail) {
|
|
2401
|
+
throw new Error("senderEmail is required for get_attachments workflow");
|
|
2402
|
+
}
|
|
2403
|
+
workflowResult = await workflows.getEmailsWithAttachments(args.senderEmail);
|
|
2404
|
+
break;
|
|
2405
|
+
default:
|
|
2406
|
+
throw new Error(`Unknown workflow type: ${workflowType}`);
|
|
2407
|
+
}
|
|
2408
|
+
return {
|
|
2409
|
+
content: [
|
|
2410
|
+
{
|
|
2411
|
+
type: "text",
|
|
2412
|
+
text: `🔄 QUICK WORKFLOW: ${workflowType}\n\n` +
|
|
2413
|
+
`📊 Search Results: ${workflowResult.searchResults?.foundEmails || 'N/A'} emails found\n` +
|
|
2414
|
+
`📧 Batch Results: ${workflowResult.batchResults?.successCount || 'N/A'} processed successfully\n\n` +
|
|
2415
|
+
`🚀 Performance Improvement:\n` +
|
|
2416
|
+
`• Traditional: ${workflowResult.performanceImprovement?.traditionalCalls || 'N/A'} HTTP calls\n` +
|
|
2417
|
+
`• Batched: ${workflowResult.performanceImprovement?.batchedCalls || 'N/A'} HTTP calls\n` +
|
|
2418
|
+
`• Reduction: ${workflowResult.performanceImprovement?.callReduction?.toFixed(1) || 'N/A'}%\n` +
|
|
2419
|
+
`• Time: ${workflowResult.performanceImprovement?.timeEstimate || 'N/A'}\n\n` +
|
|
2420
|
+
`✅ Workflow completed in ${workflowResult.totalTime || 'N/A'}ms`
|
|
2421
|
+
}
|
|
2422
|
+
]
|
|
2423
|
+
};
|
|
2424
|
+
default:
|
|
2425
|
+
throw new Error(`Unknown pipeline action: ${pipelineAction}`);
|
|
2426
|
+
}
|
|
1314
2427
|
default:
|
|
1315
2428
|
throw new Error(`Unknown tool: ${name}`);
|
|
1316
2429
|
}
|