Spaces:
Paused
Paused
File size: 4,472 Bytes
529090e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | import { DataSourceAdapter, type IngestedEntity } from '../ingestion/DataIngestionEngine.js';
import { readFile } from 'fs/promises';
import { existsSync } from 'fs';
interface OutlookEmail {
id: string;
subject: string;
sender: {
name: string;
address: string;
};
receivedDateTime: string;
bodyPreview: string;
body: {
contentType: string;
content: string;
};
importance: 'low' | 'normal' | 'high';
isRead: boolean;
}
export class OutlookJsonAdapter implements DataSourceAdapter {
name = 'Outlook';
type: 'outlook_mail' = 'outlook_mail';
private filePath: string;
private emails: OutlookEmail[] = [];
private lastLoaded: number = 0;
constructor(filePath: string) {
this.filePath = filePath;
}
/**
* Loads emails from the local JSON file
*/
private async loadEmails(): Promise<void> {
if (!existsSync(this.filePath)) {
console.warn(`[OutlookJsonAdapter] File not found: ${this.filePath}`);
this.emails = [];
return;
}
try {
const data = await readFile(this.filePath, 'utf-8');
// Handle potential wrapping structures (e.g. { value: [...] } or just [...])
const json = JSON.parse(data);
this.emails = Array.isArray(json) ? json : (json.value || []);
this.lastLoaded = Date.now();
console.log(`[OutlookJsonAdapter] Loaded ${this.emails.length} emails from ${this.filePath}`);
} catch (error) {
console.error(`[OutlookJsonAdapter] Failed to parse JSON:`, error);
this.emails = [];
}
}
/**
* Fetch emails, reloading if cache is stale (> 5 minutes)
*/
async fetch(): Promise<any[]> {
const STALE_THRESHOLD = 5 * 60 * 1000; // 5 minutes
if (this.emails.length === 0 || Date.now() - this.lastLoaded > STALE_THRESHOLD) {
await this.loadEmails();
}
return this.emails;
}
/**
* Transform Outlook emails to Unified Memory entities
*/
async transform(raw: any[]): Promise<IngestedEntity[]> {
return raw.map((email: OutlookEmail) => ({
id: email.id,
type: 'email',
source: 'Outlook',
title: email.subject,
content: `${email.subject}\n\nFrom: ${email.sender.name} <${email.sender.address}>\nDate: ${email.receivedDateTime}\n\n${email.bodyPreview}`,
metadata: {
subject: email.subject,
sender: email.sender.address,
senderName: email.sender.name,
receivedAt: email.receivedDateTime,
importance: email.importance,
isRead: email.isRead,
source: 'outlook_json',
},
timestamp: new Date(email.receivedDateTime)
}));
}
/**
* Check if the adapter is available (file exists)
*/
async isAvailable(): Promise<boolean> {
return existsSync(this.filePath);
}
/**
* Support direct queries
*/
async query(operation: string, params: any): Promise<any> {
await this.fetch(); // Ensure data is loaded
switch (operation) {
case 'search':
const term = params.query?.toLowerCase();
if (!term) return this.emails.slice(0, params.limit || 10);
return this.emails.filter(e =>
e.subject.toLowerCase().includes(term) ||
e.sender.name.toLowerCase().includes(term) ||
e.bodyPreview.toLowerCase().includes(term)
).slice(0, params.limit || 10);
case 'get_latest':
return this.emails
.sort((a, b) => new Date(b.receivedDateTime).getTime() - new Date(a.receivedDateTime).getTime())
.slice(0, params.limit || 10);
case 'get_by_sender':
const sender = params.sender?.toLowerCase();
if (!sender) return [];
return this.emails.filter(e =>
e.sender.address.toLowerCase().includes(sender) ||
e.sender.name.toLowerCase().includes(sender)
).slice(0, params.limit || 10);
default:
throw new Error(`Unsupported operation: ${operation}`);
}
}
}
|