naisys
Version:
NAISYS - Autonomous AI agent runner with built-in context management and cost tracking
111 lines • 4.29 kB
JavaScript
/** Derive a notification's kind from which payload field is populated. */
export function getNotificationKind(n) {
if (n.contextCommands !== undefined)
return "contextCommand";
if (n.debugCommands !== undefined)
return "debugCommand";
return "nonCommand";
}
export function createPromptNotificationService() {
/** Per-user notification queues keyed by userId */
const pending = new Map();
/** Single global notification — new one overwrites old */
let globalNotification = null;
/** Tracks which userIds have seen the current global notification */
const globalNotifiedUserIds = new Set();
function notify(notification) {
if (!notification.userId) {
// Global notification: overwrite previous, reset seen set
globalNotification = notification;
globalNotifiedUserIds.clear();
return;
}
const userId = notification.userId;
if (!pending.has(userId)) {
pending.set(userId, []);
}
pending.get(userId).push(notification);
}
function shouldWake(wake, wakeOnMessage) {
return wake === "always" || (wake === "yes" && wakeOnMessage);
}
function matchesKind(notification, kind) {
return kind === undefined || getNotificationKind(notification) === kind;
}
function hasPending(userId, wakeOnMessage, kind) {
const userQueue = pending.get(userId) || [];
// Check user's own queue
if (userQueue.some((n) => matchesKind(n, kind) && shouldWake(n.wake, wakeOnMessage))) {
return true;
}
// Check unseen global notification
if (globalNotification &&
!globalNotifiedUserIds.has(userId) &&
matchesKind(globalNotification, kind) &&
shouldWake(globalNotification.wake, wakeOnMessage)) {
return true;
}
return false;
}
function collectNotification(notification, result) {
if (notification.contextOutput) {
for (const text of notification.contextOutput) {
result.output.push({ type: "context", text });
}
}
if (notification.commentOutput) {
for (const text of notification.commentOutput) {
result.output.push({ type: "comment", text });
}
}
if (notification.errorOutput) {
for (const text of notification.errorOutput) {
result.output.push({ type: "error", text });
}
}
if (notification.contextCommands) {
result.contextCommands.push(...notification.contextCommands);
}
if (notification.debugCommands) {
result.debugCommands.push(...notification.debugCommands);
}
}
/** Drains notifications matching `kind` (or all if omitted); others stay
* queued for the path that owns that kind. */
async function processPending(userId, kind) {
const result = {
output: [],
contextCommands: [],
debugCommands: [],
drained: false,
};
// Process user-specific notifications
const userQueue = pending.get(userId);
if (userQueue) {
const keep = [];
while (userQueue.length > 0) {
const notification = userQueue.shift();
if (!matchesKind(notification, kind)) {
keep.push(notification);
continue;
}
collectNotification(notification, result);
result.drained = true;
await notification.processed?.();
}
userQueue.push(...keep);
}
// Process global notification if unseen and matches kind filter
if (globalNotification &&
!globalNotifiedUserIds.has(userId) &&
matchesKind(globalNotification, kind)) {
globalNotifiedUserIds.add(userId);
collectNotification(globalNotification, result);
result.drained = true;
await globalNotification.processed?.();
}
return result;
}
return { notify, hasPending, processPending };
}
//# sourceMappingURL=promptNotificationService.js.map