86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import { isInboxNoiseMessage, parseInboxJson } from './inboxNoise';
|
|
|
|
export interface IdleNotificationPayload {
|
|
type: 'idle_notification';
|
|
from?: string;
|
|
timestamp?: string;
|
|
idleReason?: 'available' | 'interrupted' | 'failed';
|
|
summary?: string;
|
|
completedTaskId?: string;
|
|
completedStatus?: 'resolved' | 'blocked' | 'failed';
|
|
failureReason?: string;
|
|
}
|
|
|
|
export type IdleNotificationPrimaryKind = 'heartbeat' | 'interrupted' | 'task_terminal' | 'failure';
|
|
|
|
export interface ClassifiedIdleNotification {
|
|
payload: IdleNotificationPayload;
|
|
primaryKind: IdleNotificationPrimaryKind;
|
|
hasPeerSummary: boolean;
|
|
peerSummary: string | null;
|
|
countsAsBootstrapConfirmation: boolean;
|
|
}
|
|
|
|
function getTrimmedOptionalString(value: unknown): string | null {
|
|
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
|
|
}
|
|
|
|
function isIdleNotificationPayload(value: unknown): value is IdleNotificationPayload {
|
|
return (
|
|
!!value &&
|
|
typeof value === 'object' &&
|
|
!Array.isArray(value) &&
|
|
(value as { type?: unknown }).type === 'idle_notification'
|
|
);
|
|
}
|
|
|
|
export function classifyIdleNotificationText(text: string): ClassifiedIdleNotification | null {
|
|
const parsed = parseInboxJson(text);
|
|
if (!isIdleNotificationPayload(parsed)) return null;
|
|
|
|
const peerSummary = getTrimmedOptionalString(parsed.summary);
|
|
const hasPeerSummary = peerSummary !== null;
|
|
const failureReason = getTrimmedOptionalString(parsed.failureReason);
|
|
const completedTaskId = getTrimmedOptionalString(parsed.completedTaskId);
|
|
|
|
let primaryKind: IdleNotificationPrimaryKind;
|
|
if (
|
|
parsed.idleReason === 'failed' ||
|
|
failureReason !== null ||
|
|
parsed.completedStatus === 'failed'
|
|
) {
|
|
primaryKind = 'failure';
|
|
} else if (
|
|
completedTaskId !== null ||
|
|
parsed.completedStatus === 'resolved' ||
|
|
parsed.completedStatus === 'blocked'
|
|
) {
|
|
primaryKind = 'task_terminal';
|
|
} else if (parsed.idleReason === 'interrupted') {
|
|
primaryKind = 'interrupted';
|
|
} else {
|
|
primaryKind = 'heartbeat';
|
|
}
|
|
|
|
return {
|
|
payload: parsed,
|
|
primaryKind,
|
|
hasPeerSummary,
|
|
peerSummary,
|
|
countsAsBootstrapConfirmation: primaryKind !== 'failure',
|
|
};
|
|
}
|
|
|
|
export function shouldSuppressDesktopNotificationForInboxText(text: string): boolean {
|
|
return classifyIdleNotificationText(text) !== null || isInboxNoiseMessage(text);
|
|
}
|
|
|
|
export function shouldExcludeInboxTextFromReplyCandidates(text: string): boolean {
|
|
return classifyIdleNotificationText(text) !== null || isInboxNoiseMessage(text);
|
|
}
|
|
|
|
export function getIdleGraphLabel(text: string): string | null {
|
|
const classified = classifyIdleNotificationText(text);
|
|
if (!classified) return null;
|
|
return classified.hasPeerSummary && classified.peerSummary ? classified.peerSummary : 'idle';
|
|
}
|