@auxiora/ambient 1.0.0
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/LICENSE +191 -0
- package/dist/anticipation.d.ts +27 -0
- package/dist/anticipation.d.ts.map +1 -0
- package/dist/anticipation.js +128 -0
- package/dist/anticipation.js.map +1 -0
- package/dist/briefing.d.ts +43 -0
- package/dist/briefing.d.ts.map +1 -0
- package/dist/briefing.js +109 -0
- package/dist/briefing.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/notification.d.ts +29 -0
- package/dist/notification.d.ts.map +1 -0
- package/dist/notification.js +87 -0
- package/dist/notification.js.map +1 -0
- package/dist/orchestrator.d.ts +40 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +130 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pattern-engine.d.ts +27 -0
- package/dist/pattern-engine.d.ts.map +1 -0
- package/dist/pattern-engine.js +187 -0
- package/dist/pattern-engine.js.map +1 -0
- package/dist/scheduler.d.ts +88 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +172 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
- package/src/anticipation.ts +141 -0
- package/src/briefing.ts +152 -0
- package/src/index.ts +26 -0
- package/src/notification.ts +101 -0
- package/src/orchestrator.ts +188 -0
- package/src/pattern-engine.ts +212 -0
- package/src/scheduler.ts +238 -0
- package/src/types.ts +85 -0
- package/tests/ambient.test.ts +363 -0
- package/tests/orchestrator.test.ts +343 -0
- package/tests/scheduler.test.ts +310 -0
- package/tests/wiring.test.ts +12 -0
- package/tsconfig.json +15 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
/** Priority ordering for queue sorting. */
|
|
3
|
+
const PRIORITY_ORDER = {
|
|
4
|
+
alert: 3,
|
|
5
|
+
nudge: 2,
|
|
6
|
+
whisper: 1,
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Priority-based queue for quiet notifications.
|
|
10
|
+
*/
|
|
11
|
+
export class QuietNotificationManager {
|
|
12
|
+
notifications = new Map();
|
|
13
|
+
/** Create and queue a notification. */
|
|
14
|
+
notify(priority, message, options) {
|
|
15
|
+
const notification = {
|
|
16
|
+
id: crypto.randomUUID(),
|
|
17
|
+
priority,
|
|
18
|
+
message,
|
|
19
|
+
detail: options?.detail,
|
|
20
|
+
createdAt: Date.now(),
|
|
21
|
+
dismissed: false,
|
|
22
|
+
source: options?.source ?? 'ambient',
|
|
23
|
+
};
|
|
24
|
+
this.notifications.set(notification.id, notification);
|
|
25
|
+
return notification;
|
|
26
|
+
}
|
|
27
|
+
/** Get all pending notifications, sorted by priority (highest first). */
|
|
28
|
+
getQueue() {
|
|
29
|
+
return Array.from(this.notifications.values())
|
|
30
|
+
.filter(n => !n.dismissed)
|
|
31
|
+
.sort((a, b) => PRIORITY_ORDER[b.priority] - PRIORITY_ORDER[a.priority]);
|
|
32
|
+
}
|
|
33
|
+
/** Get notifications filtered by priority. */
|
|
34
|
+
getByPriority(priority) {
|
|
35
|
+
return Array.from(this.notifications.values())
|
|
36
|
+
.filter(n => !n.dismissed && n.priority === priority);
|
|
37
|
+
}
|
|
38
|
+
/** Dismiss a notification. */
|
|
39
|
+
dismiss(id) {
|
|
40
|
+
const n = this.notifications.get(id);
|
|
41
|
+
if (!n)
|
|
42
|
+
return false;
|
|
43
|
+
n.dismissed = true;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/** Dismiss all notifications. */
|
|
47
|
+
dismissAll() {
|
|
48
|
+
let count = 0;
|
|
49
|
+
for (const n of this.notifications.values()) {
|
|
50
|
+
if (!n.dismissed) {
|
|
51
|
+
n.dismissed = true;
|
|
52
|
+
count++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return count;
|
|
56
|
+
}
|
|
57
|
+
/** Get a notification by ID. */
|
|
58
|
+
get(id) {
|
|
59
|
+
return this.notifications.get(id);
|
|
60
|
+
}
|
|
61
|
+
/** Get count of pending notifications. */
|
|
62
|
+
getPendingCount() {
|
|
63
|
+
let count = 0;
|
|
64
|
+
for (const n of this.notifications.values()) {
|
|
65
|
+
if (!n.dismissed)
|
|
66
|
+
count++;
|
|
67
|
+
}
|
|
68
|
+
return count;
|
|
69
|
+
}
|
|
70
|
+
/** Remove old dismissed notifications. */
|
|
71
|
+
prune(maxAge = 24 * 60 * 60 * 1000) {
|
|
72
|
+
const cutoff = Date.now() - maxAge;
|
|
73
|
+
let pruned = 0;
|
|
74
|
+
for (const [id, n] of this.notifications) {
|
|
75
|
+
if (n.dismissed && n.createdAt < cutoff) {
|
|
76
|
+
this.notifications.delete(id);
|
|
77
|
+
pruned++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return pruned;
|
|
81
|
+
}
|
|
82
|
+
/** Clear all notifications. */
|
|
83
|
+
clear() {
|
|
84
|
+
this.notifications.clear();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.js","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { TriggerEvent } from '@auxiora/connectors';
|
|
2
|
+
import type { NotificationHub, DoNotDisturbManager, NotificationPriority } from '@auxiora/notification-hub';
|
|
3
|
+
/** Configuration for the NotificationOrchestrator. */
|
|
4
|
+
export interface OrchestratorConfig {
|
|
5
|
+
/** Calendar alert window in ms (default 15 minutes). */
|
|
6
|
+
calendarAlertWindowMs?: number;
|
|
7
|
+
}
|
|
8
|
+
/** A pending orchestrator notification. */
|
|
9
|
+
export interface OrchestratorNotification {
|
|
10
|
+
id: string;
|
|
11
|
+
source: string;
|
|
12
|
+
priority: NotificationPriority;
|
|
13
|
+
message: string;
|
|
14
|
+
createdAt: number;
|
|
15
|
+
delivered: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Function that delivers a notification to the user. */
|
|
18
|
+
export type DeliveryChannelFn = (notification: OrchestratorNotification) => void;
|
|
19
|
+
export declare class NotificationOrchestrator {
|
|
20
|
+
private hub;
|
|
21
|
+
private dnd;
|
|
22
|
+
private deliveryChannel;
|
|
23
|
+
private pending;
|
|
24
|
+
private calendarAlertWindowMs;
|
|
25
|
+
constructor(hub: NotificationHub, dnd: DoNotDisturbManager, deliveryChannel: DeliveryChannelFn, config?: OrchestratorConfig);
|
|
26
|
+
/** Map trigger events to notifications and deliver or queue them. */
|
|
27
|
+
processTriggerEvents(events: TriggerEvent[]): OrchestratorNotification[];
|
|
28
|
+
/** Check calendar events and create notifications for those starting soon. */
|
|
29
|
+
processCalendarCheck(events: Array<{
|
|
30
|
+
title: string;
|
|
31
|
+
startTime: number;
|
|
32
|
+
}>, now?: number): OrchestratorNotification[];
|
|
33
|
+
/** Get all pending (undelivered or queued) notifications. */
|
|
34
|
+
getPending(): OrchestratorNotification[];
|
|
35
|
+
/** Dismiss a pending notification by ID. Returns true if found and removed. */
|
|
36
|
+
dismiss(id: string): boolean;
|
|
37
|
+
private mapTriggerEvent;
|
|
38
|
+
private routeNotification;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAE5G,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,2CAA2C;AAC3C,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,yDAAyD;AACzD,MAAM,MAAM,iBAAiB,GAAG,CAAC,YAAY,EAAE,wBAAwB,KAAK,IAAI,CAAC;AAMjF,qBAAa,wBAAwB;IACnC,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,GAAG,CAAsB;IACjC,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,qBAAqB,CAAS;gBAGpC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,mBAAmB,EACxB,eAAe,EAAE,iBAAiB,EAClC,MAAM,CAAC,EAAE,kBAAkB;IAQ7B,qEAAqE;IACrE,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,wBAAwB,EAAE;IA6BxE,8EAA8E;IAC9E,oBAAoB,CAClB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EACnD,GAAG,CAAC,EAAE,MAAM,GACX,wBAAwB,EAAE;IAkC7B,6DAA6D;IAC7D,UAAU,IAAI,wBAAwB,EAAE;IAIxC,+EAA+E;IAC/E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAO5B,OAAO,CAAC,eAAe;IA+CvB,OAAO,CAAC,iBAAiB;CAc1B"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const URGENCY_KEYWORDS = ['urgent', 'asap', 'important', 'action required', 'deadline'];
|
|
2
|
+
const DEFAULT_CALENDAR_ALERT_WINDOW_MS = 15 * 60 * 1000; // 15 minutes
|
|
3
|
+
export class NotificationOrchestrator {
|
|
4
|
+
hub;
|
|
5
|
+
dnd;
|
|
6
|
+
deliveryChannel;
|
|
7
|
+
pending = [];
|
|
8
|
+
calendarAlertWindowMs;
|
|
9
|
+
constructor(hub, dnd, deliveryChannel, config) {
|
|
10
|
+
this.hub = hub;
|
|
11
|
+
this.dnd = dnd;
|
|
12
|
+
this.deliveryChannel = deliveryChannel;
|
|
13
|
+
this.calendarAlertWindowMs = config?.calendarAlertWindowMs ?? DEFAULT_CALENDAR_ALERT_WINDOW_MS;
|
|
14
|
+
}
|
|
15
|
+
/** Map trigger events to notifications and deliver or queue them. */
|
|
16
|
+
processTriggerEvents(events) {
|
|
17
|
+
const results = [];
|
|
18
|
+
for (const event of events) {
|
|
19
|
+
const { priority, message, source } = this.mapTriggerEvent(event);
|
|
20
|
+
const notification = {
|
|
21
|
+
id: crypto.randomUUID(),
|
|
22
|
+
source,
|
|
23
|
+
priority,
|
|
24
|
+
message,
|
|
25
|
+
createdAt: Date.now(),
|
|
26
|
+
delivered: false,
|
|
27
|
+
};
|
|
28
|
+
this.hub.send({
|
|
29
|
+
source: source,
|
|
30
|
+
priority,
|
|
31
|
+
title: event.triggerId,
|
|
32
|
+
body: message,
|
|
33
|
+
});
|
|
34
|
+
this.routeNotification(notification);
|
|
35
|
+
results.push(notification);
|
|
36
|
+
}
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
/** Check calendar events and create notifications for those starting soon. */
|
|
40
|
+
processCalendarCheck(events, now) {
|
|
41
|
+
const currentTime = now ?? Date.now();
|
|
42
|
+
const results = [];
|
|
43
|
+
for (const event of events) {
|
|
44
|
+
const timeUntilStart = event.startTime - currentTime;
|
|
45
|
+
if (timeUntilStart > 0 && timeUntilStart <= this.calendarAlertWindowMs) {
|
|
46
|
+
const minutesUntil = Math.round(timeUntilStart / 60_000);
|
|
47
|
+
const message = `"${event.title}" starts in ${minutesUntil} minute${minutesUntil === 1 ? '' : 's'}`;
|
|
48
|
+
const notification = {
|
|
49
|
+
id: crypto.randomUUID(),
|
|
50
|
+
source: 'calendar',
|
|
51
|
+
priority: 'important',
|
|
52
|
+
message,
|
|
53
|
+
createdAt: currentTime,
|
|
54
|
+
delivered: false,
|
|
55
|
+
};
|
|
56
|
+
this.hub.send({
|
|
57
|
+
source: 'calendar',
|
|
58
|
+
priority: 'important',
|
|
59
|
+
title: event.title,
|
|
60
|
+
body: message,
|
|
61
|
+
});
|
|
62
|
+
this.routeNotification(notification);
|
|
63
|
+
results.push(notification);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
/** Get all pending (undelivered or queued) notifications. */
|
|
69
|
+
getPending() {
|
|
70
|
+
return this.pending.filter((n) => !n.delivered);
|
|
71
|
+
}
|
|
72
|
+
/** Dismiss a pending notification by ID. Returns true if found and removed. */
|
|
73
|
+
dismiss(id) {
|
|
74
|
+
const index = this.pending.findIndex((n) => n.id === id);
|
|
75
|
+
if (index === -1)
|
|
76
|
+
return false;
|
|
77
|
+
this.pending.splice(index, 1);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
mapTriggerEvent(event) {
|
|
81
|
+
switch (event.triggerId) {
|
|
82
|
+
case 'new-email': {
|
|
83
|
+
const subject = String(event.data['subject'] ?? '');
|
|
84
|
+
const from = String(event.data['from'] ?? 'unknown sender');
|
|
85
|
+
const isUrgent = URGENCY_KEYWORDS.some((kw) => subject.toLowerCase().includes(kw));
|
|
86
|
+
return {
|
|
87
|
+
priority: isUrgent ? 'urgent' : 'important',
|
|
88
|
+
message: `New email from ${from}: ${subject}`,
|
|
89
|
+
source: 'email',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
case 'event-starting-soon': {
|
|
93
|
+
const title = String(event.data['title'] ?? 'Untitled event');
|
|
94
|
+
return {
|
|
95
|
+
priority: 'important',
|
|
96
|
+
message: `Event starting soon: ${title}`,
|
|
97
|
+
source: 'calendar',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
case 'file-shared': {
|
|
101
|
+
const fileName = String(event.data['fileName'] ?? 'a file');
|
|
102
|
+
const sharedBy = String(event.data['sharedBy'] ?? 'someone');
|
|
103
|
+
return {
|
|
104
|
+
priority: 'low',
|
|
105
|
+
message: `${sharedBy} shared ${fileName} with you`,
|
|
106
|
+
source: 'system',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
default:
|
|
110
|
+
return {
|
|
111
|
+
priority: 'low',
|
|
112
|
+
message: `Notification from ${event.connectorId}: ${event.triggerId}`,
|
|
113
|
+
source: 'system',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
routeNotification(notification) {
|
|
118
|
+
const dndActive = this.dnd.isActive();
|
|
119
|
+
if (dndActive && notification.priority !== 'urgent') {
|
|
120
|
+
// Queue silently — do not deliver
|
|
121
|
+
notification.delivered = false;
|
|
122
|
+
this.pending.push(notification);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Deliver immediately
|
|
126
|
+
notification.delivered = true;
|
|
127
|
+
this.deliveryChannel(notification);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AmbientPattern, ObservedEvent } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Ambient pattern engine — observes events and detects behavioral patterns
|
|
4
|
+
* using sliding window frequency analysis.
|
|
5
|
+
*/
|
|
6
|
+
export declare class AmbientPatternEngine {
|
|
7
|
+
private events;
|
|
8
|
+
private patterns;
|
|
9
|
+
private windowSize;
|
|
10
|
+
constructor(windowSize?: number);
|
|
11
|
+
/** Observe a new event. */
|
|
12
|
+
observe(event: ObservedEvent): void;
|
|
13
|
+
/** Run pattern detection on observed events. */
|
|
14
|
+
detectPatterns(): AmbientPattern[];
|
|
15
|
+
/** Get all detected patterns above minimum confidence. */
|
|
16
|
+
getPatterns(): AmbientPattern[];
|
|
17
|
+
/** Get a pattern by ID. */
|
|
18
|
+
getPattern(id: string): AmbientPattern | undefined;
|
|
19
|
+
/** Get the number of observed events in the window. */
|
|
20
|
+
getEventCount(): number;
|
|
21
|
+
/** Clear all events and patterns. */
|
|
22
|
+
reset(): void;
|
|
23
|
+
private detectSchedulePattern;
|
|
24
|
+
private detectFrequencyPattern;
|
|
25
|
+
private detectCorrelations;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=pattern-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-engine.d.ts","sourceRoot":"","sources":["../src/pattern-engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAC;AASpF;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,CAAC,EAAE,MAAM;IAI/B,2BAA2B;IAC3B,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAOnC,gDAAgD;IAChD,cAAc,IAAI,cAAc,EAAE;IAyClC,0DAA0D;IAC1D,WAAW,IAAI,cAAc,EAAE;IAM/B,2BAA2B;IAC3B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIlD,uDAAuD;IACvD,aAAa,IAAI,MAAM;IAIvB,qCAAqC;IACrC,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,qBAAqB;IAkC7B,OAAO,CAAC,sBAAsB;IAsC9B,OAAO,CAAC,kBAAkB;CA2C3B"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
/** Sliding window size for frequency analysis. */
|
|
3
|
+
const DEFAULT_WINDOW_SIZE = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
4
|
+
/** Minimum occurrences to consider something a pattern. */
|
|
5
|
+
const MIN_OCCURRENCES = 3;
|
|
6
|
+
/** Minimum confidence to emit a pattern. */
|
|
7
|
+
const MIN_CONFIDENCE = 0.3;
|
|
8
|
+
/**
|
|
9
|
+
* Ambient pattern engine — observes events and detects behavioral patterns
|
|
10
|
+
* using sliding window frequency analysis.
|
|
11
|
+
*/
|
|
12
|
+
export class AmbientPatternEngine {
|
|
13
|
+
events = [];
|
|
14
|
+
patterns = new Map();
|
|
15
|
+
windowSize;
|
|
16
|
+
constructor(windowSize) {
|
|
17
|
+
this.windowSize = windowSize ?? DEFAULT_WINDOW_SIZE;
|
|
18
|
+
}
|
|
19
|
+
/** Observe a new event. */
|
|
20
|
+
observe(event) {
|
|
21
|
+
this.events.push(event);
|
|
22
|
+
// Prune events outside the window
|
|
23
|
+
const cutoff = Date.now() - this.windowSize;
|
|
24
|
+
this.events = this.events.filter(e => e.timestamp >= cutoff);
|
|
25
|
+
}
|
|
26
|
+
/** Run pattern detection on observed events. */
|
|
27
|
+
detectPatterns() {
|
|
28
|
+
const detected = [];
|
|
29
|
+
// Group events by type
|
|
30
|
+
const byType = new Map();
|
|
31
|
+
for (const event of this.events) {
|
|
32
|
+
const existing = byType.get(event.type) ?? [];
|
|
33
|
+
existing.push(event);
|
|
34
|
+
byType.set(event.type, existing);
|
|
35
|
+
}
|
|
36
|
+
// Detect schedule patterns (recurring events at similar times)
|
|
37
|
+
for (const [type, events] of byType) {
|
|
38
|
+
if (events.length >= MIN_OCCURRENCES) {
|
|
39
|
+
const schedulePattern = this.detectSchedulePattern(type, events);
|
|
40
|
+
if (schedulePattern)
|
|
41
|
+
detected.push(schedulePattern);
|
|
42
|
+
const frequencyPattern = this.detectFrequencyPattern(type, events);
|
|
43
|
+
if (frequencyPattern)
|
|
44
|
+
detected.push(frequencyPattern);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Detect correlations between event types
|
|
48
|
+
const correlations = this.detectCorrelations(byType);
|
|
49
|
+
detected.push(...correlations);
|
|
50
|
+
// Update stored patterns
|
|
51
|
+
for (const pattern of detected) {
|
|
52
|
+
const existing = this.patterns.get(pattern.id);
|
|
53
|
+
if (existing) {
|
|
54
|
+
existing.lastConfirmedAt = Date.now();
|
|
55
|
+
existing.occurrences++;
|
|
56
|
+
existing.confidence = Math.min(1, existing.confidence + 0.05);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
this.patterns.set(pattern.id, pattern);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return detected;
|
|
63
|
+
}
|
|
64
|
+
/** Get all detected patterns above minimum confidence. */
|
|
65
|
+
getPatterns() {
|
|
66
|
+
return Array.from(this.patterns.values())
|
|
67
|
+
.filter(p => p.confidence >= MIN_CONFIDENCE)
|
|
68
|
+
.sort((a, b) => b.confidence - a.confidence);
|
|
69
|
+
}
|
|
70
|
+
/** Get a pattern by ID. */
|
|
71
|
+
getPattern(id) {
|
|
72
|
+
return this.patterns.get(id);
|
|
73
|
+
}
|
|
74
|
+
/** Get the number of observed events in the window. */
|
|
75
|
+
getEventCount() {
|
|
76
|
+
return this.events.length;
|
|
77
|
+
}
|
|
78
|
+
/** Clear all events and patterns. */
|
|
79
|
+
reset() {
|
|
80
|
+
this.events = [];
|
|
81
|
+
this.patterns.clear();
|
|
82
|
+
}
|
|
83
|
+
detectSchedulePattern(type, events) {
|
|
84
|
+
// Check if events happen at similar hours of the day
|
|
85
|
+
const hours = events.map(e => new Date(e.timestamp).getHours());
|
|
86
|
+
const hourCounts = new Map();
|
|
87
|
+
for (const h of hours) {
|
|
88
|
+
hourCounts.set(h, (hourCounts.get(h) ?? 0) + 1);
|
|
89
|
+
}
|
|
90
|
+
// Find the most common hour
|
|
91
|
+
let maxHour = 0;
|
|
92
|
+
let maxCount = 0;
|
|
93
|
+
for (const [hour, count] of hourCounts) {
|
|
94
|
+
if (count > maxCount) {
|
|
95
|
+
maxHour = hour;
|
|
96
|
+
maxCount = count;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const ratio = maxCount / events.length;
|
|
100
|
+
if (ratio < 0.5 || maxCount < MIN_OCCURRENCES)
|
|
101
|
+
return null;
|
|
102
|
+
const id = crypto.randomUUID();
|
|
103
|
+
return {
|
|
104
|
+
id,
|
|
105
|
+
type: 'schedule',
|
|
106
|
+
description: `"${type}" events frequently occur around ${maxHour}:00`,
|
|
107
|
+
confidence: Math.min(1, ratio * 0.8 + (maxCount / 10) * 0.2),
|
|
108
|
+
evidence: events.slice(-3).map(e => `${type} at ${new Date(e.timestamp).toISOString()}`),
|
|
109
|
+
detectedAt: Date.now(),
|
|
110
|
+
lastConfirmedAt: Date.now(),
|
|
111
|
+
occurrences: maxCount,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
detectFrequencyPattern(type, events) {
|
|
115
|
+
if (events.length < MIN_OCCURRENCES)
|
|
116
|
+
return null;
|
|
117
|
+
// Calculate average interval between events
|
|
118
|
+
const sorted = [...events].sort((a, b) => a.timestamp - b.timestamp);
|
|
119
|
+
const intervals = [];
|
|
120
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
121
|
+
intervals.push(sorted[i].timestamp - sorted[i - 1].timestamp);
|
|
122
|
+
}
|
|
123
|
+
if (intervals.length === 0)
|
|
124
|
+
return null;
|
|
125
|
+
const avgInterval = intervals.reduce((a, b) => a + b, 0) / intervals.length;
|
|
126
|
+
const stdDev = Math.sqrt(intervals.reduce((sum, iv) => sum + (iv - avgInterval) ** 2, 0) / intervals.length);
|
|
127
|
+
// Low variance means regular frequency
|
|
128
|
+
const cv = avgInterval > 0 ? stdDev / avgInterval : Infinity;
|
|
129
|
+
if (cv > 0.5)
|
|
130
|
+
return null; // Too irregular
|
|
131
|
+
const confidence = Math.min(1, 1 - cv);
|
|
132
|
+
if (confidence < MIN_CONFIDENCE)
|
|
133
|
+
return null;
|
|
134
|
+
const hours = Math.round(avgInterval / (60 * 60 * 1000) * 10) / 10;
|
|
135
|
+
const id = crypto.randomUUID();
|
|
136
|
+
return {
|
|
137
|
+
id,
|
|
138
|
+
type: 'preference',
|
|
139
|
+
description: `"${type}" occurs roughly every ${hours} hours`,
|
|
140
|
+
confidence,
|
|
141
|
+
evidence: [`${events.length} occurrences over window`, `Average interval: ${hours}h`],
|
|
142
|
+
detectedAt: Date.now(),
|
|
143
|
+
lastConfirmedAt: Date.now(),
|
|
144
|
+
occurrences: events.length,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
detectCorrelations(byType) {
|
|
148
|
+
const patterns = [];
|
|
149
|
+
const types = Array.from(byType.keys());
|
|
150
|
+
// Check pairs of event types for temporal correlation
|
|
151
|
+
for (let i = 0; i < types.length; i++) {
|
|
152
|
+
for (let j = i + 1; j < types.length; j++) {
|
|
153
|
+
const eventsA = byType.get(types[i]);
|
|
154
|
+
const eventsB = byType.get(types[j]);
|
|
155
|
+
if (eventsA.length < 2 || eventsB.length < 2)
|
|
156
|
+
continue;
|
|
157
|
+
// Count how often B follows A within 5 minutes
|
|
158
|
+
const followWindow = 5 * 60 * 1000;
|
|
159
|
+
let follows = 0;
|
|
160
|
+
for (const a of eventsA) {
|
|
161
|
+
for (const b of eventsB) {
|
|
162
|
+
if (b.timestamp > a.timestamp && b.timestamp - a.timestamp <= followWindow) {
|
|
163
|
+
follows++;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const followRatio = follows / eventsA.length;
|
|
169
|
+
if (followRatio >= 0.5 && follows >= 2) {
|
|
170
|
+
const id = crypto.randomUUID();
|
|
171
|
+
patterns.push({
|
|
172
|
+
id,
|
|
173
|
+
type: 'correlation',
|
|
174
|
+
description: `"${types[j]}" often follows "${types[i]}" within 5 minutes`,
|
|
175
|
+
confidence: Math.min(1, followRatio * 0.9),
|
|
176
|
+
evidence: [`${follows} of ${eventsA.length} "${types[i]}" events followed by "${types[j]}"`],
|
|
177
|
+
detectedAt: Date.now(),
|
|
178
|
+
lastConfirmedAt: Date.now(),
|
|
179
|
+
occurrences: follows,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return patterns;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=pattern-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-engine.js","sourceRoot":"","sources":["../src/pattern-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAGtC,kDAAkD;AAClD,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAC9D,2DAA2D;AAC3D,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,4CAA4C;AAC5C,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B;;;GAGG;AACH,MAAM,OAAO,oBAAoB;IACvB,MAAM,GAAoB,EAAE,CAAC;IAC7B,QAAQ,GAAgC,IAAI,GAAG,EAAE,CAAC;IAClD,UAAU,CAAS;IAE3B,YAAY,UAAmB;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,mBAAmB,CAAC;IACtD,CAAC;IAED,2BAA2B;IAC3B,OAAO,CAAC,KAAoB;QAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,kCAAkC;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;IAC/D,CAAC;IAED,gDAAgD;IAChD,cAAc;QACZ,MAAM,QAAQ,GAAqB,EAAE,CAAC;QAEtC,uBAAuB;QACvB,MAAM,MAAM,GAAG,IAAI,GAAG,EAA2B,CAAC;QAClD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC9C,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACnC,CAAC;QAED,+DAA+D;QAC/D,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACpC,IAAI,MAAM,CAAC,MAAM,IAAI,eAAe,EAAE,CAAC;gBACrC,MAAM,eAAe,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBACjE,IAAI,eAAe;oBAAE,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBAEpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBACnE,IAAI,gBAAgB;oBAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACrD,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;QAE/B,yBAAyB;QACzB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC/C,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACtC,QAAQ,CAAC,WAAW,EAAE,CAAC;gBACvB,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,0DAA0D;IAC1D,WAAW;QACT,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;aACtC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,cAAc,CAAC;aAC3C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;IACjD,CAAC;IAED,2BAA2B;IAC3B,UAAU,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,uDAAuD;IACvD,aAAa;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,qCAAqC;IACrC,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAEO,qBAAqB,CAAC,IAAY,EAAE,MAAuB;QACjE,qDAAqD;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC7C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAClD,CAAC;QAED,4BAA4B;QAC5B,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,CAAC;YACvC,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;gBACrB,OAAO,GAAG,IAAI,CAAC;gBACf,QAAQ,GAAG,KAAK,CAAC;YACnB,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QACvC,IAAI,KAAK,GAAG,GAAG,IAAI,QAAQ,GAAG,eAAe;YAAE,OAAO,IAAI,CAAC;QAE3D,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAC/B,OAAO;YACL,EAAE;YACF,IAAI,EAAE,UAAU;YAChB,WAAW,EAAE,IAAI,IAAI,oCAAoC,OAAO,KAAK;YACrE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,GAAG,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC;YAC5D,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACxF,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;YACtB,eAAe,EAAE,IAAI,CAAC,GAAG,EAAE;YAC3B,WAAW,EAAE,QAAQ;SACtB,CAAC;IACJ,CAAC;IAEO,sBAAsB,CAAC,IAAY,EAAE,MAAuB;QAClE,IAAI,MAAM,CAAC,MAAM,GAAG,eAAe;YAAE,OAAO,IAAI,CAAC;QAEjD,4CAA4C;QAC5C,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QACrE,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAExC,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC;QAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CACtB,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CACnF,CAAC;QAEF,uCAAuC;QACvC,MAAM,EAAE,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7D,IAAI,EAAE,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC,CAAC,gBAAgB;QAE3C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACvC,IAAI,UAAU,GAAG,cAAc;YAAE,OAAO,IAAI,CAAC;QAE7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;QACnE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAC/B,OAAO;YACL,EAAE;YACF,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,IAAI,IAAI,0BAA0B,KAAK,QAAQ;YAC5D,UAAU;YACV,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,0BAA0B,EAAE,qBAAqB,KAAK,GAAG,CAAC;YACrF,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;YACtB,eAAe,EAAE,IAAI,CAAC,GAAG,EAAE;YAC3B,WAAW,EAAE,MAAM,CAAC,MAAM;SAC3B,CAAC;IACJ,CAAC;IAEO,kBAAkB,CAAC,MAAoC;QAC7D,MAAM,QAAQ,GAAqB,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAExC,sDAAsD;QACtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,CAAC;gBAEtC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;oBAAE,SAAS;gBAEvD,+CAA+C;gBAC/C,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;gBACnC,IAAI,OAAO,GAAG,CAAC,CAAC;gBAChB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;oBACxB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;wBACxB,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,YAAY,EAAE,CAAC;4BAC3E,OAAO,EAAE,CAAC;4BACV,MAAM;wBACR,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,MAAM,WAAW,GAAG,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;gBAC7C,IAAI,WAAW,IAAI,GAAG,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;oBACvC,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;oBAC/B,QAAQ,CAAC,IAAI,CAAC;wBACZ,EAAE;wBACF,IAAI,EAAE,aAAa;wBACnB,WAAW,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,oBAAoB,KAAK,CAAC,CAAC,CAAC,oBAAoB;wBACzE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,GAAG,CAAC;wBAC1C,QAAQ,EAAE,CAAC,GAAG,OAAO,OAAO,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,yBAAyB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;wBAC5F,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;wBACtB,eAAe,EAAE,IAAI,CAAC,GAAG,EAAE;wBAC3B,WAAW,EAAE,OAAO;qBACrB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Scheduler } from '@auxiora/behaviors';
|
|
2
|
+
import type { ConnectorRegistry, TriggerManager } from '@auxiora/connectors';
|
|
3
|
+
import type { BriefingGenerator } from './briefing.js';
|
|
4
|
+
import type { NotificationOrchestrator } from './orchestrator.js';
|
|
5
|
+
/** Configuration for the ambient scheduler. */
|
|
6
|
+
export interface AmbientSchedulerConfig {
|
|
7
|
+
/** Cron expression for morning briefing. */
|
|
8
|
+
morningCron: string;
|
|
9
|
+
/** Cron expression for evening summary. */
|
|
10
|
+
eveningCron: string;
|
|
11
|
+
/** Cron expression for email polling. */
|
|
12
|
+
emailPollCron: string;
|
|
13
|
+
/** Cron expression for calendar polling. */
|
|
14
|
+
calendarPollCron: string;
|
|
15
|
+
/** Cron expression for notification polling. */
|
|
16
|
+
notificationPollCron: string;
|
|
17
|
+
/** Calendar alert window in minutes. */
|
|
18
|
+
calendarAlertMinutes: number;
|
|
19
|
+
/** Whether the scheduler is enabled. */
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
/** Categories to include in briefings. */
|
|
22
|
+
categories: string[];
|
|
23
|
+
}
|
|
24
|
+
export declare const DEFAULT_AMBIENT_SCHEDULER_CONFIG: AmbientSchedulerConfig;
|
|
25
|
+
/** Dependencies for the ambient scheduler. */
|
|
26
|
+
export interface AmbientSchedulerDeps {
|
|
27
|
+
scheduler: Scheduler;
|
|
28
|
+
connectorRegistry: ConnectorRegistry;
|
|
29
|
+
triggerManager: TriggerManager;
|
|
30
|
+
briefingGenerator: BriefingGenerator;
|
|
31
|
+
emailIntelligence?: {
|
|
32
|
+
triage?: {
|
|
33
|
+
getTriageSummary(opts: {
|
|
34
|
+
maxResults: number;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
items: Array<{
|
|
37
|
+
subject: string;
|
|
38
|
+
priority: string;
|
|
39
|
+
}>;
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
calendarIntelligence?: {
|
|
44
|
+
analyzeDay(date: string): Promise<{
|
|
45
|
+
events: Array<{
|
|
46
|
+
title: string;
|
|
47
|
+
time: string;
|
|
48
|
+
}>;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
notificationOrchestrator?: NotificationOrchestrator;
|
|
52
|
+
deliveryChannel: (message: string) => Promise<void>;
|
|
53
|
+
userId: string;
|
|
54
|
+
config?: Partial<AmbientSchedulerConfig>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Schedules ambient polling and briefing generation using cron jobs.
|
|
58
|
+
*/
|
|
59
|
+
export declare class AmbientScheduler {
|
|
60
|
+
private readonly scheduler;
|
|
61
|
+
private readonly connectorRegistry;
|
|
62
|
+
private readonly triggerManager;
|
|
63
|
+
private readonly briefingGenerator;
|
|
64
|
+
private readonly emailIntelligence;
|
|
65
|
+
private readonly calendarIntelligence;
|
|
66
|
+
private readonly notificationOrchestrator;
|
|
67
|
+
private readonly deliveryChannel;
|
|
68
|
+
private readonly userId;
|
|
69
|
+
private readonly config;
|
|
70
|
+
private running;
|
|
71
|
+
constructor(deps: AmbientSchedulerDeps);
|
|
72
|
+
/** Start all scheduled cron jobs. */
|
|
73
|
+
start(): void;
|
|
74
|
+
/** Stop all scheduled cron jobs. */
|
|
75
|
+
stop(): void;
|
|
76
|
+
/** Whether the scheduler is currently running. */
|
|
77
|
+
isRunning(): boolean;
|
|
78
|
+
/** Get the current configuration. */
|
|
79
|
+
getConfig(): AmbientSchedulerConfig;
|
|
80
|
+
/** Generate and deliver a briefing for the specified time of day. */
|
|
81
|
+
generateAndDeliverBriefing(time: 'morning' | 'evening'): Promise<void>;
|
|
82
|
+
private pollAndNotify;
|
|
83
|
+
private parseTimeToTimestamp;
|
|
84
|
+
private pollCalendar;
|
|
85
|
+
private fetchCalendarEvents;
|
|
86
|
+
private fetchEmailSummary;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
|